[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit

Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/bio_ssl.c b/ap/lib/libssl/openssl-1.1.1o/ssl/bio_ssl.c
new file mode 100644
index 0000000..67097d5
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/bio_ssl.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <openssl/crypto.h>
+#include "internal/bio.h"
+#include <openssl/err.h>
+#include "ssl_local.h"
+
+static int ssl_write(BIO *h, const char *buf, size_t size, size_t *written);
+static int ssl_read(BIO *b, char *buf, size_t size, size_t *readbytes);
+static int ssl_puts(BIO *h, const char *str);
+static long ssl_ctrl(BIO *h, int cmd, long arg1, void *arg2);
+static int ssl_new(BIO *h);
+static int ssl_free(BIO *data);
+static long ssl_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
+typedef struct bio_ssl_st {
+    SSL *ssl;                   /* The ssl handle :-) */
+    /* re-negotiate every time the total number of bytes is this size */
+    int num_renegotiates;
+    unsigned long renegotiate_count;
+    size_t byte_count;
+    unsigned long renegotiate_timeout;
+    unsigned long last_time;
+} BIO_SSL;
+
+static const BIO_METHOD methods_sslp = {
+    BIO_TYPE_SSL,
+    "ssl",
+    ssl_write,
+    NULL,                       /* ssl_write_old, */
+    ssl_read,
+    NULL,                       /* ssl_read_old,  */
+    ssl_puts,
+    NULL,                       /* ssl_gets,      */
+    ssl_ctrl,
+    ssl_new,
+    ssl_free,
+    ssl_callback_ctrl,
+};
+
+const BIO_METHOD *BIO_f_ssl(void)
+{
+    return &methods_sslp;
+}
+
+static int ssl_new(BIO *bi)
+{
+    BIO_SSL *bs = OPENSSL_zalloc(sizeof(*bs));
+
+    if (bs == NULL) {
+        BIOerr(BIO_F_SSL_NEW, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    BIO_set_init(bi, 0);
+    BIO_set_data(bi, bs);
+    /* Clear all flags */
+    BIO_clear_flags(bi, ~0);
+
+    return 1;
+}
+
+static int ssl_free(BIO *a)
+{
+    BIO_SSL *bs;
+
+    if (a == NULL)
+        return 0;
+    bs = BIO_get_data(a);
+    if (BIO_get_shutdown(a)) {
+        if (bs->ssl != NULL)
+            SSL_shutdown(bs->ssl);
+        if (BIO_get_init(a))
+            SSL_free(bs->ssl);
+        BIO_clear_flags(a, ~0); /* Clear all flags */
+        BIO_set_init(a, 0);
+    }
+    OPENSSL_free(bs);
+    return 1;
+}
+
+static int ssl_read(BIO *b, char *buf, size_t size, size_t *readbytes)
+{
+    int ret = 1;
+    BIO_SSL *sb;
+    SSL *ssl;
+    int retry_reason = 0;
+    int r = 0;
+
+    if (buf == NULL)
+        return 0;
+    sb = BIO_get_data(b);
+    ssl = sb->ssl;
+
+    BIO_clear_retry_flags(b);
+
+    ret = ssl_read_internal(ssl, buf, size, readbytes);
+
+    switch (SSL_get_error(ssl, ret)) {
+    case SSL_ERROR_NONE:
+        if (sb->renegotiate_count > 0) {
+            sb->byte_count += *readbytes;
+            if (sb->byte_count > sb->renegotiate_count) {
+                sb->byte_count = 0;
+                sb->num_renegotiates++;
+                SSL_renegotiate(ssl);
+                r = 1;
+            }
+        }
+        if ((sb->renegotiate_timeout > 0) && (!r)) {
+            unsigned long tm;
+
+            tm = (unsigned long)time(NULL);
+            if (tm > sb->last_time + sb->renegotiate_timeout) {
+                sb->last_time = tm;
+                sb->num_renegotiates++;
+                SSL_renegotiate(ssl);
+            }
+        }
+
+        break;
+    case SSL_ERROR_WANT_READ:
+        BIO_set_retry_read(b);
+        break;
+    case SSL_ERROR_WANT_WRITE:
+        BIO_set_retry_write(b);
+        break;
+    case SSL_ERROR_WANT_X509_LOOKUP:
+        BIO_set_retry_special(b);
+        retry_reason = BIO_RR_SSL_X509_LOOKUP;
+        break;
+    case SSL_ERROR_WANT_ACCEPT:
+        BIO_set_retry_special(b);
+        retry_reason = BIO_RR_ACCEPT;
+        break;
+    case SSL_ERROR_WANT_CONNECT:
+        BIO_set_retry_special(b);
+        retry_reason = BIO_RR_CONNECT;
+        break;
+    case SSL_ERROR_SYSCALL:
+    case SSL_ERROR_SSL:
+    case SSL_ERROR_ZERO_RETURN:
+    default:
+        break;
+    }
+
+    BIO_set_retry_reason(b, retry_reason);
+
+    return ret;
+}
+
+static int ssl_write(BIO *b, const char *buf, size_t size, size_t *written)
+{
+    int ret, r = 0;
+    int retry_reason = 0;
+    SSL *ssl;
+    BIO_SSL *bs;
+
+    if (buf == NULL)
+        return 0;
+    bs = BIO_get_data(b);
+    ssl = bs->ssl;
+
+    BIO_clear_retry_flags(b);
+
+    ret = ssl_write_internal(ssl, buf, size, written);
+
+    switch (SSL_get_error(ssl, ret)) {
+    case SSL_ERROR_NONE:
+        if (bs->renegotiate_count > 0) {
+            bs->byte_count += *written;
+            if (bs->byte_count > bs->renegotiate_count) {
+                bs->byte_count = 0;
+                bs->num_renegotiates++;
+                SSL_renegotiate(ssl);
+                r = 1;
+            }
+        }
+        if ((bs->renegotiate_timeout > 0) && (!r)) {
+            unsigned long tm;
+
+            tm = (unsigned long)time(NULL);
+            if (tm > bs->last_time + bs->renegotiate_timeout) {
+                bs->last_time = tm;
+                bs->num_renegotiates++;
+                SSL_renegotiate(ssl);
+            }
+        }
+        break;
+    case SSL_ERROR_WANT_WRITE:
+        BIO_set_retry_write(b);
+        break;
+    case SSL_ERROR_WANT_READ:
+        BIO_set_retry_read(b);
+        break;
+    case SSL_ERROR_WANT_X509_LOOKUP:
+        BIO_set_retry_special(b);
+        retry_reason = BIO_RR_SSL_X509_LOOKUP;
+        break;
+    case SSL_ERROR_WANT_CONNECT:
+        BIO_set_retry_special(b);
+        retry_reason = BIO_RR_CONNECT;
+    case SSL_ERROR_SYSCALL:
+    case SSL_ERROR_SSL:
+    default:
+        break;
+    }
+
+    BIO_set_retry_reason(b, retry_reason);
+
+    return ret;
+}
+
+static long ssl_ctrl(BIO *b, int cmd, long num, void *ptr)
+{
+    SSL **sslp, *ssl;
+    BIO_SSL *bs, *dbs;
+    BIO *dbio, *bio;
+    long ret = 1;
+    BIO *next;
+
+    bs = BIO_get_data(b);
+    next = BIO_next(b);
+    ssl = bs->ssl;
+    if ((ssl == NULL) && (cmd != BIO_C_SET_SSL))
+        return 0;
+    switch (cmd) {
+    case BIO_CTRL_RESET:
+        SSL_shutdown(ssl);
+
+        if (ssl->handshake_func == ssl->method->ssl_connect)
+            SSL_set_connect_state(ssl);
+        else if (ssl->handshake_func == ssl->method->ssl_accept)
+            SSL_set_accept_state(ssl);
+
+        if (!SSL_clear(ssl)) {
+            ret = 0;
+            break;
+        }
+
+        if (next != NULL)
+            ret = BIO_ctrl(next, cmd, num, ptr);
+        else if (ssl->rbio != NULL)
+            ret = BIO_ctrl(ssl->rbio, cmd, num, ptr);
+        else
+            ret = 1;
+        break;
+    case BIO_CTRL_INFO:
+        ret = 0;
+        break;
+    case BIO_C_SSL_MODE:
+        if (num)                /* client mode */
+            SSL_set_connect_state(ssl);
+        else
+            SSL_set_accept_state(ssl);
+        break;
+    case BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT:
+        ret = bs->renegotiate_timeout;
+        if (num < 60)
+            num = 5;
+        bs->renegotiate_timeout = (unsigned long)num;
+        bs->last_time = (unsigned long)time(NULL);
+        break;
+    case BIO_C_SET_SSL_RENEGOTIATE_BYTES:
+        ret = bs->renegotiate_count;
+        if ((long)num >= 512)
+            bs->renegotiate_count = (unsigned long)num;
+        break;
+    case BIO_C_GET_SSL_NUM_RENEGOTIATES:
+        ret = bs->num_renegotiates;
+        break;
+    case BIO_C_SET_SSL:
+        if (ssl != NULL) {
+            ssl_free(b);
+            if (!ssl_new(b))
+                return 0;
+            bs = BIO_get_data(b);
+        }
+        BIO_set_shutdown(b, num);
+        ssl = (SSL *)ptr;
+        bs->ssl = ssl;
+        bio = SSL_get_rbio(ssl);
+        if (bio != NULL) {
+            if (next != NULL)
+                BIO_push(bio, next);
+            BIO_set_next(b, bio);
+            BIO_up_ref(bio);
+        }
+        BIO_set_init(b, 1);
+        break;
+    case BIO_C_GET_SSL:
+        if (ptr != NULL) {
+            sslp = (SSL **)ptr;
+            *sslp = ssl;
+        } else
+            ret = 0;
+        break;
+    case BIO_CTRL_GET_CLOSE:
+        ret = BIO_get_shutdown(b);
+        break;
+    case BIO_CTRL_SET_CLOSE:
+        BIO_set_shutdown(b, (int)num);
+        break;
+    case BIO_CTRL_WPENDING:
+        ret = BIO_ctrl(ssl->wbio, cmd, num, ptr);
+        break;
+    case BIO_CTRL_PENDING:
+        ret = SSL_pending(ssl);
+        if (ret == 0)
+            ret = BIO_pending(ssl->rbio);
+        break;
+    case BIO_CTRL_FLUSH:
+        BIO_clear_retry_flags(b);
+        ret = BIO_ctrl(ssl->wbio, cmd, num, ptr);
+        BIO_copy_next_retry(b);
+        break;
+    case BIO_CTRL_PUSH:
+        if ((next != NULL) && (next != ssl->rbio)) {
+            /*
+             * We are going to pass ownership of next to the SSL object...but
+             * we don't own a reference to pass yet - so up ref
+             */
+            BIO_up_ref(next);
+            SSL_set_bio(ssl, next, next);
+        }
+        break;
+    case BIO_CTRL_POP:
+        /* Only detach if we are the BIO explicitly being popped */
+        if (b == ptr) {
+            /* This will clear the reference we obtained during push */
+            SSL_set_bio(ssl, NULL, NULL);
+        }
+        break;
+    case BIO_C_DO_STATE_MACHINE:
+        BIO_clear_retry_flags(b);
+
+        BIO_set_retry_reason(b, 0);
+        ret = (int)SSL_do_handshake(ssl);
+
+        switch (SSL_get_error(ssl, (int)ret)) {
+        case SSL_ERROR_WANT_READ:
+            BIO_set_flags(b, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
+            break;
+        case SSL_ERROR_WANT_WRITE:
+            BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
+            break;
+        case SSL_ERROR_WANT_CONNECT:
+            BIO_set_flags(b, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY);
+            BIO_set_retry_reason(b, BIO_get_retry_reason(next));
+            break;
+        case SSL_ERROR_WANT_X509_LOOKUP:
+            BIO_set_retry_special(b);
+            BIO_set_retry_reason(b, BIO_RR_SSL_X509_LOOKUP);
+            break;
+        default:
+            break;
+        }
+        break;
+    case BIO_CTRL_DUP:
+        dbio = (BIO *)ptr;
+        dbs = BIO_get_data(dbio);
+        SSL_free(dbs->ssl);
+        dbs->ssl = SSL_dup(ssl);
+        dbs->num_renegotiates = bs->num_renegotiates;
+        dbs->renegotiate_count = bs->renegotiate_count;
+        dbs->byte_count = bs->byte_count;
+        dbs->renegotiate_timeout = bs->renegotiate_timeout;
+        dbs->last_time = bs->last_time;
+        ret = (dbs->ssl != NULL);
+        break;
+    case BIO_C_GET_FD:
+        ret = BIO_ctrl(ssl->rbio, cmd, num, ptr);
+        break;
+    case BIO_CTRL_SET_CALLBACK:
+        ret = 0; /* use callback ctrl */
+        break;
+    default:
+        ret = BIO_ctrl(ssl->rbio, cmd, num, ptr);
+        break;
+    }
+    return ret;
+}
+
+static long ssl_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
+{
+    SSL *ssl;
+    BIO_SSL *bs;
+    long ret = 1;
+
+    bs = BIO_get_data(b);
+    ssl = bs->ssl;
+    switch (cmd) {
+    case BIO_CTRL_SET_CALLBACK:
+        ret = BIO_callback_ctrl(ssl->rbio, cmd, fp);
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+    return ret;
+}
+
+static int ssl_puts(BIO *bp, const char *str)
+{
+    int n, ret;
+
+    n = strlen(str);
+    ret = BIO_write(bp, str, n);
+    return ret;
+}
+
+BIO *BIO_new_buffer_ssl_connect(SSL_CTX *ctx)
+{
+#ifndef OPENSSL_NO_SOCK
+    BIO *ret = NULL, *buf = NULL, *ssl = NULL;
+
+    if ((buf = BIO_new(BIO_f_buffer())) == NULL)
+        return NULL;
+    if ((ssl = BIO_new_ssl_connect(ctx)) == NULL)
+        goto err;
+    if ((ret = BIO_push(buf, ssl)) == NULL)
+        goto err;
+    return ret;
+ err:
+    BIO_free(buf);
+    BIO_free(ssl);
+#endif
+    return NULL;
+}
+
+BIO *BIO_new_ssl_connect(SSL_CTX *ctx)
+{
+#ifndef OPENSSL_NO_SOCK
+    BIO *ret = NULL, *con = NULL, *ssl = NULL;
+
+    if ((con = BIO_new(BIO_s_connect())) == NULL)
+        return NULL;
+    if ((ssl = BIO_new_ssl(ctx, 1)) == NULL)
+        goto err;
+    if ((ret = BIO_push(ssl, con)) == NULL)
+        goto err;
+    return ret;
+ err:
+    BIO_free(ssl);
+    BIO_free(con);
+#endif
+    return NULL;
+}
+
+BIO *BIO_new_ssl(SSL_CTX *ctx, int client)
+{
+    BIO *ret;
+    SSL *ssl;
+
+    if ((ret = BIO_new(BIO_f_ssl())) == NULL)
+        return NULL;
+    if ((ssl = SSL_new(ctx)) == NULL) {
+        BIO_free(ret);
+        return NULL;
+    }
+    if (client)
+        SSL_set_connect_state(ssl);
+    else
+        SSL_set_accept_state(ssl);
+
+    BIO_set_ssl(ret, ssl, BIO_CLOSE);
+    return ret;
+}
+
+int BIO_ssl_copy_session_id(BIO *t, BIO *f)
+{
+    BIO_SSL *tdata, *fdata;
+    t = BIO_find_type(t, BIO_TYPE_SSL);
+    f = BIO_find_type(f, BIO_TYPE_SSL);
+    if ((t == NULL) || (f == NULL))
+        return 0;
+    tdata = BIO_get_data(t);
+    fdata = BIO_get_data(f);
+    if ((tdata->ssl == NULL) || (fdata->ssl == NULL))
+        return 0;
+    if (!SSL_copy_session_id(tdata->ssl, (fdata->ssl)))
+        return 0;
+    return 1;
+}
+
+void BIO_ssl_shutdown(BIO *b)
+{
+    BIO_SSL *bdata;
+
+    for (; b != NULL; b = BIO_next(b)) {
+        if (BIO_method_type(b) != BIO_TYPE_SSL)
+            continue;
+        bdata = BIO_get_data(b);
+        if (bdata != NULL && bdata->ssl != NULL)
+            SSL_shutdown(bdata->ssl);
+    }
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/build.info b/ap/lib/libssl/openssl-1.1.1o/ssl/build.info
new file mode 100644
index 0000000..bb2f1de
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/build.info
@@ -0,0 +1,15 @@
+LIBS=../libssl
+SOURCE[../libssl]=\
+        pqueue.c packet.c \
+        statem/statem_srvr.c statem/statem_clnt.c  s3_lib.c  s3_enc.c record/rec_layer_s3.c \
+        statem/statem_lib.c statem/extensions.c statem/extensions_srvr.c \
+        statem/extensions_clnt.c statem/extensions_cust.c s3_cbc.c s3_msg.c \
+        methods.c   t1_lib.c  t1_enc.c tls13_enc.c \
+        d1_lib.c  record/rec_layer_d1.c d1_msg.c \
+        statem/statem_dtls.c d1_srtp.c \
+        ssl_lib.c ssl_cert.c ssl_sess.c \
+        ssl_ciph.c ssl_stat.c ssl_rsa.c \
+        ssl_asn1.c ssl_txt.c ssl_init.c ssl_conf.c  ssl_mcnf.c \
+        bio_ssl.c ssl_err.c tls_srp.c t1_trce.c ssl_utst.c \
+        record/ssl3_buffer.c record/ssl3_record.c record/dtls1_bitmap.c \
+        statem/statem.c record/ssl3_record_tls13.c
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/d1_lib.c b/ap/lib/libssl/openssl-1.1.1o/ssl/d1_lib.c
new file mode 100644
index 0000000..05b85c1
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/d1_lib.c
@@ -0,0 +1,972 @@
+/*
+ * Copyright 2005-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "e_os.h"
+#include <stdio.h>
+#include <openssl/objects.h>
+#include <openssl/rand.h>
+#include "ssl_local.h"
+
+static void get_current_time(struct timeval *t);
+static int dtls1_handshake_write(SSL *s);
+static size_t dtls1_link_min_mtu(void);
+
+/* XDTLS:  figure out the right values */
+static const size_t g_probable_mtu[] = { 1500, 512, 256 };
+
+const SSL3_ENC_METHOD DTLSv1_enc_data = {
+    tls1_enc,
+    tls1_mac,
+    tls1_setup_key_block,
+    tls1_generate_master_secret,
+    tls1_change_cipher_state,
+    tls1_final_finish_mac,
+    TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE,
+    TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE,
+    tls1_alert_code,
+    tls1_export_keying_material,
+    SSL_ENC_FLAG_DTLS | SSL_ENC_FLAG_EXPLICIT_IV,
+    dtls1_set_handshake_header,
+    dtls1_close_construct_packet,
+    dtls1_handshake_write
+};
+
+const SSL3_ENC_METHOD DTLSv1_2_enc_data = {
+    tls1_enc,
+    tls1_mac,
+    tls1_setup_key_block,
+    tls1_generate_master_secret,
+    tls1_change_cipher_state,
+    tls1_final_finish_mac,
+    TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE,
+    TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE,
+    tls1_alert_code,
+    tls1_export_keying_material,
+    SSL_ENC_FLAG_DTLS | SSL_ENC_FLAG_EXPLICIT_IV | SSL_ENC_FLAG_SIGALGS
+        | SSL_ENC_FLAG_SHA256_PRF | SSL_ENC_FLAG_TLS1_2_CIPHERS,
+    dtls1_set_handshake_header,
+    dtls1_close_construct_packet,
+    dtls1_handshake_write
+};
+
+long dtls1_default_timeout(void)
+{
+    /*
+     * 2 hours, the 24 hours mentioned in the DTLSv1 spec is way too long for
+     * http, the cache would over fill
+     */
+    return (60 * 60 * 2);
+}
+
+int dtls1_new(SSL *s)
+{
+    DTLS1_STATE *d1;
+
+    if (!DTLS_RECORD_LAYER_new(&s->rlayer)) {
+        return 0;
+    }
+
+    if (!ssl3_new(s))
+        return 0;
+    if ((d1 = OPENSSL_zalloc(sizeof(*d1))) == NULL) {
+        ssl3_free(s);
+        return 0;
+    }
+
+    d1->buffered_messages = pqueue_new();
+    d1->sent_messages = pqueue_new();
+
+    if (s->server) {
+        d1->cookie_len = sizeof(s->d1->cookie);
+    }
+
+    d1->link_mtu = 0;
+    d1->mtu = 0;
+
+    if (d1->buffered_messages == NULL || d1->sent_messages == NULL) {
+        pqueue_free(d1->buffered_messages);
+        pqueue_free(d1->sent_messages);
+        OPENSSL_free(d1);
+        ssl3_free(s);
+        return 0;
+    }
+
+    s->d1 = d1;
+
+    if (!s->method->ssl_clear(s))
+        return 0;
+
+    return 1;
+}
+
+static void dtls1_clear_queues(SSL *s)
+{
+    dtls1_clear_received_buffer(s);
+    dtls1_clear_sent_buffer(s);
+}
+
+void dtls1_clear_received_buffer(SSL *s)
+{
+    pitem *item = NULL;
+    hm_fragment *frag = NULL;
+
+    while ((item = pqueue_pop(s->d1->buffered_messages)) != NULL) {
+        frag = (hm_fragment *)item->data;
+        dtls1_hm_fragment_free(frag);
+        pitem_free(item);
+    }
+}
+
+void dtls1_clear_sent_buffer(SSL *s)
+{
+    pitem *item = NULL;
+    hm_fragment *frag = NULL;
+
+    while ((item = pqueue_pop(s->d1->sent_messages)) != NULL) {
+        frag = (hm_fragment *)item->data;
+        dtls1_hm_fragment_free(frag);
+        pitem_free(item);
+    }
+}
+
+
+void dtls1_free(SSL *s)
+{
+    DTLS_RECORD_LAYER_free(&s->rlayer);
+
+    ssl3_free(s);
+
+    if (s->d1 != NULL) {
+        dtls1_clear_queues(s);
+        pqueue_free(s->d1->buffered_messages);
+        pqueue_free(s->d1->sent_messages);
+    }
+
+    OPENSSL_free(s->d1);
+    s->d1 = NULL;
+}
+
+int dtls1_clear(SSL *s)
+{
+    pqueue *buffered_messages;
+    pqueue *sent_messages;
+    size_t mtu;
+    size_t link_mtu;
+
+    DTLS_RECORD_LAYER_clear(&s->rlayer);
+
+    if (s->d1) {
+        DTLS_timer_cb timer_cb = s->d1->timer_cb;
+
+        buffered_messages = s->d1->buffered_messages;
+        sent_messages = s->d1->sent_messages;
+        mtu = s->d1->mtu;
+        link_mtu = s->d1->link_mtu;
+
+        dtls1_clear_queues(s);
+
+        memset(s->d1, 0, sizeof(*s->d1));
+
+        /* Restore the timer callback from previous state */
+        s->d1->timer_cb = timer_cb;
+
+        if (s->server) {
+            s->d1->cookie_len = sizeof(s->d1->cookie);
+        }
+
+        if (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU) {
+            s->d1->mtu = mtu;
+            s->d1->link_mtu = link_mtu;
+        }
+
+        s->d1->buffered_messages = buffered_messages;
+        s->d1->sent_messages = sent_messages;
+    }
+
+    if (!ssl3_clear(s))
+        return 0;
+
+    if (s->method->version == DTLS_ANY_VERSION)
+        s->version = DTLS_MAX_VERSION;
+#ifndef OPENSSL_NO_DTLS1_METHOD
+    else if (s->options & SSL_OP_CISCO_ANYCONNECT)
+        s->client_version = s->version = DTLS1_BAD_VER;
+#endif
+    else
+        s->version = s->method->version;
+
+    return 1;
+}
+
+long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg)
+{
+    int ret = 0;
+
+    switch (cmd) {
+    case DTLS_CTRL_GET_TIMEOUT:
+        if (dtls1_get_timeout(s, (struct timeval *)parg) != NULL) {
+            ret = 1;
+        }
+        break;
+    case DTLS_CTRL_HANDLE_TIMEOUT:
+        ret = dtls1_handle_timeout(s);
+        break;
+    case DTLS_CTRL_SET_LINK_MTU:
+        if (larg < (long)dtls1_link_min_mtu())
+            return 0;
+        s->d1->link_mtu = larg;
+        return 1;
+    case DTLS_CTRL_GET_LINK_MIN_MTU:
+        return (long)dtls1_link_min_mtu();
+    case SSL_CTRL_SET_MTU:
+        /*
+         *  We may not have a BIO set yet so can't call dtls1_min_mtu()
+         *  We'll have to make do with dtls1_link_min_mtu() and max overhead
+         */
+        if (larg < (long)dtls1_link_min_mtu() - DTLS1_MAX_MTU_OVERHEAD)
+            return 0;
+        s->d1->mtu = larg;
+        return larg;
+    default:
+        ret = ssl3_ctrl(s, cmd, larg, parg);
+        break;
+    }
+    return ret;
+}
+
+void dtls1_start_timer(SSL *s)
+{
+    unsigned int sec, usec;
+
+#ifndef OPENSSL_NO_SCTP
+    /* Disable timer for SCTP */
+    if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
+        memset(&s->d1->next_timeout, 0, sizeof(s->d1->next_timeout));
+        return;
+    }
+#endif
+
+    /*
+     * If timer is not set, initialize duration with 1 second or
+     * a user-specified value if the timer callback is installed.
+     */
+    if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) {
+
+        if (s->d1->timer_cb != NULL)
+            s->d1->timeout_duration_us = s->d1->timer_cb(s, 0);
+        else
+            s->d1->timeout_duration_us = 1000000;
+    }
+
+    /* Set timeout to current time */
+    get_current_time(&(s->d1->next_timeout));
+
+    /* Add duration to current time */
+
+    sec  = s->d1->timeout_duration_us / 1000000;
+    usec = s->d1->timeout_duration_us - (sec * 1000000);
+
+    s->d1->next_timeout.tv_sec  += sec;
+    s->d1->next_timeout.tv_usec += usec;
+
+    if (s->d1->next_timeout.tv_usec >= 1000000) {
+        s->d1->next_timeout.tv_sec++;
+        s->d1->next_timeout.tv_usec -= 1000000;
+    }
+
+    BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
+             &(s->d1->next_timeout));
+}
+
+struct timeval *dtls1_get_timeout(SSL *s, struct timeval *timeleft)
+{
+    struct timeval timenow;
+
+    /* If no timeout is set, just return NULL */
+    if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) {
+        return NULL;
+    }
+
+    /* Get current time */
+    get_current_time(&timenow);
+
+    /* If timer already expired, set remaining time to 0 */
+    if (s->d1->next_timeout.tv_sec < timenow.tv_sec ||
+        (s->d1->next_timeout.tv_sec == timenow.tv_sec &&
+         s->d1->next_timeout.tv_usec <= timenow.tv_usec)) {
+        memset(timeleft, 0, sizeof(*timeleft));
+        return timeleft;
+    }
+
+    /* Calculate time left until timer expires */
+    memcpy(timeleft, &(s->d1->next_timeout), sizeof(struct timeval));
+    timeleft->tv_sec -= timenow.tv_sec;
+    timeleft->tv_usec -= timenow.tv_usec;
+    if (timeleft->tv_usec < 0) {
+        timeleft->tv_sec--;
+        timeleft->tv_usec += 1000000;
+    }
+
+    /*
+     * If remaining time is less than 15 ms, set it to 0 to prevent issues
+     * because of small divergences with socket timeouts.
+     */
+    if (timeleft->tv_sec == 0 && timeleft->tv_usec < 15000) {
+        memset(timeleft, 0, sizeof(*timeleft));
+    }
+
+    return timeleft;
+}
+
+int dtls1_is_timer_expired(SSL *s)
+{
+    struct timeval timeleft;
+
+    /* Get time left until timeout, return false if no timer running */
+    if (dtls1_get_timeout(s, &timeleft) == NULL) {
+        return 0;
+    }
+
+    /* Return false if timer is not expired yet */
+    if (timeleft.tv_sec > 0 || timeleft.tv_usec > 0) {
+        return 0;
+    }
+
+    /* Timer expired, so return true */
+    return 1;
+}
+
+static void dtls1_double_timeout(SSL *s)
+{
+    s->d1->timeout_duration_us *= 2;
+    if (s->d1->timeout_duration_us > 60000000)
+        s->d1->timeout_duration_us = 60000000;
+}
+
+void dtls1_stop_timer(SSL *s)
+{
+    /* Reset everything */
+    memset(&s->d1->timeout, 0, sizeof(s->d1->timeout));
+    memset(&s->d1->next_timeout, 0, sizeof(s->d1->next_timeout));
+    s->d1->timeout_duration_us = 1000000;
+    BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
+             &(s->d1->next_timeout));
+    /* Clear retransmission buffer */
+    dtls1_clear_sent_buffer(s);
+}
+
+int dtls1_check_timeout_num(SSL *s)
+{
+    size_t mtu;
+
+    s->d1->timeout.num_alerts++;
+
+    /* Reduce MTU after 2 unsuccessful retransmissions */
+    if (s->d1->timeout.num_alerts > 2
+        && !(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {
+        mtu =
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL);
+        if (mtu < s->d1->mtu)
+            s->d1->mtu = mtu;
+    }
+
+    if (s->d1->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT) {
+        /* fail the connection, enough alerts have been sent */
+        SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_DTLS1_CHECK_TIMEOUT_NUM,
+                 SSL_R_READ_TIMEOUT_EXPIRED);
+        return -1;
+    }
+
+    return 0;
+}
+
+int dtls1_handle_timeout(SSL *s)
+{
+    /* if no timer is expired, don't do anything */
+    if (!dtls1_is_timer_expired(s)) {
+        return 0;
+    }
+
+    if (s->d1->timer_cb != NULL)
+        s->d1->timeout_duration_us = s->d1->timer_cb(s, s->d1->timeout_duration_us);
+    else
+        dtls1_double_timeout(s);
+
+    if (dtls1_check_timeout_num(s) < 0) {
+        /* SSLfatal() already called */
+        return -1;
+    }
+
+    s->d1->timeout.read_timeouts++;
+    if (s->d1->timeout.read_timeouts > DTLS1_TMO_READ_COUNT) {
+        s->d1->timeout.read_timeouts = 1;
+    }
+
+    dtls1_start_timer(s);
+    /* Calls SSLfatal() if required */
+    return dtls1_retransmit_buffered_messages(s);
+}
+
+static void get_current_time(struct timeval *t)
+{
+#if defined(_WIN32)
+    SYSTEMTIME st;
+    union {
+        unsigned __int64 ul;
+        FILETIME ft;
+    } now;
+
+    GetSystemTime(&st);
+    SystemTimeToFileTime(&st, &now.ft);
+    /* re-bias to 1/1/1970 */
+# ifdef  __MINGW32__
+    now.ul -= 116444736000000000ULL;
+# else
+    /* *INDENT-OFF* */
+    now.ul -= 116444736000000000UI64;
+    /* *INDENT-ON* */
+# endif
+    t->tv_sec = (long)(now.ul / 10000000);
+    t->tv_usec = ((int)(now.ul % 10000000)) / 10;
+#else
+    gettimeofday(t, NULL);
+#endif
+}
+
+#define LISTEN_SUCCESS              2
+#define LISTEN_SEND_VERIFY_REQUEST  1
+
+#ifndef OPENSSL_NO_SOCK
+int DTLSv1_listen(SSL *s, BIO_ADDR *client)
+{
+    int next, n, ret = 0;
+    unsigned char cookie[DTLS1_COOKIE_LENGTH];
+    unsigned char seq[SEQ_NUM_SIZE];
+    const unsigned char *data;
+    unsigned char *buf, *wbuf;
+    size_t fragoff, fraglen, msglen, reclen, align = 0;
+    unsigned int rectype, versmajor, msgseq, msgtype, clientvers, cookielen;
+    BIO *rbio, *wbio;
+    BIO_ADDR *tmpclient = NULL;
+    PACKET pkt, msgpkt, msgpayload, session, cookiepkt;
+
+    if (s->handshake_func == NULL) {
+        /* Not properly initialized yet */
+        SSL_set_accept_state(s);
+    }
+
+    /* Ensure there is no state left over from a previous invocation */
+    if (!SSL_clear(s))
+        return -1;
+
+    ERR_clear_error();
+
+    rbio = SSL_get_rbio(s);
+    wbio = SSL_get_wbio(s);
+
+    if (!rbio || !wbio) {
+        SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_BIO_NOT_SET);
+        return -1;
+    }
+
+    /*
+     * Note: This check deliberately excludes DTLS1_BAD_VER because that version
+     * requires the MAC to be calculated *including* the first ClientHello
+     * (without the cookie). Since DTLSv1_listen is stateless that cannot be
+     * supported. DTLS1_BAD_VER must use cookies in a stateful manner (e.g. via
+     * SSL_accept)
+     */
+    if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) {
+        SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNSUPPORTED_SSL_VERSION);
+        return -1;
+    }
+
+    if (!ssl3_setup_buffers(s)) {
+        /* SSLerr already called */
+        return -1;
+    }
+    buf = RECORD_LAYER_get_rbuf(&s->rlayer)->buf;
+    wbuf = RECORD_LAYER_get_wbuf(&s->rlayer)[0].buf;
+#if defined(SSL3_ALIGN_PAYLOAD)
+# if SSL3_ALIGN_PAYLOAD != 0
+    /*
+     * Using SSL3_RT_HEADER_LENGTH here instead of DTLS1_RT_HEADER_LENGTH for
+     * consistency with ssl3_read_n. In practice it should make no difference
+     * for sensible values of SSL3_ALIGN_PAYLOAD because the difference between
+     * SSL3_RT_HEADER_LENGTH and DTLS1_RT_HEADER_LENGTH is exactly 8
+     */
+    align = (size_t)buf + SSL3_RT_HEADER_LENGTH;
+    align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD);
+# endif
+#endif
+    buf += align;
+
+    do {
+        /* Get a packet */
+
+        clear_sys_error();
+        n = BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH
+                                + DTLS1_RT_HEADER_LENGTH);
+        if (n <= 0) {
+            if (BIO_should_retry(rbio)) {
+                /* Non-blocking IO */
+                goto end;
+            }
+            return -1;
+        }
+
+        if (!PACKET_buf_init(&pkt, buf, n)) {
+            SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_INTERNAL_ERROR);
+            return -1;
+        }
+
+        /*
+         * Parse the received record. If there are any problems with it we just
+         * dump it - with no alert. RFC6347 says this "Unlike TLS, DTLS is
+         * resilient in the face of invalid records (e.g., invalid formatting,
+         * length, MAC, etc.).  In general, invalid records SHOULD be silently
+         * discarded, thus preserving the association; however, an error MAY be
+         * logged for diagnostic purposes."
+         */
+
+        /* this packet contained a partial record, dump it */
+        if (n < DTLS1_RT_HEADER_LENGTH) {
+            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_RECORD_TOO_SMALL);
+            goto end;
+        }
+
+        if (s->msg_callback)
+            s->msg_callback(0, 0, SSL3_RT_HEADER, buf,
+                            DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
+
+        /* Get the record header */
+        if (!PACKET_get_1(&pkt, &rectype)
+            || !PACKET_get_1(&pkt, &versmajor)) {
+            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
+            goto end;
+        }
+
+        if (rectype != SSL3_RT_HANDSHAKE) {
+            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
+            goto end;
+        }
+
+        /*
+         * Check record version number. We only check that the major version is
+         * the same.
+         */
+        if (versmajor != DTLS1_VERSION_MAJOR) {
+            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_BAD_PROTOCOL_VERSION_NUMBER);
+            goto end;
+        }
+
+        if (!PACKET_forward(&pkt, 1)
+            /* Save the sequence number: 64 bits, with top 2 bytes = epoch */
+            || !PACKET_copy_bytes(&pkt, seq, SEQ_NUM_SIZE)
+            || !PACKET_get_length_prefixed_2(&pkt, &msgpkt)) {
+            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
+            goto end;
+        }
+        reclen = PACKET_remaining(&msgpkt);
+        /*
+         * We allow data remaining at the end of the packet because there could
+         * be a second record (but we ignore it)
+         */
+
+        /* This is an initial ClientHello so the epoch has to be 0 */
+        if (seq[0] != 0 || seq[1] != 0) {
+            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
+            goto end;
+        }
+
+        /* Get a pointer to the raw message for the later callback */
+        data = PACKET_data(&msgpkt);
+
+        /* Finished processing the record header, now process the message */
+        if (!PACKET_get_1(&msgpkt, &msgtype)
+            || !PACKET_get_net_3_len(&msgpkt, &msglen)
+            || !PACKET_get_net_2(&msgpkt, &msgseq)
+            || !PACKET_get_net_3_len(&msgpkt, &fragoff)
+            || !PACKET_get_net_3_len(&msgpkt, &fraglen)
+            || !PACKET_get_sub_packet(&msgpkt, &msgpayload, fraglen)
+            || PACKET_remaining(&msgpkt) != 0) {
+            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
+            goto end;
+        }
+
+        if (msgtype != SSL3_MT_CLIENT_HELLO) {
+            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
+            goto end;
+        }
+
+        /* Message sequence number can only be 0 or 1 */
+        if (msgseq > 2) {
+            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_INVALID_SEQUENCE_NUMBER);
+            goto end;
+        }
+
+        /*
+         * We don't support fragment reassembly for ClientHellos whilst
+         * listening because that would require server side state (which is
+         * against the whole point of the ClientHello/HelloVerifyRequest
+         * mechanism). Instead we only look at the first ClientHello fragment
+         * and require that the cookie must be contained within it.
+         */
+        if (fragoff != 0 || fraglen > msglen) {
+            /* Non initial ClientHello fragment (or bad fragment) */
+            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_FRAGMENTED_CLIENT_HELLO);
+            goto end;
+        }
+
+        if (s->msg_callback)
+            s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, data,
+                            fraglen + DTLS1_HM_HEADER_LENGTH, s,
+                            s->msg_callback_arg);
+
+        if (!PACKET_get_net_2(&msgpayload, &clientvers)) {
+            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
+            goto end;
+        }
+
+        /*
+         * Verify client version is supported
+         */
+        if (DTLS_VERSION_LT(clientvers, (unsigned int)s->method->version) &&
+            s->method->version != DTLS_ANY_VERSION) {
+            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_WRONG_VERSION_NUMBER);
+            goto end;
+        }
+
+        if (!PACKET_forward(&msgpayload, SSL3_RANDOM_SIZE)
+            || !PACKET_get_length_prefixed_1(&msgpayload, &session)
+            || !PACKET_get_length_prefixed_1(&msgpayload, &cookiepkt)) {
+            /*
+             * Could be malformed or the cookie does not fit within the initial
+             * ClientHello fragment. Either way we can't handle it.
+             */
+            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
+            goto end;
+        }
+
+        /*
+         * Check if we have a cookie or not. If not we need to send a
+         * HelloVerifyRequest.
+         */
+        if (PACKET_remaining(&cookiepkt) == 0) {
+            next = LISTEN_SEND_VERIFY_REQUEST;
+        } else {
+            /*
+             * We have a cookie, so lets check it.
+             */
+            if (s->ctx->app_verify_cookie_cb == NULL) {
+                SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_NO_VERIFY_COOKIE_CALLBACK);
+                /* This is fatal */
+                return -1;
+            }
+            if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookiepkt),
+                    (unsigned int)PACKET_remaining(&cookiepkt)) == 0) {
+                /*
+                 * We treat invalid cookies in the same was as no cookie as
+                 * per RFC6347
+                 */
+                next = LISTEN_SEND_VERIFY_REQUEST;
+            } else {
+                /* Cookie verification succeeded */
+                next = LISTEN_SUCCESS;
+            }
+        }
+
+        if (next == LISTEN_SEND_VERIFY_REQUEST) {
+            WPACKET wpkt;
+            unsigned int version;
+            size_t wreclen;
+
+            /*
+             * There was no cookie in the ClientHello so we need to send a
+             * HelloVerifyRequest. If this fails we do not worry about trying
+             * to resend, we just drop it.
+             */
+
+            /* Generate the cookie */
+            if (s->ctx->app_gen_cookie_cb == NULL ||
+                s->ctx->app_gen_cookie_cb(s, cookie, &cookielen) == 0 ||
+                cookielen > 255) {
+                SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
+                /* This is fatal */
+                return -1;
+            }
+
+            /*
+             * Special case: for hello verify request, client version 1.0 and we
+             * haven't decided which version to use yet send back using version
+             * 1.0 header: otherwise some clients will ignore it.
+             */
+            version = (s->method->version == DTLS_ANY_VERSION) ? DTLS1_VERSION
+                                                               : s->version;
+
+            /* Construct the record and message headers */
+            if (!WPACKET_init_static_len(&wpkt,
+                                         wbuf,
+                                         ssl_get_max_send_fragment(s)
+                                         + DTLS1_RT_HEADER_LENGTH,
+                                         0)
+                    || !WPACKET_put_bytes_u8(&wpkt, SSL3_RT_HANDSHAKE)
+                    || !WPACKET_put_bytes_u16(&wpkt, version)
+                       /*
+                        * Record sequence number is always the same as in the
+                        * received ClientHello
+                        */
+                    || !WPACKET_memcpy(&wpkt, seq, SEQ_NUM_SIZE)
+                       /* End of record, start sub packet for message */
+                    || !WPACKET_start_sub_packet_u16(&wpkt)
+                       /* Message type */
+                    || !WPACKET_put_bytes_u8(&wpkt,
+                                             DTLS1_MT_HELLO_VERIFY_REQUEST)
+                       /*
+                        * Message length - doesn't follow normal TLS convention:
+                        * the length isn't the last thing in the message header.
+                        * We'll need to fill this in later when we know the
+                        * length. Set it to zero for now
+                        */
+                    || !WPACKET_put_bytes_u24(&wpkt, 0)
+                       /*
+                        * Message sequence number is always 0 for a
+                        * HelloVerifyRequest
+                        */
+                    || !WPACKET_put_bytes_u16(&wpkt, 0)
+                       /*
+                        * We never fragment a HelloVerifyRequest, so fragment
+                        * offset is 0
+                        */
+                    || !WPACKET_put_bytes_u24(&wpkt, 0)
+                       /*
+                        * Fragment length is the same as message length, but
+                        * this *is* the last thing in the message header so we
+                        * can just start a sub-packet. No need to come back
+                        * later for this one.
+                        */
+                    || !WPACKET_start_sub_packet_u24(&wpkt)
+                       /* Create the actual HelloVerifyRequest body */
+                    || !dtls_raw_hello_verify_request(&wpkt, cookie, cookielen)
+                       /* Close message body */
+                    || !WPACKET_close(&wpkt)
+                       /* Close record body */
+                    || !WPACKET_close(&wpkt)
+                    || !WPACKET_get_total_written(&wpkt, &wreclen)
+                    || !WPACKET_finish(&wpkt)) {
+                SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_INTERNAL_ERROR);
+                WPACKET_cleanup(&wpkt);
+                /* This is fatal */
+                return -1;
+            }
+
+            /*
+             * Fix up the message len in the message header. Its the same as the
+             * fragment len which has been filled in by WPACKET, so just copy
+             * that. Destination for the message len is after the record header
+             * plus one byte for the message content type. The source is the
+             * last 3 bytes of the message header
+             */
+            memcpy(&wbuf[DTLS1_RT_HEADER_LENGTH + 1],
+                   &wbuf[DTLS1_RT_HEADER_LENGTH + DTLS1_HM_HEADER_LENGTH - 3],
+                   3);
+
+            if (s->msg_callback)
+                s->msg_callback(1, 0, SSL3_RT_HEADER, buf,
+                                DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
+
+            if ((tmpclient = BIO_ADDR_new()) == NULL) {
+                SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE);
+                goto end;
+            }
+
+            /*
+             * This is unnecessary if rbio and wbio are one and the same - but
+             * maybe they're not. We ignore errors here - some BIOs do not
+             * support this.
+             */
+            if (BIO_dgram_get_peer(rbio, tmpclient) > 0) {
+                (void)BIO_dgram_set_peer(wbio, tmpclient);
+            }
+            BIO_ADDR_free(tmpclient);
+            tmpclient = NULL;
+
+            /* TODO(size_t): convert this call */
+            if (BIO_write(wbio, wbuf, wreclen) < (int)wreclen) {
+                if (BIO_should_retry(wbio)) {
+                    /*
+                     * Non-blocking IO...but we're stateless, so we're just
+                     * going to drop this packet.
+                     */
+                    goto end;
+                }
+                return -1;
+            }
+
+            if (BIO_flush(wbio) <= 0) {
+                if (BIO_should_retry(wbio)) {
+                    /*
+                     * Non-blocking IO...but we're stateless, so we're just
+                     * going to drop this packet.
+                     */
+                    goto end;
+                }
+                return -1;
+            }
+        }
+    } while (next != LISTEN_SUCCESS);
+
+    /*
+     * Set expected sequence numbers to continue the handshake.
+     */
+    s->d1->handshake_read_seq = 1;
+    s->d1->handshake_write_seq = 1;
+    s->d1->next_handshake_write_seq = 1;
+    DTLS_RECORD_LAYER_set_write_sequence(&s->rlayer, seq);
+
+    /*
+     * We are doing cookie exchange, so make sure we set that option in the
+     * SSL object
+     */
+    SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE);
+
+    /*
+     * Tell the state machine that we've done the initial hello verify
+     * exchange
+     */
+    ossl_statem_set_hello_verify_done(s);
+
+    /*
+     * Some BIOs may not support this. If we fail we clear the client address
+     */
+    if (BIO_dgram_get_peer(rbio, client) <= 0)
+        BIO_ADDR_clear(client);
+
+    /* Buffer the record in the processed_rcds queue */
+    if (!dtls_buffer_listen_record(s, reclen, seq, align))
+        return -1;
+
+    ret = 1;
+ end:
+    BIO_ADDR_free(tmpclient);
+    return ret;
+}
+#endif
+
+static int dtls1_handshake_write(SSL *s)
+{
+    return dtls1_do_write(s, SSL3_RT_HANDSHAKE);
+}
+
+int dtls1_shutdown(SSL *s)
+{
+    int ret;
+#ifndef OPENSSL_NO_SCTP
+    BIO *wbio;
+
+    wbio = SSL_get_wbio(s);
+    if (wbio != NULL && BIO_dgram_is_sctp(wbio) &&
+        !(s->shutdown & SSL_SENT_SHUTDOWN)) {
+        ret = BIO_dgram_sctp_wait_for_dry(wbio);
+        if (ret < 0)
+            return -1;
+
+        if (ret == 0)
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 1,
+                     NULL);
+    }
+#endif
+    ret = ssl3_shutdown(s);
+#ifndef OPENSSL_NO_SCTP
+    BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 0, NULL);
+#endif
+    return ret;
+}
+
+int dtls1_query_mtu(SSL *s)
+{
+    if (s->d1->link_mtu) {
+        s->d1->mtu =
+            s->d1->link_mtu - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
+        s->d1->link_mtu = 0;
+    }
+
+    /* AHA!  Figure out the MTU, and stick to the right size */
+    if (s->d1->mtu < dtls1_min_mtu(s)) {
+        if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {
+            s->d1->mtu =
+                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+
+            /*
+             * I've seen the kernel return bogus numbers when it doesn't know
+             * (initial write), so just make sure we have a reasonable number
+             */
+            if (s->d1->mtu < dtls1_min_mtu(s)) {
+                /* Set to min mtu */
+                s->d1->mtu = dtls1_min_mtu(s);
+                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU,
+                         (long)s->d1->mtu, NULL);
+            }
+        } else
+            return 0;
+    }
+    return 1;
+}
+
+static size_t dtls1_link_min_mtu(void)
+{
+    return (g_probable_mtu[(sizeof(g_probable_mtu) /
+                            sizeof(g_probable_mtu[0])) - 1]);
+}
+
+size_t dtls1_min_mtu(SSL *s)
+{
+    return dtls1_link_min_mtu() - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
+}
+
+size_t DTLS_get_data_mtu(const SSL *s)
+{
+    size_t mac_overhead, int_overhead, blocksize, ext_overhead;
+    const SSL_CIPHER *ciph = SSL_get_current_cipher(s);
+    size_t mtu = s->d1->mtu;
+
+    if (ciph == NULL)
+        return 0;
+
+    if (!ssl_cipher_get_overhead(ciph, &mac_overhead, &int_overhead,
+                                 &blocksize, &ext_overhead))
+        return 0;
+
+    if (SSL_READ_ETM(s))
+        ext_overhead += mac_overhead;
+    else
+        int_overhead += mac_overhead;
+
+    /* Subtract external overhead (e.g. IV/nonce, separate MAC) */
+    if (ext_overhead + DTLS1_RT_HEADER_LENGTH >= mtu)
+        return 0;
+    mtu -= ext_overhead + DTLS1_RT_HEADER_LENGTH;
+
+    /* Round encrypted payload down to cipher block size (for CBC etc.)
+     * No check for overflow since 'mtu % blocksize' cannot exceed mtu. */
+    if (blocksize)
+        mtu -= (mtu % blocksize);
+
+    /* Subtract internal overhead (e.g. CBC padding len byte) */
+    if (int_overhead >= mtu)
+        return 0;
+    mtu -= int_overhead;
+
+    return mtu;
+}
+
+void DTLS_set_timer_cb(SSL *s, DTLS_timer_cb cb)
+{
+    s->d1->timer_cb = cb;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/d1_msg.c b/ap/lib/libssl/openssl-1.1.1o/ssl/d1_msg.c
new file mode 100644
index 0000000..8a31064
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/d1_msg.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2005-2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "ssl_local.h"
+
+int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, size_t len,
+                               size_t *written)
+{
+    int i;
+
+    if (SSL_in_init(s) && !ossl_statem_get_in_handshake(s)) {
+        i = s->handshake_func(s);
+        if (i < 0)
+            return i;
+        if (i == 0) {
+            SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES,
+                   SSL_R_SSL_HANDSHAKE_FAILURE);
+            return -1;
+        }
+    }
+
+    if (len > SSL3_RT_MAX_PLAIN_LENGTH) {
+        SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES, SSL_R_DTLS_MESSAGE_TOO_BIG);
+        return -1;
+    }
+
+    return dtls1_write_bytes(s, type, buf_, len, written);
+}
+
+int dtls1_dispatch_alert(SSL *s)
+{
+    int i, j;
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
+    unsigned char buf[DTLS1_AL_HEADER_LENGTH];
+    unsigned char *ptr = &buf[0];
+    size_t written;
+
+    s->s3->alert_dispatch = 0;
+
+    memset(buf, 0, sizeof(buf));
+    *ptr++ = s->s3->send_alert[0];
+    *ptr++ = s->s3->send_alert[1];
+
+    i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf), 0, &written);
+    if (i <= 0) {
+        s->s3->alert_dispatch = 1;
+        /* fprintf( stderr, "not done with alert\n" ); */
+    } else {
+        (void)BIO_flush(s->wbio);
+
+        if (s->msg_callback)
+            s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert,
+                            2, s, s->msg_callback_arg);
+
+        if (s->info_callback != NULL)
+            cb = s->info_callback;
+        else if (s->ctx->info_callback != NULL)
+            cb = s->ctx->info_callback;
+
+        if (cb != NULL) {
+            j = (s->s3->send_alert[0] << 8) | s->s3->send_alert[1];
+            cb(s, SSL_CB_WRITE_ALERT, j);
+        }
+    }
+    return i;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/d1_srtp.c b/ap/lib/libssl/openssl-1.1.1o/ssl/d1_srtp.c
new file mode 100644
index 0000000..c05a77e
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/d1_srtp.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * DTLS code by Eric Rescorla <ekr@rtfm.com>
+ *
+ * Copyright (C) 2006, Network Resonance, Inc. Copyright (C) 2011, RTFM, Inc.
+ */
+
+#include <stdio.h>
+#include <openssl/objects.h>
+#include "ssl_local.h"
+
+#ifndef OPENSSL_NO_SRTP
+
+static SRTP_PROTECTION_PROFILE srtp_known_profiles[] = {
+    {
+     "SRTP_AES128_CM_SHA1_80",
+     SRTP_AES128_CM_SHA1_80,
+     },
+    {
+     "SRTP_AES128_CM_SHA1_32",
+     SRTP_AES128_CM_SHA1_32,
+     },
+    {
+     "SRTP_AEAD_AES_128_GCM",
+     SRTP_AEAD_AES_128_GCM,
+     },
+    {
+     "SRTP_AEAD_AES_256_GCM",
+     SRTP_AEAD_AES_256_GCM,
+     },
+    {0}
+};
+
+static int find_profile_by_name(char *profile_name,
+                                SRTP_PROTECTION_PROFILE **pptr, size_t len)
+{
+    SRTP_PROTECTION_PROFILE *p;
+
+    p = srtp_known_profiles;
+    while (p->name) {
+        if ((len == strlen(p->name))
+            && strncmp(p->name, profile_name, len) == 0) {
+            *pptr = p;
+            return 0;
+        }
+
+        p++;
+    }
+
+    return 1;
+}
+
+static int ssl_ctx_make_profiles(const char *profiles_string,
+                                 STACK_OF(SRTP_PROTECTION_PROFILE) **out)
+{
+    STACK_OF(SRTP_PROTECTION_PROFILE) *profiles;
+
+    char *col;
+    char *ptr = (char *)profiles_string;
+    SRTP_PROTECTION_PROFILE *p;
+
+    if ((profiles = sk_SRTP_PROTECTION_PROFILE_new_null()) == NULL) {
+        SSLerr(SSL_F_SSL_CTX_MAKE_PROFILES,
+               SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES);
+        return 1;
+    }
+
+    do {
+        col = strchr(ptr, ':');
+
+        if (!find_profile_by_name(ptr, &p, col ? (size_t)(col - ptr)
+                                               : strlen(ptr))) {
+            if (sk_SRTP_PROTECTION_PROFILE_find(profiles, p) >= 0) {
+                SSLerr(SSL_F_SSL_CTX_MAKE_PROFILES,
+                       SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+                goto err;
+            }
+
+            if (!sk_SRTP_PROTECTION_PROFILE_push(profiles, p)) {
+                SSLerr(SSL_F_SSL_CTX_MAKE_PROFILES,
+                       SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES);
+                goto err;
+            }
+        } else {
+            SSLerr(SSL_F_SSL_CTX_MAKE_PROFILES,
+                   SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE);
+            goto err;
+        }
+
+        if (col)
+            ptr = col + 1;
+    } while (col);
+
+    sk_SRTP_PROTECTION_PROFILE_free(*out);
+
+    *out = profiles;
+
+    return 0;
+ err:
+    sk_SRTP_PROTECTION_PROFILE_free(profiles);
+    return 1;
+}
+
+int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles)
+{
+    return ssl_ctx_make_profiles(profiles, &ctx->srtp_profiles);
+}
+
+int SSL_set_tlsext_use_srtp(SSL *s, const char *profiles)
+{
+    return ssl_ctx_make_profiles(profiles, &s->srtp_profiles);
+}
+
+STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *s)
+{
+    if (s != NULL) {
+        if (s->srtp_profiles != NULL) {
+            return s->srtp_profiles;
+        } else if ((s->ctx != NULL) && (s->ctx->srtp_profiles != NULL)) {
+            return s->ctx->srtp_profiles;
+        }
+    }
+
+    return NULL;
+}
+
+SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s)
+{
+    return s->srtp_profile;
+}
+#endif
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/methods.c b/ap/lib/libssl/openssl-1.1.1o/ssl/methods.c
new file mode 100644
index 0000000..c5e8898
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/methods.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <openssl/objects.h>
+#include "ssl_local.h"
+
+/*-
+ * TLS/SSLv3 methods
+ */
+
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0,
+                        TLS_method,
+                        ossl_statem_accept,
+                        ossl_statem_connect, TLSv1_2_enc_data)
+IMPLEMENT_tls_meth_func(TLS1_3_VERSION, 0, SSL_OP_NO_TLSv1_3,
+                        tlsv1_3_method,
+                        ossl_statem_accept,
+                        ossl_statem_connect, TLSv1_3_enc_data)
+#ifndef OPENSSL_NO_TLS1_2_METHOD
+IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2,
+                        tlsv1_2_method,
+                        ossl_statem_accept,
+                        ossl_statem_connect, TLSv1_2_enc_data)
+#endif
+#ifndef OPENSSL_NO_TLS1_1_METHOD
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1,
+                        tlsv1_1_method,
+                        ossl_statem_accept,
+                        ossl_statem_connect, TLSv1_1_enc_data)
+#endif
+#ifndef OPENSSL_NO_TLS1_METHOD
+IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1,
+                        tlsv1_method,
+                        ossl_statem_accept, ossl_statem_connect, TLSv1_enc_data)
+#endif
+#ifndef OPENSSL_NO_SSL3_METHOD
+IMPLEMENT_ssl3_meth_func(sslv3_method, ossl_statem_accept, ossl_statem_connect)
+#endif
+/*-
+ * TLS/SSLv3 server methods
+ */
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0,
+                        TLS_server_method,
+                        ossl_statem_accept,
+                        ssl_undefined_function, TLSv1_2_enc_data)
+IMPLEMENT_tls_meth_func(TLS1_3_VERSION, 0, SSL_OP_NO_TLSv1_3,
+                        tlsv1_3_server_method,
+                        ossl_statem_accept,
+                        ssl_undefined_function, TLSv1_3_enc_data)
+#ifndef OPENSSL_NO_TLS1_2_METHOD
+IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2,
+                        tlsv1_2_server_method,
+                        ossl_statem_accept,
+                        ssl_undefined_function, TLSv1_2_enc_data)
+#endif
+#ifndef OPENSSL_NO_TLS1_1_METHOD
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1,
+                        tlsv1_1_server_method,
+                        ossl_statem_accept,
+                        ssl_undefined_function, TLSv1_1_enc_data)
+#endif
+#ifndef OPENSSL_NO_TLS1_METHOD
+IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1,
+                        tlsv1_server_method,
+                        ossl_statem_accept,
+                        ssl_undefined_function, TLSv1_enc_data)
+#endif
+#ifndef OPENSSL_NO_SSL3_METHOD
+IMPLEMENT_ssl3_meth_func(sslv3_server_method,
+                         ossl_statem_accept, ssl_undefined_function)
+#endif
+/*-
+ * TLS/SSLv3 client methods
+ */
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0,
+                        TLS_client_method,
+                        ssl_undefined_function,
+                        ossl_statem_connect, TLSv1_2_enc_data)
+IMPLEMENT_tls_meth_func(TLS1_3_VERSION, 0, SSL_OP_NO_TLSv1_3,
+                        tlsv1_3_client_method,
+                        ssl_undefined_function,
+                        ossl_statem_connect, TLSv1_3_enc_data)
+#ifndef OPENSSL_NO_TLS1_2_METHOD
+IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2,
+                        tlsv1_2_client_method,
+                        ssl_undefined_function,
+                        ossl_statem_connect, TLSv1_2_enc_data)
+#endif
+#ifndef OPENSSL_NO_TLS1_1_METHOD
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1,
+                        tlsv1_1_client_method,
+                        ssl_undefined_function,
+                        ossl_statem_connect, TLSv1_1_enc_data)
+#endif
+#ifndef OPENSSL_NO_TLS1_METHOD
+IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1,
+                        tlsv1_client_method,
+                        ssl_undefined_function,
+                        ossl_statem_connect, TLSv1_enc_data)
+#endif
+#ifndef OPENSSL_NO_SSL3_METHOD
+IMPLEMENT_ssl3_meth_func(sslv3_client_method,
+                         ssl_undefined_function, ossl_statem_connect)
+#endif
+/*-
+ * DTLS methods
+ */
+#ifndef OPENSSL_NO_DTLS1_METHOD
+IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1,
+                          dtlsv1_method,
+                          ossl_statem_accept,
+                          ossl_statem_connect, DTLSv1_enc_data)
+#endif
+#ifndef OPENSSL_NO_DTLS1_2_METHOD
+IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2,
+                          dtlsv1_2_method,
+                          ossl_statem_accept,
+                          ossl_statem_connect, DTLSv1_2_enc_data)
+#endif
+IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0,
+                          DTLS_method,
+                          ossl_statem_accept,
+                          ossl_statem_connect, DTLSv1_2_enc_data)
+
+/*-
+ * DTLS server methods
+ */
+#ifndef OPENSSL_NO_DTLS1_METHOD
+IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1,
+                          dtlsv1_server_method,
+                          ossl_statem_accept,
+                          ssl_undefined_function, DTLSv1_enc_data)
+#endif
+#ifndef OPENSSL_NO_DTLS1_2_METHOD
+IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2,
+                          dtlsv1_2_server_method,
+                          ossl_statem_accept,
+                          ssl_undefined_function, DTLSv1_2_enc_data)
+#endif
+IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0,
+                          DTLS_server_method,
+                          ossl_statem_accept,
+                          ssl_undefined_function, DTLSv1_2_enc_data)
+
+/*-
+ * DTLS client methods
+ */
+#ifndef OPENSSL_NO_DTLS1_METHOD
+IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1,
+                          dtlsv1_client_method,
+                          ssl_undefined_function,
+                          ossl_statem_connect, DTLSv1_enc_data)
+IMPLEMENT_dtls1_meth_func(DTLS1_BAD_VER, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1,
+                          dtls_bad_ver_client_method,
+                          ssl_undefined_function,
+                          ossl_statem_connect, DTLSv1_enc_data)
+#endif
+#ifndef OPENSSL_NO_DTLS1_2_METHOD
+IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2,
+                          dtlsv1_2_client_method,
+                          ssl_undefined_function,
+                          ossl_statem_connect, DTLSv1_2_enc_data)
+#endif
+IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0,
+                          DTLS_client_method,
+                          ssl_undefined_function,
+                          ossl_statem_connect, DTLSv1_2_enc_data)
+#if OPENSSL_API_COMPAT < 0x10100000L
+# ifndef OPENSSL_NO_TLS1_2_METHOD
+const SSL_METHOD *TLSv1_2_method(void)
+{
+    return tlsv1_2_method();
+}
+
+const SSL_METHOD *TLSv1_2_server_method(void)
+{
+    return tlsv1_2_server_method();
+}
+
+const SSL_METHOD *TLSv1_2_client_method(void)
+{
+    return tlsv1_2_client_method();
+}
+# endif
+
+# ifndef OPENSSL_NO_TLS1_1_METHOD
+const SSL_METHOD *TLSv1_1_method(void)
+{
+    return tlsv1_1_method();
+}
+
+const SSL_METHOD *TLSv1_1_server_method(void)
+{
+    return tlsv1_1_server_method();
+}
+
+const SSL_METHOD *TLSv1_1_client_method(void)
+{
+    return tlsv1_1_client_method();
+}
+# endif
+
+# ifndef OPENSSL_NO_TLS1_METHOD
+const SSL_METHOD *TLSv1_method(void)
+{
+    return tlsv1_method();
+}
+
+const SSL_METHOD *TLSv1_server_method(void)
+{
+    return tlsv1_server_method();
+}
+
+const SSL_METHOD *TLSv1_client_method(void)
+{
+    return tlsv1_client_method();
+}
+# endif
+
+# ifndef OPENSSL_NO_SSL3_METHOD
+const SSL_METHOD *SSLv3_method(void)
+{
+    return sslv3_method();
+}
+
+const SSL_METHOD *SSLv3_server_method(void)
+{
+    return sslv3_server_method();
+}
+
+const SSL_METHOD *SSLv3_client_method(void)
+{
+    return sslv3_client_method();
+}
+# endif
+
+# ifndef OPENSSL_NO_DTLS1_2_METHOD
+const SSL_METHOD *DTLSv1_2_method(void)
+{
+    return dtlsv1_2_method();
+}
+
+const SSL_METHOD *DTLSv1_2_server_method(void)
+{
+    return dtlsv1_2_server_method();
+}
+
+const SSL_METHOD *DTLSv1_2_client_method(void)
+{
+    return dtlsv1_2_client_method();
+}
+# endif
+
+# ifndef OPENSSL_NO_DTLS1_METHOD
+const SSL_METHOD *DTLSv1_method(void)
+{
+    return dtlsv1_method();
+}
+
+const SSL_METHOD *DTLSv1_server_method(void)
+{
+    return dtlsv1_server_method();
+}
+
+const SSL_METHOD *DTLSv1_client_method(void)
+{
+    return dtlsv1_client_method();
+}
+# endif
+
+#endif
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/packet.c b/ap/lib/libssl/openssl-1.1.1o/ssl/packet.c
new file mode 100644
index 0000000..d635749
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/packet.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "internal/cryptlib.h"
+#include "packet_local.h"
+#include <openssl/sslerr.h>
+
+#define DEFAULT_BUF_SIZE    256
+
+int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
+{
+    if (!WPACKET_reserve_bytes(pkt, len, allocbytes))
+        return 0;
+
+    pkt->written += len;
+    pkt->curr += len;
+    return 1;
+}
+
+int WPACKET_sub_allocate_bytes__(WPACKET *pkt, size_t len,
+                                 unsigned char **allocbytes, size_t lenbytes)
+{
+    if (!WPACKET_start_sub_packet_len__(pkt, lenbytes)
+            || !WPACKET_allocate_bytes(pkt, len, allocbytes)
+            || !WPACKET_close(pkt))
+        return 0;
+
+    return 1;
+}
+
+#define GETBUF(p)   (((p)->staticbuf != NULL) \
+                     ? (p)->staticbuf : (unsigned char *)(p)->buf->data)
+
+int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
+{
+    /* Internal API, so should not fail */
+    if (!ossl_assert(pkt->subs != NULL && len != 0))
+        return 0;
+
+    if (pkt->maxsize - pkt->written < len)
+        return 0;
+
+    if (pkt->staticbuf == NULL && (pkt->buf->length - pkt->written < len)) {
+        size_t newlen;
+        size_t reflen;
+
+        reflen = (len > pkt->buf->length) ? len : pkt->buf->length;
+
+        if (reflen > SIZE_MAX / 2) {
+            newlen = SIZE_MAX;
+        } else {
+            newlen = reflen * 2;
+            if (newlen < DEFAULT_BUF_SIZE)
+                newlen = DEFAULT_BUF_SIZE;
+        }
+        if (BUF_MEM_grow(pkt->buf, newlen) == 0)
+            return 0;
+    }
+    if (allocbytes != NULL)
+        *allocbytes = WPACKET_get_curr(pkt);
+
+    return 1;
+}
+
+int WPACKET_sub_reserve_bytes__(WPACKET *pkt, size_t len,
+                                unsigned char **allocbytes, size_t lenbytes)
+{
+    if (!WPACKET_reserve_bytes(pkt, lenbytes + len, allocbytes))
+        return 0;
+
+    *allocbytes += lenbytes;
+
+    return 1;
+}
+
+static size_t maxmaxsize(size_t lenbytes)
+{
+    if (lenbytes >= sizeof(size_t) || lenbytes == 0)
+        return SIZE_MAX;
+
+    return ((size_t)1 << (lenbytes * 8)) - 1 + lenbytes;
+}
+
+static int wpacket_intern_init_len(WPACKET *pkt, size_t lenbytes)
+{
+    unsigned char *lenchars;
+
+    pkt->curr = 0;
+    pkt->written = 0;
+
+    if ((pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs))) == NULL) {
+        SSLerr(SSL_F_WPACKET_INTERN_INIT_LEN, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (lenbytes == 0)
+        return 1;
+
+    pkt->subs->pwritten = lenbytes;
+    pkt->subs->lenbytes = lenbytes;
+
+    if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars)) {
+        OPENSSL_free(pkt->subs);
+        pkt->subs = NULL;
+        return 0;
+    }
+    pkt->subs->packet_len = lenchars - GETBUF(pkt);
+
+    return 1;
+}
+
+int WPACKET_init_static_len(WPACKET *pkt, unsigned char *buf, size_t len,
+                            size_t lenbytes)
+{
+    size_t max = maxmaxsize(lenbytes);
+
+    /* Internal API, so should not fail */
+    if (!ossl_assert(buf != NULL && len > 0))
+        return 0;
+
+    pkt->staticbuf = buf;
+    pkt->buf = NULL;
+    pkt->maxsize = (max < len) ? max : len;
+
+    return wpacket_intern_init_len(pkt, lenbytes);
+}
+
+int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
+{
+    /* Internal API, so should not fail */
+    if (!ossl_assert(buf != NULL))
+        return 0;
+
+    pkt->staticbuf = NULL;
+    pkt->buf = buf;
+    pkt->maxsize = maxmaxsize(lenbytes);
+
+    return wpacket_intern_init_len(pkt, lenbytes);
+}
+
+int WPACKET_init(WPACKET *pkt, BUF_MEM *buf)
+{
+    return WPACKET_init_len(pkt, buf, 0);
+}
+
+int WPACKET_set_flags(WPACKET *pkt, unsigned int flags)
+{
+    /* Internal API, so should not fail */
+    if (!ossl_assert(pkt->subs != NULL))
+        return 0;
+
+    pkt->subs->flags = flags;
+
+    return 1;
+}
+
+/* Store the |value| of length |len| at location |data| */
+static int put_value(unsigned char *data, uint64_t value, size_t len)
+{
+    for (data += len - 1; len > 0; len--) {
+        *data = (unsigned char)(value & 0xff);
+        data--;
+        value >>= 8;
+    }
+
+    /* Check whether we could fit the value in the assigned number of bytes */
+    if (value > 0)
+        return 0;
+
+    return 1;
+}
+
+
+/*
+ * Internal helper function used by WPACKET_close(), WPACKET_finish() and
+ * WPACKET_fill_lengths() to close a sub-packet and write out its length if
+ * necessary. If |doclose| is 0 then it goes through the motions of closing
+ * (i.e. it fills in all the lengths), but doesn't actually close anything.
+ */
+static int wpacket_intern_close(WPACKET *pkt, WPACKET_SUB *sub, int doclose)
+{
+    size_t packlen = pkt->written - sub->pwritten;
+
+    if (packlen == 0
+            && (sub->flags & WPACKET_FLAGS_NON_ZERO_LENGTH) != 0)
+        return 0;
+
+    if (packlen == 0
+            && sub->flags & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) {
+        /* We can't handle this case. Return an error */
+        if (!doclose)
+            return 0;
+
+        /* Deallocate any bytes allocated for the length of the WPACKET */
+        if ((pkt->curr - sub->lenbytes) == sub->packet_len) {
+            pkt->written -= sub->lenbytes;
+            pkt->curr -= sub->lenbytes;
+        }
+
+        /* Don't write out the packet length */
+        sub->packet_len = 0;
+        sub->lenbytes = 0;
+    }
+
+    /* Write out the WPACKET length if needed */
+    if (sub->lenbytes > 0
+                && !put_value(&GETBUF(pkt)[sub->packet_len], packlen,
+                              sub->lenbytes))
+            return 0;
+
+    if (doclose) {
+        pkt->subs = sub->parent;
+        OPENSSL_free(sub);
+    }
+
+    return 1;
+}
+
+int WPACKET_fill_lengths(WPACKET *pkt)
+{
+    WPACKET_SUB *sub;
+
+    if (!ossl_assert(pkt->subs != NULL))
+        return 0;
+
+    for (sub = pkt->subs; sub != NULL; sub = sub->parent) {
+        if (!wpacket_intern_close(pkt, sub, 0))
+            return 0;
+    }
+
+    return 1;
+}
+
+int WPACKET_close(WPACKET *pkt)
+{
+    /*
+     * Internal API, so should not fail - but we do negative testing of this
+     * so no assert (otherwise the tests fail)
+     */
+    if (pkt->subs == NULL || pkt->subs->parent == NULL)
+        return 0;
+
+    return wpacket_intern_close(pkt, pkt->subs, 1);
+}
+
+int WPACKET_finish(WPACKET *pkt)
+{
+    int ret;
+
+    /*
+     * Internal API, so should not fail - but we do negative testing of this
+     * so no assert (otherwise the tests fail)
+     */
+    if (pkt->subs == NULL || pkt->subs->parent != NULL)
+        return 0;
+
+    ret = wpacket_intern_close(pkt, pkt->subs, 1);
+    if (ret) {
+        OPENSSL_free(pkt->subs);
+        pkt->subs = NULL;
+    }
+
+    return ret;
+}
+
+int WPACKET_start_sub_packet_len__(WPACKET *pkt, size_t lenbytes)
+{
+    WPACKET_SUB *sub;
+    unsigned char *lenchars;
+
+    /* Internal API, so should not fail */
+    if (!ossl_assert(pkt->subs != NULL))
+        return 0;
+
+    if ((sub = OPENSSL_zalloc(sizeof(*sub))) == NULL) {
+        SSLerr(SSL_F_WPACKET_START_SUB_PACKET_LEN__, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    sub->parent = pkt->subs;
+    pkt->subs = sub;
+    sub->pwritten = pkt->written + lenbytes;
+    sub->lenbytes = lenbytes;
+
+    if (lenbytes == 0) {
+        sub->packet_len = 0;
+        return 1;
+    }
+
+    if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars))
+        return 0;
+    /* Convert to an offset in case the underlying BUF_MEM gets realloc'd */
+    sub->packet_len = lenchars - GETBUF(pkt);
+
+    return 1;
+}
+
+int WPACKET_start_sub_packet(WPACKET *pkt)
+{
+    return WPACKET_start_sub_packet_len__(pkt, 0);
+}
+
+int WPACKET_put_bytes__(WPACKET *pkt, uint64_t val, size_t size)
+{
+    unsigned char *data;
+
+    /* Internal API, so should not fail */
+    if (!ossl_assert(size <= sizeof(uint64_t))
+            || !WPACKET_allocate_bytes(pkt, size, &data)
+            || !put_value(data, val, size))
+        return 0;
+
+    return 1;
+}
+
+int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
+{
+    WPACKET_SUB *sub;
+    size_t lenbytes;
+
+    /* Internal API, so should not fail */
+    if (!ossl_assert(pkt->subs != NULL))
+        return 0;
+
+    /* Find the WPACKET_SUB for the top level */
+    for (sub = pkt->subs; sub->parent != NULL; sub = sub->parent)
+        continue;
+
+    lenbytes = sub->lenbytes;
+    if (lenbytes == 0)
+        lenbytes = sizeof(pkt->maxsize);
+
+    if (maxmaxsize(lenbytes) < maxsize || maxsize < pkt->written)
+        return 0;
+
+    pkt->maxsize = maxsize;
+
+    return 1;
+}
+
+int WPACKET_memset(WPACKET *pkt, int ch, size_t len)
+{
+    unsigned char *dest;
+
+    if (len == 0)
+        return 1;
+
+    if (!WPACKET_allocate_bytes(pkt, len, &dest))
+        return 0;
+
+    memset(dest, ch, len);
+
+    return 1;
+}
+
+int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len)
+{
+    unsigned char *dest;
+
+    if (len == 0)
+        return 1;
+
+    if (!WPACKET_allocate_bytes(pkt, len, &dest))
+        return 0;
+
+    memcpy(dest, src, len);
+
+    return 1;
+}
+
+int WPACKET_sub_memcpy__(WPACKET *pkt, const void *src, size_t len,
+                         size_t lenbytes)
+{
+    if (!WPACKET_start_sub_packet_len__(pkt, lenbytes)
+            || !WPACKET_memcpy(pkt, src, len)
+            || !WPACKET_close(pkt))
+        return 0;
+
+    return 1;
+}
+
+int WPACKET_get_total_written(WPACKET *pkt, size_t *written)
+{
+    /* Internal API, so should not fail */
+    if (!ossl_assert(written != NULL))
+        return 0;
+
+    *written = pkt->written;
+
+    return 1;
+}
+
+int WPACKET_get_length(WPACKET *pkt, size_t *len)
+{
+    /* Internal API, so should not fail */
+    if (!ossl_assert(pkt->subs != NULL && len != NULL))
+        return 0;
+
+    *len = pkt->written - pkt->subs->pwritten;
+
+    return 1;
+}
+
+unsigned char *WPACKET_get_curr(WPACKET *pkt)
+{
+    return GETBUF(pkt) + pkt->curr;
+}
+
+void WPACKET_cleanup(WPACKET *pkt)
+{
+    WPACKET_SUB *sub, *parent;
+
+    for (sub = pkt->subs; sub != NULL; sub = parent) {
+        parent = sub->parent;
+        OPENSSL_free(sub);
+    }
+    pkt->subs = NULL;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/packet_local.h b/ap/lib/libssl/openssl-1.1.1o/ssl/packet_local.h
new file mode 100644
index 0000000..5b1d3fe
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/packet_local.h
@@ -0,0 +1,909 @@
+/*
+ * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OSSL_SSL_PACKET_LOCAL_H
+# define OSSL_SSL_PACKET_LOCAL_H
+
+# include <string.h>
+# include <openssl/bn.h>
+# include <openssl/buffer.h>
+# include <openssl/crypto.h>
+# include <openssl/e_os2.h>
+
+# include "internal/numbers.h"
+
+typedef struct {
+    /* Pointer to where we are currently reading from */
+    const unsigned char *curr;
+    /* Number of bytes remaining */
+    size_t remaining;
+} PACKET;
+
+/* Internal unchecked shorthand; don't use outside this file. */
+static ossl_inline void packet_forward(PACKET *pkt, size_t len)
+{
+    pkt->curr += len;
+    pkt->remaining -= len;
+}
+
+/*
+ * Returns the number of bytes remaining to be read in the PACKET
+ */
+static ossl_inline size_t PACKET_remaining(const PACKET *pkt)
+{
+    return pkt->remaining;
+}
+
+/*
+ * Returns a pointer to the first byte after the packet data.
+ * Useful for integrating with non-PACKET parsing code.
+ * Specifically, we use PACKET_end() to verify that a d2i_... call
+ * has consumed the entire packet contents.
+ */
+static ossl_inline const unsigned char *PACKET_end(const PACKET *pkt)
+{
+    return pkt->curr + pkt->remaining;
+}
+
+/*
+ * Returns a pointer to the PACKET's current position.
+ * For use in non-PACKETized APIs.
+ */
+static ossl_inline const unsigned char *PACKET_data(const PACKET *pkt)
+{
+    return pkt->curr;
+}
+
+/*
+ * Initialise a PACKET with |len| bytes held in |buf|. This does not make a
+ * copy of the data so |buf| must be present for the whole time that the PACKET
+ * is being used.
+ */
+__owur static ossl_inline int PACKET_buf_init(PACKET *pkt,
+                                              const unsigned char *buf,
+                                              size_t len)
+{
+    /* Sanity check for negative values. */
+    if (len > (size_t)(SIZE_MAX / 2))
+        return 0;
+
+    pkt->curr = buf;
+    pkt->remaining = len;
+    return 1;
+}
+
+/* Initialize a PACKET to hold zero bytes. */
+static ossl_inline void PACKET_null_init(PACKET *pkt)
+{
+    pkt->curr = NULL;
+    pkt->remaining = 0;
+}
+
+/*
+ * Returns 1 if the packet has length |num| and its contents equal the |num|
+ * bytes read from |ptr|. Returns 0 otherwise (lengths or contents not equal).
+ * If lengths are equal, performs the comparison in constant time.
+ */
+__owur static ossl_inline int PACKET_equal(const PACKET *pkt, const void *ptr,
+                                           size_t num)
+{
+    if (PACKET_remaining(pkt) != num)
+        return 0;
+    return CRYPTO_memcmp(pkt->curr, ptr, num) == 0;
+}
+
+/*
+ * Peek ahead and initialize |subpkt| with the next |len| bytes read from |pkt|.
+ * Data is not copied: the |subpkt| packet will share its underlying buffer with
+ * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|.
+ */
+__owur static ossl_inline int PACKET_peek_sub_packet(const PACKET *pkt,
+                                                     PACKET *subpkt, size_t len)
+{
+    if (PACKET_remaining(pkt) < len)
+        return 0;
+
+    return PACKET_buf_init(subpkt, pkt->curr, len);
+}
+
+/*
+ * Initialize |subpkt| with the next |len| bytes read from |pkt|. Data is not
+ * copied: the |subpkt| packet will share its underlying buffer with the
+ * original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|.
+ */
+__owur static ossl_inline int PACKET_get_sub_packet(PACKET *pkt,
+                                                    PACKET *subpkt, size_t len)
+{
+    if (!PACKET_peek_sub_packet(pkt, subpkt, len))
+        return 0;
+
+    packet_forward(pkt, len);
+
+    return 1;
+}
+
+/*
+ * Peek ahead at 2 bytes in network order from |pkt| and store the value in
+ * |*data|
+ */
+__owur static ossl_inline int PACKET_peek_net_2(const PACKET *pkt,
+                                                unsigned int *data)
+{
+    if (PACKET_remaining(pkt) < 2)
+        return 0;
+
+    *data = ((unsigned int)(*pkt->curr)) << 8;
+    *data |= *(pkt->curr + 1);
+
+    return 1;
+}
+
+/* Equivalent of n2s */
+/* Get 2 bytes in network order from |pkt| and store the value in |*data| */
+__owur static ossl_inline int PACKET_get_net_2(PACKET *pkt, unsigned int *data)
+{
+    if (!PACKET_peek_net_2(pkt, data))
+        return 0;
+
+    packet_forward(pkt, 2);
+
+    return 1;
+}
+
+/* Same as PACKET_get_net_2() but for a size_t */
+__owur static ossl_inline int PACKET_get_net_2_len(PACKET *pkt, size_t *data)
+{
+    unsigned int i;
+    int ret = PACKET_get_net_2(pkt, &i);
+
+    if (ret)
+        *data = (size_t)i;
+
+    return ret;
+}
+
+/*
+ * Peek ahead at 3 bytes in network order from |pkt| and store the value in
+ * |*data|
+ */
+__owur static ossl_inline int PACKET_peek_net_3(const PACKET *pkt,
+                                                unsigned long *data)
+{
+    if (PACKET_remaining(pkt) < 3)
+        return 0;
+
+    *data = ((unsigned long)(*pkt->curr)) << 16;
+    *data |= ((unsigned long)(*(pkt->curr + 1))) << 8;
+    *data |= *(pkt->curr + 2);
+
+    return 1;
+}
+
+/* Equivalent of n2l3 */
+/* Get 3 bytes in network order from |pkt| and store the value in |*data| */
+__owur static ossl_inline int PACKET_get_net_3(PACKET *pkt, unsigned long *data)
+{
+    if (!PACKET_peek_net_3(pkt, data))
+        return 0;
+
+    packet_forward(pkt, 3);
+
+    return 1;
+}
+
+/* Same as PACKET_get_net_3() but for a size_t */
+__owur static ossl_inline int PACKET_get_net_3_len(PACKET *pkt, size_t *data)
+{
+    unsigned long i;
+    int ret = PACKET_get_net_3(pkt, &i);
+
+    if (ret)
+        *data = (size_t)i;
+
+    return ret;
+}
+
+/*
+ * Peek ahead at 4 bytes in network order from |pkt| and store the value in
+ * |*data|
+ */
+__owur static ossl_inline int PACKET_peek_net_4(const PACKET *pkt,
+                                                unsigned long *data)
+{
+    if (PACKET_remaining(pkt) < 4)
+        return 0;
+
+    *data = ((unsigned long)(*pkt->curr)) << 24;
+    *data |= ((unsigned long)(*(pkt->curr + 1))) << 16;
+    *data |= ((unsigned long)(*(pkt->curr + 2))) << 8;
+    *data |= *(pkt->curr + 3);
+
+    return 1;
+}
+
+/*
+ * Peek ahead at 8 bytes in network order from |pkt| and store the value in
+ * |*data|
+ */
+__owur static ossl_inline int PACKET_peek_net_8(const PACKET *pkt,
+                                                uint64_t *data)
+{
+    if (PACKET_remaining(pkt) < 8)
+        return 0;
+
+    *data = ((uint64_t)(*pkt->curr)) << 56;
+    *data |= ((uint64_t)(*(pkt->curr + 1))) << 48;
+    *data |= ((uint64_t)(*(pkt->curr + 2))) << 40;
+    *data |= ((uint64_t)(*(pkt->curr + 3))) << 32;
+    *data |= ((uint64_t)(*(pkt->curr + 4))) << 24;
+    *data |= ((uint64_t)(*(pkt->curr + 5))) << 16;
+    *data |= ((uint64_t)(*(pkt->curr + 6))) << 8;
+    *data |= *(pkt->curr + 7);
+
+    return 1;
+}
+
+/* Equivalent of n2l */
+/* Get 4 bytes in network order from |pkt| and store the value in |*data| */
+__owur static ossl_inline int PACKET_get_net_4(PACKET *pkt, unsigned long *data)
+{
+    if (!PACKET_peek_net_4(pkt, data))
+        return 0;
+
+    packet_forward(pkt, 4);
+
+    return 1;
+}
+
+/* Same as PACKET_get_net_4() but for a size_t */
+__owur static ossl_inline int PACKET_get_net_4_len(PACKET *pkt, size_t *data)
+{
+    unsigned long i;
+    int ret = PACKET_get_net_4(pkt, &i);
+
+    if (ret)
+        *data = (size_t)i;
+
+    return ret;
+}
+ 
+/* Get 8 bytes in network order from |pkt| and store the value in |*data| */
+__owur static ossl_inline int PACKET_get_net_8(PACKET *pkt, uint64_t *data)
+{
+    if (!PACKET_peek_net_8(pkt, data))
+        return 0;
+
+    packet_forward(pkt, 8);
+
+    return 1;
+}
+
+/* Peek ahead at 1 byte from |pkt| and store the value in |*data| */
+__owur static ossl_inline int PACKET_peek_1(const PACKET *pkt,
+                                            unsigned int *data)
+{
+    if (!PACKET_remaining(pkt))
+        return 0;
+
+    *data = *pkt->curr;
+
+    return 1;
+}
+
+/* Get 1 byte from |pkt| and store the value in |*data| */
+__owur static ossl_inline int PACKET_get_1(PACKET *pkt, unsigned int *data)
+{
+    if (!PACKET_peek_1(pkt, data))
+        return 0;
+
+    packet_forward(pkt, 1);
+
+    return 1;
+}
+
+/* Same as PACKET_get_1() but for a size_t */
+__owur static ossl_inline int PACKET_get_1_len(PACKET *pkt, size_t *data)
+{
+    unsigned int i;
+    int ret = PACKET_get_1(pkt, &i);
+
+    if (ret)
+        *data = (size_t)i;
+
+    return ret;
+}
+
+/*
+ * Peek ahead at 4 bytes in reverse network order from |pkt| and store the value
+ * in |*data|
+ */
+__owur static ossl_inline int PACKET_peek_4(const PACKET *pkt,
+                                            unsigned long *data)
+{
+    if (PACKET_remaining(pkt) < 4)
+        return 0;
+
+    *data = *pkt->curr;
+    *data |= ((unsigned long)(*(pkt->curr + 1))) << 8;
+    *data |= ((unsigned long)(*(pkt->curr + 2))) << 16;
+    *data |= ((unsigned long)(*(pkt->curr + 3))) << 24;
+
+    return 1;
+}
+
+/* Equivalent of c2l */
+/*
+ * Get 4 bytes in reverse network order from |pkt| and store the value in
+ * |*data|
+ */
+__owur static ossl_inline int PACKET_get_4(PACKET *pkt, unsigned long *data)
+{
+    if (!PACKET_peek_4(pkt, data))
+        return 0;
+
+    packet_forward(pkt, 4);
+
+    return 1;
+}
+
+/*
+ * Peek ahead at |len| bytes from the |pkt| and store a pointer to them in
+ * |*data|. This just points at the underlying buffer that |pkt| is using. The
+ * caller should not free this data directly (it will be freed when the
+ * underlying buffer gets freed
+ */
+__owur static ossl_inline int PACKET_peek_bytes(const PACKET *pkt,
+                                                const unsigned char **data,
+                                                size_t len)
+{
+    if (PACKET_remaining(pkt) < len)
+        return 0;
+
+    *data = pkt->curr;
+
+    return 1;
+}
+
+/*
+ * Read |len| bytes from the |pkt| and store a pointer to them in |*data|. This
+ * just points at the underlying buffer that |pkt| is using. The caller should
+ * not free this data directly (it will be freed when the underlying buffer gets
+ * freed
+ */
+__owur static ossl_inline int PACKET_get_bytes(PACKET *pkt,
+                                               const unsigned char **data,
+                                               size_t len)
+{
+    if (!PACKET_peek_bytes(pkt, data, len))
+        return 0;
+
+    packet_forward(pkt, len);
+
+    return 1;
+}
+
+/* Peek ahead at |len| bytes from |pkt| and copy them to |data| */
+__owur static ossl_inline int PACKET_peek_copy_bytes(const PACKET *pkt,
+                                                     unsigned char *data,
+                                                     size_t len)
+{
+    if (PACKET_remaining(pkt) < len)
+        return 0;
+
+    memcpy(data, pkt->curr, len);
+
+    return 1;
+}
+
+/*
+ * Read |len| bytes from |pkt| and copy them to |data|.
+ * The caller is responsible for ensuring that |data| can hold |len| bytes.
+ */
+__owur static ossl_inline int PACKET_copy_bytes(PACKET *pkt,
+                                                unsigned char *data, size_t len)
+{
+    if (!PACKET_peek_copy_bytes(pkt, data, len))
+        return 0;
+
+    packet_forward(pkt, len);
+
+    return 1;
+}
+
+/*
+ * Copy packet data to |dest|, and set |len| to the number of copied bytes.
+ * If the packet has more than |dest_len| bytes, nothing is copied.
+ * Returns 1 if the packet data fits in |dest_len| bytes, 0 otherwise.
+ * Does not forward PACKET position (because it is typically the last thing
+ * done with a given PACKET).
+ */
+__owur static ossl_inline int PACKET_copy_all(const PACKET *pkt,
+                                              unsigned char *dest,
+                                              size_t dest_len, size_t *len)
+{
+    if (PACKET_remaining(pkt) > dest_len) {
+        *len = 0;
+        return 0;
+    }
+    *len = pkt->remaining;
+    memcpy(dest, pkt->curr, pkt->remaining);
+    return 1;
+}
+
+/*
+ * Copy |pkt| bytes to a newly allocated buffer and store a pointer to the
+ * result in |*data|, and the length in |len|.
+ * If |*data| is not NULL, the old data is OPENSSL_free'd.
+ * If the packet is empty, or malloc fails, |*data| will be set to NULL.
+ * Returns 1 if the malloc succeeds and 0 otherwise.
+ * Does not forward PACKET position (because it is typically the last thing
+ * done with a given PACKET).
+ */
+__owur static ossl_inline int PACKET_memdup(const PACKET *pkt,
+                                            unsigned char **data, size_t *len)
+{
+    size_t length;
+
+    OPENSSL_free(*data);
+    *data = NULL;
+    *len = 0;
+
+    length = PACKET_remaining(pkt);
+
+    if (length == 0)
+        return 1;
+
+    *data = OPENSSL_memdup(pkt->curr, length);
+    if (*data == NULL)
+        return 0;
+
+    *len = length;
+    return 1;
+}
+
+/*
+ * Read a C string from |pkt| and copy to a newly allocated, NUL-terminated
+ * buffer. Store a pointer to the result in |*data|.
+ * If |*data| is not NULL, the old data is OPENSSL_free'd.
+ * If the data in |pkt| does not contain a NUL-byte, the entire data is
+ * copied and NUL-terminated.
+ * Returns 1 if the malloc succeeds and 0 otherwise.
+ * Does not forward PACKET position (because it is typically the last thing done
+ * with a given PACKET).
+ */
+__owur static ossl_inline int PACKET_strndup(const PACKET *pkt, char **data)
+{
+    OPENSSL_free(*data);
+
+    /* This will succeed on an empty packet, unless pkt->curr == NULL. */
+    *data = OPENSSL_strndup((const char *)pkt->curr, PACKET_remaining(pkt));
+    return (*data != NULL);
+}
+
+/* Returns 1 if |pkt| contains at least one 0-byte, 0 otherwise. */
+static ossl_inline int PACKET_contains_zero_byte(const PACKET *pkt)
+{
+    return memchr(pkt->curr, 0, pkt->remaining) != NULL;
+}
+
+/* Move the current reading position forward |len| bytes */
+__owur static ossl_inline int PACKET_forward(PACKET *pkt, size_t len)
+{
+    if (PACKET_remaining(pkt) < len)
+        return 0;
+
+    packet_forward(pkt, len);
+
+    return 1;
+}
+
+/*
+ * Reads a variable-length vector prefixed with a one-byte length, and stores
+ * the contents in |subpkt|. |pkt| can equal |subpkt|.
+ * Data is not copied: the |subpkt| packet will share its underlying buffer with
+ * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|.
+ * Upon failure, the original |pkt| and |subpkt| are not modified.
+ */
+__owur static ossl_inline int PACKET_get_length_prefixed_1(PACKET *pkt,
+                                                           PACKET *subpkt)
+{
+    unsigned int length;
+    const unsigned char *data;
+    PACKET tmp = *pkt;
+    if (!PACKET_get_1(&tmp, &length) ||
+        !PACKET_get_bytes(&tmp, &data, (size_t)length)) {
+        return 0;
+    }
+
+    *pkt = tmp;
+    subpkt->curr = data;
+    subpkt->remaining = length;
+
+    return 1;
+}
+
+/*
+ * Like PACKET_get_length_prefixed_1, but additionally, fails when there are
+ * leftover bytes in |pkt|.
+ */
+__owur static ossl_inline int PACKET_as_length_prefixed_1(PACKET *pkt,
+                                                          PACKET *subpkt)
+{
+    unsigned int length;
+    const unsigned char *data;
+    PACKET tmp = *pkt;
+    if (!PACKET_get_1(&tmp, &length) ||
+        !PACKET_get_bytes(&tmp, &data, (size_t)length) ||
+        PACKET_remaining(&tmp) != 0) {
+        return 0;
+    }
+
+    *pkt = tmp;
+    subpkt->curr = data;
+    subpkt->remaining = length;
+
+    return 1;
+}
+
+/*
+ * Reads a variable-length vector prefixed with a two-byte length, and stores
+ * the contents in |subpkt|. |pkt| can equal |subpkt|.
+ * Data is not copied: the |subpkt| packet will share its underlying buffer with
+ * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|.
+ * Upon failure, the original |pkt| and |subpkt| are not modified.
+ */
+__owur static ossl_inline int PACKET_get_length_prefixed_2(PACKET *pkt,
+                                                           PACKET *subpkt)
+{
+    unsigned int length;
+    const unsigned char *data;
+    PACKET tmp = *pkt;
+
+    if (!PACKET_get_net_2(&tmp, &length) ||
+        !PACKET_get_bytes(&tmp, &data, (size_t)length)) {
+        return 0;
+    }
+
+    *pkt = tmp;
+    subpkt->curr = data;
+    subpkt->remaining = length;
+
+    return 1;
+}
+
+/*
+ * Like PACKET_get_length_prefixed_2, but additionally, fails when there are
+ * leftover bytes in |pkt|.
+ */
+__owur static ossl_inline int PACKET_as_length_prefixed_2(PACKET *pkt,
+                                                          PACKET *subpkt)
+{
+    unsigned int length;
+    const unsigned char *data;
+    PACKET tmp = *pkt;
+
+    if (!PACKET_get_net_2(&tmp, &length) ||
+        !PACKET_get_bytes(&tmp, &data, (size_t)length) ||
+        PACKET_remaining(&tmp) != 0) {
+        return 0;
+    }
+
+    *pkt = tmp;
+    subpkt->curr = data;
+    subpkt->remaining = length;
+
+    return 1;
+}
+
+/*
+ * Reads a variable-length vector prefixed with a three-byte length, and stores
+ * the contents in |subpkt|. |pkt| can equal |subpkt|.
+ * Data is not copied: the |subpkt| packet will share its underlying buffer with
+ * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|.
+ * Upon failure, the original |pkt| and |subpkt| are not modified.
+ */
+__owur static ossl_inline int PACKET_get_length_prefixed_3(PACKET *pkt,
+                                                           PACKET *subpkt)
+{
+    unsigned long length;
+    const unsigned char *data;
+    PACKET tmp = *pkt;
+    if (!PACKET_get_net_3(&tmp, &length) ||
+        !PACKET_get_bytes(&tmp, &data, (size_t)length)) {
+        return 0;
+    }
+
+    *pkt = tmp;
+    subpkt->curr = data;
+    subpkt->remaining = length;
+
+    return 1;
+}
+
+/* Writeable packets */
+
+typedef struct wpacket_sub WPACKET_SUB;
+struct wpacket_sub {
+    /* The parent WPACKET_SUB if we have one or NULL otherwise */
+    WPACKET_SUB *parent;
+
+    /*
+     * Offset into the buffer where the length of this WPACKET goes. We use an
+     * offset in case the buffer grows and gets reallocated.
+     */
+    size_t packet_len;
+
+    /* Number of bytes in the packet_len or 0 if we don't write the length */
+    size_t lenbytes;
+
+    /* Number of bytes written to the buf prior to this packet starting */
+    size_t pwritten;
+
+    /* Flags for this sub-packet */
+    unsigned int flags;
+};
+
+typedef struct wpacket_st WPACKET;
+struct wpacket_st {
+    /* The buffer where we store the output data */
+    BUF_MEM *buf;
+
+    /* Fixed sized buffer which can be used as an alternative to buf */
+    unsigned char *staticbuf;
+
+    /*
+     * Offset into the buffer where we are currently writing. We use an offset
+     * in case the buffer grows and gets reallocated.
+     */
+    size_t curr;
+
+    /* Number of bytes written so far */
+    size_t written;
+
+    /* Maximum number of bytes we will allow to be written to this WPACKET */
+    size_t maxsize;
+
+    /* Our sub-packets (always at least one if not finished) */
+    WPACKET_SUB *subs;
+};
+
+/* Flags */
+
+/* Default */
+#define WPACKET_FLAGS_NONE                      0
+
+/* Error on WPACKET_close() if no data written to the WPACKET */
+#define WPACKET_FLAGS_NON_ZERO_LENGTH           1
+
+/*
+ * Abandon all changes on WPACKET_close() if no data written to the WPACKET,
+ * i.e. this does not write out a zero packet length
+ */
+#define WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH    2
+
+
+/*
+ * Initialise a WPACKET with the buffer in |buf|. The buffer must exist
+ * for the whole time that the WPACKET is being used. Additionally |lenbytes| of
+ * data is preallocated at the start of the buffer to store the length of the
+ * WPACKET once we know it.
+ */
+int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes);
+
+/*
+ * Same as WPACKET_init_len except there is no preallocation of the WPACKET
+ * length.
+ */
+int WPACKET_init(WPACKET *pkt, BUF_MEM *buf);
+
+/*
+ * Same as WPACKET_init_len except we do not use a growable BUF_MEM structure.
+ * A fixed buffer of memory |buf| of size |len| is used instead. A failure will
+ * occur if you attempt to write beyond the end of the buffer
+ */
+int WPACKET_init_static_len(WPACKET *pkt, unsigned char *buf, size_t len,
+                            size_t lenbytes);
+/*
+ * Set the flags to be applied to the current sub-packet
+ */
+int WPACKET_set_flags(WPACKET *pkt, unsigned int flags);
+
+/*
+ * Closes the most recent sub-packet. It also writes out the length of the
+ * packet to the required location (normally the start of the WPACKET) if
+ * appropriate. The top level WPACKET should be closed using WPACKET_finish()
+ * instead of this function.
+ */
+int WPACKET_close(WPACKET *pkt);
+
+/*
+ * The same as WPACKET_close() but only for the top most WPACKET. Additionally
+ * frees memory resources for this WPACKET.
+ */
+int WPACKET_finish(WPACKET *pkt);
+
+/*
+ * Iterate through all the sub-packets and write out their lengths as if they
+ * were being closed. The lengths will be overwritten with the final lengths
+ * when the sub-packets are eventually closed (which may be different if more
+ * data is added to the WPACKET). This function fails if a sub-packet is of 0
+ * length and WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH is set.
+ */
+int WPACKET_fill_lengths(WPACKET *pkt);
+
+/*
+ * Initialise a new sub-packet. Additionally |lenbytes| of data is preallocated
+ * at the start of the sub-packet to store its length once we know it. Don't
+ * call this directly. Use the convenience macros below instead.
+ */
+int WPACKET_start_sub_packet_len__(WPACKET *pkt, size_t lenbytes);
+
+/*
+ * Convenience macros for calling WPACKET_start_sub_packet_len with different
+ * lengths
+ */
+#define WPACKET_start_sub_packet_u8(pkt) \
+    WPACKET_start_sub_packet_len__((pkt), 1)
+#define WPACKET_start_sub_packet_u16(pkt) \
+    WPACKET_start_sub_packet_len__((pkt), 2)
+#define WPACKET_start_sub_packet_u24(pkt) \
+    WPACKET_start_sub_packet_len__((pkt), 3)
+#define WPACKET_start_sub_packet_u32(pkt) \
+    WPACKET_start_sub_packet_len__((pkt), 4)
+
+/*
+ * Same as WPACKET_start_sub_packet_len__() except no bytes are pre-allocated
+ * for the sub-packet length.
+ */
+int WPACKET_start_sub_packet(WPACKET *pkt);
+
+/*
+ * Allocate bytes in the WPACKET for the output. This reserves the bytes
+ * and counts them as "written", but doesn't actually do the writing. A pointer
+ * to the allocated bytes is stored in |*allocbytes|. |allocbytes| may be NULL.
+ * WARNING: the allocated bytes must be filled in immediately, without further
+ * WPACKET_* calls. If not then the underlying buffer may be realloc'd and
+ * change its location.
+ */
+int WPACKET_allocate_bytes(WPACKET *pkt, size_t len,
+                           unsigned char **allocbytes);
+
+/*
+ * The same as WPACKET_allocate_bytes() except additionally a new sub-packet is
+ * started for the allocated bytes, and then closed immediately afterwards. The
+ * number of length bytes for the sub-packet is in |lenbytes|. Don't call this
+ * directly. Use the convenience macros below instead.
+ */
+int WPACKET_sub_allocate_bytes__(WPACKET *pkt, size_t len,
+                                 unsigned char **allocbytes, size_t lenbytes);
+
+/*
+ * Convenience macros for calling WPACKET_sub_allocate_bytes with different
+ * lengths
+ */
+#define WPACKET_sub_allocate_bytes_u8(pkt, len, bytes) \
+    WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 1)
+#define WPACKET_sub_allocate_bytes_u16(pkt, len, bytes) \
+    WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 2)
+#define WPACKET_sub_allocate_bytes_u24(pkt, len, bytes) \
+    WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 3)
+#define WPACKET_sub_allocate_bytes_u32(pkt, len, bytes) \
+    WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 4)
+
+/*
+ * The same as WPACKET_allocate_bytes() except the reserved bytes are not
+ * actually counted as written. Typically this will be for when we don't know
+ * how big arbitrary data is going to be up front, but we do know what the
+ * maximum size will be. If this function is used, then it should be immediately
+ * followed by a WPACKET_allocate_bytes() call before any other WPACKET
+ * functions are called (unless the write to the allocated bytes is abandoned).
+ *
+ * For example: If we are generating a signature, then the size of that
+ * signature may not be known in advance. We can use WPACKET_reserve_bytes() to
+ * handle this:
+ *
+ *  if (!WPACKET_sub_reserve_bytes_u16(&pkt, EVP_PKEY_size(pkey), &sigbytes1)
+ *          || EVP_SignFinal(md_ctx, sigbytes1, &siglen, pkey) <= 0
+ *          || !WPACKET_sub_allocate_bytes_u16(&pkt, siglen, &sigbytes2)
+ *          || sigbytes1 != sigbytes2)
+ *      goto err;
+ */
+int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes);
+
+/*
+ * The "reserve_bytes" equivalent of WPACKET_sub_allocate_bytes__()
+ */
+int WPACKET_sub_reserve_bytes__(WPACKET *pkt, size_t len,
+                                 unsigned char **allocbytes, size_t lenbytes);
+
+/*
+ * Convenience macros for  WPACKET_sub_reserve_bytes with different lengths
+ */
+#define WPACKET_sub_reserve_bytes_u8(pkt, len, bytes) \
+    WPACKET_reserve_bytes__((pkt), (len), (bytes), 1)
+#define WPACKET_sub_reserve_bytes_u16(pkt, len, bytes) \
+    WPACKET_sub_reserve_bytes__((pkt), (len), (bytes), 2)
+#define WPACKET_sub_reserve_bytes_u24(pkt, len, bytes) \
+    WPACKET_sub_reserve_bytes__((pkt), (len), (bytes), 3)
+#define WPACKET_sub_reserve_bytes_u32(pkt, len, bytes) \
+    WPACKET_sub_reserve_bytes__((pkt), (len), (bytes), 4)
+
+/*
+ * Write the value stored in |val| into the WPACKET. The value will consume
+ * |bytes| amount of storage. An error will occur if |val| cannot be
+ * accommodated in |bytes| storage, e.g. attempting to write the value 256 into
+ * 1 byte will fail. Don't call this directly. Use the convenience macros below
+ * instead.
+ */
+int WPACKET_put_bytes__(WPACKET *pkt, uint64_t val, size_t bytes);
+
+/*
+ * Convenience macros for calling WPACKET_put_bytes with different
+ * lengths
+ */
+#define WPACKET_put_bytes_u8(pkt, val) \
+    WPACKET_put_bytes__((pkt), (val), 1)
+#define WPACKET_put_bytes_u16(pkt, val) \
+    WPACKET_put_bytes__((pkt), (val), 2)
+#define WPACKET_put_bytes_u24(pkt, val) \
+    WPACKET_put_bytes__((pkt), (val), 3)
+#define WPACKET_put_bytes_u32(pkt, val) \
+    WPACKET_put_bytes__((pkt), (val), 4)
+#define WPACKET_put_bytes_u64(pkt, val) \
+    WPACKET_put_bytes__((pkt), (val), 8)
+
+/* Set a maximum size that we will not allow the WPACKET to grow beyond */
+int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize);
+
+/* Copy |len| bytes of data from |*src| into the WPACKET. */
+int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len);
+
+/* Set |len| bytes of data to |ch| into the WPACKET. */
+int WPACKET_memset(WPACKET *pkt, int ch, size_t len);
+
+/*
+ * Copy |len| bytes of data from |*src| into the WPACKET and prefix with its
+ * length (consuming |lenbytes| of data for the length). Don't call this
+ * directly. Use the convenience macros below instead.
+ */
+int WPACKET_sub_memcpy__(WPACKET *pkt, const void *src, size_t len,
+                       size_t lenbytes);
+
+/* Convenience macros for calling WPACKET_sub_memcpy with different lengths */
+#define WPACKET_sub_memcpy_u8(pkt, src, len) \
+    WPACKET_sub_memcpy__((pkt), (src), (len), 1)
+#define WPACKET_sub_memcpy_u16(pkt, src, len) \
+    WPACKET_sub_memcpy__((pkt), (src), (len), 2)
+#define WPACKET_sub_memcpy_u24(pkt, src, len) \
+    WPACKET_sub_memcpy__((pkt), (src), (len), 3)
+#define WPACKET_sub_memcpy_u32(pkt, src, len) \
+    WPACKET_sub_memcpy__((pkt), (src), (len), 4)
+
+/*
+ * Return the total number of bytes written so far to the underlying buffer
+ * including any storage allocated for length bytes
+ */
+int WPACKET_get_total_written(WPACKET *pkt, size_t *written);
+
+/*
+ * Returns the length of the current sub-packet. This excludes any bytes
+ * allocated for the length itself.
+ */
+int WPACKET_get_length(WPACKET *pkt, size_t *len);
+
+/*
+ * Returns a pointer to the current write location, but does not allocate any
+ * bytes.
+ */
+unsigned char *WPACKET_get_curr(WPACKET *pkt);
+
+/* Release resources in a WPACKET if a failure has occurred. */
+void WPACKET_cleanup(WPACKET *pkt);
+
+#endif                          /* OSSL_SSL_PACKET_LOCAL_H */
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/pqueue.c b/ap/lib/libssl/openssl-1.1.1o/ssl/pqueue.c
new file mode 100644
index 0000000..7584402
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/pqueue.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2005-2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "ssl_local.h"
+#include <openssl/bn.h>
+
+struct pqueue_st {
+    pitem *items;
+    int count;
+};
+
+pitem *pitem_new(unsigned char *prio64be, void *data)
+{
+    pitem *item = OPENSSL_malloc(sizeof(*item));
+
+    if (item == NULL) {
+        SSLerr(SSL_F_PITEM_NEW, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    memcpy(item->priority, prio64be, sizeof(item->priority));
+    item->data = data;
+    item->next = NULL;
+    return item;
+}
+
+void pitem_free(pitem *item)
+{
+    OPENSSL_free(item);
+}
+
+pqueue *pqueue_new(void)
+{
+    pqueue *pq = OPENSSL_zalloc(sizeof(*pq));
+
+    if (pq == NULL)
+        SSLerr(SSL_F_PQUEUE_NEW, ERR_R_MALLOC_FAILURE);
+
+    return pq;
+}
+
+void pqueue_free(pqueue *pq)
+{
+    OPENSSL_free(pq);
+}
+
+pitem *pqueue_insert(pqueue *pq, pitem *item)
+{
+    pitem *curr, *next;
+
+    if (pq->items == NULL) {
+        pq->items = item;
+        return item;
+    }
+
+    for (curr = NULL, next = pq->items;
+         next != NULL; curr = next, next = next->next) {
+        /*
+         * we can compare 64-bit value in big-endian encoding with memcmp:-)
+         */
+        int cmp = memcmp(next->priority, item->priority, 8);
+        if (cmp > 0) {          /* next > item */
+            item->next = next;
+
+            if (curr == NULL)
+                pq->items = item;
+            else
+                curr->next = item;
+
+            return item;
+        }
+
+        else if (cmp == 0)      /* duplicates not allowed */
+            return NULL;
+    }
+
+    item->next = NULL;
+    curr->next = item;
+
+    return item;
+}
+
+pitem *pqueue_peek(pqueue *pq)
+{
+    return pq->items;
+}
+
+pitem *pqueue_pop(pqueue *pq)
+{
+    pitem *item = pq->items;
+
+    if (pq->items != NULL)
+        pq->items = pq->items->next;
+
+    return item;
+}
+
+pitem *pqueue_find(pqueue *pq, unsigned char *prio64be)
+{
+    pitem *next;
+    pitem *found = NULL;
+
+    if (pq->items == NULL)
+        return NULL;
+
+    for (next = pq->items; next->next != NULL; next = next->next) {
+        if (memcmp(next->priority, prio64be, 8) == 0) {
+            found = next;
+            break;
+        }
+    }
+
+    /* check the one last node */
+    if (memcmp(next->priority, prio64be, 8) == 0)
+        found = next;
+
+    if (!found)
+        return NULL;
+
+    return found;
+}
+
+pitem *pqueue_iterator(pqueue *pq)
+{
+    return pqueue_peek(pq);
+}
+
+pitem *pqueue_next(piterator *item)
+{
+    pitem *ret;
+
+    if (item == NULL || *item == NULL)
+        return NULL;
+
+    /* *item != NULL */
+    ret = *item;
+    *item = (*item)->next;
+
+    return ret;
+}
+
+size_t pqueue_size(pqueue *pq)
+{
+    pitem *item = pq->items;
+    size_t count = 0;
+
+    while (item != NULL) {
+        count++;
+        item = item->next;
+    }
+    return count;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/record/README b/ap/lib/libssl/openssl-1.1.1o/ssl/record/README
new file mode 100644
index 0000000..630fe80
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/record/README
@@ -0,0 +1,74 @@
+Record Layer Design
+===================
+
+This file provides some guidance on the thinking behind the design of the
+record layer code to aid future maintenance.
+
+The record layer is divided into a number of components. At the time of writing
+there are four: SSL3_RECORD, SSL3_BUFFER, DLTS1_BITMAP and RECORD_LAYER. Each
+of these components is defined by:
+1) A struct definition of the same name as the component
+2) A set of source files that define the functions for that component
+3) A set of accessor macros
+
+All struct definitions are in record.h. The functions and macros are either
+defined in record.h or record_local.h dependent on whether they are intended to
+be private to the record layer, or whether they form part of the API to the rest
+of libssl.
+
+The source files map to components as follows:
+
+dtls1_bitmap.c                                   -> DTLS1_BITMAP component
+ssl3_buffer.c                                    -> SSL3_BUFFER component
+ssl3_record.c                                    -> SSL3_RECORD component
+rec_layer_s3.c, rec_layer_d1.c                   -> RECORD_LAYER component
+
+The RECORD_LAYER component is a facade pattern, i.e. it provides a simplified
+interface to the record layer for the rest of libssl. The other 3 components are
+entirely private to the record layer and therefore should never be accessed
+directly by libssl.
+
+Any component can directly access its own members - they are private to that
+component, e.g. ssl3_buffer.c can access members of the SSL3_BUFFER struct
+without using a macro. No component can directly access the members of another
+component, e.g. ssl3_buffer cannot reach inside the RECORD_LAYER component to
+directly access its members. Instead components use accessor macros, so if code
+in ssl3_buffer.c wants to access the members of the RECORD_LAYER it uses the
+RECORD_LAYER_* macros.
+
+Conceptually it looks like this:
+
+                        libssl
+                           |
+---------------------------|-----record.h--------------------------------------
+                           |
+                    _______V______________
+                   |                      |
+                   |    RECORD_LAYER      |
+                   |                      |
+                   |    rec_layer_s3.c    |
+                   |          ^           |
+                   | _________|__________ |
+                   ||                    ||
+                   || DTLS1_RECORD_LAYER ||
+                   ||                    ||
+                   || rec_layer_d1.c     ||
+                   ||____________________||
+                   |______________________|
+        record_local.h     ^   ^   ^
+         _________________|   |   |_________________
+        |                     |                     |
+   _____V_________      ______V________      _______V________
+  |               |    |               |    |                |
+  | SSL3_BUFFER   |    | SSL3_RECORD   |    | DTLS1_BITMAP   |
+  |               |--->|               |    |                |
+  | ssl3_buffer.c |    | ssl3_record.c |    | dtls1_bitmap.c |
+  |_______________|    |_______________|    |________________|
+
+
+The two RECORD_LAYER source files build on each other, i.e.
+the main one is rec_layer_s3.c which provides the core SSL/TLS layer. The second
+one is rec_layer_d1.c which builds off of the SSL/TLS code to provide DTLS
+specific capabilities. It uses some DTLS specific RECORD_LAYER component members
+which should only be accessed from rec_layer_d1.c. These are held in the
+DTLS1_RECORD_LAYER struct.
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/record/dtls1_bitmap.c b/ap/lib/libssl/openssl-1.1.1o/ssl/record/dtls1_bitmap.c
new file mode 100644
index 0000000..8167b41
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/record/dtls1_bitmap.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../ssl_local.h"
+#include "record_local.h"
+
+/* mod 128 saturating subtract of two 64-bit values in big-endian order */
+static int satsub64be(const unsigned char *v1, const unsigned char *v2)
+{
+    int64_t ret;
+    uint64_t l1, l2;
+
+    n2l8(v1, l1);
+    n2l8(v2, l2);
+
+    ret = l1 - l2;
+
+    /* We do not permit wrap-around */
+    if (l1 > l2 && ret < 0)
+        return 128;
+    else if (l2 > l1 && ret > 0)
+        return -128;
+
+    if (ret > 128)
+        return 128;
+    else if (ret < -128)
+        return -128;
+    else
+        return (int)ret;
+}
+
+int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap)
+{
+    int cmp;
+    unsigned int shift;
+    const unsigned char *seq = s->rlayer.read_sequence;
+
+    cmp = satsub64be(seq, bitmap->max_seq_num);
+    if (cmp > 0) {
+        SSL3_RECORD_set_seq_num(RECORD_LAYER_get_rrec(&s->rlayer), seq);
+        return 1;               /* this record in new */
+    }
+    shift = -cmp;
+    if (shift >= sizeof(bitmap->map) * 8)
+        return 0;               /* stale, outside the window */
+    else if (bitmap->map & (1UL << shift))
+        return 0;               /* record previously received */
+
+    SSL3_RECORD_set_seq_num(RECORD_LAYER_get_rrec(&s->rlayer), seq);
+    return 1;
+}
+
+void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap)
+{
+    int cmp;
+    unsigned int shift;
+    const unsigned char *seq = RECORD_LAYER_get_read_sequence(&s->rlayer);
+
+    cmp = satsub64be(seq, bitmap->max_seq_num);
+    if (cmp > 0) {
+        shift = cmp;
+        if (shift < sizeof(bitmap->map) * 8)
+            bitmap->map <<= shift, bitmap->map |= 1UL;
+        else
+            bitmap->map = 1UL;
+        memcpy(bitmap->max_seq_num, seq, SEQ_NUM_SIZE);
+    } else {
+        shift = -cmp;
+        if (shift < sizeof(bitmap->map) * 8)
+            bitmap->map |= 1UL << shift;
+    }
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/record/rec_layer_d1.c b/ap/lib/libssl/openssl-1.1.1o/ssl/record/rec_layer_d1.c
new file mode 100644
index 0000000..78d2959
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/record/rec_layer_d1.c
@@ -0,0 +1,1062 @@
+/*
+ * Copyright 2005-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include "../ssl_local.h"
+#include <openssl/evp.h>
+#include <openssl/buffer.h>
+#include "record_local.h"
+#include "../packet_local.h"
+#include "internal/cryptlib.h"
+
+int DTLS_RECORD_LAYER_new(RECORD_LAYER *rl)
+{
+    DTLS_RECORD_LAYER *d;
+
+    if ((d = OPENSSL_malloc(sizeof(*d))) == NULL) {
+        SSLerr(SSL_F_DTLS_RECORD_LAYER_NEW, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    rl->d = d;
+
+    d->unprocessed_rcds.q = pqueue_new();
+    d->processed_rcds.q = pqueue_new();
+    d->buffered_app_data.q = pqueue_new();
+
+    if (d->unprocessed_rcds.q == NULL || d->processed_rcds.q == NULL
+        || d->buffered_app_data.q == NULL) {
+        pqueue_free(d->unprocessed_rcds.q);
+        pqueue_free(d->processed_rcds.q);
+        pqueue_free(d->buffered_app_data.q);
+        OPENSSL_free(d);
+        rl->d = NULL;
+        return 0;
+    }
+
+    return 1;
+}
+
+void DTLS_RECORD_LAYER_free(RECORD_LAYER *rl)
+{
+    if (rl->d == NULL)
+        return;
+
+    DTLS_RECORD_LAYER_clear(rl);
+    pqueue_free(rl->d->unprocessed_rcds.q);
+    pqueue_free(rl->d->processed_rcds.q);
+    pqueue_free(rl->d->buffered_app_data.q);
+    OPENSSL_free(rl->d);
+    rl->d = NULL;
+}
+
+void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl)
+{
+    DTLS_RECORD_LAYER *d;
+    pitem *item = NULL;
+    DTLS1_RECORD_DATA *rdata;
+    pqueue *unprocessed_rcds;
+    pqueue *processed_rcds;
+    pqueue *buffered_app_data;
+
+    d = rl->d;
+
+    while ((item = pqueue_pop(d->unprocessed_rcds.q)) != NULL) {
+        rdata = (DTLS1_RECORD_DATA *)item->data;
+        OPENSSL_free(rdata->rbuf.buf);
+        OPENSSL_free(item->data);
+        pitem_free(item);
+    }
+
+    while ((item = pqueue_pop(d->processed_rcds.q)) != NULL) {
+        rdata = (DTLS1_RECORD_DATA *)item->data;
+        OPENSSL_free(rdata->rbuf.buf);
+        OPENSSL_free(item->data);
+        pitem_free(item);
+    }
+
+    while ((item = pqueue_pop(d->buffered_app_data.q)) != NULL) {
+        rdata = (DTLS1_RECORD_DATA *)item->data;
+        OPENSSL_free(rdata->rbuf.buf);
+        OPENSSL_free(item->data);
+        pitem_free(item);
+    }
+
+    unprocessed_rcds = d->unprocessed_rcds.q;
+    processed_rcds = d->processed_rcds.q;
+    buffered_app_data = d->buffered_app_data.q;
+    memset(d, 0, sizeof(*d));
+    d->unprocessed_rcds.q = unprocessed_rcds;
+    d->processed_rcds.q = processed_rcds;
+    d->buffered_app_data.q = buffered_app_data;
+}
+
+void DTLS_RECORD_LAYER_set_saved_w_epoch(RECORD_LAYER *rl, unsigned short e)
+{
+    if (e == rl->d->w_epoch - 1) {
+        memcpy(rl->d->curr_write_sequence,
+               rl->write_sequence, sizeof(rl->write_sequence));
+        memcpy(rl->write_sequence,
+               rl->d->last_write_sequence, sizeof(rl->write_sequence));
+    } else if (e == rl->d->w_epoch + 1) {
+        memcpy(rl->d->last_write_sequence,
+               rl->write_sequence, sizeof(unsigned char[8]));
+        memcpy(rl->write_sequence,
+               rl->d->curr_write_sequence, sizeof(rl->write_sequence));
+    }
+    rl->d->w_epoch = e;
+}
+
+void DTLS_RECORD_LAYER_set_write_sequence(RECORD_LAYER *rl, unsigned char *seq)
+{
+    memcpy(rl->write_sequence, seq, SEQ_NUM_SIZE);
+}
+
+/* copy buffered record into SSL structure */
+static int dtls1_copy_record(SSL *s, pitem *item)
+{
+    DTLS1_RECORD_DATA *rdata;
+
+    rdata = (DTLS1_RECORD_DATA *)item->data;
+
+    SSL3_BUFFER_release(&s->rlayer.rbuf);
+
+    s->rlayer.packet = rdata->packet;
+    s->rlayer.packet_length = rdata->packet_length;
+    memcpy(&s->rlayer.rbuf, &(rdata->rbuf), sizeof(SSL3_BUFFER));
+    memcpy(&s->rlayer.rrec, &(rdata->rrec), sizeof(SSL3_RECORD));
+
+    /* Set proper sequence number for mac calculation */
+    memcpy(&(s->rlayer.read_sequence[2]), &(rdata->packet[5]), 6);
+
+    return 1;
+}
+
+int dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
+{
+    DTLS1_RECORD_DATA *rdata;
+    pitem *item;
+
+    /* Limit the size of the queue to prevent DOS attacks */
+    if (pqueue_size(queue->q) >= 100)
+        return 0;
+
+    rdata = OPENSSL_malloc(sizeof(*rdata));
+    item = pitem_new(priority, rdata);
+    if (rdata == NULL || item == NULL) {
+        OPENSSL_free(rdata);
+        pitem_free(item);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS1_BUFFER_RECORD,
+                 ERR_R_INTERNAL_ERROR);
+        return -1;
+    }
+
+    rdata->packet = s->rlayer.packet;
+    rdata->packet_length = s->rlayer.packet_length;
+    memcpy(&(rdata->rbuf), &s->rlayer.rbuf, sizeof(SSL3_BUFFER));
+    memcpy(&(rdata->rrec), &s->rlayer.rrec, sizeof(SSL3_RECORD));
+
+    item->data = rdata;
+
+#ifndef OPENSSL_NO_SCTP
+    /* Store bio_dgram_sctp_rcvinfo struct */
+    if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+        (SSL_get_state(s) == TLS_ST_SR_FINISHED
+         || SSL_get_state(s) == TLS_ST_CR_FINISHED)) {
+        BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_GET_RCVINFO,
+                 sizeof(rdata->recordinfo), &rdata->recordinfo);
+    }
+#endif
+
+    s->rlayer.packet = NULL;
+    s->rlayer.packet_length = 0;
+    memset(&s->rlayer.rbuf, 0, sizeof(s->rlayer.rbuf));
+    memset(&s->rlayer.rrec, 0, sizeof(s->rlayer.rrec));
+
+    if (!ssl3_setup_buffers(s)) {
+        /* SSLfatal() already called */
+        OPENSSL_free(rdata->rbuf.buf);
+        OPENSSL_free(rdata);
+        pitem_free(item);
+        return -1;
+    }
+
+    if (pqueue_insert(queue->q, item) == NULL) {
+        /* Must be a duplicate so ignore it */
+        OPENSSL_free(rdata->rbuf.buf);
+        OPENSSL_free(rdata);
+        pitem_free(item);
+    }
+
+    return 1;
+}
+
+int dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue)
+{
+    pitem *item;
+
+    item = pqueue_pop(queue->q);
+    if (item) {
+        dtls1_copy_record(s, item);
+
+        OPENSSL_free(item->data);
+        pitem_free(item);
+
+        return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * retrieve a buffered record that belongs to the new epoch, i.e., not
+ * processed yet
+ */
+#define dtls1_get_unprocessed_record(s) \
+                   dtls1_retrieve_buffered_record((s), \
+                   &((s)->rlayer.d->unprocessed_rcds))
+
+int dtls1_process_buffered_records(SSL *s)
+{
+    pitem *item;
+    SSL3_BUFFER *rb;
+    SSL3_RECORD *rr;
+    DTLS1_BITMAP *bitmap;
+    unsigned int is_next_epoch;
+    int replayok = 1;
+
+    item = pqueue_peek(s->rlayer.d->unprocessed_rcds.q);
+    if (item) {
+        /* Check if epoch is current. */
+        if (s->rlayer.d->unprocessed_rcds.epoch != s->rlayer.d->r_epoch)
+            return 1;         /* Nothing to do. */
+
+        rr = RECORD_LAYER_get_rrec(&s->rlayer);
+
+        rb = RECORD_LAYER_get_rbuf(&s->rlayer);
+
+        if (SSL3_BUFFER_get_left(rb) > 0) {
+            /*
+             * We've still got data from the current packet to read. There could
+             * be a record from the new epoch in it - so don't overwrite it
+             * with the unprocessed records yet (we'll do it when we've
+             * finished reading the current packet).
+             */
+            return 1;
+        }
+
+        /* Process all the records. */
+        while (pqueue_peek(s->rlayer.d->unprocessed_rcds.q)) {
+            dtls1_get_unprocessed_record(s);
+            bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
+            if (bitmap == NULL) {
+                /*
+                 * Should not happen. This will only ever be NULL when the
+                 * current record is from a different epoch. But that cannot
+                 * be the case because we already checked the epoch above
+                 */
+                 SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                          SSL_F_DTLS1_PROCESS_BUFFERED_RECORDS,
+                          ERR_R_INTERNAL_ERROR);
+                 return 0;
+            }
+#ifndef OPENSSL_NO_SCTP
+            /* Only do replay check if no SCTP bio */
+            if (!BIO_dgram_is_sctp(SSL_get_rbio(s)))
+#endif
+            {
+                /*
+                 * Check whether this is a repeat, or aged record. We did this
+                 * check once already when we first received the record - but
+                 * we might have updated the window since then due to
+                 * records we subsequently processed.
+                 */
+                replayok = dtls1_record_replay_check(s, bitmap);
+            }
+
+            if (!replayok || !dtls1_process_record(s, bitmap)) {
+                if (ossl_statem_in_error(s)) {
+                    /* dtls1_process_record called SSLfatal() */
+                    return -1;
+                }
+                /* dump this record */
+                rr->length = 0;
+                RECORD_LAYER_reset_packet_length(&s->rlayer);
+                continue;
+            }
+
+            if (dtls1_buffer_record(s, &(s->rlayer.d->processed_rcds),
+                    SSL3_RECORD_get_seq_num(s->rlayer.rrec)) < 0) {
+                /* SSLfatal() already called */
+                return 0;
+            }
+        }
+    }
+
+    /*
+     * sync epoch numbers once all the unprocessed records have been
+     * processed
+     */
+    s->rlayer.d->processed_rcds.epoch = s->rlayer.d->r_epoch;
+    s->rlayer.d->unprocessed_rcds.epoch = s->rlayer.d->r_epoch + 1;
+
+    return 1;
+}
+
+/*-
+ * Return up to 'len' payload bytes received in 'type' records.
+ * 'type' is one of the following:
+ *
+ *   -  SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
+ *   -  SSL3_RT_APPLICATION_DATA (when ssl3_read calls us)
+ *   -  0 (during a shutdown, no data has to be returned)
+ *
+ * If we don't have stored data to work from, read a SSL/TLS record first
+ * (possibly multiple records if we still don't have anything to return).
+ *
+ * This function must handle any surprises the peer may have for us, such as
+ * Alert records (e.g. close_notify) or renegotiation requests. ChangeCipherSpec
+ * messages are treated as if they were handshake messages *if* the |recd_type|
+ * argument is non NULL.
+ * Also if record payloads contain fragments too small to process, we store
+ * them until there is enough for the respective protocol (the record protocol
+ * may use arbitrary fragmentation and even interleaving):
+ *     Change cipher spec protocol
+ *             just 1 byte needed, no need for keeping anything stored
+ *     Alert protocol
+ *             2 bytes needed (AlertLevel, AlertDescription)
+ *     Handshake protocol
+ *             4 bytes needed (HandshakeType, uint24 length) -- we just have
+ *             to detect unexpected Client Hello and Hello Request messages
+ *             here, anything else is handled by higher layers
+ *     Application data protocol
+ *             none of our business
+ */
+int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
+                     size_t len, int peek, size_t *readbytes)
+{
+    int i, j, iret;
+    size_t n;
+    SSL3_RECORD *rr;
+    void (*cb) (const SSL *ssl, int type2, int val) = NULL;
+
+    if (!SSL3_BUFFER_is_initialised(&s->rlayer.rbuf)) {
+        /* Not initialized yet */
+        if (!ssl3_setup_buffers(s)) {
+            /* SSLfatal() already called */
+            return -1;
+        }
+    }
+
+    if ((type && (type != SSL3_RT_APPLICATION_DATA) &&
+         (type != SSL3_RT_HANDSHAKE)) ||
+        (peek && (type != SSL3_RT_APPLICATION_DATA))) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS1_READ_BYTES,
+                 ERR_R_INTERNAL_ERROR);
+        return -1;
+    }
+
+    if (!ossl_statem_get_in_handshake(s) && SSL_in_init(s)) {
+        /* type == SSL3_RT_APPLICATION_DATA */
+        i = s->handshake_func(s);
+        /* SSLfatal() already called if appropriate */
+        if (i < 0)
+            return i;
+        if (i == 0)
+            return -1;
+    }
+
+ start:
+    s->rwstate = SSL_NOTHING;
+
+    /*-
+     * s->s3->rrec.type         - is the type of record
+     * s->s3->rrec.data,    - data
+     * s->s3->rrec.off,     - offset into 'data' for next read
+     * s->s3->rrec.length,  - number of bytes.
+     */
+    rr = s->rlayer.rrec;
+
+    /*
+     * We are not handshaking and have no data yet, so process data buffered
+     * during the last handshake in advance, if any.
+     */
+    if (SSL_is_init_finished(s) && SSL3_RECORD_get_length(rr) == 0) {
+        pitem *item;
+        item = pqueue_pop(s->rlayer.d->buffered_app_data.q);
+        if (item) {
+#ifndef OPENSSL_NO_SCTP
+            /* Restore bio_dgram_sctp_rcvinfo struct */
+            if (BIO_dgram_is_sctp(SSL_get_rbio(s))) {
+                DTLS1_RECORD_DATA *rdata = (DTLS1_RECORD_DATA *)item->data;
+                BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_SET_RCVINFO,
+                         sizeof(rdata->recordinfo), &rdata->recordinfo);
+            }
+#endif
+
+            dtls1_copy_record(s, item);
+
+            OPENSSL_free(item->data);
+            pitem_free(item);
+        }
+    }
+
+    /* Check for timeout */
+    if (dtls1_handle_timeout(s) > 0) {
+        goto start;
+    } else if (ossl_statem_in_error(s)) {
+        /* dtls1_handle_timeout() has failed with a fatal error */
+        return -1;
+    }
+
+    /* get new packet if necessary */
+    if ((SSL3_RECORD_get_length(rr) == 0)
+        || (s->rlayer.rstate == SSL_ST_READ_BODY)) {
+        RECORD_LAYER_set_numrpipes(&s->rlayer, 0);
+        iret = dtls1_get_record(s);
+        if (iret <= 0) {
+            iret = dtls1_read_failed(s, iret);
+            /*
+             * Anything other than a timeout is an error. SSLfatal() already
+             * called if appropriate.
+             */
+            if (iret <= 0)
+                return iret;
+            else
+                goto start;
+        }
+        RECORD_LAYER_set_numrpipes(&s->rlayer, 1);
+    }
+
+    /*
+     * Reset the count of consecutive warning alerts if we've got a non-empty
+     * record that isn't an alert.
+     */
+    if (SSL3_RECORD_get_type(rr) != SSL3_RT_ALERT
+            && SSL3_RECORD_get_length(rr) != 0)
+        s->rlayer.alert_count = 0;
+
+    /* we now have a packet which can be read and processed */
+
+    if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
+                                   * reset by ssl3_get_finished */
+        && (SSL3_RECORD_get_type(rr) != SSL3_RT_HANDSHAKE)) {
+        /*
+         * We now have application data between CCS and Finished. Most likely
+         * the packets were reordered on their way, so buffer the application
+         * data for later processing rather than dropping the connection.
+         */
+        if (dtls1_buffer_record(s, &(s->rlayer.d->buffered_app_data),
+                                SSL3_RECORD_get_seq_num(rr)) < 0) {
+            /* SSLfatal() already called */
+            return -1;
+        }
+        SSL3_RECORD_set_length(rr, 0);
+        SSL3_RECORD_set_read(rr);
+        goto start;
+    }
+
+    /*
+     * If the other end has shut down, throw anything we read away (even in
+     * 'peek' mode)
+     */
+    if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
+        SSL3_RECORD_set_length(rr, 0);
+        SSL3_RECORD_set_read(rr);
+        s->rwstate = SSL_NOTHING;
+        return 0;
+    }
+
+    if (type == SSL3_RECORD_get_type(rr)
+        || (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC
+            && type == SSL3_RT_HANDSHAKE && recvd_type != NULL)) {
+        /*
+         * SSL3_RT_APPLICATION_DATA or
+         * SSL3_RT_HANDSHAKE or
+         * SSL3_RT_CHANGE_CIPHER_SPEC
+         */
+        /*
+         * make sure that we are not getting application data when we are
+         * doing a handshake for the first time
+         */
+        if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&
+            (s->enc_read_ctx == NULL)) {
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS1_READ_BYTES,
+                     SSL_R_APP_DATA_IN_HANDSHAKE);
+            return -1;
+        }
+
+        if (recvd_type != NULL)
+            *recvd_type = SSL3_RECORD_get_type(rr);
+
+        if (len == 0) {
+            /*
+             * Mark a zero length record as read. This ensures multiple calls to
+             * SSL_read() with a zero length buffer will eventually cause
+             * SSL_pending() to report data as being available.
+             */
+            if (SSL3_RECORD_get_length(rr) == 0)
+                SSL3_RECORD_set_read(rr);
+            return 0;
+        }
+
+        if (len > SSL3_RECORD_get_length(rr))
+            n = SSL3_RECORD_get_length(rr);
+        else
+            n = len;
+
+        memcpy(buf, &(SSL3_RECORD_get_data(rr)[SSL3_RECORD_get_off(rr)]), n);
+        if (peek) {
+            if (SSL3_RECORD_get_length(rr) == 0)
+                SSL3_RECORD_set_read(rr);
+        } else {
+            SSL3_RECORD_sub_length(rr, n);
+            SSL3_RECORD_add_off(rr, n);
+            if (SSL3_RECORD_get_length(rr) == 0) {
+                s->rlayer.rstate = SSL_ST_READ_HEADER;
+                SSL3_RECORD_set_off(rr, 0);
+                SSL3_RECORD_set_read(rr);
+            }
+        }
+#ifndef OPENSSL_NO_SCTP
+        /*
+         * We might had to delay a close_notify alert because of reordered
+         * app data. If there was an alert and there is no message to read
+         * anymore, finally set shutdown.
+         */
+        if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+            s->d1->shutdown_received
+            && !BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
+            s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+            return 0;
+        }
+#endif
+        *readbytes = n;
+        return 1;
+    }
+
+    /*
+     * If we get here, then type != rr->type; if we have a handshake message,
+     * then it was unexpected (Hello Request or Client Hello).
+     */
+
+    if (SSL3_RECORD_get_type(rr) == SSL3_RT_ALERT) {
+        unsigned int alert_level, alert_descr;
+        unsigned char *alert_bytes = SSL3_RECORD_get_data(rr)
+                                     + SSL3_RECORD_get_off(rr);
+        PACKET alert;
+
+        if (!PACKET_buf_init(&alert, alert_bytes, SSL3_RECORD_get_length(rr))
+                || !PACKET_get_1(&alert, &alert_level)
+                || !PACKET_get_1(&alert, &alert_descr)
+                || PACKET_remaining(&alert) != 0) {
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS1_READ_BYTES,
+                     SSL_R_INVALID_ALERT);
+            return -1;
+        }
+
+        if (s->msg_callback)
+            s->msg_callback(0, s->version, SSL3_RT_ALERT, alert_bytes, 2, s,
+                            s->msg_callback_arg);
+
+        if (s->info_callback != NULL)
+            cb = s->info_callback;
+        else if (s->ctx->info_callback != NULL)
+            cb = s->ctx->info_callback;
+
+        if (cb != NULL) {
+            j = (alert_level << 8) | alert_descr;
+            cb(s, SSL_CB_READ_ALERT, j);
+        }
+
+        if (alert_level == SSL3_AL_WARNING) {
+            s->s3->warn_alert = alert_descr;
+            SSL3_RECORD_set_read(rr);
+
+            s->rlayer.alert_count++;
+            if (s->rlayer.alert_count == MAX_WARN_ALERT_COUNT) {
+                SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS1_READ_BYTES,
+                         SSL_R_TOO_MANY_WARN_ALERTS);
+                return -1;
+            }
+
+            if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
+#ifndef OPENSSL_NO_SCTP
+                /*
+                 * With SCTP and streams the socket may deliver app data
+                 * after a close_notify alert. We have to check this first so
+                 * that nothing gets discarded.
+                 */
+                if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+                    BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
+                    s->d1->shutdown_received = 1;
+                    s->rwstate = SSL_READING;
+                    BIO_clear_retry_flags(SSL_get_rbio(s));
+                    BIO_set_retry_read(SSL_get_rbio(s));
+                    return -1;
+                }
+#endif
+                s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+                return 0;
+            }
+        } else if (alert_level == SSL3_AL_FATAL) {
+            char tmp[16];
+
+            s->rwstate = SSL_NOTHING;
+            s->s3->fatal_alert = alert_descr;
+            SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_DTLS1_READ_BYTES,
+                     SSL_AD_REASON_OFFSET + alert_descr);
+            BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr);
+            ERR_add_error_data(2, "SSL alert number ", tmp);
+            s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+            SSL3_RECORD_set_read(rr);
+            SSL_CTX_remove_session(s->session_ctx, s->session);
+            return 0;
+        } else {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_DTLS1_READ_BYTES,
+                     SSL_R_UNKNOWN_ALERT_TYPE);
+            return -1;
+        }
+
+        goto start;
+    }
+
+    if (s->shutdown & SSL_SENT_SHUTDOWN) { /* but we have not received a
+                                            * shutdown */
+        s->rwstate = SSL_NOTHING;
+        SSL3_RECORD_set_length(rr, 0);
+        SSL3_RECORD_set_read(rr);
+        return 0;
+    }
+
+    if (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC) {
+        /*
+         * We can't process a CCS now, because previous handshake messages
+         * are still missing, so just drop it.
+         */
+        SSL3_RECORD_set_length(rr, 0);
+        SSL3_RECORD_set_read(rr);
+        goto start;
+    }
+
+    /*
+     * Unexpected handshake message (Client Hello, or protocol violation)
+     */
+    if ((SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) &&
+            !ossl_statem_get_in_handshake(s)) {
+        struct hm_header_st msg_hdr;
+
+        /*
+         * This may just be a stale retransmit. Also sanity check that we have
+         * at least enough record bytes for a message header
+         */
+        if (SSL3_RECORD_get_epoch(rr) != s->rlayer.d->r_epoch
+                || SSL3_RECORD_get_length(rr) < DTLS1_HM_HEADER_LENGTH) {
+            SSL3_RECORD_set_length(rr, 0);
+            SSL3_RECORD_set_read(rr);
+            goto start;
+        }
+
+        dtls1_get_message_header(rr->data, &msg_hdr);
+
+        /*
+         * If we are server, we may have a repeated FINISHED of the client
+         * here, then retransmit our CCS and FINISHED.
+         */
+        if (msg_hdr.type == SSL3_MT_FINISHED) {
+            if (dtls1_check_timeout_num(s) < 0) {
+                /* SSLfatal) already called */
+                return -1;
+            }
+
+            if (dtls1_retransmit_buffered_messages(s) <= 0) {
+                /* Fail if we encountered a fatal error */
+                if (ossl_statem_in_error(s))
+                    return -1;
+            }
+            SSL3_RECORD_set_length(rr, 0);
+            SSL3_RECORD_set_read(rr);
+            if (!(s->mode & SSL_MODE_AUTO_RETRY)) {
+                if (SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) {
+                    /* no read-ahead left? */
+                    BIO *bio;
+
+                    s->rwstate = SSL_READING;
+                    bio = SSL_get_rbio(s);
+                    BIO_clear_retry_flags(bio);
+                    BIO_set_retry_read(bio);
+                    return -1;
+                }
+            }
+            goto start;
+        }
+
+        /*
+         * To get here we must be trying to read app data but found handshake
+         * data. But if we're trying to read app data, and we're not in init
+         * (which is tested for at the top of this function) then init must be
+         * finished
+         */
+        if (!ossl_assert(SSL_is_init_finished(s))) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS1_READ_BYTES,
+                     ERR_R_INTERNAL_ERROR);
+            return -1;
+        }
+
+        /* We found handshake data, so we're going back into init */
+        ossl_statem_set_in_init(s, 1);
+
+        i = s->handshake_func(s);
+        /* SSLfatal() called if appropriate */
+        if (i < 0)
+            return i;
+        if (i == 0)
+            return -1;
+
+        if (!(s->mode & SSL_MODE_AUTO_RETRY)) {
+            if (SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) {
+                /* no read-ahead left? */
+                BIO *bio;
+                /*
+                 * In the case where we try to read application data, but we
+                 * trigger an SSL handshake, we return -1 with the retry
+                 * option set.  Otherwise renegotiation may cause nasty
+                 * problems in the blocking world
+                 */
+                s->rwstate = SSL_READING;
+                bio = SSL_get_rbio(s);
+                BIO_clear_retry_flags(bio);
+                BIO_set_retry_read(bio);
+                return -1;
+            }
+        }
+        goto start;
+    }
+
+    switch (SSL3_RECORD_get_type(rr)) {
+    default:
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS1_READ_BYTES,
+                 SSL_R_UNEXPECTED_RECORD);
+        return -1;
+    case SSL3_RT_CHANGE_CIPHER_SPEC:
+    case SSL3_RT_ALERT:
+    case SSL3_RT_HANDSHAKE:
+        /*
+         * we already handled all of these, with the possible exception of
+         * SSL3_RT_HANDSHAKE when ossl_statem_get_in_handshake(s) is true, but
+         * that should not happen when type != rr->type
+         */
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS1_READ_BYTES,
+                 ERR_R_INTERNAL_ERROR);
+        return -1;
+    case SSL3_RT_APPLICATION_DATA:
+        /*
+         * At this point, we were expecting handshake data, but have
+         * application data.  If the library was running inside ssl3_read()
+         * (i.e. in_read_app_data is set) and it makes sense to read
+         * application data at this point (session renegotiation not yet
+         * started), we will indulge it.
+         */
+        if (s->s3->in_read_app_data &&
+            (s->s3->total_renegotiations != 0) &&
+            ossl_statem_app_data_allowed(s)) {
+            s->s3->in_read_app_data = 2;
+            return -1;
+        } else {
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS1_READ_BYTES,
+                     SSL_R_UNEXPECTED_RECORD);
+            return -1;
+        }
+    }
+    /* not reached */
+}
+
+/*
+ * Call this to write data in records of type 'type' It will return <= 0 if
+ * not all data has been sent or non-blocking IO.
+ */
+int dtls1_write_bytes(SSL *s, int type, const void *buf, size_t len,
+                      size_t *written)
+{
+    int i;
+
+    if (!ossl_assert(len <= SSL3_RT_MAX_PLAIN_LENGTH)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS1_WRITE_BYTES,
+                 ERR_R_INTERNAL_ERROR);
+        return -1;
+    }
+    s->rwstate = SSL_NOTHING;
+    i = do_dtls1_write(s, type, buf, len, 0, written);
+    return i;
+}
+
+int do_dtls1_write(SSL *s, int type, const unsigned char *buf,
+                   size_t len, int create_empty_fragment, size_t *written)
+{
+    unsigned char *p, *pseq;
+    int i, mac_size, clear = 0;
+    size_t prefix_len = 0;
+    int eivlen;
+    SSL3_RECORD wr;
+    SSL3_BUFFER *wb;
+    SSL_SESSION *sess;
+
+    wb = &s->rlayer.wbuf[0];
+
+    /*
+     * DTLS writes whole datagrams, so there can't be anything left in
+     * the buffer.
+     */
+    if (!ossl_assert(SSL3_BUFFER_get_left(wb) == 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_DTLS1_WRITE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /* If we have an alert to send, lets send it */
+    if (s->s3->alert_dispatch) {
+        i = s->method->ssl_dispatch_alert(s);
+        if (i <= 0)
+            return i;
+        /* if it went, fall through and send more stuff */
+    }
+
+    if (len == 0 && !create_empty_fragment)
+        return 0;
+
+    if (len > ssl_get_max_send_fragment(s)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_DTLS1_WRITE,
+                 SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE);
+        return 0;
+    }
+
+    sess = s->session;
+
+    if ((sess == NULL) ||
+        (s->enc_write_ctx == NULL) || (EVP_MD_CTX_md(s->write_hash) == NULL))
+        clear = 1;
+
+    if (clear)
+        mac_size = 0;
+    else {
+        mac_size = EVP_MD_CTX_size(s->write_hash);
+        if (mac_size < 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_DTLS1_WRITE,
+                     SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE);
+            return -1;
+        }
+    }
+
+    p = SSL3_BUFFER_get_buf(wb) + prefix_len;
+
+    /* write the header */
+
+    *(p++) = type & 0xff;
+    SSL3_RECORD_set_type(&wr, type);
+    /*
+     * Special case: for hello verify request, client version 1.0 and we
+     * haven't decided which version to use yet send back using version 1.0
+     * header: otherwise some clients will ignore it.
+     */
+    if (s->method->version == DTLS_ANY_VERSION &&
+        s->max_proto_version != DTLS1_BAD_VER) {
+        *(p++) = DTLS1_VERSION >> 8;
+        *(p++) = DTLS1_VERSION & 0xff;
+    } else {
+        *(p++) = s->version >> 8;
+        *(p++) = s->version & 0xff;
+    }
+
+    /* field where we are to write out packet epoch, seq num and len */
+    pseq = p;
+    p += 10;
+
+    /* Explicit IV length, block ciphers appropriate version flag */
+    if (s->enc_write_ctx) {
+        int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx);
+        if (mode == EVP_CIPH_CBC_MODE) {
+            eivlen = EVP_CIPHER_CTX_iv_length(s->enc_write_ctx);
+            if (eivlen <= 1)
+                eivlen = 0;
+        }
+        /* Need explicit part of IV for GCM mode */
+        else if (mode == EVP_CIPH_GCM_MODE)
+            eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
+        else if (mode == EVP_CIPH_CCM_MODE)
+            eivlen = EVP_CCM_TLS_EXPLICIT_IV_LEN;
+        else
+            eivlen = 0;
+    } else
+        eivlen = 0;
+
+    /* lets setup the record stuff. */
+    SSL3_RECORD_set_data(&wr, p + eivlen); /* make room for IV in case of CBC */
+    SSL3_RECORD_set_length(&wr, len);
+    SSL3_RECORD_set_input(&wr, (unsigned char *)buf);
+
+    /*
+     * we now 'read' from wr.input, wr.length bytes into wr.data
+     */
+
+    /* first we compress */
+    if (s->compress != NULL) {
+        if (!ssl3_do_compress(s, &wr)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_DTLS1_WRITE,
+                     SSL_R_COMPRESSION_FAILURE);
+            return -1;
+        }
+    } else {
+        memcpy(SSL3_RECORD_get_data(&wr), SSL3_RECORD_get_input(&wr),
+               SSL3_RECORD_get_length(&wr));
+        SSL3_RECORD_reset_input(&wr);
+    }
+
+    /*
+     * we should still have the output to wr.data and the input from
+     * wr.input.  Length should be wr.length. wr.data still points in the
+     * wb->buf
+     */
+
+    if (!SSL_WRITE_ETM(s) && mac_size != 0) {
+        if (!s->method->ssl3_enc->mac(s, &wr,
+                                      &(p[SSL3_RECORD_get_length(&wr) + eivlen]),
+                                      1)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_DTLS1_WRITE,
+                     ERR_R_INTERNAL_ERROR);
+            return -1;
+        }
+        SSL3_RECORD_add_length(&wr, mac_size);
+    }
+
+    /* this is true regardless of mac size */
+    SSL3_RECORD_set_data(&wr, p);
+    SSL3_RECORD_reset_input(&wr);
+
+    if (eivlen)
+        SSL3_RECORD_add_length(&wr, eivlen);
+
+    if (s->method->ssl3_enc->enc(s, &wr, 1, 1) < 1) {
+        if (!ossl_statem_in_error(s)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_DTLS1_WRITE,
+                     ERR_R_INTERNAL_ERROR);
+        }
+        return -1;
+    }
+
+    if (SSL_WRITE_ETM(s) && mac_size != 0) {
+        if (!s->method->ssl3_enc->mac(s, &wr,
+                                      &(p[SSL3_RECORD_get_length(&wr)]), 1)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_DTLS1_WRITE,
+                     ERR_R_INTERNAL_ERROR);
+            return -1;
+        }
+        SSL3_RECORD_add_length(&wr, mac_size);
+    }
+
+    /* record length after mac and block padding */
+
+    /* there's only one epoch between handshake and app data */
+
+    s2n(s->rlayer.d->w_epoch, pseq);
+
+    memcpy(pseq, &(s->rlayer.write_sequence[2]), 6);
+    pseq += 6;
+    s2n(SSL3_RECORD_get_length(&wr), pseq);
+
+    if (s->msg_callback)
+        s->msg_callback(1, 0, SSL3_RT_HEADER, pseq - DTLS1_RT_HEADER_LENGTH,
+                        DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
+
+    /*
+     * we should now have wr.data pointing to the encrypted data, which is
+     * wr->length long
+     */
+    SSL3_RECORD_set_type(&wr, type); /* not needed but helps for debugging */
+    SSL3_RECORD_add_length(&wr, DTLS1_RT_HEADER_LENGTH);
+
+    ssl3_record_sequence_update(&(s->rlayer.write_sequence[0]));
+
+    if (create_empty_fragment) {
+        /*
+         * we are in a recursive call; just return the length, don't write
+         * out anything here
+         */
+        *written = wr.length;
+        return 1;
+    }
+
+    /* now let's set up wb */
+    SSL3_BUFFER_set_left(wb, prefix_len + SSL3_RECORD_get_length(&wr));
+    SSL3_BUFFER_set_offset(wb, 0);
+
+    /*
+     * memorize arguments so that ssl3_write_pending can detect bad write
+     * retries later
+     */
+    s->rlayer.wpend_tot = len;
+    s->rlayer.wpend_buf = buf;
+    s->rlayer.wpend_type = type;
+    s->rlayer.wpend_ret = len;
+
+    /* we now just need to write the buffer. Calls SSLfatal() as required. */
+    return ssl3_write_pending(s, type, buf, len, written);
+}
+
+DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr,
+                               unsigned int *is_next_epoch)
+{
+
+    *is_next_epoch = 0;
+
+    /* In current epoch, accept HM, CCS, DATA, & ALERT */
+    if (rr->epoch == s->rlayer.d->r_epoch)
+        return &s->rlayer.d->bitmap;
+
+    /*
+     * Only HM and ALERT messages can be from the next epoch and only if we
+     * have already processed all of the unprocessed records from the last
+     * epoch
+     */
+    else if (rr->epoch == (unsigned long)(s->rlayer.d->r_epoch + 1) &&
+             s->rlayer.d->unprocessed_rcds.epoch != s->rlayer.d->r_epoch &&
+             (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) {
+        *is_next_epoch = 1;
+        return &s->rlayer.d->next_bitmap;
+    }
+
+    return NULL;
+}
+
+void dtls1_reset_seq_numbers(SSL *s, int rw)
+{
+    unsigned char *seq;
+    unsigned int seq_bytes = sizeof(s->rlayer.read_sequence);
+
+    if (rw & SSL3_CC_READ) {
+        seq = s->rlayer.read_sequence;
+        s->rlayer.d->r_epoch++;
+        memcpy(&s->rlayer.d->bitmap, &s->rlayer.d->next_bitmap,
+               sizeof(s->rlayer.d->bitmap));
+        memset(&s->rlayer.d->next_bitmap, 0, sizeof(s->rlayer.d->next_bitmap));
+
+        /*
+         * We must not use any buffered messages received from the previous
+         * epoch
+         */
+        dtls1_clear_received_buffer(s);
+    } else {
+        seq = s->rlayer.write_sequence;
+        memcpy(s->rlayer.d->last_write_sequence, seq,
+               sizeof(s->rlayer.write_sequence));
+        s->rlayer.d->w_epoch++;
+    }
+
+    memset(seq, 0, seq_bytes);
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/record/rec_layer_s3.c b/ap/lib/libssl/openssl-1.1.1o/ssl/record/rec_layer_s3.c
new file mode 100644
index 0000000..1db1712
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/record/rec_layer_s3.c
@@ -0,0 +1,1798 @@
+/*
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <limits.h>
+#include <errno.h>
+#include "../ssl_local.h"
+#include <openssl/evp.h>
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include "record_local.h"
+#include "../packet_local.h"
+#include "internal/cryptlib.h"
+
+#if     defined(OPENSSL_SMALL_FOOTPRINT) || \
+        !(      defined(AESNI_ASM) &&   ( \
+                defined(__x86_64)       || defined(__x86_64__)  || \
+                defined(_M_AMD64)       || defined(_M_X64)      ) \
+        )
+# undef EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
+# define EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0
+#endif
+
+void RECORD_LAYER_init(RECORD_LAYER *rl, SSL *s)
+{
+    rl->s = s;
+    RECORD_LAYER_set_first_record(&s->rlayer);
+    SSL3_RECORD_clear(rl->rrec, SSL_MAX_PIPELINES);
+}
+
+void RECORD_LAYER_clear(RECORD_LAYER *rl)
+{
+    rl->rstate = SSL_ST_READ_HEADER;
+
+    /*
+     * Do I need to clear read_ahead? As far as I can tell read_ahead did not
+     * previously get reset by SSL_clear...so I'll keep it that way..but is
+     * that right?
+     */
+
+    rl->packet = NULL;
+    rl->packet_length = 0;
+    rl->wnum = 0;
+    memset(rl->handshake_fragment, 0, sizeof(rl->handshake_fragment));
+    rl->handshake_fragment_len = 0;
+    rl->wpend_tot = 0;
+    rl->wpend_type = 0;
+    rl->wpend_ret = 0;
+    rl->wpend_buf = NULL;
+
+    SSL3_BUFFER_clear(&rl->rbuf);
+    ssl3_release_write_buffer(rl->s);
+    rl->numrpipes = 0;
+    SSL3_RECORD_clear(rl->rrec, SSL_MAX_PIPELINES);
+
+    RECORD_LAYER_reset_read_sequence(rl);
+    RECORD_LAYER_reset_write_sequence(rl);
+
+    if (rl->d)
+        DTLS_RECORD_LAYER_clear(rl);
+}
+
+void RECORD_LAYER_release(RECORD_LAYER *rl)
+{
+    if (SSL3_BUFFER_is_initialised(&rl->rbuf))
+        ssl3_release_read_buffer(rl->s);
+    if (rl->numwpipes > 0)
+        ssl3_release_write_buffer(rl->s);
+    SSL3_RECORD_release(rl->rrec, SSL_MAX_PIPELINES);
+}
+
+/* Checks if we have unprocessed read ahead data pending */
+int RECORD_LAYER_read_pending(const RECORD_LAYER *rl)
+{
+    return SSL3_BUFFER_get_left(&rl->rbuf) != 0;
+}
+
+/* Checks if we have decrypted unread record data pending */
+int RECORD_LAYER_processed_read_pending(const RECORD_LAYER *rl)
+{
+    size_t curr_rec = 0, num_recs = RECORD_LAYER_get_numrpipes(rl);
+    const SSL3_RECORD *rr = rl->rrec;
+
+    while (curr_rec < num_recs && SSL3_RECORD_is_read(&rr[curr_rec]))
+        curr_rec++;
+
+    return curr_rec < num_recs;
+}
+
+int RECORD_LAYER_write_pending(const RECORD_LAYER *rl)
+{
+    return (rl->numwpipes > 0)
+        && SSL3_BUFFER_get_left(&rl->wbuf[rl->numwpipes - 1]) != 0;
+}
+
+void RECORD_LAYER_reset_read_sequence(RECORD_LAYER *rl)
+{
+    memset(rl->read_sequence, 0, sizeof(rl->read_sequence));
+}
+
+void RECORD_LAYER_reset_write_sequence(RECORD_LAYER *rl)
+{
+    memset(rl->write_sequence, 0, sizeof(rl->write_sequence));
+}
+
+size_t ssl3_pending(const SSL *s)
+{
+    size_t i, num = 0;
+
+    if (s->rlayer.rstate == SSL_ST_READ_BODY)
+        return 0;
+
+    /* Take into account DTLS buffered app data */
+    if (SSL_IS_DTLS(s)) {
+        DTLS1_RECORD_DATA *rdata;
+        pitem *item, *iter;
+
+        iter = pqueue_iterator(s->rlayer.d->buffered_app_data.q);
+        while ((item = pqueue_next(&iter)) != NULL) {
+            rdata = item->data;
+            num += rdata->rrec.length;
+        }
+    }
+
+    for (i = 0; i < RECORD_LAYER_get_numrpipes(&s->rlayer); i++) {
+        if (SSL3_RECORD_get_type(&s->rlayer.rrec[i])
+            != SSL3_RT_APPLICATION_DATA)
+            return num;
+        num += SSL3_RECORD_get_length(&s->rlayer.rrec[i]);
+    }
+
+    return num;
+}
+
+void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len)
+{
+    ctx->default_read_buf_len = len;
+}
+
+void SSL_set_default_read_buffer_len(SSL *s, size_t len)
+{
+    SSL3_BUFFER_set_default_len(RECORD_LAYER_get_rbuf(&s->rlayer), len);
+}
+
+const char *SSL_rstate_string_long(const SSL *s)
+{
+    switch (s->rlayer.rstate) {
+    case SSL_ST_READ_HEADER:
+        return "read header";
+    case SSL_ST_READ_BODY:
+        return "read body";
+    case SSL_ST_READ_DONE:
+        return "read done";
+    default:
+        return "unknown";
+    }
+}
+
+const char *SSL_rstate_string(const SSL *s)
+{
+    switch (s->rlayer.rstate) {
+    case SSL_ST_READ_HEADER:
+        return "RH";
+    case SSL_ST_READ_BODY:
+        return "RB";
+    case SSL_ST_READ_DONE:
+        return "RD";
+    default:
+        return "unknown";
+    }
+}
+
+/*
+ * Return values are as per SSL_read()
+ */
+int ssl3_read_n(SSL *s, size_t n, size_t max, int extend, int clearold,
+                size_t *readbytes)
+{
+    /*
+     * If extend == 0, obtain new n-byte packet; if extend == 1, increase
+     * packet by another n bytes. The packet will be in the sub-array of
+     * s->rlayer.rbuf.buf specified by s->rlayer.packet and
+     * s->rlayer.packet_length. (If s->rlayer.read_ahead is set, 'max' bytes may
+     * be stored in rbuf [plus s->rlayer.packet_length bytes if extend == 1].)
+     * if clearold == 1, move the packet to the start of the buffer; if
+     * clearold == 0 then leave any old packets where they were
+     */
+    size_t len, left, align = 0;
+    unsigned char *pkt;
+    SSL3_BUFFER *rb;
+
+    if (n == 0)
+        return 0;
+
+    rb = &s->rlayer.rbuf;
+    if (rb->buf == NULL)
+        if (!ssl3_setup_read_buffer(s)) {
+            /* SSLfatal() already called */
+            return -1;
+        }
+
+    left = rb->left;
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+    align = (size_t)rb->buf + SSL3_RT_HEADER_LENGTH;
+    align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD);
+#endif
+
+    if (!extend) {
+        /* start with empty packet ... */
+        if (left == 0)
+            rb->offset = align;
+        else if (align != 0 && left >= SSL3_RT_HEADER_LENGTH) {
+            /*
+             * check if next packet length is large enough to justify payload
+             * alignment...
+             */
+            pkt = rb->buf + rb->offset;
+            if (pkt[0] == SSL3_RT_APPLICATION_DATA
+                && (pkt[3] << 8 | pkt[4]) >= 128) {
+                /*
+                 * Note that even if packet is corrupted and its length field
+                 * is insane, we can only be led to wrong decision about
+                 * whether memmove will occur or not. Header values has no
+                 * effect on memmove arguments and therefore no buffer
+                 * overrun can be triggered.
+                 */
+                memmove(rb->buf + align, pkt, left);
+                rb->offset = align;
+            }
+        }
+        s->rlayer.packet = rb->buf + rb->offset;
+        s->rlayer.packet_length = 0;
+        /* ... now we can act as if 'extend' was set */
+    }
+
+    len = s->rlayer.packet_length;
+    pkt = rb->buf + align;
+    /*
+     * Move any available bytes to front of buffer: 'len' bytes already
+     * pointed to by 'packet', 'left' extra ones at the end
+     */
+    if (s->rlayer.packet != pkt && clearold == 1) {
+        memmove(pkt, s->rlayer.packet, len + left);
+        s->rlayer.packet = pkt;
+        rb->offset = len + align;
+    }
+
+    /*
+     * For DTLS/UDP reads should not span multiple packets because the read
+     * operation returns the whole packet at once (as long as it fits into
+     * the buffer).
+     */
+    if (SSL_IS_DTLS(s)) {
+        if (left == 0 && extend)
+            return 0;
+        if (left > 0 && n > left)
+            n = left;
+    }
+
+    /* if there is enough in the buffer from a previous read, take some */
+    if (left >= n) {
+        s->rlayer.packet_length += n;
+        rb->left = left - n;
+        rb->offset += n;
+        *readbytes = n;
+        return 1;
+    }
+
+    /* else we need to read more data */
+
+    if (n > rb->len - rb->offset) {
+        /* does not happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_READ_N,
+                 ERR_R_INTERNAL_ERROR);
+        return -1;
+    }
+
+    /* We always act like read_ahead is set for DTLS */
+    if (!s->rlayer.read_ahead && !SSL_IS_DTLS(s))
+        /* ignore max parameter */
+        max = n;
+    else {
+        if (max < n)
+            max = n;
+        if (max > rb->len - rb->offset)
+            max = rb->len - rb->offset;
+    }
+
+    while (left < n) {
+        size_t bioread = 0;
+        int ret;
+
+        /*
+         * Now we have len+left bytes at the front of s->s3->rbuf.buf and
+         * need to read in more until we have len+n (up to len+max if
+         * possible)
+         */
+
+        clear_sys_error();
+        if (s->rbio != NULL) {
+            s->rwstate = SSL_READING;
+            /* TODO(size_t): Convert this function */
+            ret = BIO_read(s->rbio, pkt + len + left, max - left);
+            if (ret >= 0)
+                bioread = ret;
+        } else {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_READ_N,
+                     SSL_R_READ_BIO_NOT_SET);
+            ret = -1;
+        }
+
+        if (ret <= 0) {
+            rb->left = left;
+            if (s->mode & SSL_MODE_RELEASE_BUFFERS && !SSL_IS_DTLS(s))
+                if (len + left == 0)
+                    ssl3_release_read_buffer(s);
+            return ret;
+        }
+        left += bioread;
+        /*
+         * reads should *never* span multiple packets for DTLS because the
+         * underlying transport protocol is message oriented as opposed to
+         * byte oriented as in the TLS case.
+         */
+        if (SSL_IS_DTLS(s)) {
+            if (n > left)
+                n = left;       /* makes the while condition false */
+        }
+    }
+
+    /* done reading, now the book-keeping */
+    rb->offset += n;
+    rb->left = left - n;
+    s->rlayer.packet_length += n;
+    s->rwstate = SSL_NOTHING;
+    *readbytes = n;
+    return 1;
+}
+
+/*
+ * Call this to write data in records of type 'type' It will return <= 0 if
+ * not all data has been sent or non-blocking IO.
+ */
+int ssl3_write_bytes(SSL *s, int type, const void *buf_, size_t len,
+                     size_t *written)
+{
+    const unsigned char *buf = buf_;
+    size_t tot;
+    size_t n, max_send_fragment, split_send_fragment, maxpipes;
+#if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
+    size_t nw;
+#endif
+    SSL3_BUFFER *wb = &s->rlayer.wbuf[0];
+    int i;
+    size_t tmpwrit;
+
+    s->rwstate = SSL_NOTHING;
+    tot = s->rlayer.wnum;
+    /*
+     * ensure that if we end up with a smaller value of data to write out
+     * than the original len from a write which didn't complete for
+     * non-blocking I/O and also somehow ended up avoiding the check for
+     * this in ssl3_write_pending/SSL_R_BAD_WRITE_RETRY as it must never be
+     * possible to end up with (len-tot) as a large number that will then
+     * promptly send beyond the end of the users buffer ... so we trap and
+     * report the error in a way the user will notice
+     */
+    if ((len < s->rlayer.wnum)
+        || ((wb->left != 0) && (len < (s->rlayer.wnum + s->rlayer.wpend_tot)))) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_WRITE_BYTES,
+                 SSL_R_BAD_LENGTH);
+        return -1;
+    }
+
+    if (s->early_data_state == SSL_EARLY_DATA_WRITING
+            && !early_data_count_ok(s, len, 0, 1)) {
+        /* SSLfatal() already called */
+        return -1;
+    }
+
+    s->rlayer.wnum = 0;
+
+    /*
+     * If we are supposed to be sending a KeyUpdate then go into init unless we
+     * have writes pending - in which case we should finish doing that first.
+     */
+    if (wb->left == 0 && s->key_update != SSL_KEY_UPDATE_NONE)
+        ossl_statem_set_in_init(s, 1);
+
+    /*
+     * When writing early data on the server side we could be "in_init" in
+     * between receiving the EoED and the CF - but we don't want to handle those
+     * messages yet.
+     */
+    if (SSL_in_init(s) && !ossl_statem_get_in_handshake(s)
+            && s->early_data_state != SSL_EARLY_DATA_UNAUTH_WRITING) {
+        i = s->handshake_func(s);
+        /* SSLfatal() already called */
+        if (i < 0)
+            return i;
+        if (i == 0) {
+            return -1;
+        }
+    }
+
+    /*
+     * first check if there is a SSL3_BUFFER still being written out.  This
+     * will happen with non blocking IO
+     */
+    if (wb->left != 0) {
+        /* SSLfatal() already called if appropriate */
+        i = ssl3_write_pending(s, type, &buf[tot], s->rlayer.wpend_tot,
+                               &tmpwrit);
+        if (i <= 0) {
+            /* XXX should we ssl3_release_write_buffer if i<0? */
+            s->rlayer.wnum = tot;
+            return i;
+        }
+        tot += tmpwrit;               /* this might be last fragment */
+    }
+#if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
+    /*
+     * Depending on platform multi-block can deliver several *times*
+     * better performance. Downside is that it has to allocate
+     * jumbo buffer to accommodate up to 8 records, but the
+     * compromise is considered worthy.
+     */
+    if (type == SSL3_RT_APPLICATION_DATA &&
+        len >= 4 * (max_send_fragment = ssl_get_max_send_fragment(s)) &&
+        s->compress == NULL && s->msg_callback == NULL &&
+        !SSL_WRITE_ETM(s) && SSL_USE_EXPLICIT_IV(s) &&
+        EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_write_ctx)) &
+        EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK) {
+        unsigned char aad[13];
+        EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param;
+        size_t packlen;
+        int packleni;
+
+        /* minimize address aliasing conflicts */
+        if ((max_send_fragment & 0xfff) == 0)
+            max_send_fragment -= 512;
+
+        if (tot == 0 || wb->buf == NULL) { /* allocate jumbo buffer */
+            ssl3_release_write_buffer(s);
+
+            packlen = EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,
+                                          EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE,
+                                          (int)max_send_fragment, NULL);
+
+            if (len >= 8 * max_send_fragment)
+                packlen *= 8;
+            else
+                packlen *= 4;
+
+            if (!ssl3_setup_write_buffer(s, 1, packlen)) {
+                /* SSLfatal() already called */
+                return -1;
+            }
+        } else if (tot == len) { /* done? */
+            /* free jumbo buffer */
+            ssl3_release_write_buffer(s);
+            *written = tot;
+            return 1;
+        }
+
+        n = (len - tot);
+        for (;;) {
+            if (n < 4 * max_send_fragment) {
+                /* free jumbo buffer */
+                ssl3_release_write_buffer(s);
+                break;
+            }
+
+            if (s->s3->alert_dispatch) {
+                i = s->method->ssl_dispatch_alert(s);
+                if (i <= 0) {
+                    /* SSLfatal() already called if appropriate */
+                    s->rlayer.wnum = tot;
+                    return i;
+                }
+            }
+
+            if (n >= 8 * max_send_fragment)
+                nw = max_send_fragment * (mb_param.interleave = 8);
+            else
+                nw = max_send_fragment * (mb_param.interleave = 4);
+
+            memcpy(aad, s->rlayer.write_sequence, 8);
+            aad[8] = type;
+            aad[9] = (unsigned char)(s->version >> 8);
+            aad[10] = (unsigned char)(s->version);
+            aad[11] = 0;
+            aad[12] = 0;
+            mb_param.out = NULL;
+            mb_param.inp = aad;
+            mb_param.len = nw;
+
+            packleni = EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,
+                                          EVP_CTRL_TLS1_1_MULTIBLOCK_AAD,
+                                          sizeof(mb_param), &mb_param);
+            packlen = (size_t)packleni;
+            if (packleni <= 0 || packlen > wb->len) { /* never happens */
+                /* free jumbo buffer */
+                ssl3_release_write_buffer(s);
+                break;
+            }
+
+            mb_param.out = wb->buf;
+            mb_param.inp = &buf[tot];
+            mb_param.len = nw;
+
+            if (EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,
+                                    EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT,
+                                    sizeof(mb_param), &mb_param) <= 0)
+                return -1;
+
+            s->rlayer.write_sequence[7] += mb_param.interleave;
+            if (s->rlayer.write_sequence[7] < mb_param.interleave) {
+                int j = 6;
+                while (j >= 0 && (++s->rlayer.write_sequence[j--]) == 0) ;
+            }
+
+            wb->offset = 0;
+            wb->left = packlen;
+
+            s->rlayer.wpend_tot = nw;
+            s->rlayer.wpend_buf = &buf[tot];
+            s->rlayer.wpend_type = type;
+            s->rlayer.wpend_ret = nw;
+
+            i = ssl3_write_pending(s, type, &buf[tot], nw, &tmpwrit);
+            if (i <= 0) {
+                /* SSLfatal() already called if appropriate */
+                if (i < 0 && (!s->wbio || !BIO_should_retry(s->wbio))) {
+                    /* free jumbo buffer */
+                    ssl3_release_write_buffer(s);
+                }
+                s->rlayer.wnum = tot;
+                return i;
+            }
+            if (tmpwrit == n) {
+                /* free jumbo buffer */
+                ssl3_release_write_buffer(s);
+                *written = tot + tmpwrit;
+                return 1;
+            }
+            n -= tmpwrit;
+            tot += tmpwrit;
+        }
+    } else
+#endif  /* !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK */
+    if (tot == len) {           /* done? */
+        if (s->mode & SSL_MODE_RELEASE_BUFFERS && !SSL_IS_DTLS(s))
+            ssl3_release_write_buffer(s);
+
+        *written = tot;
+        return 1;
+    }
+
+    n = (len - tot);
+
+    max_send_fragment = ssl_get_max_send_fragment(s);
+    split_send_fragment = ssl_get_split_send_fragment(s);
+    /*
+     * If max_pipelines is 0 then this means "undefined" and we default to
+     * 1 pipeline. Similarly if the cipher does not support pipelined
+     * processing then we also only use 1 pipeline, or if we're not using
+     * explicit IVs
+     */
+    maxpipes = s->max_pipelines;
+    if (maxpipes > SSL_MAX_PIPELINES) {
+        /*
+         * We should have prevented this when we set max_pipelines so we
+         * shouldn't get here
+         */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_WRITE_BYTES,
+                 ERR_R_INTERNAL_ERROR);
+        return -1;
+    }
+    if (maxpipes == 0
+        || s->enc_write_ctx == NULL
+        || !(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_write_ctx))
+             & EVP_CIPH_FLAG_PIPELINE)
+        || !SSL_USE_EXPLICIT_IV(s))
+        maxpipes = 1;
+    if (max_send_fragment == 0 || split_send_fragment == 0
+        || split_send_fragment > max_send_fragment) {
+        /*
+         * We should have prevented this when we set/get the split and max send
+         * fragments so we shouldn't get here
+         */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_WRITE_BYTES,
+                 ERR_R_INTERNAL_ERROR);
+        return -1;
+    }
+
+    for (;;) {
+        size_t pipelens[SSL_MAX_PIPELINES], tmppipelen, remain;
+        size_t numpipes, j;
+
+        if (n == 0)
+            numpipes = 1;
+        else
+            numpipes = ((n - 1) / split_send_fragment) + 1;
+        if (numpipes > maxpipes)
+            numpipes = maxpipes;
+
+        if (n / numpipes >= max_send_fragment) {
+            /*
+             * We have enough data to completely fill all available
+             * pipelines
+             */
+            for (j = 0; j < numpipes; j++) {
+                pipelens[j] = max_send_fragment;
+            }
+        } else {
+            /* We can partially fill all available pipelines */
+            tmppipelen = n / numpipes;
+            remain = n % numpipes;
+            for (j = 0; j < numpipes; j++) {
+                pipelens[j] = tmppipelen;
+                if (j < remain)
+                    pipelens[j]++;
+            }
+        }
+
+        i = do_ssl3_write(s, type, &(buf[tot]), pipelens, numpipes, 0,
+                          &tmpwrit);
+        if (i <= 0) {
+            /* SSLfatal() already called if appropriate */
+            /* XXX should we ssl3_release_write_buffer if i<0? */
+            s->rlayer.wnum = tot;
+            return i;
+        }
+
+        if (tmpwrit == n ||
+            (type == SSL3_RT_APPLICATION_DATA &&
+             (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE))) {
+            /*
+             * next chunk of data should get another prepended empty fragment
+             * in ciphersuites with known-IV weakness:
+             */
+            s->s3->empty_fragment_done = 0;
+
+            if (tmpwrit == n
+                    && (s->mode & SSL_MODE_RELEASE_BUFFERS) != 0
+                    && !SSL_IS_DTLS(s))
+                ssl3_release_write_buffer(s);
+
+            *written = tot + tmpwrit;
+            return 1;
+        }
+
+        n -= tmpwrit;
+        tot += tmpwrit;
+    }
+}
+
+int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+                  size_t *pipelens, size_t numpipes,
+                  int create_empty_fragment, size_t *written)
+{
+    WPACKET pkt[SSL_MAX_PIPELINES];
+    SSL3_RECORD wr[SSL_MAX_PIPELINES];
+    WPACKET *thispkt;
+    SSL3_RECORD *thiswr;
+    unsigned char *recordstart;
+    int i, mac_size, clear = 0;
+    size_t prefix_len = 0;
+    int eivlen = 0;
+    size_t align = 0;
+    SSL3_BUFFER *wb;
+    SSL_SESSION *sess;
+    size_t totlen = 0, len, wpinited = 0;
+    size_t j;
+
+    for (j = 0; j < numpipes; j++)
+        totlen += pipelens[j];
+    /*
+     * first check if there is a SSL3_BUFFER still being written out.  This
+     * will happen with non blocking IO
+     */
+    if (RECORD_LAYER_write_pending(&s->rlayer)) {
+        /* Calls SSLfatal() as required */
+        return ssl3_write_pending(s, type, buf, totlen, written);
+    }
+
+    /* If we have an alert to send, lets send it */
+    if (s->s3->alert_dispatch) {
+        i = s->method->ssl_dispatch_alert(s);
+        if (i <= 0) {
+            /* SSLfatal() already called if appropriate */
+            return i;
+        }
+        /* if it went, fall through and send more stuff */
+    }
+
+    if (s->rlayer.numwpipes < numpipes) {
+        if (!ssl3_setup_write_buffer(s, numpipes, 0)) {
+            /* SSLfatal() already called */
+            return -1;
+        }
+    }
+
+    if (totlen == 0 && !create_empty_fragment)
+        return 0;
+
+    sess = s->session;
+
+    if ((sess == NULL) ||
+        (s->enc_write_ctx == NULL) || (EVP_MD_CTX_md(s->write_hash) == NULL)) {
+        clear = s->enc_write_ctx ? 0 : 1; /* must be AEAD cipher */
+        mac_size = 0;
+    } else {
+        /* TODO(siz_t): Convert me */
+        mac_size = EVP_MD_CTX_size(s->write_hash);
+        if (mac_size < 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+
+    /*
+     * 'create_empty_fragment' is true only when this function calls itself
+     */
+    if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done) {
+        /*
+         * countermeasure against known-IV weakness in CBC ciphersuites (see
+         * http://www.openssl.org/~bodo/tls-cbc.txt)
+         */
+
+        if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA) {
+            /*
+             * recursive function call with 'create_empty_fragment' set; this
+             * prepares and buffers the data for an empty fragment (these
+             * 'prefix_len' bytes are sent out later together with the actual
+             * payload)
+             */
+            size_t tmppipelen = 0;
+            int ret;
+
+            ret = do_ssl3_write(s, type, buf, &tmppipelen, 1, 1, &prefix_len);
+            if (ret <= 0) {
+                /* SSLfatal() already called if appropriate */
+                goto err;
+            }
+
+            if (prefix_len >
+                (SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD)) {
+                /* insufficient space */
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                         ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+        }
+
+        s->s3->empty_fragment_done = 1;
+    }
+
+    if (create_empty_fragment) {
+        wb = &s->rlayer.wbuf[0];
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+        /*
+         * extra fragment would be couple of cipher blocks, which would be
+         * multiple of SSL3_ALIGN_PAYLOAD, so if we want to align the real
+         * payload, then we can just pretend we simply have two headers.
+         */
+        align = (size_t)SSL3_BUFFER_get_buf(wb) + 2 * SSL3_RT_HEADER_LENGTH;
+        align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD);
+#endif
+        SSL3_BUFFER_set_offset(wb, align);
+        if (!WPACKET_init_static_len(&pkt[0], SSL3_BUFFER_get_buf(wb),
+                                     SSL3_BUFFER_get_len(wb), 0)
+                || !WPACKET_allocate_bytes(&pkt[0], align, NULL)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        wpinited = 1;
+    } else if (prefix_len) {
+        wb = &s->rlayer.wbuf[0];
+        if (!WPACKET_init_static_len(&pkt[0],
+                                     SSL3_BUFFER_get_buf(wb),
+                                     SSL3_BUFFER_get_len(wb), 0)
+                || !WPACKET_allocate_bytes(&pkt[0], SSL3_BUFFER_get_offset(wb)
+                                                    + prefix_len, NULL)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        wpinited = 1;
+    } else {
+        for (j = 0; j < numpipes; j++) {
+            thispkt = &pkt[j];
+
+            wb = &s->rlayer.wbuf[j];
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0
+            align = (size_t)SSL3_BUFFER_get_buf(wb) + SSL3_RT_HEADER_LENGTH;
+            align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD);
+#endif
+            SSL3_BUFFER_set_offset(wb, align);
+            if (!WPACKET_init_static_len(thispkt, SSL3_BUFFER_get_buf(wb),
+                                         SSL3_BUFFER_get_len(wb), 0)
+                    || !WPACKET_allocate_bytes(thispkt, align, NULL)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                         ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            wpinited++;
+        }
+    }
+
+    /* Explicit IV length, block ciphers appropriate version flag */
+    if (s->enc_write_ctx && SSL_USE_EXPLICIT_IV(s) && !SSL_TREAT_AS_TLS13(s)) {
+        int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx);
+        if (mode == EVP_CIPH_CBC_MODE) {
+            /* TODO(size_t): Convert me */
+            eivlen = EVP_CIPHER_CTX_iv_length(s->enc_write_ctx);
+            if (eivlen <= 1)
+                eivlen = 0;
+        } else if (mode == EVP_CIPH_GCM_MODE) {
+            /* Need explicit part of IV for GCM mode */
+            eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
+        } else if (mode == EVP_CIPH_CCM_MODE) {
+            eivlen = EVP_CCM_TLS_EXPLICIT_IV_LEN;
+        }
+    }
+
+    totlen = 0;
+    /* Clear our SSL3_RECORD structures */
+    memset(wr, 0, sizeof(wr));
+    for (j = 0; j < numpipes; j++) {
+        unsigned int version = (s->version == TLS1_3_VERSION) ? TLS1_2_VERSION
+                                                              : s->version;
+        unsigned char *compressdata = NULL;
+        size_t maxcomplen;
+        unsigned int rectype;
+
+        thispkt = &pkt[j];
+        thiswr = &wr[j];
+
+        /*
+         * In TLSv1.3, once encrypting, we always use application data for the
+         * record type
+         */
+        if (SSL_TREAT_AS_TLS13(s)
+                && s->enc_write_ctx != NULL
+                && (s->statem.enc_write_state != ENC_WRITE_STATE_WRITE_PLAIN_ALERTS
+                    || type != SSL3_RT_ALERT))
+            rectype = SSL3_RT_APPLICATION_DATA;
+        else
+            rectype = type;
+        SSL3_RECORD_set_type(thiswr, rectype);
+
+        /*
+         * Some servers hang if initial client hello is larger than 256 bytes
+         * and record version number > TLS 1.0
+         */
+        if (SSL_get_state(s) == TLS_ST_CW_CLNT_HELLO
+                && !s->renegotiate
+                && TLS1_get_version(s) > TLS1_VERSION
+                && s->hello_retry_request == SSL_HRR_NONE)
+            version = TLS1_VERSION;
+        SSL3_RECORD_set_rec_version(thiswr, version);
+
+        maxcomplen = pipelens[j];
+        if (s->compress != NULL)
+            maxcomplen += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
+
+        /* write the header */
+        if (!WPACKET_put_bytes_u8(thispkt, rectype)
+                || !WPACKET_put_bytes_u16(thispkt, version)
+                || !WPACKET_start_sub_packet_u16(thispkt)
+                || (eivlen > 0
+                    && !WPACKET_allocate_bytes(thispkt, eivlen, NULL))
+                || (maxcomplen > 0
+                    && !WPACKET_reserve_bytes(thispkt, maxcomplen,
+                                              &compressdata))) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        /* lets setup the record stuff. */
+        SSL3_RECORD_set_data(thiswr, compressdata);
+        SSL3_RECORD_set_length(thiswr, pipelens[j]);
+        SSL3_RECORD_set_input(thiswr, (unsigned char *)&buf[totlen]);
+        totlen += pipelens[j];
+
+        /*
+         * we now 'read' from thiswr->input, thiswr->length bytes into
+         * thiswr->data
+         */
+
+        /* first we compress */
+        if (s->compress != NULL) {
+            if (!ssl3_do_compress(s, thiswr)
+                    || !WPACKET_allocate_bytes(thispkt, thiswr->length, NULL)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                         SSL_R_COMPRESSION_FAILURE);
+                goto err;
+            }
+        } else {
+            if (!WPACKET_memcpy(thispkt, thiswr->input, thiswr->length)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                         ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            SSL3_RECORD_reset_input(&wr[j]);
+        }
+
+        if (SSL_TREAT_AS_TLS13(s)
+                && s->enc_write_ctx != NULL
+                && (s->statem.enc_write_state != ENC_WRITE_STATE_WRITE_PLAIN_ALERTS
+                    || type != SSL3_RT_ALERT)) {
+            size_t rlen, max_send_fragment;
+
+            if (!WPACKET_put_bytes_u8(thispkt, type)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                         ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            SSL3_RECORD_add_length(thiswr, 1);
+
+            /* Add TLS1.3 padding */
+            max_send_fragment = ssl_get_max_send_fragment(s);
+            rlen = SSL3_RECORD_get_length(thiswr);
+            if (rlen < max_send_fragment) {
+                size_t padding = 0;
+                size_t max_padding = max_send_fragment - rlen;
+                if (s->record_padding_cb != NULL) {
+                    padding = s->record_padding_cb(s, type, rlen, s->record_padding_arg);
+                } else if (s->block_padding > 0) {
+                    size_t mask = s->block_padding - 1;
+                    size_t remainder;
+
+                    /* optimize for power of 2 */
+                    if ((s->block_padding & mask) == 0)
+                        remainder = rlen & mask;
+                    else
+                        remainder = rlen % s->block_padding;
+                    /* don't want to add a block of padding if we don't have to */
+                    if (remainder == 0)
+                        padding = 0;
+                    else
+                        padding = s->block_padding - remainder;
+                }
+                if (padding > 0) {
+                    /* do not allow the record to exceed max plaintext length */
+                    if (padding > max_padding)
+                        padding = max_padding;
+                    if (!WPACKET_memset(thispkt, 0, padding)) {
+                        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                                 ERR_R_INTERNAL_ERROR);
+                        goto err;
+                    }
+                    SSL3_RECORD_add_length(thiswr, padding);
+                }
+            }
+        }
+
+        /*
+         * we should still have the output to thiswr->data and the input from
+         * wr->input. Length should be thiswr->length. thiswr->data still points
+         * in the wb->buf
+         */
+
+        if (!SSL_WRITE_ETM(s) && mac_size != 0) {
+            unsigned char *mac;
+
+            if (!WPACKET_allocate_bytes(thispkt, mac_size, &mac)
+                    || !s->method->ssl3_enc->mac(s, thiswr, mac, 1)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                         ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+        }
+
+        /*
+        * Reserve some bytes for any growth that may occur during encryption. If
+        * we are adding the MAC independently of the cipher algorithm, then the
+        * max encrypted overhead does not need to include an allocation for that
+        * MAC
+        */
+        if (!WPACKET_reserve_bytes(thispkt,
+                                   SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD
+                                   - mac_size,
+                                   NULL)
+                   /*
+                    * We also need next the amount of bytes written to this
+                    * sub-packet
+                    */
+                || !WPACKET_get_length(thispkt, &len)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        /* Get a pointer to the start of this record excluding header */
+        recordstart = WPACKET_get_curr(thispkt) - len;
+
+        SSL3_RECORD_set_data(thiswr, recordstart);
+        SSL3_RECORD_reset_input(thiswr);
+        SSL3_RECORD_set_length(thiswr, len);
+    }
+
+    if (s->statem.enc_write_state == ENC_WRITE_STATE_WRITE_PLAIN_ALERTS) {
+        /*
+         * We haven't actually negotiated the version yet, but we're trying to
+         * send early data - so we need to use the tls13enc function.
+         */
+        if (tls13_enc(s, wr, numpipes, 1) < 1) {
+            if (!ossl_statem_in_error(s)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                         ERR_R_INTERNAL_ERROR);
+            }
+            goto err;
+        }
+    } else {
+        if (s->method->ssl3_enc->enc(s, wr, numpipes, 1) < 1) {
+            if (!ossl_statem_in_error(s)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                         ERR_R_INTERNAL_ERROR);
+            }
+            goto err;
+        }
+    }
+
+    for (j = 0; j < numpipes; j++) {
+        size_t origlen;
+
+        thispkt = &pkt[j];
+        thiswr = &wr[j];
+
+        /* Allocate bytes for the encryption overhead */
+        if (!WPACKET_get_length(thispkt, &origlen)
+                   /* Check we allowed enough room for the encryption growth */
+                || !ossl_assert(origlen + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD
+                                - mac_size >= thiswr->length)
+                   /* Encryption should never shrink the data! */
+                || origlen > thiswr->length
+                || (thiswr->length > origlen
+                    && !WPACKET_allocate_bytes(thispkt,
+                                               thiswr->length - origlen, NULL))) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        if (SSL_WRITE_ETM(s) && mac_size != 0) {
+            unsigned char *mac;
+
+            if (!WPACKET_allocate_bytes(thispkt, mac_size, &mac)
+                    || !s->method->ssl3_enc->mac(s, thiswr, mac, 1)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                         ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            SSL3_RECORD_add_length(thiswr, mac_size);
+        }
+
+        if (!WPACKET_get_length(thispkt, &len)
+                || !WPACKET_close(thispkt)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        if (s->msg_callback) {
+            recordstart = WPACKET_get_curr(thispkt) - len
+                          - SSL3_RT_HEADER_LENGTH;
+            s->msg_callback(1, 0, SSL3_RT_HEADER, recordstart,
+                            SSL3_RT_HEADER_LENGTH, s,
+                            s->msg_callback_arg);
+
+            if (SSL_TREAT_AS_TLS13(s) && s->enc_write_ctx != NULL) {
+                unsigned char ctype = type;
+
+                s->msg_callback(1, s->version, SSL3_RT_INNER_CONTENT_TYPE,
+                                &ctype, 1, s, s->msg_callback_arg);
+            }
+        }
+
+        if (!WPACKET_finish(thispkt)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        /*
+         * we should now have thiswr->data pointing to the encrypted data, which
+         * is thiswr->length long
+         */
+        SSL3_RECORD_set_type(thiswr, type); /* not needed but helps for
+                                             * debugging */
+        SSL3_RECORD_add_length(thiswr, SSL3_RT_HEADER_LENGTH);
+
+        if (create_empty_fragment) {
+            /*
+             * we are in a recursive call; just return the length, don't write
+             * out anything here
+             */
+            if (j > 0) {
+                /* We should never be pipelining an empty fragment!! */
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+                         ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            *written = SSL3_RECORD_get_length(thiswr);
+            return 1;
+        }
+
+        /* now let's set up wb */
+        SSL3_BUFFER_set_left(&s->rlayer.wbuf[j],
+                             prefix_len + SSL3_RECORD_get_length(thiswr));
+    }
+
+    /*
+     * memorize arguments so that ssl3_write_pending can detect bad write
+     * retries later
+     */
+    s->rlayer.wpend_tot = totlen;
+    s->rlayer.wpend_buf = buf;
+    s->rlayer.wpend_type = type;
+    s->rlayer.wpend_ret = totlen;
+
+    /* we now just need to write the buffer */
+    return ssl3_write_pending(s, type, buf, totlen, written);
+ err:
+    for (j = 0; j < wpinited; j++)
+        WPACKET_cleanup(&pkt[j]);
+    return -1;
+}
+
+/* if s->s3->wbuf.left != 0, we need to call this
+ *
+ * Return values are as per SSL_write()
+ */
+int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, size_t len,
+                       size_t *written)
+{
+    int i;
+    SSL3_BUFFER *wb = s->rlayer.wbuf;
+    size_t currbuf = 0;
+    size_t tmpwrit = 0;
+
+    if ((s->rlayer.wpend_tot > len)
+        || (!(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)
+            && (s->rlayer.wpend_buf != buf))
+        || (s->rlayer.wpend_type != type)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_WRITE_PENDING,
+                 SSL_R_BAD_WRITE_RETRY);
+        return -1;
+    }
+
+    for (;;) {
+        /* Loop until we find a buffer we haven't written out yet */
+        if (SSL3_BUFFER_get_left(&wb[currbuf]) == 0
+            && currbuf < s->rlayer.numwpipes - 1) {
+            currbuf++;
+            continue;
+        }
+        clear_sys_error();
+        if (s->wbio != NULL) {
+            s->rwstate = SSL_WRITING;
+            /* TODO(size_t): Convert this call */
+            i = BIO_write(s->wbio, (char *)
+                          &(SSL3_BUFFER_get_buf(&wb[currbuf])
+                            [SSL3_BUFFER_get_offset(&wb[currbuf])]),
+                          (unsigned int)SSL3_BUFFER_get_left(&wb[currbuf]));
+            if (i >= 0)
+                tmpwrit = i;
+        } else {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_WRITE_PENDING,
+                     SSL_R_BIO_NOT_SET);
+            i = -1;
+        }
+        if (i > 0 && tmpwrit == SSL3_BUFFER_get_left(&wb[currbuf])) {
+            SSL3_BUFFER_set_left(&wb[currbuf], 0);
+            SSL3_BUFFER_add_offset(&wb[currbuf], tmpwrit);
+            if (currbuf + 1 < s->rlayer.numwpipes)
+                continue;
+            s->rwstate = SSL_NOTHING;
+            *written = s->rlayer.wpend_ret;
+            return 1;
+        } else if (i <= 0) {
+            if (SSL_IS_DTLS(s)) {
+                /*
+                 * For DTLS, just drop it. That's kind of the whole point in
+                 * using a datagram service
+                 */
+                SSL3_BUFFER_set_left(&wb[currbuf], 0);
+            }
+            return i;
+        }
+        SSL3_BUFFER_add_offset(&wb[currbuf], tmpwrit);
+        SSL3_BUFFER_sub_left(&wb[currbuf], tmpwrit);
+    }
+}
+
+/*-
+ * Return up to 'len' payload bytes received in 'type' records.
+ * 'type' is one of the following:
+ *
+ *   -  SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
+ *   -  SSL3_RT_APPLICATION_DATA (when ssl3_read calls us)
+ *   -  0 (during a shutdown, no data has to be returned)
+ *
+ * If we don't have stored data to work from, read a SSL/TLS record first
+ * (possibly multiple records if we still don't have anything to return).
+ *
+ * This function must handle any surprises the peer may have for us, such as
+ * Alert records (e.g. close_notify) or renegotiation requests. ChangeCipherSpec
+ * messages are treated as if they were handshake messages *if* the |recd_type|
+ * argument is non NULL.
+ * Also if record payloads contain fragments too small to process, we store
+ * them until there is enough for the respective protocol (the record protocol
+ * may use arbitrary fragmentation and even interleaving):
+ *     Change cipher spec protocol
+ *             just 1 byte needed, no need for keeping anything stored
+ *     Alert protocol
+ *             2 bytes needed (AlertLevel, AlertDescription)
+ *     Handshake protocol
+ *             4 bytes needed (HandshakeType, uint24 length) -- we just have
+ *             to detect unexpected Client Hello and Hello Request messages
+ *             here, anything else is handled by higher layers
+ *     Application data protocol
+ *             none of our business
+ */
+int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
+                    size_t len, int peek, size_t *readbytes)
+{
+    int i, j, ret;
+    size_t n, curr_rec, num_recs, totalbytes;
+    SSL3_RECORD *rr;
+    SSL3_BUFFER *rbuf;
+    void (*cb) (const SSL *ssl, int type2, int val) = NULL;
+    int is_tls13 = SSL_IS_TLS13(s);
+
+    rbuf = &s->rlayer.rbuf;
+
+    if (!SSL3_BUFFER_is_initialised(rbuf)) {
+        /* Not initialized yet */
+        if (!ssl3_setup_read_buffer(s)) {
+            /* SSLfatal() already called */
+            return -1;
+        }
+    }
+
+    if ((type && (type != SSL3_RT_APPLICATION_DATA)
+         && (type != SSL3_RT_HANDSHAKE)) || (peek
+                                             && (type !=
+                                                 SSL3_RT_APPLICATION_DATA))) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_READ_BYTES,
+                 ERR_R_INTERNAL_ERROR);
+        return -1;
+    }
+
+    if ((type == SSL3_RT_HANDSHAKE) && (s->rlayer.handshake_fragment_len > 0))
+        /* (partially) satisfy request from storage */
+    {
+        unsigned char *src = s->rlayer.handshake_fragment;
+        unsigned char *dst = buf;
+        unsigned int k;
+
+        /* peek == 0 */
+        n = 0;
+        while ((len > 0) && (s->rlayer.handshake_fragment_len > 0)) {
+            *dst++ = *src++;
+            len--;
+            s->rlayer.handshake_fragment_len--;
+            n++;
+        }
+        /* move any remaining fragment bytes: */
+        for (k = 0; k < s->rlayer.handshake_fragment_len; k++)
+            s->rlayer.handshake_fragment[k] = *src++;
+
+        if (recvd_type != NULL)
+            *recvd_type = SSL3_RT_HANDSHAKE;
+
+        *readbytes = n;
+        return 1;
+    }
+
+    /*
+     * Now s->rlayer.handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE.
+     */
+
+    if (!ossl_statem_get_in_handshake(s) && SSL_in_init(s)) {
+        /* type == SSL3_RT_APPLICATION_DATA */
+        i = s->handshake_func(s);
+        /* SSLfatal() already called */
+        if (i < 0)
+            return i;
+        if (i == 0)
+            return -1;
+    }
+ start:
+    s->rwstate = SSL_NOTHING;
+
+    /*-
+     * For each record 'i' up to |num_recs]
+     * rr[i].type     - is the type of record
+     * rr[i].data,    - data
+     * rr[i].off,     - offset into 'data' for next read
+     * rr[i].length,  - number of bytes.
+     */
+    rr = s->rlayer.rrec;
+    num_recs = RECORD_LAYER_get_numrpipes(&s->rlayer);
+
+    do {
+        /* get new records if necessary */
+        if (num_recs == 0) {
+            ret = ssl3_get_record(s);
+            if (ret <= 0) {
+                /* SSLfatal() already called if appropriate */
+                return ret;
+            }
+            num_recs = RECORD_LAYER_get_numrpipes(&s->rlayer);
+            if (num_recs == 0) {
+                /* Shouldn't happen */
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_READ_BYTES,
+                         ERR_R_INTERNAL_ERROR);
+                return -1;
+            }
+        }
+        /* Skip over any records we have already read */
+        for (curr_rec = 0;
+             curr_rec < num_recs && SSL3_RECORD_is_read(&rr[curr_rec]);
+             curr_rec++) ;
+        if (curr_rec == num_recs) {
+            RECORD_LAYER_set_numrpipes(&s->rlayer, 0);
+            num_recs = 0;
+            curr_rec = 0;
+        }
+    } while (num_recs == 0);
+    rr = &rr[curr_rec];
+
+    if (s->rlayer.handshake_fragment_len > 0
+            && SSL3_RECORD_get_type(rr) != SSL3_RT_HANDSHAKE
+            && SSL_IS_TLS13(s)) {
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
+                 SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA);
+        return -1;
+    }
+
+    /*
+     * Reset the count of consecutive warning alerts if we've got a non-empty
+     * record that isn't an alert.
+     */
+    if (SSL3_RECORD_get_type(rr) != SSL3_RT_ALERT
+            && SSL3_RECORD_get_length(rr) != 0)
+        s->rlayer.alert_count = 0;
+
+    /* we now have a packet which can be read and processed */
+
+    if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
+                                   * reset by ssl3_get_finished */
+        && (SSL3_RECORD_get_type(rr) != SSL3_RT_HANDSHAKE)) {
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
+                 SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
+        return -1;
+    }
+
+    /*
+     * If the other end has shut down, throw anything we read away (even in
+     * 'peek' mode)
+     */
+    if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
+        SSL3_RECORD_set_length(rr, 0);
+        s->rwstate = SSL_NOTHING;
+        return 0;
+    }
+
+    if (type == SSL3_RECORD_get_type(rr)
+        || (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC
+            && type == SSL3_RT_HANDSHAKE && recvd_type != NULL
+            && !is_tls13)) {
+        /*
+         * SSL3_RT_APPLICATION_DATA or
+         * SSL3_RT_HANDSHAKE or
+         * SSL3_RT_CHANGE_CIPHER_SPEC
+         */
+        /*
+         * make sure that we are not getting application data when we are
+         * doing a handshake for the first time
+         */
+        if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&
+            (s->enc_read_ctx == NULL)) {
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
+                     SSL_R_APP_DATA_IN_HANDSHAKE);
+            return -1;
+        }
+
+        if (type == SSL3_RT_HANDSHAKE
+            && SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC
+            && s->rlayer.handshake_fragment_len > 0) {
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
+                     SSL_R_CCS_RECEIVED_EARLY);
+            return -1;
+        }
+
+        if (recvd_type != NULL)
+            *recvd_type = SSL3_RECORD_get_type(rr);
+
+        if (len == 0) {
+            /*
+             * Mark a zero length record as read. This ensures multiple calls to
+             * SSL_read() with a zero length buffer will eventually cause
+             * SSL_pending() to report data as being available.
+             */
+            if (SSL3_RECORD_get_length(rr) == 0)
+                SSL3_RECORD_set_read(rr);
+            return 0;
+        }
+
+        totalbytes = 0;
+        do {
+            if (len - totalbytes > SSL3_RECORD_get_length(rr))
+                n = SSL3_RECORD_get_length(rr);
+            else
+                n = len - totalbytes;
+
+            memcpy(buf, &(rr->data[rr->off]), n);
+            buf += n;
+            if (peek) {
+                /* Mark any zero length record as consumed CVE-2016-6305 */
+                if (SSL3_RECORD_get_length(rr) == 0)
+                    SSL3_RECORD_set_read(rr);
+            } else {
+                SSL3_RECORD_sub_length(rr, n);
+                SSL3_RECORD_add_off(rr, n);
+                if (SSL3_RECORD_get_length(rr) == 0) {
+                    s->rlayer.rstate = SSL_ST_READ_HEADER;
+                    SSL3_RECORD_set_off(rr, 0);
+                    SSL3_RECORD_set_read(rr);
+                }
+            }
+            if (SSL3_RECORD_get_length(rr) == 0
+                || (peek && n == SSL3_RECORD_get_length(rr))) {
+                curr_rec++;
+                rr++;
+            }
+            totalbytes += n;
+        } while (type == SSL3_RT_APPLICATION_DATA && curr_rec < num_recs
+                 && totalbytes < len);
+        if (totalbytes == 0) {
+            /* We must have read empty records. Get more data */
+            goto start;
+        }
+        if (!peek && curr_rec == num_recs
+            && (s->mode & SSL_MODE_RELEASE_BUFFERS)
+            && SSL3_BUFFER_get_left(rbuf) == 0)
+            ssl3_release_read_buffer(s);
+        *readbytes = totalbytes;
+        return 1;
+    }
+
+    /*
+     * If we get here, then type != rr->type; if we have a handshake message,
+     * then it was unexpected (Hello Request or Client Hello) or invalid (we
+     * were actually expecting a CCS).
+     */
+
+    /*
+     * Lets just double check that we've not got an SSLv2 record
+     */
+    if (rr->rec_version == SSL2_VERSION) {
+        /*
+         * Should never happen. ssl3_get_record() should only give us an SSLv2
+         * record back if this is the first packet and we are looking for an
+         * initial ClientHello. Therefore |type| should always be equal to
+         * |rr->type|. If not then something has gone horribly wrong
+         */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_READ_BYTES,
+                 ERR_R_INTERNAL_ERROR);
+        return -1;
+    }
+
+    if (s->method->version == TLS_ANY_VERSION
+        && (s->server || rr->type != SSL3_RT_ALERT)) {
+        /*
+         * If we've got this far and still haven't decided on what version
+         * we're using then this must be a client side alert we're dealing with
+         * (we don't allow heartbeats yet). We shouldn't be receiving anything
+         * other than a ClientHello if we are a server.
+         */
+        s->version = rr->rec_version;
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
+                 SSL_R_UNEXPECTED_MESSAGE);
+        return -1;
+    }
+
+    /*-
+     * s->rlayer.handshake_fragment_len == 4  iff  rr->type == SSL3_RT_HANDSHAKE;
+     * (Possibly rr is 'empty' now, i.e. rr->length may be 0.)
+     */
+
+    if (SSL3_RECORD_get_type(rr) == SSL3_RT_ALERT) {
+        unsigned int alert_level, alert_descr;
+        unsigned char *alert_bytes = SSL3_RECORD_get_data(rr)
+                                     + SSL3_RECORD_get_off(rr);
+        PACKET alert;
+
+        if (!PACKET_buf_init(&alert, alert_bytes, SSL3_RECORD_get_length(rr))
+                || !PACKET_get_1(&alert, &alert_level)
+                || !PACKET_get_1(&alert, &alert_descr)
+                || PACKET_remaining(&alert) != 0) {
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
+                     SSL_R_INVALID_ALERT);
+            return -1;
+        }
+
+        if (s->msg_callback)
+            s->msg_callback(0, s->version, SSL3_RT_ALERT, alert_bytes, 2, s,
+                            s->msg_callback_arg);
+
+        if (s->info_callback != NULL)
+            cb = s->info_callback;
+        else if (s->ctx->info_callback != NULL)
+            cb = s->ctx->info_callback;
+
+        if (cb != NULL) {
+            j = (alert_level << 8) | alert_descr;
+            cb(s, SSL_CB_READ_ALERT, j);
+        }
+
+        if (alert_level == SSL3_AL_WARNING
+                || (is_tls13 && alert_descr == SSL_AD_USER_CANCELLED)) {
+            s->s3->warn_alert = alert_descr;
+            SSL3_RECORD_set_read(rr);
+
+            s->rlayer.alert_count++;
+            if (s->rlayer.alert_count == MAX_WARN_ALERT_COUNT) {
+                SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
+                         SSL_R_TOO_MANY_WARN_ALERTS);
+                return -1;
+            }
+        }
+
+        /*
+         * Apart from close_notify the only other warning alert in TLSv1.3
+         * is user_cancelled - which we just ignore.
+         */
+        if (is_tls13 && alert_descr == SSL_AD_USER_CANCELLED) {
+            goto start;
+        } else if (alert_descr == SSL_AD_CLOSE_NOTIFY
+                && (is_tls13 || alert_level == SSL3_AL_WARNING)) {
+            s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+            return 0;
+        } else if (alert_level == SSL3_AL_FATAL || is_tls13) {
+            char tmp[16];
+
+            s->rwstate = SSL_NOTHING;
+            s->s3->fatal_alert = alert_descr;
+            SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_SSL3_READ_BYTES,
+                     SSL_AD_REASON_OFFSET + alert_descr);
+            BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr);
+            ERR_add_error_data(2, "SSL alert number ", tmp);
+            s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+            SSL3_RECORD_set_read(rr);
+            SSL_CTX_remove_session(s->session_ctx, s->session);
+            return 0;
+        } else if (alert_descr == SSL_AD_NO_RENEGOTIATION) {
+            /*
+             * This is a warning but we receive it if we requested
+             * renegotiation and the peer denied it. Terminate with a fatal
+             * alert because if application tried to renegotiate it
+             * presumably had a good reason and expects it to succeed. In
+             * future we might have a renegotiation where we don't care if
+             * the peer refused it where we carry on.
+             */
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_SSL3_READ_BYTES,
+                     SSL_R_NO_RENEGOTIATION);
+            return -1;
+        } else if (alert_level == SSL3_AL_WARNING) {
+            /* We ignore any other warning alert in TLSv1.2 and below */
+            goto start;
+        }
+
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SSL3_READ_BYTES,
+                 SSL_R_UNKNOWN_ALERT_TYPE);
+        return -1;
+    }
+
+    if ((s->shutdown & SSL_SENT_SHUTDOWN) != 0) {
+        if (SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) {
+            BIO *rbio;
+
+            /*
+             * We ignore any handshake messages sent to us unless they are
+             * TLSv1.3 in which case we want to process them. For all other
+             * handshake messages we can't do anything reasonable with them
+             * because we are unable to write any response due to having already
+             * sent close_notify.
+             */
+            if (!SSL_IS_TLS13(s)) {
+                SSL3_RECORD_set_length(rr, 0);
+                SSL3_RECORD_set_read(rr);
+
+                if ((s->mode & SSL_MODE_AUTO_RETRY) != 0)
+                    goto start;
+
+                s->rwstate = SSL_READING;
+                rbio = SSL_get_rbio(s);
+                BIO_clear_retry_flags(rbio);
+                BIO_set_retry_read(rbio);
+                return -1;
+            }
+        } else {
+            /*
+             * The peer is continuing to send application data, but we have
+             * already sent close_notify. If this was expected we should have
+             * been called via SSL_read() and this would have been handled
+             * above.
+             * No alert sent because we already sent close_notify
+             */
+            SSL3_RECORD_set_length(rr, 0);
+            SSL3_RECORD_set_read(rr);
+            SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_SSL3_READ_BYTES,
+                     SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY);
+            return -1;
+        }
+    }
+
+    /*
+     * For handshake data we have 'fragment' storage, so fill that so that we
+     * can process the header at a fixed place. This is done after the
+     * "SHUTDOWN" code above to avoid filling the fragment storage with data
+     * that we're just going to discard.
+     */
+    if (SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) {
+        size_t dest_maxlen = sizeof(s->rlayer.handshake_fragment);
+        unsigned char *dest = s->rlayer.handshake_fragment;
+        size_t *dest_len = &s->rlayer.handshake_fragment_len;
+
+        n = dest_maxlen - *dest_len; /* available space in 'dest' */
+        if (SSL3_RECORD_get_length(rr) < n)
+            n = SSL3_RECORD_get_length(rr); /* available bytes */
+
+        /* now move 'n' bytes: */
+        memcpy(dest + *dest_len,
+               SSL3_RECORD_get_data(rr) + SSL3_RECORD_get_off(rr), n);
+        SSL3_RECORD_add_off(rr, n);
+        SSL3_RECORD_sub_length(rr, n);
+        *dest_len += n;
+        if (SSL3_RECORD_get_length(rr) == 0)
+            SSL3_RECORD_set_read(rr);
+
+        if (*dest_len < dest_maxlen)
+            goto start;     /* fragment was too small */
+    }
+
+    if (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC) {
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
+                 SSL_R_CCS_RECEIVED_EARLY);
+        return -1;
+    }
+
+    /*
+     * Unexpected handshake message (ClientHello, NewSessionTicket (TLS1.3) or
+     * protocol violation)
+     */
+    if ((s->rlayer.handshake_fragment_len >= 4)
+            && !ossl_statem_get_in_handshake(s)) {
+        int ined = (s->early_data_state == SSL_EARLY_DATA_READING);
+
+        /* We found handshake data, so we're going back into init */
+        ossl_statem_set_in_init(s, 1);
+
+        i = s->handshake_func(s);
+        /* SSLfatal() already called if appropriate */
+        if (i < 0)
+            return i;
+        if (i == 0) {
+            return -1;
+        }
+
+        /*
+         * If we were actually trying to read early data and we found a
+         * handshake message, then we don't want to continue to try and read
+         * the application data any more. It won't be "early" now.
+         */
+        if (ined)
+            return -1;
+
+        if (!(s->mode & SSL_MODE_AUTO_RETRY)) {
+            if (SSL3_BUFFER_get_left(rbuf) == 0) {
+                /* no read-ahead left? */
+                BIO *bio;
+                /*
+                 * In the case where we try to read application data, but we
+                 * trigger an SSL handshake, we return -1 with the retry
+                 * option set.  Otherwise renegotiation may cause nasty
+                 * problems in the blocking world
+                 */
+                s->rwstate = SSL_READING;
+                bio = SSL_get_rbio(s);
+                BIO_clear_retry_flags(bio);
+                BIO_set_retry_read(bio);
+                return -1;
+            }
+        }
+        goto start;
+    }
+
+    switch (SSL3_RECORD_get_type(rr)) {
+    default:
+        /*
+         * TLS 1.0 and 1.1 say you SHOULD ignore unrecognised record types, but
+         * TLS 1.2 says you MUST send an unexpected message alert. We use the
+         * TLS 1.2 behaviour for all protocol versions to prevent issues where
+         * no progress is being made and the peer continually sends unrecognised
+         * record types, using up resources processing them.
+         */
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
+                 SSL_R_UNEXPECTED_RECORD);
+        return -1;
+    case SSL3_RT_CHANGE_CIPHER_SPEC:
+    case SSL3_RT_ALERT:
+    case SSL3_RT_HANDSHAKE:
+        /*
+         * we already handled all of these, with the possible exception of
+         * SSL3_RT_HANDSHAKE when ossl_statem_get_in_handshake(s) is true, but
+         * that should not happen when type != rr->type
+         */
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
+                 ERR_R_INTERNAL_ERROR);
+        return -1;
+    case SSL3_RT_APPLICATION_DATA:
+        /*
+         * At this point, we were expecting handshake data, but have
+         * application data.  If the library was running inside ssl3_read()
+         * (i.e. in_read_app_data is set) and it makes sense to read
+         * application data at this point (session renegotiation not yet
+         * started), we will indulge it.
+         */
+        if (ossl_statem_app_data_allowed(s)) {
+            s->s3->in_read_app_data = 2;
+            return -1;
+        } else if (ossl_statem_skip_early_data(s)) {
+            /*
+             * This can happen after a client sends a CH followed by early_data,
+             * but the server responds with a HelloRetryRequest. The server
+             * reads the next record from the client expecting to find a
+             * plaintext ClientHello but gets a record which appears to be
+             * application data. The trial decrypt "works" because null
+             * decryption was applied. We just skip it and move on to the next
+             * record.
+             */
+            if (!early_data_count_ok(s, rr->length,
+                                     EARLY_DATA_CIPHERTEXT_OVERHEAD, 0)) {
+                /* SSLfatal() already called */
+                return -1;
+            }
+            SSL3_RECORD_set_read(rr);
+            goto start;
+        } else {
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
+                     SSL_R_UNEXPECTED_RECORD);
+            return -1;
+        }
+    }
+}
+
+void ssl3_record_sequence_update(unsigned char *seq)
+{
+    int i;
+
+    for (i = 7; i >= 0; i--) {
+        ++seq[i];
+        if (seq[i] != 0)
+            break;
+    }
+}
+
+/*
+ * Returns true if the current rrec was sent in SSLv2 backwards compatible
+ * format and false otherwise.
+ */
+int RECORD_LAYER_is_sslv2_record(RECORD_LAYER *rl)
+{
+    return SSL3_RECORD_is_sslv2_record(&rl->rrec[0]);
+}
+
+/*
+ * Returns the length in bytes of the current rrec
+ */
+size_t RECORD_LAYER_get_rrec_length(RECORD_LAYER *rl)
+{
+    return SSL3_RECORD_get_length(&rl->rrec[0]);
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/record/record.h b/ap/lib/libssl/openssl-1.1.1o/ssl/record/record.h
new file mode 100644
index 0000000..af56206
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/record/record.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*****************************************************************************
+ *                                                                           *
+ * These structures should be considered PRIVATE to the record layer. No     *
+ * non-record layer code should be using these structures in any way.        *
+ *                                                                           *
+ *****************************************************************************/
+
+typedef struct ssl3_buffer_st {
+    /* at least SSL3_RT_MAX_PACKET_SIZE bytes, see ssl3_setup_buffers() */
+    unsigned char *buf;
+    /* default buffer size (or 0 if no default set) */
+    size_t default_len;
+    /* buffer size */
+    size_t len;
+    /* where to 'copy from' */
+    size_t offset;
+    /* how many bytes left */
+    size_t left;
+} SSL3_BUFFER;
+
+#define SEQ_NUM_SIZE                            8
+
+typedef struct ssl3_record_st {
+    /* Record layer version */
+    /* r */
+    int rec_version;
+    /* type of record */
+    /* r */
+    int type;
+    /* How many bytes available */
+    /* rw */
+    size_t length;
+    /*
+     * How many bytes were available before padding was removed? This is used
+     * to implement the MAC check in constant time for CBC records.
+     */
+    /* rw */
+    size_t orig_len;
+    /* read/write offset into 'buf' */
+    /* r */
+    size_t off;
+    /* pointer to the record data */
+    /* rw */
+    unsigned char *data;
+    /* where the decode bytes are */
+    /* rw */
+    unsigned char *input;
+    /* only used with decompression - malloc()ed */
+    /* r */
+    unsigned char *comp;
+    /* Whether the data from this record has already been read or not */
+    /* r */
+    unsigned int read;
+    /* epoch number, needed by DTLS1 */
+    /* r */
+    unsigned long epoch;
+    /* sequence number, needed by DTLS1 */
+    /* r */
+    unsigned char seq_num[SEQ_NUM_SIZE];
+} SSL3_RECORD;
+
+typedef struct dtls1_bitmap_st {
+    /* Track 32 packets on 32-bit systems and 64 - on 64-bit systems */
+    unsigned long map;
+    /* Max record number seen so far, 64-bit value in big-endian encoding */
+    unsigned char max_seq_num[SEQ_NUM_SIZE];
+} DTLS1_BITMAP;
+
+typedef struct record_pqueue_st {
+    unsigned short epoch;
+    struct pqueue_st *q;
+} record_pqueue;
+
+typedef struct dtls1_record_data_st {
+    unsigned char *packet;
+    size_t packet_length;
+    SSL3_BUFFER rbuf;
+    SSL3_RECORD rrec;
+#ifndef OPENSSL_NO_SCTP
+    struct bio_dgram_sctp_rcvinfo recordinfo;
+#endif
+} DTLS1_RECORD_DATA;
+
+typedef struct dtls_record_layer_st {
+    /*
+     * The current data and handshake epoch.  This is initially
+     * undefined, and starts at zero once the initial handshake is
+     * completed
+     */
+    unsigned short r_epoch;
+    unsigned short w_epoch;
+    /* records being received in the current epoch */
+    DTLS1_BITMAP bitmap;
+    /* renegotiation starts a new set of sequence numbers */
+    DTLS1_BITMAP next_bitmap;
+    /* Received handshake records (processed and unprocessed) */
+    record_pqueue unprocessed_rcds;
+    record_pqueue processed_rcds;
+    /*
+     * Buffered application records. Only for records between CCS and
+     * Finished to prevent either protocol violation or unnecessary message
+     * loss.
+     */
+    record_pqueue buffered_app_data;
+    /* save last and current sequence numbers for retransmissions */
+    unsigned char last_write_sequence[8];
+    unsigned char curr_write_sequence[8];
+} DTLS_RECORD_LAYER;
+
+/*****************************************************************************
+ *                                                                           *
+ * This structure should be considered "opaque" to anything outside of the   *
+ * record layer. No non-record layer code should be accessing the members of *
+ * this structure.                                                           *
+ *                                                                           *
+ *****************************************************************************/
+
+typedef struct record_layer_st {
+    /* The parent SSL structure */
+    SSL *s;
+    /*
+     * Read as many input bytes as possible (for
+     * non-blocking reads)
+     */
+    int read_ahead;
+    /* where we are when reading */
+    int rstate;
+    /* How many pipelines can be used to read data */
+    size_t numrpipes;
+    /* How many pipelines can be used to write data */
+    size_t numwpipes;
+    /* read IO goes into here */
+    SSL3_BUFFER rbuf;
+    /* write IO goes into here */
+    SSL3_BUFFER wbuf[SSL_MAX_PIPELINES];
+    /* each decoded record goes in here */
+    SSL3_RECORD rrec[SSL_MAX_PIPELINES];
+    /* used internally to point at a raw packet */
+    unsigned char *packet;
+    size_t packet_length;
+    /* number of bytes sent so far */
+    size_t wnum;
+    unsigned char handshake_fragment[4];
+    size_t handshake_fragment_len;
+    /* The number of consecutive empty records we have received */
+    size_t empty_record_count;
+    /* partial write - check the numbers match */
+    /* number bytes written */
+    size_t wpend_tot;
+    int wpend_type;
+    /* number of bytes submitted */
+    size_t wpend_ret;
+    const unsigned char *wpend_buf;
+    unsigned char read_sequence[SEQ_NUM_SIZE];
+    unsigned char write_sequence[SEQ_NUM_SIZE];
+    /* Set to true if this is the first record in a connection */
+    unsigned int is_first_record;
+    /* Count of the number of consecutive warning alerts received */
+    unsigned int alert_count;
+    DTLS_RECORD_LAYER *d;
+} RECORD_LAYER;
+
+/*****************************************************************************
+ *                                                                           *
+ * The following macros/functions represent the libssl internal API to the   *
+ * record layer. Any libssl code may call these functions/macros             *
+ *                                                                           *
+ *****************************************************************************/
+
+#define MIN_SSL2_RECORD_LEN     9
+
+#define RECORD_LAYER_set_read_ahead(rl, ra)     ((rl)->read_ahead = (ra))
+#define RECORD_LAYER_get_read_ahead(rl)         ((rl)->read_ahead)
+#define RECORD_LAYER_get_packet(rl)             ((rl)->packet)
+#define RECORD_LAYER_get_packet_length(rl)      ((rl)->packet_length)
+#define RECORD_LAYER_add_packet_length(rl, inc) ((rl)->packet_length += (inc))
+#define DTLS_RECORD_LAYER_get_w_epoch(rl)       ((rl)->d->w_epoch)
+#define DTLS_RECORD_LAYER_get_processed_rcds(rl) \
+                                                ((rl)->d->processed_rcds)
+#define DTLS_RECORD_LAYER_get_unprocessed_rcds(rl) \
+                                                ((rl)->d->unprocessed_rcds)
+#define RECORD_LAYER_get_rbuf(rl)               (&(rl)->rbuf)
+#define RECORD_LAYER_get_wbuf(rl)               ((rl)->wbuf)
+
+void RECORD_LAYER_init(RECORD_LAYER *rl, SSL *s);
+void RECORD_LAYER_clear(RECORD_LAYER *rl);
+void RECORD_LAYER_release(RECORD_LAYER *rl);
+int RECORD_LAYER_read_pending(const RECORD_LAYER *rl);
+int RECORD_LAYER_processed_read_pending(const RECORD_LAYER *rl);
+int RECORD_LAYER_write_pending(const RECORD_LAYER *rl);
+void RECORD_LAYER_reset_read_sequence(RECORD_LAYER *rl);
+void RECORD_LAYER_reset_write_sequence(RECORD_LAYER *rl);
+int RECORD_LAYER_is_sslv2_record(RECORD_LAYER *rl);
+size_t RECORD_LAYER_get_rrec_length(RECORD_LAYER *rl);
+__owur size_t ssl3_pending(const SSL *s);
+__owur int ssl3_write_bytes(SSL *s, int type, const void *buf, size_t len,
+                            size_t *written);
+int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+                  size_t *pipelens, size_t numpipes,
+                  int create_empty_fragment, size_t *written);
+__owur int ssl3_read_bytes(SSL *s, int type, int *recvd_type,
+                           unsigned char *buf, size_t len, int peek,
+                           size_t *readbytes);
+__owur int ssl3_setup_buffers(SSL *s);
+__owur int ssl3_enc(SSL *s, SSL3_RECORD *inrecs, size_t n_recs, int send);
+__owur int n_ssl3_mac(SSL *ssl, SSL3_RECORD *rec, unsigned char *md, int send);
+__owur int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, size_t len,
+                              size_t *written);
+__owur int tls1_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int send);
+__owur int tls1_mac(SSL *ssl, SSL3_RECORD *rec, unsigned char *md, int send);
+__owur int tls13_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int send);
+int DTLS_RECORD_LAYER_new(RECORD_LAYER *rl);
+void DTLS_RECORD_LAYER_free(RECORD_LAYER *rl);
+void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl);
+void DTLS_RECORD_LAYER_set_saved_w_epoch(RECORD_LAYER *rl, unsigned short e);
+void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl);
+void DTLS_RECORD_LAYER_set_write_sequence(RECORD_LAYER *rl, unsigned char *seq);
+__owur int dtls1_read_bytes(SSL *s, int type, int *recvd_type,
+                            unsigned char *buf, size_t len, int peek,
+                            size_t *readbytes);
+__owur int dtls1_write_bytes(SSL *s, int type, const void *buf, size_t len,
+                             size_t *written);
+int do_dtls1_write(SSL *s, int type, const unsigned char *buf,
+                   size_t len, int create_empty_fragment, size_t *written);
+void dtls1_reset_seq_numbers(SSL *s, int rw);
+int dtls_buffer_listen_record(SSL *s, size_t len, unsigned char *seq,
+                              size_t off);
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/record/record_local.h b/ap/lib/libssl/openssl-1.1.1o/ssl/record/record_local.h
new file mode 100644
index 0000000..5e8dd7f
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/record/record_local.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*****************************************************************************
+ *                                                                           *
+ * The following macros/functions are PRIVATE to the record layer. They      *
+ * should NOT be used outside of the record layer.                           *
+ *                                                                           *
+ *****************************************************************************/
+
+#define MAX_WARN_ALERT_COUNT    5
+
+/* Functions/macros provided by the RECORD_LAYER component */
+
+#define RECORD_LAYER_get_rrec(rl)               ((rl)->rrec)
+#define RECORD_LAYER_set_packet(rl, p)          ((rl)->packet = (p))
+#define RECORD_LAYER_reset_packet_length(rl)    ((rl)->packet_length = 0)
+#define RECORD_LAYER_get_rstate(rl)             ((rl)->rstate)
+#define RECORD_LAYER_set_rstate(rl, st)         ((rl)->rstate = (st))
+#define RECORD_LAYER_get_read_sequence(rl)      ((rl)->read_sequence)
+#define RECORD_LAYER_get_write_sequence(rl)     ((rl)->write_sequence)
+#define RECORD_LAYER_get_numrpipes(rl)          ((rl)->numrpipes)
+#define RECORD_LAYER_set_numrpipes(rl, n)       ((rl)->numrpipes = (n))
+#define RECORD_LAYER_inc_empty_record_count(rl) ((rl)->empty_record_count++)
+#define RECORD_LAYER_reset_empty_record_count(rl) \
+                                                ((rl)->empty_record_count = 0)
+#define RECORD_LAYER_get_empty_record_count(rl) ((rl)->empty_record_count)
+#define RECORD_LAYER_is_first_record(rl)        ((rl)->is_first_record)
+#define RECORD_LAYER_set_first_record(rl)       ((rl)->is_first_record = 1)
+#define RECORD_LAYER_clear_first_record(rl)     ((rl)->is_first_record = 0)
+#define DTLS_RECORD_LAYER_get_r_epoch(rl)       ((rl)->d->r_epoch)
+
+__owur int ssl3_read_n(SSL *s, size_t n, size_t max, int extend, int clearold,
+                       size_t *readbytes);
+
+DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr,
+                               unsigned int *is_next_epoch);
+int dtls1_process_buffered_records(SSL *s);
+int dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue);
+int dtls1_buffer_record(SSL *s, record_pqueue *q, unsigned char *priority);
+void ssl3_record_sequence_update(unsigned char *seq);
+
+/* Functions provided by the DTLS1_BITMAP component */
+
+int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap);
+void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap);
+
+/* Macros/functions provided by the SSL3_BUFFER component */
+
+#define SSL3_BUFFER_get_buf(b)              ((b)->buf)
+#define SSL3_BUFFER_set_buf(b, n)           ((b)->buf = (n))
+#define SSL3_BUFFER_get_len(b)              ((b)->len)
+#define SSL3_BUFFER_set_len(b, l)           ((b)->len = (l))
+#define SSL3_BUFFER_get_left(b)             ((b)->left)
+#define SSL3_BUFFER_set_left(b, l)          ((b)->left = (l))
+#define SSL3_BUFFER_sub_left(b, l)          ((b)->left -= (l))
+#define SSL3_BUFFER_get_offset(b)           ((b)->offset)
+#define SSL3_BUFFER_set_offset(b, o)        ((b)->offset = (o))
+#define SSL3_BUFFER_add_offset(b, o)        ((b)->offset += (o))
+#define SSL3_BUFFER_is_initialised(b)       ((b)->buf != NULL)
+#define SSL3_BUFFER_set_default_len(b, l)   ((b)->default_len = (l))
+
+void SSL3_BUFFER_clear(SSL3_BUFFER *b);
+void SSL3_BUFFER_set_data(SSL3_BUFFER *b, const unsigned char *d, size_t n);
+void SSL3_BUFFER_release(SSL3_BUFFER *b);
+__owur int ssl3_setup_read_buffer(SSL *s);
+__owur int ssl3_setup_write_buffer(SSL *s, size_t numwpipes, size_t len);
+int ssl3_release_read_buffer(SSL *s);
+int ssl3_release_write_buffer(SSL *s);
+
+/* Macros/functions provided by the SSL3_RECORD component */
+
+#define SSL3_RECORD_get_type(r)                 ((r)->type)
+#define SSL3_RECORD_set_type(r, t)              ((r)->type = (t))
+#define SSL3_RECORD_set_rec_version(r, v)       ((r)->rec_version = (v))
+#define SSL3_RECORD_get_length(r)               ((r)->length)
+#define SSL3_RECORD_set_length(r, l)            ((r)->length = (l))
+#define SSL3_RECORD_add_length(r, l)            ((r)->length += (l))
+#define SSL3_RECORD_sub_length(r, l)            ((r)->length -= (l))
+#define SSL3_RECORD_get_data(r)                 ((r)->data)
+#define SSL3_RECORD_set_data(r, d)              ((r)->data = (d))
+#define SSL3_RECORD_get_input(r)                ((r)->input)
+#define SSL3_RECORD_set_input(r, i)             ((r)->input = (i))
+#define SSL3_RECORD_reset_input(r)              ((r)->input = (r)->data)
+#define SSL3_RECORD_get_seq_num(r)              ((r)->seq_num)
+#define SSL3_RECORD_get_off(r)                  ((r)->off)
+#define SSL3_RECORD_set_off(r, o)               ((r)->off = (o))
+#define SSL3_RECORD_add_off(r, o)               ((r)->off += (o))
+#define SSL3_RECORD_get_epoch(r)                ((r)->epoch)
+#define SSL3_RECORD_is_sslv2_record(r) \
+            ((r)->rec_version == SSL2_VERSION)
+#define SSL3_RECORD_is_read(r)                  ((r)->read)
+#define SSL3_RECORD_set_read(r)                 ((r)->read = 1)
+
+void SSL3_RECORD_clear(SSL3_RECORD *r, size_t);
+void SSL3_RECORD_release(SSL3_RECORD *r, size_t num_recs);
+void SSL3_RECORD_set_seq_num(SSL3_RECORD *r, const unsigned char *seq_num);
+int ssl3_get_record(SSL *s);
+__owur int ssl3_do_compress(SSL *ssl, SSL3_RECORD *wr);
+__owur int ssl3_do_uncompress(SSL *ssl, SSL3_RECORD *rr);
+int ssl3_cbc_copy_mac(unsigned char *out,
+                       const SSL3_RECORD *rec, size_t md_size);
+__owur int ssl3_cbc_remove_padding(SSL3_RECORD *rec,
+                                   size_t block_size, size_t mac_size);
+__owur int tls1_cbc_remove_padding(const SSL *s,
+                                   SSL3_RECORD *rec,
+                                   size_t block_size, size_t mac_size);
+int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap);
+__owur int dtls1_get_record(SSL *s);
+int early_data_count_ok(SSL *s, size_t length, size_t overhead, int send);
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/record/ssl3_buffer.c b/ap/lib/libssl/openssl-1.1.1o/ssl/record/ssl3_buffer.c
new file mode 100644
index 0000000..fa597c2
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/record/ssl3_buffer.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../ssl_local.h"
+#include "record_local.h"
+
+void SSL3_BUFFER_set_data(SSL3_BUFFER *b, const unsigned char *d, size_t n)
+{
+    if (d != NULL)
+        memcpy(b->buf, d, n);
+    b->left = n;
+    b->offset = 0;
+}
+
+/*
+ * Clear the contents of an SSL3_BUFFER but retain any memory allocated. Also
+ * retains the default_len setting
+ */
+void SSL3_BUFFER_clear(SSL3_BUFFER *b)
+{
+    b->offset = 0;
+    b->left = 0;
+}
+
+void SSL3_BUFFER_release(SSL3_BUFFER *b)
+{
+    OPENSSL_free(b->buf);
+    b->buf = NULL;
+}
+
+int ssl3_setup_read_buffer(SSL *s)
+{
+    unsigned char *p;
+    size_t len, align = 0, headerlen;
+    SSL3_BUFFER *b;
+
+    b = RECORD_LAYER_get_rbuf(&s->rlayer);
+
+    if (SSL_IS_DTLS(s))
+        headerlen = DTLS1_RT_HEADER_LENGTH;
+    else
+        headerlen = SSL3_RT_HEADER_LENGTH;
+
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+    align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1);
+#endif
+
+    if (b->buf == NULL) {
+        len = SSL3_RT_MAX_PLAIN_LENGTH
+            + SSL3_RT_MAX_ENCRYPTED_OVERHEAD + headerlen + align;
+#ifndef OPENSSL_NO_COMP
+        if (ssl_allow_compression(s))
+            len += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
+#endif
+        if (b->default_len > len)
+            len = b->default_len;
+        if ((p = OPENSSL_malloc(len)) == NULL) {
+            /*
+             * We've got a malloc failure, and we're still initialising buffers.
+             * We assume we're so doomed that we won't even be able to send an
+             * alert.
+             */
+            SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_SSL3_SETUP_READ_BUFFER,
+                     ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        b->buf = p;
+        b->len = len;
+    }
+
+    return 1;
+}
+
+int ssl3_setup_write_buffer(SSL *s, size_t numwpipes, size_t len)
+{
+    unsigned char *p;
+    size_t align = 0, headerlen;
+    SSL3_BUFFER *wb;
+    size_t currpipe;
+
+    s->rlayer.numwpipes = numwpipes;
+
+    if (len == 0) {
+        if (SSL_IS_DTLS(s))
+            headerlen = DTLS1_RT_HEADER_LENGTH + 1;
+        else
+            headerlen = SSL3_RT_HEADER_LENGTH;
+
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+        align = SSL3_ALIGN_PAYLOAD - 1;
+#endif
+
+        len = ssl_get_max_send_fragment(s)
+            + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD + headerlen + align
+            + SSL_RT_MAX_CIPHER_BLOCK_SIZE /* Explicit IV allowance */;
+#ifndef OPENSSL_NO_COMP
+        if (ssl_allow_compression(s))
+            len += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
+#endif
+        /*
+         * We don't need to add an allowance for eivlen here since empty
+         * fragments only occur when we don't have an explicit IV
+         */
+        if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS))
+            len += headerlen + align + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD;
+    }
+
+    wb = RECORD_LAYER_get_wbuf(&s->rlayer);
+    for (currpipe = 0; currpipe < numwpipes; currpipe++) {
+        SSL3_BUFFER *thiswb = &wb[currpipe];
+
+        if (thiswb->buf != NULL && thiswb->len != len) {
+            OPENSSL_free(thiswb->buf);
+            thiswb->buf = NULL;         /* force reallocation */
+        }
+
+        if (thiswb->buf == NULL) {
+            p = OPENSSL_malloc(len);
+            if (p == NULL) {
+                s->rlayer.numwpipes = currpipe;
+                /*
+                 * We've got a malloc failure, and we're still initialising
+                 * buffers. We assume we're so doomed that we won't even be able
+                 * to send an alert.
+                 */
+                SSLfatal(s, SSL_AD_NO_ALERT,
+                         SSL_F_SSL3_SETUP_WRITE_BUFFER, ERR_R_MALLOC_FAILURE);
+                return 0;
+            }
+            memset(thiswb, 0, sizeof(SSL3_BUFFER));
+            thiswb->buf = p;
+            thiswb->len = len;
+        }
+    }
+
+    return 1;
+}
+
+int ssl3_setup_buffers(SSL *s)
+{
+    if (!ssl3_setup_read_buffer(s)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+    if (!ssl3_setup_write_buffer(s, 1, 0)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+    return 1;
+}
+
+int ssl3_release_write_buffer(SSL *s)
+{
+    SSL3_BUFFER *wb;
+    size_t pipes;
+
+    pipes = s->rlayer.numwpipes;
+    while (pipes > 0) {
+        wb = &RECORD_LAYER_get_wbuf(&s->rlayer)[pipes - 1];
+
+        OPENSSL_free(wb->buf);
+        wb->buf = NULL;
+        pipes--;
+    }
+    s->rlayer.numwpipes = 0;
+    return 1;
+}
+
+int ssl3_release_read_buffer(SSL *s)
+{
+    SSL3_BUFFER *b;
+
+    b = RECORD_LAYER_get_rbuf(&s->rlayer);
+    OPENSSL_free(b->buf);
+    b->buf = NULL;
+    return 1;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/record/ssl3_record.c b/ap/lib/libssl/openssl-1.1.1o/ssl/record/ssl3_record.c
new file mode 100644
index 0000000..47c7369
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/record/ssl3_record.c
@@ -0,0 +1,2071 @@
+/*
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../ssl_local.h"
+#include "internal/constant_time.h"
+#include <openssl/rand.h>
+#include "record_local.h"
+#include "internal/cryptlib.h"
+
+static const unsigned char ssl3_pad_1[48] = {
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
+};
+
+static const unsigned char ssl3_pad_2[48] = {
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c
+};
+
+/*
+ * Clear the contents of an SSL3_RECORD but retain any memory allocated
+ */
+void SSL3_RECORD_clear(SSL3_RECORD *r, size_t num_recs)
+{
+    unsigned char *comp;
+    size_t i;
+
+    for (i = 0; i < num_recs; i++) {
+        comp = r[i].comp;
+
+        memset(&r[i], 0, sizeof(*r));
+        r[i].comp = comp;
+    }
+}
+
+void SSL3_RECORD_release(SSL3_RECORD *r, size_t num_recs)
+{
+    size_t i;
+
+    for (i = 0; i < num_recs; i++) {
+        OPENSSL_free(r[i].comp);
+        r[i].comp = NULL;
+    }
+}
+
+void SSL3_RECORD_set_seq_num(SSL3_RECORD *r, const unsigned char *seq_num)
+{
+    memcpy(r->seq_num, seq_num, SEQ_NUM_SIZE);
+}
+
+/*
+ * Peeks ahead into "read_ahead" data to see if we have a whole record waiting
+ * for us in the buffer.
+ */
+static int ssl3_record_app_data_waiting(SSL *s)
+{
+    SSL3_BUFFER *rbuf;
+    size_t left, len;
+    unsigned char *p;
+
+    rbuf = RECORD_LAYER_get_rbuf(&s->rlayer);
+
+    p = SSL3_BUFFER_get_buf(rbuf);
+    if (p == NULL)
+        return 0;
+
+    left = SSL3_BUFFER_get_left(rbuf);
+
+    if (left < SSL3_RT_HEADER_LENGTH)
+        return 0;
+
+    p += SSL3_BUFFER_get_offset(rbuf);
+
+    /*
+     * We only check the type and record length, we will sanity check version
+     * etc later
+     */
+    if (*p != SSL3_RT_APPLICATION_DATA)
+        return 0;
+
+    p += 3;
+    n2s(p, len);
+
+    if (left < SSL3_RT_HEADER_LENGTH + len)
+        return 0;
+
+    return 1;
+}
+
+int early_data_count_ok(SSL *s, size_t length, size_t overhead, int send)
+{
+    uint32_t max_early_data;
+    SSL_SESSION *sess = s->session;
+
+    /*
+     * If we are a client then we always use the max_early_data from the
+     * session/psksession. Otherwise we go with the lowest out of the max early
+     * data set in the session and the configured max_early_data.
+     */
+    if (!s->server && sess->ext.max_early_data == 0) {
+        if (!ossl_assert(s->psksession != NULL
+                         && s->psksession->ext.max_early_data > 0)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_EARLY_DATA_COUNT_OK,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        sess = s->psksession;
+    }
+
+    if (!s->server)
+        max_early_data = sess->ext.max_early_data;
+    else if (s->ext.early_data != SSL_EARLY_DATA_ACCEPTED)
+        max_early_data = s->recv_max_early_data;
+    else
+        max_early_data = s->recv_max_early_data < sess->ext.max_early_data
+                         ? s->recv_max_early_data : sess->ext.max_early_data;
+
+    if (max_early_data == 0) {
+        SSLfatal(s, send ? SSL_AD_INTERNAL_ERROR : SSL_AD_UNEXPECTED_MESSAGE,
+                 SSL_F_EARLY_DATA_COUNT_OK, SSL_R_TOO_MUCH_EARLY_DATA);
+        return 0;
+    }
+
+    /* If we are dealing with ciphertext we need to allow for the overhead */
+    max_early_data += overhead;
+
+    if (s->early_data_count + length > max_early_data) {
+        SSLfatal(s, send ? SSL_AD_INTERNAL_ERROR : SSL_AD_UNEXPECTED_MESSAGE,
+                 SSL_F_EARLY_DATA_COUNT_OK, SSL_R_TOO_MUCH_EARLY_DATA);
+        return 0;
+    }
+    s->early_data_count += length;
+
+    return 1;
+}
+
+/*
+ * MAX_EMPTY_RECORDS defines the number of consecutive, empty records that
+ * will be processed per call to ssl3_get_record. Without this limit an
+ * attacker could send empty records at a faster rate than we can process and
+ * cause ssl3_get_record to loop forever.
+ */
+#define MAX_EMPTY_RECORDS 32
+
+#define SSL2_RT_HEADER_LENGTH   2
+/*-
+ * Call this to get new input records.
+ * It will return <= 0 if more data is needed, normally due to an error
+ * or non-blocking IO.
+ * When it finishes, |numrpipes| records have been decoded. For each record 'i':
+ * rr[i].type    - is the type of record
+ * rr[i].data,   - data
+ * rr[i].length, - number of bytes
+ * Multiple records will only be returned if the record types are all
+ * SSL3_RT_APPLICATION_DATA. The number of records returned will always be <=
+ * |max_pipelines|
+ */
+/* used only by ssl3_read_bytes */
+int ssl3_get_record(SSL *s)
+{
+    int enc_err, rret;
+    int i;
+    size_t more, n;
+    SSL3_RECORD *rr, *thisrr;
+    SSL3_BUFFER *rbuf;
+    SSL_SESSION *sess;
+    unsigned char *p;
+    unsigned char md[EVP_MAX_MD_SIZE];
+    unsigned int version;
+    size_t mac_size;
+    int imac_size;
+    size_t num_recs = 0, max_recs, j;
+    PACKET pkt, sslv2pkt;
+    size_t first_rec_len;
+
+    rr = RECORD_LAYER_get_rrec(&s->rlayer);
+    rbuf = RECORD_LAYER_get_rbuf(&s->rlayer);
+    max_recs = s->max_pipelines;
+    if (max_recs == 0)
+        max_recs = 1;
+    sess = s->session;
+
+    do {
+        thisrr = &rr[num_recs];
+
+        /* check if we have the header */
+        if ((RECORD_LAYER_get_rstate(&s->rlayer) != SSL_ST_READ_BODY) ||
+            (RECORD_LAYER_get_packet_length(&s->rlayer)
+             < SSL3_RT_HEADER_LENGTH)) {
+            size_t sslv2len;
+            unsigned int type;
+
+            rret = ssl3_read_n(s, SSL3_RT_HEADER_LENGTH,
+                               SSL3_BUFFER_get_len(rbuf), 0,
+                               num_recs == 0 ? 1 : 0, &n);
+            if (rret <= 0)
+                return rret;     /* error or non-blocking */
+            RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY);
+
+            p = RECORD_LAYER_get_packet(&s->rlayer);
+            if (!PACKET_buf_init(&pkt, RECORD_LAYER_get_packet(&s->rlayer),
+                                 RECORD_LAYER_get_packet_length(&s->rlayer))) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_GET_RECORD,
+                         ERR_R_INTERNAL_ERROR);
+                return -1;
+            }
+            sslv2pkt = pkt;
+            if (!PACKET_get_net_2_len(&sslv2pkt, &sslv2len)
+                    || !PACKET_get_1(&sslv2pkt, &type)) {
+                SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_SSL3_GET_RECORD,
+                         ERR_R_INTERNAL_ERROR);
+                return -1;
+            }
+            /*
+             * The first record received by the server may be a V2ClientHello.
+             */
+            if (s->server && RECORD_LAYER_is_first_record(&s->rlayer)
+                    && (sslv2len & 0x8000) != 0
+                    && (type == SSL2_MT_CLIENT_HELLO)) {
+                /*
+                 *  SSLv2 style record
+                 *
+                 * |num_recs| here will actually always be 0 because
+                 * |num_recs > 0| only ever occurs when we are processing
+                 * multiple app data records - which we know isn't the case here
+                 * because it is an SSLv2ClientHello. We keep it using
+                 * |num_recs| for the sake of consistency
+                 */
+                thisrr->type = SSL3_RT_HANDSHAKE;
+                thisrr->rec_version = SSL2_VERSION;
+
+                thisrr->length = sslv2len & 0x7fff;
+
+                if (thisrr->length > SSL3_BUFFER_get_len(rbuf)
+                    - SSL2_RT_HEADER_LENGTH) {
+                    SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_F_SSL3_GET_RECORD,
+                             SSL_R_PACKET_LENGTH_TOO_LONG);
+                    return -1;
+                }
+
+                if (thisrr->length < MIN_SSL2_RECORD_LEN) {
+                    SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_SSL3_GET_RECORD,
+                             SSL_R_LENGTH_TOO_SHORT);
+                    return -1;
+                }
+            } else {
+                /* SSLv3+ style record */
+                if (s->msg_callback)
+                    s->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, s,
+                                    s->msg_callback_arg);
+
+                /* Pull apart the header into the SSL3_RECORD */
+                if (!PACKET_get_1(&pkt, &type)
+                        || !PACKET_get_net_2(&pkt, &version)
+                        || !PACKET_get_net_2_len(&pkt, &thisrr->length)) {
+                    SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_SSL3_GET_RECORD,
+                             ERR_R_INTERNAL_ERROR);
+                    return -1;
+                }
+                thisrr->type = type;
+                thisrr->rec_version = version;
+
+                /*
+                 * Lets check version. In TLSv1.3 we only check this field
+                 * when encryption is occurring (see later check). For the
+                 * ServerHello after an HRR we haven't actually selected TLSv1.3
+                 * yet, but we still treat it as TLSv1.3, so we must check for
+                 * that explicitly
+                 */
+                if (!s->first_packet && !SSL_IS_TLS13(s)
+                        && s->hello_retry_request != SSL_HRR_PENDING
+                        && version != (unsigned int)s->version) {
+                    if ((s->version & 0xFF00) == (version & 0xFF00)
+                        && !s->enc_write_ctx && !s->write_hash) {
+                        if (thisrr->type == SSL3_RT_ALERT) {
+                            /*
+                             * The record is using an incorrect version number,
+                             * but what we've got appears to be an alert. We
+                             * haven't read the body yet to check whether its a
+                             * fatal or not - but chances are it is. We probably
+                             * shouldn't send a fatal alert back. We'll just
+                             * end.
+                             */
+                            SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_SSL3_GET_RECORD,
+                                     SSL_R_WRONG_VERSION_NUMBER);
+                            return -1;
+                        }
+                        /*
+                         * Send back error using their minor version number :-)
+                         */
+                        s->version = (unsigned short)version;
+                    }
+                    SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_F_SSL3_GET_RECORD,
+                             SSL_R_WRONG_VERSION_NUMBER);
+                    return -1;
+                }
+
+                if ((version >> 8) != SSL3_VERSION_MAJOR) {
+                    if (RECORD_LAYER_is_first_record(&s->rlayer)) {
+                        /* Go back to start of packet, look at the five bytes
+                         * that we have. */
+                        p = RECORD_LAYER_get_packet(&s->rlayer);
+                        if (strncmp((char *)p, "GET ", 4) == 0 ||
+                            strncmp((char *)p, "POST ", 5) == 0 ||
+                            strncmp((char *)p, "HEAD ", 5) == 0 ||
+                            strncmp((char *)p, "PUT ", 4) == 0) {
+                            SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_SSL3_GET_RECORD,
+                                     SSL_R_HTTP_REQUEST);
+                            return -1;
+                        } else if (strncmp((char *)p, "CONNE", 5) == 0) {
+                            SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_SSL3_GET_RECORD,
+                                     SSL_R_HTTPS_PROXY_REQUEST);
+                            return -1;
+                        }
+
+                        /* Doesn't look like TLS - don't send an alert */
+                        SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_SSL3_GET_RECORD,
+                                 SSL_R_WRONG_VERSION_NUMBER);
+                        return -1;
+                    } else {
+                        SSLfatal(s, SSL_AD_PROTOCOL_VERSION,
+                                 SSL_F_SSL3_GET_RECORD,
+                                 SSL_R_WRONG_VERSION_NUMBER);
+                        return -1;
+                    }
+                }
+
+                if (SSL_IS_TLS13(s) && s->enc_read_ctx != NULL) {
+                    if (thisrr->type != SSL3_RT_APPLICATION_DATA
+                            && (thisrr->type != SSL3_RT_CHANGE_CIPHER_SPEC
+                                || !SSL_IS_FIRST_HANDSHAKE(s))
+                            && (thisrr->type != SSL3_RT_ALERT
+                                || s->statem.enc_read_state
+                                   != ENC_READ_STATE_ALLOW_PLAIN_ALERTS)) {
+                        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+                                 SSL_F_SSL3_GET_RECORD, SSL_R_BAD_RECORD_TYPE);
+                        return -1;
+                    }
+                    if (thisrr->rec_version != TLS1_2_VERSION) {
+                        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_SSL3_GET_RECORD,
+                                 SSL_R_WRONG_VERSION_NUMBER);
+                        return -1;
+                    }
+                }
+
+                if (thisrr->length >
+                    SSL3_BUFFER_get_len(rbuf) - SSL3_RT_HEADER_LENGTH) {
+                    SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_F_SSL3_GET_RECORD,
+                             SSL_R_PACKET_LENGTH_TOO_LONG);
+                    return -1;
+                }
+            }
+
+            /* now s->rlayer.rstate == SSL_ST_READ_BODY */
+        }
+
+        if (SSL_IS_TLS13(s)) {
+            if (thisrr->length > SSL3_RT_MAX_TLS13_ENCRYPTED_LENGTH) {
+                SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_F_SSL3_GET_RECORD,
+                         SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+                return -1;
+            }
+        } else {
+            size_t len = SSL3_RT_MAX_ENCRYPTED_LENGTH;
+
+#ifndef OPENSSL_NO_COMP
+            /*
+             * If OPENSSL_NO_COMP is defined then SSL3_RT_MAX_ENCRYPTED_LENGTH
+             * does not include the compression overhead anyway.
+             */
+            if (s->expand == NULL)
+                len -= SSL3_RT_MAX_COMPRESSED_OVERHEAD;
+#endif
+
+            if (thisrr->length > len) {
+                SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_F_SSL3_GET_RECORD,
+                         SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+                return -1;
+            }
+        }
+
+        /*
+         * s->rlayer.rstate == SSL_ST_READ_BODY, get and decode the data.
+         * Calculate how much more data we need to read for the rest of the
+         * record
+         */
+        if (thisrr->rec_version == SSL2_VERSION) {
+            more = thisrr->length + SSL2_RT_HEADER_LENGTH
+                - SSL3_RT_HEADER_LENGTH;
+        } else {
+            more = thisrr->length;
+        }
+        if (more > 0) {
+            /* now s->rlayer.packet_length == SSL3_RT_HEADER_LENGTH */
+
+            rret = ssl3_read_n(s, more, more, 1, 0, &n);
+            if (rret <= 0)
+                return rret;     /* error or non-blocking io */
+        }
+
+        /* set state for later operations */
+        RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_HEADER);
+
+        /*
+         * At this point, s->rlayer.packet_length == SSL3_RT_HEADER_LENGTH
+         * + thisrr->length, or s->rlayer.packet_length == SSL2_RT_HEADER_LENGTH
+         * + thisrr->length and we have that many bytes in s->rlayer.packet
+         */
+        if (thisrr->rec_version == SSL2_VERSION) {
+            thisrr->input =
+                &(RECORD_LAYER_get_packet(&s->rlayer)[SSL2_RT_HEADER_LENGTH]);
+        } else {
+            thisrr->input =
+                &(RECORD_LAYER_get_packet(&s->rlayer)[SSL3_RT_HEADER_LENGTH]);
+        }
+
+        /*
+         * ok, we can now read from 's->rlayer.packet' data into 'thisrr'.
+         * thisrr->input points at thisrr->length bytes, which need to be copied
+         * into thisrr->data by either the decryption or by the decompression.
+         * When the data is 'copied' into the thisrr->data buffer,
+         * thisrr->input will be updated to point at the new buffer
+         */
+
+        /*
+         * We now have - encrypted [ MAC [ compressed [ plain ] ] ]
+         * thisrr->length bytes of encrypted compressed stuff.
+         */
+
+        /* decrypt in place in 'thisrr->input' */
+        thisrr->data = thisrr->input;
+        thisrr->orig_len = thisrr->length;
+
+        /* Mark this record as not read by upper layers yet */
+        thisrr->read = 0;
+
+        num_recs++;
+
+        /* we have pulled in a full packet so zero things */
+        RECORD_LAYER_reset_packet_length(&s->rlayer);
+        RECORD_LAYER_clear_first_record(&s->rlayer);
+    } while (num_recs < max_recs
+             && thisrr->type == SSL3_RT_APPLICATION_DATA
+             && SSL_USE_EXPLICIT_IV(s)
+             && s->enc_read_ctx != NULL
+             && (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_read_ctx))
+                 & EVP_CIPH_FLAG_PIPELINE)
+             && ssl3_record_app_data_waiting(s));
+
+    if (num_recs == 1
+            && thisrr->type == SSL3_RT_CHANGE_CIPHER_SPEC
+            && (SSL_IS_TLS13(s) || s->hello_retry_request != SSL_HRR_NONE)
+            && SSL_IS_FIRST_HANDSHAKE(s)) {
+        /*
+         * CCS messages must be exactly 1 byte long, containing the value 0x01
+         */
+        if (thisrr->length != 1 || thisrr->data[0] != 0x01) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SSL3_GET_RECORD,
+                     SSL_R_INVALID_CCS_MESSAGE);
+            return -1;
+        }
+        /*
+         * CCS messages are ignored in TLSv1.3. We treat it like an empty
+         * handshake record
+         */
+        thisrr->type = SSL3_RT_HANDSHAKE;
+        RECORD_LAYER_inc_empty_record_count(&s->rlayer);
+        if (RECORD_LAYER_get_empty_record_count(&s->rlayer)
+            > MAX_EMPTY_RECORDS) {
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_GET_RECORD,
+                     SSL_R_UNEXPECTED_CCS_MESSAGE);
+            return -1;
+        }
+        thisrr->read = 1;
+        RECORD_LAYER_set_numrpipes(&s->rlayer, 1);
+
+        return 1;
+    }
+
+    /*
+     * If in encrypt-then-mac mode calculate mac from encrypted record. All
+     * the details below are public so no timing details can leak.
+     */
+    if (SSL_READ_ETM(s) && s->read_hash) {
+        unsigned char *mac;
+        /* TODO(size_t): convert this to do size_t properly */
+        imac_size = EVP_MD_CTX_size(s->read_hash);
+        if (!ossl_assert(imac_size >= 0 && imac_size <= EVP_MAX_MD_SIZE)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_GET_RECORD,
+                         ERR_LIB_EVP);
+                return -1;
+        }
+        mac_size = (size_t)imac_size;
+        for (j = 0; j < num_recs; j++) {
+            thisrr = &rr[j];
+
+            if (thisrr->length < mac_size) {
+                SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_SSL3_GET_RECORD,
+                         SSL_R_LENGTH_TOO_SHORT);
+                return -1;
+            }
+            thisrr->length -= mac_size;
+            mac = thisrr->data + thisrr->length;
+            i = s->method->ssl3_enc->mac(s, thisrr, md, 0 /* not send */ );
+            if (i == 0 || CRYPTO_memcmp(md, mac, mac_size) != 0) {
+                SSLfatal(s, SSL_AD_BAD_RECORD_MAC, SSL_F_SSL3_GET_RECORD,
+                       SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+                return -1;
+            }
+        }
+    }
+
+    first_rec_len = rr[0].length;
+
+    enc_err = s->method->ssl3_enc->enc(s, rr, num_recs, 0);
+
+    /*-
+     * enc_err is:
+     *    0: (in non-constant time) if the record is publicly invalid.
+     *    1: if the padding is valid
+     *    -1: if the padding is invalid
+     */
+    if (enc_err == 0) {
+        if (ossl_statem_in_error(s)) {
+            /* SSLfatal() already got called */
+            return -1;
+        }
+        if (num_recs == 1 && ossl_statem_skip_early_data(s)) {
+            /*
+             * Valid early_data that we cannot decrypt might fail here as
+             * publicly invalid. We treat it like an empty record.
+             */
+
+            thisrr = &rr[0];
+
+            if (!early_data_count_ok(s, thisrr->length,
+                                     EARLY_DATA_CIPHERTEXT_OVERHEAD, 0)) {
+                /* SSLfatal() already called */
+                return -1;
+            }
+
+            thisrr->length = 0;
+            thisrr->read = 1;
+            RECORD_LAYER_set_numrpipes(&s->rlayer, 1);
+            RECORD_LAYER_reset_read_sequence(&s->rlayer);
+            return 1;
+        }
+        SSLfatal(s, SSL_AD_BAD_RECORD_MAC, SSL_F_SSL3_GET_RECORD,
+                 SSL_R_BLOCK_CIPHER_PAD_IS_WRONG);
+        return -1;
+    }
+#ifdef SSL_DEBUG
+    printf("dec %lu\n", (unsigned long)rr[0].length);
+    {
+        size_t z;
+        for (z = 0; z < rr[0].length; z++)
+            printf("%02X%c", rr[0].data[z], ((z + 1) % 16) ? ' ' : '\n');
+    }
+    printf("\n");
+#endif
+
+    /* r->length is now the compressed data plus mac */
+    if ((sess != NULL) &&
+        (s->enc_read_ctx != NULL) &&
+        (!SSL_READ_ETM(s) && EVP_MD_CTX_md(s->read_hash) != NULL)) {
+        /* s->read_hash != NULL => mac_size != -1 */
+        unsigned char *mac = NULL;
+        unsigned char mac_tmp[EVP_MAX_MD_SIZE];
+
+        mac_size = EVP_MD_CTX_size(s->read_hash);
+        if (!ossl_assert(mac_size <= EVP_MAX_MD_SIZE)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_GET_RECORD,
+                     ERR_R_INTERNAL_ERROR);
+            return -1;
+        }
+
+        for (j = 0; j < num_recs; j++) {
+            thisrr = &rr[j];
+            /*
+             * orig_len is the length of the record before any padding was
+             * removed. This is public information, as is the MAC in use,
+             * therefore we can safely process the record in a different amount
+             * of time if it's too short to possibly contain a MAC.
+             */
+            if (thisrr->orig_len < mac_size ||
+                /* CBC records must have a padding length byte too. */
+                (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+                 thisrr->orig_len < mac_size + 1)) {
+                SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_SSL3_GET_RECORD,
+                         SSL_R_LENGTH_TOO_SHORT);
+                return -1;
+            }
+
+            if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE) {
+                /*
+                 * We update the length so that the TLS header bytes can be
+                 * constructed correctly but we need to extract the MAC in
+                 * constant time from within the record, without leaking the
+                 * contents of the padding bytes.
+                 */
+                mac = mac_tmp;
+                if (!ssl3_cbc_copy_mac(mac_tmp, thisrr, mac_size)) {
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_GET_RECORD,
+                             ERR_R_INTERNAL_ERROR);
+                    return -1;
+                }
+                thisrr->length -= mac_size;
+            } else {
+                /*
+                 * In this case there's no padding, so |rec->orig_len| equals
+                 * |rec->length| and we checked that there's enough bytes for
+                 * |mac_size| above.
+                 */
+                thisrr->length -= mac_size;
+                mac = &thisrr->data[thisrr->length];
+            }
+
+            i = s->method->ssl3_enc->mac(s, thisrr, md, 0 /* not send */ );
+            if (i == 0 || mac == NULL
+                || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
+                enc_err = -1;
+            if (thisrr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size)
+                enc_err = -1;
+        }
+    }
+
+    if (enc_err < 0) {
+        if (ossl_statem_in_error(s)) {
+            /* We already called SSLfatal() */
+            return -1;
+        }
+        if (num_recs == 1 && ossl_statem_skip_early_data(s)) {
+            /*
+             * We assume this is unreadable early_data - we treat it like an
+             * empty record
+             */
+
+            /*
+             * The record length may have been modified by the mac check above
+             * so we use the previously saved value
+             */
+            if (!early_data_count_ok(s, first_rec_len,
+                                     EARLY_DATA_CIPHERTEXT_OVERHEAD, 0)) {
+                /* SSLfatal() already called */
+                return -1;
+            }
+
+            thisrr = &rr[0];
+            thisrr->length = 0;
+            thisrr->read = 1;
+            RECORD_LAYER_set_numrpipes(&s->rlayer, 1);
+            RECORD_LAYER_reset_read_sequence(&s->rlayer);
+            return 1;
+        }
+        /*
+         * A separate 'decryption_failed' alert was introduced with TLS 1.0,
+         * SSL 3.0 only has 'bad_record_mac'.  But unless a decryption
+         * failure is directly visible from the ciphertext anyway, we should
+         * not reveal which kind of error occurred -- this might become
+         * visible to an attacker (e.g. via a logfile)
+         */
+        SSLfatal(s, SSL_AD_BAD_RECORD_MAC, SSL_F_SSL3_GET_RECORD,
+                 SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+        return -1;
+    }
+
+    for (j = 0; j < num_recs; j++) {
+        thisrr = &rr[j];
+
+        /* thisrr->length is now just compressed */
+        if (s->expand != NULL) {
+            if (thisrr->length > SSL3_RT_MAX_COMPRESSED_LENGTH) {
+                SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_F_SSL3_GET_RECORD,
+                         SSL_R_COMPRESSED_LENGTH_TOO_LONG);
+                return -1;
+            }
+            if (!ssl3_do_uncompress(s, thisrr)) {
+                SSLfatal(s, SSL_AD_DECOMPRESSION_FAILURE, SSL_F_SSL3_GET_RECORD,
+                         SSL_R_BAD_DECOMPRESSION);
+                return -1;
+            }
+        }
+
+        if (SSL_IS_TLS13(s)
+                && s->enc_read_ctx != NULL
+                && thisrr->type != SSL3_RT_ALERT) {
+            size_t end;
+
+            if (thisrr->length == 0
+                    || thisrr->type != SSL3_RT_APPLICATION_DATA) {
+                SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_GET_RECORD,
+                         SSL_R_BAD_RECORD_TYPE);
+                return -1;
+            }
+
+            /* Strip trailing padding */
+            for (end = thisrr->length - 1; end > 0 && thisrr->data[end] == 0;
+                 end--)
+                continue;
+
+            thisrr->length = end;
+            thisrr->type = thisrr->data[end];
+            if (thisrr->type != SSL3_RT_APPLICATION_DATA
+                    && thisrr->type != SSL3_RT_ALERT
+                    && thisrr->type != SSL3_RT_HANDSHAKE) {
+                SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_GET_RECORD,
+                         SSL_R_BAD_RECORD_TYPE);
+                return -1;
+            }
+            if (s->msg_callback)
+                s->msg_callback(0, s->version, SSL3_RT_INNER_CONTENT_TYPE,
+                                &thisrr->data[end], 1, s, s->msg_callback_arg);
+        }
+
+        /*
+         * TLSv1.3 alert and handshake records are required to be non-zero in
+         * length.
+         */
+        if (SSL_IS_TLS13(s)
+                && (thisrr->type == SSL3_RT_HANDSHAKE
+                    || thisrr->type == SSL3_RT_ALERT)
+                && thisrr->length == 0) {
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_GET_RECORD,
+                     SSL_R_BAD_LENGTH);
+            return -1;
+        }
+
+        if (thisrr->length > SSL3_RT_MAX_PLAIN_LENGTH) {
+            SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_F_SSL3_GET_RECORD,
+                     SSL_R_DATA_LENGTH_TOO_LONG);
+            return -1;
+        }
+
+        /* If received packet overflows current Max Fragment Length setting */
+        if (s->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)
+                && thisrr->length > GET_MAX_FRAGMENT_LENGTH(s->session)) {
+            SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_F_SSL3_GET_RECORD,
+                     SSL_R_DATA_LENGTH_TOO_LONG);
+            return -1;
+        }
+
+        thisrr->off = 0;
+        /*-
+         * So at this point the following is true
+         * thisrr->type   is the type of record
+         * thisrr->length == number of bytes in record
+         * thisrr->off    == offset to first valid byte
+         * thisrr->data   == where to take bytes from, increment after use :-).
+         */
+
+        /* just read a 0 length packet */
+        if (thisrr->length == 0) {
+            RECORD_LAYER_inc_empty_record_count(&s->rlayer);
+            if (RECORD_LAYER_get_empty_record_count(&s->rlayer)
+                > MAX_EMPTY_RECORDS) {
+                SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_GET_RECORD,
+                         SSL_R_RECORD_TOO_SMALL);
+                return -1;
+            }
+        } else {
+            RECORD_LAYER_reset_empty_record_count(&s->rlayer);
+        }
+    }
+
+    if (s->early_data_state == SSL_EARLY_DATA_READING) {
+        thisrr = &rr[0];
+        if (thisrr->type == SSL3_RT_APPLICATION_DATA
+                && !early_data_count_ok(s, thisrr->length, 0, 0)) {
+            /* SSLfatal already called */
+            return -1;
+        }
+    }
+
+    RECORD_LAYER_set_numrpipes(&s->rlayer, num_recs);
+    return 1;
+}
+
+int ssl3_do_uncompress(SSL *ssl, SSL3_RECORD *rr)
+{
+#ifndef OPENSSL_NO_COMP
+    int i;
+
+    if (rr->comp == NULL) {
+        rr->comp = (unsigned char *)
+            OPENSSL_malloc(SSL3_RT_MAX_ENCRYPTED_LENGTH);
+    }
+    if (rr->comp == NULL)
+        return 0;
+
+    /* TODO(size_t): Convert this call */
+    i = COMP_expand_block(ssl->expand, rr->comp,
+                          SSL3_RT_MAX_PLAIN_LENGTH, rr->data, (int)rr->length);
+    if (i < 0)
+        return 0;
+    else
+        rr->length = i;
+    rr->data = rr->comp;
+#endif
+    return 1;
+}
+
+int ssl3_do_compress(SSL *ssl, SSL3_RECORD *wr)
+{
+#ifndef OPENSSL_NO_COMP
+    int i;
+
+    /* TODO(size_t): Convert this call */
+    i = COMP_compress_block(ssl->compress, wr->data,
+                            (int)(wr->length + SSL3_RT_MAX_COMPRESSED_OVERHEAD),
+                            wr->input, (int)wr->length);
+    if (i < 0)
+        return 0;
+    else
+        wr->length = i;
+
+    wr->input = wr->data;
+#endif
+    return 1;
+}
+
+/*-
+ * ssl3_enc encrypts/decrypts |n_recs| records in |inrecs|.  Will call
+ * SSLfatal() for internal errors, but not otherwise.
+ *
+ * Returns:
+ *   0: (in non-constant time) if the record is publicly invalid (i.e. too
+ *       short etc).
+ *   1: if the record's padding is valid / the encryption was successful.
+ *   -1: if the record's padding is invalid or, if sending, an internal error
+ *       occurred.
+ */
+int ssl3_enc(SSL *s, SSL3_RECORD *inrecs, size_t n_recs, int sending)
+{
+    SSL3_RECORD *rec;
+    EVP_CIPHER_CTX *ds;
+    size_t l, i;
+    size_t bs, mac_size = 0;
+    int imac_size;
+    const EVP_CIPHER *enc;
+
+    rec = inrecs;
+    /*
+     * We shouldn't ever be called with more than one record in the SSLv3 case
+     */
+    if (n_recs != 1)
+        return 0;
+    if (sending) {
+        ds = s->enc_write_ctx;
+        if (s->enc_write_ctx == NULL)
+            enc = NULL;
+        else
+            enc = EVP_CIPHER_CTX_cipher(s->enc_write_ctx);
+    } else {
+        ds = s->enc_read_ctx;
+        if (s->enc_read_ctx == NULL)
+            enc = NULL;
+        else
+            enc = EVP_CIPHER_CTX_cipher(s->enc_read_ctx);
+    }
+
+    if ((s->session == NULL) || (ds == NULL) || (enc == NULL)) {
+        memmove(rec->data, rec->input, rec->length);
+        rec->input = rec->data;
+    } else {
+        l = rec->length;
+        /* TODO(size_t): Convert this call */
+        bs = EVP_CIPHER_CTX_block_size(ds);
+
+        /* COMPRESS */
+
+        if ((bs != 1) && sending) {
+            i = bs - (l % bs);
+
+            /* we need to add 'i-1' padding bytes */
+            l += i;
+            /*
+             * the last of these zero bytes will be overwritten with the
+             * padding length.
+             */
+            memset(&rec->input[rec->length], 0, i);
+            rec->length += i;
+            rec->input[l - 1] = (unsigned char)(i - 1);
+        }
+
+        if (!sending) {
+            if (l == 0 || l % bs != 0)
+                return 0;
+            /* otherwise, rec->length >= bs */
+        }
+
+        /* TODO(size_t): Convert this call */
+        if (EVP_Cipher(ds, rec->data, rec->input, (unsigned int)l) < 1)
+            return -1;
+
+        if (EVP_MD_CTX_md(s->read_hash) != NULL) {
+            /* TODO(size_t): convert me */
+            imac_size = EVP_MD_CTX_size(s->read_hash);
+            if (imac_size < 0) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_ENC,
+                         ERR_R_INTERNAL_ERROR);
+                return -1;
+            }
+            mac_size = (size_t)imac_size;
+        }
+        if ((bs != 1) && !sending)
+            return ssl3_cbc_remove_padding(rec, bs, mac_size);
+    }
+    return 1;
+}
+
+#define MAX_PADDING 256
+/*-
+ * tls1_enc encrypts/decrypts |n_recs| in |recs|.  Will call SSLfatal() for
+ * internal errors, but not otherwise.
+ *
+ * Returns:
+ *   0: (in non-constant time) if the record is publicly invalid (i.e. too
+ *       short etc).
+ *   1: if the record's padding is valid / the encryption was successful.
+ *   -1: if the record's padding/AEAD-authenticator is invalid or, if sending,
+ *       an internal error occurred.
+ */
+int tls1_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int sending)
+{
+    EVP_CIPHER_CTX *ds;
+    size_t reclen[SSL_MAX_PIPELINES];
+    unsigned char buf[SSL_MAX_PIPELINES][EVP_AEAD_TLS1_AAD_LEN];
+    int i, pad = 0, ret, tmpr;
+    size_t bs, mac_size = 0, ctr, padnum, loop;
+    unsigned char padval;
+    int imac_size;
+    const EVP_CIPHER *enc;
+
+    if (n_recs == 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (sending) {
+        if (EVP_MD_CTX_md(s->write_hash)) {
+            int n = EVP_MD_CTX_size(s->write_hash);
+            if (!ossl_assert(n >= 0)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+                         ERR_R_INTERNAL_ERROR);
+                return -1;
+            }
+        }
+        ds = s->enc_write_ctx;
+        if (s->enc_write_ctx == NULL)
+            enc = NULL;
+        else {
+            int ivlen;
+            enc = EVP_CIPHER_CTX_cipher(s->enc_write_ctx);
+            /* For TLSv1.1 and later explicit IV */
+            if (SSL_USE_EXPLICIT_IV(s)
+                && EVP_CIPHER_mode(enc) == EVP_CIPH_CBC_MODE)
+                ivlen = EVP_CIPHER_iv_length(enc);
+            else
+                ivlen = 0;
+            if (ivlen > 1) {
+                for (ctr = 0; ctr < n_recs; ctr++) {
+                    if (recs[ctr].data != recs[ctr].input) {
+                        /*
+                         * we can't write into the input stream: Can this ever
+                         * happen?? (steve)
+                         */
+                        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+                                 ERR_R_INTERNAL_ERROR);
+                        return -1;
+                    } else if (RAND_bytes(recs[ctr].input, ivlen) <= 0) {
+                        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+                                 ERR_R_INTERNAL_ERROR);
+                        return -1;
+                    }
+                }
+            }
+        }
+    } else {
+        if (EVP_MD_CTX_md(s->read_hash)) {
+            int n = EVP_MD_CTX_size(s->read_hash);
+            if (!ossl_assert(n >= 0)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+                         ERR_R_INTERNAL_ERROR);
+                return -1;
+            }
+        }
+        ds = s->enc_read_ctx;
+        if (s->enc_read_ctx == NULL)
+            enc = NULL;
+        else
+            enc = EVP_CIPHER_CTX_cipher(s->enc_read_ctx);
+    }
+
+    if ((s->session == NULL) || (ds == NULL) || (enc == NULL)) {
+        for (ctr = 0; ctr < n_recs; ctr++) {
+            memmove(recs[ctr].data, recs[ctr].input, recs[ctr].length);
+            recs[ctr].input = recs[ctr].data;
+        }
+        ret = 1;
+    } else {
+        bs = EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(ds));
+
+        if (n_recs > 1) {
+            if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ds))
+                  & EVP_CIPH_FLAG_PIPELINE)) {
+                /*
+                 * We shouldn't have been called with pipeline data if the
+                 * cipher doesn't support pipelining
+                 */
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+                         SSL_R_PIPELINE_FAILURE);
+                return -1;
+            }
+        }
+        for (ctr = 0; ctr < n_recs; ctr++) {
+            reclen[ctr] = recs[ctr].length;
+
+            if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ds))
+                & EVP_CIPH_FLAG_AEAD_CIPHER) {
+                unsigned char *seq;
+
+                seq = sending ? RECORD_LAYER_get_write_sequence(&s->rlayer)
+                    : RECORD_LAYER_get_read_sequence(&s->rlayer);
+
+                if (SSL_IS_DTLS(s)) {
+                    /* DTLS does not support pipelining */
+                    unsigned char dtlsseq[8], *p = dtlsseq;
+
+                    s2n(sending ? DTLS_RECORD_LAYER_get_w_epoch(&s->rlayer) :
+                        DTLS_RECORD_LAYER_get_r_epoch(&s->rlayer), p);
+                    memcpy(p, &seq[2], 6);
+                    memcpy(buf[ctr], dtlsseq, 8);
+                } else {
+                    memcpy(buf[ctr], seq, 8);
+                    for (i = 7; i >= 0; i--) { /* increment */
+                        ++seq[i];
+                        if (seq[i] != 0)
+                            break;
+                    }
+                }
+
+                buf[ctr][8] = recs[ctr].type;
+                buf[ctr][9] = (unsigned char)(s->version >> 8);
+                buf[ctr][10] = (unsigned char)(s->version);
+                buf[ctr][11] = (unsigned char)(recs[ctr].length >> 8);
+                buf[ctr][12] = (unsigned char)(recs[ctr].length & 0xff);
+                pad = EVP_CIPHER_CTX_ctrl(ds, EVP_CTRL_AEAD_TLS1_AAD,
+                                          EVP_AEAD_TLS1_AAD_LEN, buf[ctr]);
+                if (pad <= 0) {
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+                             ERR_R_INTERNAL_ERROR);
+                    return -1;
+                }
+
+                if (sending) {
+                    reclen[ctr] += pad;
+                    recs[ctr].length += pad;
+                }
+
+            } else if ((bs != 1) && sending) {
+                padnum = bs - (reclen[ctr] % bs);
+
+                /* Add weird padding of up to 256 bytes */
+
+                if (padnum > MAX_PADDING) {
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+                             ERR_R_INTERNAL_ERROR);
+                    return -1;
+                }
+                /* we need to add 'padnum' padding bytes of value padval */
+                padval = (unsigned char)(padnum - 1);
+                for (loop = reclen[ctr]; loop < reclen[ctr] + padnum; loop++)
+                    recs[ctr].input[loop] = padval;
+                reclen[ctr] += padnum;
+                recs[ctr].length += padnum;
+            }
+
+            if (!sending) {
+                if (reclen[ctr] == 0 || reclen[ctr] % bs != 0)
+                    return 0;
+            }
+        }
+        if (n_recs > 1) {
+            unsigned char *data[SSL_MAX_PIPELINES];
+
+            /* Set the output buffers */
+            for (ctr = 0; ctr < n_recs; ctr++) {
+                data[ctr] = recs[ctr].data;
+            }
+            if (EVP_CIPHER_CTX_ctrl(ds, EVP_CTRL_SET_PIPELINE_OUTPUT_BUFS,
+                                    (int)n_recs, data) <= 0) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+                         SSL_R_PIPELINE_FAILURE);
+                return -1;
+            }
+            /* Set the input buffers */
+            for (ctr = 0; ctr < n_recs; ctr++) {
+                data[ctr] = recs[ctr].input;
+            }
+            if (EVP_CIPHER_CTX_ctrl(ds, EVP_CTRL_SET_PIPELINE_INPUT_BUFS,
+                                    (int)n_recs, data) <= 0
+                || EVP_CIPHER_CTX_ctrl(ds, EVP_CTRL_SET_PIPELINE_INPUT_LENS,
+                                       (int)n_recs, reclen) <= 0) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+                         SSL_R_PIPELINE_FAILURE);
+                return -1;
+            }
+        }
+
+        /* TODO(size_t): Convert this call */
+        tmpr = EVP_Cipher(ds, recs[0].data, recs[0].input,
+                          (unsigned int)reclen[0]);
+        if ((EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ds))
+             & EVP_CIPH_FLAG_CUSTOM_CIPHER)
+            ? (tmpr < 0)
+            : (tmpr == 0))
+            return -1;          /* AEAD can fail to verify MAC */
+
+        if (sending == 0) {
+            if (EVP_CIPHER_mode(enc) == EVP_CIPH_GCM_MODE) {
+                for (ctr = 0; ctr < n_recs; ctr++) {
+                    recs[ctr].data += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+                    recs[ctr].input += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+                    recs[ctr].length -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
+                }
+            } else if (EVP_CIPHER_mode(enc) == EVP_CIPH_CCM_MODE) {
+                for (ctr = 0; ctr < n_recs; ctr++) {
+                    recs[ctr].data += EVP_CCM_TLS_EXPLICIT_IV_LEN;
+                    recs[ctr].input += EVP_CCM_TLS_EXPLICIT_IV_LEN;
+                    recs[ctr].length -= EVP_CCM_TLS_EXPLICIT_IV_LEN;
+                }
+            }
+        }
+
+        ret = 1;
+        if (!SSL_READ_ETM(s) && EVP_MD_CTX_md(s->read_hash) != NULL) {
+            imac_size = EVP_MD_CTX_size(s->read_hash);
+            if (imac_size < 0) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+                         ERR_R_INTERNAL_ERROR);
+                return -1;
+            }
+            mac_size = (size_t)imac_size;
+        }
+        if ((bs != 1) && !sending) {
+            int tmpret;
+            for (ctr = 0; ctr < n_recs; ctr++) {
+                tmpret = tls1_cbc_remove_padding(s, &recs[ctr], bs, mac_size);
+                /*
+                 * If tmpret == 0 then this means publicly invalid so we can
+                 * short circuit things here. Otherwise we must respect constant
+                 * time behaviour.
+                 */
+                if (tmpret == 0)
+                    return 0;
+                ret = constant_time_select_int(constant_time_eq_int(tmpret, 1),
+                                               ret, -1);
+            }
+        }
+        if (pad && !sending) {
+            for (ctr = 0; ctr < n_recs; ctr++) {
+                recs[ctr].length -= pad;
+            }
+        }
+    }
+    return ret;
+}
+
+int n_ssl3_mac(SSL *ssl, SSL3_RECORD *rec, unsigned char *md, int sending)
+{
+    unsigned char *mac_sec, *seq;
+    const EVP_MD_CTX *hash;
+    unsigned char *p, rec_char;
+    size_t md_size;
+    size_t npad;
+    int t;
+
+    if (sending) {
+        mac_sec = &(ssl->s3->write_mac_secret[0]);
+        seq = RECORD_LAYER_get_write_sequence(&ssl->rlayer);
+        hash = ssl->write_hash;
+    } else {
+        mac_sec = &(ssl->s3->read_mac_secret[0]);
+        seq = RECORD_LAYER_get_read_sequence(&ssl->rlayer);
+        hash = ssl->read_hash;
+    }
+
+    t = EVP_MD_CTX_size(hash);
+    if (t < 0)
+        return 0;
+    md_size = t;
+    npad = (48 / md_size) * md_size;
+
+    if (!sending &&
+        EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+        ssl3_cbc_record_digest_supported(hash)) {
+        /*
+         * This is a CBC-encrypted record. We must avoid leaking any
+         * timing-side channel information about how many blocks of data we
+         * are hashing because that gives an attacker a timing-oracle.
+         */
+
+        /*-
+         * npad is, at most, 48 bytes and that's with MD5:
+         *   16 + 48 + 8 (sequence bytes) + 1 + 2 = 75.
+         *
+         * With SHA-1 (the largest hash speced for SSLv3) the hash size
+         * goes up 4, but npad goes down by 8, resulting in a smaller
+         * total size.
+         */
+        unsigned char header[75];
+        size_t j = 0;
+        memcpy(header + j, mac_sec, md_size);
+        j += md_size;
+        memcpy(header + j, ssl3_pad_1, npad);
+        j += npad;
+        memcpy(header + j, seq, 8);
+        j += 8;
+        header[j++] = rec->type;
+        header[j++] = (unsigned char)(rec->length >> 8);
+        header[j++] = (unsigned char)(rec->length & 0xff);
+
+        /* Final param == is SSLv3 */
+        if (ssl3_cbc_digest_record(hash,
+                                   md, &md_size,
+                                   header, rec->input,
+                                   rec->length + md_size, rec->orig_len,
+                                   mac_sec, md_size, 1) <= 0)
+            return 0;
+    } else {
+        unsigned int md_size_u;
+        /* Chop the digest off the end :-) */
+        EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
+
+        if (md_ctx == NULL)
+            return 0;
+
+        rec_char = rec->type;
+        p = md;
+        s2n(rec->length, p);
+        if (EVP_MD_CTX_copy_ex(md_ctx, hash) <= 0
+            || EVP_DigestUpdate(md_ctx, mac_sec, md_size) <= 0
+            || EVP_DigestUpdate(md_ctx, ssl3_pad_1, npad) <= 0
+            || EVP_DigestUpdate(md_ctx, seq, 8) <= 0
+            || EVP_DigestUpdate(md_ctx, &rec_char, 1) <= 0
+            || EVP_DigestUpdate(md_ctx, md, 2) <= 0
+            || EVP_DigestUpdate(md_ctx, rec->input, rec->length) <= 0
+            || EVP_DigestFinal_ex(md_ctx, md, NULL) <= 0
+            || EVP_MD_CTX_copy_ex(md_ctx, hash) <= 0
+            || EVP_DigestUpdate(md_ctx, mac_sec, md_size) <= 0
+            || EVP_DigestUpdate(md_ctx, ssl3_pad_2, npad) <= 0
+            || EVP_DigestUpdate(md_ctx, md, md_size) <= 0
+            || EVP_DigestFinal_ex(md_ctx, md, &md_size_u) <= 0) {
+            EVP_MD_CTX_free(md_ctx);
+            return 0;
+        }
+
+        EVP_MD_CTX_free(md_ctx);
+    }
+
+    ssl3_record_sequence_update(seq);
+    return 1;
+}
+
+int tls1_mac(SSL *ssl, SSL3_RECORD *rec, unsigned char *md, int sending)
+{
+    unsigned char *seq;
+    EVP_MD_CTX *hash;
+    size_t md_size;
+    int i;
+    EVP_MD_CTX *hmac = NULL, *mac_ctx;
+    unsigned char header[13];
+    int stream_mac = (sending ? (ssl->mac_flags & SSL_MAC_FLAG_WRITE_MAC_STREAM)
+                      : (ssl->mac_flags & SSL_MAC_FLAG_READ_MAC_STREAM));
+    int t;
+
+    if (sending) {
+        seq = RECORD_LAYER_get_write_sequence(&ssl->rlayer);
+        hash = ssl->write_hash;
+    } else {
+        seq = RECORD_LAYER_get_read_sequence(&ssl->rlayer);
+        hash = ssl->read_hash;
+    }
+
+    t = EVP_MD_CTX_size(hash);
+    if (!ossl_assert(t >= 0))
+        return 0;
+    md_size = t;
+
+    /* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */
+    if (stream_mac) {
+        mac_ctx = hash;
+    } else {
+        hmac = EVP_MD_CTX_new();
+        if (hmac == NULL || !EVP_MD_CTX_copy(hmac, hash)) {
+            EVP_MD_CTX_free(hmac);
+            return 0;
+        }
+        mac_ctx = hmac;
+    }
+
+    if (SSL_IS_DTLS(ssl)) {
+        unsigned char dtlsseq[8], *p = dtlsseq;
+
+        s2n(sending ? DTLS_RECORD_LAYER_get_w_epoch(&ssl->rlayer) :
+            DTLS_RECORD_LAYER_get_r_epoch(&ssl->rlayer), p);
+        memcpy(p, &seq[2], 6);
+
+        memcpy(header, dtlsseq, 8);
+    } else
+        memcpy(header, seq, 8);
+
+    header[8] = rec->type;
+    header[9] = (unsigned char)(ssl->version >> 8);
+    header[10] = (unsigned char)(ssl->version);
+    header[11] = (unsigned char)(rec->length >> 8);
+    header[12] = (unsigned char)(rec->length & 0xff);
+
+    if (!sending && !SSL_READ_ETM(ssl) &&
+        EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+        ssl3_cbc_record_digest_supported(mac_ctx)) {
+        /*
+         * This is a CBC-encrypted record. We must avoid leaking any
+         * timing-side channel information about how many blocks of data we
+         * are hashing because that gives an attacker a timing-oracle.
+         */
+        /* Final param == not SSLv3 */
+        if (ssl3_cbc_digest_record(mac_ctx,
+                                   md, &md_size,
+                                   header, rec->input,
+                                   rec->length + md_size, rec->orig_len,
+                                   ssl->s3->read_mac_secret,
+                                   ssl->s3->read_mac_secret_size, 0) <= 0) {
+            EVP_MD_CTX_free(hmac);
+            return 0;
+        }
+    } else {
+        /* TODO(size_t): Convert these calls */
+        if (EVP_DigestSignUpdate(mac_ctx, header, sizeof(header)) <= 0
+            || EVP_DigestSignUpdate(mac_ctx, rec->input, rec->length) <= 0
+            || EVP_DigestSignFinal(mac_ctx, md, &md_size) <= 0) {
+            EVP_MD_CTX_free(hmac);
+            return 0;
+        }
+    }
+
+    EVP_MD_CTX_free(hmac);
+
+#ifdef SSL_DEBUG
+    fprintf(stderr, "seq=");
+    {
+        int z;
+        for (z = 0; z < 8; z++)
+            fprintf(stderr, "%02X ", seq[z]);
+        fprintf(stderr, "\n");
+    }
+    fprintf(stderr, "rec=");
+    {
+        size_t z;
+        for (z = 0; z < rec->length; z++)
+            fprintf(stderr, "%02X ", rec->data[z]);
+        fprintf(stderr, "\n");
+    }
+#endif
+
+    if (!SSL_IS_DTLS(ssl)) {
+        for (i = 7; i >= 0; i--) {
+            ++seq[i];
+            if (seq[i] != 0)
+                break;
+        }
+    }
+#ifdef SSL_DEBUG
+    {
+        unsigned int z;
+        for (z = 0; z < md_size; z++)
+            fprintf(stderr, "%02X ", md[z]);
+        fprintf(stderr, "\n");
+    }
+#endif
+    return 1;
+}
+
+/*-
+ * ssl3_cbc_remove_padding removes padding from the decrypted, SSLv3, CBC
+ * record in |rec| by updating |rec->length| in constant time.
+ *
+ * block_size: the block size of the cipher used to encrypt the record.
+ * returns:
+ *   0: (in non-constant time) if the record is publicly invalid.
+ *   1: if the padding was valid
+ *  -1: otherwise.
+ */
+int ssl3_cbc_remove_padding(SSL3_RECORD *rec,
+                            size_t block_size, size_t mac_size)
+{
+    size_t padding_length;
+    size_t good;
+    const size_t overhead = 1 /* padding length byte */  + mac_size;
+
+    /*
+     * These lengths are all public so we can test them in non-constant time.
+     */
+    if (overhead > rec->length)
+        return 0;
+
+    padding_length = rec->data[rec->length - 1];
+    good = constant_time_ge_s(rec->length, padding_length + overhead);
+    /* SSLv3 requires that the padding is minimal. */
+    good &= constant_time_ge_s(block_size, padding_length + 1);
+    rec->length -= good & (padding_length + 1);
+    return constant_time_select_int_s(good, 1, -1);
+}
+
+/*-
+ * tls1_cbc_remove_padding removes the CBC padding from the decrypted, TLS, CBC
+ * record in |rec| in constant time and returns 1 if the padding is valid and
+ * -1 otherwise. It also removes any explicit IV from the start of the record
+ * without leaking any timing about whether there was enough space after the
+ * padding was removed.
+ *
+ * block_size: the block size of the cipher used to encrypt the record.
+ * returns:
+ *   0: (in non-constant time) if the record is publicly invalid.
+ *   1: if the padding was valid
+ *  -1: otherwise.
+ */
+int tls1_cbc_remove_padding(const SSL *s,
+                            SSL3_RECORD *rec,
+                            size_t block_size, size_t mac_size)
+{
+    size_t good;
+    size_t padding_length, to_check, i;
+    const size_t overhead = 1 /* padding length byte */  + mac_size;
+    /* Check if version requires explicit IV */
+    if (SSL_USE_EXPLICIT_IV(s)) {
+        /*
+         * These lengths are all public so we can test them in non-constant
+         * time.
+         */
+        if (overhead + block_size > rec->length)
+            return 0;
+        /* We can now safely skip explicit IV */
+        rec->data += block_size;
+        rec->input += block_size;
+        rec->length -= block_size;
+        rec->orig_len -= block_size;
+    } else if (overhead > rec->length)
+        return 0;
+
+    padding_length = rec->data[rec->length - 1];
+
+    if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_read_ctx)) &
+        EVP_CIPH_FLAG_AEAD_CIPHER) {
+        /* padding is already verified */
+        rec->length -= padding_length + 1;
+        return 1;
+    }
+
+    good = constant_time_ge_s(rec->length, overhead + padding_length);
+    /*
+     * The padding consists of a length byte at the end of the record and
+     * then that many bytes of padding, all with the same value as the length
+     * byte. Thus, with the length byte included, there are i+1 bytes of
+     * padding. We can't check just |padding_length+1| bytes because that
+     * leaks decrypted information. Therefore we always have to check the
+     * maximum amount of padding possible. (Again, the length of the record
+     * is public information so we can use it.)
+     */
+    to_check = 256;            /* maximum amount of padding, inc length byte. */
+    if (to_check > rec->length)
+        to_check = rec->length;
+
+    for (i = 0; i < to_check; i++) {
+        unsigned char mask = constant_time_ge_8_s(padding_length, i);
+        unsigned char b = rec->data[rec->length - 1 - i];
+        /*
+         * The final |padding_length+1| bytes should all have the value
+         * |padding_length|. Therefore the XOR should be zero.
+         */
+        good &= ~(mask & (padding_length ^ b));
+    }
+
+    /*
+     * If any of the final |padding_length+1| bytes had the wrong value, one
+     * or more of the lower eight bits of |good| will be cleared.
+     */
+    good = constant_time_eq_s(0xff, good & 0xff);
+    rec->length -= good & (padding_length + 1);
+
+    return constant_time_select_int_s(good, 1, -1);
+}
+
+/*-
+ * ssl3_cbc_copy_mac copies |md_size| bytes from the end of |rec| to |out| in
+ * constant time (independent of the concrete value of rec->length, which may
+ * vary within a 256-byte window).
+ *
+ * ssl3_cbc_remove_padding or tls1_cbc_remove_padding must be called prior to
+ * this function.
+ *
+ * On entry:
+ *   rec->orig_len >= md_size
+ *   md_size <= EVP_MAX_MD_SIZE
+ *
+ * If CBC_MAC_ROTATE_IN_PLACE is defined then the rotation is performed with
+ * variable accesses in a 64-byte-aligned buffer. Assuming that this fits into
+ * a single or pair of cache-lines, then the variable memory accesses don't
+ * actually affect the timing. CPUs with smaller cache-lines [if any] are
+ * not multi-core and are not considered vulnerable to cache-timing attacks.
+ */
+#define CBC_MAC_ROTATE_IN_PLACE
+
+int ssl3_cbc_copy_mac(unsigned char *out,
+                       const SSL3_RECORD *rec, size_t md_size)
+{
+#if defined(CBC_MAC_ROTATE_IN_PLACE)
+    unsigned char rotated_mac_buf[64 + EVP_MAX_MD_SIZE];
+    unsigned char *rotated_mac;
+    char aux1, aux2, aux3, mask;
+#else
+    unsigned char rotated_mac[EVP_MAX_MD_SIZE];
+#endif
+
+    /*
+     * mac_end is the index of |rec->data| just after the end of the MAC.
+     */
+    size_t mac_end = rec->length;
+    size_t mac_start = mac_end - md_size;
+    size_t in_mac;
+    /*
+     * scan_start contains the number of bytes that we can ignore because the
+     * MAC's position can only vary by 255 bytes.
+     */
+    size_t scan_start = 0;
+    size_t i, j;
+    size_t rotate_offset;
+
+    if (!ossl_assert(rec->orig_len >= md_size
+                     && md_size <= EVP_MAX_MD_SIZE))
+        return 0;
+
+#if defined(CBC_MAC_ROTATE_IN_PLACE)
+    rotated_mac = rotated_mac_buf + ((0 - (size_t)rotated_mac_buf) & 63);
+#endif
+
+    /* This information is public so it's safe to branch based on it. */
+    if (rec->orig_len > md_size + 255 + 1)
+        scan_start = rec->orig_len - (md_size + 255 + 1);
+
+    in_mac = 0;
+    rotate_offset = 0;
+    memset(rotated_mac, 0, md_size);
+    for (i = scan_start, j = 0; i < rec->orig_len; i++) {
+        size_t mac_started = constant_time_eq_s(i, mac_start);
+        size_t mac_ended = constant_time_lt_s(i, mac_end);
+        unsigned char b = rec->data[i];
+
+        in_mac |= mac_started;
+        in_mac &= mac_ended;
+        rotate_offset |= j & mac_started;
+        rotated_mac[j++] |= b & in_mac;
+        j &= constant_time_lt_s(j, md_size);
+    }
+
+    /* Now rotate the MAC */
+#if defined(CBC_MAC_ROTATE_IN_PLACE)
+    j = 0;
+    for (i = 0; i < md_size; i++) {
+        /*
+         * in case cache-line is 32 bytes,
+         * load from both lines and select appropriately
+         */
+        aux1 = rotated_mac[rotate_offset & ~32];
+        aux2 = rotated_mac[rotate_offset | 32];
+        mask = constant_time_eq_8(rotate_offset & ~32, rotate_offset);
+        aux3 = constant_time_select_8(mask, aux1, aux2);
+        out[j++] = aux3;
+        rotate_offset++;
+        rotate_offset &= constant_time_lt_s(rotate_offset, md_size);
+    }
+#else
+    memset(out, 0, md_size);
+    rotate_offset = md_size - rotate_offset;
+    rotate_offset &= constant_time_lt_s(rotate_offset, md_size);
+    for (i = 0; i < md_size; i++) {
+        for (j = 0; j < md_size; j++)
+            out[j] |= rotated_mac[i] & constant_time_eq_8_s(j, rotate_offset);
+        rotate_offset++;
+        rotate_offset &= constant_time_lt_s(rotate_offset, md_size);
+    }
+#endif
+
+    return 1;
+}
+
+int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap)
+{
+    int i;
+    int enc_err;
+    SSL_SESSION *sess;
+    SSL3_RECORD *rr;
+    int imac_size;
+    size_t mac_size;
+    unsigned char md[EVP_MAX_MD_SIZE];
+    size_t max_plain_length = SSL3_RT_MAX_PLAIN_LENGTH;
+
+    rr = RECORD_LAYER_get_rrec(&s->rlayer);
+    sess = s->session;
+
+    /*
+     * At this point, s->rlayer.packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
+     * and we have that many bytes in s->rlayer.packet
+     */
+    rr->input = &(RECORD_LAYER_get_packet(&s->rlayer)[DTLS1_RT_HEADER_LENGTH]);
+
+    /*
+     * ok, we can now read from 's->rlayer.packet' data into 'rr'. rr->input
+     * points at rr->length bytes, which need to be copied into rr->data by
+     * either the decryption or by the decompression. When the data is 'copied'
+     * into the rr->data buffer, rr->input will be pointed at the new buffer
+     */
+
+    /*
+     * We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length
+     * bytes of encrypted compressed stuff.
+     */
+
+    /* check is not needed I believe */
+    if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
+        SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_F_DTLS1_PROCESS_RECORD,
+                 SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+        return 0;
+    }
+
+    /* decrypt in place in 'rr->input' */
+    rr->data = rr->input;
+    rr->orig_len = rr->length;
+
+    if (SSL_READ_ETM(s) && s->read_hash) {
+        unsigned char *mac;
+        mac_size = EVP_MD_CTX_size(s->read_hash);
+        if (!ossl_assert(mac_size <= EVP_MAX_MD_SIZE)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS1_PROCESS_RECORD,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        if (rr->orig_len < mac_size) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_DTLS1_PROCESS_RECORD,
+                     SSL_R_LENGTH_TOO_SHORT);
+            return 0;
+        }
+        rr->length -= mac_size;
+        mac = rr->data + rr->length;
+        i = s->method->ssl3_enc->mac(s, rr, md, 0 /* not send */ );
+        if (i == 0 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) {
+            SSLfatal(s, SSL_AD_BAD_RECORD_MAC, SSL_F_DTLS1_PROCESS_RECORD,
+                   SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+            return 0;
+        }
+    }
+
+    enc_err = s->method->ssl3_enc->enc(s, rr, 1, 0);
+    /*-
+     * enc_err is:
+     *    0: (in non-constant time) if the record is publicly invalid.
+     *    1: if the padding is valid
+     *   -1: if the padding is invalid
+     */
+    if (enc_err == 0) {
+        if (ossl_statem_in_error(s)) {
+            /* SSLfatal() got called */
+            return 0;
+        }
+        /* For DTLS we simply ignore bad packets. */
+        rr->length = 0;
+        RECORD_LAYER_reset_packet_length(&s->rlayer);
+        return 0;
+    }
+#ifdef SSL_DEBUG
+    printf("dec %ld\n", rr->length);
+    {
+        size_t z;
+        for (z = 0; z < rr->length; z++)
+            printf("%02X%c", rr->data[z], ((z + 1) % 16) ? ' ' : '\n');
+    }
+    printf("\n");
+#endif
+
+    /* r->length is now the compressed data plus mac */
+    if ((sess != NULL) && !SSL_READ_ETM(s) &&
+        (s->enc_read_ctx != NULL) && (EVP_MD_CTX_md(s->read_hash) != NULL)) {
+        /* s->read_hash != NULL => mac_size != -1 */
+        unsigned char *mac = NULL;
+        unsigned char mac_tmp[EVP_MAX_MD_SIZE];
+
+        /* TODO(size_t): Convert this to do size_t properly */
+        imac_size = EVP_MD_CTX_size(s->read_hash);
+        if (imac_size < 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS1_PROCESS_RECORD,
+                     ERR_LIB_EVP);
+            return 0;
+        }
+        mac_size = (size_t)imac_size;
+        if (!ossl_assert(mac_size <= EVP_MAX_MD_SIZE)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS1_PROCESS_RECORD,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+
+        /*
+         * orig_len is the length of the record before any padding was
+         * removed. This is public information, as is the MAC in use,
+         * therefore we can safely process the record in a different amount
+         * of time if it's too short to possibly contain a MAC.
+         */
+        if (rr->orig_len < mac_size ||
+            /* CBC records must have a padding length byte too. */
+            (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+             rr->orig_len < mac_size + 1)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_DTLS1_PROCESS_RECORD,
+                     SSL_R_LENGTH_TOO_SHORT);
+            return 0;
+        }
+
+        if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE) {
+            /*
+             * We update the length so that the TLS header bytes can be
+             * constructed correctly but we need to extract the MAC in
+             * constant time from within the record, without leaking the
+             * contents of the padding bytes.
+             */
+            mac = mac_tmp;
+            if (!ssl3_cbc_copy_mac(mac_tmp, rr, mac_size)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS1_PROCESS_RECORD,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+            rr->length -= mac_size;
+        } else {
+            /*
+             * In this case there's no padding, so |rec->orig_len| equals
+             * |rec->length| and we checked that there's enough bytes for
+             * |mac_size| above.
+             */
+            rr->length -= mac_size;
+            mac = &rr->data[rr->length];
+        }
+
+        i = s->method->ssl3_enc->mac(s, rr, md, 0 /* not send */ );
+        if (i == 0 || mac == NULL
+            || CRYPTO_memcmp(md, mac, mac_size) != 0)
+            enc_err = -1;
+        if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size)
+            enc_err = -1;
+    }
+
+    if (enc_err < 0) {
+        /* decryption failed, silently discard message */
+        rr->length = 0;
+        RECORD_LAYER_reset_packet_length(&s->rlayer);
+        return 0;
+    }
+
+    /* r->length is now just compressed */
+    if (s->expand != NULL) {
+        if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH) {
+            SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_F_DTLS1_PROCESS_RECORD,
+                     SSL_R_COMPRESSED_LENGTH_TOO_LONG);
+            return 0;
+        }
+        if (!ssl3_do_uncompress(s, rr)) {
+            SSLfatal(s, SSL_AD_DECOMPRESSION_FAILURE,
+                     SSL_F_DTLS1_PROCESS_RECORD, SSL_R_BAD_DECOMPRESSION);
+            return 0;
+        }
+    }
+
+    /* use current Max Fragment Length setting if applicable */
+    if (s->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(s->session))
+        max_plain_length = GET_MAX_FRAGMENT_LENGTH(s->session);
+
+    /* send overflow if the plaintext is too long now it has passed MAC */
+    if (rr->length > max_plain_length) {
+        SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_F_DTLS1_PROCESS_RECORD,
+                 SSL_R_DATA_LENGTH_TOO_LONG);
+        return 0;
+    }
+
+    rr->off = 0;
+    /*-
+     * So at this point the following is true
+     * ssl->s3->rrec.type   is the type of record
+     * ssl->s3->rrec.length == number of bytes in record
+     * ssl->s3->rrec.off    == offset to first valid byte
+     * ssl->s3->rrec.data   == where to take bytes from, increment
+     *                         after use :-).
+     */
+
+    /* we have pulled in a full packet so zero things */
+    RECORD_LAYER_reset_packet_length(&s->rlayer);
+
+    /* Mark receipt of record. */
+    dtls1_record_bitmap_update(s, bitmap);
+
+    return 1;
+}
+
+/*
+ * Retrieve a buffered record that belongs to the current epoch, i.e. processed
+ */
+#define dtls1_get_processed_record(s) \
+                   dtls1_retrieve_buffered_record((s), \
+                   &(DTLS_RECORD_LAYER_get_processed_rcds(&s->rlayer)))
+
+/*-
+ * Call this to get a new input record.
+ * It will return <= 0 if more data is needed, normally due to an error
+ * or non-blocking IO.
+ * When it finishes, one packet has been decoded and can be found in
+ * ssl->s3->rrec.type    - is the type of record
+ * ssl->s3->rrec.data,   - data
+ * ssl->s3->rrec.length, - number of bytes
+ */
+/* used only by dtls1_read_bytes */
+int dtls1_get_record(SSL *s)
+{
+    int ssl_major, ssl_minor;
+    int rret;
+    size_t more, n;
+    SSL3_RECORD *rr;
+    unsigned char *p = NULL;
+    unsigned short version;
+    DTLS1_BITMAP *bitmap;
+    unsigned int is_next_epoch;
+
+    rr = RECORD_LAYER_get_rrec(&s->rlayer);
+
+ again:
+    /*
+     * The epoch may have changed.  If so, process all the pending records.
+     * This is a non-blocking operation.
+     */
+    if (!dtls1_process_buffered_records(s)) {
+        /* SSLfatal() already called */
+        return -1;
+    }
+
+    /* if we're renegotiating, then there may be buffered records */
+    if (dtls1_get_processed_record(s))
+        return 1;
+
+    /* get something from the wire */
+
+    /* check if we have the header */
+    if ((RECORD_LAYER_get_rstate(&s->rlayer) != SSL_ST_READ_BODY) ||
+        (RECORD_LAYER_get_packet_length(&s->rlayer) < DTLS1_RT_HEADER_LENGTH)) {
+        rret = ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH,
+                           SSL3_BUFFER_get_len(&s->rlayer.rbuf), 0, 1, &n);
+        /* read timeout is handled by dtls1_read_bytes */
+        if (rret <= 0) {
+            /* SSLfatal() already called if appropriate */
+            return rret;         /* error or non-blocking */
+        }
+
+        /* this packet contained a partial record, dump it */
+        if (RECORD_LAYER_get_packet_length(&s->rlayer) !=
+            DTLS1_RT_HEADER_LENGTH) {
+            RECORD_LAYER_reset_packet_length(&s->rlayer);
+            goto again;
+        }
+
+        RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY);
+
+        p = RECORD_LAYER_get_packet(&s->rlayer);
+
+        if (s->msg_callback)
+            s->msg_callback(0, 0, SSL3_RT_HEADER, p, DTLS1_RT_HEADER_LENGTH,
+                            s, s->msg_callback_arg);
+
+        /* Pull apart the header into the DTLS1_RECORD */
+        rr->type = *(p++);
+        ssl_major = *(p++);
+        ssl_minor = *(p++);
+        version = (ssl_major << 8) | ssl_minor;
+
+        /* sequence number is 64 bits, with top 2 bytes = epoch */
+        n2s(p, rr->epoch);
+
+        memcpy(&(RECORD_LAYER_get_read_sequence(&s->rlayer)[2]), p, 6);
+        p += 6;
+
+        n2s(p, rr->length);
+        rr->read = 0;
+
+        /*
+         * Lets check the version. We tolerate alerts that don't have the exact
+         * version number (e.g. because of protocol version errors)
+         */
+        if (!s->first_packet && rr->type != SSL3_RT_ALERT) {
+            if (version != s->version) {
+                /* unexpected version, silently discard */
+                rr->length = 0;
+                rr->read = 1;
+                RECORD_LAYER_reset_packet_length(&s->rlayer);
+                goto again;
+            }
+        }
+
+        if ((version & 0xff00) != (s->version & 0xff00)) {
+            /* wrong version, silently discard record */
+            rr->length = 0;
+            rr->read = 1;
+            RECORD_LAYER_reset_packet_length(&s->rlayer);
+            goto again;
+        }
+
+        if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
+            /* record too long, silently discard it */
+            rr->length = 0;
+            rr->read = 1;
+            RECORD_LAYER_reset_packet_length(&s->rlayer);
+            goto again;
+        }
+
+        /* If received packet overflows own-client Max Fragment Length setting */
+        if (s->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)
+                && rr->length > GET_MAX_FRAGMENT_LENGTH(s->session) + SSL3_RT_MAX_ENCRYPTED_OVERHEAD) {
+            /* record too long, silently discard it */
+            rr->length = 0;
+            rr->read = 1;
+            RECORD_LAYER_reset_packet_length(&s->rlayer);
+            goto again;
+        }
+
+        /* now s->rlayer.rstate == SSL_ST_READ_BODY */
+    }
+
+    /* s->rlayer.rstate == SSL_ST_READ_BODY, get and decode the data */
+
+    if (rr->length >
+        RECORD_LAYER_get_packet_length(&s->rlayer) - DTLS1_RT_HEADER_LENGTH) {
+        /* now s->rlayer.packet_length == DTLS1_RT_HEADER_LENGTH */
+        more = rr->length;
+        rret = ssl3_read_n(s, more, more, 1, 1, &n);
+        /* this packet contained a partial record, dump it */
+        if (rret <= 0 || n != more) {
+            if (ossl_statem_in_error(s)) {
+                /* ssl3_read_n() called SSLfatal() */
+                return -1;
+            }
+            rr->length = 0;
+            rr->read = 1;
+            RECORD_LAYER_reset_packet_length(&s->rlayer);
+            goto again;
+        }
+
+        /*
+         * now n == rr->length, and s->rlayer.packet_length ==
+         * DTLS1_RT_HEADER_LENGTH + rr->length
+         */
+    }
+    /* set state for later operations */
+    RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_HEADER);
+
+    /* match epochs.  NULL means the packet is dropped on the floor */
+    bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
+    if (bitmap == NULL) {
+        rr->length = 0;
+        RECORD_LAYER_reset_packet_length(&s->rlayer); /* dump this record */
+        goto again;             /* get another record */
+    }
+#ifndef OPENSSL_NO_SCTP
+    /* Only do replay check if no SCTP bio */
+    if (!BIO_dgram_is_sctp(SSL_get_rbio(s))) {
+#endif
+        /* Check whether this is a repeat, or aged record. */
+        /*
+         * TODO: Does it make sense to have replay protection in epoch 0 where
+         * we have no integrity negotiated yet?
+         */
+        if (!dtls1_record_replay_check(s, bitmap)) {
+            rr->length = 0;
+            rr->read = 1;
+            RECORD_LAYER_reset_packet_length(&s->rlayer); /* dump this record */
+            goto again;         /* get another record */
+        }
+#ifndef OPENSSL_NO_SCTP
+    }
+#endif
+
+    /* just read a 0 length packet */
+    if (rr->length == 0) {
+        rr->read = 1;
+        goto again;
+    }
+
+    /*
+     * If this record is from the next epoch (either HM or ALERT), and a
+     * handshake is currently in progress, buffer it since it cannot be
+     * processed at this time.
+     */
+    if (is_next_epoch) {
+        if ((SSL_in_init(s) || ossl_statem_get_in_handshake(s))) {
+            if (dtls1_buffer_record (s,
+                    &(DTLS_RECORD_LAYER_get_unprocessed_rcds(&s->rlayer)),
+                    rr->seq_num) < 0) {
+                /* SSLfatal() already called */
+                return -1;
+            }
+        }
+        rr->length = 0;
+        rr->read = 1;
+        RECORD_LAYER_reset_packet_length(&s->rlayer);
+        goto again;
+    }
+
+    if (!dtls1_process_record(s, bitmap)) {
+        if (ossl_statem_in_error(s)) {
+            /* dtls1_process_record() called SSLfatal */
+            return -1;
+        }
+        rr->length = 0;
+        rr->read = 1;
+        RECORD_LAYER_reset_packet_length(&s->rlayer); /* dump this record */
+        goto again;             /* get another record */
+    }
+
+    return 1;
+
+}
+
+int dtls_buffer_listen_record(SSL *s, size_t len, unsigned char *seq, size_t off)
+{
+    SSL3_RECORD *rr;
+
+    rr = RECORD_LAYER_get_rrec(&s->rlayer);
+    memset(rr, 0, sizeof(SSL3_RECORD));
+
+    rr->length = len;
+    rr->type = SSL3_RT_HANDSHAKE;
+    memcpy(rr->seq_num, seq, sizeof(rr->seq_num));
+    rr->off = off;
+
+    s->rlayer.packet = RECORD_LAYER_get_rbuf(&s->rlayer)->buf;
+    s->rlayer.packet_length = DTLS1_RT_HEADER_LENGTH + len;
+    rr->data = s->rlayer.packet + DTLS1_RT_HEADER_LENGTH;
+
+    if (dtls1_buffer_record(s, &(s->rlayer.d->processed_rcds),
+                            SSL3_RECORD_get_seq_num(s->rlayer.rrec)) <= 0) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    return 1;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/record/ssl3_record_tls13.c b/ap/lib/libssl/openssl-1.1.1o/ssl/record/ssl3_record_tls13.c
new file mode 100644
index 0000000..ab50e37
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/record/ssl3_record_tls13.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../ssl_local.h"
+#include "record_local.h"
+#include "internal/cryptlib.h"
+
+/*-
+ * tls13_enc encrypts/decrypts |n_recs| in |recs|. Will call SSLfatal() for
+ * internal errors, but not otherwise.
+ *
+ * Returns:
+ *    0: (in non-constant time) if the record is publicly invalid (i.e. too
+ *        short etc).
+ *    1: if the record encryption was successful.
+ *   -1: if the record's AEAD-authenticator is invalid or, if sending,
+ *       an internal error occurred.
+ */
+int tls13_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int sending)
+{
+    EVP_CIPHER_CTX *ctx;
+    unsigned char iv[EVP_MAX_IV_LENGTH], recheader[SSL3_RT_HEADER_LENGTH];
+    size_t ivlen, taglen, offset, loop, hdrlen;
+    unsigned char *staticiv;
+    unsigned char *seq;
+    int lenu, lenf;
+    SSL3_RECORD *rec = &recs[0];
+    uint32_t alg_enc;
+    WPACKET wpkt;
+
+    if (n_recs != 1) {
+        /* Should not happen */
+        /* TODO(TLS1.3): Support pipelining */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC,
+                 ERR_R_INTERNAL_ERROR);
+        return -1;
+    }
+
+    if (sending) {
+        ctx = s->enc_write_ctx;
+        staticiv = s->write_iv;
+        seq = RECORD_LAYER_get_write_sequence(&s->rlayer);
+    } else {
+        ctx = s->enc_read_ctx;
+        staticiv = s->read_iv;
+        seq = RECORD_LAYER_get_read_sequence(&s->rlayer);
+    }
+
+    /*
+     * If we're sending an alert and ctx != NULL then we must be forcing
+     * plaintext alerts. If we're reading and ctx != NULL then we allow
+     * plaintext alerts at certain points in the handshake. If we've got this
+     * far then we have already validated that a plaintext alert is ok here.
+     */
+    if (ctx == NULL || rec->type == SSL3_RT_ALERT) {
+        memmove(rec->data, rec->input, rec->length);
+        rec->input = rec->data;
+        return 1;
+    }
+
+    ivlen = EVP_CIPHER_CTX_iv_length(ctx);
+
+    if (s->early_data_state == SSL_EARLY_DATA_WRITING
+            || s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) {
+        if (s->session != NULL && s->session->ext.max_early_data > 0) {
+            alg_enc = s->session->cipher->algorithm_enc;
+        } else {
+            if (!ossl_assert(s->psksession != NULL
+                             && s->psksession->ext.max_early_data > 0)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC,
+                         ERR_R_INTERNAL_ERROR);
+                return -1;
+            }
+            alg_enc = s->psksession->cipher->algorithm_enc;
+        }
+    } else {
+        /*
+         * To get here we must have selected a ciphersuite - otherwise ctx would
+         * be NULL
+         */
+        if (!ossl_assert(s->s3->tmp.new_cipher != NULL)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC,
+                     ERR_R_INTERNAL_ERROR);
+            return -1;
+        }
+        alg_enc = s->s3->tmp.new_cipher->algorithm_enc;
+    }
+
+    if (alg_enc & SSL_AESCCM) {
+        if (alg_enc & (SSL_AES128CCM8 | SSL_AES256CCM8))
+            taglen = EVP_CCM8_TLS_TAG_LEN;
+         else
+            taglen = EVP_CCM_TLS_TAG_LEN;
+         if (sending && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, taglen,
+                                         NULL) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC,
+                     ERR_R_INTERNAL_ERROR);
+            return -1;
+        }
+    } else if (alg_enc & SSL_AESGCM) {
+        taglen = EVP_GCM_TLS_TAG_LEN;
+    } else if (alg_enc & SSL_CHACHA20) {
+        taglen = EVP_CHACHAPOLY_TLS_TAG_LEN;
+    } else {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC,
+                 ERR_R_INTERNAL_ERROR);
+        return -1;
+    }
+
+    if (!sending) {
+        /*
+         * Take off tag. There must be at least one byte of content type as
+         * well as the tag
+         */
+        if (rec->length < taglen + 1)
+            return 0;
+        rec->length -= taglen;
+    }
+
+    /* Set up IV */
+    if (ivlen < SEQ_NUM_SIZE) {
+        /* Should not happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC,
+                 ERR_R_INTERNAL_ERROR);
+        return -1;
+    }
+    offset = ivlen - SEQ_NUM_SIZE;
+    memcpy(iv, staticiv, offset);
+    for (loop = 0; loop < SEQ_NUM_SIZE; loop++)
+        iv[offset + loop] = staticiv[offset + loop] ^ seq[loop];
+
+    /* Increment the sequence counter */
+    for (loop = SEQ_NUM_SIZE; loop > 0; loop--) {
+        ++seq[loop - 1];
+        if (seq[loop - 1] != 0)
+            break;
+    }
+    if (loop == 0) {
+        /* Sequence has wrapped */
+        return -1;
+    }
+
+    /* TODO(size_t): lenu/lenf should be a size_t but EVP doesn't support it */
+    if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv, sending) <= 0
+            || (!sending && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
+                                             taglen,
+                                             rec->data + rec->length) <= 0)) {
+        return -1;
+    }
+
+    /* Set up the AAD */
+    if (!WPACKET_init_static_len(&wpkt, recheader, sizeof(recheader), 0)
+            || !WPACKET_put_bytes_u8(&wpkt, rec->type)
+            || !WPACKET_put_bytes_u16(&wpkt, rec->rec_version)
+            || !WPACKET_put_bytes_u16(&wpkt, rec->length + taglen)
+            || !WPACKET_get_total_written(&wpkt, &hdrlen)
+            || hdrlen != SSL3_RT_HEADER_LENGTH
+            || !WPACKET_finish(&wpkt)) {
+        WPACKET_cleanup(&wpkt);
+        return -1;
+    }
+
+    /*
+     * For CCM we must explicitly set the total plaintext length before we add
+     * any AAD.
+     */
+    if (((alg_enc & SSL_AESCCM) != 0
+                 && EVP_CipherUpdate(ctx, NULL, &lenu, NULL,
+                                     (unsigned int)rec->length) <= 0)
+            || EVP_CipherUpdate(ctx, NULL, &lenu, recheader,
+                                sizeof(recheader)) <= 0
+            || EVP_CipherUpdate(ctx, rec->data, &lenu, rec->input,
+                                (unsigned int)rec->length) <= 0
+            || EVP_CipherFinal_ex(ctx, rec->data + lenu, &lenf) <= 0
+            || (size_t)(lenu + lenf) != rec->length) {
+        return -1;
+    }
+    if (sending) {
+        /* Add the tag */
+        if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, taglen,
+                                rec->data + rec->length) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC,
+                     ERR_R_INTERNAL_ERROR);
+            return -1;
+        }
+        rec->length += taglen;
+    }
+
+    return 1;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/s3_cbc.c b/ap/lib/libssl/openssl-1.1.1o/ssl/s3_cbc.c
new file mode 100644
index 0000000..c95dcd9
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/s3_cbc.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright 2012-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "internal/constant_time.h"
+#include "ssl_local.h"
+#include "internal/cryptlib.h"
+
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+
+/*
+ * MAX_HASH_BIT_COUNT_BYTES is the maximum number of bytes in the hash's
+ * length field. (SHA-384/512 have 128-bit length.)
+ */
+#define MAX_HASH_BIT_COUNT_BYTES 16
+
+/*
+ * MAX_HASH_BLOCK_SIZE is the maximum hash block size that we'll support.
+ * Currently SHA-384/512 has a 128-byte block size and that's the largest
+ * supported by TLS.)
+ */
+#define MAX_HASH_BLOCK_SIZE 128
+
+/*
+ * u32toLE serialises an unsigned, 32-bit number (n) as four bytes at (p) in
+ * little-endian order. The value of p is advanced by four.
+ */
+#define u32toLE(n, p) \
+        (*((p)++)=(unsigned char)(n), \
+         *((p)++)=(unsigned char)(n>>8), \
+         *((p)++)=(unsigned char)(n>>16), \
+         *((p)++)=(unsigned char)(n>>24))
+
+/*
+ * These functions serialize the state of a hash and thus perform the
+ * standard "final" operation without adding the padding and length that such
+ * a function typically does.
+ */
+static void tls1_md5_final_raw(void *ctx, unsigned char *md_out)
+{
+    MD5_CTX *md5 = ctx;
+    u32toLE(md5->A, md_out);
+    u32toLE(md5->B, md_out);
+    u32toLE(md5->C, md_out);
+    u32toLE(md5->D, md_out);
+}
+
+static void tls1_sha1_final_raw(void *ctx, unsigned char *md_out)
+{
+    SHA_CTX *sha1 = ctx;
+    l2n(sha1->h0, md_out);
+    l2n(sha1->h1, md_out);
+    l2n(sha1->h2, md_out);
+    l2n(sha1->h3, md_out);
+    l2n(sha1->h4, md_out);
+}
+
+static void tls1_sha256_final_raw(void *ctx, unsigned char *md_out)
+{
+    SHA256_CTX *sha256 = ctx;
+    unsigned i;
+
+    for (i = 0; i < 8; i++) {
+        l2n(sha256->h[i], md_out);
+    }
+}
+
+static void tls1_sha512_final_raw(void *ctx, unsigned char *md_out)
+{
+    SHA512_CTX *sha512 = ctx;
+    unsigned i;
+
+    for (i = 0; i < 8; i++) {
+        l2n8(sha512->h[i], md_out);
+    }
+}
+
+#undef  LARGEST_DIGEST_CTX
+#define LARGEST_DIGEST_CTX SHA512_CTX
+
+/*
+ * ssl3_cbc_record_digest_supported returns 1 iff |ctx| uses a hash function
+ * which ssl3_cbc_digest_record supports.
+ */
+char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx)
+{
+    switch (EVP_MD_CTX_type(ctx)) {
+    case NID_md5:
+    case NID_sha1:
+    case NID_sha224:
+    case NID_sha256:
+    case NID_sha384:
+    case NID_sha512:
+        return 1;
+    default:
+        return 0;
+    }
+}
+
+/*-
+ * ssl3_cbc_digest_record computes the MAC of a decrypted, padded SSLv3/TLS
+ * record.
+ *
+ *   ctx: the EVP_MD_CTX from which we take the hash function.
+ *     ssl3_cbc_record_digest_supported must return true for this EVP_MD_CTX.
+ *   md_out: the digest output. At most EVP_MAX_MD_SIZE bytes will be written.
+ *   md_out_size: if non-NULL, the number of output bytes is written here.
+ *   header: the 13-byte, TLS record header.
+ *   data: the record data itself, less any preceding explicit IV.
+ *   data_plus_mac_size: the secret, reported length of the data and MAC
+ *     once the padding has been removed.
+ *   data_plus_mac_plus_padding_size: the public length of the whole
+ *     record, including padding.
+ *   is_sslv3: non-zero if we are to use SSLv3. Otherwise, TLS.
+ *
+ * On entry: by virtue of having been through one of the remove_padding
+ * functions, above, we know that data_plus_mac_size is large enough to contain
+ * a padding byte and MAC. (If the padding was invalid, it might contain the
+ * padding too. )
+ * Returns 1 on success or 0 on error
+ */
+int ssl3_cbc_digest_record(const EVP_MD_CTX *ctx,
+                           unsigned char *md_out,
+                           size_t *md_out_size,
+                           const unsigned char *header,
+                           const unsigned char *data,
+                           size_t data_plus_mac_size,
+                           size_t data_plus_mac_plus_padding_size,
+                           const unsigned char *mac_secret,
+                           size_t mac_secret_length, char is_sslv3)
+{
+    union {
+        double align;
+        unsigned char c[sizeof(LARGEST_DIGEST_CTX)];
+    } md_state;
+    void (*md_final_raw) (void *ctx, unsigned char *md_out);
+    void (*md_transform) (void *ctx, const unsigned char *block);
+    size_t md_size, md_block_size = 64;
+    size_t sslv3_pad_length = 40, header_length, variance_blocks,
+        len, max_mac_bytes, num_blocks,
+        num_starting_blocks, k, mac_end_offset, c, index_a, index_b;
+    size_t bits;          /* at most 18 bits */
+    unsigned char length_bytes[MAX_HASH_BIT_COUNT_BYTES];
+    /* hmac_pad is the masked HMAC key. */
+    unsigned char hmac_pad[MAX_HASH_BLOCK_SIZE];
+    unsigned char first_block[MAX_HASH_BLOCK_SIZE];
+    unsigned char mac_out[EVP_MAX_MD_SIZE];
+    size_t i, j;
+    unsigned md_out_size_u;
+    EVP_MD_CTX *md_ctx = NULL;
+    /*
+     * mdLengthSize is the number of bytes in the length field that
+     * terminates * the hash.
+     */
+    size_t md_length_size = 8;
+    char length_is_big_endian = 1;
+    int ret;
+
+    /*
+     * This is a, hopefully redundant, check that allows us to forget about
+     * many possible overflows later in this function.
+     */
+    if (!ossl_assert(data_plus_mac_plus_padding_size < 1024 * 1024))
+        return 0;
+
+    switch (EVP_MD_CTX_type(ctx)) {
+    case NID_md5:
+        if (MD5_Init((MD5_CTX *)md_state.c) <= 0)
+            return 0;
+        md_final_raw = tls1_md5_final_raw;
+        md_transform =
+            (void (*)(void *ctx, const unsigned char *block))MD5_Transform;
+        md_size = 16;
+        sslv3_pad_length = 48;
+        length_is_big_endian = 0;
+        break;
+    case NID_sha1:
+        if (SHA1_Init((SHA_CTX *)md_state.c) <= 0)
+            return 0;
+        md_final_raw = tls1_sha1_final_raw;
+        md_transform =
+            (void (*)(void *ctx, const unsigned char *block))SHA1_Transform;
+        md_size = 20;
+        break;
+    case NID_sha224:
+        if (SHA224_Init((SHA256_CTX *)md_state.c) <= 0)
+            return 0;
+        md_final_raw = tls1_sha256_final_raw;
+        md_transform =
+            (void (*)(void *ctx, const unsigned char *block))SHA256_Transform;
+        md_size = 224 / 8;
+        break;
+    case NID_sha256:
+        if (SHA256_Init((SHA256_CTX *)md_state.c) <= 0)
+            return 0;
+        md_final_raw = tls1_sha256_final_raw;
+        md_transform =
+            (void (*)(void *ctx, const unsigned char *block))SHA256_Transform;
+        md_size = 32;
+        break;
+    case NID_sha384:
+        if (SHA384_Init((SHA512_CTX *)md_state.c) <= 0)
+            return 0;
+        md_final_raw = tls1_sha512_final_raw;
+        md_transform =
+            (void (*)(void *ctx, const unsigned char *block))SHA512_Transform;
+        md_size = 384 / 8;
+        md_block_size = 128;
+        md_length_size = 16;
+        break;
+    case NID_sha512:
+        if (SHA512_Init((SHA512_CTX *)md_state.c) <= 0)
+            return 0;
+        md_final_raw = tls1_sha512_final_raw;
+        md_transform =
+            (void (*)(void *ctx, const unsigned char *block))SHA512_Transform;
+        md_size = 64;
+        md_block_size = 128;
+        md_length_size = 16;
+        break;
+    default:
+        /*
+         * ssl3_cbc_record_digest_supported should have been called first to
+         * check that the hash function is supported.
+         */
+        if (md_out_size != NULL)
+            *md_out_size = 0;
+        return ossl_assert(0);
+    }
+
+    if (!ossl_assert(md_length_size <= MAX_HASH_BIT_COUNT_BYTES)
+            || !ossl_assert(md_block_size <= MAX_HASH_BLOCK_SIZE)
+            || !ossl_assert(md_size <= EVP_MAX_MD_SIZE))
+        return 0;
+
+    header_length = 13;
+    if (is_sslv3) {
+        header_length = mac_secret_length + sslv3_pad_length + 8 /* sequence
+                                                                  * number */  +
+            1 /* record type */  +
+            2 /* record length */ ;
+    }
+
+    /*
+     * variance_blocks is the number of blocks of the hash that we have to
+     * calculate in constant time because they could be altered by the
+     * padding value. In SSLv3, the padding must be minimal so the end of
+     * the plaintext varies by, at most, 15+20 = 35 bytes. (We conservatively
+     * assume that the MAC size varies from 0..20 bytes.) In case the 9 bytes
+     * of hash termination (0x80 + 64-bit length) don't fit in the final
+     * block, we say that the final two blocks can vary based on the padding.
+     * TLSv1 has MACs up to 48 bytes long (SHA-384) and the padding is not
+     * required to be minimal. Therefore we say that the final |variance_blocks|
+     * blocks can
+     * vary based on the padding. Later in the function, if the message is
+     * short and there obviously cannot be this many blocks then
+     * variance_blocks can be reduced.
+     */
+    variance_blocks = is_sslv3 ? 2 : ( ((255 + 1 + md_size + md_block_size - 1) / md_block_size) + 1);
+    /*
+     * From now on we're dealing with the MAC, which conceptually has 13
+     * bytes of `header' before the start of the data (TLS) or 71/75 bytes
+     * (SSLv3)
+     */
+    len = data_plus_mac_plus_padding_size + header_length;
+    /*
+     * max_mac_bytes contains the maximum bytes of bytes in the MAC,
+     * including * |header|, assuming that there's no padding.
+     */
+    max_mac_bytes = len - md_size - 1;
+    /* num_blocks is the maximum number of hash blocks. */
+    num_blocks =
+        (max_mac_bytes + 1 + md_length_size + md_block_size -
+         1) / md_block_size;
+    /*
+     * In order to calculate the MAC in constant time we have to handle the
+     * final blocks specially because the padding value could cause the end
+     * to appear somewhere in the final |variance_blocks| blocks and we can't
+     * leak where. However, |num_starting_blocks| worth of data can be hashed
+     * right away because no padding value can affect whether they are
+     * plaintext.
+     */
+    num_starting_blocks = 0;
+    /*
+     * k is the starting byte offset into the conceptual header||data where
+     * we start processing.
+     */
+    k = 0;
+    /*
+     * mac_end_offset is the index just past the end of the data to be MACed.
+     */
+    mac_end_offset = data_plus_mac_size + header_length - md_size;
+    /*
+     * c is the index of the 0x80 byte in the final hash block that contains
+     * application data.
+     */
+    c = mac_end_offset % md_block_size;
+    /*
+     * index_a is the hash block number that contains the 0x80 terminating
+     * value.
+     */
+    index_a = mac_end_offset / md_block_size;
+    /*
+     * index_b is the hash block number that contains the 64-bit hash length,
+     * in bits.
+     */
+    index_b = (mac_end_offset + md_length_size) / md_block_size;
+    /*
+     * bits is the hash-length in bits. It includes the additional hash block
+     * for the masked HMAC key, or whole of |header| in the case of SSLv3.
+     */
+
+    /*
+     * For SSLv3, if we're going to have any starting blocks then we need at
+     * least two because the header is larger than a single block.
+     */
+    if (num_blocks > variance_blocks + (is_sslv3 ? 1 : 0)) {
+        num_starting_blocks = num_blocks - variance_blocks;
+        k = md_block_size * num_starting_blocks;
+    }
+
+    bits = 8 * mac_end_offset;
+    if (!is_sslv3) {
+        /*
+         * Compute the initial HMAC block. For SSLv3, the padding and secret
+         * bytes are included in |header| because they take more than a
+         * single block.
+         */
+        bits += 8 * md_block_size;
+        memset(hmac_pad, 0, md_block_size);
+        if (!ossl_assert(mac_secret_length <= sizeof(hmac_pad)))
+            return 0;
+        memcpy(hmac_pad, mac_secret, mac_secret_length);
+        for (i = 0; i < md_block_size; i++)
+            hmac_pad[i] ^= 0x36;
+
+        md_transform(md_state.c, hmac_pad);
+    }
+
+    if (length_is_big_endian) {
+        memset(length_bytes, 0, md_length_size - 4);
+        length_bytes[md_length_size - 4] = (unsigned char)(bits >> 24);
+        length_bytes[md_length_size - 3] = (unsigned char)(bits >> 16);
+        length_bytes[md_length_size - 2] = (unsigned char)(bits >> 8);
+        length_bytes[md_length_size - 1] = (unsigned char)bits;
+    } else {
+        memset(length_bytes, 0, md_length_size);
+        length_bytes[md_length_size - 5] = (unsigned char)(bits >> 24);
+        length_bytes[md_length_size - 6] = (unsigned char)(bits >> 16);
+        length_bytes[md_length_size - 7] = (unsigned char)(bits >> 8);
+        length_bytes[md_length_size - 8] = (unsigned char)bits;
+    }
+
+    if (k > 0) {
+        if (is_sslv3) {
+            size_t overhang;
+
+            /*
+             * The SSLv3 header is larger than a single block. overhang is
+             * the number of bytes beyond a single block that the header
+             * consumes: either 7 bytes (SHA1) or 11 bytes (MD5). There are no
+             * ciphersuites in SSLv3 that are not SHA1 or MD5 based and
+             * therefore we can be confident that the header_length will be
+             * greater than |md_block_size|. However we add a sanity check just
+             * in case
+             */
+            if (header_length <= md_block_size) {
+                /* Should never happen */
+                return 0;
+            }
+            overhang = header_length - md_block_size;
+            md_transform(md_state.c, header);
+            memcpy(first_block, header + md_block_size, overhang);
+            memcpy(first_block + overhang, data, md_block_size - overhang);
+            md_transform(md_state.c, first_block);
+            for (i = 1; i < k / md_block_size - 1; i++)
+                md_transform(md_state.c, data + md_block_size * i - overhang);
+        } else {
+            /* k is a multiple of md_block_size. */
+            memcpy(first_block, header, 13);
+            memcpy(first_block + 13, data, md_block_size - 13);
+            md_transform(md_state.c, first_block);
+            for (i = 1; i < k / md_block_size; i++)
+                md_transform(md_state.c, data + md_block_size * i - 13);
+        }
+    }
+
+    memset(mac_out, 0, sizeof(mac_out));
+
+    /*
+     * We now process the final hash blocks. For each block, we construct it
+     * in constant time. If the |i==index_a| then we'll include the 0x80
+     * bytes and zero pad etc. For each block we selectively copy it, in
+     * constant time, to |mac_out|.
+     */
+    for (i = num_starting_blocks; i <= num_starting_blocks + variance_blocks;
+         i++) {
+        unsigned char block[MAX_HASH_BLOCK_SIZE];
+        unsigned char is_block_a = constant_time_eq_8_s(i, index_a);
+        unsigned char is_block_b = constant_time_eq_8_s(i, index_b);
+        for (j = 0; j < md_block_size; j++) {
+            unsigned char b = 0, is_past_c, is_past_cp1;
+            if (k < header_length)
+                b = header[k];
+            else if (k < data_plus_mac_plus_padding_size + header_length)
+                b = data[k - header_length];
+            k++;
+
+            is_past_c = is_block_a & constant_time_ge_8_s(j, c);
+            is_past_cp1 = is_block_a & constant_time_ge_8_s(j, c + 1);
+            /*
+             * If this is the block containing the end of the application
+             * data, and we are at the offset for the 0x80 value, then
+             * overwrite b with 0x80.
+             */
+            b = constant_time_select_8(is_past_c, 0x80, b);
+            /*
+             * If this block contains the end of the application data
+             * and we're past the 0x80 value then just write zero.
+             */
+            b = b & ~is_past_cp1;
+            /*
+             * If this is index_b (the final block), but not index_a (the end
+             * of the data), then the 64-bit length didn't fit into index_a
+             * and we're having to add an extra block of zeros.
+             */
+            b &= ~is_block_b | is_block_a;
+
+            /*
+             * The final bytes of one of the blocks contains the length.
+             */
+            if (j >= md_block_size - md_length_size) {
+                /* If this is index_b, write a length byte. */
+                b = constant_time_select_8(is_block_b,
+                                           length_bytes[j -
+                                                        (md_block_size -
+                                                         md_length_size)], b);
+            }
+            block[j] = b;
+        }
+
+        md_transform(md_state.c, block);
+        md_final_raw(md_state.c, block);
+        /* If this is index_b, copy the hash value to |mac_out|. */
+        for (j = 0; j < md_size; j++)
+            mac_out[j] |= block[j] & is_block_b;
+    }
+
+    md_ctx = EVP_MD_CTX_new();
+    if (md_ctx == NULL)
+        goto err;
+    if (EVP_DigestInit_ex(md_ctx, EVP_MD_CTX_md(ctx), NULL /* engine */ ) <= 0)
+        goto err;
+    if (is_sslv3) {
+        /* We repurpose |hmac_pad| to contain the SSLv3 pad2 block. */
+        memset(hmac_pad, 0x5c, sslv3_pad_length);
+
+        if (EVP_DigestUpdate(md_ctx, mac_secret, mac_secret_length) <= 0
+            || EVP_DigestUpdate(md_ctx, hmac_pad, sslv3_pad_length) <= 0
+            || EVP_DigestUpdate(md_ctx, mac_out, md_size) <= 0)
+            goto err;
+    } else {
+        /* Complete the HMAC in the standard manner. */
+        for (i = 0; i < md_block_size; i++)
+            hmac_pad[i] ^= 0x6a;
+
+        if (EVP_DigestUpdate(md_ctx, hmac_pad, md_block_size) <= 0
+            || EVP_DigestUpdate(md_ctx, mac_out, md_size) <= 0)
+            goto err;
+    }
+    /* TODO(size_t): Convert me */
+    ret = EVP_DigestFinal(md_ctx, md_out, &md_out_size_u);
+    if (ret && md_out_size)
+        *md_out_size = md_out_size_u;
+    EVP_MD_CTX_free(md_ctx);
+
+    return 1;
+ err:
+    EVP_MD_CTX_free(md_ctx);
+    return 0;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/s3_enc.c b/ap/lib/libssl/openssl-1.1.1o/ssl/s3_enc.c
new file mode 100644
index 0000000..7b119b4
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/s3_enc.c
@@ -0,0 +1,597 @@
+/*
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include "ssl_local.h"
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+#include "internal/cryptlib.h"
+
+static int ssl3_generate_key_block(SSL *s, unsigned char *km, int num)
+{
+    EVP_MD_CTX *m5;
+    EVP_MD_CTX *s1;
+    unsigned char buf[16], smd[SHA_DIGEST_LENGTH];
+    unsigned char c = 'A';
+    unsigned int i, j, k;
+    int ret = 0;
+
+#ifdef CHARSET_EBCDIC
+    c = os_toascii[c];          /* 'A' in ASCII */
+#endif
+    k = 0;
+    m5 = EVP_MD_CTX_new();
+    s1 = EVP_MD_CTX_new();
+    if (m5 == NULL || s1 == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_GENERATE_KEY_BLOCK,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    EVP_MD_CTX_set_flags(m5, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+    for (i = 0; (int)i < num; i += MD5_DIGEST_LENGTH) {
+        k++;
+        if (k > sizeof(buf)) {
+            /* bug: 'buf' is too small for this ciphersuite */
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_GENERATE_KEY_BLOCK,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        for (j = 0; j < k; j++)
+            buf[j] = c;
+        c++;
+        if (!EVP_DigestInit_ex(s1, EVP_sha1(), NULL)
+            || !EVP_DigestUpdate(s1, buf, k)
+            || !EVP_DigestUpdate(s1, s->session->master_key,
+                                 s->session->master_key_length)
+            || !EVP_DigestUpdate(s1, s->s3->server_random, SSL3_RANDOM_SIZE)
+            || !EVP_DigestUpdate(s1, s->s3->client_random, SSL3_RANDOM_SIZE)
+            || !EVP_DigestFinal_ex(s1, smd, NULL)
+            || !EVP_DigestInit_ex(m5, EVP_md5(), NULL)
+            || !EVP_DigestUpdate(m5, s->session->master_key,
+                                 s->session->master_key_length)
+            || !EVP_DigestUpdate(m5, smd, SHA_DIGEST_LENGTH)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_GENERATE_KEY_BLOCK,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        if ((int)(i + MD5_DIGEST_LENGTH) > num) {
+            if (!EVP_DigestFinal_ex(m5, smd, NULL)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_SSL3_GENERATE_KEY_BLOCK, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            memcpy(km, smd, (num - i));
+        } else {
+            if (!EVP_DigestFinal_ex(m5, km, NULL)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_SSL3_GENERATE_KEY_BLOCK, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+        }
+
+        km += MD5_DIGEST_LENGTH;
+    }
+    OPENSSL_cleanse(smd, sizeof(smd));
+    ret = 1;
+ err:
+    EVP_MD_CTX_free(m5);
+    EVP_MD_CTX_free(s1);
+    return ret;
+}
+
+int ssl3_change_cipher_state(SSL *s, int which)
+{
+    unsigned char *p, *mac_secret;
+    unsigned char *ms, *key, *iv;
+    EVP_CIPHER_CTX *dd;
+    const EVP_CIPHER *c;
+#ifndef OPENSSL_NO_COMP
+    COMP_METHOD *comp;
+#endif
+    const EVP_MD *m;
+    int mdi;
+    size_t n, i, j, k, cl;
+    int reuse_dd = 0;
+
+    c = s->s3->tmp.new_sym_enc;
+    m = s->s3->tmp.new_hash;
+    /* m == NULL will lead to a crash later */
+    if (!ossl_assert(m != NULL)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_CHANGE_CIPHER_STATE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+#ifndef OPENSSL_NO_COMP
+    if (s->s3->tmp.new_compression == NULL)
+        comp = NULL;
+    else
+        comp = s->s3->tmp.new_compression->method;
+#endif
+
+    if (which & SSL3_CC_READ) {
+        if (s->enc_read_ctx != NULL) {
+            reuse_dd = 1;
+        } else if ((s->enc_read_ctx = EVP_CIPHER_CTX_new()) == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_CHANGE_CIPHER_STATE,
+                     ERR_R_MALLOC_FAILURE);
+            goto err;
+        } else {
+            /*
+             * make sure it's initialised in case we exit later with an error
+             */
+            EVP_CIPHER_CTX_reset(s->enc_read_ctx);
+        }
+        dd = s->enc_read_ctx;
+
+        if (ssl_replace_hash(&s->read_hash, m) == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_CHANGE_CIPHER_STATE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+#ifndef OPENSSL_NO_COMP
+        /* COMPRESS */
+        COMP_CTX_free(s->expand);
+        s->expand = NULL;
+        if (comp != NULL) {
+            s->expand = COMP_CTX_new(comp);
+            if (s->expand == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_SSL3_CHANGE_CIPHER_STATE,
+                         SSL_R_COMPRESSION_LIBRARY_ERROR);
+                goto err;
+            }
+        }
+#endif
+        RECORD_LAYER_reset_read_sequence(&s->rlayer);
+        mac_secret = &(s->s3->read_mac_secret[0]);
+    } else {
+        s->statem.enc_write_state = ENC_WRITE_STATE_INVALID;
+        if (s->enc_write_ctx != NULL) {
+            reuse_dd = 1;
+        } else if ((s->enc_write_ctx = EVP_CIPHER_CTX_new()) == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_CHANGE_CIPHER_STATE,
+                     ERR_R_MALLOC_FAILURE);
+            goto err;
+        } else {
+            /*
+             * make sure it's initialised in case we exit later with an error
+             */
+            EVP_CIPHER_CTX_reset(s->enc_write_ctx);
+        }
+        dd = s->enc_write_ctx;
+        if (ssl_replace_hash(&s->write_hash, m) == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_CHANGE_CIPHER_STATE,
+                     ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+#ifndef OPENSSL_NO_COMP
+        /* COMPRESS */
+        COMP_CTX_free(s->compress);
+        s->compress = NULL;
+        if (comp != NULL) {
+            s->compress = COMP_CTX_new(comp);
+            if (s->compress == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_SSL3_CHANGE_CIPHER_STATE,
+                         SSL_R_COMPRESSION_LIBRARY_ERROR);
+                goto err;
+            }
+        }
+#endif
+        RECORD_LAYER_reset_write_sequence(&s->rlayer);
+        mac_secret = &(s->s3->write_mac_secret[0]);
+    }
+
+    if (reuse_dd)
+        EVP_CIPHER_CTX_reset(dd);
+
+    p = s->s3->tmp.key_block;
+    mdi = EVP_MD_size(m);
+    if (mdi < 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_CHANGE_CIPHER_STATE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    i = mdi;
+    cl = EVP_CIPHER_key_length(c);
+    j = cl;
+    k = EVP_CIPHER_iv_length(c);
+    if ((which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) ||
+        (which == SSL3_CHANGE_CIPHER_SERVER_READ)) {
+        ms = &(p[0]);
+        n = i + i;
+        key = &(p[n]);
+        n += j + j;
+        iv = &(p[n]);
+        n += k + k;
+    } else {
+        n = i;
+        ms = &(p[n]);
+        n += i + j;
+        key = &(p[n]);
+        n += j + k;
+        iv = &(p[n]);
+        n += k;
+    }
+
+    if (n > s->s3->tmp.key_block_length) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_CHANGE_CIPHER_STATE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    memcpy(mac_secret, ms, i);
+
+    if (!EVP_CipherInit_ex(dd, c, NULL, key, iv, (which & SSL3_CC_WRITE))) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_CHANGE_CIPHER_STATE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
+    return 1;
+ err:
+    return 0;
+}
+
+int ssl3_setup_key_block(SSL *s)
+{
+    unsigned char *p;
+    const EVP_CIPHER *c;
+    const EVP_MD *hash;
+    int num;
+    int ret = 0;
+    SSL_COMP *comp;
+
+    if (s->s3->tmp.key_block_length != 0)
+        return 1;
+
+    if (!ssl_cipher_get_evp(s->session, &c, &hash, NULL, NULL, &comp, 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_SETUP_KEY_BLOCK,
+                 SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
+        return 0;
+    }
+
+    s->s3->tmp.new_sym_enc = c;
+    s->s3->tmp.new_hash = hash;
+#ifdef OPENSSL_NO_COMP
+    s->s3->tmp.new_compression = NULL;
+#else
+    s->s3->tmp.new_compression = comp;
+#endif
+
+    num = EVP_MD_size(hash);
+    if (num < 0)
+        return 0;
+
+    num = EVP_CIPHER_key_length(c) + num + EVP_CIPHER_iv_length(c);
+    num *= 2;
+
+    ssl3_cleanup_key_block(s);
+
+    if ((p = OPENSSL_malloc(num)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_SETUP_KEY_BLOCK,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    s->s3->tmp.key_block_length = num;
+    s->s3->tmp.key_block = p;
+
+    /* Calls SSLfatal() as required */
+    ret = ssl3_generate_key_block(s, p, num);
+
+    if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)) {
+        /*
+         * enable vulnerability countermeasure for CBC ciphers with known-IV
+         * problem (http://www.openssl.org/~bodo/tls-cbc.txt)
+         */
+        s->s3->need_empty_fragments = 1;
+
+        if (s->session->cipher != NULL) {
+            if (s->session->cipher->algorithm_enc == SSL_eNULL)
+                s->s3->need_empty_fragments = 0;
+
+#ifndef OPENSSL_NO_RC4
+            if (s->session->cipher->algorithm_enc == SSL_RC4)
+                s->s3->need_empty_fragments = 0;
+#endif
+        }
+    }
+
+    return ret;
+}
+
+void ssl3_cleanup_key_block(SSL *s)
+{
+    OPENSSL_clear_free(s->s3->tmp.key_block, s->s3->tmp.key_block_length);
+    s->s3->tmp.key_block = NULL;
+    s->s3->tmp.key_block_length = 0;
+}
+
+int ssl3_init_finished_mac(SSL *s)
+{
+    BIO *buf = BIO_new(BIO_s_mem());
+
+    if (buf == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_INIT_FINISHED_MAC,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    ssl3_free_digest_list(s);
+    s->s3->handshake_buffer = buf;
+    (void)BIO_set_close(s->s3->handshake_buffer, BIO_CLOSE);
+    return 1;
+}
+
+/*
+ * Free digest list. Also frees handshake buffer since they are always freed
+ * together.
+ */
+
+void ssl3_free_digest_list(SSL *s)
+{
+    BIO_free(s->s3->handshake_buffer);
+    s->s3->handshake_buffer = NULL;
+    EVP_MD_CTX_free(s->s3->handshake_dgst);
+    s->s3->handshake_dgst = NULL;
+}
+
+int ssl3_finish_mac(SSL *s, const unsigned char *buf, size_t len)
+{
+    int ret;
+
+    if (s->s3->handshake_dgst == NULL) {
+        /* Note: this writes to a memory BIO so a failure is a fatal error */
+        if (len > INT_MAX) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_FINISH_MAC,
+                     SSL_R_OVERFLOW_ERROR);
+            return 0;
+        }
+        ret = BIO_write(s->s3->handshake_buffer, (void *)buf, (int)len);
+        if (ret <= 0 || ret != (int)len) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_FINISH_MAC,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    } else {
+        ret = EVP_DigestUpdate(s->s3->handshake_dgst, buf, len);
+        if (!ret) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_FINISH_MAC,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+    return 1;
+}
+
+int ssl3_digest_cached_records(SSL *s, int keep)
+{
+    const EVP_MD *md;
+    long hdatalen;
+    void *hdata;
+
+    if (s->s3->handshake_dgst == NULL) {
+        hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+        if (hdatalen <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_DIGEST_CACHED_RECORDS,
+                     SSL_R_BAD_HANDSHAKE_LENGTH);
+            return 0;
+        }
+
+        s->s3->handshake_dgst = EVP_MD_CTX_new();
+        if (s->s3->handshake_dgst == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_DIGEST_CACHED_RECORDS,
+                     ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+
+        md = ssl_handshake_md(s);
+        if (md == NULL || !EVP_DigestInit_ex(s->s3->handshake_dgst, md, NULL)
+            || !EVP_DigestUpdate(s->s3->handshake_dgst, hdata, hdatalen)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_DIGEST_CACHED_RECORDS,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+    if (keep == 0) {
+        BIO_free(s->s3->handshake_buffer);
+        s->s3->handshake_buffer = NULL;
+    }
+
+    return 1;
+}
+
+size_t ssl3_final_finish_mac(SSL *s, const char *sender, size_t len,
+                             unsigned char *p)
+{
+    int ret;
+    EVP_MD_CTX *ctx = NULL;
+
+    if (!ssl3_digest_cached_records(s, 0)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    if (EVP_MD_CTX_type(s->s3->handshake_dgst) != NID_md5_sha1) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_FINAL_FINISH_MAC,
+                 SSL_R_NO_REQUIRED_DIGEST);
+        return 0;
+    }
+
+    ctx = EVP_MD_CTX_new();
+    if (ctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_FINAL_FINISH_MAC,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    if (!EVP_MD_CTX_copy_ex(ctx, s->s3->handshake_dgst)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_FINAL_FINISH_MAC,
+                 ERR_R_INTERNAL_ERROR);
+        ret = 0;
+        goto err;
+    }
+
+    ret = EVP_MD_CTX_size(ctx);
+    if (ret < 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_FINAL_FINISH_MAC,
+                 ERR_R_INTERNAL_ERROR);
+        ret = 0;
+        goto err;
+    }
+
+    if ((sender != NULL && EVP_DigestUpdate(ctx, sender, len) <= 0)
+        || EVP_MD_CTX_ctrl(ctx, EVP_CTRL_SSL3_MASTER_SECRET,
+                           (int)s->session->master_key_length,
+                           s->session->master_key) <= 0
+        || EVP_DigestFinal_ex(ctx, p, NULL) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_FINAL_FINISH_MAC,
+                 ERR_R_INTERNAL_ERROR);
+        ret = 0;
+    }
+
+ err:
+    EVP_MD_CTX_free(ctx);
+
+    return ret;
+}
+
+int ssl3_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
+                                size_t len, size_t *secret_size)
+{
+    static const unsigned char *salt[3] = {
+#ifndef CHARSET_EBCDIC
+        (const unsigned char *)"A",
+        (const unsigned char *)"BB",
+        (const unsigned char *)"CCC",
+#else
+        (const unsigned char *)"\x41",
+        (const unsigned char *)"\x42\x42",
+        (const unsigned char *)"\x43\x43\x43",
+#endif
+    };
+    unsigned char buf[EVP_MAX_MD_SIZE];
+    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
+    int i, ret = 1;
+    unsigned int n;
+    size_t ret_secret_size = 0;
+
+    if (ctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_GENERATE_MASTER_SECRET,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    for (i = 0; i < 3; i++) {
+        if (EVP_DigestInit_ex(ctx, s->ctx->sha1, NULL) <= 0
+            || EVP_DigestUpdate(ctx, salt[i],
+                                strlen((const char *)salt[i])) <= 0
+            || EVP_DigestUpdate(ctx, p, len) <= 0
+            || EVP_DigestUpdate(ctx, &(s->s3->client_random[0]),
+                                SSL3_RANDOM_SIZE) <= 0
+            || EVP_DigestUpdate(ctx, &(s->s3->server_random[0]),
+                                SSL3_RANDOM_SIZE) <= 0
+               /* TODO(size_t) : convert me */
+            || EVP_DigestFinal_ex(ctx, buf, &n) <= 0
+            || EVP_DigestInit_ex(ctx, s->ctx->md5, NULL) <= 0
+            || EVP_DigestUpdate(ctx, p, len) <= 0
+            || EVP_DigestUpdate(ctx, buf, n) <= 0
+            || EVP_DigestFinal_ex(ctx, out, &n) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_SSL3_GENERATE_MASTER_SECRET, ERR_R_INTERNAL_ERROR);
+            ret = 0;
+            break;
+        }
+        out += n;
+        ret_secret_size += n;
+    }
+    EVP_MD_CTX_free(ctx);
+
+    OPENSSL_cleanse(buf, sizeof(buf));
+    if (ret)
+        *secret_size = ret_secret_size;
+    return ret;
+}
+
+int ssl3_alert_code(int code)
+{
+    switch (code) {
+    case SSL_AD_CLOSE_NOTIFY:
+        return SSL3_AD_CLOSE_NOTIFY;
+    case SSL_AD_UNEXPECTED_MESSAGE:
+        return SSL3_AD_UNEXPECTED_MESSAGE;
+    case SSL_AD_BAD_RECORD_MAC:
+        return SSL3_AD_BAD_RECORD_MAC;
+    case SSL_AD_DECRYPTION_FAILED:
+        return SSL3_AD_BAD_RECORD_MAC;
+    case SSL_AD_RECORD_OVERFLOW:
+        return SSL3_AD_BAD_RECORD_MAC;
+    case SSL_AD_DECOMPRESSION_FAILURE:
+        return SSL3_AD_DECOMPRESSION_FAILURE;
+    case SSL_AD_HANDSHAKE_FAILURE:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_NO_CERTIFICATE:
+        return SSL3_AD_NO_CERTIFICATE;
+    case SSL_AD_BAD_CERTIFICATE:
+        return SSL3_AD_BAD_CERTIFICATE;
+    case SSL_AD_UNSUPPORTED_CERTIFICATE:
+        return SSL3_AD_UNSUPPORTED_CERTIFICATE;
+    case SSL_AD_CERTIFICATE_REVOKED:
+        return SSL3_AD_CERTIFICATE_REVOKED;
+    case SSL_AD_CERTIFICATE_EXPIRED:
+        return SSL3_AD_CERTIFICATE_EXPIRED;
+    case SSL_AD_CERTIFICATE_UNKNOWN:
+        return SSL3_AD_CERTIFICATE_UNKNOWN;
+    case SSL_AD_ILLEGAL_PARAMETER:
+        return SSL3_AD_ILLEGAL_PARAMETER;
+    case SSL_AD_UNKNOWN_CA:
+        return SSL3_AD_BAD_CERTIFICATE;
+    case SSL_AD_ACCESS_DENIED:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_DECODE_ERROR:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_DECRYPT_ERROR:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_EXPORT_RESTRICTION:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_PROTOCOL_VERSION:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_INSUFFICIENT_SECURITY:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_INTERNAL_ERROR:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_USER_CANCELLED:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_NO_RENEGOTIATION:
+        return -1;            /* Don't send it :-) */
+    case SSL_AD_UNSUPPORTED_EXTENSION:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_CERTIFICATE_UNOBTAINABLE:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_UNRECOGNIZED_NAME:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_BAD_CERTIFICATE_HASH_VALUE:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_UNKNOWN_PSK_IDENTITY:
+        return TLS1_AD_UNKNOWN_PSK_IDENTITY;
+    case SSL_AD_INAPPROPRIATE_FALLBACK:
+        return TLS1_AD_INAPPROPRIATE_FALLBACK;
+    case SSL_AD_NO_APPLICATION_PROTOCOL:
+        return TLS1_AD_NO_APPLICATION_PROTOCOL;
+    case SSL_AD_CERTIFICATE_REQUIRED:
+        return SSL_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_MISSING_EXTENSION:
+        return SSL_AD_HANDSHAKE_FAILURE;
+    default:
+        return -1;
+    }
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/s3_lib.c b/ap/lib/libssl/openssl-1.1.1o/ssl/s3_lib.c
new file mode 100644
index 0000000..32f9b25
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/s3_lib.c
@@ -0,0 +1,4870 @@
+/*
+ * 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.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <openssl/objects.h>
+#include "internal/nelem.h"
+#include "ssl_local.h"
+#include <openssl/md5.h>
+#include <openssl/dh.h>
+#include <openssl/rand.h>
+#include "internal/cryptlib.h"
+
+#define TLS13_NUM_CIPHERS       OSSL_NELEM(tls13_ciphers)
+#define SSL3_NUM_CIPHERS        OSSL_NELEM(ssl3_ciphers)
+#define SSL3_NUM_SCSVS          OSSL_NELEM(ssl3_scsvs)
+
+/* TLSv1.3 downgrade protection sentinel values */
+const unsigned char tls11downgrade[] = {
+    0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00
+};
+const unsigned char tls12downgrade[] = {
+    0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01
+};
+
+/* The list of available TLSv1.3 ciphers */
+static SSL_CIPHER tls13_ciphers[] = {
+    {
+        1,
+        TLS1_3_RFC_AES_128_GCM_SHA256,
+        TLS1_3_RFC_AES_128_GCM_SHA256,
+        TLS1_3_CK_AES_128_GCM_SHA256,
+        SSL_kANY,
+        SSL_aANY,
+        SSL_AES128GCM,
+        SSL_AEAD,
+        TLS1_3_VERSION, TLS1_3_VERSION,
+        0, 0,
+        SSL_HIGH,
+        SSL_HANDSHAKE_MAC_SHA256,
+        128,
+        128,
+    }, {
+        1,
+        TLS1_3_RFC_AES_256_GCM_SHA384,
+        TLS1_3_RFC_AES_256_GCM_SHA384,
+        TLS1_3_CK_AES_256_GCM_SHA384,
+        SSL_kANY,
+        SSL_aANY,
+        SSL_AES256GCM,
+        SSL_AEAD,
+        TLS1_3_VERSION, TLS1_3_VERSION,
+        0, 0,
+        SSL_HIGH,
+        SSL_HANDSHAKE_MAC_SHA384,
+        256,
+        256,
+    },
+#if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+    {
+        1,
+        TLS1_3_RFC_CHACHA20_POLY1305_SHA256,
+        TLS1_3_RFC_CHACHA20_POLY1305_SHA256,
+        TLS1_3_CK_CHACHA20_POLY1305_SHA256,
+        SSL_kANY,
+        SSL_aANY,
+        SSL_CHACHA20POLY1305,
+        SSL_AEAD,
+        TLS1_3_VERSION, TLS1_3_VERSION,
+        0, 0,
+        SSL_HIGH,
+        SSL_HANDSHAKE_MAC_SHA256,
+        256,
+        256,
+    },
+#endif
+    {
+        1,
+        TLS1_3_RFC_AES_128_CCM_SHA256,
+        TLS1_3_RFC_AES_128_CCM_SHA256,
+        TLS1_3_CK_AES_128_CCM_SHA256,
+        SSL_kANY,
+        SSL_aANY,
+        SSL_AES128CCM,
+        SSL_AEAD,
+        TLS1_3_VERSION, TLS1_3_VERSION,
+        0, 0,
+        SSL_NOT_DEFAULT | SSL_HIGH,
+        SSL_HANDSHAKE_MAC_SHA256,
+        128,
+        128,
+    }, {
+        1,
+        TLS1_3_RFC_AES_128_CCM_8_SHA256,
+        TLS1_3_RFC_AES_128_CCM_8_SHA256,
+        TLS1_3_CK_AES_128_CCM_8_SHA256,
+        SSL_kANY,
+        SSL_aANY,
+        SSL_AES128CCM8,
+        SSL_AEAD,
+        TLS1_3_VERSION, TLS1_3_VERSION,
+        0, 0,
+        SSL_NOT_DEFAULT | SSL_HIGH,
+        SSL_HANDSHAKE_MAC_SHA256,
+        128,
+        128,
+    }
+};
+
+/*
+ * The list of available ciphers, mostly organized into the following
+ * groups:
+ *      Always there
+ *      EC
+ *      PSK
+ *      SRP (within that: RSA EC PSK)
+ *      Cipher families: Chacha/poly, Camellia, Gost, IDEA, SEED
+ *      Weak ciphers
+ */
+static SSL_CIPHER ssl3_ciphers[] = {
+    {
+     1,
+     SSL3_TXT_RSA_NULL_MD5,
+     SSL3_RFC_RSA_NULL_MD5,
+     SSL3_CK_RSA_NULL_MD5,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_eNULL,
+     SSL_MD5,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+    {
+     1,
+     SSL3_TXT_RSA_NULL_SHA,
+     SSL3_RFC_RSA_NULL_SHA,
+     SSL3_CK_RSA_NULL_SHA,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_eNULL,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS
+    {
+     1,
+     SSL3_TXT_RSA_DES_192_CBC3_SHA,
+     SSL3_RFC_RSA_DES_192_CBC3_SHA,
+     SSL3_CK_RSA_DES_192_CBC3_SHA,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_3DES,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+    {
+     1,
+     SSL3_TXT_DHE_DSS_DES_192_CBC3_SHA,
+     SSL3_RFC_DHE_DSS_DES_192_CBC3_SHA,
+     SSL3_CK_DHE_DSS_DES_192_CBC3_SHA,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_3DES,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+    {
+     1,
+     SSL3_TXT_DHE_RSA_DES_192_CBC3_SHA,
+     SSL3_RFC_DHE_RSA_DES_192_CBC3_SHA,
+     SSL3_CK_DHE_RSA_DES_192_CBC3_SHA,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_3DES,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+    {
+     1,
+     SSL3_TXT_ADH_DES_192_CBC_SHA,
+     SSL3_RFC_ADH_DES_192_CBC_SHA,
+     SSL3_CK_ADH_DES_192_CBC_SHA,
+     SSL_kDHE,
+     SSL_aNULL,
+     SSL_3DES,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+#endif
+    {
+     1,
+     TLS1_TXT_RSA_WITH_AES_128_SHA,
+     TLS1_RFC_RSA_WITH_AES_128_SHA,
+     TLS1_CK_RSA_WITH_AES_128_SHA,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_AES128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_DSS_WITH_AES_128_SHA,
+     TLS1_RFC_DHE_DSS_WITH_AES_128_SHA,
+     TLS1_CK_DHE_DSS_WITH_AES_128_SHA,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_AES128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_AES_128_SHA,
+     TLS1_RFC_DHE_RSA_WITH_AES_128_SHA,
+     TLS1_CK_DHE_RSA_WITH_AES_128_SHA,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_AES128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ADH_WITH_AES_128_SHA,
+     TLS1_RFC_ADH_WITH_AES_128_SHA,
+     TLS1_CK_ADH_WITH_AES_128_SHA,
+     SSL_kDHE,
+     SSL_aNULL,
+     SSL_AES128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_AES_256_SHA,
+     TLS1_RFC_RSA_WITH_AES_256_SHA,
+     TLS1_CK_RSA_WITH_AES_256_SHA,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_AES256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_DSS_WITH_AES_256_SHA,
+     TLS1_RFC_DHE_DSS_WITH_AES_256_SHA,
+     TLS1_CK_DHE_DSS_WITH_AES_256_SHA,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_AES256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_AES_256_SHA,
+     TLS1_RFC_DHE_RSA_WITH_AES_256_SHA,
+     TLS1_CK_DHE_RSA_WITH_AES_256_SHA,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_AES256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ADH_WITH_AES_256_SHA,
+     TLS1_RFC_ADH_WITH_AES_256_SHA,
+     TLS1_CK_ADH_WITH_AES_256_SHA,
+     SSL_kDHE,
+     SSL_aNULL,
+     SSL_AES256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_NULL_SHA256,
+     TLS1_RFC_RSA_WITH_NULL_SHA256,
+     TLS1_CK_RSA_WITH_NULL_SHA256,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_eNULL,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_AES_128_SHA256,
+     TLS1_RFC_RSA_WITH_AES_128_SHA256,
+     TLS1_CK_RSA_WITH_AES_128_SHA256,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_AES128,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_AES_256_SHA256,
+     TLS1_RFC_RSA_WITH_AES_256_SHA256,
+     TLS1_CK_RSA_WITH_AES_256_SHA256,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_AES256,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_DSS_WITH_AES_128_SHA256,
+     TLS1_RFC_DHE_DSS_WITH_AES_128_SHA256,
+     TLS1_CK_DHE_DSS_WITH_AES_128_SHA256,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_AES128,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256,
+     TLS1_RFC_DHE_RSA_WITH_AES_128_SHA256,
+     TLS1_CK_DHE_RSA_WITH_AES_128_SHA256,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_AES128,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_DSS_WITH_AES_256_SHA256,
+     TLS1_RFC_DHE_DSS_WITH_AES_256_SHA256,
+     TLS1_CK_DHE_DSS_WITH_AES_256_SHA256,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_AES256,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256,
+     TLS1_RFC_DHE_RSA_WITH_AES_256_SHA256,
+     TLS1_CK_DHE_RSA_WITH_AES_256_SHA256,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_AES256,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ADH_WITH_AES_128_SHA256,
+     TLS1_RFC_ADH_WITH_AES_128_SHA256,
+     TLS1_CK_ADH_WITH_AES_128_SHA256,
+     SSL_kDHE,
+     SSL_aNULL,
+     SSL_AES128,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ADH_WITH_AES_256_SHA256,
+     TLS1_RFC_ADH_WITH_AES_256_SHA256,
+     TLS1_CK_ADH_WITH_AES_256_SHA256,
+     SSL_kDHE,
+     SSL_aNULL,
+     SSL_AES256,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256,
+     TLS1_RFC_RSA_WITH_AES_128_GCM_SHA256,
+     TLS1_CK_RSA_WITH_AES_128_GCM_SHA256,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_AES128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384,
+     TLS1_RFC_RSA_WITH_AES_256_GCM_SHA384,
+     TLS1_CK_RSA_WITH_AES_256_GCM_SHA384,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_AES256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256,
+     TLS1_RFC_DHE_RSA_WITH_AES_128_GCM_SHA256,
+     TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_AES128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384,
+     TLS1_RFC_DHE_RSA_WITH_AES_256_GCM_SHA384,
+     TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_AES256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_DSS_WITH_AES_128_GCM_SHA256,
+     TLS1_RFC_DHE_DSS_WITH_AES_128_GCM_SHA256,
+     TLS1_CK_DHE_DSS_WITH_AES_128_GCM_SHA256,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_AES128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_DSS_WITH_AES_256_GCM_SHA384,
+     TLS1_RFC_DHE_DSS_WITH_AES_256_GCM_SHA384,
+     TLS1_CK_DHE_DSS_WITH_AES_256_GCM_SHA384,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_AES256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ADH_WITH_AES_128_GCM_SHA256,
+     TLS1_RFC_ADH_WITH_AES_128_GCM_SHA256,
+     TLS1_CK_ADH_WITH_AES_128_GCM_SHA256,
+     SSL_kDHE,
+     SSL_aNULL,
+     SSL_AES128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ADH_WITH_AES_256_GCM_SHA384,
+     TLS1_RFC_ADH_WITH_AES_256_GCM_SHA384,
+     TLS1_CK_ADH_WITH_AES_256_GCM_SHA384,
+     SSL_kDHE,
+     SSL_aNULL,
+     SSL_AES256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_AES_128_CCM,
+     TLS1_RFC_RSA_WITH_AES_128_CCM,
+     TLS1_CK_RSA_WITH_AES_128_CCM,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_AES128CCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_AES_256_CCM,
+     TLS1_RFC_RSA_WITH_AES_256_CCM,
+     TLS1_CK_RSA_WITH_AES_256_CCM,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_AES256CCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_AES_128_CCM,
+     TLS1_RFC_DHE_RSA_WITH_AES_128_CCM,
+     TLS1_CK_DHE_RSA_WITH_AES_128_CCM,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_AES128CCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_AES_256_CCM,
+     TLS1_RFC_DHE_RSA_WITH_AES_256_CCM,
+     TLS1_CK_DHE_RSA_WITH_AES_256_CCM,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_AES256CCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_AES_128_CCM_8,
+     TLS1_RFC_RSA_WITH_AES_128_CCM_8,
+     TLS1_CK_RSA_WITH_AES_128_CCM_8,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_AES128CCM8,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_AES_256_CCM_8,
+     TLS1_RFC_RSA_WITH_AES_256_CCM_8,
+     TLS1_CK_RSA_WITH_AES_256_CCM_8,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_AES256CCM8,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_AES_128_CCM_8,
+     TLS1_RFC_DHE_RSA_WITH_AES_128_CCM_8,
+     TLS1_CK_DHE_RSA_WITH_AES_128_CCM_8,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_AES128CCM8,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_AES_256_CCM_8,
+     TLS1_RFC_DHE_RSA_WITH_AES_256_CCM_8,
+     TLS1_CK_DHE_RSA_WITH_AES_256_CCM_8,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_AES256CCM8,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_AES_128_CCM,
+     TLS1_RFC_PSK_WITH_AES_128_CCM,
+     TLS1_CK_PSK_WITH_AES_128_CCM,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_AES128CCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_AES_256_CCM,
+     TLS1_RFC_PSK_WITH_AES_256_CCM,
+     TLS1_CK_PSK_WITH_AES_256_CCM,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_AES256CCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_AES_128_CCM,
+     TLS1_RFC_DHE_PSK_WITH_AES_128_CCM,
+     TLS1_CK_DHE_PSK_WITH_AES_128_CCM,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_AES128CCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_AES_256_CCM,
+     TLS1_RFC_DHE_PSK_WITH_AES_256_CCM,
+     TLS1_CK_DHE_PSK_WITH_AES_256_CCM,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_AES256CCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_AES_128_CCM_8,
+     TLS1_RFC_PSK_WITH_AES_128_CCM_8,
+     TLS1_CK_PSK_WITH_AES_128_CCM_8,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_AES128CCM8,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_AES_256_CCM_8,
+     TLS1_RFC_PSK_WITH_AES_256_CCM_8,
+     TLS1_CK_PSK_WITH_AES_256_CCM_8,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_AES256CCM8,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_AES_128_CCM_8,
+     TLS1_RFC_DHE_PSK_WITH_AES_128_CCM_8,
+     TLS1_CK_DHE_PSK_WITH_AES_128_CCM_8,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_AES128CCM8,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_AES_256_CCM_8,
+     TLS1_RFC_DHE_PSK_WITH_AES_256_CCM_8,
+     TLS1_CK_DHE_PSK_WITH_AES_256_CCM_8,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_AES256CCM8,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CCM,
+     TLS1_RFC_ECDHE_ECDSA_WITH_AES_128_CCM,
+     TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CCM,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_AES128CCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CCM,
+     TLS1_RFC_ECDHE_ECDSA_WITH_AES_256_CCM,
+     TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CCM,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_AES256CCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CCM_8,
+     TLS1_RFC_ECDHE_ECDSA_WITH_AES_128_CCM_8,
+     TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CCM_8,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_AES128CCM8,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CCM_8,
+     TLS1_RFC_ECDHE_ECDSA_WITH_AES_256_CCM_8,
+     TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CCM_8,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_AES256CCM8,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA,
+     TLS1_RFC_ECDHE_ECDSA_WITH_NULL_SHA,
+     TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_eNULL,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA,
+     TLS1_RFC_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA,
+     TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_3DES,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+# endif
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+     TLS1_RFC_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+     TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_AES128,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+     TLS1_RFC_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+     TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_AES256,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA,
+     TLS1_RFC_ECDHE_RSA_WITH_NULL_SHA,
+     TLS1_CK_ECDHE_RSA_WITH_NULL_SHA,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_eNULL,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA,
+     TLS1_RFC_ECDHE_RSA_WITH_DES_192_CBC3_SHA,
+     TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_3DES,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+# endif
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+     TLS1_RFC_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+     TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_AES128,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+     TLS1_RFC_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+     TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_AES256,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDH_anon_WITH_NULL_SHA,
+     TLS1_RFC_ECDH_anon_WITH_NULL_SHA,
+     TLS1_CK_ECDH_anon_WITH_NULL_SHA,
+     SSL_kECDHE,
+     SSL_aNULL,
+     SSL_eNULL,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS
+    {
+     1,
+     TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA,
+     TLS1_RFC_ECDH_anon_WITH_DES_192_CBC3_SHA,
+     TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA,
+     SSL_kECDHE,
+     SSL_aNULL,
+     SSL_3DES,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+# endif
+    {
+     1,
+     TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA,
+     TLS1_RFC_ECDH_anon_WITH_AES_128_CBC_SHA,
+     TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA,
+     SSL_kECDHE,
+     SSL_aNULL,
+     SSL_AES128,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA,
+     TLS1_RFC_ECDH_anon_WITH_AES_256_CBC_SHA,
+     TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA,
+     SSL_kECDHE,
+     SSL_aNULL,
+     SSL_AES256,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256,
+     TLS1_RFC_ECDHE_ECDSA_WITH_AES_128_SHA256,
+     TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_AES128,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384,
+     TLS1_RFC_ECDHE_ECDSA_WITH_AES_256_SHA384,
+     TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_AES256,
+     SSL_SHA384,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256,
+     TLS1_RFC_ECDHE_RSA_WITH_AES_128_SHA256,
+     TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_AES128,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384,
+     TLS1_RFC_ECDHE_RSA_WITH_AES_256_SHA384,
+     TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_AES256,
+     SSL_SHA384,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+     TLS1_RFC_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+     TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_AES128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+     TLS1_RFC_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+     TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_AES256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+     TLS1_RFC_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+     TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_AES128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+     TLS1_RFC_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+     TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_AES256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_NULL_SHA,
+     TLS1_RFC_PSK_WITH_NULL_SHA,
+     TLS1_CK_PSK_WITH_NULL_SHA,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_eNULL,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_NULL_SHA,
+     TLS1_RFC_DHE_PSK_WITH_NULL_SHA,
+     TLS1_CK_DHE_PSK_WITH_NULL_SHA,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_eNULL,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_NULL_SHA,
+     TLS1_RFC_RSA_PSK_WITH_NULL_SHA,
+     TLS1_CK_RSA_PSK_WITH_NULL_SHA,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_eNULL,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS
+    {
+     1,
+     TLS1_TXT_PSK_WITH_3DES_EDE_CBC_SHA,
+     TLS1_RFC_PSK_WITH_3DES_EDE_CBC_SHA,
+     TLS1_CK_PSK_WITH_3DES_EDE_CBC_SHA,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_3DES,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+# endif
+    {
+     1,
+     TLS1_TXT_PSK_WITH_AES_128_CBC_SHA,
+     TLS1_RFC_PSK_WITH_AES_128_CBC_SHA,
+     TLS1_CK_PSK_WITH_AES_128_CBC_SHA,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_AES128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_AES_256_CBC_SHA,
+     TLS1_RFC_PSK_WITH_AES_256_CBC_SHA,
+     TLS1_CK_PSK_WITH_AES_256_CBC_SHA,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_AES256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+     TLS1_RFC_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+     TLS1_CK_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_3DES,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+# endif
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_AES_128_CBC_SHA,
+     TLS1_RFC_DHE_PSK_WITH_AES_128_CBC_SHA,
+     TLS1_CK_DHE_PSK_WITH_AES_128_CBC_SHA,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_AES128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_AES_256_CBC_SHA,
+     TLS1_RFC_DHE_PSK_WITH_AES_256_CBC_SHA,
+     TLS1_CK_DHE_PSK_WITH_AES_256_CBC_SHA,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_AES256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+     TLS1_RFC_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+     TLS1_CK_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_3DES,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+# endif
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_AES_128_CBC_SHA,
+     TLS1_RFC_RSA_PSK_WITH_AES_128_CBC_SHA,
+     TLS1_CK_RSA_PSK_WITH_AES_128_CBC_SHA,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_AES128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_AES_256_CBC_SHA,
+     TLS1_RFC_RSA_PSK_WITH_AES_256_CBC_SHA,
+     TLS1_CK_RSA_PSK_WITH_AES_256_CBC_SHA,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_AES256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_AES_128_GCM_SHA256,
+     TLS1_RFC_PSK_WITH_AES_128_GCM_SHA256,
+     TLS1_CK_PSK_WITH_AES_128_GCM_SHA256,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_AES128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_AES_256_GCM_SHA384,
+     TLS1_RFC_PSK_WITH_AES_256_GCM_SHA384,
+     TLS1_CK_PSK_WITH_AES_256_GCM_SHA384,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_AES256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_AES_128_GCM_SHA256,
+     TLS1_RFC_DHE_PSK_WITH_AES_128_GCM_SHA256,
+     TLS1_CK_DHE_PSK_WITH_AES_128_GCM_SHA256,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_AES128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_AES_256_GCM_SHA384,
+     TLS1_RFC_DHE_PSK_WITH_AES_256_GCM_SHA384,
+     TLS1_CK_DHE_PSK_WITH_AES_256_GCM_SHA384,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_AES256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_AES_128_GCM_SHA256,
+     TLS1_RFC_RSA_PSK_WITH_AES_128_GCM_SHA256,
+     TLS1_CK_RSA_PSK_WITH_AES_128_GCM_SHA256,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_AES128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_AES_256_GCM_SHA384,
+     TLS1_RFC_RSA_PSK_WITH_AES_256_GCM_SHA384,
+     TLS1_CK_RSA_PSK_WITH_AES_256_GCM_SHA384,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_AES256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_AES_128_CBC_SHA256,
+     TLS1_RFC_PSK_WITH_AES_128_CBC_SHA256,
+     TLS1_CK_PSK_WITH_AES_128_CBC_SHA256,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_AES128,
+     SSL_SHA256,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_AES_256_CBC_SHA384,
+     TLS1_RFC_PSK_WITH_AES_256_CBC_SHA384,
+     TLS1_CK_PSK_WITH_AES_256_CBC_SHA384,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_AES256,
+     SSL_SHA384,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_NULL_SHA256,
+     TLS1_RFC_PSK_WITH_NULL_SHA256,
+     TLS1_CK_PSK_WITH_NULL_SHA256,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_eNULL,
+     SSL_SHA256,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_NULL_SHA384,
+     TLS1_RFC_PSK_WITH_NULL_SHA384,
+     TLS1_CK_PSK_WITH_NULL_SHA384,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_eNULL,
+     SSL_SHA384,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     0,
+     0,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_AES_128_CBC_SHA256,
+     TLS1_RFC_DHE_PSK_WITH_AES_128_CBC_SHA256,
+     TLS1_CK_DHE_PSK_WITH_AES_128_CBC_SHA256,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_AES128,
+     SSL_SHA256,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_AES_256_CBC_SHA384,
+     TLS1_RFC_DHE_PSK_WITH_AES_256_CBC_SHA384,
+     TLS1_CK_DHE_PSK_WITH_AES_256_CBC_SHA384,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_AES256,
+     SSL_SHA384,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_NULL_SHA256,
+     TLS1_RFC_DHE_PSK_WITH_NULL_SHA256,
+     TLS1_CK_DHE_PSK_WITH_NULL_SHA256,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_eNULL,
+     SSL_SHA256,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_NULL_SHA384,
+     TLS1_RFC_DHE_PSK_WITH_NULL_SHA384,
+     TLS1_CK_DHE_PSK_WITH_NULL_SHA384,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_eNULL,
+     SSL_SHA384,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     0,
+     0,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_AES_128_CBC_SHA256,
+     TLS1_RFC_RSA_PSK_WITH_AES_128_CBC_SHA256,
+     TLS1_CK_RSA_PSK_WITH_AES_128_CBC_SHA256,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_AES128,
+     SSL_SHA256,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_AES_256_CBC_SHA384,
+     TLS1_RFC_RSA_PSK_WITH_AES_256_CBC_SHA384,
+     TLS1_CK_RSA_PSK_WITH_AES_256_CBC_SHA384,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_AES256,
+     SSL_SHA384,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_NULL_SHA256,
+     TLS1_RFC_RSA_PSK_WITH_NULL_SHA256,
+     TLS1_CK_RSA_PSK_WITH_NULL_SHA256,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_eNULL,
+     SSL_SHA256,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_NULL_SHA384,
+     TLS1_RFC_RSA_PSK_WITH_NULL_SHA384,
+     TLS1_CK_RSA_PSK_WITH_NULL_SHA384,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_eNULL,
+     SSL_SHA384,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     0,
+     0,
+     },
+#  ifndef OPENSSL_NO_WEAK_SSL_CIPHERS
+    {
+     1,
+     TLS1_TXT_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
+     TLS1_RFC_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
+     TLS1_CK_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
+     SSL_kECDHEPSK,
+     SSL_aPSK,
+     SSL_3DES,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+#  endif
+    {
+     1,
+     TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+     TLS1_RFC_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+     TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+     SSL_kECDHEPSK,
+     SSL_aPSK,
+     SSL_AES128,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA,
+     TLS1_RFC_ECDHE_PSK_WITH_AES_256_CBC_SHA,
+     TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA,
+     SSL_kECDHEPSK,
+     SSL_aPSK,
+     SSL_AES256,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+     TLS1_RFC_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+     TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+     SSL_kECDHEPSK,
+     SSL_aPSK,
+     SSL_AES128,
+     SSL_SHA256,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
+     TLS1_RFC_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
+     TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
+     SSL_kECDHEPSK,
+     SSL_aPSK,
+     SSL_AES256,
+     SSL_SHA384,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_PSK_WITH_NULL_SHA,
+     TLS1_RFC_ECDHE_PSK_WITH_NULL_SHA,
+     TLS1_CK_ECDHE_PSK_WITH_NULL_SHA,
+     SSL_kECDHEPSK,
+     SSL_aPSK,
+     SSL_eNULL,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_PSK_WITH_NULL_SHA256,
+     TLS1_RFC_ECDHE_PSK_WITH_NULL_SHA256,
+     TLS1_CK_ECDHE_PSK_WITH_NULL_SHA256,
+     SSL_kECDHEPSK,
+     SSL_aPSK,
+     SSL_eNULL,
+     SSL_SHA256,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     0,
+     0,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_PSK_WITH_NULL_SHA384,
+     TLS1_RFC_ECDHE_PSK_WITH_NULL_SHA384,
+     TLS1_CK_ECDHE_PSK_WITH_NULL_SHA384,
+     SSL_kECDHEPSK,
+     SSL_aPSK,
+     SSL_eNULL,
+     SSL_SHA384,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_STRONG_NONE | SSL_FIPS,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     0,
+     0,
+     },
+
+# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS
+    {
+     1,
+     TLS1_TXT_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
+     TLS1_RFC_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
+     TLS1_CK_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
+     SSL_kSRP,
+     SSL_aSRP,
+     SSL_3DES,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+    {
+     1,
+     TLS1_TXT_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+     TLS1_RFC_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+     TLS1_CK_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+     SSL_kSRP,
+     SSL_aRSA,
+     SSL_3DES,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+    {
+     1,
+     TLS1_TXT_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+     TLS1_RFC_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+     TLS1_CK_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+     SSL_kSRP,
+     SSL_aDSS,
+     SSL_3DES,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     112,
+     168,
+     },
+# endif
+    {
+     1,
+     TLS1_TXT_SRP_SHA_WITH_AES_128_CBC_SHA,
+     TLS1_RFC_SRP_SHA_WITH_AES_128_CBC_SHA,
+     TLS1_CK_SRP_SHA_WITH_AES_128_CBC_SHA,
+     SSL_kSRP,
+     SSL_aSRP,
+     SSL_AES128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+     TLS1_RFC_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+     TLS1_CK_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+     SSL_kSRP,
+     SSL_aRSA,
+     SSL_AES128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+     TLS1_RFC_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+     TLS1_CK_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+     SSL_kSRP,
+     SSL_aDSS,
+     SSL_AES128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_SRP_SHA_WITH_AES_256_CBC_SHA,
+     TLS1_RFC_SRP_SHA_WITH_AES_256_CBC_SHA,
+     TLS1_CK_SRP_SHA_WITH_AES_256_CBC_SHA,
+     SSL_kSRP,
+     SSL_aSRP,
+     SSL_AES256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
+     TLS1_RFC_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
+     TLS1_CK_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
+     SSL_kSRP,
+     SSL_aRSA,
+     SSL_AES256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
+     TLS1_RFC_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
+     TLS1_CK_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
+     SSL_kSRP,
+     SSL_aDSS,
+     SSL_AES256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+
+#if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305,
+     TLS1_RFC_DHE_RSA_WITH_CHACHA20_POLY1305,
+     TLS1_CK_DHE_RSA_WITH_CHACHA20_POLY1305,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_CHACHA20POLY1305,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+     TLS1_RFC_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+     TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_CHACHA20POLY1305,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+     TLS1_RFC_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+     TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_CHACHA20POLY1305,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_CHACHA20_POLY1305,
+     TLS1_RFC_PSK_WITH_CHACHA20_POLY1305,
+     TLS1_CK_PSK_WITH_CHACHA20_POLY1305,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_CHACHA20POLY1305,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_PSK_WITH_CHACHA20_POLY1305,
+     TLS1_RFC_ECDHE_PSK_WITH_CHACHA20_POLY1305,
+     TLS1_CK_ECDHE_PSK_WITH_CHACHA20_POLY1305,
+     SSL_kECDHEPSK,
+     SSL_aPSK,
+     SSL_CHACHA20POLY1305,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_CHACHA20_POLY1305,
+     TLS1_RFC_DHE_PSK_WITH_CHACHA20_POLY1305,
+     TLS1_CK_DHE_PSK_WITH_CHACHA20_POLY1305,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_CHACHA20POLY1305,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_CHACHA20_POLY1305,
+     TLS1_RFC_RSA_PSK_WITH_CHACHA20_POLY1305,
+     TLS1_CK_RSA_PSK_WITH_CHACHA20_POLY1305,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_CHACHA20POLY1305,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+#endif                          /* !defined(OPENSSL_NO_CHACHA) &&
+                                 * !defined(OPENSSL_NO_POLY1305) */
+
+#ifndef OPENSSL_NO_CAMELLIA
+    {
+     1,
+     TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_RFC_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_CAMELLIA128,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_RFC_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_CAMELLIA128,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_RFC_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_CAMELLIA128,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_RFC_ADH_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA256,
+     SSL_kDHE,
+     SSL_aNULL,
+     SSL_CAMELLIA128,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+     TLS1_RFC_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+     TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_CAMELLIA256,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256,
+     TLS1_RFC_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256,
+     TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_CAMELLIA256,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+     TLS1_RFC_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+     TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_CAMELLIA256,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA256,
+     TLS1_RFC_ADH_WITH_CAMELLIA_256_CBC_SHA256,
+     TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA256,
+     SSL_kDHE,
+     SSL_aNULL,
+     SSL_CAMELLIA256,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA,
+     TLS1_RFC_RSA_WITH_CAMELLIA_256_CBC_SHA,
+     TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_CAMELLIA256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
+     TLS1_RFC_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
+     TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_CAMELLIA256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+     TLS1_RFC_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+     TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_CAMELLIA256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA,
+     TLS1_RFC_ADH_WITH_CAMELLIA_256_CBC_SHA,
+     TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA,
+     SSL_kDHE,
+     SSL_aNULL,
+     SSL_CAMELLIA256,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA,
+     TLS1_RFC_RSA_WITH_CAMELLIA_128_CBC_SHA,
+     TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_CAMELLIA128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
+     TLS1_RFC_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
+     TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_CAMELLIA128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+     TLS1_RFC_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+     TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_CAMELLIA128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA,
+     TLS1_RFC_ADH_WITH_CAMELLIA_128_CBC_SHA,
+     TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA,
+     SSL_kDHE,
+     SSL_aNULL,
+     SSL_CAMELLIA128,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_RFC_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_CK_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_CAMELLIA128,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
+     TLS1_RFC_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
+     TLS1_CK_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_CAMELLIA256,
+     SSL_SHA384,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_RFC_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_CK_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_CAMELLIA128,
+     SSL_SHA256,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
+     TLS1_RFC_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
+     TLS1_CK_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_CAMELLIA256,
+     SSL_SHA384,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_RFC_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_CK_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_CAMELLIA128,
+     SSL_SHA256,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+     TLS1_RFC_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+     TLS1_CK_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_CAMELLIA256,
+     SSL_SHA384,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_RFC_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_CK_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_CAMELLIA128,
+     SSL_SHA256,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+     TLS1_RFC_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+     TLS1_CK_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_CAMELLIA256,
+     SSL_SHA384,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_RFC_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_CK_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_CAMELLIA128,
+     SSL_SHA256,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+     TLS1_RFC_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+     TLS1_CK_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_CAMELLIA256,
+     SSL_SHA384,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_RFC_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+     TLS1_CK_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+     SSL_kECDHEPSK,
+     SSL_aPSK,
+     SSL_CAMELLIA128,
+     SSL_SHA256,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+     TLS1_RFC_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+     TLS1_CK_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+     SSL_kECDHEPSK,
+     SSL_aPSK,
+     SSL_CAMELLIA256,
+     SSL_SHA384,
+     TLS1_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+#endif                          /* OPENSSL_NO_CAMELLIA */
+
+#ifndef OPENSSL_NO_GOST
+    {
+     1,
+     "GOST2001-GOST89-GOST89",
+     "TLS_GOSTR341001_WITH_28147_CNT_IMIT",
+     0x3000081,
+     SSL_kGOST,
+     SSL_aGOST01,
+     SSL_eGOST2814789CNT,
+     SSL_GOST89MAC,
+     TLS1_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_GOST94 | TLS1_PRF_GOST94 | TLS1_STREAM_MAC,
+     256,
+     256,
+     },
+    {
+     1,
+     "GOST2001-NULL-GOST94",
+     "TLS_GOSTR341001_WITH_NULL_GOSTR3411",
+     0x3000083,
+     SSL_kGOST,
+     SSL_aGOST01,
+     SSL_eNULL,
+     SSL_GOST94,
+     TLS1_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_STRONG_NONE,
+     SSL_HANDSHAKE_MAC_GOST94 | TLS1_PRF_GOST94,
+     0,
+     0,
+     },
+    {
+     1,
+     "GOST2012-GOST8912-GOST8912",
+     NULL,
+     0x0300ff85,
+     SSL_kGOST,
+     SSL_aGOST12 | SSL_aGOST01,
+     SSL_eGOST2814789CNT12,
+     SSL_GOST89MAC12,
+     TLS1_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_PRF_GOST12_256 | TLS1_STREAM_MAC,
+     256,
+     256,
+     },
+    {
+     1,
+     "GOST2012-NULL-GOST12",
+     NULL,
+     0x0300ff87,
+     SSL_kGOST,
+     SSL_aGOST12 | SSL_aGOST01,
+     SSL_eNULL,
+     SSL_GOST12_256,
+     TLS1_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_STRONG_NONE,
+     SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_PRF_GOST12_256 | TLS1_STREAM_MAC,
+     0,
+     0,
+     },
+#endif                          /* OPENSSL_NO_GOST */
+
+#ifndef OPENSSL_NO_IDEA
+    {
+     1,
+     SSL3_TXT_RSA_IDEA_128_SHA,
+     SSL3_RFC_RSA_IDEA_128_SHA,
+     SSL3_CK_RSA_IDEA_128_SHA,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_IDEA,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_1_VERSION,
+     DTLS1_BAD_VER, DTLS1_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+#endif
+
+#ifndef OPENSSL_NO_SEED
+    {
+     1,
+     TLS1_TXT_RSA_WITH_SEED_SHA,
+     TLS1_RFC_RSA_WITH_SEED_SHA,
+     TLS1_CK_RSA_WITH_SEED_SHA,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_SEED,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_DSS_WITH_SEED_SHA,
+     TLS1_RFC_DHE_DSS_WITH_SEED_SHA,
+     TLS1_CK_DHE_DSS_WITH_SEED_SHA,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_SEED,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_SEED_SHA,
+     TLS1_RFC_DHE_RSA_WITH_SEED_SHA,
+     TLS1_CK_DHE_RSA_WITH_SEED_SHA,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_SEED,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ADH_WITH_SEED_SHA,
+     TLS1_RFC_ADH_WITH_SEED_SHA,
+     TLS1_CK_ADH_WITH_SEED_SHA,
+     SSL_kDHE,
+     SSL_aNULL,
+     SSL_SEED,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     DTLS1_BAD_VER, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+#endif                          /* OPENSSL_NO_SEED */
+
+#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS
+    {
+     1,
+     SSL3_TXT_RSA_RC4_128_MD5,
+     SSL3_RFC_RSA_RC4_128_MD5,
+     SSL3_CK_RSA_RC4_128_MD5,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_RC4,
+     SSL_MD5,
+     SSL3_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     SSL3_TXT_RSA_RC4_128_SHA,
+     SSL3_RFC_RSA_RC4_128_SHA,
+     SSL3_CK_RSA_RC4_128_SHA,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_RC4,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     SSL3_TXT_ADH_RC4_128_MD5,
+     SSL3_RFC_ADH_RC4_128_MD5,
+     SSL3_CK_ADH_RC4_128_MD5,
+     SSL_kDHE,
+     SSL_aNULL,
+     SSL_RC4,
+     SSL_MD5,
+     SSL3_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_PSK_WITH_RC4_128_SHA,
+     TLS1_RFC_ECDHE_PSK_WITH_RC4_128_SHA,
+     TLS1_CK_ECDHE_PSK_WITH_RC4_128_SHA,
+     SSL_kECDHEPSK,
+     SSL_aPSK,
+     SSL_RC4,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA,
+     TLS1_RFC_ECDH_anon_WITH_RC4_128_SHA,
+     TLS1_CK_ECDH_anon_WITH_RC4_128_SHA,
+     SSL_kECDHE,
+     SSL_aNULL,
+     SSL_RC4,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA,
+     TLS1_RFC_ECDHE_ECDSA_WITH_RC4_128_SHA,
+     TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_RC4,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA,
+     TLS1_RFC_ECDHE_RSA_WITH_RC4_128_SHA,
+     TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_RC4,
+     SSL_SHA1,
+     TLS1_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_RC4_128_SHA,
+     TLS1_RFC_PSK_WITH_RC4_128_SHA,
+     TLS1_CK_PSK_WITH_RC4_128_SHA,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_RC4,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_RC4_128_SHA,
+     TLS1_RFC_RSA_PSK_WITH_RC4_128_SHA,
+     TLS1_CK_RSA_PSK_WITH_RC4_128_SHA,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_RC4,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_RC4_128_SHA,
+     TLS1_RFC_DHE_PSK_WITH_RC4_128_SHA,
+     TLS1_CK_DHE_PSK_WITH_RC4_128_SHA,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_RC4,
+     SSL_SHA1,
+     SSL3_VERSION, TLS1_2_VERSION,
+     0, 0,
+     SSL_NOT_DEFAULT | SSL_MEDIUM,
+     SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF,
+     128,
+     128,
+     },
+#endif                          /* OPENSSL_NO_WEAK_SSL_CIPHERS */
+
+#ifndef OPENSSL_NO_ARIA
+    {
+     1,
+     TLS1_TXT_RSA_WITH_ARIA_128_GCM_SHA256,
+     TLS1_RFC_RSA_WITH_ARIA_128_GCM_SHA256,
+     TLS1_CK_RSA_WITH_ARIA_128_GCM_SHA256,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_ARIA128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_WITH_ARIA_256_GCM_SHA384,
+     TLS1_RFC_RSA_WITH_ARIA_256_GCM_SHA384,
+     TLS1_CK_RSA_WITH_ARIA_256_GCM_SHA384,
+     SSL_kRSA,
+     SSL_aRSA,
+     SSL_ARIA256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_ARIA_128_GCM_SHA256,
+     TLS1_RFC_DHE_RSA_WITH_ARIA_128_GCM_SHA256,
+     TLS1_CK_DHE_RSA_WITH_ARIA_128_GCM_SHA256,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_ARIA128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_RSA_WITH_ARIA_256_GCM_SHA384,
+     TLS1_RFC_DHE_RSA_WITH_ARIA_256_GCM_SHA384,
+     TLS1_CK_DHE_RSA_WITH_ARIA_256_GCM_SHA384,
+     SSL_kDHE,
+     SSL_aRSA,
+     SSL_ARIA256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_DSS_WITH_ARIA_128_GCM_SHA256,
+     TLS1_RFC_DHE_DSS_WITH_ARIA_128_GCM_SHA256,
+     TLS1_CK_DHE_DSS_WITH_ARIA_128_GCM_SHA256,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_ARIA128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_DSS_WITH_ARIA_256_GCM_SHA384,
+     TLS1_RFC_DHE_DSS_WITH_ARIA_256_GCM_SHA384,
+     TLS1_CK_DHE_DSS_WITH_ARIA_256_GCM_SHA384,
+     SSL_kDHE,
+     SSL_aDSS,
+     SSL_ARIA256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256,
+     TLS1_RFC_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256,
+     TLS1_CK_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_ARIA128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384,
+     TLS1_RFC_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384,
+     TLS1_CK_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384,
+     SSL_kECDHE,
+     SSL_aECDSA,
+     SSL_ARIA256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256,
+     TLS1_RFC_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256,
+     TLS1_CK_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_ARIA128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384,
+     TLS1_RFC_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384,
+     TLS1_CK_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384,
+     SSL_kECDHE,
+     SSL_aRSA,
+     SSL_ARIA256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_ARIA_128_GCM_SHA256,
+     TLS1_RFC_PSK_WITH_ARIA_128_GCM_SHA256,
+     TLS1_CK_PSK_WITH_ARIA_128_GCM_SHA256,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_ARIA128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_PSK_WITH_ARIA_256_GCM_SHA384,
+     TLS1_RFC_PSK_WITH_ARIA_256_GCM_SHA384,
+     TLS1_CK_PSK_WITH_ARIA_256_GCM_SHA384,
+     SSL_kPSK,
+     SSL_aPSK,
+     SSL_ARIA256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_ARIA_128_GCM_SHA256,
+     TLS1_RFC_DHE_PSK_WITH_ARIA_128_GCM_SHA256,
+     TLS1_CK_DHE_PSK_WITH_ARIA_128_GCM_SHA256,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_ARIA128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_DHE_PSK_WITH_ARIA_256_GCM_SHA384,
+     TLS1_RFC_DHE_PSK_WITH_ARIA_256_GCM_SHA384,
+     TLS1_CK_DHE_PSK_WITH_ARIA_256_GCM_SHA384,
+     SSL_kDHEPSK,
+     SSL_aPSK,
+     SSL_ARIA256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
+     TLS1_RFC_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
+     TLS1_CK_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_ARIA128GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
+     128,
+     128,
+     },
+    {
+     1,
+     TLS1_TXT_RSA_PSK_WITH_ARIA_256_GCM_SHA384,
+     TLS1_RFC_RSA_PSK_WITH_ARIA_256_GCM_SHA384,
+     TLS1_CK_RSA_PSK_WITH_ARIA_256_GCM_SHA384,
+     SSL_kRSAPSK,
+     SSL_aRSA,
+     SSL_ARIA256GCM,
+     SSL_AEAD,
+     TLS1_2_VERSION, TLS1_2_VERSION,
+     DTLS1_2_VERSION, DTLS1_2_VERSION,
+     SSL_NOT_DEFAULT | SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384,
+     256,
+     256,
+     },
+#endif /* OPENSSL_NO_ARIA */
+};
+
+/*
+ * The list of known Signalling Cipher-Suite Value "ciphers", non-valid
+ * values stuffed into the ciphers field of the wire protocol for signalling
+ * purposes.
+ */
+static SSL_CIPHER ssl3_scsvs[] = {
+    {
+     0,
+     "TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
+     "TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
+     SSL3_CK_SCSV,
+     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    },
+    {
+     0,
+     "TLS_FALLBACK_SCSV",
+     "TLS_FALLBACK_SCSV",
+     SSL3_CK_FALLBACK_SCSV,
+     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    },
+};
+
+static int cipher_compare(const void *a, const void *b)
+{
+    const SSL_CIPHER *ap = (const SSL_CIPHER *)a;
+    const SSL_CIPHER *bp = (const SSL_CIPHER *)b;
+
+    if (ap->id == bp->id)
+        return 0;
+    return ap->id < bp->id ? -1 : 1;
+}
+
+void ssl_sort_cipher_list(void)
+{
+    qsort(tls13_ciphers, TLS13_NUM_CIPHERS, sizeof(tls13_ciphers[0]),
+          cipher_compare);
+    qsort(ssl3_ciphers, SSL3_NUM_CIPHERS, sizeof(ssl3_ciphers[0]),
+          cipher_compare);
+    qsort(ssl3_scsvs, SSL3_NUM_SCSVS, sizeof(ssl3_scsvs[0]), cipher_compare);
+}
+
+static int ssl_undefined_function_1(SSL *ssl, unsigned char *r, size_t s,
+                                    const char * t, size_t u,
+                                    const unsigned char * v, size_t w, int x)
+{
+    (void)r;
+    (void)s;
+    (void)t;
+    (void)u;
+    (void)v;
+    (void)w;
+    (void)x;
+    return ssl_undefined_function(ssl);
+}
+
+const SSL3_ENC_METHOD SSLv3_enc_data = {
+    ssl3_enc,
+    n_ssl3_mac,
+    ssl3_setup_key_block,
+    ssl3_generate_master_secret,
+    ssl3_change_cipher_state,
+    ssl3_final_finish_mac,
+    SSL3_MD_CLIENT_FINISHED_CONST, 4,
+    SSL3_MD_SERVER_FINISHED_CONST, 4,
+    ssl3_alert_code,
+    ssl_undefined_function_1,
+    0,
+    ssl3_set_handshake_header,
+    tls_close_construct_packet,
+    ssl3_handshake_write
+};
+
+long ssl3_default_timeout(void)
+{
+    /*
+     * 2 hours, the 24 hours mentioned in the SSLv3 spec is way too long for
+     * http, the cache would over fill
+     */
+    return (60 * 60 * 2);
+}
+
+int ssl3_num_ciphers(void)
+{
+    return SSL3_NUM_CIPHERS;
+}
+
+const SSL_CIPHER *ssl3_get_cipher(unsigned int u)
+{
+    if (u < SSL3_NUM_CIPHERS)
+        return &(ssl3_ciphers[SSL3_NUM_CIPHERS - 1 - u]);
+    else
+        return NULL;
+}
+
+int ssl3_set_handshake_header(SSL *s, WPACKET *pkt, int htype)
+{
+    /* No header in the event of a CCS */
+    if (htype == SSL3_MT_CHANGE_CIPHER_SPEC)
+        return 1;
+
+    /* Set the content type and 3 bytes for the message len */
+    if (!WPACKET_put_bytes_u8(pkt, htype)
+            || !WPACKET_start_sub_packet_u24(pkt))
+        return 0;
+
+    return 1;
+}
+
+int ssl3_handshake_write(SSL *s)
+{
+    return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+}
+
+int ssl3_new(SSL *s)
+{
+    SSL3_STATE *s3;
+
+    if ((s3 = OPENSSL_zalloc(sizeof(*s3))) == NULL)
+        goto err;
+    s->s3 = s3;
+
+#ifndef OPENSSL_NO_SRP
+    if (!SSL_SRP_CTX_init(s))
+        goto err;
+#endif
+
+    if (!s->method->ssl_clear(s))
+        return 0;
+
+    return 1;
+ err:
+    return 0;
+}
+
+void ssl3_free(SSL *s)
+{
+    if (s == NULL || s->s3 == NULL)
+        return;
+
+    ssl3_cleanup_key_block(s);
+
+#if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)
+    EVP_PKEY_free(s->s3->peer_tmp);
+    s->s3->peer_tmp = NULL;
+    EVP_PKEY_free(s->s3->tmp.pkey);
+    s->s3->tmp.pkey = NULL;
+#endif
+
+    OPENSSL_free(s->s3->tmp.ctype);
+    sk_X509_NAME_pop_free(s->s3->tmp.peer_ca_names, X509_NAME_free);
+    OPENSSL_free(s->s3->tmp.ciphers_raw);
+    OPENSSL_clear_free(s->s3->tmp.pms, s->s3->tmp.pmslen);
+    OPENSSL_free(s->s3->tmp.peer_sigalgs);
+    OPENSSL_free(s->s3->tmp.peer_cert_sigalgs);
+    ssl3_free_digest_list(s);
+    OPENSSL_free(s->s3->alpn_selected);
+    OPENSSL_free(s->s3->alpn_proposed);
+
+#ifndef OPENSSL_NO_SRP
+    SSL_SRP_CTX_free(s);
+#endif
+    OPENSSL_clear_free(s->s3, sizeof(*s->s3));
+    s->s3 = NULL;
+}
+
+int ssl3_clear(SSL *s)
+{
+    ssl3_cleanup_key_block(s);
+    OPENSSL_free(s->s3->tmp.ctype);
+    sk_X509_NAME_pop_free(s->s3->tmp.peer_ca_names, X509_NAME_free);
+    OPENSSL_free(s->s3->tmp.ciphers_raw);
+    OPENSSL_clear_free(s->s3->tmp.pms, s->s3->tmp.pmslen);
+    OPENSSL_free(s->s3->tmp.peer_sigalgs);
+    OPENSSL_free(s->s3->tmp.peer_cert_sigalgs);
+
+#if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)
+    EVP_PKEY_free(s->s3->tmp.pkey);
+    EVP_PKEY_free(s->s3->peer_tmp);
+#endif                          /* !OPENSSL_NO_EC */
+
+    ssl3_free_digest_list(s);
+
+    OPENSSL_free(s->s3->alpn_selected);
+    OPENSSL_free(s->s3->alpn_proposed);
+
+    /* NULL/zero-out everything in the s3 struct */
+    memset(s->s3, 0, sizeof(*s->s3));
+
+    if (!ssl_free_wbio_buffer(s))
+        return 0;
+
+    s->version = SSL3_VERSION;
+
+#if !defined(OPENSSL_NO_NEXTPROTONEG)
+    OPENSSL_free(s->ext.npn);
+    s->ext.npn = NULL;
+    s->ext.npn_len = 0;
+#endif
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SRP
+static char *srp_password_from_info_cb(SSL *s, void *arg)
+{
+    return OPENSSL_strdup(s->srp_ctx.info);
+}
+#endif
+
+static int ssl3_set_req_cert_type(CERT *c, const unsigned char *p, size_t len);
+
+long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
+{
+    int ret = 0;
+
+    switch (cmd) {
+    case SSL_CTRL_GET_CLIENT_CERT_REQUEST:
+        break;
+    case SSL_CTRL_GET_NUM_RENEGOTIATIONS:
+        ret = s->s3->num_renegotiations;
+        break;
+    case SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS:
+        ret = s->s3->num_renegotiations;
+        s->s3->num_renegotiations = 0;
+        break;
+    case SSL_CTRL_GET_TOTAL_RENEGOTIATIONS:
+        ret = s->s3->total_renegotiations;
+        break;
+    case SSL_CTRL_GET_FLAGS:
+        ret = (int)(s->s3->flags);
+        break;
+#ifndef OPENSSL_NO_DH
+    case SSL_CTRL_SET_TMP_DH:
+        {
+            DH *dh = (DH *)parg;
+            EVP_PKEY *pkdh = NULL;
+            if (dh == NULL) {
+                SSLerr(SSL_F_SSL3_CTRL, ERR_R_PASSED_NULL_PARAMETER);
+                return ret;
+            }
+            pkdh = ssl_dh_to_pkey(dh);
+            if (pkdh == NULL) {
+                SSLerr(SSL_F_SSL3_CTRL, ERR_R_MALLOC_FAILURE);
+                return 0;
+            }
+            if (!ssl_security(s, SSL_SECOP_TMP_DH,
+                              EVP_PKEY_security_bits(pkdh), 0, pkdh)) {
+                SSLerr(SSL_F_SSL3_CTRL, SSL_R_DH_KEY_TOO_SMALL);
+                EVP_PKEY_free(pkdh);
+                return ret;
+            }
+            EVP_PKEY_free(s->cert->dh_tmp);
+            s->cert->dh_tmp = pkdh;
+            ret = 1;
+        }
+        break;
+    case SSL_CTRL_SET_TMP_DH_CB:
+        {
+            SSLerr(SSL_F_SSL3_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+            return ret;
+        }
+    case SSL_CTRL_SET_DH_AUTO:
+        s->cert->dh_tmp_auto = larg;
+        return 1;
+#endif
+#ifndef OPENSSL_NO_EC
+    case SSL_CTRL_SET_TMP_ECDH:
+        {
+            const EC_GROUP *group = NULL;
+            int nid;
+
+            if (parg == NULL) {
+                SSLerr(SSL_F_SSL3_CTRL, ERR_R_PASSED_NULL_PARAMETER);
+                return 0;
+            }
+            group = EC_KEY_get0_group((const EC_KEY *)parg);
+            if (group == NULL) {
+                SSLerr(SSL_F_SSL3_CTRL, EC_R_MISSING_PARAMETERS);
+                return 0;
+            }
+            nid = EC_GROUP_get_curve_name(group);
+            if (nid == NID_undef)
+                return 0;
+            return tls1_set_groups(&s->ext.supportedgroups,
+                                   &s->ext.supportedgroups_len,
+                                   &nid, 1);
+        }
+        break;
+#endif                          /* !OPENSSL_NO_EC */
+    case SSL_CTRL_SET_TLSEXT_HOSTNAME:
+        /*
+         * TODO(OpenSSL1.2)
+         * This API is only used for a client to set what SNI it will request
+         * from the server, but we currently allow it to be used on servers
+         * as well, which is a programming error.  Currently we just clear
+         * the field in SSL_do_handshake() for server SSLs, but when we can
+         * make ABI-breaking changes, we may want to make use of this API
+         * an error on server SSLs.
+         */
+        if (larg == TLSEXT_NAMETYPE_host_name) {
+            size_t len;
+
+            OPENSSL_free(s->ext.hostname);
+            s->ext.hostname = NULL;
+
+            ret = 1;
+            if (parg == NULL)
+                break;
+            len = strlen((char *)parg);
+            if (len == 0 || len > TLSEXT_MAXLEN_host_name) {
+                SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME);
+                return 0;
+            }
+            if ((s->ext.hostname = OPENSSL_strdup((char *)parg)) == NULL) {
+                SSLerr(SSL_F_SSL3_CTRL, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        } else {
+            SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE);
+            return 0;
+        }
+        break;
+    case SSL_CTRL_SET_TLSEXT_DEBUG_ARG:
+        s->ext.debug_arg = parg;
+        ret = 1;
+        break;
+
+    case SSL_CTRL_GET_TLSEXT_STATUS_REQ_TYPE:
+        ret = s->ext.status_type;
+        break;
+
+    case SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE:
+        s->ext.status_type = larg;
+        ret = 1;
+        break;
+
+    case SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS:
+        *(STACK_OF(X509_EXTENSION) **)parg = s->ext.ocsp.exts;
+        ret = 1;
+        break;
+
+    case SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS:
+        s->ext.ocsp.exts = parg;
+        ret = 1;
+        break;
+
+    case SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS:
+        *(STACK_OF(OCSP_RESPID) **)parg = s->ext.ocsp.ids;
+        ret = 1;
+        break;
+
+    case SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS:
+        s->ext.ocsp.ids = parg;
+        ret = 1;
+        break;
+
+    case SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP:
+        *(unsigned char **)parg = s->ext.ocsp.resp;
+        if (s->ext.ocsp.resp_len == 0
+                || s->ext.ocsp.resp_len > LONG_MAX)
+            return -1;
+        return (long)s->ext.ocsp.resp_len;
+
+    case SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP:
+        OPENSSL_free(s->ext.ocsp.resp);
+        s->ext.ocsp.resp = parg;
+        s->ext.ocsp.resp_len = larg;
+        ret = 1;
+        break;
+
+#ifndef OPENSSL_NO_HEARTBEATS
+    case SSL_CTRL_DTLS_EXT_SEND_HEARTBEAT:
+    case SSL_CTRL_GET_DTLS_EXT_HEARTBEAT_PENDING:
+    case SSL_CTRL_SET_DTLS_EXT_HEARTBEAT_NO_REQUESTS:
+        break;
+#endif
+
+    case SSL_CTRL_CHAIN:
+        if (larg)
+            return ssl_cert_set1_chain(s, NULL, (STACK_OF(X509) *)parg);
+        else
+            return ssl_cert_set0_chain(s, NULL, (STACK_OF(X509) *)parg);
+
+    case SSL_CTRL_CHAIN_CERT:
+        if (larg)
+            return ssl_cert_add1_chain_cert(s, NULL, (X509 *)parg);
+        else
+            return ssl_cert_add0_chain_cert(s, NULL, (X509 *)parg);
+
+    case SSL_CTRL_GET_CHAIN_CERTS:
+        *(STACK_OF(X509) **)parg = s->cert->key->chain;
+        ret = 1;
+        break;
+
+    case SSL_CTRL_SELECT_CURRENT_CERT:
+        return ssl_cert_select_current(s->cert, (X509 *)parg);
+
+    case SSL_CTRL_SET_CURRENT_CERT:
+        if (larg == SSL_CERT_SET_SERVER) {
+            const SSL_CIPHER *cipher;
+            if (!s->server)
+                return 0;
+            cipher = s->s3->tmp.new_cipher;
+            if (cipher == NULL)
+                return 0;
+            /*
+             * No certificate for unauthenticated ciphersuites or using SRP
+             * authentication
+             */
+            if (cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP))
+                return 2;
+            if (s->s3->tmp.cert == NULL)
+                return 0;
+            s->cert->key = s->s3->tmp.cert;
+            return 1;
+        }
+        return ssl_cert_set_current(s->cert, larg);
+
+#ifndef OPENSSL_NO_EC
+    case SSL_CTRL_GET_GROUPS:
+        {
+            uint16_t *clist;
+            size_t clistlen;
+
+            if (!s->session)
+                return 0;
+            clist = s->ext.peer_supportedgroups;
+            clistlen = s->ext.peer_supportedgroups_len;
+            if (parg) {
+                size_t i;
+                int *cptr = parg;
+
+                for (i = 0; i < clistlen; i++) {
+                    const TLS_GROUP_INFO *cinf = tls1_group_id_lookup(clist[i]);
+
+                    if (cinf != NULL)
+                        cptr[i] = cinf->nid;
+                    else
+                        cptr[i] = TLSEXT_nid_unknown | clist[i];
+                }
+            }
+            return (int)clistlen;
+        }
+
+    case SSL_CTRL_SET_GROUPS:
+        return tls1_set_groups(&s->ext.supportedgroups,
+                               &s->ext.supportedgroups_len, parg, larg);
+
+    case SSL_CTRL_SET_GROUPS_LIST:
+        return tls1_set_groups_list(&s->ext.supportedgroups,
+                                    &s->ext.supportedgroups_len, parg);
+
+    case SSL_CTRL_GET_SHARED_GROUP:
+        {
+            uint16_t id = tls1_shared_group(s, larg);
+
+            if (larg != -1) {
+                const TLS_GROUP_INFO *ginf = tls1_group_id_lookup(id);
+
+                return ginf == NULL ? 0 : ginf->nid;
+            }
+            return id;
+        }
+#endif
+    case SSL_CTRL_SET_SIGALGS:
+        return tls1_set_sigalgs(s->cert, parg, larg, 0);
+
+    case SSL_CTRL_SET_SIGALGS_LIST:
+        return tls1_set_sigalgs_list(s->cert, parg, 0);
+
+    case SSL_CTRL_SET_CLIENT_SIGALGS:
+        return tls1_set_sigalgs(s->cert, parg, larg, 1);
+
+    case SSL_CTRL_SET_CLIENT_SIGALGS_LIST:
+        return tls1_set_sigalgs_list(s->cert, parg, 1);
+
+    case SSL_CTRL_GET_CLIENT_CERT_TYPES:
+        {
+            const unsigned char **pctype = parg;
+            if (s->server || !s->s3->tmp.cert_req)
+                return 0;
+            if (pctype)
+                *pctype = s->s3->tmp.ctype;
+            return s->s3->tmp.ctype_len;
+        }
+
+    case SSL_CTRL_SET_CLIENT_CERT_TYPES:
+        if (!s->server)
+            return 0;
+        return ssl3_set_req_cert_type(s->cert, parg, larg);
+
+    case SSL_CTRL_BUILD_CERT_CHAIN:
+        return ssl_build_cert_chain(s, NULL, larg);
+
+    case SSL_CTRL_SET_VERIFY_CERT_STORE:
+        return ssl_cert_set_cert_store(s->cert, parg, 0, larg);
+
+    case SSL_CTRL_SET_CHAIN_CERT_STORE:
+        return ssl_cert_set_cert_store(s->cert, parg, 1, larg);
+
+    case SSL_CTRL_GET_VERIFY_CERT_STORE:
+        return ssl_cert_get_cert_store(s->cert, parg, 0);
+
+    case SSL_CTRL_GET_CHAIN_CERT_STORE:
+        return ssl_cert_get_cert_store(s->cert, parg, 1);
+
+    case SSL_CTRL_GET_PEER_SIGNATURE_NID:
+        if (s->s3->tmp.peer_sigalg == NULL)
+            return 0;
+        *(int *)parg = s->s3->tmp.peer_sigalg->hash;
+        return 1;
+
+    case SSL_CTRL_GET_SIGNATURE_NID:
+        if (s->s3->tmp.sigalg == NULL)
+            return 0;
+        *(int *)parg = s->s3->tmp.sigalg->hash;
+        return 1;
+
+    case SSL_CTRL_GET_PEER_TMP_KEY:
+#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_EC)
+        if (s->session == NULL || s->s3->peer_tmp == NULL) {
+            return 0;
+        } else {
+            EVP_PKEY_up_ref(s->s3->peer_tmp);
+            *(EVP_PKEY **)parg = s->s3->peer_tmp;
+            return 1;
+        }
+#else
+        return 0;
+#endif
+
+    case SSL_CTRL_GET_TMP_KEY:
+#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_EC)
+        if (s->session == NULL || s->s3->tmp.pkey == NULL) {
+            return 0;
+        } else {
+            EVP_PKEY_up_ref(s->s3->tmp.pkey);
+            *(EVP_PKEY **)parg = s->s3->tmp.pkey;
+            return 1;
+        }
+#else
+        return 0;
+#endif
+
+#ifndef OPENSSL_NO_EC
+    case SSL_CTRL_GET_EC_POINT_FORMATS:
+        {
+            const unsigned char **pformat = parg;
+
+            if (s->ext.peer_ecpointformats == NULL)
+                return 0;
+            *pformat = s->ext.peer_ecpointformats;
+            return (int)s->ext.peer_ecpointformats_len;
+        }
+#endif
+
+    default:
+        break;
+    }
+    return ret;
+}
+
+long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp) (void))
+{
+    int ret = 0;
+
+    switch (cmd) {
+#ifndef OPENSSL_NO_DH
+    case SSL_CTRL_SET_TMP_DH_CB:
+        {
+            s->cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp;
+        }
+        break;
+#endif
+    case SSL_CTRL_SET_TLSEXT_DEBUG_CB:
+        s->ext.debug_cb = (void (*)(SSL *, int, int,
+                                    const unsigned char *, int, void *))fp;
+        break;
+
+    case SSL_CTRL_SET_NOT_RESUMABLE_SESS_CB:
+        {
+            s->not_resumable_session_cb = (int (*)(SSL *, int))fp;
+        }
+        break;
+    default:
+        break;
+    }
+    return ret;
+}
+
+long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
+{
+    switch (cmd) {
+#ifndef OPENSSL_NO_DH
+    case SSL_CTRL_SET_TMP_DH:
+        {
+            DH *dh = (DH *)parg;
+            EVP_PKEY *pkdh = NULL;
+            if (dh == NULL) {
+                SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_PASSED_NULL_PARAMETER);
+                return 0;
+            }
+            pkdh = ssl_dh_to_pkey(dh);
+            if (pkdh == NULL) {
+                SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_MALLOC_FAILURE);
+                return 0;
+            }
+            if (!ssl_ctx_security(ctx, SSL_SECOP_TMP_DH,
+                                  EVP_PKEY_security_bits(pkdh), 0, pkdh)) {
+                SSLerr(SSL_F_SSL3_CTX_CTRL, SSL_R_DH_KEY_TOO_SMALL);
+                EVP_PKEY_free(pkdh);
+                return 0;
+            }
+            EVP_PKEY_free(ctx->cert->dh_tmp);
+            ctx->cert->dh_tmp = pkdh;
+            return 1;
+        }
+    case SSL_CTRL_SET_TMP_DH_CB:
+        {
+            SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+            return 0;
+        }
+    case SSL_CTRL_SET_DH_AUTO:
+        ctx->cert->dh_tmp_auto = larg;
+        return 1;
+#endif
+#ifndef OPENSSL_NO_EC
+    case SSL_CTRL_SET_TMP_ECDH:
+        {
+            const EC_GROUP *group = NULL;
+            int nid;
+
+            if (parg == NULL) {
+                SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_PASSED_NULL_PARAMETER);
+                return 0;
+            }
+            group = EC_KEY_get0_group((const EC_KEY *)parg);
+            if (group == NULL) {
+                SSLerr(SSL_F_SSL3_CTX_CTRL, EC_R_MISSING_PARAMETERS);
+                return 0;
+            }
+            nid = EC_GROUP_get_curve_name(group);
+            if (nid == NID_undef)
+                return 0;
+            return tls1_set_groups(&ctx->ext.supportedgroups,
+                                   &ctx->ext.supportedgroups_len,
+                                   &nid, 1);
+        }
+#endif                          /* !OPENSSL_NO_EC */
+    case SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG:
+        ctx->ext.servername_arg = parg;
+        break;
+    case SSL_CTRL_SET_TLSEXT_TICKET_KEYS:
+    case SSL_CTRL_GET_TLSEXT_TICKET_KEYS:
+        {
+            unsigned char *keys = parg;
+            long tick_keylen = (sizeof(ctx->ext.tick_key_name) +
+                                sizeof(ctx->ext.secure->tick_hmac_key) +
+                                sizeof(ctx->ext.secure->tick_aes_key));
+            if (keys == NULL)
+                return tick_keylen;
+            if (larg != tick_keylen) {
+                SSLerr(SSL_F_SSL3_CTX_CTRL, SSL_R_INVALID_TICKET_KEYS_LENGTH);
+                return 0;
+            }
+            if (cmd == SSL_CTRL_SET_TLSEXT_TICKET_KEYS) {
+                memcpy(ctx->ext.tick_key_name, keys,
+                       sizeof(ctx->ext.tick_key_name));
+                memcpy(ctx->ext.secure->tick_hmac_key,
+                       keys + sizeof(ctx->ext.tick_key_name),
+                       sizeof(ctx->ext.secure->tick_hmac_key));
+                memcpy(ctx->ext.secure->tick_aes_key,
+                       keys + sizeof(ctx->ext.tick_key_name) +
+                       sizeof(ctx->ext.secure->tick_hmac_key),
+                       sizeof(ctx->ext.secure->tick_aes_key));
+            } else {
+                memcpy(keys, ctx->ext.tick_key_name,
+                       sizeof(ctx->ext.tick_key_name));
+                memcpy(keys + sizeof(ctx->ext.tick_key_name),
+                       ctx->ext.secure->tick_hmac_key,
+                       sizeof(ctx->ext.secure->tick_hmac_key));
+                memcpy(keys + sizeof(ctx->ext.tick_key_name) +
+                       sizeof(ctx->ext.secure->tick_hmac_key),
+                       ctx->ext.secure->tick_aes_key,
+                       sizeof(ctx->ext.secure->tick_aes_key));
+            }
+            return 1;
+        }
+
+    case SSL_CTRL_GET_TLSEXT_STATUS_REQ_TYPE:
+        return ctx->ext.status_type;
+
+    case SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE:
+        ctx->ext.status_type = larg;
+        break;
+
+    case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG:
+        ctx->ext.status_arg = parg;
+        return 1;
+
+    case SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB_ARG:
+        *(void**)parg = ctx->ext.status_arg;
+        break;
+
+    case SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB:
+        *(int (**)(SSL*, void*))parg = ctx->ext.status_cb;
+        break;
+
+#ifndef OPENSSL_NO_SRP
+    case SSL_CTRL_SET_TLS_EXT_SRP_USERNAME:
+        ctx->srp_ctx.srp_Mask |= SSL_kSRP;
+        OPENSSL_free(ctx->srp_ctx.login);
+        ctx->srp_ctx.login = NULL;
+        if (parg == NULL)
+            break;
+        if (strlen((const char *)parg) > 255 || strlen((const char *)parg) < 1) {
+            SSLerr(SSL_F_SSL3_CTX_CTRL, SSL_R_INVALID_SRP_USERNAME);
+            return 0;
+        }
+        if ((ctx->srp_ctx.login = OPENSSL_strdup((char *)parg)) == NULL) {
+            SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        break;
+    case SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD:
+        ctx->srp_ctx.SRP_give_srp_client_pwd_callback =
+            srp_password_from_info_cb;
+        if (ctx->srp_ctx.info != NULL)
+            OPENSSL_free(ctx->srp_ctx.info);
+        if ((ctx->srp_ctx.info = BUF_strdup((char *)parg)) == NULL) {
+            SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        break;
+    case SSL_CTRL_SET_SRP_ARG:
+        ctx->srp_ctx.srp_Mask |= SSL_kSRP;
+        ctx->srp_ctx.SRP_cb_arg = parg;
+        break;
+
+    case SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH:
+        ctx->srp_ctx.strength = larg;
+        break;
+#endif
+
+#ifndef OPENSSL_NO_EC
+    case SSL_CTRL_SET_GROUPS:
+        return tls1_set_groups(&ctx->ext.supportedgroups,
+                               &ctx->ext.supportedgroups_len,
+                               parg, larg);
+
+    case SSL_CTRL_SET_GROUPS_LIST:
+        return tls1_set_groups_list(&ctx->ext.supportedgroups,
+                                    &ctx->ext.supportedgroups_len,
+                                    parg);
+#endif
+    case SSL_CTRL_SET_SIGALGS:
+        return tls1_set_sigalgs(ctx->cert, parg, larg, 0);
+
+    case SSL_CTRL_SET_SIGALGS_LIST:
+        return tls1_set_sigalgs_list(ctx->cert, parg, 0);
+
+    case SSL_CTRL_SET_CLIENT_SIGALGS:
+        return tls1_set_sigalgs(ctx->cert, parg, larg, 1);
+
+    case SSL_CTRL_SET_CLIENT_SIGALGS_LIST:
+        return tls1_set_sigalgs_list(ctx->cert, parg, 1);
+
+    case SSL_CTRL_SET_CLIENT_CERT_TYPES:
+        return ssl3_set_req_cert_type(ctx->cert, parg, larg);
+
+    case SSL_CTRL_BUILD_CERT_CHAIN:
+        return ssl_build_cert_chain(NULL, ctx, larg);
+
+    case SSL_CTRL_SET_VERIFY_CERT_STORE:
+        return ssl_cert_set_cert_store(ctx->cert, parg, 0, larg);
+
+    case SSL_CTRL_SET_CHAIN_CERT_STORE:
+        return ssl_cert_set_cert_store(ctx->cert, parg, 1, larg);
+
+    case SSL_CTRL_GET_VERIFY_CERT_STORE:
+        return ssl_cert_get_cert_store(ctx->cert, parg, 0);
+
+    case SSL_CTRL_GET_CHAIN_CERT_STORE:
+        return ssl_cert_get_cert_store(ctx->cert, parg, 1);
+
+        /* A Thawte special :-) */
+    case SSL_CTRL_EXTRA_CHAIN_CERT:
+        if (ctx->extra_certs == NULL) {
+            if ((ctx->extra_certs = sk_X509_new_null()) == NULL) {
+                SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_MALLOC_FAILURE);
+                return 0;
+            }
+        }
+        if (!sk_X509_push(ctx->extra_certs, (X509 *)parg)) {
+            SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        break;
+
+    case SSL_CTRL_GET_EXTRA_CHAIN_CERTS:
+        if (ctx->extra_certs == NULL && larg == 0)
+            *(STACK_OF(X509) **)parg = ctx->cert->key->chain;
+        else
+            *(STACK_OF(X509) **)parg = ctx->extra_certs;
+        break;
+
+    case SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS:
+        sk_X509_pop_free(ctx->extra_certs, X509_free);
+        ctx->extra_certs = NULL;
+        break;
+
+    case SSL_CTRL_CHAIN:
+        if (larg)
+            return ssl_cert_set1_chain(NULL, ctx, (STACK_OF(X509) *)parg);
+        else
+            return ssl_cert_set0_chain(NULL, ctx, (STACK_OF(X509) *)parg);
+
+    case SSL_CTRL_CHAIN_CERT:
+        if (larg)
+            return ssl_cert_add1_chain_cert(NULL, ctx, (X509 *)parg);
+        else
+            return ssl_cert_add0_chain_cert(NULL, ctx, (X509 *)parg);
+
+    case SSL_CTRL_GET_CHAIN_CERTS:
+        *(STACK_OF(X509) **)parg = ctx->cert->key->chain;
+        break;
+
+    case SSL_CTRL_SELECT_CURRENT_CERT:
+        return ssl_cert_select_current(ctx->cert, (X509 *)parg);
+
+    case SSL_CTRL_SET_CURRENT_CERT:
+        return ssl_cert_set_current(ctx->cert, larg);
+
+    default:
+        return 0;
+    }
+    return 1;
+}
+
+long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp) (void))
+{
+    switch (cmd) {
+#ifndef OPENSSL_NO_DH
+    case SSL_CTRL_SET_TMP_DH_CB:
+        {
+            ctx->cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp;
+        }
+        break;
+#endif
+    case SSL_CTRL_SET_TLSEXT_SERVERNAME_CB:
+        ctx->ext.servername_cb = (int (*)(SSL *, int *, void *))fp;
+        break;
+
+    case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB:
+        ctx->ext.status_cb = (int (*)(SSL *, void *))fp;
+        break;
+
+    case SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB:
+        ctx->ext.ticket_key_cb = (int (*)(SSL *, unsigned char *,
+                                             unsigned char *,
+                                             EVP_CIPHER_CTX *,
+                                             HMAC_CTX *, int))fp;
+        break;
+
+#ifndef OPENSSL_NO_SRP
+    case SSL_CTRL_SET_SRP_VERIFY_PARAM_CB:
+        ctx->srp_ctx.srp_Mask |= SSL_kSRP;
+        ctx->srp_ctx.SRP_verify_param_callback = (int (*)(SSL *, void *))fp;
+        break;
+    case SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB:
+        ctx->srp_ctx.srp_Mask |= SSL_kSRP;
+        ctx->srp_ctx.TLS_ext_srp_username_callback =
+            (int (*)(SSL *, int *, void *))fp;
+        break;
+    case SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB:
+        ctx->srp_ctx.srp_Mask |= SSL_kSRP;
+        ctx->srp_ctx.SRP_give_srp_client_pwd_callback =
+            (char *(*)(SSL *, void *))fp;
+        break;
+#endif
+    case SSL_CTRL_SET_NOT_RESUMABLE_SESS_CB:
+        {
+            ctx->not_resumable_session_cb = (int (*)(SSL *, int))fp;
+        }
+        break;
+    default:
+        return 0;
+    }
+    return 1;
+}
+
+const SSL_CIPHER *ssl3_get_cipher_by_id(uint32_t id)
+{
+    SSL_CIPHER c;
+    const SSL_CIPHER *cp;
+
+    c.id = id;
+    cp = OBJ_bsearch_ssl_cipher_id(&c, tls13_ciphers, TLS13_NUM_CIPHERS);
+    if (cp != NULL)
+        return cp;
+    cp = OBJ_bsearch_ssl_cipher_id(&c, ssl3_ciphers, SSL3_NUM_CIPHERS);
+    if (cp != NULL)
+        return cp;
+    return OBJ_bsearch_ssl_cipher_id(&c, ssl3_scsvs, SSL3_NUM_SCSVS);
+}
+
+const SSL_CIPHER *ssl3_get_cipher_by_std_name(const char *stdname)
+{
+    SSL_CIPHER *tbl;
+    SSL_CIPHER *alltabs[] = {tls13_ciphers, ssl3_ciphers, ssl3_scsvs};
+    size_t i, j, tblsize[] = {TLS13_NUM_CIPHERS, SSL3_NUM_CIPHERS,
+                              SSL3_NUM_SCSVS};
+
+    /* this is not efficient, necessary to optimize this? */
+    for (j = 0; j < OSSL_NELEM(alltabs); j++) {
+        for (i = 0, tbl = alltabs[j]; i < tblsize[j]; i++, tbl++) {
+            if (tbl->stdname == NULL)
+                continue;
+            if (strcmp(stdname, tbl->stdname) == 0) {
+                return tbl;
+            }
+        }
+    }
+    return NULL;
+}
+
+/*
+ * This function needs to check if the ciphers required are actually
+ * available
+ */
+const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p)
+{
+    return ssl3_get_cipher_by_id(SSL3_CK_CIPHERSUITE_FLAG
+                                 | ((uint32_t)p[0] << 8L)
+                                 | (uint32_t)p[1]);
+}
+
+int ssl3_put_cipher_by_char(const SSL_CIPHER *c, WPACKET *pkt, size_t *len)
+{
+    if ((c->id & 0xff000000) != SSL3_CK_CIPHERSUITE_FLAG) {
+        *len = 0;
+        return 1;
+    }
+
+    if (!WPACKET_put_bytes_u16(pkt, c->id & 0xffff))
+        return 0;
+
+    *len = 2;
+    return 1;
+}
+
+/*
+ * ssl3_choose_cipher - choose a cipher from those offered by the client
+ * @s: SSL connection
+ * @clnt: ciphers offered by the client
+ * @srvr: ciphers enabled on the server?
+ *
+ * Returns the selected cipher or NULL when no common ciphers.
+ */
+const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
+                                     STACK_OF(SSL_CIPHER) *srvr)
+{
+    const SSL_CIPHER *c, *ret = NULL;
+    STACK_OF(SSL_CIPHER) *prio, *allow;
+    int i, ii, ok, prefer_sha256 = 0;
+    unsigned long alg_k = 0, alg_a = 0, mask_k = 0, mask_a = 0;
+    const EVP_MD *mdsha256 = EVP_sha256();
+#ifndef OPENSSL_NO_CHACHA
+    STACK_OF(SSL_CIPHER) *prio_chacha = NULL;
+#endif
+
+    /* Let's see which ciphers we can support */
+
+    /*
+     * Do not set the compare functions, because this may lead to a
+     * reordering by "id". We want to keep the original ordering. We may pay
+     * a price in performance during sk_SSL_CIPHER_find(), but would have to
+     * pay with the price of sk_SSL_CIPHER_dup().
+     */
+
+#ifdef CIPHER_DEBUG
+    fprintf(stderr, "Server has %d from %p:\n", sk_SSL_CIPHER_num(srvr),
+            (void *)srvr);
+    for (i = 0; i < sk_SSL_CIPHER_num(srvr); ++i) {
+        c = sk_SSL_CIPHER_value(srvr, i);
+        fprintf(stderr, "%p:%s\n", (void *)c, c->name);
+    }
+    fprintf(stderr, "Client sent %d from %p:\n", sk_SSL_CIPHER_num(clnt),
+            (void *)clnt);
+    for (i = 0; i < sk_SSL_CIPHER_num(clnt); ++i) {
+        c = sk_SSL_CIPHER_value(clnt, i);
+        fprintf(stderr, "%p:%s\n", (void *)c, c->name);
+    }
+#endif
+
+    /* SUITE-B takes precedence over server preference and ChaCha priortiy */
+    if (tls1_suiteb(s)) {
+        prio = srvr;
+        allow = clnt;
+    } else if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) {
+        prio = srvr;
+        allow = clnt;
+#ifndef OPENSSL_NO_CHACHA
+        /* If ChaCha20 is at the top of the client preference list,
+           and there are ChaCha20 ciphers in the server list, then
+           temporarily prioritize all ChaCha20 ciphers in the servers list. */
+        if (s->options & SSL_OP_PRIORITIZE_CHACHA && sk_SSL_CIPHER_num(clnt) > 0) {
+            c = sk_SSL_CIPHER_value(clnt, 0);
+            if (c->algorithm_enc == SSL_CHACHA20POLY1305) {
+                /* ChaCha20 is client preferred, check server... */
+                int num = sk_SSL_CIPHER_num(srvr);
+                int found = 0;
+                for (i = 0; i < num; i++) {
+                    c = sk_SSL_CIPHER_value(srvr, i);
+                    if (c->algorithm_enc == SSL_CHACHA20POLY1305) {
+                        found = 1;
+                        break;
+                    }
+                }
+                if (found) {
+                    prio_chacha = sk_SSL_CIPHER_new_reserve(NULL, num);
+                    /* if reserve fails, then there's likely a memory issue */
+                    if (prio_chacha != NULL) {
+                        /* Put all ChaCha20 at the top, starting with the one we just found */
+                        sk_SSL_CIPHER_push(prio_chacha, c);
+                        for (i++; i < num; i++) {
+                            c = sk_SSL_CIPHER_value(srvr, i);
+                            if (c->algorithm_enc == SSL_CHACHA20POLY1305)
+                                sk_SSL_CIPHER_push(prio_chacha, c);
+                        }
+                        /* Pull in the rest */
+                        for (i = 0; i < num; i++) {
+                            c = sk_SSL_CIPHER_value(srvr, i);
+                            if (c->algorithm_enc != SSL_CHACHA20POLY1305)
+                                sk_SSL_CIPHER_push(prio_chacha, c);
+                        }
+                        prio = prio_chacha;
+                    }
+                }
+            }
+        }
+# endif
+    } else {
+        prio = clnt;
+        allow = srvr;
+    }
+
+    if (SSL_IS_TLS13(s)) {
+#ifndef OPENSSL_NO_PSK
+        int j;
+
+        /*
+         * If we allow "old" style PSK callbacks, and we have no certificate (so
+         * we're not going to succeed without a PSK anyway), and we're in
+         * TLSv1.3 then the default hash for a PSK is SHA-256 (as per the
+         * TLSv1.3 spec). Therefore we should prioritise ciphersuites using
+         * that.
+         */
+        if (s->psk_server_callback != NULL) {
+            for (j = 0; j < SSL_PKEY_NUM && !ssl_has_cert(s, j); j++);
+            if (j == SSL_PKEY_NUM) {
+                /* There are no certificates */
+                prefer_sha256 = 1;
+            }
+        }
+#endif
+    } else {
+        tls1_set_cert_validity(s);
+        ssl_set_masks(s);
+    }
+
+    for (i = 0; i < sk_SSL_CIPHER_num(prio); i++) {
+        c = sk_SSL_CIPHER_value(prio, i);
+
+        /* Skip ciphers not supported by the protocol version */
+        if (!SSL_IS_DTLS(s) &&
+            ((s->version < c->min_tls) || (s->version > c->max_tls)))
+            continue;
+        if (SSL_IS_DTLS(s) &&
+            (DTLS_VERSION_LT(s->version, c->min_dtls) ||
+             DTLS_VERSION_GT(s->version, c->max_dtls)))
+            continue;
+
+        /*
+         * Since TLS 1.3 ciphersuites can be used with any auth or
+         * key exchange scheme skip tests.
+         */
+        if (!SSL_IS_TLS13(s)) {
+            mask_k = s->s3->tmp.mask_k;
+            mask_a = s->s3->tmp.mask_a;
+#ifndef OPENSSL_NO_SRP
+            if (s->srp_ctx.srp_Mask & SSL_kSRP) {
+                mask_k |= SSL_kSRP;
+                mask_a |= SSL_aSRP;
+            }
+#endif
+
+            alg_k = c->algorithm_mkey;
+            alg_a = c->algorithm_auth;
+
+#ifndef OPENSSL_NO_PSK
+            /* with PSK there must be server callback set */
+            if ((alg_k & SSL_PSK) && s->psk_server_callback == NULL)
+                continue;
+#endif                          /* OPENSSL_NO_PSK */
+
+            ok = (alg_k & mask_k) && (alg_a & mask_a);
+#ifdef CIPHER_DEBUG
+            fprintf(stderr, "%d:[%08lX:%08lX:%08lX:%08lX]%p:%s\n", ok, alg_k,
+                    alg_a, mask_k, mask_a, (void *)c, c->name);
+#endif
+
+#ifndef OPENSSL_NO_EC
+            /*
+             * if we are considering an ECC cipher suite that uses an ephemeral
+             * EC key check it
+             */
+            if (alg_k & SSL_kECDHE)
+                ok = ok && tls1_check_ec_tmp_key(s, c->id);
+#endif                          /* OPENSSL_NO_EC */
+
+            if (!ok)
+                continue;
+        }
+        ii = sk_SSL_CIPHER_find(allow, c);
+        if (ii >= 0) {
+            /* Check security callback permits this cipher */
+            if (!ssl_security(s, SSL_SECOP_CIPHER_SHARED,
+                              c->strength_bits, 0, (void *)c))
+                continue;
+#if !defined(OPENSSL_NO_EC)
+            if ((alg_k & SSL_kECDHE) && (alg_a & SSL_aECDSA)
+                && s->s3->is_probably_safari) {
+                if (!ret)
+                    ret = sk_SSL_CIPHER_value(allow, ii);
+                continue;
+            }
+#endif
+            if (prefer_sha256) {
+                const SSL_CIPHER *tmp = sk_SSL_CIPHER_value(allow, ii);
+
+                if (ssl_md(tmp->algorithm2) == mdsha256) {
+                    ret = tmp;
+                    break;
+                }
+                if (ret == NULL)
+                    ret = tmp;
+                continue;
+            }
+            ret = sk_SSL_CIPHER_value(allow, ii);
+            break;
+        }
+    }
+#ifndef OPENSSL_NO_CHACHA
+    sk_SSL_CIPHER_free(prio_chacha);
+#endif
+    return ret;
+}
+
+int ssl3_get_req_cert_type(SSL *s, WPACKET *pkt)
+{
+    uint32_t alg_k, alg_a = 0;
+
+    /* If we have custom certificate types set, use them */
+    if (s->cert->ctype)
+        return WPACKET_memcpy(pkt, s->cert->ctype, s->cert->ctype_len);
+    /* Get mask of algorithms disabled by signature list */
+    ssl_set_sig_mask(&alg_a, s, SSL_SECOP_SIGALG_MASK);
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+#ifndef OPENSSL_NO_GOST
+    if (s->version >= TLS1_VERSION && (alg_k & SSL_kGOST))
+            return WPACKET_put_bytes_u8(pkt, TLS_CT_GOST01_SIGN)
+                    && WPACKET_put_bytes_u8(pkt, TLS_CT_GOST12_SIGN)
+                    && WPACKET_put_bytes_u8(pkt, TLS_CT_GOST12_512_SIGN);
+#endif
+
+    if ((s->version == SSL3_VERSION) && (alg_k & SSL_kDHE)) {
+#ifndef OPENSSL_NO_DH
+# ifndef OPENSSL_NO_RSA
+        if (!WPACKET_put_bytes_u8(pkt, SSL3_CT_RSA_EPHEMERAL_DH))
+            return 0;
+# endif
+# ifndef OPENSSL_NO_DSA
+        if (!WPACKET_put_bytes_u8(pkt, SSL3_CT_DSS_EPHEMERAL_DH))
+            return 0;
+# endif
+#endif                          /* !OPENSSL_NO_DH */
+    }
+#ifndef OPENSSL_NO_RSA
+    if (!(alg_a & SSL_aRSA) && !WPACKET_put_bytes_u8(pkt, SSL3_CT_RSA_SIGN))
+        return 0;
+#endif
+#ifndef OPENSSL_NO_DSA
+    if (!(alg_a & SSL_aDSS) && !WPACKET_put_bytes_u8(pkt, SSL3_CT_DSS_SIGN))
+        return 0;
+#endif
+#ifndef OPENSSL_NO_EC
+    /*
+     * ECDSA certs can be used with RSA cipher suites too so we don't
+     * need to check for SSL_kECDH or SSL_kECDHE
+     */
+    if (s->version >= TLS1_VERSION
+            && !(alg_a & SSL_aECDSA)
+            && !WPACKET_put_bytes_u8(pkt, TLS_CT_ECDSA_SIGN))
+        return 0;
+#endif
+    return 1;
+}
+
+static int ssl3_set_req_cert_type(CERT *c, const unsigned char *p, size_t len)
+{
+    OPENSSL_free(c->ctype);
+    c->ctype = NULL;
+    c->ctype_len = 0;
+    if (p == NULL || len == 0)
+        return 1;
+    if (len > 0xff)
+        return 0;
+    c->ctype = OPENSSL_memdup(p, len);
+    if (c->ctype == NULL)
+        return 0;
+    c->ctype_len = len;
+    return 1;
+}
+
+int ssl3_shutdown(SSL *s)
+{
+    int ret;
+
+    /*
+     * Don't do anything much if we have not done the handshake or we don't
+     * want to send messages :-)
+     */
+    if (s->quiet_shutdown || SSL_in_before(s)) {
+        s->shutdown = (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
+        return 1;
+    }
+
+    if (!(s->shutdown & SSL_SENT_SHUTDOWN)) {
+        s->shutdown |= SSL_SENT_SHUTDOWN;
+        ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY);
+        /*
+         * our shutdown alert has been sent now, and if it still needs to be
+         * written, s->s3->alert_dispatch will be true
+         */
+        if (s->s3->alert_dispatch)
+            return -1;        /* return WANT_WRITE */
+    } else if (s->s3->alert_dispatch) {
+        /* resend it if not sent */
+        ret = s->method->ssl_dispatch_alert(s);
+        if (ret == -1) {
+            /*
+             * we only get to return -1 here the 2nd/Nth invocation, we must
+             * have already signalled return 0 upon a previous invocation,
+             * return WANT_WRITE
+             */
+            return ret;
+        }
+    } else if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN)) {
+        size_t readbytes;
+        /*
+         * If we are waiting for a close from our peer, we are closed
+         */
+        s->method->ssl_read_bytes(s, 0, NULL, NULL, 0, 0, &readbytes);
+        if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN)) {
+            return -1;        /* return WANT_READ */
+        }
+    }
+
+    if ((s->shutdown == (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN)) &&
+        !s->s3->alert_dispatch)
+        return 1;
+    else
+        return 0;
+}
+
+int ssl3_write(SSL *s, const void *buf, size_t len, size_t *written)
+{
+    clear_sys_error();
+    if (s->s3->renegotiate)
+        ssl3_renegotiate_check(s, 0);
+
+    return s->method->ssl_write_bytes(s, SSL3_RT_APPLICATION_DATA, buf, len,
+                                      written);
+}
+
+static int ssl3_read_internal(SSL *s, void *buf, size_t len, int peek,
+                              size_t *readbytes)
+{
+    int ret;
+
+    clear_sys_error();
+    if (s->s3->renegotiate)
+        ssl3_renegotiate_check(s, 0);
+    s->s3->in_read_app_data = 1;
+    ret =
+        s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, NULL, buf, len,
+                                  peek, readbytes);
+    if ((ret == -1) && (s->s3->in_read_app_data == 2)) {
+        /*
+         * ssl3_read_bytes decided to call s->handshake_func, which called
+         * ssl3_read_bytes to read handshake data. However, ssl3_read_bytes
+         * actually found application data and thinks that application data
+         * makes sense here; so disable handshake processing and try to read
+         * application data again.
+         */
+        ossl_statem_set_in_handshake(s, 1);
+        ret =
+            s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, NULL, buf,
+                                      len, peek, readbytes);
+        ossl_statem_set_in_handshake(s, 0);
+    } else
+        s->s3->in_read_app_data = 0;
+
+    return ret;
+}
+
+int ssl3_read(SSL *s, void *buf, size_t len, size_t *readbytes)
+{
+    return ssl3_read_internal(s, buf, len, 0, readbytes);
+}
+
+int ssl3_peek(SSL *s, void *buf, size_t len, size_t *readbytes)
+{
+    return ssl3_read_internal(s, buf, len, 1, readbytes);
+}
+
+int ssl3_renegotiate(SSL *s)
+{
+    if (s->handshake_func == NULL)
+        return 1;
+
+    s->s3->renegotiate = 1;
+    return 1;
+}
+
+/*
+ * Check if we are waiting to do a renegotiation and if so whether now is a
+ * good time to do it. If |initok| is true then we are being called from inside
+ * the state machine so ignore the result of SSL_in_init(s). Otherwise we
+ * should not do a renegotiation if SSL_in_init(s) is true. Returns 1 if we
+ * should do a renegotiation now and sets up the state machine for it. Otherwise
+ * returns 0.
+ */
+int ssl3_renegotiate_check(SSL *s, int initok)
+{
+    int ret = 0;
+
+    if (s->s3->renegotiate) {
+        if (!RECORD_LAYER_read_pending(&s->rlayer)
+            && !RECORD_LAYER_write_pending(&s->rlayer)
+            && (initok || !SSL_in_init(s))) {
+            /*
+             * if we are the server, and we have sent a 'RENEGOTIATE'
+             * message, we need to set the state machine into the renegotiate
+             * state.
+             */
+            ossl_statem_set_renegotiate(s);
+            s->s3->renegotiate = 0;
+            s->s3->num_renegotiations++;
+            s->s3->total_renegotiations++;
+            ret = 1;
+        }
+    }
+    return ret;
+}
+
+/*
+ * If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF and
+ * handshake macs if required.
+ *
+ * If PSK and using SHA384 for TLS < 1.2 switch to default.
+ */
+long ssl_get_algorithm2(SSL *s)
+{
+    long alg2;
+    if (s->s3 == NULL || s->s3->tmp.new_cipher == NULL)
+        return -1;
+    alg2 = s->s3->tmp.new_cipher->algorithm2;
+    if (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_SHA256_PRF) {
+        if (alg2 == (SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF))
+            return SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256;
+    } else if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK) {
+        if (alg2 == (SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384))
+            return SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF;
+    }
+    return alg2;
+}
+
+/*
+ * Fill a ClientRandom or ServerRandom field of length len. Returns <= 0 on
+ * failure, 1 on success.
+ */
+int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, size_t len,
+                          DOWNGRADE dgrd)
+{
+    int send_time = 0, ret;
+
+    if (len < 4)
+        return 0;
+    if (server)
+        send_time = (s->mode & SSL_MODE_SEND_SERVERHELLO_TIME) != 0;
+    else
+        send_time = (s->mode & SSL_MODE_SEND_CLIENTHELLO_TIME) != 0;
+    if (send_time) {
+        unsigned long Time = (unsigned long)time(NULL);
+        unsigned char *p = result;
+
+        l2n(Time, p);
+        ret = RAND_bytes(p, len - 4);
+    } else {
+        ret = RAND_bytes(result, len);
+    }
+
+    if (ret > 0) {
+        if (!ossl_assert(sizeof(tls11downgrade) < len)
+                || !ossl_assert(sizeof(tls12downgrade) < len))
+             return 0;
+        if (dgrd == DOWNGRADE_TO_1_2)
+            memcpy(result + len - sizeof(tls12downgrade), tls12downgrade,
+                   sizeof(tls12downgrade));
+        else if (dgrd == DOWNGRADE_TO_1_1)
+            memcpy(result + len - sizeof(tls11downgrade), tls11downgrade,
+                   sizeof(tls11downgrade));
+    }
+
+    return ret;
+}
+
+int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
+                               int free_pms)
+{
+    unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+    int ret = 0;
+
+    if (alg_k & SSL_PSK) {
+#ifndef OPENSSL_NO_PSK
+        unsigned char *pskpms, *t;
+        size_t psklen = s->s3->tmp.psklen;
+        size_t pskpmslen;
+
+        /* create PSK premaster_secret */
+
+        /* For plain PSK "other_secret" is psklen zeroes */
+        if (alg_k & SSL_kPSK)
+            pmslen = psklen;
+
+        pskpmslen = 4 + pmslen + psklen;
+        pskpms = OPENSSL_malloc(pskpmslen);
+        if (pskpms == NULL)
+            goto err;
+        t = pskpms;
+        s2n(pmslen, t);
+        if (alg_k & SSL_kPSK)
+            memset(t, 0, pmslen);
+        else
+            memcpy(t, pms, pmslen);
+        t += pmslen;
+        s2n(psklen, t);
+        memcpy(t, s->s3->tmp.psk, psklen);
+
+        OPENSSL_clear_free(s->s3->tmp.psk, psklen);
+        s->s3->tmp.psk = NULL;
+        s->s3->tmp.psklen = 0;
+        if (!s->method->ssl3_enc->generate_master_secret(s,
+                    s->session->master_key, pskpms, pskpmslen,
+                    &s->session->master_key_length)) {
+            OPENSSL_clear_free(pskpms, pskpmslen);
+            /* SSLfatal() already called */
+            goto err;
+        }
+        OPENSSL_clear_free(pskpms, pskpmslen);
+#else
+        /* Should never happen */
+        goto err;
+#endif
+    } else {
+        if (!s->method->ssl3_enc->generate_master_secret(s,
+                s->session->master_key, pms, pmslen,
+                &s->session->master_key_length)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    }
+
+    ret = 1;
+ err:
+    if (pms) {
+        if (free_pms)
+            OPENSSL_clear_free(pms, pmslen);
+        else
+            OPENSSL_cleanse(pms, pmslen);
+    }
+    if (s->server == 0) {
+        s->s3->tmp.pms = NULL;
+        s->s3->tmp.pmslen = 0;
+    }
+    return ret;
+}
+
+/* Generate a private key from parameters */
+EVP_PKEY *ssl_generate_pkey(EVP_PKEY *pm)
+{
+    EVP_PKEY_CTX *pctx = NULL;
+    EVP_PKEY *pkey = NULL;
+
+    if (pm == NULL)
+        return NULL;
+    pctx = EVP_PKEY_CTX_new(pm, NULL);
+    if (pctx == NULL)
+        goto err;
+    if (EVP_PKEY_keygen_init(pctx) <= 0)
+        goto err;
+    if (EVP_PKEY_keygen(pctx, &pkey) <= 0) {
+        EVP_PKEY_free(pkey);
+        pkey = NULL;
+    }
+
+    err:
+    EVP_PKEY_CTX_free(pctx);
+    return pkey;
+}
+#ifndef OPENSSL_NO_EC
+/* Generate a private key from a group ID */
+EVP_PKEY *ssl_generate_pkey_group(SSL *s, uint16_t id)
+{
+    EVP_PKEY_CTX *pctx = NULL;
+    EVP_PKEY *pkey = NULL;
+    const TLS_GROUP_INFO *ginf = tls1_group_id_lookup(id);
+    uint16_t gtype;
+
+    if (ginf == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GENERATE_PKEY_GROUP,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    gtype = ginf->flags & TLS_CURVE_TYPE;
+    if (gtype == TLS_CURVE_CUSTOM)
+        pctx = EVP_PKEY_CTX_new_id(ginf->nid, NULL);
+    else
+        pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+    if (pctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GENERATE_PKEY_GROUP,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    if (EVP_PKEY_keygen_init(pctx) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GENERATE_PKEY_GROUP,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+    if (gtype != TLS_CURVE_CUSTOM
+            && EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ginf->nid) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GENERATE_PKEY_GROUP,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+    if (EVP_PKEY_keygen(pctx, &pkey) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GENERATE_PKEY_GROUP,
+                 ERR_R_EVP_LIB);
+        EVP_PKEY_free(pkey);
+        pkey = NULL;
+    }
+
+ err:
+    EVP_PKEY_CTX_free(pctx);
+    return pkey;
+}
+
+/*
+ * Generate parameters from a group ID
+ */
+EVP_PKEY *ssl_generate_param_group(uint16_t id)
+{
+    EVP_PKEY_CTX *pctx = NULL;
+    EVP_PKEY *pkey = NULL;
+    const TLS_GROUP_INFO *ginf = tls1_group_id_lookup(id);
+
+    if (ginf == NULL)
+        goto err;
+
+    if ((ginf->flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) {
+        pkey = EVP_PKEY_new();
+        if (pkey != NULL && EVP_PKEY_set_type(pkey, ginf->nid))
+            return pkey;
+        EVP_PKEY_free(pkey);
+        return NULL;
+    }
+
+    pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+    if (pctx == NULL)
+        goto err;
+    if (EVP_PKEY_paramgen_init(pctx) <= 0)
+        goto err;
+    if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ginf->nid) <= 0)
+        goto err;
+    if (EVP_PKEY_paramgen(pctx, &pkey) <= 0) {
+        EVP_PKEY_free(pkey);
+        pkey = NULL;
+    }
+
+ err:
+    EVP_PKEY_CTX_free(pctx);
+    return pkey;
+}
+#endif
+
+/* Derive secrets for ECDH/DH */
+int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey, int gensecret)
+{
+    int rv = 0;
+    unsigned char *pms = NULL;
+    size_t pmslen = 0;
+    EVP_PKEY_CTX *pctx;
+
+    if (privkey == NULL || pubkey == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_DERIVE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    pctx = EVP_PKEY_CTX_new(privkey, NULL);
+
+    if (EVP_PKEY_derive_init(pctx) <= 0
+        || EVP_PKEY_derive_set_peer(pctx, pubkey) <= 0
+        || EVP_PKEY_derive(pctx, NULL, &pmslen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_DERIVE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    pms = OPENSSL_malloc(pmslen);
+    if (pms == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_DERIVE,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (EVP_PKEY_derive(pctx, pms, &pmslen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_DERIVE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (gensecret) {
+        /* SSLfatal() called as appropriate in the below functions */
+        if (SSL_IS_TLS13(s)) {
+            /*
+             * If we are resuming then we already generated the early secret
+             * when we created the ClientHello, so don't recreate it.
+             */
+            if (!s->hit)
+                rv = tls13_generate_secret(s, ssl_handshake_md(s), NULL, NULL,
+                                           0,
+                                           (unsigned char *)&s->early_secret);
+            else
+                rv = 1;
+
+            rv = rv && tls13_generate_handshake_secret(s, pms, pmslen);
+        } else {
+            rv = ssl_generate_master_secret(s, pms, pmslen, 0);
+        }
+    } else {
+        /* Save premaster secret */
+        s->s3->tmp.pms = pms;
+        s->s3->tmp.pmslen = pmslen;
+        pms = NULL;
+        rv = 1;
+    }
+
+ err:
+    OPENSSL_clear_free(pms, pmslen);
+    EVP_PKEY_CTX_free(pctx);
+    return rv;
+}
+
+#ifndef OPENSSL_NO_DH
+EVP_PKEY *ssl_dh_to_pkey(DH *dh)
+{
+    EVP_PKEY *ret;
+    if (dh == NULL)
+        return NULL;
+    ret = EVP_PKEY_new();
+    if (EVP_PKEY_set1_DH(ret, dh) <= 0) {
+        EVP_PKEY_free(ret);
+        return NULL;
+    }
+    return ret;
+}
+#endif
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/s3_msg.c b/ap/lib/libssl/openssl-1.1.1o/ssl/s3_msg.c
new file mode 100644
index 0000000..707e962
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/s3_msg.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "ssl_local.h"
+
+int ssl3_do_change_cipher_spec(SSL *s)
+{
+    int i;
+
+    if (s->server)
+        i = SSL3_CHANGE_CIPHER_SERVER_READ;
+    else
+        i = SSL3_CHANGE_CIPHER_CLIENT_READ;
+
+    if (s->s3->tmp.key_block == NULL) {
+        if (s->session == NULL || s->session->master_key_length == 0) {
+            /* might happen if dtls1_read_bytes() calls this */
+            SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, SSL_R_CCS_RECEIVED_EARLY);
+            return 0;
+        }
+
+        s->session->cipher = s->s3->tmp.new_cipher;
+        if (!s->method->ssl3_enc->setup_key_block(s))
+            return 0;
+    }
+
+    if (!s->method->ssl3_enc->change_cipher_state(s, i))
+        return 0;
+
+    return 1;
+}
+
+int ssl3_send_alert(SSL *s, int level, int desc)
+{
+    /* Map tls/ssl alert value to correct one */
+    if (SSL_TREAT_AS_TLS13(s))
+        desc = tls13_alert_code(desc);
+    else
+        desc = s->method->ssl3_enc->alert_value(desc);
+    if (s->version == SSL3_VERSION && desc == SSL_AD_PROTOCOL_VERSION)
+        desc = SSL_AD_HANDSHAKE_FAILURE; /* SSL 3.0 does not have
+                                          * protocol_version alerts */
+    if (desc < 0)
+        return -1;
+    if (s->shutdown & SSL_SENT_SHUTDOWN && desc != SSL_AD_CLOSE_NOTIFY)
+        return -1;
+    /* If a fatal one, remove from cache */
+    if ((level == SSL3_AL_FATAL) && (s->session != NULL))
+        SSL_CTX_remove_session(s->session_ctx, s->session);
+
+    s->s3->alert_dispatch = 1;
+    s->s3->send_alert[0] = level;
+    s->s3->send_alert[1] = desc;
+    if (!RECORD_LAYER_write_pending(&s->rlayer)) {
+        /* data still being written out? */
+        return s->method->ssl_dispatch_alert(s);
+    }
+    /*
+     * else data is still being written out, we will get written some time in
+     * the future
+     */
+    return -1;
+}
+
+int ssl3_dispatch_alert(SSL *s)
+{
+    int i, j;
+    size_t alertlen;
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
+    size_t written;
+
+    s->s3->alert_dispatch = 0;
+    alertlen = 2;
+    i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], &alertlen, 1, 0,
+                      &written);
+    if (i <= 0) {
+        s->s3->alert_dispatch = 1;
+    } else {
+        /*
+         * Alert sent to BIO - now flush. If the message does not get sent due
+         * to non-blocking IO, we will not worry too much.
+         */
+        (void)BIO_flush(s->wbio);
+
+        if (s->msg_callback)
+            s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert,
+                            2, s, s->msg_callback_arg);
+
+        if (s->info_callback != NULL)
+            cb = s->info_callback;
+        else if (s->ctx->info_callback != NULL)
+            cb = s->ctx->info_callback;
+
+        if (cb != NULL) {
+            j = (s->s3->send_alert[0] << 8) | s->s3->send_alert[1];
+            cb(s, SSL_CB_WRITE_ALERT, j);
+        }
+    }
+    return i;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_asn1.c b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_asn1.c
new file mode 100644
index 0000000..9264364
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_asn1.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "ssl_local.h"
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+
+typedef struct {
+    uint32_t version;
+    int32_t ssl_version;
+    ASN1_OCTET_STRING *cipher;
+    ASN1_OCTET_STRING *comp_id;
+    ASN1_OCTET_STRING *master_key;
+    ASN1_OCTET_STRING *session_id;
+    ASN1_OCTET_STRING *key_arg;
+    int64_t time;
+    int64_t timeout;
+    X509 *peer;
+    ASN1_OCTET_STRING *session_id_context;
+    int32_t verify_result;
+    ASN1_OCTET_STRING *tlsext_hostname;
+    uint64_t tlsext_tick_lifetime_hint;
+    uint32_t tlsext_tick_age_add;
+    ASN1_OCTET_STRING *tlsext_tick;
+#ifndef OPENSSL_NO_PSK
+    ASN1_OCTET_STRING *psk_identity_hint;
+    ASN1_OCTET_STRING *psk_identity;
+#endif
+#ifndef OPENSSL_NO_SRP
+    ASN1_OCTET_STRING *srp_username;
+#endif
+    uint64_t flags;
+    uint32_t max_early_data;
+    ASN1_OCTET_STRING *alpn_selected;
+    uint32_t tlsext_max_fragment_len_mode;
+    ASN1_OCTET_STRING *ticket_appdata;
+} SSL_SESSION_ASN1;
+
+ASN1_SEQUENCE(SSL_SESSION_ASN1) = {
+    ASN1_EMBED(SSL_SESSION_ASN1, version, UINT32),
+    ASN1_EMBED(SSL_SESSION_ASN1, ssl_version, INT32),
+    ASN1_SIMPLE(SSL_SESSION_ASN1, cipher, ASN1_OCTET_STRING),
+    ASN1_SIMPLE(SSL_SESSION_ASN1, session_id, ASN1_OCTET_STRING),
+    ASN1_SIMPLE(SSL_SESSION_ASN1, master_key, ASN1_OCTET_STRING),
+    ASN1_IMP_OPT(SSL_SESSION_ASN1, key_arg, ASN1_OCTET_STRING, 0),
+    ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, time, ZINT64, 1),
+    ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, timeout, ZINT64, 2),
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, peer, X509, 3),
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, session_id_context, ASN1_OCTET_STRING, 4),
+    ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, verify_result, ZINT32, 5),
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, tlsext_hostname, ASN1_OCTET_STRING, 6),
+#ifndef OPENSSL_NO_PSK
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, psk_identity_hint, ASN1_OCTET_STRING, 7),
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, psk_identity, ASN1_OCTET_STRING, 8),
+#endif
+    ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, tlsext_tick_lifetime_hint, ZUINT64, 9),
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, tlsext_tick, ASN1_OCTET_STRING, 10),
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, comp_id, ASN1_OCTET_STRING, 11),
+#ifndef OPENSSL_NO_SRP
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, srp_username, ASN1_OCTET_STRING, 12),
+#endif
+    ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, flags, ZUINT64, 13),
+    ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, tlsext_tick_age_add, ZUINT32, 14),
+    ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, max_early_data, ZUINT32, 15),
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, alpn_selected, ASN1_OCTET_STRING, 16),
+    ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, tlsext_max_fragment_len_mode, ZUINT32, 17),
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, ticket_appdata, ASN1_OCTET_STRING, 18)
+} static_ASN1_SEQUENCE_END(SSL_SESSION_ASN1)
+
+IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(SSL_SESSION_ASN1)
+
+/* Utility functions for i2d_SSL_SESSION */
+
+/* Initialise OCTET STRING from buffer and length */
+
+static void ssl_session_oinit(ASN1_OCTET_STRING **dest, ASN1_OCTET_STRING *os,
+                              unsigned char *data, size_t len)
+{
+    os->data = data;
+    os->length = (int)len;
+    os->flags = 0;
+    *dest = os;
+}
+
+/* Initialise OCTET STRING from string */
+static void ssl_session_sinit(ASN1_OCTET_STRING **dest, ASN1_OCTET_STRING *os,
+                              char *data)
+{
+    if (data != NULL)
+        ssl_session_oinit(dest, os, (unsigned char *)data, strlen(data));
+    else
+        *dest = NULL;
+}
+
+int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
+{
+
+    SSL_SESSION_ASN1 as;
+
+    ASN1_OCTET_STRING cipher;
+    unsigned char cipher_data[2];
+    ASN1_OCTET_STRING master_key, session_id, sid_ctx;
+
+#ifndef OPENSSL_NO_COMP
+    ASN1_OCTET_STRING comp_id;
+    unsigned char comp_id_data;
+#endif
+    ASN1_OCTET_STRING tlsext_hostname, tlsext_tick;
+#ifndef OPENSSL_NO_SRP
+    ASN1_OCTET_STRING srp_username;
+#endif
+#ifndef OPENSSL_NO_PSK
+    ASN1_OCTET_STRING psk_identity, psk_identity_hint;
+#endif
+    ASN1_OCTET_STRING alpn_selected;
+    ASN1_OCTET_STRING ticket_appdata;
+
+    long l;
+
+    if ((in == NULL) || ((in->cipher == NULL) && (in->cipher_id == 0)))
+        return 0;
+
+    memset(&as, 0, sizeof(as));
+
+    as.version = SSL_SESSION_ASN1_VERSION;
+    as.ssl_version = in->ssl_version;
+
+    if (in->cipher == NULL)
+        l = in->cipher_id;
+    else
+        l = in->cipher->id;
+    cipher_data[0] = ((unsigned char)(l >> 8L)) & 0xff;
+    cipher_data[1] = ((unsigned char)(l)) & 0xff;
+
+    ssl_session_oinit(&as.cipher, &cipher, cipher_data, 2);
+
+#ifndef OPENSSL_NO_COMP
+    if (in->compress_meth) {
+        comp_id_data = (unsigned char)in->compress_meth;
+        ssl_session_oinit(&as.comp_id, &comp_id, &comp_id_data, 1);
+    }
+#endif
+
+    ssl_session_oinit(&as.master_key, &master_key,
+                      in->master_key, in->master_key_length);
+
+    ssl_session_oinit(&as.session_id, &session_id,
+                      in->session_id, in->session_id_length);
+
+    ssl_session_oinit(&as.session_id_context, &sid_ctx,
+                      in->sid_ctx, in->sid_ctx_length);
+
+    as.time = in->time;
+    as.timeout = in->timeout;
+    as.verify_result = in->verify_result;
+
+    as.peer = in->peer;
+
+    ssl_session_sinit(&as.tlsext_hostname, &tlsext_hostname,
+                      in->ext.hostname);
+    if (in->ext.tick) {
+        ssl_session_oinit(&as.tlsext_tick, &tlsext_tick,
+                          in->ext.tick, in->ext.ticklen);
+    }
+    if (in->ext.tick_lifetime_hint > 0)
+        as.tlsext_tick_lifetime_hint = in->ext.tick_lifetime_hint;
+    as.tlsext_tick_age_add = in->ext.tick_age_add;
+#ifndef OPENSSL_NO_PSK
+    ssl_session_sinit(&as.psk_identity_hint, &psk_identity_hint,
+                      in->psk_identity_hint);
+    ssl_session_sinit(&as.psk_identity, &psk_identity, in->psk_identity);
+#endif                          /* OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_SRP
+    ssl_session_sinit(&as.srp_username, &srp_username, in->srp_username);
+#endif                          /* OPENSSL_NO_SRP */
+
+    as.flags = in->flags;
+    as.max_early_data = in->ext.max_early_data;
+
+    if (in->ext.alpn_selected == NULL)
+        as.alpn_selected = NULL;
+    else
+        ssl_session_oinit(&as.alpn_selected, &alpn_selected,
+                          in->ext.alpn_selected, in->ext.alpn_selected_len);
+
+    as.tlsext_max_fragment_len_mode = in->ext.max_fragment_len_mode;
+
+    if (in->ticket_appdata == NULL)
+        as.ticket_appdata = NULL;
+    else
+        ssl_session_oinit(&as.ticket_appdata, &ticket_appdata,
+                          in->ticket_appdata, in->ticket_appdata_len);
+
+    return i2d_SSL_SESSION_ASN1(&as, pp);
+
+}
+
+/* Utility functions for d2i_SSL_SESSION */
+
+/* OPENSSL_strndup an OCTET STRING */
+
+static int ssl_session_strndup(char **pdst, ASN1_OCTET_STRING *src)
+{
+    OPENSSL_free(*pdst);
+    *pdst = NULL;
+    if (src == NULL)
+        return 1;
+    *pdst = OPENSSL_strndup((char *)src->data, src->length);
+    if (*pdst == NULL)
+        return 0;
+    return 1;
+}
+
+/* Copy an OCTET STRING, return error if it exceeds maximum length */
+
+static int ssl_session_memcpy(unsigned char *dst, size_t *pdstlen,
+                              ASN1_OCTET_STRING *src, size_t maxlen)
+{
+    if (src == NULL || src->length == 0) {
+        *pdstlen = 0;
+        return 1;
+    }
+    if (src->length < 0 || src->length > (int)maxlen)
+        return 0;
+    memcpy(dst, src->data, src->length);
+    *pdstlen = src->length;
+    return 1;
+}
+
+SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
+                             long length)
+{
+    long id;
+    size_t tmpl;
+    const unsigned char *p = *pp;
+    SSL_SESSION_ASN1 *as = NULL;
+    SSL_SESSION *ret = NULL;
+
+    as = d2i_SSL_SESSION_ASN1(NULL, &p, length);
+    /* ASN.1 code returns suitable error */
+    if (as == NULL)
+        goto err;
+
+    if (!a || !*a) {
+        ret = SSL_SESSION_new();
+        if (ret == NULL)
+            goto err;
+    } else {
+        ret = *a;
+    }
+
+    if (as->version != SSL_SESSION_ASN1_VERSION) {
+        SSLerr(SSL_F_D2I_SSL_SESSION, SSL_R_UNKNOWN_SSL_VERSION);
+        goto err;
+    }
+
+    if ((as->ssl_version >> 8) != SSL3_VERSION_MAJOR
+        && (as->ssl_version >> 8) != DTLS1_VERSION_MAJOR
+        && as->ssl_version != DTLS1_BAD_VER) {
+        SSLerr(SSL_F_D2I_SSL_SESSION, SSL_R_UNSUPPORTED_SSL_VERSION);
+        goto err;
+    }
+
+    ret->ssl_version = (int)as->ssl_version;
+
+    if (as->cipher->length != 2) {
+        SSLerr(SSL_F_D2I_SSL_SESSION, SSL_R_CIPHER_CODE_WRONG_LENGTH);
+        goto err;
+    }
+
+    id = 0x03000000L | ((unsigned long)as->cipher->data[0] << 8L)
+                     | (unsigned long)as->cipher->data[1];
+
+    ret->cipher_id = id;
+    ret->cipher = ssl3_get_cipher_by_id(id);
+    if (ret->cipher == NULL)
+        goto err;
+
+    if (!ssl_session_memcpy(ret->session_id, &ret->session_id_length,
+                            as->session_id, SSL3_MAX_SSL_SESSION_ID_LENGTH))
+        goto err;
+
+    if (!ssl_session_memcpy(ret->master_key, &tmpl,
+                            as->master_key, TLS13_MAX_RESUMPTION_PSK_LENGTH))
+        goto err;
+
+    ret->master_key_length = tmpl;
+
+    if (as->time != 0)
+        ret->time = (long)as->time;
+    else
+        ret->time = (long)time(NULL);
+
+    if (as->timeout != 0)
+        ret->timeout = (long)as->timeout;
+    else
+        ret->timeout = 3;
+
+    X509_free(ret->peer);
+    ret->peer = as->peer;
+    as->peer = NULL;
+
+    if (!ssl_session_memcpy(ret->sid_ctx, &ret->sid_ctx_length,
+                            as->session_id_context, SSL_MAX_SID_CTX_LENGTH))
+        goto err;
+
+    /* NB: this defaults to zero which is X509_V_OK */
+    ret->verify_result = as->verify_result;
+
+    if (!ssl_session_strndup(&ret->ext.hostname, as->tlsext_hostname))
+        goto err;
+
+#ifndef OPENSSL_NO_PSK
+    if (!ssl_session_strndup(&ret->psk_identity_hint, as->psk_identity_hint))
+        goto err;
+    if (!ssl_session_strndup(&ret->psk_identity, as->psk_identity))
+        goto err;
+#endif
+
+    ret->ext.tick_lifetime_hint = (unsigned long)as->tlsext_tick_lifetime_hint;
+    ret->ext.tick_age_add = as->tlsext_tick_age_add;
+    OPENSSL_free(ret->ext.tick);
+    if (as->tlsext_tick != NULL) {
+        ret->ext.tick = as->tlsext_tick->data;
+        ret->ext.ticklen = as->tlsext_tick->length;
+        as->tlsext_tick->data = NULL;
+    } else {
+        ret->ext.tick = NULL;
+    }
+#ifndef OPENSSL_NO_COMP
+    if (as->comp_id) {
+        if (as->comp_id->length != 1) {
+            SSLerr(SSL_F_D2I_SSL_SESSION, SSL_R_BAD_LENGTH);
+            goto err;
+        }
+        ret->compress_meth = as->comp_id->data[0];
+    } else {
+        ret->compress_meth = 0;
+    }
+#endif
+
+#ifndef OPENSSL_NO_SRP
+    if (!ssl_session_strndup(&ret->srp_username, as->srp_username))
+        goto err;
+#endif                          /* OPENSSL_NO_SRP */
+    /* Flags defaults to zero which is fine */
+    ret->flags = (int32_t)as->flags;
+    ret->ext.max_early_data = as->max_early_data;
+
+    OPENSSL_free(ret->ext.alpn_selected);
+    if (as->alpn_selected != NULL) {
+        ret->ext.alpn_selected = as->alpn_selected->data;
+        ret->ext.alpn_selected_len = as->alpn_selected->length;
+        as->alpn_selected->data = NULL;
+    } else {
+        ret->ext.alpn_selected = NULL;
+        ret->ext.alpn_selected_len = 0;
+    }
+
+    ret->ext.max_fragment_len_mode = as->tlsext_max_fragment_len_mode;
+
+    OPENSSL_free(ret->ticket_appdata);
+    if (as->ticket_appdata != NULL) {
+        ret->ticket_appdata = as->ticket_appdata->data;
+        ret->ticket_appdata_len = as->ticket_appdata->length;
+        as->ticket_appdata->data = NULL;
+    } else {
+        ret->ticket_appdata = NULL;
+        ret->ticket_appdata_len = 0;
+    }
+
+    M_ASN1_free_of(as, SSL_SESSION_ASN1);
+
+    if ((a != NULL) && (*a == NULL))
+        *a = ret;
+    *pp = p;
+    return ret;
+
+ err:
+    M_ASN1_free_of(as, SSL_SESSION_ASN1);
+    if ((a == NULL) || (*a != ret))
+        SSL_SESSION_free(ret);
+    return NULL;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_cert.c b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_cert.c
new file mode 100644
index 0000000..b615e70
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_cert.c
@@ -0,0 +1,1031 @@
+/*
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "internal/nelem.h"
+#include "internal/o_dir.h"
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#include <openssl/crypto.h>
+#include "internal/refcount.h"
+#include "ssl_local.h"
+#include "ssl_cert_table.h"
+#include "internal/thread_once.h"
+
+static int ssl_security_default_callback(const SSL *s, const SSL_CTX *ctx,
+                                         int op, int bits, int nid, void *other,
+                                         void *ex);
+
+static CRYPTO_ONCE ssl_x509_store_ctx_once = CRYPTO_ONCE_STATIC_INIT;
+static volatile int ssl_x509_store_ctx_idx = -1;
+
+DEFINE_RUN_ONCE_STATIC(ssl_x509_store_ctx_init)
+{
+    ssl_x509_store_ctx_idx = X509_STORE_CTX_get_ex_new_index(0,
+                                                             "SSL for verify callback",
+                                                             NULL, NULL, NULL);
+    return ssl_x509_store_ctx_idx >= 0;
+}
+
+int SSL_get_ex_data_X509_STORE_CTX_idx(void)
+{
+
+    if (!RUN_ONCE(&ssl_x509_store_ctx_once, ssl_x509_store_ctx_init))
+        return -1;
+    return ssl_x509_store_ctx_idx;
+}
+
+CERT *ssl_cert_new(void)
+{
+    CERT *ret = OPENSSL_zalloc(sizeof(*ret));
+
+    if (ret == NULL) {
+        SSLerr(SSL_F_SSL_CERT_NEW, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    ret->key = &(ret->pkeys[SSL_PKEY_RSA]);
+    ret->references = 1;
+    ret->sec_cb = ssl_security_default_callback;
+    ret->sec_level = OPENSSL_TLS_SECURITY_LEVEL;
+    ret->sec_ex = NULL;
+    ret->lock = CRYPTO_THREAD_lock_new();
+    if (ret->lock == NULL) {
+        SSLerr(SSL_F_SSL_CERT_NEW, ERR_R_MALLOC_FAILURE);
+        OPENSSL_free(ret);
+        return NULL;
+    }
+
+    return ret;
+}
+
+CERT *ssl_cert_dup(CERT *cert)
+{
+    CERT *ret = OPENSSL_zalloc(sizeof(*ret));
+    int i;
+
+    if (ret == NULL) {
+        SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    ret->references = 1;
+    ret->key = &ret->pkeys[cert->key - cert->pkeys];
+    ret->lock = CRYPTO_THREAD_lock_new();
+    if (ret->lock == NULL) {
+        SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE);
+        OPENSSL_free(ret);
+        return NULL;
+    }
+#ifndef OPENSSL_NO_DH
+    if (cert->dh_tmp != NULL) {
+        ret->dh_tmp = cert->dh_tmp;
+        EVP_PKEY_up_ref(ret->dh_tmp);
+    }
+    ret->dh_tmp_cb = cert->dh_tmp_cb;
+    ret->dh_tmp_auto = cert->dh_tmp_auto;
+#endif
+
+    for (i = 0; i < SSL_PKEY_NUM; i++) {
+        CERT_PKEY *cpk = cert->pkeys + i;
+        CERT_PKEY *rpk = ret->pkeys + i;
+        if (cpk->x509 != NULL) {
+            rpk->x509 = cpk->x509;
+            X509_up_ref(rpk->x509);
+        }
+
+        if (cpk->privatekey != NULL) {
+            rpk->privatekey = cpk->privatekey;
+            EVP_PKEY_up_ref(cpk->privatekey);
+        }
+
+        if (cpk->chain) {
+            rpk->chain = X509_chain_up_ref(cpk->chain);
+            if (!rpk->chain) {
+                SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+        }
+        if (cert->pkeys[i].serverinfo != NULL) {
+            /* Just copy everything. */
+            ret->pkeys[i].serverinfo =
+                OPENSSL_malloc(cert->pkeys[i].serverinfo_length);
+            if (ret->pkeys[i].serverinfo == NULL) {
+                SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+            ret->pkeys[i].serverinfo_length = cert->pkeys[i].serverinfo_length;
+            memcpy(ret->pkeys[i].serverinfo,
+                   cert->pkeys[i].serverinfo, cert->pkeys[i].serverinfo_length);
+        }
+    }
+
+    /* Configured sigalgs copied across */
+    if (cert->conf_sigalgs) {
+        ret->conf_sigalgs = OPENSSL_malloc(cert->conf_sigalgslen
+                                           * sizeof(*cert->conf_sigalgs));
+        if (ret->conf_sigalgs == NULL)
+            goto err;
+        memcpy(ret->conf_sigalgs, cert->conf_sigalgs,
+               cert->conf_sigalgslen * sizeof(*cert->conf_sigalgs));
+        ret->conf_sigalgslen = cert->conf_sigalgslen;
+    } else
+        ret->conf_sigalgs = NULL;
+
+    if (cert->client_sigalgs) {
+        ret->client_sigalgs = OPENSSL_malloc(cert->client_sigalgslen
+                                             * sizeof(*cert->client_sigalgs));
+        if (ret->client_sigalgs == NULL)
+            goto err;
+        memcpy(ret->client_sigalgs, cert->client_sigalgs,
+               cert->client_sigalgslen * sizeof(*cert->client_sigalgs));
+        ret->client_sigalgslen = cert->client_sigalgslen;
+    } else
+        ret->client_sigalgs = NULL;
+    /* Copy any custom client certificate types */
+    if (cert->ctype) {
+        ret->ctype = OPENSSL_memdup(cert->ctype, cert->ctype_len);
+        if (ret->ctype == NULL)
+            goto err;
+        ret->ctype_len = cert->ctype_len;
+    }
+
+    ret->cert_flags = cert->cert_flags;
+
+    ret->cert_cb = cert->cert_cb;
+    ret->cert_cb_arg = cert->cert_cb_arg;
+
+    if (cert->verify_store) {
+        X509_STORE_up_ref(cert->verify_store);
+        ret->verify_store = cert->verify_store;
+    }
+
+    if (cert->chain_store) {
+        X509_STORE_up_ref(cert->chain_store);
+        ret->chain_store = cert->chain_store;
+    }
+
+    ret->sec_cb = cert->sec_cb;
+    ret->sec_level = cert->sec_level;
+    ret->sec_ex = cert->sec_ex;
+
+    if (!custom_exts_copy(&ret->custext, &cert->custext))
+        goto err;
+#ifndef OPENSSL_NO_PSK
+    if (cert->psk_identity_hint) {
+        ret->psk_identity_hint = OPENSSL_strdup(cert->psk_identity_hint);
+        if (ret->psk_identity_hint == NULL)
+            goto err;
+    }
+#endif
+    return ret;
+
+ err:
+    ssl_cert_free(ret);
+
+    return NULL;
+}
+
+/* Free up and clear all certificates and chains */
+
+void ssl_cert_clear_certs(CERT *c)
+{
+    int i;
+    if (c == NULL)
+        return;
+    for (i = 0; i < SSL_PKEY_NUM; i++) {
+        CERT_PKEY *cpk = c->pkeys + i;
+        X509_free(cpk->x509);
+        cpk->x509 = NULL;
+        EVP_PKEY_free(cpk->privatekey);
+        cpk->privatekey = NULL;
+        sk_X509_pop_free(cpk->chain, X509_free);
+        cpk->chain = NULL;
+        OPENSSL_free(cpk->serverinfo);
+        cpk->serverinfo = NULL;
+        cpk->serverinfo_length = 0;
+    }
+}
+
+void ssl_cert_free(CERT *c)
+{
+    int i;
+
+    if (c == NULL)
+        return;
+    CRYPTO_DOWN_REF(&c->references, &i, c->lock);
+    REF_PRINT_COUNT("CERT", c);
+    if (i > 0)
+        return;
+    REF_ASSERT_ISNT(i < 0);
+
+#ifndef OPENSSL_NO_DH
+    EVP_PKEY_free(c->dh_tmp);
+#endif
+
+    ssl_cert_clear_certs(c);
+    OPENSSL_free(c->conf_sigalgs);
+    OPENSSL_free(c->client_sigalgs);
+    OPENSSL_free(c->ctype);
+    X509_STORE_free(c->verify_store);
+    X509_STORE_free(c->chain_store);
+    custom_exts_free(&c->custext);
+#ifndef OPENSSL_NO_PSK
+    OPENSSL_free(c->psk_identity_hint);
+#endif
+    CRYPTO_THREAD_lock_free(c->lock);
+    OPENSSL_free(c);
+}
+
+int ssl_cert_set0_chain(SSL *s, SSL_CTX *ctx, STACK_OF(X509) *chain)
+{
+    int i, r;
+    CERT_PKEY *cpk = s ? s->cert->key : ctx->cert->key;
+    if (!cpk)
+        return 0;
+    for (i = 0; i < sk_X509_num(chain); i++) {
+        r = ssl_security_cert(s, ctx, sk_X509_value(chain, i), 0, 0);
+        if (r != 1) {
+            SSLerr(SSL_F_SSL_CERT_SET0_CHAIN, r);
+            return 0;
+        }
+    }
+    sk_X509_pop_free(cpk->chain, X509_free);
+    cpk->chain = chain;
+    return 1;
+}
+
+int ssl_cert_set1_chain(SSL *s, SSL_CTX *ctx, STACK_OF(X509) *chain)
+{
+    STACK_OF(X509) *dchain;
+    if (!chain)
+        return ssl_cert_set0_chain(s, ctx, NULL);
+    dchain = X509_chain_up_ref(chain);
+    if (!dchain)
+        return 0;
+    if (!ssl_cert_set0_chain(s, ctx, dchain)) {
+        sk_X509_pop_free(dchain, X509_free);
+        return 0;
+    }
+    return 1;
+}
+
+int ssl_cert_add0_chain_cert(SSL *s, SSL_CTX *ctx, X509 *x)
+{
+    int r;
+    CERT_PKEY *cpk = s ? s->cert->key : ctx->cert->key;
+    if (!cpk)
+        return 0;
+    r = ssl_security_cert(s, ctx, x, 0, 0);
+    if (r != 1) {
+        SSLerr(SSL_F_SSL_CERT_ADD0_CHAIN_CERT, r);
+        return 0;
+    }
+    if (!cpk->chain)
+        cpk->chain = sk_X509_new_null();
+    if (!cpk->chain || !sk_X509_push(cpk->chain, x))
+        return 0;
+    return 1;
+}
+
+int ssl_cert_add1_chain_cert(SSL *s, SSL_CTX *ctx, X509 *x)
+{
+    if (!ssl_cert_add0_chain_cert(s, ctx, x))
+        return 0;
+    X509_up_ref(x);
+    return 1;
+}
+
+int ssl_cert_select_current(CERT *c, X509 *x)
+{
+    int i;
+    if (x == NULL)
+        return 0;
+    for (i = 0; i < SSL_PKEY_NUM; i++) {
+        CERT_PKEY *cpk = c->pkeys + i;
+        if (cpk->x509 == x && cpk->privatekey) {
+            c->key = cpk;
+            return 1;
+        }
+    }
+
+    for (i = 0; i < SSL_PKEY_NUM; i++) {
+        CERT_PKEY *cpk = c->pkeys + i;
+        if (cpk->privatekey && cpk->x509 && !X509_cmp(cpk->x509, x)) {
+            c->key = cpk;
+            return 1;
+        }
+    }
+    return 0;
+}
+
+int ssl_cert_set_current(CERT *c, long op)
+{
+    int i, idx;
+    if (!c)
+        return 0;
+    if (op == SSL_CERT_SET_FIRST)
+        idx = 0;
+    else if (op == SSL_CERT_SET_NEXT) {
+        idx = (int)(c->key - c->pkeys + 1);
+        if (idx >= SSL_PKEY_NUM)
+            return 0;
+    } else
+        return 0;
+    for (i = idx; i < SSL_PKEY_NUM; i++) {
+        CERT_PKEY *cpk = c->pkeys + i;
+        if (cpk->x509 && cpk->privatekey) {
+            c->key = cpk;
+            return 1;
+        }
+    }
+    return 0;
+}
+
+void ssl_cert_set_cert_cb(CERT *c, int (*cb) (SSL *ssl, void *arg), void *arg)
+{
+    c->cert_cb = cb;
+    c->cert_cb_arg = arg;
+}
+
+int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk)
+{
+    X509 *x;
+    int i = 0;
+    X509_STORE *verify_store;
+    X509_STORE_CTX *ctx = NULL;
+    X509_VERIFY_PARAM *param;
+
+    if ((sk == NULL) || (sk_X509_num(sk) == 0))
+        return 0;
+
+    if (s->cert->verify_store)
+        verify_store = s->cert->verify_store;
+    else
+        verify_store = s->ctx->cert_store;
+
+    ctx = X509_STORE_CTX_new();
+    if (ctx == NULL) {
+        SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    x = sk_X509_value(sk, 0);
+    if (!X509_STORE_CTX_init(ctx, verify_store, x, sk)) {
+        SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN, ERR_R_X509_LIB);
+        goto end;
+    }
+    param = X509_STORE_CTX_get0_param(ctx);
+    /*
+     * XXX: Separate @AUTHSECLEVEL and @TLSSECLEVEL would be useful at some
+     * point, for now a single @SECLEVEL sets the same policy for TLS crypto
+     * and PKI authentication.
+     */
+    X509_VERIFY_PARAM_set_auth_level(param, SSL_get_security_level(s));
+
+    /* Set suite B flags if needed */
+    X509_STORE_CTX_set_flags(ctx, tls1_suiteb(s));
+    if (!X509_STORE_CTX_set_ex_data
+        (ctx, SSL_get_ex_data_X509_STORE_CTX_idx(), s)) {
+        goto end;
+    }
+
+    /* Verify via DANE if enabled */
+    if (DANETLS_ENABLED(&s->dane))
+        X509_STORE_CTX_set0_dane(ctx, &s->dane);
+
+    /*
+     * We need to inherit the verify parameters. These can be determined by
+     * the context: if its a server it will verify SSL client certificates or
+     * vice versa.
+     */
+
+    X509_STORE_CTX_set_default(ctx, s->server ? "ssl_client" : "ssl_server");
+    /*
+     * Anything non-default in "s->param" should overwrite anything in the ctx.
+     */
+    X509_VERIFY_PARAM_set1(param, s->param);
+
+    if (s->verify_callback)
+        X509_STORE_CTX_set_verify_cb(ctx, s->verify_callback);
+
+    if (s->ctx->app_verify_callback != NULL)
+        i = s->ctx->app_verify_callback(ctx, s->ctx->app_verify_arg);
+    else
+        i = X509_verify_cert(ctx);
+
+    s->verify_result = X509_STORE_CTX_get_error(ctx);
+    sk_X509_pop_free(s->verified_chain, X509_free);
+    s->verified_chain = NULL;
+    if (X509_STORE_CTX_get0_chain(ctx) != NULL) {
+        s->verified_chain = X509_STORE_CTX_get1_chain(ctx);
+        if (s->verified_chain == NULL) {
+            SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN, ERR_R_MALLOC_FAILURE);
+            i = 0;
+        }
+    }
+
+    /* Move peername from the store context params to the SSL handle's */
+    X509_VERIFY_PARAM_move_peername(s->param, param);
+
+ end:
+    X509_STORE_CTX_free(ctx);
+    return i;
+}
+
+static void set0_CA_list(STACK_OF(X509_NAME) **ca_list,
+                        STACK_OF(X509_NAME) *name_list)
+{
+    sk_X509_NAME_pop_free(*ca_list, X509_NAME_free);
+    *ca_list = name_list;
+}
+
+STACK_OF(X509_NAME) *SSL_dup_CA_list(const STACK_OF(X509_NAME) *sk)
+{
+    int i;
+    const int num = sk_X509_NAME_num(sk);
+    STACK_OF(X509_NAME) *ret;
+    X509_NAME *name;
+
+    ret = sk_X509_NAME_new_reserve(NULL, num);
+    if (ret == NULL) {
+        SSLerr(SSL_F_SSL_DUP_CA_LIST, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+    for (i = 0; i < num; i++) {
+        name = X509_NAME_dup(sk_X509_NAME_value(sk, i));
+        if (name == NULL) {
+            SSLerr(SSL_F_SSL_DUP_CA_LIST, ERR_R_MALLOC_FAILURE);
+            sk_X509_NAME_pop_free(ret, X509_NAME_free);
+            return NULL;
+        }
+        sk_X509_NAME_push(ret, name);   /* Cannot fail after reserve call */
+    }
+    return ret;
+}
+
+void SSL_set0_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list)
+{
+    set0_CA_list(&s->ca_names, name_list);
+}
+
+void SSL_CTX_set0_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list)
+{
+    set0_CA_list(&ctx->ca_names, name_list);
+}
+
+const STACK_OF(X509_NAME) *SSL_CTX_get0_CA_list(const SSL_CTX *ctx)
+{
+    return ctx->ca_names;
+}
+
+const STACK_OF(X509_NAME) *SSL_get0_CA_list(const SSL *s)
+{
+    return s->ca_names != NULL ? s->ca_names : s->ctx->ca_names;
+}
+
+void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list)
+{
+    set0_CA_list(&ctx->client_ca_names, name_list);
+}
+
+STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx)
+{
+    return ctx->client_ca_names;
+}
+
+void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list)
+{
+    set0_CA_list(&s->client_ca_names, name_list);
+}
+
+const STACK_OF(X509_NAME) *SSL_get0_peer_CA_list(const SSL *s)
+{
+    return s->s3 != NULL ? s->s3->tmp.peer_ca_names : NULL;
+}
+
+STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s)
+{
+    if (!s->server)
+        return s->s3 != NULL ?  s->s3->tmp.peer_ca_names : NULL;
+    return s->client_ca_names != NULL ?  s->client_ca_names
+                                      : s->ctx->client_ca_names;
+}
+
+static int add_ca_name(STACK_OF(X509_NAME) **sk, const X509 *x)
+{
+    X509_NAME *name;
+
+    if (x == NULL)
+        return 0;
+    if (*sk == NULL && ((*sk = sk_X509_NAME_new_null()) == NULL))
+        return 0;
+
+    if ((name = X509_NAME_dup(X509_get_subject_name(x))) == NULL)
+        return 0;
+
+    if (!sk_X509_NAME_push(*sk, name)) {
+        X509_NAME_free(name);
+        return 0;
+    }
+    return 1;
+}
+
+int SSL_add1_to_CA_list(SSL *ssl, const X509 *x)
+{
+    return add_ca_name(&ssl->ca_names, x);
+}
+
+int SSL_CTX_add1_to_CA_list(SSL_CTX *ctx, const X509 *x)
+{
+    return add_ca_name(&ctx->ca_names, x);
+}
+
+/*
+ * The following two are older names are to be replaced with
+ * SSL(_CTX)_add1_to_CA_list
+ */
+int SSL_add_client_CA(SSL *ssl, X509 *x)
+{
+    return add_ca_name(&ssl->client_ca_names, x);
+}
+
+int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x)
+{
+    return add_ca_name(&ctx->client_ca_names, x);
+}
+
+static int xname_cmp(const X509_NAME *a, const X509_NAME *b)
+{
+    unsigned char *abuf = NULL, *bbuf = NULL;
+    int alen, blen, ret;
+
+    /* X509_NAME_cmp() itself casts away constness in this way, so
+     * assume it's safe:
+     */
+    alen = i2d_X509_NAME((X509_NAME *)a, &abuf);
+    blen = i2d_X509_NAME((X509_NAME *)b, &bbuf);
+
+    if (alen < 0 || blen < 0)
+        ret = -2;
+    else if (alen != blen)
+        ret = alen - blen;
+    else /* alen == blen */
+        ret = memcmp(abuf, bbuf, alen);
+
+    OPENSSL_free(abuf);
+    OPENSSL_free(bbuf);
+
+    return ret;
+}
+
+static int xname_sk_cmp(const X509_NAME *const *a, const X509_NAME *const *b)
+{
+    return xname_cmp(*a, *b);
+}
+
+static unsigned long xname_hash(const X509_NAME *a)
+{
+    return X509_NAME_hash((X509_NAME *)a);
+}
+
+STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file)
+{
+    BIO *in = BIO_new(BIO_s_file());
+    X509 *x = NULL;
+    X509_NAME *xn = NULL;
+    STACK_OF(X509_NAME) *ret = NULL;
+    LHASH_OF(X509_NAME) *name_hash = lh_X509_NAME_new(xname_hash, xname_cmp);
+
+    if ((name_hash == NULL) || (in == NULL)) {
+        SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (!BIO_read_filename(in, file))
+        goto err;
+
+    for (;;) {
+        if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL)
+            break;
+        if (ret == NULL) {
+            ret = sk_X509_NAME_new_null();
+            if (ret == NULL) {
+                SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+        }
+        if ((xn = X509_get_subject_name(x)) == NULL)
+            goto err;
+        /* check for duplicates */
+        xn = X509_NAME_dup(xn);
+        if (xn == NULL)
+            goto err;
+        if (lh_X509_NAME_retrieve(name_hash, xn) != NULL) {
+            /* Duplicate. */
+            X509_NAME_free(xn);
+            xn = NULL;
+        } else {
+            lh_X509_NAME_insert(name_hash, xn);
+            if (!sk_X509_NAME_push(ret, xn))
+                goto err;
+        }
+    }
+    goto done;
+
+ err:
+    X509_NAME_free(xn);
+    sk_X509_NAME_pop_free(ret, X509_NAME_free);
+    ret = NULL;
+ done:
+    BIO_free(in);
+    X509_free(x);
+    lh_X509_NAME_free(name_hash);
+    if (ret != NULL)
+        ERR_clear_error();
+    return ret;
+}
+
+int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+                                        const char *file)
+{
+    BIO *in;
+    X509 *x = NULL;
+    X509_NAME *xn = NULL;
+    int ret = 1;
+    int (*oldcmp) (const X509_NAME *const *a, const X509_NAME *const *b);
+
+    oldcmp = sk_X509_NAME_set_cmp_func(stack, xname_sk_cmp);
+
+    in = BIO_new(BIO_s_file());
+
+    if (in == NULL) {
+        SSLerr(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (!BIO_read_filename(in, file))
+        goto err;
+
+    for (;;) {
+        if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL)
+            break;
+        if ((xn = X509_get_subject_name(x)) == NULL)
+            goto err;
+        xn = X509_NAME_dup(xn);
+        if (xn == NULL)
+            goto err;
+        if (sk_X509_NAME_find(stack, xn) >= 0) {
+            /* Duplicate. */
+            X509_NAME_free(xn);
+        } else if (!sk_X509_NAME_push(stack, xn)) {
+            X509_NAME_free(xn);
+            goto err;
+        }
+    }
+
+    ERR_clear_error();
+    goto done;
+
+ err:
+    ret = 0;
+ done:
+    BIO_free(in);
+    X509_free(x);
+    (void)sk_X509_NAME_set_cmp_func(stack, oldcmp);
+    return ret;
+}
+
+int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+                                       const char *dir)
+{
+    OPENSSL_DIR_CTX *d = NULL;
+    const char *filename;
+    int ret = 0;
+
+    /* Note that a side effect is that the CAs will be sorted by name */
+
+    while ((filename = OPENSSL_DIR_read(&d, dir))) {
+        char buf[1024];
+        int r;
+
+        if (strlen(dir) + strlen(filename) + 2 > sizeof(buf)) {
+            SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK,
+                   SSL_R_PATH_TOO_LONG);
+            goto err;
+        }
+#ifdef OPENSSL_SYS_VMS
+        r = BIO_snprintf(buf, sizeof(buf), "%s%s", dir, filename);
+#else
+        r = BIO_snprintf(buf, sizeof(buf), "%s/%s", dir, filename);
+#endif
+        if (r <= 0 || r >= (int)sizeof(buf))
+            goto err;
+        if (!SSL_add_file_cert_subjects_to_stack(stack, buf))
+            goto err;
+    }
+
+    if (errno) {
+        SYSerr(SYS_F_OPENDIR, get_last_sys_error());
+        ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')");
+        SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, ERR_R_SYS_LIB);
+        goto err;
+    }
+
+    ret = 1;
+
+ err:
+    if (d)
+        OPENSSL_DIR_end(&d);
+
+    return ret;
+}
+
+/* Build a certificate chain for current certificate */
+int ssl_build_cert_chain(SSL *s, SSL_CTX *ctx, int flags)
+{
+    CERT *c = s ? s->cert : ctx->cert;
+    CERT_PKEY *cpk = c->key;
+    X509_STORE *chain_store = NULL;
+    X509_STORE_CTX *xs_ctx = NULL;
+    STACK_OF(X509) *chain = NULL, *untrusted = NULL;
+    X509 *x;
+    int i, rv = 0;
+
+    if (!cpk->x509) {
+        SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_NO_CERTIFICATE_SET);
+        goto err;
+    }
+    /* Rearranging and check the chain: add everything to a store */
+    if (flags & SSL_BUILD_CHAIN_FLAG_CHECK) {
+        chain_store = X509_STORE_new();
+        if (chain_store == NULL)
+            goto err;
+        for (i = 0; i < sk_X509_num(cpk->chain); i++) {
+            x = sk_X509_value(cpk->chain, i);
+            if (!X509_STORE_add_cert(chain_store, x))
+                goto err;
+        }
+        /* Add EE cert too: it might be self signed */
+        if (!X509_STORE_add_cert(chain_store, cpk->x509))
+            goto err;
+    } else {
+        if (c->chain_store)
+            chain_store = c->chain_store;
+        else if (s)
+            chain_store = s->ctx->cert_store;
+        else
+            chain_store = ctx->cert_store;
+
+        if (flags & SSL_BUILD_CHAIN_FLAG_UNTRUSTED)
+            untrusted = cpk->chain;
+    }
+
+    xs_ctx = X509_STORE_CTX_new();
+    if (xs_ctx == NULL) {
+        SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    if (!X509_STORE_CTX_init(xs_ctx, chain_store, cpk->x509, untrusted)) {
+        SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, ERR_R_X509_LIB);
+        goto err;
+    }
+    /* Set suite B flags if needed */
+    X509_STORE_CTX_set_flags(xs_ctx,
+                             c->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS);
+
+    i = X509_verify_cert(xs_ctx);
+    if (i <= 0 && flags & SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR) {
+        if (flags & SSL_BUILD_CHAIN_FLAG_CLEAR_ERROR)
+            ERR_clear_error();
+        i = 1;
+        rv = 2;
+    }
+    if (i > 0)
+        chain = X509_STORE_CTX_get1_chain(xs_ctx);
+    if (i <= 0) {
+        SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_CERTIFICATE_VERIFY_FAILED);
+        i = X509_STORE_CTX_get_error(xs_ctx);
+        ERR_add_error_data(2, "Verify error:",
+                           X509_verify_cert_error_string(i));
+
+        goto err;
+    }
+    /* Remove EE certificate from chain */
+    x = sk_X509_shift(chain);
+    X509_free(x);
+    if (flags & SSL_BUILD_CHAIN_FLAG_NO_ROOT) {
+        if (sk_X509_num(chain) > 0) {
+            /* See if last cert is self signed */
+            x = sk_X509_value(chain, sk_X509_num(chain) - 1);
+            if (X509_get_extension_flags(x) & EXFLAG_SS) {
+                x = sk_X509_pop(chain);
+                X509_free(x);
+            }
+        }
+    }
+    /*
+     * Check security level of all CA certificates: EE will have been checked
+     * already.
+     */
+    for (i = 0; i < sk_X509_num(chain); i++) {
+        x = sk_X509_value(chain, i);
+        rv = ssl_security_cert(s, ctx, x, 0, 0);
+        if (rv != 1) {
+            SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, rv);
+            sk_X509_pop_free(chain, X509_free);
+            rv = 0;
+            goto err;
+        }
+    }
+    sk_X509_pop_free(cpk->chain, X509_free);
+    cpk->chain = chain;
+    if (rv == 0)
+        rv = 1;
+ err:
+    if (flags & SSL_BUILD_CHAIN_FLAG_CHECK)
+        X509_STORE_free(chain_store);
+    X509_STORE_CTX_free(xs_ctx);
+
+    return rv;
+}
+
+int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref)
+{
+    X509_STORE **pstore;
+    if (chain)
+        pstore = &c->chain_store;
+    else
+        pstore = &c->verify_store;
+    X509_STORE_free(*pstore);
+    *pstore = store;
+    if (ref && store)
+        X509_STORE_up_ref(store);
+    return 1;
+}
+
+int ssl_cert_get_cert_store(CERT *c, X509_STORE **pstore, int chain)
+{
+    *pstore = (chain ? c->chain_store : c->verify_store);
+    return 1;
+}
+
+int ssl_get_security_level_bits(const SSL *s, const SSL_CTX *ctx, int *levelp)
+{
+    int level;
+    static const int minbits_table[5 + 1] = { 0, 80, 112, 128, 192, 256 };
+
+    if (ctx != NULL)
+        level = SSL_CTX_get_security_level(ctx);
+    else
+        level = SSL_get_security_level(s);
+
+    if (level > 5)
+        level = 5;
+    else if (level < 0)
+        level = 0;
+
+    if (levelp != NULL)
+        *levelp = level;
+
+    return minbits_table[level];
+}
+
+static int ssl_security_default_callback(const SSL *s, const SSL_CTX *ctx,
+                                         int op, int bits, int nid, void *other,
+                                         void *ex)
+{
+    int level, minbits, pfs_mask;
+
+    minbits = ssl_get_security_level_bits(s, ctx, &level);
+
+    if (level == 0) {
+        /*
+         * No EDH keys weaker than 1024-bits even at level 0, otherwise,
+         * anything goes.
+         */
+        if (op == SSL_SECOP_TMP_DH && bits < 80)
+            return 0;
+        return 1;
+    }
+    switch (op) {
+    case SSL_SECOP_CIPHER_SUPPORTED:
+    case SSL_SECOP_CIPHER_SHARED:
+    case SSL_SECOP_CIPHER_CHECK:
+        {
+            const SSL_CIPHER *c = other;
+            /* No ciphers below security level */
+            if (bits < minbits)
+                return 0;
+            /* No unauthenticated ciphersuites */
+            if (c->algorithm_auth & SSL_aNULL)
+                return 0;
+            /* No MD5 mac ciphersuites */
+            if (c->algorithm_mac & SSL_MD5)
+                return 0;
+            /* SHA1 HMAC is 160 bits of security */
+            if (minbits > 160 && c->algorithm_mac & SSL_SHA1)
+                return 0;
+            /* Level 2: no RC4 */
+            if (level >= 2 && c->algorithm_enc == SSL_RC4)
+                return 0;
+            /* Level 3: forward secure ciphersuites only */
+            pfs_mask = SSL_kDHE | SSL_kECDHE | SSL_kDHEPSK | SSL_kECDHEPSK;
+            if (level >= 3 && c->min_tls != TLS1_3_VERSION &&
+                               !(c->algorithm_mkey & pfs_mask))
+                return 0;
+            break;
+        }
+    case SSL_SECOP_VERSION:
+        if (!SSL_IS_DTLS(s)) {
+            /* SSLv3 not allowed at level 2 */
+            if (nid <= SSL3_VERSION && level >= 2)
+                return 0;
+            /* TLS v1.1 and above only for level 3 */
+            if (nid <= TLS1_VERSION && level >= 3)
+                return 0;
+            /* TLS v1.2 only for level 4 and above */
+            if (nid <= TLS1_1_VERSION && level >= 4)
+                return 0;
+        } else {
+            /* DTLS v1.2 only for level 4 and above */
+            if (DTLS_VERSION_LT(nid, DTLS1_2_VERSION) && level >= 4)
+                return 0;
+        }
+        break;
+
+    case SSL_SECOP_COMPRESSION:
+        if (level >= 2)
+            return 0;
+        break;
+    case SSL_SECOP_TICKET:
+        if (level >= 3)
+            return 0;
+        break;
+    default:
+        if (bits < minbits)
+            return 0;
+    }
+    return 1;
+}
+
+int ssl_security(const SSL *s, int op, int bits, int nid, void *other)
+{
+    return s->cert->sec_cb(s, NULL, op, bits, nid, other, s->cert->sec_ex);
+}
+
+int ssl_ctx_security(const SSL_CTX *ctx, int op, int bits, int nid, void *other)
+{
+    return ctx->cert->sec_cb(NULL, ctx, op, bits, nid, other,
+                             ctx->cert->sec_ex);
+}
+
+int ssl_cert_lookup_by_nid(int nid, size_t *pidx)
+{
+    size_t i;
+
+    for (i = 0; i < OSSL_NELEM(ssl_cert_info); i++) {
+        if (ssl_cert_info[i].nid == nid) {
+            *pidx = i;
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+const SSL_CERT_LOOKUP *ssl_cert_lookup_by_pkey(const EVP_PKEY *pk, size_t *pidx)
+{
+    int nid = EVP_PKEY_id(pk);
+    size_t tmpidx;
+
+    if (nid == NID_undef)
+        return NULL;
+
+    if (!ssl_cert_lookup_by_nid(nid, &tmpidx))
+        return NULL;
+
+    if (pidx != NULL)
+        *pidx = tmpidx;
+
+    return &ssl_cert_info[tmpidx];
+}
+
+const SSL_CERT_LOOKUP *ssl_cert_lookup_by_idx(size_t idx)
+{
+    if (idx >= OSSL_NELEM(ssl_cert_info))
+        return NULL;
+    return &ssl_cert_info[idx];
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_cert_table.h b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_cert_table.h
new file mode 100644
index 0000000..0c47241
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_cert_table.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * Certificate table information. NB: table entries must match SSL_PKEY indices
+ */
+static const SSL_CERT_LOOKUP ssl_cert_info [] = {
+    {EVP_PKEY_RSA, SSL_aRSA}, /* SSL_PKEY_RSA */
+    {EVP_PKEY_RSA_PSS, SSL_aRSA}, /* SSL_PKEY_RSA_PSS_SIGN */
+    {EVP_PKEY_DSA, SSL_aDSS}, /* SSL_PKEY_DSA_SIGN */
+    {EVP_PKEY_EC, SSL_aECDSA}, /* SSL_PKEY_ECC */
+    {NID_id_GostR3410_2001, SSL_aGOST01}, /* SSL_PKEY_GOST01 */
+    {NID_id_GostR3410_2012_256, SSL_aGOST12}, /* SSL_PKEY_GOST12_256 */
+    {NID_id_GostR3410_2012_512, SSL_aGOST12}, /* SSL_PKEY_GOST12_512 */
+    {EVP_PKEY_ED25519, SSL_aECDSA}, /* SSL_PKEY_ED25519 */
+    {EVP_PKEY_ED448, SSL_aECDSA} /* SSL_PKEY_ED448 */
+};
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_ciph.c b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_ciph.c
new file mode 100644
index 0000000..a3ca529
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_ciph.c
@@ -0,0 +1,2163 @@
+/*
+ * 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.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <openssl/objects.h>
+#include <openssl/comp.h>
+#include <openssl/engine.h>
+#include <openssl/crypto.h>
+#include <openssl/conf.h>
+#include "internal/nelem.h"
+#include "ssl_local.h"
+#include "internal/thread_once.h"
+#include "internal/cryptlib.h"
+
+#define SSL_ENC_DES_IDX         0
+#define SSL_ENC_3DES_IDX        1
+#define SSL_ENC_RC4_IDX         2
+#define SSL_ENC_RC2_IDX         3
+#define SSL_ENC_IDEA_IDX        4
+#define SSL_ENC_NULL_IDX        5
+#define SSL_ENC_AES128_IDX      6
+#define SSL_ENC_AES256_IDX      7
+#define SSL_ENC_CAMELLIA128_IDX 8
+#define SSL_ENC_CAMELLIA256_IDX 9
+#define SSL_ENC_GOST89_IDX      10
+#define SSL_ENC_SEED_IDX        11
+#define SSL_ENC_AES128GCM_IDX   12
+#define SSL_ENC_AES256GCM_IDX   13
+#define SSL_ENC_AES128CCM_IDX   14
+#define SSL_ENC_AES256CCM_IDX   15
+#define SSL_ENC_AES128CCM8_IDX  16
+#define SSL_ENC_AES256CCM8_IDX  17
+#define SSL_ENC_GOST8912_IDX    18
+#define SSL_ENC_CHACHA_IDX      19
+#define SSL_ENC_ARIA128GCM_IDX  20
+#define SSL_ENC_ARIA256GCM_IDX  21
+#define SSL_ENC_NUM_IDX         22
+
+/* NB: make sure indices in these tables match values above */
+
+typedef struct {
+    uint32_t mask;
+    int nid;
+} ssl_cipher_table;
+
+/* Table of NIDs for each cipher */
+static const ssl_cipher_table ssl_cipher_table_cipher[SSL_ENC_NUM_IDX] = {
+    {SSL_DES, NID_des_cbc},     /* SSL_ENC_DES_IDX 0 */
+    {SSL_3DES, NID_des_ede3_cbc}, /* SSL_ENC_3DES_IDX 1 */
+    {SSL_RC4, NID_rc4},         /* SSL_ENC_RC4_IDX 2 */
+    {SSL_RC2, NID_rc2_cbc},     /* SSL_ENC_RC2_IDX 3 */
+    {SSL_IDEA, NID_idea_cbc},   /* SSL_ENC_IDEA_IDX 4 */
+    {SSL_eNULL, NID_undef},     /* SSL_ENC_NULL_IDX 5 */
+    {SSL_AES128, NID_aes_128_cbc}, /* SSL_ENC_AES128_IDX 6 */
+    {SSL_AES256, NID_aes_256_cbc}, /* SSL_ENC_AES256_IDX 7 */
+    {SSL_CAMELLIA128, NID_camellia_128_cbc}, /* SSL_ENC_CAMELLIA128_IDX 8 */
+    {SSL_CAMELLIA256, NID_camellia_256_cbc}, /* SSL_ENC_CAMELLIA256_IDX 9 */
+    {SSL_eGOST2814789CNT, NID_gost89_cnt}, /* SSL_ENC_GOST89_IDX 10 */
+    {SSL_SEED, NID_seed_cbc},   /* SSL_ENC_SEED_IDX 11 */
+    {SSL_AES128GCM, NID_aes_128_gcm}, /* SSL_ENC_AES128GCM_IDX 12 */
+    {SSL_AES256GCM, NID_aes_256_gcm}, /* SSL_ENC_AES256GCM_IDX 13 */
+    {SSL_AES128CCM, NID_aes_128_ccm}, /* SSL_ENC_AES128CCM_IDX 14 */
+    {SSL_AES256CCM, NID_aes_256_ccm}, /* SSL_ENC_AES256CCM_IDX 15 */
+    {SSL_AES128CCM8, NID_aes_128_ccm}, /* SSL_ENC_AES128CCM8_IDX 16 */
+    {SSL_AES256CCM8, NID_aes_256_ccm}, /* SSL_ENC_AES256CCM8_IDX 17 */
+    {SSL_eGOST2814789CNT12, NID_gost89_cnt_12}, /* SSL_ENC_GOST8912_IDX 18 */
+    {SSL_CHACHA20POLY1305, NID_chacha20_poly1305}, /* SSL_ENC_CHACHA_IDX 19 */
+    {SSL_ARIA128GCM, NID_aria_128_gcm}, /* SSL_ENC_ARIA128GCM_IDX 20 */
+    {SSL_ARIA256GCM, NID_aria_256_gcm}, /* SSL_ENC_ARIA256GCM_IDX 21 */
+};
+
+static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX];
+
+#define SSL_COMP_NULL_IDX       0
+#define SSL_COMP_ZLIB_IDX       1
+#define SSL_COMP_NUM_IDX        2
+
+static STACK_OF(SSL_COMP) *ssl_comp_methods = NULL;
+
+#ifndef OPENSSL_NO_COMP
+static CRYPTO_ONCE ssl_load_builtin_comp_once = CRYPTO_ONCE_STATIC_INIT;
+#endif
+
+/*
+ * Constant SSL_MAX_DIGEST equal to size of digests array should be defined
+ * in the ssl_local.h
+ */
+
+#define SSL_MD_NUM_IDX  SSL_MAX_DIGEST
+
+/* NB: make sure indices in this table matches values above */
+static const ssl_cipher_table ssl_cipher_table_mac[SSL_MD_NUM_IDX] = {
+    {SSL_MD5, NID_md5},         /* SSL_MD_MD5_IDX 0 */
+    {SSL_SHA1, NID_sha1},       /* SSL_MD_SHA1_IDX 1 */
+    {SSL_GOST94, NID_id_GostR3411_94}, /* SSL_MD_GOST94_IDX 2 */
+    {SSL_GOST89MAC, NID_id_Gost28147_89_MAC}, /* SSL_MD_GOST89MAC_IDX 3 */
+    {SSL_SHA256, NID_sha256},   /* SSL_MD_SHA256_IDX 4 */
+    {SSL_SHA384, NID_sha384},   /* SSL_MD_SHA384_IDX 5 */
+    {SSL_GOST12_256, NID_id_GostR3411_2012_256}, /* SSL_MD_GOST12_256_IDX 6 */
+    {SSL_GOST89MAC12, NID_gost_mac_12}, /* SSL_MD_GOST89MAC12_IDX 7 */
+    {SSL_GOST12_512, NID_id_GostR3411_2012_512}, /* SSL_MD_GOST12_512_IDX 8 */
+    {0, NID_md5_sha1},          /* SSL_MD_MD5_SHA1_IDX 9 */
+    {0, NID_sha224},            /* SSL_MD_SHA224_IDX 10 */
+    {0, NID_sha512}             /* SSL_MD_SHA512_IDX 11 */
+};
+
+static const EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX] = {
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+/* *INDENT-OFF* */
+static const ssl_cipher_table ssl_cipher_table_kx[] = {
+    {SSL_kRSA,      NID_kx_rsa},
+    {SSL_kECDHE,    NID_kx_ecdhe},
+    {SSL_kDHE,      NID_kx_dhe},
+    {SSL_kECDHEPSK, NID_kx_ecdhe_psk},
+    {SSL_kDHEPSK,   NID_kx_dhe_psk},
+    {SSL_kRSAPSK,   NID_kx_rsa_psk},
+    {SSL_kPSK,      NID_kx_psk},
+    {SSL_kSRP,      NID_kx_srp},
+    {SSL_kGOST,     NID_kx_gost},
+    {SSL_kANY,      NID_kx_any}
+};
+
+static const ssl_cipher_table ssl_cipher_table_auth[] = {
+    {SSL_aRSA,    NID_auth_rsa},
+    {SSL_aECDSA,  NID_auth_ecdsa},
+    {SSL_aPSK,    NID_auth_psk},
+    {SSL_aDSS,    NID_auth_dss},
+    {SSL_aGOST01, NID_auth_gost01},
+    {SSL_aGOST12, NID_auth_gost12},
+    {SSL_aSRP,    NID_auth_srp},
+    {SSL_aNULL,   NID_auth_null},
+    {SSL_aANY,    NID_auth_any}
+};
+/* *INDENT-ON* */
+
+/* Utility function for table lookup */
+static int ssl_cipher_info_find(const ssl_cipher_table * table,
+                                size_t table_cnt, uint32_t mask)
+{
+    size_t i;
+    for (i = 0; i < table_cnt; i++, table++) {
+        if (table->mask == mask)
+            return (int)i;
+    }
+    return -1;
+}
+
+#define ssl_cipher_info_lookup(table, x) \
+    ssl_cipher_info_find(table, OSSL_NELEM(table), x)
+
+/*
+ * PKEY_TYPE for GOST89MAC is known in advance, but, because implementation
+ * is engine-provided, we'll fill it only if corresponding EVP_PKEY_METHOD is
+ * found
+ */
+static int ssl_mac_pkey_id[SSL_MD_NUM_IDX] = {
+    /* MD5, SHA, GOST94, MAC89 */
+    EVP_PKEY_HMAC, EVP_PKEY_HMAC, EVP_PKEY_HMAC, NID_undef,
+    /* SHA256, SHA384, GOST2012_256, MAC89-12 */
+    EVP_PKEY_HMAC, EVP_PKEY_HMAC, EVP_PKEY_HMAC, NID_undef,
+    /* GOST2012_512 */
+    EVP_PKEY_HMAC,
+    /* MD5/SHA1, SHA224, SHA512 */
+    NID_undef, NID_undef, NID_undef
+};
+
+static size_t ssl_mac_secret_size[SSL_MD_NUM_IDX];
+
+#define CIPHER_ADD      1
+#define CIPHER_KILL     2
+#define CIPHER_DEL      3
+#define CIPHER_ORD      4
+#define CIPHER_SPECIAL  5
+/*
+ * Bump the ciphers to the top of the list.
+ * This rule isn't currently supported by the public cipherstring API.
+ */
+#define CIPHER_BUMP     6
+
+typedef struct cipher_order_st {
+    const SSL_CIPHER *cipher;
+    int active;
+    int dead;
+    struct cipher_order_st *next, *prev;
+} CIPHER_ORDER;
+
+static const SSL_CIPHER cipher_aliases[] = {
+    /* "ALL" doesn't include eNULL (must be specifically enabled) */
+    {0, SSL_TXT_ALL, NULL, 0, 0, 0, ~SSL_eNULL},
+    /* "COMPLEMENTOFALL" */
+    {0, SSL_TXT_CMPALL, NULL, 0, 0, 0, SSL_eNULL},
+
+    /*
+     * "COMPLEMENTOFDEFAULT" (does *not* include ciphersuites not found in
+     * ALL!)
+     */
+    {0, SSL_TXT_CMPDEF, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, SSL_NOT_DEFAULT},
+
+    /*
+     * key exchange aliases (some of those using only a single bit here
+     * combine multiple key exchange algs according to the RFCs, e.g. kDHE
+     * combines DHE_DSS and DHE_RSA)
+     */
+    {0, SSL_TXT_kRSA, NULL, 0, SSL_kRSA},
+
+    {0, SSL_TXT_kEDH, NULL, 0, SSL_kDHE},
+    {0, SSL_TXT_kDHE, NULL, 0, SSL_kDHE},
+    {0, SSL_TXT_DH, NULL, 0, SSL_kDHE},
+
+    {0, SSL_TXT_kEECDH, NULL, 0, SSL_kECDHE},
+    {0, SSL_TXT_kECDHE, NULL, 0, SSL_kECDHE},
+    {0, SSL_TXT_ECDH, NULL, 0, SSL_kECDHE},
+
+    {0, SSL_TXT_kPSK, NULL, 0, SSL_kPSK},
+    {0, SSL_TXT_kRSAPSK, NULL, 0, SSL_kRSAPSK},
+    {0, SSL_TXT_kECDHEPSK, NULL, 0, SSL_kECDHEPSK},
+    {0, SSL_TXT_kDHEPSK, NULL, 0, SSL_kDHEPSK},
+    {0, SSL_TXT_kSRP, NULL, 0, SSL_kSRP},
+    {0, SSL_TXT_kGOST, NULL, 0, SSL_kGOST},
+
+    /* server authentication aliases */
+    {0, SSL_TXT_aRSA, NULL, 0, 0, SSL_aRSA},
+    {0, SSL_TXT_aDSS, NULL, 0, 0, SSL_aDSS},
+    {0, SSL_TXT_DSS, NULL, 0, 0, SSL_aDSS},
+    {0, SSL_TXT_aNULL, NULL, 0, 0, SSL_aNULL},
+    {0, SSL_TXT_aECDSA, NULL, 0, 0, SSL_aECDSA},
+    {0, SSL_TXT_ECDSA, NULL, 0, 0, SSL_aECDSA},
+    {0, SSL_TXT_aPSK, NULL, 0, 0, SSL_aPSK},
+    {0, SSL_TXT_aGOST01, NULL, 0, 0, SSL_aGOST01},
+    {0, SSL_TXT_aGOST12, NULL, 0, 0, SSL_aGOST12},
+    {0, SSL_TXT_aGOST, NULL, 0, 0, SSL_aGOST01 | SSL_aGOST12},
+    {0, SSL_TXT_aSRP, NULL, 0, 0, SSL_aSRP},
+
+    /* aliases combining key exchange and server authentication */
+    {0, SSL_TXT_EDH, NULL, 0, SSL_kDHE, ~SSL_aNULL},
+    {0, SSL_TXT_DHE, NULL, 0, SSL_kDHE, ~SSL_aNULL},
+    {0, SSL_TXT_EECDH, NULL, 0, SSL_kECDHE, ~SSL_aNULL},
+    {0, SSL_TXT_ECDHE, NULL, 0, SSL_kECDHE, ~SSL_aNULL},
+    {0, SSL_TXT_NULL, NULL, 0, 0, 0, SSL_eNULL},
+    {0, SSL_TXT_RSA, NULL, 0, SSL_kRSA, SSL_aRSA},
+    {0, SSL_TXT_ADH, NULL, 0, SSL_kDHE, SSL_aNULL},
+    {0, SSL_TXT_AECDH, NULL, 0, SSL_kECDHE, SSL_aNULL},
+    {0, SSL_TXT_PSK, NULL, 0, SSL_PSK},
+    {0, SSL_TXT_SRP, NULL, 0, SSL_kSRP},
+
+    /* symmetric encryption aliases */
+    {0, SSL_TXT_3DES, NULL, 0, 0, 0, SSL_3DES},
+    {0, SSL_TXT_RC4, NULL, 0, 0, 0, SSL_RC4},
+    {0, SSL_TXT_RC2, NULL, 0, 0, 0, SSL_RC2},
+    {0, SSL_TXT_IDEA, NULL, 0, 0, 0, SSL_IDEA},
+    {0, SSL_TXT_SEED, NULL, 0, 0, 0, SSL_SEED},
+    {0, SSL_TXT_eNULL, NULL, 0, 0, 0, SSL_eNULL},
+    {0, SSL_TXT_GOST, NULL, 0, 0, 0, SSL_eGOST2814789CNT | SSL_eGOST2814789CNT12},
+    {0, SSL_TXT_AES128, NULL, 0, 0, 0,
+     SSL_AES128 | SSL_AES128GCM | SSL_AES128CCM | SSL_AES128CCM8},
+    {0, SSL_TXT_AES256, NULL, 0, 0, 0,
+     SSL_AES256 | SSL_AES256GCM | SSL_AES256CCM | SSL_AES256CCM8},
+    {0, SSL_TXT_AES, NULL, 0, 0, 0, SSL_AES},
+    {0, SSL_TXT_AES_GCM, NULL, 0, 0, 0, SSL_AES128GCM | SSL_AES256GCM},
+    {0, SSL_TXT_AES_CCM, NULL, 0, 0, 0,
+     SSL_AES128CCM | SSL_AES256CCM | SSL_AES128CCM8 | SSL_AES256CCM8},
+    {0, SSL_TXT_AES_CCM_8, NULL, 0, 0, 0, SSL_AES128CCM8 | SSL_AES256CCM8},
+    {0, SSL_TXT_CAMELLIA128, NULL, 0, 0, 0, SSL_CAMELLIA128},
+    {0, SSL_TXT_CAMELLIA256, NULL, 0, 0, 0, SSL_CAMELLIA256},
+    {0, SSL_TXT_CAMELLIA, NULL, 0, 0, 0, SSL_CAMELLIA},
+    {0, SSL_TXT_CHACHA20, NULL, 0, 0, 0, SSL_CHACHA20},
+
+    {0, SSL_TXT_ARIA, NULL, 0, 0, 0, SSL_ARIA},
+    {0, SSL_TXT_ARIA_GCM, NULL, 0, 0, 0, SSL_ARIA128GCM | SSL_ARIA256GCM},
+    {0, SSL_TXT_ARIA128, NULL, 0, 0, 0, SSL_ARIA128GCM},
+    {0, SSL_TXT_ARIA256, NULL, 0, 0, 0, SSL_ARIA256GCM},
+
+    /* MAC aliases */
+    {0, SSL_TXT_MD5, NULL, 0, 0, 0, 0, SSL_MD5},
+    {0, SSL_TXT_SHA1, NULL, 0, 0, 0, 0, SSL_SHA1},
+    {0, SSL_TXT_SHA, NULL, 0, 0, 0, 0, SSL_SHA1},
+    {0, SSL_TXT_GOST94, NULL, 0, 0, 0, 0, SSL_GOST94},
+    {0, SSL_TXT_GOST89MAC, NULL, 0, 0, 0, 0, SSL_GOST89MAC | SSL_GOST89MAC12},
+    {0, SSL_TXT_SHA256, NULL, 0, 0, 0, 0, SSL_SHA256},
+    {0, SSL_TXT_SHA384, NULL, 0, 0, 0, 0, SSL_SHA384},
+    {0, SSL_TXT_GOST12, NULL, 0, 0, 0, 0, SSL_GOST12_256},
+
+    /* protocol version aliases */
+    {0, SSL_TXT_SSLV3, NULL, 0, 0, 0, 0, 0, SSL3_VERSION},
+    {0, SSL_TXT_TLSV1, NULL, 0, 0, 0, 0, 0, TLS1_VERSION},
+    {0, "TLSv1.0", NULL, 0, 0, 0, 0, 0, TLS1_VERSION},
+    {0, SSL_TXT_TLSV1_2, NULL, 0, 0, 0, 0, 0, TLS1_2_VERSION},
+
+    /* strength classes */
+    {0, SSL_TXT_LOW, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, SSL_LOW},
+    {0, SSL_TXT_MEDIUM, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, SSL_MEDIUM},
+    {0, SSL_TXT_HIGH, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, SSL_HIGH},
+    /* FIPS 140-2 approved ciphersuite */
+    {0, SSL_TXT_FIPS, NULL, 0, 0, 0, ~SSL_eNULL, 0, 0, 0, 0, 0, SSL_FIPS},
+
+    /* "EDH-" aliases to "DHE-" labels (for backward compatibility) */
+    {0, SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA, NULL, 0,
+     SSL_kDHE, SSL_aDSS, SSL_3DES, SSL_SHA1, 0, 0, 0, 0, SSL_HIGH | SSL_FIPS},
+    {0, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA, NULL, 0,
+     SSL_kDHE, SSL_aRSA, SSL_3DES, SSL_SHA1, 0, 0, 0, 0, SSL_HIGH | SSL_FIPS},
+
+};
+
+/*
+ * Search for public key algorithm with given name and return its pkey_id if
+ * it is available. Otherwise return 0
+ */
+#ifdef OPENSSL_NO_ENGINE
+
+static int get_optional_pkey_id(const char *pkey_name)
+{
+    const EVP_PKEY_ASN1_METHOD *ameth;
+    int pkey_id = 0;
+    ameth = EVP_PKEY_asn1_find_str(NULL, pkey_name, -1);
+    if (ameth && EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL,
+                                         ameth) > 0)
+        return pkey_id;
+    return 0;
+}
+
+#else
+
+static int get_optional_pkey_id(const char *pkey_name)
+{
+    const EVP_PKEY_ASN1_METHOD *ameth;
+    ENGINE *tmpeng = NULL;
+    int pkey_id = 0;
+    ameth = EVP_PKEY_asn1_find_str(&tmpeng, pkey_name, -1);
+    if (ameth) {
+        if (EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL,
+                                    ameth) <= 0)
+            pkey_id = 0;
+    }
+    ENGINE_finish(tmpeng);
+    return pkey_id;
+}
+
+#endif
+
+/* masks of disabled algorithms */
+static uint32_t disabled_enc_mask;
+static uint32_t disabled_mac_mask;
+static uint32_t disabled_mkey_mask;
+static uint32_t disabled_auth_mask;
+
+int ssl_load_ciphers(void)
+{
+    size_t i;
+    const ssl_cipher_table *t;
+
+    disabled_enc_mask = 0;
+    ssl_sort_cipher_list();
+    for (i = 0, t = ssl_cipher_table_cipher; i < SSL_ENC_NUM_IDX; i++, t++) {
+        if (t->nid == NID_undef) {
+            ssl_cipher_methods[i] = NULL;
+        } else {
+            const EVP_CIPHER *cipher = EVP_get_cipherbynid(t->nid);
+            ssl_cipher_methods[i] = cipher;
+            if (cipher == NULL)
+                disabled_enc_mask |= t->mask;
+        }
+    }
+    disabled_mac_mask = 0;
+    for (i = 0, t = ssl_cipher_table_mac; i < SSL_MD_NUM_IDX; i++, t++) {
+        const EVP_MD *md = EVP_get_digestbynid(t->nid);
+        ssl_digest_methods[i] = md;
+        if (md == NULL) {
+            disabled_mac_mask |= t->mask;
+        } else {
+            int tmpsize = EVP_MD_size(md);
+            if (!ossl_assert(tmpsize >= 0))
+                return 0;
+            ssl_mac_secret_size[i] = tmpsize;
+        }
+    }
+    /* Make sure we can access MD5 and SHA1 */
+    if (!ossl_assert(ssl_digest_methods[SSL_MD_MD5_IDX] != NULL))
+        return 0;
+    if (!ossl_assert(ssl_digest_methods[SSL_MD_SHA1_IDX] != NULL))
+        return 0;
+
+    disabled_mkey_mask = 0;
+    disabled_auth_mask = 0;
+
+#ifdef OPENSSL_NO_RSA
+    disabled_mkey_mask |= SSL_kRSA | SSL_kRSAPSK;
+    disabled_auth_mask |= SSL_aRSA;
+#endif
+#ifdef OPENSSL_NO_DSA
+    disabled_auth_mask |= SSL_aDSS;
+#endif
+#ifdef OPENSSL_NO_DH
+    disabled_mkey_mask |= SSL_kDHE | SSL_kDHEPSK;
+#endif
+#ifdef OPENSSL_NO_EC
+    disabled_mkey_mask |= SSL_kECDHE | SSL_kECDHEPSK;
+    disabled_auth_mask |= SSL_aECDSA;
+#endif
+#ifdef OPENSSL_NO_PSK
+    disabled_mkey_mask |= SSL_PSK;
+    disabled_auth_mask |= SSL_aPSK;
+#endif
+#ifdef OPENSSL_NO_SRP
+    disabled_mkey_mask |= SSL_kSRP;
+#endif
+
+    /*
+     * Check for presence of GOST 34.10 algorithms, and if they are not
+     * present, disable appropriate auth and key exchange
+     */
+    ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX] = get_optional_pkey_id("gost-mac");
+    if (ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX])
+        ssl_mac_secret_size[SSL_MD_GOST89MAC_IDX] = 32;
+    else
+        disabled_mac_mask |= SSL_GOST89MAC;
+
+    ssl_mac_pkey_id[SSL_MD_GOST89MAC12_IDX] =
+        get_optional_pkey_id("gost-mac-12");
+    if (ssl_mac_pkey_id[SSL_MD_GOST89MAC12_IDX])
+        ssl_mac_secret_size[SSL_MD_GOST89MAC12_IDX] = 32;
+    else
+        disabled_mac_mask |= SSL_GOST89MAC12;
+
+    if (!get_optional_pkey_id("gost2001"))
+        disabled_auth_mask |= SSL_aGOST01 | SSL_aGOST12;
+    if (!get_optional_pkey_id("gost2012_256"))
+        disabled_auth_mask |= SSL_aGOST12;
+    if (!get_optional_pkey_id("gost2012_512"))
+        disabled_auth_mask |= SSL_aGOST12;
+    /*
+     * Disable GOST key exchange if no GOST signature algs are available *
+     */
+    if ((disabled_auth_mask & (SSL_aGOST01 | SSL_aGOST12)) ==
+        (SSL_aGOST01 | SSL_aGOST12))
+        disabled_mkey_mask |= SSL_kGOST;
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_COMP
+
+static int sk_comp_cmp(const SSL_COMP *const *a, const SSL_COMP *const *b)
+{
+    return ((*a)->id - (*b)->id);
+}
+
+DEFINE_RUN_ONCE_STATIC(do_load_builtin_compressions)
+{
+    SSL_COMP *comp = NULL;
+    COMP_METHOD *method = COMP_zlib();
+
+    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
+    ssl_comp_methods = sk_SSL_COMP_new(sk_comp_cmp);
+
+    if (COMP_get_type(method) != NID_undef && ssl_comp_methods != NULL) {
+        comp = OPENSSL_malloc(sizeof(*comp));
+        if (comp != NULL) {
+            comp->method = method;
+            comp->id = SSL_COMP_ZLIB_IDX;
+            comp->name = COMP_get_name(method);
+            sk_SSL_COMP_push(ssl_comp_methods, comp);
+            sk_SSL_COMP_sort(ssl_comp_methods);
+        }
+    }
+    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
+    return 1;
+}
+
+static int load_builtin_compressions(void)
+{
+    return RUN_ONCE(&ssl_load_builtin_comp_once, do_load_builtin_compressions);
+}
+#endif
+
+int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc,
+                       const EVP_MD **md, int *mac_pkey_type,
+                       size_t *mac_secret_size, SSL_COMP **comp, int use_etm)
+{
+    int i;
+    const SSL_CIPHER *c;
+
+    c = s->cipher;
+    if (c == NULL)
+        return 0;
+    if (comp != NULL) {
+        SSL_COMP ctmp;
+#ifndef OPENSSL_NO_COMP
+        if (!load_builtin_compressions()) {
+            /*
+             * Currently don't care, since a failure only means that
+             * ssl_comp_methods is NULL, which is perfectly OK
+             */
+        }
+#endif
+        *comp = NULL;
+        ctmp.id = s->compress_meth;
+        if (ssl_comp_methods != NULL) {
+            i = sk_SSL_COMP_find(ssl_comp_methods, &ctmp);
+            *comp = sk_SSL_COMP_value(ssl_comp_methods, i);
+        }
+        /* If were only interested in comp then return success */
+        if ((enc == NULL) && (md == NULL))
+            return 1;
+    }
+
+    if ((enc == NULL) || (md == NULL))
+        return 0;
+
+    i = ssl_cipher_info_lookup(ssl_cipher_table_cipher, c->algorithm_enc);
+
+    if (i == -1) {
+        *enc = NULL;
+    } else {
+        if (i == SSL_ENC_NULL_IDX)
+            *enc = EVP_enc_null();
+        else
+            *enc = ssl_cipher_methods[i];
+    }
+
+    i = ssl_cipher_info_lookup(ssl_cipher_table_mac, c->algorithm_mac);
+    if (i == -1) {
+        *md = NULL;
+        if (mac_pkey_type != NULL)
+            *mac_pkey_type = NID_undef;
+        if (mac_secret_size != NULL)
+            *mac_secret_size = 0;
+        if (c->algorithm_mac == SSL_AEAD)
+            mac_pkey_type = NULL;
+    } else {
+        *md = ssl_digest_methods[i];
+        if (mac_pkey_type != NULL)
+            *mac_pkey_type = ssl_mac_pkey_id[i];
+        if (mac_secret_size != NULL)
+            *mac_secret_size = ssl_mac_secret_size[i];
+    }
+
+    if ((*enc != NULL) &&
+        (*md != NULL || (EVP_CIPHER_flags(*enc) & EVP_CIPH_FLAG_AEAD_CIPHER))
+        && (!mac_pkey_type || *mac_pkey_type != NID_undef)) {
+        const EVP_CIPHER *evp;
+
+        if (use_etm)
+            return 1;
+
+        if (s->ssl_version >> 8 != TLS1_VERSION_MAJOR ||
+            s->ssl_version < TLS1_VERSION)
+            return 1;
+
+        if (c->algorithm_enc == SSL_RC4 &&
+            c->algorithm_mac == SSL_MD5 &&
+            (evp = EVP_get_cipherbyname("RC4-HMAC-MD5")))
+            *enc = evp, *md = NULL;
+        else if (c->algorithm_enc == SSL_AES128 &&
+                 c->algorithm_mac == SSL_SHA1 &&
+                 (evp = EVP_get_cipherbyname("AES-128-CBC-HMAC-SHA1")))
+            *enc = evp, *md = NULL;
+        else if (c->algorithm_enc == SSL_AES256 &&
+                 c->algorithm_mac == SSL_SHA1 &&
+                 (evp = EVP_get_cipherbyname("AES-256-CBC-HMAC-SHA1")))
+            *enc = evp, *md = NULL;
+        else if (c->algorithm_enc == SSL_AES128 &&
+                 c->algorithm_mac == SSL_SHA256 &&
+                 (evp = EVP_get_cipherbyname("AES-128-CBC-HMAC-SHA256")))
+            *enc = evp, *md = NULL;
+        else if (c->algorithm_enc == SSL_AES256 &&
+                 c->algorithm_mac == SSL_SHA256 &&
+                 (evp = EVP_get_cipherbyname("AES-256-CBC-HMAC-SHA256")))
+            *enc = evp, *md = NULL;
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+const EVP_MD *ssl_md(int idx)
+{
+    idx &= SSL_HANDSHAKE_MAC_MASK;
+    if (idx < 0 || idx >= SSL_MD_NUM_IDX)
+        return NULL;
+    return ssl_digest_methods[idx];
+}
+
+const EVP_MD *ssl_handshake_md(SSL *s)
+{
+    return ssl_md(ssl_get_algorithm2(s));
+}
+
+const EVP_MD *ssl_prf_md(SSL *s)
+{
+    return ssl_md(ssl_get_algorithm2(s) >> TLS1_PRF_DGST_SHIFT);
+}
+
+#define ITEM_SEP(a) \
+        (((a) == ':') || ((a) == ' ') || ((a) == ';') || ((a) == ','))
+
+static void ll_append_tail(CIPHER_ORDER **head, CIPHER_ORDER *curr,
+                           CIPHER_ORDER **tail)
+{
+    if (curr == *tail)
+        return;
+    if (curr == *head)
+        *head = curr->next;
+    if (curr->prev != NULL)
+        curr->prev->next = curr->next;
+    if (curr->next != NULL)
+        curr->next->prev = curr->prev;
+    (*tail)->next = curr;
+    curr->prev = *tail;
+    curr->next = NULL;
+    *tail = curr;
+}
+
+static void ll_append_head(CIPHER_ORDER **head, CIPHER_ORDER *curr,
+                           CIPHER_ORDER **tail)
+{
+    if (curr == *head)
+        return;
+    if (curr == *tail)
+        *tail = curr->prev;
+    if (curr->next != NULL)
+        curr->next->prev = curr->prev;
+    if (curr->prev != NULL)
+        curr->prev->next = curr->next;
+    (*head)->prev = curr;
+    curr->next = *head;
+    curr->prev = NULL;
+    *head = curr;
+}
+
+static void ssl_cipher_collect_ciphers(const SSL_METHOD *ssl_method,
+                                       int num_of_ciphers,
+                                       uint32_t disabled_mkey,
+                                       uint32_t disabled_auth,
+                                       uint32_t disabled_enc,
+                                       uint32_t disabled_mac,
+                                       CIPHER_ORDER *co_list,
+                                       CIPHER_ORDER **head_p,
+                                       CIPHER_ORDER **tail_p)
+{
+    int i, co_list_num;
+    const SSL_CIPHER *c;
+
+    /*
+     * We have num_of_ciphers descriptions compiled in, depending on the
+     * method selected (SSLv3, TLSv1 etc).
+     * These will later be sorted in a linked list with at most num
+     * entries.
+     */
+
+    /* Get the initial list of ciphers */
+    co_list_num = 0;            /* actual count of ciphers */
+    for (i = 0; i < num_of_ciphers; i++) {
+        c = ssl_method->get_cipher(i);
+        /* drop those that use any of that is not available */
+        if (c == NULL || !c->valid)
+            continue;
+        if ((c->algorithm_mkey & disabled_mkey) ||
+            (c->algorithm_auth & disabled_auth) ||
+            (c->algorithm_enc & disabled_enc) ||
+            (c->algorithm_mac & disabled_mac))
+            continue;
+        if (((ssl_method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS) == 0) &&
+            c->min_tls == 0)
+            continue;
+        if (((ssl_method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS) != 0) &&
+            c->min_dtls == 0)
+            continue;
+
+        co_list[co_list_num].cipher = c;
+        co_list[co_list_num].next = NULL;
+        co_list[co_list_num].prev = NULL;
+        co_list[co_list_num].active = 0;
+        co_list_num++;
+    }
+
+    /*
+     * Prepare linked list from list entries
+     */
+    if (co_list_num > 0) {
+        co_list[0].prev = NULL;
+
+        if (co_list_num > 1) {
+            co_list[0].next = &co_list[1];
+
+            for (i = 1; i < co_list_num - 1; i++) {
+                co_list[i].prev = &co_list[i - 1];
+                co_list[i].next = &co_list[i + 1];
+            }
+
+            co_list[co_list_num - 1].prev = &co_list[co_list_num - 2];
+        }
+
+        co_list[co_list_num - 1].next = NULL;
+
+        *head_p = &co_list[0];
+        *tail_p = &co_list[co_list_num - 1];
+    }
+}
+
+static void ssl_cipher_collect_aliases(const SSL_CIPHER **ca_list,
+                                       int num_of_group_aliases,
+                                       uint32_t disabled_mkey,
+                                       uint32_t disabled_auth,
+                                       uint32_t disabled_enc,
+                                       uint32_t disabled_mac,
+                                       CIPHER_ORDER *head)
+{
+    CIPHER_ORDER *ciph_curr;
+    const SSL_CIPHER **ca_curr;
+    int i;
+    uint32_t mask_mkey = ~disabled_mkey;
+    uint32_t mask_auth = ~disabled_auth;
+    uint32_t mask_enc = ~disabled_enc;
+    uint32_t mask_mac = ~disabled_mac;
+
+    /*
+     * First, add the real ciphers as already collected
+     */
+    ciph_curr = head;
+    ca_curr = ca_list;
+    while (ciph_curr != NULL) {
+        *ca_curr = ciph_curr->cipher;
+        ca_curr++;
+        ciph_curr = ciph_curr->next;
+    }
+
+    /*
+     * Now we add the available ones from the cipher_aliases[] table.
+     * They represent either one or more algorithms, some of which
+     * in any affected category must be supported (set in enabled_mask),
+     * or represent a cipher strength value (will be added in any case because algorithms=0).
+     */
+    for (i = 0; i < num_of_group_aliases; i++) {
+        uint32_t algorithm_mkey = cipher_aliases[i].algorithm_mkey;
+        uint32_t algorithm_auth = cipher_aliases[i].algorithm_auth;
+        uint32_t algorithm_enc = cipher_aliases[i].algorithm_enc;
+        uint32_t algorithm_mac = cipher_aliases[i].algorithm_mac;
+
+        if (algorithm_mkey)
+            if ((algorithm_mkey & mask_mkey) == 0)
+                continue;
+
+        if (algorithm_auth)
+            if ((algorithm_auth & mask_auth) == 0)
+                continue;
+
+        if (algorithm_enc)
+            if ((algorithm_enc & mask_enc) == 0)
+                continue;
+
+        if (algorithm_mac)
+            if ((algorithm_mac & mask_mac) == 0)
+                continue;
+
+        *ca_curr = (SSL_CIPHER *)(cipher_aliases + i);
+        ca_curr++;
+    }
+
+    *ca_curr = NULL;            /* end of list */
+}
+
+static void ssl_cipher_apply_rule(uint32_t cipher_id, uint32_t alg_mkey,
+                                  uint32_t alg_auth, uint32_t alg_enc,
+                                  uint32_t alg_mac, int min_tls,
+                                  uint32_t algo_strength, int rule,
+                                  int32_t strength_bits, CIPHER_ORDER **head_p,
+                                  CIPHER_ORDER **tail_p)
+{
+    CIPHER_ORDER *head, *tail, *curr, *next, *last;
+    const SSL_CIPHER *cp;
+    int reverse = 0;
+
+#ifdef CIPHER_DEBUG
+    fprintf(stderr,
+            "Applying rule %d with %08x/%08x/%08x/%08x/%08x %08x (%d)\n",
+            rule, alg_mkey, alg_auth, alg_enc, alg_mac, min_tls,
+            algo_strength, strength_bits);
+#endif
+
+    if (rule == CIPHER_DEL || rule == CIPHER_BUMP)
+        reverse = 1;            /* needed to maintain sorting between currently
+                                 * deleted ciphers */
+
+    head = *head_p;
+    tail = *tail_p;
+
+    if (reverse) {
+        next = tail;
+        last = head;
+    } else {
+        next = head;
+        last = tail;
+    }
+
+    curr = NULL;
+    for (;;) {
+        if (curr == last)
+            break;
+
+        curr = next;
+
+        if (curr == NULL)
+            break;
+
+        next = reverse ? curr->prev : curr->next;
+
+        cp = curr->cipher;
+
+        /*
+         * Selection criteria is either the value of strength_bits
+         * or the algorithms used.
+         */
+        if (strength_bits >= 0) {
+            if (strength_bits != cp->strength_bits)
+                continue;
+        } else {
+#ifdef CIPHER_DEBUG
+            fprintf(stderr,
+                    "\nName: %s:\nAlgo = %08x/%08x/%08x/%08x/%08x Algo_strength = %08x\n",
+                    cp->name, cp->algorithm_mkey, cp->algorithm_auth,
+                    cp->algorithm_enc, cp->algorithm_mac, cp->min_tls,
+                    cp->algo_strength);
+#endif
+            if (cipher_id != 0 && (cipher_id != cp->id))
+                continue;
+            if (alg_mkey && !(alg_mkey & cp->algorithm_mkey))
+                continue;
+            if (alg_auth && !(alg_auth & cp->algorithm_auth))
+                continue;
+            if (alg_enc && !(alg_enc & cp->algorithm_enc))
+                continue;
+            if (alg_mac && !(alg_mac & cp->algorithm_mac))
+                continue;
+            if (min_tls && (min_tls != cp->min_tls))
+                continue;
+            if ((algo_strength & SSL_STRONG_MASK)
+                && !(algo_strength & SSL_STRONG_MASK & cp->algo_strength))
+                continue;
+            if ((algo_strength & SSL_DEFAULT_MASK)
+                && !(algo_strength & SSL_DEFAULT_MASK & cp->algo_strength))
+                continue;
+        }
+
+#ifdef CIPHER_DEBUG
+        fprintf(stderr, "Action = %d\n", rule);
+#endif
+
+        /* add the cipher if it has not been added yet. */
+        if (rule == CIPHER_ADD) {
+            /* reverse == 0 */
+            if (!curr->active) {
+                ll_append_tail(&head, curr, &tail);
+                curr->active = 1;
+            }
+        }
+        /* Move the added cipher to this location */
+        else if (rule == CIPHER_ORD) {
+            /* reverse == 0 */
+            if (curr->active) {
+                ll_append_tail(&head, curr, &tail);
+            }
+        } else if (rule == CIPHER_DEL) {
+            /* reverse == 1 */
+            if (curr->active) {
+                /*
+                 * most recently deleted ciphersuites get best positions for
+                 * any future CIPHER_ADD (note that the CIPHER_DEL loop works
+                 * in reverse to maintain the order)
+                 */
+                ll_append_head(&head, curr, &tail);
+                curr->active = 0;
+            }
+        } else if (rule == CIPHER_BUMP) {
+            if (curr->active)
+                ll_append_head(&head, curr, &tail);
+        } else if (rule == CIPHER_KILL) {
+            /* reverse == 0 */
+            if (head == curr)
+                head = curr->next;
+            else
+                curr->prev->next = curr->next;
+            if (tail == curr)
+                tail = curr->prev;
+            curr->active = 0;
+            if (curr->next != NULL)
+                curr->next->prev = curr->prev;
+            if (curr->prev != NULL)
+                curr->prev->next = curr->next;
+            curr->next = NULL;
+            curr->prev = NULL;
+        }
+    }
+
+    *head_p = head;
+    *tail_p = tail;
+}
+
+static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p,
+                                    CIPHER_ORDER **tail_p)
+{
+    int32_t max_strength_bits;
+    int i, *number_uses;
+    CIPHER_ORDER *curr;
+
+    /*
+     * This routine sorts the ciphers with descending strength. The sorting
+     * must keep the pre-sorted sequence, so we apply the normal sorting
+     * routine as '+' movement to the end of the list.
+     */
+    max_strength_bits = 0;
+    curr = *head_p;
+    while (curr != NULL) {
+        if (curr->active && (curr->cipher->strength_bits > max_strength_bits))
+            max_strength_bits = curr->cipher->strength_bits;
+        curr = curr->next;
+    }
+
+    number_uses = OPENSSL_zalloc(sizeof(int) * (max_strength_bits + 1));
+    if (number_uses == NULL) {
+        SSLerr(SSL_F_SSL_CIPHER_STRENGTH_SORT, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    /*
+     * Now find the strength_bits values actually used
+     */
+    curr = *head_p;
+    while (curr != NULL) {
+        if (curr->active)
+            number_uses[curr->cipher->strength_bits]++;
+        curr = curr->next;
+    }
+    /*
+     * Go through the list of used strength_bits values in descending
+     * order.
+     */
+    for (i = max_strength_bits; i >= 0; i--)
+        if (number_uses[i] > 0)
+            ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ORD, i, head_p,
+                                  tail_p);
+
+    OPENSSL_free(number_uses);
+    return 1;
+}
+
+static int ssl_cipher_process_rulestr(const char *rule_str,
+                                      CIPHER_ORDER **head_p,
+                                      CIPHER_ORDER **tail_p,
+                                      const SSL_CIPHER **ca_list, CERT *c)
+{
+    uint32_t alg_mkey, alg_auth, alg_enc, alg_mac, algo_strength;
+    int min_tls;
+    const char *l, *buf;
+    int j, multi, found, rule, retval, ok, buflen;
+    uint32_t cipher_id = 0;
+    char ch;
+
+    retval = 1;
+    l = rule_str;
+    for ( ; ; ) {
+        ch = *l;
+
+        if (ch == '\0')
+            break;              /* done */
+        if (ch == '-') {
+            rule = CIPHER_DEL;
+            l++;
+        } else if (ch == '+') {
+            rule = CIPHER_ORD;
+            l++;
+        } else if (ch == '!') {
+            rule = CIPHER_KILL;
+            l++;
+        } else if (ch == '@') {
+            rule = CIPHER_SPECIAL;
+            l++;
+        } else {
+            rule = CIPHER_ADD;
+        }
+
+        if (ITEM_SEP(ch)) {
+            l++;
+            continue;
+        }
+
+        alg_mkey = 0;
+        alg_auth = 0;
+        alg_enc = 0;
+        alg_mac = 0;
+        min_tls = 0;
+        algo_strength = 0;
+
+        for (;;) {
+            ch = *l;
+            buf = l;
+            buflen = 0;
+#ifndef CHARSET_EBCDIC
+            while (((ch >= 'A') && (ch <= 'Z')) ||
+                   ((ch >= '0') && (ch <= '9')) ||
+                   ((ch >= 'a') && (ch <= 'z')) ||
+                   (ch == '-') || (ch == '.') || (ch == '='))
+#else
+            while (isalnum((unsigned char)ch) || (ch == '-') || (ch == '.')
+                   || (ch == '='))
+#endif
+            {
+                ch = *(++l);
+                buflen++;
+            }
+
+            if (buflen == 0) {
+                /*
+                 * We hit something we cannot deal with,
+                 * it is no command or separator nor
+                 * alphanumeric, so we call this an error.
+                 */
+                SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, SSL_R_INVALID_COMMAND);
+                return 0;
+            }
+
+            if (rule == CIPHER_SPECIAL) {
+                found = 0;      /* unused -- avoid compiler warning */
+                break;          /* special treatment */
+            }
+
+            /* check for multi-part specification */
+            if (ch == '+') {
+                multi = 1;
+                l++;
+            } else {
+                multi = 0;
+            }
+
+            /*
+             * Now search for the cipher alias in the ca_list. Be careful
+             * with the strncmp, because the "buflen" limitation
+             * will make the rule "ADH:SOME" and the cipher
+             * "ADH-MY-CIPHER" look like a match for buflen=3.
+             * So additionally check whether the cipher name found
+             * has the correct length. We can save a strlen() call:
+             * just checking for the '\0' at the right place is
+             * sufficient, we have to strncmp() anyway. (We cannot
+             * use strcmp(), because buf is not '\0' terminated.)
+             */
+            j = found = 0;
+            cipher_id = 0;
+            while (ca_list[j]) {
+                if (strncmp(buf, ca_list[j]->name, buflen) == 0
+                    && (ca_list[j]->name[buflen] == '\0')) {
+                    found = 1;
+                    break;
+                } else
+                    j++;
+            }
+
+            if (!found)
+                break;          /* ignore this entry */
+
+            if (ca_list[j]->algorithm_mkey) {
+                if (alg_mkey) {
+                    alg_mkey &= ca_list[j]->algorithm_mkey;
+                    if (!alg_mkey) {
+                        found = 0;
+                        break;
+                    }
+                } else {
+                    alg_mkey = ca_list[j]->algorithm_mkey;
+                }
+            }
+
+            if (ca_list[j]->algorithm_auth) {
+                if (alg_auth) {
+                    alg_auth &= ca_list[j]->algorithm_auth;
+                    if (!alg_auth) {
+                        found = 0;
+                        break;
+                    }
+                } else {
+                    alg_auth = ca_list[j]->algorithm_auth;
+                }
+            }
+
+            if (ca_list[j]->algorithm_enc) {
+                if (alg_enc) {
+                    alg_enc &= ca_list[j]->algorithm_enc;
+                    if (!alg_enc) {
+                        found = 0;
+                        break;
+                    }
+                } else {
+                    alg_enc = ca_list[j]->algorithm_enc;
+                }
+            }
+
+            if (ca_list[j]->algorithm_mac) {
+                if (alg_mac) {
+                    alg_mac &= ca_list[j]->algorithm_mac;
+                    if (!alg_mac) {
+                        found = 0;
+                        break;
+                    }
+                } else {
+                    alg_mac = ca_list[j]->algorithm_mac;
+                }
+            }
+
+            if (ca_list[j]->algo_strength & SSL_STRONG_MASK) {
+                if (algo_strength & SSL_STRONG_MASK) {
+                    algo_strength &=
+                        (ca_list[j]->algo_strength & SSL_STRONG_MASK) |
+                        ~SSL_STRONG_MASK;
+                    if (!(algo_strength & SSL_STRONG_MASK)) {
+                        found = 0;
+                        break;
+                    }
+                } else {
+                    algo_strength = ca_list[j]->algo_strength & SSL_STRONG_MASK;
+                }
+            }
+
+            if (ca_list[j]->algo_strength & SSL_DEFAULT_MASK) {
+                if (algo_strength & SSL_DEFAULT_MASK) {
+                    algo_strength &=
+                        (ca_list[j]->algo_strength & SSL_DEFAULT_MASK) |
+                        ~SSL_DEFAULT_MASK;
+                    if (!(algo_strength & SSL_DEFAULT_MASK)) {
+                        found = 0;
+                        break;
+                    }
+                } else {
+                    algo_strength |=
+                        ca_list[j]->algo_strength & SSL_DEFAULT_MASK;
+                }
+            }
+
+            if (ca_list[j]->valid) {
+                /*
+                 * explicit ciphersuite found; its protocol version does not
+                 * become part of the search pattern!
+                 */
+
+                cipher_id = ca_list[j]->id;
+            } else {
+                /*
+                 * not an explicit ciphersuite; only in this case, the
+                 * protocol version is considered part of the search pattern
+                 */
+
+                if (ca_list[j]->min_tls) {
+                    if (min_tls != 0 && min_tls != ca_list[j]->min_tls) {
+                        found = 0;
+                        break;
+                    } else {
+                        min_tls = ca_list[j]->min_tls;
+                    }
+                }
+            }
+
+            if (!multi)
+                break;
+        }
+
+        /*
+         * Ok, we have the rule, now apply it
+         */
+        if (rule == CIPHER_SPECIAL) { /* special command */
+            ok = 0;
+            if ((buflen == 8) && strncmp(buf, "STRENGTH", 8) == 0) {
+                ok = ssl_cipher_strength_sort(head_p, tail_p);
+            } else if (buflen == 10 && strncmp(buf, "SECLEVEL=", 9) == 0) {
+                int level = buf[9] - '0';
+                if (level < 0 || level > 5) {
+                    SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR,
+                           SSL_R_INVALID_COMMAND);
+                } else {
+                    c->sec_level = level;
+                    ok = 1;
+                }
+            } else {
+                SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, SSL_R_INVALID_COMMAND);
+            }
+            if (ok == 0)
+                retval = 0;
+            /*
+             * We do not support any "multi" options
+             * together with "@", so throw away the
+             * rest of the command, if any left, until
+             * end or ':' is found.
+             */
+            while ((*l != '\0') && !ITEM_SEP(*l))
+                l++;
+        } else if (found) {
+            ssl_cipher_apply_rule(cipher_id,
+                                  alg_mkey, alg_auth, alg_enc, alg_mac,
+                                  min_tls, algo_strength, rule, -1, head_p,
+                                  tail_p);
+        } else {
+            while ((*l != '\0') && !ITEM_SEP(*l))
+                l++;
+        }
+        if (*l == '\0')
+            break;              /* done */
+    }
+
+    return retval;
+}
+
+#ifndef OPENSSL_NO_EC
+static int check_suiteb_cipher_list(const SSL_METHOD *meth, CERT *c,
+                                    const char **prule_str)
+{
+    unsigned int suiteb_flags = 0, suiteb_comb2 = 0;
+    if (strncmp(*prule_str, "SUITEB128ONLY", 13) == 0) {
+        suiteb_flags = SSL_CERT_FLAG_SUITEB_128_LOS_ONLY;
+    } else if (strncmp(*prule_str, "SUITEB128C2", 11) == 0) {
+        suiteb_comb2 = 1;
+        suiteb_flags = SSL_CERT_FLAG_SUITEB_128_LOS;
+    } else if (strncmp(*prule_str, "SUITEB128", 9) == 0) {
+        suiteb_flags = SSL_CERT_FLAG_SUITEB_128_LOS;
+    } else if (strncmp(*prule_str, "SUITEB192", 9) == 0) {
+        suiteb_flags = SSL_CERT_FLAG_SUITEB_192_LOS;
+    }
+
+    if (suiteb_flags) {
+        c->cert_flags &= ~SSL_CERT_FLAG_SUITEB_128_LOS;
+        c->cert_flags |= suiteb_flags;
+    } else {
+        suiteb_flags = c->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS;
+    }
+
+    if (!suiteb_flags)
+        return 1;
+    /* Check version: if TLS 1.2 ciphers allowed we can use Suite B */
+
+    if (!(meth->ssl3_enc->enc_flags & SSL_ENC_FLAG_TLS1_2_CIPHERS)) {
+        SSLerr(SSL_F_CHECK_SUITEB_CIPHER_LIST,
+               SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE);
+        return 0;
+    }
+# ifndef OPENSSL_NO_EC
+    switch (suiteb_flags) {
+    case SSL_CERT_FLAG_SUITEB_128_LOS:
+        if (suiteb_comb2)
+            *prule_str = "ECDHE-ECDSA-AES256-GCM-SHA384";
+        else
+            *prule_str =
+                "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384";
+        break;
+    case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
+        *prule_str = "ECDHE-ECDSA-AES128-GCM-SHA256";
+        break;
+    case SSL_CERT_FLAG_SUITEB_192_LOS:
+        *prule_str = "ECDHE-ECDSA-AES256-GCM-SHA384";
+        break;
+    }
+    return 1;
+# else
+    SSLerr(SSL_F_CHECK_SUITEB_CIPHER_LIST, SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE);
+    return 0;
+# endif
+}
+#endif
+
+static int ciphersuite_cb(const char *elem, int len, void *arg)
+{
+    STACK_OF(SSL_CIPHER) *ciphersuites = (STACK_OF(SSL_CIPHER) *)arg;
+    const SSL_CIPHER *cipher;
+    /* Arbitrary sized temp buffer for the cipher name. Should be big enough */
+    char name[80];
+
+    if (len > (int)(sizeof(name) - 1)) {
+        SSLerr(SSL_F_CIPHERSUITE_CB, SSL_R_NO_CIPHER_MATCH);
+        return 0;
+    }
+
+    memcpy(name, elem, len);
+    name[len] = '\0';
+
+    cipher = ssl3_get_cipher_by_std_name(name);
+    if (cipher == NULL) {
+        SSLerr(SSL_F_CIPHERSUITE_CB, SSL_R_NO_CIPHER_MATCH);
+        return 0;
+    }
+
+    if (!sk_SSL_CIPHER_push(ciphersuites, cipher)) {
+        SSLerr(SSL_F_CIPHERSUITE_CB, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+static __owur int set_ciphersuites(STACK_OF(SSL_CIPHER) **currciphers, const char *str)
+{
+    STACK_OF(SSL_CIPHER) *newciphers = sk_SSL_CIPHER_new_null();
+
+    if (newciphers == NULL)
+        return 0;
+
+    /* Parse the list. We explicitly allow an empty list */
+    if (*str != '\0'
+            && !CONF_parse_list(str, ':', 1, ciphersuite_cb, newciphers)) {
+        sk_SSL_CIPHER_free(newciphers);
+        return 0;
+    }
+    sk_SSL_CIPHER_free(*currciphers);
+    *currciphers = newciphers;
+
+    return 1;
+}
+
+static int update_cipher_list_by_id(STACK_OF(SSL_CIPHER) **cipher_list_by_id,
+                                    STACK_OF(SSL_CIPHER) *cipherstack)
+{
+    STACK_OF(SSL_CIPHER) *tmp_cipher_list = sk_SSL_CIPHER_dup(cipherstack);
+
+    if (tmp_cipher_list == NULL) {
+        return 0;
+    }
+
+    sk_SSL_CIPHER_free(*cipher_list_by_id);
+    *cipher_list_by_id = tmp_cipher_list;
+
+    (void)sk_SSL_CIPHER_set_cmp_func(*cipher_list_by_id, ssl_cipher_ptr_id_cmp);
+    sk_SSL_CIPHER_sort(*cipher_list_by_id);
+
+    return 1;
+}
+
+static int update_cipher_list(STACK_OF(SSL_CIPHER) **cipher_list,
+                              STACK_OF(SSL_CIPHER) **cipher_list_by_id,
+                              STACK_OF(SSL_CIPHER) *tls13_ciphersuites)
+{
+    int i;
+    STACK_OF(SSL_CIPHER) *tmp_cipher_list = sk_SSL_CIPHER_dup(*cipher_list);
+
+    if (tmp_cipher_list == NULL)
+        return 0;
+
+    /*
+     * Delete any existing TLSv1.3 ciphersuites. These are always first in the
+     * list.
+     */
+    while (sk_SSL_CIPHER_num(tmp_cipher_list) > 0
+           && sk_SSL_CIPHER_value(tmp_cipher_list, 0)->min_tls
+              == TLS1_3_VERSION)
+        sk_SSL_CIPHER_delete(tmp_cipher_list, 0);
+
+    /* Insert the new TLSv1.3 ciphersuites */
+    for (i = 0; i < sk_SSL_CIPHER_num(tls13_ciphersuites); i++)
+        sk_SSL_CIPHER_insert(tmp_cipher_list,
+                             sk_SSL_CIPHER_value(tls13_ciphersuites, i), i);
+
+    if (!update_cipher_list_by_id(cipher_list_by_id, tmp_cipher_list))
+        return 0;
+
+    sk_SSL_CIPHER_free(*cipher_list);
+    *cipher_list = tmp_cipher_list;
+
+    return 1;
+}
+
+int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str)
+{
+    int ret = set_ciphersuites(&(ctx->tls13_ciphersuites), str);
+
+    if (ret && ctx->cipher_list != NULL)
+        return update_cipher_list(&ctx->cipher_list, &ctx->cipher_list_by_id,
+                                  ctx->tls13_ciphersuites);
+
+    return ret;
+}
+
+int SSL_set_ciphersuites(SSL *s, const char *str)
+{
+    STACK_OF(SSL_CIPHER) *cipher_list;
+    int ret = set_ciphersuites(&(s->tls13_ciphersuites), str);
+
+    if (s->cipher_list == NULL) {
+        if ((cipher_list = SSL_get_ciphers(s)) != NULL)
+            s->cipher_list = sk_SSL_CIPHER_dup(cipher_list);
+    }
+    if (ret && s->cipher_list != NULL)
+        return update_cipher_list(&s->cipher_list, &s->cipher_list_by_id,
+                                  s->tls13_ciphersuites);
+
+    return ret;
+}
+
+STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
+                                             STACK_OF(SSL_CIPHER) *tls13_ciphersuites,
+                                             STACK_OF(SSL_CIPHER) **cipher_list,
+                                             STACK_OF(SSL_CIPHER) **cipher_list_by_id,
+                                             const char *rule_str,
+                                             CERT *c)
+{
+    int ok, num_of_ciphers, num_of_alias_max, num_of_group_aliases, i;
+    uint32_t disabled_mkey, disabled_auth, disabled_enc, disabled_mac;
+    STACK_OF(SSL_CIPHER) *cipherstack;
+    const char *rule_p;
+    CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr;
+    const SSL_CIPHER **ca_list = NULL;
+
+    /*
+     * Return with error if nothing to do.
+     */
+    if (rule_str == NULL || cipher_list == NULL || cipher_list_by_id == NULL)
+        return NULL;
+#ifndef OPENSSL_NO_EC
+    if (!check_suiteb_cipher_list(ssl_method, c, &rule_str))
+        return NULL;
+#endif
+
+    /*
+     * To reduce the work to do we only want to process the compiled
+     * in algorithms, so we first get the mask of disabled ciphers.
+     */
+
+    disabled_mkey = disabled_mkey_mask;
+    disabled_auth = disabled_auth_mask;
+    disabled_enc = disabled_enc_mask;
+    disabled_mac = disabled_mac_mask;
+
+    /*
+     * Now we have to collect the available ciphers from the compiled
+     * in ciphers. We cannot get more than the number compiled in, so
+     * it is used for allocation.
+     */
+    num_of_ciphers = ssl_method->num_ciphers();
+
+    co_list = OPENSSL_malloc(sizeof(*co_list) * num_of_ciphers);
+    if (co_list == NULL) {
+        SSLerr(SSL_F_SSL_CREATE_CIPHER_LIST, ERR_R_MALLOC_FAILURE);
+        return NULL;          /* Failure */
+    }
+
+    ssl_cipher_collect_ciphers(ssl_method, num_of_ciphers,
+                               disabled_mkey, disabled_auth, disabled_enc,
+                               disabled_mac, co_list, &head, &tail);
+
+    /* Now arrange all ciphers by preference. */
+
+    /*
+     * Everything else being equal, prefer ephemeral ECDH over other key
+     * exchange mechanisms.
+     * For consistency, prefer ECDSA over RSA (though this only matters if the
+     * server has both certificates, and is using the DEFAULT, or a client
+     * preference).
+     */
+    ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, 0, 0, 0, 0, CIPHER_ADD,
+                          -1, &head, &tail);
+    ssl_cipher_apply_rule(0, SSL_kECDHE, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head,
+                          &tail);
+    ssl_cipher_apply_rule(0, SSL_kECDHE, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head,
+                          &tail);
+
+    /* Within each strength group, we prefer GCM over CHACHA... */
+    ssl_cipher_apply_rule(0, 0, 0, SSL_AESGCM, 0, 0, 0, CIPHER_ADD, -1,
+                          &head, &tail);
+    ssl_cipher_apply_rule(0, 0, 0, SSL_CHACHA20, 0, 0, 0, CIPHER_ADD, -1,
+                          &head, &tail);
+
+    /*
+     * ...and generally, our preferred cipher is AES.
+     * Note that AEADs will be bumped to take preference after sorting by
+     * strength.
+     */
+    ssl_cipher_apply_rule(0, 0, 0, SSL_AES ^ SSL_AESGCM, 0, 0, 0, CIPHER_ADD,
+                          -1, &head, &tail);
+
+    /* Temporarily enable everything else for sorting */
+    ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head, &tail);
+
+    /* Low priority for MD5 */
+    ssl_cipher_apply_rule(0, 0, 0, 0, SSL_MD5, 0, 0, CIPHER_ORD, -1, &head,
+                          &tail);
+
+    /*
+     * Move anonymous ciphers to the end.  Usually, these will remain
+     * disabled. (For applications that allow them, they aren't too bad, but
+     * we prefer authenticated ciphers.)
+     */
+    ssl_cipher_apply_rule(0, 0, SSL_aNULL, 0, 0, 0, 0, CIPHER_ORD, -1, &head,
+                          &tail);
+
+    ssl_cipher_apply_rule(0, SSL_kRSA, 0, 0, 0, 0, 0, CIPHER_ORD, -1, &head,
+                          &tail);
+    ssl_cipher_apply_rule(0, SSL_kPSK, 0, 0, 0, 0, 0, CIPHER_ORD, -1, &head,
+                          &tail);
+
+    /* RC4 is sort-of broken -- move to the end */
+    ssl_cipher_apply_rule(0, 0, 0, SSL_RC4, 0, 0, 0, CIPHER_ORD, -1, &head,
+                          &tail);
+
+    /*
+     * Now sort by symmetric encryption strength.  The above ordering remains
+     * in force within each class
+     */
+    if (!ssl_cipher_strength_sort(&head, &tail)) {
+        OPENSSL_free(co_list);
+        return NULL;
+    }
+
+    /*
+     * Partially overrule strength sort to prefer TLS 1.2 ciphers/PRFs.
+     * TODO(openssl-team): is there an easier way to accomplish all this?
+     */
+    ssl_cipher_apply_rule(0, 0, 0, 0, 0, TLS1_2_VERSION, 0, CIPHER_BUMP, -1,
+                          &head, &tail);
+
+    /*
+     * Irrespective of strength, enforce the following order:
+     * (EC)DHE + AEAD > (EC)DHE > rest of AEAD > rest.
+     * Within each group, ciphers remain sorted by strength and previous
+     * preference, i.e.,
+     * 1) ECDHE > DHE
+     * 2) GCM > CHACHA
+     * 3) AES > rest
+     * 4) TLS 1.2 > legacy
+     *
+     * Because we now bump ciphers to the top of the list, we proceed in
+     * reverse order of preference.
+     */
+    ssl_cipher_apply_rule(0, 0, 0, 0, SSL_AEAD, 0, 0, CIPHER_BUMP, -1,
+                          &head, &tail);
+    ssl_cipher_apply_rule(0, SSL_kDHE | SSL_kECDHE, 0, 0, 0, 0, 0,
+                          CIPHER_BUMP, -1, &head, &tail);
+    ssl_cipher_apply_rule(0, SSL_kDHE | SSL_kECDHE, 0, 0, SSL_AEAD, 0, 0,
+                          CIPHER_BUMP, -1, &head, &tail);
+
+    /* Now disable everything (maintaining the ordering!) */
+    ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head, &tail);
+
+    /*
+     * We also need cipher aliases for selecting based on the rule_str.
+     * There might be two types of entries in the rule_str: 1) names
+     * of ciphers themselves 2) aliases for groups of ciphers.
+     * For 1) we need the available ciphers and for 2) the cipher
+     * groups of cipher_aliases added together in one list (otherwise
+     * we would be happy with just the cipher_aliases table).
+     */
+    num_of_group_aliases = OSSL_NELEM(cipher_aliases);
+    num_of_alias_max = num_of_ciphers + num_of_group_aliases + 1;
+    ca_list = OPENSSL_malloc(sizeof(*ca_list) * num_of_alias_max);
+    if (ca_list == NULL) {
+        OPENSSL_free(co_list);
+        SSLerr(SSL_F_SSL_CREATE_CIPHER_LIST, ERR_R_MALLOC_FAILURE);
+        return NULL;          /* Failure */
+    }
+    ssl_cipher_collect_aliases(ca_list, num_of_group_aliases,
+                               disabled_mkey, disabled_auth, disabled_enc,
+                               disabled_mac, head);
+
+    /*
+     * If the rule_string begins with DEFAULT, apply the default rule
+     * before using the (possibly available) additional rules.
+     */
+    ok = 1;
+    rule_p = rule_str;
+    if (strncmp(rule_str, "DEFAULT", 7) == 0) {
+        ok = ssl_cipher_process_rulestr(SSL_DEFAULT_CIPHER_LIST,
+                                        &head, &tail, ca_list, c);
+        rule_p += 7;
+        if (*rule_p == ':')
+            rule_p++;
+    }
+
+    if (ok && (strlen(rule_p) > 0))
+        ok = ssl_cipher_process_rulestr(rule_p, &head, &tail, ca_list, c);
+
+    OPENSSL_free(ca_list);      /* Not needed anymore */
+
+    if (!ok) {                  /* Rule processing failure */
+        OPENSSL_free(co_list);
+        return NULL;
+    }
+
+    /*
+     * Allocate new "cipherstack" for the result, return with error
+     * if we cannot get one.
+     */
+    if ((cipherstack = sk_SSL_CIPHER_new_null()) == NULL) {
+        OPENSSL_free(co_list);
+        return NULL;
+    }
+
+    /* Add TLSv1.3 ciphers first - we always prefer those if possible */
+    for (i = 0; i < sk_SSL_CIPHER_num(tls13_ciphersuites); i++) {
+        if (!sk_SSL_CIPHER_push(cipherstack,
+                                sk_SSL_CIPHER_value(tls13_ciphersuites, i))) {
+            OPENSSL_free(co_list);
+            sk_SSL_CIPHER_free(cipherstack);
+            return NULL;
+        }
+    }
+
+    /*
+     * The cipher selection for the list is done. The ciphers are added
+     * to the resulting precedence to the STACK_OF(SSL_CIPHER).
+     */
+    for (curr = head; curr != NULL; curr = curr->next) {
+        if (curr->active) {
+            if (!sk_SSL_CIPHER_push(cipherstack, curr->cipher)) {
+                OPENSSL_free(co_list);
+                sk_SSL_CIPHER_free(cipherstack);
+                return NULL;
+            }
+#ifdef CIPHER_DEBUG
+            fprintf(stderr, "<%s>\n", curr->cipher->name);
+#endif
+        }
+    }
+    OPENSSL_free(co_list);      /* Not needed any longer */
+
+    if (!update_cipher_list_by_id(cipher_list_by_id, cipherstack)) {
+        sk_SSL_CIPHER_free(cipherstack);
+        return NULL;
+    }
+    sk_SSL_CIPHER_free(*cipher_list);
+    *cipher_list = cipherstack;
+
+    return cipherstack;
+}
+
+char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
+{
+    const char *ver;
+    const char *kx, *au, *enc, *mac;
+    uint32_t alg_mkey, alg_auth, alg_enc, alg_mac;
+    static const char *format = "%-23s %s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s\n";
+
+    if (buf == NULL) {
+        len = 128;
+        if ((buf = OPENSSL_malloc(len)) == NULL) {
+            SSLerr(SSL_F_SSL_CIPHER_DESCRIPTION, ERR_R_MALLOC_FAILURE);
+            return NULL;
+        }
+    } else if (len < 128) {
+        return NULL;
+    }
+
+    alg_mkey = cipher->algorithm_mkey;
+    alg_auth = cipher->algorithm_auth;
+    alg_enc = cipher->algorithm_enc;
+    alg_mac = cipher->algorithm_mac;
+
+    ver = ssl_protocol_to_string(cipher->min_tls);
+
+    switch (alg_mkey) {
+    case SSL_kRSA:
+        kx = "RSA";
+        break;
+    case SSL_kDHE:
+        kx = "DH";
+        break;
+    case SSL_kECDHE:
+        kx = "ECDH";
+        break;
+    case SSL_kPSK:
+        kx = "PSK";
+        break;
+    case SSL_kRSAPSK:
+        kx = "RSAPSK";
+        break;
+    case SSL_kECDHEPSK:
+        kx = "ECDHEPSK";
+        break;
+    case SSL_kDHEPSK:
+        kx = "DHEPSK";
+        break;
+    case SSL_kSRP:
+        kx = "SRP";
+        break;
+    case SSL_kGOST:
+        kx = "GOST";
+        break;
+    case SSL_kANY:
+        kx = "any";
+        break;
+    default:
+        kx = "unknown";
+    }
+
+    switch (alg_auth) {
+    case SSL_aRSA:
+        au = "RSA";
+        break;
+    case SSL_aDSS:
+        au = "DSS";
+        break;
+    case SSL_aNULL:
+        au = "None";
+        break;
+    case SSL_aECDSA:
+        au = "ECDSA";
+        break;
+    case SSL_aPSK:
+        au = "PSK";
+        break;
+    case SSL_aSRP:
+        au = "SRP";
+        break;
+    case SSL_aGOST01:
+        au = "GOST01";
+        break;
+    /* New GOST ciphersuites have both SSL_aGOST12 and SSL_aGOST01 bits */
+    case (SSL_aGOST12 | SSL_aGOST01):
+        au = "GOST12";
+        break;
+    case SSL_aANY:
+        au = "any";
+        break;
+    default:
+        au = "unknown";
+        break;
+    }
+
+    switch (alg_enc) {
+    case SSL_DES:
+        enc = "DES(56)";
+        break;
+    case SSL_3DES:
+        enc = "3DES(168)";
+        break;
+    case SSL_RC4:
+        enc = "RC4(128)";
+        break;
+    case SSL_RC2:
+        enc = "RC2(128)";
+        break;
+    case SSL_IDEA:
+        enc = "IDEA(128)";
+        break;
+    case SSL_eNULL:
+        enc = "None";
+        break;
+    case SSL_AES128:
+        enc = "AES(128)";
+        break;
+    case SSL_AES256:
+        enc = "AES(256)";
+        break;
+    case SSL_AES128GCM:
+        enc = "AESGCM(128)";
+        break;
+    case SSL_AES256GCM:
+        enc = "AESGCM(256)";
+        break;
+    case SSL_AES128CCM:
+        enc = "AESCCM(128)";
+        break;
+    case SSL_AES256CCM:
+        enc = "AESCCM(256)";
+        break;
+    case SSL_AES128CCM8:
+        enc = "AESCCM8(128)";
+        break;
+    case SSL_AES256CCM8:
+        enc = "AESCCM8(256)";
+        break;
+    case SSL_CAMELLIA128:
+        enc = "Camellia(128)";
+        break;
+    case SSL_CAMELLIA256:
+        enc = "Camellia(256)";
+        break;
+    case SSL_ARIA128GCM:
+        enc = "ARIAGCM(128)";
+        break;
+    case SSL_ARIA256GCM:
+        enc = "ARIAGCM(256)";
+        break;
+    case SSL_SEED:
+        enc = "SEED(128)";
+        break;
+    case SSL_eGOST2814789CNT:
+    case SSL_eGOST2814789CNT12:
+        enc = "GOST89(256)";
+        break;
+    case SSL_CHACHA20POLY1305:
+        enc = "CHACHA20/POLY1305(256)";
+        break;
+    default:
+        enc = "unknown";
+        break;
+    }
+
+    switch (alg_mac) {
+    case SSL_MD5:
+        mac = "MD5";
+        break;
+    case SSL_SHA1:
+        mac = "SHA1";
+        break;
+    case SSL_SHA256:
+        mac = "SHA256";
+        break;
+    case SSL_SHA384:
+        mac = "SHA384";
+        break;
+    case SSL_AEAD:
+        mac = "AEAD";
+        break;
+    case SSL_GOST89MAC:
+    case SSL_GOST89MAC12:
+        mac = "GOST89";
+        break;
+    case SSL_GOST94:
+        mac = "GOST94";
+        break;
+    case SSL_GOST12_256:
+    case SSL_GOST12_512:
+        mac = "GOST2012";
+        break;
+    default:
+        mac = "unknown";
+        break;
+    }
+
+    BIO_snprintf(buf, len, format, cipher->name, ver, kx, au, enc, mac);
+
+    return buf;
+}
+
+const char *SSL_CIPHER_get_version(const SSL_CIPHER *c)
+{
+    if (c == NULL)
+        return "(NONE)";
+
+    /*
+     * Backwards-compatibility crutch.  In almost all contexts we report TLS
+     * 1.0 as "TLSv1", but for ciphers we report "TLSv1.0".
+     */
+    if (c->min_tls == TLS1_VERSION)
+        return "TLSv1.0";
+    return ssl_protocol_to_string(c->min_tls);
+}
+
+/* return the actual cipher being used */
+const char *SSL_CIPHER_get_name(const SSL_CIPHER *c)
+{
+    if (c != NULL)
+        return c->name;
+    return "(NONE)";
+}
+
+/* return the actual cipher being used in RFC standard name */
+const char *SSL_CIPHER_standard_name(const SSL_CIPHER *c)
+{
+    if (c != NULL)
+        return c->stdname;
+    return "(NONE)";
+}
+
+/* return the OpenSSL name based on given RFC standard name */
+const char *OPENSSL_cipher_name(const char *stdname)
+{
+    const SSL_CIPHER *c;
+
+    if (stdname == NULL)
+        return "(NONE)";
+    c = ssl3_get_cipher_by_std_name(stdname);
+    return SSL_CIPHER_get_name(c);
+}
+
+/* number of bits for symmetric cipher */
+int SSL_CIPHER_get_bits(const SSL_CIPHER *c, int *alg_bits)
+{
+    int ret = 0;
+
+    if (c != NULL) {
+        if (alg_bits != NULL)
+            *alg_bits = (int)c->alg_bits;
+        ret = (int)c->strength_bits;
+    }
+    return ret;
+}
+
+uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *c)
+{
+    return c->id;
+}
+
+uint16_t SSL_CIPHER_get_protocol_id(const SSL_CIPHER *c)
+{
+    return c->id & 0xFFFF;
+}
+
+SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n)
+{
+    SSL_COMP *ctmp;
+    int i, nn;
+
+    if ((n == 0) || (sk == NULL))
+        return NULL;
+    nn = sk_SSL_COMP_num(sk);
+    for (i = 0; i < nn; i++) {
+        ctmp = sk_SSL_COMP_value(sk, i);
+        if (ctmp->id == n)
+            return ctmp;
+    }
+    return NULL;
+}
+
+#ifdef OPENSSL_NO_COMP
+STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void)
+{
+    return NULL;
+}
+
+STACK_OF(SSL_COMP) *SSL_COMP_set0_compression_methods(STACK_OF(SSL_COMP)
+                                                      *meths)
+{
+    return meths;
+}
+
+int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm)
+{
+    return 1;
+}
+
+#else
+STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void)
+{
+    load_builtin_compressions();
+    return ssl_comp_methods;
+}
+
+STACK_OF(SSL_COMP) *SSL_COMP_set0_compression_methods(STACK_OF(SSL_COMP)
+                                                      *meths)
+{
+    STACK_OF(SSL_COMP) *old_meths = ssl_comp_methods;
+    ssl_comp_methods = meths;
+    return old_meths;
+}
+
+static void cmeth_free(SSL_COMP *cm)
+{
+    OPENSSL_free(cm);
+}
+
+void ssl_comp_free_compression_methods_int(void)
+{
+    STACK_OF(SSL_COMP) *old_meths = ssl_comp_methods;
+    ssl_comp_methods = NULL;
+    sk_SSL_COMP_pop_free(old_meths, cmeth_free);
+}
+
+int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm)
+{
+    SSL_COMP *comp;
+
+    if (cm == NULL || COMP_get_type(cm) == NID_undef)
+        return 1;
+
+    /*-
+     * According to draft-ietf-tls-compression-04.txt, the
+     * compression number ranges should be the following:
+     *
+     *   0 to  63:  methods defined by the IETF
+     *  64 to 192:  external party methods assigned by IANA
+     * 193 to 255:  reserved for private use
+     */
+    if (id < 193 || id > 255) {
+        SSLerr(SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD,
+               SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE);
+        return 1;
+    }
+
+    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
+    comp = OPENSSL_malloc(sizeof(*comp));
+    if (comp == NULL) {
+        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
+        SSLerr(SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD, ERR_R_MALLOC_FAILURE);
+        return 1;
+    }
+
+    comp->id = id;
+    comp->method = cm;
+    load_builtin_compressions();
+    if (ssl_comp_methods && sk_SSL_COMP_find(ssl_comp_methods, comp) >= 0) {
+        OPENSSL_free(comp);
+        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
+        SSLerr(SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD,
+               SSL_R_DUPLICATE_COMPRESSION_ID);
+        return 1;
+    }
+    if (ssl_comp_methods == NULL || !sk_SSL_COMP_push(ssl_comp_methods, comp)) {
+        OPENSSL_free(comp);
+        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
+        SSLerr(SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD, ERR_R_MALLOC_FAILURE);
+        return 1;
+    }
+    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
+    return 0;
+}
+#endif
+
+const char *SSL_COMP_get_name(const COMP_METHOD *comp)
+{
+#ifndef OPENSSL_NO_COMP
+    return comp ? COMP_get_name(comp) : NULL;
+#else
+    return NULL;
+#endif
+}
+
+const char *SSL_COMP_get0_name(const SSL_COMP *comp)
+{
+#ifndef OPENSSL_NO_COMP
+    return comp->name;
+#else
+    return NULL;
+#endif
+}
+
+int SSL_COMP_get_id(const SSL_COMP *comp)
+{
+#ifndef OPENSSL_NO_COMP
+    return comp->id;
+#else
+    return -1;
+#endif
+}
+
+const SSL_CIPHER *ssl_get_cipher_by_char(SSL *ssl, const unsigned char *ptr,
+                                         int all)
+{
+    const SSL_CIPHER *c = ssl->method->get_cipher_by_char(ptr);
+
+    if (c == NULL || (!all && c->valid == 0))
+        return NULL;
+    return c;
+}
+
+const SSL_CIPHER *SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr)
+{
+    return ssl->method->get_cipher_by_char(ptr);
+}
+
+int SSL_CIPHER_get_cipher_nid(const SSL_CIPHER *c)
+{
+    int i;
+    if (c == NULL)
+        return NID_undef;
+    i = ssl_cipher_info_lookup(ssl_cipher_table_cipher, c->algorithm_enc);
+    if (i == -1)
+        return NID_undef;
+    return ssl_cipher_table_cipher[i].nid;
+}
+
+int SSL_CIPHER_get_digest_nid(const SSL_CIPHER *c)
+{
+    int i = ssl_cipher_info_lookup(ssl_cipher_table_mac, c->algorithm_mac);
+
+    if (i == -1)
+        return NID_undef;
+    return ssl_cipher_table_mac[i].nid;
+}
+
+int SSL_CIPHER_get_kx_nid(const SSL_CIPHER *c)
+{
+    int i = ssl_cipher_info_lookup(ssl_cipher_table_kx, c->algorithm_mkey);
+
+    if (i == -1)
+        return NID_undef;
+    return ssl_cipher_table_kx[i].nid;
+}
+
+int SSL_CIPHER_get_auth_nid(const SSL_CIPHER *c)
+{
+    int i = ssl_cipher_info_lookup(ssl_cipher_table_auth, c->algorithm_auth);
+
+    if (i == -1)
+        return NID_undef;
+    return ssl_cipher_table_auth[i].nid;
+}
+
+const EVP_MD *SSL_CIPHER_get_handshake_digest(const SSL_CIPHER *c)
+{
+    int idx = c->algorithm2 & SSL_HANDSHAKE_MAC_MASK;
+
+    if (idx < 0 || idx >= SSL_MD_NUM_IDX)
+        return NULL;
+    return ssl_digest_methods[idx];
+}
+
+int SSL_CIPHER_is_aead(const SSL_CIPHER *c)
+{
+    return (c->algorithm_mac & SSL_AEAD) ? 1 : 0;
+}
+
+int ssl_cipher_get_overhead(const SSL_CIPHER *c, size_t *mac_overhead,
+                            size_t *int_overhead, size_t *blocksize,
+                            size_t *ext_overhead)
+{
+    size_t mac = 0, in = 0, blk = 0, out = 0;
+
+    /* Some hard-coded numbers for the CCM/Poly1305 MAC overhead
+     * because there are no handy #defines for those. */
+    if (c->algorithm_enc & (SSL_AESGCM | SSL_ARIAGCM)) {
+        out = EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
+    } else if (c->algorithm_enc & (SSL_AES128CCM | SSL_AES256CCM)) {
+        out = EVP_CCM_TLS_EXPLICIT_IV_LEN + 16;
+    } else if (c->algorithm_enc & (SSL_AES128CCM8 | SSL_AES256CCM8)) {
+        out = EVP_CCM_TLS_EXPLICIT_IV_LEN + 8;
+    } else if (c->algorithm_enc & SSL_CHACHA20POLY1305) {
+        out = 16;
+    } else if (c->algorithm_mac & SSL_AEAD) {
+        /* We're supposed to have handled all the AEAD modes above */
+        return 0;
+    } else {
+        /* Non-AEAD modes. Calculate MAC/cipher overhead separately */
+        int digest_nid = SSL_CIPHER_get_digest_nid(c);
+        const EVP_MD *e_md = EVP_get_digestbynid(digest_nid);
+
+        if (e_md == NULL)
+            return 0;
+
+        mac = EVP_MD_size(e_md);
+        if (c->algorithm_enc != SSL_eNULL) {
+            int cipher_nid = SSL_CIPHER_get_cipher_nid(c);
+            const EVP_CIPHER *e_ciph = EVP_get_cipherbynid(cipher_nid);
+
+            /* If it wasn't AEAD or SSL_eNULL, we expect it to be a
+               known CBC cipher. */
+            if (e_ciph == NULL ||
+                EVP_CIPHER_mode(e_ciph) != EVP_CIPH_CBC_MODE)
+                return 0;
+
+            in = 1; /* padding length byte */
+            out = EVP_CIPHER_iv_length(e_ciph);
+            blk = EVP_CIPHER_block_size(e_ciph);
+        }
+    }
+
+    *mac_overhead = mac;
+    *int_overhead = in;
+    *blocksize = blk;
+    *ext_overhead = out;
+
+    return 1;
+}
+
+int ssl_cert_is_disabled(size_t idx)
+{
+    const SSL_CERT_LOOKUP *cl = ssl_cert_lookup_by_idx(idx);
+
+    if (cl == NULL || (cl->amask & disabled_auth_mask) != 0)
+        return 1;
+    return 0;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_conf.c b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_conf.c
new file mode 100644
index 0000000..0a3fef7
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_conf.c
@@ -0,0 +1,1000 @@
+/*
+ * Copyright 2012-2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include "ssl_local.h"
+#include <openssl/conf.h>
+#include <openssl/objects.h>
+#include <openssl/dh.h>
+#include "internal/nelem.h"
+
+/*
+ * structure holding name tables. This is used for permitted elements in lists
+ * such as TLSv1.
+ */
+
+typedef struct {
+    const char *name;
+    int namelen;
+    unsigned int name_flags;
+    unsigned long option_value;
+} ssl_flag_tbl;
+
+/* Switch table: use for single command line switches like no_tls2 */
+typedef struct {
+    unsigned long option_value;
+    unsigned int name_flags;
+} ssl_switch_tbl;
+
+/* Sense of name is inverted e.g. "TLSv1" will clear SSL_OP_NO_TLSv1 */
+#define SSL_TFLAG_INV   0x1
+/* Mask for type of flag referred to */
+#define SSL_TFLAG_TYPE_MASK 0xf00
+/* Flag is for options */
+#define SSL_TFLAG_OPTION    0x000
+/* Flag is for cert_flags */
+#define SSL_TFLAG_CERT      0x100
+/* Flag is for verify mode */
+#define SSL_TFLAG_VFY       0x200
+/* Option can only be used for clients */
+#define SSL_TFLAG_CLIENT SSL_CONF_FLAG_CLIENT
+/* Option can only be used for servers */
+#define SSL_TFLAG_SERVER SSL_CONF_FLAG_SERVER
+#define SSL_TFLAG_BOTH (SSL_TFLAG_CLIENT|SSL_TFLAG_SERVER)
+
+#define SSL_FLAG_TBL(str, flag) \
+        {str, (int)(sizeof(str) - 1), SSL_TFLAG_BOTH, flag}
+#define SSL_FLAG_TBL_SRV(str, flag) \
+        {str, (int)(sizeof(str) - 1), SSL_TFLAG_SERVER, flag}
+#define SSL_FLAG_TBL_CLI(str, flag) \
+        {str, (int)(sizeof(str) - 1), SSL_TFLAG_CLIENT, flag}
+#define SSL_FLAG_TBL_INV(str, flag) \
+        {str, (int)(sizeof(str) - 1), SSL_TFLAG_INV|SSL_TFLAG_BOTH, flag}
+#define SSL_FLAG_TBL_SRV_INV(str, flag) \
+        {str, (int)(sizeof(str) - 1), SSL_TFLAG_INV|SSL_TFLAG_SERVER, flag}
+#define SSL_FLAG_TBL_CERT(str, flag) \
+        {str, (int)(sizeof(str) - 1), SSL_TFLAG_CERT|SSL_TFLAG_BOTH, flag}
+
+#define SSL_FLAG_VFY_CLI(str, flag) \
+        {str, (int)(sizeof(str) - 1), SSL_TFLAG_VFY | SSL_TFLAG_CLIENT, flag}
+#define SSL_FLAG_VFY_SRV(str, flag) \
+        {str, (int)(sizeof(str) - 1), SSL_TFLAG_VFY | SSL_TFLAG_SERVER, flag}
+
+/*
+ * Opaque structure containing SSL configuration context.
+ */
+
+struct ssl_conf_ctx_st {
+    /*
+     * Various flags indicating (among other things) which options we will
+     * recognise.
+     */
+    unsigned int flags;
+    /* Prefix and length of commands */
+    char *prefix;
+    size_t prefixlen;
+    /* SSL_CTX or SSL structure to perform operations on */
+    SSL_CTX *ctx;
+    SSL *ssl;
+    /* Pointer to SSL or SSL_CTX options field or NULL if none */
+    uint32_t *poptions;
+    /* Certificate filenames for each type */
+    char *cert_filename[SSL_PKEY_NUM];
+    /* Pointer to SSL or SSL_CTX cert_flags or NULL if none */
+    uint32_t *pcert_flags;
+    /* Pointer to SSL or SSL_CTX verify_mode or NULL if none */
+    uint32_t *pvfy_flags;
+    /* Pointer to SSL or SSL_CTX min_version field or NULL if none */
+    int *min_version;
+    /* Pointer to SSL or SSL_CTX max_version field or NULL if none */
+    int *max_version;
+    /* Current flag table being worked on */
+    const ssl_flag_tbl *tbl;
+    /* Size of table */
+    size_t ntbl;
+    /* Client CA names */
+    STACK_OF(X509_NAME) *canames;
+};
+
+static void ssl_set_option(SSL_CONF_CTX *cctx, unsigned int name_flags,
+                           unsigned long option_value, int onoff)
+{
+    uint32_t *pflags;
+    if (cctx->poptions == NULL)
+        return;
+    if (name_flags & SSL_TFLAG_INV)
+        onoff ^= 1;
+    switch (name_flags & SSL_TFLAG_TYPE_MASK) {
+
+    case SSL_TFLAG_CERT:
+        pflags = cctx->pcert_flags;
+        break;
+
+    case SSL_TFLAG_VFY:
+        pflags = cctx->pvfy_flags;
+        break;
+
+    case SSL_TFLAG_OPTION:
+        pflags = cctx->poptions;
+        break;
+
+    default:
+        return;
+
+    }
+    if (onoff)
+        *pflags |= option_value;
+    else
+        *pflags &= ~option_value;
+}
+
+static int ssl_match_option(SSL_CONF_CTX *cctx, const ssl_flag_tbl *tbl,
+                            const char *name, int namelen, int onoff)
+{
+    /* If name not relevant for context skip */
+    if (!(cctx->flags & tbl->name_flags & SSL_TFLAG_BOTH))
+        return 0;
+    if (namelen == -1) {
+        if (strcmp(tbl->name, name))
+            return 0;
+    } else if (tbl->namelen != namelen || strncasecmp(tbl->name, name, namelen))
+        return 0;
+    ssl_set_option(cctx, tbl->name_flags, tbl->option_value, onoff);
+    return 1;
+}
+
+static int ssl_set_option_list(const char *elem, int len, void *usr)
+{
+    SSL_CONF_CTX *cctx = usr;
+    size_t i;
+    const ssl_flag_tbl *tbl;
+    int onoff = 1;
+    /*
+     * len == -1 indicates not being called in list context, just for single
+     * command line switches, so don't allow +, -.
+     */
+    if (elem == NULL)
+        return 0;
+    if (len != -1) {
+        if (*elem == '+') {
+            elem++;
+            len--;
+            onoff = 1;
+        } else if (*elem == '-') {
+            elem++;
+            len--;
+            onoff = 0;
+        }
+    }
+    for (i = 0, tbl = cctx->tbl; i < cctx->ntbl; i++, tbl++) {
+        if (ssl_match_option(cctx, tbl, elem, len, onoff))
+            return 1;
+    }
+    return 0;
+}
+
+/* Set supported signature algorithms */
+static int cmd_SignatureAlgorithms(SSL_CONF_CTX *cctx, const char *value)
+{
+    int rv;
+    if (cctx->ssl)
+        rv = SSL_set1_sigalgs_list(cctx->ssl, value);
+    /* NB: ctx == NULL performs syntax checking only */
+    else
+        rv = SSL_CTX_set1_sigalgs_list(cctx->ctx, value);
+    return rv > 0;
+}
+
+/* Set supported client signature algorithms */
+static int cmd_ClientSignatureAlgorithms(SSL_CONF_CTX *cctx, const char *value)
+{
+    int rv;
+    if (cctx->ssl)
+        rv = SSL_set1_client_sigalgs_list(cctx->ssl, value);
+    /* NB: ctx == NULL performs syntax checking only */
+    else
+        rv = SSL_CTX_set1_client_sigalgs_list(cctx->ctx, value);
+    return rv > 0;
+}
+
+static int cmd_Groups(SSL_CONF_CTX *cctx, const char *value)
+{
+    int rv;
+    if (cctx->ssl)
+        rv = SSL_set1_groups_list(cctx->ssl, value);
+    /* NB: ctx == NULL performs syntax checking only */
+    else
+        rv = SSL_CTX_set1_groups_list(cctx->ctx, value);
+    return rv > 0;
+}
+
+/* This is the old name for cmd_Groups - retained for backwards compatibility */
+static int cmd_Curves(SSL_CONF_CTX *cctx, const char *value)
+{
+    return cmd_Groups(cctx, value);
+}
+
+#ifndef OPENSSL_NO_EC
+/* ECDH temporary parameters */
+static int cmd_ECDHParameters(SSL_CONF_CTX *cctx, const char *value)
+{
+    int rv = 1;
+    EC_KEY *ecdh;
+    int nid;
+
+    /* Ignore values supported by 1.0.2 for the automatic selection */
+    if ((cctx->flags & SSL_CONF_FLAG_FILE)
+            && (strcasecmp(value, "+automatic") == 0
+                || strcasecmp(value, "automatic") == 0))
+        return 1;
+    if ((cctx->flags & SSL_CONF_FLAG_CMDLINE) &&
+        strcmp(value, "auto") == 0)
+        return 1;
+
+    nid = EC_curve_nist2nid(value);
+    if (nid == NID_undef)
+        nid = OBJ_sn2nid(value);
+    if (nid == 0)
+        return 0;
+    ecdh = EC_KEY_new_by_curve_name(nid);
+    if (!ecdh)
+        return 0;
+    if (cctx->ctx)
+        rv = SSL_CTX_set_tmp_ecdh(cctx->ctx, ecdh);
+    else if (cctx->ssl)
+        rv = SSL_set_tmp_ecdh(cctx->ssl, ecdh);
+    EC_KEY_free(ecdh);
+
+    return rv > 0;
+}
+#endif
+static int cmd_CipherString(SSL_CONF_CTX *cctx, const char *value)
+{
+    int rv = 1;
+
+    if (cctx->ctx)
+        rv = SSL_CTX_set_cipher_list(cctx->ctx, value);
+    if (cctx->ssl)
+        rv = SSL_set_cipher_list(cctx->ssl, value);
+    return rv > 0;
+}
+
+static int cmd_Ciphersuites(SSL_CONF_CTX *cctx, const char *value)
+{
+    int rv = 1;
+
+    if (cctx->ctx)
+        rv = SSL_CTX_set_ciphersuites(cctx->ctx, value);
+    if (cctx->ssl)
+        rv = SSL_set_ciphersuites(cctx->ssl, value);
+    return rv > 0;
+}
+
+static int cmd_Protocol(SSL_CONF_CTX *cctx, const char *value)
+{
+    static const ssl_flag_tbl ssl_protocol_list[] = {
+        SSL_FLAG_TBL_INV("ALL", SSL_OP_NO_SSL_MASK),
+        SSL_FLAG_TBL_INV("SSLv2", SSL_OP_NO_SSLv2),
+        SSL_FLAG_TBL_INV("SSLv3", SSL_OP_NO_SSLv3),
+        SSL_FLAG_TBL_INV("TLSv1", SSL_OP_NO_TLSv1),
+        SSL_FLAG_TBL_INV("TLSv1.1", SSL_OP_NO_TLSv1_1),
+        SSL_FLAG_TBL_INV("TLSv1.2", SSL_OP_NO_TLSv1_2),
+        SSL_FLAG_TBL_INV("TLSv1.3", SSL_OP_NO_TLSv1_3),
+        SSL_FLAG_TBL_INV("DTLSv1", SSL_OP_NO_DTLSv1),
+        SSL_FLAG_TBL_INV("DTLSv1.2", SSL_OP_NO_DTLSv1_2)
+    };
+    cctx->tbl = ssl_protocol_list;
+    cctx->ntbl = OSSL_NELEM(ssl_protocol_list);
+    return CONF_parse_list(value, ',', 1, ssl_set_option_list, cctx);
+}
+
+/*
+ * protocol_from_string - converts a protocol version string to a number
+ *
+ * Returns -1 on failure or the version on success
+ */
+static int protocol_from_string(const char *value)
+{
+    struct protocol_versions {
+        const char *name;
+        int version;
+    };
+    /*
+     * Note: To avoid breaking previously valid configurations, we must retain
+     * legacy entries in this table even if the underlying protocol is no
+     * longer supported.  This also means that the constants SSL3_VERSION, ...
+     * need to be retained indefinitely.  This table can only grow, never
+     * shrink.
+     */
+    static const struct protocol_versions versions[] = {
+        {"None", 0},
+        {"SSLv3", SSL3_VERSION},
+        {"TLSv1", TLS1_VERSION},
+        {"TLSv1.1", TLS1_1_VERSION},
+        {"TLSv1.2", TLS1_2_VERSION},
+        {"TLSv1.3", TLS1_3_VERSION},
+        {"DTLSv1", DTLS1_VERSION},
+        {"DTLSv1.2", DTLS1_2_VERSION}
+    };
+    size_t i;
+    size_t n = OSSL_NELEM(versions);
+
+    for (i = 0; i < n; i++)
+        if (strcmp(versions[i].name, value) == 0)
+            return versions[i].version;
+    return -1;
+}
+
+static int min_max_proto(SSL_CONF_CTX *cctx, const char *value, int *bound)
+{
+    int method_version;
+    int new_version;
+
+    if (cctx->ctx != NULL)
+        method_version = cctx->ctx->method->version;
+    else if (cctx->ssl != NULL)
+        method_version = cctx->ssl->ctx->method->version;
+    else
+        return 0;
+    if ((new_version = protocol_from_string(value)) < 0)
+        return 0;
+    return ssl_set_version_bound(method_version, new_version, bound);
+}
+
+/*
+ * cmd_MinProtocol - Set min protocol version
+ * @cctx: config structure to save settings in
+ * @value: The min protocol version in string form
+ *
+ * Returns 1 on success and 0 on failure.
+ */
+static int cmd_MinProtocol(SSL_CONF_CTX *cctx, const char *value)
+{
+    return min_max_proto(cctx, value, cctx->min_version);
+}
+
+/*
+ * cmd_MaxProtocol - Set max protocol version
+ * @cctx: config structure to save settings in
+ * @value: The max protocol version in string form
+ *
+ * Returns 1 on success and 0 on failure.
+ */
+static int cmd_MaxProtocol(SSL_CONF_CTX *cctx, const char *value)
+{
+    return min_max_proto(cctx, value, cctx->max_version);
+}
+
+static int cmd_Options(SSL_CONF_CTX *cctx, const char *value)
+{
+    static const ssl_flag_tbl ssl_option_list[] = {
+        SSL_FLAG_TBL_INV("SessionTicket", SSL_OP_NO_TICKET),
+        SSL_FLAG_TBL_INV("EmptyFragments",
+                         SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS),
+        SSL_FLAG_TBL("Bugs", SSL_OP_ALL),
+        SSL_FLAG_TBL_INV("Compression", SSL_OP_NO_COMPRESSION),
+        SSL_FLAG_TBL_SRV("ServerPreference", SSL_OP_CIPHER_SERVER_PREFERENCE),
+        SSL_FLAG_TBL_SRV("NoResumptionOnRenegotiation",
+                         SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION),
+        SSL_FLAG_TBL_SRV("DHSingle", SSL_OP_SINGLE_DH_USE),
+        SSL_FLAG_TBL_SRV("ECDHSingle", SSL_OP_SINGLE_ECDH_USE),
+        SSL_FLAG_TBL("UnsafeLegacyRenegotiation",
+                     SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION),
+        SSL_FLAG_TBL_INV("EncryptThenMac", SSL_OP_NO_ENCRYPT_THEN_MAC),
+        SSL_FLAG_TBL("NoRenegotiation", SSL_OP_NO_RENEGOTIATION),
+        SSL_FLAG_TBL("AllowNoDHEKEX", SSL_OP_ALLOW_NO_DHE_KEX),
+        SSL_FLAG_TBL("PrioritizeChaCha", SSL_OP_PRIORITIZE_CHACHA),
+        SSL_FLAG_TBL("MiddleboxCompat", SSL_OP_ENABLE_MIDDLEBOX_COMPAT),
+        SSL_FLAG_TBL_INV("AntiReplay", SSL_OP_NO_ANTI_REPLAY)
+    };
+    if (value == NULL)
+        return -3;
+    cctx->tbl = ssl_option_list;
+    cctx->ntbl = OSSL_NELEM(ssl_option_list);
+    return CONF_parse_list(value, ',', 1, ssl_set_option_list, cctx);
+}
+
+static int cmd_VerifyMode(SSL_CONF_CTX *cctx, const char *value)
+{
+    static const ssl_flag_tbl ssl_vfy_list[] = {
+        SSL_FLAG_VFY_CLI("Peer", SSL_VERIFY_PEER),
+        SSL_FLAG_VFY_SRV("Request", SSL_VERIFY_PEER),
+        SSL_FLAG_VFY_SRV("Require",
+                         SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
+        SSL_FLAG_VFY_SRV("Once", SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE),
+        SSL_FLAG_VFY_SRV("RequestPostHandshake",
+                         SSL_VERIFY_PEER | SSL_VERIFY_POST_HANDSHAKE),
+        SSL_FLAG_VFY_SRV("RequirePostHandshake",
+                         SSL_VERIFY_PEER | SSL_VERIFY_POST_HANDSHAKE |
+                         SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
+    };
+    if (value == NULL)
+        return -3;
+    cctx->tbl = ssl_vfy_list;
+    cctx->ntbl = OSSL_NELEM(ssl_vfy_list);
+    return CONF_parse_list(value, ',', 1, ssl_set_option_list, cctx);
+}
+
+static int cmd_Certificate(SSL_CONF_CTX *cctx, const char *value)
+{
+    int rv = 1;
+    CERT *c = NULL;
+    if (cctx->ctx) {
+        rv = SSL_CTX_use_certificate_chain_file(cctx->ctx, value);
+        c = cctx->ctx->cert;
+    }
+    if (cctx->ssl) {
+        rv = SSL_use_certificate_chain_file(cctx->ssl, value);
+        c = cctx->ssl->cert;
+    }
+    if (rv > 0 && c && cctx->flags & SSL_CONF_FLAG_REQUIRE_PRIVATE) {
+        char **pfilename = &cctx->cert_filename[c->key - c->pkeys];
+        OPENSSL_free(*pfilename);
+        *pfilename = OPENSSL_strdup(value);
+        if (!*pfilename)
+            rv = 0;
+    }
+
+    return rv > 0;
+}
+
+static int cmd_PrivateKey(SSL_CONF_CTX *cctx, const char *value)
+{
+    int rv = 1;
+    if (!(cctx->flags & SSL_CONF_FLAG_CERTIFICATE))
+        return -2;
+    if (cctx->ctx)
+        rv = SSL_CTX_use_PrivateKey_file(cctx->ctx, value, SSL_FILETYPE_PEM);
+    if (cctx->ssl)
+        rv = SSL_use_PrivateKey_file(cctx->ssl, value, SSL_FILETYPE_PEM);
+    return rv > 0;
+}
+
+static int cmd_ServerInfoFile(SSL_CONF_CTX *cctx, const char *value)
+{
+    int rv = 1;
+    if (cctx->ctx)
+        rv = SSL_CTX_use_serverinfo_file(cctx->ctx, value);
+    return rv > 0;
+}
+
+static int do_store(SSL_CONF_CTX *cctx,
+                    const char *CAfile, const char *CApath, int verify_store)
+{
+    CERT *cert;
+    X509_STORE **st;
+    if (cctx->ctx)
+        cert = cctx->ctx->cert;
+    else if (cctx->ssl)
+        cert = cctx->ssl->cert;
+    else
+        return 1;
+    st = verify_store ? &cert->verify_store : &cert->chain_store;
+    if (*st == NULL) {
+        *st = X509_STORE_new();
+        if (*st == NULL)
+            return 0;
+    }
+    return X509_STORE_load_locations(*st, CAfile, CApath) > 0;
+}
+
+static int cmd_ChainCAPath(SSL_CONF_CTX *cctx, const char *value)
+{
+    return do_store(cctx, NULL, value, 0);
+}
+
+static int cmd_ChainCAFile(SSL_CONF_CTX *cctx, const char *value)
+{
+    return do_store(cctx, value, NULL, 0);
+}
+
+static int cmd_VerifyCAPath(SSL_CONF_CTX *cctx, const char *value)
+{
+    return do_store(cctx, NULL, value, 1);
+}
+
+static int cmd_VerifyCAFile(SSL_CONF_CTX *cctx, const char *value)
+{
+    return do_store(cctx, value, NULL, 1);
+}
+
+static int cmd_RequestCAFile(SSL_CONF_CTX *cctx, const char *value)
+{
+    if (cctx->canames == NULL)
+        cctx->canames = sk_X509_NAME_new_null();
+    if (cctx->canames == NULL)
+        return 0;
+    return SSL_add_file_cert_subjects_to_stack(cctx->canames, value);
+}
+
+static int cmd_ClientCAFile(SSL_CONF_CTX *cctx, const char *value)
+{
+    return cmd_RequestCAFile(cctx, value);
+}
+
+static int cmd_RequestCAPath(SSL_CONF_CTX *cctx, const char *value)
+{
+    if (cctx->canames == NULL)
+        cctx->canames = sk_X509_NAME_new_null();
+    if (cctx->canames == NULL)
+        return 0;
+    return SSL_add_dir_cert_subjects_to_stack(cctx->canames, value);
+}
+
+static int cmd_ClientCAPath(SSL_CONF_CTX *cctx, const char *value)
+{
+    return cmd_RequestCAPath(cctx, value);
+}
+
+#ifndef OPENSSL_NO_DH
+static int cmd_DHParameters(SSL_CONF_CTX *cctx, const char *value)
+{
+    int rv = 0;
+    DH *dh = NULL;
+    BIO *in = NULL;
+    if (cctx->ctx || cctx->ssl) {
+        in = BIO_new(BIO_s_file());
+        if (in == NULL)
+            goto end;
+        if (BIO_read_filename(in, value) <= 0)
+            goto end;
+        dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
+        if (dh == NULL)
+            goto end;
+    } else
+        return 1;
+    if (cctx->ctx)
+        rv = SSL_CTX_set_tmp_dh(cctx->ctx, dh);
+    if (cctx->ssl)
+        rv = SSL_set_tmp_dh(cctx->ssl, dh);
+ end:
+    DH_free(dh);
+    BIO_free(in);
+    return rv > 0;
+}
+#endif
+
+static int cmd_RecordPadding(SSL_CONF_CTX *cctx, const char *value)
+{
+    int rv = 0;
+    int block_size = atoi(value);
+
+    /*
+     * All we care about is a non-negative value,
+     * the setters check the range
+     */
+    if (block_size >= 0) {
+        if (cctx->ctx)
+            rv = SSL_CTX_set_block_padding(cctx->ctx, block_size);
+        if (cctx->ssl)
+            rv = SSL_set_block_padding(cctx->ssl, block_size);
+    }
+    return rv;
+}
+
+
+static int cmd_NumTickets(SSL_CONF_CTX *cctx, const char *value)
+{
+    int rv = 0;
+    int num_tickets = atoi(value);
+
+    if (num_tickets >= 0) {
+        if (cctx->ctx)
+            rv = SSL_CTX_set_num_tickets(cctx->ctx, num_tickets);
+        if (cctx->ssl)
+            rv = SSL_set_num_tickets(cctx->ssl, num_tickets);
+    }
+    return rv;
+}
+
+typedef struct {
+    int (*cmd) (SSL_CONF_CTX *cctx, const char *value);
+    const char *str_file;
+    const char *str_cmdline;
+    unsigned short flags;
+    unsigned short value_type;
+} ssl_conf_cmd_tbl;
+
+/* Table of supported parameters */
+
+#define SSL_CONF_CMD(name, cmdopt, flags, type) \
+        {cmd_##name, #name, cmdopt, flags, type}
+
+#define SSL_CONF_CMD_STRING(name, cmdopt, flags) \
+        SSL_CONF_CMD(name, cmdopt, flags, SSL_CONF_TYPE_STRING)
+
+#define SSL_CONF_CMD_SWITCH(name, flags) \
+        {0, NULL, name, flags, SSL_CONF_TYPE_NONE}
+
+/* See apps/apps.h if you change this table. */
+static const ssl_conf_cmd_tbl ssl_conf_cmds[] = {
+    SSL_CONF_CMD_SWITCH("no_ssl3", 0),
+    SSL_CONF_CMD_SWITCH("no_tls1", 0),
+    SSL_CONF_CMD_SWITCH("no_tls1_1", 0),
+    SSL_CONF_CMD_SWITCH("no_tls1_2", 0),
+    SSL_CONF_CMD_SWITCH("no_tls1_3", 0),
+    SSL_CONF_CMD_SWITCH("bugs", 0),
+    SSL_CONF_CMD_SWITCH("no_comp", 0),
+    SSL_CONF_CMD_SWITCH("comp", 0),
+    SSL_CONF_CMD_SWITCH("ecdh_single", SSL_CONF_FLAG_SERVER),
+    SSL_CONF_CMD_SWITCH("no_ticket", 0),
+    SSL_CONF_CMD_SWITCH("serverpref", SSL_CONF_FLAG_SERVER),
+    SSL_CONF_CMD_SWITCH("legacy_renegotiation", 0),
+    SSL_CONF_CMD_SWITCH("legacy_server_connect", SSL_CONF_FLAG_SERVER),
+    SSL_CONF_CMD_SWITCH("no_renegotiation", 0),
+    SSL_CONF_CMD_SWITCH("no_resumption_on_reneg", SSL_CONF_FLAG_SERVER),
+    SSL_CONF_CMD_SWITCH("no_legacy_server_connect", SSL_CONF_FLAG_SERVER),
+    SSL_CONF_CMD_SWITCH("allow_no_dhe_kex", 0),
+    SSL_CONF_CMD_SWITCH("prioritize_chacha", SSL_CONF_FLAG_SERVER),
+    SSL_CONF_CMD_SWITCH("strict", 0),
+    SSL_CONF_CMD_SWITCH("no_middlebox", 0),
+    SSL_CONF_CMD_SWITCH("anti_replay", SSL_CONF_FLAG_SERVER),
+    SSL_CONF_CMD_SWITCH("no_anti_replay", SSL_CONF_FLAG_SERVER),
+    SSL_CONF_CMD_STRING(SignatureAlgorithms, "sigalgs", 0),
+    SSL_CONF_CMD_STRING(ClientSignatureAlgorithms, "client_sigalgs", 0),
+    SSL_CONF_CMD_STRING(Curves, "curves", 0),
+    SSL_CONF_CMD_STRING(Groups, "groups", 0),
+#ifndef OPENSSL_NO_EC
+    SSL_CONF_CMD_STRING(ECDHParameters, "named_curve", SSL_CONF_FLAG_SERVER),
+#endif
+    SSL_CONF_CMD_STRING(CipherString, "cipher", 0),
+    SSL_CONF_CMD_STRING(Ciphersuites, "ciphersuites", 0),
+    SSL_CONF_CMD_STRING(Protocol, NULL, 0),
+    SSL_CONF_CMD_STRING(MinProtocol, "min_protocol", 0),
+    SSL_CONF_CMD_STRING(MaxProtocol, "max_protocol", 0),
+    SSL_CONF_CMD_STRING(Options, NULL, 0),
+    SSL_CONF_CMD_STRING(VerifyMode, NULL, 0),
+    SSL_CONF_CMD(Certificate, "cert", SSL_CONF_FLAG_CERTIFICATE,
+                 SSL_CONF_TYPE_FILE),
+    SSL_CONF_CMD(PrivateKey, "key", SSL_CONF_FLAG_CERTIFICATE,
+                 SSL_CONF_TYPE_FILE),
+    SSL_CONF_CMD(ServerInfoFile, NULL,
+                 SSL_CONF_FLAG_SERVER | SSL_CONF_FLAG_CERTIFICATE,
+                 SSL_CONF_TYPE_FILE),
+    SSL_CONF_CMD(ChainCAPath, "chainCApath", SSL_CONF_FLAG_CERTIFICATE,
+                 SSL_CONF_TYPE_DIR),
+    SSL_CONF_CMD(ChainCAFile, "chainCAfile", SSL_CONF_FLAG_CERTIFICATE,
+                 SSL_CONF_TYPE_FILE),
+    SSL_CONF_CMD(VerifyCAPath, "verifyCApath", SSL_CONF_FLAG_CERTIFICATE,
+                 SSL_CONF_TYPE_DIR),
+    SSL_CONF_CMD(VerifyCAFile, "verifyCAfile", SSL_CONF_FLAG_CERTIFICATE,
+                 SSL_CONF_TYPE_FILE),
+    SSL_CONF_CMD(RequestCAFile, "requestCAFile", SSL_CONF_FLAG_CERTIFICATE,
+                 SSL_CONF_TYPE_FILE),
+    SSL_CONF_CMD(ClientCAFile, NULL,
+                 SSL_CONF_FLAG_SERVER | SSL_CONF_FLAG_CERTIFICATE,
+                 SSL_CONF_TYPE_FILE),
+    SSL_CONF_CMD(RequestCAPath, NULL, SSL_CONF_FLAG_CERTIFICATE,
+                 SSL_CONF_TYPE_DIR),
+    SSL_CONF_CMD(ClientCAPath, NULL,
+                 SSL_CONF_FLAG_SERVER | SSL_CONF_FLAG_CERTIFICATE,
+                 SSL_CONF_TYPE_DIR),
+#ifndef OPENSSL_NO_DH
+    SSL_CONF_CMD(DHParameters, "dhparam",
+                 SSL_CONF_FLAG_SERVER | SSL_CONF_FLAG_CERTIFICATE,
+                 SSL_CONF_TYPE_FILE),
+#endif
+    SSL_CONF_CMD_STRING(RecordPadding, "record_padding", 0),
+    SSL_CONF_CMD_STRING(NumTickets, "num_tickets", SSL_CONF_FLAG_SERVER),
+};
+
+/* Supported switches: must match order of switches in ssl_conf_cmds */
+static const ssl_switch_tbl ssl_cmd_switches[] = {
+    {SSL_OP_NO_SSLv3, 0},       /* no_ssl3 */
+    {SSL_OP_NO_TLSv1, 0},       /* no_tls1 */
+    {SSL_OP_NO_TLSv1_1, 0},     /* no_tls1_1 */
+    {SSL_OP_NO_TLSv1_2, 0},     /* no_tls1_2 */
+    {SSL_OP_NO_TLSv1_3, 0},     /* no_tls1_3 */
+    {SSL_OP_ALL, 0},            /* bugs */
+    {SSL_OP_NO_COMPRESSION, 0}, /* no_comp */
+    {SSL_OP_NO_COMPRESSION, SSL_TFLAG_INV}, /* comp */
+    {SSL_OP_SINGLE_ECDH_USE, 0}, /* ecdh_single */
+    {SSL_OP_NO_TICKET, 0},      /* no_ticket */
+    {SSL_OP_CIPHER_SERVER_PREFERENCE, 0}, /* serverpref */
+    /* legacy_renegotiation */
+    {SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, 0},
+    /* legacy_server_connect */
+    {SSL_OP_LEGACY_SERVER_CONNECT, 0},
+    /* no_renegotiation */
+    {SSL_OP_NO_RENEGOTIATION, 0},
+    /* no_resumption_on_reneg */
+    {SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION, 0},
+    /* no_legacy_server_connect */
+    {SSL_OP_LEGACY_SERVER_CONNECT, SSL_TFLAG_INV},
+    /* allow_no_dhe_kex */
+    {SSL_OP_ALLOW_NO_DHE_KEX, 0},
+    /* chacha reprioritization */
+    {SSL_OP_PRIORITIZE_CHACHA, 0},
+    {SSL_CERT_FLAG_TLS_STRICT, SSL_TFLAG_CERT}, /* strict */
+    /* no_middlebox */
+    {SSL_OP_ENABLE_MIDDLEBOX_COMPAT, SSL_TFLAG_INV},
+    /* anti_replay */
+    {SSL_OP_NO_ANTI_REPLAY, SSL_TFLAG_INV},
+    /* no_anti_replay */
+    {SSL_OP_NO_ANTI_REPLAY, 0},
+};
+
+static int ssl_conf_cmd_skip_prefix(SSL_CONF_CTX *cctx, const char **pcmd)
+{
+    if (!pcmd || !*pcmd)
+        return 0;
+    /* If a prefix is set, check and skip */
+    if (cctx->prefix) {
+        if (strlen(*pcmd) <= cctx->prefixlen)
+            return 0;
+        if (cctx->flags & SSL_CONF_FLAG_CMDLINE &&
+            strncmp(*pcmd, cctx->prefix, cctx->prefixlen))
+            return 0;
+        if (cctx->flags & SSL_CONF_FLAG_FILE &&
+            strncasecmp(*pcmd, cctx->prefix, cctx->prefixlen))
+            return 0;
+        *pcmd += cctx->prefixlen;
+    } else if (cctx->flags & SSL_CONF_FLAG_CMDLINE) {
+        if (**pcmd != '-' || !(*pcmd)[1])
+            return 0;
+        *pcmd += 1;
+    }
+    return 1;
+}
+
+/* Determine if a command is allowed according to cctx flags */
+static int ssl_conf_cmd_allowed(SSL_CONF_CTX *cctx, const ssl_conf_cmd_tbl * t)
+{
+    unsigned int tfl = t->flags;
+    unsigned int cfl = cctx->flags;
+    if ((tfl & SSL_CONF_FLAG_SERVER) && !(cfl & SSL_CONF_FLAG_SERVER))
+        return 0;
+    if ((tfl & SSL_CONF_FLAG_CLIENT) && !(cfl & SSL_CONF_FLAG_CLIENT))
+        return 0;
+    if ((tfl & SSL_CONF_FLAG_CERTIFICATE)
+        && !(cfl & SSL_CONF_FLAG_CERTIFICATE))
+        return 0;
+    return 1;
+}
+
+static const ssl_conf_cmd_tbl *ssl_conf_cmd_lookup(SSL_CONF_CTX *cctx,
+                                                   const char *cmd)
+{
+    const ssl_conf_cmd_tbl *t;
+    size_t i;
+    if (cmd == NULL)
+        return NULL;
+
+    /* Look for matching parameter name in table */
+    for (i = 0, t = ssl_conf_cmds; i < OSSL_NELEM(ssl_conf_cmds); i++, t++) {
+        if (ssl_conf_cmd_allowed(cctx, t)) {
+            if (cctx->flags & SSL_CONF_FLAG_CMDLINE) {
+                if (t->str_cmdline && strcmp(t->str_cmdline, cmd) == 0)
+                    return t;
+            }
+            if (cctx->flags & SSL_CONF_FLAG_FILE) {
+                if (t->str_file && strcasecmp(t->str_file, cmd) == 0)
+                    return t;
+            }
+        }
+    }
+    return NULL;
+}
+
+static int ctrl_switch_option(SSL_CONF_CTX *cctx, const ssl_conf_cmd_tbl * cmd)
+{
+    /* Find index of command in table */
+    size_t idx = cmd - ssl_conf_cmds;
+    const ssl_switch_tbl *scmd;
+    /* Sanity check index */
+    if (idx >= OSSL_NELEM(ssl_cmd_switches))
+        return 0;
+    /* Obtain switches entry with same index */
+    scmd = ssl_cmd_switches + idx;
+    ssl_set_option(cctx, scmd->name_flags, scmd->option_value, 1);
+    return 1;
+}
+
+int SSL_CONF_cmd(SSL_CONF_CTX *cctx, const char *cmd, const char *value)
+{
+    const ssl_conf_cmd_tbl *runcmd;
+    if (cmd == NULL) {
+        SSLerr(SSL_F_SSL_CONF_CMD, SSL_R_INVALID_NULL_CMD_NAME);
+        return 0;
+    }
+
+    if (!ssl_conf_cmd_skip_prefix(cctx, &cmd))
+        return -2;
+
+    runcmd = ssl_conf_cmd_lookup(cctx, cmd);
+
+    if (runcmd) {
+        int rv;
+        if (runcmd->value_type == SSL_CONF_TYPE_NONE) {
+            return ctrl_switch_option(cctx, runcmd);
+        }
+        if (value == NULL)
+            return -3;
+        rv = runcmd->cmd(cctx, value);
+        if (rv > 0)
+            return 2;
+        if (rv == -2)
+            return -2;
+        if (cctx->flags & SSL_CONF_FLAG_SHOW_ERRORS) {
+            SSLerr(SSL_F_SSL_CONF_CMD, SSL_R_BAD_VALUE);
+            ERR_add_error_data(4, "cmd=", cmd, ", value=", value);
+        }
+        return 0;
+    }
+
+    if (cctx->flags & SSL_CONF_FLAG_SHOW_ERRORS) {
+        SSLerr(SSL_F_SSL_CONF_CMD, SSL_R_UNKNOWN_CMD_NAME);
+        ERR_add_error_data(2, "cmd=", cmd);
+    }
+
+    return -2;
+}
+
+int SSL_CONF_cmd_argv(SSL_CONF_CTX *cctx, int *pargc, char ***pargv)
+{
+    int rv;
+    const char *arg = NULL, *argn;
+    if (pargc && *pargc == 0)
+        return 0;
+    if (!pargc || *pargc > 0)
+        arg = **pargv;
+    if (arg == NULL)
+        return 0;
+    if (!pargc || *pargc > 1)
+        argn = (*pargv)[1];
+    else
+        argn = NULL;
+    cctx->flags &= ~SSL_CONF_FLAG_FILE;
+    cctx->flags |= SSL_CONF_FLAG_CMDLINE;
+    rv = SSL_CONF_cmd(cctx, arg, argn);
+    if (rv > 0) {
+        /* Success: update pargc, pargv */
+        (*pargv) += rv;
+        if (pargc)
+            (*pargc) -= rv;
+        return rv;
+    }
+    /* Unknown switch: indicate no arguments processed */
+    if (rv == -2)
+        return 0;
+    /* Some error occurred processing command, return fatal error */
+    if (rv == 0)
+        return -1;
+    return rv;
+}
+
+int SSL_CONF_cmd_value_type(SSL_CONF_CTX *cctx, const char *cmd)
+{
+    if (ssl_conf_cmd_skip_prefix(cctx, &cmd)) {
+        const ssl_conf_cmd_tbl *runcmd;
+        runcmd = ssl_conf_cmd_lookup(cctx, cmd);
+        if (runcmd)
+            return runcmd->value_type;
+    }
+    return SSL_CONF_TYPE_UNKNOWN;
+}
+
+SSL_CONF_CTX *SSL_CONF_CTX_new(void)
+{
+    SSL_CONF_CTX *ret = OPENSSL_zalloc(sizeof(*ret));
+
+    return ret;
+}
+
+int SSL_CONF_CTX_finish(SSL_CONF_CTX *cctx)
+{
+    /* See if any certificates are missing private keys */
+    size_t i;
+    CERT *c = NULL;
+    if (cctx->ctx)
+        c = cctx->ctx->cert;
+    else if (cctx->ssl)
+        c = cctx->ssl->cert;
+    if (c && cctx->flags & SSL_CONF_FLAG_REQUIRE_PRIVATE) {
+        for (i = 0; i < SSL_PKEY_NUM; i++) {
+            const char *p = cctx->cert_filename[i];
+            /*
+             * If missing private key try to load one from certificate file
+             */
+            if (p && !c->pkeys[i].privatekey) {
+                if (!cmd_PrivateKey(cctx, p))
+                    return 0;
+            }
+        }
+    }
+    if (cctx->canames) {
+        if (cctx->ssl)
+            SSL_set0_CA_list(cctx->ssl, cctx->canames);
+        else if (cctx->ctx)
+            SSL_CTX_set0_CA_list(cctx->ctx, cctx->canames);
+        else
+            sk_X509_NAME_pop_free(cctx->canames, X509_NAME_free);
+        cctx->canames = NULL;
+    }
+    return 1;
+}
+
+void SSL_CONF_CTX_free(SSL_CONF_CTX *cctx)
+{
+    if (cctx) {
+        size_t i;
+        for (i = 0; i < SSL_PKEY_NUM; i++)
+            OPENSSL_free(cctx->cert_filename[i]);
+        OPENSSL_free(cctx->prefix);
+        sk_X509_NAME_pop_free(cctx->canames, X509_NAME_free);
+        OPENSSL_free(cctx);
+    }
+}
+
+unsigned int SSL_CONF_CTX_set_flags(SSL_CONF_CTX *cctx, unsigned int flags)
+{
+    cctx->flags |= flags;
+    return cctx->flags;
+}
+
+unsigned int SSL_CONF_CTX_clear_flags(SSL_CONF_CTX *cctx, unsigned int flags)
+{
+    cctx->flags &= ~flags;
+    return cctx->flags;
+}
+
+int SSL_CONF_CTX_set1_prefix(SSL_CONF_CTX *cctx, const char *pre)
+{
+    char *tmp = NULL;
+    if (pre) {
+        tmp = OPENSSL_strdup(pre);
+        if (tmp == NULL)
+            return 0;
+    }
+    OPENSSL_free(cctx->prefix);
+    cctx->prefix = tmp;
+    if (tmp)
+        cctx->prefixlen = strlen(tmp);
+    else
+        cctx->prefixlen = 0;
+    return 1;
+}
+
+void SSL_CONF_CTX_set_ssl(SSL_CONF_CTX *cctx, SSL *ssl)
+{
+    cctx->ssl = ssl;
+    cctx->ctx = NULL;
+    if (ssl) {
+        cctx->poptions = &ssl->options;
+        cctx->min_version = &ssl->min_proto_version;
+        cctx->max_version = &ssl->max_proto_version;
+        cctx->pcert_flags = &ssl->cert->cert_flags;
+        cctx->pvfy_flags = &ssl->verify_mode;
+    } else {
+        cctx->poptions = NULL;
+        cctx->min_version = NULL;
+        cctx->max_version = NULL;
+        cctx->pcert_flags = NULL;
+        cctx->pvfy_flags = NULL;
+    }
+}
+
+void SSL_CONF_CTX_set_ssl_ctx(SSL_CONF_CTX *cctx, SSL_CTX *ctx)
+{
+    cctx->ctx = ctx;
+    cctx->ssl = NULL;
+    if (ctx) {
+        cctx->poptions = &ctx->options;
+        cctx->min_version = &ctx->min_proto_version;
+        cctx->max_version = &ctx->max_proto_version;
+        cctx->pcert_flags = &ctx->cert->cert_flags;
+        cctx->pvfy_flags = &ctx->verify_mode;
+    } else {
+        cctx->poptions = NULL;
+        cctx->min_version = NULL;
+        cctx->max_version = NULL;
+        cctx->pcert_flags = NULL;
+        cctx->pvfy_flags = NULL;
+    }
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_err.c b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_err.c
new file mode 100644
index 0000000..324f2cc
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_err.c
@@ -0,0 +1,1282 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/err.h>
+#include <openssl/sslerr.h>
+
+#ifndef OPENSSL_NO_ERR
+
+static const ERR_STRING_DATA SSL_str_functs[] = {
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_ADD_CLIENT_KEY_SHARE_EXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_ADD_KEY_SHARE, 0), "add_key_share"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_BYTES_TO_CIPHER_LIST, 0),
+     "bytes_to_cipher_list"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_CHECK_SUITEB_CIPHER_LIST, 0),
+     "check_suiteb_cipher_list"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_CIPHERSUITE_CB, 0), "ciphersuite_cb"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_CONSTRUCT_CA_NAMES, 0), "construct_ca_names"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_CONSTRUCT_KEY_EXCHANGE_TBS, 0),
+     "construct_key_exchange_tbs"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_CONSTRUCT_STATEFUL_TICKET, 0),
+     "construct_stateful_ticket"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_CONSTRUCT_STATELESS_TICKET, 0),
+     "construct_stateless_ticket"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH, 0),
+     "create_synthetic_message_hash"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_CREATE_TICKET_PREQUEL, 0),
+     "create_ticket_prequel"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_CT_MOVE_SCTS, 0), "ct_move_scts"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_CT_STRICT, 0), "ct_strict"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_CUSTOM_EXT_ADD, 0), "custom_ext_add"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_CUSTOM_EXT_PARSE, 0), "custom_ext_parse"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_D2I_SSL_SESSION, 0), "d2i_SSL_SESSION"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DANE_CTX_ENABLE, 0), "dane_ctx_enable"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DANE_MTYPE_SET, 0), "dane_mtype_set"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DANE_TLSA_ADD, 0), "dane_tlsa_add"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DERIVE_SECRET_KEY_AND_IV, 0),
+     "derive_secret_key_and_iv"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DO_DTLS1_WRITE, 0), "do_dtls1_write"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DO_SSL3_WRITE, 0), "do_ssl3_write"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS1_BUFFER_RECORD, 0),
+     "dtls1_buffer_record"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS1_CHECK_TIMEOUT_NUM, 0),
+     "dtls1_check_timeout_num"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS1_HEARTBEAT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS1_HM_FRAGMENT_NEW, 0),
+     "dtls1_hm_fragment_new"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS1_PREPROCESS_FRAGMENT, 0),
+     "dtls1_preprocess_fragment"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS1_PROCESS_BUFFERED_RECORDS, 0),
+     "dtls1_process_buffered_records"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS1_PROCESS_RECORD, 0),
+     "dtls1_process_record"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS1_READ_BYTES, 0), "dtls1_read_bytes"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS1_READ_FAILED, 0), "dtls1_read_failed"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS1_RETRANSMIT_MESSAGE, 0),
+     "dtls1_retransmit_message"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS1_WRITE_APP_DATA_BYTES, 0),
+     "dtls1_write_app_data_bytes"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS1_WRITE_BYTES, 0), "dtls1_write_bytes"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLSV1_LISTEN, 0), "DTLSv1_listen"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS_CONSTRUCT_CHANGE_CIPHER_SPEC, 0),
+     "dtls_construct_change_cipher_spec"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS_CONSTRUCT_HELLO_VERIFY_REQUEST, 0),
+     "dtls_construct_hello_verify_request"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, 0),
+     "dtls_get_reassembled_message"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS_PROCESS_HELLO_VERIFY, 0),
+     "dtls_process_hello_verify"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS_RECORD_LAYER_NEW, 0),
+     "DTLS_RECORD_LAYER_new"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_DTLS_WAIT_FOR_DRY, 0), "dtls_wait_for_dry"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_EARLY_DATA_COUNT_OK, 0),
+     "early_data_count_ok"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_EARLY_DATA, 0), "final_early_data"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_EC_PT_FORMATS, 0),
+     "final_ec_pt_formats"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_EMS, 0), "final_ems"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_KEY_SHARE, 0), "final_key_share"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_MAXFRAGMENTLEN, 0),
+     "final_maxfragmentlen"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_PSK, 0), "final_psk"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_RENEGOTIATE, 0), "final_renegotiate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_SERVER_NAME, 0), "final_server_name"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_SIG_ALGS, 0), "final_sig_algs"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_GET_CERT_VERIFY_TBS_DATA, 0),
+     "get_cert_verify_tbs_data"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_NSS_KEYLOG_INT, 0), "nss_keylog_int"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OPENSSL_INIT_SSL, 0), "OPENSSL_init_ssl"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_CLIENT13_READ_TRANSITION, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_CLIENT13_WRITE_TRANSITION, 0),
+     "ossl_statem_client13_write_transition"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_CLIENT_CONSTRUCT_MESSAGE, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_CLIENT_POST_PROCESS_MESSAGE, 0),
+     "ossl_statem_client_post_process_message"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_CLIENT_PROCESS_MESSAGE, 0),
+     "ossl_statem_client_process_message"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_CLIENT_READ_TRANSITION, 0),
+     "ossl_statem_client_read_transition"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_CLIENT_WRITE_TRANSITION, 0),
+     "ossl_statem_client_write_transition"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER13_READ_TRANSITION, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER13_WRITE_TRANSITION, 0),
+     "ossl_statem_server13_write_transition"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_CONSTRUCT_MESSAGE, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_POST_PROCESS_MESSAGE, 0),
+     "ossl_statem_server_post_process_message"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_POST_WORK, 0),
+     "ossl_statem_server_post_work"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_PROCESS_MESSAGE, 0),
+     "ossl_statem_server_process_message"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION, 0),
+     "ossl_statem_server_read_transition"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_WRITE_TRANSITION, 0),
+     "ossl_statem_server_write_transition"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_PARSE_CA_NAMES, 0), "parse_ca_names"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_PITEM_NEW, 0), "pitem_new"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_PQUEUE_NEW, 0), "pqueue_new"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_PROCESS_KEY_SHARE_EXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_READ_STATE_MACHINE, 0), "read_state_machine"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SET_CLIENT_CIPHERSUITE, 0),
+     "set_client_ciphersuite"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SRP_GENERATE_CLIENT_MASTER_SECRET, 0),
+     "srp_generate_client_master_secret"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SRP_GENERATE_SERVER_MASTER_SECRET, 0),
+     "srp_generate_server_master_secret"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SRP_VERIFY_SERVER_PARAM, 0),
+     "srp_verify_server_param"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_CHANGE_CIPHER_STATE, 0),
+     "ssl3_change_cipher_state"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, 0),
+     "ssl3_check_cert_and_algorithm"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_CTRL, 0), "ssl3_ctrl"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_CTX_CTRL, 0), "ssl3_ctx_ctrl"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_DIGEST_CACHED_RECORDS, 0),
+     "ssl3_digest_cached_records"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, 0),
+     "ssl3_do_change_cipher_spec"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_ENC, 0), "ssl3_enc"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_FINAL_FINISH_MAC, 0),
+     "ssl3_final_finish_mac"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_FINISH_MAC, 0), "ssl3_finish_mac"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_GENERATE_KEY_BLOCK, 0),
+     "ssl3_generate_key_block"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_GENERATE_MASTER_SECRET, 0),
+     "ssl3_generate_master_secret"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_GET_RECORD, 0), "ssl3_get_record"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_INIT_FINISHED_MAC, 0),
+     "ssl3_init_finished_mac"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_OUTPUT_CERT_CHAIN, 0),
+     "ssl3_output_cert_chain"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_READ_BYTES, 0), "ssl3_read_bytes"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_READ_N, 0), "ssl3_read_n"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_SETUP_KEY_BLOCK, 0),
+     "ssl3_setup_key_block"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_SETUP_READ_BUFFER, 0),
+     "ssl3_setup_read_buffer"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_SETUP_WRITE_BUFFER, 0),
+     "ssl3_setup_write_buffer"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_WRITE_BYTES, 0), "ssl3_write_bytes"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_WRITE_PENDING, 0), "ssl3_write_pending"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_ADD_CERT_CHAIN, 0), "ssl_add_cert_chain"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_ADD_CERT_TO_BUF, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_ADD_CERT_TO_WPACKET, 0),
+     "ssl_add_cert_to_wpacket"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, 0),
+     "SSL_add_dir_cert_subjects_to_stack"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK, 0),
+     "SSL_add_file_cert_subjects_to_stack"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_ADD_SERVERHELLO_USE_SRTP_EXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_BAD_METHOD, 0), "ssl_bad_method"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_BUILD_CERT_CHAIN, 0),
+     "ssl_build_cert_chain"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_BYTES_TO_CIPHER_LIST, 0),
+     "SSL_bytes_to_cipher_list"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CACHE_CIPHERLIST, 0),
+     "ssl_cache_cipherlist"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CERT_ADD0_CHAIN_CERT, 0),
+     "ssl_cert_add0_chain_cert"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CERT_DUP, 0), "ssl_cert_dup"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CERT_NEW, 0), "ssl_cert_new"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CERT_SET0_CHAIN, 0),
+     "ssl_cert_set0_chain"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CHECK_PRIVATE_KEY, 0),
+     "SSL_check_private_key"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CHECK_SRP_EXT_CLIENTHELLO, 0),
+     "ssl_check_srp_ext_ClientHello"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, 0),
+     "ssl_check_srvr_ecc_cert_and_alg"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CHOOSE_CLIENT_VERSION, 0),
+     "ssl_choose_client_version"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CIPHER_DESCRIPTION, 0),
+     "SSL_CIPHER_description"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CIPHER_LIST_TO_BYTES, 0),
+     "ssl_cipher_list_to_bytes"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CIPHER_PROCESS_RULESTR, 0),
+     "ssl_cipher_process_rulestr"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CIPHER_STRENGTH_SORT, 0),
+     "ssl_cipher_strength_sort"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CLEAR, 0), "SSL_clear"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CLIENT_HELLO_GET1_EXTENSIONS_PRESENT, 0),
+     "SSL_client_hello_get1_extensions_present"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD, 0),
+     "SSL_COMP_add_compression_method"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CONF_CMD, 0), "SSL_CONF_cmd"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CREATE_CIPHER_LIST, 0),
+     "ssl_create_cipher_list"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTRL, 0), "SSL_ctrl"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_CHECK_PRIVATE_KEY, 0),
+     "SSL_CTX_check_private_key"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_ENABLE_CT, 0), "SSL_CTX_enable_ct"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_MAKE_PROFILES, 0),
+     "ssl_ctx_make_profiles"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_NEW, 0), "SSL_CTX_new"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_SET_ALPN_PROTOS, 0),
+     "SSL_CTX_set_alpn_protos"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_SET_CIPHER_LIST, 0),
+     "SSL_CTX_set_cipher_list"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE, 0),
+     "SSL_CTX_set_client_cert_engine"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_SET_CT_VALIDATION_CALLBACK, 0),
+     "SSL_CTX_set_ct_validation_callback"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT, 0),
+     "SSL_CTX_set_session_id_context"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_SET_SSL_VERSION, 0),
+     "SSL_CTX_set_ssl_version"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_SET_TLSEXT_MAX_FRAGMENT_LENGTH, 0),
+     "SSL_CTX_set_tlsext_max_fragment_length"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_CERTIFICATE, 0),
+     "SSL_CTX_use_certificate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1, 0),
+     "SSL_CTX_use_certificate_ASN1"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, 0),
+     "SSL_CTX_use_certificate_file"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_PRIVATEKEY, 0),
+     "SSL_CTX_use_PrivateKey"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1, 0),
+     "SSL_CTX_use_PrivateKey_ASN1"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, 0),
+     "SSL_CTX_use_PrivateKey_file"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT, 0),
+     "SSL_CTX_use_psk_identity_hint"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_RSAPRIVATEKEY, 0),
+     "SSL_CTX_use_RSAPrivateKey"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1, 0),
+     "SSL_CTX_use_RSAPrivateKey_ASN1"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE, 0),
+     "SSL_CTX_use_RSAPrivateKey_file"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_SERVERINFO, 0),
+     "SSL_CTX_use_serverinfo"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_SERVERINFO_EX, 0),
+     "SSL_CTX_use_serverinfo_ex"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_SERVERINFO_FILE, 0),
+     "SSL_CTX_use_serverinfo_file"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_DANE_DUP, 0), "ssl_dane_dup"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_DANE_ENABLE, 0), "SSL_dane_enable"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_DERIVE, 0), "ssl_derive"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_DO_CONFIG, 0), "ssl_do_config"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_DO_HANDSHAKE, 0), "SSL_do_handshake"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_DUP_CA_LIST, 0), "SSL_dup_CA_list"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_ENABLE_CT, 0), "SSL_enable_ct"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_GENERATE_PKEY_GROUP, 0),
+     "ssl_generate_pkey_group"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_GENERATE_SESSION_ID, 0),
+     "ssl_generate_session_id"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_GET_NEW_SESSION, 0),
+     "ssl_get_new_session"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_GET_PREV_SESSION, 0),
+     "ssl_get_prev_session"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_GET_SERVER_CERT_INDEX, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_GET_SIGN_PKEY, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_HANDSHAKE_HASH, 0), "ssl_handshake_hash"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_INIT_WBIO_BUFFER, 0),
+     "ssl_init_wbio_buffer"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_KEY_UPDATE, 0), "SSL_key_update"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_LOAD_CLIENT_CA_FILE, 0),
+     "SSL_load_client_CA_file"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_LOG_MASTER_SECRET, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_LOG_RSA_CLIENT_KEY_EXCHANGE, 0),
+     "ssl_log_rsa_client_key_exchange"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_MODULE_INIT, 0), "ssl_module_init"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_NEW, 0), "SSL_new"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_NEXT_PROTO_VALIDATE, 0),
+     "ssl_next_proto_validate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PEEK, 0), "SSL_peek"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PEEK_EX, 0), "SSL_peek_ex"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PEEK_INTERNAL, 0), "ssl_peek_internal"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_READ, 0), "SSL_read"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_READ_EARLY_DATA, 0),
+     "SSL_read_early_data"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_READ_EX, 0), "SSL_read_ex"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_READ_INTERNAL, 0), "ssl_read_internal"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_RENEGOTIATE, 0), "SSL_renegotiate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_RENEGOTIATE_ABBREVIATED, 0),
+     "SSL_renegotiate_abbreviated"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_DUP, 0), "ssl_session_dup"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_NEW, 0), "SSL_SESSION_new"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_PRINT_FP, 0),
+     "SSL_SESSION_print_fp"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_SET1_ID, 0),
+     "SSL_SESSION_set1_id"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_SET1_ID_CONTEXT, 0),
+     "SSL_SESSION_set1_id_context"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_ALPN_PROTOS, 0),
+     "SSL_set_alpn_protos"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_CERT, 0), "ssl_set_cert"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_CERT_AND_KEY, 0),
+     "ssl_set_cert_and_key"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_CIPHER_LIST, 0),
+     "SSL_set_cipher_list"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_CT_VALIDATION_CALLBACK, 0),
+     "SSL_set_ct_validation_callback"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_FD, 0), "SSL_set_fd"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_PKEY, 0), "ssl_set_pkey"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_RFD, 0), "SSL_set_rfd"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_SESSION, 0), "SSL_set_session"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_SESSION_ID_CONTEXT, 0),
+     "SSL_set_session_id_context"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_SESSION_TICKET_EXT, 0),
+     "SSL_set_session_ticket_ext"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_TLSEXT_MAX_FRAGMENT_LENGTH, 0),
+     "SSL_set_tlsext_max_fragment_length"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_WFD, 0), "SSL_set_wfd"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SHUTDOWN, 0), "SSL_shutdown"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SRP_CTX_INIT, 0), "SSL_SRP_CTX_init"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_START_ASYNC_JOB, 0),
+     "ssl_start_async_job"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_UNDEFINED_FUNCTION, 0),
+     "ssl_undefined_function"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_UNDEFINED_VOID_FUNCTION, 0),
+     "ssl_undefined_void_function"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_CERTIFICATE, 0),
+     "SSL_use_certificate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_CERTIFICATE_ASN1, 0),
+     "SSL_use_certificate_ASN1"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_CERTIFICATE_FILE, 0),
+     "SSL_use_certificate_file"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_PRIVATEKEY, 0), "SSL_use_PrivateKey"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_PRIVATEKEY_ASN1, 0),
+     "SSL_use_PrivateKey_ASN1"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_PRIVATEKEY_FILE, 0),
+     "SSL_use_PrivateKey_file"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_PSK_IDENTITY_HINT, 0),
+     "SSL_use_psk_identity_hint"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_RSAPRIVATEKEY, 0),
+     "SSL_use_RSAPrivateKey"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1, 0),
+     "SSL_use_RSAPrivateKey_ASN1"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_RSAPRIVATEKEY_FILE, 0),
+     "SSL_use_RSAPrivateKey_file"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_VALIDATE_CT, 0), "ssl_validate_ct"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_VERIFY_CERT_CHAIN, 0),
+     "ssl_verify_cert_chain"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, 0),
+     "SSL_verify_client_post_handshake"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE, 0), "SSL_write"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE_EARLY_DATA, 0),
+     "SSL_write_early_data"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE_EARLY_FINISH, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE_EX, 0), "SSL_write_ex"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE_INTERNAL, 0), "ssl_write_internal"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_STATE_MACHINE, 0), "state_machine"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS12_CHECK_PEER_SIGALG, 0),
+     "tls12_check_peer_sigalg"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS12_COPY_SIGALGS, 0), "tls12_copy_sigalgs"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS13_CHANGE_CIPHER_STATE, 0),
+     "tls13_change_cipher_state"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS13_ENC, 0), "tls13_enc"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS13_FINAL_FINISH_MAC, 0),
+     "tls13_final_finish_mac"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS13_GENERATE_SECRET, 0),
+     "tls13_generate_secret"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS13_HKDF_EXPAND, 0), "tls13_hkdf_expand"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS13_RESTORE_HANDSHAKE_DIGEST_FOR_PHA, 0),
+     "tls13_restore_handshake_digest_for_pha"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS13_SAVE_HANDSHAKE_DIGEST_FOR_PHA, 0),
+     "tls13_save_handshake_digest_for_pha"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS13_SETUP_KEY_BLOCK, 0),
+     "tls13_setup_key_block"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_CHANGE_CIPHER_STATE, 0),
+     "tls1_change_cipher_state"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_ENC, 0), "tls1_enc"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_EXPORT_KEYING_MATERIAL, 0),
+     "tls1_export_keying_material"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_GET_CURVELIST, 0), "tls1_get_curvelist"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_PRF, 0), "tls1_PRF"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_SAVE_U16, 0), "tls1_save_u16"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_SETUP_KEY_BLOCK, 0),
+     "tls1_setup_key_block"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_SET_GROUPS, 0), "tls1_set_groups"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_SET_RAW_SIGALGS, 0),
+     "tls1_set_raw_sigalgs"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_SET_SERVER_SIGALGS, 0),
+     "tls1_set_server_sigalgs"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_SET_SHARED_SIGALGS, 0),
+     "tls1_set_shared_sigalgs"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_SET_SIGALGS, 0), "tls1_set_sigalgs"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CHOOSE_SIGALG, 0), "tls_choose_sigalg"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK, 0),
+     "tls_client_key_exchange_post_work"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_COLLECT_EXTENSIONS, 0),
+     "tls_collect_extensions"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CERTIFICATE_AUTHORITIES, 0),
+     "tls_construct_certificate_authorities"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST, 0),
+     "tls_construct_certificate_request"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CERT_STATUS, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CERT_STATUS_BODY, 0),
+     "tls_construct_cert_status_body"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CERT_VERIFY, 0),
+     "tls_construct_cert_verify"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CHANGE_CIPHER_SPEC, 0),
+     "tls_construct_change_cipher_spec"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CKE_DHE, 0),
+     "tls_construct_cke_dhe"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CKE_ECDHE, 0),
+     "tls_construct_cke_ecdhe"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CKE_GOST, 0),
+     "tls_construct_cke_gost"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, 0),
+     "tls_construct_cke_psk_preamble"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CKE_RSA, 0),
+     "tls_construct_cke_rsa"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CKE_SRP, 0),
+     "tls_construct_cke_srp"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE, 0),
+     "tls_construct_client_certificate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, 0),
+     "tls_construct_client_hello"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, 0),
+     "tls_construct_client_key_exchange"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_ALPN, 0),
+     "tls_construct_ctos_alpn"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_CERTIFICATE, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_COOKIE, 0),
+     "tls_construct_ctos_cookie"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA, 0),
+     "tls_construct_ctos_early_data"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_EC_PT_FORMATS, 0),
+     "tls_construct_ctos_ec_pt_formats"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_EMS, 0),
+     "tls_construct_ctos_ems"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_ETM, 0),
+     "tls_construct_ctos_etm"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_HELLO, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_KEY_EXCHANGE, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, 0),
+     "tls_construct_ctos_key_share"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_MAXFRAGMENTLEN, 0),
+     "tls_construct_ctos_maxfragmentlen"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_NPN, 0),
+     "tls_construct_ctos_npn"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_PADDING, 0),
+     "tls_construct_ctos_padding"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_POST_HANDSHAKE_AUTH, 0),
+     "tls_construct_ctos_post_handshake_auth"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_PSK, 0),
+     "tls_construct_ctos_psk"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES, 0),
+     "tls_construct_ctos_psk_kex_modes"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE, 0),
+     "tls_construct_ctos_renegotiate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_SCT, 0),
+     "tls_construct_ctos_sct"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME, 0),
+     "tls_construct_ctos_server_name"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_SESSION_TICKET, 0),
+     "tls_construct_ctos_session_ticket"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_SIG_ALGS, 0),
+     "tls_construct_ctos_sig_algs"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_SRP, 0),
+     "tls_construct_ctos_srp"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST, 0),
+     "tls_construct_ctos_status_request"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS, 0),
+     "tls_construct_ctos_supported_groups"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS, 0),
+     "tls_construct_ctos_supported_versions"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_USE_SRTP, 0),
+     "tls_construct_ctos_use_srtp"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_VERIFY, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_ENCRYPTED_EXTENSIONS, 0),
+     "tls_construct_encrypted_extensions"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_END_OF_EARLY_DATA, 0),
+     "tls_construct_end_of_early_data"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_EXTENSIONS, 0),
+     "tls_construct_extensions"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_FINISHED, 0),
+     "tls_construct_finished"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_HELLO_REQUEST, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_HELLO_RETRY_REQUEST, 0),
+     "tls_construct_hello_retry_request"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_KEY_UPDATE, 0),
+     "tls_construct_key_update"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, 0),
+     "tls_construct_new_session_ticket"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_NEXT_PROTO, 0),
+     "tls_construct_next_proto"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE, 0),
+     "tls_construct_server_certificate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_SERVER_HELLO, 0),
+     "tls_construct_server_hello"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, 0),
+     "tls_construct_server_key_exchange"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_ALPN, 0),
+     "tls_construct_stoc_alpn"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_CERTIFICATE, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_COOKIE, 0),
+     "tls_construct_stoc_cookie"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_CRYPTOPRO_BUG, 0),
+     "tls_construct_stoc_cryptopro_bug"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_DONE, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA, 0),
+     "tls_construct_stoc_early_data"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA_INFO, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_EC_PT_FORMATS, 0),
+     "tls_construct_stoc_ec_pt_formats"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_EMS, 0),
+     "tls_construct_stoc_ems"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_ETM, 0),
+     "tls_construct_stoc_etm"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_HELLO, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_KEY_EXCHANGE, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, 0),
+     "tls_construct_stoc_key_share"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_MAXFRAGMENTLEN, 0),
+     "tls_construct_stoc_maxfragmentlen"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG, 0),
+     "tls_construct_stoc_next_proto_neg"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_PSK, 0),
+     "tls_construct_stoc_psk"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE, 0),
+     "tls_construct_stoc_renegotiate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME, 0),
+     "tls_construct_stoc_server_name"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_SESSION_TICKET, 0),
+     "tls_construct_stoc_session_ticket"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_STATUS_REQUEST, 0),
+     "tls_construct_stoc_status_request"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS, 0),
+     "tls_construct_stoc_supported_groups"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_VERSIONS, 0),
+     "tls_construct_stoc_supported_versions"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_USE_SRTP, 0),
+     "tls_construct_stoc_use_srtp"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO, 0),
+     "tls_early_post_process_client_hello"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_FINISH_HANDSHAKE, 0),
+     "tls_finish_handshake"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_GET_MESSAGE_BODY, 0),
+     "tls_get_message_body"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_GET_MESSAGE_HEADER, 0),
+     "tls_get_message_header"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_HANDLE_ALPN, 0), "tls_handle_alpn"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_HANDLE_STATUS_REQUEST, 0),
+     "tls_handle_status_request"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CERTIFICATE_AUTHORITIES, 0),
+     "tls_parse_certificate_authorities"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CLIENTHELLO_TLSEXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_ALPN, 0),
+     "tls_parse_ctos_alpn"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_COOKIE, 0),
+     "tls_parse_ctos_cookie"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_EARLY_DATA, 0),
+     "tls_parse_ctos_early_data"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_EC_PT_FORMATS, 0),
+     "tls_parse_ctos_ec_pt_formats"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_EMS, 0), "tls_parse_ctos_ems"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_KEY_SHARE, 0),
+     "tls_parse_ctos_key_share"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_MAXFRAGMENTLEN, 0),
+     "tls_parse_ctos_maxfragmentlen"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_POST_HANDSHAKE_AUTH, 0),
+     "tls_parse_ctos_post_handshake_auth"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_PSK, 0), "tls_parse_ctos_psk"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_PSK_KEX_MODES, 0),
+     "tls_parse_ctos_psk_kex_modes"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_RENEGOTIATE, 0),
+     "tls_parse_ctos_renegotiate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_SERVER_NAME, 0),
+     "tls_parse_ctos_server_name"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_SESSION_TICKET, 0),
+     "tls_parse_ctos_session_ticket"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_SIG_ALGS, 0),
+     "tls_parse_ctos_sig_algs"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_SIG_ALGS_CERT, 0),
+     "tls_parse_ctos_sig_algs_cert"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_SRP, 0), "tls_parse_ctos_srp"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_STATUS_REQUEST, 0),
+     "tls_parse_ctos_status_request"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_SUPPORTED_GROUPS, 0),
+     "tls_parse_ctos_supported_groups"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_USE_SRTP, 0),
+     "tls_parse_ctos_use_srtp"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_ALPN, 0),
+     "tls_parse_stoc_alpn"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_COOKIE, 0),
+     "tls_parse_stoc_cookie"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_EARLY_DATA, 0),
+     "tls_parse_stoc_early_data"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_EARLY_DATA_INFO, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_EC_PT_FORMATS, 0),
+     "tls_parse_stoc_ec_pt_formats"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_KEY_SHARE, 0),
+     "tls_parse_stoc_key_share"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_MAXFRAGMENTLEN, 0),
+     "tls_parse_stoc_maxfragmentlen"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_NPN, 0), "tls_parse_stoc_npn"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_PSK, 0), "tls_parse_stoc_psk"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_RENEGOTIATE, 0),
+     "tls_parse_stoc_renegotiate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_SCT, 0), "tls_parse_stoc_sct"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_SERVER_NAME, 0),
+     "tls_parse_stoc_server_name"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_SESSION_TICKET, 0),
+     "tls_parse_stoc_session_ticket"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_STATUS_REQUEST, 0),
+     "tls_parse_stoc_status_request"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_SUPPORTED_VERSIONS, 0),
+     "tls_parse_stoc_supported_versions"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_USE_SRTP, 0),
+     "tls_parse_stoc_use_srtp"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, 0),
+     "tls_post_process_client_hello"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE, 0),
+     "tls_post_process_client_key_exchange"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE, 0),
+     "tls_prepare_client_certificate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_AS_HELLO_RETRY_REQUEST, 0),
+     "tls_process_as_hello_retry_request"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, 0),
+     "tls_process_certificate_request"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CERT_STATUS, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CERT_STATUS_BODY, 0),
+     "tls_process_cert_status_body"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CERT_VERIFY, 0),
+     "tls_process_cert_verify"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC, 0),
+     "tls_process_change_cipher_spec"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CKE_DHE, 0),
+     "tls_process_cke_dhe"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CKE_ECDHE, 0),
+     "tls_process_cke_ecdhe"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CKE_GOST, 0),
+     "tls_process_cke_gost"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE, 0),
+     "tls_process_cke_psk_preamble"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CKE_RSA, 0),
+     "tls_process_cke_rsa"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CKE_SRP, 0),
+     "tls_process_cke_srp"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, 0),
+     "tls_process_client_certificate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CLIENT_HELLO, 0),
+     "tls_process_client_hello"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, 0),
+     "tls_process_client_key_exchange"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS, 0),
+     "tls_process_encrypted_extensions"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_END_OF_EARLY_DATA, 0),
+     "tls_process_end_of_early_data"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_FINISHED, 0),
+     "tls_process_finished"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_HELLO_REQ, 0),
+     "tls_process_hello_req"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, 0),
+     "tls_process_hello_retry_request"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT, 0),
+     "tls_process_initial_server_flight"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_KEY_EXCHANGE, 0),
+     "tls_process_key_exchange"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_KEY_UPDATE, 0),
+     "tls_process_key_update"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, 0),
+     "tls_process_new_session_ticket"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_NEXT_PROTO, 0),
+     "tls_process_next_proto"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, 0),
+     "tls_process_server_certificate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_SERVER_DONE, 0),
+     "tls_process_server_done"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_SERVER_HELLO, 0),
+     "tls_process_server_hello"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_SKE_DHE, 0),
+     "tls_process_ske_dhe"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_SKE_ECDHE, 0),
+     "tls_process_ske_ecdhe"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE, 0),
+     "tls_process_ske_psk_preamble"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_SKE_SRP, 0),
+     "tls_process_ske_srp"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PSK_DO_BINDER, 0), "tls_psk_do_binder"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_SCAN_CLIENTHELLO_TLSEXT, 0), ""},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_SETUP_HANDSHAKE, 0),
+     "tls_setup_handshake"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_USE_CERTIFICATE_CHAIN_FILE, 0),
+     "use_certificate_chain_file"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_WPACKET_INTERN_INIT_LEN, 0),
+     "wpacket_intern_init_len"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_WPACKET_START_SUB_PACKET_LEN__, 0),
+     "WPACKET_start_sub_packet_len__"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_WRITE_STATE_MACHINE, 0),
+     "write_state_machine"},
+    {0, NULL}
+};
+
+static const ERR_STRING_DATA SSL_str_reasons[] = {
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY),
+    "application data after close notify"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_APP_DATA_IN_HANDSHAKE),
+    "app data in handshake"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT),
+    "attempt to reuse session in different context"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE),
+    "at least TLS 1.0 needed in FIPS mode"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE),
+    "at least (D)TLS 1.2 needed in Suite B mode"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CHANGE_CIPHER_SPEC),
+    "bad change cipher spec"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CIPHER), "bad cipher"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA), "bad data"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK),
+    "bad data returned by callback"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DECOMPRESSION), "bad decompression"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DH_VALUE), "bad dh value"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DIGEST_LENGTH), "bad digest length"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_EARLY_DATA), "bad early data"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ECC_CERT), "bad ecc cert"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ECPOINT), "bad ecpoint"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_EXTENSION), "bad extension"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HANDSHAKE_LENGTH),
+    "bad handshake length"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HANDSHAKE_STATE),
+    "bad handshake state"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HELLO_REQUEST), "bad hello request"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HRR_VERSION), "bad hrr version"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_KEY_SHARE), "bad key share"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_KEY_UPDATE), "bad key update"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_LEGACY_VERSION), "bad legacy version"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_LENGTH), "bad length"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PACKET), "bad packet"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PACKET_LENGTH), "bad packet length"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PROTOCOL_VERSION_NUMBER),
+    "bad protocol version number"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PSK), "bad psk"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PSK_IDENTITY), "bad psk identity"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RECORD_TYPE), "bad record type"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RSA_ENCRYPT), "bad rsa encrypt"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SIGNATURE), "bad signature"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRP_A_LENGTH), "bad srp a length"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRP_PARAMETERS), "bad srp parameters"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRTP_MKI_VALUE), "bad srtp mki value"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST),
+    "bad srtp protection profile list"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SSL_FILETYPE), "bad ssl filetype"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_VALUE), "bad value"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_WRITE_RETRY), "bad write retry"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BINDER_DOES_NOT_VERIFY),
+    "binder does not verify"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BIO_NOT_SET), "bio not set"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG),
+    "block cipher pad is wrong"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BN_LIB), "bn lib"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CALLBACK_FAILED), "callback failed"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CANNOT_CHANGE_CIPHER),
+    "cannot change cipher"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CA_DN_LENGTH_MISMATCH),
+    "ca dn length mismatch"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CA_KEY_TOO_SMALL), "ca key too small"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CA_MD_TOO_WEAK), "ca md too weak"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CCS_RECEIVED_EARLY), "ccs received early"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERTIFICATE_VERIFY_FAILED),
+    "certificate verify failed"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERT_CB_ERROR), "cert cb error"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERT_LENGTH_MISMATCH),
+    "cert length mismatch"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED),
+    "ciphersuite digest has changed"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHER_CODE_WRONG_LENGTH),
+    "cipher code wrong length"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHER_OR_HASH_UNAVAILABLE),
+    "cipher or hash unavailable"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CLIENTHELLO_TLSEXT), "clienthello tlsext"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSED_LENGTH_TOO_LONG),
+    "compressed length too long"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_DISABLED),
+    "compression disabled"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_FAILURE),
+    "compression failure"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE),
+    "compression id not within private range"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_LIBRARY_ERROR),
+    "compression library error"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CONNECTION_TYPE_NOT_SET),
+    "connection type not set"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CONTEXT_NOT_DANE_ENABLED),
+    "context not dane enabled"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COOKIE_GEN_CALLBACK_FAILURE),
+    "cookie gen callback failure"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COOKIE_MISMATCH), "cookie mismatch"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED),
+    "custom ext handler already installed"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_ALREADY_ENABLED),
+    "dane already enabled"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL),
+    "dane cannot override mtype full"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_NOT_ENABLED), "dane not enabled"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_CERTIFICATE),
+    "dane tlsa bad certificate"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE),
+    "dane tlsa bad certificate usage"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_DATA_LENGTH),
+    "dane tlsa bad data length"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH),
+    "dane tlsa bad digest length"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_MATCHING_TYPE),
+    "dane tlsa bad matching type"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_PUBLIC_KEY),
+    "dane tlsa bad public key"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_SELECTOR),
+    "dane tlsa bad selector"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_NULL_DATA),
+    "dane tlsa null data"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED),
+    "data between ccs and finished"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DATA_LENGTH_TOO_LONG),
+    "data length too long"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DECRYPTION_FAILED), "decryption failed"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC),
+    "decryption failed or bad record mac"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DH_KEY_TOO_SMALL), "dh key too small"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG),
+    "dh public value length is wrong"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DIGEST_CHECK_FAILED),
+    "digest check failed"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DTLS_MESSAGE_TOO_BIG),
+    "dtls message too big"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DUPLICATE_COMPRESSION_ID),
+    "duplicate compression id"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECC_CERT_NOT_FOR_SIGNING),
+    "ecc cert not for signing"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE),
+    "ecdh required for suiteb mode"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EE_KEY_TOO_SMALL), "ee key too small"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST),
+    "empty srtp protection profile list"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ENCRYPTED_LENGTH_TOO_LONG),
+    "encrypted length too long"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST),
+    "error in received cipher list"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN),
+    "error setting tlsa base domain"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE),
+    "exceeds max fragment size"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXCESSIVE_MESSAGE_SIZE),
+    "excessive message size"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXTENSION_NOT_RECEIVED),
+    "extension not received"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXTRA_DATA_IN_MESSAGE),
+    "extra data in message"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXT_LENGTH_MISMATCH),
+    "ext length mismatch"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_FAILED_TO_INIT_ASYNC),
+    "failed to init async"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_FRAGMENTED_CLIENT_HELLO),
+    "fragmented client hello"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOT_A_FIN_BEFORE_A_CCS),
+    "got a fin before a ccs"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HTTPS_PROXY_REQUEST),
+    "https proxy request"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HTTP_REQUEST), "http request"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ILLEGAL_POINT_COMPRESSION),
+    "illegal point compression"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ILLEGAL_SUITEB_DIGEST),
+    "illegal Suite B digest"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INAPPROPRIATE_FALLBACK),
+    "inappropriate fallback"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_COMPRESSION),
+    "inconsistent compression"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_EARLY_DATA_ALPN),
+    "inconsistent early data alpn"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_EARLY_DATA_SNI),
+    "inconsistent early data sni"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_EXTMS), "inconsistent extms"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INSUFFICIENT_SECURITY),
+    "insufficient security"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_ALERT), "invalid alert"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CCS_MESSAGE),
+    "invalid ccs message"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CERTIFICATE_OR_ALG),
+    "invalid certificate or alg"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_COMMAND), "invalid command"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_COMPRESSION_ALGORITHM),
+    "invalid compression algorithm"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CONFIG), "invalid config"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CONFIGURATION_NAME),
+    "invalid configuration name"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CONTEXT), "invalid context"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CT_VALIDATION_TYPE),
+    "invalid ct validation type"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_KEY_UPDATE_TYPE),
+    "invalid key update type"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_MAX_EARLY_DATA),
+    "invalid max early data"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_NULL_CMD_NAME),
+    "invalid null cmd name"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SEQUENCE_NUMBER),
+    "invalid sequence number"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SERVERINFO_DATA),
+    "invalid serverinfo data"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SESSION_ID), "invalid session id"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SRP_USERNAME),
+    "invalid srp username"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_STATUS_RESPONSE),
+    "invalid status response"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_TICKET_KEYS_LENGTH),
+    "invalid ticket keys length"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LENGTH_MISMATCH), "length mismatch"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LENGTH_TOO_LONG), "length too long"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LENGTH_TOO_SHORT), "length too short"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LIBRARY_BUG), "library bug"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LIBRARY_HAS_NO_CIPHERS),
+    "library has no ciphers"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_DSA_SIGNING_CERT),
+    "missing dsa signing cert"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_ECDSA_SIGNING_CERT),
+    "missing ecdsa signing cert"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_FATAL), "missing fatal"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_PARAMETERS), "missing parameters"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_PSK_KEX_MODES_EXTENSION),
+    "missing psk kex modes extension"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_CERTIFICATE),
+    "missing rsa certificate"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_ENCRYPTING_CERT),
+    "missing rsa encrypting cert"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_SIGNING_CERT),
+    "missing rsa signing cert"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_SIGALGS_EXTENSION),
+    "missing sigalgs extension"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_SIGNING_CERT),
+    "missing signing cert"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_SRP_PARAM),
+    "can't find SRP server param"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_SUPPORTED_GROUPS_EXTENSION),
+    "missing supported groups extension"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_DH_KEY), "missing tmp dh key"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_ECDH_KEY),
+    "missing tmp ecdh key"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA),
+    "mixed handshake and non handshake data"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_ON_RECORD_BOUNDARY),
+    "not on record boundary"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_REPLACING_CERTIFICATE),
+    "not replacing certificate"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_SERVER), "not server"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_APPLICATION_PROTOCOL),
+    "no application protocol"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATES_RETURNED),
+    "no certificates returned"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATE_ASSIGNED),
+    "no certificate assigned"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATE_SET), "no certificate set"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CHANGE_FOLLOWING_HRR),
+    "no change following hrr"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHERS_AVAILABLE),
+    "no ciphers available"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHERS_SPECIFIED),
+    "no ciphers specified"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHER_MATCH), "no cipher match"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CLIENT_CERT_METHOD),
+    "no client cert method"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_COMPRESSION_SPECIFIED),
+    "no compression specified"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_COOKIE_CALLBACK_SET),
+    "no cookie callback set"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER),
+    "Peer haven't sent GOST certificate, required for selected ciphersuite"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_METHOD_SPECIFIED),
+    "no method specified"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PEM_EXTENSIONS), "no pem extensions"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PRIVATE_KEY_ASSIGNED),
+    "no private key assigned"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PROTOCOLS_AVAILABLE),
+    "no protocols available"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_RENEGOTIATION), "no renegotiation"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_REQUIRED_DIGEST), "no required digest"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SHARED_CIPHER), "no shared cipher"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SHARED_GROUPS), "no shared groups"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS),
+    "no shared signature algorithms"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SRTP_PROFILES), "no srtp profiles"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SUITABLE_KEY_SHARE),
+    "no suitable key share"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM),
+    "no suitable signature algorithm"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_VALID_SCTS), "no valid scts"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_VERIFY_COOKIE_CALLBACK),
+    "no verify cookie callback"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NULL_SSL_CTX), "null ssl ctx"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NULL_SSL_METHOD_PASSED),
+    "null ssl method passed"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OCSP_CALLBACK_FAILURE),
+    "ocsp callback failure"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),
+    "old session cipher not returned"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED),
+    "old session compression algorithm not returned"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OVERFLOW_ERROR), "overflow error"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PACKET_LENGTH_TOO_LONG),
+    "packet length too long"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PARSE_TLSEXT), "parse tlsext"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PATH_TOO_LONG), "path too long"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE),
+    "peer did not return a certificate"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEM_NAME_BAD_PREFIX),
+    "pem name bad prefix"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEM_NAME_TOO_SHORT), "pem name too short"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PIPELINE_FAILURE), "pipeline failure"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR),
+    "post handshake auth encoding err"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PRIVATE_KEY_MISMATCH),
+    "private key mismatch"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PROTOCOL_IS_SHUTDOWN),
+    "protocol is shutdown"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_IDENTITY_NOT_FOUND),
+    "psk identity not found"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_NO_CLIENT_CB), "psk no client cb"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_NO_SERVER_CB), "psk no server cb"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_READ_BIO_NOT_SET), "read bio not set"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_READ_TIMEOUT_EXPIRED),
+    "read timeout expired"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_LENGTH_MISMATCH),
+    "record length mismatch"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_TOO_SMALL), "record too small"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RENEGOTIATE_EXT_TOO_LONG),
+    "renegotiate ext too long"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RENEGOTIATION_ENCODING_ERR),
+    "renegotiation encoding err"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RENEGOTIATION_MISMATCH),
+    "renegotiation mismatch"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUEST_PENDING), "request pending"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUEST_SENT), "request sent"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUIRED_CIPHER_MISSING),
+    "required cipher missing"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING),
+    "required compression algorithm missing"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING),
+    "scsv received when renegotiating"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SCT_VERIFICATION_FAILED),
+    "sct verification failed"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SERVERHELLO_TLSEXT), "serverhello tlsext"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED),
+    "session id context uninitialized"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHUTDOWN_WHILE_IN_INIT),
+    "shutdown while in init"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SIGNATURE_ALGORITHMS_ERROR),
+    "signature algorithms error"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE),
+    "signature for non signing certificate"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRP_A_CALC), "error with the srp params"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES),
+    "srtp could not allocate profiles"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG),
+    "srtp protection profile list too long"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE),
+    "srtp unknown protection profile"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH),
+    "ssl3 ext invalid max fragment length"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_EXT_INVALID_SERVERNAME),
+    "ssl3 ext invalid servername"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE),
+    "ssl3 ext invalid servername type"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_SESSION_ID_TOO_LONG),
+    "ssl3 session id too long"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_BAD_CERTIFICATE),
+    "sslv3 alert bad certificate"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_BAD_RECORD_MAC),
+    "sslv3 alert bad record mac"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED),
+    "sslv3 alert certificate expired"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED),
+    "sslv3 alert certificate revoked"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN),
+    "sslv3 alert certificate unknown"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE),
+    "sslv3 alert decompression failure"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE),
+    "sslv3 alert handshake failure"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER),
+    "sslv3 alert illegal parameter"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_NO_CERTIFICATE),
+    "sslv3 alert no certificate"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE),
+    "sslv3 alert unexpected message"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE),
+    "sslv3 alert unsupported certificate"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_COMMAND_SECTION_EMPTY),
+    "ssl command section empty"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_COMMAND_SECTION_NOT_FOUND),
+    "ssl command section not found"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION),
+    "ssl ctx has no default ssl version"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_HANDSHAKE_FAILURE),
+    "ssl handshake failure"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS),
+    "ssl library has no ciphers"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_NEGATIVE_LENGTH),
+    "ssl negative length"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SECTION_EMPTY), "ssl section empty"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SECTION_NOT_FOUND),
+    "ssl section not found"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED),
+    "ssl session id callback failed"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_CONFLICT),
+    "ssl session id conflict"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG),
+    "ssl session id context too long"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH),
+    "ssl session id has bad length"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_TOO_LONG),
+    "ssl session id too long"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_VERSION_MISMATCH),
+    "ssl session version mismatch"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_STILL_IN_INIT), "still in init"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED),
+    "tlsv13 alert certificate required"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV13_ALERT_MISSING_EXTENSION),
+    "tlsv13 alert missing extension"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_ACCESS_DENIED),
+    "tlsv1 alert access denied"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECODE_ERROR),
+    "tlsv1 alert decode error"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECRYPTION_FAILED),
+    "tlsv1 alert decryption failed"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECRYPT_ERROR),
+    "tlsv1 alert decrypt error"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION),
+    "tlsv1 alert export restriction"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK),
+    "tlsv1 alert inappropriate fallback"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY),
+    "tlsv1 alert insufficient security"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INTERNAL_ERROR),
+    "tlsv1 alert internal error"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_NO_RENEGOTIATION),
+    "tlsv1 alert no renegotiation"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_PROTOCOL_VERSION),
+    "tlsv1 alert protocol version"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_RECORD_OVERFLOW),
+    "tlsv1 alert record overflow"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_UNKNOWN_CA),
+    "tlsv1 alert unknown ca"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_USER_CANCELLED),
+    "tlsv1 alert user cancelled"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE),
+    "tlsv1 bad certificate hash value"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE),
+    "tlsv1 bad certificate status response"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE),
+    "tlsv1 certificate unobtainable"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_UNRECOGNIZED_NAME),
+    "tlsv1 unrecognized name"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_UNSUPPORTED_EXTENSION),
+    "tlsv1 unsupported extension"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT),
+    "peer does not accept heartbeats"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_HEARTBEAT_PENDING),
+    "heartbeat request already pending"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL),
+    "tls illegal exporter label"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST),
+    "tls invalid ecpointformat list"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TOO_MANY_KEY_UPDATES),
+    "too many key updates"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TOO_MANY_WARN_ALERTS),
+    "too many warn alerts"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TOO_MUCH_EARLY_DATA),
+    "too much early data"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS),
+    "unable to find ecdh parameters"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS),
+    "unable to find public key parameters"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES),
+    "unable to load ssl3 md5 routines"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES),
+    "unable to load ssl3 sha1 routines"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_CCS_MESSAGE),
+    "unexpected ccs message"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_END_OF_EARLY_DATA),
+    "unexpected end of early data"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_MESSAGE), "unexpected message"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_RECORD), "unexpected record"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNINITIALIZED), "uninitialized"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_ALERT_TYPE), "unknown alert type"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CERTIFICATE_TYPE),
+    "unknown certificate type"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CIPHER_RETURNED),
+    "unknown cipher returned"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CIPHER_TYPE),
+    "unknown cipher type"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CMD_NAME), "unknown cmd name"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_COMMAND), "unknown command"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_DIGEST), "unknown digest"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE),
+    "unknown key exchange type"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_PKEY_TYPE), "unknown pkey type"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_PROTOCOL), "unknown protocol"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_SSL_VERSION),
+    "unknown ssl version"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_STATE), "unknown state"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED),
+    "unsafe legacy renegotiation disabled"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSOLICITED_EXTENSION),
+    "unsolicited extension"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM),
+    "unsupported compression algorithm"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE),
+    "unsupported elliptic curve"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_PROTOCOL),
+    "unsupported protocol"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_SSL_VERSION),
+    "unsupported ssl version"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_STATUS_TYPE),
+    "unsupported status type"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_USE_SRTP_NOT_NEGOTIATED),
+    "use srtp not negotiated"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_VERSION_TOO_HIGH), "version too high"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_VERSION_TOO_LOW), "version too low"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CERTIFICATE_TYPE),
+    "wrong certificate type"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CIPHER_RETURNED),
+    "wrong cipher returned"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CURVE), "wrong curve"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_LENGTH),
+    "wrong signature length"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_SIZE),
+    "wrong signature size"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_TYPE),
+    "wrong signature type"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SSL_VERSION), "wrong ssl version"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_VERSION_NUMBER),
+    "wrong version number"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_X509_LIB), "x509 lib"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS),
+    "x509 verification setup problems"},
+    {0, NULL}
+};
+
+#endif
+
+int ERR_load_SSL_strings(void)
+{
+#ifndef OPENSSL_NO_ERR
+    if (ERR_func_error_string(SSL_str_functs[0].error) == NULL) {
+        ERR_load_strings_const(SSL_str_functs);
+        ERR_load_strings_const(SSL_str_reasons);
+    }
+#endif
+    return 1;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_init.c b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_init.c
new file mode 100644
index 0000000..a5d4548
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_init.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "e_os.h"
+
+#include "internal/err.h"
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include "ssl_local.h"
+#include "internal/thread_once.h"
+
+static int stopped;
+
+static void ssl_library_stop(void);
+
+static CRYPTO_ONCE ssl_base = CRYPTO_ONCE_STATIC_INIT;
+static int ssl_base_inited = 0;
+DEFINE_RUN_ONCE_STATIC(ossl_init_ssl_base)
+{
+#ifdef OPENSSL_INIT_DEBUG
+    fprintf(stderr, "OPENSSL_INIT: ossl_init_ssl_base: "
+            "Adding SSL ciphers and digests\n");
+#endif
+#ifndef OPENSSL_NO_DES
+    EVP_add_cipher(EVP_des_cbc());
+    EVP_add_cipher(EVP_des_ede3_cbc());
+#endif
+#ifndef OPENSSL_NO_IDEA
+    EVP_add_cipher(EVP_idea_cbc());
+#endif
+#ifndef OPENSSL_NO_RC4
+    EVP_add_cipher(EVP_rc4());
+# ifndef OPENSSL_NO_MD5
+    EVP_add_cipher(EVP_rc4_hmac_md5());
+# endif
+#endif
+#ifndef OPENSSL_NO_RC2
+    EVP_add_cipher(EVP_rc2_cbc());
+    /*
+     * Not actually used for SSL/TLS but this makes PKCS#12 work if an
+     * application only calls SSL_library_init().
+     */
+    EVP_add_cipher(EVP_rc2_40_cbc());
+#endif
+    EVP_add_cipher(EVP_aes_128_cbc());
+    EVP_add_cipher(EVP_aes_192_cbc());
+    EVP_add_cipher(EVP_aes_256_cbc());
+    EVP_add_cipher(EVP_aes_128_gcm());
+    EVP_add_cipher(EVP_aes_256_gcm());
+    EVP_add_cipher(EVP_aes_128_ccm());
+    EVP_add_cipher(EVP_aes_256_ccm());
+    EVP_add_cipher(EVP_aes_128_cbc_hmac_sha1());
+    EVP_add_cipher(EVP_aes_256_cbc_hmac_sha1());
+    EVP_add_cipher(EVP_aes_128_cbc_hmac_sha256());
+    EVP_add_cipher(EVP_aes_256_cbc_hmac_sha256());
+#ifndef OPENSSL_NO_ARIA
+    EVP_add_cipher(EVP_aria_128_gcm());
+    EVP_add_cipher(EVP_aria_256_gcm());
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+    EVP_add_cipher(EVP_camellia_128_cbc());
+    EVP_add_cipher(EVP_camellia_256_cbc());
+#endif
+#if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+    EVP_add_cipher(EVP_chacha20_poly1305());
+#endif
+
+#ifndef OPENSSL_NO_SEED
+    EVP_add_cipher(EVP_seed_cbc());
+#endif
+
+#ifndef OPENSSL_NO_MD5
+    EVP_add_digest(EVP_md5());
+    EVP_add_digest_alias(SN_md5, "ssl3-md5");
+    EVP_add_digest(EVP_md5_sha1());
+#endif
+    EVP_add_digest(EVP_sha1()); /* RSA with sha1 */
+    EVP_add_digest_alias(SN_sha1, "ssl3-sha1");
+    EVP_add_digest_alias(SN_sha1WithRSAEncryption, SN_sha1WithRSA);
+    EVP_add_digest(EVP_sha224());
+    EVP_add_digest(EVP_sha256());
+    EVP_add_digest(EVP_sha384());
+    EVP_add_digest(EVP_sha512());
+#ifndef OPENSSL_NO_COMP
+# ifdef OPENSSL_INIT_DEBUG
+    fprintf(stderr, "OPENSSL_INIT: ossl_init_ssl_base: "
+            "SSL_COMP_get_compression_methods()\n");
+# endif
+    /*
+     * This will initialise the built-in compression algorithms. The value
+     * returned is a STACK_OF(SSL_COMP), but that can be discarded safely
+     */
+    SSL_COMP_get_compression_methods();
+#endif
+    /* initialize cipher/digest methods table */
+    if (!ssl_load_ciphers())
+        return 0;
+
+#ifdef OPENSSL_INIT_DEBUG
+    fprintf(stderr, "OPENSSL_INIT: ossl_init_ssl_base: "
+            "SSL_add_ssl_module()\n");
+#endif
+    /*
+     * We ignore an error return here. Not much we can do - but not that bad
+     * either. We can still safely continue.
+     */
+    OPENSSL_atexit(ssl_library_stop);
+    ssl_base_inited = 1;
+    return 1;
+}
+
+static CRYPTO_ONCE ssl_strings = CRYPTO_ONCE_STATIC_INIT;
+
+DEFINE_RUN_ONCE_STATIC(ossl_init_load_ssl_strings)
+{
+    /*
+     * OPENSSL_NO_AUTOERRINIT is provided here to prevent at compile time
+     * pulling in all the error strings during static linking
+     */
+#if !defined(OPENSSL_NO_ERR) && !defined(OPENSSL_NO_AUTOERRINIT)
+# ifdef OPENSSL_INIT_DEBUG
+    fprintf(stderr, "OPENSSL_INIT: ossl_init_load_ssl_strings: "
+            "ERR_load_SSL_strings()\n");
+# endif
+    ERR_load_SSL_strings();
+#endif
+    return 1;
+}
+
+DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_load_ssl_strings,
+                           ossl_init_load_ssl_strings)
+{
+    /* Do nothing in this case */
+    return 1;
+}
+
+static void ssl_library_stop(void)
+{
+    /* Might be explicitly called and also by atexit */
+    if (stopped)
+        return;
+    stopped = 1;
+
+    if (ssl_base_inited) {
+#ifndef OPENSSL_NO_COMP
+# ifdef OPENSSL_INIT_DEBUG
+        fprintf(stderr, "OPENSSL_INIT: ssl_library_stop: "
+                "ssl_comp_free_compression_methods_int()\n");
+# endif
+        ssl_comp_free_compression_methods_int();
+#endif
+    }
+}
+
+/*
+ * If this function is called with a non NULL settings value then it must be
+ * called prior to any threads making calls to any OpenSSL functions,
+ * i.e. passing a non-null settings value is assumed to be single-threaded.
+ */
+int OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS * settings)
+{
+    static int stoperrset = 0;
+
+    if (stopped) {
+        if (!stoperrset) {
+            /*
+             * We only ever set this once to avoid getting into an infinite
+             * loop where the error system keeps trying to init and fails so
+             * sets an error etc
+             */
+            stoperrset = 1;
+            SSLerr(SSL_F_OPENSSL_INIT_SSL, ERR_R_INIT_FAIL);
+        }
+        return 0;
+    }
+
+    opts |= OPENSSL_INIT_ADD_ALL_CIPHERS
+         |  OPENSSL_INIT_ADD_ALL_DIGESTS;
+#ifndef OPENSSL_NO_AUTOLOAD_CONFIG
+    if ((opts & OPENSSL_INIT_NO_LOAD_CONFIG) == 0)
+        opts |= OPENSSL_INIT_LOAD_CONFIG;
+#endif
+
+    if (!OPENSSL_init_crypto(opts, settings))
+        return 0;
+
+    if (!RUN_ONCE(&ssl_base, ossl_init_ssl_base))
+        return 0;
+
+    if ((opts & OPENSSL_INIT_NO_LOAD_SSL_STRINGS)
+        && !RUN_ONCE_ALT(&ssl_strings, ossl_init_no_load_ssl_strings,
+                         ossl_init_load_ssl_strings))
+        return 0;
+
+    if ((opts & OPENSSL_INIT_LOAD_SSL_STRINGS)
+        && !RUN_ONCE(&ssl_strings, ossl_init_load_ssl_strings))
+        return 0;
+
+    return 1;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_lib.c b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_lib.c
new file mode 100644
index 0000000..47adc32
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_lib.c
@@ -0,0 +1,5709 @@
+/*
+ * 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.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include "ssl_local.h"
+#include <openssl/objects.h>
+#include <openssl/x509v3.h>
+#include <openssl/rand.h>
+#include <openssl/rand_drbg.h>
+#include <openssl/ocsp.h>
+#include <openssl/dh.h>
+#include <openssl/engine.h>
+#include <openssl/async.h>
+#include <openssl/ct.h>
+#include "internal/cryptlib.h"
+#include "internal/refcount.h"
+
+const char SSL_version_str[] = OPENSSL_VERSION_TEXT;
+
+static int ssl_undefined_function_1(SSL *ssl, SSL3_RECORD *r, size_t s, int t)
+{
+    (void)r;
+    (void)s;
+    (void)t;
+    return ssl_undefined_function(ssl);
+}
+
+static int ssl_undefined_function_2(SSL *ssl, SSL3_RECORD *r, unsigned char *s,
+                                    int t)
+{
+    (void)r;
+    (void)s;
+    (void)t;
+    return ssl_undefined_function(ssl);
+}
+
+static int ssl_undefined_function_3(SSL *ssl, unsigned char *r,
+                                    unsigned char *s, size_t t, size_t *u)
+{
+    (void)r;
+    (void)s;
+    (void)t;
+    (void)u;
+    return ssl_undefined_function(ssl);
+}
+
+static int ssl_undefined_function_4(SSL *ssl, int r)
+{
+    (void)r;
+    return ssl_undefined_function(ssl);
+}
+
+static size_t ssl_undefined_function_5(SSL *ssl, const char *r, size_t s,
+                                       unsigned char *t)
+{
+    (void)r;
+    (void)s;
+    (void)t;
+    return ssl_undefined_function(ssl);
+}
+
+static int ssl_undefined_function_6(int r)
+{
+    (void)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,
+                                    const unsigned char *v, size_t w, int x)
+{
+    (void)r;
+    (void)s;
+    (void)t;
+    (void)u;
+    (void)v;
+    (void)w;
+    (void)x;
+    return ssl_undefined_function(ssl);
+}
+
+SSL3_ENC_METHOD ssl3_undef_enc_method = {
+    ssl_undefined_function_1,
+    ssl_undefined_function_2,
+    ssl_undefined_function,
+    ssl_undefined_function_3,
+    ssl_undefined_function_4,
+    ssl_undefined_function_5,
+    NULL,                       /* client_finished_label */
+    0,                          /* client_finished_label_len */
+    NULL,                       /* server_finished_label */
+    0,                          /* server_finished_label_len */
+    ssl_undefined_function_6,
+    ssl_undefined_function_7,
+};
+
+struct ssl_async_args {
+    SSL *s;
+    void *buf;
+    size_t num;
+    enum { READFUNC, WRITEFUNC, OTHERFUNC } type;
+    union {
+        int (*func_read) (SSL *, void *, size_t, size_t *);
+        int (*func_write) (SSL *, const void *, size_t, size_t *);
+        int (*func_other) (SSL *);
+    } f;
+};
+
+static const struct {
+    uint8_t mtype;
+    uint8_t ord;
+    int nid;
+} dane_mds[] = {
+    {
+        DANETLS_MATCHING_FULL, 0, NID_undef
+    },
+    {
+        DANETLS_MATCHING_2256, 1, NID_sha256
+    },
+    {
+        DANETLS_MATCHING_2512, 2, NID_sha512
+    },
+};
+
+static int dane_ctx_enable(struct dane_ctx_st *dctx)
+{
+    const EVP_MD **mdevp;
+    uint8_t *mdord;
+    uint8_t mdmax = DANETLS_MATCHING_LAST;
+    int n = ((int)mdmax) + 1;   /* int to handle PrivMatch(255) */
+    size_t i;
+
+    if (dctx->mdevp != NULL)
+        return 1;
+
+    mdevp = OPENSSL_zalloc(n * sizeof(*mdevp));
+    mdord = OPENSSL_zalloc(n * sizeof(*mdord));
+
+    if (mdord == NULL || mdevp == NULL) {
+        OPENSSL_free(mdord);
+        OPENSSL_free(mdevp);
+        SSLerr(SSL_F_DANE_CTX_ENABLE, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    /* Install default entries */
+    for (i = 0; i < OSSL_NELEM(dane_mds); ++i) {
+        const EVP_MD *md;
+
+        if (dane_mds[i].nid == NID_undef ||
+            (md = EVP_get_digestbynid(dane_mds[i].nid)) == NULL)
+            continue;
+        mdevp[dane_mds[i].mtype] = md;
+        mdord[dane_mds[i].mtype] = dane_mds[i].ord;
+    }
+
+    dctx->mdevp = mdevp;
+    dctx->mdord = mdord;
+    dctx->mdmax = mdmax;
+
+    return 1;
+}
+
+static void dane_ctx_final(struct dane_ctx_st *dctx)
+{
+    OPENSSL_free(dctx->mdevp);
+    dctx->mdevp = NULL;
+
+    OPENSSL_free(dctx->mdord);
+    dctx->mdord = NULL;
+    dctx->mdmax = 0;
+}
+
+static void tlsa_free(danetls_record *t)
+{
+    if (t == NULL)
+        return;
+    OPENSSL_free(t->data);
+    EVP_PKEY_free(t->spki);
+    OPENSSL_free(t);
+}
+
+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);
+    dane->certs = NULL;
+
+    X509_free(dane->mcert);
+    dane->mcert = NULL;
+    dane->mtlsa = NULL;
+    dane->mdpth = -1;
+    dane->pdpth = -1;
+}
+
+/*
+ * dane_copy - Copy dane configuration, sans verification state.
+ */
+static int ssl_dane_dup(SSL *to, SSL *from)
+{
+    int num;
+    int i;
+
+    if (!DANETLS_ENABLED(&from->dane))
+        return 1;
+
+    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.trecs = sk_danetls_record_new_reserve(NULL, num);
+
+    if (to->dane.trecs == NULL) {
+        SSLerr(SSL_F_SSL_DANE_DUP, ERR_R_MALLOC_FAILURE);
+        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)
+            return 0;
+    }
+    return 1;
+}
+
+static int dane_mtype_set(struct dane_ctx_st *dctx,
+                          const EVP_MD *md, uint8_t mtype, uint8_t ord)
+{
+    int i;
+
+    if (mtype == DANETLS_MATCHING_FULL && md != NULL) {
+        SSLerr(SSL_F_DANE_MTYPE_SET, SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL);
+        return 0;
+    }
+
+    if (mtype > dctx->mdmax) {
+        const EVP_MD **mdevp;
+        uint8_t *mdord;
+        int n = ((int)mtype) + 1;
+
+        mdevp = OPENSSL_realloc(dctx->mdevp, n * sizeof(*mdevp));
+        if (mdevp == NULL) {
+            SSLerr(SSL_F_DANE_MTYPE_SET, ERR_R_MALLOC_FAILURE);
+            return -1;
+        }
+        dctx->mdevp = mdevp;
+
+        mdord = OPENSSL_realloc(dctx->mdord, n * sizeof(*mdord));
+        if (mdord == NULL) {
+            SSLerr(SSL_F_DANE_MTYPE_SET, ERR_R_MALLOC_FAILURE);
+            return -1;
+        }
+        dctx->mdord = mdord;
+
+        /* Zero-fill any gaps */
+        for (i = dctx->mdmax + 1; i < mtype; ++i) {
+            mdevp[i] = NULL;
+            mdord[i] = 0;
+        }
+
+        dctx->mdmax = mtype;
+    }
+
+    dctx->mdevp[mtype] = md;
+    /* Coerce ordinal of disabled matching types to 0 */
+    dctx->mdord[mtype] = (md == NULL) ? 0 : ord;
+
+    return 1;
+}
+
+static const EVP_MD *tlsa_md_get(SSL_DANE *dane, uint8_t mtype)
+{
+    if (mtype > dane->dctx->mdmax)
+        return NULL;
+    return dane->dctx->mdevp[mtype];
+}
+
+static int dane_tlsa_add(SSL_DANE *dane,
+                         uint8_t usage,
+                         uint8_t selector,
+                         uint8_t mtype, unsigned const char *data, size_t dlen)
+{
+    danetls_record *t;
+    const EVP_MD *md = NULL;
+    int ilen = (int)dlen;
+    int i;
+    int num;
+
+    if (dane->trecs == NULL) {
+        SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_NOT_ENABLED);
+        return -1;
+    }
+
+    if (ilen < 0 || dlen != (size_t)ilen) {
+        SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_DATA_LENGTH);
+        return 0;
+    }
+
+    if (usage > DANETLS_USAGE_LAST) {
+        SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE);
+        return 0;
+    }
+
+    if (selector > DANETLS_SELECTOR_LAST) {
+        SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_SELECTOR);
+        return 0;
+    }
+
+    if (mtype != DANETLS_MATCHING_FULL) {
+        md = tlsa_md_get(dane, mtype);
+        if (md == NULL) {
+            SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_MATCHING_TYPE);
+            return 0;
+        }
+    }
+
+    if (md != NULL && dlen != (size_t)EVP_MD_size(md)) {
+        SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH);
+        return 0;
+    }
+    if (!data) {
+        SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_NULL_DATA);
+        return 0;
+    }
+
+    if ((t = OPENSSL_zalloc(sizeof(*t))) == NULL) {
+        SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE);
+        return -1;
+    }
+
+    t->usage = usage;
+    t->selector = selector;
+    t->mtype = mtype;
+    t->data = OPENSSL_malloc(dlen);
+    if (t->data == NULL) {
+        tlsa_free(t);
+        SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE);
+        return -1;
+    }
+    memcpy(t->data, data, dlen);
+    t->dlen = dlen;
+
+    /* Validate and cache full certificate or public key */
+    if (mtype == DANETLS_MATCHING_FULL) {
+        const unsigned char *p = data;
+        X509 *cert = NULL;
+        EVP_PKEY *pkey = NULL;
+
+        switch (selector) {
+        case DANETLS_SELECTOR_CERT:
+            if (!d2i_X509(&cert, &p, ilen) || p < data ||
+                dlen != (size_t)(p - data)) {
+                tlsa_free(t);
+                SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_CERTIFICATE);
+                return 0;
+            }
+            if (X509_get0_pubkey(cert) == NULL) {
+                tlsa_free(t);
+                SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_CERTIFICATE);
+                return 0;
+            }
+
+            if ((DANETLS_USAGE_BIT(usage) & DANETLS_TA_MASK) == 0) {
+                X509_free(cert);
+                break;
+            }
+
+            /*
+             * For usage DANE-TA(2), we support authentication via "2 0 0" TLSA
+             * records that contain full certificates of trust-anchors that are
+             * not present in the wire chain.  For usage PKIX-TA(0), we augment
+             * the chain with untrusted Full(0) certificates from DNS, in case
+             * they are missing from the chain.
+             */
+            if ((dane->certs == NULL &&
+                 (dane->certs = sk_X509_new_null()) == NULL) ||
+                !sk_X509_push(dane->certs, cert)) {
+                SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE);
+                X509_free(cert);
+                tlsa_free(t);
+                return -1;
+            }
+            break;
+
+        case DANETLS_SELECTOR_SPKI:
+            if (!d2i_PUBKEY(&pkey, &p, ilen) || p < data ||
+                dlen != (size_t)(p - data)) {
+                tlsa_free(t);
+                SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_PUBLIC_KEY);
+                return 0;
+            }
+
+            /*
+             * For usage DANE-TA(2), we support authentication via "2 1 0" TLSA
+             * records that contain full bare keys of trust-anchors that are
+             * not present in the wire chain.
+             */
+            if (usage == DANETLS_USAGE_DANE_TA)
+                t->spki = pkey;
+            else
+                EVP_PKEY_free(pkey);
+            break;
+        }
+    }
+
+    /*-
+     * Find the right insertion point for the new record.
+     *
+     * See crypto/x509/x509_vfy.c.  We sort DANE-EE(3) records first, so that
+     * they can be processed first, as they require no chain building, and no
+     * expiration or hostname checks.  Because DANE-EE(3) is numerically
+     * largest, this is accomplished via descending sort by "usage".
+     *
+     * We also sort in descending order by matching ordinal to simplify
+     * the implementation of digest agility in the verification code.
+     *
+     * The choice of order for the selector is not significant, so we
+     * use the same descending order for consistency.
+     */
+    num = sk_danetls_record_num(dane->trecs);
+    for (i = 0; i < num; ++i) {
+        danetls_record *rec = sk_danetls_record_value(dane->trecs, i);
+
+        if (rec->usage > usage)
+            continue;
+        if (rec->usage < usage)
+            break;
+        if (rec->selector > selector)
+            continue;
+        if (rec->selector < selector)
+            break;
+        if (dane->dctx->mdord[rec->mtype] > dane->dctx->mdord[mtype])
+            continue;
+        break;
+    }
+
+    if (!sk_danetls_record_insert(dane->trecs, t, i)) {
+        tlsa_free(t);
+        SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE);
+        return -1;
+    }
+    dane->umask |= DANETLS_USAGE_BIT(usage);
+
+    return 1;
+}
+
+/*
+ * Return 0 if there is only one version configured and it was disabled
+ * at configure time.  Return 1 otherwise.
+ */
+static int ssl_check_allowed_versions(int min_version, int max_version)
+{
+    int minisdtls = 0, maxisdtls = 0;
+
+    /* Figure out if we're doing DTLS versions or TLS versions */
+    if (min_version == DTLS1_BAD_VER
+        || min_version >> 8 == DTLS1_VERSION_MAJOR)
+        minisdtls = 1;
+    if (max_version == DTLS1_BAD_VER
+        || max_version >> 8 == DTLS1_VERSION_MAJOR)
+        maxisdtls = 1;
+    /* A wildcard version of 0 could be DTLS or TLS. */
+    if ((minisdtls && !maxisdtls && max_version != 0)
+        || (maxisdtls && !minisdtls && min_version != 0)) {
+        /* Mixing DTLS and TLS versions will lead to sadness; deny it. */
+        return 0;
+    }
+
+    if (minisdtls || maxisdtls) {
+        /* Do DTLS version checks. */
+        if (min_version == 0)
+            /* Ignore DTLS1_BAD_VER */
+            min_version = DTLS1_VERSION;
+        if (max_version == 0)
+            max_version = DTLS1_2_VERSION;
+#ifdef OPENSSL_NO_DTLS1_2
+        if (max_version == DTLS1_2_VERSION)
+            max_version = DTLS1_VERSION;
+#endif
+#ifdef OPENSSL_NO_DTLS1
+        if (min_version == DTLS1_VERSION)
+            min_version = DTLS1_2_VERSION;
+#endif
+        /* Done massaging versions; do the check. */
+        if (0
+#ifdef OPENSSL_NO_DTLS1
+            || (DTLS_VERSION_GE(min_version, DTLS1_VERSION)
+                && DTLS_VERSION_GE(DTLS1_VERSION, max_version))
+#endif
+#ifdef OPENSSL_NO_DTLS1_2
+            || (DTLS_VERSION_GE(min_version, DTLS1_2_VERSION)
+                && DTLS_VERSION_GE(DTLS1_2_VERSION, max_version))
+#endif
+            )
+            return 0;
+    } else {
+        /* Regular TLS version checks. */
+        if (min_version == 0)
+            min_version = SSL3_VERSION;
+        if (max_version == 0)
+            max_version = TLS1_3_VERSION;
+#ifdef OPENSSL_NO_TLS1_3
+        if (max_version == TLS1_3_VERSION)
+            max_version = TLS1_2_VERSION;
+#endif
+#ifdef OPENSSL_NO_TLS1_2
+        if (max_version == TLS1_2_VERSION)
+            max_version = TLS1_1_VERSION;
+#endif
+#ifdef OPENSSL_NO_TLS1_1
+        if (max_version == TLS1_1_VERSION)
+            max_version = TLS1_VERSION;
+#endif
+#ifdef OPENSSL_NO_TLS1
+        if (max_version == TLS1_VERSION)
+            max_version = SSL3_VERSION;
+#endif
+#ifdef OPENSSL_NO_SSL3
+        if (min_version == SSL3_VERSION)
+            min_version = TLS1_VERSION;
+#endif
+#ifdef OPENSSL_NO_TLS1
+        if (min_version == TLS1_VERSION)
+            min_version = TLS1_1_VERSION;
+#endif
+#ifdef OPENSSL_NO_TLS1_1
+        if (min_version == TLS1_1_VERSION)
+            min_version = TLS1_2_VERSION;
+#endif
+#ifdef OPENSSL_NO_TLS1_2
+        if (min_version == TLS1_2_VERSION)
+            min_version = TLS1_3_VERSION;
+#endif
+        /* Done massaging versions; do the check. */
+        if (0
+#ifdef OPENSSL_NO_SSL3
+            || (min_version <= SSL3_VERSION && SSL3_VERSION <= max_version)
+#endif
+#ifdef OPENSSL_NO_TLS1
+            || (min_version <= TLS1_VERSION && TLS1_VERSION <= max_version)
+#endif
+#ifdef OPENSSL_NO_TLS1_1
+            || (min_version <= TLS1_1_VERSION && TLS1_1_VERSION <= max_version)
+#endif
+#ifdef OPENSSL_NO_TLS1_2
+            || (min_version <= TLS1_2_VERSION && TLS1_2_VERSION <= max_version)
+#endif
+#ifdef OPENSSL_NO_TLS1_3
+            || (min_version <= TLS1_3_VERSION && TLS1_3_VERSION <= max_version)
+#endif
+            )
+            return 0;
+    }
+    return 1;
+}
+
+static void clear_ciphers(SSL *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 SSL_clear(SSL *s)
+{
+    if (s->method == NULL) {
+        SSLerr(SSL_F_SSL_CLEAR, SSL_R_NO_METHOD_SPECIFIED);
+        return 0;
+    }
+
+    if (ssl_clear_bad_session(s)) {
+        SSL_SESSION_free(s->session);
+        s->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;
+
+    s->error = 0;
+    s->hit = 0;
+    s->shutdown = 0;
+
+    if (s->renegotiate) {
+        SSLerr(SSL_F_SSL_CLEAR, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    ossl_statem_clear(s);
+
+    s->version = s->method->version;
+    s->client_version = s->version;
+    s->rwstate = SSL_NOTHING;
+
+    BUF_MEM_free(s->init_buf);
+    s->init_buf = NULL;
+    clear_ciphers(s);
+    s->first_packet = 0;
+
+    s->key_update = SSL_KEY_UPDATE_NONE;
+
+    EVP_MD_CTX_free(s->pha_dgst);
+    s->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;
+
+    /* Clear the verification result peername */
+    X509_VERIFY_PARAM_move_peername(s->param, NULL);
+
+    /* Clear any shared connection state */
+    OPENSSL_free(s->shared_sigalgs);
+    s->shared_sigalgs = NULL;
+    s->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))
+            return 0;
+    } else {
+        if (!s->method->ssl_clear(s))
+            return 0;
+    }
+
+    RECORD_LAYER_clear(&s->rlayer);
+
+    return 1;
+}
+
+/** Used to change an SSL_CTXs default SSL method type */
+int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth)
+{
+    STACK_OF(SSL_CIPHER) *sk;
+
+    ctx->method = meth;
+
+    if (!SSL_CTX_set_ciphersuites(ctx, TLS_DEFAULT_CIPHERSUITES)) {
+        SSLerr(SSL_F_SSL_CTX_SET_SSL_VERSION, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS);
+        return 0;
+    }
+    sk = ssl_create_cipher_list(ctx->method,
+                                ctx->tls13_ciphersuites,
+                                &(ctx->cipher_list),
+                                &(ctx->cipher_list_by_id),
+                                SSL_DEFAULT_CIPHER_LIST, ctx->cert);
+    if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= 0)) {
+        SSLerr(SSL_F_SSL_CTX_SET_SSL_VERSION, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS);
+        return 0;
+    }
+    return 1;
+}
+
+SSL *SSL_new(SSL_CTX *ctx)
+{
+    SSL *s;
+
+    if (ctx == NULL) {
+        SSLerr(SSL_F_SSL_NEW, SSL_R_NULL_SSL_CTX);
+        return NULL;
+    }
+    if (ctx->method == NULL) {
+        SSLerr(SSL_F_SSL_NEW, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION);
+        return NULL;
+    }
+
+    s = OPENSSL_zalloc(sizeof(*s));
+    if (s == NULL)
+        goto err;
+
+    s->references = 1;
+    s->lock = CRYPTO_THREAD_lock_new();
+    if (s->lock == NULL) {
+        OPENSSL_free(s);
+        s = NULL;
+        goto err;
+    }
+
+    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;
+    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;
+
+    /*
+     * Earlier library versions used to copy the pointer to the CERT, not
+     * its contents; only when setting new parameters for the per-SSL
+     * copy, ssl_cert_new would be called (and the direct reference to
+     * the per-SSL_CTX settings would be lost, but those still were
+     * indirectly accessed for various purposes, and for that reason they
+     * used to be known as s->ctx->default_cert). Now we don't look at the
+     * SSL_CTX's CERT after having duplicated it once.
+     */
+    s->cert = ssl_cert_dup(ctx->cert);
+    if (s->cert == NULL)
+        goto err;
+
+    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->sid_ctx_length = ctx->sid_ctx_length;
+    if (!ossl_assert(s->sid_ctx_length <= sizeof(s->sid_ctx)))
+        goto err;
+    memcpy(&s->sid_ctx, &ctx->sid_ctx, sizeof(s->sid_ctx));
+    s->verify_callback = ctx->default_verify_callback;
+    s->generate_session_id = ctx->generate_session_id;
+
+    s->param = X509_VERIFY_PARAM_new();
+    if (s->param == NULL)
+        goto err;
+    X509_VERIFY_PARAM_inherit(s->param, ctx->param);
+    s->quiet_shutdown = ctx->quiet_shutdown;
+
+    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;
+    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);
+
+    SSL_CTX_up_ref(ctx);
+    s->ctx = ctx;
+    s->ext.debug_cb = 0;
+    s->ext.debug_arg = NULL;
+    s->ext.ticket_expected = 0;
+    s->ext.status_type = ctx->ext.status_type;
+    s->ext.status_expected = 0;
+    s->ext.ocsp.ids = NULL;
+    s->ext.ocsp.exts = NULL;
+    s->ext.ocsp.resp = NULL;
+    s->ext.ocsp.resp_len = 0;
+    SSL_CTX_up_ref(ctx);
+    s->session_ctx = ctx;
+#ifndef OPENSSL_NO_EC
+    if (ctx->ext.ecpointformats) {
+        s->ext.ecpointformats =
+            OPENSSL_memdup(ctx->ext.ecpointformats,
+                           ctx->ext.ecpointformats_len);
+        if (!s->ext.ecpointformats) {
+            s->ext.ecpointformats_len = 0;
+            goto err;
+        }
+        s->ext.ecpointformats_len =
+            ctx->ext.ecpointformats_len;
+    }
+    if (ctx->ext.supportedgroups) {
+        s->ext.supportedgroups =
+            OPENSSL_memdup(ctx->ext.supportedgroups,
+                           ctx->ext.supportedgroups_len
+                                * sizeof(*ctx->ext.supportedgroups));
+        if (!s->ext.supportedgroups) {
+            s->ext.supportedgroups_len = 0;
+            goto err;
+        }
+        s->ext.supportedgroups_len = ctx->ext.supportedgroups_len;
+    }
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    s->ext.npn = NULL;
+#endif
+
+    if (s->ctx->ext.alpn) {
+        s->ext.alpn = OPENSSL_malloc(s->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;
+    }
+
+    s->verified_chain = NULL;
+    s->verify_result = X509_V_OK;
+
+    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 (!SSL_clear(s))
+        goto err;
+
+    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data))
+        goto err;
+
+#ifndef OPENSSL_NO_PSK
+    s->psk_client_callback = ctx->psk_client_callback;
+    s->psk_server_callback = ctx->psk_server_callback;
+#endif
+    s->psk_find_session_cb = ctx->psk_find_session_cb;
+    s->psk_use_session_cb = ctx->psk_use_session_cb;
+
+    s->job = NULL;
+
+#ifndef OPENSSL_NO_CT
+    if (!SSL_set_ct_validation_callback(s, ctx->ct_validation_callback,
+                                        ctx->ct_validation_callback_arg))
+        goto err;
+#endif
+
+    return s;
+ err:
+    SSL_free(s);
+    SSLerr(SSL_F_SSL_NEW, ERR_R_MALLOC_FAILURE);
+    return NULL;
+}
+
+int SSL_is_dtls(const SSL *s)
+{
+    return SSL_IS_DTLS(s) ? 1 : 0;
+}
+
+int SSL_up_ref(SSL *s)
+{
+    int i;
+
+    if (CRYPTO_UP_REF(&s->references, &i, s->lock) <= 0)
+        return 0;
+
+    REF_PRINT_COUNT("SSL", s);
+    REF_ASSERT_ISNT(i < 2);
+    return ((i > 1) ? 1 : 0);
+}
+
+int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx,
+                                   unsigned int sid_ctx_len)
+{
+    if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) {
+        SSLerr(SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT,
+               SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+        return 0;
+    }
+    ctx->sid_ctx_length = sid_ctx_len;
+    memcpy(ctx->sid_ctx, sid_ctx, sid_ctx_len);
+
+    return 1;
+}
+
+int SSL_set_session_id_context(SSL *ssl, const unsigned char *sid_ctx,
+                               unsigned int sid_ctx_len)
+{
+    if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) {
+        SSLerr(SSL_F_SSL_SET_SESSION_ID_CONTEXT,
+               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);
+
+    return 1;
+}
+
+int SSL_CTX_set_generate_session_id(SSL_CTX *ctx, GEN_SESSION_CB cb)
+{
+    CRYPTO_THREAD_write_lock(ctx->lock);
+    ctx->generate_session_id = cb;
+    CRYPTO_THREAD_unlock(ctx->lock);
+    return 1;
+}
+
+int SSL_set_generate_session_id(SSL *ssl, GEN_SESSION_CB cb)
+{
+    CRYPTO_THREAD_write_lock(ssl->lock);
+    ssl->generate_session_id = cb;
+    CRYPTO_THREAD_unlock(ssl->lock);
+    return 1;
+}
+
+int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id,
+                                unsigned int id_len)
+{
+    /*
+     * A quick examination of SSL_SESSION_hash and SSL_SESSION_cmp shows how
+     * we can "construct" a session to give us the desired check - i.e. to
+     * find if there's a session in the hash table that would conflict with
+     * any new session built out of this id/id_len and the ssl_version in use
+     * by this SSL.
+     */
+    SSL_SESSION r, *p;
+
+    if (id_len > sizeof(r.session_id))
+        return 0;
+
+    r.ssl_version = ssl->version;
+    r.session_id_length = id_len;
+    memcpy(r.session_id, id, id_len);
+
+    CRYPTO_THREAD_read_lock(ssl->session_ctx->lock);
+    p = lh_SSL_SESSION_retrieve(ssl->session_ctx->sessions, &r);
+    CRYPTO_THREAD_unlock(ssl->session_ctx->lock);
+    return (p != NULL);
+}
+
+int SSL_CTX_set_purpose(SSL_CTX *s, int purpose)
+{
+    return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
+}
+
+int SSL_set_purpose(SSL *s, int purpose)
+{
+    return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
+}
+
+int SSL_CTX_set_trust(SSL_CTX *s, int trust)
+{
+    return X509_VERIFY_PARAM_set_trust(s->param, trust);
+}
+
+int SSL_set_trust(SSL *s, int trust)
+{
+    return X509_VERIFY_PARAM_set_trust(s->param, trust);
+}
+
+int SSL_set1_host(SSL *s, const char *hostname)
+{
+    return X509_VERIFY_PARAM_set1_host(s->param, hostname, 0);
+}
+
+int SSL_add1_host(SSL *s, const char *hostname)
+{
+    return X509_VERIFY_PARAM_add1_host(s->param, hostname, 0);
+}
+
+void SSL_set_hostflags(SSL *s, unsigned int flags)
+{
+    X509_VERIFY_PARAM_set_hostflags(s->param, flags);
+}
+
+const char *SSL_get0_peername(SSL *s)
+{
+    return X509_VERIFY_PARAM_get0_peername(s->param);
+}
+
+int SSL_CTX_dane_enable(SSL_CTX *ctx)
+{
+    return dane_ctx_enable(&ctx->dane);
+}
+
+unsigned long SSL_CTX_dane_set_flags(SSL_CTX *ctx, unsigned long flags)
+{
+    unsigned long orig = ctx->dane.flags;
+
+    ctx->dane.flags |= flags;
+    return orig;
+}
+
+unsigned long SSL_CTX_dane_clear_flags(SSL_CTX *ctx, unsigned long flags)
+{
+    unsigned long orig = ctx->dane.flags;
+
+    ctx->dane.flags &= ~flags;
+    return orig;
+}
+
+int SSL_dane_enable(SSL *s, const char *basedomain)
+{
+    SSL_DANE *dane = &s->dane;
+
+    if (s->ctx->dane.mdmax == 0) {
+        SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_CONTEXT_NOT_DANE_ENABLED);
+        return 0;
+    }
+    if (dane->trecs != NULL) {
+        SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_DANE_ALREADY_ENABLED);
+        return 0;
+    }
+
+    /*
+     * Default SNI name.  This rejects empty names, while set1_host below
+     * accepts them and disables host name checks.  To avoid side-effects with
+     * invalid input, set the SNI name first.
+     */
+    if (s->ext.hostname == NULL) {
+        if (!SSL_set_tlsext_host_name(s, basedomain)) {
+            SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN);
+            return -1;
+        }
+    }
+
+    /* Primary RFC6125 reference identifier */
+    if (!X509_VERIFY_PARAM_set1_host(s->param, basedomain, 0)) {
+        SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN);
+        return -1;
+    }
+
+    dane->mdpth = -1;
+    dane->pdpth = -1;
+    dane->dctx = &s->ctx->dane;
+    dane->trecs = sk_danetls_record_new_null();
+
+    if (dane->trecs == NULL) {
+        SSLerr(SSL_F_SSL_DANE_ENABLE, ERR_R_MALLOC_FAILURE);
+        return -1;
+    }
+    return 1;
+}
+
+unsigned long SSL_dane_set_flags(SSL *ssl, unsigned long flags)
+{
+    unsigned long orig = ssl->dane.flags;
+
+    ssl->dane.flags |= flags;
+    return orig;
+}
+
+unsigned long SSL_dane_clear_flags(SSL *ssl, unsigned long flags)
+{
+    unsigned long orig = ssl->dane.flags;
+
+    ssl->dane.flags &= ~flags;
+    return orig;
+}
+
+int SSL_get0_dane_authority(SSL *s, X509 **mcert, EVP_PKEY **mspki)
+{
+    SSL_DANE *dane = &s->dane;
+
+    if (!DANETLS_ENABLED(dane) || s->verify_result != X509_V_OK)
+        return -1;
+    if (dane->mtlsa) {
+        if (mcert)
+            *mcert = dane->mcert;
+        if (mspki)
+            *mspki = (dane->mcert == NULL) ? dane->mtlsa->spki : NULL;
+    }
+    return dane->mdpth;
+}
+
+int SSL_get0_dane_tlsa(SSL *s, uint8_t *usage, uint8_t *selector,
+                       uint8_t *mtype, unsigned const char **data, size_t *dlen)
+{
+    SSL_DANE *dane = &s->dane;
+
+    if (!DANETLS_ENABLED(dane) || s->verify_result != X509_V_OK)
+        return -1;
+    if (dane->mtlsa) {
+        if (usage)
+            *usage = dane->mtlsa->usage;
+        if (selector)
+            *selector = dane->mtlsa->selector;
+        if (mtype)
+            *mtype = dane->mtlsa->mtype;
+        if (data)
+            *data = dane->mtlsa->data;
+        if (dlen)
+            *dlen = dane->mtlsa->dlen;
+    }
+    return dane->mdpth;
+}
+
+SSL_DANE *SSL_get0_dane(SSL *s)
+{
+    return &s->dane;
+}
+
+int SSL_dane_tlsa_add(SSL *s, uint8_t usage, uint8_t selector,
+                      uint8_t mtype, unsigned const char *data, size_t dlen)
+{
+    return dane_tlsa_add(&s->dane, usage, selector, mtype, data, dlen);
+}
+
+int SSL_CTX_dane_mtype_set(SSL_CTX *ctx, const EVP_MD *md, uint8_t mtype,
+                           uint8_t ord)
+{
+    return dane_mtype_set(&ctx->dane, md, mtype, ord);
+}
+
+int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm)
+{
+    return X509_VERIFY_PARAM_set1(ctx->param, vpm);
+}
+
+int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm)
+{
+    return X509_VERIFY_PARAM_set1(ssl->param, vpm);
+}
+
+X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx)
+{
+    return ctx->param;
+}
+
+X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl)
+{
+    return ssl->param;
+}
+
+void SSL_certs_clear(SSL *s)
+{
+    ssl_cert_clear_certs(s->cert);
+}
+
+void SSL_free(SSL *s)
+{
+    int i;
+
+    if (s == NULL)
+        return;
+    CRYPTO_DOWN_REF(&s->references, &i, s->lock);
+    REF_PRINT_COUNT("SSL", s);
+    if (i > 0)
+        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);
+
+    /* Ignore return value */
+    ssl_free_wbio_buffer(s);
+
+    BIO_free_all(s->wbio);
+    BIO_free_all(s->rbio);
+
+    BUF_MEM_free(s->init_buf);
+
+    /* add extra stuff */
+    sk_SSL_CIPHER_free(s->cipher_list);
+    sk_SSL_CIPHER_free(s->cipher_list_by_id);
+    sk_SSL_CIPHER_free(s->tls13_ciphersuites);
+    sk_SSL_CIPHER_free(s->peer_ciphers);
+
+    /* Make the next call work :-) */
+    if (s->session != NULL) {
+        ssl_clear_bad_session(s);
+        SSL_SESSION_free(s->session);
+    }
+    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 */
+
+    OPENSSL_free(s->ext.hostname);
+    SSL_CTX_free(s->session_ctx);
+#ifndef OPENSSL_NO_EC
+    OPENSSL_free(s->ext.ecpointformats);
+    OPENSSL_free(s->ext.peer_ecpointformats);
+    OPENSSL_free(s->ext.supportedgroups);
+    OPENSSL_free(s->ext.peer_supportedgroups);
+#endif                          /* OPENSSL_NO_EC */
+    sk_X509_EXTENSION_pop_free(s->ext.ocsp.exts, X509_EXTENSION_free);
+#ifndef OPENSSL_NO_OCSP
+    sk_OCSP_RESPID_pop_free(s->ext.ocsp.ids, OCSP_RESPID_free);
+#endif
+#ifndef OPENSSL_NO_CT
+    SCT_LIST_free(s->scts);
+    OPENSSL_free(s->ext.scts);
+#endif
+    OPENSSL_free(s->ext.ocsp.resp);
+    OPENSSL_free(s->ext.alpn);
+    OPENSSL_free(s->ext.tls13_cookie);
+    if (s->clienthello != NULL)
+        OPENSSL_free(s->clienthello->pre_proc_exts);
+    OPENSSL_free(s->clienthello);
+    OPENSSL_free(s->pha_context);
+    EVP_MD_CTX_free(s->pha_dgst);
+
+    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);
+
+    RECORD_LAYER_release(&s->rlayer);
+
+    SSL_CTX_free(s->ctx);
+
+    ASYNC_WAIT_CTX_free(s->waitctx);
+
+#if !defined(OPENSSL_NO_NEXTPROTONEG)
+    OPENSSL_free(s->ext.npn);
+#endif
+
+#ifndef OPENSSL_NO_SRTP
+    sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles);
+#endif
+
+    CRYPTO_THREAD_lock_free(s->lock);
+
+    OPENSSL_free(s);
+}
+
+void SSL_set0_rbio(SSL *s, BIO *rbio)
+{
+    BIO_free_all(s->rbio);
+    s->rbio = rbio;
+}
+
+void SSL_set0_wbio(SSL *s, BIO *wbio)
+{
+    /*
+     * If the output buffering BIO is still in place, remove it
+     */
+    if (s->bbio != NULL)
+        s->wbio = BIO_pop(s->wbio);
+
+    BIO_free_all(s->wbio);
+    s->wbio = wbio;
+
+    /* Re-attach |bbio| to the new |wbio|. */
+    if (s->bbio != NULL)
+        s->wbio = BIO_push(s->bbio, s->wbio);
+}
+
+void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio)
+{
+    /*
+     * For historical reasons, this function has many different cases in
+     * ownership handling.
+     */
+
+    /* If nothing has changed, do nothing */
+    if (rbio == SSL_get_rbio(s) && wbio == SSL_get_wbio(s))
+        return;
+
+    /*
+     * If the two arguments are equal then one fewer reference is granted by the
+     * caller than we want to take
+     */
+    if (rbio != NULL && rbio == wbio)
+        BIO_up_ref(rbio);
+
+    /*
+     * If only the wbio is changed only adopt one reference.
+     */
+    if (rbio == SSL_get_rbio(s)) {
+        SSL_set0_wbio(s, wbio);
+        return;
+    }
+    /*
+     * There is an asymmetry here for historical reasons. If only the rbio is
+     * changed AND the rbio and wbio were originally different, then we only
+     * adopt one reference.
+     */
+    if (wbio == SSL_get_wbio(s) && SSL_get_rbio(s) != SSL_get_wbio(s)) {
+        SSL_set0_rbio(s, rbio);
+        return;
+    }
+
+    /* Otherwise, adopt both references. */
+    SSL_set0_rbio(s, rbio);
+    SSL_set0_wbio(s, wbio);
+}
+
+BIO *SSL_get_rbio(const SSL *s)
+{
+    return s->rbio;
+}
+
+BIO *SSL_get_wbio(const SSL *s)
+{
+    if (s->bbio != NULL) {
+        /*
+         * If |bbio| is active, the true caller-configured BIO is its
+         * |next_bio|.
+         */
+        return BIO_next(s->bbio);
+    }
+    return s->wbio;
+}
+
+int SSL_get_fd(const SSL *s)
+{
+    return SSL_get_rfd(s);
+}
+
+int SSL_get_rfd(const SSL *s)
+{
+    int ret = -1;
+    BIO *b, *r;
+
+    b = SSL_get_rbio(s);
+    r = BIO_find_type(b, BIO_TYPE_DESCRIPTOR);
+    if (r != NULL)
+        BIO_get_fd(r, &ret);
+    return ret;
+}
+
+int SSL_get_wfd(const SSL *s)
+{
+    int ret = -1;
+    BIO *b, *r;
+
+    b = SSL_get_wbio(s);
+    r = BIO_find_type(b, BIO_TYPE_DESCRIPTOR);
+    if (r != NULL)
+        BIO_get_fd(r, &ret);
+    return ret;
+}
+
+#ifndef OPENSSL_NO_SOCK
+int SSL_set_fd(SSL *s, int fd)
+{
+    int ret = 0;
+    BIO *bio = NULL;
+
+    bio = BIO_new(BIO_s_socket());
+
+    if (bio == NULL) {
+        SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
+        goto err;
+    }
+    BIO_set_fd(bio, fd, BIO_NOCLOSE);
+    SSL_set_bio(s, bio, bio);
+    ret = 1;
+ err:
+    return ret;
+}
+
+int SSL_set_wfd(SSL *s, int fd)
+{
+    BIO *rbio = SSL_get_rbio(s);
+
+    if (rbio == NULL || BIO_method_type(rbio) != BIO_TYPE_SOCKET
+        || (int)BIO_get_fd(rbio, NULL) != fd) {
+        BIO *bio = BIO_new(BIO_s_socket());
+
+        if (bio == NULL) {
+            SSLerr(SSL_F_SSL_SET_WFD, ERR_R_BUF_LIB);
+            return 0;
+        }
+        BIO_set_fd(bio, fd, BIO_NOCLOSE);
+        SSL_set0_wbio(s, bio);
+    } else {
+        BIO_up_ref(rbio);
+        SSL_set0_wbio(s, rbio);
+    }
+    return 1;
+}
+
+int SSL_set_rfd(SSL *s, int fd)
+{
+    BIO *wbio = SSL_get_wbio(s);
+
+    if (wbio == NULL || BIO_method_type(wbio) != BIO_TYPE_SOCKET
+        || ((int)BIO_get_fd(wbio, NULL) != fd)) {
+        BIO *bio = BIO_new(BIO_s_socket());
+
+        if (bio == NULL) {
+            SSLerr(SSL_F_SSL_SET_RFD, ERR_R_BUF_LIB);
+            return 0;
+        }
+        BIO_set_fd(bio, fd, BIO_NOCLOSE);
+        SSL_set0_rbio(s, bio);
+    } else {
+        BIO_up_ref(wbio);
+        SSL_set0_rbio(s, wbio);
+    }
+
+    return 1;
+}
+#endif
+
+/* return length of latest Finished message we sent, copy to 'buf' */
+size_t SSL_get_finished(const SSL *s, void *buf, size_t count)
+{
+    size_t ret = 0;
+
+    if (s->s3 != NULL) {
+        ret = s->s3->tmp.finish_md_len;
+        if (count > ret)
+            count = ret;
+        memcpy(buf, s->s3->tmp.finish_md, count);
+    }
+    return ret;
+}
+
+/* return length of latest Finished message we expected, copy to 'buf' */
+size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count)
+{
+    size_t ret = 0;
+
+    if (s->s3 != NULL) {
+        ret = s->s3->tmp.peer_finish_md_len;
+        if (count > ret)
+            count = ret;
+        memcpy(buf, s->s3->tmp.peer_finish_md, count);
+    }
+    return ret;
+}
+
+int SSL_get_verify_mode(const SSL *s)
+{
+    return s->verify_mode;
+}
+
+int SSL_get_verify_depth(const SSL *s)
+{
+    return X509_VERIFY_PARAM_get_depth(s->param);
+}
+
+int (*SSL_get_verify_callback(const SSL *s)) (int, X509_STORE_CTX *) {
+    return s->verify_callback;
+}
+
+int SSL_CTX_get_verify_mode(const SSL_CTX *ctx)
+{
+    return ctx->verify_mode;
+}
+
+int SSL_CTX_get_verify_depth(const SSL_CTX *ctx)
+{
+    return X509_VERIFY_PARAM_get_depth(ctx->param);
+}
+
+int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx)) (int, X509_STORE_CTX *) {
+    return ctx->default_verify_callback;
+}
+
+void SSL_set_verify(SSL *s, int mode,
+                    int (*callback) (int ok, X509_STORE_CTX *ctx))
+{
+    s->verify_mode = mode;
+    if (callback != NULL)
+        s->verify_callback = callback;
+}
+
+void SSL_set_verify_depth(SSL *s, int depth)
+{
+    X509_VERIFY_PARAM_set_depth(s->param, depth);
+}
+
+void SSL_set_read_ahead(SSL *s, int yes)
+{
+    RECORD_LAYER_set_read_ahead(&s->rlayer, yes);
+}
+
+int SSL_get_read_ahead(const SSL *s)
+{
+    return RECORD_LAYER_get_read_ahead(&s->rlayer);
+}
+
+int SSL_pending(const SSL *s)
+{
+    size_t pending = s->method->ssl_pending(s);
+
+    /*
+     * SSL_pending cannot work properly if read-ahead is enabled
+     * (SSL_[CTX_]ctrl(..., SSL_CTRL_SET_READ_AHEAD, 1, NULL)), and it is
+     * impossible to fix since SSL_pending cannot report errors that may be
+     * observed while scanning the new data. (Note that SSL_pending() is
+     * often used as a boolean value, so we'd better not return -1.)
+     *
+     * SSL_pending also cannot work properly if the value >INT_MAX. In that case
+     * we just return INT_MAX.
+     */
+    return pending < INT_MAX ? (int)pending : INT_MAX;
+}
+
+int SSL_has_pending(const SSL *s)
+{
+    /*
+     * Similar to SSL_pending() but returns a 1 to indicate that we have
+     * 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.
+     */
+
+    /* Check buffered app data if any first */
+    if (SSL_IS_DTLS(s)) {
+        DTLS1_RECORD_DATA *rdata;
+        pitem *item, *iter;
+
+        iter = pqueue_iterator(s->rlayer.d->buffered_app_data.q);
+        while ((item = pqueue_next(&iter)) != NULL) {
+            rdata = item->data;
+            if (rdata->rrec.length > 0)
+                return 1;
+        }
+    }
+
+    if (RECORD_LAYER_processed_read_pending(&s->rlayer))
+        return 1;
+
+    return RECORD_LAYER_read_pending(&s->rlayer);
+}
+
+X509 *SSL_get_peer_certificate(const SSL *s)
+{
+    X509 *r;
+
+    if ((s == NULL) || (s->session == NULL))
+        r = NULL;
+    else
+        r = s->session->peer;
+
+    if (r == NULL)
+        return r;
+
+    X509_up_ref(r);
+
+    return r;
+}
+
+STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s)
+{
+    STACK_OF(X509) *r;
+
+    if ((s == NULL) || (s->session == NULL))
+        r = NULL;
+    else
+        r = s->session->peer_chain;
+
+    /*
+     * If we are a client, cert_chain includes the peer's own certificate; if
+     * we are a server, it does not.
+     */
+
+    return r;
+}
+
+/*
+ * Now in theory, since the calling process own 't' it should be safe to
+ * modify.  We need to be able to read f without being hassled
+ */
+int SSL_copy_session_id(SSL *t, const SSL *f)
+{
+    int i;
+    /* Do we need to to SSL locking? */
+    if (!SSL_set_session(t, SSL_get_session(f))) {
+        return 0;
+    }
+
+    /*
+     * 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 = f->method;
+        if (t->method->ssl_new(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)) {
+        return 0;
+    }
+
+    return 1;
+}
+
+/* Fix this so it checks all the valid key/cert options */
+int SSL_CTX_check_private_key(const SSL_CTX *ctx)
+{
+    if ((ctx == NULL) || (ctx->cert->key->x509 == NULL)) {
+        SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY, SSL_R_NO_CERTIFICATE_ASSIGNED);
+        return 0;
+    }
+    if (ctx->cert->key->privatekey == NULL) {
+        SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+        return 0;
+    }
+    return X509_check_private_key
+            (ctx->cert->key->x509, ctx->cert->key->privatekey);
+}
+
+/* Fix this function so that it takes an optional type parameter */
+int SSL_check_private_key(const SSL *ssl)
+{
+    if (ssl == NULL) {
+        SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    if (ssl->cert->key->x509 == NULL) {
+        SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY, SSL_R_NO_CERTIFICATE_ASSIGNED);
+        return 0;
+    }
+    if (ssl->cert->key->privatekey == NULL) {
+        SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+        return 0;
+    }
+    return X509_check_private_key(ssl->cert->key->x509,
+                                   ssl->cert->key->privatekey);
+}
+
+int SSL_waiting_for_async(SSL *s)
+{
+    if (s->job)
+        return 1;
+
+    return 0;
+}
+
+int SSL_get_all_async_fds(SSL *s, OSSL_ASYNC_FD *fds, size_t *numfds)
+{
+    ASYNC_WAIT_CTX *ctx = s->waitctx;
+
+    if (ctx == NULL)
+        return 0;
+    return ASYNC_WAIT_CTX_get_all_fds(ctx, fds, 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;
+
+    if (ctx == NULL)
+        return 0;
+    return ASYNC_WAIT_CTX_get_changed_fds(ctx, addfd, numaddfds, delfd,
+                                          numdelfds);
+}
+
+int SSL_accept(SSL *s)
+{
+    if (s->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) {
+        /* Not properly initialized yet */
+        SSL_set_connect_state(s);
+    }
+
+    return SSL_do_handshake(s);
+}
+
+long SSL_get_default_timeout(const SSL *s)
+{
+    return s->method->get_timeout();
+}
+
+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)
+            return -1;
+    }
+
+    s->rwstate = SSL_NOTHING;
+    switch (ASYNC_start_job(&s->job, s->waitctx, &ret, func, args,
+                            sizeof(struct ssl_async_args))) {
+    case ASYNC_ERR:
+        s->rwstate = SSL_NOTHING;
+        SSLerr(SSL_F_SSL_START_ASYNC_JOB, SSL_R_FAILED_TO_INIT_ASYNC);
+        return -1;
+    case ASYNC_PAUSE:
+        s->rwstate = SSL_ASYNC_PAUSED;
+        return -1;
+    case ASYNC_NO_JOBS:
+        s->rwstate = SSL_ASYNC_NO_JOBS;
+        return -1;
+    case ASYNC_FINISH:
+        s->job = NULL;
+        return ret;
+    default:
+        s->rwstate = SSL_NOTHING;
+        SSLerr(SSL_F_SSL_START_ASYNC_JOB, ERR_R_INTERNAL_ERROR);
+        /* Shouldn't happen */
+        return -1;
+    }
+}
+
+static int ssl_io_intern(void *vargs)
+{
+    struct ssl_async_args *args;
+    SSL *s;
+    void *buf;
+    size_t num;
+
+    args = (struct ssl_async_args *)vargs;
+    s = args->s;
+    buf = args->buf;
+    num = args->num;
+    switch (args->type) {
+    case READFUNC:
+        return args->f.func_read(s, buf, num, &s->asyncrw);
+    case WRITEFUNC:
+        return args->f.func_write(s, buf, num, &s->asyncrw);
+    case OTHERFUNC:
+        return args->f.func_other(s);
+    }
+    return -1;
+}
+
+int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
+{
+    if (s->handshake_func == NULL) {
+        SSLerr(SSL_F_SSL_READ_INTERNAL, SSL_R_UNINITIALIZED);
+        return -1;
+    }
+
+    if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
+        s->rwstate = SSL_NOTHING;
+        return 0;
+    }
+
+    if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY
+                || s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY) {
+        SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+        return 0;
+    }
+    /*
+     * If we are a client and haven't received the ServerHello etc then we
+     * better do that
+     */
+    ossl_statem_check_finish_init(s, 0);
+
+    if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
+        struct ssl_async_args args;
+        int ret;
+
+        args.s = s;
+        args.buf = buf;
+        args.num = num;
+        args.type = READFUNC;
+        args.f.func_read = s->method->ssl_read;
+
+        ret = ssl_start_async_job(s, &args, ssl_io_intern);
+        *readbytes = s->asyncrw;
+        return ret;
+    } else {
+        return s->method->ssl_read(s, buf, num, readbytes);
+    }
+}
+
+int SSL_read(SSL *s, void *buf, int num)
+{
+    int ret;
+    size_t readbytes;
+
+    if (num < 0) {
+        SSLerr(SSL_F_SSL_READ, SSL_R_BAD_LENGTH);
+        return -1;
+    }
+
+    ret = ssl_read_internal(s, buf, (size_t)num, &readbytes);
+
+    /*
+     * The cast is safe here because ret should be <= INT_MAX because num is
+     * <= INT_MAX
+     */
+    if (ret > 0)
+        ret = (int)readbytes;
+
+    return ret;
+}
+
+int SSL_read_ex(SSL *s, void *buf, size_t num, size_t *readbytes)
+{
+    int ret = ssl_read_internal(s, buf, num, readbytes);
+
+    if (ret < 0)
+        ret = 0;
+    return ret;
+}
+
+int SSL_read_early_data(SSL *s, void *buf, size_t num, size_t *readbytes)
+{
+    int ret;
+
+    if (!s->server) {
+        SSLerr(SSL_F_SSL_READ_EARLY_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+        return SSL_READ_EARLY_DATA_ERROR;
+    }
+
+    switch (s->early_data_state) {
+    case SSL_EARLY_DATA_NONE:
+        if (!SSL_in_before(s)) {
+            SSLerr(SSL_F_SSL_READ_EARLY_DATA,
+                   ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+            return SSL_READ_EARLY_DATA_ERROR;
+        }
+        /* fall through */
+
+    case SSL_EARLY_DATA_ACCEPT_RETRY:
+        s->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;
+            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;
+            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
+                                        != SSL_EARLY_DATA_FINISHED_READING)) {
+                s->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;
+        }
+        *readbytes = 0;
+        return SSL_READ_EARLY_DATA_FINISH;
+
+    default:
+        SSLerr(SSL_F_SSL_READ_EARLY_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+        return SSL_READ_EARLY_DATA_ERROR;
+    }
+}
+
+int SSL_get_early_data_status(const SSL *s)
+{
+    return s->ext.early_data;
+}
+
+static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
+{
+    if (s->handshake_func == NULL) {
+        SSLerr(SSL_F_SSL_PEEK_INTERNAL, SSL_R_UNINITIALIZED);
+        return -1;
+    }
+
+    if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
+        return 0;
+    }
+    if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
+        struct ssl_async_args args;
+        int ret;
+
+        args.s = s;
+        args.buf = buf;
+        args.num = num;
+        args.type = READFUNC;
+        args.f.func_read = s->method->ssl_peek;
+
+        ret = ssl_start_async_job(s, &args, ssl_io_intern);
+        *readbytes = s->asyncrw;
+        return ret;
+    } else {
+        return s->method->ssl_peek(s, buf, num, readbytes);
+    }
+}
+
+int SSL_peek(SSL *s, void *buf, int num)
+{
+    int ret;
+    size_t readbytes;
+
+    if (num < 0) {
+        SSLerr(SSL_F_SSL_PEEK, SSL_R_BAD_LENGTH);
+        return -1;
+    }
+
+    ret = ssl_peek_internal(s, buf, (size_t)num, &readbytes);
+
+    /*
+     * The cast is safe here because ret should be <= INT_MAX because num is
+     * <= INT_MAX
+     */
+    if (ret > 0)
+        ret = (int)readbytes;
+
+    return ret;
+}
+
+
+int SSL_peek_ex(SSL *s, void *buf, size_t num, size_t *readbytes)
+{
+    int ret = ssl_peek_internal(s, buf, num, readbytes);
+
+    if (ret < 0)
+        ret = 0;
+    return ret;
+}
+
+int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
+{
+    if (s->handshake_func == NULL) {
+        SSLerr(SSL_F_SSL_WRITE_INTERNAL, SSL_R_UNINITIALIZED);
+        return -1;
+    }
+
+    if (s->shutdown & SSL_SENT_SHUTDOWN) {
+        s->rwstate = SSL_NOTHING;
+        SSLerr(SSL_F_SSL_WRITE_INTERNAL, 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) {
+        SSLerr(SSL_F_SSL_WRITE_INTERNAL, 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);
+
+    if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
+        int ret;
+        struct ssl_async_args args;
+
+        args.s = s;
+        args.buf = (void *)buf;
+        args.num = num;
+        args.type = WRITEFUNC;
+        args.f.func_write = s->method->ssl_write;
+
+        ret = ssl_start_async_job(s, &args, ssl_io_intern);
+        *written = s->asyncrw;
+        return ret;
+    } else {
+        return s->method->ssl_write(s, buf, num, written);
+    }
+}
+
+int SSL_write(SSL *s, const void *buf, int num)
+{
+    int ret;
+    size_t written;
+
+    if (num < 0) {
+        SSLerr(SSL_F_SSL_WRITE, SSL_R_BAD_LENGTH);
+        return -1;
+    }
+
+    ret = ssl_write_internal(s, buf, (size_t)num, &written);
+
+    /*
+     * The cast is safe here because ret should be <= INT_MAX because num is
+     * <= INT_MAX
+     */
+    if (ret > 0)
+        ret = (int)written;
+
+    return ret;
+}
+
+int SSL_write_ex(SSL *s, const void *buf, size_t num, size_t *written)
+{
+    int ret = ssl_write_internal(s, buf, num, written);
+
+    if (ret < 0)
+        ret = 0;
+    return ret;
+}
+
+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;
+
+    switch (s->early_data_state) {
+    case SSL_EARLY_DATA_NONE:
+        if (s->server
+                || !SSL_in_before(s)
+                || ((s->session == NULL || s->session->ext.max_early_data == 0)
+                     && (s->psk_use_session_cb == NULL))) {
+            SSLerr(SSL_F_SSL_WRITE_EARLY_DATA,
+                   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;
+        ret = SSL_connect(s);
+        if (ret <= 0) {
+            /* NBIO or error */
+            s->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;
+        /*
+         * 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;
+        ret = SSL_write_ex(s, buf, num, &writtmp);
+        s->mode |= partialwrite;
+        if (!ret) {
+            s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
+            return ret;
+        }
+        s->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)
+            return 0;
+        *written = num;
+        s->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;
+        /* We are a server writing to an unauthenticated client */
+        s->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;
+        return ret;
+
+    default:
+        SSLerr(SSL_F_SSL_WRITE_EARLY_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+        return 0;
+    }
+}
+
+int SSL_shutdown(SSL *s)
+{
+    /*
+     * Note that this function behaves differently from what one might
+     * expect.  Return values are 0 for no success (yet), 1 for success; but
+     * calling it once is usually not enough, even if blocking I/O is used
+     * (see ssl3_shutdown).
+     */
+
+    if (s->handshake_func == NULL) {
+        SSLerr(SSL_F_SSL_SHUTDOWN, SSL_R_UNINITIALIZED);
+        return -1;
+    }
+
+    if (!SSL_in_init(s)) {
+        if ((s->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;
+
+            return ssl_start_async_job(s, &args, ssl_io_intern);
+        } else {
+            return s->method->ssl_shutdown(s);
+        }
+    } else {
+        SSLerr(SSL_F_SSL_SHUTDOWN, SSL_R_SHUTDOWN_WHILE_IN_INIT);
+        return -1;
+    }
+}
+
+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)) {
+        SSLerr(SSL_F_SSL_KEY_UPDATE, SSL_R_WRONG_SSL_VERSION);
+        return 0;
+    }
+
+    if (updatetype != SSL_KEY_UPDATE_NOT_REQUESTED
+            && updatetype != SSL_KEY_UPDATE_REQUESTED) {
+        SSLerr(SSL_F_SSL_KEY_UPDATE, SSL_R_INVALID_KEY_UPDATE_TYPE);
+        return 0;
+    }
+
+    if (!SSL_is_init_finished(s)) {
+        SSLerr(SSL_F_SSL_KEY_UPDATE, SSL_R_STILL_IN_INIT);
+        return 0;
+    }
+
+    if (RECORD_LAYER_write_pending(&s->rlayer)) {
+        SSLerr(SSL_F_SSL_KEY_UPDATE, SSL_R_BAD_WRITE_RETRY);
+        return 0;
+    }
+
+    ossl_statem_set_in_init(s, 1);
+    s->key_update = updatetype;
+    return 1;
+}
+
+int SSL_get_key_update_type(const SSL *s)
+{
+    return s->key_update;
+}
+
+int SSL_renegotiate(SSL *s)
+{
+    if (SSL_IS_TLS13(s)) {
+        SSLerr(SSL_F_SSL_RENEGOTIATE, SSL_R_WRONG_SSL_VERSION);
+        return 0;
+    }
+
+    if ((s->options & SSL_OP_NO_RENEGOTIATION)) {
+        SSLerr(SSL_F_SSL_RENEGOTIATE, SSL_R_NO_RENEGOTIATION);
+        return 0;
+    }
+
+    s->renegotiate = 1;
+    s->new_session = 1;
+
+    return s->method->ssl_renegotiate(s);
+}
+
+int SSL_renegotiate_abbreviated(SSL *s)
+{
+    if (SSL_IS_TLS13(s)) {
+        SSLerr(SSL_F_SSL_RENEGOTIATE_ABBREVIATED, SSL_R_WRONG_SSL_VERSION);
+        return 0;
+    }
+
+    if ((s->options & SSL_OP_NO_RENEGOTIATION)) {
+        SSLerr(SSL_F_SSL_RENEGOTIATE_ABBREVIATED, SSL_R_NO_RENEGOTIATION);
+        return 0;
+    }
+
+    s->renegotiate = 1;
+    s->new_session = 0;
+
+    return s->method->ssl_renegotiate(s);
+}
+
+int SSL_renegotiate_pending(const SSL *s)
+{
+    /*
+     * becomes true when negotiation is requested; false again once a
+     * handshake has finished
+     */
+    return (s->renegotiate != 0);
+}
+
+long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
+{
+    long l;
+
+    switch (cmd) {
+    case SSL_CTRL_GET_READ_AHEAD:
+        return RECORD_LAYER_get_read_ahead(&s->rlayer);
+    case SSL_CTRL_SET_READ_AHEAD:
+        l = RECORD_LAYER_get_read_ahead(&s->rlayer);
+        RECORD_LAYER_set_read_ahead(&s->rlayer, larg);
+        return l;
+
+    case SSL_CTRL_SET_MSG_CALLBACK_ARG:
+        s->msg_callback_arg = parg;
+        return 1;
+
+    case SSL_CTRL_MODE:
+        return (s->mode |= larg);
+    case SSL_CTRL_CLEAR_MODE:
+        return (s->mode &= ~larg);
+    case SSL_CTRL_GET_MAX_CERT_LIST:
+        return (long)s->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;
+        return l;
+    case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
+        if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
+            return 0;
+        s->max_send_fragment = larg;
+        if (s->max_send_fragment < s->split_send_fragment)
+            s->split_send_fragment = s->max_send_fragment;
+        return 1;
+    case SSL_CTRL_SET_SPLIT_SEND_FRAGMENT:
+        if ((size_t)larg > s->max_send_fragment || larg == 0)
+            return 0;
+        s->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);
+        return 1;
+    case SSL_CTRL_GET_RI_SUPPORT:
+        if (s->s3)
+            return s->s3->send_connection_binding;
+        else
+            return 0;
+    case SSL_CTRL_CERT_FLAGS:
+        return (s->cert->cert_flags |= larg);
+    case SSL_CTRL_CLEAR_CERT_FLAGS:
+        return (s->cert->cert_flags &= ~larg);
+
+    case SSL_CTRL_GET_RAW_CIPHERLIST:
+        if (parg) {
+            if (s->s3->tmp.ciphers_raw == NULL)
+                return 0;
+            *(unsigned char **)parg = s->s3->tmp.ciphers_raw;
+            return (int)s->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))
+            return -1;
+        if (s->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);
+    case SSL_CTRL_GET_MIN_PROTO_VERSION:
+        return s->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);
+    case SSL_CTRL_GET_MAX_PROTO_VERSION:
+        return s->max_proto_version;
+    default:
+        return s->method->ssl_ctrl(s, cmd, larg, parg);
+    }
+}
+
+long SSL_callback_ctrl(SSL *s, int cmd, void (*fp) (void))
+{
+    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);
+        return 1;
+
+    default:
+        return s->method->ssl_callback_ctrl(s, cmd, fp);
+    }
+}
+
+LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx)
+{
+    return ctx->sessions;
+}
+
+long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
+{
+    long l;
+    /* For some cases with ctx == NULL perform syntax checks */
+    if (ctx == NULL) {
+        switch (cmd) {
+#ifndef OPENSSL_NO_EC
+        case SSL_CTRL_SET_GROUPS_LIST:
+            return tls1_set_groups_list(NULL, NULL, parg);
+#endif
+        case SSL_CTRL_SET_SIGALGS_LIST:
+        case SSL_CTRL_SET_CLIENT_SIGALGS_LIST:
+            return tls1_set_sigalgs_list(NULL, parg, 0);
+        default:
+            return 0;
+        }
+    }
+
+    switch (cmd) {
+    case SSL_CTRL_GET_READ_AHEAD:
+        return ctx->read_ahead;
+    case SSL_CTRL_SET_READ_AHEAD:
+        l = ctx->read_ahead;
+        ctx->read_ahead = larg;
+        return l;
+
+    case SSL_CTRL_SET_MSG_CALLBACK_ARG:
+        ctx->msg_callback_arg = parg;
+        return 1;
+
+    case SSL_CTRL_GET_MAX_CERT_LIST:
+        return (long)ctx->max_cert_list;
+    case SSL_CTRL_SET_MAX_CERT_LIST:
+        if (larg < 0)
+            return 0;
+        l = (long)ctx->max_cert_list;
+        ctx->max_cert_list = (size_t)larg;
+        return l;
+
+    case SSL_CTRL_SET_SESS_CACHE_SIZE:
+        if (larg < 0)
+            return 0;
+        l = (long)ctx->session_cache_size;
+        ctx->session_cache_size = (size_t)larg;
+        return l;
+    case SSL_CTRL_GET_SESS_CACHE_SIZE:
+        return (long)ctx->session_cache_size;
+    case SSL_CTRL_SET_SESS_CACHE_MODE:
+        l = ctx->session_cache_mode;
+        ctx->session_cache_mode = larg;
+        return l;
+    case SSL_CTRL_GET_SESS_CACHE_MODE:
+        return ctx->session_cache_mode;
+
+    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);
+    case SSL_CTRL_SESS_CONNECT_GOOD:
+        return tsan_load(&ctx->stats.sess_connect_good);
+    case SSL_CTRL_SESS_CONNECT_RENEGOTIATE:
+        return tsan_load(&ctx->stats.sess_connect_renegotiate);
+    case SSL_CTRL_SESS_ACCEPT:
+        return tsan_load(&ctx->stats.sess_accept);
+    case SSL_CTRL_SESS_ACCEPT_GOOD:
+        return tsan_load(&ctx->stats.sess_accept_good);
+    case SSL_CTRL_SESS_ACCEPT_RENEGOTIATE:
+        return tsan_load(&ctx->stats.sess_accept_renegotiate);
+    case SSL_CTRL_SESS_HIT:
+        return tsan_load(&ctx->stats.sess_hit);
+    case SSL_CTRL_SESS_CB_HIT:
+        return tsan_load(&ctx->stats.sess_cb_hit);
+    case SSL_CTRL_SESS_MISSES:
+        return tsan_load(&ctx->stats.sess_miss);
+    case SSL_CTRL_SESS_TIMEOUTS:
+        return tsan_load(&ctx->stats.sess_timeout);
+    case SSL_CTRL_SESS_CACHE_FULL:
+        return tsan_load(&ctx->stats.sess_cache_full);
+    case SSL_CTRL_MODE:
+        return (ctx->mode |= larg);
+    case SSL_CTRL_CLEAR_MODE:
+        return (ctx->mode &= ~larg);
+    case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
+        if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
+            return 0;
+        ctx->max_send_fragment = larg;
+        if (ctx->max_send_fragment < ctx->split_send_fragment)
+            ctx->split_send_fragment = ctx->max_send_fragment;
+        return 1;
+    case SSL_CTRL_SET_SPLIT_SEND_FRAGMENT:
+        if ((size_t)larg > ctx->max_send_fragment || larg == 0)
+            return 0;
+        ctx->split_send_fragment = larg;
+        return 1;
+    case SSL_CTRL_SET_MAX_PIPELINES:
+        if (larg < 1 || larg > SSL_MAX_PIPELINES)
+            return 0;
+        ctx->max_pipelines = larg;
+        return 1;
+    case SSL_CTRL_CERT_FLAGS:
+        return (ctx->cert->cert_flags |= larg);
+    case SSL_CTRL_CLEAR_CERT_FLAGS:
+        return (ctx->cert->cert_flags &= ~larg);
+    case SSL_CTRL_SET_MIN_PROTO_VERSION:
+        return ssl_check_allowed_versions(larg, ctx->max_proto_version)
+               && ssl_set_version_bound(ctx->method->version, (int)larg,
+                                        &ctx->min_proto_version);
+    case SSL_CTRL_GET_MIN_PROTO_VERSION:
+        return ctx->min_proto_version;
+    case SSL_CTRL_SET_MAX_PROTO_VERSION:
+        return ssl_check_allowed_versions(ctx->min_proto_version, larg)
+               && ssl_set_version_bound(ctx->method->version, (int)larg,
+                                        &ctx->max_proto_version);
+    case SSL_CTRL_GET_MAX_PROTO_VERSION:
+        return ctx->max_proto_version;
+    default:
+        return ctx->method->ssl_ctx_ctrl(ctx, cmd, larg, parg);
+    }
+}
+
+long SSL_CTX_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp) (void))
+{
+    switch (cmd) {
+    case SSL_CTRL_SET_MSG_CALLBACK:
+        ctx->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 ctx->method->ssl_ctx_callback_ctrl(ctx, cmd, fp);
+    }
+}
+
+int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b)
+{
+    if (a->id > b->id)
+        return 1;
+    if (a->id < b->id)
+        return -1;
+    return 0;
+}
+
+int ssl_cipher_ptr_id_cmp(const SSL_CIPHER *const *ap,
+                          const SSL_CIPHER *const *bp)
+{
+    if ((*ap)->id > (*bp)->id)
+        return 1;
+    if ((*ap)->id < (*bp)->id)
+        return -1;
+    return 0;
+}
+
+/** 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;
+        } else if ((s->ctx != NULL) && (s->ctx->cipher_list != NULL)) {
+            return s->ctx->cipher_list;
+        }
+    }
+    return NULL;
+}
+
+STACK_OF(SSL_CIPHER) *SSL_get_client_ciphers(const SSL *s)
+{
+    if ((s == NULL) || !s->server)
+        return NULL;
+    return s->peer_ciphers;
+}
+
+STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s)
+{
+    STACK_OF(SSL_CIPHER) *sk = NULL, *ciphers;
+    int i;
+
+    ciphers = SSL_get_ciphers(s);
+    if (!ciphers)
+        return NULL;
+    if (!ssl_set_client_disabled(s))
+        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 (!sk)
+                sk = sk_SSL_CIPHER_new_null();
+            if (!sk)
+                return NULL;
+            if (!sk_SSL_CIPHER_push(sk, c)) {
+                sk_SSL_CIPHER_free(sk);
+                return NULL;
+            }
+        }
+    }
+    return sk;
+}
+
+/** 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)
+{
+    if (s != 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;
+        }
+    }
+    return NULL;
+}
+
+/** The old interface to get the same thing as SSL_get_ciphers() */
+const char *SSL_get_cipher_list(const SSL *s, int n)
+{
+    const SSL_CIPHER *c;
+    STACK_OF(SSL_CIPHER) *sk;
+
+    if (s == NULL)
+        return NULL;
+    sk = SSL_get_ciphers(s);
+    if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= n))
+        return NULL;
+    c = sk_SSL_CIPHER_value(sk, n);
+    if (c == NULL)
+        return NULL;
+    return c->name;
+}
+
+/** return a STACK of the ciphers available for the SSL_CTX and in order of
+ * preference */
+STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx)
+{
+    if (ctx != NULL)
+        return ctx->cipher_list;
+    return NULL;
+}
+
+/*
+ * Distinguish between ciphers controlled by set_ciphersuite() and
+ * set_cipher_list() when counting.
+ */
+static int cipher_list_tls12_num(STACK_OF(SSL_CIPHER) *sk)
+{
+    int i, num = 0;
+    const SSL_CIPHER *c;
+
+    if (sk == NULL)
+        return 0;
+    for (i = 0; i < sk_SSL_CIPHER_num(sk); ++i) {
+        c = sk_SSL_CIPHER_value(sk, i);
+        if (c->min_tls >= TLS1_3_VERSION)
+            continue;
+        num++;
+    }
+    return num;
+}
+
+/** specify the ciphers to be used by default by the SSL_CTX */
+int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str)
+{
+    STACK_OF(SSL_CIPHER) *sk;
+
+    sk = ssl_create_cipher_list(ctx->method, ctx->tls13_ciphersuites,
+                                &ctx->cipher_list, &ctx->cipher_list_by_id, str,
+                                ctx->cert);
+    /*
+     * ssl_create_cipher_list may return an empty stack if it was unable to
+     * find a cipher matching the given rule string (for example if the rule
+     * string specifies a cipher which has been disabled). This is not an
+     * error as far as ssl_create_cipher_list is concerned, and hence
+     * ctx->cipher_list and ctx->cipher_list_by_id has been updated.
+     */
+    if (sk == NULL)
+        return 0;
+    else if (cipher_list_tls12_num(sk) == 0) {
+        SSLerr(SSL_F_SSL_CTX_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH);
+        return 0;
+    }
+    return 1;
+}
+
+/** specify the ciphers to be used by the SSL */
+int SSL_set_cipher_list(SSL *s, const char *str)
+{
+    STACK_OF(SSL_CIPHER) *sk;
+
+    sk = ssl_create_cipher_list(s->ctx->method, s->tls13_ciphersuites,
+                                &s->cipher_list, &s->cipher_list_by_id, str,
+                                s->cert);
+    /* see comment in SSL_CTX_set_cipher_list */
+    if (sk == NULL)
+        return 0;
+    else if (cipher_list_tls12_num(sk) == 0) {
+        SSLerr(SSL_F_SSL_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH);
+        return 0;
+    }
+    return 1;
+}
+
+char *SSL_get_shared_ciphers(const SSL *s, char *buf, int size)
+{
+    char *p;
+    STACK_OF(SSL_CIPHER) *clntsk, *srvrsk;
+    const SSL_CIPHER *c;
+    int i;
+
+    if (!s->server
+            || s->peer_ciphers == NULL
+            || size < 2)
+        return NULL;
+
+    p = buf;
+    clntsk = s->peer_ciphers;
+    srvrsk = SSL_get_ciphers(s);
+    if (clntsk == NULL || srvrsk == NULL)
+        return NULL;
+
+    if (sk_SSL_CIPHER_num(clntsk) == 0 || sk_SSL_CIPHER_num(srvrsk) == 0)
+        return NULL;
+
+    for (i = 0; i < sk_SSL_CIPHER_num(clntsk); i++) {
+        int n;
+
+        c = sk_SSL_CIPHER_value(clntsk, i);
+        if (sk_SSL_CIPHER_find(srvrsk, c) < 0)
+            continue;
+
+        n = strlen(c->name);
+        if (n + 1 > size) {
+            if (p != buf)
+                --p;
+            *p = '\0';
+            return buf;
+        }
+        strcpy(p, c->name);
+        p += n;
+        *(p++) = ':';
+        size -= n + 1;
+    }
+    p[-1] = '\0';
+    return buf;
+}
+
+/**
+ * Return the requested servername (SNI) value. Note that the behaviour varies
+ * depending on:
+ * - whether this is called by the client or the server,
+ * - 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)
+{
+    /*
+     * 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;
+    if (type != TLSEXT_NAMETYPE_host_name)
+        return NULL;
+
+    if (server) {
+        /**
+         * Server side
+         * In TLSv1.3 on the server SNI is not associated with the session
+         * but in TLSv1.2 or below it is.
+         *
+         * Before the handshake:
+         *  - return NULL
+         *
+         * During/after the handshake (TLSv1.2 or below resumption occurred):
+         * - If a servername was accepted by the server in the original
+         *   handshake then it will return that servername, or NULL otherwise.
+         *
+         * During/after the handshake (TLSv1.2 or below resumption did not occur):
+         * - 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;
+    } else {
+        /**
+         * Client side
+         *
+         * Before the handshake:
+         *  - If a servername has been set via a call to
+         *    SSL_set_tlsext_host_name() then it will return that servername
+         *  - If one has not been set, but a TLSv1.2 resumption is being
+         *    attempted and the session from the original handshake had a
+         *    servername accepted by the server then it will return that
+         *    servername
+         *  - Otherwise it returns NULL
+         *
+         * During/after the handshake (TLSv1.2 or below resumption occurred):
+         * - If the session from the original handshake had a servername accepted
+         *   by the server then it will return that servername.
+         * - Otherwise it returns the servername set via
+         *   SSL_set_tlsext_host_name() (or NULL if it was not called).
+         *
+         * During/after the handshake (TLSv1.2 or below resumption did not occur):
+         * - It will return the servername set via SSL_set_tlsext_host_name()
+         *   (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;
+        } else {
+            if (!SSL_IS_TLS13(s) && s->hit && s->session->ext.hostname != NULL)
+                return s->session->ext.hostname;
+        }
+    }
+
+    return s->ext.hostname;
+}
+
+int SSL_get_servername_type(const SSL *s)
+{
+    if (SSL_get_servername(s, TLSEXT_NAMETYPE_host_name) != NULL)
+        return TLSEXT_NAMETYPE_host_name;
+    return -1;
+}
+
+/*
+ * SSL_select_next_proto implements the standard protocol selection. It is
+ * expected that this function is called from the callback set by
+ * SSL_CTX_set_next_proto_select_cb. The protocol data is assumed to be a
+ * vector of 8-bit, length prefixed byte strings. The length byte itself is
+ * not included in the length. A byte string of length 0 is invalid. No byte
+ * string may be truncated. The current, but experimental algorithm for
+ * selecting the protocol is: 1) If the server doesn't support NPN then this
+ * is indicated to the callback. In this case, the client application has to
+ * abort the connection or have a default application level protocol. 2) If
+ * the server supports NPN, but advertises an empty list then the client
+ * selects the first protocol in its list, but indicates via the API that this
+ * fallback case was enacted. 3) Otherwise, the client finds the first
+ * protocol in the server's list that it supports and selects this protocol.
+ * This is because it's assumed that the server has better information about
+ * which protocol a client should use. 4) If the client doesn't support any
+ * of the server's advertised protocols, then this is treated the same as
+ * case 2. It returns either OPENSSL_NPN_NEGOTIATED if a common protocol was
+ * found, or OPENSSL_NPN_NO_OVERLAP if the fallback case was reached.
+ */
+int SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
+                          const unsigned char *server,
+                          unsigned int server_len,
+                          const unsigned char *client, unsigned int client_len)
+{
+    unsigned int i, j;
+    const unsigned char *result;
+    int status = OPENSSL_NPN_UNSUPPORTED;
+
+    /*
+     * For each protocol in server preference order, see if we support it.
+     */
+    for (i = 0; i < server_len;) {
+        for (j = 0; j < client_len;) {
+            if (server[i] == client[j] &&
+                memcmp(&server[i + 1], &client[j + 1], server[i]) == 0) {
+                /* We found a match */
+                result = &server[i];
+                status = OPENSSL_NPN_NEGOTIATED;
+                goto found;
+            }
+            j += client[j];
+            j++;
+        }
+        i += server[i];
+        i++;
+    }
+
+    /* There's no overlap between our protocols and the server's list. */
+    result = client;
+    status = OPENSSL_NPN_NO_OVERLAP;
+
+ found:
+    *out = (unsigned char *)result + 1;
+    *outlen = result[0];
+    return status;
+}
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+/*
+ * SSL_get0_next_proto_negotiated sets *data and *len to point to the
+ * client's requested protocol for this connection and returns 0. If the
+ * client didn't request any protocol, then *data is set to NULL. Note that
+ * the client can request any protocol it chooses. The value returned from
+ * this function need not be a member of the list of supported protocols
+ * provided by the callback.
+ */
+void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data,
+                                    unsigned *len)
+{
+    *data = s->ext.npn;
+    if (!*data) {
+        *len = 0;
+    } else {
+        *len = (unsigned int)s->ext.npn_len;
+    }
+}
+
+/*
+ * SSL_CTX_set_npn_advertised_cb sets a callback that is called when
+ * a TLS server needs a list of supported protocols for Next Protocol
+ * Negotiation. The returned list must be in wire format.  The list is
+ * returned by setting |out| to point to it and |outlen| to its length. This
+ * memory will not be modified, but one should assume that the SSL* keeps a
+ * reference to it. The callback should return SSL_TLSEXT_ERR_OK if it
+ * wishes to advertise. Otherwise, no such extension will be included in the
+ * ServerHello.
+ */
+void SSL_CTX_set_npn_advertised_cb(SSL_CTX *ctx,
+                                   SSL_CTX_npn_advertised_cb_func cb,
+                                   void *arg)
+{
+    ctx->ext.npn_advertised_cb = cb;
+    ctx->ext.npn_advertised_cb_arg = arg;
+}
+
+/*
+ * SSL_CTX_set_next_proto_select_cb sets a callback that is called when a
+ * client needs to select a protocol from the server's provided list. |out|
+ * must be set to point to the selected protocol (which may be within |in|).
+ * The length of the protocol name must be written into |outlen|. The
+ * server's advertised protocols are provided in |in| and |inlen|. The
+ * callback can assume that |in| is syntactically valid. The client must
+ * select a protocol. It is fatal to the connection if this callback returns
+ * a value other than SSL_TLSEXT_ERR_OK.
+ */
+void SSL_CTX_set_npn_select_cb(SSL_CTX *ctx,
+                               SSL_CTX_npn_select_cb_func cb,
+                               void *arg)
+{
+    ctx->ext.npn_select_cb = cb;
+    ctx->ext.npn_select_cb_arg = arg;
+}
+#endif
+
+static int alpn_value_ok(const unsigned char *protos, unsigned int protos_len)
+{
+    unsigned int idx;
+
+    if (protos_len < 2 || protos == NULL)
+        return 0;
+
+    for (idx = 0; idx < protos_len; idx += protos[idx] + 1) {
+        if (protos[idx] == 0)
+            return 0;
+    }
+    return idx == protos_len;
+}
+/*
+ * SSL_CTX_set_alpn_protos sets the ALPN protocol list on |ctx| to |protos|.
+ * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
+ * length-prefixed strings). Returns 0 on success.
+ */
+int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos,
+                            unsigned int protos_len)
+{
+    unsigned char *alpn;
+
+    if (protos_len == 0 || protos == NULL) {
+        OPENSSL_free(ctx->ext.alpn);
+        ctx->ext.alpn = NULL;
+        ctx->ext.alpn_len = 0;
+        return 0;
+    }
+    /* Not valid per RFC */
+    if (!alpn_value_ok(protos, protos_len))
+        return 1;
+
+    alpn = OPENSSL_memdup(protos, protos_len);
+    if (alpn == NULL) {
+        SSLerr(SSL_F_SSL_CTX_SET_ALPN_PROTOS, ERR_R_MALLOC_FAILURE);
+        return 1;
+    }
+    OPENSSL_free(ctx->ext.alpn);
+    ctx->ext.alpn = alpn;
+    ctx->ext.alpn_len = protos_len;
+
+    return 0;
+}
+
+/*
+ * SSL_set_alpn_protos sets the ALPN protocol list on |ssl| to |protos|.
+ * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
+ * length-prefixed strings). Returns 0 on success.
+ */
+int SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos,
+                        unsigned int protos_len)
+{
+    unsigned char *alpn;
+
+    if (protos_len == 0 || protos == NULL) {
+        OPENSSL_free(ssl->ext.alpn);
+        ssl->ext.alpn = NULL;
+        ssl->ext.alpn_len = 0;
+        return 0;
+    }
+    /* Not valid per RFC */
+    if (!alpn_value_ok(protos, protos_len))
+        return 1;
+
+    alpn = OPENSSL_memdup(protos, protos_len);
+    if (alpn == NULL) {
+        SSLerr(SSL_F_SSL_SET_ALPN_PROTOS, ERR_R_MALLOC_FAILURE);
+        return 1;
+    }
+    OPENSSL_free(ssl->ext.alpn);
+    ssl->ext.alpn = alpn;
+    ssl->ext.alpn_len = protos_len;
+
+    return 0;
+}
+
+/*
+ * SSL_CTX_set_alpn_select_cb sets a callback function on |ctx| that is
+ * called during ClientHello processing in order to select an ALPN protocol
+ * from the client's list of offered protocols.
+ */
+void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx,
+                                SSL_CTX_alpn_select_cb_func cb,
+                                void *arg)
+{
+    ctx->ext.alpn_select_cb = cb;
+    ctx->ext.alpn_select_cb_arg = arg;
+}
+
+/*
+ * SSL_get0_alpn_selected gets the selected ALPN protocol (if any) from |ssl|.
+ * On return it sets |*data| to point to |*len| bytes of protocol name
+ * (not including the leading length-prefix byte). If the server didn't
+ * respond with a negotiated protocol then |*len| will be zero.
+ */
+void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
+                            unsigned int *len)
+{
+    *data = NULL;
+    if (ssl->s3)
+        *data = ssl->s3->alpn_selected;
+    if (*data == NULL)
+        *len = 0;
+    else
+        *len = (unsigned int)ssl->s3->alpn_selected_len;
+}
+
+int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
+                               const char *label, size_t llen,
+                               const unsigned char *context, size_t contextlen,
+                               int use_context)
+{
+    if (s->session == NULL
+        || (s->version < TLS1_VERSION && s->version != DTLS1_BAD_VER))
+        return -1;
+
+    return s->method->ssl3_enc->export_keying_material(s, out, olen, label,
+                                                       llen, context,
+                                                       contextlen, use_context);
+}
+
+int SSL_export_keying_material_early(SSL *s, unsigned char *out, size_t olen,
+                                     const char *label, size_t llen,
+                                     const unsigned char *context,
+                                     size_t contextlen)
+{
+    if (s->version != TLS1_3_VERSION)
+        return 0;
+
+    return tls13_export_keying_material_early(s, out, olen, label, llen,
+                                              context, contextlen);
+}
+
+static unsigned long ssl_session_hash(const SSL_SESSION *a)
+{
+    const unsigned char *session_id = a->session_id;
+    unsigned long l;
+    unsigned char tmp_storage[4];
+
+    if (a->session_id_length < sizeof(tmp_storage)) {
+        memset(tmp_storage, 0, sizeof(tmp_storage));
+        memcpy(tmp_storage, a->session_id, a->session_id_length);
+        session_id = tmp_storage;
+    }
+
+    l = (unsigned long)
+        ((unsigned long)session_id[0]) |
+        ((unsigned long)session_id[1] << 8L) |
+        ((unsigned long)session_id[2] << 16L) |
+        ((unsigned long)session_id[3] << 24L);
+    return l;
+}
+
+/*
+ * NB: If this function (or indeed the hash function which uses a sort of
+ * coarser function than this one) is changed, ensure
+ * SSL_CTX_has_matching_session_id() is checked accordingly. It relies on
+ * being able to construct an SSL_SESSION that will collide with any existing
+ * session with a matching session ID.
+ */
+static int ssl_session_cmp(const SSL_SESSION *a, const SSL_SESSION *b)
+{
+    if (a->ssl_version != b->ssl_version)
+        return 1;
+    if (a->session_id_length != b->session_id_length)
+        return 1;
+    return memcmp(a->session_id, b->session_id, a->session_id_length);
+}
+
+/*
+ * These wrapper functions should remain rather than redeclaring
+ * SSL_SESSION_hash and SSL_SESSION_cmp for void* types and casting each
+ * variable. The reason is that the functions aren't static, they're exposed
+ * via ssl.h.
+ */
+
+SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
+{
+    SSL_CTX *ret = NULL;
+
+    if (meth == NULL) {
+        SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_NULL_SSL_METHOD_PASSED);
+        return NULL;
+    }
+
+    if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL))
+        return NULL;
+
+    if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0) {
+        SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
+        goto err;
+    }
+    ret = OPENSSL_zalloc(sizeof(*ret));
+    if (ret == NULL)
+        goto err;
+
+    ret->method = meth;
+    ret->min_proto_version = 0;
+    ret->max_proto_version = 0;
+    ret->mode = SSL_MODE_AUTO_RETRY;
+    ret->session_cache_mode = SSL_SESS_CACHE_SERVER;
+    ret->session_cache_size = SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;
+    /* We take the system default. */
+    ret->session_timeout = meth->get_timeout();
+    ret->references = 1;
+    ret->lock = CRYPTO_THREAD_lock_new();
+    if (ret->lock == NULL) {
+        SSLerr(SSL_F_SSL_CTX_NEW, ERR_R_MALLOC_FAILURE);
+        OPENSSL_free(ret);
+        return NULL;
+    }
+    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)
+        goto err;
+    ret->cert_store = X509_STORE_new();
+    if (ret->cert_store == NULL)
+        goto err;
+#ifndef OPENSSL_NO_CT
+    ret->ctlog_store = CTLOG_STORE_new();
+    if (ret->ctlog_store == NULL)
+        goto err;
+#endif
+
+    if (!SSL_CTX_set_ciphersuites(ret, TLS_DEFAULT_CIPHERSUITES))
+        goto err;
+
+    if (!ssl_create_cipher_list(ret->method,
+                                ret->tls13_ciphersuites,
+                                &ret->cipher_list, &ret->cipher_list_by_id,
+                                SSL_DEFAULT_CIPHER_LIST, ret->cert)
+        || sk_SSL_CIPHER_num(ret->cipher_list) <= 0) {
+        SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_LIBRARY_HAS_NO_CIPHERS);
+        goto err2;
+    }
+
+    ret->param = X509_VERIFY_PARAM_new();
+    if (ret->param == NULL)
+        goto err;
+
+    if ((ret->md5 = EVP_get_digestbyname("ssl3-md5")) == NULL) {
+        SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES);
+        goto err2;
+    }
+    if ((ret->sha1 = EVP_get_digestbyname("ssl3-sha1")) == NULL) {
+        SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES);
+        goto err2;
+    }
+
+    if ((ret->ca_names = sk_X509_NAME_new_null()) == NULL)
+        goto err;
+
+    if ((ret->client_ca_names = sk_X509_NAME_new_null()) == NULL)
+        goto err;
+
+    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_CTX, ret, &ret->ex_data))
+        goto err;
+
+    if ((ret->ext.secure = OPENSSL_secure_zalloc(sizeof(*ret->ext.secure))) == NULL)
+        goto err;
+
+    /* No compression for DTLS */
+    if (!(meth->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS))
+        ret->comp_methods = SSL_COMP_get_compression_methods();
+
+    ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
+    ret->split_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
+
+    /* Setup RFC5077 ticket keys */
+    if ((RAND_bytes(ret->ext.tick_key_name,
+                    sizeof(ret->ext.tick_key_name)) <= 0)
+        || (RAND_priv_bytes(ret->ext.secure->tick_hmac_key,
+                       sizeof(ret->ext.secure->tick_hmac_key)) <= 0)
+        || (RAND_priv_bytes(ret->ext.secure->tick_aes_key,
+                       sizeof(ret->ext.secure->tick_aes_key)) <= 0))
+        ret->options |= SSL_OP_NO_TICKET;
+
+    if (RAND_priv_bytes(ret->ext.cookie_hmac_key,
+                   sizeof(ret->ext.cookie_hmac_key)) <= 0)
+        goto err;
+
+#ifndef OPENSSL_NO_SRP
+    if (!SSL_CTX_SRP_CTX_init(ret))
+        goto err;
+#endif
+#ifndef OPENSSL_NO_ENGINE
+# ifdef OPENSSL_SSL_CLIENT_ENGINE_AUTO
+#  define eng_strx(x)     #x
+#  define eng_str(x)      eng_strx(x)
+    /* Use specific client engine automatically... ignore errors */
+    {
+        ENGINE *eng;
+        eng = ENGINE_by_id(eng_str(OPENSSL_SSL_CLIENT_ENGINE_AUTO));
+        if (!eng) {
+            ERR_clear_error();
+            ENGINE_load_builtin_engines();
+            eng = ENGINE_by_id(eng_str(OPENSSL_SSL_CLIENT_ENGINE_AUTO));
+        }
+        if (!eng || !SSL_CTX_set_client_cert_engine(ret, eng))
+            ERR_clear_error();
+    }
+# endif
+#endif
+    /*
+     * Default is to connect to non-RI servers. When RI is more widely
+     * deployed might change this.
+     */
+    ret->options |= SSL_OP_LEGACY_SERVER_CONNECT;
+    /*
+     * Disable compression by default to prevent CRIME. Applications can
+     * re-enable compression by configuring
+     * SSL_CTX_clear_options(ctx, SSL_OP_NO_COMPRESSION);
+     * or by using the SSL_CONF library. Similarly we also enable TLSv1.3
+     * middlebox compatibility by default. This may be disabled by default in
+     * a later OpenSSL version.
+     */
+    ret->options |= SSL_OP_NO_COMPRESSION | SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
+
+    ret->ext.status_type = TLSEXT_STATUSTYPE_nothing;
+
+    /*
+     * We cannot usefully set a default max_early_data here (which gets
+     * propagated in SSL_new(), for the following reason: setting the
+     * SSL field causes tls_construct_stoc_early_data() to tell the
+     * client that early data will be accepted when constructing a TLS 1.3
+     * session ticket, and the client will accordingly send us early data
+     * when using that ticket (if the client has early data to send).
+     * However, in order for the early data to actually be consumed by
+     * the application, the application must also have calls to
+     * SSL_read_early_data(); otherwise we'll just skip past the early data
+     * and ignore it.  So, since the application must add calls to
+     * SSL_read_early_data(), we also require them to add
+     * calls to SSL_CTX_set_max_early_data() in order to use early data,
+     * eliminating the bandwidth-wasting early data in the case described
+     * above.
+     */
+    ret->max_early_data = 0;
+
+    /*
+     * Default recv_max_early_data is a fully loaded single record. Could be
+     * split across multiple records in practice. We set this differently to
+     * max_early_data so that, in the default case, we do not advertise any
+     * support for early_data, but if a client were to send us some (e.g.
+     * because of an old, stale ticket) then we will tolerate it and skip over
+     * it.
+     */
+    ret->recv_max_early_data = SSL3_RT_MAX_PLAIN_LENGTH;
+
+    /* By default we send two session tickets automatically in TLSv1.3 */
+    ret->num_tickets = 2;
+
+    ssl_ctx_system_config(ret);
+
+    return ret;
+ err:
+    SSLerr(SSL_F_SSL_CTX_NEW, ERR_R_MALLOC_FAILURE);
+ err2:
+    SSL_CTX_free(ret);
+    return NULL;
+}
+
+int SSL_CTX_up_ref(SSL_CTX *ctx)
+{
+    int i;
+
+    if (CRYPTO_UP_REF(&ctx->references, &i, ctx->lock) <= 0)
+        return 0;
+
+    REF_PRINT_COUNT("SSL_CTX", ctx);
+    REF_ASSERT_ISNT(i < 2);
+    return ((i > 1) ? 1 : 0);
+}
+
+void SSL_CTX_free(SSL_CTX *a)
+{
+    int i;
+
+    if (a == NULL)
+        return;
+
+    CRYPTO_DOWN_REF(&a->references, &i, a->lock);
+    REF_PRINT_COUNT("SSL_CTX", a);
+    if (i > 0)
+        return;
+    REF_ASSERT_ISNT(i < 0);
+
+    X509_VERIFY_PARAM_free(a->param);
+    dane_ctx_final(&a->dane);
+
+    /*
+     * Free internal session cache. However: the remove_cb() may reference
+     * the ex_data of SSL_CTX, thus the ex_data store can only be removed
+     * after the sessions were flushed.
+     * As the ex_data handling routines might also touch the session cache,
+     * the most secure solution seems to be: empty (flush) the cache, then
+     * free ex_data, then finally free the cache.
+     * (See ticket [openssl.org #212].)
+     */
+    if (a->sessions != NULL)
+        SSL_CTX_flush_sessions(a, 0);
+
+    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_CTX, a, &a->ex_data);
+    lh_SSL_SESSION_free(a->sessions);
+    X509_STORE_free(a->cert_store);
+#ifndef OPENSSL_NO_CT
+    CTLOG_STORE_free(a->ctlog_store);
+#endif
+    sk_SSL_CIPHER_free(a->cipher_list);
+    sk_SSL_CIPHER_free(a->cipher_list_by_id);
+    sk_SSL_CIPHER_free(a->tls13_ciphersuites);
+    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);
+    a->comp_methods = NULL;
+#ifndef OPENSSL_NO_SRTP
+    sk_SRTP_PROTECTION_PROFILE_free(a->srtp_profiles);
+#endif
+#ifndef OPENSSL_NO_SRP
+    SSL_CTX_SRP_CTX_free(a);
+#endif
+#ifndef OPENSSL_NO_ENGINE
+    ENGINE_finish(a->client_cert_engine);
+#endif
+
+#ifndef OPENSSL_NO_EC
+    OPENSSL_free(a->ext.ecpointformats);
+    OPENSSL_free(a->ext.supportedgroups);
+#endif
+    OPENSSL_free(a->ext.alpn);
+    OPENSSL_secure_free(a->ext.secure);
+
+    CRYPTO_THREAD_lock_free(a->lock);
+
+    OPENSSL_free(a);
+}
+
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb)
+{
+    ctx->default_passwd_callback = cb;
+}
+
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u)
+{
+    ctx->default_passwd_callback_userdata = u;
+}
+
+pem_password_cb *SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx)
+{
+    return ctx->default_passwd_callback;
+}
+
+void *SSL_CTX_get_default_passwd_cb_userdata(SSL_CTX *ctx)
+{
+    return ctx->default_passwd_callback_userdata;
+}
+
+void SSL_set_default_passwd_cb(SSL *s, pem_password_cb *cb)
+{
+    s->default_passwd_callback = cb;
+}
+
+void SSL_set_default_passwd_cb_userdata(SSL *s, void *u)
+{
+    s->default_passwd_callback_userdata = u;
+}
+
+pem_password_cb *SSL_get_default_passwd_cb(SSL *s)
+{
+    return s->default_passwd_callback;
+}
+
+void *SSL_get_default_passwd_cb_userdata(SSL *s)
+{
+    return s->default_passwd_callback_userdata;
+}
+
+void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx,
+                                      int (*cb) (X509_STORE_CTX *, void *),
+                                      void *arg)
+{
+    ctx->app_verify_callback = cb;
+    ctx->app_verify_arg = arg;
+}
+
+void SSL_CTX_set_verify(SSL_CTX *ctx, int mode,
+                        int (*cb) (int, X509_STORE_CTX *))
+{
+    ctx->verify_mode = mode;
+    ctx->default_verify_callback = cb;
+}
+
+void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth)
+{
+    X509_VERIFY_PARAM_set_depth(ctx->param, depth);
+}
+
+void SSL_CTX_set_cert_cb(SSL_CTX *c, int (*cb) (SSL *ssl, void *arg), void *arg)
+{
+    ssl_cert_set_cert_cb(c->cert, cb, 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);
+}
+
+void ssl_set_masks(SSL *s)
+{
+    CERT *c = s->cert;
+    uint32_t *pvalid = s->s3->tmp.valid_flags;
+    int rsa_enc, rsa_sign, dh_tmp, dsa_sign;
+    unsigned long mask_k, mask_a;
+#ifndef OPENSSL_NO_EC
+    int have_ecc_cert, ecdsa_ok;
+#endif
+    if (c == NULL)
+        return;
+
+#ifndef OPENSSL_NO_DH
+    dh_tmp = (c->dh_tmp != NULL || c->dh_tmp_cb != NULL || c->dh_tmp_auto);
+#else
+    dh_tmp = 0;
+#endif
+
+    rsa_enc = pvalid[SSL_PKEY_RSA] & CERT_PKEY_VALID;
+    rsa_sign = pvalid[SSL_PKEY_RSA] & CERT_PKEY_VALID;
+    dsa_sign = pvalid[SSL_PKEY_DSA_SIGN] & CERT_PKEY_VALID;
+#ifndef OPENSSL_NO_EC
+    have_ecc_cert = pvalid[SSL_PKEY_ECC] & CERT_PKEY_VALID;
+#endif
+    mask_k = 0;
+    mask_a = 0;
+
+#ifdef CIPHER_DEBUG
+    fprintf(stderr, "dht=%d re=%d rs=%d ds=%d\n",
+            dh_tmp, rsa_enc, rsa_sign, dsa_sign);
+#endif
+
+#ifndef OPENSSL_NO_GOST
+    if (ssl_has_cert(s, SSL_PKEY_GOST12_512)) {
+        mask_k |= SSL_kGOST;
+        mask_a |= SSL_aGOST12;
+    }
+    if (ssl_has_cert(s, SSL_PKEY_GOST12_256)) {
+        mask_k |= SSL_kGOST;
+        mask_a |= SSL_aGOST12;
+    }
+    if (ssl_has_cert(s, SSL_PKEY_GOST01)) {
+        mask_k |= SSL_kGOST;
+        mask_a |= SSL_aGOST01;
+    }
+#endif
+
+    if (rsa_enc)
+        mask_k |= SSL_kRSA;
+
+    if (dh_tmp)
+        mask_k |= SSL_kDHE;
+
+    /*
+     * If we only have an RSA-PSS certificate allow RSA authentication
+     * if TLS 1.2 and peer supports it.
+     */
+
+    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))
+        mask_a |= SSL_aRSA;
+
+    if (dsa_sign) {
+        mask_a |= SSL_aDSS;
+    }
+
+    mask_a |= SSL_aNULL;
+
+    /*
+     * An ECC certificate may be usable for ECDH and/or ECDSA cipher suites
+     * depending on the key usage extension.
+     */
+#ifndef OPENSSL_NO_EC
+    if (have_ecc_cert) {
+        uint32_t ex_kusage;
+        ex_kusage = X509_get_key_usage(c->pkeys[SSL_PKEY_ECC].x509);
+        ecdsa_ok = ex_kusage & X509v3_KU_DIGITAL_SIGNATURE;
+        if (!(pvalid[SSL_PKEY_ECC] & CERT_PKEY_SIGN))
+            ecdsa_ok = 0;
+        if (ecdsa_ok)
+            mask_a |= SSL_aECDSA;
+    }
+    /* 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)
+            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)
+            mask_a |= SSL_aECDSA;
+#endif
+
+#ifndef OPENSSL_NO_EC
+    mask_k |= SSL_kECDHE;
+#endif
+
+#ifndef OPENSSL_NO_PSK
+    mask_k |= SSL_kPSK;
+    mask_a |= SSL_aPSK;
+    if (mask_k & SSL_kRSA)
+        mask_k |= SSL_kRSAPSK;
+    if (mask_k & SSL_kDHE)
+        mask_k |= SSL_kDHEPSK;
+    if (mask_k & SSL_kECDHE)
+        mask_k |= SSL_kECDHEPSK;
+#endif
+
+    s->s3->tmp.mask_k = mask_k;
+    s->s3->tmp.mask_a = mask_a;
+}
+
+#ifndef OPENSSL_NO_EC
+
+int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
+{
+    if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aECDSA) {
+        /* key usage, if present, must allow signing */
+        if (!(X509_get_key_usage(x) & X509v3_KU_DIGITAL_SIGNATURE)) {
+            SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG,
+                   SSL_R_ECC_CERT_NOT_FOR_SIGNING);
+            return 0;
+        }
+    }
+    return 1;                   /* all checks are ok */
+}
+
+#endif
+
+int ssl_get_server_cert_serverinfo(SSL *s, const unsigned char **serverinfo,
+                                   size_t *serverinfo_length)
+{
+    CERT_PKEY *cpk = s->s3->tmp.cert;
+    *serverinfo_length = 0;
+
+    if (cpk == NULL || cpk->serverinfo == NULL)
+        return 0;
+
+    *serverinfo = cpk->serverinfo;
+    *serverinfo_length = cpk->serverinfo_length;
+    return 1;
+}
+
+void ssl_update_cache(SSL *s, int mode)
+{
+    int i;
+
+    /*
+     * If the session_id_length is 0, we are not supposed to cache it, and it
+     * would be rather hard to do anyway :-)
+     */
+    if (s->session->session_id_length == 0)
+        return;
+
+    /*
+     * If sid_ctx_length is 0 there is no specific application context
+     * associated with this session, so when we try to resume it and
+     * SSL_VERIFY_PEER is requested to verify the client identity, we have no
+     * indication that this is actually a session for the proper application
+     * context, and the *handshake* will fail, not just the resumption attempt.
+     * Do not cache (on the server) these sessions that are not resumable
+     * (clients can set SSL_VERIFY_PEER without needing a sid_ctx set).
+     */
+    if (s->server && s->session->sid_ctx_length == 0
+            && (s->verify_mode & SSL_VERIFY_PEER) != 0)
+        return;
+
+    i = s->session_ctx->session_cache_mode;
+    if ((i & mode) != 0
+        && (!s->hit || SSL_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
+         * with only a dummy session id so there is no reason to cache it,
+         * unless:
+         * - we are doing early_data, in which case we cache so that we can
+         *   detect replays
+         * - the application has set a remove_session_cb so needs to know about
+         *   session timeout events
+         * - 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)
+                    || !s->server
+                    || (s->max_early_data > 0
+                        && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0)
+                    || s->session_ctx->remove_session_cb != NULL
+                    || (s->options & SSL_OP_NO_TICKET) != 0))
+            SSL_CTX_add_session(s->session_ctx, s->session);
+
+        /*
+         * Add the session to the external cache. We do this even in server side
+         * TLSv1.3 without early data because some applications just want to
+         * know about the creation of a session and aren't doing a full cache.
+         */
+        if (s->session_ctx->new_session_cb != NULL) {
+            SSL_SESSION_up_ref(s->session);
+            if (!s->session_ctx->new_session_cb(s, s->session))
+                SSL_SESSION_free(s->session);
+        }
+    }
+
+    /* 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)
+            SSL_CTX_flush_sessions(s->session_ctx, (unsigned long)time(NULL));
+    }
+}
+
+const SSL_METHOD *SSL_CTX_get_ssl_method(const SSL_CTX *ctx)
+{
+    return ctx->method;
+}
+
+const SSL_METHOD *SSL_get_ssl_method(const SSL *s)
+{
+    return s->method;
+}
+
+int SSL_set_ssl_method(SSL *s, const SSL_METHOD *meth)
+{
+    int ret = 1;
+
+    if (s->method != meth) {
+        const SSL_METHOD *sm = s->method;
+        int (*hf) (SSL *) = s->handshake_func;
+
+        if (sm->version == meth->version)
+            s->method = meth;
+        else {
+            sm->ssl_free(s);
+            s->method = meth;
+            ret = s->method->ssl_new(s);
+        }
+
+        if (hf == sm->ssl_connect)
+            s->handshake_func = meth->ssl_connect;
+        else if (hf == sm->ssl_accept)
+            s->handshake_func = meth->ssl_accept;
+    }
+    return ret;
+}
+
+int SSL_get_error(const SSL *s, int i)
+{
+    int reason;
+    unsigned long l;
+    BIO *bio;
+
+    if (i > 0)
+        return SSL_ERROR_NONE;
+
+    /*
+     * 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 (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 */
+        }
+    }
+
+    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))
+            /*
+             * 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_async(s))
+        return SSL_ERROR_WANT_ASYNC;
+    if (SSL_want_async_job(s))
+        return SSL_ERROR_WANT_ASYNC_JOB;
+    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))
+        return SSL_ERROR_ZERO_RETURN;
+
+    return SSL_ERROR_SYSCALL;
+}
+
+static int ssl_do_handshake_intern(void *vargs)
+{
+    struct ssl_async_args *args;
+    SSL *s;
+
+    args = (struct ssl_async_args *)vargs;
+    s = args->s;
+
+    return s->handshake_func(s);
+}
+
+int SSL_do_handshake(SSL *s)
+{
+    int ret = 1;
+
+    if (s->handshake_func == NULL) {
+        SSLerr(SSL_F_SSL_DO_HANDSHAKE, SSL_R_CONNECTION_TYPE_NOT_SET);
+        return -1;
+    }
+
+    ossl_statem_check_finish_init(s, -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) {
+            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);
+        }
+    }
+    return ret;
+}
+
+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);
+}
+
+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);
+}
+
+int ssl_undefined_function(SSL *s)
+{
+    SSLerr(SSL_F_SSL_UNDEFINED_FUNCTION, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    return 0;
+}
+
+int ssl_undefined_void_function(void)
+{
+    SSLerr(SSL_F_SSL_UNDEFINED_VOID_FUNCTION,
+           ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    return 0;
+}
+
+int ssl_undefined_const_function(const SSL *s)
+{
+    return 0;
+}
+
+const SSL_METHOD *ssl_bad_method(int ver)
+{
+    SSLerr(SSL_F_SSL_BAD_METHOD, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    return NULL;
+}
+
+const char *ssl_protocol_to_string(int version)
+{
+    switch(version)
+    {
+    case TLS1_3_VERSION:
+        return "TLSv1.3";
+
+    case TLS1_2_VERSION:
+        return "TLSv1.2";
+
+    case TLS1_1_VERSION:
+        return "TLSv1.1";
+
+    case TLS1_VERSION:
+        return "TLSv1";
+
+    case SSL3_VERSION:
+        return "SSLv3";
+
+    case DTLS1_BAD_VER:
+        return "DTLSv0.9";
+
+    case DTLS1_VERSION:
+        return "DTLSv1";
+
+    case DTLS1_2_VERSION:
+        return "DTLSv1.2";
+
+    default:
+        return "unknown";
+    }
+}
+
+const char *SSL_get_version(const SSL *s)
+{
+    return ssl_protocol_to_string(s->version);
+}
+
+static int dup_ca_names(STACK_OF(X509_NAME) **dst, STACK_OF(X509_NAME) *src)
+{
+    STACK_OF(X509_NAME) *sk;
+    X509_NAME *xn;
+    int i;
+
+    if (src == NULL) {
+        *dst = NULL;
+        return 1;
+    }
+
+    if ((sk = sk_X509_NAME_new_null()) == NULL)
+        return 0;
+    for (i = 0; i < sk_X509_NAME_num(src); i++) {
+        xn = X509_NAME_dup(sk_X509_NAME_value(src, i));
+        if (xn == NULL) {
+            sk_X509_NAME_pop_free(sk, X509_NAME_free);
+            return 0;
+        }
+        if (sk_X509_NAME_insert(sk, xn, i) == 0) {
+            X509_NAME_free(xn);
+            sk_X509_NAME_pop_free(sk, X509_NAME_free);
+            return 0;
+        }
+    }
+    *dst = sk;
+
+    return 1;
+}
+
+SSL *SSL_dup(SSL *s)
+{
+    SSL *ret;
+    int i;
+
+    /* 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);
+        return s;
+    }
+
+    /*
+     * Otherwise, copy configuration state, and session if set.
+     */
+    if ((ret = SSL_new(SSL_get_SSL_CTX(s))) == NULL)
+        return NULL;
+
+    if (s->session != NULL) {
+        /*
+         * Arranges to share the same session via up_ref.  This "copies"
+         * session-id, SSL_METHOD, sid_ctx, and 'cert'
+         */
+        if (!SSL_copy_session_id(ret, s))
+            goto err;
+    } else {
+        /*
+         * No session has been established yet, so we have to expect that
+         * s->cert or ret->cert will be changed later -- they should not both
+         * point to the same object, and thus we can't use
+         * SSL_copy_session_id.
+         */
+        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)
+                goto err;
+        }
+
+        if (!SSL_set_session_id_context(ret, s->sid_ctx,
+                                        (int)s->sid_ctx_length))
+            goto err;
+    }
+
+    if (!ssl_dane_dup(ret, s))
+        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;
+    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;
+    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;
+
+    SSL_set_info_callback(ret, SSL_get_info_callback(s));
+
+    /* copy app data, a little dangerous perhaps */
+    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)
+            SSL_set_accept_state(ret);
+        else
+            SSL_set_connect_state(ret);
+    }
+    ret->shutdown = s->shutdown;
+    ret->hit = s->hit;
+
+    ret->default_passwd_callback = s->default_passwd_callback;
+    ret->default_passwd_callback_userdata = s->default_passwd_callback_userdata;
+
+    X509_VERIFY_PARAM_inherit(ret->param, s->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)
+            goto err;
+    }
+    if (s->cipher_list_by_id != NULL)
+        if ((ret->cipher_list_by_id = sk_SSL_CIPHER_dup(s->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))
+        goto err;
+
+    return ret;
+
+ err:
+    SSL_free(ret);
+    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;
+    else
+        return NULL;
+}
+
+EVP_PKEY *SSL_get_privatekey(const SSL *s)
+{
+    if (s->cert != NULL)
+        return s->cert->key->privatekey;
+    else
+        return NULL;
+}
+
+X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx)
+{
+    if (ctx->cert != NULL)
+        return ctx->cert->key->x509;
+    else
+        return NULL;
+}
+
+EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx)
+{
+    if (ctx->cert != NULL)
+        return ctx->cert->key->privatekey;
+    else
+        return NULL;
+}
+
+const SSL_CIPHER *SSL_get_current_cipher(const SSL *s)
+{
+    if ((s->session != NULL) && (s->session->cipher != NULL))
+        return s->session->cipher;
+    return NULL;
+}
+
+const SSL_CIPHER *SSL_get_pending_cipher(const SSL *s)
+{
+    return s->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;
+#else
+    return NULL;
+#endif
+}
+
+const COMP_METHOD *SSL_get_current_expansion(const SSL *s)
+{
+#ifndef OPENSSL_NO_COMP
+    return s->expand ? COMP_CTX_get_method(s->expand) : NULL;
+#else
+    return NULL;
+#endif
+}
+
+int ssl_init_wbio_buffer(SSL *s)
+{
+    BIO *bbio;
+
+    if (s->bbio != NULL) {
+        /* Already buffered. */
+        return 1;
+    }
+
+    bbio = BIO_new(BIO_f_buffer());
+    if (bbio == NULL || !BIO_set_read_buffer_size(bbio, 1)) {
+        BIO_free(bbio);
+        SSLerr(SSL_F_SSL_INIT_WBIO_BUFFER, ERR_R_BUF_LIB);
+        return 0;
+    }
+    s->bbio = bbio;
+    s->wbio = BIO_push(bbio, s->wbio);
+
+    return 1;
+}
+
+int ssl_free_wbio_buffer(SSL *s)
+{
+    /* callers ensure s is never null */
+    if (s->bbio == NULL)
+        return 1;
+
+    s->wbio = BIO_pop(s->wbio);
+    BIO_free(s->bbio);
+    s->bbio = NULL;
+
+    return 1;
+}
+
+void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode)
+{
+    ctx->quiet_shutdown = mode;
+}
+
+int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx)
+{
+    return ctx->quiet_shutdown;
+}
+
+void SSL_set_quiet_shutdown(SSL *s, int mode)
+{
+    s->quiet_shutdown = mode;
+}
+
+int SSL_get_quiet_shutdown(const SSL *s)
+{
+    return s->quiet_shutdown;
+}
+
+void SSL_set_shutdown(SSL *s, int mode)
+{
+    s->shutdown = mode;
+}
+
+int SSL_get_shutdown(const SSL *s)
+{
+    return s->shutdown;
+}
+
+int SSL_version(const SSL *s)
+{
+    return s->version;
+}
+
+int SSL_client_version(const SSL *s)
+{
+    return s->client_version;
+}
+
+SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl)
+{
+    return ssl->ctx;
+}
+
+SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx)
+{
+    CERT *new_cert;
+    if (ssl->ctx == ctx)
+        return ssl->ctx;
+    if (ctx == NULL)
+        ctx = ssl->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)) {
+        ssl_cert_free(new_cert);
+        return NULL;
+    }
+
+    ssl_cert_free(ssl->cert);
+    ssl->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)))
+        return NULL;
+
+    /*
+     * If the session ID context matches that of the parent SSL_CTX,
+     * inherit it from the new SSL_CTX as well. If however the context does
+     * not match (i.e., it was set per-ssl with SSL_set_session_id_context),
+     * 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));
+    }
+
+    SSL_CTX_up_ref(ctx);
+    SSL_CTX_free(ssl->ctx);     /* decrement reference count */
+    ssl->ctx = ctx;
+
+    return ssl->ctx;
+}
+
+int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)
+{
+    return X509_STORE_set_default_paths(ctx->cert_store);
+}
+
+int SSL_CTX_set_default_verify_dir(SSL_CTX *ctx)
+{
+    X509_LOOKUP *lookup;
+
+    lookup = X509_STORE_add_lookup(ctx->cert_store, X509_LOOKUP_hash_dir());
+    if (lookup == NULL)
+        return 0;
+    X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
+
+    /* Clear any errors if the default directory does not exist */
+    ERR_clear_error();
+
+    return 1;
+}
+
+int SSL_CTX_set_default_verify_file(SSL_CTX *ctx)
+{
+    X509_LOOKUP *lookup;
+
+    lookup = X509_STORE_add_lookup(ctx->cert_store, X509_LOOKUP_file());
+    if (lookup == NULL)
+        return 0;
+
+    X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
+
+    /* Clear any errors if the default file does not exist */
+    ERR_clear_error();
+
+    return 1;
+}
+
+int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
+                                  const char *CApath)
+{
+    return X509_STORE_load_locations(ctx->cert_store, CAfile, CApath);
+}
+
+void SSL_set_info_callback(SSL *ssl,
+                           void (*cb) (const SSL *ssl, int type, int val))
+{
+    ssl->info_callback = cb;
+}
+
+/*
+ * One compiler (Diab DCC) doesn't like argument names in returned function
+ * pointer.
+ */
+void (*SSL_get_info_callback(const SSL *ssl)) (const SSL * /* ssl */ ,
+                                               int /* type */ ,
+                                               int /* val */ ) {
+    return ssl->info_callback;
+}
+
+void SSL_set_verify_result(SSL *ssl, long arg)
+{
+    ssl->verify_result = arg;
+}
+
+long SSL_get_verify_result(const SSL *ssl)
+{
+    return ssl->verify_result;
+}
+
+size_t SSL_get_client_random(const SSL *ssl, unsigned char *out, size_t outlen)
+{
+    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 outlen;
+}
+
+size_t SSL_get_server_random(const SSL *ssl, unsigned char *out, size_t outlen)
+{
+    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 outlen;
+}
+
+size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
+                                  unsigned char *out, size_t outlen)
+{
+    if (outlen == 0)
+        return session->master_key_length;
+    if (outlen > session->master_key_length)
+        outlen = session->master_key_length;
+    memcpy(out, session->master_key, outlen);
+    return outlen;
+}
+
+int SSL_SESSION_set1_master_key(SSL_SESSION *sess, const unsigned char *in,
+                                size_t len)
+{
+    if (len > sizeof(sess->master_key))
+        return 0;
+
+    memcpy(sess->master_key, in, len);
+    sess->master_key_length = len;
+    return 1;
+}
+
+
+int SSL_set_ex_data(SSL *s, int idx, void *arg)
+{
+    return CRYPTO_set_ex_data(&s->ex_data, idx, arg);
+}
+
+void *SSL_get_ex_data(const SSL *s, int idx)
+{
+    return CRYPTO_get_ex_data(&s->ex_data, idx);
+}
+
+int SSL_CTX_set_ex_data(SSL_CTX *s, int idx, void *arg)
+{
+    return CRYPTO_set_ex_data(&s->ex_data, idx, arg);
+}
+
+void *SSL_CTX_get_ex_data(const SSL_CTX *s, int idx)
+{
+    return CRYPTO_get_ex_data(&s->ex_data, idx);
+}
+
+X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx)
+{
+    return ctx->cert_store;
+}
+
+void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store)
+{
+    X509_STORE_free(ctx->cert_store);
+    ctx->cert_store = store;
+}
+
+void SSL_CTX_set1_cert_store(SSL_CTX *ctx, X509_STORE *store)
+{
+    if (store != NULL)
+        X509_STORE_up_ref(store);
+    SSL_CTX_set_cert_store(ctx, store);
+}
+
+int SSL_want(const SSL *s)
+{
+    return s->rwstate;
+}
+
+/**
+ * \brief Set the callback for generating temporary DH keys.
+ * \param ctx the SSL context.
+ * \param dh the callback
+ */
+
+#ifndef OPENSSL_NO_DH
+void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,
+                                 DH *(*dh) (SSL *ssl, int is_export,
+                                            int keylength))
+{
+    SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TMP_DH_CB, (void (*)(void))dh);
+}
+
+void SSL_set_tmp_dh_callback(SSL *ssl, DH *(*dh) (SSL *ssl, int is_export,
+                                                  int keylength))
+{
+    SSL_callback_ctrl(ssl, SSL_CTRL_SET_TMP_DH_CB, (void (*)(void))dh);
+}
+#endif
+
+#ifndef OPENSSL_NO_PSK
+int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint)
+{
+    if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) {
+        SSLerr(SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT, SSL_R_DATA_LENGTH_TOO_LONG);
+        return 0;
+    }
+    OPENSSL_free(ctx->cert->psk_identity_hint);
+    if (identity_hint != NULL) {
+        ctx->cert->psk_identity_hint = OPENSSL_strdup(identity_hint);
+        if (ctx->cert->psk_identity_hint == NULL)
+            return 0;
+    } else
+        ctx->cert->psk_identity_hint = NULL;
+    return 1;
+}
+
+int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint)
+{
+    if (s == NULL)
+        return 0;
+
+    if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) {
+        SSLerr(SSL_F_SSL_USE_PSK_IDENTITY_HINT, SSL_R_DATA_LENGTH_TOO_LONG);
+        return 0;
+    }
+    OPENSSL_free(s->cert->psk_identity_hint);
+    if (identity_hint != NULL) {
+        s->cert->psk_identity_hint = OPENSSL_strdup(identity_hint);
+        if (s->cert->psk_identity_hint == NULL)
+            return 0;
+    } else
+        s->cert->psk_identity_hint = NULL;
+    return 1;
+}
+
+const char *SSL_get_psk_identity_hint(const SSL *s)
+{
+    if (s == NULL || s->session == NULL)
+        return NULL;
+    return s->session->psk_identity_hint;
+}
+
+const char *SSL_get_psk_identity(const SSL *s)
+{
+    if (s == NULL || s->session == NULL)
+        return NULL;
+    return s->session->psk_identity;
+}
+
+void SSL_set_psk_client_callback(SSL *s, SSL_psk_client_cb_func cb)
+{
+    s->psk_client_callback = cb;
+}
+
+void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx, SSL_psk_client_cb_func cb)
+{
+    ctx->psk_client_callback = cb;
+}
+
+void SSL_set_psk_server_callback(SSL *s, SSL_psk_server_cb_func cb)
+{
+    s->psk_server_callback = cb;
+}
+
+void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, SSL_psk_server_cb_func cb)
+{
+    ctx->psk_server_callback = cb;
+}
+#endif
+
+void SSL_set_psk_find_session_callback(SSL *s, SSL_psk_find_session_cb_func cb)
+{
+    s->psk_find_session_cb = cb;
+}
+
+void SSL_CTX_set_psk_find_session_callback(SSL_CTX *ctx,
+                                           SSL_psk_find_session_cb_func cb)
+{
+    ctx->psk_find_session_cb = cb;
+}
+
+void SSL_set_psk_use_session_callback(SSL *s, SSL_psk_use_session_cb_func cb)
+{
+    s->psk_use_session_cb = cb;
+}
+
+void SSL_CTX_set_psk_use_session_callback(SSL_CTX *ctx,
+                                           SSL_psk_use_session_cb_func cb)
+{
+    ctx->psk_use_session_cb = cb;
+}
+
+void SSL_CTX_set_msg_callback(SSL_CTX *ctx,
+                              void (*cb) (int write_p, int version,
+                                          int content_type, const void *buf,
+                                          size_t len, SSL *ssl, void *arg))
+{
+    SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
+}
+
+void SSL_set_msg_callback(SSL *ssl,
+                          void (*cb) (int write_p, int version,
+                                      int content_type, const void *buf,
+                                      size_t len, SSL *ssl, void *arg))
+{
+    SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
+}
+
+void SSL_CTX_set_not_resumable_session_callback(SSL_CTX *ctx,
+                                                int (*cb) (SSL *ssl,
+                                                           int
+                                                           is_forward_secure))
+{
+    SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_NOT_RESUMABLE_SESS_CB,
+                          (void (*)(void))cb);
+}
+
+void SSL_set_not_resumable_session_callback(SSL *ssl,
+                                            int (*cb) (SSL *ssl,
+                                                       int is_forward_secure))
+{
+    SSL_callback_ctrl(ssl, SSL_CTRL_SET_NOT_RESUMABLE_SESS_CB,
+                      (void (*)(void))cb);
+}
+
+void SSL_CTX_set_record_padding_callback(SSL_CTX *ctx,
+                                         size_t (*cb) (SSL *ssl, int type,
+                                                       size_t len, void *arg))
+{
+    ctx->record_padding_cb = cb;
+}
+
+void SSL_CTX_set_record_padding_callback_arg(SSL_CTX *ctx, void *arg)
+{
+    ctx->record_padding_arg = arg;
+}
+
+void *SSL_CTX_get_record_padding_callback_arg(const SSL_CTX *ctx)
+{
+    return ctx->record_padding_arg;
+}
+
+int SSL_CTX_set_block_padding(SSL_CTX *ctx, size_t block_size)
+{
+    /* block size of 0 or 1 is basically no padding */
+    if (block_size == 1)
+        ctx->block_padding = 0;
+    else if (block_size <= SSL3_RT_MAX_PLAIN_LENGTH)
+        ctx->block_padding = block_size;
+    else
+        return 0;
+    return 1;
+}
+
+void SSL_set_record_padding_callback(SSL *ssl,
+                                     size_t (*cb) (SSL *ssl, int type,
+                                                   size_t len, void *arg))
+{
+    ssl->record_padding_cb = cb;
+}
+
+void SSL_set_record_padding_callback_arg(SSL *ssl, void *arg)
+{
+    ssl->record_padding_arg = arg;
+}
+
+void *SSL_get_record_padding_callback_arg(const SSL *ssl)
+{
+    return ssl->record_padding_arg;
+}
+
+int SSL_set_block_padding(SSL *ssl, size_t block_size)
+{
+    /* block size of 0 or 1 is basically no padding */
+    if (block_size == 1)
+        ssl->block_padding = 0;
+    else if (block_size <= SSL3_RT_MAX_PLAIN_LENGTH)
+        ssl->block_padding = block_size;
+    else
+        return 0;
+    return 1;
+}
+
+int SSL_set_num_tickets(SSL *s, size_t num_tickets)
+{
+    s->num_tickets = num_tickets;
+
+    return 1;
+}
+
+size_t SSL_get_num_tickets(const SSL *s)
+{
+    return s->num_tickets;
+}
+
+int SSL_CTX_set_num_tickets(SSL_CTX *ctx, size_t num_tickets)
+{
+    ctx->num_tickets = num_tickets;
+
+    return 1;
+}
+
+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,
+                       size_t *hashlen)
+{
+    EVP_MD_CTX *ctx = NULL;
+    EVP_MD_CTX *hdgst = s->s3->handshake_dgst;
+    int hashleni = EVP_MD_CTX_size(hdgst);
+    int ret = 0;
+
+    if (hashleni < 0 || (size_t)hashleni > outlen) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_HANDSHAKE_HASH,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    ctx = EVP_MD_CTX_new();
+    if (ctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_HANDSHAKE_HASH,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (!EVP_MD_CTX_copy_ex(ctx, hdgst)
+        || EVP_DigestFinal_ex(ctx, out, NULL) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_HANDSHAKE_HASH,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    *hashlen = hashleni;
+
+    ret = 1;
+ err:
+    EVP_MD_CTX_free(ctx);
+    return ret;
+}
+
+int SSL_session_reused(const SSL *s)
+{
+    return s->hit;
+}
+
+int SSL_is_server(const SSL *s)
+{
+    return s->server;
+}
+
+#if OPENSSL_API_COMPAT < 0x10100000L
+void SSL_set_debug(SSL *s, int debug)
+{
+    /* Old function was do-nothing anyway... */
+    (void)s;
+    (void)debug;
+}
+#endif
+
+void SSL_set_security_level(SSL *s, int level)
+{
+    s->cert->sec_level = level;
+}
+
+int SSL_get_security_level(const SSL *s)
+{
+    return s->cert->sec_level;
+}
+
+void SSL_set_security_callback(SSL *s,
+                               int (*cb) (const SSL *s, const SSL_CTX *ctx,
+                                          int op, int bits, int nid,
+                                          void *other, void *ex))
+{
+    s->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;
+}
+
+void SSL_set0_security_ex_data(SSL *s, void *ex)
+{
+    s->cert->sec_ex = ex;
+}
+
+void *SSL_get0_security_ex_data(const SSL *s)
+{
+    return s->cert->sec_ex;
+}
+
+void SSL_CTX_set_security_level(SSL_CTX *ctx, int level)
+{
+    ctx->cert->sec_level = level;
+}
+
+int SSL_CTX_get_security_level(const SSL_CTX *ctx)
+{
+    return ctx->cert->sec_level;
+}
+
+void SSL_CTX_set_security_callback(SSL_CTX *ctx,
+                                   int (*cb) (const SSL *s, const SSL_CTX *ctx,
+                                              int op, int bits, int nid,
+                                              void *other, void *ex))
+{
+    ctx->cert->sec_cb = cb;
+}
+
+int (*SSL_CTX_get_security_callback(const SSL_CTX *ctx)) (const SSL *s,
+                                                          const SSL_CTX *ctx,
+                                                          int op, int bits,
+                                                          int nid,
+                                                          void *other,
+                                                          void *ex) {
+    return ctx->cert->sec_cb;
+}
+
+void SSL_CTX_set0_security_ex_data(SSL_CTX *ctx, void *ex)
+{
+    ctx->cert->sec_ex = ex;
+}
+
+void *SSL_CTX_get0_security_ex_data(const SSL_CTX *ctx)
+{
+    return ctx->cert->sec_ex;
+}
+
+/*
+ * Get/Set/Clear options in SSL_CTX or SSL, formerly macros, now functions that
+ * can return unsigned long, instead of the generic long return value from the
+ * control interface.
+ */
+unsigned long SSL_CTX_get_options(const SSL_CTX *ctx)
+{
+    return ctx->options;
+}
+
+unsigned long SSL_get_options(const SSL *s)
+{
+    return s->options;
+}
+
+unsigned long SSL_CTX_set_options(SSL_CTX *ctx, unsigned long op)
+{
+    return ctx->options |= op;
+}
+
+unsigned long SSL_set_options(SSL *s, unsigned long op)
+{
+    return s->options |= op;
+}
+
+unsigned long SSL_CTX_clear_options(SSL_CTX *ctx, unsigned long op)
+{
+    return ctx->options &= ~op;
+}
+
+unsigned long SSL_clear_options(SSL *s, unsigned long op)
+{
+    return s->options &= ~op;
+}
+
+STACK_OF(X509) *SSL_get0_verified_chain(const SSL *s)
+{
+    return s->verified_chain;
+}
+
+IMPLEMENT_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER, ssl_cipher_id);
+
+#ifndef OPENSSL_NO_CT
+
+/*
+ * Moves SCTs from the |src| stack to the |dst| stack.
+ * The source of each SCT will be set to |origin|.
+ * If |dst| points to a NULL pointer, a new stack will be created and owned by
+ * the caller.
+ * Returns the number of SCTs moved, or a negative integer if an error occurs.
+ */
+static int ct_move_scts(STACK_OF(SCT) **dst, STACK_OF(SCT) *src,
+                        sct_source_t origin)
+{
+    int scts_moved = 0;
+    SCT *sct = NULL;
+
+    if (*dst == NULL) {
+        *dst = sk_SCT_new_null();
+        if (*dst == NULL) {
+            SSLerr(SSL_F_CT_MOVE_SCTS, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+    }
+
+    while ((sct = sk_SCT_pop(src)) != NULL) {
+        if (SCT_set_source(sct, origin) != 1)
+            goto err;
+
+        if (sk_SCT_push(*dst, sct) <= 0)
+            goto err;
+        scts_moved += 1;
+    }
+
+    return scts_moved;
+ err:
+    if (sct != NULL)
+        sk_SCT_push(src, sct);  /* Put the SCT back */
+    return -1;
+}
+
+/*
+ * 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)
+{
+    int scts_extracted = 0;
+
+    if (s->ext.scts != NULL) {
+        const unsigned char *p = s->ext.scts;
+        STACK_OF(SCT) *scts = o2i_SCT_LIST(NULL, &p, s->ext.scts_len);
+
+        scts_extracted = ct_move_scts(&s->scts, scts, SCT_SOURCE_TLS_EXTENSION);
+
+        SCT_LIST_free(scts);
+    }
+
+    return scts_extracted;
+}
+
+/*
+ * Checks for an OCSP response and then attempts to extract any SCTs found if it
+ * contains an SCT X509 extension. They will be stored in |s->scts|.
+ * Returns:
+ * - The number of SCTs extracted, assuming an OCSP response exists.
+ * - 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)
+{
+# ifndef OPENSSL_NO_OCSP
+    int scts_extracted = 0;
+    const unsigned char *p;
+    OCSP_BASICRESP *br = NULL;
+    OCSP_RESPONSE *rsp = NULL;
+    STACK_OF(SCT) *scts = NULL;
+    int i;
+
+    if (s->ext.ocsp.resp == NULL || s->ext.ocsp.resp_len == 0)
+        goto err;
+
+    p = s->ext.ocsp.resp;
+    rsp = d2i_OCSP_RESPONSE(NULL, &p, (int)s->ext.ocsp.resp_len);
+    if (rsp == NULL)
+        goto err;
+
+    br = OCSP_response_get1_basic(rsp);
+    if (br == NULL)
+        goto err;
+
+    for (i = 0; i < OCSP_resp_count(br); ++i) {
+        OCSP_SINGLERESP *single = OCSP_resp_get0(br, i);
+
+        if (single == NULL)
+            continue;
+
+        scts =
+            OCSP_SINGLERESP_get1_ext_d2i(single, NID_ct_cert_scts, NULL, NULL);
+        scts_extracted =
+            ct_move_scts(&s->scts, scts, SCT_SOURCE_OCSP_STAPLED_RESPONSE);
+        if (scts_extracted < 0)
+            goto err;
+    }
+ err:
+    SCT_LIST_free(scts);
+    OCSP_BASICRESP_free(br);
+    OCSP_RESPONSE_free(rsp);
+    return scts_extracted;
+# else
+    /* Behave as if no OCSP response exists */
+    return 0;
+# endif
+}
+
+/*
+ * Attempts to extract SCTs from the peer certificate.
+ * Return the number of SCTs extracted, or a negative integer if an error
+ * occurs.
+ */
+static int ct_extract_x509v3_extension_scts(SSL *s)
+{
+    int scts_extracted = 0;
+    X509 *cert = s->session != NULL ? s->session->peer : NULL;
+
+    if (cert != NULL) {
+        STACK_OF(SCT) *scts =
+            X509_get_ext_d2i(cert, NID_ct_precert_scts, NULL, NULL);
+
+        scts_extracted =
+            ct_move_scts(&s->scts, scts, SCT_SOURCE_X509V3_EXTENSION);
+
+        SCT_LIST_free(scts);
+    }
+
+    return scts_extracted;
+}
+
+/*
+ * Attempts to find all received SCTs by checking TLS extensions, the OCSP
+ * response (if it exists) and X509v3 extensions in the certificate.
+ * Returns NULL if an error occurs.
+ */
+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)
+            goto err;
+
+        s->scts_parsed = 1;
+    }
+    return s->scts;
+ err:
+    return NULL;
+}
+
+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,
+                     const STACK_OF(SCT) *scts, void *unused_arg)
+{
+    int count = scts != NULL ? sk_SCT_num(scts) : 0;
+    int i;
+
+    for (i = 0; i < count; ++i) {
+        SCT *sct = sk_SCT_value(scts, i);
+        int status = SCT_get_validation_status(sct);
+
+        if (status == SCT_VALIDATION_STATUS_VALID)
+            return 1;
+    }
+    SSLerr(SSL_F_CT_STRICT, SSL_R_NO_VALID_SCTS);
+    return 0;
+}
+
+int SSL_set_ct_validation_callback(SSL *s, ssl_ct_validation_cb callback,
+                                   void *arg)
+{
+    /*
+     * 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.
+     */
+    if (callback != NULL && SSL_CTX_has_client_custom_ext(s->ctx,
+                                                          TLSEXT_TYPE_signed_certificate_timestamp))
+    {
+        SSLerr(SSL_F_SSL_SET_CT_VALIDATION_CALLBACK,
+               SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED);
+        return 0;
+    }
+
+    if (callback != NULL) {
+        /*
+         * If we are validating CT, then we MUST accept SCTs served via OCSP
+         */
+        if (!SSL_set_tlsext_status_type(s, TLSEXT_STATUSTYPE_ocsp))
+            return 0;
+    }
+
+    s->ct_validation_callback = callback;
+    s->ct_validation_callback_arg = arg;
+
+    return 1;
+}
+
+int SSL_CTX_set_ct_validation_callback(SSL_CTX *ctx,
+                                       ssl_ct_validation_cb callback, void *arg)
+{
+    /*
+     * 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.
+     */
+    if (callback != NULL && SSL_CTX_has_client_custom_ext(ctx,
+                                                          TLSEXT_TYPE_signed_certificate_timestamp))
+    {
+        SSLerr(SSL_F_SSL_CTX_SET_CT_VALIDATION_CALLBACK,
+               SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED);
+        return 0;
+    }
+
+    ctx->ct_validation_callback = callback;
+    ctx->ct_validation_callback_arg = arg;
+    return 1;
+}
+
+int SSL_ct_is_enabled(const SSL *s)
+{
+    return s->ct_validation_callback != NULL;
+}
+
+int SSL_CTX_ct_is_enabled(const SSL_CTX *ctx)
+{
+    return ctx->ct_validation_callback != NULL;
+}
+
+int ssl_validate_ct(SSL *s)
+{
+    int ret = 0;
+    X509 *cert = s->session != NULL ? s->session->peer : NULL;
+    X509 *issuer;
+    SSL_DANE *dane = &s->dane;
+    CT_POLICY_EVAL_CTX *ctx = NULL;
+    const STACK_OF(SCT) *scts;
+
+    /*
+     * If no callback is set, the peer is anonymous, or its chain is invalid,
+     * skip SCT validation - just return success.  Applications that continue
+     * handshakes without certificates, with unverified chains, or pinned leaf
+     * certificates are outside the scope of the WebPKI and CT.
+     *
+     * The above exclusions notwithstanding the vast majority of peers will
+     * have rather ordinary certificate chains validated by typical
+     * applications that perform certificate verification and therefore will
+     * process SCTs when enabled.
+     */
+    if (s->ct_validation_callback == NULL || cert == NULL ||
+        s->verify_result != X509_V_OK ||
+        s->verified_chain == NULL || sk_X509_num(s->verified_chain) <= 1)
+        return 1;
+
+    /*
+     * CT not applicable for chains validated via DANE-TA(2) or DANE-EE(3)
+     * trust-anchors.  See https://tools.ietf.org/html/rfc7671#section-4.2
+     */
+    if (DANETLS_ENABLED(dane) && dane->mtlsa != NULL) {
+        switch (dane->mtlsa->usage) {
+        case DANETLS_USAGE_DANE_TA:
+        case DANETLS_USAGE_DANE_EE:
+            return 1;
+        }
+    }
+
+    ctx = CT_POLICY_EVAL_CTX_new();
+    if (ctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_VALIDATE_CT,
+                 ERR_R_MALLOC_FAILURE);
+        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_time(
+            ctx, (uint64_t)SSL_SESSION_get_time(SSL_get0_session(s)) * 1000);
+
+    scts = SSL_get0_peer_scts(s);
+
+    /*
+     * This function returns success (> 0) only when all the SCTs are valid, 0
+     * when some are invalid, and < 0 on various internal errors (out of
+     * memory, etc.).  Having some, or even all, invalid SCTs is not sufficient
+     * reason to abort the handshake, that decision is up to the callback.
+     * Therefore, we error out only in the unexpected case that the return
+     * value is negative.
+     *
+     * XXX: One might well argue that the return value of this function is an
+     * unfortunate design choice.  Its job is only to determine the validation
+     * status of each of the provided SCTs.  So long as it correctly separates
+     * the wheat from the chaff it should return success.  Failure in this case
+     * ought to correspond to an inability to carry out its duties.
+     */
+    if (SCT_LIST_validate(scts, ctx) < 0) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_SSL_VALIDATE_CT,
+                 SSL_R_SCT_VERIFICATION_FAILED);
+        goto end;
+    }
+
+    ret = s->ct_validation_callback(ctx, scts, s->ct_validation_callback_arg);
+    if (ret < 0)
+        ret = 0;                /* This function returns 0 on failure */
+    if (!ret)
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_SSL_VALIDATE_CT,
+                 SSL_R_CALLBACK_FAILED);
+
+ end:
+    CT_POLICY_EVAL_CTX_free(ctx);
+    /*
+     * With SSL_VERIFY_NONE the session may be cached and re-used despite a
+     * failure return code here.  Also the application may wish the complete
+     * the handshake, and then disconnect cleanly at a higher layer, after
+     * checking the verification status of the completed connection.
+     *
+     * We therefore force a certificate verification failure which will be
+     * visible via SSL_get_verify_result() and cached as part of any resumed
+     * session.
+     *
+     * Note: the permissive callback is for information gathering only, always
+     * returns success, and does not affect verification status.  Only the
+     * strict callback or a custom application-specified callback can trigger
+     * connection failure or record a verification error.
+     */
+    if (ret <= 0)
+        s->verify_result = X509_V_ERR_NO_VALID_SCTS;
+    return ret;
+}
+
+int SSL_CTX_enable_ct(SSL_CTX *ctx, int validation_mode)
+{
+    switch (validation_mode) {
+    default:
+        SSLerr(SSL_F_SSL_CTX_ENABLE_CT, SSL_R_INVALID_CT_VALIDATION_TYPE);
+        return 0;
+    case SSL_CT_VALIDATION_PERMISSIVE:
+        return SSL_CTX_set_ct_validation_callback(ctx, ct_permissive, NULL);
+    case SSL_CT_VALIDATION_STRICT:
+        return SSL_CTX_set_ct_validation_callback(ctx, ct_strict, NULL);
+    }
+}
+
+int SSL_enable_ct(SSL *s, int validation_mode)
+{
+    switch (validation_mode) {
+    default:
+        SSLerr(SSL_F_SSL_ENABLE_CT, SSL_R_INVALID_CT_VALIDATION_TYPE);
+        return 0;
+    case SSL_CT_VALIDATION_PERMISSIVE:
+        return SSL_set_ct_validation_callback(s, ct_permissive, NULL);
+    case SSL_CT_VALIDATION_STRICT:
+        return SSL_set_ct_validation_callback(s, ct_strict, NULL);
+    }
+}
+
+int SSL_CTX_set_default_ctlog_list_file(SSL_CTX *ctx)
+{
+    return CTLOG_STORE_load_default_file(ctx->ctlog_store);
+}
+
+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)
+{
+    CTLOG_STORE_free(ctx->ctlog_store);
+    ctx->ctlog_store = logs;
+}
+
+const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx)
+{
+    return ctx->ctlog_store;
+}
+
+#endif  /* OPENSSL_NO_CT */
+
+void SSL_CTX_set_client_hello_cb(SSL_CTX *c, SSL_client_hello_cb_fn cb,
+                                 void *arg)
+{
+    c->client_hello_cb = cb;
+    c->client_hello_cb_arg = arg;
+}
+
+int SSL_client_hello_isv2(SSL *s)
+{
+    if (s->clienthello == NULL)
+        return 0;
+    return s->clienthello->isv2;
+}
+
+unsigned int SSL_client_hello_get0_legacy_version(SSL *s)
+{
+    if (s->clienthello == NULL)
+        return 0;
+    return s->clienthello->legacy_version;
+}
+
+size_t SSL_client_hello_get0_random(SSL *s, const unsigned char **out)
+{
+    if (s->clienthello == NULL)
+        return 0;
+    if (out != NULL)
+        *out = s->clienthello->random;
+    return SSL3_RANDOM_SIZE;
+}
+
+size_t SSL_client_hello_get0_session_id(SSL *s, const unsigned char **out)
+{
+    if (s->clienthello == NULL)
+        return 0;
+    if (out != NULL)
+        *out = s->clienthello->session_id;
+    return s->clienthello->session_id_len;
+}
+
+size_t SSL_client_hello_get0_ciphers(SSL *s, const unsigned char **out)
+{
+    if (s->clienthello == NULL)
+        return 0;
+    if (out != NULL)
+        *out = PACKET_data(&s->clienthello->ciphersuites);
+    return PACKET_remaining(&s->clienthello->ciphersuites);
+}
+
+size_t SSL_client_hello_get0_compression_methods(SSL *s, const unsigned char **out)
+{
+    if (s->clienthello == NULL)
+        return 0;
+    if (out != NULL)
+        *out = s->clienthello->compressions;
+    return s->clienthello->compressions_len;
+}
+
+int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen)
+{
+    RAW_EXTENSION *ext;
+    int *present;
+    size_t num = 0, i;
+
+    if (s->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;
+        if (ext->present)
+            num++;
+    }
+    if (num == 0) {
+        *out = NULL;
+        *outlen = 0;
+        return 1;
+    }
+    if ((present = OPENSSL_malloc(sizeof(*present) * num)) == NULL) {
+        SSLerr(SSL_F_SSL_CLIENT_HELLO_GET1_EXTENSIONS_PRESENT,
+               ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    for (i = 0; i < s->clienthello->pre_proc_exts_len; i++) {
+        ext = s->clienthello->pre_proc_exts + i;
+        if (ext->present) {
+            if (ext->received_order >= num)
+                goto err;
+            present[ext->received_order] = ext->type;
+        }
+    }
+    *out = present;
+    *outlen = num;
+    return 1;
+ err:
+    OPENSSL_free(present);
+    return 0;
+}
+
+int SSL_client_hello_get0_ext(SSL *s, unsigned int type, const unsigned char **out,
+                       size_t *outlen)
+{
+    size_t i;
+    RAW_EXTENSION *r;
+
+    if (s->clienthello == NULL)
+        return 0;
+    for (i = 0; i < s->clienthello->pre_proc_exts_len; ++i) {
+        r = s->clienthello->pre_proc_exts + i;
+        if (r->present && r->type == type) {
+            if (out != NULL)
+                *out = PACKET_data(&r->data);
+            if (outlen != NULL)
+                *outlen = PACKET_remaining(&r->data);
+            return 1;
+        }
+    }
+    return 0;
+}
+
+int SSL_free_buffers(SSL *ssl)
+{
+    RECORD_LAYER *rl = &ssl->rlayer;
+
+    if (RECORD_LAYER_read_pending(rl) || RECORD_LAYER_write_pending(rl))
+        return 0;
+
+    RECORD_LAYER_release(rl);
+    return 1;
+}
+
+int SSL_alloc_buffers(SSL *ssl)
+{
+    return ssl3_setup_buffers(ssl);
+}
+
+void SSL_CTX_set_keylog_callback(SSL_CTX *ctx, SSL_CTX_keylog_cb_func cb)
+{
+    ctx->keylog_callback = cb;
+}
+
+SSL_CTX_keylog_cb_func SSL_CTX_get_keylog_callback(const SSL_CTX *ctx)
+{
+    return ctx->keylog_callback;
+}
+
+static int nss_keylog_int(const char *prefix,
+                          SSL *ssl,
+                          const uint8_t *parameter_1,
+                          size_t parameter_1_len,
+                          const uint8_t *parameter_2,
+                          size_t parameter_2_len)
+{
+    char *out = NULL;
+    char *cursor = NULL;
+    size_t out_len = 0;
+    size_t i;
+    size_t prefix_len;
+
+    if (ssl->ctx->keylog_callback == NULL)
+        return 1;
+
+    /*
+     * Our output buffer will contain the following strings, rendered with
+     * space characters in between, terminated by a NULL character: first the
+     * prefix, then the first parameter, then the second parameter. The
+     * meaning of each parameter depends on the specific key material being
+     * logged. Note that the first and second parameters are encoded in
+     * hexadecimal, so we need a buffer that is twice their lengths.
+     */
+    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, SSL_F_NSS_KEYLOG_INT,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    strcpy(cursor, prefix);
+    cursor += prefix_len;
+    *cursor++ = ' ';
+
+    for (i = 0; i < parameter_1_len; i++) {
+        sprintf(cursor, "%02x", parameter_1[i]);
+        cursor += 2;
+    }
+    *cursor++ = ' ';
+
+    for (i = 0; i < parameter_2_len; i++) {
+        sprintf(cursor, "%02x", parameter_2[i]);
+        cursor += 2;
+    }
+    *cursor = '\0';
+
+    ssl->ctx->keylog_callback(ssl, (const char *)out);
+    OPENSSL_clear_free(out, out_len);
+    return 1;
+
+}
+
+int ssl_log_rsa_client_key_exchange(SSL *ssl,
+                                    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,
+                 SSL_F_SSL_LOG_RSA_CLIENT_KEY_EXCHANGE, 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,
+                          encrypted_premaster,
+                          8,
+                          premaster,
+                          premaster_len);
+}
+
+int ssl_log_secret(SSL *ssl,
+                   const char *label,
+                   const uint8_t *secret,
+                   size_t secret_len)
+{
+    return nss_keylog_int(label,
+                          ssl,
+                          ssl->s3->client_random,
+                          SSL3_RANDOM_SIZE,
+                          secret,
+                          secret_len);
+}
+
+#define SSLV2_CIPHER_LEN    3
+
+int ssl_cache_cipherlist(SSL *s, PACKET *cipher_suites, int sslv2format)
+{
+    int n;
+
+    n = sslv2format ? SSLV2_CIPHER_LEN : TLS_CIPHER_LEN;
+
+    if (PACKET_remaining(cipher_suites) == 0) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SSL_CACHE_CIPHERLIST,
+                 SSL_R_NO_CIPHERS_SPECIFIED);
+        return 0;
+    }
+
+    if (PACKET_remaining(cipher_suites) % n != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_SSL_CACHE_CIPHERLIST,
+                 SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
+        return 0;
+    }
+
+    OPENSSL_free(s->s3->tmp.ciphers_raw);
+    s->s3->tmp.ciphers_raw = NULL;
+    s->s3->tmp.ciphers_rawlen = 0;
+
+    if (sslv2format) {
+        size_t numciphers = PACKET_remaining(cipher_suites) / n;
+        PACKET sslv2ciphers = *cipher_suites;
+        unsigned int leadbyte;
+        unsigned char *raw;
+
+        /*
+         * We store the raw ciphers list in SSLv3+ format so we need to do some
+         * preprocessing to convert the list first. If there are any SSLv2 only
+         * ciphersuites with a non-zero leading byte then we are going to
+         * slightly over allocate because we won't store those. But that isn't a
+         * problem.
+         */
+        raw = OPENSSL_malloc(numciphers * TLS_CIPHER_LEN);
+        s->s3->tmp.ciphers_raw = raw;
+        if (raw == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_CACHE_CIPHERLIST,
+                     ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        for (s->s3->tmp.ciphers_rawlen = 0;
+             PACKET_remaining(&sslv2ciphers) > 0;
+             raw += TLS_CIPHER_LEN) {
+            if (!PACKET_get_1(&sslv2ciphers, &leadbyte)
+                    || (leadbyte == 0
+                        && !PACKET_copy_bytes(&sslv2ciphers, raw,
+                                              TLS_CIPHER_LEN))
+                    || (leadbyte != 0
+                        && !PACKET_forward(&sslv2ciphers, TLS_CIPHER_LEN))) {
+                SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_SSL_CACHE_CIPHERLIST,
+                         SSL_R_BAD_PACKET);
+                OPENSSL_free(s->s3->tmp.ciphers_raw);
+                s->s3->tmp.ciphers_raw = NULL;
+                s->s3->tmp.ciphers_rawlen = 0;
+                return 0;
+            }
+            if (leadbyte == 0)
+                s->s3->tmp.ciphers_rawlen += TLS_CIPHER_LEN;
+        }
+    } else if (!PACKET_memdup(cipher_suites, &s->s3->tmp.ciphers_raw,
+                           &s->s3->tmp.ciphers_rawlen)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_CACHE_CIPHERLIST,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    return 1;
+}
+
+int SSL_bytes_to_cipher_list(SSL *s, const unsigned char *bytes, size_t len,
+                             int isv2format, STACK_OF(SSL_CIPHER) **sk,
+                             STACK_OF(SSL_CIPHER) **scsvs)
+{
+    PACKET pkt;
+
+    if (!PACKET_buf_init(&pkt, bytes, len))
+        return 0;
+    return bytes_to_cipher_list(s, &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)
+{
+    const SSL_CIPHER *c;
+    STACK_OF(SSL_CIPHER) *sk = NULL;
+    STACK_OF(SSL_CIPHER) *scsvs = NULL;
+    int n;
+    /* 3 = SSLV2_CIPHER_LEN > TLS_CIPHER_LEN = 2. */
+    unsigned char cipher[SSLV2_CIPHER_LEN];
+
+    n = sslv2format ? SSLV2_CIPHER_LEN : TLS_CIPHER_LEN;
+
+    if (PACKET_remaining(cipher_suites) == 0) {
+        if (fatal)
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_BYTES_TO_CIPHER_LIST,
+                     SSL_R_NO_CIPHERS_SPECIFIED);
+        else
+            SSLerr(SSL_F_BYTES_TO_CIPHER_LIST, SSL_R_NO_CIPHERS_SPECIFIED);
+        return 0;
+    }
+
+    if (PACKET_remaining(cipher_suites) % n != 0) {
+        if (fatal)
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_BYTES_TO_CIPHER_LIST,
+                     SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
+        else
+            SSLerr(SSL_F_BYTES_TO_CIPHER_LIST,
+                   SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
+        return 0;
+    }
+
+    sk = sk_SSL_CIPHER_new_null();
+    scsvs = sk_SSL_CIPHER_new_null();
+    if (sk == NULL || scsvs == NULL) {
+        if (fatal)
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_BYTES_TO_CIPHER_LIST,
+                     ERR_R_MALLOC_FAILURE);
+        else
+            SSLerr(SSL_F_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    while (PACKET_copy_bytes(cipher_suites, cipher, n)) {
+        /*
+         * SSLv3 ciphers wrapped in an SSLv2-compatible ClientHello have the
+         * first byte set to zero, while true SSLv2 ciphers have a non-zero
+         * first byte. We don't support any true SSLv2 ciphers, so skip them.
+         */
+        if (sslv2format && cipher[0] != '\0')
+            continue;
+
+        /* For SSLv2-compat, ignore leading 0-byte. */
+        c = ssl_get_cipher_by_char(s, sslv2format ? &cipher[1] : cipher, 1);
+        if (c != NULL) {
+            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,
+                             SSL_F_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE);
+                else
+                    SSLerr(SSL_F_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+        }
+    }
+    if (PACKET_remaining(cipher_suites) > 0) {
+        if (fatal)
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_BYTES_TO_CIPHER_LIST,
+                     SSL_R_BAD_LENGTH);
+        else
+            SSLerr(SSL_F_BYTES_TO_CIPHER_LIST, SSL_R_BAD_LENGTH);
+        goto err;
+    }
+
+    if (skp != NULL)
+        *skp = sk;
+    else
+        sk_SSL_CIPHER_free(sk);
+    if (scsvs_out != NULL)
+        *scsvs_out = scsvs;
+    else
+        sk_SSL_CIPHER_free(scsvs);
+    return 1;
+ err:
+    sk_SSL_CIPHER_free(sk);
+    sk_SSL_CIPHER_free(scsvs);
+    return 0;
+}
+
+int SSL_CTX_set_max_early_data(SSL_CTX *ctx, uint32_t max_early_data)
+{
+    ctx->max_early_data = max_early_data;
+
+    return 1;
+}
+
+uint32_t SSL_CTX_get_max_early_data(const SSL_CTX *ctx)
+{
+    return ctx->max_early_data;
+}
+
+int SSL_set_max_early_data(SSL *s, uint32_t max_early_data)
+{
+    s->max_early_data = max_early_data;
+
+    return 1;
+}
+
+uint32_t SSL_get_max_early_data(const SSL *s)
+{
+    return s->max_early_data;
+}
+
+int SSL_CTX_set_recv_max_early_data(SSL_CTX *ctx, uint32_t recv_max_early_data)
+{
+    ctx->recv_max_early_data = recv_max_early_data;
+
+    return 1;
+}
+
+uint32_t SSL_CTX_get_recv_max_early_data(const SSL_CTX *ctx)
+{
+    return ctx->recv_max_early_data;
+}
+
+int SSL_set_recv_max_early_data(SSL *s, uint32_t recv_max_early_data)
+{
+    s->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;
+}
+
+__owur unsigned int ssl_get_max_send_fragment(const SSL *ssl)
+{
+    /* 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);
+
+    /* return current SSL connection setting */
+    return ssl->max_send_fragment;
+}
+
+__owur unsigned int ssl_get_split_send_fragment(const SSL *ssl)
+{
+    /* 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);
+
+    /* else limit |split_send_fragment| to current |max_send_fragment| */
+    if (ssl->split_send_fragment > ssl->max_send_fragment)
+        return ssl->max_send_fragment;
+
+    /* return current SSL connection setting */
+    return ssl->split_send_fragment;
+}
+
+int SSL_stateless(SSL *s)
+{
+    int ret;
+
+    /* Ensure there is no state left over from a previous invocation */
+    if (!SSL_clear(s))
+        return 0;
+
+    ERR_clear_error();
+
+    s->s3->flags |= TLS1_FLAGS_STATELESS;
+    ret = SSL_accept(s);
+    s->s3->flags &= ~TLS1_FLAGS_STATELESS;
+
+    if (ret > 0 && s->ext.cookieok)
+        return 1;
+
+    if (s->hello_retry_request == SSL_HRR_PENDING && !ossl_statem_in_error(s))
+        return 0;
+
+    return -1;
+}
+
+void SSL_CTX_set_post_handshake_auth(SSL_CTX *ctx, int val)
+{
+    ctx->pha_enabled = val;
+}
+
+void SSL_set_post_handshake_auth(SSL *ssl, int val)
+{
+    ssl->pha_enabled = val;
+}
+
+int SSL_verify_client_post_handshake(SSL *ssl)
+{
+    if (!SSL_IS_TLS13(ssl)) {
+        SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_WRONG_SSL_VERSION);
+        return 0;
+    }
+    if (!ssl->server) {
+        SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_NOT_SERVER);
+        return 0;
+    }
+
+    if (!SSL_is_init_finished(ssl)) {
+        SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_STILL_IN_INIT);
+        return 0;
+    }
+
+    switch (ssl->post_handshake_auth) {
+    case SSL_PHA_NONE:
+        SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_EXTENSION_NOT_RECEIVED);
+        return 0;
+    default:
+    case SSL_PHA_EXT_SENT:
+        SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    case SSL_PHA_EXT_RECEIVED:
+        break;
+    case SSL_PHA_REQUEST_PENDING:
+        SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_REQUEST_PENDING);
+        return 0;
+    case SSL_PHA_REQUESTED:
+        SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_REQUEST_SENT);
+        return 0;
+    }
+
+    ssl->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 */
+        SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_INVALID_CONFIG);
+        return 0;
+    }
+
+    ossl_statem_set_in_init(ssl, 1);
+    return 1;
+}
+
+int SSL_CTX_set_session_ticket_cb(SSL_CTX *ctx,
+                                  SSL_CTX_generate_session_ticket_fn gen_cb,
+                                  SSL_CTX_decrypt_session_ticket_fn dec_cb,
+                                  void *arg)
+{
+    ctx->generate_ticket_cb = gen_cb;
+    ctx->decrypt_ticket_cb = dec_cb;
+    ctx->ticket_cb_data = arg;
+    return 1;
+}
+
+void SSL_CTX_set_allow_early_data_cb(SSL_CTX *ctx,
+                                     SSL_allow_early_data_cb_fn cb,
+                                     void *arg)
+{
+    ctx->allow_early_data_cb = cb;
+    ctx->allow_early_data_cb_data = arg;
+}
+
+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;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_local.h b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_local.h
new file mode 100644
index 0000000..5c79215
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_local.h
@@ -0,0 +1,2672 @@
+/*
+ * 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.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OSSL_SSL_LOCAL_H
+# define OSSL_SSL_LOCAL_H
+
+# include "e_os.h"              /* struct timeval for DTLS */
+# include <stdlib.h>
+# include <time.h>
+# include <string.h>
+# include <errno.h>
+
+# include <openssl/buffer.h>
+# include <openssl/comp.h>
+# include <openssl/bio.h>
+# include <openssl/rsa.h>
+# include <openssl/dsa.h>
+# include <openssl/err.h>
+# include <openssl/ssl.h>
+# include <openssl/async.h>
+# include <openssl/symhacks.h>
+# include <openssl/ct.h>
+# include "record/record.h"
+# include "statem/statem.h"
+# include "packet_local.h"
+# include "internal/dane.h"
+# include "internal/refcount.h"
+# include "internal/tsan_assist.h"
+
+# ifdef OPENSSL_BUILD_SHLIBSSL
+#  undef OPENSSL_EXTERN
+#  define OPENSSL_EXTERN OPENSSL_EXPORT
+# endif
+
+# define c2l(c,l)        (l = ((unsigned long)(*((c)++)))     , \
+                         l|=(((unsigned long)(*((c)++)))<< 8), \
+                         l|=(((unsigned long)(*((c)++)))<<16), \
+                         l|=(((unsigned long)(*((c)++)))<<24))
+
+/* NOTE - c is not incremented as per c2l */
+# define c2ln(c,l1,l2,n) { \
+                        c+=n; \
+                        l1=l2=0; \
+                        switch (n) { \
+                        case 8: l2 =((unsigned long)(*(--(c))))<<24; \
+                        case 7: l2|=((unsigned long)(*(--(c))))<<16; \
+                        case 6: l2|=((unsigned long)(*(--(c))))<< 8; \
+                        case 5: l2|=((unsigned long)(*(--(c))));     \
+                        case 4: l1 =((unsigned long)(*(--(c))))<<24; \
+                        case 3: l1|=((unsigned long)(*(--(c))))<<16; \
+                        case 2: l1|=((unsigned long)(*(--(c))))<< 8; \
+                        case 1: l1|=((unsigned long)(*(--(c))));     \
+                                } \
+                        }
+
+# define l2c(l,c)        (*((c)++)=(unsigned char)(((l)    )&0xff), \
+                         *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>>24)&0xff))
+
+# define n2l(c,l)        (l =((unsigned long)(*((c)++)))<<24, \
+                         l|=((unsigned long)(*((c)++)))<<16, \
+                         l|=((unsigned long)(*((c)++)))<< 8, \
+                         l|=((unsigned long)(*((c)++))))
+
+# define n2l8(c,l)       (l =((uint64_t)(*((c)++)))<<56, \
+                         l|=((uint64_t)(*((c)++)))<<48, \
+                         l|=((uint64_t)(*((c)++)))<<40, \
+                         l|=((uint64_t)(*((c)++)))<<32, \
+                         l|=((uint64_t)(*((c)++)))<<24, \
+                         l|=((uint64_t)(*((c)++)))<<16, \
+                         l|=((uint64_t)(*((c)++)))<< 8, \
+                         l|=((uint64_t)(*((c)++))))
+
+
+# define l2n(l,c)        (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+                         *((c)++)=(unsigned char)(((l)    )&0xff))
+
+# define l2n6(l,c)       (*((c)++)=(unsigned char)(((l)>>40)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>>32)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>>24)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+                         *((c)++)=(unsigned char)(((l)    )&0xff))
+
+# define l2n8(l,c)       (*((c)++)=(unsigned char)(((l)>>56)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>>48)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>>40)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>>32)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>>24)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+                         *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+                         *((c)++)=(unsigned char)(((l)    )&0xff))
+
+/* NOTE - c is not incremented as per l2c */
+# define l2cn(l1,l2,c,n) { \
+                        c+=n; \
+                        switch (n) { \
+                        case 8: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \
+                        case 7: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \
+                        case 6: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \
+                        case 5: *(--(c))=(unsigned char)(((l2)    )&0xff); \
+                        case 4: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \
+                        case 3: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \
+                        case 2: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \
+                        case 1: *(--(c))=(unsigned char)(((l1)    )&0xff); \
+                                } \
+                        }
+
+# define n2s(c,s)        ((s=(((unsigned int)((c)[0]))<< 8)| \
+                             (((unsigned int)((c)[1]))    )),(c)+=2)
+# define s2n(s,c)        (((c)[0]=(unsigned char)(((s)>> 8)&0xff), \
+                           (c)[1]=(unsigned char)(((s)    )&0xff)),(c)+=2)
+
+# define n2l3(c,l)       ((l =(((unsigned long)((c)[0]))<<16)| \
+                              (((unsigned long)((c)[1]))<< 8)| \
+                              (((unsigned long)((c)[2]))    )),(c)+=3)
+
+# define l2n3(l,c)       (((c)[0]=(unsigned char)(((l)>>16)&0xff), \
+                           (c)[1]=(unsigned char)(((l)>> 8)&0xff), \
+                           (c)[2]=(unsigned char)(((l)    )&0xff)),(c)+=3)
+
+/*
+ * DTLS version numbers are strange because they're inverted. Except for
+ * DTLS1_BAD_VER, which should be considered "lower" than the rest.
+ */
+# define dtls_ver_ordinal(v1) (((v1) == DTLS1_BAD_VER) ? 0xff00 : (v1))
+# define DTLS_VERSION_GT(v1, v2) (dtls_ver_ordinal(v1) < dtls_ver_ordinal(v2))
+# define DTLS_VERSION_GE(v1, v2) (dtls_ver_ordinal(v1) <= dtls_ver_ordinal(v2))
+# define DTLS_VERSION_LT(v1, v2) (dtls_ver_ordinal(v1) > dtls_ver_ordinal(v2))
+# define DTLS_VERSION_LE(v1, v2) (dtls_ver_ordinal(v1) >= dtls_ver_ordinal(v2))
+
+
+/*
+ * Define the Bitmasks for SSL_CIPHER.algorithms.
+ * This bits are used packed as dense as possible. If new methods/ciphers
+ * etc will be added, the bits a likely to change, so this information
+ * is for internal library use only, even though SSL_CIPHER.algorithms
+ * can be publicly accessed.
+ * Use the according functions for cipher management instead.
+ *
+ * The bit mask handling in the selection and sorting scheme in
+ * ssl_create_cipher_list() has only limited capabilities, reflecting
+ * that the different entities within are mutually exclusive:
+ * ONLY ONE BIT PER MASK CAN BE SET AT A TIME.
+ */
+
+/* Bits for algorithm_mkey (key exchange algorithm) */
+/* RSA key exchange */
+# define SSL_kRSA                0x00000001U
+/* tmp DH key no DH cert */
+# define SSL_kDHE                0x00000002U
+/* synonym */
+# define SSL_kEDH                SSL_kDHE
+/* ephemeral ECDH */
+# define SSL_kECDHE              0x00000004U
+/* synonym */
+# define SSL_kEECDH              SSL_kECDHE
+/* PSK */
+# define SSL_kPSK                0x00000008U
+/* GOST key exchange */
+# define SSL_kGOST               0x00000010U
+/* SRP */
+# define SSL_kSRP                0x00000020U
+
+# define SSL_kRSAPSK             0x00000040U
+# define SSL_kECDHEPSK           0x00000080U
+# define SSL_kDHEPSK             0x00000100U
+
+/* all PSK */
+
+# define SSL_PSK     (SSL_kPSK | SSL_kRSAPSK | SSL_kECDHEPSK | SSL_kDHEPSK)
+
+/* Any appropriate key exchange algorithm (for TLS 1.3 ciphersuites) */
+# define SSL_kANY                0x00000000U
+
+/* Bits for algorithm_auth (server authentication) */
+/* RSA auth */
+# define SSL_aRSA                0x00000001U
+/* DSS auth */
+# define SSL_aDSS                0x00000002U
+/* no auth (i.e. use ADH or AECDH) */
+# define SSL_aNULL               0x00000004U
+/* ECDSA auth*/
+# define SSL_aECDSA              0x00000008U
+/* PSK auth */
+# define SSL_aPSK                0x00000010U
+/* GOST R 34.10-2001 signature auth */
+# define SSL_aGOST01             0x00000020U
+/* SRP auth */
+# define SSL_aSRP                0x00000040U
+/* GOST R 34.10-2012 signature auth */
+# define SSL_aGOST12             0x00000080U
+/* Any appropriate signature auth (for TLS 1.3 ciphersuites) */
+# define SSL_aANY                0x00000000U
+/* All bits requiring a certificate */
+#define SSL_aCERT \
+    (SSL_aRSA | SSL_aDSS | SSL_aECDSA | SSL_aGOST01 | SSL_aGOST12)
+
+/* Bits for algorithm_enc (symmetric encryption) */
+# define SSL_DES                 0x00000001U
+# define SSL_3DES                0x00000002U
+# define SSL_RC4                 0x00000004U
+# define SSL_RC2                 0x00000008U
+# define SSL_IDEA                0x00000010U
+# define SSL_eNULL               0x00000020U
+# define SSL_AES128              0x00000040U
+# define SSL_AES256              0x00000080U
+# define SSL_CAMELLIA128         0x00000100U
+# define SSL_CAMELLIA256         0x00000200U
+# define SSL_eGOST2814789CNT     0x00000400U
+# define SSL_SEED                0x00000800U
+# define SSL_AES128GCM           0x00001000U
+# define SSL_AES256GCM           0x00002000U
+# define SSL_AES128CCM           0x00004000U
+# define SSL_AES256CCM           0x00008000U
+# define SSL_AES128CCM8          0x00010000U
+# define SSL_AES256CCM8          0x00020000U
+# define SSL_eGOST2814789CNT12   0x00040000U
+# define SSL_CHACHA20POLY1305    0x00080000U
+# define SSL_ARIA128GCM          0x00100000U
+# define SSL_ARIA256GCM          0x00200000U
+
+# define SSL_AESGCM              (SSL_AES128GCM | SSL_AES256GCM)
+# define SSL_AESCCM              (SSL_AES128CCM | SSL_AES256CCM | SSL_AES128CCM8 | SSL_AES256CCM8)
+# define SSL_AES                 (SSL_AES128|SSL_AES256|SSL_AESGCM|SSL_AESCCM)
+# define SSL_CAMELLIA            (SSL_CAMELLIA128|SSL_CAMELLIA256)
+# define SSL_CHACHA20            (SSL_CHACHA20POLY1305)
+# define SSL_ARIAGCM             (SSL_ARIA128GCM | SSL_ARIA256GCM)
+# define SSL_ARIA                (SSL_ARIAGCM)
+
+/* Bits for algorithm_mac (symmetric authentication) */
+
+# define SSL_MD5                 0x00000001U
+# define SSL_SHA1                0x00000002U
+# define SSL_GOST94      0x00000004U
+# define SSL_GOST89MAC   0x00000008U
+# define SSL_SHA256              0x00000010U
+# define SSL_SHA384              0x00000020U
+/* Not a real MAC, just an indication it is part of cipher */
+# define SSL_AEAD                0x00000040U
+# define SSL_GOST12_256          0x00000080U
+# define SSL_GOST89MAC12         0x00000100U
+# define SSL_GOST12_512          0x00000200U
+
+/*
+ * When adding new digest in the ssl_ciph.c and increment SSL_MD_NUM_IDX make
+ * sure to update this constant too
+ */
+
+# define SSL_MD_MD5_IDX  0
+# define SSL_MD_SHA1_IDX 1
+# define SSL_MD_GOST94_IDX 2
+# define SSL_MD_GOST89MAC_IDX 3
+# define SSL_MD_SHA256_IDX 4
+# define SSL_MD_SHA384_IDX 5
+# define SSL_MD_GOST12_256_IDX  6
+# define SSL_MD_GOST89MAC12_IDX 7
+# define SSL_MD_GOST12_512_IDX  8
+# define SSL_MD_MD5_SHA1_IDX 9
+# define SSL_MD_SHA224_IDX 10
+# define SSL_MD_SHA512_IDX 11
+# define SSL_MAX_DIGEST 12
+
+/* Bits for algorithm2 (handshake digests and other extra flags) */
+
+/* Bits 0-7 are handshake MAC */
+# define SSL_HANDSHAKE_MAC_MASK  0xFF
+# define SSL_HANDSHAKE_MAC_MD5_SHA1 SSL_MD_MD5_SHA1_IDX
+# define SSL_HANDSHAKE_MAC_SHA256   SSL_MD_SHA256_IDX
+# define SSL_HANDSHAKE_MAC_SHA384   SSL_MD_SHA384_IDX
+# define SSL_HANDSHAKE_MAC_GOST94 SSL_MD_GOST94_IDX
+# define SSL_HANDSHAKE_MAC_GOST12_256 SSL_MD_GOST12_256_IDX
+# define SSL_HANDSHAKE_MAC_GOST12_512 SSL_MD_GOST12_512_IDX
+# define SSL_HANDSHAKE_MAC_DEFAULT  SSL_HANDSHAKE_MAC_MD5_SHA1
+
+/* Bits 8-15 bits are PRF */
+# define TLS1_PRF_DGST_SHIFT 8
+# define TLS1_PRF_SHA1_MD5 (SSL_MD_MD5_SHA1_IDX << TLS1_PRF_DGST_SHIFT)
+# define TLS1_PRF_SHA256 (SSL_MD_SHA256_IDX << TLS1_PRF_DGST_SHIFT)
+# define TLS1_PRF_SHA384 (SSL_MD_SHA384_IDX << TLS1_PRF_DGST_SHIFT)
+# define TLS1_PRF_GOST94 (SSL_MD_GOST94_IDX << TLS1_PRF_DGST_SHIFT)
+# define TLS1_PRF_GOST12_256 (SSL_MD_GOST12_256_IDX << TLS1_PRF_DGST_SHIFT)
+# define TLS1_PRF_GOST12_512 (SSL_MD_GOST12_512_IDX << TLS1_PRF_DGST_SHIFT)
+# define TLS1_PRF            (SSL_MD_MD5_SHA1_IDX << TLS1_PRF_DGST_SHIFT)
+
+/*
+ * Stream MAC for GOST ciphersuites from cryptopro draft (currently this also
+ * goes into algorithm2)
+ */
+# define TLS1_STREAM_MAC 0x10000
+
+# define SSL_STRONG_MASK         0x0000001FU
+# define SSL_DEFAULT_MASK        0X00000020U
+
+# define SSL_STRONG_NONE         0x00000001U
+# define SSL_LOW                 0x00000002U
+# define SSL_MEDIUM              0x00000004U
+# define SSL_HIGH                0x00000008U
+# define SSL_FIPS                0x00000010U
+# define SSL_NOT_DEFAULT         0x00000020U
+
+/* we have used 0000003f - 26 bits left to go */
+
+/* Flag used on OpenSSL ciphersuite ids to indicate they are for SSLv3+ */
+# define SSL3_CK_CIPHERSUITE_FLAG                0x03000000
+
+/* Check if an SSL structure is using DTLS */
+# define SSL_IS_DTLS(s)  (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS)
+
+/* Check if we are using TLSv1.3 */
+# define SSL_IS_TLS13(s) (!SSL_IS_DTLS(s) \
+                          && (s)->method->version >= TLS1_3_VERSION \
+                          && (s)->method->version != TLS_ANY_VERSION)
+
+# define SSL_TREAT_AS_TLS13(s) \
+    (SSL_IS_TLS13(s) || (s)->early_data_state == SSL_EARLY_DATA_CONNECTING \
+     || (s)->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY \
+     || (s)->early_data_state == SSL_EARLY_DATA_WRITING \
+     || (s)->early_data_state == SSL_EARLY_DATA_WRITE_RETRY \
+     || (s)->hello_retry_request == SSL_HRR_PENDING)
+
+# define SSL_IS_FIRST_HANDSHAKE(S) ((s)->s3->tmp.finish_md_len == 0 \
+                                    || (s)->s3->tmp.peer_finish_md_len == 0)
+
+/* See if we need explicit IV */
+# define SSL_USE_EXPLICIT_IV(s)  \
+                (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_EXPLICIT_IV)
+/*
+ * See if we use signature algorithms extension and signature algorithm
+ * before signatures.
+ */
+# define SSL_USE_SIGALGS(s)      \
+                        (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_SIGALGS)
+/*
+ * Allow TLS 1.2 ciphersuites: applies to DTLS 1.2 as well as TLS 1.2: may
+ * apply to others in future.
+ */
+# define SSL_USE_TLS1_2_CIPHERS(s)       \
+                (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_TLS1_2_CIPHERS)
+/*
+ * Determine if a client can use TLS 1.2 ciphersuites: can't rely on method
+ * flags because it may not be set to correct version yet.
+ */
+# define SSL_CLIENT_USE_TLS1_2_CIPHERS(s)        \
+    ((!SSL_IS_DTLS(s) && s->client_version >= TLS1_2_VERSION) || \
+     (SSL_IS_DTLS(s) && DTLS_VERSION_GE(s->client_version, DTLS1_2_VERSION)))
+/*
+ * Determine if a client should send signature algorithms extension:
+ * as with TLS1.2 cipher we can't rely on method flags.
+ */
+# define SSL_CLIENT_USE_SIGALGS(s)        \
+    SSL_CLIENT_USE_TLS1_2_CIPHERS(s)
+
+# define IS_MAX_FRAGMENT_LENGTH_EXT_VALID(value) \
+    (((value) >= TLSEXT_max_fragment_length_512) && \
+     ((value) <= TLSEXT_max_fragment_length_4096))
+# define USE_MAX_FRAGMENT_LENGTH_EXT(session) \
+    IS_MAX_FRAGMENT_LENGTH_EXT_VALID(session->ext.max_fragment_len_mode)
+# define GET_MAX_FRAGMENT_LENGTH(session) \
+    (512U << (session->ext.max_fragment_len_mode - 1))
+
+# define SSL_READ_ETM(s) (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC_READ)
+# define SSL_WRITE_ETM(s) (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC_WRITE)
+
+/* Mostly for SSLv3 */
+# define SSL_PKEY_RSA            0
+# define SSL_PKEY_RSA_PSS_SIGN   1
+# define SSL_PKEY_DSA_SIGN       2
+# define SSL_PKEY_ECC            3
+# define SSL_PKEY_GOST01         4
+# define SSL_PKEY_GOST12_256     5
+# define SSL_PKEY_GOST12_512     6
+# define SSL_PKEY_ED25519        7
+# define SSL_PKEY_ED448          8
+# define SSL_PKEY_NUM            9
+
+/*-
+ * SSL_kRSA <- RSA_ENC
+ * SSL_kDH  <- DH_ENC & (RSA_ENC | RSA_SIGN | DSA_SIGN)
+ * SSL_kDHE <- RSA_ENC | RSA_SIGN | DSA_SIGN
+ * SSL_aRSA <- RSA_ENC | RSA_SIGN
+ * SSL_aDSS <- DSA_SIGN
+ */
+
+/*-
+#define CERT_INVALID            0
+#define CERT_PUBLIC_KEY         1
+#define CERT_PRIVATE_KEY        2
+*/
+
+/* Post-Handshake Authentication state */
+typedef enum {
+    SSL_PHA_NONE = 0,
+    SSL_PHA_EXT_SENT,        /* client-side only: extension sent */
+    SSL_PHA_EXT_RECEIVED,    /* server-side only: extension received */
+    SSL_PHA_REQUEST_PENDING, /* server-side only: request pending */
+    SSL_PHA_REQUESTED        /* request received by client, or sent by server */
+} SSL_PHA_STATE;
+
+/* CipherSuite length. SSLv3 and all TLS versions. */
+# define TLS_CIPHER_LEN 2
+/* used to hold info on the particular ciphers used */
+struct ssl_cipher_st {
+    uint32_t valid;
+    const char *name;           /* text name */
+    const char *stdname;        /* RFC name */
+    uint32_t id;                /* id, 4 bytes, first is version */
+    /*
+     * changed in 1.0.0: these four used to be portions of a single value
+     * 'algorithms'
+     */
+    uint32_t algorithm_mkey;    /* key exchange algorithm */
+    uint32_t algorithm_auth;    /* server authentication */
+    uint32_t algorithm_enc;     /* symmetric encryption */
+    uint32_t algorithm_mac;     /* symmetric authentication */
+    int min_tls;                /* minimum SSL/TLS protocol version */
+    int max_tls;                /* maximum SSL/TLS protocol version */
+    int min_dtls;               /* minimum DTLS protocol version */
+    int max_dtls;               /* maximum DTLS protocol version */
+    uint32_t algo_strength;     /* strength and export flags */
+    uint32_t algorithm2;        /* Extra flags */
+    int32_t strength_bits;      /* Number of bits really used */
+    uint32_t alg_bits;          /* Number of bits for algorithm */
+};
+
+/* Used to hold SSL/TLS functions */
+struct ssl_method_st {
+    int version;
+    unsigned flags;
+    unsigned long mask;
+    int (*ssl_new) (SSL *s);
+    int (*ssl_clear) (SSL *s);
+    void (*ssl_free) (SSL *s);
+    int (*ssl_accept) (SSL *s);
+    int (*ssl_connect) (SSL *s);
+    int (*ssl_read) (SSL *s, void *buf, size_t len, size_t *readbytes);
+    int (*ssl_peek) (SSL *s, void *buf, size_t len, size_t *readbytes);
+    int (*ssl_write) (SSL *s, const void *buf, size_t len, size_t *written);
+    int (*ssl_shutdown) (SSL *s);
+    int (*ssl_renegotiate) (SSL *s);
+    int (*ssl_renegotiate_check) (SSL *s, int);
+    int (*ssl_read_bytes) (SSL *s, int type, int *recvd_type,
+                           unsigned char *buf, size_t len, int peek,
+                           size_t *readbytes);
+    int (*ssl_write_bytes) (SSL *s, int type, const void *buf_, size_t len,
+                            size_t *written);
+    int (*ssl_dispatch_alert) (SSL *s);
+    long (*ssl_ctrl) (SSL *s, int cmd, long larg, void *parg);
+    long (*ssl_ctx_ctrl) (SSL_CTX *ctx, int cmd, long larg, void *parg);
+    const SSL_CIPHER *(*get_cipher_by_char) (const unsigned char *ptr);
+    int (*put_cipher_by_char) (const SSL_CIPHER *cipher, WPACKET *pkt,
+                               size_t *len);
+    size_t (*ssl_pending) (const SSL *s);
+    int (*num_ciphers) (void);
+    const SSL_CIPHER *(*get_cipher) (unsigned ncipher);
+    long (*get_timeout) (void);
+    const struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */
+    int (*ssl_version) (void);
+    long (*ssl_callback_ctrl) (SSL *s, int cb_id, void (*fp) (void));
+    long (*ssl_ctx_callback_ctrl) (SSL_CTX *s, int cb_id, void (*fp) (void));
+};
+
+/*
+ * Matches the length of PSK_MAX_PSK_LEN. We keep it the same value for
+ * consistency, even in the event of OPENSSL_NO_PSK being defined.
+ */
+# define TLS13_MAX_RESUMPTION_PSK_LENGTH      256
+
+/*-
+ * Lets make this into an ASN.1 type structure as follows
+ * SSL_SESSION_ID ::= SEQUENCE {
+ *      version                 INTEGER,        -- structure version number
+ *      SSLversion              INTEGER,        -- SSL version number
+ *      Cipher                  OCTET STRING,   -- the 3 byte cipher ID
+ *      Session_ID              OCTET STRING,   -- the Session ID
+ *      Master_key              OCTET STRING,   -- the master key
+ *      Key_Arg [ 0 ] IMPLICIT  OCTET STRING,   -- the optional Key argument
+ *      Time [ 1 ] EXPLICIT     INTEGER,        -- optional Start Time
+ *      Timeout [ 2 ] EXPLICIT  INTEGER,        -- optional Timeout ins seconds
+ *      Peer [ 3 ] EXPLICIT     X509,           -- optional Peer Certificate
+ *      Session_ID_context [ 4 ] EXPLICIT OCTET STRING,   -- the Session ID context
+ *      Verify_result [ 5 ] EXPLICIT INTEGER,   -- X509_V_... code for `Peer'
+ *      HostName [ 6 ] EXPLICIT OCTET STRING,   -- optional HostName from servername TLS extension
+ *      PSK_identity_hint [ 7 ] EXPLICIT OCTET STRING, -- optional PSK identity hint
+ *      PSK_identity [ 8 ] EXPLICIT OCTET STRING,  -- optional PSK identity
+ *      Ticket_lifetime_hint [9] EXPLICIT INTEGER, -- server's lifetime hint for session ticket
+ *      Ticket [10]             EXPLICIT OCTET STRING, -- session ticket (clients only)
+ *      Compression_meth [11]   EXPLICIT OCTET STRING, -- optional compression method
+ *      SRP_username [ 12 ] EXPLICIT OCTET STRING -- optional SRP username
+ *      flags [ 13 ] EXPLICIT INTEGER -- optional flags
+ *      }
+ * Look in ssl/ssl_asn1.c for more details
+ * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-).
+ */
+struct ssl_session_st {
+    int ssl_version;            /* what ssl version session info is being kept
+                                 * in here? */
+    size_t master_key_length;
+
+    /* TLSv1.3 early_secret used for external PSKs */
+    unsigned char early_secret[EVP_MAX_MD_SIZE];
+    /*
+     * For <=TLS1.2 this is the master_key. For TLS1.3 this is the resumption
+     * PSK
+     */
+    unsigned char master_key[TLS13_MAX_RESUMPTION_PSK_LENGTH];
+    /* session_id - valid? */
+    size_t session_id_length;
+    unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
+    /*
+     * this is used to determine whether the session is being reused in the
+     * appropriate context. It is up to the application to set this, via
+     * SSL_new
+     */
+    size_t sid_ctx_length;
+    unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
+# ifndef OPENSSL_NO_PSK
+    char *psk_identity_hint;
+    char *psk_identity;
+# endif
+    /*
+     * Used to indicate that session resumption is not allowed. Applications
+     * can also set this bit for a new session via not_resumable_session_cb
+     * to disable session caching and tickets.
+     */
+    int not_resumable;
+    /* This is the cert and type for the other end. */
+    X509 *peer;
+    /* Certificate chain peer sent. */
+    STACK_OF(X509) *peer_chain;
+    /*
+     * when app_verify_callback accepts a session where the peer's
+     * certificate is not ok, we must remember the error for session reuse:
+     */
+    long verify_result;         /* only for servers */
+    CRYPTO_REF_COUNT references;
+    long timeout;
+    long time;
+    unsigned int compress_meth; /* Need to lookup the method */
+    const SSL_CIPHER *cipher;
+    unsigned long cipher_id;    /* when ASN.1 loaded, this needs to be used to
+                                 * load the 'cipher' structure */
+    CRYPTO_EX_DATA ex_data;     /* application specific data */
+    /*
+     * These are used to make removal of session-ids more efficient and to
+     * implement a maximum cache size.
+     */
+    struct ssl_session_st *prev, *next;
+
+    struct {
+        char *hostname;
+        /* RFC4507 info */
+        unsigned char *tick; /* Session ticket */
+        size_t ticklen;      /* Session ticket length */
+        /* Session lifetime hint in seconds */
+        unsigned long tick_lifetime_hint;
+        uint32_t tick_age_add;
+        /* Max number of bytes that can be sent as early data */
+        uint32_t max_early_data;
+        /* The ALPN protocol selected for this session */
+        unsigned char *alpn_selected;
+        size_t alpn_selected_len;
+        /*
+         * Maximum Fragment Length as per RFC 4366.
+         * If this value does not contain RFC 4366 allowed values (1-4) then
+         * either the Maximum Fragment Length Negotiation failed or was not
+         * performed at all.
+         */
+        uint8_t max_fragment_len_mode;
+    } ext;
+# ifndef OPENSSL_NO_SRP
+    char *srp_username;
+# endif
+    unsigned char *ticket_appdata;
+    size_t ticket_appdata_len;
+    uint32_t flags;
+    CRYPTO_RWLOCK *lock;
+};
+
+/* Extended master secret support */
+# define SSL_SESS_FLAG_EXTMS             0x1
+
+# ifndef OPENSSL_NO_SRP
+
+typedef struct srp_ctx_st {
+    /* param for all the callbacks */
+    void *SRP_cb_arg;
+    /* set client Hello login callback */
+    int (*TLS_ext_srp_username_callback) (SSL *, int *, void *);
+    /* set SRP N/g param callback for verification */
+    int (*SRP_verify_param_callback) (SSL *, void *);
+    /* set SRP client passwd callback */
+    char *(*SRP_give_srp_client_pwd_callback) (SSL *, void *);
+    char *login;
+    BIGNUM *N, *g, *s, *B, *A;
+    BIGNUM *a, *b, *v;
+    char *info;
+    int strength;
+    unsigned long srp_Mask;
+} SRP_CTX;
+
+# endif
+
+typedef enum {
+    SSL_EARLY_DATA_NONE = 0,
+    SSL_EARLY_DATA_CONNECT_RETRY,
+    SSL_EARLY_DATA_CONNECTING,
+    SSL_EARLY_DATA_WRITE_RETRY,
+    SSL_EARLY_DATA_WRITING,
+    SSL_EARLY_DATA_WRITE_FLUSH,
+    SSL_EARLY_DATA_UNAUTH_WRITING,
+    SSL_EARLY_DATA_FINISHED_WRITING,
+    SSL_EARLY_DATA_ACCEPT_RETRY,
+    SSL_EARLY_DATA_ACCEPTING,
+    SSL_EARLY_DATA_READ_RETRY,
+    SSL_EARLY_DATA_READING,
+    SSL_EARLY_DATA_FINISHED_READING
+} SSL_EARLY_DATA_STATE;
+
+/*
+ * We check that the amount of unreadable early data doesn't exceed
+ * max_early_data. max_early_data is given in plaintext bytes. However if it is
+ * unreadable then we only know the number of ciphertext bytes. We also don't
+ * know how much the overhead should be because it depends on the ciphersuite.
+ * We make a small allowance. We assume 5 records of actual data plus the end
+ * of early data alert record. Each record has a tag and a content type byte.
+ * The longest tag length we know of is EVP_GCM_TLS_TAG_LEN. We don't count the
+ * content of the alert record either which is 2 bytes.
+ */
+# define EARLY_DATA_CIPHERTEXT_OVERHEAD ((6 * (EVP_GCM_TLS_TAG_LEN + 1)) + 2)
+
+/*
+ * The allowance we have between the client's calculated ticket age and our own.
+ * We allow for 10 seconds (units are in ms). If a ticket is presented and the
+ * client's age calculation is different by more than this than our own then we
+ * do not allow that ticket for early_data.
+ */
+# define TICKET_AGE_ALLOWANCE   (10 * 1000)
+
+#define MAX_COMPRESSIONS_SIZE   255
+
+struct ssl_comp_st {
+    int id;
+    const char *name;
+    COMP_METHOD *method;
+};
+
+typedef struct raw_extension_st {
+    /* Raw packet data for the extension */
+    PACKET data;
+    /* Set to 1 if the extension is present or 0 otherwise */
+    int present;
+    /* Set to 1 if we have already parsed the extension or 0 otherwise */
+    int parsed;
+    /* The type of this extension, i.e. a TLSEXT_TYPE_* value */
+    unsigned int type;
+    /* Track what order extensions are received in (0-based). */
+    size_t received_order;
+} RAW_EXTENSION;
+
+typedef struct {
+    unsigned int isv2;
+    unsigned int legacy_version;
+    unsigned char random[SSL3_RANDOM_SIZE];
+    size_t session_id_len;
+    unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
+    size_t dtls_cookie_len;
+    unsigned char dtls_cookie[DTLS1_COOKIE_LENGTH];
+    PACKET ciphersuites;
+    size_t compressions_len;
+    unsigned char compressions[MAX_COMPRESSIONS_SIZE];
+    PACKET extensions;
+    size_t pre_proc_exts_len;
+    RAW_EXTENSION *pre_proc_exts;
+} CLIENTHELLO_MSG;
+
+/*
+ * Extension index values NOTE: Any updates to these defines should be mirrored
+ * with equivalent updates to ext_defs in extensions.c
+ */
+typedef enum tlsext_index_en {
+    TLSEXT_IDX_renegotiate,
+    TLSEXT_IDX_server_name,
+    TLSEXT_IDX_max_fragment_length,
+    TLSEXT_IDX_srp,
+    TLSEXT_IDX_ec_point_formats,
+    TLSEXT_IDX_supported_groups,
+    TLSEXT_IDX_session_ticket,
+    TLSEXT_IDX_status_request,
+    TLSEXT_IDX_next_proto_neg,
+    TLSEXT_IDX_application_layer_protocol_negotiation,
+    TLSEXT_IDX_use_srtp,
+    TLSEXT_IDX_encrypt_then_mac,
+    TLSEXT_IDX_signed_certificate_timestamp,
+    TLSEXT_IDX_extended_master_secret,
+    TLSEXT_IDX_signature_algorithms_cert,
+    TLSEXT_IDX_post_handshake_auth,
+    TLSEXT_IDX_signature_algorithms,
+    TLSEXT_IDX_supported_versions,
+    TLSEXT_IDX_psk_kex_modes,
+    TLSEXT_IDX_key_share,
+    TLSEXT_IDX_cookie,
+    TLSEXT_IDX_cryptopro_bug,
+    TLSEXT_IDX_early_data,
+    TLSEXT_IDX_certificate_authorities,
+    TLSEXT_IDX_padding,
+    TLSEXT_IDX_psk,
+    /* Dummy index - must always be the last entry */
+    TLSEXT_IDX_num_builtins
+} TLSEXT_INDEX;
+
+DEFINE_LHASH_OF(SSL_SESSION);
+/* Needed in ssl_cert.c */
+DEFINE_LHASH_OF(X509_NAME);
+
+# define TLSEXT_KEYNAME_LENGTH  16
+# define TLSEXT_TICK_KEY_LENGTH 32
+
+typedef struct ssl_ctx_ext_secure_st {
+    unsigned char tick_hmac_key[TLSEXT_TICK_KEY_LENGTH];
+    unsigned char tick_aes_key[TLSEXT_TICK_KEY_LENGTH];
+} SSL_CTX_EXT_SECURE;
+
+struct ssl_ctx_st {
+    const SSL_METHOD *method;
+    STACK_OF(SSL_CIPHER) *cipher_list;
+    /* same as above but sorted for lookup */
+    STACK_OF(SSL_CIPHER) *cipher_list_by_id;
+    /* TLSv1.3 specific ciphersuites */
+    STACK_OF(SSL_CIPHER) *tls13_ciphersuites;
+    struct x509_store_st /* X509_STORE */ *cert_store;
+    LHASH_OF(SSL_SESSION) *sessions;
+    /*
+     * Most session-ids that will be cached, default is
+     * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited.
+     */
+    size_t session_cache_size;
+    struct ssl_session_st *session_cache_head;
+    struct ssl_session_st *session_cache_tail;
+    /*
+     * This can have one of 2 values, ored together, SSL_SESS_CACHE_CLIENT,
+     * SSL_SESS_CACHE_SERVER, Default is SSL_SESSION_CACHE_SERVER, which
+     * means only SSL_accept will cache SSL_SESSIONS.
+     */
+    uint32_t session_cache_mode;
+    /*
+     * If timeout is not 0, it is the default timeout value set when
+     * SSL_new() is called.  This has been put in to make life easier to set
+     * things up
+     */
+    long session_timeout;
+    /*
+     * If this callback is not null, it will be called each time a session id
+     * is added to the cache.  If this function returns 1, it means that the
+     * callback will do a SSL_SESSION_free() when it has finished using it.
+     * Otherwise, on 0, it means the callback has finished with it. If
+     * remove_session_cb is not null, it will be called when a session-id is
+     * removed from the cache.  After the call, OpenSSL will
+     * SSL_SESSION_free() it.
+     */
+    int (*new_session_cb) (struct ssl_st *ssl, SSL_SESSION *sess);
+    void (*remove_session_cb) (struct ssl_ctx_st *ctx, SSL_SESSION *sess);
+    SSL_SESSION *(*get_session_cb) (struct ssl_st *ssl,
+                                    const unsigned char *data, int len,
+                                    int *copy);
+    struct {
+        TSAN_QUALIFIER int sess_connect;       /* SSL new conn - started */
+        TSAN_QUALIFIER int sess_connect_renegotiate; /* SSL reneg - requested */
+        TSAN_QUALIFIER int sess_connect_good;  /* SSL new conne/reneg - finished */
+        TSAN_QUALIFIER int sess_accept;        /* SSL new accept - started */
+        TSAN_QUALIFIER int sess_accept_renegotiate; /* SSL reneg - requested */
+        TSAN_QUALIFIER int sess_accept_good;   /* SSL accept/reneg - finished */
+        TSAN_QUALIFIER int sess_miss;          /* session lookup misses */
+        TSAN_QUALIFIER int sess_timeout;       /* reuse attempt on timeouted session */
+        TSAN_QUALIFIER int sess_cache_full;    /* session removed due to full cache */
+        TSAN_QUALIFIER int sess_hit;           /* session reuse actually done */
+        TSAN_QUALIFIER int sess_cb_hit;        /* session-id that was not in
+                                                * the cache was passed back via
+                                                * the callback. This indicates
+                                                * that the application is
+                                                * supplying session-id's from
+                                                * other processes - spooky
+                                                * :-) */
+    } stats;
+
+    CRYPTO_REF_COUNT references;
+
+    /* if defined, these override the X509_verify_cert() calls */
+    int (*app_verify_callback) (X509_STORE_CTX *, void *);
+    void *app_verify_arg;
+    /*
+     * before OpenSSL 0.9.7, 'app_verify_arg' was ignored
+     * ('app_verify_callback' was called with just one argument)
+     */
+
+    /* Default password callback. */
+    pem_password_cb *default_passwd_callback;
+
+    /* Default password callback user data. */
+    void *default_passwd_callback_userdata;
+
+    /* get client cert callback */
+    int (*client_cert_cb) (SSL *ssl, X509 **x509, EVP_PKEY **pkey);
+
+    /* cookie generate callback */
+    int (*app_gen_cookie_cb) (SSL *ssl, unsigned char *cookie,
+                              unsigned int *cookie_len);
+
+    /* verify cookie callback */
+    int (*app_verify_cookie_cb) (SSL *ssl, const unsigned char *cookie,
+                                 unsigned int cookie_len);
+
+    /* TLS1.3 app-controlled cookie generate callback */
+    int (*gen_stateless_cookie_cb) (SSL *ssl, unsigned char *cookie,
+                                    size_t *cookie_len);
+
+    /* TLS1.3 verify app-controlled cookie callback */
+    int (*verify_stateless_cookie_cb) (SSL *ssl, const unsigned char *cookie,
+                                       size_t cookie_len);
+
+    CRYPTO_EX_DATA ex_data;
+
+    const EVP_MD *md5;          /* For SSLv3/TLSv1 'ssl3-md5' */
+    const EVP_MD *sha1;         /* For SSLv3/TLSv1 'ssl3->sha1' */
+
+    STACK_OF(X509) *extra_certs;
+    STACK_OF(SSL_COMP) *comp_methods; /* stack of SSL_COMP, SSLv3/TLSv1 */
+
+    /* Default values used when no per-SSL value is defined follow */
+
+    /* used if SSL's info_callback is NULL */
+    void (*info_callback) (const SSL *ssl, int type, int val);
+
+    /*
+     * What we put in certificate_authorities extension for TLS 1.3
+     * (ClientHello and CertificateRequest) or just client cert requests for
+     * earlier versions. If client_ca_names is populated then it is only used
+     * for client cert requests, and in preference to ca_names.
+     */
+    STACK_OF(X509_NAME) *ca_names;
+    STACK_OF(X509_NAME) *client_ca_names;
+
+    /*
+     * Default values to use in SSL structures follow (these are copied by
+     * SSL_new)
+     */
+
+    uint32_t options;
+    uint32_t mode;
+    int min_proto_version;
+    int max_proto_version;
+    size_t max_cert_list;
+
+    struct cert_st /* CERT */ *cert;
+    int read_ahead;
+
+    /* callback that allows applications to peek at protocol messages */
+    void (*msg_callback) (int write_p, int version, int content_type,
+                          const void *buf, size_t len, SSL *ssl, void *arg);
+    void *msg_callback_arg;
+
+    uint32_t verify_mode;
+    size_t sid_ctx_length;
+    unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
+    /* called 'verify_callback' in the SSL */
+    int (*default_verify_callback) (int ok, X509_STORE_CTX *ctx);
+
+    /* Default generate session ID callback. */
+    GEN_SESSION_CB generate_session_id;
+
+    X509_VERIFY_PARAM *param;
+
+    int quiet_shutdown;
+
+# ifndef OPENSSL_NO_CT
+    CTLOG_STORE *ctlog_store;   /* CT Log Store */
+    /*
+     * Validates that the SCTs (Signed Certificate Timestamps) are sufficient.
+     * If they are not, the connection should be aborted.
+     */
+    ssl_ct_validation_cb ct_validation_callback;
+    void *ct_validation_callback_arg;
+# endif
+
+    /*
+     * If we're using more than one pipeline how should we divide the data
+     * up between the pipes?
+     */
+    size_t split_send_fragment;
+    /*
+     * Maximum amount of data to send in one fragment. actual record size can
+     * be more than this due to padding and MAC overheads.
+     */
+    size_t max_send_fragment;
+
+    /* Up to how many pipelines should we use? If 0 then 1 is assumed */
+    size_t max_pipelines;
+
+    /* The default read buffer length to use (0 means not set) */
+    size_t default_read_buf_len;
+
+# ifndef OPENSSL_NO_ENGINE
+    /*
+     * Engine to pass requests for client certs to
+     */
+    ENGINE *client_cert_engine;
+# endif
+
+    /* ClientHello callback.  Mostly for extensions, but not entirely. */
+    SSL_client_hello_cb_fn client_hello_cb;
+    void *client_hello_cb_arg;
+
+    /* TLS extensions. */
+    struct {
+        /* TLS extensions servername callback */
+        int (*servername_cb) (SSL *, int *, void *);
+        void *servername_arg;
+        /* RFC 4507 session ticket keys */
+        unsigned char tick_key_name[TLSEXT_KEYNAME_LENGTH];
+        SSL_CTX_EXT_SECURE *secure;
+        /* Callback to support customisation of ticket key setting */
+        int (*ticket_key_cb) (SSL *ssl,
+                              unsigned char *name, unsigned char *iv,
+                              EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc);
+
+        /* certificate status request info */
+        /* Callback for status request */
+        int (*status_cb) (SSL *ssl, void *arg);
+        void *status_arg;
+        /* ext status type used for CSR extension (OCSP Stapling) */
+        int status_type;
+        /* RFC 4366 Maximum Fragment Length Negotiation */
+        uint8_t max_fragment_len_mode;
+
+# ifndef OPENSSL_NO_EC
+        /* EC extension values inherited by SSL structure */
+        size_t ecpointformats_len;
+        unsigned char *ecpointformats;
+        size_t supportedgroups_len;
+        uint16_t *supportedgroups;
+# endif                         /* OPENSSL_NO_EC */
+
+        /*
+         * ALPN information (we are in the process of transitioning from NPN to
+         * ALPN.)
+         */
+
+        /*-
+         * For a server, this contains a callback function that allows the
+         * server to select the protocol for the connection.
+         *   out: on successful return, this must point to the raw protocol
+         *        name (without the length prefix).
+         *   outlen: on successful return, this contains the length of |*out|.
+         *   in: points to the client's list of supported protocols in
+         *       wire-format.
+         *   inlen: the length of |in|.
+         */
+        int (*alpn_select_cb) (SSL *s,
+                               const unsigned char **out,
+                               unsigned char *outlen,
+                               const unsigned char *in,
+                               unsigned int inlen, void *arg);
+        void *alpn_select_cb_arg;
+
+        /*
+         * For a client, this contains the list of supported protocols in wire
+         * format.
+         */
+        unsigned char *alpn;
+        size_t alpn_len;
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+        /* Next protocol negotiation information */
+
+        /*
+         * For a server, this contains a callback function by which the set of
+         * advertised protocols can be provided.
+         */
+        SSL_CTX_npn_advertised_cb_func npn_advertised_cb;
+        void *npn_advertised_cb_arg;
+        /*
+         * For a client, this contains a callback function that selects the next
+         * protocol from the list provided by the server.
+         */
+        SSL_CTX_npn_select_cb_func npn_select_cb;
+        void *npn_select_cb_arg;
+# endif
+
+        unsigned char cookie_hmac_key[SHA256_DIGEST_LENGTH];
+    } ext;
+
+# ifndef OPENSSL_NO_PSK
+    SSL_psk_client_cb_func psk_client_callback;
+    SSL_psk_server_cb_func psk_server_callback;
+# endif
+    SSL_psk_find_session_cb_func psk_find_session_cb;
+    SSL_psk_use_session_cb_func psk_use_session_cb;
+
+# ifndef OPENSSL_NO_SRP
+    SRP_CTX srp_ctx;            /* ctx for SRP authentication */
+# endif
+
+    /* Shared DANE context */
+    struct dane_ctx_st dane;
+
+# ifndef OPENSSL_NO_SRTP
+    /* SRTP profiles we are willing to do from RFC 5764 */
+    STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;
+# endif
+    /*
+     * Callback for disabling session caching and ticket support on a session
+     * basis, depending on the chosen cipher.
+     */
+    int (*not_resumable_session_cb) (SSL *ssl, int is_forward_secure);
+
+    CRYPTO_RWLOCK *lock;
+
+    /*
+     * Callback for logging key material for use with debugging tools like
+     * Wireshark. The callback should log `line` followed by a newline.
+     */
+    SSL_CTX_keylog_cb_func keylog_callback;
+
+    /*
+     * The maximum number of bytes advertised in session tickets that can be
+     * sent as early data.
+     */
+    uint32_t max_early_data;
+
+    /*
+     * The maximum number of bytes of early data that a server will tolerate
+     * (which should be at least as much as max_early_data).
+     */
+    uint32_t recv_max_early_data;
+
+    /* TLS1.3 padding callback */
+    size_t (*record_padding_cb)(SSL *s, int type, size_t len, void *arg);
+    void *record_padding_arg;
+    size_t block_padding;
+
+    /* Session ticket appdata */
+    SSL_CTX_generate_session_ticket_fn generate_ticket_cb;
+    SSL_CTX_decrypt_session_ticket_fn decrypt_ticket_cb;
+    void *ticket_cb_data;
+
+    /* The number of TLS1.3 tickets to automatically send */
+    size_t num_tickets;
+
+    /* Callback to determine if early_data is acceptable or not */
+    SSL_allow_early_data_cb_fn allow_early_data_cb;
+    void *allow_early_data_cb_data;
+
+    /* Do we advertise Post-handshake auth support? */
+    int pha_enabled;
+};
+
+struct ssl_st {
+    /*
+     * protocol version (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION,
+     * DTLS1_VERSION)
+     */
+    int version;
+    /* SSLv3 */
+    const SSL_METHOD *method;
+    /*
+     * There are 2 BIO's even though they are normally both the same.  This
+     * is so data can be read and written to different handlers
+     */
+    /* used by SSL_read */
+    BIO *rbio;
+    /* used by SSL_write */
+    BIO *wbio;
+    /* used during session-id reuse to concatenate messages */
+    BIO *bbio;
+    /*
+     * This holds a variable that indicates what we were doing when a 0 or -1
+     * is returned.  This is needed for non-blocking IO so we know what
+     * request needs re-doing when in SSL_accept or SSL_connect
+     */
+    int rwstate;
+    int (*handshake_func) (SSL *);
+    /*
+     * Imagine that here's a boolean member "init" that is switched as soon
+     * as SSL_set_{accept/connect}_state is called for the first time, so
+     * that "state" and "handshake_func" are properly initialized.  But as
+     * handshake_func is == 0 until then, we use this test instead of an
+     * "init" member.
+     */
+    /* are we the server side? */
+    int server;
+    /*
+     * Generate a new session or reuse an old one.
+     * NB: For servers, the 'new' session may actually be a previously
+     * cached session or even the previous session unless
+     * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set
+     */
+    int new_session;
+    /* don't send shutdown packets */
+    int quiet_shutdown;
+    /* we have shut things down, 0x01 sent, 0x02 for received */
+    int shutdown;
+    /* where we are */
+    OSSL_STATEM statem;
+    SSL_EARLY_DATA_STATE early_data_state;
+    BUF_MEM *init_buf;          /* buffer used during init */
+    void *init_msg;             /* pointer to handshake message body, set by
+                                 * ssl3_get_message() */
+    size_t init_num;               /* amount read/written */
+    size_t init_off;               /* amount read/written */
+    struct ssl3_state_st *s3;   /* SSLv3 variables */
+    struct dtls1_state_st *d1;  /* DTLSv1 variables */
+    /* callback that allows applications to peek at protocol messages */
+    void (*msg_callback) (int write_p, int version, int content_type,
+                          const void *buf, size_t len, SSL *ssl, void *arg);
+    void *msg_callback_arg;
+    int hit;                    /* reusing a previous session */
+    X509_VERIFY_PARAM *param;
+    /* Per connection DANE state */
+    SSL_DANE dane;
+    /* crypto */
+    STACK_OF(SSL_CIPHER) *peer_ciphers;
+    STACK_OF(SSL_CIPHER) *cipher_list;
+    STACK_OF(SSL_CIPHER) *cipher_list_by_id;
+    /* TLSv1.3 specific ciphersuites */
+    STACK_OF(SSL_CIPHER) *tls13_ciphersuites;
+    /*
+     * These are the ones being used, the ones in SSL_SESSION are the ones to
+     * be 'copied' into these ones
+     */
+    uint32_t mac_flags;
+    /*
+     * The TLS1.3 secrets.
+     */
+    unsigned char early_secret[EVP_MAX_MD_SIZE];
+    unsigned char handshake_secret[EVP_MAX_MD_SIZE];
+    unsigned char master_secret[EVP_MAX_MD_SIZE];
+    unsigned char resumption_master_secret[EVP_MAX_MD_SIZE];
+    unsigned char client_finished_secret[EVP_MAX_MD_SIZE];
+    unsigned char server_finished_secret[EVP_MAX_MD_SIZE];
+    unsigned char server_finished_hash[EVP_MAX_MD_SIZE];
+    unsigned char handshake_traffic_hash[EVP_MAX_MD_SIZE];
+    unsigned char client_app_traffic_secret[EVP_MAX_MD_SIZE];
+    unsigned char server_app_traffic_secret[EVP_MAX_MD_SIZE];
+    unsigned char exporter_master_secret[EVP_MAX_MD_SIZE];
+    unsigned char early_exporter_master_secret[EVP_MAX_MD_SIZE];
+    EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
+    unsigned char read_iv[EVP_MAX_IV_LENGTH]; /* TLSv1.3 static read IV */
+    EVP_MD_CTX *read_hash;      /* used for mac generation */
+    COMP_CTX *compress;         /* compression */
+    COMP_CTX *expand;           /* uncompress */
+    EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
+    unsigned char write_iv[EVP_MAX_IV_LENGTH]; /* TLSv1.3 static write IV */
+    EVP_MD_CTX *write_hash;     /* used for mac generation */
+    /* session info */
+    /* client cert? */
+    /* This is used to hold the server certificate used */
+    struct cert_st /* CERT */ *cert;
+
+    /*
+     * The hash of all messages prior to the CertificateVerify, and the length
+     * of that hash.
+     */
+    unsigned char cert_verify_hash[EVP_MAX_MD_SIZE];
+    size_t cert_verify_hash_len;
+
+    /* Flag to indicate whether we should send a HelloRetryRequest or not */
+    enum {SSL_HRR_NONE = 0, SSL_HRR_PENDING, SSL_HRR_COMPLETE}
+        hello_retry_request;
+
+    /*
+     * the session_id_context is used to ensure sessions are only reused in
+     * the appropriate context
+     */
+    size_t sid_ctx_length;
+    unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
+    /* This can also be in the session once a session is established */
+    SSL_SESSION *session;
+    /* TLSv1.3 PSK session */
+    SSL_SESSION *psksession;
+    unsigned char *psksession_id;
+    size_t psksession_id_len;
+    /* Default generate session ID callback. */
+    GEN_SESSION_CB generate_session_id;
+    /*
+     * The temporary TLSv1.3 session id. This isn't really a session id at all
+     * but is a random value sent in the legacy session id field.
+     */
+    unsigned char tmp_session_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
+    size_t tmp_session_id_len;
+    /* Used in SSL3 */
+    /*
+     * 0 don't care about verify failure.
+     * 1 fail if verify fails
+     */
+    uint32_t verify_mode;
+    /* fail if callback returns 0 */
+    int (*verify_callback) (int ok, X509_STORE_CTX *ctx);
+    /* optional informational callback */
+    void (*info_callback) (const SSL *ssl, int type, int val);
+    /* error bytes to be written */
+    int error;
+    /* actual code */
+    int error_code;
+# ifndef OPENSSL_NO_PSK
+    SSL_psk_client_cb_func psk_client_callback;
+    SSL_psk_server_cb_func psk_server_callback;
+# endif
+    SSL_psk_find_session_cb_func psk_find_session_cb;
+    SSL_psk_use_session_cb_func psk_use_session_cb;
+
+    SSL_CTX *ctx;
+    /* Verified chain of peer */
+    STACK_OF(X509) *verified_chain;
+    long verify_result;
+    /* extra application data */
+    CRYPTO_EX_DATA ex_data;
+    /*
+     * What we put in certificate_authorities extension for TLS 1.3
+     * (ClientHello and CertificateRequest) or just client cert requests for
+     * earlier versions. If client_ca_names is populated then it is only used
+     * for client cert requests, and in preference to ca_names.
+     */
+    STACK_OF(X509_NAME) *ca_names;
+    STACK_OF(X509_NAME) *client_ca_names;
+    CRYPTO_REF_COUNT references;
+    /* protocol behaviour */
+    uint32_t options;
+    /* API behaviour */
+    uint32_t mode;
+    int min_proto_version;
+    int max_proto_version;
+    size_t max_cert_list;
+    int first_packet;
+    /*
+     * What was passed in ClientHello.legacy_version. Used for RSA pre-master
+     * secret and SSLv3/TLS (<=1.2) rollback check
+     */
+    int client_version;
+    /*
+     * If we're using more than one pipeline how should we divide the data
+     * up between the pipes?
+     */
+    size_t split_send_fragment;
+    /*
+     * Maximum amount of data to send in one fragment. actual record size can
+     * be more than this due to padding and MAC overheads.
+     */
+    size_t max_send_fragment;
+    /* Up to how many pipelines should we use? If 0 then 1 is assumed */
+    size_t max_pipelines;
+
+    struct {
+        /* Built-in extension flags */
+        uint8_t extflags[TLSEXT_IDX_num_builtins];
+        /* TLS extension debug callback */
+        void (*debug_cb)(SSL *s, int client_server, int type,
+                         const unsigned char *data, int len, void *arg);
+        void *debug_arg;
+        char *hostname;
+        /* certificate status request info */
+        /* Status type or -1 if no status type */
+        int status_type;
+        /* Raw extension data, if seen */
+        unsigned char *scts;
+        /* Length of raw extension data, if seen */
+        uint16_t scts_len;
+        /* Expect OCSP CertificateStatus message */
+        int status_expected;
+
+        struct {
+            /* OCSP status request only */
+            STACK_OF(OCSP_RESPID) *ids;
+            X509_EXTENSIONS *exts;
+            /* OCSP response received or to be sent */
+            unsigned char *resp;
+            size_t resp_len;
+        } ocsp;
+
+        /* RFC4507 session ticket expected to be received or sent */
+        int ticket_expected;
+# ifndef OPENSSL_NO_EC
+        size_t ecpointformats_len;
+        /* our list */
+        unsigned char *ecpointformats;
+
+        size_t peer_ecpointformats_len;
+        /* peer's list */
+        unsigned char *peer_ecpointformats;
+# endif                         /* OPENSSL_NO_EC */
+        size_t supportedgroups_len;
+        /* our list */
+        uint16_t *supportedgroups;
+
+        size_t peer_supportedgroups_len;
+         /* peer's list */
+        uint16_t *peer_supportedgroups;
+
+        /* TLS Session Ticket extension override */
+        TLS_SESSION_TICKET_EXT *session_ticket;
+        /* TLS Session Ticket extension callback */
+        tls_session_ticket_ext_cb_fn session_ticket_cb;
+        void *session_ticket_cb_arg;
+        /* TLS pre-shared secret session resumption */
+        tls_session_secret_cb_fn session_secret_cb;
+        void *session_secret_cb_arg;
+        /*
+         * For a client, this contains the list of supported protocols in wire
+         * format.
+         */
+        unsigned char *alpn;
+        size_t alpn_len;
+        /*
+         * Next protocol negotiation. For the client, this is the protocol that
+         * we sent in NextProtocol and is set when handling ServerHello
+         * extensions. For a server, this is the client's selected_protocol from
+         * NextProtocol and is set when handling the NextProtocol message, before
+         * the Finished message.
+         */
+        unsigned char *npn;
+        size_t npn_len;
+
+        /* The available PSK key exchange modes */
+        int psk_kex_mode;
+
+        /* Set to one if we have negotiated ETM */
+        int use_etm;
+
+        /* Are we expecting to receive early data? */
+        int early_data;
+        /* Is the session suitable for early data? */
+        int early_data_ok;
+
+        /* May be sent by a server in HRR. Must be echoed back in ClientHello */
+        unsigned char *tls13_cookie;
+        size_t tls13_cookie_len;
+        /* Have we received a cookie from the client? */
+        int cookieok;
+
+        /*
+         * Maximum Fragment Length as per RFC 4366.
+         * If this member contains one of the allowed values (1-4)
+         * then we should include Maximum Fragment Length Negotiation
+         * extension in Client Hello.
+         * Please note that value of this member does not have direct
+         * effect. The actual (binding) value is stored in SSL_SESSION,
+         * as this extension is optional on server side.
+         */
+        uint8_t max_fragment_len_mode;
+
+        /*
+         * On the client side the number of ticket identities we sent in the
+         * ClientHello. On the server side the identity of the ticket we
+         * selected.
+         */
+        int tick_identity;
+    } ext;
+
+    /*
+     * Parsed form of the ClientHello, kept around across client_hello_cb
+     * calls.
+     */
+    CLIENTHELLO_MSG *clienthello;
+
+    /*-
+     * no further mod of servername
+     * 0 : call the servername extension callback.
+     * 1 : prepare 2, allow last ack just after in server callback.
+     * 2 : don't call servername callback, no ack in server hello
+     */
+    int servername_done;
+# ifndef OPENSSL_NO_CT
+    /*
+     * Validates that the SCTs (Signed Certificate Timestamps) are sufficient.
+     * If they are not, the connection should be aborted.
+     */
+    ssl_ct_validation_cb ct_validation_callback;
+    /* User-supplied argument that is passed to the ct_validation_callback */
+    void *ct_validation_callback_arg;
+    /*
+     * Consolidated stack of SCTs from all sources.
+     * Lazily populated by CT_get_peer_scts(SSL*)
+     */
+    STACK_OF(SCT) *scts;
+    /* Have we attempted to find/parse SCTs yet? */
+    int scts_parsed;
+# endif
+    SSL_CTX *session_ctx;       /* initial ctx, used to store sessions */
+# ifndef OPENSSL_NO_SRTP
+    /* What we'll do */
+    STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;
+    /* What's been chosen */
+    SRTP_PROTECTION_PROFILE *srtp_profile;
+# endif
+    /*-
+     * 1 if we are renegotiating.
+     * 2 if we are a server and are inside a handshake
+     * (i.e. not just sending a HelloRequest)
+     */
+    int renegotiate;
+    /* If sending a KeyUpdate is pending */
+    int key_update;
+    /* Post-handshake authentication state */
+    SSL_PHA_STATE post_handshake_auth;
+    int pha_enabled;
+    uint8_t* pha_context;
+    size_t pha_context_len;
+    int certreqs_sent;
+    EVP_MD_CTX *pha_dgst; /* this is just the digest through ClientFinished */
+
+# ifndef OPENSSL_NO_SRP
+    /* ctx for SRP authentication */
+    SRP_CTX srp_ctx;
+# endif
+    /*
+     * Callback for disabling session caching and ticket support on a session
+     * basis, depending on the chosen cipher.
+     */
+    int (*not_resumable_session_cb) (SSL *ssl, int is_forward_secure);
+    RECORD_LAYER rlayer;
+    /* Default password callback. */
+    pem_password_cb *default_passwd_callback;
+    /* Default password callback user data. */
+    void *default_passwd_callback_userdata;
+    /* Async Job info */
+    ASYNC_JOB *job;
+    ASYNC_WAIT_CTX *waitctx;
+    size_t asyncrw;
+
+    /*
+     * The maximum number of bytes advertised in session tickets that can be
+     * sent as early data.
+     */
+    uint32_t max_early_data;
+    /*
+     * The maximum number of bytes of early data that a server will tolerate
+     * (which should be at least as much as max_early_data).
+     */
+    uint32_t recv_max_early_data;
+
+    /*
+     * The number of bytes of early data received so far. If we accepted early
+     * data then this is a count of the plaintext bytes. If we rejected it then
+     * this is a count of the ciphertext bytes.
+     */
+    uint32_t early_data_count;
+
+    /* TLS1.3 padding callback */
+    size_t (*record_padding_cb)(SSL *s, int type, size_t len, void *arg);
+    void *record_padding_arg;
+    size_t block_padding;
+
+    CRYPTO_RWLOCK *lock;
+
+    /* The number of TLS1.3 tickets to automatically send */
+    size_t num_tickets;
+    /* The number of TLS1.3 tickets actually sent so far */
+    size_t sent_tickets;
+    /* The next nonce value to use when we send a ticket on this connection */
+    uint64_t next_ticket_nonce;
+
+    /* Callback to determine if early_data is acceptable or not */
+    SSL_allow_early_data_cb_fn allow_early_data_cb;
+    void *allow_early_data_cb_data;
+
+    /*
+     * Signature algorithms shared by client and server: cached because these
+     * are used most often.
+     */
+    const struct sigalg_lookup_st **shared_sigalgs;
+    size_t shared_sigalgslen;
+};
+
+/*
+ * Structure containing table entry of values associated with the signature
+ * algorithms (signature scheme) extension
+*/
+typedef struct sigalg_lookup_st {
+    /* TLS 1.3 signature scheme name */
+    const char *name;
+    /* Raw value used in extension */
+    uint16_t sigalg;
+    /* NID of hash algorithm or NID_undef if no hash */
+    int hash;
+    /* Index of hash algorithm or -1 if no hash algorithm */
+    int hash_idx;
+    /* NID of signature algorithm */
+    int sig;
+    /* Index of signature algorithm */
+    int sig_idx;
+    /* Combined hash and signature NID, if any */
+    int sigandhash;
+    /* Required public key curve (ECDSA only) */
+    int curve;
+} SIGALG_LOOKUP;
+
+typedef struct tls_group_info_st {
+    int nid;                    /* Curve NID */
+    int secbits;                /* Bits of security (from SP800-57) */
+    uint16_t flags;             /* Flags: currently just group type */
+} TLS_GROUP_INFO;
+
+/* flags values */
+# define TLS_CURVE_TYPE          0x3 /* Mask for group type */
+# define TLS_CURVE_PRIME         0x0
+# define TLS_CURVE_CHAR2         0x1
+# define TLS_CURVE_CUSTOM        0x2
+
+typedef struct cert_pkey_st CERT_PKEY;
+
+/*
+ * Structure containing table entry of certificate info corresponding to
+ * CERT_PKEY entries
+ */
+typedef struct {
+    int nid; /* NID of public key algorithm */
+    uint32_t amask; /* authmask corresponding to key type */
+} SSL_CERT_LOOKUP;
+
+typedef struct ssl3_state_st {
+    long flags;
+    size_t read_mac_secret_size;
+    unsigned char read_mac_secret[EVP_MAX_MD_SIZE];
+    size_t write_mac_secret_size;
+    unsigned char write_mac_secret[EVP_MAX_MD_SIZE];
+    unsigned char server_random[SSL3_RANDOM_SIZE];
+    unsigned char client_random[SSL3_RANDOM_SIZE];
+    /* flags for countermeasure against known-IV weakness */
+    int need_empty_fragments;
+    int empty_fragment_done;
+    /* used during startup, digest all incoming/outgoing packets */
+    BIO *handshake_buffer;
+    /*
+     * When handshake digest is determined, buffer is hashed and
+     * freed and MD_CTX for the required digest is stored here.
+     */
+    EVP_MD_CTX *handshake_dgst;
+    /*
+     * Set whenever an expected ChangeCipherSpec message is processed.
+     * Unset when the peer's Finished message is received.
+     * Unexpected ChangeCipherSpec messages trigger a fatal alert.
+     */
+    int change_cipher_spec;
+    int warn_alert;
+    int fatal_alert;
+    /*
+     * we allow one fatal and one warning alert to be outstanding, send close
+     * alert via the warning alert
+     */
+    int alert_dispatch;
+    unsigned char send_alert[2];
+    /*
+     * This flag is set when we should renegotiate ASAP, basically when there
+     * is no more data in the read or write buffers
+     */
+    int renegotiate;
+    int total_renegotiations;
+    int num_renegotiations;
+    int in_read_app_data;
+    struct {
+        /* actually only need to be 16+20 for SSLv3 and 12 for TLS */
+        unsigned char finish_md[EVP_MAX_MD_SIZE * 2];
+        size_t finish_md_len;
+        unsigned char peer_finish_md[EVP_MAX_MD_SIZE * 2];
+        size_t peer_finish_md_len;
+        size_t message_size;
+        int message_type;
+        /* used to hold the new cipher we are going to use */
+        const SSL_CIPHER *new_cipher;
+# if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)
+        EVP_PKEY *pkey;         /* holds short lived DH/ECDH key */
+# endif
+        /* used for certificate requests */
+        int cert_req;
+        /* Certificate types in certificate request message. */
+        uint8_t *ctype;
+        size_t ctype_len;
+        /* Certificate authorities list peer sent */
+        STACK_OF(X509_NAME) *peer_ca_names;
+        size_t key_block_length;
+        unsigned char *key_block;
+        const EVP_CIPHER *new_sym_enc;
+        const EVP_MD *new_hash;
+        int new_mac_pkey_type;
+        size_t new_mac_secret_size;
+# ifndef OPENSSL_NO_COMP
+        const SSL_COMP *new_compression;
+# else
+        char *new_compression;
+# endif
+        int cert_request;
+        /* Raw values of the cipher list from a client */
+        unsigned char *ciphers_raw;
+        size_t ciphers_rawlen;
+        /* Temporary storage for premaster secret */
+        unsigned char *pms;
+        size_t pmslen;
+# ifndef OPENSSL_NO_PSK
+        /* Temporary storage for PSK key */
+        unsigned char *psk;
+        size_t psklen;
+# endif
+        /* Signature algorithm we actually use */
+        const SIGALG_LOOKUP *sigalg;
+        /* Pointer to certificate we use */
+        CERT_PKEY *cert;
+        /*
+         * signature algorithms peer reports: e.g. supported signature
+         * algorithms extension for server or as part of a certificate
+         * request for client.
+         * Keep track of the algorithms for TLS and X.509 usage separately.
+         */
+        uint16_t *peer_sigalgs;
+        uint16_t *peer_cert_sigalgs;
+        /* Size of above arrays */
+        size_t peer_sigalgslen;
+        size_t peer_cert_sigalgslen;
+        /* Sigalg peer actually uses */
+        const SIGALG_LOOKUP *peer_sigalg;
+        /*
+         * Set if corresponding CERT_PKEY can be used with current
+         * SSL session: e.g. appropriate curve, signature algorithms etc.
+         * If zero it can't be used at all.
+         */
+        uint32_t valid_flags[SSL_PKEY_NUM];
+        /*
+         * For servers the following masks are for the key and auth algorithms
+         * that are supported by the certs below. For clients they are masks of
+         * *disabled* algorithms based on the current session.
+         */
+        uint32_t mask_k;
+        uint32_t mask_a;
+        /*
+         * The following are used by the client to see if a cipher is allowed or
+         * not.  It contains the minimum and maximum version the client's using
+         * based on what it knows so far.
+         */
+        int min_ver;
+        int max_ver;
+    } tmp;
+
+    /* Connection binding to prevent renegotiation attacks */
+    unsigned char previous_client_finished[EVP_MAX_MD_SIZE];
+    size_t previous_client_finished_len;
+    unsigned char previous_server_finished[EVP_MAX_MD_SIZE];
+    size_t previous_server_finished_len;
+    int send_connection_binding; /* TODOEKR */
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+    /*
+     * Set if we saw the Next Protocol Negotiation extension from our peer.
+     */
+    int npn_seen;
+# endif
+
+    /*
+     * ALPN information (we are in the process of transitioning from NPN to
+     * ALPN.)
+     */
+
+    /*
+     * In a server these point to the selected ALPN protocol after the
+     * ClientHello has been processed. In a client these contain the protocol
+     * that the server selected once the ServerHello has been processed.
+     */
+    unsigned char *alpn_selected;
+    size_t alpn_selected_len;
+    /* used by the server to know what options were proposed */
+    unsigned char *alpn_proposed;
+    size_t alpn_proposed_len;
+    /* used by the client to know if it actually sent alpn */
+    int alpn_sent;
+
+# ifndef OPENSSL_NO_EC
+    /*
+     * This is set to true if we believe that this is a version of Safari
+     * running on OS X 10.6 or newer. We wish to know this because Safari on
+     * 10.8 .. 10.8.3 has broken ECDHE-ECDSA support.
+     */
+    char is_probably_safari;
+# endif                         /* !OPENSSL_NO_EC */
+
+    /* For clients: peer temporary key */
+# if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)
+    /* The group_id for the DH/ECDH key */
+    uint16_t group_id;
+    EVP_PKEY *peer_tmp;
+# endif
+
+} SSL3_STATE;
+
+/* DTLS structures */
+
+# ifndef OPENSSL_NO_SCTP
+#  define DTLS1_SCTP_AUTH_LABEL   "EXPORTER_DTLS_OVER_SCTP"
+# endif
+
+/* Max MTU overhead we know about so far is 40 for IPv6 + 8 for UDP */
+# define DTLS1_MAX_MTU_OVERHEAD                   48
+
+/*
+ * Flag used in message reuse to indicate the buffer contains the record
+ * header as well as the handshake message header.
+ */
+# define DTLS1_SKIP_RECORD_HEADER                 2
+
+struct dtls1_retransmit_state {
+    EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
+    EVP_MD_CTX *write_hash;     /* used for mac generation */
+    COMP_CTX *compress;         /* compression */
+    SSL_SESSION *session;
+    unsigned short epoch;
+};
+
+struct hm_header_st {
+    unsigned char type;
+    size_t msg_len;
+    unsigned short seq;
+    size_t frag_off;
+    size_t frag_len;
+    unsigned int is_ccs;
+    struct dtls1_retransmit_state saved_retransmit_state;
+};
+
+struct dtls1_timeout_st {
+    /* Number of read timeouts so far */
+    unsigned int read_timeouts;
+    /* Number of write timeouts so far */
+    unsigned int write_timeouts;
+    /* Number of alerts received so far */
+    unsigned int num_alerts;
+};
+
+typedef struct hm_fragment_st {
+    struct hm_header_st msg_header;
+    unsigned char *fragment;
+    unsigned char *reassembly;
+} hm_fragment;
+
+typedef struct pqueue_st pqueue;
+typedef struct pitem_st pitem;
+
+struct pitem_st {
+    unsigned char priority[8];  /* 64-bit value in big-endian encoding */
+    void *data;
+    pitem *next;
+};
+
+typedef struct pitem_st *piterator;
+
+pitem *pitem_new(unsigned char *prio64be, void *data);
+void pitem_free(pitem *item);
+pqueue *pqueue_new(void);
+void pqueue_free(pqueue *pq);
+pitem *pqueue_insert(pqueue *pq, pitem *item);
+pitem *pqueue_peek(pqueue *pq);
+pitem *pqueue_pop(pqueue *pq);
+pitem *pqueue_find(pqueue *pq, unsigned char *prio64be);
+pitem *pqueue_iterator(pqueue *pq);
+pitem *pqueue_next(piterator *iter);
+size_t pqueue_size(pqueue *pq);
+
+typedef struct dtls1_state_st {
+    unsigned char cookie[DTLS1_COOKIE_LENGTH];
+    size_t cookie_len;
+    unsigned int cookie_verified;
+    /* handshake message numbers */
+    unsigned short handshake_write_seq;
+    unsigned short next_handshake_write_seq;
+    unsigned short handshake_read_seq;
+    /* Buffered handshake messages */
+    pqueue *buffered_messages;
+    /* Buffered (sent) handshake records */
+    pqueue *sent_messages;
+    size_t link_mtu;      /* max on-the-wire DTLS packet size */
+    size_t mtu;           /* max DTLS packet size */
+    struct hm_header_st w_msg_hdr;
+    struct hm_header_st r_msg_hdr;
+    struct dtls1_timeout_st timeout;
+    /*
+     * Indicates when the last handshake msg sent will timeout
+     */
+    struct timeval next_timeout;
+    /* Timeout duration */
+    unsigned int timeout_duration_us;
+
+    unsigned int retransmitting;
+# ifndef OPENSSL_NO_SCTP
+    int shutdown_received;
+# endif
+
+    DTLS_timer_cb timer_cb;
+
+} DTLS1_STATE;
+
+# ifndef OPENSSL_NO_EC
+/*
+ * From ECC-TLS draft, used in encoding the curve type in ECParameters
+ */
+#  define EXPLICIT_PRIME_CURVE_TYPE  1
+#  define EXPLICIT_CHAR2_CURVE_TYPE  2
+#  define NAMED_CURVE_TYPE           3
+# endif                         /* OPENSSL_NO_EC */
+
+struct cert_pkey_st {
+    X509 *x509;
+    EVP_PKEY *privatekey;
+    /* Chain for this certificate */
+    STACK_OF(X509) *chain;
+    /*-
+     * serverinfo data for this certificate.  The data is in TLS Extension
+     * wire format, specifically it's a series of records like:
+     *   uint16_t extension_type; // (RFC 5246, 7.4.1.4, Extension)
+     *   uint16_t length;
+     *   uint8_t data[length];
+     */
+    unsigned char *serverinfo;
+    size_t serverinfo_length;
+};
+/* Retrieve Suite B flags */
+# define tls1_suiteb(s)  (s->cert->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS)
+/* Uses to check strict mode: suite B modes are always strict */
+# define SSL_CERT_FLAGS_CHECK_TLS_STRICT \
+        (SSL_CERT_FLAG_SUITEB_128_LOS|SSL_CERT_FLAG_TLS_STRICT)
+
+typedef enum {
+    ENDPOINT_CLIENT = 0,
+    ENDPOINT_SERVER,
+    ENDPOINT_BOTH
+} ENDPOINT;
+
+
+typedef struct {
+    unsigned short ext_type;
+    ENDPOINT role;
+    /* The context which this extension applies to */
+    unsigned int context;
+    /*
+     * Per-connection flags relating to this extension type: not used if
+     * part of an SSL_CTX structure.
+     */
+    uint32_t ext_flags;
+    SSL_custom_ext_add_cb_ex add_cb;
+    SSL_custom_ext_free_cb_ex free_cb;
+    void *add_arg;
+    SSL_custom_ext_parse_cb_ex parse_cb;
+    void *parse_arg;
+} custom_ext_method;
+
+/* ext_flags values */
+
+/*
+ * Indicates an extension has been received. Used to check for unsolicited or
+ * duplicate extensions.
+ */
+# define SSL_EXT_FLAG_RECEIVED   0x1
+/*
+ * Indicates an extension has been sent: used to enable sending of
+ * corresponding ServerHello extension.
+ */
+# define SSL_EXT_FLAG_SENT       0x2
+
+typedef struct {
+    custom_ext_method *meths;
+    size_t meths_count;
+} custom_ext_methods;
+
+typedef struct cert_st {
+    /* Current active set */
+    /*
+     * ALWAYS points to an element of the pkeys array
+     * Probably it would make more sense to store
+     * an index, not a pointer.
+     */
+    CERT_PKEY *key;
+# ifndef OPENSSL_NO_DH
+    EVP_PKEY *dh_tmp;
+    DH *(*dh_tmp_cb) (SSL *ssl, int is_export, int keysize);
+    int dh_tmp_auto;
+# endif
+    /* Flags related to certificates */
+    uint32_t cert_flags;
+    CERT_PKEY pkeys[SSL_PKEY_NUM];
+    /* Custom certificate types sent in certificate request message. */
+    uint8_t *ctype;
+    size_t ctype_len;
+    /*
+     * supported signature algorithms. When set on a client this is sent in
+     * the client hello as the supported signature algorithms extension. For
+     * servers it represents the signature algorithms we are willing to use.
+     */
+    uint16_t *conf_sigalgs;
+    /* Size of above array */
+    size_t conf_sigalgslen;
+    /*
+     * Client authentication signature algorithms, if not set then uses
+     * conf_sigalgs. On servers these will be the signature algorithms sent
+     * to the client in a certificate request for TLS 1.2. On a client this
+     * represents the signature algorithms we are willing to use for client
+     * authentication.
+     */
+    uint16_t *client_sigalgs;
+    /* Size of above array */
+    size_t client_sigalgslen;
+    /*
+     * Certificate setup callback: if set is called whenever a certificate
+     * may be required (client or server). the callback can then examine any
+     * appropriate parameters and setup any certificates required. This
+     * allows advanced applications to select certificates on the fly: for
+     * example based on supported signature algorithms or curves.
+     */
+    int (*cert_cb) (SSL *ssl, void *arg);
+    void *cert_cb_arg;
+    /*
+     * Optional X509_STORE for chain building or certificate validation If
+     * NULL the parent SSL_CTX store is used instead.
+     */
+    X509_STORE *chain_store;
+    X509_STORE *verify_store;
+    /* Custom extensions */
+    custom_ext_methods custext;
+    /* Security callback */
+    int (*sec_cb) (const SSL *s, const SSL_CTX *ctx, int op, int bits, int nid,
+                   void *other, void *ex);
+    /* Security level */
+    int sec_level;
+    void *sec_ex;
+# ifndef OPENSSL_NO_PSK
+    /* If not NULL psk identity hint to use for servers */
+    char *psk_identity_hint;
+# endif
+    CRYPTO_REF_COUNT references;             /* >1 only if SSL_copy_session_id is used */
+    CRYPTO_RWLOCK *lock;
+} CERT;
+
+# define FP_ICC  (int (*)(const void *,const void *))
+
+/*
+ * This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit
+ * of a mess of functions, but hell, think of it as an opaque structure :-)
+ */
+typedef struct ssl3_enc_method {
+    int (*enc) (SSL *, SSL3_RECORD *, size_t, int);
+    int (*mac) (SSL *, SSL3_RECORD *, unsigned char *, int);
+    int (*setup_key_block) (SSL *);
+    int (*generate_master_secret) (SSL *, unsigned char *, unsigned char *,
+                                   size_t, size_t *);
+    int (*change_cipher_state) (SSL *, int);
+    size_t (*final_finish_mac) (SSL *, const char *, size_t, unsigned char *);
+    const char *client_finished_label;
+    size_t client_finished_label_len;
+    const char *server_finished_label;
+    size_t server_finished_label_len;
+    int (*alert_value) (int);
+    int (*export_keying_material) (SSL *, unsigned char *, size_t,
+                                   const char *, size_t,
+                                   const unsigned char *, size_t,
+                                   int use_context);
+    /* Various flags indicating protocol version requirements */
+    uint32_t enc_flags;
+    /* Set the handshake header */
+    int (*set_handshake_header) (SSL *s, WPACKET *pkt, int type);
+    /* Close construction of the handshake message */
+    int (*close_construct_packet) (SSL *s, WPACKET *pkt, int htype);
+    /* Write out handshake message */
+    int (*do_write) (SSL *s);
+} SSL3_ENC_METHOD;
+
+# define ssl_set_handshake_header(s, pkt, htype) \
+        s->method->ssl3_enc->set_handshake_header((s), (pkt), (htype))
+# define ssl_close_construct_packet(s, pkt, htype) \
+        s->method->ssl3_enc->close_construct_packet((s), (pkt), (htype))
+# define ssl_do_write(s)  s->method->ssl3_enc->do_write(s)
+
+/* Values for enc_flags */
+
+/* Uses explicit IV for CBC mode */
+# define SSL_ENC_FLAG_EXPLICIT_IV        0x1
+/* Uses signature algorithms extension */
+# define SSL_ENC_FLAG_SIGALGS            0x2
+/* Uses SHA256 default PRF */
+# define SSL_ENC_FLAG_SHA256_PRF         0x4
+/* Is DTLS */
+# define SSL_ENC_FLAG_DTLS               0x8
+/*
+ * Allow TLS 1.2 ciphersuites: applies to DTLS 1.2 as well as TLS 1.2: may
+ * apply to others in future.
+ */
+# define SSL_ENC_FLAG_TLS1_2_CIPHERS     0x10
+
+# ifndef OPENSSL_NO_COMP
+/* Used for holding the relevant compression methods loaded into SSL_CTX */
+typedef struct ssl3_comp_st {
+    int comp_id;                /* The identifier byte for this compression
+                                 * type */
+    char *name;                 /* Text name used for the compression type */
+    COMP_METHOD *method;        /* The method :-) */
+} SSL3_COMP;
+# endif
+
+typedef enum downgrade_en {
+    DOWNGRADE_NONE,
+    DOWNGRADE_TO_1_2,
+    DOWNGRADE_TO_1_1
+} DOWNGRADE;
+
+/*
+ * Dummy status type for the status_type extension. Indicates no status type
+ * set
+ */
+#define TLSEXT_STATUSTYPE_nothing  -1
+
+/* Sigalgs values */
+#define TLSEXT_SIGALG_ecdsa_secp256r1_sha256                    0x0403
+#define TLSEXT_SIGALG_ecdsa_secp384r1_sha384                    0x0503
+#define TLSEXT_SIGALG_ecdsa_secp521r1_sha512                    0x0603
+#define TLSEXT_SIGALG_ecdsa_sha224                              0x0303
+#define TLSEXT_SIGALG_ecdsa_sha1                                0x0203
+#define TLSEXT_SIGALG_rsa_pss_rsae_sha256                       0x0804
+#define TLSEXT_SIGALG_rsa_pss_rsae_sha384                       0x0805
+#define TLSEXT_SIGALG_rsa_pss_rsae_sha512                       0x0806
+#define TLSEXT_SIGALG_rsa_pss_pss_sha256                        0x0809
+#define TLSEXT_SIGALG_rsa_pss_pss_sha384                        0x080a
+#define TLSEXT_SIGALG_rsa_pss_pss_sha512                        0x080b
+#define TLSEXT_SIGALG_rsa_pkcs1_sha256                          0x0401
+#define TLSEXT_SIGALG_rsa_pkcs1_sha384                          0x0501
+#define TLSEXT_SIGALG_rsa_pkcs1_sha512                          0x0601
+#define TLSEXT_SIGALG_rsa_pkcs1_sha224                          0x0301
+#define TLSEXT_SIGALG_rsa_pkcs1_sha1                            0x0201
+#define TLSEXT_SIGALG_dsa_sha256                                0x0402
+#define TLSEXT_SIGALG_dsa_sha384                                0x0502
+#define TLSEXT_SIGALG_dsa_sha512                                0x0602
+#define TLSEXT_SIGALG_dsa_sha224                                0x0302
+#define TLSEXT_SIGALG_dsa_sha1                                  0x0202
+#define TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256       0xeeee
+#define TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512       0xefef
+#define TLSEXT_SIGALG_gostr34102001_gostr3411                   0xeded
+
+#define TLSEXT_SIGALG_ed25519                                   0x0807
+#define TLSEXT_SIGALG_ed448                                     0x0808
+
+/* Known PSK key exchange modes */
+#define TLSEXT_KEX_MODE_KE                                      0x00
+#define TLSEXT_KEX_MODE_KE_DHE                                  0x01
+
+/*
+ * Internal representations of key exchange modes
+ */
+#define TLSEXT_KEX_MODE_FLAG_NONE                               0
+#define TLSEXT_KEX_MODE_FLAG_KE                                 1
+#define TLSEXT_KEX_MODE_FLAG_KE_DHE                             2
+
+#define SSL_USE_PSS(s) (s->s3->tmp.peer_sigalg != NULL && \
+                        s->s3->tmp.peer_sigalg->sig == EVP_PKEY_RSA_PSS)
+
+/* A dummy signature value not valid for TLSv1.2 signature algs */
+#define TLSEXT_signature_rsa_pss                                0x0101
+
+/* TLSv1.3 downgrade protection sentinel values */
+extern const unsigned char tls11downgrade[8];
+extern const unsigned char tls12downgrade[8];
+
+extern SSL3_ENC_METHOD ssl3_undef_enc_method;
+
+__owur const SSL_METHOD *ssl_bad_method(int ver);
+__owur const SSL_METHOD *sslv3_method(void);
+__owur const SSL_METHOD *sslv3_server_method(void);
+__owur const SSL_METHOD *sslv3_client_method(void);
+__owur const SSL_METHOD *tlsv1_method(void);
+__owur const SSL_METHOD *tlsv1_server_method(void);
+__owur const SSL_METHOD *tlsv1_client_method(void);
+__owur const SSL_METHOD *tlsv1_1_method(void);
+__owur const SSL_METHOD *tlsv1_1_server_method(void);
+__owur const SSL_METHOD *tlsv1_1_client_method(void);
+__owur const SSL_METHOD *tlsv1_2_method(void);
+__owur const SSL_METHOD *tlsv1_2_server_method(void);
+__owur const SSL_METHOD *tlsv1_2_client_method(void);
+__owur const SSL_METHOD *tlsv1_3_method(void);
+__owur const SSL_METHOD *tlsv1_3_server_method(void);
+__owur const SSL_METHOD *tlsv1_3_client_method(void);
+__owur const SSL_METHOD *dtlsv1_method(void);
+__owur const SSL_METHOD *dtlsv1_server_method(void);
+__owur const SSL_METHOD *dtlsv1_client_method(void);
+__owur const SSL_METHOD *dtls_bad_ver_client_method(void);
+__owur const SSL_METHOD *dtlsv1_2_method(void);
+__owur const SSL_METHOD *dtlsv1_2_server_method(void);
+__owur const SSL_METHOD *dtlsv1_2_client_method(void);
+
+extern const SSL3_ENC_METHOD TLSv1_enc_data;
+extern const SSL3_ENC_METHOD TLSv1_1_enc_data;
+extern const SSL3_ENC_METHOD TLSv1_2_enc_data;
+extern const SSL3_ENC_METHOD TLSv1_3_enc_data;
+extern const SSL3_ENC_METHOD SSLv3_enc_data;
+extern const SSL3_ENC_METHOD DTLSv1_enc_data;
+extern const SSL3_ENC_METHOD DTLSv1_2_enc_data;
+
+/*
+ * Flags for SSL methods
+ */
+# define SSL_METHOD_NO_FIPS      (1U<<0)
+# define SSL_METHOD_NO_SUITEB    (1U<<1)
+
+# define IMPLEMENT_tls_meth_func(version, flags, mask, func_name, s_accept, \
+                                 s_connect, enc_data) \
+const SSL_METHOD *func_name(void)  \
+        { \
+        static const SSL_METHOD func_name##_data= { \
+                version, \
+                flags, \
+                mask, \
+                tls1_new, \
+                tls1_clear, \
+                tls1_free, \
+                s_accept, \
+                s_connect, \
+                ssl3_read, \
+                ssl3_peek, \
+                ssl3_write, \
+                ssl3_shutdown, \
+                ssl3_renegotiate, \
+                ssl3_renegotiate_check, \
+                ssl3_read_bytes, \
+                ssl3_write_bytes, \
+                ssl3_dispatch_alert, \
+                ssl3_ctrl, \
+                ssl3_ctx_ctrl, \
+                ssl3_get_cipher_by_char, \
+                ssl3_put_cipher_by_char, \
+                ssl3_pending, \
+                ssl3_num_ciphers, \
+                ssl3_get_cipher, \
+                tls1_default_timeout, \
+                &enc_data, \
+                ssl_undefined_void_function, \
+                ssl3_callback_ctrl, \
+                ssl3_ctx_callback_ctrl, \
+        }; \
+        return &func_name##_data; \
+        }
+
+# define IMPLEMENT_ssl3_meth_func(func_name, s_accept, s_connect) \
+const SSL_METHOD *func_name(void)  \
+        { \
+        static const SSL_METHOD func_name##_data= { \
+                SSL3_VERSION, \
+                SSL_METHOD_NO_FIPS | SSL_METHOD_NO_SUITEB, \
+                SSL_OP_NO_SSLv3, \
+                ssl3_new, \
+                ssl3_clear, \
+                ssl3_free, \
+                s_accept, \
+                s_connect, \
+                ssl3_read, \
+                ssl3_peek, \
+                ssl3_write, \
+                ssl3_shutdown, \
+                ssl3_renegotiate, \
+                ssl3_renegotiate_check, \
+                ssl3_read_bytes, \
+                ssl3_write_bytes, \
+                ssl3_dispatch_alert, \
+                ssl3_ctrl, \
+                ssl3_ctx_ctrl, \
+                ssl3_get_cipher_by_char, \
+                ssl3_put_cipher_by_char, \
+                ssl3_pending, \
+                ssl3_num_ciphers, \
+                ssl3_get_cipher, \
+                ssl3_default_timeout, \
+                &SSLv3_enc_data, \
+                ssl_undefined_void_function, \
+                ssl3_callback_ctrl, \
+                ssl3_ctx_callback_ctrl, \
+        }; \
+        return &func_name##_data; \
+        }
+
+# define IMPLEMENT_dtls1_meth_func(version, flags, mask, func_name, s_accept, \
+                                        s_connect, enc_data) \
+const SSL_METHOD *func_name(void)  \
+        { \
+        static const SSL_METHOD func_name##_data= { \
+                version, \
+                flags, \
+                mask, \
+                dtls1_new, \
+                dtls1_clear, \
+                dtls1_free, \
+                s_accept, \
+                s_connect, \
+                ssl3_read, \
+                ssl3_peek, \
+                ssl3_write, \
+                dtls1_shutdown, \
+                ssl3_renegotiate, \
+                ssl3_renegotiate_check, \
+                dtls1_read_bytes, \
+                dtls1_write_app_data_bytes, \
+                dtls1_dispatch_alert, \
+                dtls1_ctrl, \
+                ssl3_ctx_ctrl, \
+                ssl3_get_cipher_by_char, \
+                ssl3_put_cipher_by_char, \
+                ssl3_pending, \
+                ssl3_num_ciphers, \
+                ssl3_get_cipher, \
+                dtls1_default_timeout, \
+                &enc_data, \
+                ssl_undefined_void_function, \
+                ssl3_callback_ctrl, \
+                ssl3_ctx_callback_ctrl, \
+        }; \
+        return &func_name##_data; \
+        }
+
+struct openssl_ssl_test_functions {
+    int (*p_ssl_init_wbio_buffer) (SSL *s);
+    int (*p_ssl3_setup_buffers) (SSL *s);
+};
+
+const char *ssl_protocol_to_string(int version);
+
+/* Returns true if certificate and private key for 'idx' are present */
+static ossl_inline int ssl_has_cert(const SSL *s, int idx)
+{
+    if (idx < 0 || idx >= SSL_PKEY_NUM)
+        return 0;
+    return s->cert->pkeys[idx].x509 != NULL
+        && s->cert->pkeys[idx].privatekey != NULL;
+}
+
+static ossl_inline void tls1_get_peer_groups(SSL *s, const uint16_t **pgroups,
+                                             size_t *pgroupslen)
+{
+    *pgroups = s->ext.peer_supportedgroups;
+    *pgroupslen = s->ext.peer_supportedgroups_len;
+}
+
+# ifndef OPENSSL_UNIT_TEST
+
+__owur int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes);
+__owur int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written);
+void ssl_clear_cipher_ctx(SSL *s);
+int ssl_clear_bad_session(SSL *s);
+__owur CERT *ssl_cert_new(void);
+__owur CERT *ssl_cert_dup(CERT *cert);
+void ssl_cert_clear_certs(CERT *c);
+void ssl_cert_free(CERT *c);
+__owur int ssl_generate_session_id(SSL *s, SSL_SESSION *ss);
+__owur int ssl_get_new_session(SSL *s, int session);
+__owur SSL_SESSION *lookup_sess_in_cache(SSL *s, const unsigned char *sess_id,
+                                         size_t sess_id_len);
+__owur int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello);
+__owur SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket);
+__owur int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b);
+DECLARE_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER, ssl_cipher_id);
+__owur int ssl_cipher_ptr_id_cmp(const SSL_CIPHER *const *ap,
+                                 const SSL_CIPHER *const *bp);
+__owur STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
+                                                    STACK_OF(SSL_CIPHER) *tls13_ciphersuites,
+                                                    STACK_OF(SSL_CIPHER) **cipher_list,
+                                                    STACK_OF(SSL_CIPHER) **cipher_list_by_id,
+                                                    const char *rule_str,
+                                                    CERT *c);
+__owur int ssl_cache_cipherlist(SSL *s, PACKET *cipher_suites, int sslv2format);
+__owur int bytes_to_cipher_list(SSL *s, PACKET *cipher_suites,
+                                STACK_OF(SSL_CIPHER) **skp,
+                                STACK_OF(SSL_CIPHER) **scsvs, int sslv2format,
+                                int fatal);
+void ssl_update_cache(SSL *s, int mode);
+__owur int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc,
+                              const EVP_MD **md, int *mac_pkey_type,
+                              size_t *mac_secret_size, SSL_COMP **comp,
+                              int use_etm);
+__owur int ssl_cipher_get_overhead(const SSL_CIPHER *c, size_t *mac_overhead,
+                                   size_t *int_overhead, size_t *blocksize,
+                                   size_t *ext_overhead);
+__owur int ssl_cert_is_disabled(size_t idx);
+__owur const SSL_CIPHER *ssl_get_cipher_by_char(SSL *ssl,
+                                                const unsigned char *ptr,
+                                                int all);
+__owur int ssl_cert_set0_chain(SSL *s, SSL_CTX *ctx, STACK_OF(X509) *chain);
+__owur int ssl_cert_set1_chain(SSL *s, SSL_CTX *ctx, STACK_OF(X509) *chain);
+__owur int ssl_cert_add0_chain_cert(SSL *s, SSL_CTX *ctx, X509 *x);
+__owur int ssl_cert_add1_chain_cert(SSL *s, SSL_CTX *ctx, X509 *x);
+__owur int ssl_cert_select_current(CERT *c, X509 *x);
+__owur int ssl_cert_set_current(CERT *c, long arg);
+void ssl_cert_set_cert_cb(CERT *c, int (*cb) (SSL *ssl, void *arg), void *arg);
+
+__owur int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk);
+__owur int ssl_build_cert_chain(SSL *s, SSL_CTX *ctx, int flags);
+__owur int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain,
+                                   int ref);
+__owur int ssl_cert_get_cert_store(CERT *c, X509_STORE **pstore, int chain);
+
+__owur int ssl_security(const SSL *s, int op, int bits, int nid, void *other);
+__owur int ssl_ctx_security(const SSL_CTX *ctx, int op, int bits, int nid,
+                            void *other);
+int ssl_get_security_level_bits(const SSL *s, const SSL_CTX *ctx, int *levelp);
+
+__owur int ssl_cert_lookup_by_nid(int nid, size_t *pidx);
+__owur const SSL_CERT_LOOKUP *ssl_cert_lookup_by_pkey(const EVP_PKEY *pk,
+                                                      size_t *pidx);
+__owur const SSL_CERT_LOOKUP *ssl_cert_lookup_by_idx(size_t idx);
+
+int ssl_undefined_function(SSL *s);
+__owur int ssl_undefined_void_function(void);
+__owur int ssl_undefined_const_function(const SSL *s);
+__owur int ssl_get_server_cert_serverinfo(SSL *s,
+                                          const unsigned char **serverinfo,
+                                          size_t *serverinfo_length);
+void ssl_set_masks(SSL *s);
+__owur STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s);
+__owur int ssl_x509err2alert(int type);
+void ssl_sort_cipher_list(void);
+int ssl_load_ciphers(void);
+__owur int ssl_fill_hello_random(SSL *s, int server, unsigned char *field,
+                                 size_t len, DOWNGRADE dgrd);
+__owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
+                                      int free_pms);
+__owur EVP_PKEY *ssl_generate_pkey(EVP_PKEY *pm);
+__owur int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey,
+                      int genmaster);
+__owur EVP_PKEY *ssl_dh_to_pkey(DH *dh);
+__owur unsigned int ssl_get_max_send_fragment(const SSL *ssl);
+__owur unsigned int ssl_get_split_send_fragment(const SSL *ssl);
+
+__owur const SSL_CIPHER *ssl3_get_cipher_by_id(uint32_t id);
+__owur const SSL_CIPHER *ssl3_get_cipher_by_std_name(const char *stdname);
+__owur const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p);
+__owur int ssl3_put_cipher_by_char(const SSL_CIPHER *c, WPACKET *pkt,
+                                   size_t *len);
+int ssl3_init_finished_mac(SSL *s);
+__owur int ssl3_setup_key_block(SSL *s);
+__owur int ssl3_change_cipher_state(SSL *s, int which);
+void ssl3_cleanup_key_block(SSL *s);
+__owur int ssl3_do_write(SSL *s, int type);
+int ssl3_send_alert(SSL *s, int level, int desc);
+__owur int ssl3_generate_master_secret(SSL *s, unsigned char *out,
+                                       unsigned char *p, size_t len,
+                                       size_t *secret_size);
+__owur int ssl3_get_req_cert_type(SSL *s, WPACKET *pkt);
+__owur int ssl3_num_ciphers(void);
+__owur const SSL_CIPHER *ssl3_get_cipher(unsigned int u);
+int ssl3_renegotiate(SSL *ssl);
+int ssl3_renegotiate_check(SSL *ssl, int initok);
+__owur int ssl3_dispatch_alert(SSL *s);
+__owur size_t ssl3_final_finish_mac(SSL *s, const char *sender, size_t slen,
+                                    unsigned char *p);
+__owur int ssl3_finish_mac(SSL *s, const unsigned char *buf, size_t len);
+void ssl3_free_digest_list(SSL *s);
+__owur unsigned long ssl3_output_cert_chain(SSL *s, WPACKET *pkt,
+                                            CERT_PKEY *cpk);
+__owur const SSL_CIPHER *ssl3_choose_cipher(SSL *ssl,
+                                            STACK_OF(SSL_CIPHER) *clnt,
+                                            STACK_OF(SSL_CIPHER) *srvr);
+__owur int ssl3_digest_cached_records(SSL *s, int keep);
+__owur int ssl3_new(SSL *s);
+void ssl3_free(SSL *s);
+__owur int ssl3_read(SSL *s, void *buf, size_t len, size_t *readbytes);
+__owur int ssl3_peek(SSL *s, void *buf, size_t len, size_t *readbytes);
+__owur int ssl3_write(SSL *s, const void *buf, size_t len, size_t *written);
+__owur int ssl3_shutdown(SSL *s);
+int ssl3_clear(SSL *s);
+__owur long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg);
+__owur long ssl3_ctx_ctrl(SSL_CTX *s, int cmd, long larg, void *parg);
+__owur long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp) (void));
+__owur long ssl3_ctx_callback_ctrl(SSL_CTX *s, int cmd, void (*fp) (void));
+
+__owur int ssl3_do_change_cipher_spec(SSL *ssl);
+__owur long ssl3_default_timeout(void);
+
+__owur int ssl3_set_handshake_header(SSL *s, WPACKET *pkt, int htype);
+__owur int tls_close_construct_packet(SSL *s, WPACKET *pkt, int htype);
+__owur int tls_setup_handshake(SSL *s);
+__owur int dtls1_set_handshake_header(SSL *s, WPACKET *pkt, int htype);
+__owur int dtls1_close_construct_packet(SSL *s, WPACKET *pkt, int htype);
+__owur int ssl3_handshake_write(SSL *s);
+
+__owur int ssl_allow_compression(SSL *s);
+
+__owur int ssl_version_supported(const SSL *s, int version,
+                                 const SSL_METHOD **meth);
+
+__owur int ssl_set_client_hello_version(SSL *s);
+__owur int ssl_check_version_downgrade(SSL *s);
+__owur int ssl_set_version_bound(int method_version, int version, int *bound);
+__owur int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello,
+                                     DOWNGRADE *dgrd);
+__owur int ssl_choose_client_version(SSL *s, int version,
+                                     RAW_EXTENSION *extensions);
+__owur int ssl_get_min_max_version(const SSL *s, int *min_version,
+                                   int *max_version, int *real_max);
+
+__owur long tls1_default_timeout(void);
+__owur int dtls1_do_write(SSL *s, int type);
+void dtls1_set_message_header(SSL *s,
+                              unsigned char mt,
+                              size_t len,
+                              size_t frag_off, size_t frag_len);
+
+int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, size_t len,
+                               size_t *written);
+
+__owur int dtls1_read_failed(SSL *s, int code);
+__owur int dtls1_buffer_message(SSL *s, int ccs);
+__owur int dtls1_retransmit_message(SSL *s, unsigned short seq, int *found);
+__owur int dtls1_get_queue_priority(unsigned short seq, int is_ccs);
+int dtls1_retransmit_buffered_messages(SSL *s);
+void dtls1_clear_received_buffer(SSL *s);
+void dtls1_clear_sent_buffer(SSL *s);
+void dtls1_get_message_header(unsigned char *data,
+                              struct hm_header_st *msg_hdr);
+__owur long dtls1_default_timeout(void);
+__owur struct timeval *dtls1_get_timeout(SSL *s, struct timeval *timeleft);
+__owur int dtls1_check_timeout_num(SSL *s);
+__owur int dtls1_handle_timeout(SSL *s);
+void dtls1_start_timer(SSL *s);
+void dtls1_stop_timer(SSL *s);
+__owur int dtls1_is_timer_expired(SSL *s);
+__owur int dtls_raw_hello_verify_request(WPACKET *pkt, unsigned char *cookie,
+                                         size_t cookie_len);
+__owur size_t dtls1_min_mtu(SSL *s);
+void dtls1_hm_fragment_free(hm_fragment *frag);
+__owur int dtls1_query_mtu(SSL *s);
+
+__owur int tls1_new(SSL *s);
+void tls1_free(SSL *s);
+int tls1_clear(SSL *s);
+
+__owur int dtls1_new(SSL *s);
+void dtls1_free(SSL *s);
+int dtls1_clear(SSL *s);
+long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg);
+__owur int dtls1_shutdown(SSL *s);
+
+__owur int dtls1_dispatch_alert(SSL *s);
+
+__owur int ssl_init_wbio_buffer(SSL *s);
+int ssl_free_wbio_buffer(SSL *s);
+
+__owur int tls1_change_cipher_state(SSL *s, int which);
+__owur int tls1_setup_key_block(SSL *s);
+__owur size_t tls1_final_finish_mac(SSL *s, const char *str, size_t slen,
+                                    unsigned char *p);
+__owur int tls1_generate_master_secret(SSL *s, unsigned char *out,
+                                       unsigned char *p, size_t len,
+                                       size_t *secret_size);
+__owur int tls13_setup_key_block(SSL *s);
+__owur size_t tls13_final_finish_mac(SSL *s, const char *str, size_t slen,
+                                     unsigned char *p);
+__owur int tls13_change_cipher_state(SSL *s, int which);
+__owur int tls13_update_key(SSL *s, int send);
+__owur int tls13_hkdf_expand(SSL *s, const EVP_MD *md,
+                             const unsigned char *secret,
+                             const unsigned char *label, size_t labellen,
+                             const unsigned char *data, size_t datalen,
+                             unsigned char *out, size_t outlen, int fatal);
+__owur int tls13_derive_key(SSL *s, const EVP_MD *md,
+                            const unsigned char *secret, unsigned char *key,
+                            size_t keylen);
+__owur int tls13_derive_iv(SSL *s, const EVP_MD *md,
+                           const unsigned char *secret, unsigned char *iv,
+                           size_t ivlen);
+__owur int tls13_derive_finishedkey(SSL *s, const EVP_MD *md,
+                                    const unsigned char *secret,
+                                    unsigned char *fin, size_t finlen);
+int tls13_generate_secret(SSL *s, const EVP_MD *md,
+                          const unsigned char *prevsecret,
+                          const unsigned char *insecret,
+                          size_t insecretlen,
+                          unsigned char *outsecret);
+__owur int tls13_generate_handshake_secret(SSL *s,
+                                           const unsigned char *insecret,
+                                           size_t insecretlen);
+__owur int tls13_generate_master_secret(SSL *s, unsigned char *out,
+                                        unsigned char *prev, size_t prevlen,
+                                        size_t *secret_size);
+__owur int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen,
+                                       const char *label, size_t llen,
+                                       const unsigned char *p, size_t plen,
+                                       int use_context);
+__owur int tls13_export_keying_material(SSL *s, unsigned char *out, size_t olen,
+                                        const char *label, size_t llen,
+                                        const unsigned char *context,
+                                        size_t contextlen, int use_context);
+__owur int tls13_export_keying_material_early(SSL *s, unsigned char *out,
+                                              size_t olen, const char *label,
+                                              size_t llen,
+                                              const unsigned char *context,
+                                              size_t contextlen);
+__owur int tls1_alert_code(int code);
+__owur int tls13_alert_code(int code);
+__owur int ssl3_alert_code(int code);
+
+#  ifndef OPENSSL_NO_EC
+__owur int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s);
+#  endif
+
+SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n);
+
+#  ifndef OPENSSL_NO_EC
+
+__owur const TLS_GROUP_INFO *tls1_group_id_lookup(uint16_t curve_id);
+__owur int tls1_check_group_id(SSL *s, uint16_t group_id, int check_own_curves);
+__owur uint16_t tls1_shared_group(SSL *s, int nmatch);
+__owur int tls1_set_groups(uint16_t **pext, size_t *pextlen,
+                           int *curves, size_t ncurves);
+__owur int tls1_set_groups_list(uint16_t **pext, size_t *pextlen,
+                                const char *str);
+void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
+                         size_t *num_formats);
+__owur int tls1_check_ec_tmp_key(SSL *s, unsigned long id);
+__owur EVP_PKEY *ssl_generate_pkey_group(SSL *s, uint16_t id);
+__owur EVP_PKEY *ssl_generate_param_group(uint16_t id);
+#  endif                        /* OPENSSL_NO_EC */
+
+__owur int tls_curve_allowed(SSL *s, uint16_t curve, int op);
+void tls1_get_supported_groups(SSL *s, const uint16_t **pgroups,
+                               size_t *pgroupslen);
+
+__owur int tls1_set_server_sigalgs(SSL *s);
+
+__owur SSL_TICKET_STATUS tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
+                                                    SSL_SESSION **ret);
+__owur SSL_TICKET_STATUS tls_decrypt_ticket(SSL *s, const unsigned char *etick,
+                                            size_t eticklen,
+                                            const unsigned char *sess_id,
+                                            size_t sesslen, SSL_SESSION **psess);
+
+__owur int tls_use_ticket(SSL *s);
+
+void ssl_set_sig_mask(uint32_t *pmask_a, SSL *s, int op);
+
+__owur int tls1_set_sigalgs_list(CERT *c, const char *str, int client);
+__owur int tls1_set_raw_sigalgs(CERT *c, const uint16_t *psigs, size_t salglen,
+                                int client);
+__owur int tls1_set_sigalgs(CERT *c, const int *salg, size_t salglen,
+                            int client);
+int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
+                     int idx);
+void tls1_set_cert_validity(SSL *s);
+
+#  ifndef OPENSSL_NO_CT
+__owur int ssl_validate_ct(SSL *s);
+#  endif
+
+#  ifndef OPENSSL_NO_DH
+__owur DH *ssl_get_auto_dh(SSL *s);
+#  endif
+
+__owur int ssl_security_cert(SSL *s, SSL_CTX *ctx, X509 *x, int vfy, int is_ee);
+__owur int ssl_security_cert_chain(SSL *s, STACK_OF(X509) *sk, X509 *ex,
+                                   int vfy);
+
+int tls_choose_sigalg(SSL *s, int fatalerrs);
+
+__owur EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash, const EVP_MD *md);
+void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
+__owur long ssl_get_algorithm2(SSL *s);
+__owur int tls12_copy_sigalgs(SSL *s, WPACKET *pkt,
+                              const uint16_t *psig, size_t psiglen);
+__owur int tls1_save_u16(PACKET *pkt, uint16_t **pdest, size_t *pdestlen);
+__owur int tls1_save_sigalgs(SSL *s, PACKET *pkt, int cert);
+__owur int tls1_process_sigalgs(SSL *s);
+__owur int tls1_set_peer_legacy_sigalg(SSL *s, const EVP_PKEY *pkey);
+__owur int tls1_lookup_md(const SIGALG_LOOKUP *lu, const EVP_MD **pmd);
+__owur size_t tls12_get_psigalgs(SSL *s, int sent, const uint16_t **psigs);
+#  ifndef OPENSSL_NO_EC
+__owur int tls_check_sigalg_curve(const SSL *s, int curve);
+#  endif
+__owur int tls12_check_peer_sigalg(SSL *s, uint16_t, EVP_PKEY *pkey);
+__owur int ssl_set_client_disabled(SSL *s);
+__owur int ssl_cipher_disabled(const SSL *s, const SSL_CIPHER *c, int op, int echde);
+
+__owur int ssl_handshake_hash(SSL *s, unsigned char *out, size_t outlen,
+                                 size_t *hashlen);
+__owur const EVP_MD *ssl_md(int idx);
+__owur const EVP_MD *ssl_handshake_md(SSL *s);
+__owur const EVP_MD *ssl_prf_md(SSL *s);
+
+/*
+ * ssl_log_rsa_client_key_exchange logs |premaster| to the SSL_CTX associated
+ * with |ssl|, if logging is enabled. It returns one on success and zero on
+ * failure. The entry is identified by the first 8 bytes of
+ * |encrypted_premaster|.
+ */
+__owur int ssl_log_rsa_client_key_exchange(SSL *ssl,
+                                           const uint8_t *encrypted_premaster,
+                                           size_t encrypted_premaster_len,
+                                           const uint8_t *premaster,
+                                           size_t premaster_len);
+
+/*
+ * ssl_log_secret logs |secret| to the SSL_CTX associated with |ssl|, if
+ * logging is available. It returns one on success and zero on failure. It tags
+ * the entry with |label|.
+ */
+__owur int ssl_log_secret(SSL *ssl, const char *label,
+                          const uint8_t *secret, size_t secret_len);
+
+#define MASTER_SECRET_LABEL "CLIENT_RANDOM"
+#define CLIENT_EARLY_LABEL "CLIENT_EARLY_TRAFFIC_SECRET"
+#define CLIENT_HANDSHAKE_LABEL "CLIENT_HANDSHAKE_TRAFFIC_SECRET"
+#define SERVER_HANDSHAKE_LABEL "SERVER_HANDSHAKE_TRAFFIC_SECRET"
+#define CLIENT_APPLICATION_LABEL "CLIENT_TRAFFIC_SECRET_0"
+#define SERVER_APPLICATION_LABEL "SERVER_TRAFFIC_SECRET_0"
+#define EARLY_EXPORTER_SECRET_LABEL "EARLY_EXPORTER_SECRET"
+#define EXPORTER_SECRET_LABEL "EXPORTER_SECRET"
+
+/* s3_cbc.c */
+__owur char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx);
+__owur int ssl3_cbc_digest_record(const EVP_MD_CTX *ctx,
+                                  unsigned char *md_out,
+                                  size_t *md_out_size,
+                                  const unsigned char *header,
+                                  const unsigned char *data,
+                                  size_t data_plus_mac_size,
+                                  size_t data_plus_mac_plus_padding_size,
+                                  const unsigned char *mac_secret,
+                                  size_t mac_secret_length, char is_sslv3);
+
+__owur int srp_generate_server_master_secret(SSL *s);
+__owur int srp_generate_client_master_secret(SSL *s);
+__owur int srp_verify_server_param(SSL *s);
+
+/* statem/statem_srvr.c */
+
+__owur int send_certificate_request(SSL *s);
+
+/* statem/extensions_cust.c */
+
+custom_ext_method *custom_ext_find(const custom_ext_methods *exts,
+                                   ENDPOINT role, unsigned int ext_type,
+                                   size_t *idx);
+
+void custom_ext_init(custom_ext_methods *meths);
+
+__owur int custom_ext_parse(SSL *s, unsigned int context, unsigned int ext_type,
+                            const unsigned char *ext_data, size_t ext_size,
+                            X509 *x, size_t chainidx);
+__owur int custom_ext_add(SSL *s, int context, WPACKET *pkt, X509 *x,
+                          size_t chainidx, int maxversion);
+
+__owur int custom_exts_copy(custom_ext_methods *dst,
+                            const custom_ext_methods *src);
+__owur int custom_exts_copy_flags(custom_ext_methods *dst,
+                                  const custom_ext_methods *src);
+void custom_exts_free(custom_ext_methods *exts);
+
+void ssl_comp_free_compression_methods_int(void);
+
+/* ssl_mcnf.c */
+void ssl_ctx_system_config(SSL_CTX *ctx);
+
+# else /* OPENSSL_UNIT_TEST */
+
+#  define ssl_init_wbio_buffer SSL_test_functions()->p_ssl_init_wbio_buffer
+#  define ssl3_setup_buffers SSL_test_functions()->p_ssl3_setup_buffers
+
+# endif
+#endif
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_mcnf.c b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_mcnf.c
new file mode 100644
index 0000000..583df41
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_mcnf.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <openssl/conf.h>
+#include <openssl/ssl.h>
+#include "ssl_local.h"
+#include "internal/sslconf.h"
+
+/* SSL library configuration module. */
+
+void SSL_add_ssl_module(void)
+{
+    /* Do nothing. This will be added automatically by libcrypto */
+}
+
+static int ssl_do_config(SSL *s, SSL_CTX *ctx, const char *name, int system)
+{
+    SSL_CONF_CTX *cctx = NULL;
+    size_t i, idx, cmd_count;
+    int rv = 0;
+    unsigned int flags;
+    const SSL_METHOD *meth;
+    const SSL_CONF_CMD *cmds;
+
+    if (s == NULL && ctx == NULL) {
+        SSLerr(SSL_F_SSL_DO_CONFIG, ERR_R_PASSED_NULL_PARAMETER);
+        goto err;
+    }
+
+    if (name == NULL && system)
+        name = "system_default";
+    if (!conf_ssl_name_find(name, &idx)) {
+        if (!system) {
+            SSLerr(SSL_F_SSL_DO_CONFIG, SSL_R_INVALID_CONFIGURATION_NAME);
+            ERR_add_error_data(2, "name=", name);
+        }
+        goto err;
+    }
+    cmds = conf_ssl_get(idx, &name, &cmd_count);
+    cctx = SSL_CONF_CTX_new();
+    if (cctx == NULL)
+        goto err;
+    flags = SSL_CONF_FLAG_FILE;
+    if (!system)
+        flags |= SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_REQUIRE_PRIVATE;
+    if (s != NULL) {
+        meth = s->method;
+        SSL_CONF_CTX_set_ssl(cctx, s);
+    } else {
+        meth = ctx->method;
+        SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);
+    }
+    if (meth->ssl_accept != ssl_undefined_function)
+        flags |= SSL_CONF_FLAG_SERVER;
+    if (meth->ssl_connect != ssl_undefined_function)
+        flags |= SSL_CONF_FLAG_CLIENT;
+    SSL_CONF_CTX_set_flags(cctx, flags);
+    for (i = 0; i < cmd_count; i++) {
+        char *cmdstr, *arg;
+
+        conf_ssl_get_cmd(cmds, i, &cmdstr, &arg);
+        rv = SSL_CONF_cmd(cctx, cmdstr, arg);
+        if (rv <= 0) {
+            if (rv == -2)
+                SSLerr(SSL_F_SSL_DO_CONFIG, SSL_R_UNKNOWN_COMMAND);
+            else
+                SSLerr(SSL_F_SSL_DO_CONFIG, SSL_R_BAD_VALUE);
+            ERR_add_error_data(6, "section=", name, ", cmd=", cmdstr,
+                               ", arg=", arg);
+            goto err;
+        }
+    }
+    rv = SSL_CONF_CTX_finish(cctx);
+ err:
+    SSL_CONF_CTX_free(cctx);
+    return rv <= 0 ? 0 : 1;
+}
+
+int SSL_config(SSL *s, const char *name)
+{
+    return ssl_do_config(s, NULL, name, 0);
+}
+
+int SSL_CTX_config(SSL_CTX *ctx, const char *name)
+{
+    return ssl_do_config(NULL, ctx, name, 0);
+}
+
+void ssl_ctx_system_config(SSL_CTX *ctx)
+{
+    ssl_do_config(NULL, ctx, NULL, 1);
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_rsa.c b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_rsa.c
new file mode 100644
index 0000000..2df07be
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_rsa.c
@@ -0,0 +1,1161 @@
+/*
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include "ssl_local.h"
+#include "packet_local.h"
+#include <openssl/bio.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+
+static int ssl_set_cert(CERT *c, X509 *x509);
+static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey);
+
+#define  SYNTHV1CONTEXT     (SSL_EXT_TLS1_2_AND_BELOW_ONLY \
+                             | SSL_EXT_CLIENT_HELLO \
+                             | SSL_EXT_TLS1_2_SERVER_HELLO \
+                             | SSL_EXT_IGNORE_ON_RESUMPTION)
+
+int SSL_use_certificate(SSL *ssl, X509 *x)
+{
+    int rv;
+    if (x == NULL) {
+        SSLerr(SSL_F_SSL_USE_CERTIFICATE, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    rv = ssl_security_cert(ssl, NULL, x, 0, 1);
+    if (rv != 1) {
+        SSLerr(SSL_F_SSL_USE_CERTIFICATE, rv);
+        return 0;
+    }
+
+    return ssl_set_cert(ssl->cert, x);
+}
+
+int SSL_use_certificate_file(SSL *ssl, const char *file, int type)
+{
+    int j;
+    BIO *in;
+    int ret = 0;
+    X509 *x = NULL;
+
+    in = BIO_new(BIO_s_file());
+    if (in == NULL) {
+        SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE, ERR_R_BUF_LIB);
+        goto end;
+    }
+
+    if (BIO_read_filename(in, file) <= 0) {
+        SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB);
+        goto end;
+    }
+    if (type == SSL_FILETYPE_ASN1) {
+        j = ERR_R_ASN1_LIB;
+        x = d2i_X509_bio(in, NULL);
+    } else if (type == SSL_FILETYPE_PEM) {
+        j = ERR_R_PEM_LIB;
+        x = PEM_read_bio_X509(in, NULL, ssl->default_passwd_callback,
+                              ssl->default_passwd_callback_userdata);
+    } else {
+        SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE, SSL_R_BAD_SSL_FILETYPE);
+        goto end;
+    }
+
+    if (x == NULL) {
+        SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE, j);
+        goto end;
+    }
+
+    ret = SSL_use_certificate(ssl, x);
+ end:
+    X509_free(x);
+    BIO_free(in);
+    return ret;
+}
+
+int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len)
+{
+    X509 *x;
+    int ret;
+
+    x = d2i_X509(NULL, &d, (long)len);
+    if (x == NULL) {
+        SSLerr(SSL_F_SSL_USE_CERTIFICATE_ASN1, ERR_R_ASN1_LIB);
+        return 0;
+    }
+
+    ret = SSL_use_certificate(ssl, x);
+    X509_free(x);
+    return ret;
+}
+
+#ifndef OPENSSL_NO_RSA
+int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa)
+{
+    EVP_PKEY *pkey;
+    int ret;
+
+    if (rsa == NULL) {
+        SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    if ((pkey = EVP_PKEY_new()) == NULL) {
+        SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY, ERR_R_EVP_LIB);
+        return 0;
+    }
+
+    RSA_up_ref(rsa);
+    if (EVP_PKEY_assign_RSA(pkey, rsa) <= 0) {
+        RSA_free(rsa);
+        EVP_PKEY_free(pkey);
+        return 0;
+    }
+
+    ret = ssl_set_pkey(ssl->cert, pkey);
+    EVP_PKEY_free(pkey);
+    return ret;
+}
+#endif
+
+static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey)
+{
+    size_t i;
+
+    if (ssl_cert_lookup_by_pkey(pkey, &i) == NULL) {
+        SSLerr(SSL_F_SSL_SET_PKEY, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+        return 0;
+    }
+
+    if (c->pkeys[i].x509 != NULL) {
+        EVP_PKEY *pktmp;
+        pktmp = X509_get0_pubkey(c->pkeys[i].x509);
+        if (pktmp == NULL) {
+            SSLerr(SSL_F_SSL_SET_PKEY, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        /*
+         * The return code from EVP_PKEY_copy_parameters is deliberately
+         * ignored. Some EVP_PKEY types cannot do this.
+         */
+        EVP_PKEY_copy_parameters(pktmp, pkey);
+        ERR_clear_error();
+
+        if (!X509_check_private_key(c->pkeys[i].x509, pkey)) {
+            X509_free(c->pkeys[i].x509);
+            c->pkeys[i].x509 = NULL;
+            return 0;
+        }
+    }
+
+    EVP_PKEY_free(c->pkeys[i].privatekey);
+    EVP_PKEY_up_ref(pkey);
+    c->pkeys[i].privatekey = pkey;
+    c->key = &c->pkeys[i];
+    return 1;
+}
+
+#ifndef OPENSSL_NO_RSA
+int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type)
+{
+    int j, ret = 0;
+    BIO *in;
+    RSA *rsa = NULL;
+
+    in = BIO_new(BIO_s_file());
+    if (in == NULL) {
+        SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE, ERR_R_BUF_LIB);
+        goto end;
+    }
+
+    if (BIO_read_filename(in, file) <= 0) {
+        SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE, ERR_R_SYS_LIB);
+        goto end;
+    }
+    if (type == SSL_FILETYPE_ASN1) {
+        j = ERR_R_ASN1_LIB;
+        rsa = d2i_RSAPrivateKey_bio(in, NULL);
+    } else if (type == SSL_FILETYPE_PEM) {
+        j = ERR_R_PEM_LIB;
+        rsa = PEM_read_bio_RSAPrivateKey(in, NULL,
+                                         ssl->default_passwd_callback,
+                                         ssl->default_passwd_callback_userdata);
+    } else {
+        SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE, SSL_R_BAD_SSL_FILETYPE);
+        goto end;
+    }
+    if (rsa == NULL) {
+        SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE, j);
+        goto end;
+    }
+    ret = SSL_use_RSAPrivateKey(ssl, rsa);
+    RSA_free(rsa);
+ end:
+    BIO_free(in);
+    return ret;
+}
+
+int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const unsigned char *d, long len)
+{
+    int ret;
+    const unsigned char *p;
+    RSA *rsa;
+
+    p = d;
+    if ((rsa = d2i_RSAPrivateKey(NULL, &p, (long)len)) == NULL) {
+        SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1, ERR_R_ASN1_LIB);
+        return 0;
+    }
+
+    ret = SSL_use_RSAPrivateKey(ssl, rsa);
+    RSA_free(rsa);
+    return ret;
+}
+#endif                          /* !OPENSSL_NO_RSA */
+
+int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey)
+{
+    int ret;
+
+    if (pkey == NULL) {
+        SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    ret = ssl_set_pkey(ssl->cert, pkey);
+    return ret;
+}
+
+int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type)
+{
+    int j, ret = 0;
+    BIO *in;
+    EVP_PKEY *pkey = NULL;
+
+    in = BIO_new(BIO_s_file());
+    if (in == NULL) {
+        SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE, ERR_R_BUF_LIB);
+        goto end;
+    }
+
+    if (BIO_read_filename(in, file) <= 0) {
+        SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE, ERR_R_SYS_LIB);
+        goto end;
+    }
+    if (type == SSL_FILETYPE_PEM) {
+        j = ERR_R_PEM_LIB;
+        pkey = PEM_read_bio_PrivateKey(in, NULL,
+                                       ssl->default_passwd_callback,
+                                       ssl->default_passwd_callback_userdata);
+    } else if (type == SSL_FILETYPE_ASN1) {
+        j = ERR_R_ASN1_LIB;
+        pkey = d2i_PrivateKey_bio(in, NULL);
+    } else {
+        SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE, SSL_R_BAD_SSL_FILETYPE);
+        goto end;
+    }
+    if (pkey == NULL) {
+        SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE, j);
+        goto end;
+    }
+    ret = SSL_use_PrivateKey(ssl, pkey);
+    EVP_PKEY_free(pkey);
+ end:
+    BIO_free(in);
+    return ret;
+}
+
+int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d,
+                            long len)
+{
+    int ret;
+    const unsigned char *p;
+    EVP_PKEY *pkey;
+
+    p = d;
+    if ((pkey = d2i_PrivateKey(type, NULL, &p, (long)len)) == NULL) {
+        SSLerr(SSL_F_SSL_USE_PRIVATEKEY_ASN1, ERR_R_ASN1_LIB);
+        return 0;
+    }
+
+    ret = SSL_use_PrivateKey(ssl, pkey);
+    EVP_PKEY_free(pkey);
+    return ret;
+}
+
+int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x)
+{
+    int rv;
+    if (x == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    rv = ssl_security_cert(NULL, ctx, x, 0, 1);
+    if (rv != 1) {
+        SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE, rv);
+        return 0;
+    }
+    return ssl_set_cert(ctx->cert, x);
+}
+
+static int ssl_set_cert(CERT *c, X509 *x)
+{
+    EVP_PKEY *pkey;
+    size_t i;
+
+    pkey = X509_get0_pubkey(x);
+    if (pkey == NULL) {
+        SSLerr(SSL_F_SSL_SET_CERT, SSL_R_X509_LIB);
+        return 0;
+    }
+
+    if (ssl_cert_lookup_by_pkey(pkey, &i) == NULL) {
+        SSLerr(SSL_F_SSL_SET_CERT, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+        return 0;
+    }
+#ifndef OPENSSL_NO_EC
+    if (i == SSL_PKEY_ECC && !EC_KEY_can_sign(EVP_PKEY_get0_EC_KEY(pkey))) {
+        SSLerr(SSL_F_SSL_SET_CERT, SSL_R_ECC_CERT_NOT_FOR_SIGNING);
+        return 0;
+    }
+#endif
+    if (c->pkeys[i].privatekey != NULL) {
+        /*
+         * The return code from EVP_PKEY_copy_parameters is deliberately
+         * ignored. Some EVP_PKEY types cannot do this.
+         */
+        EVP_PKEY_copy_parameters(pkey, c->pkeys[i].privatekey);
+        ERR_clear_error();
+
+        if (!X509_check_private_key(x, c->pkeys[i].privatekey)) {
+            /*
+             * don't fail for a cert/key mismatch, just free current private
+             * key (when switching to a different cert & key, first this
+             * function should be used, then ssl_set_pkey
+             */
+            EVP_PKEY_free(c->pkeys[i].privatekey);
+            c->pkeys[i].privatekey = NULL;
+            /* clear error queue */
+            ERR_clear_error();
+        }
+    }
+
+    X509_free(c->pkeys[i].x509);
+    X509_up_ref(x);
+    c->pkeys[i].x509 = x;
+    c->key = &(c->pkeys[i]);
+
+    return 1;
+}
+
+int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type)
+{
+    int j;
+    BIO *in;
+    int ret = 0;
+    X509 *x = NULL;
+
+    in = BIO_new(BIO_s_file());
+    if (in == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_BUF_LIB);
+        goto end;
+    }
+
+    if (BIO_read_filename(in, file) <= 0) {
+        SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB);
+        goto end;
+    }
+    if (type == SSL_FILETYPE_ASN1) {
+        j = ERR_R_ASN1_LIB;
+        x = d2i_X509_bio(in, NULL);
+    } else if (type == SSL_FILETYPE_PEM) {
+        j = ERR_R_PEM_LIB;
+        x = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback,
+                              ctx->default_passwd_callback_userdata);
+    } else {
+        SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, SSL_R_BAD_SSL_FILETYPE);
+        goto end;
+    }
+
+    if (x == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, j);
+        goto end;
+    }
+
+    ret = SSL_CTX_use_certificate(ctx, x);
+ end:
+    X509_free(x);
+    BIO_free(in);
+    return ret;
+}
+
+int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d)
+{
+    X509 *x;
+    int ret;
+
+    x = d2i_X509(NULL, &d, (long)len);
+    if (x == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1, ERR_R_ASN1_LIB);
+        return 0;
+    }
+
+    ret = SSL_CTX_use_certificate(ctx, x);
+    X509_free(x);
+    return ret;
+}
+
+#ifndef OPENSSL_NO_RSA
+int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa)
+{
+    int ret;
+    EVP_PKEY *pkey;
+
+    if (rsa == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    if ((pkey = EVP_PKEY_new()) == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY, ERR_R_EVP_LIB);
+        return 0;
+    }
+
+    RSA_up_ref(rsa);
+    if (EVP_PKEY_assign_RSA(pkey, rsa) <= 0) {
+        RSA_free(rsa);
+        EVP_PKEY_free(pkey);
+        return 0;
+    }
+
+    ret = ssl_set_pkey(ctx->cert, pkey);
+    EVP_PKEY_free(pkey);
+    return ret;
+}
+
+int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type)
+{
+    int j, ret = 0;
+    BIO *in;
+    RSA *rsa = NULL;
+
+    in = BIO_new(BIO_s_file());
+    if (in == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE, ERR_R_BUF_LIB);
+        goto end;
+    }
+
+    if (BIO_read_filename(in, file) <= 0) {
+        SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE, ERR_R_SYS_LIB);
+        goto end;
+    }
+    if (type == SSL_FILETYPE_ASN1) {
+        j = ERR_R_ASN1_LIB;
+        rsa = d2i_RSAPrivateKey_bio(in, NULL);
+    } else if (type == SSL_FILETYPE_PEM) {
+        j = ERR_R_PEM_LIB;
+        rsa = PEM_read_bio_RSAPrivateKey(in, NULL,
+                                         ctx->default_passwd_callback,
+                                         ctx->default_passwd_callback_userdata);
+    } else {
+        SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE, SSL_R_BAD_SSL_FILETYPE);
+        goto end;
+    }
+    if (rsa == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE, j);
+        goto end;
+    }
+    ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa);
+    RSA_free(rsa);
+ end:
+    BIO_free(in);
+    return ret;
+}
+
+int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d,
+                                   long len)
+{
+    int ret;
+    const unsigned char *p;
+    RSA *rsa;
+
+    p = d;
+    if ((rsa = d2i_RSAPrivateKey(NULL, &p, (long)len)) == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1, ERR_R_ASN1_LIB);
+        return 0;
+    }
+
+    ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa);
+    RSA_free(rsa);
+    return ret;
+}
+#endif                          /* !OPENSSL_NO_RSA */
+
+int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey)
+{
+    if (pkey == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    return ssl_set_pkey(ctx->cert, pkey);
+}
+
+int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type)
+{
+    int j, ret = 0;
+    BIO *in;
+    EVP_PKEY *pkey = NULL;
+
+    in = BIO_new(BIO_s_file());
+    if (in == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_BUF_LIB);
+        goto end;
+    }
+
+    if (BIO_read_filename(in, file) <= 0) {
+        SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_SYS_LIB);
+        goto end;
+    }
+    if (type == SSL_FILETYPE_PEM) {
+        j = ERR_R_PEM_LIB;
+        pkey = PEM_read_bio_PrivateKey(in, NULL,
+                                       ctx->default_passwd_callback,
+                                       ctx->default_passwd_callback_userdata);
+    } else if (type == SSL_FILETYPE_ASN1) {
+        j = ERR_R_ASN1_LIB;
+        pkey = d2i_PrivateKey_bio(in, NULL);
+    } else {
+        SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, SSL_R_BAD_SSL_FILETYPE);
+        goto end;
+    }
+    if (pkey == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, j);
+        goto end;
+    }
+    ret = SSL_CTX_use_PrivateKey(ctx, pkey);
+    EVP_PKEY_free(pkey);
+ end:
+    BIO_free(in);
+    return ret;
+}
+
+int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx,
+                                const unsigned char *d, long len)
+{
+    int ret;
+    const unsigned char *p;
+    EVP_PKEY *pkey;
+
+    p = d;
+    if ((pkey = d2i_PrivateKey(type, NULL, &p, (long)len)) == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1, ERR_R_ASN1_LIB);
+        return 0;
+    }
+
+    ret = SSL_CTX_use_PrivateKey(ctx, pkey);
+    EVP_PKEY_free(pkey);
+    return ret;
+}
+
+/*
+ * Read a file that contains our certificate in "PEM" format, possibly
+ * followed by a sequence of CA certificates that should be sent to the peer
+ * in the Certificate message.
+ */
+static int use_certificate_chain_file(SSL_CTX *ctx, SSL *ssl, const char *file)
+{
+    BIO *in;
+    int ret = 0;
+    X509 *x = NULL;
+    pem_password_cb *passwd_callback;
+    void *passwd_callback_userdata;
+
+    ERR_clear_error();          /* clear error stack for
+                                 * SSL_CTX_use_certificate() */
+
+    if (ctx != NULL) {
+        passwd_callback = ctx->default_passwd_callback;
+        passwd_callback_userdata = ctx->default_passwd_callback_userdata;
+    } else {
+        passwd_callback = ssl->default_passwd_callback;
+        passwd_callback_userdata = ssl->default_passwd_callback_userdata;
+    }
+
+    in = BIO_new(BIO_s_file());
+    if (in == NULL) {
+        SSLerr(SSL_F_USE_CERTIFICATE_CHAIN_FILE, ERR_R_BUF_LIB);
+        goto end;
+    }
+
+    if (BIO_read_filename(in, file) <= 0) {
+        SSLerr(SSL_F_USE_CERTIFICATE_CHAIN_FILE, ERR_R_SYS_LIB);
+        goto end;
+    }
+
+    x = PEM_read_bio_X509_AUX(in, NULL, passwd_callback,
+                              passwd_callback_userdata);
+    if (x == NULL) {
+        SSLerr(SSL_F_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB);
+        goto end;
+    }
+
+    if (ctx)
+        ret = SSL_CTX_use_certificate(ctx, x);
+    else
+        ret = SSL_use_certificate(ssl, x);
+
+    if (ERR_peek_error() != 0)
+        ret = 0;                /* Key/certificate mismatch doesn't imply
+                                 * ret==0 ... */
+    if (ret) {
+        /*
+         * If we could set up our certificate, now proceed to the CA
+         * certificates.
+         */
+        X509 *ca;
+        int r;
+        unsigned long err;
+
+        if (ctx)
+            r = SSL_CTX_clear_chain_certs(ctx);
+        else
+            r = SSL_clear_chain_certs(ssl);
+
+        if (r == 0) {
+            ret = 0;
+            goto end;
+        }
+
+        while ((ca = PEM_read_bio_X509(in, NULL, passwd_callback,
+                                       passwd_callback_userdata))
+               != NULL) {
+            if (ctx)
+                r = SSL_CTX_add0_chain_cert(ctx, ca);
+            else
+                r = SSL_add0_chain_cert(ssl, ca);
+            /*
+             * Note that we must not free ca if it was successfully added to
+             * the chain (while we must free the main certificate, since its
+             * reference count is increased by SSL_CTX_use_certificate).
+             */
+            if (!r) {
+                X509_free(ca);
+                ret = 0;
+                goto end;
+            }
+        }
+        /* When the while loop ends, it's usually just EOF. */
+        err = ERR_peek_last_error();
+        if (ERR_GET_LIB(err) == ERR_LIB_PEM
+            && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)
+            ERR_clear_error();
+        else
+            ret = 0;            /* some real error */
+    }
+
+ end:
+    X509_free(x);
+    BIO_free(in);
+    return ret;
+}
+
+int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file)
+{
+    return use_certificate_chain_file(ctx, NULL, file);
+}
+
+int SSL_use_certificate_chain_file(SSL *ssl, const char *file)
+{
+    return use_certificate_chain_file(NULL, ssl, file);
+}
+
+static int serverinfo_find_extension(const unsigned char *serverinfo,
+                                     size_t serverinfo_length,
+                                     unsigned int extension_type,
+                                     const unsigned char **extension_data,
+                                     size_t *extension_length)
+{
+    PACKET pkt, data;
+
+    *extension_data = NULL;
+    *extension_length = 0;
+    if (serverinfo == NULL || serverinfo_length == 0)
+        return -1;
+
+    if (!PACKET_buf_init(&pkt, serverinfo, serverinfo_length))
+        return -1;
+
+    for (;;) {
+        unsigned int type = 0;
+        unsigned long context = 0;
+
+        /* end of serverinfo */
+        if (PACKET_remaining(&pkt) == 0)
+            return 0;           /* Extension not found */
+
+        if (!PACKET_get_net_4(&pkt, &context)
+                || !PACKET_get_net_2(&pkt, &type)
+                || !PACKET_get_length_prefixed_2(&pkt, &data))
+            return -1;
+
+        if (type == extension_type) {
+            *extension_data = PACKET_data(&data);
+            *extension_length = PACKET_remaining(&data);;
+            return 1;           /* Success */
+        }
+    }
+    /* Unreachable */
+}
+
+static int serverinfoex_srv_parse_cb(SSL *s, unsigned int ext_type,
+                                     unsigned int context,
+                                     const unsigned char *in,
+                                     size_t inlen, X509 *x, size_t chainidx,
+                                     int *al, void *arg)
+{
+
+    if (inlen != 0) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    return 1;
+}
+
+static size_t extension_contextoff(unsigned int version)
+{
+    return version == SSL_SERVERINFOV1 ? 4 : 0;
+}
+
+static size_t extension_append_length(unsigned int version, size_t extension_length)
+{
+    return extension_length + extension_contextoff(version);
+}
+
+static void extension_append(unsigned int version,
+                             const unsigned char *extension,
+                             const size_t extension_length,
+                             unsigned char *serverinfo)
+{
+    const size_t contextoff = extension_contextoff(version);
+
+    if (contextoff > 0) {
+        /* We know this only uses the last 2 bytes */
+        serverinfo[0] = 0;
+        serverinfo[1] = 0;
+        serverinfo[2] = (SYNTHV1CONTEXT >> 8) & 0xff;
+        serverinfo[3] = SYNTHV1CONTEXT & 0xff;
+    }
+
+    memcpy(serverinfo + contextoff, extension, extension_length);
+}
+
+static int serverinfo_srv_parse_cb(SSL *s, unsigned int ext_type,
+                                   const unsigned char *in,
+                                   size_t inlen, int *al, void *arg)
+{
+    return serverinfoex_srv_parse_cb(s, ext_type, 0, in, inlen, NULL, 0, al,
+                                     arg);
+}
+
+static int serverinfoex_srv_add_cb(SSL *s, unsigned int ext_type,
+                                   unsigned int context,
+                                   const unsigned char **out,
+                                   size_t *outlen, X509 *x, size_t chainidx,
+                                   int *al, void *arg)
+{
+    const unsigned char *serverinfo = NULL;
+    size_t serverinfo_length = 0;
+
+    /* We only support extensions for the first Certificate */
+    if ((context & SSL_EXT_TLS1_3_CERTIFICATE) != 0 && chainidx > 0)
+        return 0;
+
+    /* Is there serverinfo data for the chosen server cert? */
+    if ((ssl_get_server_cert_serverinfo(s, &serverinfo,
+                                        &serverinfo_length)) != 0) {
+        /* Find the relevant extension from the serverinfo */
+        int retval = serverinfo_find_extension(serverinfo, serverinfo_length,
+                                               ext_type, out, outlen);
+        if (retval == -1) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            return -1;          /* Error */
+        }
+        if (retval == 0)
+            return 0;           /* No extension found, don't send extension */
+        return 1;               /* Send extension */
+    }
+    return 0;                   /* No serverinfo data found, don't send
+                                 * extension */
+}
+
+static int serverinfo_srv_add_cb(SSL *s, unsigned int ext_type,
+                                 const unsigned char **out, size_t *outlen,
+                                 int *al, void *arg)
+{
+    return serverinfoex_srv_add_cb(s, ext_type, 0, out, outlen, NULL, 0, al,
+                                   arg);
+}
+
+/*
+ * With a NULL context, this function just checks that the serverinfo data
+ * parses correctly.  With a non-NULL context, it registers callbacks for
+ * the included extensions.
+ */
+static int serverinfo_process_buffer(unsigned int version,
+                                     const unsigned char *serverinfo,
+                                     size_t serverinfo_length, SSL_CTX *ctx)
+{
+    PACKET pkt;
+
+    if (serverinfo == NULL || serverinfo_length == 0)
+        return 0;
+
+    if (version != SSL_SERVERINFOV1 && version != SSL_SERVERINFOV2)
+        return 0;
+
+    if (!PACKET_buf_init(&pkt, serverinfo, serverinfo_length))
+        return 0;
+
+    while (PACKET_remaining(&pkt)) {
+        unsigned long context = 0;
+        unsigned int ext_type = 0;
+        PACKET data;
+
+        if ((version == SSL_SERVERINFOV2 && !PACKET_get_net_4(&pkt, &context))
+                || !PACKET_get_net_2(&pkt, &ext_type)
+                || !PACKET_get_length_prefixed_2(&pkt, &data))
+            return 0;
+
+        if (ctx == NULL)
+            continue;
+
+        /*
+         * The old style custom extensions API could be set separately for
+         * server/client, i.e. you could set one custom extension for a client,
+         * and *for the same extension in the same SSL_CTX* you could set a
+         * custom extension for the server as well. It seems quite weird to be
+         * setting a custom extension for both client and server in a single
+         * SSL_CTX - but theoretically possible. This isn't possible in the
+         * new API. Therefore, if we have V1 serverinfo we use the old API. We
+         * also use the old API even if we have V2 serverinfo but the context
+         * looks like an old style <= TLSv1.2 extension.
+         */
+        if (version == SSL_SERVERINFOV1 || context == SYNTHV1CONTEXT) {
+            if (!SSL_CTX_add_server_custom_ext(ctx, ext_type,
+                                               serverinfo_srv_add_cb,
+                                               NULL, NULL,
+                                               serverinfo_srv_parse_cb,
+                                               NULL))
+                return 0;
+        } else {
+            if (!SSL_CTX_add_custom_ext(ctx, ext_type, context,
+                                        serverinfoex_srv_add_cb,
+                                        NULL, NULL,
+                                        serverinfoex_srv_parse_cb,
+                                        NULL))
+                return 0;
+        }
+    }
+
+    return 1;
+}
+
+int SSL_CTX_use_serverinfo_ex(SSL_CTX *ctx, unsigned int version,
+                              const unsigned char *serverinfo,
+                              size_t serverinfo_length)
+{
+    unsigned char *new_serverinfo = NULL;
+
+    if (ctx == NULL || serverinfo == NULL || serverinfo_length == 0) {
+        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_EX, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    if (version == SSL_SERVERINFOV1) {
+        /*
+         * Convert serverinfo version v1 to v2 and call yourself recursively
+         * over the converted serverinfo.
+         */
+        const size_t sinfo_length = extension_append_length(SSL_SERVERINFOV1,
+                                                            serverinfo_length);
+        unsigned char *sinfo;
+        int ret;
+
+        sinfo = OPENSSL_malloc(sinfo_length);
+        if (sinfo == NULL) {
+            SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_EX, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+
+        extension_append(SSL_SERVERINFOV1, serverinfo, serverinfo_length, sinfo);
+
+        ret = SSL_CTX_use_serverinfo_ex(ctx, SSL_SERVERINFOV2, sinfo,
+                                        sinfo_length);
+
+        OPENSSL_free(sinfo);
+        return ret;
+    }
+    if (!serverinfo_process_buffer(version, serverinfo, serverinfo_length,
+                                   NULL)) {
+        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_EX, SSL_R_INVALID_SERVERINFO_DATA);
+        return 0;
+    }
+    if (ctx->cert->key == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_EX, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    new_serverinfo = OPENSSL_realloc(ctx->cert->key->serverinfo,
+                                     serverinfo_length);
+    if (new_serverinfo == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_EX, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    ctx->cert->key->serverinfo = new_serverinfo;
+    memcpy(ctx->cert->key->serverinfo, serverinfo, serverinfo_length);
+    ctx->cert->key->serverinfo_length = serverinfo_length;
+
+    /*
+     * Now that the serverinfo is validated and stored, go ahead and
+     * register callbacks.
+     */
+    if (!serverinfo_process_buffer(version, serverinfo, serverinfo_length,
+                                   ctx)) {
+        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_EX, SSL_R_INVALID_SERVERINFO_DATA);
+        return 0;
+    }
+    return 1;
+}
+
+int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo,
+                           size_t serverinfo_length)
+{
+    return SSL_CTX_use_serverinfo_ex(ctx, SSL_SERVERINFOV1, serverinfo,
+                                     serverinfo_length);
+}
+
+int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file)
+{
+    unsigned char *serverinfo = NULL;
+    unsigned char *tmp;
+    size_t serverinfo_length = 0;
+    unsigned char *extension = 0;
+    long extension_length = 0;
+    char *name = NULL;
+    char *header = NULL;
+    char namePrefix1[] = "SERVERINFO FOR ";
+    char namePrefix2[] = "SERVERINFOV2 FOR ";
+    int ret = 0;
+    BIO *bin = NULL;
+    size_t num_extensions = 0;
+
+    if (ctx == NULL || file == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_PASSED_NULL_PARAMETER);
+        goto end;
+    }
+
+    bin = BIO_new(BIO_s_file());
+    if (bin == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_BUF_LIB);
+        goto end;
+    }
+    if (BIO_read_filename(bin, file) <= 0) {
+        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_SYS_LIB);
+        goto end;
+    }
+
+    for (num_extensions = 0;; num_extensions++) {
+        unsigned int version;
+        size_t append_length;
+
+        if (PEM_read_bio(bin, &name, &header, &extension, &extension_length)
+            == 0) {
+            /*
+             * There must be at least one extension in this file
+             */
+            if (num_extensions == 0) {
+                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE,
+                       SSL_R_NO_PEM_EXTENSIONS);
+                goto end;
+            } else              /* End of file, we're done */
+                break;
+        }
+        /* Check that PEM name starts with "BEGIN SERVERINFO FOR " */
+        if (strlen(name) < strlen(namePrefix1)) {
+            SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_PEM_NAME_TOO_SHORT);
+            goto end;
+        }
+        if (strncmp(name, namePrefix1, strlen(namePrefix1)) == 0) {
+            version = SSL_SERVERINFOV1;
+        } else {
+            if (strlen(name) < strlen(namePrefix2)) {
+                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE,
+                       SSL_R_PEM_NAME_TOO_SHORT);
+                goto end;
+            }
+            if (strncmp(name, namePrefix2, strlen(namePrefix2)) != 0) {
+                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE,
+                       SSL_R_PEM_NAME_BAD_PREFIX);
+                goto end;
+            }
+            version = SSL_SERVERINFOV2;
+        }
+        /*
+         * Check that the decoded PEM data is plausible (valid length field)
+         */
+        if (version == SSL_SERVERINFOV1) {
+            /* 4 byte header: 2 bytes type, 2 bytes len */
+            if (extension_length < 4
+                    || (extension[2] << 8) + extension[3]
+                       != extension_length - 4) {
+                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_BAD_DATA);
+                goto end;
+            }
+        } else {
+            /* 8 byte header: 4 bytes context, 2 bytes type, 2 bytes len */
+            if (extension_length < 8
+                    || (extension[6] << 8) + extension[7]
+                       != extension_length - 8) {
+                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_BAD_DATA);
+                goto end;
+            }
+        }
+        /* Append the decoded extension to the serverinfo buffer */
+        append_length = extension_append_length(version, extension_length);
+        tmp = OPENSSL_realloc(serverinfo, serverinfo_length + append_length);
+        if (tmp == NULL) {
+            SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_MALLOC_FAILURE);
+            goto end;
+        }
+        serverinfo = tmp;
+        extension_append(version, extension, extension_length,
+                         serverinfo + serverinfo_length);
+        serverinfo_length += append_length;
+
+        OPENSSL_free(name);
+        name = NULL;
+        OPENSSL_free(header);
+        header = NULL;
+        OPENSSL_free(extension);
+        extension = NULL;
+    }
+
+    ret = SSL_CTX_use_serverinfo_ex(ctx, SSL_SERVERINFOV2, serverinfo,
+                                    serverinfo_length);
+ end:
+    /* SSL_CTX_use_serverinfo makes a local copy of the serverinfo. */
+    OPENSSL_free(name);
+    OPENSSL_free(header);
+    OPENSSL_free(extension);
+    OPENSSL_free(serverinfo);
+    BIO_free(bin);
+    return ret;
+}
+
+static int ssl_set_cert_and_key(SSL *ssl, SSL_CTX *ctx, X509 *x509, EVP_PKEY *privatekey,
+                                STACK_OF(X509) *chain, int override)
+{
+    int ret = 0;
+    size_t i;
+    int j;
+    int rv;
+    CERT *c = ssl != NULL ? ssl->cert : ctx->cert;
+    STACK_OF(X509) *dup_chain = NULL;
+    EVP_PKEY *pubkey = NULL;
+
+    /* Do all security checks before anything else */
+    rv = ssl_security_cert(ssl, ctx, x509, 0, 1);
+    if (rv != 1) {
+        SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, rv);
+        goto out;
+    }
+    for (j = 0; j < sk_X509_num(chain); j++) {
+        rv = ssl_security_cert(ssl, ctx, sk_X509_value(chain, j), 0, 0);
+        if (rv != 1) {
+            SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, rv);
+            goto out;
+        }
+    }
+
+    pubkey = X509_get_pubkey(x509); /* bumps reference */
+    if (pubkey == NULL)
+        goto out;
+    if (privatekey == NULL) {
+        privatekey = pubkey;
+    } else {
+        /* For RSA, which has no parameters, missing returns 0 */
+        if (EVP_PKEY_missing_parameters(privatekey)) {
+            if (EVP_PKEY_missing_parameters(pubkey)) {
+                /* nobody has parameters? - error */
+                SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, SSL_R_MISSING_PARAMETERS);
+                goto out;
+            } else {
+                /* copy to privatekey from pubkey */
+                EVP_PKEY_copy_parameters(privatekey, pubkey);
+            }
+        } else if (EVP_PKEY_missing_parameters(pubkey)) {
+            /* copy to pubkey from privatekey */
+            EVP_PKEY_copy_parameters(pubkey, privatekey);
+        } /* else both have parameters */
+
+        /* check that key <-> cert match */
+        if (EVP_PKEY_cmp(pubkey, privatekey) != 1) {
+            SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, SSL_R_PRIVATE_KEY_MISMATCH);
+            goto out;
+        }
+    }
+    if (ssl_cert_lookup_by_pkey(pubkey, &i) == NULL) {
+        SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+        goto out;
+    }
+
+    if (!override && (c->pkeys[i].x509 != NULL
+                      || c->pkeys[i].privatekey != NULL
+                      || c->pkeys[i].chain != NULL)) {
+        /* No override, and something already there */
+        SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, SSL_R_NOT_REPLACING_CERTIFICATE);
+        goto out;
+    }
+
+    if (chain != NULL) {
+        dup_chain = X509_chain_up_ref(chain);
+        if  (dup_chain == NULL) {
+            SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, ERR_R_MALLOC_FAILURE);
+            goto out;
+        }
+    }
+
+    sk_X509_pop_free(c->pkeys[i].chain, X509_free);
+    c->pkeys[i].chain = dup_chain;
+
+    X509_free(c->pkeys[i].x509);
+    X509_up_ref(x509);
+    c->pkeys[i].x509 = x509;
+
+    EVP_PKEY_free(c->pkeys[i].privatekey);
+    EVP_PKEY_up_ref(privatekey);
+    c->pkeys[i].privatekey = privatekey;
+
+    c->key = &(c->pkeys[i]);
+
+    ret = 1;
+ out:
+    EVP_PKEY_free(pubkey);
+    return ret;
+}
+
+int SSL_use_cert_and_key(SSL *ssl, X509 *x509, EVP_PKEY *privatekey,
+                         STACK_OF(X509) *chain, int override)
+{
+    return ssl_set_cert_and_key(ssl, NULL, x509, privatekey, chain, override);
+}
+
+int SSL_CTX_use_cert_and_key(SSL_CTX *ctx, X509 *x509, EVP_PKEY *privatekey,
+                             STACK_OF(X509) *chain, int override)
+{
+    return ssl_set_cert_and_key(NULL, ctx, x509, privatekey, chain, override);
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_sess.c b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_sess.c
new file mode 100644
index 0000000..cda6b7c
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_sess.c
@@ -0,0 +1,1280 @@
+/*
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <openssl/rand.h>
+#include <openssl/engine.h>
+#include "internal/refcount.h"
+#include "internal/cryptlib.h"
+#include "ssl_local.h"
+#include "statem/statem_local.h"
+
+static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s);
+static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s);
+static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck);
+
+/*
+ * SSL_get_session() and SSL_get1_session() are problematic in TLS1.3 because,
+ * unlike in earlier protocol versions, the session ticket may not have been
+ * sent yet even though a handshake has finished. The session ticket data could
+ * come in sometime later...or even change if multiple session ticket messages
+ * are sent from the server. The preferred way for applications to obtain
+ * a resumable session is to use SSL_CTX_sess_set_new_cb().
+ */
+
+SSL_SESSION *SSL_get_session(const SSL *ssl)
+/* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */
+{
+    return ssl->session;
+}
+
+SSL_SESSION *SSL_get1_session(SSL *ssl)
+/* variant of SSL_get_session: caller really gets something */
+{
+    SSL_SESSION *sess;
+    /*
+     * Need to lock this all up rather than just use CRYPTO_add so that
+     * somebody doesn't free ssl->session between when we check it's non-null
+     * and when we up the reference count.
+     */
+    CRYPTO_THREAD_read_lock(ssl->lock);
+    sess = ssl->session;
+    if (sess)
+        SSL_SESSION_up_ref(sess);
+    CRYPTO_THREAD_unlock(ssl->lock);
+    return sess;
+}
+
+int SSL_SESSION_set_ex_data(SSL_SESSION *s, int idx, void *arg)
+{
+    return CRYPTO_set_ex_data(&s->ex_data, idx, arg);
+}
+
+void *SSL_SESSION_get_ex_data(const SSL_SESSION *s, int idx)
+{
+    return CRYPTO_get_ex_data(&s->ex_data, idx);
+}
+
+SSL_SESSION *SSL_SESSION_new(void)
+{
+    SSL_SESSION *ss;
+
+    if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL))
+        return NULL;
+
+    ss = OPENSSL_zalloc(sizeof(*ss));
+    if (ss == NULL) {
+        SSLerr(SSL_F_SSL_SESSION_NEW, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    ss->verify_result = 1;      /* avoid 0 (= X509_V_OK) just in case */
+    ss->references = 1;
+    ss->timeout = 60 * 5 + 4;   /* 5 minute timeout by default */
+    ss->time = (unsigned long)time(NULL);
+    ss->lock = CRYPTO_THREAD_lock_new();
+    if (ss->lock == NULL) {
+        SSLerr(SSL_F_SSL_SESSION_NEW, ERR_R_MALLOC_FAILURE);
+        OPENSSL_free(ss);
+        return NULL;
+    }
+
+    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data)) {
+        CRYPTO_THREAD_lock_free(ss->lock);
+        OPENSSL_free(ss);
+        return NULL;
+    }
+    return ss;
+}
+
+SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *src)
+{
+    return ssl_session_dup(src, 1);
+}
+
+/*
+ * Create a new SSL_SESSION and duplicate the contents of |src| into it. If
+ * ticket == 0 then no ticket information is duplicated, otherwise it is.
+ */
+SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket)
+{
+    SSL_SESSION *dest;
+
+    dest = OPENSSL_malloc(sizeof(*dest));
+    if (dest == NULL) {
+        goto err;
+    }
+    memcpy(dest, src, sizeof(*dest));
+
+    /*
+     * Set the various pointers to NULL so that we can call SSL_SESSION_free in
+     * the case of an error whilst halfway through constructing dest
+     */
+#ifndef OPENSSL_NO_PSK
+    dest->psk_identity_hint = NULL;
+    dest->psk_identity = NULL;
+#endif
+    dest->ext.hostname = NULL;
+    dest->ext.tick = NULL;
+    dest->ext.alpn_selected = NULL;
+#ifndef OPENSSL_NO_SRP
+    dest->srp_username = NULL;
+#endif
+    dest->peer_chain = NULL;
+    dest->peer = NULL;
+    dest->ticket_appdata = NULL;
+    memset(&dest->ex_data, 0, sizeof(dest->ex_data));
+
+    /* We deliberately don't copy the prev and next pointers */
+    dest->prev = NULL;
+    dest->next = NULL;
+
+    dest->references = 1;
+
+    dest->lock = CRYPTO_THREAD_lock_new();
+    if (dest->lock == NULL)
+        goto err;
+
+    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, dest, &dest->ex_data))
+        goto err;
+
+    if (src->peer != NULL) {
+        if (!X509_up_ref(src->peer))
+            goto err;
+        dest->peer = src->peer;
+    }
+
+    if (src->peer_chain != NULL) {
+        dest->peer_chain = X509_chain_up_ref(src->peer_chain);
+        if (dest->peer_chain == NULL)
+            goto err;
+    }
+#ifndef OPENSSL_NO_PSK
+    if (src->psk_identity_hint) {
+        dest->psk_identity_hint = OPENSSL_strdup(src->psk_identity_hint);
+        if (dest->psk_identity_hint == NULL) {
+            goto err;
+        }
+    }
+    if (src->psk_identity) {
+        dest->psk_identity = OPENSSL_strdup(src->psk_identity);
+        if (dest->psk_identity == NULL) {
+            goto err;
+        }
+    }
+#endif
+
+    if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_SSL_SESSION,
+                            &dest->ex_data, &src->ex_data)) {
+        goto err;
+    }
+
+    if (src->ext.hostname) {
+        dest->ext.hostname = OPENSSL_strdup(src->ext.hostname);
+        if (dest->ext.hostname == NULL) {
+            goto err;
+        }
+    }
+
+    if (ticket != 0 && src->ext.tick != NULL) {
+        dest->ext.tick =
+            OPENSSL_memdup(src->ext.tick, src->ext.ticklen);
+        if (dest->ext.tick == NULL)
+            goto err;
+    } else {
+        dest->ext.tick_lifetime_hint = 0;
+        dest->ext.ticklen = 0;
+    }
+
+    if (src->ext.alpn_selected != NULL) {
+        dest->ext.alpn_selected = OPENSSL_memdup(src->ext.alpn_selected,
+                                                 src->ext.alpn_selected_len);
+        if (dest->ext.alpn_selected == NULL)
+            goto err;
+    }
+
+#ifndef OPENSSL_NO_SRP
+    if (src->srp_username) {
+        dest->srp_username = OPENSSL_strdup(src->srp_username);
+        if (dest->srp_username == NULL) {
+            goto err;
+        }
+    }
+#endif
+
+    if (src->ticket_appdata != NULL) {
+        dest->ticket_appdata =
+            OPENSSL_memdup(src->ticket_appdata, src->ticket_appdata_len);
+        if (dest->ticket_appdata == NULL)
+            goto err;
+    }
+
+    return dest;
+ err:
+    SSLerr(SSL_F_SSL_SESSION_DUP, ERR_R_MALLOC_FAILURE);
+    SSL_SESSION_free(dest);
+    return NULL;
+}
+
+const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len)
+{
+    if (len)
+        *len = (unsigned int)s->session_id_length;
+    return s->session_id;
+}
+const unsigned char *SSL_SESSION_get0_id_context(const SSL_SESSION *s,
+                                                unsigned int *len)
+{
+    if (len != NULL)
+        *len = (unsigned int)s->sid_ctx_length;
+    return s->sid_ctx;
+}
+
+unsigned int SSL_SESSION_get_compress_id(const SSL_SESSION *s)
+{
+    return s->compress_meth;
+}
+
+/*
+ * SSLv3/TLSv1 has 32 bytes (256 bits) of session ID space. As such, filling
+ * the ID with random junk repeatedly until we have no conflict is going to
+ * complete in one iteration pretty much "most" of the time (btw:
+ * understatement). So, if it takes us 10 iterations and we still can't avoid
+ * a conflict - well that's a reasonable point to call it quits. Either the
+ * RAND code is broken or someone is trying to open roughly very close to
+ * 2^256 SSL sessions to our server. How you might store that many sessions
+ * is perhaps a more interesting question ...
+ */
+
+#define MAX_SESS_ID_ATTEMPTS 10
+static int def_generate_session_id(SSL *ssl, unsigned char *id,
+                                   unsigned int *id_len)
+{
+    unsigned int retry = 0;
+    do
+        if (RAND_bytes(id, *id_len) <= 0)
+            return 0;
+    while (SSL_has_matching_session_id(ssl, id, *id_len) &&
+           (++retry < MAX_SESS_ID_ATTEMPTS)) ;
+    if (retry < MAX_SESS_ID_ATTEMPTS)
+        return 1;
+    /* else - woops a session_id match */
+    /*
+     * XXX We should also check the external cache -- but the probability of
+     * a collision is negligible, and we could not prevent the concurrent
+     * creation of sessions with identical IDs since we currently don't have
+     * means to atomically check whether a session ID already exists and make
+     * a reservation for it if it does not (this problem applies to the
+     * internal cache as well).
+     */
+    return 0;
+}
+
+int ssl_generate_session_id(SSL *s, SSL_SESSION *ss)
+{
+    unsigned int tmp;
+    GEN_SESSION_CB cb = def_generate_session_id;
+
+    switch (s->version) {
+    case SSL3_VERSION:
+    case TLS1_VERSION:
+    case TLS1_1_VERSION:
+    case TLS1_2_VERSION:
+    case TLS1_3_VERSION:
+    case DTLS1_BAD_VER:
+    case DTLS1_VERSION:
+    case DTLS1_2_VERSION:
+        ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
+        break;
+    default:
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GENERATE_SESSION_ID,
+                 SSL_R_UNSUPPORTED_SSL_VERSION);
+        return 0;
+    }
+
+    /*-
+     * If RFC5077 ticket, use empty session ID (as server).
+     * Note that:
+     * (a) ssl_get_prev_session() does lookahead into the
+     *     ClientHello extensions to find the session ticket.
+     *     When ssl_get_prev_session() fails, statem_srvr.c calls
+     *     ssl_get_new_session() in tls_process_client_hello().
+     *     At that point, it has not yet parsed the extensions,
+     *     however, because of the lookahead, it already knows
+     *     whether a ticket is expected or not.
+     *
+     * (b) statem_clnt.c calls ssl_get_new_session() before parsing
+     *     ServerHello extensions, and before recording the session
+     *     ID received from the server, so this block is a noop.
+     */
+    if (s->ext.ticket_expected) {
+        ss->session_id_length = 0;
+        return 1;
+    }
+
+    /* Choose which callback will set the session ID */
+    CRYPTO_THREAD_read_lock(s->lock);
+    CRYPTO_THREAD_read_lock(s->session_ctx->lock);
+    if (s->generate_session_id)
+        cb = s->generate_session_id;
+    else if (s->session_ctx->generate_session_id)
+        cb = s->session_ctx->generate_session_id;
+    CRYPTO_THREAD_unlock(s->session_ctx->lock);
+    CRYPTO_THREAD_unlock(s->lock);
+    /* Choose a session ID */
+    memset(ss->session_id, 0, ss->session_id_length);
+    tmp = (int)ss->session_id_length;
+    if (!cb(s, ss->session_id, &tmp)) {
+        /* The callback failed */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GENERATE_SESSION_ID,
+                 SSL_R_SSL_SESSION_ID_CALLBACK_FAILED);
+        return 0;
+    }
+    /*
+     * Don't allow the callback to set the session length to zero. nor
+     * set it higher than it was.
+     */
+    if (tmp == 0 || tmp > ss->session_id_length) {
+        /* The callback set an illegal length */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GENERATE_SESSION_ID,
+                 SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH);
+        return 0;
+    }
+    ss->session_id_length = tmp;
+    /* Finally, check for a conflict */
+    if (SSL_has_matching_session_id(s, ss->session_id,
+                                    (unsigned int)ss->session_id_length)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GENERATE_SESSION_ID,
+                 SSL_R_SSL_SESSION_ID_CONFLICT);
+        return 0;
+    }
+
+    return 1;
+}
+
+int ssl_get_new_session(SSL *s, int session)
+{
+    /* This gets used by clients and servers. */
+
+    SSL_SESSION *ss = NULL;
+
+    if ((ss = SSL_SESSION_new()) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GET_NEW_SESSION,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    /* If the context has a default timeout, use it */
+    if (s->session_ctx->session_timeout == 0)
+        ss->timeout = SSL_get_default_timeout(s);
+    else
+        ss->timeout = s->session_ctx->session_timeout;
+
+    SSL_SESSION_free(s->session);
+    s->session = NULL;
+
+    if (session) {
+        if (SSL_IS_TLS13(s)) {
+            /*
+             * We generate the session id while constructing the
+             * NewSessionTicket in TLSv1.3.
+             */
+            ss->session_id_length = 0;
+        } else if (!ssl_generate_session_id(s, ss)) {
+            /* SSLfatal() already called */
+            SSL_SESSION_free(ss);
+            return 0;
+        }
+
+    } else {
+        ss->session_id_length = 0;
+    }
+
+    if (s->sid_ctx_length > sizeof(ss->sid_ctx)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GET_NEW_SESSION,
+                 ERR_R_INTERNAL_ERROR);
+        SSL_SESSION_free(ss);
+        return 0;
+    }
+    memcpy(ss->sid_ctx, s->sid_ctx, s->sid_ctx_length);
+    ss->sid_ctx_length = s->sid_ctx_length;
+    s->session = ss;
+    ss->ssl_version = s->version;
+    ss->verify_result = X509_V_OK;
+
+    /* If client supports extended master secret set it in session */
+    if (s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS)
+        ss->flags |= SSL_SESS_FLAG_EXTMS;
+
+    return 1;
+}
+
+SSL_SESSION *lookup_sess_in_cache(SSL *s, const unsigned char *sess_id,
+                                  size_t sess_id_len)
+{
+    SSL_SESSION *ret = NULL;
+
+    if ((s->session_ctx->session_cache_mode
+         & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP) == 0) {
+        SSL_SESSION data;
+
+        data.ssl_version = s->version;
+        if (!ossl_assert(sess_id_len <= SSL_MAX_SSL_SESSION_ID_LENGTH))
+            return NULL;
+
+        memcpy(data.session_id, sess_id, sess_id_len);
+        data.session_id_length = sess_id_len;
+
+        CRYPTO_THREAD_read_lock(s->session_ctx->lock);
+        ret = lh_SSL_SESSION_retrieve(s->session_ctx->sessions, &data);
+        if (ret != NULL) {
+            /* don't allow other threads to steal it: */
+            SSL_SESSION_up_ref(ret);
+        }
+        CRYPTO_THREAD_unlock(s->session_ctx->lock);
+        if (ret == NULL)
+            tsan_counter(&s->session_ctx->stats.sess_miss);
+    }
+
+    if (ret == NULL && s->session_ctx->get_session_cb != NULL) {
+        int copy = 1;
+
+        ret = s->session_ctx->get_session_cb(s, sess_id, sess_id_len, &copy);
+
+        if (ret != NULL) {
+            tsan_counter(&s->session_ctx->stats.sess_cb_hit);
+
+            /*
+             * Increment reference count now if the session callback asks us
+             * to do so (note that if the session structures returned by the
+             * callback are shared between threads, it must handle the
+             * reference count itself [i.e. copy == 0], or things won't be
+             * thread-safe).
+             */
+            if (copy)
+                SSL_SESSION_up_ref(ret);
+
+            /*
+             * Add the externally cached session to the internal cache as
+             * well if and only if we are supposed to.
+             */
+            if ((s->session_ctx->session_cache_mode &
+                 SSL_SESS_CACHE_NO_INTERNAL_STORE) == 0) {
+                /*
+                 * Either return value of SSL_CTX_add_session should not
+                 * interrupt the session resumption process. The return
+                 * value is intentionally ignored.
+                 */
+                (void)SSL_CTX_add_session(s->session_ctx, ret);
+            }
+        }
+    }
+
+    return ret;
+}
+
+/*-
+ * ssl_get_prev attempts to find an SSL_SESSION to be used to resume this
+ * connection. It is only called by servers.
+ *
+ *   hello: The parsed ClientHello data
+ *
+ * Returns:
+ *   -1: fatal error
+ *    0: no session found
+ *    1: a session may have been found.
+ *
+ * Side effects:
+ *   - If a session is found then s->session is pointed at it (after freeing an
+ *     existing session if need be) and s->verify_result is set from the session.
+ *   - Both for new and resumed sessions, s->ext.ticket_expected is set to 1
+ *     if the server should issue a new session ticket (to 0 otherwise).
+ */
+int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello)
+{
+    /* This is used only by servers. */
+
+    SSL_SESSION *ret = NULL;
+    int fatal = 0;
+    int try_session_cache = 0;
+    SSL_TICKET_STATUS r;
+
+    if (SSL_IS_TLS13(s)) {
+        /*
+         * By default we will send a new ticket. This can be overridden in the
+         * ticket processing.
+         */
+        s->ext.ticket_expected = 1;
+        if (!tls_parse_extension(s, TLSEXT_IDX_psk_kex_modes,
+                                 SSL_EXT_CLIENT_HELLO, hello->pre_proc_exts,
+                                 NULL, 0)
+                || !tls_parse_extension(s, TLSEXT_IDX_psk, SSL_EXT_CLIENT_HELLO,
+                                        hello->pre_proc_exts, NULL, 0))
+            return -1;
+
+        ret = s->session;
+    } else {
+        /* sets s->ext.ticket_expected */
+        r = tls_get_ticket_from_client(s, hello, &ret);
+        switch (r) {
+        case SSL_TICKET_FATAL_ERR_MALLOC:
+        case SSL_TICKET_FATAL_ERR_OTHER:
+            fatal = 1;
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GET_PREV_SESSION,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        case SSL_TICKET_NONE:
+        case SSL_TICKET_EMPTY:
+            if (hello->session_id_len > 0) {
+                try_session_cache = 1;
+                ret = lookup_sess_in_cache(s, hello->session_id,
+                                           hello->session_id_len);
+            }
+            break;
+        case SSL_TICKET_NO_DECRYPT:
+        case SSL_TICKET_SUCCESS:
+        case SSL_TICKET_SUCCESS_RENEW:
+            break;
+        }
+    }
+
+    if (ret == NULL)
+        goto err;
+
+    /* Now ret is non-NULL and we own one of its reference counts. */
+
+    /* Check TLS version consistency */
+    if (ret->ssl_version != s->version)
+        goto err;
+
+    if (ret->sid_ctx_length != s->sid_ctx_length
+        || memcmp(ret->sid_ctx, s->sid_ctx, ret->sid_ctx_length)) {
+        /*
+         * We have the session requested by the client, but we don't want to
+         * use it in this context.
+         */
+        goto err;               /* treat like cache miss */
+    }
+
+    if ((s->verify_mode & SSL_VERIFY_PEER) && s->sid_ctx_length == 0) {
+        /*
+         * We can't be sure if this session is being used out of context,
+         * which is especially important for SSL_VERIFY_PEER. The application
+         * should have used SSL[_CTX]_set_session_id_context. For this error
+         * case, we generate an error instead of treating the event like a
+         * cache miss (otherwise it would be easy for applications to
+         * effectively disable the session cache by accident without anyone
+         * noticing).
+         */
+
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GET_PREV_SESSION,
+                 SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED);
+        fatal = 1;
+        goto err;
+    }
+
+    if (ret->timeout < (long)(time(NULL) - ret->time)) { /* timeout */
+        tsan_counter(&s->session_ctx->stats.sess_timeout);
+        if (try_session_cache) {
+            /* session was from the cache, so remove it */
+            SSL_CTX_remove_session(s->session_ctx, ret);
+        }
+        goto err;
+    }
+
+    /* Check extended master secret extension consistency */
+    if (ret->flags & SSL_SESS_FLAG_EXTMS) {
+        /* If old session includes extms, but new does not: abort handshake */
+        if (!(s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS)) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SSL_GET_PREV_SESSION,
+                     SSL_R_INCONSISTENT_EXTMS);
+            fatal = 1;
+            goto err;
+        }
+    } else if (s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) {
+        /* If new session includes extms, but old does not: do not resume */
+        goto err;
+    }
+
+    if (!SSL_IS_TLS13(s)) {
+        /* We already did this for TLS1.3 */
+        SSL_SESSION_free(s->session);
+        s->session = ret;
+    }
+
+    tsan_counter(&s->session_ctx->stats.sess_hit);
+    s->verify_result = s->session->verify_result;
+    return 1;
+
+ err:
+    if (ret != NULL) {
+        SSL_SESSION_free(ret);
+        /* In TLSv1.3 s->session was already set to ret, so we NULL it out */
+        if (SSL_IS_TLS13(s))
+            s->session = NULL;
+
+        if (!try_session_cache) {
+            /*
+             * The session was from a ticket, so we should issue a ticket for
+             * the new session
+             */
+            s->ext.ticket_expected = 1;
+        }
+    }
+    if (fatal)
+        return -1;
+
+    return 0;
+}
+
+int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c)
+{
+    int ret = 0;
+    SSL_SESSION *s;
+
+    /*
+     * add just 1 reference count for the SSL_CTX's session cache even though
+     * it has two ways of access: each session is in a doubly linked list and
+     * an lhash
+     */
+    SSL_SESSION_up_ref(c);
+    /*
+     * if session c is in already in cache, we take back the increment later
+     */
+
+    CRYPTO_THREAD_write_lock(ctx->lock);
+    s = lh_SSL_SESSION_insert(ctx->sessions, c);
+
+    /*
+     * s != NULL iff we already had a session with the given PID. In this
+     * case, s == c should hold (then we did not really modify
+     * ctx->sessions), or we're in trouble.
+     */
+    if (s != NULL && s != c) {
+        /* We *are* in trouble ... */
+        SSL_SESSION_list_remove(ctx, s);
+        SSL_SESSION_free(s);
+        /*
+         * ... so pretend the other session did not exist in cache (we cannot
+         * handle two SSL_SESSION structures with identical session ID in the
+         * same cache, which could happen e.g. when two threads concurrently
+         * obtain the same session from an external cache)
+         */
+        s = NULL;
+    } else if (s == NULL &&
+               lh_SSL_SESSION_retrieve(ctx->sessions, c) == NULL) {
+        /* s == NULL can also mean OOM error in lh_SSL_SESSION_insert ... */
+
+        /*
+         * ... so take back the extra reference and also don't add
+         * the session to the SSL_SESSION_list at this time
+         */
+        s = c;
+    }
+
+    /* Put at the head of the queue unless it is already in the cache */
+    if (s == NULL)
+        SSL_SESSION_list_add(ctx, c);
+
+    if (s != NULL) {
+        /*
+         * existing cache entry -- decrement previously incremented reference
+         * count because it already takes into account the cache
+         */
+
+        SSL_SESSION_free(s);    /* s == c */
+        ret = 0;
+    } else {
+        /*
+         * new cache entry -- remove old ones if cache has become too large
+         */
+
+        ret = 1;
+
+        if (SSL_CTX_sess_get_cache_size(ctx) > 0) {
+            while (SSL_CTX_sess_number(ctx) > SSL_CTX_sess_get_cache_size(ctx)) {
+                if (!remove_session_lock(ctx, ctx->session_cache_tail, 0))
+                    break;
+                else
+                    tsan_counter(&ctx->stats.sess_cache_full);
+            }
+        }
+    }
+    CRYPTO_THREAD_unlock(ctx->lock);
+    return ret;
+}
+
+int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *c)
+{
+    return remove_session_lock(ctx, c, 1);
+}
+
+static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck)
+{
+    SSL_SESSION *r;
+    int ret = 0;
+
+    if ((c != NULL) && (c->session_id_length != 0)) {
+        if (lck)
+            CRYPTO_THREAD_write_lock(ctx->lock);
+        if ((r = lh_SSL_SESSION_retrieve(ctx->sessions, c)) != NULL) {
+            ret = 1;
+            r = lh_SSL_SESSION_delete(ctx->sessions, r);
+            SSL_SESSION_list_remove(ctx, r);
+        }
+        c->not_resumable = 1;
+
+        if (lck)
+            CRYPTO_THREAD_unlock(ctx->lock);
+
+        if (ctx->remove_session_cb != NULL)
+            ctx->remove_session_cb(ctx, c);
+
+        if (ret)
+            SSL_SESSION_free(r);
+    } else
+        ret = 0;
+    return ret;
+}
+
+void SSL_SESSION_free(SSL_SESSION *ss)
+{
+    int i;
+
+    if (ss == NULL)
+        return;
+    CRYPTO_DOWN_REF(&ss->references, &i, ss->lock);
+    REF_PRINT_COUNT("SSL_SESSION", ss);
+    if (i > 0)
+        return;
+    REF_ASSERT_ISNT(i < 0);
+
+    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
+
+    OPENSSL_cleanse(ss->master_key, sizeof(ss->master_key));
+    OPENSSL_cleanse(ss->session_id, sizeof(ss->session_id));
+    X509_free(ss->peer);
+    sk_X509_pop_free(ss->peer_chain, X509_free);
+    OPENSSL_free(ss->ext.hostname);
+    OPENSSL_free(ss->ext.tick);
+#ifndef OPENSSL_NO_PSK
+    OPENSSL_free(ss->psk_identity_hint);
+    OPENSSL_free(ss->psk_identity);
+#endif
+#ifndef OPENSSL_NO_SRP
+    OPENSSL_free(ss->srp_username);
+#endif
+    OPENSSL_free(ss->ext.alpn_selected);
+    OPENSSL_free(ss->ticket_appdata);
+    CRYPTO_THREAD_lock_free(ss->lock);
+    OPENSSL_clear_free(ss, sizeof(*ss));
+}
+
+int SSL_SESSION_up_ref(SSL_SESSION *ss)
+{
+    int i;
+
+    if (CRYPTO_UP_REF(&ss->references, &i, ss->lock) <= 0)
+        return 0;
+
+    REF_PRINT_COUNT("SSL_SESSION", ss);
+    REF_ASSERT_ISNT(i < 2);
+    return ((i > 1) ? 1 : 0);
+}
+
+int SSL_set_session(SSL *s, SSL_SESSION *session)
+{
+    ssl_clear_bad_session(s);
+    if (s->ctx->method != s->method) {
+        if (!SSL_set_ssl_method(s, s->ctx->method))
+            return 0;
+    }
+
+    if (session != NULL) {
+        SSL_SESSION_up_ref(session);
+        s->verify_result = session->verify_result;
+    }
+    SSL_SESSION_free(s->session);
+    s->session = session;
+
+    return 1;
+}
+
+int SSL_SESSION_set1_id(SSL_SESSION *s, const unsigned char *sid,
+                        unsigned int sid_len)
+{
+    if (sid_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
+      SSLerr(SSL_F_SSL_SESSION_SET1_ID,
+             SSL_R_SSL_SESSION_ID_TOO_LONG);
+      return 0;
+    }
+    s->session_id_length = sid_len;
+    if (sid != s->session_id)
+        memcpy(s->session_id, sid, sid_len);
+    return 1;
+}
+
+long SSL_SESSION_set_timeout(SSL_SESSION *s, long t)
+{
+    if (s == NULL)
+        return 0;
+    s->timeout = t;
+    return 1;
+}
+
+long SSL_SESSION_get_timeout(const SSL_SESSION *s)
+{
+    if (s == NULL)
+        return 0;
+    return s->timeout;
+}
+
+long SSL_SESSION_get_time(const SSL_SESSION *s)
+{
+    if (s == NULL)
+        return 0;
+    return s->time;
+}
+
+long SSL_SESSION_set_time(SSL_SESSION *s, long t)
+{
+    if (s == NULL)
+        return 0;
+    s->time = t;
+    return t;
+}
+
+int SSL_SESSION_get_protocol_version(const SSL_SESSION *s)
+{
+    return s->ssl_version;
+}
+
+int SSL_SESSION_set_protocol_version(SSL_SESSION *s, int version)
+{
+    s->ssl_version = version;
+    return 1;
+}
+
+const SSL_CIPHER *SSL_SESSION_get0_cipher(const SSL_SESSION *s)
+{
+    return s->cipher;
+}
+
+int SSL_SESSION_set_cipher(SSL_SESSION *s, const SSL_CIPHER *cipher)
+{
+    s->cipher = cipher;
+    return 1;
+}
+
+const char *SSL_SESSION_get0_hostname(const SSL_SESSION *s)
+{
+    return s->ext.hostname;
+}
+
+int SSL_SESSION_set1_hostname(SSL_SESSION *s, const char *hostname)
+{
+    OPENSSL_free(s->ext.hostname);
+    if (hostname == NULL) {
+        s->ext.hostname = NULL;
+        return 1;
+    }
+    s->ext.hostname = OPENSSL_strdup(hostname);
+
+    return s->ext.hostname != NULL;
+}
+
+int SSL_SESSION_has_ticket(const SSL_SESSION *s)
+{
+    return (s->ext.ticklen > 0) ? 1 : 0;
+}
+
+unsigned long SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *s)
+{
+    return s->ext.tick_lifetime_hint;
+}
+
+void SSL_SESSION_get0_ticket(const SSL_SESSION *s, const unsigned char **tick,
+                             size_t *len)
+{
+    *len = s->ext.ticklen;
+    if (tick != NULL)
+        *tick = s->ext.tick;
+}
+
+uint32_t SSL_SESSION_get_max_early_data(const SSL_SESSION *s)
+{
+    return s->ext.max_early_data;
+}
+
+int SSL_SESSION_set_max_early_data(SSL_SESSION *s, uint32_t max_early_data)
+{
+    s->ext.max_early_data = max_early_data;
+
+    return 1;
+}
+
+void SSL_SESSION_get0_alpn_selected(const SSL_SESSION *s,
+                                    const unsigned char **alpn,
+                                    size_t *len)
+{
+    *alpn = s->ext.alpn_selected;
+    *len = s->ext.alpn_selected_len;
+}
+
+int SSL_SESSION_set1_alpn_selected(SSL_SESSION *s, const unsigned char *alpn,
+                                   size_t len)
+{
+    OPENSSL_free(s->ext.alpn_selected);
+    if (alpn == NULL || len == 0) {
+        s->ext.alpn_selected = NULL;
+        s->ext.alpn_selected_len = 0;
+        return 1;
+    }
+    s->ext.alpn_selected = OPENSSL_memdup(alpn, len);
+    if (s->ext.alpn_selected == NULL) {
+        s->ext.alpn_selected_len = 0;
+        return 0;
+    }
+    s->ext.alpn_selected_len = len;
+
+    return 1;
+}
+
+X509 *SSL_SESSION_get0_peer(SSL_SESSION *s)
+{
+    return s->peer;
+}
+
+int SSL_SESSION_set1_id_context(SSL_SESSION *s, const unsigned char *sid_ctx,
+                                unsigned int sid_ctx_len)
+{
+    if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) {
+        SSLerr(SSL_F_SSL_SESSION_SET1_ID_CONTEXT,
+               SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+        return 0;
+    }
+    s->sid_ctx_length = sid_ctx_len;
+    if (sid_ctx != s->sid_ctx)
+        memcpy(s->sid_ctx, sid_ctx, sid_ctx_len);
+
+    return 1;
+}
+
+int SSL_SESSION_is_resumable(const SSL_SESSION *s)
+{
+    /*
+     * In the case of EAP-FAST, we can have a pre-shared "ticket" without a
+     * session ID.
+     */
+    return !s->not_resumable
+           && (s->session_id_length > 0 || s->ext.ticklen > 0);
+}
+
+long SSL_CTX_set_timeout(SSL_CTX *s, long t)
+{
+    long l;
+    if (s == NULL)
+        return 0;
+    l = s->session_timeout;
+    s->session_timeout = t;
+    return l;
+}
+
+long SSL_CTX_get_timeout(const SSL_CTX *s)
+{
+    if (s == NULL)
+        return 0;
+    return s->session_timeout;
+}
+
+int SSL_set_session_secret_cb(SSL *s,
+                              tls_session_secret_cb_fn tls_session_secret_cb,
+                              void *arg)
+{
+    if (s == NULL)
+        return 0;
+    s->ext.session_secret_cb = tls_session_secret_cb;
+    s->ext.session_secret_cb_arg = arg;
+    return 1;
+}
+
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
+                                  void *arg)
+{
+    if (s == NULL)
+        return 0;
+    s->ext.session_ticket_cb = cb;
+    s->ext.session_ticket_cb_arg = arg;
+    return 1;
+}
+
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
+{
+    if (s->version >= TLS1_VERSION) {
+        OPENSSL_free(s->ext.session_ticket);
+        s->ext.session_ticket = NULL;
+        s->ext.session_ticket =
+            OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
+        if (s->ext.session_ticket == NULL) {
+            SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+
+        if (ext_data != NULL) {
+            s->ext.session_ticket->length = ext_len;
+            s->ext.session_ticket->data = s->ext.session_ticket + 1;
+            memcpy(s->ext.session_ticket->data, ext_data, ext_len);
+        } else {
+            s->ext.session_ticket->length = 0;
+            s->ext.session_ticket->data = NULL;
+        }
+
+        return 1;
+    }
+
+    return 0;
+}
+
+typedef struct timeout_param_st {
+    SSL_CTX *ctx;
+    long time;
+    LHASH_OF(SSL_SESSION) *cache;
+} TIMEOUT_PARAM;
+
+static void timeout_cb(SSL_SESSION *s, TIMEOUT_PARAM *p)
+{
+    if ((p->time == 0) || (p->time > (s->time + s->timeout))) { /* timeout */
+        /*
+         * The reason we don't call SSL_CTX_remove_session() is to save on
+         * locking overhead
+         */
+        (void)lh_SSL_SESSION_delete(p->cache, s);
+        SSL_SESSION_list_remove(p->ctx, s);
+        s->not_resumable = 1;
+        if (p->ctx->remove_session_cb != NULL)
+            p->ctx->remove_session_cb(p->ctx, s);
+        SSL_SESSION_free(s);
+    }
+}
+
+IMPLEMENT_LHASH_DOALL_ARG(SSL_SESSION, TIMEOUT_PARAM);
+
+void SSL_CTX_flush_sessions(SSL_CTX *s, long t)
+{
+    unsigned long i;
+    TIMEOUT_PARAM tp;
+
+    tp.ctx = s;
+    tp.cache = s->sessions;
+    if (tp.cache == NULL)
+        return;
+    tp.time = t;
+    CRYPTO_THREAD_write_lock(s->lock);
+    i = lh_SSL_SESSION_get_down_load(s->sessions);
+    lh_SSL_SESSION_set_down_load(s->sessions, 0);
+    lh_SSL_SESSION_doall_TIMEOUT_PARAM(tp.cache, timeout_cb, &tp);
+    lh_SSL_SESSION_set_down_load(s->sessions, i);
+    CRYPTO_THREAD_unlock(s->lock);
+}
+
+int ssl_clear_bad_session(SSL *s)
+{
+    if ((s->session != NULL) &&
+        !(s->shutdown & SSL_SENT_SHUTDOWN) &&
+        !(SSL_in_init(s) || SSL_in_before(s))) {
+        SSL_CTX_remove_session(s->session_ctx, s->session);
+        return 1;
+    } else
+        return 0;
+}
+
+/* locked by SSL_CTX in the calling function */
+static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s)
+{
+    if ((s->next == NULL) || (s->prev == NULL))
+        return;
+
+    if (s->next == (SSL_SESSION *)&(ctx->session_cache_tail)) {
+        /* last element in list */
+        if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head)) {
+            /* only one element in list */
+            ctx->session_cache_head = NULL;
+            ctx->session_cache_tail = NULL;
+        } else {
+            ctx->session_cache_tail = s->prev;
+            s->prev->next = (SSL_SESSION *)&(ctx->session_cache_tail);
+        }
+    } else {
+        if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head)) {
+            /* first element in list */
+            ctx->session_cache_head = s->next;
+            s->next->prev = (SSL_SESSION *)&(ctx->session_cache_head);
+        } else {
+            /* middle of list */
+            s->next->prev = s->prev;
+            s->prev->next = s->next;
+        }
+    }
+    s->prev = s->next = NULL;
+}
+
+static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s)
+{
+    if ((s->next != NULL) && (s->prev != NULL))
+        SSL_SESSION_list_remove(ctx, s);
+
+    if (ctx->session_cache_head == NULL) {
+        ctx->session_cache_head = s;
+        ctx->session_cache_tail = s;
+        s->prev = (SSL_SESSION *)&(ctx->session_cache_head);
+        s->next = (SSL_SESSION *)&(ctx->session_cache_tail);
+    } else {
+        s->next = ctx->session_cache_head;
+        s->next->prev = s;
+        s->prev = (SSL_SESSION *)&(ctx->session_cache_head);
+        ctx->session_cache_head = s;
+    }
+}
+
+void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx,
+                             int (*cb) (struct ssl_st *ssl, SSL_SESSION *sess))
+{
+    ctx->new_session_cb = cb;
+}
+
+int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx)) (SSL *ssl, SSL_SESSION *sess) {
+    return ctx->new_session_cb;
+}
+
+void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx,
+                                void (*cb) (SSL_CTX *ctx, SSL_SESSION *sess))
+{
+    ctx->remove_session_cb = cb;
+}
+
+void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx)) (SSL_CTX *ctx,
+                                                  SSL_SESSION *sess) {
+    return ctx->remove_session_cb;
+}
+
+void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx,
+                             SSL_SESSION *(*cb) (struct ssl_st *ssl,
+                                                 const unsigned char *data,
+                                                 int len, int *copy))
+{
+    ctx->get_session_cb = cb;
+}
+
+SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx)) (SSL *ssl,
+                                                       const unsigned char
+                                                       *data, int len,
+                                                       int *copy) {
+    return ctx->get_session_cb;
+}
+
+void SSL_CTX_set_info_callback(SSL_CTX *ctx,
+                               void (*cb) (const SSL *ssl, int type, int val))
+{
+    ctx->info_callback = cb;
+}
+
+void (*SSL_CTX_get_info_callback(SSL_CTX *ctx)) (const SSL *ssl, int type,
+                                                 int val) {
+    return ctx->info_callback;
+}
+
+void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx,
+                                int (*cb) (SSL *ssl, X509 **x509,
+                                           EVP_PKEY **pkey))
+{
+    ctx->client_cert_cb = cb;
+}
+
+int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx)) (SSL *ssl, X509 **x509,
+                                                 EVP_PKEY **pkey) {
+    return ctx->client_cert_cb;
+}
+
+#ifndef OPENSSL_NO_ENGINE
+int SSL_CTX_set_client_cert_engine(SSL_CTX *ctx, ENGINE *e)
+{
+    if (!ENGINE_init(e)) {
+        SSLerr(SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE, ERR_R_ENGINE_LIB);
+        return 0;
+    }
+    if (!ENGINE_get_ssl_client_cert_function(e)) {
+        SSLerr(SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE,
+               SSL_R_NO_CLIENT_CERT_METHOD);
+        ENGINE_finish(e);
+        return 0;
+    }
+    ctx->client_cert_engine = e;
+    return 1;
+}
+#endif
+
+void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx,
+                                    int (*cb) (SSL *ssl,
+                                               unsigned char *cookie,
+                                               unsigned int *cookie_len))
+{
+    ctx->app_gen_cookie_cb = cb;
+}
+
+void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx,
+                                  int (*cb) (SSL *ssl,
+                                             const unsigned char *cookie,
+                                             unsigned int cookie_len))
+{
+    ctx->app_verify_cookie_cb = cb;
+}
+
+int SSL_SESSION_set1_ticket_appdata(SSL_SESSION *ss, const void *data, size_t len)
+{
+    OPENSSL_free(ss->ticket_appdata);
+    ss->ticket_appdata_len = 0;
+    if (data == NULL || len == 0) {
+        ss->ticket_appdata = NULL;
+        return 1;
+    }
+    ss->ticket_appdata = OPENSSL_memdup(data, len);
+    if (ss->ticket_appdata != NULL) {
+        ss->ticket_appdata_len = len;
+        return 1;
+    }
+    return 0;
+}
+
+int SSL_SESSION_get0_ticket_appdata(SSL_SESSION *ss, void **data, size_t *len)
+{
+    *data = ss->ticket_appdata;
+    *len = ss->ticket_appdata_len;
+    return 1;
+}
+
+void SSL_CTX_set_stateless_cookie_generate_cb(
+    SSL_CTX *ctx,
+    int (*cb) (SSL *ssl,
+               unsigned char *cookie,
+               size_t *cookie_len))
+{
+    ctx->gen_stateless_cookie_cb = cb;
+}
+
+void SSL_CTX_set_stateless_cookie_verify_cb(
+    SSL_CTX *ctx,
+    int (*cb) (SSL *ssl,
+               const unsigned char *cookie,
+               size_t cookie_len))
+{
+    ctx->verify_stateless_cookie_cb = cb;
+}
+
+IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION)
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_stat.c b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_stat.c
new file mode 100644
index 0000000..ca51c03
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_stat.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include "ssl_local.h"
+
+const char *SSL_state_string_long(const SSL *s)
+{
+    if (ossl_statem_in_error(s))
+        return "error";
+
+    switch (SSL_get_state(s)) {
+    case TLS_ST_CR_CERT_STATUS:
+        return "SSLv3/TLS read certificate status";
+    case TLS_ST_CW_NEXT_PROTO:
+        return "SSLv3/TLS write next proto";
+    case TLS_ST_SR_NEXT_PROTO:
+        return "SSLv3/TLS read next proto";
+    case TLS_ST_SW_CERT_STATUS:
+        return "SSLv3/TLS write certificate status";
+    case TLS_ST_BEFORE:
+        return "before SSL initialization";
+    case TLS_ST_OK:
+        return "SSL negotiation finished successfully";
+    case TLS_ST_CW_CLNT_HELLO:
+        return "SSLv3/TLS write client hello";
+    case TLS_ST_CR_SRVR_HELLO:
+        return "SSLv3/TLS read server hello";
+    case TLS_ST_CR_CERT:
+        return "SSLv3/TLS read server certificate";
+    case TLS_ST_CR_KEY_EXCH:
+        return "SSLv3/TLS read server key exchange";
+    case TLS_ST_CR_CERT_REQ:
+        return "SSLv3/TLS read server certificate request";
+    case TLS_ST_CR_SESSION_TICKET:
+        return "SSLv3/TLS read server session ticket";
+    case TLS_ST_CR_SRVR_DONE:
+        return "SSLv3/TLS read server done";
+    case TLS_ST_CW_CERT:
+        return "SSLv3/TLS write client certificate";
+    case TLS_ST_CW_KEY_EXCH:
+        return "SSLv3/TLS write client key exchange";
+    case TLS_ST_CW_CERT_VRFY:
+        return "SSLv3/TLS write certificate verify";
+    case TLS_ST_CW_CHANGE:
+    case TLS_ST_SW_CHANGE:
+        return "SSLv3/TLS write change cipher spec";
+    case TLS_ST_CW_FINISHED:
+    case TLS_ST_SW_FINISHED:
+        return "SSLv3/TLS write finished";
+    case TLS_ST_CR_CHANGE:
+    case TLS_ST_SR_CHANGE:
+        return "SSLv3/TLS read change cipher spec";
+    case TLS_ST_CR_FINISHED:
+    case TLS_ST_SR_FINISHED:
+        return "SSLv3/TLS read finished";
+    case TLS_ST_SR_CLNT_HELLO:
+        return "SSLv3/TLS read client hello";
+    case TLS_ST_SW_HELLO_REQ:
+        return "SSLv3/TLS write hello request";
+    case TLS_ST_SW_SRVR_HELLO:
+        return "SSLv3/TLS write server hello";
+    case TLS_ST_SW_CERT:
+        return "SSLv3/TLS write certificate";
+    case TLS_ST_SW_KEY_EXCH:
+        return "SSLv3/TLS write key exchange";
+    case TLS_ST_SW_CERT_REQ:
+        return "SSLv3/TLS write certificate request";
+    case TLS_ST_SW_SESSION_TICKET:
+        return "SSLv3/TLS write session ticket";
+    case TLS_ST_SW_SRVR_DONE:
+        return "SSLv3/TLS write server done";
+    case TLS_ST_SR_CERT:
+        return "SSLv3/TLS read client certificate";
+    case TLS_ST_SR_KEY_EXCH:
+        return "SSLv3/TLS read client key exchange";
+    case TLS_ST_SR_CERT_VRFY:
+        return "SSLv3/TLS read certificate verify";
+    case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+        return "DTLS1 read hello verify request";
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        return "DTLS1 write hello verify request";
+    case TLS_ST_SW_ENCRYPTED_EXTENSIONS:
+        return "TLSv1.3 write encrypted extensions";
+    case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
+        return "TLSv1.3 read encrypted extensions";
+    case TLS_ST_CR_CERT_VRFY:
+        return "TLSv1.3 read server certificate verify";
+    case TLS_ST_SW_CERT_VRFY:
+        return "TLSv1.3 write server certificate verify";
+    case TLS_ST_CR_HELLO_REQ:
+        return "SSLv3/TLS read hello request";
+    case TLS_ST_SW_KEY_UPDATE:
+        return "TLSv1.3 write server key update";
+    case TLS_ST_CW_KEY_UPDATE:
+        return "TLSv1.3 write client key update";
+    case TLS_ST_SR_KEY_UPDATE:
+        return "TLSv1.3 read client key update";
+    case TLS_ST_CR_KEY_UPDATE:
+        return "TLSv1.3 read server key update";
+    case TLS_ST_EARLY_DATA:
+        return "TLSv1.3 early data";
+    case TLS_ST_PENDING_EARLY_DATA_END:
+        return "TLSv1.3 pending early data end";
+    case TLS_ST_CW_END_OF_EARLY_DATA:
+        return "TLSv1.3 write end of early data";
+    case TLS_ST_SR_END_OF_EARLY_DATA:
+        return "TLSv1.3 read end of early data";
+    default:
+        return "unknown state";
+    }
+}
+
+const char *SSL_state_string(const SSL *s)
+{
+    if (ossl_statem_in_error(s))
+        return "SSLERR";
+
+    switch (SSL_get_state(s)) {
+    case TLS_ST_SR_NEXT_PROTO:
+        return "TRNP";
+    case TLS_ST_SW_SESSION_TICKET:
+        return "TWST";
+    case TLS_ST_SW_CERT_STATUS:
+        return "TWCS";
+    case TLS_ST_CR_CERT_STATUS:
+        return "TRCS";
+    case TLS_ST_CR_SESSION_TICKET:
+        return "TRST";
+    case TLS_ST_CW_NEXT_PROTO:
+        return "TWNP";
+    case TLS_ST_BEFORE:
+        return "PINIT ";
+    case TLS_ST_OK:
+        return "SSLOK ";
+    case TLS_ST_CW_CLNT_HELLO:
+        return "TWCH";
+    case TLS_ST_CR_SRVR_HELLO:
+        return "TRSH";
+    case TLS_ST_CR_CERT:
+        return "TRSC";
+    case TLS_ST_CR_KEY_EXCH:
+        return "TRSKE";
+    case TLS_ST_CR_CERT_REQ:
+        return "TRCR";
+    case TLS_ST_CR_SRVR_DONE:
+        return "TRSD";
+    case TLS_ST_CW_CERT:
+        return "TWCC";
+    case TLS_ST_CW_KEY_EXCH:
+        return "TWCKE";
+    case TLS_ST_CW_CERT_VRFY:
+        return "TWCV";
+    case TLS_ST_SW_CHANGE:
+    case TLS_ST_CW_CHANGE:
+        return "TWCCS";
+    case TLS_ST_SW_FINISHED:
+    case TLS_ST_CW_FINISHED:
+        return "TWFIN";
+    case TLS_ST_SR_CHANGE:
+    case TLS_ST_CR_CHANGE:
+        return "TRCCS";
+    case TLS_ST_SR_FINISHED:
+    case TLS_ST_CR_FINISHED:
+        return "TRFIN";
+    case TLS_ST_SW_HELLO_REQ:
+        return "TWHR";
+    case TLS_ST_SR_CLNT_HELLO:
+        return "TRCH";
+    case TLS_ST_SW_SRVR_HELLO:
+        return "TWSH";
+    case TLS_ST_SW_CERT:
+        return "TWSC";
+    case TLS_ST_SW_KEY_EXCH:
+        return "TWSKE";
+    case TLS_ST_SW_CERT_REQ:
+        return "TWCR";
+    case TLS_ST_SW_SRVR_DONE:
+        return "TWSD";
+    case TLS_ST_SR_CERT:
+        return "TRCC";
+    case TLS_ST_SR_KEY_EXCH:
+        return "TRCKE";
+    case TLS_ST_SR_CERT_VRFY:
+        return "TRCV";
+    case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+        return "DRCHV";
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        return "DWCHV";
+    case TLS_ST_SW_ENCRYPTED_EXTENSIONS:
+        return "TWEE";
+    case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
+        return "TREE";
+    case TLS_ST_CR_CERT_VRFY:
+        return "TRSCV";
+    case TLS_ST_SW_CERT_VRFY:
+        return "TRSCV";
+    case TLS_ST_CR_HELLO_REQ:
+        return "TRHR";
+    case TLS_ST_SW_KEY_UPDATE:
+        return "TWSKU";
+    case TLS_ST_CW_KEY_UPDATE:
+        return "TWCKU";
+    case TLS_ST_SR_KEY_UPDATE:
+        return "TRCKU";
+    case TLS_ST_CR_KEY_UPDATE:
+        return "TRSKU";
+    case TLS_ST_EARLY_DATA:
+        return "TED";
+    case TLS_ST_PENDING_EARLY_DATA_END:
+        return "TPEDE";
+    case TLS_ST_CW_END_OF_EARLY_DATA:
+        return "TWEOED";
+    case TLS_ST_SR_END_OF_EARLY_DATA:
+        return "TWEOED";
+    default:
+        return "UNKWN ";
+    }
+}
+
+const char *SSL_alert_type_string_long(int value)
+{
+    switch (value >> 8) {
+    case SSL3_AL_WARNING:
+        return "warning";
+    case SSL3_AL_FATAL:
+        return "fatal";
+    default:
+        return "unknown";
+    }
+}
+
+const char *SSL_alert_type_string(int value)
+{
+    switch (value >> 8) {
+    case SSL3_AL_WARNING:
+        return "W";
+    case SSL3_AL_FATAL:
+        return "F";
+    default:
+        return "U";
+    }
+}
+
+const char *SSL_alert_desc_string(int value)
+{
+    switch (value & 0xff) {
+    case SSL3_AD_CLOSE_NOTIFY:
+        return "CN";
+    case SSL3_AD_UNEXPECTED_MESSAGE:
+        return "UM";
+    case SSL3_AD_BAD_RECORD_MAC:
+        return "BM";
+    case SSL3_AD_DECOMPRESSION_FAILURE:
+        return "DF";
+    case SSL3_AD_HANDSHAKE_FAILURE:
+        return "HF";
+    case SSL3_AD_NO_CERTIFICATE:
+        return "NC";
+    case SSL3_AD_BAD_CERTIFICATE:
+        return "BC";
+    case SSL3_AD_UNSUPPORTED_CERTIFICATE:
+        return "UC";
+    case SSL3_AD_CERTIFICATE_REVOKED:
+        return "CR";
+    case SSL3_AD_CERTIFICATE_EXPIRED:
+        return "CE";
+    case SSL3_AD_CERTIFICATE_UNKNOWN:
+        return "CU";
+    case SSL3_AD_ILLEGAL_PARAMETER:
+        return "IP";
+    case TLS1_AD_DECRYPTION_FAILED:
+        return "DC";
+    case TLS1_AD_RECORD_OVERFLOW:
+        return "RO";
+    case TLS1_AD_UNKNOWN_CA:
+        return "CA";
+    case TLS1_AD_ACCESS_DENIED:
+        return "AD";
+    case TLS1_AD_DECODE_ERROR:
+        return "DE";
+    case TLS1_AD_DECRYPT_ERROR:
+        return "CY";
+    case TLS1_AD_EXPORT_RESTRICTION:
+        return "ER";
+    case TLS1_AD_PROTOCOL_VERSION:
+        return "PV";
+    case TLS1_AD_INSUFFICIENT_SECURITY:
+        return "IS";
+    case TLS1_AD_INTERNAL_ERROR:
+        return "IE";
+    case TLS1_AD_USER_CANCELLED:
+        return "US";
+    case TLS1_AD_NO_RENEGOTIATION:
+        return "NR";
+    case TLS1_AD_UNSUPPORTED_EXTENSION:
+        return "UE";
+    case TLS1_AD_CERTIFICATE_UNOBTAINABLE:
+        return "CO";
+    case TLS1_AD_UNRECOGNIZED_NAME:
+        return "UN";
+    case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE:
+        return "BR";
+    case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE:
+        return "BH";
+    case TLS1_AD_UNKNOWN_PSK_IDENTITY:
+        return "UP";
+    default:
+        return "UK";
+    }
+}
+
+const char *SSL_alert_desc_string_long(int value)
+{
+    switch (value & 0xff) {
+    case SSL3_AD_CLOSE_NOTIFY:
+        return "close notify";
+    case SSL3_AD_UNEXPECTED_MESSAGE:
+        return "unexpected_message";
+    case SSL3_AD_BAD_RECORD_MAC:
+        return "bad record mac";
+    case SSL3_AD_DECOMPRESSION_FAILURE:
+        return "decompression failure";
+    case SSL3_AD_HANDSHAKE_FAILURE:
+        return "handshake failure";
+    case SSL3_AD_NO_CERTIFICATE:
+        return "no certificate";
+    case SSL3_AD_BAD_CERTIFICATE:
+        return "bad certificate";
+    case SSL3_AD_UNSUPPORTED_CERTIFICATE:
+        return "unsupported certificate";
+    case SSL3_AD_CERTIFICATE_REVOKED:
+        return "certificate revoked";
+    case SSL3_AD_CERTIFICATE_EXPIRED:
+        return "certificate expired";
+    case SSL3_AD_CERTIFICATE_UNKNOWN:
+        return "certificate unknown";
+    case SSL3_AD_ILLEGAL_PARAMETER:
+        return "illegal parameter";
+    case TLS1_AD_DECRYPTION_FAILED:
+        return "decryption failed";
+    case TLS1_AD_RECORD_OVERFLOW:
+        return "record overflow";
+    case TLS1_AD_UNKNOWN_CA:
+        return "unknown CA";
+    case TLS1_AD_ACCESS_DENIED:
+        return "access denied";
+    case TLS1_AD_DECODE_ERROR:
+        return "decode error";
+    case TLS1_AD_DECRYPT_ERROR:
+        return "decrypt error";
+    case TLS1_AD_EXPORT_RESTRICTION:
+        return "export restriction";
+    case TLS1_AD_PROTOCOL_VERSION:
+        return "protocol version";
+    case TLS1_AD_INSUFFICIENT_SECURITY:
+        return "insufficient security";
+    case TLS1_AD_INTERNAL_ERROR:
+        return "internal error";
+    case TLS1_AD_USER_CANCELLED:
+        return "user canceled";
+    case TLS1_AD_NO_RENEGOTIATION:
+        return "no renegotiation";
+    case TLS1_AD_UNSUPPORTED_EXTENSION:
+        return "unsupported extension";
+    case TLS1_AD_CERTIFICATE_UNOBTAINABLE:
+        return "certificate unobtainable";
+    case TLS1_AD_UNRECOGNIZED_NAME:
+        return "unrecognized name";
+    case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE:
+        return "bad certificate status response";
+    case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE:
+        return "bad certificate hash value";
+    case TLS1_AD_UNKNOWN_PSK_IDENTITY:
+        return "unknown PSK identity";
+    case TLS1_AD_NO_APPLICATION_PROTOCOL:
+        return "no application protocol";
+    default:
+        return "unknown";
+    }
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_txt.c b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_txt.c
new file mode 100644
index 0000000..759e187
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_txt.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <openssl/buffer.h>
+#include "ssl_local.h"
+
+#ifndef OPENSSL_NO_STDIO
+int SSL_SESSION_print_fp(FILE *fp, const SSL_SESSION *x)
+{
+    BIO *b;
+    int ret;
+
+    if ((b = BIO_new(BIO_s_file())) == NULL) {
+        SSLerr(SSL_F_SSL_SESSION_PRINT_FP, ERR_R_BUF_LIB);
+        return 0;
+    }
+    BIO_set_fp(b, fp, BIO_NOCLOSE);
+    ret = SSL_SESSION_print(b, x);
+    BIO_free(b);
+    return ret;
+}
+#endif
+
+int SSL_SESSION_print(BIO *bp, const SSL_SESSION *x)
+{
+    size_t i;
+    const char *s;
+    int istls13;
+
+    if (x == NULL)
+        goto err;
+    istls13 = (x->ssl_version == TLS1_3_VERSION);
+    if (BIO_puts(bp, "SSL-Session:\n") <= 0)
+        goto err;
+    s = ssl_protocol_to_string(x->ssl_version);
+    if (BIO_printf(bp, "    Protocol  : %s\n", s) <= 0)
+        goto err;
+
+    if (x->cipher == NULL) {
+        if (((x->cipher_id) & 0xff000000) == 0x02000000) {
+            if (BIO_printf(bp, "    Cipher    : %06lX\n",
+                           x->cipher_id & 0xffffff) <= 0)
+                goto err;
+        } else {
+            if (BIO_printf(bp, "    Cipher    : %04lX\n",
+                           x->cipher_id & 0xffff) <= 0)
+                goto err;
+        }
+    } else {
+        if (BIO_printf(bp, "    Cipher    : %s\n",
+                       ((x->cipher->name == NULL) ? "unknown"
+                                                  : x->cipher->name)) <= 0)
+            goto err;
+    }
+    if (BIO_puts(bp, "    Session-ID: ") <= 0)
+        goto err;
+    for (i = 0; i < x->session_id_length; i++) {
+        if (BIO_printf(bp, "%02X", x->session_id[i]) <= 0)
+            goto err;
+    }
+    if (BIO_puts(bp, "\n    Session-ID-ctx: ") <= 0)
+        goto err;
+    for (i = 0; i < x->sid_ctx_length; i++) {
+        if (BIO_printf(bp, "%02X", x->sid_ctx[i]) <= 0)
+            goto err;
+    }
+    if (istls13) {
+        if (BIO_puts(bp, "\n    Resumption PSK: ") <= 0)
+            goto err;
+    } else if (BIO_puts(bp, "\n    Master-Key: ") <= 0)
+        goto err;
+    for (i = 0; i < x->master_key_length; i++) {
+        if (BIO_printf(bp, "%02X", x->master_key[i]) <= 0)
+            goto err;
+    }
+#ifndef OPENSSL_NO_PSK
+    if (BIO_puts(bp, "\n    PSK identity: ") <= 0)
+        goto err;
+    if (BIO_printf(bp, "%s", x->psk_identity ? x->psk_identity : "None") <= 0)
+        goto err;
+    if (BIO_puts(bp, "\n    PSK identity hint: ") <= 0)
+        goto err;
+    if (BIO_printf
+        (bp, "%s", x->psk_identity_hint ? x->psk_identity_hint : "None") <= 0)
+        goto err;
+#endif
+#ifndef OPENSSL_NO_SRP
+    if (BIO_puts(bp, "\n    SRP username: ") <= 0)
+        goto err;
+    if (BIO_printf(bp, "%s", x->srp_username ? x->srp_username : "None") <= 0)
+        goto err;
+#endif
+    if (x->ext.tick_lifetime_hint) {
+        if (BIO_printf(bp,
+                       "\n    TLS session ticket lifetime hint: %ld (seconds)",
+                       x->ext.tick_lifetime_hint) <= 0)
+            goto err;
+    }
+    if (x->ext.tick) {
+        if (BIO_puts(bp, "\n    TLS session ticket:\n") <= 0)
+            goto err;
+        /* TODO(size_t): Convert this call */
+        if (BIO_dump_indent
+            (bp, (const char *)x->ext.tick, (int)x->ext.ticklen, 4)
+            <= 0)
+            goto err;
+    }
+#ifndef OPENSSL_NO_COMP
+    if (x->compress_meth != 0) {
+        SSL_COMP *comp = NULL;
+
+        if (!ssl_cipher_get_evp(x, NULL, NULL, NULL, NULL, &comp, 0))
+            goto err;
+        if (comp == NULL) {
+            if (BIO_printf(bp, "\n    Compression: %d", x->compress_meth) <= 0)
+                goto err;
+        } else {
+            if (BIO_printf(bp, "\n    Compression: %d (%s)", comp->id,
+                           comp->name) <= 0)
+                goto err;
+        }
+    }
+#endif
+    if (x->time != 0L) {
+        if (BIO_printf(bp, "\n    Start Time: %lld", (long long)x->time) <= 0)
+            goto err;
+    }
+    if (x->timeout != 0L) {
+        if (BIO_printf(bp, "\n    Timeout   : %lld (sec)", (long long)x->timeout) <= 0)
+            goto err;
+    }
+    if (BIO_puts(bp, "\n") <= 0)
+        goto err;
+
+    if (BIO_puts(bp, "    Verify return code: ") <= 0)
+        goto err;
+    if (BIO_printf(bp, "%ld (%s)\n", x->verify_result,
+                   X509_verify_cert_error_string(x->verify_result)) <= 0)
+        goto err;
+
+    if (BIO_printf(bp, "    Extended master secret: %s\n",
+                   x->flags & SSL_SESS_FLAG_EXTMS ? "yes" : "no") <= 0)
+        goto err;
+
+    if (istls13) {
+        if (BIO_printf(bp, "    Max Early Data: %u\n",
+                       x->ext.max_early_data) <= 0)
+            goto err;
+    }
+
+    return 1;
+ err:
+    return 0;
+}
+
+/*
+ * print session id and master key in NSS keylog format (RSA
+ * Session-ID:<session id> Master-Key:<master key>)
+ */
+int SSL_SESSION_print_keylog(BIO *bp, const SSL_SESSION *x)
+{
+    size_t i;
+
+    if (x == NULL)
+        goto err;
+    if (x->session_id_length == 0 || x->master_key_length == 0)
+        goto err;
+
+    /*
+     * the RSA prefix is required by the format's definition although there's
+     * nothing RSA-specific in the output, therefore, we don't have to check if
+     * the cipher suite is based on RSA
+     */
+    if (BIO_puts(bp, "RSA ") <= 0)
+        goto err;
+
+    if (BIO_puts(bp, "Session-ID:") <= 0)
+        goto err;
+    for (i = 0; i < x->session_id_length; i++) {
+        if (BIO_printf(bp, "%02X", x->session_id[i]) <= 0)
+            goto err;
+    }
+    if (BIO_puts(bp, " Master-Key:") <= 0)
+        goto err;
+    for (i = 0; i < x->master_key_length; i++) {
+        if (BIO_printf(bp, "%02X", x->master_key[i]) <= 0)
+            goto err;
+    }
+    if (BIO_puts(bp, "\n") <= 0)
+        goto err;
+
+    return 1;
+ err:
+    return 0;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_utst.c b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_utst.c
new file mode 100644
index 0000000..487f56e
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/ssl_utst.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "ssl_local.h"
+
+#ifndef OPENSSL_NO_UNIT_TEST
+
+static const struct openssl_ssl_test_functions ssl_test_functions = {
+    ssl_init_wbio_buffer,
+    ssl3_setup_buffers,
+};
+
+const struct openssl_ssl_test_functions *SSL_test_functions(void)
+{
+    return &ssl_test_functions;
+}
+
+#endif
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/statem/README b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/README
new file mode 100644
index 0000000..bafe330
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/README
@@ -0,0 +1,63 @@
+State Machine Design
+====================
+
+This file provides some guidance on the thinking behind the design of the
+state machine code to aid future maintenance.
+
+The state machine code replaces an older state machine present in OpenSSL
+versions 1.0.2 and below. The new state machine has the following objectives:
+    - Remove duplication of state code between client and server
+    - Remove duplication of state code between TLS and DTLS
+    - Simplify transitions and bring the logic together in a single location
+      so that it is easier to validate
+    - Remove duplication of code between each of the message handling functions
+    - Receive a message first and then work out whether that is a valid
+      transition - not the other way around (the other way causes lots of issues
+      where we are expecting one type of message next but actually get something
+      else)
+    - Separate message flow state from handshake state (in order to better
+      understand each)
+      - message flow state = when to flush buffers; handling restarts in the
+        event of NBIO events; handling the common flow of steps for reading a
+        message and the common flow of steps for writing a message etc
+      - handshake state = what handshake message are we working on now
+    - Control complexity: only the state machine can change state: keep all
+      the state changes local to the state machine component
+
+The message flow state machine is divided into a reading sub-state machine and a
+writing sub-state machine. See the source comments in statem.c for a more
+detailed description of the various states and transitions possible.
+
+Conceptually the state machine component is designed as follows:
+
+                        libssl
+                           |
+---------------------------|-----statem.h--------------------------------------
+                           |
+                    _______V____________________
+                   |                            |
+                   |    statem.c                |
+                   |                            |
+                   |    Core state machine code |
+                   |____________________________|
+        statem_local.h     ^          ^
+                 _________|          |_______
+                |                            |
+   _____________|____________   _____________|____________
+  |                          | |                          |
+  | statem_clnt.c            | | statem_srvr.c            |
+  |                          | |                          |
+  | TLS/DTLS client specific | | TLS/DTLS server specific |
+  | state machine code       | | state machine code       |
+  |__________________________| |__________________________|
+               |        |_______________|__       |
+               |        ________________|  |      |
+               |       |                   |      |
+   ____________V_______V________   ________V______V_______________
+  |                             | |                               |
+  | statem_lib.c                | | statem_dtls.c                 |
+  |                             | |                               |
+  | Non core functions common   | | Non core functions common to  |
+  | to both servers and clients | | both DTLS servers and clients |
+  |_____________________________| |_______________________________|
+
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/statem/extensions.c b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/extensions.c
new file mode 100644
index 0000000..0f39275
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/extensions.c
@@ -0,0 +1,1747 @@
+/*
+ * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include "internal/nelem.h"
+#include "internal/cryptlib.h"
+#include "../ssl_local.h"
+#include "statem_local.h"
+#include "internal/cryptlib.h"
+
+static int final_renegotiate(SSL *s, unsigned int context, int sent);
+static int init_server_name(SSL *s, unsigned int context);
+static int final_server_name(SSL *s, unsigned int context, int sent);
+#ifndef OPENSSL_NO_EC
+static int init_ec_point_formats(SSL *s, unsigned int context);
+static int final_ec_pt_formats(SSL *s, unsigned int context, int sent);
+#endif
+static int init_session_ticket(SSL *s, unsigned int context);
+#ifndef OPENSSL_NO_OCSP
+static int init_status_request(SSL *s, unsigned int context);
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+static int init_npn(SSL *s, unsigned int context);
+#endif
+static int init_alpn(SSL *s, unsigned int context);
+static int final_alpn(SSL *s, unsigned int context, int sent);
+static int init_sig_algs_cert(SSL *s, unsigned int context);
+static int init_sig_algs(SSL *s, unsigned int context);
+static int init_certificate_authorities(SSL *s, unsigned int context);
+static EXT_RETURN tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
+                                                        unsigned int context,
+                                                        X509 *x,
+                                                        size_t chainidx);
+static int tls_parse_certificate_authorities(SSL *s, PACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx);
+#ifndef OPENSSL_NO_SRP
+static int init_srp(SSL *s, unsigned int context);
+#endif
+static int init_etm(SSL *s, unsigned int context);
+static int init_ems(SSL *s, unsigned int context);
+static int final_ems(SSL *s, unsigned int context, int sent);
+static int init_psk_kex_modes(SSL *s, unsigned int context);
+#ifndef OPENSSL_NO_EC
+static int final_key_share(SSL *s, unsigned int context, int sent);
+#endif
+#ifndef OPENSSL_NO_SRTP
+static int init_srtp(SSL *s, unsigned int context);
+#endif
+static int final_sig_algs(SSL *s, unsigned int context, int sent);
+static int final_early_data(SSL *s, unsigned int context, int sent);
+static int final_maxfragmentlen(SSL *s, unsigned int context, int sent);
+static int init_post_handshake_auth(SSL *s, unsigned int context);
+static int final_psk(SSL *s, unsigned int context, int sent);
+
+/* Structure to define a built-in extension */
+typedef struct extensions_definition_st {
+    /* The defined type for the extension */
+    unsigned int type;
+    /*
+     * The context that this extension applies to, e.g. what messages and
+     * protocol versions
+     */
+    unsigned int context;
+    /*
+     * Initialise extension before parsing. Always called for relevant contexts
+     * even if extension not present
+     */
+    int (*init)(SSL *s, unsigned int context);
+    /* Parse extension sent from client to server */
+    int (*parse_ctos)(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                      size_t chainidx);
+    /* Parse extension send from server to client */
+    int (*parse_stoc)(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                      size_t chainidx);
+    /* Construct extension sent from server to client */
+    EXT_RETURN (*construct_stoc)(SSL *s, WPACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx);
+    /* Construct extension sent from client to server */
+    EXT_RETURN (*construct_ctos)(SSL *s, WPACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx);
+    /*
+     * Finalise extension after parsing. Always called where an extensions was
+     * initialised even if the extension was not present. |sent| is set to 1 if
+     * the extension was seen, or 0 otherwise.
+     */
+    int (*final)(SSL *s, unsigned int context, int sent);
+} EXTENSION_DEFINITION;
+
+/*
+ * Definitions of all built-in extensions. NOTE: Changes in the number or order
+ * of these extensions should be mirrored with equivalent changes to the
+ * indexes ( TLSEXT_IDX_* ) defined in ssl_local.h.
+ * Each extension has an initialiser, a client and
+ * server side parser and a finaliser. The initialiser is called (if the
+ * extension is relevant to the given context) even if we did not see the
+ * extension in the message that we received. The parser functions are only
+ * called if we see the extension in the message. The finalisers are always
+ * called if the initialiser was called.
+ * There are also server and client side constructor functions which are always
+ * called during message construction if the extension is relevant for the
+ * given context.
+ * The initialisation, parsing, finalisation and construction functions are
+ * always called in the order defined in this list. Some extensions may depend
+ * on others having been processed first, so the order of this list is
+ * significant.
+ * The extension context is defined by a series of flags which specify which
+ * messages the extension is relevant to. These flags also specify whether the
+ * extension is relevant to a particular protocol or protocol version.
+ *
+ * TODO(TLS1.3): Make sure we have a test to check the consistency of these
+ *
+ * NOTE: WebSphere Application Server 7+ cannot handle empty extensions at
+ * the end, keep these extensions before signature_algorithm.
+ */
+#define INVALID_EXTENSION { 0x10000, 0, NULL, NULL, NULL, NULL, NULL, NULL }
+static const EXTENSION_DEFINITION ext_defs[] = {
+    {
+        TLSEXT_TYPE_renegotiate,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_SSL3_ALLOWED | SSL_EXT_TLS1_2_AND_BELOW_ONLY,
+        NULL, tls_parse_ctos_renegotiate, tls_parse_stoc_renegotiate,
+        tls_construct_stoc_renegotiate, tls_construct_ctos_renegotiate,
+        final_renegotiate
+    },
+    {
+        TLSEXT_TYPE_server_name,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
+        init_server_name,
+        tls_parse_ctos_server_name, tls_parse_stoc_server_name,
+        tls_construct_stoc_server_name, tls_construct_ctos_server_name,
+        final_server_name
+    },
+    {
+        TLSEXT_TYPE_max_fragment_length,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
+        NULL, tls_parse_ctos_maxfragmentlen, tls_parse_stoc_maxfragmentlen,
+        tls_construct_stoc_maxfragmentlen, tls_construct_ctos_maxfragmentlen,
+        final_maxfragmentlen
+    },
+#ifndef OPENSSL_NO_SRP
+    {
+        TLSEXT_TYPE_srp,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_AND_BELOW_ONLY,
+        init_srp, tls_parse_ctos_srp, NULL, NULL, tls_construct_ctos_srp, NULL
+    },
+#else
+    INVALID_EXTENSION,
+#endif
+#ifndef OPENSSL_NO_EC
+    {
+        TLSEXT_TYPE_ec_point_formats,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_TLS1_2_AND_BELOW_ONLY,
+        init_ec_point_formats, tls_parse_ctos_ec_pt_formats, tls_parse_stoc_ec_pt_formats,
+        tls_construct_stoc_ec_pt_formats, tls_construct_ctos_ec_pt_formats,
+        final_ec_pt_formats
+    },
+    {
+        /*
+         * "supported_groups" is spread across several specifications.
+         * It was originally specified as "elliptic_curves" in RFC 4492,
+         * and broadened to include named FFDH groups by RFC 7919.
+         * Both RFCs 4492 and 7919 do not include a provision for the server
+         * to indicate to the client the complete list of groups supported
+         * by the server, with the server instead just indicating the
+         * selected group for this connection in the ServerKeyExchange
+         * message.  TLS 1.3 adds a scheme for the server to indicate
+         * to the client its list of supported groups in the
+         * EncryptedExtensions message, but none of the relevant
+         * specifications permit sending supported_groups in the ServerHello.
+         * Nonetheless (possibly due to the close proximity to the
+         * "ec_point_formats" extension, which is allowed in the ServerHello),
+         * there are several servers that send this extension in the
+         * ServerHello anyway.  Up to and including the 1.1.0 release,
+         * we did not check for the presence of nonpermitted extensions,
+         * so to avoid a regression, we must permit this extension in the
+         * TLS 1.2 ServerHello as well.
+         *
+         * Note that there is no tls_parse_stoc_supported_groups function,
+         * so we do not perform any additional parsing, validation, or
+         * processing on the server's group list -- this is just a minimal
+         * change to preserve compatibility with these misbehaving servers.
+         */
+        TLSEXT_TYPE_supported_groups,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+        | SSL_EXT_TLS1_2_SERVER_HELLO,
+        NULL, tls_parse_ctos_supported_groups, NULL,
+        tls_construct_stoc_supported_groups,
+        tls_construct_ctos_supported_groups, NULL
+    },
+#else
+    INVALID_EXTENSION,
+    INVALID_EXTENSION,
+#endif
+    {
+        TLSEXT_TYPE_session_ticket,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_TLS1_2_AND_BELOW_ONLY,
+        init_session_ticket, tls_parse_ctos_session_ticket,
+        tls_parse_stoc_session_ticket, tls_construct_stoc_session_ticket,
+        tls_construct_ctos_session_ticket, NULL
+    },
+#ifndef OPENSSL_NO_OCSP
+    {
+        TLSEXT_TYPE_status_request,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_TLS1_3_CERTIFICATE | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST,
+        init_status_request, tls_parse_ctos_status_request,
+        tls_parse_stoc_status_request, tls_construct_stoc_status_request,
+        tls_construct_ctos_status_request, NULL
+    },
+#else
+    INVALID_EXTENSION,
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    {
+        TLSEXT_TYPE_next_proto_neg,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_TLS1_2_AND_BELOW_ONLY,
+        init_npn, tls_parse_ctos_npn, tls_parse_stoc_npn,
+        tls_construct_stoc_next_proto_neg, tls_construct_ctos_npn, NULL
+    },
+#else
+    INVALID_EXTENSION,
+#endif
+    {
+        /*
+         * Must appear in this list after server_name so that finalisation
+         * happens after server_name callbacks
+         */
+        TLSEXT_TYPE_application_layer_protocol_negotiation,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
+        init_alpn, tls_parse_ctos_alpn, tls_parse_stoc_alpn,
+        tls_construct_stoc_alpn, tls_construct_ctos_alpn, final_alpn
+    },
+#ifndef OPENSSL_NO_SRTP
+    {
+        TLSEXT_TYPE_use_srtp,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS | SSL_EXT_DTLS_ONLY,
+        init_srtp, tls_parse_ctos_use_srtp, tls_parse_stoc_use_srtp,
+        tls_construct_stoc_use_srtp, tls_construct_ctos_use_srtp, NULL
+    },
+#else
+    INVALID_EXTENSION,
+#endif
+    {
+        TLSEXT_TYPE_encrypt_then_mac,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_TLS1_2_AND_BELOW_ONLY,
+        init_etm, tls_parse_ctos_etm, tls_parse_stoc_etm,
+        tls_construct_stoc_etm, tls_construct_ctos_etm, NULL
+    },
+#ifndef OPENSSL_NO_CT
+    {
+        TLSEXT_TYPE_signed_certificate_timestamp,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_TLS1_3_CERTIFICATE | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST,
+        NULL,
+        /*
+         * No server side support for this, but can be provided by a custom
+         * extension. This is an exception to the rule that custom extensions
+         * cannot override built in ones.
+         */
+        NULL, tls_parse_stoc_sct, NULL, tls_construct_ctos_sct,  NULL
+    },
+#else
+    INVALID_EXTENSION,
+#endif
+    {
+        TLSEXT_TYPE_extended_master_secret,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_TLS1_2_AND_BELOW_ONLY,
+        init_ems, tls_parse_ctos_ems, tls_parse_stoc_ems,
+        tls_construct_stoc_ems, tls_construct_ctos_ems, final_ems
+    },
+    {
+        TLSEXT_TYPE_signature_algorithms_cert,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST,
+        init_sig_algs_cert, tls_parse_ctos_sig_algs_cert,
+        tls_parse_ctos_sig_algs_cert,
+        /* We do not generate signature_algorithms_cert at present. */
+        NULL, NULL, NULL
+    },
+    {
+        TLSEXT_TYPE_post_handshake_auth,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ONLY,
+        init_post_handshake_auth,
+        tls_parse_ctos_post_handshake_auth, NULL,
+        NULL, tls_construct_ctos_post_handshake_auth,
+        NULL,
+    },
+    {
+        TLSEXT_TYPE_signature_algorithms,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST,
+        init_sig_algs, tls_parse_ctos_sig_algs,
+        tls_parse_ctos_sig_algs, tls_construct_ctos_sig_algs,
+        tls_construct_ctos_sig_algs, final_sig_algs
+    },
+    {
+        TLSEXT_TYPE_supported_versions,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_SERVER_HELLO
+        | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST | SSL_EXT_TLS_IMPLEMENTATION_ONLY,
+        NULL,
+        /* Processed inline as part of version selection */
+        NULL, tls_parse_stoc_supported_versions,
+        tls_construct_stoc_supported_versions,
+        tls_construct_ctos_supported_versions, NULL
+    },
+    {
+        TLSEXT_TYPE_psk_kex_modes,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS_IMPLEMENTATION_ONLY
+        | SSL_EXT_TLS1_3_ONLY,
+        init_psk_kex_modes, tls_parse_ctos_psk_kex_modes, NULL, NULL,
+        tls_construct_ctos_psk_kex_modes, NULL
+    },
+#ifndef OPENSSL_NO_EC
+    {
+        /*
+         * Must be in this list after supported_groups. We need that to have
+         * been parsed before we do this one.
+         */
+        TLSEXT_TYPE_key_share,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_SERVER_HELLO
+        | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST | SSL_EXT_TLS_IMPLEMENTATION_ONLY
+        | SSL_EXT_TLS1_3_ONLY,
+        NULL, tls_parse_ctos_key_share, tls_parse_stoc_key_share,
+        tls_construct_stoc_key_share, tls_construct_ctos_key_share,
+        final_key_share
+    },
+#else
+    INVALID_EXTENSION,
+#endif
+    {
+        /* Must be after key_share */
+        TLSEXT_TYPE_cookie,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST
+        | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY,
+        NULL, tls_parse_ctos_cookie, tls_parse_stoc_cookie,
+        tls_construct_stoc_cookie, tls_construct_ctos_cookie, NULL
+    },
+    {
+        /*
+         * Special unsolicited ServerHello extension only used when
+         * SSL_OP_CRYPTOPRO_TLSEXT_BUG is set. We allow it in a ClientHello but
+         * ignore it.
+         */
+        TLSEXT_TYPE_cryptopro_bug,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_TLS1_2_AND_BELOW_ONLY,
+        NULL, NULL, NULL, tls_construct_stoc_cryptopro_bug, NULL, NULL
+    },
+    {
+        TLSEXT_TYPE_early_data,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+        | SSL_EXT_TLS1_3_NEW_SESSION_TICKET | SSL_EXT_TLS1_3_ONLY,
+        NULL, tls_parse_ctos_early_data, tls_parse_stoc_early_data,
+        tls_construct_stoc_early_data, tls_construct_ctos_early_data,
+        final_early_data
+    },
+    {
+        TLSEXT_TYPE_certificate_authorities,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST
+        | SSL_EXT_TLS1_3_ONLY,
+        init_certificate_authorities,
+        tls_parse_certificate_authorities, tls_parse_certificate_authorities,
+        tls_construct_certificate_authorities,
+        tls_construct_certificate_authorities, NULL,
+    },
+    {
+        /* Must be immediately before pre_shared_key */
+        TLSEXT_TYPE_padding,
+        SSL_EXT_CLIENT_HELLO,
+        NULL,
+        /* We send this, but don't read it */
+        NULL, NULL, NULL, tls_construct_ctos_padding, NULL
+    },
+    {
+        /* Required by the TLSv1.3 spec to always be the last extension */
+        TLSEXT_TYPE_psk,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_SERVER_HELLO
+        | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY,
+        NULL, tls_parse_ctos_psk, tls_parse_stoc_psk, tls_construct_stoc_psk,
+        tls_construct_ctos_psk, final_psk
+    }
+};
+
+/* Check whether an extension's context matches the current context */
+static int validate_context(SSL *s, unsigned int extctx, unsigned int thisctx)
+{
+    /* Check we're allowed to use this extension in this context */
+    if ((thisctx & extctx) == 0)
+        return 0;
+
+    if (SSL_IS_DTLS(s)) {
+        if ((extctx & SSL_EXT_TLS_ONLY) != 0)
+            return 0;
+    } else if ((extctx & SSL_EXT_DTLS_ONLY) != 0) {
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_validate_all_contexts(SSL *s, unsigned int thisctx, RAW_EXTENSION *exts)
+{
+    size_t i, num_exts, builtin_num = OSSL_NELEM(ext_defs), offset;
+    RAW_EXTENSION *thisext;
+    unsigned int context;
+    ENDPOINT role = ENDPOINT_BOTH;
+
+    if ((thisctx & SSL_EXT_CLIENT_HELLO) != 0)
+        role = ENDPOINT_SERVER;
+    else if ((thisctx & SSL_EXT_TLS1_2_SERVER_HELLO) != 0)
+        role = ENDPOINT_CLIENT;
+
+    /* Calculate the number of extensions in the extensions list */
+    num_exts = builtin_num + s->cert->custext.meths_count;
+
+    for (thisext = exts, i = 0; i < num_exts; i++, thisext++) {
+        if (!thisext->present)
+            continue;
+
+        if (i < builtin_num) {
+            context = ext_defs[i].context;
+        } else {
+            custom_ext_method *meth = NULL;
+
+            meth = custom_ext_find(&s->cert->custext, role, thisext->type,
+                                   &offset);
+            if (!ossl_assert(meth != NULL))
+                return 0;
+            context = meth->context;
+        }
+
+        if (!validate_context(s, context, thisctx))
+            return 0;
+    }
+
+    return 1;
+}
+
+/*
+ * Verify whether we are allowed to use the extension |type| in the current
+ * |context|. Returns 1 to indicate the extension is allowed or unknown or 0 to
+ * indicate the extension is not allowed. If returning 1 then |*found| is set to
+ * the definition for the extension we found.
+ */
+static int verify_extension(SSL *s, unsigned int context, unsigned int type,
+                            custom_ext_methods *meths, RAW_EXTENSION *rawexlist,
+                            RAW_EXTENSION **found)
+{
+    size_t i;
+    size_t builtin_num = OSSL_NELEM(ext_defs);
+    const EXTENSION_DEFINITION *thisext;
+
+    for (i = 0, thisext = ext_defs; i < builtin_num; i++, thisext++) {
+        if (type == thisext->type) {
+            if (!validate_context(s, thisext->context, context))
+                return 0;
+
+            *found = &rawexlist[i];
+            return 1;
+        }
+    }
+
+    /* Check the custom extensions */
+    if (meths != NULL) {
+        size_t offset = 0;
+        ENDPOINT role = ENDPOINT_BOTH;
+        custom_ext_method *meth = NULL;
+
+        if ((context & SSL_EXT_CLIENT_HELLO) != 0)
+            role = ENDPOINT_SERVER;
+        else if ((context & SSL_EXT_TLS1_2_SERVER_HELLO) != 0)
+            role = ENDPOINT_CLIENT;
+
+        meth = custom_ext_find(meths, role, type, &offset);
+        if (meth != NULL) {
+            if (!validate_context(s, meth->context, context))
+                return 0;
+            *found = &rawexlist[offset + builtin_num];
+            return 1;
+        }
+    }
+
+    /* Unknown extension. We allow it */
+    *found = NULL;
+    return 1;
+}
+
+/*
+ * Check whether the context defined for an extension |extctx| means whether
+ * the extension is relevant for the current context |thisctx| or not. Returns
+ * 1 if the extension is relevant for this context, and 0 otherwise
+ */
+int extension_is_relevant(SSL *s, unsigned int extctx, unsigned int thisctx)
+{
+    int is_tls13;
+
+    /*
+     * For HRR we haven't selected the version yet but we know it will be
+     * TLSv1.3
+     */
+    if ((thisctx & SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST) != 0)
+        is_tls13 = 1;
+    else
+        is_tls13 = SSL_IS_TLS13(s);
+
+    if ((SSL_IS_DTLS(s)
+                && (extctx & SSL_EXT_TLS_IMPLEMENTATION_ONLY) != 0)
+            || (s->version == SSL3_VERSION
+                    && (extctx & SSL_EXT_SSL3_ALLOWED) == 0)
+            /*
+             * Note that SSL_IS_TLS13() means "TLS 1.3 has been negotiated",
+             * which is never true when generating the ClientHello.
+             * However, version negotiation *has* occurred by the time the
+             * ClientHello extensions are being parsed.
+             * Be careful to allow TLS 1.3-only extensions when generating
+             * the ClientHello.
+             */
+            || (is_tls13 && (extctx & SSL_EXT_TLS1_2_AND_BELOW_ONLY) != 0)
+            || (!is_tls13 && (extctx & SSL_EXT_TLS1_3_ONLY) != 0
+                && (thisctx & SSL_EXT_CLIENT_HELLO) == 0)
+            || (s->server && !is_tls13 && (extctx & SSL_EXT_TLS1_3_ONLY) != 0)
+            || (s->hit && (extctx & SSL_EXT_IGNORE_ON_RESUMPTION) != 0))
+        return 0;
+    return 1;
+}
+
+/*
+ * Gather a list of all the extensions from the data in |packet]. |context|
+ * tells us which message this extension is for. The raw extension data is
+ * stored in |*res| on success. We don't actually process the content of the
+ * extensions yet, except to check their types. This function also runs the
+ * initialiser functions for all known extensions if |init| is nonzero (whether
+ * we have collected them or not). If successful the caller is responsible for
+ * freeing the contents of |*res|.
+ *
+ * Per http://tools.ietf.org/html/rfc5246#section-7.4.1.4, there may not be
+ * more than one extension of the same type in a ClientHello or ServerHello.
+ * This function returns 1 if all extensions are unique and we have parsed their
+ * types, and 0 if the extensions contain duplicates, could not be successfully
+ * found, or an internal error occurred. We only check duplicates for
+ * extensions that we know about. We ignore others.
+ */
+int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
+                           RAW_EXTENSION **res, size_t *len, int init)
+{
+    PACKET extensions = *packet;
+    size_t i = 0;
+    size_t num_exts;
+    custom_ext_methods *exts = &s->cert->custext;
+    RAW_EXTENSION *raw_extensions = NULL;
+    const EXTENSION_DEFINITION *thisexd;
+
+    *res = NULL;
+
+    /*
+     * Initialise server side custom extensions. Client side is done during
+     * construction of extensions for the ClientHello.
+     */
+    if ((context & SSL_EXT_CLIENT_HELLO) != 0)
+        custom_ext_init(&s->cert->custext);
+
+    num_exts = OSSL_NELEM(ext_defs) + (exts != NULL ? exts->meths_count : 0);
+    raw_extensions = OPENSSL_zalloc(num_exts * sizeof(*raw_extensions));
+    if (raw_extensions == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_COLLECT_EXTENSIONS,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    i = 0;
+    while (PACKET_remaining(&extensions) > 0) {
+        unsigned int type, idx;
+        PACKET extension;
+        RAW_EXTENSION *thisex;
+
+        if (!PACKET_get_net_2(&extensions, &type) ||
+            !PACKET_get_length_prefixed_2(&extensions, &extension)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_COLLECT_EXTENSIONS,
+                     SSL_R_BAD_EXTENSION);
+            goto err;
+        }
+        /*
+         * Verify this extension is allowed. We only check duplicates for
+         * extensions that we recognise. We also have a special case for the
+         * PSK extension, which must be the last one in the ClientHello.
+         */
+        if (!verify_extension(s, context, type, exts, raw_extensions, &thisex)
+                || (thisex != NULL && thisex->present == 1)
+                || (type == TLSEXT_TYPE_psk
+                    && (context & SSL_EXT_CLIENT_HELLO) != 0
+                    && PACKET_remaining(&extensions) != 0)) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_COLLECT_EXTENSIONS,
+                     SSL_R_BAD_EXTENSION);
+            goto err;
+        }
+        idx = thisex - raw_extensions;
+        /*-
+         * Check that we requested this extension (if appropriate). Requests can
+         * be sent in the ClientHello and CertificateRequest. Unsolicited
+         * extensions can be sent in the NewSessionTicket. We only do this for
+         * the built-in extensions. Custom extensions have a different but
+         * similar check elsewhere.
+         * Special cases:
+         * - The HRR cookie extension is unsolicited
+         * - The renegotiate extension is unsolicited (the client signals
+         *   support via an SCSV)
+         * - The signed_certificate_timestamp extension can be provided by a
+         * custom extension or by the built-in version. We let the extension
+         * itself handle unsolicited response checks.
+         */
+        if (idx < OSSL_NELEM(ext_defs)
+                && (context & (SSL_EXT_CLIENT_HELLO
+                               | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST
+                               | SSL_EXT_TLS1_3_NEW_SESSION_TICKET)) == 0
+                && type != TLSEXT_TYPE_cookie
+                && type != TLSEXT_TYPE_renegotiate
+                && type != TLSEXT_TYPE_signed_certificate_timestamp
+                && (s->ext.extflags[idx] & SSL_EXT_FLAG_SENT) == 0
+#ifndef OPENSSL_NO_GOST
+                && !((context & SSL_EXT_TLS1_2_SERVER_HELLO) != 0
+                     && type == TLSEXT_TYPE_cryptopro_bug)
+#endif
+								) {
+            SSLfatal(s, SSL_AD_UNSUPPORTED_EXTENSION,
+                     SSL_F_TLS_COLLECT_EXTENSIONS, SSL_R_UNSOLICITED_EXTENSION);
+            goto err;
+        }
+        if (thisex != NULL) {
+            thisex->data = extension;
+            thisex->present = 1;
+            thisex->type = type;
+            thisex->received_order = i++;
+            if (s->ext.debug_cb)
+                s->ext.debug_cb(s, !s->server, thisex->type,
+                                PACKET_data(&thisex->data),
+                                PACKET_remaining(&thisex->data),
+                                s->ext.debug_arg);
+        }
+    }
+
+    if (init) {
+        /*
+         * Initialise all known extensions relevant to this context,
+         * whether we have found them or not
+         */
+        for (thisexd = ext_defs, i = 0; i < OSSL_NELEM(ext_defs);
+             i++, thisexd++) {
+            if (thisexd->init != NULL && (thisexd->context & context) != 0
+                && extension_is_relevant(s, thisexd->context, context)
+                && !thisexd->init(s, context)) {
+                /* SSLfatal() already called */
+                goto err;
+            }
+        }
+    }
+
+    *res = raw_extensions;
+    if (len != NULL)
+        *len = num_exts;
+    return 1;
+
+ err:
+    OPENSSL_free(raw_extensions);
+    return 0;
+}
+
+/*
+ * Runs the parser for a given extension with index |idx|. |exts| contains the
+ * list of all parsed extensions previously collected by
+ * tls_collect_extensions(). The parser is only run if it is applicable for the
+ * given |context| and the parser has not already been run. If this is for a
+ * Certificate message, then we also provide the parser with the relevant
+ * Certificate |x| and its position in the |chainidx| with 0 being the first
+ * Certificate. Returns 1 on success or 0 on failure. If an extension is not
+ * present this counted as success.
+ */
+int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
+                        RAW_EXTENSION *exts, X509 *x, size_t chainidx)
+{
+    RAW_EXTENSION *currext = &exts[idx];
+    int (*parser)(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                  size_t chainidx) = NULL;
+
+    /* Skip if the extension is not present */
+    if (!currext->present)
+        return 1;
+
+    /* Skip if we've already parsed this extension */
+    if (currext->parsed)
+        return 1;
+
+    currext->parsed = 1;
+
+    if (idx < OSSL_NELEM(ext_defs)) {
+        /* We are handling a built-in extension */
+        const EXTENSION_DEFINITION *extdef = &ext_defs[idx];
+
+        /* Check if extension is defined for our protocol. If not, skip */
+        if (!extension_is_relevant(s, extdef->context, context))
+            return 1;
+
+        parser = s->server ? extdef->parse_ctos : extdef->parse_stoc;
+
+        if (parser != NULL)
+            return parser(s, &currext->data, context, x, chainidx);
+
+        /*
+         * If the parser is NULL we fall through to the custom extension
+         * processing
+         */
+    }
+
+    /* Parse custom extensions */
+    return custom_ext_parse(s, context, currext->type,
+                            PACKET_data(&currext->data),
+                            PACKET_remaining(&currext->data),
+                            x, chainidx);
+}
+
+/*
+ * Parse all remaining extensions that have not yet been parsed. Also calls the
+ * finalisation for all extensions at the end if |fin| is nonzero, whether we
+ * collected them or not. Returns 1 for success or 0 for failure. If we are
+ * working on a Certificate message then we also pass the Certificate |x| and
+ * its position in the |chainidx|, with 0 being the first certificate.
+ */
+int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, X509 *x,
+                             size_t chainidx, int fin)
+{
+    size_t i, numexts = OSSL_NELEM(ext_defs);
+    const EXTENSION_DEFINITION *thisexd;
+
+    /* Calculate the number of extensions in the extensions list */
+    numexts += s->cert->custext.meths_count;
+
+    /* Parse each extension in turn */
+    for (i = 0; i < numexts; i++) {
+        if (!tls_parse_extension(s, i, context, exts, x, chainidx)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+    }
+
+    if (fin) {
+        /*
+         * Finalise all known extensions relevant to this context,
+         * whether we have found them or not
+         */
+        for (i = 0, thisexd = ext_defs; i < OSSL_NELEM(ext_defs);
+             i++, thisexd++) {
+            if (thisexd->final != NULL && (thisexd->context & context) != 0
+                && !thisexd->final(s, context, exts[i].present)) {
+                /* SSLfatal() already called */
+                return 0;
+            }
+        }
+    }
+
+    return 1;
+}
+
+int should_add_extension(SSL *s, unsigned int extctx, unsigned int thisctx,
+                         int max_version)
+{
+    /* Skip if not relevant for our context */
+    if ((extctx & thisctx) == 0)
+        return 0;
+
+    /* Check if this extension is defined for our protocol. If not, skip */
+    if (!extension_is_relevant(s, extctx, thisctx)
+            || ((extctx & SSL_EXT_TLS1_3_ONLY) != 0
+                && (thisctx & SSL_EXT_CLIENT_HELLO) != 0
+                && (SSL_IS_DTLS(s) || max_version < TLS1_3_VERSION)))
+        return 0;
+
+    return 1;
+}
+
+/*
+ * Construct all the extensions relevant to the current |context| and write
+ * them to |pkt|. If this is an extension for a Certificate in a Certificate
+ * message, then |x| will be set to the Certificate we are handling, and
+ * |chainidx| will indicate the position in the chainidx we are processing (with
+ * 0 being the first in the chain). Returns 1 on success or 0 on failure. On a
+ * failure construction stops at the first extension to fail to construct.
+ */
+int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
+                             X509 *x, size_t chainidx)
+{
+    size_t i;
+    int min_version, max_version = 0, reason;
+    const EXTENSION_DEFINITION *thisexd;
+
+    if (!WPACKET_start_sub_packet_u16(pkt)
+               /*
+                * If extensions are of zero length then we don't even add the
+                * extensions length bytes to a ClientHello/ServerHello
+                * (for non-TLSv1.3).
+                */
+            || ((context &
+                 (SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO)) != 0
+                && !WPACKET_set_flags(pkt,
+                                     WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH))) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_EXTENSIONS,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if ((context & SSL_EXT_CLIENT_HELLO) != 0) {
+        reason = ssl_get_min_max_version(s, &min_version, &max_version, NULL);
+        if (reason != 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_EXTENSIONS,
+                     reason);
+            return 0;
+        }
+    }
+
+    /* Add custom extensions first */
+    if ((context & SSL_EXT_CLIENT_HELLO) != 0) {
+        /* On the server side with initialise during ClientHello parsing */
+        custom_ext_init(&s->cert->custext);
+    }
+    if (!custom_ext_add(s, context, pkt, x, chainidx, max_version)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    for (i = 0, thisexd = ext_defs; i < OSSL_NELEM(ext_defs); i++, thisexd++) {
+        EXT_RETURN (*construct)(SSL *s, WPACKET *pkt, unsigned int context,
+                                X509 *x, size_t chainidx);
+        EXT_RETURN ret;
+
+        /* Skip if not relevant for our context */
+        if (!should_add_extension(s, thisexd->context, context, max_version))
+            continue;
+
+        construct = s->server ? thisexd->construct_stoc
+                              : thisexd->construct_ctos;
+
+        if (construct == NULL)
+            continue;
+
+        ret = construct(s, pkt, context, x, chainidx);
+        if (ret == EXT_RETURN_FAIL) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+        if (ret == EXT_RETURN_SENT
+                && (context & (SSL_EXT_CLIENT_HELLO
+                               | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST
+                               | SSL_EXT_TLS1_3_NEW_SESSION_TICKET)) != 0)
+            s->ext.extflags[i] |= SSL_EXT_FLAG_SENT;
+    }
+
+    if (!WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_EXTENSIONS,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+/*
+ * Built in extension finalisation and initialisation functions. All initialise
+ * or finalise the associated extension type for the given |context|. For
+ * finalisers |sent| is set to 1 if we saw the extension during parsing, and 0
+ * otherwise. These functions return 1 on success or 0 on failure.
+ */
+
+static int final_renegotiate(SSL *s, unsigned int context, int sent)
+{
+    if (!s->server) {
+        /*
+         * Check if we can connect to a server that doesn't support safe
+         * renegotiation
+         */
+        if (!(s->options & SSL_OP_LEGACY_SERVER_CONNECT)
+                && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)
+                && !sent) {
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_FINAL_RENEGOTIATE,
+                     SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+            return 0;
+        }
+
+        return 1;
+    }
+
+    /* Need RI if renegotiating */
+    if (s->renegotiate
+            && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)
+            && !sent) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_FINAL_RENEGOTIATE,
+                 SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+        return 0;
+    }
+
+
+    return 1;
+}
+
+static int init_server_name(SSL *s, unsigned int context)
+{
+    if (s->server) {
+        s->servername_done = 0;
+
+        OPENSSL_free(s->ext.hostname);
+        s->ext.hostname = NULL;
+    }
+
+    return 1;
+}
+
+static int final_server_name(SSL *s, unsigned int context, int sent)
+{
+    int ret = SSL_TLSEXT_ERR_NOACK;
+    int altmp = SSL_AD_UNRECOGNIZED_NAME;
+    int was_ticket = (SSL_get_options(s) & SSL_OP_NO_TICKET) == 0;
+
+    if (!ossl_assert(s->ctx != NULL) || !ossl_assert(s->session_ctx != NULL)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_FINAL_SERVER_NAME,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (s->ctx->ext.servername_cb != NULL)
+        ret = s->ctx->ext.servername_cb(s, &altmp,
+                                        s->ctx->ext.servername_arg);
+    else if (s->session_ctx->ext.servername_cb != NULL)
+        ret = s->session_ctx->ext.servername_cb(s, &altmp,
+                                       s->session_ctx->ext.servername_arg);
+
+    /*
+     * For servers, propagate the SNI hostname from the temporary
+     * storage in the SSL to the persistent SSL_SESSION, now that we
+     * know we accepted it.
+     * Clients make this copy when parsing the server's response to
+     * the extension, which is when they find out that the negotiation
+     * was successful.
+     */
+    if (s->server) {
+        if (sent && ret == SSL_TLSEXT_ERR_OK && !s->hit) {
+            /* Only store the hostname in the session if we accepted it. */
+            OPENSSL_free(s->session->ext.hostname);
+            s->session->ext.hostname = OPENSSL_strdup(s->ext.hostname);
+            if (s->session->ext.hostname == NULL && s->ext.hostname != NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_FINAL_SERVER_NAME,
+                         ERR_R_INTERNAL_ERROR);
+            }
+        }
+    }
+
+    /*
+     * If we switched contexts (whether here or in the client_hello callback),
+     * move the sess_accept increment from the session_ctx to the new
+     * context, to avoid the confusing situation of having sess_accept_good
+     * exceed sess_accept (zero) for the new context.
+     */
+    if (SSL_IS_FIRST_HANDSHAKE(s) && s->ctx != s->session_ctx
+		    && s->hello_retry_request == SSL_HRR_NONE) {
+        tsan_counter(&s->ctx->stats.sess_accept);
+        tsan_decr(&s->session_ctx->stats.sess_accept);
+    }
+
+    /*
+     * If we're expecting to send a ticket, and tickets were previously enabled,
+     * and now tickets are disabled, then turn off expected ticket.
+     * Also, if this is not a resumption, create a new session ID
+     */
+    if (ret == SSL_TLSEXT_ERR_OK && s->ext.ticket_expected
+            && was_ticket && (SSL_get_options(s) & SSL_OP_NO_TICKET) != 0) {
+        s->ext.ticket_expected = 0;
+        if (!s->hit) {
+            SSL_SESSION* ss = SSL_get_session(s);
+
+            if (ss != NULL) {
+                OPENSSL_free(ss->ext.tick);
+                ss->ext.tick = NULL;
+                ss->ext.ticklen = 0;
+                ss->ext.tick_lifetime_hint = 0;
+                ss->ext.tick_age_add = 0;
+                if (!ssl_generate_session_id(s, ss)) {
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_FINAL_SERVER_NAME,
+                             ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+            } else {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_FINAL_SERVER_NAME,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
+    }
+
+    switch (ret) {
+    case SSL_TLSEXT_ERR_ALERT_FATAL:
+        SSLfatal(s, altmp, SSL_F_FINAL_SERVER_NAME, SSL_R_CALLBACK_FAILED);
+        return 0;
+
+    case SSL_TLSEXT_ERR_ALERT_WARNING:
+        /* TLSv1.3 doesn't have warning alerts so we suppress this */
+        if (!SSL_IS_TLS13(s))
+            ssl3_send_alert(s, SSL3_AL_WARNING, altmp);
+        s->servername_done = 0;
+        return 1;
+
+    case SSL_TLSEXT_ERR_NOACK:
+        s->servername_done = 0;
+        return 1;
+
+    default:
+        return 1;
+    }
+}
+
+#ifndef OPENSSL_NO_EC
+static int init_ec_point_formats(SSL *s, unsigned int context)
+{
+    OPENSSL_free(s->ext.peer_ecpointformats);
+    s->ext.peer_ecpointformats = NULL;
+    s->ext.peer_ecpointformats_len = 0;
+
+    return 1;
+}
+
+static int final_ec_pt_formats(SSL *s, unsigned int context, int sent)
+{
+    unsigned long alg_k, alg_a;
+
+    if (s->server)
+        return 1;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+    alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+
+    /*
+     * If we are client and using an elliptic curve cryptography cipher
+     * suite, then if server returns an EC point formats lists extension it
+     * must contain uncompressed.
+     */
+    if (s->ext.ecpointformats != NULL
+            && s->ext.ecpointformats_len > 0
+            && s->ext.peer_ecpointformats != NULL
+            && s->ext.peer_ecpointformats_len > 0
+            && ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA))) {
+        /* we are using an ECC cipher */
+        size_t i;
+        unsigned char *list = s->ext.peer_ecpointformats;
+
+        for (i = 0; i < s->ext.peer_ecpointformats_len; i++) {
+            if (*list++ == TLSEXT_ECPOINTFORMAT_uncompressed)
+                break;
+        }
+        if (i == s->ext.peer_ecpointformats_len) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_FINAL_EC_PT_FORMATS,
+                     SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif
+
+static int init_session_ticket(SSL *s, unsigned int context)
+{
+    if (!s->server)
+        s->ext.ticket_expected = 0;
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_OCSP
+static int init_status_request(SSL *s, unsigned int context)
+{
+    if (s->server) {
+        s->ext.status_type = TLSEXT_STATUSTYPE_nothing;
+    } else {
+        /*
+         * Ensure we get sensible values passed to tlsext_status_cb in the event
+         * that we don't receive a status message
+         */
+        OPENSSL_free(s->ext.ocsp.resp);
+        s->ext.ocsp.resp = NULL;
+        s->ext.ocsp.resp_len = 0;
+    }
+
+    return 1;
+}
+#endif
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+static int init_npn(SSL *s, unsigned int context)
+{
+    s->s3->npn_seen = 0;
+
+    return 1;
+}
+#endif
+
+static int init_alpn(SSL *s, unsigned int context)
+{
+    OPENSSL_free(s->s3->alpn_selected);
+    s->s3->alpn_selected = NULL;
+    s->s3->alpn_selected_len = 0;
+    if (s->server) {
+        OPENSSL_free(s->s3->alpn_proposed);
+        s->s3->alpn_proposed = NULL;
+        s->s3->alpn_proposed_len = 0;
+    }
+    return 1;
+}
+
+static int final_alpn(SSL *s, unsigned int context, int sent)
+{
+    if (!s->server && !sent && s->session->ext.alpn_selected != NULL)
+            s->ext.early_data_ok = 0;
+
+    if (!s->server || !SSL_IS_TLS13(s))
+        return 1;
+
+    /*
+     * Call alpn_select callback if needed.  Has to be done after SNI and
+     * cipher negotiation (HTTP/2 restricts permitted ciphers). In TLSv1.3
+     * we also have to do this before we decide whether to accept early_data.
+     * In TLSv1.3 we've already negotiated our cipher so we do this call now.
+     * For < TLSv1.3 we defer it until after cipher negotiation.
+     *
+     * On failure SSLfatal() already called.
+     */
+    return tls_handle_alpn(s);
+}
+
+static int init_sig_algs(SSL *s, unsigned int context)
+{
+    /* Clear any signature algorithms extension received */
+    OPENSSL_free(s->s3->tmp.peer_sigalgs);
+    s->s3->tmp.peer_sigalgs = NULL;
+    s->s3->tmp.peer_sigalgslen = 0;
+
+    return 1;
+}
+
+static int init_sig_algs_cert(SSL *s, unsigned int context)
+{
+    /* Clear any signature algorithms extension received */
+    OPENSSL_free(s->s3->tmp.peer_cert_sigalgs);
+    s->s3->tmp.peer_cert_sigalgs = NULL;
+    s->s3->tmp.peer_cert_sigalgslen = 0;
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SRP
+static int init_srp(SSL *s, unsigned int context)
+{
+    OPENSSL_free(s->srp_ctx.login);
+    s->srp_ctx.login = NULL;
+
+    return 1;
+}
+#endif
+
+static int init_etm(SSL *s, unsigned int context)
+{
+    s->ext.use_etm = 0;
+
+    return 1;
+}
+
+static int init_ems(SSL *s, unsigned int context)
+{
+    if (s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) {
+        s->s3->flags &= ~TLS1_FLAGS_RECEIVED_EXTMS;
+        s->s3->flags |= TLS1_FLAGS_REQUIRED_EXTMS;
+    }
+
+    return 1;
+}
+
+static int final_ems(SSL *s, unsigned int context, int sent)
+{
+    /*
+     * Check extended master secret extension is not dropped on
+     * renegotiation.
+     */
+    if (!(s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS)
+        && (s->s3->flags & TLS1_FLAGS_REQUIRED_EXTMS)) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_FINAL_EMS,
+                 SSL_R_INCONSISTENT_EXTMS);
+        return 0;
+    }
+    if (!s->server && s->hit) {
+        /*
+         * Check extended master secret extension is consistent with
+         * original session.
+         */
+        if (!(s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) !=
+            !(s->session->flags & SSL_SESS_FLAG_EXTMS)) {
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_FINAL_EMS,
+                     SSL_R_INCONSISTENT_EXTMS);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+static int init_certificate_authorities(SSL *s, unsigned int context)
+{
+    sk_X509_NAME_pop_free(s->s3->tmp.peer_ca_names, X509_NAME_free);
+    s->s3->tmp.peer_ca_names = NULL;
+    return 1;
+}
+
+static EXT_RETURN tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
+                                                        unsigned int context,
+                                                        X509 *x,
+                                                        size_t chainidx)
+{
+    const STACK_OF(X509_NAME) *ca_sk = get_ca_names(s);
+
+    if (ca_sk == NULL || sk_X509_NAME_num(ca_sk) == 0)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_certificate_authorities)
+        || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CERTIFICATE_AUTHORITIES,
+               ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    if (!construct_ca_names(s, ca_sk, pkt)) {
+        /* SSLfatal() already called */
+        return EXT_RETURN_FAIL;
+    }
+
+    if (!WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CERTIFICATE_AUTHORITIES,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+static int tls_parse_certificate_authorities(SSL *s, PACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx)
+{
+    if (!parse_ca_names(s, pkt))
+        return 0;
+    if (PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CERTIFICATE_AUTHORITIES, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SRTP
+static int init_srtp(SSL *s, unsigned int context)
+{
+    if (s->server)
+        s->srtp_profile = NULL;
+
+    return 1;
+}
+#endif
+
+static int final_sig_algs(SSL *s, unsigned int context, int sent)
+{
+    if (!sent && SSL_IS_TLS13(s) && !s->hit) {
+        SSLfatal(s, TLS13_AD_MISSING_EXTENSION, SSL_F_FINAL_SIG_ALGS,
+                 SSL_R_MISSING_SIGALGS_EXTENSION);
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_EC
+static int final_key_share(SSL *s, unsigned int context, int sent)
+{
+    if (!SSL_IS_TLS13(s))
+        return 1;
+
+    /* Nothing to do for key_share in an HRR */
+    if ((context & SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST) != 0)
+        return 1;
+
+    /*
+     * If
+     *     we are a client
+     *     AND
+     *     we have no key_share
+     *     AND
+     *     (we are not resuming
+     *      OR the kex_mode doesn't allow non key_share resumes)
+     * THEN
+     *     fail;
+     */
+    if (!s->server
+            && !sent
+            && (!s->hit
+                || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) == 0)) {
+        /* Nothing left we can do - just fail */
+        SSLfatal(s, SSL_AD_MISSING_EXTENSION, SSL_F_FINAL_KEY_SHARE,
+                 SSL_R_NO_SUITABLE_KEY_SHARE);
+        return 0;
+    }
+    /*
+     * IF
+     *     we are a server
+     * THEN
+     *     IF
+     *         we have a suitable key_share
+     *     THEN
+     *         IF
+     *             we are stateless AND we have no cookie
+     *         THEN
+     *             send a HelloRetryRequest
+     *     ELSE
+     *         IF
+     *             we didn't already send a HelloRetryRequest
+     *             AND
+     *             the client sent a key_share extension
+     *             AND
+     *             (we are not resuming
+     *              OR the kex_mode allows key_share resumes)
+     *             AND
+     *             a shared group exists
+     *         THEN
+     *             send a HelloRetryRequest
+     *         ELSE IF
+     *             we are not resuming
+     *             OR
+     *             the kex_mode doesn't allow non key_share resumes
+     *         THEN
+     *             fail
+     *         ELSE IF
+     *             we are stateless AND we have no cookie
+     *         THEN
+     *             send a HelloRetryRequest
+     */
+    if (s->server) {
+        if (s->s3->peer_tmp != NULL) {
+            /* We have a suitable key_share */
+            if ((s->s3->flags & TLS1_FLAGS_STATELESS) != 0
+                    && !s->ext.cookieok) {
+                if (!ossl_assert(s->hello_retry_request == SSL_HRR_NONE)) {
+                    /*
+                     * If we are stateless then we wouldn't know about any
+                     * previously sent HRR - so how can this be anything other
+                     * than 0?
+                     */
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_FINAL_KEY_SHARE,
+                             ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+                s->hello_retry_request = SSL_HRR_PENDING;
+                return 1;
+            }
+        } else {
+            /* No suitable key_share */
+            if (s->hello_retry_request == SSL_HRR_NONE && sent
+                    && (!s->hit
+                        || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE)
+                           != 0)) {
+                const uint16_t *pgroups, *clntgroups;
+                size_t num_groups, clnt_num_groups, i;
+                unsigned int group_id = 0;
+
+                /* Check if a shared group exists */
+
+                /* Get the clients list of supported groups. */
+                tls1_get_peer_groups(s, &clntgroups, &clnt_num_groups);
+                tls1_get_supported_groups(s, &pgroups, &num_groups);
+
+                /*
+                 * Find the first group we allow that is also in client's list
+                 */
+                for (i = 0; i < num_groups; i++) {
+                    group_id = pgroups[i];
+
+                    if (check_in_list(s, group_id, clntgroups, clnt_num_groups,
+                                      1))
+                        break;
+                }
+
+                if (i < num_groups) {
+                    /* A shared group exists so send a HelloRetryRequest */
+                    s->s3->group_id = group_id;
+                    s->hello_retry_request = SSL_HRR_PENDING;
+                    return 1;
+                }
+            }
+            if (!s->hit
+                    || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) == 0) {
+                /* Nothing left we can do - just fail */
+                SSLfatal(s, sent ? SSL_AD_HANDSHAKE_FAILURE
+                                 : SSL_AD_MISSING_EXTENSION,
+                         SSL_F_FINAL_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
+                return 0;
+            }
+
+            if ((s->s3->flags & TLS1_FLAGS_STATELESS) != 0
+                    && !s->ext.cookieok) {
+                if (!ossl_assert(s->hello_retry_request == SSL_HRR_NONE)) {
+                    /*
+                     * If we are stateless then we wouldn't know about any
+                     * previously sent HRR - so how can this be anything other
+                     * than 0?
+                     */
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_FINAL_KEY_SHARE,
+                             ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+                s->hello_retry_request = SSL_HRR_PENDING;
+                return 1;
+            }
+        }
+
+        /*
+         * We have a key_share so don't send any more HelloRetryRequest
+         * messages
+         */
+        if (s->hello_retry_request == SSL_HRR_PENDING)
+            s->hello_retry_request = SSL_HRR_COMPLETE;
+    } else {
+        /*
+         * For a client side resumption with no key_share we need to generate
+         * the handshake secret (otherwise this is done during key_share
+         * processing).
+         */
+        if (!sent && !tls13_generate_handshake_secret(s, NULL, 0)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_FINAL_KEY_SHARE,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif
+
+static int init_psk_kex_modes(SSL *s, unsigned int context)
+{
+    s->ext.psk_kex_mode = TLSEXT_KEX_MODE_FLAG_NONE;
+    return 1;
+}
+
+int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
+                      size_t binderoffset, const unsigned char *binderin,
+                      unsigned char *binderout, SSL_SESSION *sess, int sign,
+                      int external)
+{
+    EVP_PKEY *mackey = NULL;
+    EVP_MD_CTX *mctx = NULL;
+    unsigned char hash[EVP_MAX_MD_SIZE], binderkey[EVP_MAX_MD_SIZE];
+    unsigned char finishedkey[EVP_MAX_MD_SIZE], tmpbinder[EVP_MAX_MD_SIZE];
+    unsigned char *early_secret;
+#ifdef CHARSET_EBCDIC
+    static const unsigned char resumption_label[] = { 0x72, 0x65, 0x73, 0x20, 0x62, 0x69, 0x6E, 0x64, 0x65, 0x72, 0x00 };
+    static const unsigned char external_label[]   = { 0x65, 0x78, 0x74, 0x20, 0x62, 0x69, 0x6E, 0x64, 0x65, 0x72, 0x00 };
+#else
+    static const unsigned char resumption_label[] = "res binder";
+    static const unsigned char external_label[] = "ext binder";
+#endif
+    const unsigned char *label;
+    size_t bindersize, labelsize, hashsize;
+    int hashsizei = EVP_MD_size(md);
+    int ret = -1;
+    int usepskfored = 0;
+
+    /* Ensure cast to size_t is safe */
+    if (!ossl_assert(hashsizei >= 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PSK_DO_BINDER,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    hashsize = (size_t)hashsizei;
+
+    if (external
+            && s->early_data_state == SSL_EARLY_DATA_CONNECTING
+            && s->session->ext.max_early_data == 0
+            && sess->ext.max_early_data > 0)
+        usepskfored = 1;
+
+    if (external) {
+        label = external_label;
+        labelsize = sizeof(external_label) - 1;
+    } else {
+        label = resumption_label;
+        labelsize = sizeof(resumption_label) - 1;
+    }
+
+    /*
+     * Generate the early_secret. On the server side we've selected a PSK to
+     * resume with (internal or external) so we always do this. On the client
+     * side we do this for a non-external (i.e. resumption) PSK or external PSK
+     * that will be used for early_data so that it is in place for sending early
+     * data. For client side external PSK not being used for early_data we
+     * generate it but store it away for later use.
+     */
+    if (s->server || !external || usepskfored)
+        early_secret = (unsigned char *)s->early_secret;
+    else
+        early_secret = (unsigned char *)sess->early_secret;
+
+    if (!tls13_generate_secret(s, md, NULL, sess->master_key,
+                               sess->master_key_length, early_secret)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    /*
+     * Create the handshake hash for the binder key...the messages so far are
+     * empty!
+     */
+    mctx = EVP_MD_CTX_new();
+    if (mctx == NULL
+            || EVP_DigestInit_ex(mctx, md, NULL) <= 0
+            || EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PSK_DO_BINDER,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /* Generate the binder key */
+    if (!tls13_hkdf_expand(s, md, early_secret, label, labelsize, hash,
+                           hashsize, binderkey, hashsize, 1)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    /* Generate the finished key */
+    if (!tls13_derive_finishedkey(s, md, binderkey, finishedkey, hashsize)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    if (EVP_DigestInit_ex(mctx, md, NULL) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PSK_DO_BINDER,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /*
+     * Get a hash of the ClientHello up to the start of the binders. If we are
+     * following a HelloRetryRequest then this includes the hash of the first
+     * ClientHello and the HelloRetryRequest itself.
+     */
+    if (s->hello_retry_request == SSL_HRR_PENDING) {
+        size_t hdatalen;
+        long hdatalen_l;
+        void *hdata;
+
+        hdatalen = hdatalen_l =
+            BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+        if (hdatalen_l <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PSK_DO_BINDER,
+                     SSL_R_BAD_HANDSHAKE_LENGTH);
+            goto err;
+        }
+
+        /*
+         * For servers the handshake buffer data will include the second
+         * ClientHello - which we don't want - so we need to take that bit off.
+         */
+        if (s->server) {
+            PACKET hashprefix, msg;
+
+            /* Find how many bytes are left after the first two messages */
+            if (!PACKET_buf_init(&hashprefix, hdata, hdatalen)
+                    || !PACKET_forward(&hashprefix, 1)
+                    || !PACKET_get_length_prefixed_3(&hashprefix, &msg)
+                    || !PACKET_forward(&hashprefix, 1)
+                    || !PACKET_get_length_prefixed_3(&hashprefix, &msg)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PSK_DO_BINDER,
+                         ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            hdatalen -= PACKET_remaining(&hashprefix);
+        }
+
+        if (EVP_DigestUpdate(mctx, hdata, hdatalen) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PSK_DO_BINDER,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+
+    if (EVP_DigestUpdate(mctx, msgstart, binderoffset) <= 0
+            || EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PSK_DO_BINDER,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    mackey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, finishedkey,
+                                          hashsize);
+    if (mackey == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PSK_DO_BINDER,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (!sign)
+        binderout = tmpbinder;
+
+    bindersize = hashsize;
+    if (EVP_DigestSignInit(mctx, NULL, md, NULL, mackey) <= 0
+            || EVP_DigestSignUpdate(mctx, hash, hashsize) <= 0
+            || EVP_DigestSignFinal(mctx, binderout, &bindersize) <= 0
+            || bindersize != hashsize) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PSK_DO_BINDER,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (sign) {
+        ret = 1;
+    } else {
+        /* HMAC keys can't do EVP_DigestVerify* - use CRYPTO_memcmp instead */
+        ret = (CRYPTO_memcmp(binderin, binderout, hashsize) == 0);
+        if (!ret)
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PSK_DO_BINDER,
+                     SSL_R_BINDER_DOES_NOT_VERIFY);
+    }
+
+ err:
+    OPENSSL_cleanse(binderkey, sizeof(binderkey));
+    OPENSSL_cleanse(finishedkey, sizeof(finishedkey));
+    EVP_PKEY_free(mackey);
+    EVP_MD_CTX_free(mctx);
+
+    return ret;
+}
+
+static int final_early_data(SSL *s, unsigned int context, int sent)
+{
+    if (!sent)
+        return 1;
+
+    if (!s->server) {
+        if (context == SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+                && sent
+                && !s->ext.early_data_ok) {
+            /*
+             * If we get here then the server accepted our early_data but we
+             * later realised that it shouldn't have done (e.g. inconsistent
+             * ALPN)
+             */
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_FINAL_EARLY_DATA,
+                     SSL_R_BAD_EARLY_DATA);
+            return 0;
+        }
+
+        return 1;
+    }
+
+    if (s->max_early_data == 0
+            || !s->hit
+            || s->early_data_state != SSL_EARLY_DATA_ACCEPTING
+            || !s->ext.early_data_ok
+            || s->hello_retry_request != SSL_HRR_NONE
+            || (s->allow_early_data_cb != NULL
+                && !s->allow_early_data_cb(s,
+                                         s->allow_early_data_cb_data))) {
+        s->ext.early_data = SSL_EARLY_DATA_REJECTED;
+    } else {
+        s->ext.early_data = SSL_EARLY_DATA_ACCEPTED;
+
+        if (!tls13_change_cipher_state(s,
+                    SSL3_CC_EARLY | SSL3_CHANGE_CIPHER_SERVER_READ)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+static int final_maxfragmentlen(SSL *s, unsigned int context, int sent)
+{
+    /*
+     * Session resumption on server-side with MFL extension active
+     *  BUT MFL extension packet was not resent (i.e. sent == 0)
+     */
+    if (s->server && s->hit && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)
+            && !sent ) {
+        SSLfatal(s, SSL_AD_MISSING_EXTENSION, SSL_F_FINAL_MAXFRAGMENTLEN,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    /* Current SSL buffer is lower than requested MFL */
+    if (s->session && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)
+            && s->max_send_fragment < GET_MAX_FRAGMENT_LENGTH(s->session))
+        /* trigger a larger buffer reallocation */
+        if (!ssl3_setup_buffers(s)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+
+    return 1;
+}
+
+static int init_post_handshake_auth(SSL *s, unsigned int context)
+{
+    s->post_handshake_auth = SSL_PHA_NONE;
+
+    return 1;
+}
+
+/*
+ * If clients offer "pre_shared_key" without a "psk_key_exchange_modes"
+ * extension, servers MUST abort the handshake.
+ */
+static int final_psk(SSL *s, unsigned int context, int sent)
+{
+    if (s->server && sent && s->clienthello != NULL
+            && !s->clienthello->pre_proc_exts[TLSEXT_IDX_psk_kex_modes].present) {
+        SSLfatal(s, TLS13_AD_MISSING_EXTENSION, SSL_F_FINAL_PSK,
+                 SSL_R_MISSING_PSK_KEX_MODES_EXTENSION);
+        return 0;
+    }
+
+    return 1;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/statem/extensions_clnt.c b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/extensions_clnt.c
new file mode 100644
index 0000000..1cbaefa
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/extensions_clnt.c
@@ -0,0 +1,2027 @@
+/*
+ * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/ocsp.h>
+#include "../ssl_local.h"
+#include "internal/cryptlib.h"
+#include "statem_local.h"
+
+EXT_RETURN tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
+                                          size_t chainidx)
+{
+    /* Add RI if renegotiating */
+    if (!s->renegotiate)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u8(pkt, s->s3->previous_client_finished,
+                               s->s3->previous_client_finished_len)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+EXT_RETURN tls_construct_ctos_server_name(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
+                                          size_t chainidx)
+{
+    if (s->ext.hostname == NULL)
+        return EXT_RETURN_NOT_SENT;
+
+    /* Add TLS extension servername to the Client Hello message */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name)
+               /* Sub-packet for server_name extension */
+            || !WPACKET_start_sub_packet_u16(pkt)
+               /* Sub-packet for servername list (always 1 hostname)*/
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u8(pkt, TLSEXT_NAMETYPE_host_name)
+            || !WPACKET_sub_memcpy_u16(pkt, s->ext.hostname,
+                                       strlen(s->ext.hostname))
+            || !WPACKET_close(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+/* Push a Max Fragment Len extension into ClientHello */
+EXT_RETURN tls_construct_ctos_maxfragmentlen(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx)
+{
+    if (s->ext.max_fragment_len_mode == TLSEXT_max_fragment_length_DISABLED)
+        return EXT_RETURN_NOT_SENT;
+
+    /* Add Max Fragment Length extension if client enabled it. */
+    /*-
+     * 4 bytes for this extension type and extension length
+     * 1 byte for the Max Fragment Length code value.
+     */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_max_fragment_length)
+            /* Sub-packet for Max Fragment Length extension (1 byte) */
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u8(pkt, s->ext.max_fragment_len_mode)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CTOS_MAXFRAGMENTLEN, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+#ifndef OPENSSL_NO_SRP
+EXT_RETURN tls_construct_ctos_srp(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    /* Add SRP username if there is one */
+    if (s->srp_ctx.login == NULL)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_srp)
+               /* Sub-packet for SRP extension */
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u8(pkt)
+               /* login must not be zero...internal error if so */
+            || !WPACKET_set_flags(pkt, WPACKET_FLAGS_NON_ZERO_LENGTH)
+            || !WPACKET_memcpy(pkt, s->srp_ctx.login,
+                               strlen(s->srp_ctx.login))
+            || !WPACKET_close(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_SRP,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+#endif
+
+#ifndef OPENSSL_NO_EC
+static int use_ecc(SSL *s)
+{
+    int i, end, ret = 0;
+    unsigned long alg_k, alg_a;
+    STACK_OF(SSL_CIPHER) *cipher_stack = NULL;
+    const uint16_t *pgroups = NULL;
+    size_t num_groups, j;
+
+    /* See if we support any ECC ciphersuites */
+    if (s->version == SSL3_VERSION)
+        return 0;
+
+    cipher_stack = SSL_get1_supported_ciphers(s);
+    end = sk_SSL_CIPHER_num(cipher_stack);
+    for (i = 0; i < end; i++) {
+        const SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
+
+        alg_k = c->algorithm_mkey;
+        alg_a = c->algorithm_auth;
+        if ((alg_k & (SSL_kECDHE | SSL_kECDHEPSK))
+                || (alg_a & SSL_aECDSA)
+                || c->min_tls >= TLS1_3_VERSION) {
+            ret = 1;
+            break;
+        }
+    }
+
+    sk_SSL_CIPHER_free(cipher_stack);
+    if (!ret)
+        return 0;
+
+    /* Check we have at least one EC supported group */
+    tls1_get_supported_groups(s, &pgroups, &num_groups);
+    for (j = 0; j < num_groups; j++) {
+        uint16_t ctmp = pgroups[j];
+
+        if (tls_curve_allowed(s, ctmp, SSL_SECOP_CURVE_SUPPORTED))
+            return 1;
+    }
+
+    return 0;
+}
+
+EXT_RETURN tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx)
+{
+    const unsigned char *pformats;
+    size_t num_formats;
+
+    if (!use_ecc(s))
+        return EXT_RETURN_NOT_SENT;
+
+    /* Add TLS extension ECPointFormats to the ClientHello message */
+    tls1_get_formatlist(s, &pformats, &num_formats);
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_ec_point_formats)
+               /* Sub-packet for formats extension */
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u8(pkt, pformats, num_formats)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CTOS_EC_PT_FORMATS, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+EXT_RETURN tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
+                                               unsigned int context, X509 *x,
+                                               size_t chainidx)
+{
+    const uint16_t *pgroups = NULL;
+    size_t num_groups = 0, i;
+
+    if (!use_ecc(s))
+        return EXT_RETURN_NOT_SENT;
+
+    /*
+     * Add TLS extension supported_groups to the ClientHello message
+     */
+    /* TODO(TLS1.3): Add support for DHE groups */
+    tls1_get_supported_groups(s, &pgroups, &num_groups);
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_groups)
+               /* Sub-packet for supported_groups extension */
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+    /* Copy curve ID if supported */
+    for (i = 0; i < num_groups; i++) {
+        uint16_t ctmp = pgroups[i];
+
+        if (tls_curve_allowed(s, ctmp, SSL_SECOP_CURVE_SUPPORTED)) {
+            if (!WPACKET_put_bytes_u16(pkt, ctmp)) {
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                             SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
+                             ERR_R_INTERNAL_ERROR);
+                    return EXT_RETURN_FAIL;
+                }
+        }
+    }
+    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+#endif
+
+EXT_RETURN tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx)
+{
+    size_t ticklen;
+
+    if (!tls_use_ticket(s))
+        return EXT_RETURN_NOT_SENT;
+
+    if (!s->new_session && s->session != NULL
+            && s->session->ext.tick != NULL
+            && s->session->ssl_version != TLS1_3_VERSION) {
+        ticklen = s->session->ext.ticklen;
+    } else if (s->session && s->ext.session_ticket != NULL
+               && s->ext.session_ticket->data != NULL) {
+        ticklen = s->ext.session_ticket->length;
+        s->session->ext.tick = OPENSSL_malloc(ticklen);
+        if (s->session->ext.tick == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_CTOS_SESSION_TICKET,
+                     ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+        memcpy(s->session->ext.tick,
+               s->ext.session_ticket->data, ticklen);
+        s->session->ext.ticklen = ticklen;
+    } else {
+        ticklen = 0;
+    }
+
+    if (ticklen == 0 && s->ext.session_ticket != NULL &&
+            s->ext.session_ticket->data == NULL)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket)
+            || !WPACKET_sub_memcpy_u16(pkt, s->session->ext.tick, ticklen)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CTOS_SESSION_TICKET, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+EXT_RETURN tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt,
+                                       unsigned int context, X509 *x,
+                                       size_t chainidx)
+{
+    size_t salglen;
+    const uint16_t *salg;
+
+    if (!SSL_CLIENT_USE_SIGALGS(s))
+        return EXT_RETURN_NOT_SENT;
+
+    salglen = tls12_get_psigalgs(s, 1, &salg);
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_signature_algorithms)
+               /* Sub-packet for sig-algs extension */
+            || !WPACKET_start_sub_packet_u16(pkt)
+               /* Sub-packet for the actual list */
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !tls12_copy_sigalgs(s, pkt, salg, salglen)
+            || !WPACKET_close(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_SIG_ALGS,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+#ifndef OPENSSL_NO_OCSP
+EXT_RETURN tls_construct_ctos_status_request(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx)
+{
+    int i;
+
+    /* This extension isn't defined for client Certificates */
+    if (x != NULL)
+        return EXT_RETURN_NOT_SENT;
+
+    if (s->ext.status_type != TLSEXT_STATUSTYPE_ocsp)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request)
+               /* Sub-packet for status request extension */
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u8(pkt, TLSEXT_STATUSTYPE_ocsp)
+               /* Sub-packet for the ids */
+            || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+    for (i = 0; i < sk_OCSP_RESPID_num(s->ext.ocsp.ids); i++) {
+        unsigned char *idbytes;
+        OCSP_RESPID *id = sk_OCSP_RESPID_value(s->ext.ocsp.ids, i);
+        int idlen = i2d_OCSP_RESPID(id, NULL);
+
+        if (idlen <= 0
+                   /* Sub-packet for an individual id */
+                || !WPACKET_sub_allocate_bytes_u16(pkt, idlen, &idbytes)
+                || i2d_OCSP_RESPID(id, &idbytes) != idlen) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST,
+                     ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+    }
+    if (!WPACKET_close(pkt)
+            || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+    if (s->ext.ocsp.exts) {
+        unsigned char *extbytes;
+        int extlen = i2d_X509_EXTENSIONS(s->ext.ocsp.exts, NULL);
+
+        if (extlen < 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST,
+                     ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+        if (!WPACKET_allocate_bytes(pkt, extlen, &extbytes)
+                || i2d_X509_EXTENSIONS(s->ext.ocsp.exts, &extbytes)
+                   != extlen) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST,
+                     ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+       }
+    }
+    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+#endif
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+EXT_RETURN tls_construct_ctos_npn(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    if (s->ctx->ext.npn_select_cb == NULL || !SSL_IS_FIRST_HANDSHAKE(s))
+        return EXT_RETURN_NOT_SENT;
+
+    /*
+     * The client advertises an empty extension to indicate its support
+     * for Next Protocol Negotiation
+     */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_NPN,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+#endif
+
+EXT_RETURN tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx)
+{
+    s->s3->alpn_sent = 0;
+
+    if (s->ext.alpn == NULL || !SSL_IS_FIRST_HANDSHAKE(s))
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt,
+                TLSEXT_TYPE_application_layer_protocol_negotiation)
+               /* Sub-packet ALPN extension */
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u16(pkt, s->ext.alpn, s->ext.alpn_len)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_ALPN,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+    s->s3->alpn_sent = 1;
+
+    return EXT_RETURN_SENT;
+}
+
+
+#ifndef OPENSSL_NO_SRTP
+EXT_RETURN tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt,
+                                       unsigned int context, X509 *x,
+                                       size_t chainidx)
+{
+    STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = SSL_get_srtp_profiles(s);
+    int i, end;
+
+    if (clnt == NULL)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_use_srtp)
+               /* Sub-packet for SRTP extension */
+            || !WPACKET_start_sub_packet_u16(pkt)
+               /* Sub-packet for the protection profile list */
+            || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_USE_SRTP,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    end = sk_SRTP_PROTECTION_PROFILE_num(clnt);
+    for (i = 0; i < end; i++) {
+        const SRTP_PROTECTION_PROFILE *prof =
+            sk_SRTP_PROTECTION_PROFILE_value(clnt, i);
+
+        if (prof == NULL || !WPACKET_put_bytes_u16(pkt, prof->id)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_CTOS_USE_SRTP, ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+    }
+    if (!WPACKET_close(pkt)
+               /* Add an empty use_mki value */
+            || !WPACKET_put_bytes_u8(pkt, 0)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_USE_SRTP,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+#endif
+
+EXT_RETURN tls_construct_ctos_etm(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    if (s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_encrypt_then_mac)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_ETM,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+#ifndef OPENSSL_NO_CT
+EXT_RETURN tls_construct_ctos_sct(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    if (s->ct_validation_callback == NULL)
+        return EXT_RETURN_NOT_SENT;
+
+    /* Not defined for client Certificates */
+    if (x != NULL)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_signed_certificate_timestamp)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_SCT,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+#endif
+
+EXT_RETURN tls_construct_ctos_ems(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_EMS,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+EXT_RETURN tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt,
+                                                 unsigned int context, X509 *x,
+                                                 size_t chainidx)
+{
+    int currv, min_version, max_version, reason;
+
+    reason = ssl_get_min_max_version(s, &min_version, &max_version, NULL);
+    if (reason != 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS, reason);
+        return EXT_RETURN_FAIL;
+    }
+
+    /*
+     * Don't include this if we can't negotiate TLSv1.3. We can do a straight
+     * comparison here because we will never be called in DTLS.
+     */
+    if (max_version < TLS1_3_VERSION)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_versions)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u8(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    for (currv = max_version; currv >= min_version; currv--) {
+        if (!WPACKET_put_bytes_u16(pkt, currv)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS,
+                     ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+    }
+    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+/*
+ * Construct a psk_kex_modes extension.
+ */
+EXT_RETURN tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    int nodhe = s->options & SSL_OP_ALLOW_NO_DHE_KEX;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_psk_kex_modes)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u8(pkt)
+            || !WPACKET_put_bytes_u8(pkt, TLSEXT_KEX_MODE_KE_DHE)
+            || (nodhe && !WPACKET_put_bytes_u8(pkt, TLSEXT_KEX_MODE_KE))
+            || !WPACKET_close(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    s->ext.psk_kex_mode = TLSEXT_KEX_MODE_FLAG_KE_DHE;
+    if (nodhe)
+        s->ext.psk_kex_mode |= TLSEXT_KEX_MODE_FLAG_KE;
+#endif
+
+    return EXT_RETURN_SENT;
+}
+
+#ifndef OPENSSL_NO_TLS1_3
+static int add_key_share(SSL *s, WPACKET *pkt, unsigned int curve_id)
+{
+    unsigned char *encoded_point = NULL;
+    EVP_PKEY *key_share_key = NULL;
+    size_t encodedlen;
+
+    if (s->s3->tmp.pkey != NULL) {
+        if (!ossl_assert(s->hello_retry_request == SSL_HRR_PENDING)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_ADD_KEY_SHARE,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        /*
+         * Could happen if we got an HRR that wasn't requesting a new key_share
+         */
+        key_share_key = s->s3->tmp.pkey;
+    } else {
+        key_share_key = ssl_generate_pkey_group(s, curve_id);
+        if (key_share_key == NULL) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+    }
+
+    /* Encode the public key. */
+    encodedlen = EVP_PKEY_get1_tls_encodedpoint(key_share_key,
+                                                &encoded_point);
+    if (encodedlen == 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_ADD_KEY_SHARE, ERR_R_EC_LIB);
+        goto err;
+    }
+
+    /* Create KeyShareEntry */
+    if (!WPACKET_put_bytes_u16(pkt, curve_id)
+            || !WPACKET_sub_memcpy_u16(pkt, encoded_point, encodedlen)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_ADD_KEY_SHARE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /*
+     * TODO(TLS1.3): When changing to send more than one key_share we're
+     * going to need to be able to save more than one EVP_PKEY. For now
+     * we reuse the existing tmp.pkey
+     */
+    s->s3->tmp.pkey = key_share_key;
+    s->s3->group_id = curve_id;
+    OPENSSL_free(encoded_point);
+
+    return 1;
+ err:
+    if (s->s3->tmp.pkey == NULL)
+        EVP_PKEY_free(key_share_key);
+    OPENSSL_free(encoded_point);
+    return 0;
+}
+#endif
+
+EXT_RETURN tls_construct_ctos_key_share(SSL *s, WPACKET *pkt,
+                                        unsigned int context, X509 *x,
+                                        size_t chainidx)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    size_t i, num_groups = 0;
+    const uint16_t *pgroups = NULL;
+    uint16_t curve_id = 0;
+
+    /* key_share extension */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
+               /* Extension data sub-packet */
+            || !WPACKET_start_sub_packet_u16(pkt)
+               /* KeyShare list sub-packet */
+            || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    tls1_get_supported_groups(s, &pgroups, &num_groups);
+
+    /*
+     * TODO(TLS1.3): Make the number of key_shares sent configurable. For
+     * now, just send one
+     */
+    if (s->s3->group_id != 0) {
+        curve_id = s->s3->group_id;
+    } else {
+        for (i = 0; i < num_groups; i++) {
+
+            if (!tls_curve_allowed(s, pgroups[i], SSL_SECOP_CURVE_SUPPORTED))
+                continue;
+
+            curve_id = pgroups[i];
+            break;
+        }
+    }
+
+    if (curve_id == 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE,
+                 SSL_R_NO_SUITABLE_KEY_SHARE);
+        return EXT_RETURN_FAIL;
+    }
+
+    if (!add_key_share(s, pkt, curve_id)) {
+        /* SSLfatal() already called */
+        return EXT_RETURN_FAIL;
+    }
+
+    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+    return EXT_RETURN_SENT;
+#else
+    return EXT_RETURN_NOT_SENT;
+#endif
+}
+
+EXT_RETURN tls_construct_ctos_cookie(SSL *s, WPACKET *pkt, unsigned int context,
+                                     X509 *x, size_t chainidx)
+{
+    EXT_RETURN ret = EXT_RETURN_FAIL;
+
+    /* Should only be set if we've had an HRR */
+    if (s->ext.tls13_cookie_len == 0)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_cookie)
+               /* Extension data sub-packet */
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u16(pkt, s->ext.tls13_cookie,
+                                       s->ext.tls13_cookie_len)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_COOKIE,
+                 ERR_R_INTERNAL_ERROR);
+        goto end;
+    }
+
+    ret = EXT_RETURN_SENT;
+ end:
+    OPENSSL_free(s->ext.tls13_cookie);
+    s->ext.tls13_cookie = NULL;
+    s->ext.tls13_cookie_len = 0;
+
+    return ret;
+}
+
+EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt,
+                                         unsigned int context, X509 *x,
+                                         size_t chainidx)
+{
+#ifndef OPENSSL_NO_PSK
+    char identity[PSK_MAX_IDENTITY_LEN + 1];
+#endif  /* OPENSSL_NO_PSK */
+    const unsigned char *id = NULL;
+    size_t idlen = 0;
+    SSL_SESSION *psksess = NULL;
+    SSL_SESSION *edsess = NULL;
+    const EVP_MD *handmd = NULL;
+
+    if (s->hello_retry_request == SSL_HRR_PENDING)
+        handmd = ssl_handshake_md(s);
+
+    if (s->psk_use_session_cb != NULL
+            && (!s->psk_use_session_cb(s, handmd, &id, &idlen, &psksess)
+                || (psksess != NULL
+                    && psksess->ssl_version != TLS1_3_VERSION))) {
+        SSL_SESSION_free(psksess);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA,
+                 SSL_R_BAD_PSK);
+        return EXT_RETURN_FAIL;
+    }
+
+#ifndef OPENSSL_NO_PSK
+    if (psksess == NULL && s->psk_client_callback != NULL) {
+        unsigned char psk[PSK_MAX_PSK_LEN];
+        size_t psklen = 0;
+
+        memset(identity, 0, sizeof(identity));
+        psklen = s->psk_client_callback(s, NULL, identity, sizeof(identity) - 1,
+                                        psk, sizeof(psk));
+
+        if (psklen > PSK_MAX_PSK_LEN) {
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                     SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA, ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        } else if (psklen > 0) {
+            const unsigned char tls13_aes128gcmsha256_id[] = { 0x13, 0x01 };
+            const SSL_CIPHER *cipher;
+
+            idlen = strlen(identity);
+            if (idlen > PSK_MAX_IDENTITY_LEN) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA,
+                         ERR_R_INTERNAL_ERROR);
+                return EXT_RETURN_FAIL;
+            }
+            id = (unsigned char *)identity;
+
+            /*
+             * We found a PSK using an old style callback. We don't know
+             * the digest so we default to SHA256 as per the TLSv1.3 spec
+             */
+            cipher = SSL_CIPHER_find(s, tls13_aes128gcmsha256_id);
+            if (cipher == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA,
+                         ERR_R_INTERNAL_ERROR);
+                return EXT_RETURN_FAIL;
+            }
+
+            psksess = SSL_SESSION_new();
+            if (psksess == NULL
+                    || !SSL_SESSION_set1_master_key(psksess, psk, psklen)
+                    || !SSL_SESSION_set_cipher(psksess, cipher)
+                    || !SSL_SESSION_set_protocol_version(psksess, TLS1_3_VERSION)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA,
+                         ERR_R_INTERNAL_ERROR);
+                OPENSSL_cleanse(psk, psklen);
+                return EXT_RETURN_FAIL;
+            }
+            OPENSSL_cleanse(psk, psklen);
+        }
+    }
+#endif  /* OPENSSL_NO_PSK */
+
+    SSL_SESSION_free(s->psksession);
+    s->psksession = psksess;
+    if (psksess != NULL) {
+        OPENSSL_free(s->psksession_id);
+        s->psksession_id = OPENSSL_memdup(id, idlen);
+        if (s->psksession_id == NULL) {
+            s->psksession_id_len = 0;
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA, ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+        s->psksession_id_len = idlen;
+    }
+
+    if (s->early_data_state != SSL_EARLY_DATA_CONNECTING
+            || (s->session->ext.max_early_data == 0
+                && (psksess == NULL || psksess->ext.max_early_data == 0))) {
+        s->max_early_data = 0;
+        return EXT_RETURN_NOT_SENT;
+    }
+    edsess = s->session->ext.max_early_data != 0 ? s->session : psksess;
+    s->max_early_data = edsess->ext.max_early_data;
+
+    if (edsess->ext.hostname != NULL) {
+        if (s->ext.hostname == NULL
+                || (s->ext.hostname != NULL
+                    && strcmp(s->ext.hostname, edsess->ext.hostname) != 0)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA,
+                     SSL_R_INCONSISTENT_EARLY_DATA_SNI);
+            return EXT_RETURN_FAIL;
+        }
+    }
+
+    if ((s->ext.alpn == NULL && edsess->ext.alpn_selected != NULL)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA,
+                 SSL_R_INCONSISTENT_EARLY_DATA_ALPN);
+        return EXT_RETURN_FAIL;
+    }
+
+    /*
+     * Verify that we are offering an ALPN protocol consistent with the early
+     * data.
+     */
+    if (edsess->ext.alpn_selected != NULL) {
+        PACKET prots, alpnpkt;
+        int found = 0;
+
+        if (!PACKET_buf_init(&prots, s->ext.alpn, s->ext.alpn_len)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA, ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+        while (PACKET_get_length_prefixed_1(&prots, &alpnpkt)) {
+            if (PACKET_equal(&alpnpkt, edsess->ext.alpn_selected,
+                             edsess->ext.alpn_selected_len)) {
+                found = 1;
+                break;
+            }
+        }
+        if (!found) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA,
+                     SSL_R_INCONSISTENT_EARLY_DATA_ALPN);
+            return EXT_RETURN_FAIL;
+        }
+    }
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    /*
+     * We set this to rejected here. Later, if the server acknowledges the
+     * extension, we set it to accepted.
+     */
+    s->ext.early_data = SSL_EARLY_DATA_REJECTED;
+    s->ext.early_data_ok = 1;
+
+    return EXT_RETURN_SENT;
+}
+
+#define F5_WORKAROUND_MIN_MSG_LEN   0xff
+#define F5_WORKAROUND_MAX_MSG_LEN   0x200
+
+/*
+ * PSK pre binder overhead =
+ *  2 bytes for TLSEXT_TYPE_psk
+ *  2 bytes for extension length
+ *  2 bytes for identities list length
+ *  2 bytes for identity length
+ *  4 bytes for obfuscated_ticket_age
+ *  2 bytes for binder list length
+ *  1 byte for binder length
+ * The above excludes the number of bytes for the identity itself and the
+ * subsequent binder bytes
+ */
+#define PSK_PRE_BINDER_OVERHEAD (2 + 2 + 2 + 2 + 4 + 2 + 1)
+
+EXT_RETURN tls_construct_ctos_padding(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
+                                      size_t chainidx)
+{
+    unsigned char *padbytes;
+    size_t hlen;
+
+    if ((s->options & SSL_OP_TLSEXT_PADDING) == 0)
+        return EXT_RETURN_NOT_SENT;
+
+    /*
+     * Add padding to workaround bugs in F5 terminators. See RFC7685.
+     * This code calculates the length of all extensions added so far but
+     * excludes the PSK extension (because that MUST be written last). Therefore
+     * this extension MUST always appear second to last.
+     */
+    if (!WPACKET_get_total_written(pkt, &hlen)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_PADDING,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    /*
+     * If we're going to send a PSK then that will be written out after this
+     * extension, so we need to calculate how long it is going to be.
+     */
+    if (s->session->ssl_version == TLS1_3_VERSION
+            && s->session->ext.ticklen != 0
+            && s->session->cipher != NULL) {
+        const EVP_MD *md = ssl_md(s->session->cipher->algorithm2);
+
+        if (md != NULL) {
+            /*
+             * Add the fixed PSK overhead, the identity length and the binder
+             * length.
+             */
+            hlen +=  PSK_PRE_BINDER_OVERHEAD + s->session->ext.ticklen
+                     + EVP_MD_size(md);
+        }
+    }
+
+    if (hlen > F5_WORKAROUND_MIN_MSG_LEN && hlen < F5_WORKAROUND_MAX_MSG_LEN) {
+        /* Calculate the amount of padding we need to add */
+        hlen = F5_WORKAROUND_MAX_MSG_LEN - hlen;
+
+        /*
+         * Take off the size of extension header itself (2 bytes for type and
+         * 2 bytes for length bytes), but ensure that the extension is at least
+         * 1 byte long so as not to have an empty extension last (WebSphere 7.x,
+         * 8.x are intolerant of that condition)
+         */
+        if (hlen > 4)
+            hlen -= 4;
+        else
+            hlen = 1;
+
+        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_padding)
+                || !WPACKET_sub_allocate_bytes_u16(pkt, hlen, &padbytes)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_PADDING,
+                     ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+        memset(padbytes, 0, hlen);
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+/*
+ * Construct the pre_shared_key extension
+ */
+EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    uint32_t agesec, agems = 0;
+    size_t reshashsize = 0, pskhashsize = 0, binderoffset, msglen;
+    unsigned char *resbinder = NULL, *pskbinder = NULL, *msgstart = NULL;
+    const EVP_MD *handmd = NULL, *mdres = NULL, *mdpsk = NULL;
+    int dores = 0;
+
+    s->ext.tick_identity = 0;
+
+    /*
+     * Note: At this stage of the code we only support adding a single
+     * resumption PSK. If we add support for multiple PSKs then the length
+     * calculations in the padding extension will need to be adjusted.
+     */
+
+    /*
+     * If this is an incompatible or new session then we have nothing to resume
+     * so don't add this extension.
+     */
+    if (s->session->ssl_version != TLS1_3_VERSION
+            || (s->session->ext.ticklen == 0 && s->psksession == NULL))
+        return EXT_RETURN_NOT_SENT;
+
+    if (s->hello_retry_request == SSL_HRR_PENDING)
+        handmd = ssl_handshake_md(s);
+
+    if (s->session->ext.ticklen != 0) {
+        /* Get the digest associated with the ciphersuite in the session */
+        if (s->session->cipher == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_PSK,
+                     ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+        mdres = ssl_md(s->session->cipher->algorithm2);
+        if (mdres == NULL) {
+            /*
+             * Don't recognize this cipher so we can't use the session.
+             * Ignore it
+             */
+            goto dopsksess;
+        }
+
+        if (s->hello_retry_request == SSL_HRR_PENDING && mdres != handmd) {
+            /*
+             * Selected ciphersuite hash does not match the hash for the session
+             * so we can't use it.
+             */
+            goto dopsksess;
+        }
+
+        /*
+         * Technically the C standard just says time() returns a time_t and says
+         * nothing about the encoding of that type. In practice most
+         * implementations follow POSIX which holds it as an integral type in
+         * seconds since epoch. We've already made the assumption that we can do
+         * this in multiple places in the code, so portability shouldn't be an
+         * issue.
+         */
+        agesec = (uint32_t)(time(NULL) - s->session->time);
+        /*
+         * We calculate the age in seconds but the server may work in ms. Due to
+         * rounding errors we could overestimate the age by up to 1s. It is
+         * better to underestimate it. Otherwise, if the RTT is very short, when
+         * the server calculates the age reported by the client it could be
+         * bigger than the age calculated on the server - which should never
+         * happen.
+         */
+        if (agesec > 0)
+            agesec--;
+
+        if (s->session->ext.tick_lifetime_hint < agesec) {
+            /* Ticket is too old. Ignore it. */
+            goto dopsksess;
+        }
+
+        /*
+         * Calculate age in ms. We're just doing it to nearest second. Should be
+         * good enough.
+         */
+        agems = agesec * (uint32_t)1000;
+
+        if (agesec != 0 && agems / (uint32_t)1000 != agesec) {
+            /*
+             * Overflow. Shouldn't happen unless this is a *really* old session.
+             * If so we just ignore it.
+             */
+            goto dopsksess;
+        }
+
+        /*
+         * Obfuscate the age. Overflow here is fine, this addition is supposed
+         * to be mod 2^32.
+         */
+        agems += s->session->ext.tick_age_add;
+
+        reshashsize = EVP_MD_size(mdres);
+        s->ext.tick_identity++;
+        dores = 1;
+    }
+
+ dopsksess:
+    if (!dores && s->psksession == NULL)
+        return EXT_RETURN_NOT_SENT;
+
+    if (s->psksession != NULL) {
+        mdpsk = ssl_md(s->psksession->cipher->algorithm2);
+        if (mdpsk == NULL) {
+            /*
+             * Don't recognize this cipher so we can't use the session.
+             * If this happens it's an application bug.
+             */
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_PSK,
+                     SSL_R_BAD_PSK);
+            return EXT_RETURN_FAIL;
+        }
+
+        if (s->hello_retry_request == SSL_HRR_PENDING && mdpsk != handmd) {
+            /*
+             * Selected ciphersuite hash does not match the hash for the PSK
+             * session. This is an application bug.
+             */
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_PSK,
+                     SSL_R_BAD_PSK);
+            return EXT_RETURN_FAIL;
+        }
+
+        pskhashsize = EVP_MD_size(mdpsk);
+    }
+
+    /* Create the extension, but skip over the binder for now */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_psk)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_PSK,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    if (dores) {
+        if (!WPACKET_sub_memcpy_u16(pkt, s->session->ext.tick,
+                                           s->session->ext.ticklen)
+                || !WPACKET_put_bytes_u32(pkt, agems)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_PSK,
+                     ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+    }
+
+    if (s->psksession != NULL) {
+        if (!WPACKET_sub_memcpy_u16(pkt, s->psksession_id,
+                                    s->psksession_id_len)
+                || !WPACKET_put_bytes_u32(pkt, 0)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_PSK,
+                     ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+        s->ext.tick_identity++;
+    }
+
+    if (!WPACKET_close(pkt)
+            || !WPACKET_get_total_written(pkt, &binderoffset)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || (dores
+                && !WPACKET_sub_allocate_bytes_u8(pkt, reshashsize, &resbinder))
+            || (s->psksession != NULL
+                && !WPACKET_sub_allocate_bytes_u8(pkt, pskhashsize, &pskbinder))
+            || !WPACKET_close(pkt)
+            || !WPACKET_close(pkt)
+            || !WPACKET_get_total_written(pkt, &msglen)
+               /*
+                * We need to fill in all the sub-packet lengths now so we can
+                * calculate the HMAC of the message up to the binders
+                */
+            || !WPACKET_fill_lengths(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_PSK,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    msgstart = WPACKET_get_curr(pkt) - msglen;
+
+    if (dores
+            && tls_psk_do_binder(s, mdres, msgstart, binderoffset, NULL,
+                                 resbinder, s->session, 1, 0) != 1) {
+        /* SSLfatal() already called */
+        return EXT_RETURN_FAIL;
+    }
+
+    if (s->psksession != NULL
+            && tls_psk_do_binder(s, mdpsk, msgstart, binderoffset, NULL,
+                                 pskbinder, s->psksession, 1, 1) != 1) {
+        /* SSLfatal() already called */
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+#else
+    return EXT_RETURN_NOT_SENT;
+#endif
+}
+
+EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt,
+                                                  unsigned int context,
+                                                  X509 *x, size_t chainidx)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    if (!s->pha_enabled)
+        return EXT_RETURN_NOT_SENT;
+
+    /* construct extension - 0 length, no contents */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_post_handshake_auth)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CTOS_POST_HANDSHAKE_AUTH,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    s->post_handshake_auth = SSL_PHA_EXT_SENT;
+
+    return EXT_RETURN_SENT;
+#else
+    return EXT_RETURN_NOT_SENT;
+#endif
+}
+
+
+/*
+ * Parse the server's renegotiation binding and abort if it's not right
+ */
+int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx)
+{
+    size_t expected_len = s->s3->previous_client_finished_len
+        + s->s3->previous_server_finished_len;
+    size_t ilen;
+    const unsigned char *data;
+
+    /* Check for logic errors */
+    if (!ossl_assert(expected_len == 0
+                     || s->s3->previous_client_finished_len != 0)
+        || !ossl_assert(expected_len == 0
+                        || s->s3->previous_server_finished_len != 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /* Parse the length byte */
+    if (!PACKET_get_1_len(pkt, &ilen)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
+                 SSL_R_RENEGOTIATION_ENCODING_ERR);
+        return 0;
+    }
+
+    /* Consistency check */
+    if (PACKET_remaining(pkt) != ilen) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
+                 SSL_R_RENEGOTIATION_ENCODING_ERR);
+        return 0;
+    }
+
+    /* Check that the extension matches */
+    if (ilen != expected_len) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
+                 SSL_R_RENEGOTIATION_MISMATCH);
+        return 0;
+    }
+
+    if (!PACKET_get_bytes(pkt, &data, s->s3->previous_client_finished_len)
+        || memcmp(data, s->s3->previous_client_finished,
+                  s->s3->previous_client_finished_len) != 0) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
+                 SSL_R_RENEGOTIATION_MISMATCH);
+        return 0;
+    }
+
+    if (!PACKET_get_bytes(pkt, &data, s->s3->previous_server_finished_len)
+        || memcmp(data, s->s3->previous_server_finished,
+                  s->s3->previous_server_finished_len) != 0) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
+                 SSL_R_RENEGOTIATION_MISMATCH);
+        return 0;
+    }
+    s->s3->send_connection_binding = 1;
+
+    return 1;
+}
+
+/* Parse the server's max fragment len extension packet */
+int tls_parse_stoc_maxfragmentlen(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    unsigned int value;
+
+    if (PACKET_remaining(pkt) != 1 || !PACKET_get_1(pkt, &value)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_MAXFRAGMENTLEN,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    /* |value| should contains a valid max-fragment-length code. */
+    if (!IS_MAX_FRAGMENT_LENGTH_EXT_VALID(value)) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                 SSL_F_TLS_PARSE_STOC_MAXFRAGMENTLEN,
+                 SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH);
+        return 0;
+    }
+
+    /* Must be the same value as client-configured one who was sent to server */
+    /*-
+     * RFC 6066: if a client receives a maximum fragment length negotiation
+     * response that differs from the length it requested, ...
+     * It must abort with SSL_AD_ILLEGAL_PARAMETER alert
+     */
+    if (value != s->ext.max_fragment_len_mode) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                 SSL_F_TLS_PARSE_STOC_MAXFRAGMENTLEN,
+                 SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH);
+        return 0;
+    }
+
+    /*
+     * Maximum Fragment Length Negotiation succeeded.
+     * The negotiated Maximum Fragment Length is binding now.
+     */
+    s->session->ext.max_fragment_len_mode = value;
+
+    return 1;
+}
+
+int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx)
+{
+    if (s->ext.hostname == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_SERVER_NAME,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (PACKET_remaining(pkt) > 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_SERVER_NAME,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    if (!s->hit) {
+        if (s->session->ext.hostname != NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_SERVER_NAME,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        s->session->ext.hostname = OPENSSL_strdup(s->ext.hostname);
+        if (s->session->ext.hostname == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_SERVER_NAME,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_EC
+int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx)
+{
+    size_t ecpointformats_len;
+    PACKET ecptformatlist;
+
+    if (!PACKET_as_length_prefixed_1(pkt, &ecptformatlist)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_EC_PT_FORMATS,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    if (!s->hit) {
+        ecpointformats_len = PACKET_remaining(&ecptformatlist);
+        if (ecpointformats_len == 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PARSE_STOC_EC_PT_FORMATS, SSL_R_BAD_LENGTH);
+            return 0;
+        }
+
+        s->ext.peer_ecpointformats_len = 0;
+        OPENSSL_free(s->ext.peer_ecpointformats);
+        s->ext.peer_ecpointformats = OPENSSL_malloc(ecpointformats_len);
+        if (s->ext.peer_ecpointformats == NULL) {
+            s->ext.peer_ecpointformats_len = 0;
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PARSE_STOC_EC_PT_FORMATS, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+
+        s->ext.peer_ecpointformats_len = ecpointformats_len;
+
+        if (!PACKET_copy_bytes(&ecptformatlist,
+                               s->ext.peer_ecpointformats,
+                               ecpointformats_len)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PARSE_STOC_EC_PT_FORMATS, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif
+
+int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    if (s->ext.session_ticket_cb != NULL &&
+        !s->ext.session_ticket_cb(s, PACKET_data(pkt),
+                              PACKET_remaining(pkt),
+                              s->ext.session_ticket_cb_arg)) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                 SSL_F_TLS_PARSE_STOC_SESSION_TICKET, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    if (!tls_use_ticket(s)) {
+        SSLfatal(s, SSL_AD_UNSUPPORTED_EXTENSION,
+                 SSL_F_TLS_PARSE_STOC_SESSION_TICKET, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    if (PACKET_remaining(pkt) > 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_STOC_SESSION_TICKET, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    s->ext.ticket_expected = 1;
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_OCSP
+int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    if (context == SSL_EXT_TLS1_3_CERTIFICATE_REQUEST) {
+        /* We ignore this if the server sends a CertificateRequest */
+        /* TODO(TLS1.3): Add support for this */
+        return 1;
+    }
+
+    /*
+     * MUST only be sent if we've requested a status
+     * request message. In TLS <= 1.2 it must also be empty.
+     */
+    if (s->ext.status_type != TLSEXT_STATUSTYPE_ocsp) {
+        SSLfatal(s, SSL_AD_UNSUPPORTED_EXTENSION,
+                 SSL_F_TLS_PARSE_STOC_STATUS_REQUEST, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    if (!SSL_IS_TLS13(s) && PACKET_remaining(pkt) > 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_STOC_STATUS_REQUEST, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    if (SSL_IS_TLS13(s)) {
+        /* We only know how to handle this if it's for the first Certificate in
+         * the chain. We ignore any other responses.
+         */
+        if (chainidx != 0)
+            return 1;
+
+        /* SSLfatal() already called */
+        return tls_process_cert_status_body(s, pkt);
+    }
+
+    /* Set flag to expect CertificateStatus message */
+    s->ext.status_expected = 1;
+
+    return 1;
+}
+#endif
+
+
+#ifndef OPENSSL_NO_CT
+int tls_parse_stoc_sct(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx)
+{
+    if (context == SSL_EXT_TLS1_3_CERTIFICATE_REQUEST) {
+        /* We ignore this if the server sends it in a CertificateRequest */
+        /* TODO(TLS1.3): Add support for this */
+        return 1;
+    }
+
+    /*
+     * Only take it if we asked for it - i.e if there is no CT validation
+     * callback set, then a custom extension MAY be processing it, so we
+     * need to let control continue to flow to that.
+     */
+    if (s->ct_validation_callback != NULL) {
+        size_t size = PACKET_remaining(pkt);
+
+        /* Simply copy it off for later processing */
+        OPENSSL_free(s->ext.scts);
+        s->ext.scts = NULL;
+
+        s->ext.scts_len = (uint16_t)size;
+        if (size > 0) {
+            s->ext.scts = OPENSSL_malloc(size);
+            if (s->ext.scts == NULL) {
+                s->ext.scts_len = 0;
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_SCT,
+                         ERR_R_MALLOC_FAILURE);
+                return 0;
+            }
+            if (!PACKET_copy_bytes(pkt, s->ext.scts, size)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_SCT,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
+    } else {
+        ENDPOINT role = (context & SSL_EXT_TLS1_2_SERVER_HELLO) != 0
+                        ? ENDPOINT_CLIENT : ENDPOINT_BOTH;
+
+        /*
+         * If we didn't ask for it then there must be a custom extension,
+         * otherwise this is unsolicited.
+         */
+        if (custom_ext_find(&s->cert->custext, role,
+                            TLSEXT_TYPE_signed_certificate_timestamp,
+                            NULL) == NULL) {
+            SSLfatal(s, TLS1_AD_UNSUPPORTED_EXTENSION, SSL_F_TLS_PARSE_STOC_SCT,
+                     SSL_R_BAD_EXTENSION);
+            return 0;
+        }
+
+        if (!custom_ext_parse(s, context,
+                             TLSEXT_TYPE_signed_certificate_timestamp,
+                             PACKET_data(pkt), PACKET_remaining(pkt),
+                             x, chainidx)) {
+            /* SSLfatal already called */
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif
+
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+/*
+ * ssl_next_proto_validate validates a Next Protocol Negotiation block. No
+ * elements of zero length are allowed and the set of elements must exactly
+ * fill the length of the block. Returns 1 on success or 0 on failure.
+ */
+static int ssl_next_proto_validate(SSL *s, PACKET *pkt)
+{
+    PACKET tmp_protocol;
+
+    while (PACKET_remaining(pkt)) {
+        if (!PACKET_get_length_prefixed_1(pkt, &tmp_protocol)
+            || PACKET_remaining(&tmp_protocol) == 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_SSL_NEXT_PROTO_VALIDATE,
+                     SSL_R_BAD_EXTENSION);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+int tls_parse_stoc_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx)
+{
+    unsigned char *selected;
+    unsigned char selected_len;
+    PACKET tmppkt;
+
+    /* Check if we are in a renegotiation. If so ignore this extension */
+    if (!SSL_IS_FIRST_HANDSHAKE(s))
+        return 1;
+
+    /* We must have requested it. */
+    if (s->ctx->ext.npn_select_cb == NULL) {
+        SSLfatal(s, SSL_AD_UNSUPPORTED_EXTENSION, SSL_F_TLS_PARSE_STOC_NPN,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    /* The data must be valid */
+    tmppkt = *pkt;
+    if (!ssl_next_proto_validate(s, &tmppkt)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+    if (s->ctx->ext.npn_select_cb(s, &selected, &selected_len,
+                                  PACKET_data(pkt),
+                                  PACKET_remaining(pkt),
+                                  s->ctx->ext.npn_select_cb_arg) !=
+             SSL_TLSEXT_ERR_OK) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS_PARSE_STOC_NPN,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    /*
+     * Could be non-NULL if server has sent multiple NPN extensions in
+     * a single Serverhello
+     */
+    OPENSSL_free(s->ext.npn);
+    s->ext.npn = OPENSSL_malloc(selected_len);
+    if (s->ext.npn == NULL) {
+        s->ext.npn_len = 0;
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_NPN,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    memcpy(s->ext.npn, selected, selected_len);
+    s->ext.npn_len = selected_len;
+    s->s3->npn_seen = 1;
+
+    return 1;
+}
+#endif
+
+int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                        size_t chainidx)
+{
+    size_t len;
+
+    /* We must have requested it. */
+    if (!s->s3->alpn_sent) {
+        SSLfatal(s, SSL_AD_UNSUPPORTED_EXTENSION, SSL_F_TLS_PARSE_STOC_ALPN,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    /*-
+     * The extension data consists of:
+     *   uint16 list_length
+     *   uint8 proto_length;
+     *   uint8 proto[proto_length];
+     */
+    if (!PACKET_get_net_2_len(pkt, &len)
+        || PACKET_remaining(pkt) != len || !PACKET_get_1_len(pkt, &len)
+        || PACKET_remaining(pkt) != len) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_ALPN,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    OPENSSL_free(s->s3->alpn_selected);
+    s->s3->alpn_selected = OPENSSL_malloc(len);
+    if (s->s3->alpn_selected == NULL) {
+        s->s3->alpn_selected_len = 0;
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_ALPN,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    if (!PACKET_copy_bytes(pkt, s->s3->alpn_selected, len)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_ALPN,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    s->s3->alpn_selected_len = len;
+
+    if (s->session->ext.alpn_selected == NULL
+            || s->session->ext.alpn_selected_len != len
+            || memcmp(s->session->ext.alpn_selected, s->s3->alpn_selected, len)
+               != 0) {
+        /* ALPN not consistent with the old session so cannot use early_data */
+        s->ext.early_data_ok = 0;
+    }
+    if (!s->hit) {
+        /*
+         * This is a new session and so alpn_selected should have been
+         * initialised to NULL. We should update it with the selected ALPN.
+         */
+        if (!ossl_assert(s->session->ext.alpn_selected == NULL)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_ALPN,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        s->session->ext.alpn_selected =
+            OPENSSL_memdup(s->s3->alpn_selected, s->s3->alpn_selected_len);
+        if (s->session->ext.alpn_selected == NULL) {
+            s->session->ext.alpn_selected_len = 0;
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_ALPN,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        s->session->ext.alpn_selected_len = s->s3->alpn_selected_len;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SRTP
+int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx)
+{
+    unsigned int id, ct, mki;
+    int i;
+    STACK_OF(SRTP_PROTECTION_PROFILE) *clnt;
+    SRTP_PROTECTION_PROFILE *prof;
+
+    if (!PACKET_get_net_2(pkt, &ct) || ct != 2
+            || !PACKET_get_net_2(pkt, &id)
+            || !PACKET_get_1(pkt, &mki)
+            || PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_USE_SRTP,
+                 SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+        return 0;
+    }
+
+    if (mki != 0) {
+        /* Must be no MKI, since we never offer one */
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_USE_SRTP,
+                 SSL_R_BAD_SRTP_MKI_VALUE);
+        return 0;
+    }
+
+    /* Throw an error if the server gave us an unsolicited extension */
+    clnt = SSL_get_srtp_profiles(s);
+    if (clnt == NULL) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_USE_SRTP,
+                 SSL_R_NO_SRTP_PROFILES);
+        return 0;
+    }
+
+    /*
+     * Check to see if the server gave us something we support (and
+     * presumably offered)
+     */
+    for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(clnt); i++) {
+        prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i);
+
+        if (prof->id == id) {
+            s->srtp_profile = prof;
+            return 1;
+        }
+    }
+
+    SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_USE_SRTP,
+             SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+    return 0;
+}
+#endif
+
+int tls_parse_stoc_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx)
+{
+    /* Ignore if inappropriate ciphersuite */
+    if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)
+            && s->s3->tmp.new_cipher->algorithm_mac != SSL_AEAD
+            && s->s3->tmp.new_cipher->algorithm_enc != SSL_RC4
+            && s->s3->tmp.new_cipher->algorithm_enc != SSL_eGOST2814789CNT
+            && s->s3->tmp.new_cipher->algorithm_enc != SSL_eGOST2814789CNT12)
+        s->ext.use_etm = 1;
+
+    return 1;
+}
+
+int tls_parse_stoc_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx)
+{
+    s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS;
+    if (!s->hit)
+        s->session->flags |= SSL_SESS_FLAG_EXTMS;
+
+    return 1;
+}
+
+int tls_parse_stoc_supported_versions(SSL *s, PACKET *pkt, unsigned int context,
+                                      X509 *x, size_t chainidx)
+{
+    unsigned int version;
+
+    if (!PACKET_get_net_2(pkt, &version)
+            || PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_STOC_SUPPORTED_VERSIONS,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    /*
+     * The only protocol version we support which is valid in this extension in
+     * a ServerHello is TLSv1.3 therefore we shouldn't be getting anything else.
+     */
+    if (version != TLS1_3_VERSION) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                 SSL_F_TLS_PARSE_STOC_SUPPORTED_VERSIONS,
+                 SSL_R_BAD_PROTOCOL_VERSION_NUMBER);
+        return 0;
+    }
+
+    /* We ignore this extension for HRRs except to sanity check it */
+    if (context == SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST)
+        return 1;
+
+    /* We just set it here. We validate it in ssl_choose_client_version */
+    s->version = version;
+
+    return 1;
+}
+
+int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                             size_t chainidx)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    unsigned int group_id;
+    PACKET encoded_pt;
+    EVP_PKEY *ckey = s->s3->tmp.pkey, *skey = NULL;
+
+    /* Sanity check */
+    if (ckey == NULL || s->s3->peer_tmp != NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_KEY_SHARE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (!PACKET_get_net_2(pkt, &group_id)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_KEY_SHARE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    if ((context & SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST) != 0) {
+        const uint16_t *pgroups = NULL;
+        size_t i, num_groups;
+
+        if (PACKET_remaining(pkt) != 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_KEY_SHARE,
+                     SSL_R_LENGTH_MISMATCH);
+            return 0;
+        }
+
+        /*
+         * It is an error if the HelloRetryRequest wants a key_share that we
+         * already sent in the first ClientHello
+         */
+        if (group_id == s->s3->group_id) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
+            return 0;
+        }
+
+        /* Validate the selected group is one we support */
+        tls1_get_supported_groups(s, &pgroups, &num_groups);
+        for (i = 0; i < num_groups; i++) {
+            if (group_id == pgroups[i])
+                break;
+        }
+        if (i >= num_groups
+                || !tls_curve_allowed(s, group_id, SSL_SECOP_CURVE_SUPPORTED)) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
+            return 0;
+        }
+
+        s->s3->group_id = group_id;
+        EVP_PKEY_free(s->s3->tmp.pkey);
+        s->s3->tmp.pkey = NULL;
+        return 1;
+    }
+
+    if (group_id != s->s3->group_id) {
+        /*
+         * This isn't for the group that we sent in the original
+         * key_share!
+         */
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_KEY_SHARE,
+                 SSL_R_BAD_KEY_SHARE);
+        return 0;
+    }
+
+    if (!PACKET_as_length_prefixed_2(pkt, &encoded_pt)
+            || PACKET_remaining(&encoded_pt) == 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_KEY_SHARE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    skey = EVP_PKEY_new();
+    if (skey == NULL || EVP_PKEY_copy_parameters(skey, ckey) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_KEY_SHARE,
+                 ERR_R_MALLOC_FAILURE);
+        EVP_PKEY_free(skey);
+        return 0;
+    }
+    if (!EVP_PKEY_set1_tls_encodedpoint(skey, PACKET_data(&encoded_pt),
+                                        PACKET_remaining(&encoded_pt))) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_KEY_SHARE,
+                 SSL_R_BAD_ECPOINT);
+        EVP_PKEY_free(skey);
+        return 0;
+    }
+
+    if (ssl_derive(s, ckey, skey, 1) == 0) {
+        /* SSLfatal() already called */
+        EVP_PKEY_free(skey);
+        return 0;
+    }
+    s->s3->peer_tmp = skey;
+#endif
+
+    return 1;
+}
+
+int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx)
+{
+    PACKET cookie;
+
+    if (!PACKET_as_length_prefixed_2(pkt, &cookie)
+            || !PACKET_memdup(&cookie, &s->ext.tls13_cookie,
+                              &s->ext.tls13_cookie_len)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_COOKIE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
+                              X509 *x, size_t chainidx)
+{
+    if (context == SSL_EXT_TLS1_3_NEW_SESSION_TICKET) {
+        unsigned long max_early_data;
+
+        if (!PACKET_get_net_4(pkt, &max_early_data)
+                || PACKET_remaining(pkt) != 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_EARLY_DATA,
+                     SSL_R_INVALID_MAX_EARLY_DATA);
+            return 0;
+        }
+
+        s->session->ext.max_early_data = max_early_data;
+
+        return 1;
+    }
+
+    if (PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_EARLY_DATA,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    if (!s->ext.early_data_ok
+            || !s->hit) {
+        /*
+         * If we get here then we didn't send early data, or we didn't resume
+         * using the first identity, or the SNI/ALPN is not consistent so the
+         * server should not be accepting it.
+         */
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_EARLY_DATA,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    s->ext.early_data = SSL_EARLY_DATA_ACCEPTED;
+
+    return 1;
+}
+
+int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    unsigned int identity;
+
+    if (!PACKET_get_net_2(pkt, &identity) || PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_PSK,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    if (identity >= (unsigned int)s->ext.tick_identity) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_PSK,
+                 SSL_R_BAD_PSK_IDENTITY);
+        return 0;
+    }
+
+    /*
+     * Session resumption tickets are always sent before PSK tickets. If the
+     * ticket index is 0 then it must be for a session resumption ticket if we
+     * sent two tickets, or if we didn't send a PSK ticket.
+     */
+    if (identity == 0 && (s->psksession == NULL || s->ext.tick_identity == 2)) {
+        s->hit = 1;
+        SSL_SESSION_free(s->psksession);
+        s->psksession = NULL;
+        return 1;
+    }
+
+    if (s->psksession == NULL) {
+        /* Should never happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_PSK,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /*
+     * If we used the external PSK for sending early_data then s->early_secret
+     * is already set up, so don't overwrite it. Otherwise we copy the
+     * early_secret across that we generated earlier.
+     */
+    if ((s->early_data_state != SSL_EARLY_DATA_WRITE_RETRY
+                && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING)
+            || s->session->ext.max_early_data > 0
+            || s->psksession->ext.max_early_data == 0)
+        memcpy(s->early_secret, s->psksession->early_secret, EVP_MAX_MD_SIZE);
+
+    SSL_SESSION_free(s->session);
+    s->session = s->psksession;
+    s->psksession = NULL;
+    s->hit = 1;
+    /* Early data is only allowed if we used the first ticket */
+    if (identity != 0)
+        s->ext.early_data_ok = 0;
+#endif
+
+    return 1;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/statem/extensions_cust.c b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/extensions_cust.c
new file mode 100644
index 0000000..1fe226f
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/extensions_cust.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright 2014-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* Custom extension utility functions */
+
+#include <openssl/ct.h>
+#include "../ssl_local.h"
+#include "internal/cryptlib.h"
+#include "statem_local.h"
+
+typedef struct {
+    void *add_arg;
+    custom_ext_add_cb add_cb;
+    custom_ext_free_cb free_cb;
+} custom_ext_add_cb_wrap;
+
+typedef struct {
+    void *parse_arg;
+    custom_ext_parse_cb parse_cb;
+} custom_ext_parse_cb_wrap;
+
+/*
+ * Provide thin wrapper callbacks which convert new style arguments to old style
+ */
+static int custom_ext_add_old_cb_wrap(SSL *s, unsigned int ext_type,
+                                      unsigned int context,
+                                      const unsigned char **out,
+                                      size_t *outlen, X509 *x, size_t chainidx,
+                                      int *al, void *add_arg)
+{
+    custom_ext_add_cb_wrap *add_cb_wrap = (custom_ext_add_cb_wrap *)add_arg;
+
+    if (add_cb_wrap->add_cb == NULL)
+        return 1;
+
+    return add_cb_wrap->add_cb(s, ext_type, out, outlen, al,
+                               add_cb_wrap->add_arg);
+}
+
+static void custom_ext_free_old_cb_wrap(SSL *s, unsigned int ext_type,
+                                        unsigned int context,
+                                        const unsigned char *out, void *add_arg)
+{
+    custom_ext_add_cb_wrap *add_cb_wrap = (custom_ext_add_cb_wrap *)add_arg;
+
+    if (add_cb_wrap->free_cb == NULL)
+        return;
+
+    add_cb_wrap->free_cb(s, ext_type, out, add_cb_wrap->add_arg);
+}
+
+static int custom_ext_parse_old_cb_wrap(SSL *s, unsigned int ext_type,
+                                        unsigned int context,
+                                        const unsigned char *in,
+                                        size_t inlen, X509 *x, size_t chainidx,
+                                        int *al, void *parse_arg)
+{
+    custom_ext_parse_cb_wrap *parse_cb_wrap =
+        (custom_ext_parse_cb_wrap *)parse_arg;
+
+    if (parse_cb_wrap->parse_cb == NULL)
+        return 1;
+
+    return parse_cb_wrap->parse_cb(s, ext_type, in, inlen, al,
+                                   parse_cb_wrap->parse_arg);
+}
+
+/*
+ * Find a custom extension from the list. The |role| param is there to
+ * support the legacy API where custom extensions for client and server could
+ * be set independently on the same SSL_CTX. It is set to ENDPOINT_SERVER if we
+ * are trying to find a method relevant to the server, ENDPOINT_CLIENT for the
+ * client, or ENDPOINT_BOTH for either
+ */
+custom_ext_method *custom_ext_find(const custom_ext_methods *exts,
+                                   ENDPOINT role, unsigned int ext_type,
+                                   size_t *idx)
+{
+    size_t i;
+    custom_ext_method *meth = exts->meths;
+
+    for (i = 0; i < exts->meths_count; i++, meth++) {
+        if (ext_type == meth->ext_type
+                && (role == ENDPOINT_BOTH || role == meth->role
+                    || meth->role == ENDPOINT_BOTH)) {
+            if (idx != NULL)
+                *idx = i;
+            return meth;
+        }
+    }
+    return NULL;
+}
+
+/*
+ * Initialise custom extensions flags to indicate neither sent nor received.
+ */
+void custom_ext_init(custom_ext_methods *exts)
+{
+    size_t i;
+    custom_ext_method *meth = exts->meths;
+
+    for (i = 0; i < exts->meths_count; i++, meth++)
+        meth->ext_flags = 0;
+}
+
+/* Pass received custom extension data to the application for parsing. */
+int custom_ext_parse(SSL *s, unsigned int context, unsigned int ext_type,
+                     const unsigned char *ext_data, size_t ext_size, X509 *x,
+                     size_t chainidx)
+{
+    int al;
+    custom_ext_methods *exts = &s->cert->custext;
+    custom_ext_method *meth;
+    ENDPOINT role = ENDPOINT_BOTH;
+
+    if ((context & (SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO)) != 0)
+        role = s->server ? ENDPOINT_SERVER : ENDPOINT_CLIENT;
+
+    meth = custom_ext_find(exts, role, ext_type, NULL);
+    /* If not found return success */
+    if (!meth)
+        return 1;
+
+    /* Check if extension is defined for our protocol. If not, skip */
+    if (!extension_is_relevant(s, meth->context, context))
+        return 1;
+
+    if ((context & (SSL_EXT_TLS1_2_SERVER_HELLO
+                    | SSL_EXT_TLS1_3_SERVER_HELLO
+                    | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS)) != 0) {
+        /*
+         * If it's ServerHello or EncryptedExtensions we can't have any
+         * extensions not sent in ClientHello.
+         */
+        if ((meth->ext_flags & SSL_EXT_FLAG_SENT) == 0) {
+            SSLfatal(s, TLS1_AD_UNSUPPORTED_EXTENSION, SSL_F_CUSTOM_EXT_PARSE,
+                     SSL_R_BAD_EXTENSION);
+            return 0;
+        }
+    }
+
+    /*
+     * Extensions received in the ClientHello or CertificateRequest are marked
+     * with the SSL_EXT_FLAG_RECEIVED. This is so we know to add the equivalent
+     * extensions in the response messages
+     */
+    if ((context & (SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST))
+            != 0)
+        meth->ext_flags |= SSL_EXT_FLAG_RECEIVED;
+
+    /* If no parse function set return success */
+    if (!meth->parse_cb)
+        return 1;
+
+    if (meth->parse_cb(s, ext_type, context, ext_data, ext_size, x, chainidx,
+                       &al, meth->parse_arg) <= 0) {
+        SSLfatal(s, al, SSL_F_CUSTOM_EXT_PARSE, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    return 1;
+}
+
+/*
+ * Request custom extension data from the application and add to the return
+ * buffer.
+ */
+int custom_ext_add(SSL *s, int context, WPACKET *pkt, X509 *x, size_t chainidx,
+                   int maxversion)
+{
+    custom_ext_methods *exts = &s->cert->custext;
+    custom_ext_method *meth;
+    size_t i;
+    int al;
+
+    for (i = 0; i < exts->meths_count; i++) {
+        const unsigned char *out = NULL;
+        size_t outlen = 0;
+
+        meth = exts->meths + i;
+
+        if (!should_add_extension(s, meth->context, context, maxversion))
+            continue;
+
+        if ((context & (SSL_EXT_TLS1_2_SERVER_HELLO
+                        | SSL_EXT_TLS1_3_SERVER_HELLO
+                        | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+                        | SSL_EXT_TLS1_3_CERTIFICATE
+                        | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST)) != 0) {
+            /* Only send extensions present in ClientHello/CertificateRequest */
+            if (!(meth->ext_flags & SSL_EXT_FLAG_RECEIVED))
+                continue;
+        }
+        /*
+         * We skip it if the callback is absent - except for a ClientHello where
+         * we add an empty extension.
+         */
+        if ((context & SSL_EXT_CLIENT_HELLO) == 0 && meth->add_cb == NULL)
+            continue;
+
+        if (meth->add_cb != NULL) {
+            int cb_retval = meth->add_cb(s, meth->ext_type, context, &out,
+                                         &outlen, x, chainidx, &al,
+                                         meth->add_arg);
+
+            if (cb_retval < 0) {
+                SSLfatal(s, al, SSL_F_CUSTOM_EXT_ADD, SSL_R_CALLBACK_FAILED);
+                return 0;       /* error */
+            }
+            if (cb_retval == 0)
+                continue;       /* skip this extension */
+        }
+
+        if (!WPACKET_put_bytes_u16(pkt, meth->ext_type)
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || (outlen > 0 && !WPACKET_memcpy(pkt, out, outlen))
+                || !WPACKET_close(pkt)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CUSTOM_EXT_ADD,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        if ((context & SSL_EXT_CLIENT_HELLO) != 0) {
+            /*
+             * We can't send duplicates: code logic should prevent this.
+             */
+            if (!ossl_assert((meth->ext_flags & SSL_EXT_FLAG_SENT) == 0)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CUSTOM_EXT_ADD,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+            /*
+             * Indicate extension has been sent: this is both a sanity check to
+             * ensure we don't send duplicate extensions and indicates that it
+             * is not an error if the extension is present in ServerHello.
+             */
+            meth->ext_flags |= SSL_EXT_FLAG_SENT;
+        }
+        if (meth->free_cb != NULL)
+            meth->free_cb(s, meth->ext_type, context, out, meth->add_arg);
+    }
+    return 1;
+}
+
+/* Copy the flags from src to dst for any extensions that exist in both */
+int custom_exts_copy_flags(custom_ext_methods *dst,
+                           const custom_ext_methods *src)
+{
+    size_t i;
+    custom_ext_method *methsrc = src->meths;
+
+    for (i = 0; i < src->meths_count; i++, methsrc++) {
+        custom_ext_method *methdst = custom_ext_find(dst, methsrc->role,
+                                                     methsrc->ext_type, NULL);
+
+        if (methdst == NULL)
+            continue;
+
+        methdst->ext_flags = methsrc->ext_flags;
+    }
+
+    return 1;
+}
+
+/* Copy table of custom extensions */
+int custom_exts_copy(custom_ext_methods *dst, const custom_ext_methods *src)
+{
+    size_t i;
+    int err = 0;
+
+    if (src->meths_count > 0) {
+        dst->meths =
+            OPENSSL_memdup(src->meths,
+                           sizeof(*src->meths) * src->meths_count);
+        if (dst->meths == NULL)
+            return 0;
+        dst->meths_count = src->meths_count;
+
+        for (i = 0; i < src->meths_count; i++) {
+            custom_ext_method *methsrc = src->meths + i;
+            custom_ext_method *methdst = dst->meths + i;
+
+            if (methsrc->add_cb != custom_ext_add_old_cb_wrap)
+                continue;
+
+            /*
+             * We have found an old style API wrapper. We need to copy the
+             * arguments too.
+             */
+
+            if (err) {
+                methdst->add_arg = NULL;
+                methdst->parse_arg = NULL;
+                continue;
+            }
+
+            methdst->add_arg = OPENSSL_memdup(methsrc->add_arg,
+                                              sizeof(custom_ext_add_cb_wrap));
+            methdst->parse_arg = OPENSSL_memdup(methsrc->parse_arg,
+                                            sizeof(custom_ext_parse_cb_wrap));
+
+            if (methdst->add_arg == NULL || methdst->parse_arg == NULL)
+                err = 1;
+        }
+    }
+
+    if (err) {
+        custom_exts_free(dst);
+        return 0;
+    }
+
+    return 1;
+}
+
+void custom_exts_free(custom_ext_methods *exts)
+{
+    size_t i;
+    custom_ext_method *meth;
+
+    for (i = 0, meth = exts->meths; i < exts->meths_count; i++, meth++) {
+        if (meth->add_cb != custom_ext_add_old_cb_wrap)
+            continue;
+
+        /* Old style API wrapper. Need to free the arguments too */
+        OPENSSL_free(meth->add_arg);
+        OPENSSL_free(meth->parse_arg);
+    }
+    OPENSSL_free(exts->meths);
+}
+
+/* Return true if a client custom extension exists, false otherwise */
+int SSL_CTX_has_client_custom_ext(const SSL_CTX *ctx, unsigned int ext_type)
+{
+    return custom_ext_find(&ctx->cert->custext, ENDPOINT_CLIENT, ext_type,
+                           NULL) != NULL;
+}
+
+static int add_custom_ext_intern(SSL_CTX *ctx, ENDPOINT role,
+                                 unsigned int ext_type,
+                                 unsigned int context,
+                                 SSL_custom_ext_add_cb_ex add_cb,
+                                 SSL_custom_ext_free_cb_ex free_cb,
+                                 void *add_arg,
+                                 SSL_custom_ext_parse_cb_ex parse_cb,
+                                 void *parse_arg)
+{
+    custom_ext_methods *exts = &ctx->cert->custext;
+    custom_ext_method *meth, *tmp;
+
+    /*
+     * Check application error: if add_cb is not set free_cb will never be
+     * called.
+     */
+    if (add_cb == NULL && free_cb != NULL)
+        return 0;
+
+#ifndef OPENSSL_NO_CT
+    /*
+     * We don't want applications registering callbacks for SCT extensions
+     * whilst simultaneously using the built-in SCT validation features, as
+     * these two things may not play well together.
+     */
+    if (ext_type == TLSEXT_TYPE_signed_certificate_timestamp
+            && (context & SSL_EXT_CLIENT_HELLO) != 0
+            && SSL_CTX_ct_is_enabled(ctx))
+        return 0;
+#endif
+
+    /*
+     * Don't add if extension supported internally, but make exception
+     * for extension types that previously were not supported, but now are.
+     */
+    if (SSL_extension_supported(ext_type)
+            && ext_type != TLSEXT_TYPE_signed_certificate_timestamp)
+        return 0;
+
+    /* Extension type must fit in 16 bits */
+    if (ext_type > 0xffff)
+        return 0;
+    /* Search for duplicate */
+    if (custom_ext_find(exts, role, ext_type, NULL))
+        return 0;
+    tmp = OPENSSL_realloc(exts->meths,
+                          (exts->meths_count + 1) * sizeof(custom_ext_method));
+    if (tmp == NULL)
+        return 0;
+
+    exts->meths = tmp;
+    meth = exts->meths + exts->meths_count;
+    memset(meth, 0, sizeof(*meth));
+    meth->role = role;
+    meth->context = context;
+    meth->parse_cb = parse_cb;
+    meth->add_cb = add_cb;
+    meth->free_cb = free_cb;
+    meth->ext_type = ext_type;
+    meth->add_arg = add_arg;
+    meth->parse_arg = parse_arg;
+    exts->meths_count++;
+    return 1;
+}
+
+static int add_old_custom_ext(SSL_CTX *ctx, ENDPOINT role,
+                              unsigned int ext_type,
+                              unsigned int context,
+                              custom_ext_add_cb add_cb,
+                              custom_ext_free_cb free_cb,
+                              void *add_arg,
+                              custom_ext_parse_cb parse_cb, void *parse_arg)
+{
+    custom_ext_add_cb_wrap *add_cb_wrap
+        = OPENSSL_malloc(sizeof(*add_cb_wrap));
+    custom_ext_parse_cb_wrap *parse_cb_wrap
+        = OPENSSL_malloc(sizeof(*parse_cb_wrap));
+    int ret;
+
+    if (add_cb_wrap == NULL || parse_cb_wrap == NULL) {
+        OPENSSL_free(add_cb_wrap);
+        OPENSSL_free(parse_cb_wrap);
+        return 0;
+    }
+
+    add_cb_wrap->add_arg = add_arg;
+    add_cb_wrap->add_cb = add_cb;
+    add_cb_wrap->free_cb = free_cb;
+    parse_cb_wrap->parse_arg = parse_arg;
+    parse_cb_wrap->parse_cb = parse_cb;
+
+    ret = add_custom_ext_intern(ctx, role, ext_type,
+                                context,
+                                custom_ext_add_old_cb_wrap,
+                                custom_ext_free_old_cb_wrap,
+                                add_cb_wrap,
+                                custom_ext_parse_old_cb_wrap,
+                                parse_cb_wrap);
+
+    if (!ret) {
+        OPENSSL_free(add_cb_wrap);
+        OPENSSL_free(parse_cb_wrap);
+    }
+
+    return ret;
+}
+
+/* Application level functions to add the old custom extension callbacks */
+int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
+                                  custom_ext_add_cb add_cb,
+                                  custom_ext_free_cb free_cb,
+                                  void *add_arg,
+                                  custom_ext_parse_cb parse_cb, void *parse_arg)
+{
+    return add_old_custom_ext(ctx, ENDPOINT_CLIENT, ext_type,
+                              SSL_EXT_TLS1_2_AND_BELOW_ONLY
+                              | SSL_EXT_CLIENT_HELLO
+                              | SSL_EXT_TLS1_2_SERVER_HELLO
+                              | SSL_EXT_IGNORE_ON_RESUMPTION,
+                              add_cb, free_cb, add_arg, parse_cb, parse_arg);
+}
+
+int SSL_CTX_add_server_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
+                                  custom_ext_add_cb add_cb,
+                                  custom_ext_free_cb free_cb,
+                                  void *add_arg,
+                                  custom_ext_parse_cb parse_cb, void *parse_arg)
+{
+    return add_old_custom_ext(ctx, ENDPOINT_SERVER, ext_type,
+                              SSL_EXT_TLS1_2_AND_BELOW_ONLY
+                              | SSL_EXT_CLIENT_HELLO
+                              | SSL_EXT_TLS1_2_SERVER_HELLO
+                              | SSL_EXT_IGNORE_ON_RESUMPTION,
+                              add_cb, free_cb, add_arg, parse_cb, parse_arg);
+}
+
+int SSL_CTX_add_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
+                           unsigned int context,
+                           SSL_custom_ext_add_cb_ex add_cb,
+                           SSL_custom_ext_free_cb_ex free_cb,
+                           void *add_arg,
+                           SSL_custom_ext_parse_cb_ex parse_cb, void *parse_arg)
+{
+    return add_custom_ext_intern(ctx, ENDPOINT_BOTH, ext_type, context, add_cb,
+                                 free_cb, add_arg, parse_cb, parse_arg);
+}
+
+int SSL_extension_supported(unsigned int ext_type)
+{
+    switch (ext_type) {
+        /* Internally supported extensions. */
+    case TLSEXT_TYPE_application_layer_protocol_negotiation:
+#ifndef OPENSSL_NO_EC
+    case TLSEXT_TYPE_ec_point_formats:
+    case TLSEXT_TYPE_supported_groups:
+    case TLSEXT_TYPE_key_share:
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    case TLSEXT_TYPE_next_proto_neg:
+#endif
+    case TLSEXT_TYPE_padding:
+    case TLSEXT_TYPE_renegotiate:
+    case TLSEXT_TYPE_max_fragment_length:
+    case TLSEXT_TYPE_server_name:
+    case TLSEXT_TYPE_session_ticket:
+    case TLSEXT_TYPE_signature_algorithms:
+#ifndef OPENSSL_NO_SRP
+    case TLSEXT_TYPE_srp:
+#endif
+#ifndef OPENSSL_NO_OCSP
+    case TLSEXT_TYPE_status_request:
+#endif
+#ifndef OPENSSL_NO_CT
+    case TLSEXT_TYPE_signed_certificate_timestamp:
+#endif
+#ifndef OPENSSL_NO_SRTP
+    case TLSEXT_TYPE_use_srtp:
+#endif
+    case TLSEXT_TYPE_encrypt_then_mac:
+    case TLSEXT_TYPE_supported_versions:
+    case TLSEXT_TYPE_extended_master_secret:
+    case TLSEXT_TYPE_psk_kex_modes:
+    case TLSEXT_TYPE_cookie:
+    case TLSEXT_TYPE_early_data:
+    case TLSEXT_TYPE_certificate_authorities:
+    case TLSEXT_TYPE_psk:
+    case TLSEXT_TYPE_post_handshake_auth:
+        return 1;
+    default:
+        return 0;
+    }
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/statem/extensions_srvr.c b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/extensions_srvr.c
new file mode 100644
index 0000000..4754110
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/extensions_srvr.c
@@ -0,0 +1,1980 @@
+/*
+ * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/ocsp.h>
+#include "../ssl_local.h"
+#include "statem_local.h"
+#include "internal/cryptlib.h"
+
+#define COOKIE_STATE_FORMAT_VERSION     1
+
+/*
+ * 2 bytes for packet length, 2 bytes for format version, 2 bytes for
+ * protocol version, 2 bytes for group id, 2 bytes for cipher id, 1 byte for
+ * key_share present flag, 8 bytes for timestamp, 2 bytes for the hashlen,
+ * EVP_MAX_MD_SIZE for transcript hash, 1 byte for app cookie length, app cookie
+ * length bytes, SHA256_DIGEST_LENGTH bytes for the HMAC of the whole thing.
+ */
+#define MAX_COOKIE_SIZE (2 + 2 + 2 + 2 + 2 + 1 + 8 + 2 + EVP_MAX_MD_SIZE + 1 \
+                         + SSL_COOKIE_LENGTH + SHA256_DIGEST_LENGTH)
+
+/*
+ * Message header + 2 bytes for protocol version + number of random bytes +
+ * + 1 byte for legacy session id length + number of bytes in legacy session id
+ * + 2 bytes for ciphersuite + 1 byte for legacy compression
+ * + 2 bytes for extension block length + 6 bytes for key_share extension
+ * + 4 bytes for cookie extension header + the number of bytes in the cookie
+ */
+#define MAX_HRR_SIZE    (SSL3_HM_HEADER_LENGTH + 2 + SSL3_RANDOM_SIZE + 1 \
+                         + SSL_MAX_SSL_SESSION_ID_LENGTH + 2 + 1 + 2 + 6 + 4 \
+                         + MAX_COOKIE_SIZE)
+
+/*
+ * Parse the client's renegotiation binding and abort if it's not right
+ */
+int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx)
+{
+    unsigned int ilen;
+    const unsigned char *data;
+
+    /* Parse the length byte */
+    if (!PACKET_get_1(pkt, &ilen)
+        || !PACKET_get_bytes(pkt, &data, ilen)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_RENEGOTIATE,
+                 SSL_R_RENEGOTIATION_ENCODING_ERR);
+        return 0;
+    }
+
+    /* Check that the extension matches */
+    if (ilen != s->s3->previous_client_finished_len) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS_PARSE_CTOS_RENEGOTIATE,
+                 SSL_R_RENEGOTIATION_MISMATCH);
+        return 0;
+    }
+
+    if (memcmp(data, s->s3->previous_client_finished,
+               s->s3->previous_client_finished_len)) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS_PARSE_CTOS_RENEGOTIATE,
+                 SSL_R_RENEGOTIATION_MISMATCH);
+        return 0;
+    }
+
+    s->s3->send_connection_binding = 1;
+
+    return 1;
+}
+
+/*-
+ * The servername extension is treated as follows:
+ *
+ * - Only the hostname type is supported with a maximum length of 255.
+ * - The servername is rejected if too long or if it contains zeros,
+ *   in which case an fatal alert is generated.
+ * - The servername field is maintained together with the session cache.
+ * - When a session is resumed, the servername call back invoked in order
+ *   to allow the application to position itself to the right context.
+ * - The servername is acknowledged if it is new for a session or when
+ *   it is identical to a previously used for the same session.
+ *   Applications can control the behaviour.  They can at any time
+ *   set a 'desirable' servername for a new SSL object. This can be the
+ *   case for example with HTTPS when a Host: header field is received and
+ *   a renegotiation is requested. In this case, a possible servername
+ *   presented in the new client hello is only acknowledged if it matches
+ *   the value of the Host: field.
+ * - Applications must  use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ *   if they provide for changing an explicit servername context for the
+ *   session, i.e. when the session has been established with a servername
+ *   extension.
+ * - On session reconnect, the servername extension may be absent.
+ */
+int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx)
+{
+    unsigned int servname_type;
+    PACKET sni, hostname;
+
+    if (!PACKET_as_length_prefixed_2(pkt, &sni)
+        /* ServerNameList must be at least 1 byte long. */
+        || PACKET_remaining(&sni) == 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_SERVER_NAME,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    /*
+     * Although the intent was for server_name to be extensible, RFC 4366
+     * was not clear about it; and so OpenSSL among other implementations,
+     * always and only allows a 'host_name' name types.
+     * RFC 6066 corrected the mistake but adding new name types
+     * is nevertheless no longer feasible, so act as if no other
+     * SNI types can exist, to simplify parsing.
+     *
+     * Also note that the RFC permits only one SNI value per type,
+     * i.e., we can only have a single hostname.
+     */
+    if (!PACKET_get_1(&sni, &servname_type)
+        || servname_type != TLSEXT_NAMETYPE_host_name
+        || !PACKET_as_length_prefixed_2(&sni, &hostname)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_SERVER_NAME,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    /*
+     * In TLSv1.2 and below the SNI is associated with the session. In TLSv1.3
+     * we always use the SNI value from the handshake.
+     */
+    if (!s->hit || SSL_IS_TLS13(s)) {
+        if (PACKET_remaining(&hostname) > TLSEXT_MAXLEN_host_name) {
+            SSLfatal(s, SSL_AD_UNRECOGNIZED_NAME,
+                     SSL_F_TLS_PARSE_CTOS_SERVER_NAME,
+                     SSL_R_BAD_EXTENSION);
+            return 0;
+        }
+
+        if (PACKET_contains_zero_byte(&hostname)) {
+            SSLfatal(s, SSL_AD_UNRECOGNIZED_NAME,
+                     SSL_F_TLS_PARSE_CTOS_SERVER_NAME,
+                     SSL_R_BAD_EXTENSION);
+            return 0;
+        }
+
+        /*
+         * Store the requested SNI in the SSL as temporary storage.
+         * If we accept it, it will get stored in the SSL_SESSION as well.
+         */
+        OPENSSL_free(s->ext.hostname);
+        s->ext.hostname = NULL;
+        if (!PACKET_strndup(&hostname, &s->ext.hostname)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_SERVER_NAME,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+
+        s->servername_done = 1;
+    } else {
+        /*
+         * In TLSv1.2 and below we should check if the SNI is consistent between
+         * the initial handshake and the resumption. In TLSv1.3 SNI is not
+         * associated with the session.
+         */
+        /*
+         * TODO(openssl-team): if the SNI doesn't match, we MUST
+         * fall back to a full handshake.
+         */
+        s->servername_done = (s->session->ext.hostname != NULL)
+            && PACKET_equal(&hostname, s->session->ext.hostname,
+                            strlen(s->session->ext.hostname));
+    }
+
+    return 1;
+}
+
+int tls_parse_ctos_maxfragmentlen(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    unsigned int value;
+
+    if (PACKET_remaining(pkt) != 1 || !PACKET_get_1(pkt, &value)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_MAXFRAGMENTLEN,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    /* Received |value| should be a valid max-fragment-length code. */
+    if (!IS_MAX_FRAGMENT_LENGTH_EXT_VALID(value)) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                 SSL_F_TLS_PARSE_CTOS_MAXFRAGMENTLEN,
+                 SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH);
+        return 0;
+    }
+
+    /*
+     * RFC 6066:  The negotiated length applies for the duration of the session
+     * including session resumptions.
+     * We should receive the same code as in resumed session !
+     */
+    if (s->hit && s->session->ext.max_fragment_len_mode != value) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                 SSL_F_TLS_PARSE_CTOS_MAXFRAGMENTLEN,
+                 SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH);
+        return 0;
+    }
+
+    /*
+     * Store it in session, so it'll become binding for us
+     * and we'll include it in a next Server Hello.
+     */
+    s->session->ext.max_fragment_len_mode = value;
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SRP
+int tls_parse_ctos_srp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx)
+{
+    PACKET srp_I;
+
+    if (!PACKET_as_length_prefixed_1(pkt, &srp_I)
+            || PACKET_contains_zero_byte(&srp_I)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_SRP,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    /*
+     * TODO(openssl-team): currently, we re-authenticate the user
+     * upon resumption. Instead, we MUST ignore the login.
+     */
+    if (!PACKET_strndup(&srp_I, &s->srp_ctx.login)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_SRP,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+#ifndef OPENSSL_NO_EC
+int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx)
+{
+    PACKET ec_point_format_list;
+
+    if (!PACKET_as_length_prefixed_1(pkt, &ec_point_format_list)
+        || PACKET_remaining(&ec_point_format_list) == 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_EC_PT_FORMATS,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    if (!s->hit) {
+        if (!PACKET_memdup(&ec_point_format_list,
+                           &s->ext.peer_ecpointformats,
+                           &s->ext.peer_ecpointformats_len)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PARSE_CTOS_EC_PT_FORMATS, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif                          /* OPENSSL_NO_EC */
+
+int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    if (s->ext.session_ticket_cb &&
+            !s->ext.session_ticket_cb(s, PACKET_data(pkt),
+                                  PACKET_remaining(pkt),
+                                  s->ext.session_ticket_cb_arg)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_SESSION_TICKET, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_parse_ctos_sig_algs_cert(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx)
+{
+    PACKET supported_sig_algs;
+
+    if (!PACKET_as_length_prefixed_2(pkt, &supported_sig_algs)
+            || PACKET_remaining(&supported_sig_algs) == 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_SIG_ALGS_CERT, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    if (!s->hit && !tls1_save_sigalgs(s, &supported_sig_algs, 1)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_SIG_ALGS_CERT, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx)
+{
+    PACKET supported_sig_algs;
+
+    if (!PACKET_as_length_prefixed_2(pkt, &supported_sig_algs)
+            || PACKET_remaining(&supported_sig_algs) == 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_SIG_ALGS, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    if (!s->hit && !tls1_save_sigalgs(s, &supported_sig_algs, 0)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_SIG_ALGS, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_OCSP
+int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    PACKET responder_id_list, exts;
+
+    /* We ignore this in a resumption handshake */
+    if (s->hit)
+        return 1;
+
+    /* Not defined if we get one of these in a client Certificate */
+    if (x != NULL)
+        return 1;
+
+    if (!PACKET_get_1(pkt, (unsigned int *)&s->ext.status_type)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_STATUS_REQUEST, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    if (s->ext.status_type != TLSEXT_STATUSTYPE_ocsp) {
+        /*
+         * We don't know what to do with any other type so ignore it.
+         */
+        s->ext.status_type = TLSEXT_STATUSTYPE_nothing;
+        return 1;
+    }
+
+    if (!PACKET_get_length_prefixed_2 (pkt, &responder_id_list)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_STATUS_REQUEST, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    /*
+     * We remove any OCSP_RESPIDs from a previous handshake
+     * to prevent unbounded memory growth - CVE-2016-6304
+     */
+    sk_OCSP_RESPID_pop_free(s->ext.ocsp.ids, OCSP_RESPID_free);
+    if (PACKET_remaining(&responder_id_list) > 0) {
+        s->ext.ocsp.ids = sk_OCSP_RESPID_new_null();
+        if (s->ext.ocsp.ids == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PARSE_CTOS_STATUS_REQUEST, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+    } else {
+        s->ext.ocsp.ids = NULL;
+    }
+
+    while (PACKET_remaining(&responder_id_list) > 0) {
+        OCSP_RESPID *id;
+        PACKET responder_id;
+        const unsigned char *id_data;
+
+        if (!PACKET_get_length_prefixed_2(&responder_id_list, &responder_id)
+                || PACKET_remaining(&responder_id) == 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PARSE_CTOS_STATUS_REQUEST, SSL_R_BAD_EXTENSION);
+            return 0;
+        }
+
+        id_data = PACKET_data(&responder_id);
+        /* TODO(size_t): Convert d2i_* to size_t */
+        id = d2i_OCSP_RESPID(NULL, &id_data,
+                             (int)PACKET_remaining(&responder_id));
+        if (id == NULL) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PARSE_CTOS_STATUS_REQUEST, SSL_R_BAD_EXTENSION);
+            return 0;
+        }
+
+        if (id_data != PACKET_end(&responder_id)) {
+            OCSP_RESPID_free(id);
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PARSE_CTOS_STATUS_REQUEST, SSL_R_BAD_EXTENSION);
+
+            return 0;
+        }
+
+        if (!sk_OCSP_RESPID_push(s->ext.ocsp.ids, id)) {
+            OCSP_RESPID_free(id);
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PARSE_CTOS_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
+
+            return 0;
+        }
+    }
+
+    /* Read in request_extensions */
+    if (!PACKET_as_length_prefixed_2(pkt, &exts)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_STATUS_REQUEST, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    if (PACKET_remaining(&exts) > 0) {
+        const unsigned char *ext_data = PACKET_data(&exts);
+
+        sk_X509_EXTENSION_pop_free(s->ext.ocsp.exts,
+                                   X509_EXTENSION_free);
+        s->ext.ocsp.exts =
+            d2i_X509_EXTENSIONS(NULL, &ext_data, (int)PACKET_remaining(&exts));
+        if (s->ext.ocsp.exts == NULL || ext_data != PACKET_end(&exts)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PARSE_CTOS_STATUS_REQUEST, SSL_R_BAD_EXTENSION);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int tls_parse_ctos_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx)
+{
+    /*
+     * We shouldn't accept this extension on a
+     * renegotiation.
+     */
+    if (SSL_IS_FIRST_HANDSHAKE(s))
+        s->s3->npn_seen = 1;
+
+    return 1;
+}
+#endif
+
+/*
+ * Save the ALPN extension in a ClientHello.|pkt| holds the contents of the ALPN
+ * extension, not including type and length. Returns: 1 on success, 0 on error.
+ */
+int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                        size_t chainidx)
+{
+    PACKET protocol_list, save_protocol_list, protocol;
+
+    if (!SSL_IS_FIRST_HANDSHAKE(s))
+        return 1;
+
+    if (!PACKET_as_length_prefixed_2(pkt, &protocol_list)
+        || PACKET_remaining(&protocol_list) < 2) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_ALPN,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    save_protocol_list = protocol_list;
+    do {
+        /* Protocol names can't be empty. */
+        if (!PACKET_get_length_prefixed_1(&protocol_list, &protocol)
+                || PACKET_remaining(&protocol) == 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_ALPN,
+                     SSL_R_BAD_EXTENSION);
+            return 0;
+        }
+    } while (PACKET_remaining(&protocol_list) != 0);
+
+    OPENSSL_free(s->s3->alpn_proposed);
+    s->s3->alpn_proposed = NULL;
+    s->s3->alpn_proposed_len = 0;
+    if (!PACKET_memdup(&save_protocol_list,
+                       &s->s3->alpn_proposed, &s->s3->alpn_proposed_len)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_ALPN,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SRTP
+int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx)
+{
+    STACK_OF(SRTP_PROTECTION_PROFILE) *srvr;
+    unsigned int ct, mki_len, id;
+    int i, srtp_pref;
+    PACKET subpkt;
+
+    /* Ignore this if we have no SRTP profiles */
+    if (SSL_get_srtp_profiles(s) == NULL)
+        return 1;
+
+    /* Pull off the length of the cipher suite list  and check it is even */
+    if (!PACKET_get_net_2(pkt, &ct) || (ct & 1) != 0
+            || !PACKET_get_sub_packet(pkt, &subpkt, ct)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_USE_SRTP,
+               SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+        return 0;
+    }
+
+    srvr = SSL_get_srtp_profiles(s);
+    s->srtp_profile = NULL;
+    /* Search all profiles for a match initially */
+    srtp_pref = sk_SRTP_PROTECTION_PROFILE_num(srvr);
+
+    while (PACKET_remaining(&subpkt)) {
+        if (!PACKET_get_net_2(&subpkt, &id)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_USE_SRTP,
+                     SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+            return 0;
+        }
+
+        /*
+         * Only look for match in profiles of higher preference than
+         * current match.
+         * If no profiles have been have been configured then this
+         * does nothing.
+         */
+        for (i = 0; i < srtp_pref; i++) {
+            SRTP_PROTECTION_PROFILE *sprof =
+                sk_SRTP_PROTECTION_PROFILE_value(srvr, i);
+
+            if (sprof->id == id) {
+                s->srtp_profile = sprof;
+                srtp_pref = i;
+                break;
+            }
+        }
+    }
+
+    /* Now extract the MKI value as a sanity check, but discard it for now */
+    if (!PACKET_get_1(pkt, &mki_len)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_USE_SRTP,
+                 SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+        return 0;
+    }
+
+    if (!PACKET_forward(pkt, mki_len)
+        || PACKET_remaining(pkt)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_USE_SRTP,
+                 SSL_R_BAD_SRTP_MKI_VALUE);
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+int tls_parse_ctos_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx)
+{
+    if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC))
+        s->ext.use_etm = 1;
+
+    return 1;
+}
+
+/*
+ * Process a psk_kex_modes extension received in the ClientHello. |pkt| contains
+ * the raw PACKET data for the extension. Returns 1 on success or 0 on failure.
+ */
+int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    PACKET psk_kex_modes;
+    unsigned int mode;
+
+    if (!PACKET_as_length_prefixed_1(pkt, &psk_kex_modes)
+            || PACKET_remaining(&psk_kex_modes) == 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_PSK_KEX_MODES,
+                 SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    while (PACKET_get_1(&psk_kex_modes, &mode)) {
+        if (mode == TLSEXT_KEX_MODE_KE_DHE)
+            s->ext.psk_kex_mode |= TLSEXT_KEX_MODE_FLAG_KE_DHE;
+        else if (mode == TLSEXT_KEX_MODE_KE
+                && (s->options & SSL_OP_ALLOW_NO_DHE_KEX) != 0)
+            s->ext.psk_kex_mode |= TLSEXT_KEX_MODE_FLAG_KE;
+    }
+#endif
+
+    return 1;
+}
+
+/*
+ * Process a key_share extension received in the ClientHello. |pkt| contains
+ * the raw PACKET data for the extension. Returns 1 on success or 0 on failure.
+ */
+int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                             size_t chainidx)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    unsigned int group_id;
+    PACKET key_share_list, encoded_pt;
+    const uint16_t *clntgroups, *srvrgroups;
+    size_t clnt_num_groups, srvr_num_groups;
+    int found = 0;
+
+    if (s->hit && (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE) == 0)
+        return 1;
+
+    /* Sanity check */
+    if (s->s3->peer_tmp != NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_KEY_SHARE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (!PACKET_as_length_prefixed_2(pkt, &key_share_list)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_KEY_SHARE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    /* Get our list of supported groups */
+    tls1_get_supported_groups(s, &srvrgroups, &srvr_num_groups);
+    /* Get the clients list of supported groups. */
+    tls1_get_peer_groups(s, &clntgroups, &clnt_num_groups);
+    if (clnt_num_groups == 0) {
+        /*
+         * This can only happen if the supported_groups extension was not sent,
+         * because we verify that the length is non-zero when we process that
+         * extension.
+         */
+        SSLfatal(s, SSL_AD_MISSING_EXTENSION, SSL_F_TLS_PARSE_CTOS_KEY_SHARE,
+                 SSL_R_MISSING_SUPPORTED_GROUPS_EXTENSION);
+        return 0;
+    }
+
+    if (s->s3->group_id != 0 && PACKET_remaining(&key_share_list) == 0) {
+        /*
+         * If we set a group_id already, then we must have sent an HRR
+         * requesting a new key_share. If we haven't got one then that is an
+         * error
+         */
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_CTOS_KEY_SHARE,
+                 SSL_R_BAD_KEY_SHARE);
+        return 0;
+    }
+
+    while (PACKET_remaining(&key_share_list) > 0) {
+        if (!PACKET_get_net_2(&key_share_list, &group_id)
+                || !PACKET_get_length_prefixed_2(&key_share_list, &encoded_pt)
+                || PACKET_remaining(&encoded_pt) == 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_KEY_SHARE,
+                     SSL_R_LENGTH_MISMATCH);
+            return 0;
+        }
+
+        /*
+         * If we already found a suitable key_share we loop through the
+         * rest to verify the structure, but don't process them.
+         */
+        if (found)
+            continue;
+
+        /*
+         * If we sent an HRR then the key_share sent back MUST be for the group
+         * we requested, and must be the only key_share sent.
+         */
+        if (s->s3->group_id != 0
+                && (group_id != s->s3->group_id
+                    || PACKET_remaining(&key_share_list) != 0)) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
+            return 0;
+        }
+
+        /* Check if this share is in supported_groups sent from client */
+        if (!check_in_list(s, group_id, clntgroups, clnt_num_groups, 0)) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
+            return 0;
+        }
+
+        /* Check if this share is for a group we can use */
+        if (!check_in_list(s, group_id, srvrgroups, srvr_num_groups, 1)) {
+            /* Share not suitable */
+            continue;
+        }
+
+        if ((s->s3->peer_tmp = ssl_generate_param_group(group_id)) == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_KEY_SHARE,
+                   SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
+            return 0;
+        }
+
+        s->s3->group_id = group_id;
+
+        if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp,
+                PACKET_data(&encoded_pt),
+                PACKET_remaining(&encoded_pt))) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_BAD_ECPOINT);
+            return 0;
+        }
+
+        found = 1;
+    }
+#endif
+
+    return 1;
+}
+
+int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                          size_t chainidx)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    unsigned int format, version, key_share, group_id;
+    EVP_MD_CTX *hctx;
+    EVP_PKEY *pkey;
+    PACKET cookie, raw, chhash, appcookie;
+    WPACKET hrrpkt;
+    const unsigned char *data, *mdin, *ciphdata;
+    unsigned char hmac[SHA256_DIGEST_LENGTH];
+    unsigned char hrr[MAX_HRR_SIZE];
+    size_t rawlen, hmaclen, hrrlen, ciphlen;
+    uint64_t tm, now;
+
+    /* Ignore any cookie if we're not set up to verify it */
+    if (s->ctx->verify_stateless_cookie_cb == NULL
+            || (s->s3->flags & TLS1_FLAGS_STATELESS) == 0)
+        return 1;
+
+    if (!PACKET_as_length_prefixed_2(pkt, &cookie)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    raw = cookie;
+    data = PACKET_data(&raw);
+    rawlen = PACKET_remaining(&raw);
+    if (rawlen < SHA256_DIGEST_LENGTH
+            || !PACKET_forward(&raw, rawlen - SHA256_DIGEST_LENGTH)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+    mdin = PACKET_data(&raw);
+
+    /* Verify the HMAC of the cookie */
+    hctx = EVP_MD_CTX_create();
+    pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
+                                        s->session_ctx->ext.cookie_hmac_key,
+                                        sizeof(s->session_ctx->ext
+                                               .cookie_hmac_key));
+    if (hctx == NULL || pkey == NULL) {
+        EVP_MD_CTX_free(hctx);
+        EVP_PKEY_free(pkey);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    hmaclen = SHA256_DIGEST_LENGTH;
+    if (EVP_DigestSignInit(hctx, NULL, EVP_sha256(), NULL, pkey) <= 0
+            || EVP_DigestSign(hctx, hmac, &hmaclen, data,
+                              rawlen - SHA256_DIGEST_LENGTH) <= 0
+            || hmaclen != SHA256_DIGEST_LENGTH) {
+        EVP_MD_CTX_free(hctx);
+        EVP_PKEY_free(pkey);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    EVP_MD_CTX_free(hctx);
+    EVP_PKEY_free(pkey);
+
+    if (CRYPTO_memcmp(hmac, mdin, SHA256_DIGEST_LENGTH) != 0) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 SSL_R_COOKIE_MISMATCH);
+        return 0;
+    }
+
+    if (!PACKET_get_net_2(&cookie, &format)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+    /* Check the cookie format is something we recognise. Ignore it if not */
+    if (format != COOKIE_STATE_FORMAT_VERSION)
+        return 1;
+
+    /*
+     * The rest of these checks really shouldn't fail since we have verified the
+     * HMAC above.
+     */
+
+    /* Check the version number is sane */
+    if (!PACKET_get_net_2(&cookie, &version)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+    if (version != TLS1_3_VERSION) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 SSL_R_BAD_PROTOCOL_VERSION_NUMBER);
+        return 0;
+    }
+
+    if (!PACKET_get_net_2(&cookie, &group_id)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    ciphdata = PACKET_data(&cookie);
+    if (!PACKET_forward(&cookie, 2)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+    if (group_id != s->s3->group_id
+            || s->s3->tmp.new_cipher
+               != ssl_get_cipher_by_char(s, ciphdata, 0)) {
+        /*
+         * We chose a different cipher or group id this time around to what is
+         * in the cookie. Something must have changed.
+         */
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 SSL_R_BAD_CIPHER);
+        return 0;
+    }
+
+    if (!PACKET_get_1(&cookie, &key_share)
+            || !PACKET_get_net_8(&cookie, &tm)
+            || !PACKET_get_length_prefixed_2(&cookie, &chhash)
+            || !PACKET_get_length_prefixed_1(&cookie, &appcookie)
+            || PACKET_remaining(&cookie) != SHA256_DIGEST_LENGTH) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    /* We tolerate a cookie age of up to 10 minutes (= 60 * 10 seconds) */
+    now = time(NULL);
+    if (tm > now || (now - tm) > 600) {
+        /* Cookie is stale. Ignore it */
+        return 1;
+    }
+
+    /* Verify the app cookie */
+    if (s->ctx->verify_stateless_cookie_cb(s, PACKET_data(&appcookie),
+                                     PACKET_remaining(&appcookie)) == 0) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 SSL_R_COOKIE_MISMATCH);
+        return 0;
+    }
+
+    /*
+     * Reconstruct the HRR that we would have sent in response to the original
+     * ClientHello so we can add it to the transcript hash.
+     * Note: This won't work with custom HRR extensions
+     */
+    if (!WPACKET_init_static_len(&hrrpkt, hrr, sizeof(hrr), 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    if (!WPACKET_put_bytes_u8(&hrrpkt, SSL3_MT_SERVER_HELLO)
+            || !WPACKET_start_sub_packet_u24(&hrrpkt)
+            || !WPACKET_put_bytes_u16(&hrrpkt, TLS1_2_VERSION)
+            || !WPACKET_memcpy(&hrrpkt, hrrrandom, SSL3_RANDOM_SIZE)
+            || !WPACKET_sub_memcpy_u8(&hrrpkt, s->tmp_session_id,
+                                      s->tmp_session_id_len)
+            || !s->method->put_cipher_by_char(s->s3->tmp.new_cipher, &hrrpkt,
+                                              &ciphlen)
+            || !WPACKET_put_bytes_u8(&hrrpkt, 0)
+            || !WPACKET_start_sub_packet_u16(&hrrpkt)) {
+        WPACKET_cleanup(&hrrpkt);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    if (!WPACKET_put_bytes_u16(&hrrpkt, TLSEXT_TYPE_supported_versions)
+            || !WPACKET_start_sub_packet_u16(&hrrpkt)
+            || !WPACKET_put_bytes_u16(&hrrpkt, s->version)
+            || !WPACKET_close(&hrrpkt)) {
+        WPACKET_cleanup(&hrrpkt);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    if (key_share) {
+        if (!WPACKET_put_bytes_u16(&hrrpkt, TLSEXT_TYPE_key_share)
+                || !WPACKET_start_sub_packet_u16(&hrrpkt)
+                || !WPACKET_put_bytes_u16(&hrrpkt, s->s3->group_id)
+                || !WPACKET_close(&hrrpkt)) {
+            WPACKET_cleanup(&hrrpkt);
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+    if (!WPACKET_put_bytes_u16(&hrrpkt, TLSEXT_TYPE_cookie)
+            || !WPACKET_start_sub_packet_u16(&hrrpkt)
+            || !WPACKET_sub_memcpy_u16(&hrrpkt, data, rawlen)
+            || !WPACKET_close(&hrrpkt) /* cookie extension */
+            || !WPACKET_close(&hrrpkt) /* extension block */
+            || !WPACKET_close(&hrrpkt) /* message */
+            || !WPACKET_get_total_written(&hrrpkt, &hrrlen)
+            || !WPACKET_finish(&hrrpkt)) {
+        WPACKET_cleanup(&hrrpkt);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /* Reconstruct the transcript hash */
+    if (!create_synthetic_message_hash(s, PACKET_data(&chhash),
+                                       PACKET_remaining(&chhash), hrr,
+                                       hrrlen)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    /* Act as if this ClientHello came after a HelloRetryRequest */
+    s->hello_retry_request = 1;
+
+    s->ext.cookieok = 1;
+#endif
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_EC
+int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, unsigned int context,
+                                    X509 *x, size_t chainidx)
+{
+    PACKET supported_groups_list;
+
+    /* Each group is 2 bytes and we must have at least 1. */
+    if (!PACKET_as_length_prefixed_2(pkt, &supported_groups_list)
+            || PACKET_remaining(&supported_groups_list) == 0
+            || (PACKET_remaining(&supported_groups_list) % 2) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_SUPPORTED_GROUPS, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    if (!s->hit || SSL_IS_TLS13(s)) {
+        OPENSSL_free(s->ext.peer_supportedgroups);
+        s->ext.peer_supportedgroups = NULL;
+        s->ext.peer_supportedgroups_len = 0;
+        if (!tls1_save_u16(&supported_groups_list,
+                           &s->ext.peer_supportedgroups,
+                           &s->ext.peer_supportedgroups_len)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PARSE_CTOS_SUPPORTED_GROUPS,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif
+
+int tls_parse_ctos_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx)
+{
+    /* The extension must always be empty */
+    if (PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_EMS, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS;
+
+    return 1;
+}
+
+
+int tls_parse_ctos_early_data(SSL *s, PACKET *pkt, unsigned int context,
+                              X509 *x, size_t chainidx)
+{
+    if (PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_EARLY_DATA, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    if (s->hello_retry_request != SSL_HRR_NONE) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                 SSL_F_TLS_PARSE_CTOS_EARLY_DATA, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    return 1;
+}
+
+static SSL_TICKET_STATUS tls_get_stateful_ticket(SSL *s, PACKET *tick,
+                                                 SSL_SESSION **sess)
+{
+    SSL_SESSION *tmpsess = NULL;
+
+    s->ext.ticket_expected = 1;
+
+    switch (PACKET_remaining(tick)) {
+        case 0:
+            return SSL_TICKET_EMPTY;
+
+        case SSL_MAX_SSL_SESSION_ID_LENGTH:
+            break;
+
+        default:
+            return SSL_TICKET_NO_DECRYPT;
+    }
+
+    tmpsess = lookup_sess_in_cache(s, PACKET_data(tick),
+                                   SSL_MAX_SSL_SESSION_ID_LENGTH);
+
+    if (tmpsess == NULL)
+        return SSL_TICKET_NO_DECRYPT;
+
+    *sess = tmpsess;
+    return SSL_TICKET_SUCCESS;
+}
+
+int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx)
+{
+    PACKET identities, binders, binder;
+    size_t binderoffset, hashsize;
+    SSL_SESSION *sess = NULL;
+    unsigned int id, i, ext = 0;
+    const EVP_MD *md = NULL;
+
+    /*
+     * If we have no PSK kex mode that we recognise then we can't resume so
+     * ignore this extension
+     */
+    if ((s->ext.psk_kex_mode
+            & (TLSEXT_KEX_MODE_FLAG_KE | TLSEXT_KEX_MODE_FLAG_KE_DHE)) == 0)
+        return 1;
+
+    if (!PACKET_get_length_prefixed_2(pkt, &identities)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_PSK, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    s->ext.ticket_expected = 0;
+    for (id = 0; PACKET_remaining(&identities) != 0; id++) {
+        PACKET identity;
+        unsigned long ticket_agel;
+        size_t idlen;
+
+        if (!PACKET_get_length_prefixed_2(&identities, &identity)
+                || !PACKET_get_net_4(&identities, &ticket_agel)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PARSE_CTOS_PSK, SSL_R_BAD_EXTENSION);
+            return 0;
+        }
+
+        idlen = PACKET_remaining(&identity);
+        if (s->psk_find_session_cb != NULL
+                && !s->psk_find_session_cb(s, PACKET_data(&identity), idlen,
+                                           &sess)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PARSE_CTOS_PSK, SSL_R_BAD_EXTENSION);
+            return 0;
+        }
+
+#ifndef OPENSSL_NO_PSK
+        if(sess == NULL
+                && s->psk_server_callback != NULL
+                && idlen <= PSK_MAX_IDENTITY_LEN) {
+            char *pskid = NULL;
+            unsigned char pskdata[PSK_MAX_PSK_LEN];
+            unsigned int pskdatalen;
+
+            if (!PACKET_strndup(&identity, &pskid)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+            pskdatalen = s->psk_server_callback(s, pskid, pskdata,
+                                                sizeof(pskdata));
+            OPENSSL_free(pskid);
+            if (pskdatalen > PSK_MAX_PSK_LEN) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            } else if (pskdatalen > 0) {
+                const SSL_CIPHER *cipher;
+                const unsigned char tls13_aes128gcmsha256_id[] = { 0x13, 0x01 };
+
+                /*
+                 * We found a PSK using an old style callback. We don't know
+                 * the digest so we default to SHA256 as per the TLSv1.3 spec
+                 */
+                cipher = SSL_CIPHER_find(s, tls13_aes128gcmsha256_id);
+                if (cipher == NULL) {
+                    OPENSSL_cleanse(pskdata, pskdatalen);
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
+                             ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+
+                sess = SSL_SESSION_new();
+                if (sess == NULL
+                        || !SSL_SESSION_set1_master_key(sess, pskdata,
+                                                        pskdatalen)
+                        || !SSL_SESSION_set_cipher(sess, cipher)
+                        || !SSL_SESSION_set_protocol_version(sess,
+                                                             TLS1_3_VERSION)) {
+                    OPENSSL_cleanse(pskdata, pskdatalen);
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
+                             ERR_R_INTERNAL_ERROR);
+                    goto err;
+                }
+                OPENSSL_cleanse(pskdata, pskdatalen);
+            }
+        }
+#endif /* OPENSSL_NO_PSK */
+
+        if (sess != NULL) {
+            /* We found a PSK */
+            SSL_SESSION *sesstmp = ssl_session_dup(sess, 0);
+
+            if (sesstmp == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_PARSE_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            SSL_SESSION_free(sess);
+            sess = sesstmp;
+
+            /*
+             * We've just been told to use this session for this context so
+             * make sure the sid_ctx matches up.
+             */
+            memcpy(sess->sid_ctx, s->sid_ctx, s->sid_ctx_length);
+            sess->sid_ctx_length = s->sid_ctx_length;
+            ext = 1;
+            if (id == 0)
+                s->ext.early_data_ok = 1;
+            s->ext.ticket_expected = 1;
+        } else {
+            uint32_t ticket_age = 0, agesec, agems;
+            int ret;
+
+            /*
+             * If we are using anti-replay protection then we behave as if
+             * SSL_OP_NO_TICKET is set - we are caching tickets anyway so there
+             * is no point in using full stateless tickets.
+             */
+            if ((s->options & SSL_OP_NO_TICKET) != 0
+                    || (s->max_early_data > 0
+                        && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0))
+                ret = tls_get_stateful_ticket(s, &identity, &sess);
+            else
+                ret = tls_decrypt_ticket(s, PACKET_data(&identity),
+                                         PACKET_remaining(&identity), NULL, 0,
+                                         &sess);
+
+            if (ret == SSL_TICKET_EMPTY) {
+                SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
+                         SSL_R_BAD_EXTENSION);
+                return 0;
+            }
+
+            if (ret == SSL_TICKET_FATAL_ERR_MALLOC
+                    || ret == SSL_TICKET_FATAL_ERR_OTHER) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_PARSE_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+            if (ret == SSL_TICKET_NONE || ret == SSL_TICKET_NO_DECRYPT)
+                continue;
+
+            /* Check for replay */
+            if (s->max_early_data > 0
+                    && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0
+                    && !SSL_CTX_remove_session(s->session_ctx, sess)) {
+                SSL_SESSION_free(sess);
+                sess = NULL;
+                continue;
+            }
+
+            ticket_age = (uint32_t)ticket_agel;
+            agesec = (uint32_t)(time(NULL) - sess->time);
+            agems = agesec * (uint32_t)1000;
+            ticket_age -= sess->ext.tick_age_add;
+
+            /*
+             * For simplicity we do our age calculations in seconds. If the
+             * client does it in ms then it could appear that their ticket age
+             * is longer than ours (our ticket age calculation should always be
+             * slightly longer than the client's due to the network latency).
+             * Therefore we add 1000ms to our age calculation to adjust for
+             * rounding errors.
+             */
+            if (id == 0
+                    && sess->timeout >= (long)agesec
+                    && agems / (uint32_t)1000 == agesec
+                    && ticket_age <= agems + 1000
+                    && ticket_age + TICKET_AGE_ALLOWANCE >= agems + 1000) {
+                /*
+                 * Ticket age is within tolerance and not expired. We allow it
+                 * for early data
+                 */
+                s->ext.early_data_ok = 1;
+            }
+        }
+
+        md = ssl_md(sess->cipher->algorithm2);
+        if (md != ssl_md(s->s3->tmp.new_cipher->algorithm2)) {
+            /* The ciphersuite is not compatible with this session. */
+            SSL_SESSION_free(sess);
+            sess = NULL;
+            s->ext.early_data_ok = 0;
+            s->ext.ticket_expected = 0;
+            continue;
+        }
+        break;
+    }
+
+    if (sess == NULL)
+        return 1;
+
+    binderoffset = PACKET_data(pkt) - (const unsigned char *)s->init_buf->data;
+    hashsize = EVP_MD_size(md);
+
+    if (!PACKET_get_length_prefixed_2(pkt, &binders)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
+                 SSL_R_BAD_EXTENSION);
+        goto err;
+    }
+
+    for (i = 0; i <= id; i++) {
+        if (!PACKET_get_length_prefixed_1(&binders, &binder)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
+                     SSL_R_BAD_EXTENSION);
+            goto err;
+        }
+    }
+
+    if (PACKET_remaining(&binder) != hashsize) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
+                 SSL_R_BAD_EXTENSION);
+        goto err;
+    }
+    if (tls_psk_do_binder(s, md, (const unsigned char *)s->init_buf->data,
+                          binderoffset, PACKET_data(&binder), NULL, sess, 0,
+                          ext) != 1) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    s->ext.tick_identity = id;
+
+    SSL_SESSION_free(s->session);
+    s->session = sess;
+    return 1;
+err:
+    SSL_SESSION_free(sess);
+    return 0;
+}
+
+int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt, unsigned int context,
+                                       X509 *x, size_t chainidx)
+{
+    if (PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_POST_HANDSHAKE_AUTH,
+                 SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR);
+        return 0;
+    }
+
+    s->post_handshake_auth = SSL_PHA_EXT_RECEIVED;
+
+    return 1;
+}
+
+/*
+ * Add the server's renegotiation binding
+ */
+EXT_RETURN tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
+                                          size_t chainidx)
+{
+    if (!s->s3->send_connection_binding)
+        return EXT_RETURN_NOT_SENT;
+
+    /* Still add this even if SSL_OP_NO_RENEGOTIATION is set */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u8(pkt)
+            || !WPACKET_memcpy(pkt, s->s3->previous_client_finished,
+                               s->s3->previous_client_finished_len)
+            || !WPACKET_memcpy(pkt, s->s3->previous_server_finished,
+                               s->s3->previous_server_finished_len)
+            || !WPACKET_close(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+EXT_RETURN tls_construct_stoc_server_name(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
+                                          size_t chainidx)
+{
+    if (s->servername_done != 1)
+        return EXT_RETURN_NOT_SENT;
+
+    /*
+     * Prior to TLSv1.3 we ignore any SNI in the current handshake if resuming.
+     * We just use the servername from the initial handshake.
+     */
+    if (s->hit && !SSL_IS_TLS13(s))
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+/* Add/include the server's max fragment len extension into ServerHello */
+EXT_RETURN tls_construct_stoc_maxfragmentlen(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx)
+{
+    if (!USE_MAX_FRAGMENT_LENGTH_EXT(s->session))
+        return EXT_RETURN_NOT_SENT;
+
+    /*-
+     * 4 bytes for this extension type and extension length
+     * 1 byte for the Max Fragment Length code value.
+     */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_max_fragment_length)
+        || !WPACKET_start_sub_packet_u16(pkt)
+        || !WPACKET_put_bytes_u8(pkt, s->session->ext.max_fragment_len_mode)
+        || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_STOC_MAXFRAGMENTLEN, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+#ifndef OPENSSL_NO_EC
+EXT_RETURN tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx)
+{
+    unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+    unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+    int using_ecc = ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA))
+                    && (s->ext.peer_ecpointformats != NULL);
+    const unsigned char *plist;
+    size_t plistlen;
+
+    if (!using_ecc)
+        return EXT_RETURN_NOT_SENT;
+
+    tls1_get_formatlist(s, &plist, &plistlen);
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_ec_point_formats)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u8(pkt, plist, plistlen)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_STOC_EC_PT_FORMATS, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+#endif
+
+#ifndef OPENSSL_NO_EC
+EXT_RETURN tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt,
+                                               unsigned int context, X509 *x,
+                                               size_t chainidx)
+{
+    const uint16_t *groups;
+    size_t numgroups, i, first = 1;
+
+    /* s->s3->group_id is non zero if we accepted a key_share */
+    if (s->s3->group_id == 0)
+        return EXT_RETURN_NOT_SENT;
+
+    /* Get our list of supported groups */
+    tls1_get_supported_groups(s, &groups, &numgroups);
+    if (numgroups == 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    /* Copy group ID if supported */
+    for (i = 0; i < numgroups; i++) {
+        uint16_t group = groups[i];
+
+        if (tls_curve_allowed(s, group, SSL_SECOP_CURVE_SUPPORTED)) {
+            if (first) {
+                /*
+                 * Check if the client is already using our preferred group. If
+                 * so we don't need to add this extension
+                 */
+                if (s->s3->group_id == group)
+                    return EXT_RETURN_NOT_SENT;
+
+                /* Add extension header */
+                if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_groups)
+                           /* Sub-packet for supported_groups extension */
+                        || !WPACKET_start_sub_packet_u16(pkt)
+                        || !WPACKET_start_sub_packet_u16(pkt)) {
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                             SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS,
+                             ERR_R_INTERNAL_ERROR);
+                    return EXT_RETURN_FAIL;
+                }
+
+                first = 0;
+            }
+            if (!WPACKET_put_bytes_u16(pkt, group)) {
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                             SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS,
+                             ERR_R_INTERNAL_ERROR);
+                    return EXT_RETURN_FAIL;
+                }
+        }
+    }
+
+    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+#endif
+
+EXT_RETURN tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx)
+{
+    if (!s->ext.ticket_expected || !tls_use_ticket(s)) {
+        s->ext.ticket_expected = 0;
+        return EXT_RETURN_NOT_SENT;
+    }
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_STOC_SESSION_TICKET, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+#ifndef OPENSSL_NO_OCSP
+EXT_RETURN tls_construct_stoc_status_request(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx)
+{
+    /* We don't currently support this extension inside a CertificateRequest */
+    if (context == SSL_EXT_TLS1_3_CERTIFICATE_REQUEST)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!s->ext.status_expected)
+        return EXT_RETURN_NOT_SENT;
+
+    if (SSL_IS_TLS13(s) && chainidx != 0)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request)
+            || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_STOC_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    /*
+     * In TLSv1.3 we include the certificate status itself. In <= TLSv1.2 we
+     * send back an empty extension, with the certificate status appearing as a
+     * separate message
+     */
+    if (SSL_IS_TLS13(s) && !tls_construct_cert_status_body(s, pkt)) {
+       /* SSLfatal() already called */
+       return EXT_RETURN_FAIL;
+    }
+    if (!WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_STOC_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+#endif
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+EXT_RETURN tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx)
+{
+    const unsigned char *npa;
+    unsigned int npalen;
+    int ret;
+    int npn_seen = s->s3->npn_seen;
+
+    s->s3->npn_seen = 0;
+    if (!npn_seen || s->ctx->ext.npn_advertised_cb == NULL)
+        return EXT_RETURN_NOT_SENT;
+
+    ret = s->ctx->ext.npn_advertised_cb(s, &npa, &npalen,
+                                        s->ctx->ext.npn_advertised_cb_arg);
+    if (ret == SSL_TLSEXT_ERR_OK) {
+        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg)
+                || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG,
+                     ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+        s->s3->npn_seen = 1;
+    }
+
+    return EXT_RETURN_SENT;
+}
+#endif
+
+EXT_RETURN tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx)
+{
+    if (s->s3->alpn_selected == NULL)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt,
+                TLSEXT_TYPE_application_layer_protocol_negotiation)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u8(pkt, s->s3->alpn_selected,
+                                      s->s3->alpn_selected_len)
+            || !WPACKET_close(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_STOC_ALPN, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+#ifndef OPENSSL_NO_SRTP
+EXT_RETURN tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt,
+                                       unsigned int context, X509 *x,
+                                       size_t chainidx)
+{
+    if (s->srtp_profile == NULL)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_use_srtp)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u16(pkt, 2)
+            || !WPACKET_put_bytes_u16(pkt, s->srtp_profile->id)
+            || !WPACKET_put_bytes_u8(pkt, 0)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_USE_SRTP,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+#endif
+
+EXT_RETURN tls_construct_stoc_etm(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    if (!s->ext.use_etm)
+        return EXT_RETURN_NOT_SENT;
+
+    /*
+     * Don't use encrypt_then_mac if AEAD or RC4 might want to disable
+     * for other cases too.
+     */
+    if (s->s3->tmp.new_cipher->algorithm_mac == SSL_AEAD
+        || s->s3->tmp.new_cipher->algorithm_enc == SSL_RC4
+        || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT
+        || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT12) {
+        s->ext.use_etm = 0;
+        return EXT_RETURN_NOT_SENT;
+    }
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_encrypt_then_mac)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_ETM,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+EXT_RETURN tls_construct_stoc_ems(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    if ((s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) == 0)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_EMS,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+EXT_RETURN tls_construct_stoc_supported_versions(SSL *s, WPACKET *pkt,
+                                                 unsigned int context, X509 *x,
+                                                 size_t chainidx)
+{
+    if (!ossl_assert(SSL_IS_TLS13(s))) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_VERSIONS,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_versions)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u16(pkt, s->version)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_VERSIONS,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt,
+                                        unsigned int context, X509 *x,
+                                        size_t chainidx)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    unsigned char *encodedPoint;
+    size_t encoded_pt_len = 0;
+    EVP_PKEY *ckey = s->s3->peer_tmp, *skey = NULL;
+
+    if (s->hello_retry_request == SSL_HRR_PENDING) {
+        if (ckey != NULL) {
+            /* Original key_share was acceptable so don't ask for another one */
+            return EXT_RETURN_NOT_SENT;
+        }
+        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)
+                || !WPACKET_close(pkt)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+                     ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+
+        return EXT_RETURN_SENT;
+    }
+
+    if (ckey == NULL) {
+        /* No key_share received from client - must be resuming */
+        if (!s->hit || !tls13_generate_handshake_secret(s, NULL, 0)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+        return EXT_RETURN_NOT_SENT;
+    }
+    if (s->hit && (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE) == 0) {
+        /*
+         * PSK ('hit') and explicitly not doing DHE (if the client sent the
+         * DHE option we always take it); don't send key share.
+         */
+        return EXT_RETURN_NOT_SENT;
+    }
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    skey = ssl_generate_pkey(ckey);
+    if (skey == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+                 ERR_R_MALLOC_FAILURE);
+        return EXT_RETURN_FAIL;
+    }
+
+    /* Generate encoding of server key */
+    encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint);
+    if (encoded_pt_len == 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+                 ERR_R_EC_LIB);
+        EVP_PKEY_free(skey);
+        return EXT_RETURN_FAIL;
+    }
+
+    if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+                 ERR_R_INTERNAL_ERROR);
+        EVP_PKEY_free(skey);
+        OPENSSL_free(encodedPoint);
+        return EXT_RETURN_FAIL;
+    }
+    OPENSSL_free(encodedPoint);
+
+    /* This causes the crypto state to be updated based on the derived keys */
+    s->s3->tmp.pkey = skey;
+    if (ssl_derive(s, skey, ckey, 1) == 0) {
+        /* SSLfatal() already called */
+        return EXT_RETURN_FAIL;
+    }
+    return EXT_RETURN_SENT;
+#else
+    return EXT_RETURN_FAIL;
+#endif
+}
+
+EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context,
+                                     X509 *x, size_t chainidx)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    unsigned char *hashval1, *hashval2, *appcookie1, *appcookie2, *cookie;
+    unsigned char *hmac, *hmac2;
+    size_t startlen, ciphlen, totcookielen, hashlen, hmaclen, appcookielen;
+    EVP_MD_CTX *hctx;
+    EVP_PKEY *pkey;
+    int ret = EXT_RETURN_FAIL;
+
+    if ((s->s3->flags & TLS1_FLAGS_STATELESS) == 0)
+        return EXT_RETURN_NOT_SENT;
+
+    if (s->ctx->gen_stateless_cookie_cb == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
+                 SSL_R_NO_COOKIE_CALLBACK_SET);
+        return EXT_RETURN_FAIL;
+    }
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_cookie)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_get_total_written(pkt, &startlen)
+            || !WPACKET_reserve_bytes(pkt, MAX_COOKIE_SIZE, &cookie)
+            || !WPACKET_put_bytes_u16(pkt, COOKIE_STATE_FORMAT_VERSION)
+            || !WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION)
+            || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)
+            || !s->method->put_cipher_by_char(s->s3->tmp.new_cipher, pkt,
+                                              &ciphlen)
+               /* Is there a key_share extension present in this HRR? */
+            || !WPACKET_put_bytes_u8(pkt, s->s3->peer_tmp == NULL)
+            || !WPACKET_put_bytes_u64(pkt, time(NULL))
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_reserve_bytes(pkt, EVP_MAX_MD_SIZE, &hashval1)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    /*
+     * Get the hash of the initial ClientHello. ssl_handshake_hash() operates
+     * on raw buffers, so we first reserve sufficient bytes (above) and then
+     * subsequently allocate them (below)
+     */
+    if (!ssl3_digest_cached_records(s, 0)
+            || !ssl_handshake_hash(s, hashval1, EVP_MAX_MD_SIZE, &hashlen)) {
+        /* SSLfatal() already called */
+        return EXT_RETURN_FAIL;
+    }
+
+    if (!WPACKET_allocate_bytes(pkt, hashlen, &hashval2)
+            || !ossl_assert(hashval1 == hashval2)
+            || !WPACKET_close(pkt)
+            || !WPACKET_start_sub_packet_u8(pkt)
+            || !WPACKET_reserve_bytes(pkt, SSL_COOKIE_LENGTH, &appcookie1)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    /* Generate the application cookie */
+    if (s->ctx->gen_stateless_cookie_cb(s, appcookie1, &appcookielen) == 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
+                 SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
+        return EXT_RETURN_FAIL;
+    }
+
+    if (!WPACKET_allocate_bytes(pkt, appcookielen, &appcookie2)
+            || !ossl_assert(appcookie1 == appcookie2)
+            || !WPACKET_close(pkt)
+            || !WPACKET_get_total_written(pkt, &totcookielen)
+            || !WPACKET_reserve_bytes(pkt, SHA256_DIGEST_LENGTH, &hmac)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+    hmaclen = SHA256_DIGEST_LENGTH;
+
+    totcookielen -= startlen;
+    if (!ossl_assert(totcookielen <= MAX_COOKIE_SIZE - SHA256_DIGEST_LENGTH)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    /* HMAC the cookie */
+    hctx = EVP_MD_CTX_create();
+    pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
+                                        s->session_ctx->ext.cookie_hmac_key,
+                                        sizeof(s->session_ctx->ext
+                                               .cookie_hmac_key));
+    if (hctx == NULL || pkey == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (EVP_DigestSignInit(hctx, NULL, EVP_sha256(), NULL, pkey) <= 0
+            || EVP_DigestSign(hctx, hmac, &hmaclen, cookie,
+                              totcookielen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (!ossl_assert(totcookielen + hmaclen <= MAX_COOKIE_SIZE)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (!WPACKET_allocate_bytes(pkt, hmaclen, &hmac2)
+            || !ossl_assert(hmac == hmac2)
+            || !ossl_assert(cookie == hmac - totcookielen)
+            || !WPACKET_close(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    ret = EXT_RETURN_SENT;
+
+ err:
+    EVP_MD_CTX_free(hctx);
+    EVP_PKEY_free(pkey);
+    return ret;
+#else
+    return EXT_RETURN_FAIL;
+#endif
+}
+
+EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx)
+{
+    const unsigned char cryptopro_ext[36] = {
+        0xfd, 0xe8,         /* 65000 */
+        0x00, 0x20,         /* 32 bytes length */
+        0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85,
+        0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06,
+        0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08,
+        0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17
+    };
+
+    if (((s->s3->tmp.new_cipher->id & 0xFFFF) != 0x80
+         && (s->s3->tmp.new_cipher->id & 0xFFFF) != 0x81)
+            || (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG) == 0)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_memcpy(pkt, cryptopro_ext, sizeof(cryptopro_ext))) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_STOC_CRYPTOPRO_BUG, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt,
+                                         unsigned int context, X509 *x,
+                                         size_t chainidx)
+{
+    if (context == SSL_EXT_TLS1_3_NEW_SESSION_TICKET) {
+        if (s->max_early_data == 0)
+            return EXT_RETURN_NOT_SENT;
+
+        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data)
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || !WPACKET_put_bytes_u32(pkt, s->max_early_data)
+                || !WPACKET_close(pkt)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA, ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
+        }
+
+        return EXT_RETURN_SENT;
+    }
+
+    if (s->ext.early_data != SSL_EARLY_DATA_ACCEPTED)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
+EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx)
+{
+    if (!s->hit)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_psk)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u16(pkt, s->ext.tick_identity)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_STOC_PSK, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem.c b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem.c
new file mode 100644
index 0000000..20f5bd5
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem.c
@@ -0,0 +1,972 @@
+/*
+ * Copyright 2015-2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "internal/cryptlib.h"
+#include <openssl/rand.h>
+#include "../ssl_local.h"
+#include "statem_local.h"
+#include <assert.h>
+
+/*
+ * This file implements the SSL/TLS/DTLS state machines.
+ *
+ * There are two primary state machines:
+ *
+ * 1) Message flow state machine
+ * 2) Handshake state machine
+ *
+ * The Message flow state machine controls the reading and sending of messages
+ * including handling of non-blocking IO events, flushing of the underlying
+ * write BIO, handling unexpected messages, etc. It is itself broken into two
+ * separate sub-state machines which control reading and writing respectively.
+ *
+ * The Handshake state machine keeps track of the current SSL/TLS handshake
+ * state. Transitions of the handshake state are the result of events that
+ * occur within the Message flow state machine.
+ *
+ * Overall it looks like this:
+ *
+ * ---------------------------------------------            -------------------
+ * |                                           |            |                 |
+ * | Message flow state machine                |            |                 |
+ * |                                           |            |                 |
+ * | -------------------- -------------------- | Transition | Handshake state |
+ * | | MSG_FLOW_READING | | MSG_FLOW_WRITING | | Event      | machine         |
+ * | | sub-state        | | sub-state        | |----------->|                 |
+ * | | machine for      | | machine for      | |            |                 |
+ * | | reading messages | | writing messages | |            |                 |
+ * | -------------------- -------------------- |            |                 |
+ * |                                           |            |                 |
+ * ---------------------------------------------            -------------------
+ *
+ */
+
+/* Sub state machine return values */
+typedef enum {
+    /* Something bad happened or NBIO */
+    SUB_STATE_ERROR,
+    /* Sub state finished go to the next sub state */
+    SUB_STATE_FINISHED,
+    /* Sub state finished and handshake was completed */
+    SUB_STATE_END_HANDSHAKE
+} SUB_STATE_RETURN;
+
+static int state_machine(SSL *s, int server);
+static void init_read_state_machine(SSL *s);
+static SUB_STATE_RETURN read_state_machine(SSL *s);
+static void init_write_state_machine(SSL *s);
+static SUB_STATE_RETURN write_state_machine(SSL *s);
+
+OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl)
+{
+    return ssl->statem.hand_state;
+}
+
+int SSL_in_init(const SSL *s)
+{
+    return s->statem.in_init;
+}
+
+int SSL_is_init_finished(const SSL *s)
+{
+    return !(s->statem.in_init) && (s->statem.hand_state == TLS_ST_OK);
+}
+
+int SSL_in_before(const SSL *s)
+{
+    /*
+     * Historically being "in before" meant before anything had happened. In the
+     * current code though we remain in the "before" state for a while after we
+     * have started the handshake process (e.g. as a server waiting for the
+     * first message to arrive). There "in before" is taken to mean "in before"
+     * and not started any handshake process yet.
+     */
+    return (s->statem.hand_state == TLS_ST_BEFORE)
+        && (s->statem.state == MSG_FLOW_UNINITED);
+}
+
+/*
+ * Clear the state machine state and reset back to MSG_FLOW_UNINITED
+ */
+void ossl_statem_clear(SSL *s)
+{
+    s->statem.state = MSG_FLOW_UNINITED;
+    s->statem.hand_state = TLS_ST_BEFORE;
+    s->statem.in_init = 1;
+    s->statem.no_cert_verify = 0;
+}
+
+/*
+ * Set the state machine up ready for a renegotiation handshake
+ */
+void ossl_statem_set_renegotiate(SSL *s)
+{
+    s->statem.in_init = 1;
+    s->statem.request_state = TLS_ST_SW_HELLO_REQ;
+}
+
+/*
+ * Put the state machine into an error state and send an alert if appropriate.
+ * This is a permanent error for the current connection.
+ */
+void ossl_statem_fatal(SSL *s, int al, int func, int reason, const char *file,
+                       int line)
+{
+    ERR_put_error(ERR_LIB_SSL, func, reason, file, line);
+    /* We shouldn't call SSLfatal() twice. Once is enough */
+    if (s->statem.in_init && s->statem.state == MSG_FLOW_ERROR)
+      return;
+    s->statem.in_init = 1;
+    s->statem.state = MSG_FLOW_ERROR;
+    if (al != SSL_AD_NO_ALERT
+            && s->statem.enc_write_state != ENC_WRITE_STATE_INVALID)
+        ssl3_send_alert(s, SSL3_AL_FATAL, al);
+}
+
+/*
+ * This macro should only be called if we are already expecting to be in
+ * a fatal error state. We verify that we are, and set it if not (this would
+ * indicate a bug).
+ */
+#define check_fatal(s, f) \
+    do { \
+        if (!ossl_assert((s)->statem.in_init \
+                         && (s)->statem.state == MSG_FLOW_ERROR)) \
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, (f), \
+                     SSL_R_MISSING_FATAL); \
+    } while (0)
+
+/*
+ * Discover whether the current connection is in the error state.
+ *
+ * Valid return values are:
+ *   1: Yes
+ *   0: No
+ */
+int ossl_statem_in_error(const SSL *s)
+{
+    if (s->statem.state == MSG_FLOW_ERROR)
+        return 1;
+
+    return 0;
+}
+
+void ossl_statem_set_in_init(SSL *s, int init)
+{
+    s->statem.in_init = init;
+}
+
+int ossl_statem_get_in_handshake(SSL *s)
+{
+    return s->statem.in_handshake;
+}
+
+void ossl_statem_set_in_handshake(SSL *s, int inhand)
+{
+    if (inhand)
+        s->statem.in_handshake++;
+    else
+        s->statem.in_handshake--;
+}
+
+/* Are we in a sensible state to skip over unreadable early data? */
+int ossl_statem_skip_early_data(SSL *s)
+{
+    if (s->ext.early_data != SSL_EARLY_DATA_REJECTED)
+        return 0;
+
+    if (!s->server
+            || s->statem.hand_state != TLS_ST_EARLY_DATA
+            || s->hello_retry_request == SSL_HRR_COMPLETE)
+        return 0;
+
+    return 1;
+}
+
+/*
+ * Called when we are in SSL_read*(), SSL_write*(), or SSL_accept()
+ * /SSL_connect()/SSL_do_handshake(). Used to test whether we are in an early
+ * data state and whether we should attempt to move the handshake on if so.
+ * |sending| is 1 if we are attempting to send data (SSL_write*()), 0 if we are
+ * attempting to read data (SSL_read*()), or -1 if we are in SSL_do_handshake()
+ * or similar.
+ */
+void ossl_statem_check_finish_init(SSL *s, int sending)
+{
+    if (sending == -1) {
+        if (s->statem.hand_state == TLS_ST_PENDING_EARLY_DATA_END
+                || s->statem.hand_state == TLS_ST_EARLY_DATA) {
+            ossl_statem_set_in_init(s, 1);
+            if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) {
+                /*
+                 * SSL_connect() or SSL_do_handshake() has been called directly.
+                 * We don't allow any more writing of early data.
+                 */
+                s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING;
+            }
+        }
+    } else if (!s->server) {
+        if ((sending && (s->statem.hand_state == TLS_ST_PENDING_EARLY_DATA_END
+                      || s->statem.hand_state == TLS_ST_EARLY_DATA)
+                  && s->early_data_state != SSL_EARLY_DATA_WRITING)
+                || (!sending && s->statem.hand_state == TLS_ST_EARLY_DATA)) {
+            ossl_statem_set_in_init(s, 1);
+            /*
+             * SSL_write() has been called directly. We don't allow any more
+             * writing of early data.
+             */
+            if (sending && s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY)
+                s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING;
+        }
+    } else {
+        if (s->early_data_state == SSL_EARLY_DATA_FINISHED_READING
+                && s->statem.hand_state == TLS_ST_EARLY_DATA)
+            ossl_statem_set_in_init(s, 1);
+    }
+}
+
+void ossl_statem_set_hello_verify_done(SSL *s)
+{
+    s->statem.state = MSG_FLOW_UNINITED;
+    s->statem.in_init = 1;
+    /*
+     * This will get reset (briefly) back to TLS_ST_BEFORE when we enter
+     * state_machine() because |state| is MSG_FLOW_UNINITED, but until then any
+     * calls to SSL_in_before() will return false. Also calls to
+     * SSL_state_string() and SSL_state_string_long() will return something
+     * sensible.
+     */
+    s->statem.hand_state = TLS_ST_SR_CLNT_HELLO;
+}
+
+int ossl_statem_connect(SSL *s)
+{
+    return state_machine(s, 0);
+}
+
+int ossl_statem_accept(SSL *s)
+{
+    return state_machine(s, 1);
+}
+
+typedef void (*info_cb) (const SSL *, int, int);
+
+static info_cb get_callback(SSL *s)
+{
+    if (s->info_callback != NULL)
+        return s->info_callback;
+    else if (s->ctx->info_callback != NULL)
+        return s->ctx->info_callback;
+
+    return NULL;
+}
+
+/*
+ * The main message flow state machine. We start in the MSG_FLOW_UNINITED or
+ * MSG_FLOW_FINISHED state and finish in MSG_FLOW_FINISHED. Valid states and
+ * transitions are as follows:
+ *
+ * MSG_FLOW_UNINITED     MSG_FLOW_FINISHED
+ *        |                       |
+ *        +-----------------------+
+ *        v
+ * MSG_FLOW_WRITING <---> MSG_FLOW_READING
+ *        |
+ *        V
+ * MSG_FLOW_FINISHED
+ *        |
+ *        V
+ *    [SUCCESS]
+ *
+ * We may exit at any point due to an error or NBIO event. If an NBIO event
+ * occurs then we restart at the point we left off when we are recalled.
+ * MSG_FLOW_WRITING and MSG_FLOW_READING have sub-state machines associated with them.
+ *
+ * In addition to the above there is also the MSG_FLOW_ERROR state. We can move
+ * into that state at any point in the event that an irrecoverable error occurs.
+ *
+ * Valid return values are:
+ *   1: Success
+ * <=0: NBIO or error
+ */
+static int state_machine(SSL *s, int server)
+{
+    BUF_MEM *buf = NULL;
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
+    OSSL_STATEM *st = &s->statem;
+    int ret = -1;
+    int ssret;
+
+    if (st->state == MSG_FLOW_ERROR) {
+        /* Shouldn't have been called if we're already in the error state */
+        return -1;
+    }
+
+    ERR_clear_error();
+    clear_sys_error();
+
+    cb = get_callback(s);
+
+    st->in_handshake++;
+    if (!SSL_in_init(s) || SSL_in_before(s)) {
+        /*
+         * If we are stateless then we already called SSL_clear() - don't do
+         * it again and clear the STATELESS flag itself.
+         */
+        if ((s->s3->flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear(s))
+            return -1;
+    }
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) {
+        /*
+         * Notify SCTP BIO socket to enter handshake mode and prevent stream
+         * identifier other than 0.
+         */
+        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
+                 st->in_handshake, NULL);
+    }
+#endif
+
+    /* Initialise state machine */
+    if (st->state == MSG_FLOW_UNINITED
+            || st->state == MSG_FLOW_FINISHED) {
+        if (st->state == MSG_FLOW_UNINITED) {
+            st->hand_state = TLS_ST_BEFORE;
+            st->request_state = TLS_ST_BEFORE;
+        }
+
+        s->server = server;
+        if (cb != NULL) {
+            if (SSL_IS_FIRST_HANDSHAKE(s) || !SSL_IS_TLS13(s))
+                cb(s, SSL_CB_HANDSHAKE_START, 1);
+        }
+
+        /*
+         * Fatal errors in this block don't send an alert because we have
+         * failed to even initialise properly. Sending an alert is probably
+         * doomed to failure.
+         */
+
+        if (SSL_IS_DTLS(s)) {
+            if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00) &&
+                (server || (s->version & 0xff00) != (DTLS1_BAD_VER & 0xff00))) {
+                SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
+                goto end;
+            }
+        } else {
+            if ((s->version >> 8) != SSL3_VERSION_MAJOR) {
+                SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
+                goto end;
+            }
+        }
+
+        if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
+            SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                     ERR_R_INTERNAL_ERROR);
+            goto end;
+        }
+
+        if (s->init_buf == NULL) {
+            if ((buf = BUF_MEM_new()) == NULL) {
+                SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
+                goto end;
+            }
+            if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
+                SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
+                goto end;
+            }
+            s->init_buf = buf;
+            buf = NULL;
+        }
+
+        if (!ssl3_setup_buffers(s)) {
+            SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                     ERR_R_INTERNAL_ERROR);
+            goto end;
+        }
+        s->init_num = 0;
+
+        /*
+         * Should have been reset by tls_process_finished, too.
+         */
+        s->s3->change_cipher_spec = 0;
+
+        /*
+         * Ok, we now need to push on a buffering BIO ...but not with
+         * SCTP
+         */
+#ifndef OPENSSL_NO_SCTP
+        if (!SSL_IS_DTLS(s) || !BIO_dgram_is_sctp(SSL_get_wbio(s)))
+#endif
+            if (!ssl_init_wbio_buffer(s)) {
+                SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
+                goto end;
+            }
+
+        if ((SSL_in_before(s))
+                || s->renegotiate) {
+            if (!tls_setup_handshake(s)) {
+                /* SSLfatal() already called */
+                goto end;
+            }
+
+            if (SSL_IS_FIRST_HANDSHAKE(s))
+                st->read_state_first_init = 1;
+        }
+
+        st->state = MSG_FLOW_WRITING;
+        init_write_state_machine(s);
+    }
+
+    while (st->state != MSG_FLOW_FINISHED) {
+        if (st->state == MSG_FLOW_READING) {
+            ssret = read_state_machine(s);
+            if (ssret == SUB_STATE_FINISHED) {
+                st->state = MSG_FLOW_WRITING;
+                init_write_state_machine(s);
+            } else {
+                /* NBIO or error */
+                goto end;
+            }
+        } else if (st->state == MSG_FLOW_WRITING) {
+            ssret = write_state_machine(s);
+            if (ssret == SUB_STATE_FINISHED) {
+                st->state = MSG_FLOW_READING;
+                init_read_state_machine(s);
+            } else if (ssret == SUB_STATE_END_HANDSHAKE) {
+                st->state = MSG_FLOW_FINISHED;
+            } else {
+                /* NBIO or error */
+                goto end;
+            }
+        } else {
+            /* Error */
+            check_fatal(s, SSL_F_STATE_MACHINE);
+            SSLerr(SSL_F_STATE_MACHINE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+            goto end;
+        }
+    }
+
+    ret = 1;
+
+ end:
+    st->in_handshake--;
+
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) {
+        /*
+         * Notify SCTP BIO socket to leave handshake mode and allow stream
+         * identifier other than 0.
+         */
+        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
+                 st->in_handshake, NULL);
+    }
+#endif
+
+    BUF_MEM_free(buf);
+    if (cb != NULL) {
+        if (server)
+            cb(s, SSL_CB_ACCEPT_EXIT, ret);
+        else
+            cb(s, SSL_CB_CONNECT_EXIT, ret);
+    }
+    return ret;
+}
+
+/*
+ * Initialise the MSG_FLOW_READING sub-state machine
+ */
+static void init_read_state_machine(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    st->read_state = READ_STATE_HEADER;
+}
+
+static int grow_init_buf(SSL *s, size_t size) {
+
+    size_t msg_offset = (char *)s->init_msg - s->init_buf->data;
+
+    if (!BUF_MEM_grow_clean(s->init_buf, (int)size))
+        return 0;
+
+    if (size < msg_offset)
+        return 0;
+
+    s->init_msg = s->init_buf->data + msg_offset;
+
+    return 1;
+}
+
+/*
+ * This function implements the sub-state machine when the message flow is in
+ * MSG_FLOW_READING. The valid sub-states and transitions are:
+ *
+ * READ_STATE_HEADER <--+<-------------+
+ *        |             |              |
+ *        v             |              |
+ * READ_STATE_BODY -----+-->READ_STATE_POST_PROCESS
+ *        |                            |
+ *        +----------------------------+
+ *        v
+ * [SUB_STATE_FINISHED]
+ *
+ * READ_STATE_HEADER has the responsibility for reading in the message header
+ * and transitioning the state of the handshake state machine.
+ *
+ * READ_STATE_BODY reads in the rest of the message and then subsequently
+ * processes it.
+ *
+ * READ_STATE_POST_PROCESS is an optional step that may occur if some post
+ * processing activity performed on the message may block.
+ *
+ * Any of the above states could result in an NBIO event occurring in which case
+ * control returns to the calling application. When this function is recalled we
+ * will resume in the same state where we left off.
+ */
+static SUB_STATE_RETURN read_state_machine(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+    int ret, mt;
+    size_t len = 0;
+    int (*transition) (SSL *s, int mt);
+    PACKET pkt;
+    MSG_PROCESS_RETURN(*process_message) (SSL *s, PACKET *pkt);
+    WORK_STATE(*post_process_message) (SSL *s, WORK_STATE wst);
+    size_t (*max_message_size) (SSL *s);
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
+
+    cb = get_callback(s);
+
+    if (s->server) {
+        transition = ossl_statem_server_read_transition;
+        process_message = ossl_statem_server_process_message;
+        max_message_size = ossl_statem_server_max_message_size;
+        post_process_message = ossl_statem_server_post_process_message;
+    } else {
+        transition = ossl_statem_client_read_transition;
+        process_message = ossl_statem_client_process_message;
+        max_message_size = ossl_statem_client_max_message_size;
+        post_process_message = ossl_statem_client_post_process_message;
+    }
+
+    if (st->read_state_first_init) {
+        s->first_packet = 1;
+        st->read_state_first_init = 0;
+    }
+
+    while (1) {
+        switch (st->read_state) {
+        case READ_STATE_HEADER:
+            /* Get the state the peer wants to move to */
+            if (SSL_IS_DTLS(s)) {
+                /*
+                 * In DTLS we get the whole message in one go - header and body
+                 */
+                ret = dtls_get_message(s, &mt, &len);
+            } else {
+                ret = tls_get_message_header(s, &mt);
+            }
+
+            if (ret == 0) {
+                /* Could be non-blocking IO */
+                return SUB_STATE_ERROR;
+            }
+
+            if (cb != NULL) {
+                /* Notify callback of an impending state change */
+                if (s->server)
+                    cb(s, SSL_CB_ACCEPT_LOOP, 1);
+                else
+                    cb(s, SSL_CB_CONNECT_LOOP, 1);
+            }
+            /*
+             * Validate that we are allowed to move to the new state and move
+             * to that state if so
+             */
+            if (!transition(s, mt))
+                return SUB_STATE_ERROR;
+
+            if (s->s3->tmp.message_size > max_message_size(s)) {
+                SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_READ_STATE_MACHINE,
+                         SSL_R_EXCESSIVE_MESSAGE_SIZE);
+                return SUB_STATE_ERROR;
+            }
+
+            /* dtls_get_message already did this */
+            if (!SSL_IS_DTLS(s)
+                    && s->s3->tmp.message_size > 0
+                    && !grow_init_buf(s, s->s3->tmp.message_size
+                                         + SSL3_HM_HEADER_LENGTH)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_READ_STATE_MACHINE,
+                         ERR_R_BUF_LIB);
+                return SUB_STATE_ERROR;
+            }
+
+            st->read_state = READ_STATE_BODY;
+            /* Fall through */
+
+        case READ_STATE_BODY:
+            if (!SSL_IS_DTLS(s)) {
+                /* We already got this above for DTLS */
+                ret = tls_get_message_body(s, &len);
+                if (ret == 0) {
+                    /* Could be non-blocking IO */
+                    return SUB_STATE_ERROR;
+                }
+            }
+
+            s->first_packet = 0;
+            if (!PACKET_buf_init(&pkt, s->init_msg, len)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_READ_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
+                return SUB_STATE_ERROR;
+            }
+            ret = process_message(s, &pkt);
+
+            /* Discard the packet data */
+            s->init_num = 0;
+
+            switch (ret) {
+            case MSG_PROCESS_ERROR:
+                check_fatal(s, SSL_F_READ_STATE_MACHINE);
+                return SUB_STATE_ERROR;
+
+            case MSG_PROCESS_FINISHED_READING:
+                if (SSL_IS_DTLS(s)) {
+                    dtls1_stop_timer(s);
+                }
+                return SUB_STATE_FINISHED;
+
+            case MSG_PROCESS_CONTINUE_PROCESSING:
+                st->read_state = READ_STATE_POST_PROCESS;
+                st->read_state_work = WORK_MORE_A;
+                break;
+
+            default:
+                st->read_state = READ_STATE_HEADER;
+                break;
+            }
+            break;
+
+        case READ_STATE_POST_PROCESS:
+            st->read_state_work = post_process_message(s, st->read_state_work);
+            switch (st->read_state_work) {
+            case WORK_ERROR:
+                check_fatal(s, SSL_F_READ_STATE_MACHINE);
+                /* Fall through */
+            case WORK_MORE_A:
+            case WORK_MORE_B:
+            case WORK_MORE_C:
+                return SUB_STATE_ERROR;
+
+            case WORK_FINISHED_CONTINUE:
+                st->read_state = READ_STATE_HEADER;
+                break;
+
+            case WORK_FINISHED_STOP:
+                if (SSL_IS_DTLS(s)) {
+                    dtls1_stop_timer(s);
+                }
+                return SUB_STATE_FINISHED;
+            }
+            break;
+
+        default:
+            /* Shouldn't happen */
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_READ_STATE_MACHINE,
+                     ERR_R_INTERNAL_ERROR);
+            return SUB_STATE_ERROR;
+        }
+    }
+}
+
+/*
+ * Send a previously constructed message to the peer.
+ */
+static int statem_do_write(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    if (st->hand_state == TLS_ST_CW_CHANGE
+        || st->hand_state == TLS_ST_SW_CHANGE) {
+        if (SSL_IS_DTLS(s))
+            return dtls1_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
+        else
+            return ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
+    } else {
+        return ssl_do_write(s);
+    }
+}
+
+/*
+ * Initialise the MSG_FLOW_WRITING sub-state machine
+ */
+static void init_write_state_machine(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    st->write_state = WRITE_STATE_TRANSITION;
+}
+
+/*
+ * This function implements the sub-state machine when the message flow is in
+ * MSG_FLOW_WRITING. The valid sub-states and transitions are:
+ *
+ * +-> WRITE_STATE_TRANSITION ------> [SUB_STATE_FINISHED]
+ * |             |
+ * |             v
+ * |      WRITE_STATE_PRE_WORK -----> [SUB_STATE_END_HANDSHAKE]
+ * |             |
+ * |             v
+ * |       WRITE_STATE_SEND
+ * |             |
+ * |             v
+ * |     WRITE_STATE_POST_WORK
+ * |             |
+ * +-------------+
+ *
+ * WRITE_STATE_TRANSITION transitions the state of the handshake state machine
+
+ * WRITE_STATE_PRE_WORK performs any work necessary to prepare the later
+ * sending of the message. This could result in an NBIO event occurring in
+ * which case control returns to the calling application. When this function
+ * is recalled we will resume in the same state where we left off.
+ *
+ * WRITE_STATE_SEND sends the message and performs any work to be done after
+ * sending.
+ *
+ * WRITE_STATE_POST_WORK performs any work necessary after the sending of the
+ * message has been completed. As for WRITE_STATE_PRE_WORK this could also
+ * result in an NBIO event.
+ */
+static SUB_STATE_RETURN write_state_machine(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+    int ret;
+    WRITE_TRAN(*transition) (SSL *s);
+    WORK_STATE(*pre_work) (SSL *s, WORK_STATE wst);
+    WORK_STATE(*post_work) (SSL *s, WORK_STATE wst);
+    int (*get_construct_message_f) (SSL *s, WPACKET *pkt,
+                                    int (**confunc) (SSL *s, WPACKET *pkt),
+                                    int *mt);
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
+    int (*confunc) (SSL *s, WPACKET *pkt);
+    int mt;
+    WPACKET pkt;
+
+    cb = get_callback(s);
+
+    if (s->server) {
+        transition = ossl_statem_server_write_transition;
+        pre_work = ossl_statem_server_pre_work;
+        post_work = ossl_statem_server_post_work;
+        get_construct_message_f = ossl_statem_server_construct_message;
+    } else {
+        transition = ossl_statem_client_write_transition;
+        pre_work = ossl_statem_client_pre_work;
+        post_work = ossl_statem_client_post_work;
+        get_construct_message_f = ossl_statem_client_construct_message;
+    }
+
+    while (1) {
+        switch (st->write_state) {
+        case WRITE_STATE_TRANSITION:
+            if (cb != NULL) {
+                /* Notify callback of an impending state change */
+                if (s->server)
+                    cb(s, SSL_CB_ACCEPT_LOOP, 1);
+                else
+                    cb(s, SSL_CB_CONNECT_LOOP, 1);
+            }
+            switch (transition(s)) {
+            case WRITE_TRAN_CONTINUE:
+                st->write_state = WRITE_STATE_PRE_WORK;
+                st->write_state_work = WORK_MORE_A;
+                break;
+
+            case WRITE_TRAN_FINISHED:
+                return SUB_STATE_FINISHED;
+                break;
+
+            case WRITE_TRAN_ERROR:
+                check_fatal(s, SSL_F_WRITE_STATE_MACHINE);
+                return SUB_STATE_ERROR;
+            }
+            break;
+
+        case WRITE_STATE_PRE_WORK:
+            switch (st->write_state_work = pre_work(s, st->write_state_work)) {
+            case WORK_ERROR:
+                check_fatal(s, SSL_F_WRITE_STATE_MACHINE);
+                /* Fall through */
+            case WORK_MORE_A:
+            case WORK_MORE_B:
+            case WORK_MORE_C:
+                return SUB_STATE_ERROR;
+
+            case WORK_FINISHED_CONTINUE:
+                st->write_state = WRITE_STATE_SEND;
+                break;
+
+            case WORK_FINISHED_STOP:
+                return SUB_STATE_END_HANDSHAKE;
+            }
+            if (!get_construct_message_f(s, &pkt, &confunc, &mt)) {
+                /* SSLfatal() already called */
+                return SUB_STATE_ERROR;
+            }
+            if (mt == SSL3_MT_DUMMY) {
+                /* Skip construction and sending. This isn't a "real" state */
+                st->write_state = WRITE_STATE_POST_WORK;
+                st->write_state_work = WORK_MORE_A;
+                break;
+            }
+            if (!WPACKET_init(&pkt, s->init_buf)
+                    || !ssl_set_handshake_header(s, &pkt, mt)) {
+                WPACKET_cleanup(&pkt);
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_WRITE_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
+                return SUB_STATE_ERROR;
+            }
+            if (confunc != NULL && !confunc(s, &pkt)) {
+                WPACKET_cleanup(&pkt);
+                check_fatal(s, SSL_F_WRITE_STATE_MACHINE);
+                return SUB_STATE_ERROR;
+            }
+            if (!ssl_close_construct_packet(s, &pkt, mt)
+                    || !WPACKET_finish(&pkt)) {
+                WPACKET_cleanup(&pkt);
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_WRITE_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
+                return SUB_STATE_ERROR;
+            }
+
+            /* Fall through */
+
+        case WRITE_STATE_SEND:
+            if (SSL_IS_DTLS(s) && st->use_timer) {
+                dtls1_start_timer(s);
+            }
+            ret = statem_do_write(s);
+            if (ret <= 0) {
+                return SUB_STATE_ERROR;
+            }
+            st->write_state = WRITE_STATE_POST_WORK;
+            st->write_state_work = WORK_MORE_A;
+            /* Fall through */
+
+        case WRITE_STATE_POST_WORK:
+            switch (st->write_state_work = post_work(s, st->write_state_work)) {
+            case WORK_ERROR:
+                check_fatal(s, SSL_F_WRITE_STATE_MACHINE);
+                /* Fall through */
+            case WORK_MORE_A:
+            case WORK_MORE_B:
+            case WORK_MORE_C:
+                return SUB_STATE_ERROR;
+
+            case WORK_FINISHED_CONTINUE:
+                st->write_state = WRITE_STATE_TRANSITION;
+                break;
+
+            case WORK_FINISHED_STOP:
+                return SUB_STATE_END_HANDSHAKE;
+            }
+            break;
+
+        default:
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_WRITE_STATE_MACHINE,
+                     ERR_R_INTERNAL_ERROR);
+            return SUB_STATE_ERROR;
+        }
+    }
+}
+
+/*
+ * Flush the write BIO
+ */
+int statem_flush(SSL *s)
+{
+    s->rwstate = SSL_WRITING;
+    if (BIO_flush(s->wbio) <= 0) {
+        return 0;
+    }
+    s->rwstate = SSL_NOTHING;
+
+    return 1;
+}
+
+/*
+ * Called by the record layer to determine whether application data is
+ * allowed to be received in the current handshake state or not.
+ *
+ * Return values are:
+ *   1: Yes (application data allowed)
+ *   0: No (application data not allowed)
+ */
+int ossl_statem_app_data_allowed(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    if (st->state == MSG_FLOW_UNINITED)
+        return 0;
+
+    if (!s->s3->in_read_app_data || (s->s3->total_renegotiations == 0))
+        return 0;
+
+    if (s->server) {
+        /*
+         * If we're a server and we haven't got as far as writing our
+         * ServerHello yet then we allow app data
+         */
+        if (st->hand_state == TLS_ST_BEFORE
+            || st->hand_state == TLS_ST_SR_CLNT_HELLO)
+            return 1;
+    } else {
+        /*
+         * If we're a client and we haven't read the ServerHello yet then we
+         * allow app data
+         */
+        if (st->hand_state == TLS_ST_CW_CLNT_HELLO)
+            return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * This function returns 1 if TLS exporter is ready to export keying
+ * material, or 0 if otherwise.
+ */
+int ossl_statem_export_allowed(SSL *s)
+{
+    return s->s3->previous_server_finished_len != 0
+           && s->statem.hand_state != TLS_ST_SW_FINISHED;
+}
+
+/*
+ * Return 1 if early TLS exporter is ready to export keying material,
+ * or 0 if otherwise.
+ */
+int ossl_statem_export_early_allowed(SSL *s)
+{
+    /*
+     * The early exporter secret is only present on the server if we
+     * have accepted early_data. It is present on the client as long
+     * as we have sent early_data.
+     */
+    return s->ext.early_data == SSL_EARLY_DATA_ACCEPTED
+           || (!s->server && s->ext.early_data != SSL_EARLY_DATA_NOT_SENT);
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem.h b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem.h
new file mode 100644
index 0000000..144d930
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*****************************************************************************
+ *                                                                           *
+ * These enums should be considered PRIVATE to the state machine. No         *
+ * non-state machine code should need to use these                           *
+ *                                                                           *
+ *****************************************************************************/
+/*
+ * Valid return codes used for functions performing work prior to or after
+ * sending or receiving a message
+ */
+typedef enum {
+    /* Something went wrong */
+    WORK_ERROR,
+    /* We're done working and there shouldn't be anything else to do after */
+    WORK_FINISHED_STOP,
+    /* We're done working move onto the next thing */
+    WORK_FINISHED_CONTINUE,
+    /* We're working on phase A */
+    WORK_MORE_A,
+    /* We're working on phase B */
+    WORK_MORE_B,
+    /* We're working on phase C */
+    WORK_MORE_C
+} WORK_STATE;
+
+/* Write transition return codes */
+typedef enum {
+    /* Something went wrong */
+    WRITE_TRAN_ERROR,
+    /* A transition was successfully completed and we should continue */
+    WRITE_TRAN_CONTINUE,
+    /* There is no more write work to be done */
+    WRITE_TRAN_FINISHED
+} WRITE_TRAN;
+
+/* Message flow states */
+typedef enum {
+    /* No handshake in progress */
+    MSG_FLOW_UNINITED,
+    /* A permanent error with this connection */
+    MSG_FLOW_ERROR,
+    /* We are reading messages */
+    MSG_FLOW_READING,
+    /* We are writing messages */
+    MSG_FLOW_WRITING,
+    /* Handshake has finished */
+    MSG_FLOW_FINISHED
+} MSG_FLOW_STATE;
+
+/* Read states */
+typedef enum {
+    READ_STATE_HEADER,
+    READ_STATE_BODY,
+    READ_STATE_POST_PROCESS
+} READ_STATE;
+
+/* Write states */
+typedef enum {
+    WRITE_STATE_TRANSITION,
+    WRITE_STATE_PRE_WORK,
+    WRITE_STATE_SEND,
+    WRITE_STATE_POST_WORK
+} WRITE_STATE;
+
+typedef enum {
+    /* The enc_write_ctx can be used normally */
+    ENC_WRITE_STATE_VALID,
+    /* The enc_write_ctx cannot be used */
+    ENC_WRITE_STATE_INVALID,
+    /* Write alerts in plaintext, but otherwise use the enc_write_ctx */
+    ENC_WRITE_STATE_WRITE_PLAIN_ALERTS
+} ENC_WRITE_STATES;
+
+typedef enum {
+    /* The enc_read_ctx can be used normally */
+    ENC_READ_STATE_VALID,
+    /* We may receive encrypted or plaintext alerts */
+    ENC_READ_STATE_ALLOW_PLAIN_ALERTS
+} ENC_READ_STATES;
+
+/*****************************************************************************
+ *                                                                           *
+ * This structure should be considered "opaque" to anything outside of the   *
+ * state machine. No non-state machine code should be accessing the members  *
+ * of this structure.                                                        *
+ *                                                                           *
+ *****************************************************************************/
+
+struct ossl_statem_st {
+    MSG_FLOW_STATE state;
+    WRITE_STATE write_state;
+    WORK_STATE write_state_work;
+    READ_STATE read_state;
+    WORK_STATE read_state_work;
+    OSSL_HANDSHAKE_STATE hand_state;
+    /* The handshake state requested by an API call (e.g. HelloRequest) */
+    OSSL_HANDSHAKE_STATE request_state;
+    int in_init;
+    int read_state_first_init;
+    /* true when we are actually in SSL_accept() or SSL_connect() */
+    int in_handshake;
+    /*
+     * True when are processing a "real" handshake that needs cleaning up (not
+     * just a HelloRequest or similar).
+     */
+    int cleanuphand;
+    /* Should we skip the CertificateVerify message? */
+    unsigned int no_cert_verify;
+    int use_timer;
+    ENC_WRITE_STATES enc_write_state;
+    ENC_READ_STATES enc_read_state;
+};
+typedef struct ossl_statem_st OSSL_STATEM;
+
+/*****************************************************************************
+ *                                                                           *
+ * The following macros/functions represent the libssl internal API to the   *
+ * state machine. Any libssl code may call these functions/macros            *
+ *                                                                           *
+ *****************************************************************************/
+
+__owur int ossl_statem_accept(SSL *s);
+__owur int ossl_statem_connect(SSL *s);
+void ossl_statem_clear(SSL *s);
+void ossl_statem_set_renegotiate(SSL *s);
+void ossl_statem_fatal(SSL *s, int al, int func, int reason, const char *file,
+                       int line);
+# define SSL_AD_NO_ALERT    -1
+# ifndef OPENSSL_NO_ERR
+#  define SSLfatal(s, al, f, r)  ossl_statem_fatal((s), (al), (f), (r), \
+                                                   OPENSSL_FILE, OPENSSL_LINE)
+# else
+#  define SSLfatal(s, al, f, r)  ossl_statem_fatal((s), (al), (f), (r), NULL, 0)
+# endif
+
+int ossl_statem_in_error(const SSL *s);
+void ossl_statem_set_in_init(SSL *s, int init);
+int ossl_statem_get_in_handshake(SSL *s);
+void ossl_statem_set_in_handshake(SSL *s, int inhand);
+__owur int ossl_statem_skip_early_data(SSL *s);
+void ossl_statem_check_finish_init(SSL *s, int send);
+void ossl_statem_set_hello_verify_done(SSL *s);
+__owur int ossl_statem_app_data_allowed(SSL *s);
+__owur int ossl_statem_export_allowed(SSL *s);
+__owur int ossl_statem_export_early_allowed(SSL *s);
+
+/* Flush the write BIO */
+int statem_flush(SSL *s);
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_clnt.c b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_clnt.c
new file mode 100644
index 0000000..d19c44e
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_clnt.c
@@ -0,0 +1,3855 @@
+/*
+ * 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.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <assert.h>
+#include "../ssl_local.h"
+#include "statem_local.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#include <openssl/engine.h>
+#include <internal/cryptlib.h>
+
+static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL *s, PACKET *pkt);
+static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt);
+
+static ossl_inline int cert_req_allowed(SSL *s);
+static int key_exchange_expected(SSL *s);
+static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
+                                    WPACKET *pkt);
+
+/*
+ * Is a CertificateRequest message allowed at the moment or not?
+ *
+ *  Return values are:
+ *  1: Yes
+ *  0: No
+ */
+static ossl_inline int cert_req_allowed(SSL *s)
+{
+    /* TLS does not like anon-DH with client cert */
+    if ((s->version > SSL3_VERSION
+         && (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL))
+        || (s->s3->tmp.new_cipher->algorithm_auth & (SSL_aSRP | SSL_aPSK)))
+        return 0;
+
+    return 1;
+}
+
+/*
+ * Should we expect the ServerKeyExchange message or not?
+ *
+ *  Return values are:
+ *  1: Yes
+ *  0: No
+ */
+static int key_exchange_expected(SSL *s)
+{
+    long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    /*
+     * Can't skip server key exchange if this is an ephemeral
+     * ciphersuite or for SRP
+     */
+    if (alg_k & (SSL_kDHE | SSL_kECDHE | SSL_kDHEPSK | SSL_kECDHEPSK
+                 | SSL_kSRP)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * ossl_statem_client_read_transition() encapsulates the logic for the allowed
+ * handshake state transitions when a TLS1.3 client is reading messages from the
+ * server. The message type that the server has sent is provided in |mt|. The
+ * current state is in |s->statem.hand_state|.
+ *
+ * Return values are 1 for success (transition allowed) and  0 on error
+ * (transition not allowed)
+ */
+static int ossl_statem_client13_read_transition(SSL *s, int mt)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    /*
+     * Note: There is no case for TLS_ST_CW_CLNT_HELLO, because we haven't
+     * yet negotiated TLSv1.3 at that point so that is handled by
+     * ossl_statem_client_read_transition()
+     */
+
+    switch (st->hand_state) {
+    default:
+        break;
+
+    case TLS_ST_CW_CLNT_HELLO:
+        /*
+         * This must a ClientHello following a HelloRetryRequest, so the only
+         * thing we can get now is a ServerHello.
+         */
+        if (mt == SSL3_MT_SERVER_HELLO) {
+            st->hand_state = TLS_ST_CR_SRVR_HELLO;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CR_SRVR_HELLO:
+        if (mt == SSL3_MT_ENCRYPTED_EXTENSIONS) {
+            st->hand_state = TLS_ST_CR_ENCRYPTED_EXTENSIONS;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
+        if (s->hit) {
+            if (mt == SSL3_MT_FINISHED) {
+                st->hand_state = TLS_ST_CR_FINISHED;
+                return 1;
+            }
+        } else {
+            if (mt == SSL3_MT_CERTIFICATE_REQUEST) {
+                st->hand_state = TLS_ST_CR_CERT_REQ;
+                return 1;
+            }
+            if (mt == SSL3_MT_CERTIFICATE) {
+                st->hand_state = TLS_ST_CR_CERT;
+                return 1;
+            }
+        }
+        break;
+
+    case TLS_ST_CR_CERT_REQ:
+        if (mt == SSL3_MT_CERTIFICATE) {
+            st->hand_state = TLS_ST_CR_CERT;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CR_CERT:
+        if (mt == SSL3_MT_CERTIFICATE_VERIFY) {
+            st->hand_state = TLS_ST_CR_CERT_VRFY;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CR_CERT_VRFY:
+        if (mt == SSL3_MT_FINISHED) {
+            st->hand_state = TLS_ST_CR_FINISHED;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_OK:
+        if (mt == SSL3_MT_NEWSESSION_TICKET) {
+            st->hand_state = TLS_ST_CR_SESSION_TICKET;
+            return 1;
+        }
+        if (mt == SSL3_MT_KEY_UPDATE) {
+            st->hand_state = TLS_ST_CR_KEY_UPDATE;
+            return 1;
+        }
+        if (mt == SSL3_MT_CERTIFICATE_REQUEST) {
+#if DTLS_MAX_VERSION != DTLS1_2_VERSION
+# error TODO(DTLS1.3): Restore digest for PHA before adding message.
+#endif
+            if (!SSL_IS_DTLS(s) && s->post_handshake_auth == SSL_PHA_EXT_SENT) {
+                s->post_handshake_auth = SSL_PHA_REQUESTED;
+                /*
+                 * In TLS, this is called before the message is added to the
+                 * digest. In DTLS, this is expected to be called after adding
+                 * to the digest. Either move the digest restore, or add the
+                 * message here after the swap, or do it after the clientFinished?
+                 */
+                if (!tls13_restore_handshake_digest_for_pha(s)) {
+                    /* SSLfatal() already called */
+                    return 0;
+                }
+                st->hand_state = TLS_ST_CR_CERT_REQ;
+                return 1;
+            }
+        }
+        break;
+    }
+
+    /* No valid transition found */
+    return 0;
+}
+
+/*
+ * ossl_statem_client_read_transition() encapsulates the logic for the allowed
+ * handshake state transitions when the client is reading messages from the
+ * server. The message type that the server has sent is provided in |mt|. The
+ * current state is in |s->statem.hand_state|.
+ *
+ * Return values are 1 for success (transition allowed) and  0 on error
+ * (transition not allowed)
+ */
+int ossl_statem_client_read_transition(SSL *s, int mt)
+{
+    OSSL_STATEM *st = &s->statem;
+    int ske_expected;
+
+    /*
+     * Note that after writing the first ClientHello we don't know what version
+     * we are going to negotiate yet, so we don't take this branch until later.
+     */
+    if (SSL_IS_TLS13(s)) {
+        if (!ossl_statem_client13_read_transition(s, mt))
+            goto err;
+        return 1;
+    }
+
+    switch (st->hand_state) {
+    default:
+        break;
+
+    case TLS_ST_CW_CLNT_HELLO:
+        if (mt == SSL3_MT_SERVER_HELLO) {
+            st->hand_state = TLS_ST_CR_SRVR_HELLO;
+            return 1;
+        }
+
+        if (SSL_IS_DTLS(s)) {
+            if (mt == DTLS1_MT_HELLO_VERIFY_REQUEST) {
+                st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
+                return 1;
+            }
+        }
+        break;
+
+    case TLS_ST_EARLY_DATA:
+        /*
+         * We've not actually selected TLSv1.3 yet, but we have sent early
+         * data. The only thing allowed now is a ServerHello or a
+         * HelloRetryRequest.
+         */
+        if (mt == SSL3_MT_SERVER_HELLO) {
+            st->hand_state = TLS_ST_CR_SRVR_HELLO;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CR_SRVR_HELLO:
+        if (s->hit) {
+            if (s->ext.ticket_expected) {
+                if (mt == SSL3_MT_NEWSESSION_TICKET) {
+                    st->hand_state = TLS_ST_CR_SESSION_TICKET;
+                    return 1;
+                }
+            } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+                st->hand_state = TLS_ST_CR_CHANGE;
+                return 1;
+            }
+        } else {
+            if (SSL_IS_DTLS(s) && mt == DTLS1_MT_HELLO_VERIFY_REQUEST) {
+                st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
+                return 1;
+            } else if (s->version >= TLS1_VERSION
+                       && s->ext.session_secret_cb != NULL
+                       && s->session->ext.tick != NULL
+                       && mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+                /*
+                 * Normally, we can tell if the server is resuming the session
+                 * from the session ID. EAP-FAST (RFC 4851), however, relies on
+                 * the next server message after the ServerHello to determine if
+                 * the server is resuming.
+                 */
+                s->hit = 1;
+                st->hand_state = TLS_ST_CR_CHANGE;
+                return 1;
+            } else if (!(s->s3->tmp.new_cipher->algorithm_auth
+                         & (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
+                if (mt == SSL3_MT_CERTIFICATE) {
+                    st->hand_state = TLS_ST_CR_CERT;
+                    return 1;
+                }
+            } else {
+                ske_expected = key_exchange_expected(s);
+                /* SKE is optional for some PSK ciphersuites */
+                if (ske_expected
+                    || ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)
+                        && mt == SSL3_MT_SERVER_KEY_EXCHANGE)) {
+                    if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
+                        st->hand_state = TLS_ST_CR_KEY_EXCH;
+                        return 1;
+                    }
+                } else if (mt == SSL3_MT_CERTIFICATE_REQUEST
+                           && cert_req_allowed(s)) {
+                    st->hand_state = TLS_ST_CR_CERT_REQ;
+                    return 1;
+                } else if (mt == SSL3_MT_SERVER_DONE) {
+                    st->hand_state = TLS_ST_CR_SRVR_DONE;
+                    return 1;
+                }
+            }
+        }
+        break;
+
+    case TLS_ST_CR_CERT:
+        /*
+         * The CertificateStatus message is optional even if
+         * |ext.status_expected| is set
+         */
+        if (s->ext.status_expected && mt == SSL3_MT_CERTIFICATE_STATUS) {
+            st->hand_state = TLS_ST_CR_CERT_STATUS;
+            return 1;
+        }
+        /* Fall through */
+
+    case TLS_ST_CR_CERT_STATUS:
+        ske_expected = key_exchange_expected(s);
+        /* SKE is optional for some PSK ciphersuites */
+        if (ske_expected || ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)
+                             && mt == SSL3_MT_SERVER_KEY_EXCHANGE)) {
+            if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
+                st->hand_state = TLS_ST_CR_KEY_EXCH;
+                return 1;
+            }
+            goto err;
+        }
+        /* Fall through */
+
+    case TLS_ST_CR_KEY_EXCH:
+        if (mt == SSL3_MT_CERTIFICATE_REQUEST) {
+            if (cert_req_allowed(s)) {
+                st->hand_state = TLS_ST_CR_CERT_REQ;
+                return 1;
+            }
+            goto err;
+        }
+        /* Fall through */
+
+    case TLS_ST_CR_CERT_REQ:
+        if (mt == SSL3_MT_SERVER_DONE) {
+            st->hand_state = TLS_ST_CR_SRVR_DONE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CW_FINISHED:
+        if (s->ext.ticket_expected) {
+            if (mt == SSL3_MT_NEWSESSION_TICKET) {
+                st->hand_state = TLS_ST_CR_SESSION_TICKET;
+                return 1;
+            }
+        } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_CR_CHANGE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CR_SESSION_TICKET:
+        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_CR_CHANGE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CR_CHANGE:
+        if (mt == SSL3_MT_FINISHED) {
+            st->hand_state = TLS_ST_CR_FINISHED;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_OK:
+        if (mt == SSL3_MT_HELLO_REQUEST) {
+            st->hand_state = TLS_ST_CR_HELLO_REQ;
+            return 1;
+        }
+        break;
+    }
+
+ err:
+    /* No valid transition found */
+    if (SSL_IS_DTLS(s) && mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+        BIO *rbio;
+
+        /*
+         * CCS messages don't have a message sequence number so this is probably
+         * because of an out-of-order CCS. We'll just drop it.
+         */
+        s->init_num = 0;
+        s->rwstate = SSL_READING;
+        rbio = SSL_get_rbio(s);
+        BIO_clear_retry_flags(rbio);
+        BIO_set_retry_read(rbio);
+        return 0;
+    }
+    SSLfatal(s, SSL3_AD_UNEXPECTED_MESSAGE,
+             SSL_F_OSSL_STATEM_CLIENT_READ_TRANSITION,
+             SSL_R_UNEXPECTED_MESSAGE);
+    return 0;
+}
+
+/*
+ * ossl_statem_client13_write_transition() works out what handshake state to
+ * move to next when the TLSv1.3 client is writing messages to be sent to the
+ * server.
+ */
+static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    /*
+     * Note: There are no cases for TLS_ST_BEFORE because we haven't negotiated
+     * TLSv1.3 yet at that point. They are handled by
+     * ossl_statem_client_write_transition().
+     */
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_OSSL_STATEM_CLIENT13_WRITE_TRANSITION,
+                 ERR_R_INTERNAL_ERROR);
+        return WRITE_TRAN_ERROR;
+
+    case TLS_ST_CR_CERT_REQ:
+        if (s->post_handshake_auth == SSL_PHA_REQUESTED) {
+            st->hand_state = TLS_ST_CW_CERT;
+            return WRITE_TRAN_CONTINUE;
+        }
+        /*
+         * We should only get here if we received a CertificateRequest after
+         * we already sent close_notify
+         */
+        if (!ossl_assert((s->shutdown & SSL_SENT_SHUTDOWN) != 0)) {
+            /* Shouldn't happen - same as default case */
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_OSSL_STATEM_CLIENT13_WRITE_TRANSITION,
+                     ERR_R_INTERNAL_ERROR);
+            return WRITE_TRAN_ERROR;
+        }
+        st->hand_state = TLS_ST_OK;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CR_FINISHED:
+        if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY
+                || s->early_data_state == SSL_EARLY_DATA_FINISHED_WRITING)
+            st->hand_state = TLS_ST_PENDING_EARLY_DATA_END;
+        else if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0
+                 && s->hello_retry_request == SSL_HRR_NONE)
+            st->hand_state = TLS_ST_CW_CHANGE;
+        else
+            st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
+                                                        : TLS_ST_CW_FINISHED;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_PENDING_EARLY_DATA_END:
+        if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
+            st->hand_state = TLS_ST_CW_END_OF_EARLY_DATA;
+            return WRITE_TRAN_CONTINUE;
+        }
+        /* Fall through */
+
+    case TLS_ST_CW_END_OF_EARLY_DATA:
+    case TLS_ST_CW_CHANGE:
+        st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
+                                                    : TLS_ST_CW_FINISHED;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CW_CERT:
+        /* If a non-empty Certificate we also send CertificateVerify */
+        st->hand_state = (s->s3->tmp.cert_req == 1) ? TLS_ST_CW_CERT_VRFY
+                                                    : TLS_ST_CW_FINISHED;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CW_CERT_VRFY:
+        st->hand_state = TLS_ST_CW_FINISHED;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CR_KEY_UPDATE:
+    case TLS_ST_CW_KEY_UPDATE:
+    case TLS_ST_CR_SESSION_TICKET:
+    case TLS_ST_CW_FINISHED:
+        st->hand_state = TLS_ST_OK;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_OK:
+        if (s->key_update != SSL_KEY_UPDATE_NONE) {
+            st->hand_state = TLS_ST_CW_KEY_UPDATE;
+            return WRITE_TRAN_CONTINUE;
+        }
+
+        /* Try to read from the server instead */
+        return WRITE_TRAN_FINISHED;
+    }
+}
+
+/*
+ * ossl_statem_client_write_transition() works out what handshake state to
+ * move to next when the client is writing messages to be sent to the server.
+ */
+WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    /*
+     * Note that immediately before/after a ClientHello we don't know what
+     * version we are going to negotiate yet, so we don't take this branch until
+     * later
+     */
+    if (SSL_IS_TLS13(s))
+        return ossl_statem_client13_write_transition(s);
+
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_OSSL_STATEM_CLIENT_WRITE_TRANSITION,
+                 ERR_R_INTERNAL_ERROR);
+        return WRITE_TRAN_ERROR;
+
+    case TLS_ST_OK:
+        if (!s->renegotiate) {
+            /*
+             * We haven't requested a renegotiation ourselves so we must have
+             * received a message from the server. Better read it.
+             */
+            return WRITE_TRAN_FINISHED;
+        }
+        /* Renegotiation */
+        /* fall thru */
+    case TLS_ST_BEFORE:
+        st->hand_state = TLS_ST_CW_CLNT_HELLO;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CW_CLNT_HELLO:
+        if (s->early_data_state == SSL_EARLY_DATA_CONNECTING) {
+            /*
+             * We are assuming this is a TLSv1.3 connection, although we haven't
+             * actually selected a version yet.
+             */
+            if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0)
+                st->hand_state = TLS_ST_CW_CHANGE;
+            else
+                st->hand_state = TLS_ST_EARLY_DATA;
+            return WRITE_TRAN_CONTINUE;
+        }
+        /*
+         * No transition at the end of writing because we don't know what
+         * we will be sent
+         */
+        return WRITE_TRAN_FINISHED;
+
+    case TLS_ST_CR_SRVR_HELLO:
+        /*
+         * We only get here in TLSv1.3. We just received an HRR, so issue a
+         * CCS unless middlebox compat mode is off, or we already issued one
+         * because we did early data.
+         */
+        if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0
+                && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING)
+            st->hand_state = TLS_ST_CW_CHANGE;
+        else
+            st->hand_state = TLS_ST_CW_CLNT_HELLO;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_EARLY_DATA:
+        return WRITE_TRAN_FINISHED;
+
+    case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+        st->hand_state = TLS_ST_CW_CLNT_HELLO;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CR_SRVR_DONE:
+        if (s->s3->tmp.cert_req)
+            st->hand_state = TLS_ST_CW_CERT;
+        else
+            st->hand_state = TLS_ST_CW_KEY_EXCH;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CW_CERT:
+        st->hand_state = TLS_ST_CW_KEY_EXCH;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CW_KEY_EXCH:
+        /*
+         * For TLS, cert_req is set to 2, so a cert chain of nothing is
+         * sent, but no verify packet is sent
+         */
+        /*
+         * XXX: For now, we do not support client authentication in ECDH
+         * cipher suites with ECDH (rather than ECDSA) certificates. We
+         * need to skip the certificate verify message when client's
+         * ECDH public key is sent inside the client certificate.
+         */
+        if (s->s3->tmp.cert_req == 1) {
+            st->hand_state = TLS_ST_CW_CERT_VRFY;
+        } else {
+            st->hand_state = TLS_ST_CW_CHANGE;
+        }
+        if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) {
+            st->hand_state = TLS_ST_CW_CHANGE;
+        }
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CW_CERT_VRFY:
+        st->hand_state = TLS_ST_CW_CHANGE;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CW_CHANGE:
+        if (s->hello_retry_request == SSL_HRR_PENDING) {
+            st->hand_state = TLS_ST_CW_CLNT_HELLO;
+        } else if (s->early_data_state == SSL_EARLY_DATA_CONNECTING) {
+            st->hand_state = TLS_ST_EARLY_DATA;
+        } else {
+#if defined(OPENSSL_NO_NEXTPROTONEG)
+            st->hand_state = TLS_ST_CW_FINISHED;
+#else
+            if (!SSL_IS_DTLS(s) && s->s3->npn_seen)
+                st->hand_state = TLS_ST_CW_NEXT_PROTO;
+            else
+                st->hand_state = TLS_ST_CW_FINISHED;
+#endif
+        }
+        return WRITE_TRAN_CONTINUE;
+
+#if !defined(OPENSSL_NO_NEXTPROTONEG)
+    case TLS_ST_CW_NEXT_PROTO:
+        st->hand_state = TLS_ST_CW_FINISHED;
+        return WRITE_TRAN_CONTINUE;
+#endif
+
+    case TLS_ST_CW_FINISHED:
+        if (s->hit) {
+            st->hand_state = TLS_ST_OK;
+            return WRITE_TRAN_CONTINUE;
+        } else {
+            return WRITE_TRAN_FINISHED;
+        }
+
+    case TLS_ST_CR_FINISHED:
+        if (s->hit) {
+            st->hand_state = TLS_ST_CW_CHANGE;
+            return WRITE_TRAN_CONTINUE;
+        } else {
+            st->hand_state = TLS_ST_OK;
+            return WRITE_TRAN_CONTINUE;
+        }
+
+    case TLS_ST_CR_HELLO_REQ:
+        /*
+         * If we can renegotiate now then do so, otherwise wait for a more
+         * convenient time.
+         */
+        if (ssl3_renegotiate_check(s, 1)) {
+            if (!tls_setup_handshake(s)) {
+                /* SSLfatal() already called */
+                return WRITE_TRAN_ERROR;
+            }
+            st->hand_state = TLS_ST_CW_CLNT_HELLO;
+            return WRITE_TRAN_CONTINUE;
+        }
+        st->hand_state = TLS_ST_OK;
+        return WRITE_TRAN_CONTINUE;
+    }
+}
+
+/*
+ * Perform any pre work that needs to be done prior to sending a message from
+ * the client to the server.
+ */
+WORK_STATE ossl_statem_client_pre_work(SSL *s, WORK_STATE wst)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch (st->hand_state) {
+    default:
+        /* No pre work to be done */
+        break;
+
+    case TLS_ST_CW_CLNT_HELLO:
+        s->shutdown = 0;
+        if (SSL_IS_DTLS(s)) {
+            /* every DTLS ClientHello resets Finished MAC */
+            if (!ssl3_init_finished_mac(s)) {
+                /* SSLfatal() already called */
+                return WORK_ERROR;
+            }
+        }
+        break;
+
+    case TLS_ST_CW_CHANGE:
+        if (SSL_IS_DTLS(s)) {
+            if (s->hit) {
+                /*
+                 * We're into the last flight so we don't retransmit these
+                 * messages unless we need to.
+                 */
+                st->use_timer = 0;
+            }
+#ifndef OPENSSL_NO_SCTP
+            if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
+                /* Calls SSLfatal() as required */
+                return dtls_wait_for_dry(s);
+            }
+#endif
+        }
+        break;
+
+    case TLS_ST_PENDING_EARLY_DATA_END:
+        /*
+         * If we've been called by SSL_do_handshake()/SSL_write(), or we did not
+         * attempt to write early data before calling SSL_read() then we press
+         * on with the handshake. Otherwise we pause here.
+         */
+        if (s->early_data_state == SSL_EARLY_DATA_FINISHED_WRITING
+                || s->early_data_state == SSL_EARLY_DATA_NONE)
+            return WORK_FINISHED_CONTINUE;
+        /* Fall through */
+
+    case TLS_ST_EARLY_DATA:
+        return tls_finish_handshake(s, wst, 0, 1);
+
+    case TLS_ST_OK:
+        /* Calls SSLfatal() as required */
+        return tls_finish_handshake(s, wst, 1, 1);
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+/*
+ * Perform any work that needs to be done after sending a message from the
+ * client to the server.
+ */
+WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    s->init_num = 0;
+
+    switch (st->hand_state) {
+    default:
+        /* No post work to be done */
+        break;
+
+    case TLS_ST_CW_CLNT_HELLO:
+        if (s->early_data_state == SSL_EARLY_DATA_CONNECTING
+                && s->max_early_data > 0) {
+            /*
+             * We haven't selected TLSv1.3 yet so we don't call the change
+             * cipher state function associated with the SSL_METHOD. Instead
+             * we call tls13_change_cipher_state() directly.
+             */
+            if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) == 0) {
+                if (!tls13_change_cipher_state(s,
+                            SSL3_CC_EARLY | SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
+                    /* SSLfatal() already called */
+                    return WORK_ERROR;
+                }
+            }
+            /* else we're in compat mode so we delay flushing until after CCS */
+        } else if (!statem_flush(s)) {
+            return WORK_MORE_A;
+        }
+
+        if (SSL_IS_DTLS(s)) {
+            /* Treat the next message as the first packet */
+            s->first_packet = 1;
+        }
+        break;
+
+    case TLS_ST_CW_END_OF_EARLY_DATA:
+        /*
+         * We set the enc_write_ctx back to NULL because we may end up writing
+         * in cleartext again if we get a HelloRetryRequest from the server.
+         */
+        EVP_CIPHER_CTX_free(s->enc_write_ctx);
+        s->enc_write_ctx = NULL;
+        break;
+
+    case TLS_ST_CW_KEY_EXCH:
+        if (tls_client_key_exchange_post_work(s) == 0) {
+            /* SSLfatal() already called */
+            return WORK_ERROR;
+        }
+        break;
+
+    case TLS_ST_CW_CHANGE:
+        if (SSL_IS_TLS13(s) || s->hello_retry_request == SSL_HRR_PENDING)
+            break;
+        if (s->early_data_state == SSL_EARLY_DATA_CONNECTING
+                    && s->max_early_data > 0) {
+            /*
+             * We haven't selected TLSv1.3 yet so we don't call the change
+             * cipher state function associated with the SSL_METHOD. Instead
+             * we call tls13_change_cipher_state() directly.
+             */
+            if (!tls13_change_cipher_state(s,
+                        SSL3_CC_EARLY | SSL3_CHANGE_CIPHER_CLIENT_WRITE))
+                return WORK_ERROR;
+            break;
+        }
+        s->session->cipher = s->s3->tmp.new_cipher;
+#ifdef OPENSSL_NO_COMP
+        s->session->compress_meth = 0;
+#else
+        if (s->s3->tmp.new_compression == NULL)
+            s->session->compress_meth = 0;
+        else
+            s->session->compress_meth = s->s3->tmp.new_compression->id;
+#endif
+        if (!s->method->ssl3_enc->setup_key_block(s)) {
+            /* SSLfatal() already called */
+            return WORK_ERROR;
+        }
+
+        if (!s->method->ssl3_enc->change_cipher_state(s,
+                                          SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
+            /* SSLfatal() already called */
+            return WORK_ERROR;
+        }
+
+        if (SSL_IS_DTLS(s)) {
+#ifndef OPENSSL_NO_SCTP
+            if (s->hit) {
+                /*
+                 * Change to new shared key of SCTP-Auth, will be ignored if
+                 * no SCTP used.
+                 */
+                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+                         0, NULL);
+            }
+#endif
+
+            dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
+        }
+        break;
+
+    case TLS_ST_CW_FINISHED:
+#ifndef OPENSSL_NO_SCTP
+        if (wst == WORK_MORE_A && SSL_IS_DTLS(s) && s->hit == 0) {
+            /*
+             * Change to new shared key of SCTP-Auth, will be ignored if
+             * no SCTP used.
+             */
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+                     0, NULL);
+        }
+#endif
+        if (statem_flush(s) != 1)
+            return WORK_MORE_B;
+
+        if (SSL_IS_TLS13(s)) {
+            if (!tls13_save_handshake_digest_for_pha(s)) {
+                /* SSLfatal() already called */
+                return WORK_ERROR;
+            }
+            if (s->post_handshake_auth != SSL_PHA_REQUESTED) {
+                if (!s->method->ssl3_enc->change_cipher_state(s,
+                        SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
+                    /* SSLfatal() already called */
+                    return WORK_ERROR;
+                }
+            }
+        }
+        break;
+
+    case TLS_ST_CW_KEY_UPDATE:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+        if (!tls13_update_key(s, 1)) {
+            /* SSLfatal() already called */
+            return WORK_ERROR;
+        }
+        break;
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+/*
+ * Get the message construction function and message type for sending from the
+ * client
+ *
+ * Valid return values are:
+ *   1: Success
+ *   0: Error
+ */
+int ossl_statem_client_construct_message(SSL *s, WPACKET *pkt,
+                                         confunc_f *confunc, int *mt)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_OSSL_STATEM_CLIENT_CONSTRUCT_MESSAGE,
+                 SSL_R_BAD_HANDSHAKE_STATE);
+        return 0;
+
+    case TLS_ST_CW_CHANGE:
+        if (SSL_IS_DTLS(s))
+            *confunc = dtls_construct_change_cipher_spec;
+        else
+            *confunc = tls_construct_change_cipher_spec;
+        *mt = SSL3_MT_CHANGE_CIPHER_SPEC;
+        break;
+
+    case TLS_ST_CW_CLNT_HELLO:
+        *confunc = tls_construct_client_hello;
+        *mt = SSL3_MT_CLIENT_HELLO;
+        break;
+
+    case TLS_ST_CW_END_OF_EARLY_DATA:
+        *confunc = tls_construct_end_of_early_data;
+        *mt = SSL3_MT_END_OF_EARLY_DATA;
+        break;
+
+    case TLS_ST_PENDING_EARLY_DATA_END:
+        *confunc = NULL;
+        *mt = SSL3_MT_DUMMY;
+        break;
+
+    case TLS_ST_CW_CERT:
+        *confunc = tls_construct_client_certificate;
+        *mt = SSL3_MT_CERTIFICATE;
+        break;
+
+    case TLS_ST_CW_KEY_EXCH:
+        *confunc = tls_construct_client_key_exchange;
+        *mt = SSL3_MT_CLIENT_KEY_EXCHANGE;
+        break;
+
+    case TLS_ST_CW_CERT_VRFY:
+        *confunc = tls_construct_cert_verify;
+        *mt = SSL3_MT_CERTIFICATE_VERIFY;
+        break;
+
+#if !defined(OPENSSL_NO_NEXTPROTONEG)
+    case TLS_ST_CW_NEXT_PROTO:
+        *confunc = tls_construct_next_proto;
+        *mt = SSL3_MT_NEXT_PROTO;
+        break;
+#endif
+    case TLS_ST_CW_FINISHED:
+        *confunc = tls_construct_finished;
+        *mt = SSL3_MT_FINISHED;
+        break;
+
+    case TLS_ST_CW_KEY_UPDATE:
+        *confunc = tls_construct_key_update;
+        *mt = SSL3_MT_KEY_UPDATE;
+        break;
+    }
+
+    return 1;
+}
+
+/*
+ * Returns the maximum allowed length for the current message that we are
+ * reading. Excludes the message header.
+ */
+size_t ossl_statem_client_max_message_size(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        return 0;
+
+    case TLS_ST_CR_SRVR_HELLO:
+        return SERVER_HELLO_MAX_LENGTH;
+
+    case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+        return HELLO_VERIFY_REQUEST_MAX_LENGTH;
+
+    case TLS_ST_CR_CERT:
+        return s->max_cert_list;
+
+    case TLS_ST_CR_CERT_VRFY:
+        return SSL3_RT_MAX_PLAIN_LENGTH;
+
+    case TLS_ST_CR_CERT_STATUS:
+        return SSL3_RT_MAX_PLAIN_LENGTH;
+
+    case TLS_ST_CR_KEY_EXCH:
+        return SERVER_KEY_EXCH_MAX_LENGTH;
+
+    case TLS_ST_CR_CERT_REQ:
+        /*
+         * Set to s->max_cert_list for compatibility with previous releases. In
+         * practice these messages can get quite long if servers are configured
+         * to provide a long list of acceptable CAs
+         */
+        return s->max_cert_list;
+
+    case TLS_ST_CR_SRVR_DONE:
+        return SERVER_HELLO_DONE_MAX_LENGTH;
+
+    case TLS_ST_CR_CHANGE:
+        if (s->version == DTLS1_BAD_VER)
+            return 3;
+        return CCS_MAX_LENGTH;
+
+    case TLS_ST_CR_SESSION_TICKET:
+        return (SSL_IS_TLS13(s)) ? SESSION_TICKET_MAX_LENGTH_TLS13
+                                 : SESSION_TICKET_MAX_LENGTH_TLS12;
+
+    case TLS_ST_CR_FINISHED:
+        return FINISHED_MAX_LENGTH;
+
+    case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
+        return ENCRYPTED_EXTENSIONS_MAX_LENGTH;
+
+    case TLS_ST_CR_KEY_UPDATE:
+        return KEY_UPDATE_MAX_LENGTH;
+    }
+}
+
+/*
+ * Process a message that the client has been received from the server.
+ */
+MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_OSSL_STATEM_CLIENT_PROCESS_MESSAGE,
+                 ERR_R_INTERNAL_ERROR);
+        return MSG_PROCESS_ERROR;
+
+    case TLS_ST_CR_SRVR_HELLO:
+        return tls_process_server_hello(s, pkt);
+
+    case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+        return dtls_process_hello_verify(s, pkt);
+
+    case TLS_ST_CR_CERT:
+        return tls_process_server_certificate(s, pkt);
+
+    case TLS_ST_CR_CERT_VRFY:
+        return tls_process_cert_verify(s, pkt);
+
+    case TLS_ST_CR_CERT_STATUS:
+        return tls_process_cert_status(s, pkt);
+
+    case TLS_ST_CR_KEY_EXCH:
+        return tls_process_key_exchange(s, pkt);
+
+    case TLS_ST_CR_CERT_REQ:
+        return tls_process_certificate_request(s, pkt);
+
+    case TLS_ST_CR_SRVR_DONE:
+        return tls_process_server_done(s, pkt);
+
+    case TLS_ST_CR_CHANGE:
+        return tls_process_change_cipher_spec(s, pkt);
+
+    case TLS_ST_CR_SESSION_TICKET:
+        return tls_process_new_session_ticket(s, pkt);
+
+    case TLS_ST_CR_FINISHED:
+        return tls_process_finished(s, pkt);
+
+    case TLS_ST_CR_HELLO_REQ:
+        return tls_process_hello_req(s, pkt);
+
+    case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
+        return tls_process_encrypted_extensions(s, pkt);
+
+    case TLS_ST_CR_KEY_UPDATE:
+        return tls_process_key_update(s, pkt);
+    }
+}
+
+/*
+ * Perform any further processing required following the receipt of a message
+ * from the server
+ */
+WORK_STATE ossl_statem_client_post_process_message(SSL *s, WORK_STATE wst)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_OSSL_STATEM_CLIENT_POST_PROCESS_MESSAGE,
+                 ERR_R_INTERNAL_ERROR);
+        return WORK_ERROR;
+
+    case TLS_ST_CR_CERT_VRFY:
+    case TLS_ST_CR_CERT_REQ:
+        return tls_prepare_client_certificate(s, wst);
+    }
+}
+
+int tls_construct_client_hello(SSL *s, WPACKET *pkt)
+{
+    unsigned char *p;
+    size_t sess_id_len;
+    int i, protverr;
+#ifndef OPENSSL_NO_COMP
+    SSL_COMP *comp;
+#endif
+    SSL_SESSION *sess = s->session;
+    unsigned char *session_id;
+
+    /* Work out what SSL/TLS/DTLS version to use */
+    protverr = ssl_set_client_hello_version(s);
+    if (protverr != 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CLIENT_HELLO,
+                 protverr);
+        return 0;
+    }
+
+    if (sess == NULL
+            || !ssl_version_supported(s, sess->ssl_version, NULL)
+            || !SSL_SESSION_is_resumable(sess)) {
+        if (s->hello_retry_request == SSL_HRR_NONE
+                && !ssl_get_new_session(s, 0)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+    }
+    /* else use the pre-loaded session */
+
+    p = s->s3->client_random;
+
+    /*
+     * for DTLS if client_random is initialized, reuse it, we are
+     * required to use same upon reply to HelloVerify
+     */
+    if (SSL_IS_DTLS(s)) {
+        size_t idx;
+        i = 1;
+        for (idx = 0; idx < sizeof(s->s3->client_random); idx++) {
+            if (p[idx]) {
+                i = 0;
+                break;
+            }
+        }
+    } else {
+        i = (s->hello_retry_request == SSL_HRR_NONE);
+    }
+
+    if (i && ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random),
+                                   DOWNGRADE_NONE) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CLIENT_HELLO,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /*-
+     * version indicates the negotiated version: for example from
+     * an SSLv2/v3 compatible client hello). The client_version
+     * field is the maximum version we permit and it is also
+     * used in RSA encrypted premaster secrets. Some servers can
+     * choke if we initially report a higher version then
+     * renegotiate to a lower one in the premaster secret. This
+     * didn't happen with TLS 1.0 as most servers supported it
+     * but it can with TLS 1.1 or later if the server only supports
+     * 1.0.
+     *
+     * Possible scenario with previous logic:
+     *      1. Client hello indicates TLS 1.2
+     *      2. Server hello says TLS 1.0
+     *      3. RSA encrypted premaster secret uses 1.2.
+     *      4. Handshake proceeds using TLS 1.0.
+     *      5. Server sends hello request to renegotiate.
+     *      6. Client hello indicates TLS v1.0 as we now
+     *         know that is maximum server supports.
+     *      7. Server chokes on RSA encrypted premaster secret
+     *         containing version 1.0.
+     *
+     * For interoperability it should be OK to always use the
+     * maximum version we support in client hello and then rely
+     * on the checking of version to ensure the servers isn't
+     * being inconsistent: for example initially negotiating with
+     * TLS 1.0 and renegotiating with TLS 1.2. We do this by using
+     * client_version in client hello and not resetting it to
+     * the negotiated version.
+     *
+     * For TLS 1.3 we always set the ClientHello version to 1.2 and rely on the
+     * supported_versions extension for the real supported versions.
+     */
+    if (!WPACKET_put_bytes_u16(pkt, s->client_version)
+            || !WPACKET_memcpy(pkt, s->s3->client_random, SSL3_RANDOM_SIZE)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CLIENT_HELLO,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /* Session ID */
+    session_id = s->session->session_id;
+    if (s->new_session || s->session->ssl_version == TLS1_3_VERSION) {
+        if (s->version == TLS1_3_VERSION
+                && (s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0) {
+            sess_id_len = sizeof(s->tmp_session_id);
+            s->tmp_session_id_len = sess_id_len;
+            session_id = s->tmp_session_id;
+            if (s->hello_retry_request == SSL_HRR_NONE
+                    && RAND_bytes(s->tmp_session_id, sess_id_len) <= 0) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_CONSTRUCT_CLIENT_HELLO,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        } else {
+            sess_id_len = 0;
+        }
+    } else {
+        assert(s->session->session_id_length <= sizeof(s->session->session_id));
+        sess_id_len = s->session->session_id_length;
+        if (s->version == TLS1_3_VERSION) {
+            s->tmp_session_id_len = sess_id_len;
+            memcpy(s->tmp_session_id, s->session->session_id, sess_id_len);
+        }
+    }
+    if (!WPACKET_start_sub_packet_u8(pkt)
+            || (sess_id_len != 0 && !WPACKET_memcpy(pkt, session_id,
+                                                    sess_id_len))
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CLIENT_HELLO,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /* cookie stuff for DTLS */
+    if (SSL_IS_DTLS(s)) {
+        if (s->d1->cookie_len > sizeof(s->d1->cookie)
+                || !WPACKET_sub_memcpy_u8(pkt, s->d1->cookie,
+                                          s->d1->cookie_len)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CLIENT_HELLO,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+
+    /* Ciphers supported */
+    if (!WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CLIENT_HELLO,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (!ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), pkt)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+    if (!WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CLIENT_HELLO,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /* COMPRESSION */
+    if (!WPACKET_start_sub_packet_u8(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CLIENT_HELLO,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+#ifndef OPENSSL_NO_COMP
+    if (ssl_allow_compression(s)
+            && s->ctx->comp_methods
+            && (SSL_IS_DTLS(s) || s->s3->tmp.max_ver < TLS1_3_VERSION)) {
+        int compnum = sk_SSL_COMP_num(s->ctx->comp_methods);
+        for (i = 0; i < compnum; i++) {
+            comp = sk_SSL_COMP_value(s->ctx->comp_methods, i);
+            if (!WPACKET_put_bytes_u8(pkt, comp->id)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_CONSTRUCT_CLIENT_HELLO,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
+    }
+#endif
+    /* Add the NULL method */
+    if (!WPACKET_put_bytes_u8(pkt, 0) || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CLIENT_HELLO,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /* TLS extensions */
+    if (!tls_construct_extensions(s, pkt, SSL_EXT_CLIENT_HELLO, NULL, 0)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    return 1;
+}
+
+MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt)
+{
+    size_t cookie_len;
+    PACKET cookiepkt;
+
+    if (!PACKET_forward(pkt, 2)
+        || !PACKET_get_length_prefixed_1(pkt, &cookiepkt)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_DTLS_PROCESS_HELLO_VERIFY,
+                 SSL_R_LENGTH_MISMATCH);
+        return MSG_PROCESS_ERROR;
+    }
+
+    cookie_len = PACKET_remaining(&cookiepkt);
+    if (cookie_len > sizeof(s->d1->cookie)) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_DTLS_PROCESS_HELLO_VERIFY,
+                 SSL_R_LENGTH_TOO_LONG);
+        return MSG_PROCESS_ERROR;
+    }
+
+    if (!PACKET_copy_bytes(&cookiepkt, s->d1->cookie, cookie_len)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_DTLS_PROCESS_HELLO_VERIFY,
+                 SSL_R_LENGTH_MISMATCH);
+        return MSG_PROCESS_ERROR;
+    }
+    s->d1->cookie_len = cookie_len;
+
+    return MSG_PROCESS_FINISHED_READING;
+}
+
+static int set_client_ciphersuite(SSL *s, const unsigned char *cipherchars)
+{
+    STACK_OF(SSL_CIPHER) *sk;
+    const SSL_CIPHER *c;
+    int i;
+
+    c = ssl_get_cipher_by_char(s, cipherchars, 0);
+    if (c == NULL) {
+        /* unknown cipher */
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SET_CLIENT_CIPHERSUITE,
+                 SSL_R_UNKNOWN_CIPHER_RETURNED);
+        return 0;
+    }
+    /*
+     * If it is a disabled cipher we either didn't send it in client hello,
+     * or it's not allowed for the selected protocol. So we return an error.
+     */
+    if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK, 1)) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SET_CLIENT_CIPHERSUITE,
+                 SSL_R_WRONG_CIPHER_RETURNED);
+        return 0;
+    }
+
+    sk = ssl_get_ciphers_by_id(s);
+    i = sk_SSL_CIPHER_find(sk, c);
+    if (i < 0) {
+        /* we did not say we would use this cipher */
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SET_CLIENT_CIPHERSUITE,
+                 SSL_R_WRONG_CIPHER_RETURNED);
+        return 0;
+    }
+
+    if (SSL_IS_TLS13(s) && s->s3->tmp.new_cipher != NULL
+            && s->s3->tmp.new_cipher->id != c->id) {
+        /* ServerHello selected a different ciphersuite to that in the HRR */
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SET_CLIENT_CIPHERSUITE,
+                 SSL_R_WRONG_CIPHER_RETURNED);
+        return 0;
+    }
+
+    /*
+     * Depending on the session caching (internal/external), the cipher
+     * and/or cipher_id values may not be set. Make sure that cipher_id is
+     * set and use it for comparison.
+     */
+    if (s->session->cipher != NULL)
+        s->session->cipher_id = s->session->cipher->id;
+    if (s->hit && (s->session->cipher_id != c->id)) {
+        if (SSL_IS_TLS13(s)) {
+            /*
+             * In TLSv1.3 it is valid for the server to select a different
+             * ciphersuite as long as the hash is the same.
+             */
+            if (ssl_md(c->algorithm2)
+                    != ssl_md(s->session->cipher->algorithm2)) {
+                SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                         SSL_F_SET_CLIENT_CIPHERSUITE,
+                         SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED);
+                return 0;
+            }
+        } else {
+            /*
+             * Prior to TLSv1.3 resuming a session always meant using the same
+             * ciphersuite.
+             */
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SET_CLIENT_CIPHERSUITE,
+                     SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+            return 0;
+        }
+    }
+    s->s3->tmp.new_cipher = c;
+
+    return 1;
+}
+
+MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
+{
+    PACKET session_id, extpkt;
+    size_t session_id_len;
+    const unsigned char *cipherchars;
+    int hrr = 0;
+    unsigned int compression;
+    unsigned int sversion;
+    unsigned int context;
+    RAW_EXTENSION *extensions = NULL;
+#ifndef OPENSSL_NO_COMP
+    SSL_COMP *comp;
+#endif
+
+    if (!PACKET_get_net_2(pkt, &sversion)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                 SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    /* load the server random */
+    if (s->version == TLS1_3_VERSION
+            && sversion == TLS1_2_VERSION
+            && PACKET_remaining(pkt) >= SSL3_RANDOM_SIZE
+            && memcmp(hrrrandom, PACKET_data(pkt), SSL3_RANDOM_SIZE) == 0) {
+        if (s->hello_retry_request != SSL_HRR_NONE) {
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+                     SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNEXPECTED_MESSAGE);
+            goto err;
+        }
+        s->hello_retry_request = SSL_HRR_PENDING;
+        hrr = 1;
+        if (!PACKET_forward(pkt, SSL3_RANDOM_SIZE)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                     SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+    } else {
+        if (!PACKET_copy_bytes(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                     SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+    }
+
+    /* Get the session-id. */
+    if (!PACKET_get_length_prefixed_1(pkt, &session_id)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                 SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+    session_id_len = PACKET_remaining(&session_id);
+    if (session_id_len > sizeof(s->session->session_id)
+        || session_id_len > SSL3_SESSION_ID_SIZE) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                 SSL_R_SSL3_SESSION_ID_TOO_LONG);
+        goto err;
+    }
+
+    if (!PACKET_get_bytes(pkt, &cipherchars, TLS_CIPHER_LEN)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                 SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    if (!PACKET_get_1(pkt, &compression)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                 SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    /* TLS extensions */
+    if (PACKET_remaining(pkt) == 0 && !hrr) {
+        PACKET_null_init(&extpkt);
+    } else if (!PACKET_as_length_prefixed_2(pkt, &extpkt)
+               || PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                 SSL_R_BAD_LENGTH);
+        goto err;
+    }
+
+    if (!hrr) {
+        if (!tls_collect_extensions(s, &extpkt,
+                                    SSL_EXT_TLS1_2_SERVER_HELLO
+                                    | SSL_EXT_TLS1_3_SERVER_HELLO,
+                                    &extensions, NULL, 1)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+
+        if (!ssl_choose_client_version(s, sversion, extensions)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    }
+
+    if (SSL_IS_TLS13(s) || hrr) {
+        if (compression != 0) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_PROCESS_SERVER_HELLO,
+                     SSL_R_INVALID_COMPRESSION_ALGORITHM);
+            goto err;
+        }
+
+        if (session_id_len != s->tmp_session_id_len
+                || memcmp(PACKET_data(&session_id), s->tmp_session_id,
+                          session_id_len) != 0) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_INVALID_SESSION_ID);
+            goto err;
+        }
+    }
+
+    if (hrr) {
+        if (!set_client_ciphersuite(s, cipherchars)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+
+        return tls_process_as_hello_retry_request(s, &extpkt);
+    }
+
+    /*
+     * Now we have chosen the version we need to check again that the extensions
+     * are appropriate for this version.
+     */
+    context = SSL_IS_TLS13(s) ? SSL_EXT_TLS1_3_SERVER_HELLO
+                              : SSL_EXT_TLS1_2_SERVER_HELLO;
+    if (!tls_validate_all_contexts(s, context, extensions)) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                 SSL_R_BAD_EXTENSION);
+        goto err;
+    }
+
+    s->hit = 0;
+
+    if (SSL_IS_TLS13(s)) {
+        /*
+         * In TLSv1.3 a ServerHello message signals a key change so the end of
+         * the message must be on a record boundary.
+         */
+        if (RECORD_LAYER_processed_read_pending(&s->rlayer)) {
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+                     SSL_F_TLS_PROCESS_SERVER_HELLO,
+                     SSL_R_NOT_ON_RECORD_BOUNDARY);
+            goto err;
+        }
+
+        /* This will set s->hit if we are resuming */
+        if (!tls_parse_extension(s, TLSEXT_IDX_psk,
+                                 SSL_EXT_TLS1_3_SERVER_HELLO,
+                                 extensions, NULL, 0)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else {
+        /*
+         * Check if we can resume the session based on external pre-shared
+         * secret. EAP-FAST (RFC 4851) supports two types of session resumption.
+         * Resumption based on server-side state works with session IDs.
+         * Resumption based on pre-shared Protected Access Credentials (PACs)
+         * works by overriding the SessionTicket extension at the application
+         * layer, and does not send a session ID. (We do not know whether
+         * EAP-FAST servers would honour the session ID.) Therefore, the session
+         * ID alone is not a reliable indicator of session resumption, so we
+         * first check if we can resume, and later peek at the next handshake
+         * message to see if the server wants to resume.
+         */
+        if (s->version >= TLS1_VERSION
+                && s->ext.session_secret_cb != NULL && s->session->ext.tick) {
+            const SSL_CIPHER *pref_cipher = NULL;
+            /*
+             * s->session->master_key_length is a size_t, but this is an int for
+             * backwards compat reasons
+             */
+            int master_key_length;
+            master_key_length = sizeof(s->session->master_key);
+            if (s->ext.session_secret_cb(s, s->session->master_key,
+                                         &master_key_length,
+                                         NULL, &pref_cipher,
+                                         s->ext.session_secret_cb_arg)
+                     && master_key_length > 0) {
+                s->session->master_key_length = master_key_length;
+                s->session->cipher = pref_cipher ?
+                    pref_cipher : ssl_get_cipher_by_char(s, cipherchars, 0);
+            } else {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_PROCESS_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+        }
+
+        if (session_id_len != 0
+                && session_id_len == s->session->session_id_length
+                && memcmp(PACKET_data(&session_id), s->session->session_id,
+                          session_id_len) == 0)
+            s->hit = 1;
+    }
+
+    if (s->hit) {
+        if (s->sid_ctx_length != s->session->sid_ctx_length
+                || memcmp(s->session->sid_ctx, s->sid_ctx, s->sid_ctx_length)) {
+            /* actually a client application bug */
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_PROCESS_SERVER_HELLO,
+                     SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
+            goto err;
+        }
+    } else {
+        /*
+         * If we were trying for session-id reuse but the server
+         * didn't resume, make a new SSL_SESSION.
+         * In the case of EAP-FAST and PAC, we do not send a session ID,
+         * so the PAC-based session secret is always preserved. It'll be
+         * overwritten if the server refuses resumption.
+         */
+        if (s->session->session_id_length > 0) {
+            tsan_counter(&s->session_ctx->stats.sess_miss);
+            if (!ssl_get_new_session(s, 0)) {
+                /* SSLfatal() already called */
+                goto err;
+            }
+        }
+
+        s->session->ssl_version = s->version;
+        /*
+         * In TLSv1.2 and below we save the session id we were sent so we can
+         * resume it later. In TLSv1.3 the session id we were sent is just an
+         * echo of what we originally sent in the ClientHello and should not be
+         * used for resumption.
+         */
+        if (!SSL_IS_TLS13(s)) {
+            s->session->session_id_length = session_id_len;
+            /* session_id_len could be 0 */
+            if (session_id_len > 0)
+                memcpy(s->session->session_id, PACKET_data(&session_id),
+                       session_id_len);
+        }
+    }
+
+    /* Session version and negotiated protocol version should match */
+    if (s->version != s->session->ssl_version) {
+        SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                 SSL_R_SSL_SESSION_VERSION_MISMATCH);
+        goto err;
+    }
+    /*
+     * Now that we know the version, update the check to see if it's an allowed
+     * version.
+     */
+    s->s3->tmp.min_ver = s->version;
+    s->s3->tmp.max_ver = s->version;
+
+    if (!set_client_ciphersuite(s, cipherchars)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+#ifdef OPENSSL_NO_COMP
+    if (compression != 0) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                 SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
+        goto err;
+    }
+    /*
+     * If compression is disabled we'd better not try to resume a session
+     * using compression.
+     */
+    if (s->session->compress_meth != 0) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                 SSL_R_INCONSISTENT_COMPRESSION);
+        goto err;
+    }
+#else
+    if (s->hit && compression != s->session->compress_meth) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                 SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED);
+        goto err;
+    }
+    if (compression == 0)
+        comp = NULL;
+    else if (!ssl_allow_compression(s)) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                 SSL_R_COMPRESSION_DISABLED);
+        goto err;
+    } else {
+        comp = ssl3_comp_find(s->ctx->comp_methods, compression);
+    }
+
+    if (compression != 0 && comp == NULL) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                 SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
+        goto err;
+    } else {
+        s->s3->tmp.new_compression = comp;
+    }
+#endif
+
+    if (!tls_parse_all_extensions(s, context, extensions, NULL, 0, 1)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s) && s->hit) {
+        unsigned char sctpauthkey[64];
+        char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+        size_t labellen;
+
+        /*
+         * Add new shared key for SCTP-Auth, will be ignored if
+         * no SCTP used.
+         */
+        memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
+               sizeof(DTLS1_SCTP_AUTH_LABEL));
+
+        /* Don't include the terminating zero. */
+        labellen = sizeof(labelbuffer) - 1;
+        if (s->mode & SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG)
+            labellen += 1;
+
+        if (SSL_export_keying_material(s, sctpauthkey,
+                                       sizeof(sctpauthkey),
+                                       labelbuffer,
+                                       labellen, NULL, 0, 0) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        BIO_ctrl(SSL_get_wbio(s),
+                 BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+                 sizeof(sctpauthkey), sctpauthkey);
+    }
+#endif
+
+    /*
+     * In TLSv1.3 we have some post-processing to change cipher state, otherwise
+     * we're done with this message
+     */
+    if (SSL_IS_TLS13(s)
+            && (!s->method->ssl3_enc->setup_key_block(s)
+                || !s->method->ssl3_enc->change_cipher_state(s,
+                    SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_CLIENT_READ))) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    OPENSSL_free(extensions);
+    return MSG_PROCESS_CONTINUE_READING;
+ err:
+    OPENSSL_free(extensions);
+    return MSG_PROCESS_ERROR;
+}
+
+static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL *s,
+                                                             PACKET *extpkt)
+{
+    RAW_EXTENSION *extensions = NULL;
+
+    /*
+     * If we were sending early_data then the enc_write_ctx is now invalid and
+     * should not be used.
+     */
+    EVP_CIPHER_CTX_free(s->enc_write_ctx);
+    s->enc_write_ctx = NULL;
+
+    if (!tls_collect_extensions(s, extpkt, SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST,
+                                &extensions, NULL, 1)
+            || !tls_parse_all_extensions(s, SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST,
+                                         extensions, NULL, 0, 1)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    OPENSSL_free(extensions);
+    extensions = NULL;
+
+    if (s->ext.tls13_cookie_len == 0
+#if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)
+        && s->s3->tmp.pkey != NULL
+#endif
+        ) {
+        /*
+         * We didn't receive a cookie or a new key_share so the next
+         * ClientHello will not change
+         */
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                 SSL_F_TLS_PROCESS_AS_HELLO_RETRY_REQUEST,
+                 SSL_R_NO_CHANGE_FOLLOWING_HRR);
+        goto err;
+    }
+
+    /*
+     * Re-initialise the Transcript Hash. We're going to prepopulate it with
+     * a synthetic message_hash in place of ClientHello1.
+     */
+    if (!create_synthetic_message_hash(s, NULL, 0, NULL, 0)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    /*
+     * Add this message to the Transcript Hash. Normally this is done
+     * automatically prior to the message processing stage. However due to the
+     * need to create the synthetic message hash, we defer that step until now
+     * for HRR messages.
+     */
+    if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+                                s->init_num + SSL3_HM_HEADER_LENGTH)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    return MSG_PROCESS_FINISHED_READING;
+ err:
+    OPENSSL_free(extensions);
+    return MSG_PROCESS_ERROR;
+}
+
+MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
+{
+    int i;
+    MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR;
+    unsigned long cert_list_len, cert_len;
+    X509 *x = NULL;
+    const unsigned char *certstart, *certbytes;
+    STACK_OF(X509) *sk = NULL;
+    EVP_PKEY *pkey = NULL;
+    size_t chainidx, certidx;
+    unsigned int context = 0;
+    const SSL_CERT_LOOKUP *clu;
+
+    if ((sk = sk_X509_new_null()) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if ((SSL_IS_TLS13(s) && !PACKET_get_1(pkt, &context))
+            || context != 0
+            || !PACKET_get_net_3(pkt, &cert_list_len)
+            || PACKET_remaining(pkt) != cert_list_len
+            || PACKET_remaining(pkt) == 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+                 SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+    for (chainidx = 0; PACKET_remaining(pkt); chainidx++) {
+        if (!PACKET_get_net_3(pkt, &cert_len)
+            || !PACKET_get_bytes(pkt, &certbytes, cert_len)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+                     SSL_R_CERT_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        certstart = certbytes;
+        x = d2i_X509(NULL, (const unsigned char **)&certbytes, cert_len);
+        if (x == NULL) {
+            SSLfatal(s, SSL_AD_BAD_CERTIFICATE,
+                     SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_ASN1_LIB);
+            goto err;
+        }
+        if (certbytes != (certstart + cert_len)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+                     SSL_R_CERT_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        if (SSL_IS_TLS13(s)) {
+            RAW_EXTENSION *rawexts = NULL;
+            PACKET extensions;
+
+            if (!PACKET_get_length_prefixed_2(pkt, &extensions)) {
+                SSLfatal(s, SSL_AD_DECODE_ERROR,
+                         SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+                         SSL_R_BAD_LENGTH);
+                goto err;
+            }
+            if (!tls_collect_extensions(s, &extensions,
+                                        SSL_EXT_TLS1_3_CERTIFICATE, &rawexts,
+                                        NULL, chainidx == 0)
+                || !tls_parse_all_extensions(s, SSL_EXT_TLS1_3_CERTIFICATE,
+                                             rawexts, x, chainidx,
+                                             PACKET_remaining(pkt) == 0)) {
+                OPENSSL_free(rawexts);
+                /* SSLfatal already called */
+                goto err;
+            }
+            OPENSSL_free(rawexts);
+        }
+
+        if (!sk_X509_push(sk, x)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+                     ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+        x = NULL;
+    }
+
+    i = ssl_verify_cert_chain(s, sk);
+    /*
+     * The documented interface is that SSL_VERIFY_PEER should be set in order
+     * for client side verification of the server certificate to take place.
+     * However, historically the code has only checked that *any* flag is set
+     * to cause server verification to take place. Use of the other flags makes
+     * no sense in client mode. An attempt to clean up the semantics was
+     * reverted because at least one application *only* set
+     * SSL_VERIFY_FAIL_IF_NO_PEER_CERT. Prior to the clean up this still caused
+     * server verification to take place, after the clean up it silently did
+     * nothing. SSL_CTX_set_verify()/SSL_set_verify() cannot validate the flags
+     * sent to them because they are void functions. Therefore, we now use the
+     * (less clean) historic behaviour of performing validation if any flag is
+     * set. The *documented* interface remains the same.
+     */
+    if (s->verify_mode != SSL_VERIFY_NONE && i <= 0) {
+        SSLfatal(s, ssl_x509err2alert(s->verify_result),
+                 SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+                 SSL_R_CERTIFICATE_VERIFY_FAILED);
+        goto err;
+    }
+    ERR_clear_error();          /* but we keep s->verify_result */
+    if (i > 1) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                 SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, i);
+        goto err;
+    }
+
+    s->session->peer_chain = sk;
+    /*
+     * Inconsistency alert: cert_chain does include the peer's certificate,
+     * which we don't include in statem_srvr.c
+     */
+    x = sk_X509_value(sk, 0);
+    sk = NULL;
+
+    pkey = X509_get0_pubkey(x);
+
+    if (pkey == NULL || EVP_PKEY_missing_parameters(pkey)) {
+        x = NULL;
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+                 SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS);
+        goto err;
+    }
+
+    if ((clu = ssl_cert_lookup_by_pkey(pkey, &certidx)) == NULL) {
+        x = NULL;
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                 SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+                 SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+        goto err;
+    }
+    /*
+     * Check certificate type is consistent with ciphersuite. For TLS 1.3
+     * skip check since TLS 1.3 ciphersuites can be used with any certificate
+     * type.
+     */
+    if (!SSL_IS_TLS13(s)) {
+        if ((clu->amask & s->s3->tmp.new_cipher->algorithm_auth) == 0) {
+            x = NULL;
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+                     SSL_R_WRONG_CERTIFICATE_TYPE);
+            goto err;
+        }
+    }
+
+    X509_free(s->session->peer);
+    X509_up_ref(x);
+    s->session->peer = x;
+    s->session->verify_result = s->verify_result;
+    x = NULL;
+
+    /* Save the current hash state for when we receive the CertificateVerify */
+    if (SSL_IS_TLS13(s)
+            && !ssl_handshake_hash(s, s->cert_verify_hash,
+                                   sizeof(s->cert_verify_hash),
+                                   &s->cert_verify_hash_len)) {
+        /* SSLfatal() already called */;
+        goto err;
+    }
+
+    ret = MSG_PROCESS_CONTINUE_READING;
+
+ err:
+    X509_free(x);
+    sk_X509_pop_free(sk, X509_free);
+    return ret;
+}
+
+static int tls_process_ske_psk_preamble(SSL *s, PACKET *pkt)
+{
+#ifndef OPENSSL_NO_PSK
+    PACKET psk_identity_hint;
+
+    /* PSK ciphersuites are preceded by an identity hint */
+
+    if (!PACKET_get_length_prefixed_2(pkt, &psk_identity_hint)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    /*
+     * Store PSK identity hint for later use, hint is used in
+     * tls_construct_client_key_exchange.  Assume that the maximum length of
+     * a PSK identity hint can be as long as the maximum length of a PSK
+     * identity.
+     */
+    if (PACKET_remaining(&psk_identity_hint) > PSK_MAX_IDENTITY_LEN) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                 SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE,
+                 SSL_R_DATA_LENGTH_TOO_LONG);
+        return 0;
+    }
+
+    if (PACKET_remaining(&psk_identity_hint) == 0) {
+        OPENSSL_free(s->session->psk_identity_hint);
+        s->session->psk_identity_hint = NULL;
+    } else if (!PACKET_strndup(&psk_identity_hint,
+                               &s->session->psk_identity_hint)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+#else
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+static int tls_process_ske_srp(SSL *s, PACKET *pkt, EVP_PKEY **pkey)
+{
+#ifndef OPENSSL_NO_SRP
+    PACKET prime, generator, salt, server_pub;
+
+    if (!PACKET_get_length_prefixed_2(pkt, &prime)
+        || !PACKET_get_length_prefixed_2(pkt, &generator)
+        || !PACKET_get_length_prefixed_1(pkt, &salt)
+        || !PACKET_get_length_prefixed_2(pkt, &server_pub)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SKE_SRP,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    /* TODO(size_t): Convert BN_bin2bn() calls */
+    if ((s->srp_ctx.N =
+         BN_bin2bn(PACKET_data(&prime),
+                   (int)PACKET_remaining(&prime), NULL)) == NULL
+        || (s->srp_ctx.g =
+            BN_bin2bn(PACKET_data(&generator),
+                      (int)PACKET_remaining(&generator), NULL)) == NULL
+        || (s->srp_ctx.s =
+            BN_bin2bn(PACKET_data(&salt),
+                      (int)PACKET_remaining(&salt), NULL)) == NULL
+        || (s->srp_ctx.B =
+            BN_bin2bn(PACKET_data(&server_pub),
+                      (int)PACKET_remaining(&server_pub), NULL)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_SRP,
+                 ERR_R_BN_LIB);
+        return 0;
+    }
+
+    if (!srp_verify_server_param(s)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    /* We must check if there is a certificate */
+    if (s->s3->tmp.new_cipher->algorithm_auth & (SSL_aRSA | SSL_aDSS))
+        *pkey = X509_get0_pubkey(s->session->peer);
+
+    return 1;
+#else
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_SRP,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+static int tls_process_ske_dhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey)
+{
+#ifndef OPENSSL_NO_DH
+    PACKET prime, generator, pub_key;
+    EVP_PKEY *peer_tmp = NULL;
+
+    DH *dh = NULL;
+    BIGNUM *p = NULL, *g = NULL, *bnpub_key = NULL;
+
+    int check_bits = 0;
+
+    if (!PACKET_get_length_prefixed_2(pkt, &prime)
+        || !PACKET_get_length_prefixed_2(pkt, &generator)
+        || !PACKET_get_length_prefixed_2(pkt, &pub_key)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SKE_DHE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    peer_tmp = EVP_PKEY_new();
+    dh = DH_new();
+
+    if (peer_tmp == NULL || dh == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_DHE,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    /* TODO(size_t): Convert these calls */
+    p = BN_bin2bn(PACKET_data(&prime), (int)PACKET_remaining(&prime), NULL);
+    g = BN_bin2bn(PACKET_data(&generator), (int)PACKET_remaining(&generator),
+                  NULL);
+    bnpub_key = BN_bin2bn(PACKET_data(&pub_key),
+                          (int)PACKET_remaining(&pub_key), NULL);
+    if (p == NULL || g == NULL || bnpub_key == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_DHE,
+                 ERR_R_BN_LIB);
+        goto err;
+    }
+
+    /* test non-zero pubkey */
+    if (BN_is_zero(bnpub_key)) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SKE_DHE,
+                 SSL_R_BAD_DH_VALUE);
+        goto err;
+    }
+
+    if (!DH_set0_pqg(dh, p, NULL, g)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_DHE,
+                 ERR_R_BN_LIB);
+        goto err;
+    }
+    p = g = NULL;
+
+    if (DH_check_params(dh, &check_bits) == 0 || check_bits != 0) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SKE_DHE,
+                 SSL_R_BAD_DH_VALUE);
+        goto err;
+    }
+
+    if (!DH_set0_key(dh, bnpub_key, NULL)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_DHE,
+                 ERR_R_BN_LIB);
+        goto err;
+    }
+    bnpub_key = NULL;
+
+    if (EVP_PKEY_assign_DH(peer_tmp, dh) == 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_DHE,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+    dh = NULL;
+
+    if (!ssl_security(s, SSL_SECOP_TMP_DH, EVP_PKEY_security_bits(peer_tmp),
+                      0, peer_tmp)) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS_PROCESS_SKE_DHE,
+                 SSL_R_DH_KEY_TOO_SMALL);
+        goto err;
+    }
+
+    s->s3->peer_tmp = peer_tmp;
+
+    /*
+     * FIXME: This makes assumptions about which ciphersuites come with
+     * public keys. We should have a less ad-hoc way of doing this
+     */
+    if (s->s3->tmp.new_cipher->algorithm_auth & (SSL_aRSA | SSL_aDSS))
+        *pkey = X509_get0_pubkey(s->session->peer);
+    /* else anonymous DH, so no certificate or pkey. */
+
+    return 1;
+
+ err:
+    BN_free(p);
+    BN_free(g);
+    BN_free(bnpub_key);
+    DH_free(dh);
+    EVP_PKEY_free(peer_tmp);
+
+    return 0;
+#else
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_DHE,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+static int tls_process_ske_ecdhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey)
+{
+#ifndef OPENSSL_NO_EC
+    PACKET encoded_pt;
+    unsigned int curve_type, curve_id;
+
+    /*
+     * Extract elliptic curve parameters and the server's ephemeral ECDH
+     * public key. We only support named (not generic) curves and
+     * ECParameters in this case is just three bytes.
+     */
+    if (!PACKET_get_1(pkt, &curve_type) || !PACKET_get_net_2(pkt, &curve_id)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SKE_ECDHE,
+                 SSL_R_LENGTH_TOO_SHORT);
+        return 0;
+    }
+    /*
+     * Check curve is named curve type and one of our preferences, if not
+     * server has sent an invalid curve.
+     */
+    if (curve_type != NAMED_CURVE_TYPE
+            || !tls1_check_group_id(s, curve_id, 1)) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SKE_ECDHE,
+                 SSL_R_WRONG_CURVE);
+        return 0;
+    }
+
+    if ((s->s3->peer_tmp = ssl_generate_param_group(curve_id)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_ECDHE,
+                 SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
+        return 0;
+    }
+
+    if (!PACKET_get_length_prefixed_1(pkt, &encoded_pt)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SKE_ECDHE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp,
+                                        PACKET_data(&encoded_pt),
+                                        PACKET_remaining(&encoded_pt))) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SKE_ECDHE,
+                 SSL_R_BAD_ECPOINT);
+        return 0;
+    }
+
+    /*
+     * The ECC/TLS specification does not mention the use of DSA to sign
+     * ECParameters in the server key exchange message. We do support RSA
+     * and ECDSA.
+     */
+    if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aECDSA)
+        *pkey = X509_get0_pubkey(s->session->peer);
+    else if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aRSA)
+        *pkey = X509_get0_pubkey(s->session->peer);
+    /* else anonymous ECDH, so no certificate or pkey. */
+
+    return 1;
+#else
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_ECDHE,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
+{
+    long alg_k;
+    EVP_PKEY *pkey = NULL;
+    EVP_MD_CTX *md_ctx = NULL;
+    EVP_PKEY_CTX *pctx = NULL;
+    PACKET save_param_start, signature;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    save_param_start = *pkt;
+
+#if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)
+    EVP_PKEY_free(s->s3->peer_tmp);
+    s->s3->peer_tmp = NULL;
+#endif
+
+    if (alg_k & SSL_PSK) {
+        if (!tls_process_ske_psk_preamble(s, pkt)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    }
+
+    /* Nothing else to do for plain PSK or RSAPSK */
+    if (alg_k & (SSL_kPSK | SSL_kRSAPSK)) {
+    } else if (alg_k & SSL_kSRP) {
+        if (!tls_process_ske_srp(s, pkt, &pkey)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
+        if (!tls_process_ske_dhe(s, pkt, &pkey)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
+        if (!tls_process_ske_ecdhe(s, pkt, &pkey)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else if (alg_k) {
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                 SSL_R_UNEXPECTED_MESSAGE);
+        goto err;
+    }
+
+    /* if it was signed, check the signature */
+    if (pkey != NULL) {
+        PACKET params;
+        int maxsig;
+        const EVP_MD *md = NULL;
+        unsigned char *tbs;
+        size_t tbslen;
+        int rv;
+
+        /*
+         * |pkt| now points to the beginning of the signature, so the difference
+         * equals the length of the parameters.
+         */
+        if (!PACKET_get_sub_packet(&save_param_start, &params,
+                                   PACKET_remaining(&save_param_start) -
+                                   PACKET_remaining(pkt))) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        if (SSL_USE_SIGALGS(s)) {
+            unsigned int sigalg;
+
+            if (!PACKET_get_net_2(pkt, &sigalg)) {
+                SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                         SSL_R_LENGTH_TOO_SHORT);
+                goto err;
+            }
+            if (tls12_check_peer_sigalg(s, sigalg, pkey) <=0) {
+                /* SSLfatal() already called */
+                goto err;
+            }
+        } else if (!tls1_set_peer_legacy_sigalg(s, pkey)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        if (!tls1_lookup_md(s->s3->tmp.peer_sigalg, &md)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+#ifdef SSL_DEBUG
+        if (SSL_USE_SIGALGS(s))
+            fprintf(stderr, "USING TLSv1.2 HASH %s\n",
+                    md == NULL ? "n/a" : EVP_MD_name(md));
+#endif
+
+        if (!PACKET_get_length_prefixed_2(pkt, &signature)
+            || PACKET_remaining(pkt) != 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                     SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+        maxsig = EVP_PKEY_size(pkey);
+        if (maxsig < 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        /*
+         * Check signature length
+         */
+        if (PACKET_remaining(&signature) > (size_t)maxsig) {
+            /* wrong packet length */
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                   SSL_R_WRONG_SIGNATURE_LENGTH);
+            goto err;
+        }
+
+        md_ctx = EVP_MD_CTX_new();
+        if (md_ctx == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                     ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        if (EVP_DigestVerifyInit(md_ctx, &pctx, md, NULL, pkey) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                     ERR_R_EVP_LIB);
+            goto err;
+        }
+        if (SSL_USE_PSS(s)) {
+            if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0
+                || EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx,
+                                                RSA_PSS_SALTLEN_DIGEST) <= 0) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EVP_LIB);
+                goto err;
+            }
+        }
+        tbslen = construct_key_exchange_tbs(s, &tbs, PACKET_data(&params),
+                                            PACKET_remaining(&params));
+        if (tbslen == 0) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+
+        rv = EVP_DigestVerify(md_ctx, PACKET_data(&signature),
+                              PACKET_remaining(&signature), tbs, tbslen);
+        OPENSSL_free(tbs);
+        if (rv <= 0) {
+            SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                     SSL_R_BAD_SIGNATURE);
+            goto err;
+        }
+        EVP_MD_CTX_free(md_ctx);
+        md_ctx = NULL;
+    } else {
+        /* aNULL, aSRP or PSK do not need public keys */
+        if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP))
+            && !(alg_k & SSL_PSK)) {
+            /* Might be wrong key type, check it */
+            if (ssl3_check_cert_and_algorithm(s)) {
+                SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                         SSL_R_BAD_DATA);
+            }
+            /* else this shouldn't happen, SSLfatal() already called */
+            goto err;
+        }
+        /* still data left over */
+        if (PACKET_remaining(pkt) != 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                     SSL_R_EXTRA_DATA_IN_MESSAGE);
+            goto err;
+        }
+    }
+
+    return MSG_PROCESS_CONTINUE_READING;
+ err:
+    EVP_MD_CTX_free(md_ctx);
+    return MSG_PROCESS_ERROR;
+}
+
+MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt)
+{
+    size_t i;
+
+    /* Clear certificate validity flags */
+    for (i = 0; i < SSL_PKEY_NUM; i++)
+        s->s3->tmp.valid_flags[i] = 0;
+
+    if (SSL_IS_TLS13(s)) {
+        PACKET reqctx, extensions;
+        RAW_EXTENSION *rawexts = NULL;
+
+        if ((s->shutdown & SSL_SENT_SHUTDOWN) != 0) {
+            /*
+             * We already sent close_notify. This can only happen in TLSv1.3
+             * post-handshake messages. We can't reasonably respond to this, so
+             * we just ignore it
+             */
+            return MSG_PROCESS_FINISHED_READING;
+        }
+
+        /* Free and zero certificate types: it is not present in TLS 1.3 */
+        OPENSSL_free(s->s3->tmp.ctype);
+        s->s3->tmp.ctype = NULL;
+        s->s3->tmp.ctype_len = 0;
+        OPENSSL_free(s->pha_context);
+        s->pha_context = NULL;
+        s->pha_context_len = 0;
+
+        if (!PACKET_get_length_prefixed_1(pkt, &reqctx) ||
+            !PACKET_memdup(&reqctx, &s->pha_context, &s->pha_context_len)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                     SSL_R_LENGTH_MISMATCH);
+            return MSG_PROCESS_ERROR;
+        }
+
+        if (!PACKET_get_length_prefixed_2(pkt, &extensions)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                     SSL_R_BAD_LENGTH);
+            return MSG_PROCESS_ERROR;
+        }
+        if (!tls_collect_extensions(s, &extensions,
+                                    SSL_EXT_TLS1_3_CERTIFICATE_REQUEST,
+                                    &rawexts, NULL, 1)
+            || !tls_parse_all_extensions(s, SSL_EXT_TLS1_3_CERTIFICATE_REQUEST,
+                                         rawexts, NULL, 0, 1)) {
+            /* SSLfatal() already called */
+            OPENSSL_free(rawexts);
+            return MSG_PROCESS_ERROR;
+        }
+        OPENSSL_free(rawexts);
+        if (!tls1_process_sigalgs(s)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                     SSL_R_BAD_LENGTH);
+            return MSG_PROCESS_ERROR;
+        }
+    } else {
+        PACKET ctypes;
+
+        /* get the certificate types */
+        if (!PACKET_get_length_prefixed_1(pkt, &ctypes)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                     SSL_R_LENGTH_MISMATCH);
+            return MSG_PROCESS_ERROR;
+        }
+
+        if (!PACKET_memdup(&ctypes, &s->s3->tmp.ctype, &s->s3->tmp.ctype_len)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                     ERR_R_INTERNAL_ERROR);
+            return MSG_PROCESS_ERROR;
+        }
+
+        if (SSL_USE_SIGALGS(s)) {
+            PACKET sigalgs;
+
+            if (!PACKET_get_length_prefixed_2(pkt, &sigalgs)) {
+                SSLfatal(s, SSL_AD_DECODE_ERROR,
+                         SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                         SSL_R_LENGTH_MISMATCH);
+                return MSG_PROCESS_ERROR;
+            }
+
+            /*
+             * Despite this being for certificates, preserve compatibility
+             * with pre-TLS 1.3 and use the regular sigalgs field.
+             */
+            if (!tls1_save_sigalgs(s, &sigalgs, 0)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                         SSL_R_SIGNATURE_ALGORITHMS_ERROR);
+                return MSG_PROCESS_ERROR;
+            }
+            if (!tls1_process_sigalgs(s)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                         ERR_R_MALLOC_FAILURE);
+                return MSG_PROCESS_ERROR;
+            }
+        }
+
+        /* get the CA RDNs */
+        if (!parse_ca_names(s, pkt)) {
+            /* SSLfatal() already called */
+            return MSG_PROCESS_ERROR;
+        }
+    }
+
+    if (PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                 SSL_R_LENGTH_MISMATCH);
+        return MSG_PROCESS_ERROR;
+    }
+
+    /* we should setup a certificate to return.... */
+    s->s3->tmp.cert_req = 1;
+
+    /*
+     * In TLSv1.3 we don't prepare the client certificate yet. We wait until
+     * after the CertificateVerify message has been received. This is because
+     * in TLSv1.3 the CertificateRequest arrives before the Certificate message
+     * but in TLSv1.2 it is the other way around. We want to make sure that
+     * SSL_get_peer_certificate() returns something sensible in
+     * client_cert_cb.
+     */
+    if (SSL_IS_TLS13(s) && s->post_handshake_auth != SSL_PHA_REQUESTED)
+        return MSG_PROCESS_CONTINUE_READING;
+
+    return MSG_PROCESS_CONTINUE_PROCESSING;
+}
+
+MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt)
+{
+    unsigned int ticklen;
+    unsigned long ticket_lifetime_hint, age_add = 0;
+    unsigned int sess_len;
+    RAW_EXTENSION *exts = NULL;
+    PACKET nonce;
+
+    PACKET_null_init(&nonce);
+
+    if (!PACKET_get_net_4(pkt, &ticket_lifetime_hint)
+        || (SSL_IS_TLS13(s)
+            && (!PACKET_get_net_4(pkt, &age_add)
+                || !PACKET_get_length_prefixed_1(pkt, &nonce)))
+        || !PACKET_get_net_2(pkt, &ticklen)
+        || (SSL_IS_TLS13(s) ? (ticklen == 0 || PACKET_remaining(pkt) < ticklen)
+                            : PACKET_remaining(pkt) != ticklen)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_NEW_SESSION_TICKET,
+                 SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    /*
+     * Server is allowed to change its mind (in <=TLSv1.2) and send an empty
+     * ticket. We already checked this TLSv1.3 case above, so it should never
+     * be 0 here in that instance
+     */
+    if (ticklen == 0)
+        return MSG_PROCESS_CONTINUE_READING;
+
+    /*
+     * Sessions must be immutable once they go into the session cache. Otherwise
+     * we can get multi-thread problems. Therefore we don't "update" sessions,
+     * we replace them with a duplicate. In TLSv1.3 we need to do this every
+     * time a NewSessionTicket arrives because those messages arrive
+     * post-handshake and the session may have already gone into the session
+     * cache.
+     */
+    if (SSL_IS_TLS13(s) || s->session->session_id_length > 0) {
+        SSL_SESSION *new_sess;
+
+        /*
+         * We reused an existing session, so we need to replace it with a new
+         * one
+         */
+        if ((new_sess = ssl_session_dup(s->session, 0)) == 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PROCESS_NEW_SESSION_TICKET,
+                     ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        if ((s->session_ctx->session_cache_mode & SSL_SESS_CACHE_CLIENT) != 0
+                && !SSL_IS_TLS13(s)) {
+            /*
+             * In TLSv1.2 and below the arrival of a new tickets signals that
+             * any old ticket we were using is now out of date, so we remove the
+             * old session from the cache. We carry on if this fails
+             */
+            SSL_CTX_remove_session(s->session_ctx, s->session);
+        }
+
+        SSL_SESSION_free(s->session);
+        s->session = new_sess;
+    }
+
+    /*
+     * Technically the cast to long here is not guaranteed by the C standard -
+     * but we use it elsewhere, so this should be ok.
+     */
+    s->session->time = (long)time(NULL);
+
+    OPENSSL_free(s->session->ext.tick);
+    s->session->ext.tick = NULL;
+    s->session->ext.ticklen = 0;
+
+    s->session->ext.tick = OPENSSL_malloc(ticklen);
+    if (s->session->ext.tick == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_NEW_SESSION_TICKET,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    if (!PACKET_copy_bytes(pkt, s->session->ext.tick, ticklen)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_NEW_SESSION_TICKET,
+                 SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    s->session->ext.tick_lifetime_hint = ticket_lifetime_hint;
+    s->session->ext.tick_age_add = age_add;
+    s->session->ext.ticklen = ticklen;
+
+    if (SSL_IS_TLS13(s)) {
+        PACKET extpkt;
+
+        if (!PACKET_as_length_prefixed_2(pkt, &extpkt)
+                || PACKET_remaining(pkt) != 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PROCESS_NEW_SESSION_TICKET,
+                     SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        if (!tls_collect_extensions(s, &extpkt,
+                                    SSL_EXT_TLS1_3_NEW_SESSION_TICKET, &exts,
+                                    NULL, 1)
+                || !tls_parse_all_extensions(s,
+                                             SSL_EXT_TLS1_3_NEW_SESSION_TICKET,
+                                             exts, NULL, 0, 1)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    }
+
+    /*
+     * There are two ways to detect a resumed ticket session. One is to set
+     * an appropriate session ID and then the server must return a match in
+     * ServerHello. This allows the normal client session ID matching to work
+     * and we know much earlier that the ticket has been accepted. The
+     * other way is to set zero length session ID when the ticket is
+     * presented and rely on the handshake to determine session resumption.
+     * We choose the former approach because this fits in with assumptions
+     * elsewhere in OpenSSL. The session ID is set to the SHA256 (or SHA1 is
+     * SHA256 is disabled) hash of the ticket.
+     */
+    /*
+     * TODO(size_t): we use sess_len here because EVP_Digest expects an int
+     * but s->session->session_id_length is a size_t
+     */
+    if (!EVP_Digest(s->session->ext.tick, ticklen,
+                    s->session->session_id, &sess_len,
+                    EVP_sha256(), NULL)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_NEW_SESSION_TICKET,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+    s->session->session_id_length = sess_len;
+    s->session->not_resumable = 0;
+
+    /* This is a standalone message in TLSv1.3, so there is no more to read */
+    if (SSL_IS_TLS13(s)) {
+        const EVP_MD *md = ssl_handshake_md(s);
+        int hashleni = EVP_MD_size(md);
+        size_t hashlen;
+        static const unsigned char nonce_label[] = "resumption";
+
+        /* Ensure cast to size_t is safe */
+        if (!ossl_assert(hashleni >= 0)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PROCESS_NEW_SESSION_TICKET,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        hashlen = (size_t)hashleni;
+
+        if (!tls13_hkdf_expand(s, md, s->resumption_master_secret,
+                               nonce_label,
+                               sizeof(nonce_label) - 1,
+                               PACKET_data(&nonce),
+                               PACKET_remaining(&nonce),
+                               s->session->master_key,
+                               hashlen, 1)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+        s->session->master_key_length = hashlen;
+
+        OPENSSL_free(exts);
+        ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
+        return MSG_PROCESS_FINISHED_READING;
+    }
+
+    return MSG_PROCESS_CONTINUE_READING;
+ err:
+    OPENSSL_free(exts);
+    return MSG_PROCESS_ERROR;
+}
+
+/*
+ * In TLSv1.3 this is called from the extensions code, otherwise it is used to
+ * parse a separate message. Returns 1 on success or 0 on failure
+ */
+int tls_process_cert_status_body(SSL *s, PACKET *pkt)
+{
+    size_t resplen;
+    unsigned int type;
+
+    if (!PACKET_get_1(pkt, &type)
+        || type != TLSEXT_STATUSTYPE_ocsp) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CERT_STATUS_BODY,
+                 SSL_R_UNSUPPORTED_STATUS_TYPE);
+        return 0;
+    }
+    if (!PACKET_get_net_3_len(pkt, &resplen)
+        || PACKET_remaining(pkt) != resplen) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CERT_STATUS_BODY,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+    s->ext.ocsp.resp = OPENSSL_malloc(resplen);
+    if (s->ext.ocsp.resp == NULL) {
+        s->ext.ocsp.resp_len = 0;
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_STATUS_BODY,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    s->ext.ocsp.resp_len = resplen;
+    if (!PACKET_copy_bytes(pkt, s->ext.ocsp.resp, resplen)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CERT_STATUS_BODY,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    return 1;
+}
+
+
+MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt)
+{
+    if (!tls_process_cert_status_body(s, pkt)) {
+        /* SSLfatal() already called */
+        return MSG_PROCESS_ERROR;
+    }
+
+    return MSG_PROCESS_CONTINUE_READING;
+}
+
+/*
+ * Perform miscellaneous checks and processing after we have received the
+ * server's initial flight. In TLS1.3 this is after the Server Finished message.
+ * In <=TLS1.2 this is after the ServerDone message. Returns 1 on success or 0
+ * on failure.
+ */
+int tls_process_initial_server_flight(SSL *s)
+{
+    /*
+     * at this point we check that we have the required stuff from
+     * the server
+     */
+    if (!ssl3_check_cert_and_algorithm(s)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    /*
+     * Call the ocsp status callback if needed. The |ext.ocsp.resp| and
+     * |ext.ocsp.resp_len| values will be set if we actually received a status
+     * message, or NULL and -1 otherwise
+     */
+    if (s->ext.status_type != TLSEXT_STATUSTYPE_nothing
+            && s->ctx->ext.status_cb != NULL) {
+        int ret = s->ctx->ext.status_cb(s, s->ctx->ext.status_arg);
+
+        if (ret == 0) {
+            SSLfatal(s, SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE,
+                     SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT,
+                     SSL_R_INVALID_STATUS_RESPONSE);
+            return 0;
+        }
+        if (ret < 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT,
+                     SSL_R_OCSP_CALLBACK_FAILURE);
+            return 0;
+        }
+    }
+#ifndef OPENSSL_NO_CT
+    if (s->ct_validation_callback != NULL) {
+        /* Note we validate the SCTs whether or not we abort on error */
+        if (!ssl_validate_ct(s) && (s->verify_mode & SSL_VERIFY_PEER)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+    }
+#endif
+
+    return 1;
+}
+
+MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt)
+{
+    if (PACKET_remaining(pkt) > 0) {
+        /* should contain no data */
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_DONE,
+                 SSL_R_LENGTH_MISMATCH);
+        return MSG_PROCESS_ERROR;
+    }
+#ifndef OPENSSL_NO_SRP
+    if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) {
+        if (SRP_Calc_A_param(s) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SERVER_DONE,
+                     SSL_R_SRP_A_CALC);
+            return MSG_PROCESS_ERROR;
+        }
+    }
+#endif
+
+    if (!tls_process_initial_server_flight(s)) {
+        /* SSLfatal() already called */
+        return MSG_PROCESS_ERROR;
+    }
+
+    return MSG_PROCESS_FINISHED_READING;
+}
+
+static int tls_construct_cke_psk_preamble(SSL *s, WPACKET *pkt)
+{
+#ifndef OPENSSL_NO_PSK
+    int ret = 0;
+    /*
+     * The callback needs PSK_MAX_IDENTITY_LEN + 1 bytes to return a
+     * \0-terminated identity. The last byte is for us for simulating
+     * strnlen.
+     */
+    char identity[PSK_MAX_IDENTITY_LEN + 1];
+    size_t identitylen = 0;
+    unsigned char psk[PSK_MAX_PSK_LEN];
+    unsigned char *tmppsk = NULL;
+    char *tmpidentity = NULL;
+    size_t psklen = 0;
+
+    if (s->psk_client_callback == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE,
+                 SSL_R_PSK_NO_CLIENT_CB);
+        goto err;
+    }
+
+    memset(identity, 0, sizeof(identity));
+
+    psklen = s->psk_client_callback(s, s->session->psk_identity_hint,
+                                    identity, sizeof(identity) - 1,
+                                    psk, sizeof(psk));
+
+    if (psklen > PSK_MAX_PSK_LEN) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                 SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, ERR_R_INTERNAL_ERROR);
+        psklen = PSK_MAX_PSK_LEN;   /* Avoid overrunning the array on cleanse */
+        goto err;
+    } else if (psklen == 0) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                 SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE,
+                 SSL_R_PSK_IDENTITY_NOT_FOUND);
+        goto err;
+    }
+
+    identitylen = strlen(identity);
+    if (identitylen > PSK_MAX_IDENTITY_LEN) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    tmppsk = OPENSSL_memdup(psk, psklen);
+    tmpidentity = OPENSSL_strdup(identity);
+    if (tmppsk == NULL || tmpidentity == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    OPENSSL_free(s->s3->tmp.psk);
+    s->s3->tmp.psk = tmppsk;
+    s->s3->tmp.psklen = psklen;
+    tmppsk = NULL;
+    OPENSSL_free(s->session->psk_identity);
+    s->session->psk_identity = tmpidentity;
+    tmpidentity = NULL;
+
+    if (!WPACKET_sub_memcpy_u16(pkt, identity, identitylen))  {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    ret = 1;
+
+ err:
+    OPENSSL_cleanse(psk, psklen);
+    OPENSSL_cleanse(identity, sizeof(identity));
+    OPENSSL_clear_free(tmppsk, psklen);
+    OPENSSL_clear_free(tmpidentity, identitylen);
+
+    return ret;
+#else
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+static int tls_construct_cke_rsa(SSL *s, WPACKET *pkt)
+{
+#ifndef OPENSSL_NO_RSA
+    unsigned char *encdata = NULL;
+    EVP_PKEY *pkey = NULL;
+    EVP_PKEY_CTX *pctx = NULL;
+    size_t enclen;
+    unsigned char *pms = NULL;
+    size_t pmslen = 0;
+
+    if (s->session->peer == NULL) {
+        /*
+         * We should always have a server certificate with SSL_kRSA.
+         */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_RSA,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    pkey = X509_get0_pubkey(s->session->peer);
+    if (EVP_PKEY_get0_RSA(pkey) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_RSA,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    pmslen = SSL_MAX_MASTER_KEY_LENGTH;
+    pms = OPENSSL_malloc(pmslen);
+    if (pms == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_RSA,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    pms[0] = s->client_version >> 8;
+    pms[1] = s->client_version & 0xff;
+    /* TODO(size_t): Convert this function */
+    if (RAND_bytes(pms + 2, (int)(pmslen - 2)) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_RSA,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    /* Fix buf for TLS and beyond */
+    if (s->version > SSL3_VERSION && !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_RSA,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    pctx = EVP_PKEY_CTX_new(pkey, NULL);
+    if (pctx == NULL || EVP_PKEY_encrypt_init(pctx) <= 0
+        || EVP_PKEY_encrypt(pctx, NULL, &enclen, pms, pmslen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_RSA,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+    if (!WPACKET_allocate_bytes(pkt, enclen, &encdata)
+            || EVP_PKEY_encrypt(pctx, encdata, &enclen, pms, pmslen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_RSA,
+                 SSL_R_BAD_RSA_ENCRYPT);
+        goto err;
+    }
+    EVP_PKEY_CTX_free(pctx);
+    pctx = NULL;
+
+    /* Fix buf for TLS and beyond */
+    if (s->version > SSL3_VERSION && !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_RSA,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /* Log the premaster secret, if logging is enabled. */
+    if (!ssl_log_rsa_client_key_exchange(s, encdata, enclen, pms, pmslen)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    s->s3->tmp.pms = pms;
+    s->s3->tmp.pmslen = pmslen;
+
+    return 1;
+ err:
+    OPENSSL_clear_free(pms, pmslen);
+    EVP_PKEY_CTX_free(pctx);
+
+    return 0;
+#else
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_RSA,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+static int tls_construct_cke_dhe(SSL *s, WPACKET *pkt)
+{
+#ifndef OPENSSL_NO_DH
+    DH *dh_clnt = NULL;
+    const BIGNUM *pub_key;
+    EVP_PKEY *ckey = NULL, *skey = NULL;
+    unsigned char *keybytes = NULL;
+
+    skey = s->s3->peer_tmp;
+    if (skey == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_DHE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    ckey = ssl_generate_pkey(skey);
+    if (ckey == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_DHE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    dh_clnt = EVP_PKEY_get0_DH(ckey);
+
+    if (dh_clnt == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_DHE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (ssl_derive(s, ckey, skey, 0) == 0) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    /* send off the data */
+    DH_get0_key(dh_clnt, &pub_key, NULL);
+    if (!WPACKET_sub_allocate_bytes_u16(pkt, BN_num_bytes(pub_key),
+                                        &keybytes)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_DHE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    BN_bn2bin(pub_key, keybytes);
+    EVP_PKEY_free(ckey);
+
+    return 1;
+ err:
+    EVP_PKEY_free(ckey);
+    return 0;
+#else
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_DHE,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+static int tls_construct_cke_ecdhe(SSL *s, WPACKET *pkt)
+{
+#ifndef OPENSSL_NO_EC
+    unsigned char *encodedPoint = NULL;
+    size_t encoded_pt_len = 0;
+    EVP_PKEY *ckey = NULL, *skey = NULL;
+    int ret = 0;
+
+    skey = s->s3->peer_tmp;
+    if (skey == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_ECDHE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    ckey = ssl_generate_pkey(skey);
+    if (ckey == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_ECDHE,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (ssl_derive(s, ckey, skey, 0) == 0) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    /* Generate encoding of client key */
+    encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(ckey, &encodedPoint);
+
+    if (encoded_pt_len == 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_ECDHE,
+                 ERR_R_EC_LIB);
+        goto err;
+    }
+
+    if (!WPACKET_sub_memcpy_u8(pkt, encodedPoint, encoded_pt_len)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_ECDHE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    ret = 1;
+ err:
+    OPENSSL_free(encodedPoint);
+    EVP_PKEY_free(ckey);
+    return ret;
+#else
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_ECDHE,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+static int tls_construct_cke_gost(SSL *s, WPACKET *pkt)
+{
+#ifndef OPENSSL_NO_GOST
+    /* GOST key exchange message creation */
+    EVP_PKEY_CTX *pkey_ctx = NULL;
+    X509 *peer_cert;
+    size_t msglen;
+    unsigned int md_len;
+    unsigned char shared_ukm[32], tmp[256];
+    EVP_MD_CTX *ukm_hash = NULL;
+    int dgst_nid = NID_id_GostR3411_94;
+    unsigned char *pms = NULL;
+    size_t pmslen = 0;
+
+    if ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aGOST12) != 0)
+        dgst_nid = NID_id_GostR3411_2012_256;
+
+    /*
+     * Get server certificate PKEY and create ctx from it
+     */
+    peer_cert = s->session->peer;
+    if (!peer_cert) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS_CONSTRUCT_CKE_GOST,
+               SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
+        return 0;
+    }
+
+    pkey_ctx = EVP_PKEY_CTX_new(X509_get0_pubkey(peer_cert), NULL);
+    if (pkey_ctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    /*
+     * If we have send a certificate, and certificate key
+     * parameters match those of server certificate, use
+     * certificate key for key exchange
+     */
+
+    /* Otherwise, generate ephemeral key pair */
+    pmslen = 32;
+    pms = OPENSSL_malloc(pmslen);
+    if (pms == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (EVP_PKEY_encrypt_init(pkey_ctx) <= 0
+        /* Generate session key
+         * TODO(size_t): Convert this function
+         */
+        || RAND_bytes(pms, (int)pmslen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    };
+    /*
+     * Compute shared IV and store it in algorithm-specific context
+     * data
+     */
+    ukm_hash = EVP_MD_CTX_new();
+    if (ukm_hash == NULL
+        || EVP_DigestInit(ukm_hash, EVP_get_digestbynid(dgst_nid)) <= 0
+        || EVP_DigestUpdate(ukm_hash, s->s3->client_random,
+                            SSL3_RANDOM_SIZE) <= 0
+        || EVP_DigestUpdate(ukm_hash, s->s3->server_random,
+                            SSL3_RANDOM_SIZE) <= 0
+        || EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    EVP_MD_CTX_free(ukm_hash);
+    ukm_hash = NULL;
+    if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT,
+                          EVP_PKEY_CTRL_SET_IV, 8, shared_ukm) < 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST,
+                 SSL_R_LIBRARY_BUG);
+        goto err;
+    }
+    /* Make GOST keytransport blob message */
+    /*
+     * Encapsulate it into sequence
+     */
+    msglen = 255;
+    if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST,
+                 SSL_R_LIBRARY_BUG);
+        goto err;
+    }
+
+    if (!WPACKET_put_bytes_u8(pkt, V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED)
+            || (msglen >= 0x80 && !WPACKET_put_bytes_u8(pkt, 0x81))
+            || !WPACKET_sub_memcpy_u8(pkt, tmp, msglen)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    EVP_PKEY_CTX_free(pkey_ctx);
+    s->s3->tmp.pms = pms;
+    s->s3->tmp.pmslen = pmslen;
+
+    return 1;
+ err:
+    EVP_PKEY_CTX_free(pkey_ctx);
+    OPENSSL_clear_free(pms, pmslen);
+    EVP_MD_CTX_free(ukm_hash);
+    return 0;
+#else
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+static int tls_construct_cke_srp(SSL *s, WPACKET *pkt)
+{
+#ifndef OPENSSL_NO_SRP
+    unsigned char *abytes = NULL;
+
+    if (s->srp_ctx.A == NULL
+            || !WPACKET_sub_allocate_bytes_u16(pkt, BN_num_bytes(s->srp_ctx.A),
+                                               &abytes)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_SRP,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    BN_bn2bin(s->srp_ctx.A, abytes);
+
+    OPENSSL_free(s->session->srp_username);
+    s->session->srp_username = OPENSSL_strdup(s->srp_ctx.login);
+    if (s->session->srp_username == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_SRP,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    return 1;
+#else
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_SRP,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+int tls_construct_client_key_exchange(SSL *s, WPACKET *pkt)
+{
+    unsigned long alg_k;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    /*
+     * All of the construct functions below call SSLfatal() if necessary so
+     * no need to do so here.
+     */
+    if ((alg_k & SSL_PSK)
+        && !tls_construct_cke_psk_preamble(s, pkt))
+        goto err;
+
+    if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
+        if (!tls_construct_cke_rsa(s, pkt))
+            goto err;
+    } else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
+        if (!tls_construct_cke_dhe(s, pkt))
+            goto err;
+    } else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
+        if (!tls_construct_cke_ecdhe(s, pkt))
+            goto err;
+    } else if (alg_k & SSL_kGOST) {
+        if (!tls_construct_cke_gost(s, pkt))
+            goto err;
+    } else if (alg_k & SSL_kSRP) {
+        if (!tls_construct_cke_srp(s, pkt))
+            goto err;
+    } else if (!(alg_k & SSL_kPSK)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    return 1;
+ err:
+    OPENSSL_clear_free(s->s3->tmp.pms, s->s3->tmp.pmslen);
+    s->s3->tmp.pms = NULL;
+    s->s3->tmp.pmslen = 0;
+#ifndef OPENSSL_NO_PSK
+    OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen);
+    s->s3->tmp.psk = NULL;
+    s->s3->tmp.psklen = 0;
+#endif
+    return 0;
+}
+
+int tls_client_key_exchange_post_work(SSL *s)
+{
+    unsigned char *pms = NULL;
+    size_t pmslen = 0;
+
+    pms = s->s3->tmp.pms;
+    pmslen = s->s3->tmp.pmslen;
+
+#ifndef OPENSSL_NO_SRP
+    /* Check for SRP */
+    if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) {
+        if (!srp_generate_client_master_secret(s)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+        return 1;
+    }
+#endif
+
+    if (pms == NULL && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    if (!ssl_generate_master_secret(s, pms, pmslen, 1)) {
+        /* SSLfatal() already called */
+        /* ssl_generate_master_secret frees the pms even on error */
+        pms = NULL;
+        pmslen = 0;
+        goto err;
+    }
+    pms = NULL;
+    pmslen = 0;
+
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s)) {
+        unsigned char sctpauthkey[64];
+        char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+        size_t labellen;
+
+        /*
+         * Add new shared key for SCTP-Auth, will be ignored if no SCTP
+         * used.
+         */
+        memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
+               sizeof(DTLS1_SCTP_AUTH_LABEL));
+
+        /* Don't include the terminating zero. */
+        labellen = sizeof(labelbuffer) - 1;
+        if (s->mode & SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG)
+            labellen += 1;
+
+        if (SSL_export_keying_material(s, sctpauthkey,
+                                       sizeof(sctpauthkey), labelbuffer,
+                                       labellen, NULL, 0, 0) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+                 sizeof(sctpauthkey), sctpauthkey);
+    }
+#endif
+
+    return 1;
+ err:
+    OPENSSL_clear_free(pms, pmslen);
+    s->s3->tmp.pms = NULL;
+    s->s3->tmp.pmslen = 0;
+    return 0;
+}
+
+/*
+ * Check a certificate can be used for client authentication. Currently check
+ * cert exists, if we have a suitable digest for TLS 1.2 if static DH client
+ * certificates can be used and optionally checks suitability for Suite B.
+ */
+static int ssl3_check_client_certificate(SSL *s)
+{
+    /* If no suitable signature algorithm can't use certificate */
+    if (!tls_choose_sigalg(s, 0) || s->s3->tmp.sigalg == NULL)
+        return 0;
+    /*
+     * If strict mode check suitability of chain before using it. This also
+     * adjusts suite B digest if necessary.
+     */
+    if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT &&
+        !tls1_check_chain(s, NULL, NULL, NULL, -2))
+        return 0;
+    return 1;
+}
+
+WORK_STATE tls_prepare_client_certificate(SSL *s, WORK_STATE wst)
+{
+    X509 *x509 = NULL;
+    EVP_PKEY *pkey = NULL;
+    int i;
+
+    if (wst == WORK_MORE_A) {
+        /* Let cert callback update client certificates if required */
+        if (s->cert->cert_cb) {
+            i = s->cert->cert_cb(s, s->cert->cert_cb_arg);
+            if (i < 0) {
+                s->rwstate = SSL_X509_LOOKUP;
+                return WORK_MORE_A;
+            }
+            if (i == 0) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE,
+                         SSL_R_CALLBACK_FAILED);
+                return WORK_ERROR;
+            }
+            s->rwstate = SSL_NOTHING;
+        }
+        if (ssl3_check_client_certificate(s)) {
+            if (s->post_handshake_auth == SSL_PHA_REQUESTED) {
+                return WORK_FINISHED_STOP;
+            }
+            return WORK_FINISHED_CONTINUE;
+        }
+
+        /* Fall through to WORK_MORE_B */
+        wst = WORK_MORE_B;
+    }
+
+    /* We need to get a client cert */
+    if (wst == WORK_MORE_B) {
+        /*
+         * If we get an error, we need to ssl->rwstate=SSL_X509_LOOKUP;
+         * return(-1); We then get retied later
+         */
+        i = ssl_do_client_cert_cb(s, &x509, &pkey);
+        if (i < 0) {
+            s->rwstate = SSL_X509_LOOKUP;
+            return WORK_MORE_B;
+        }
+        s->rwstate = SSL_NOTHING;
+        if ((i == 1) && (pkey != NULL) && (x509 != NULL)) {
+            if (!SSL_use_certificate(s, x509) || !SSL_use_PrivateKey(s, pkey))
+                i = 0;
+        } else if (i == 1) {
+            i = 0;
+            SSLerr(SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE,
+                   SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
+        }
+
+        X509_free(x509);
+        EVP_PKEY_free(pkey);
+        if (i && !ssl3_check_client_certificate(s))
+            i = 0;
+        if (i == 0) {
+            if (s->version == SSL3_VERSION) {
+                s->s3->tmp.cert_req = 0;
+                ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE);
+                return WORK_FINISHED_CONTINUE;
+            } else {
+                s->s3->tmp.cert_req = 2;
+                if (!ssl3_digest_cached_records(s, 0)) {
+                    /* SSLfatal() already called */
+                    return WORK_ERROR;
+                }
+            }
+        }
+
+        if (s->post_handshake_auth == SSL_PHA_REQUESTED)
+            return WORK_FINISHED_STOP;
+        return WORK_FINISHED_CONTINUE;
+    }
+
+    /* Shouldn't ever get here */
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE,
+             ERR_R_INTERNAL_ERROR);
+    return WORK_ERROR;
+}
+
+int tls_construct_client_certificate(SSL *s, WPACKET *pkt)
+{
+    if (SSL_IS_TLS13(s)) {
+        if (s->pha_context == NULL) {
+            /* no context available, add 0-length context */
+            if (!WPACKET_put_bytes_u8(pkt, 0)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        } else if (!WPACKET_sub_memcpy_u8(pkt, s->pha_context, s->pha_context_len)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+    if (!ssl3_output_cert_chain(s, pkt,
+                                (s->s3->tmp.cert_req == 2) ? NULL
+                                                           : s->cert->key)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    if (SSL_IS_TLS13(s)
+            && SSL_IS_FIRST_HANDSHAKE(s)
+            && (!s->method->ssl3_enc->change_cipher_state(s,
+                    SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_CLIENT_WRITE))) {
+        /*
+         * This is a fatal error, which leaves enc_write_ctx in an inconsistent
+         * state and thus ssl3_send_alert may crash.
+         */
+        SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE,
+                 SSL_R_CANNOT_CHANGE_CIPHER);
+        return 0;
+    }
+
+    return 1;
+}
+
+int ssl3_check_cert_and_algorithm(SSL *s)
+{
+    const SSL_CERT_LOOKUP *clu;
+    size_t idx;
+    long alg_k, alg_a;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+    alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+
+    /* we don't have a certificate */
+    if (!(alg_a & SSL_aCERT))
+        return 1;
+
+    /* This is the passed certificate */
+    clu = ssl_cert_lookup_by_pkey(X509_get0_pubkey(s->session->peer), &idx);
+
+    /* Check certificate is recognised and suitable for cipher */
+    if (clu == NULL || (alg_a & clu->amask) == 0) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                 SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                 SSL_R_MISSING_SIGNING_CERT);
+        return 0;
+    }
+
+#ifndef OPENSSL_NO_EC
+    if (clu->amask & SSL_aECDSA) {
+        if (ssl_check_srvr_ecc_cert_and_alg(s->session->peer, s))
+            return 1;
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                 SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_BAD_ECC_CERT);
+        return 0;
+    }
+#endif
+#ifndef OPENSSL_NO_RSA
+    if (alg_k & (SSL_kRSA | SSL_kRSAPSK) && idx != SSL_PKEY_RSA) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                 SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                 SSL_R_MISSING_RSA_ENCRYPTING_CERT);
+        return 0;
+    }
+#endif
+#ifndef OPENSSL_NO_DH
+    if ((alg_k & SSL_kDHE) && (s->s3->peer_tmp == NULL)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+#endif
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int tls_construct_next_proto(SSL *s, WPACKET *pkt)
+{
+    size_t len, padding_len;
+    unsigned char *padding = NULL;
+
+    len = s->ext.npn_len;
+    padding_len = 32 - ((len + 2) % 32);
+
+    if (!WPACKET_sub_memcpy_u8(pkt, s->ext.npn, len)
+            || !WPACKET_sub_allocate_bytes_u8(pkt, padding_len, &padding)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_NEXT_PROTO,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    memset(padding, 0, padding_len);
+
+    return 1;
+}
+#endif
+
+MSG_PROCESS_RETURN tls_process_hello_req(SSL *s, PACKET *pkt)
+{
+    if (PACKET_remaining(pkt) > 0) {
+        /* should contain no data */
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_HELLO_REQ,
+                 SSL_R_LENGTH_MISMATCH);
+        return MSG_PROCESS_ERROR;
+    }
+
+    if ((s->options & SSL_OP_NO_RENEGOTIATION)) {
+        ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION);
+        return MSG_PROCESS_FINISHED_READING;
+    }
+
+    /*
+     * This is a historical discrepancy (not in the RFC) maintained for
+     * compatibility reasons. If a TLS client receives a HelloRequest it will
+     * attempt an abbreviated handshake. However if a DTLS client receives a
+     * HelloRequest it will do a full handshake. Either behaviour is reasonable
+     * but doing one for TLS and another for DTLS is odd.
+     */
+    if (SSL_IS_DTLS(s))
+        SSL_renegotiate(s);
+    else
+        SSL_renegotiate_abbreviated(s);
+
+    return MSG_PROCESS_FINISHED_READING;
+}
+
+static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt)
+{
+    PACKET extensions;
+    RAW_EXTENSION *rawexts = NULL;
+
+    if (!PACKET_as_length_prefixed_2(pkt, &extensions)
+            || PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS,
+                 SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    if (!tls_collect_extensions(s, &extensions,
+                                SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS, &rawexts,
+                                NULL, 1)
+            || !tls_parse_all_extensions(s, SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
+                                         rawexts, NULL, 0, 1)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    OPENSSL_free(rawexts);
+    return MSG_PROCESS_CONTINUE_READING;
+
+ err:
+    OPENSSL_free(rawexts);
+    return MSG_PROCESS_ERROR;
+}
+
+int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
+{
+    int i = 0;
+#ifndef OPENSSL_NO_ENGINE
+    if (s->ctx->client_cert_engine) {
+        i = ENGINE_load_ssl_client_cert(s->ctx->client_cert_engine, s,
+                                        SSL_get_client_CA_list(s),
+                                        px509, ppkey, NULL, NULL, NULL);
+        if (i != 0)
+            return i;
+    }
+#endif
+    if (s->ctx->client_cert_cb)
+        i = s->ctx->client_cert_cb(s, px509, ppkey);
+    return i;
+}
+
+int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, WPACKET *pkt)
+{
+    int i;
+    size_t totlen = 0, len, maxlen, maxverok = 0;
+    int empty_reneg_info_scsv = !s->renegotiate;
+
+    /* Set disabled masks for this session */
+    if (!ssl_set_client_disabled(s)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_CIPHER_LIST_TO_BYTES,
+                 SSL_R_NO_PROTOCOLS_AVAILABLE);
+        return 0;
+    }
+
+    if (sk == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_CIPHER_LIST_TO_BYTES,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH
+# if OPENSSL_MAX_TLS1_2_CIPHER_LENGTH < 6
+#  error Max cipher length too short
+# endif
+    /*
+     * Some servers hang if client hello > 256 bytes as hack workaround
+     * chop number of supported ciphers to keep it well below this if we
+     * use TLS v1.2
+     */
+    if (TLS1_get_version(s) >= TLS1_2_VERSION)
+        maxlen = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1;
+    else
+#endif
+        /* Maximum length that can be stored in 2 bytes. Length must be even */
+        maxlen = 0xfffe;
+
+    if (empty_reneg_info_scsv)
+        maxlen -= 2;
+    if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV)
+        maxlen -= 2;
+
+    for (i = 0; i < sk_SSL_CIPHER_num(sk) && totlen < maxlen; i++) {
+        const SSL_CIPHER *c;
+
+        c = sk_SSL_CIPHER_value(sk, i);
+        /* Skip disabled ciphers */
+        if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED, 0))
+            continue;
+
+        if (!s->method->put_cipher_by_char(c, pkt, &len)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_CIPHER_LIST_TO_BYTES,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+
+        /* Sanity check that the maximum version we offer has ciphers enabled */
+        if (!maxverok) {
+            if (SSL_IS_DTLS(s)) {
+                if (DTLS_VERSION_GE(c->max_dtls, s->s3->tmp.max_ver)
+                        && DTLS_VERSION_LE(c->min_dtls, s->s3->tmp.max_ver))
+                    maxverok = 1;
+            } else {
+                if (c->max_tls >= s->s3->tmp.max_ver
+                        && c->min_tls <= s->s3->tmp.max_ver)
+                    maxverok = 1;
+            }
+        }
+
+        totlen += len;
+    }
+
+    if (totlen == 0 || !maxverok) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_CIPHER_LIST_TO_BYTES,
+                 SSL_R_NO_CIPHERS_AVAILABLE);
+
+        if (!maxverok)
+            ERR_add_error_data(1, "No ciphers enabled for max supported "
+                                  "SSL/TLS version");
+
+        return 0;
+    }
+
+    if (totlen != 0) {
+        if (empty_reneg_info_scsv) {
+            static SSL_CIPHER scsv = {
+                0, NULL, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
+            };
+            if (!s->method->put_cipher_by_char(&scsv, pkt, &len)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_SSL_CIPHER_LIST_TO_BYTES, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
+        if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV) {
+            static SSL_CIPHER scsv = {
+                0, NULL, NULL, SSL3_CK_FALLBACK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
+            };
+            if (!s->method->put_cipher_by_char(&scsv, pkt, &len)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_SSL_CIPHER_LIST_TO_BYTES, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
+    }
+
+    return 1;
+}
+
+int tls_construct_end_of_early_data(SSL *s, WPACKET *pkt)
+{
+    if (s->early_data_state != SSL_EARLY_DATA_WRITE_RETRY
+            && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_END_OF_EARLY_DATA,
+                 ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+        return 0;
+    }
+
+    s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING;
+    return 1;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_dtls.c b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_dtls.c
new file mode 100644
index 0000000..8fe6cea
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_dtls.c
@@ -0,0 +1,1281 @@
+/*
+ * Copyright 2005-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include "../ssl_local.h"
+#include "statem_local.h"
+#include "internal/cryptlib.h"
+#include <openssl/buffer.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#define RSMBLY_BITMASK_SIZE(msg_len) (((msg_len) + 7) / 8)
+
+#define RSMBLY_BITMASK_MARK(bitmask, start, end) { \
+                        if ((end) - (start) <= 8) { \
+                                long ii; \
+                                for (ii = (start); ii < (end); ii++) bitmask[((ii) >> 3)] |= (1 << ((ii) & 7)); \
+                        } else { \
+                                long ii; \
+                                bitmask[((start) >> 3)] |= bitmask_start_values[((start) & 7)]; \
+                                for (ii = (((start) >> 3) + 1); ii < ((((end) - 1)) >> 3); ii++) bitmask[ii] = 0xff; \
+                                bitmask[(((end) - 1) >> 3)] |= bitmask_end_values[((end) & 7)]; \
+                        } }
+
+#define RSMBLY_BITMASK_IS_COMPLETE(bitmask, msg_len, is_complete) { \
+                        long ii; \
+                        is_complete = 1; \
+                        if (bitmask[(((msg_len) - 1) >> 3)] != bitmask_end_values[((msg_len) & 7)]) is_complete = 0; \
+                        if (is_complete) for (ii = (((msg_len) - 1) >> 3) - 1; ii >= 0 ; ii--) \
+                                if (bitmask[ii] != 0xff) { is_complete = 0; break; } }
+
+static unsigned char bitmask_start_values[] =
+    { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80 };
+static unsigned char bitmask_end_values[] =
+    { 0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f };
+
+static void dtls1_fix_message_header(SSL *s, size_t frag_off,
+                                     size_t frag_len);
+static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p);
+static void dtls1_set_message_header_int(SSL *s, unsigned char mt,
+                                         size_t len,
+                                         unsigned short seq_num,
+                                         size_t frag_off,
+                                         size_t frag_len);
+static int dtls_get_reassembled_message(SSL *s, int *errtype, size_t *len);
+
+static hm_fragment *dtls1_hm_fragment_new(size_t frag_len, int reassembly)
+{
+    hm_fragment *frag = NULL;
+    unsigned char *buf = NULL;
+    unsigned char *bitmask = NULL;
+
+    if ((frag = OPENSSL_malloc(sizeof(*frag))) == NULL) {
+        SSLerr(SSL_F_DTLS1_HM_FRAGMENT_NEW, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    if (frag_len) {
+        if ((buf = OPENSSL_malloc(frag_len)) == NULL) {
+            SSLerr(SSL_F_DTLS1_HM_FRAGMENT_NEW, ERR_R_MALLOC_FAILURE);
+            OPENSSL_free(frag);
+            return NULL;
+        }
+    }
+
+    /* zero length fragment gets zero frag->fragment */
+    frag->fragment = buf;
+
+    /* Initialize reassembly bitmask if necessary */
+    if (reassembly) {
+        bitmask = OPENSSL_zalloc(RSMBLY_BITMASK_SIZE(frag_len));
+        if (bitmask == NULL) {
+            SSLerr(SSL_F_DTLS1_HM_FRAGMENT_NEW, ERR_R_MALLOC_FAILURE);
+            OPENSSL_free(buf);
+            OPENSSL_free(frag);
+            return NULL;
+        }
+    }
+
+    frag->reassembly = bitmask;
+
+    return frag;
+}
+
+void dtls1_hm_fragment_free(hm_fragment *frag)
+{
+    if (!frag)
+        return;
+    if (frag->msg_header.is_ccs) {
+        EVP_CIPHER_CTX_free(frag->msg_header.
+                            saved_retransmit_state.enc_write_ctx);
+        EVP_MD_CTX_free(frag->msg_header.saved_retransmit_state.write_hash);
+    }
+    OPENSSL_free(frag->fragment);
+    OPENSSL_free(frag->reassembly);
+    OPENSSL_free(frag);
+}
+
+/*
+ * send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or
+ * SSL3_RT_CHANGE_CIPHER_SPEC)
+ */
+int dtls1_do_write(SSL *s, int type)
+{
+    int ret;
+    size_t written;
+    size_t curr_mtu;
+    int retry = 1;
+    size_t len, frag_off, mac_size, blocksize, used_len;
+
+    if (!dtls1_query_mtu(s))
+        return -1;
+
+    if (s->d1->mtu < dtls1_min_mtu(s))
+        /* should have something reasonable now */
+        return -1;
+
+    if (s->init_off == 0 && type == SSL3_RT_HANDSHAKE) {
+        if (!ossl_assert(s->init_num ==
+                         s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH))
+            return -1;
+    }
+
+    if (s->write_hash) {
+        if (s->enc_write_ctx
+            && (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_write_ctx)) &
+                EVP_CIPH_FLAG_AEAD_CIPHER) != 0)
+            mac_size = 0;
+        else
+            mac_size = EVP_MD_CTX_size(s->write_hash);
+    } else
+        mac_size = 0;
+
+    if (s->enc_write_ctx &&
+        (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE))
+        blocksize = 2 * EVP_CIPHER_CTX_block_size(s->enc_write_ctx);
+    else
+        blocksize = 0;
+
+    frag_off = 0;
+    s->rwstate = SSL_NOTHING;
+
+    /* s->init_num shouldn't ever be < 0...but just in case */
+    while (s->init_num > 0) {
+        if (type == SSL3_RT_HANDSHAKE && s->init_off != 0) {
+            /* We must be writing a fragment other than the first one */
+
+            if (frag_off > 0) {
+                /* This is the first attempt at writing out this fragment */
+
+                if (s->init_off <= DTLS1_HM_HEADER_LENGTH) {
+                    /*
+                     * Each fragment that was already sent must at least have
+                     * contained the message header plus one other byte.
+                     * Therefore |init_off| must have progressed by at least
+                     * |DTLS1_HM_HEADER_LENGTH + 1| bytes. If not something went
+                     * wrong.
+                     */
+                    return -1;
+                }
+
+                /*
+                 * Adjust |init_off| and |init_num| to allow room for a new
+                 * message header for this fragment.
+                 */
+                s->init_off -= DTLS1_HM_HEADER_LENGTH;
+                s->init_num += DTLS1_HM_HEADER_LENGTH;
+            } else {
+                /*
+                 * We must have been called again after a retry so use the
+                 * fragment offset from our last attempt. We do not need
+                 * to adjust |init_off| and |init_num| as above, because
+                 * that should already have been done before the retry.
+                 */
+                frag_off = s->d1->w_msg_hdr.frag_off;
+            }
+        }
+
+        used_len = BIO_wpending(s->wbio) + DTLS1_RT_HEADER_LENGTH
+            + mac_size + blocksize;
+        if (s->d1->mtu > used_len)
+            curr_mtu = s->d1->mtu - used_len;
+        else
+            curr_mtu = 0;
+
+        if (curr_mtu <= DTLS1_HM_HEADER_LENGTH) {
+            /*
+             * grr.. we could get an error if MTU picked was wrong
+             */
+            ret = BIO_flush(s->wbio);
+            if (ret <= 0) {
+                s->rwstate = SSL_WRITING;
+                return ret;
+            }
+            used_len = DTLS1_RT_HEADER_LENGTH + mac_size + blocksize;
+            if (s->d1->mtu > used_len + DTLS1_HM_HEADER_LENGTH) {
+                curr_mtu = s->d1->mtu - used_len;
+            } else {
+                /* Shouldn't happen */
+                return -1;
+            }
+        }
+
+        /*
+         * We just checked that s->init_num > 0 so this cast should be safe
+         */
+        if (((unsigned int)s->init_num) > curr_mtu)
+            len = curr_mtu;
+        else
+            len = s->init_num;
+
+        if (len > ssl_get_max_send_fragment(s))
+            len = ssl_get_max_send_fragment(s);
+
+        /*
+         * XDTLS: this function is too long.  split out the CCS part
+         */
+        if (type == SSL3_RT_HANDSHAKE) {
+            if (len < DTLS1_HM_HEADER_LENGTH) {
+                /*
+                 * len is so small that we really can't do anything sensible
+                 * so fail
+                 */
+                return -1;
+            }
+            dtls1_fix_message_header(s, frag_off, len - DTLS1_HM_HEADER_LENGTH);
+
+            dtls1_write_message_header(s,
+                                       (unsigned char *)&s->init_buf->
+                                       data[s->init_off]);
+        }
+
+        ret = dtls1_write_bytes(s, type, &s->init_buf->data[s->init_off], len,
+                                &written);
+        if (ret <= 0) {
+            /*
+             * might need to update MTU here, but we don't know which
+             * previous packet caused the failure -- so can't really
+             * retransmit anything.  continue as if everything is fine and
+             * wait for an alert to handle the retransmit
+             */
+            if (retry && BIO_ctrl(SSL_get_wbio(s),
+                                  BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0) {
+                if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {
+                    if (!dtls1_query_mtu(s))
+                        return -1;
+                    /* Have one more go */
+                    retry = 0;
+                } else
+                    return -1;
+            } else {
+                return -1;
+            }
+        } else {
+
+            /*
+             * bad if this assert fails, only part of the handshake message
+             * got sent.  but why would this happen?
+             */
+            if (!ossl_assert(len == written))
+                return -1;
+
+            if (type == SSL3_RT_HANDSHAKE && !s->d1->retransmitting) {
+                /*
+                 * should not be done for 'Hello Request's, but in that case
+                 * we'll ignore the result anyway
+                 */
+                unsigned char *p =
+                    (unsigned char *)&s->init_buf->data[s->init_off];
+                const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+                size_t xlen;
+
+                if (frag_off == 0 && s->version != DTLS1_BAD_VER) {
+                    /*
+                     * reconstruct message header is if it is being sent in
+                     * single fragment
+                     */
+                    *p++ = msg_hdr->type;
+                    l2n3(msg_hdr->msg_len, p);
+                    s2n(msg_hdr->seq, p);
+                    l2n3(0, p);
+                    l2n3(msg_hdr->msg_len, p);
+                    p -= DTLS1_HM_HEADER_LENGTH;
+                    xlen = written;
+                } else {
+                    p += DTLS1_HM_HEADER_LENGTH;
+                    xlen = written - DTLS1_HM_HEADER_LENGTH;
+                }
+
+                if (!ssl3_finish_mac(s, p, xlen))
+                    return -1;
+            }
+
+            if (written == s->init_num) {
+                if (s->msg_callback)
+                    s->msg_callback(1, s->version, type, s->init_buf->data,
+                                    (size_t)(s->init_off + s->init_num), s,
+                                    s->msg_callback_arg);
+
+                s->init_off = 0; /* done writing this message */
+                s->init_num = 0;
+
+                return 1;
+            }
+            s->init_off += written;
+            s->init_num -= written;
+            written -= DTLS1_HM_HEADER_LENGTH;
+            frag_off += written;
+
+            /*
+             * We save the fragment offset for the next fragment so we have it
+             * available in case of an IO retry. We don't know the length of the
+             * next fragment yet so just set that to 0 for now. It will be
+             * updated again later.
+             */
+            dtls1_fix_message_header(s, frag_off, 0);
+        }
+    }
+    return 0;
+}
+
+int dtls_get_message(SSL *s, int *mt, size_t *len)
+{
+    struct hm_header_st *msg_hdr;
+    unsigned char *p;
+    size_t msg_len;
+    size_t tmplen;
+    int errtype;
+
+    msg_hdr = &s->d1->r_msg_hdr;
+    memset(msg_hdr, 0, sizeof(*msg_hdr));
+
+ again:
+    if (!dtls_get_reassembled_message(s, &errtype, &tmplen)) {
+        if (errtype == DTLS1_HM_BAD_FRAGMENT
+                || errtype == DTLS1_HM_FRAGMENT_RETRY) {
+            /* bad fragment received */
+            goto again;
+        }
+        return 0;
+    }
+
+    *mt = s->s3->tmp.message_type;
+
+    p = (unsigned char *)s->init_buf->data;
+    *len = s->init_num;
+
+    if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+        if (s->msg_callback) {
+            s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC,
+                            p, 1, s, s->msg_callback_arg);
+        }
+        /*
+         * This isn't a real handshake message so skip the processing below.
+         */
+        return 1;
+    }
+
+    msg_len = msg_hdr->msg_len;
+
+    /* reconstruct message header */
+    *(p++) = msg_hdr->type;
+    l2n3(msg_len, p);
+    s2n(msg_hdr->seq, p);
+    l2n3(0, p);
+    l2n3(msg_len, p);
+    if (s->version != DTLS1_BAD_VER) {
+        p -= DTLS1_HM_HEADER_LENGTH;
+        msg_len += DTLS1_HM_HEADER_LENGTH;
+    }
+
+    /*
+     * If receiving Finished, record MAC of prior handshake messages for
+     * Finished verification.
+     */
+    if (*mt == SSL3_MT_FINISHED && !ssl3_take_mac(s)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    if (!ssl3_finish_mac(s, p, msg_len))
+        return 0;
+    if (s->msg_callback)
+        s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+                        p, msg_len, s, s->msg_callback_arg);
+
+    memset(msg_hdr, 0, sizeof(*msg_hdr));
+
+    s->d1->handshake_read_seq++;
+
+    s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+
+    return 1;
+}
+
+/*
+ * dtls1_max_handshake_message_len returns the maximum number of bytes
+ * permitted in a DTLS handshake message for |s|. The minimum is 16KB, but
+ * may be greater if the maximum certificate list size requires it.
+ */
+static size_t dtls1_max_handshake_message_len(const SSL *s)
+{
+    size_t max_len = DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
+    if (max_len < s->max_cert_list)
+        return s->max_cert_list;
+    return max_len;
+}
+
+static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr)
+{
+    size_t frag_off, frag_len, msg_len;
+
+    msg_len = msg_hdr->msg_len;
+    frag_off = msg_hdr->frag_off;
+    frag_len = msg_hdr->frag_len;
+
+    /* sanity checking */
+    if ((frag_off + frag_len) > msg_len
+            || msg_len > dtls1_max_handshake_message_len(s)) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_DTLS1_PREPROCESS_FRAGMENT,
+                 SSL_R_EXCESSIVE_MESSAGE_SIZE);
+        return 0;
+    }
+
+    if (s->d1->r_msg_hdr.frag_off == 0) { /* first fragment */
+        /*
+         * msg_len is limited to 2^24, but is effectively checked against
+         * dtls_max_handshake_message_len(s) above
+         */
+        if (!BUF_MEM_grow_clean(s->init_buf, msg_len + DTLS1_HM_HEADER_LENGTH)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS1_PREPROCESS_FRAGMENT,
+                     ERR_R_BUF_LIB);
+            return 0;
+        }
+
+        s->s3->tmp.message_size = msg_len;
+        s->d1->r_msg_hdr.msg_len = msg_len;
+        s->s3->tmp.message_type = msg_hdr->type;
+        s->d1->r_msg_hdr.type = msg_hdr->type;
+        s->d1->r_msg_hdr.seq = msg_hdr->seq;
+    } else if (msg_len != s->d1->r_msg_hdr.msg_len) {
+        /*
+         * They must be playing with us! BTW, failure to enforce upper limit
+         * would open possibility for buffer overrun.
+         */
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_DTLS1_PREPROCESS_FRAGMENT,
+                 SSL_R_EXCESSIVE_MESSAGE_SIZE);
+        return 0;
+    }
+
+    return 1;
+}
+
+/*
+ * Returns 1 if there is a buffered fragment available, 0 if not, or -1 on a
+ * fatal error.
+ */
+static int dtls1_retrieve_buffered_fragment(SSL *s, size_t *len)
+{
+    /*-
+     * (0) check whether the desired fragment is available
+     * if so:
+     * (1) copy over the fragment to s->init_buf->data[]
+     * (2) update s->init_num
+     */
+    pitem *item;
+    hm_fragment *frag;
+    int ret;
+
+    do {
+        item = pqueue_peek(s->d1->buffered_messages);
+        if (item == NULL)
+            return 0;
+
+        frag = (hm_fragment *)item->data;
+
+        if (frag->msg_header.seq < s->d1->handshake_read_seq) {
+            /* This is a stale message that has been buffered so clear it */
+            pqueue_pop(s->d1->buffered_messages);
+            dtls1_hm_fragment_free(frag);
+            pitem_free(item);
+            item = NULL;
+            frag = NULL;
+        }
+    } while (item == NULL);
+
+    /* Don't return if reassembly still in progress */
+    if (frag->reassembly != NULL)
+        return 0;
+
+    if (s->d1->handshake_read_seq == frag->msg_header.seq) {
+        size_t frag_len = frag->msg_header.frag_len;
+        pqueue_pop(s->d1->buffered_messages);
+
+        /* Calls SSLfatal() as required */
+        ret = dtls1_preprocess_fragment(s, &frag->msg_header);
+
+        if (ret && frag->msg_header.frag_len > 0) {
+            unsigned char *p =
+                (unsigned char *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+            memcpy(&p[frag->msg_header.frag_off], frag->fragment,
+                   frag->msg_header.frag_len);
+        }
+
+        dtls1_hm_fragment_free(frag);
+        pitem_free(item);
+
+        if (ret) {
+            *len = frag_len;
+            return 1;
+        }
+
+        /* Fatal error */
+        s->init_num = 0;
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+static int
+dtls1_reassemble_fragment(SSL *s, const struct hm_header_st *msg_hdr)
+{
+    hm_fragment *frag = NULL;
+    pitem *item = NULL;
+    int i = -1, is_complete;
+    unsigned char seq64be[8];
+    size_t frag_len = msg_hdr->frag_len;
+    size_t readbytes;
+
+    if ((msg_hdr->frag_off + frag_len) > msg_hdr->msg_len ||
+        msg_hdr->msg_len > dtls1_max_handshake_message_len(s))
+        goto err;
+
+    if (frag_len == 0) {
+        return DTLS1_HM_FRAGMENT_RETRY;
+    }
+
+    /* Try to find item in queue */
+    memset(seq64be, 0, sizeof(seq64be));
+    seq64be[6] = (unsigned char)(msg_hdr->seq >> 8);
+    seq64be[7] = (unsigned char)msg_hdr->seq;
+    item = pqueue_find(s->d1->buffered_messages, seq64be);
+
+    if (item == NULL) {
+        frag = dtls1_hm_fragment_new(msg_hdr->msg_len, 1);
+        if (frag == NULL)
+            goto err;
+        memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
+        frag->msg_header.frag_len = frag->msg_header.msg_len;
+        frag->msg_header.frag_off = 0;
+    } else {
+        frag = (hm_fragment *)item->data;
+        if (frag->msg_header.msg_len != msg_hdr->msg_len) {
+            item = NULL;
+            frag = NULL;
+            goto err;
+        }
+    }
+
+    /*
+     * If message is already reassembled, this must be a retransmit and can
+     * be dropped. In this case item != NULL and so frag does not need to be
+     * freed.
+     */
+    if (frag->reassembly == NULL) {
+        unsigned char devnull[256];
+
+        while (frag_len) {
+            i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
+                                          devnull,
+                                          frag_len >
+                                          sizeof(devnull) ? sizeof(devnull) :
+                                          frag_len, 0, &readbytes);
+            if (i <= 0)
+                goto err;
+            frag_len -= readbytes;
+        }
+        return DTLS1_HM_FRAGMENT_RETRY;
+    }
+
+    /* read the body of the fragment (header has already been read */
+    i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
+                                  frag->fragment + msg_hdr->frag_off,
+                                  frag_len, 0, &readbytes);
+    if (i <= 0 || readbytes != frag_len)
+        i = -1;
+    if (i <= 0)
+        goto err;
+
+    RSMBLY_BITMASK_MARK(frag->reassembly, (long)msg_hdr->frag_off,
+                        (long)(msg_hdr->frag_off + frag_len));
+
+    if (!ossl_assert(msg_hdr->msg_len > 0))
+        goto err;
+    RSMBLY_BITMASK_IS_COMPLETE(frag->reassembly, (long)msg_hdr->msg_len,
+                               is_complete);
+
+    if (is_complete) {
+        OPENSSL_free(frag->reassembly);
+        frag->reassembly = NULL;
+    }
+
+    if (item == NULL) {
+        item = pitem_new(seq64be, frag);
+        if (item == NULL) {
+            i = -1;
+            goto err;
+        }
+
+        item = pqueue_insert(s->d1->buffered_messages, item);
+        /*
+         * pqueue_insert fails iff a duplicate item is inserted. However,
+         * |item| cannot be a duplicate. If it were, |pqueue_find|, above,
+         * would have returned it and control would never have reached this
+         * branch.
+         */
+        if (!ossl_assert(item != NULL))
+            goto err;
+    }
+
+    return DTLS1_HM_FRAGMENT_RETRY;
+
+ err:
+    if (item == NULL)
+        dtls1_hm_fragment_free(frag);
+    return -1;
+}
+
+static int
+dtls1_process_out_of_seq_message(SSL *s, const struct hm_header_st *msg_hdr)
+{
+    int i = -1;
+    hm_fragment *frag = NULL;
+    pitem *item = NULL;
+    unsigned char seq64be[8];
+    size_t frag_len = msg_hdr->frag_len;
+    size_t readbytes;
+
+    if ((msg_hdr->frag_off + frag_len) > msg_hdr->msg_len)
+        goto err;
+
+    /* Try to find item in queue, to prevent duplicate entries */
+    memset(seq64be, 0, sizeof(seq64be));
+    seq64be[6] = (unsigned char)(msg_hdr->seq >> 8);
+    seq64be[7] = (unsigned char)msg_hdr->seq;
+    item = pqueue_find(s->d1->buffered_messages, seq64be);
+
+    /*
+     * If we already have an entry and this one is a fragment, don't discard
+     * it and rather try to reassemble it.
+     */
+    if (item != NULL && frag_len != msg_hdr->msg_len)
+        item = NULL;
+
+    /*
+     * Discard the message if sequence number was already there, is too far
+     * in the future, already in the queue or if we received a FINISHED
+     * before the SERVER_HELLO, which then must be a stale retransmit.
+     */
+    if (msg_hdr->seq <= s->d1->handshake_read_seq ||
+        msg_hdr->seq > s->d1->handshake_read_seq + 10 || item != NULL ||
+        (s->d1->handshake_read_seq == 0 && msg_hdr->type == SSL3_MT_FINISHED)) {
+        unsigned char devnull[256];
+
+        while (frag_len) {
+            i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
+                                          devnull,
+                                          frag_len >
+                                          sizeof(devnull) ? sizeof(devnull) :
+                                          frag_len, 0, &readbytes);
+            if (i <= 0)
+                goto err;
+            frag_len -= readbytes;
+        }
+    } else {
+        if (frag_len != msg_hdr->msg_len) {
+            return dtls1_reassemble_fragment(s, msg_hdr);
+        }
+
+        if (frag_len > dtls1_max_handshake_message_len(s))
+            goto err;
+
+        frag = dtls1_hm_fragment_new(frag_len, 0);
+        if (frag == NULL)
+            goto err;
+
+        memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
+
+        if (frag_len) {
+            /*
+             * read the body of the fragment (header has already been read
+             */
+            i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
+                                          frag->fragment, frag_len, 0,
+                                          &readbytes);
+            if (i<=0 || readbytes != frag_len)
+                i = -1;
+            if (i <= 0)
+                goto err;
+        }
+
+        item = pitem_new(seq64be, frag);
+        if (item == NULL)
+            goto err;
+
+        item = pqueue_insert(s->d1->buffered_messages, item);
+        /*
+         * pqueue_insert fails iff a duplicate item is inserted. However,
+         * |item| cannot be a duplicate. If it were, |pqueue_find|, above,
+         * would have returned it. Then, either |frag_len| !=
+         * |msg_hdr->msg_len| in which case |item| is set to NULL and it will
+         * have been processed with |dtls1_reassemble_fragment|, above, or
+         * the record will have been discarded.
+         */
+        if (!ossl_assert(item != NULL))
+            goto err;
+    }
+
+    return DTLS1_HM_FRAGMENT_RETRY;
+
+ err:
+    if (item == NULL)
+        dtls1_hm_fragment_free(frag);
+    return 0;
+}
+
+static int dtls_get_reassembled_message(SSL *s, int *errtype, size_t *len)
+{
+    unsigned char wire[DTLS1_HM_HEADER_LENGTH];
+    size_t mlen, frag_off, frag_len;
+    int i, ret, recvd_type;
+    struct hm_header_st msg_hdr;
+    size_t readbytes;
+
+    *errtype = 0;
+
+ redo:
+    /* see if we have the required fragment already */
+    ret = dtls1_retrieve_buffered_fragment(s, &frag_len);
+    if (ret < 0) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+    if (ret > 0) {
+        s->init_num = frag_len;
+        *len = frag_len;
+        return 1;
+    }
+
+    /* read handshake message header */
+    i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type, wire,
+                                  DTLS1_HM_HEADER_LENGTH, 0, &readbytes);
+    if (i <= 0) {               /* nbio, or an error */
+        s->rwstate = SSL_READING;
+        *len = 0;
+        return 0;
+    }
+    if (recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
+        if (wire[0] != SSL3_MT_CCS) {
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+                     SSL_F_DTLS_GET_REASSEMBLED_MESSAGE,
+                     SSL_R_BAD_CHANGE_CIPHER_SPEC);
+            goto f_err;
+        }
+
+        memcpy(s->init_buf->data, wire, readbytes);
+        s->init_num = readbytes - 1;
+        s->init_msg = s->init_buf->data + 1;
+        s->s3->tmp.message_type = SSL3_MT_CHANGE_CIPHER_SPEC;
+        s->s3->tmp.message_size = readbytes - 1;
+        *len = readbytes - 1;
+        return 1;
+    }
+
+    /* Handshake fails if message header is incomplete */
+    if (readbytes != DTLS1_HM_HEADER_LENGTH) {
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+                 SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
+        goto f_err;
+    }
+
+    /* parse the message fragment header */
+    dtls1_get_message_header(wire, &msg_hdr);
+
+    mlen = msg_hdr.msg_len;
+    frag_off = msg_hdr.frag_off;
+    frag_len = msg_hdr.frag_len;
+
+    /*
+     * We must have at least frag_len bytes left in the record to be read.
+     * Fragments must not span records.
+     */
+    if (frag_len > RECORD_LAYER_get_rrec_length(&s->rlayer)) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                 SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_BAD_LENGTH);
+        goto f_err;
+    }
+
+    /*
+     * if this is a future (or stale) message it gets buffered
+     * (or dropped)--no further processing at this time
+     * While listening, we accept seq 1 (ClientHello with cookie)
+     * although we're still expecting seq 0 (ClientHello)
+     */
+    if (msg_hdr.seq != s->d1->handshake_read_seq) {
+        *errtype = dtls1_process_out_of_seq_message(s, &msg_hdr);
+        return 0;
+    }
+
+    if (frag_len && frag_len < mlen) {
+        *errtype = dtls1_reassemble_fragment(s, &msg_hdr);
+        return 0;
+    }
+
+    if (!s->server
+            && s->d1->r_msg_hdr.frag_off == 0
+            && s->statem.hand_state != TLS_ST_OK
+            && wire[0] == SSL3_MT_HELLO_REQUEST) {
+        /*
+         * The server may always send 'Hello Request' messages -- we are
+         * doing a handshake anyway now, so ignore them if their format is
+         * correct. Does not count for 'Finished' MAC.
+         */
+        if (wire[1] == 0 && wire[2] == 0 && wire[3] == 0) {
+            if (s->msg_callback)
+                s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+                                wire, DTLS1_HM_HEADER_LENGTH, s,
+                                s->msg_callback_arg);
+
+            s->init_num = 0;
+            goto redo;
+        } else {                /* Incorrectly formatted Hello request */
+
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+                     SSL_F_DTLS_GET_REASSEMBLED_MESSAGE,
+                     SSL_R_UNEXPECTED_MESSAGE);
+            goto f_err;
+        }
+    }
+
+    if (!dtls1_preprocess_fragment(s, &msg_hdr)) {
+        /* SSLfatal() already called */
+        goto f_err;
+    }
+
+    if (frag_len > 0) {
+        unsigned char *p =
+            (unsigned char *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+
+        i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
+                                      &p[frag_off], frag_len, 0, &readbytes);
+
+        /*
+         * This shouldn't ever fail due to NBIO because we already checked
+         * that we have enough data in the record
+         */
+        if (i <= 0) {
+            s->rwstate = SSL_READING;
+            *len = 0;
+            return 0;
+        }
+    } else {
+        readbytes = 0;
+    }
+
+    /*
+     * XDTLS: an incorrectly formatted fragment should cause the handshake
+     * to fail
+     */
+    if (readbytes != frag_len) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                 SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_BAD_LENGTH);
+        goto f_err;
+    }
+
+    /*
+     * Note that s->init_num is *not* used as current offset in
+     * s->init_buf->data, but as a counter summing up fragments' lengths: as
+     * soon as they sum up to handshake packet length, we assume we have got
+     * all the fragments.
+     */
+    *len = s->init_num = frag_len;
+    return 1;
+
+ f_err:
+    s->init_num = 0;
+    *len = 0;
+    return 0;
+}
+
+/*-
+ * for these 2 messages, we need to
+ * ssl->enc_read_ctx                    re-init
+ * ssl->rlayer.read_sequence            zero
+ * ssl->s3->read_mac_secret             re-init
+ * ssl->session->read_sym_enc           assign
+ * ssl->session->read_compression       assign
+ * ssl->session->read_hash              assign
+ */
+int dtls_construct_change_cipher_spec(SSL *s, WPACKET *pkt)
+{
+    if (s->version == DTLS1_BAD_VER) {
+        s->d1->next_handshake_write_seq++;
+
+        if (!WPACKET_put_bytes_u16(pkt, s->d1->handshake_write_seq)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_DTLS_CONSTRUCT_CHANGE_CIPHER_SPEC,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SCTP
+/*
+ * Wait for a dry event. Should only be called at a point in the handshake
+ * where we are not expecting any data from the peer except an alert.
+ */
+WORK_STATE dtls_wait_for_dry(SSL *s)
+{
+    int ret, errtype;
+    size_t len;
+
+    /* read app data until dry event */
+    ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
+    if (ret < 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS_WAIT_FOR_DRY,
+                 ERR_R_INTERNAL_ERROR);
+        return WORK_ERROR;
+    }
+
+    if (ret == 0) {
+        /*
+         * We're not expecting any more messages from the peer at this point -
+         * but we could get an alert. If an alert is waiting then we will never
+         * return successfully. Therefore we attempt to read a message. This
+         * should never succeed but will process any waiting alerts.
+         */
+        if (dtls_get_reassembled_message(s, &errtype, &len)) {
+            /* The call succeeded! This should never happen */
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS_WAIT_FOR_DRY,
+                     SSL_R_UNEXPECTED_MESSAGE);
+            return WORK_ERROR;
+        }
+
+        s->s3->in_read_app_data = 2;
+        s->rwstate = SSL_READING;
+        BIO_clear_retry_flags(SSL_get_rbio(s));
+        BIO_set_retry_read(SSL_get_rbio(s));
+        return WORK_MORE_A;
+    }
+    return WORK_FINISHED_CONTINUE;
+}
+#endif
+
+int dtls1_read_failed(SSL *s, int code)
+{
+    if (code > 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_DTLS1_READ_FAILED, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (!dtls1_is_timer_expired(s) || ossl_statem_in_error(s)) {
+        /*
+         * not a timeout, none of our business, let higher layers handle
+         * this.  in fact it's probably an error
+         */
+        return code;
+    }
+    /* done, no need to send a retransmit */
+    if (!SSL_in_init(s))
+    {
+        BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ);
+        return code;
+    }
+
+    return dtls1_handle_timeout(s);
+}
+
+int dtls1_get_queue_priority(unsigned short seq, int is_ccs)
+{
+    /*
+     * The index of the retransmission queue actually is the message sequence
+     * number, since the queue only contains messages of a single handshake.
+     * However, the ChangeCipherSpec has no message sequence number and so
+     * using only the sequence will result in the CCS and Finished having the
+     * same index. To prevent this, the sequence number is multiplied by 2.
+     * In case of a CCS 1 is subtracted. This does not only differ CSS and
+     * Finished, it also maintains the order of the index (important for
+     * priority queues) and fits in the unsigned short variable.
+     */
+    return seq * 2 - is_ccs;
+}
+
+int dtls1_retransmit_buffered_messages(SSL *s)
+{
+    pqueue *sent = s->d1->sent_messages;
+    piterator iter;
+    pitem *item;
+    hm_fragment *frag;
+    int found = 0;
+
+    iter = pqueue_iterator(sent);
+
+    for (item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter)) {
+        frag = (hm_fragment *)item->data;
+        if (dtls1_retransmit_message(s, (unsigned short)
+                                     dtls1_get_queue_priority
+                                     (frag->msg_header.seq,
+                                      frag->msg_header.is_ccs), &found) <= 0)
+            return -1;
+    }
+
+    return 1;
+}
+
+int dtls1_buffer_message(SSL *s, int is_ccs)
+{
+    pitem *item;
+    hm_fragment *frag;
+    unsigned char seq64be[8];
+
+    /*
+     * this function is called immediately after a message has been
+     * serialized
+     */
+    if (!ossl_assert(s->init_off == 0))
+        return 0;
+
+    frag = dtls1_hm_fragment_new(s->init_num, 0);
+    if (frag == NULL)
+        return 0;
+
+    memcpy(frag->fragment, s->init_buf->data, s->init_num);
+
+    if (is_ccs) {
+        /* For DTLS1_BAD_VER the header length is non-standard */
+        if (!ossl_assert(s->d1->w_msg_hdr.msg_len +
+                         ((s->version ==
+                           DTLS1_BAD_VER) ? 3 : DTLS1_CCS_HEADER_LENGTH)
+                         == (unsigned int)s->init_num))
+            return 0;
+    } else {
+        if (!ossl_assert(s->d1->w_msg_hdr.msg_len +
+                         DTLS1_HM_HEADER_LENGTH == (unsigned int)s->init_num))
+            return 0;
+    }
+
+    frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len;
+    frag->msg_header.seq = s->d1->w_msg_hdr.seq;
+    frag->msg_header.type = s->d1->w_msg_hdr.type;
+    frag->msg_header.frag_off = 0;
+    frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len;
+    frag->msg_header.is_ccs = is_ccs;
+
+    /* save current state */
+    frag->msg_header.saved_retransmit_state.enc_write_ctx = s->enc_write_ctx;
+    frag->msg_header.saved_retransmit_state.write_hash = s->write_hash;
+    frag->msg_header.saved_retransmit_state.compress = s->compress;
+    frag->msg_header.saved_retransmit_state.session = s->session;
+    frag->msg_header.saved_retransmit_state.epoch =
+        DTLS_RECORD_LAYER_get_w_epoch(&s->rlayer);
+
+    memset(seq64be, 0, sizeof(seq64be));
+    seq64be[6] =
+        (unsigned
+         char)(dtls1_get_queue_priority(frag->msg_header.seq,
+                                        frag->msg_header.is_ccs) >> 8);
+    seq64be[7] =
+        (unsigned
+         char)(dtls1_get_queue_priority(frag->msg_header.seq,
+                                        frag->msg_header.is_ccs));
+
+    item = pitem_new(seq64be, frag);
+    if (item == NULL) {
+        dtls1_hm_fragment_free(frag);
+        return 0;
+    }
+
+    pqueue_insert(s->d1->sent_messages, item);
+    return 1;
+}
+
+int dtls1_retransmit_message(SSL *s, unsigned short seq, int *found)
+{
+    int ret;
+    /* XDTLS: for now assuming that read/writes are blocking */
+    pitem *item;
+    hm_fragment *frag;
+    unsigned long header_length;
+    unsigned char seq64be[8];
+    struct dtls1_retransmit_state saved_state;
+
+    /* XDTLS:  the requested message ought to be found, otherwise error */
+    memset(seq64be, 0, sizeof(seq64be));
+    seq64be[6] = (unsigned char)(seq >> 8);
+    seq64be[7] = (unsigned char)seq;
+
+    item = pqueue_find(s->d1->sent_messages, seq64be);
+    if (item == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS1_RETRANSMIT_MESSAGE,
+                 ERR_R_INTERNAL_ERROR);
+        *found = 0;
+        return 0;
+    }
+
+    *found = 1;
+    frag = (hm_fragment *)item->data;
+
+    if (frag->msg_header.is_ccs)
+        header_length = DTLS1_CCS_HEADER_LENGTH;
+    else
+        header_length = DTLS1_HM_HEADER_LENGTH;
+
+    memcpy(s->init_buf->data, frag->fragment,
+           frag->msg_header.msg_len + header_length);
+    s->init_num = frag->msg_header.msg_len + header_length;
+
+    dtls1_set_message_header_int(s, frag->msg_header.type,
+                                 frag->msg_header.msg_len,
+                                 frag->msg_header.seq, 0,
+                                 frag->msg_header.frag_len);
+
+    /* save current state */
+    saved_state.enc_write_ctx = s->enc_write_ctx;
+    saved_state.write_hash = s->write_hash;
+    saved_state.compress = s->compress;
+    saved_state.session = s->session;
+    saved_state.epoch = DTLS_RECORD_LAYER_get_w_epoch(&s->rlayer);
+
+    s->d1->retransmitting = 1;
+
+    /* restore state in which the message was originally sent */
+    s->enc_write_ctx = frag->msg_header.saved_retransmit_state.enc_write_ctx;
+    s->write_hash = frag->msg_header.saved_retransmit_state.write_hash;
+    s->compress = frag->msg_header.saved_retransmit_state.compress;
+    s->session = frag->msg_header.saved_retransmit_state.session;
+    DTLS_RECORD_LAYER_set_saved_w_epoch(&s->rlayer,
+                                        frag->msg_header.
+                                        saved_retransmit_state.epoch);
+
+    ret = dtls1_do_write(s, frag->msg_header.is_ccs ?
+                         SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE);
+
+    /* restore current state */
+    s->enc_write_ctx = saved_state.enc_write_ctx;
+    s->write_hash = saved_state.write_hash;
+    s->compress = saved_state.compress;
+    s->session = saved_state.session;
+    DTLS_RECORD_LAYER_set_saved_w_epoch(&s->rlayer, saved_state.epoch);
+
+    s->d1->retransmitting = 0;
+
+    (void)BIO_flush(s->wbio);
+    return ret;
+}
+
+void dtls1_set_message_header(SSL *s,
+                              unsigned char mt, size_t len,
+                              size_t frag_off, size_t frag_len)
+{
+    if (frag_off == 0) {
+        s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
+        s->d1->next_handshake_write_seq++;
+    }
+
+    dtls1_set_message_header_int(s, mt, len, s->d1->handshake_write_seq,
+                                 frag_off, frag_len);
+}
+
+/* don't actually do the writing, wait till the MTU has been retrieved */
+static void
+dtls1_set_message_header_int(SSL *s, unsigned char mt,
+                             size_t len, unsigned short seq_num,
+                             size_t frag_off, size_t frag_len)
+{
+    struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+
+    msg_hdr->type = mt;
+    msg_hdr->msg_len = len;
+    msg_hdr->seq = seq_num;
+    msg_hdr->frag_off = frag_off;
+    msg_hdr->frag_len = frag_len;
+}
+
+static void
+dtls1_fix_message_header(SSL *s, size_t frag_off, size_t frag_len)
+{
+    struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+
+    msg_hdr->frag_off = frag_off;
+    msg_hdr->frag_len = frag_len;
+}
+
+static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p)
+{
+    struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+
+    *p++ = msg_hdr->type;
+    l2n3(msg_hdr->msg_len, p);
+
+    s2n(msg_hdr->seq, p);
+    l2n3(msg_hdr->frag_off, p);
+    l2n3(msg_hdr->frag_len, p);
+
+    return p;
+}
+
+void dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr)
+{
+    memset(msg_hdr, 0, sizeof(*msg_hdr));
+    msg_hdr->type = *(data++);
+    n2l3(data, msg_hdr->msg_len);
+
+    n2s(data, msg_hdr->seq);
+    n2l3(data, msg_hdr->frag_off);
+    n2l3(data, msg_hdr->frag_len);
+}
+
+int dtls1_set_handshake_header(SSL *s, WPACKET *pkt, int htype)
+{
+    unsigned char *header;
+
+    if (htype == SSL3_MT_CHANGE_CIPHER_SPEC) {
+        s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
+        dtls1_set_message_header_int(s, SSL3_MT_CCS, 0,
+                                     s->d1->handshake_write_seq, 0, 0);
+        if (!WPACKET_put_bytes_u8(pkt, SSL3_MT_CCS))
+            return 0;
+    } else {
+        dtls1_set_message_header(s, htype, 0, 0, 0);
+        /*
+         * We allocate space at the start for the message header. This gets
+         * filled in later
+         */
+        if (!WPACKET_allocate_bytes(pkt, DTLS1_HM_HEADER_LENGTH, &header)
+                || !WPACKET_start_sub_packet(pkt))
+            return 0;
+    }
+
+    return 1;
+}
+
+int dtls1_close_construct_packet(SSL *s, WPACKET *pkt, int htype)
+{
+    size_t msglen;
+
+    if ((htype != SSL3_MT_CHANGE_CIPHER_SPEC && !WPACKET_close(pkt))
+            || !WPACKET_get_length(pkt, &msglen)
+            || msglen > INT_MAX)
+        return 0;
+
+    if (htype != SSL3_MT_CHANGE_CIPHER_SPEC) {
+        s->d1->w_msg_hdr.msg_len = msglen - DTLS1_HM_HEADER_LENGTH;
+        s->d1->w_msg_hdr.frag_len = msglen - DTLS1_HM_HEADER_LENGTH;
+    }
+    s->init_num = (int)msglen;
+    s->init_off = 0;
+
+    if (htype != DTLS1_MT_HELLO_VERIFY_REQUEST) {
+        /* Buffer the message to handle re-xmits */
+        if (!dtls1_buffer_message(s, htype == SSL3_MT_CHANGE_CIPHER_SPEC
+                                     ? 1 : 0))
+            return 0;
+    }
+
+    return 1;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_lib.c b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_lib.c
new file mode 100644
index 0000000..695caab
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_lib.c
@@ -0,0 +1,2441 @@
+/*
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include "../ssl_local.h"
+#include "statem_local.h"
+#include "internal/cryptlib.h"
+#include <openssl/buffer.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+/*
+ * Map error codes to TLS/SSL alart types.
+ */
+typedef struct x509err2alert_st {
+    int x509err;
+    int alert;
+} X509ERR2ALERT;
+
+/* Fixed value used in the ServerHello random field to identify an HRR */
+const unsigned char hrrrandom[] = {
+    0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02,
+    0x1e, 0x65, 0xb8, 0x91, 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e,
+    0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c
+};
+
+/*
+ * send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or
+ * SSL3_RT_CHANGE_CIPHER_SPEC)
+ */
+int ssl3_do_write(SSL *s, int type)
+{
+    int ret;
+    size_t written = 0;
+
+    ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off],
+                           s->init_num, &written);
+    if (ret < 0)
+        return -1;
+    if (type == SSL3_RT_HANDSHAKE)
+        /*
+         * should not be done for 'Hello Request's, but in that case we'll
+         * ignore the result anyway
+         * TLS1.3 KeyUpdate and NewSessionTicket do not need to be added
+         */
+        if (!SSL_IS_TLS13(s) || (s->statem.hand_state != TLS_ST_SW_SESSION_TICKET
+                                 && s->statem.hand_state != TLS_ST_CW_KEY_UPDATE
+                                 && s->statem.hand_state != TLS_ST_SW_KEY_UPDATE))
+            if (!ssl3_finish_mac(s,
+                                 (unsigned char *)&s->init_buf->data[s->init_off],
+                                 written))
+                return -1;
+    if (written == s->init_num) {
+        if (s->msg_callback)
+            s->msg_callback(1, s->version, type, s->init_buf->data,
+                            (size_t)(s->init_off + s->init_num), s,
+                            s->msg_callback_arg);
+        return 1;
+    }
+    s->init_off += written;
+    s->init_num -= written;
+    return 0;
+}
+
+int tls_close_construct_packet(SSL *s, WPACKET *pkt, int htype)
+{
+    size_t msglen;
+
+    if ((htype != SSL3_MT_CHANGE_CIPHER_SPEC && !WPACKET_close(pkt))
+            || !WPACKET_get_length(pkt, &msglen)
+            || msglen > INT_MAX)
+        return 0;
+    s->init_num = (int)msglen;
+    s->init_off = 0;
+
+    return 1;
+}
+
+int tls_setup_handshake(SSL *s)
+{
+    if (!ssl3_init_finished_mac(s)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    /* Reset any extension flags */
+    memset(s->ext.extflags, 0, sizeof(s->ext.extflags));
+
+    if (s->server) {
+        STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(s);
+        int i, ver_min, ver_max, ok = 0;
+
+        /*
+         * Sanity check that the maximum version we accept has ciphers
+         * enabled. For clients we do this check during construction of the
+         * ClientHello.
+         */
+        if (ssl_get_min_max_version(s, &ver_min, &ver_max, NULL) != 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_SETUP_HANDSHAKE,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
+            const SSL_CIPHER *c = sk_SSL_CIPHER_value(ciphers, i);
+
+            if (SSL_IS_DTLS(s)) {
+                if (DTLS_VERSION_GE(ver_max, c->min_dtls) &&
+                        DTLS_VERSION_LE(ver_max, c->max_dtls))
+                    ok = 1;
+            } else if (ver_max >= c->min_tls && ver_max <= c->max_tls) {
+                ok = 1;
+            }
+            if (ok)
+                break;
+        }
+        if (!ok) {
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS_SETUP_HANDSHAKE,
+                     SSL_R_NO_CIPHERS_AVAILABLE);
+            ERR_add_error_data(1, "No ciphers enabled for max supported "
+                                  "SSL/TLS version");
+            return 0;
+        }
+        if (SSL_IS_FIRST_HANDSHAKE(s)) {
+            /* N.B. s->session_ctx == s->ctx here */
+            tsan_counter(&s->session_ctx->stats.sess_accept);
+        } else {
+            /* N.B. s->ctx may not equal s->session_ctx */
+            tsan_counter(&s->ctx->stats.sess_accept_renegotiate);
+
+            s->s3->tmp.cert_request = 0;
+        }
+    } else {
+        if (SSL_IS_FIRST_HANDSHAKE(s))
+            tsan_counter(&s->session_ctx->stats.sess_connect);
+        else
+            tsan_counter(&s->session_ctx->stats.sess_connect_renegotiate);
+
+        /* mark client_random uninitialized */
+        memset(s->s3->client_random, 0, sizeof(s->s3->client_random));
+        s->hit = 0;
+
+        s->s3->tmp.cert_req = 0;
+
+        if (SSL_IS_DTLS(s))
+            s->statem.use_timer = 1;
+    }
+
+    return 1;
+}
+
+/*
+ * Size of the to-be-signed TLS13 data, without the hash size itself:
+ * 64 bytes of value 32, 33 context bytes, 1 byte separator
+ */
+#define TLS13_TBS_START_SIZE            64
+#define TLS13_TBS_PREAMBLE_SIZE         (TLS13_TBS_START_SIZE + 33 + 1)
+
+static int get_cert_verify_tbs_data(SSL *s, unsigned char *tls13tbs,
+                                    void **hdata, size_t *hdatalen)
+{
+#ifdef CHARSET_EBCDIC
+    static const char servercontext[] = { 0x54, 0x4c, 0x53, 0x20, 0x31, 0x2e,
+     0x33, 0x2c, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x65,
+     0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72,
+     0x69, 0x66, 0x79, 0x00 };
+    static const char clientcontext[] = { 0x54, 0x4c, 0x53, 0x20, 0x31, 0x2e,
+     0x33, 0x2c, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x43, 0x65,
+     0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72,
+     0x69, 0x66, 0x79, 0x00 };
+#else
+    static const char servercontext[] = "TLS 1.3, server CertificateVerify";
+    static const char clientcontext[] = "TLS 1.3, client CertificateVerify";
+#endif
+    if (SSL_IS_TLS13(s)) {
+        size_t hashlen;
+
+        /* Set the first 64 bytes of to-be-signed data to octet 32 */
+        memset(tls13tbs, 32, TLS13_TBS_START_SIZE);
+        /* This copies the 33 bytes of context plus the 0 separator byte */
+        if (s->statem.hand_state == TLS_ST_CR_CERT_VRFY
+                 || s->statem.hand_state == TLS_ST_SW_CERT_VRFY)
+            strcpy((char *)tls13tbs + TLS13_TBS_START_SIZE, servercontext);
+        else
+            strcpy((char *)tls13tbs + TLS13_TBS_START_SIZE, clientcontext);
+
+        /*
+         * If we're currently reading then we need to use the saved handshake
+         * hash value. We can't use the current handshake hash state because
+         * that includes the CertVerify itself.
+         */
+        if (s->statem.hand_state == TLS_ST_CR_CERT_VRFY
+                || s->statem.hand_state == TLS_ST_SR_CERT_VRFY) {
+            memcpy(tls13tbs + TLS13_TBS_PREAMBLE_SIZE, s->cert_verify_hash,
+                   s->cert_verify_hash_len);
+            hashlen = s->cert_verify_hash_len;
+        } else if (!ssl_handshake_hash(s, tls13tbs + TLS13_TBS_PREAMBLE_SIZE,
+                                       EVP_MAX_MD_SIZE, &hashlen)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+
+        *hdata = tls13tbs;
+        *hdatalen = TLS13_TBS_PREAMBLE_SIZE + hashlen;
+    } else {
+        size_t retlen;
+        long retlen_l;
+
+        retlen = retlen_l = BIO_get_mem_data(s->s3->handshake_buffer, hdata);
+        if (retlen_l <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_GET_CERT_VERIFY_TBS_DATA,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        *hdatalen = retlen;
+    }
+
+    return 1;
+}
+
+int tls_construct_cert_verify(SSL *s, WPACKET *pkt)
+{
+    EVP_PKEY *pkey = NULL;
+    const EVP_MD *md = NULL;
+    EVP_MD_CTX *mctx = NULL;
+    EVP_PKEY_CTX *pctx = NULL;
+    size_t hdatalen = 0, siglen = 0;
+    void *hdata;
+    unsigned char *sig = NULL;
+    unsigned char tls13tbs[TLS13_TBS_PREAMBLE_SIZE + EVP_MAX_MD_SIZE];
+    const SIGALG_LOOKUP *lu = s->s3->tmp.sigalg;
+
+    if (lu == NULL || s->s3->tmp.cert == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    pkey = s->s3->tmp.cert->privatekey;
+
+    if (pkey == NULL || !tls1_lookup_md(lu, &md)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    mctx = EVP_MD_CTX_new();
+    if (mctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    /* Get the data to be signed */
+    if (!get_cert_verify_tbs_data(s, tls13tbs, &hdata, &hdatalen)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    if (SSL_USE_SIGALGS(s) && !WPACKET_put_bytes_u16(pkt, lu->sigalg)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    siglen = EVP_PKEY_size(pkey);
+    sig = OPENSSL_malloc(siglen);
+    if (sig == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (EVP_DigestSignInit(mctx, &pctx, md, NULL, pkey) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+
+    if (lu->sig == EVP_PKEY_RSA_PSS) {
+        if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0
+            || EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx,
+                                                RSA_PSS_SALTLEN_DIGEST) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+                     ERR_R_EVP_LIB);
+            goto err;
+        }
+    }
+    if (s->version == SSL3_VERSION) {
+        if (EVP_DigestSignUpdate(mctx, hdata, hdatalen) <= 0
+            || !EVP_MD_CTX_ctrl(mctx, EVP_CTRL_SSL3_MASTER_SECRET,
+                                (int)s->session->master_key_length,
+                                s->session->master_key)
+            || EVP_DigestSignFinal(mctx, sig, &siglen) <= 0) {
+
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+                     ERR_R_EVP_LIB);
+            goto err;
+        }
+    } else if (EVP_DigestSign(mctx, sig, &siglen, hdata, hdatalen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+
+#ifndef OPENSSL_NO_GOST
+    {
+        int pktype = lu->sig;
+
+        if (pktype == NID_id_GostR3410_2001
+            || pktype == NID_id_GostR3410_2012_256
+            || pktype == NID_id_GostR3410_2012_512)
+            BUF_reverse(sig, NULL, siglen);
+    }
+#endif
+
+    if (!WPACKET_sub_memcpy_u16(pkt, sig, siglen)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /* Digest cached records and discard handshake buffer */
+    if (!ssl3_digest_cached_records(s, 0)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    OPENSSL_free(sig);
+    EVP_MD_CTX_free(mctx);
+    return 1;
+ err:
+    OPENSSL_free(sig);
+    EVP_MD_CTX_free(mctx);
+    return 0;
+}
+
+MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
+{
+    EVP_PKEY *pkey = NULL;
+    const unsigned char *data;
+#ifndef OPENSSL_NO_GOST
+    unsigned char *gost_data = NULL;
+#endif
+    MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR;
+    int j;
+    unsigned int len;
+    X509 *peer;
+    const EVP_MD *md = NULL;
+    size_t hdatalen = 0;
+    void *hdata;
+    unsigned char tls13tbs[TLS13_TBS_PREAMBLE_SIZE + EVP_MAX_MD_SIZE];
+    EVP_MD_CTX *mctx = EVP_MD_CTX_new();
+    EVP_PKEY_CTX *pctx = NULL;
+
+    if (mctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    peer = s->session->peer;
+    pkey = X509_get0_pubkey(peer);
+    if (pkey == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (ssl_cert_lookup_by_pkey(pkey, NULL) == NULL) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                 SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE);
+        goto err;
+    }
+
+    if (SSL_USE_SIGALGS(s)) {
+        unsigned int sigalg;
+
+        if (!PACKET_get_net_2(pkt, &sigalg)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                     SSL_R_BAD_PACKET);
+            goto err;
+        }
+        if (tls12_check_peer_sigalg(s, sigalg, pkey) <= 0) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else if (!tls1_set_peer_legacy_sigalg(s, pkey)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+    }
+
+    if (!tls1_lookup_md(s->s3->tmp.peer_sigalg, &md)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+#ifdef SSL_DEBUG
+    if (SSL_USE_SIGALGS(s))
+        fprintf(stderr, "USING TLSv1.2 HASH %s\n",
+                md == NULL ? "n/a" : EVP_MD_name(md));
+#endif
+
+    /* Check for broken implementations of GOST ciphersuites */
+    /*
+     * If key is GOST and len is exactly 64 or 128, it is signature without
+     * length field (CryptoPro implementations at least till TLS 1.2)
+     */
+#ifndef OPENSSL_NO_GOST
+    if (!SSL_USE_SIGALGS(s)
+        && ((PACKET_remaining(pkt) == 64
+             && (EVP_PKEY_id(pkey) == NID_id_GostR3410_2001
+                 || EVP_PKEY_id(pkey) == NID_id_GostR3410_2012_256))
+            || (PACKET_remaining(pkt) == 128
+                && EVP_PKEY_id(pkey) == NID_id_GostR3410_2012_512))) {
+        len = PACKET_remaining(pkt);
+    } else
+#endif
+    if (!PACKET_get_net_2(pkt, &len)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                 SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    j = EVP_PKEY_size(pkey);
+    if (((int)len > j) || ((int)PACKET_remaining(pkt) > j)
+        || (PACKET_remaining(pkt) == 0)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                 SSL_R_WRONG_SIGNATURE_SIZE);
+        goto err;
+    }
+    if (!PACKET_get_bytes(pkt, &data, len)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                 SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    if (!get_cert_verify_tbs_data(s, tls13tbs, &hdata, &hdatalen)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+#ifdef SSL_DEBUG
+    fprintf(stderr, "Using client verify alg %s\n",
+            md == NULL ? "n/a" : EVP_MD_name(md));
+#endif
+    if (EVP_DigestVerifyInit(mctx, &pctx, md, NULL, pkey) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+#ifndef OPENSSL_NO_GOST
+    {
+        int pktype = EVP_PKEY_id(pkey);
+        if (pktype == NID_id_GostR3410_2001
+            || pktype == NID_id_GostR3410_2012_256
+            || pktype == NID_id_GostR3410_2012_512) {
+            if ((gost_data = OPENSSL_malloc(len)) == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+            BUF_reverse(gost_data, data, len);
+            data = gost_data;
+        }
+    }
+#endif
+
+    if (SSL_USE_PSS(s)) {
+        if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0
+            || EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx,
+                                                RSA_PSS_SALTLEN_DIGEST) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                     ERR_R_EVP_LIB);
+            goto err;
+        }
+    }
+    if (s->version == SSL3_VERSION) {
+        if (EVP_DigestVerifyUpdate(mctx, hdata, hdatalen) <= 0
+                || !EVP_MD_CTX_ctrl(mctx, EVP_CTRL_SSL3_MASTER_SECRET,
+                                    (int)s->session->master_key_length,
+                                    s->session->master_key)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                     ERR_R_EVP_LIB);
+            goto err;
+        }
+        if (EVP_DigestVerifyFinal(mctx, data, len) <= 0) {
+            SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                     SSL_R_BAD_SIGNATURE);
+            goto err;
+        }
+    } else {
+        j = EVP_DigestVerify(mctx, data, len, hdata, hdatalen);
+        if (j <= 0) {
+            SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                     SSL_R_BAD_SIGNATURE);
+            goto err;
+        }
+    }
+
+    /*
+     * In TLSv1.3 on the client side we make sure we prepare the client
+     * certificate after the CertVerify instead of when we get the
+     * CertificateRequest. This is because in TLSv1.3 the CertificateRequest
+     * comes *before* the Certificate message. In TLSv1.2 it comes after. We
+     * want to make sure that SSL_get_peer_certificate() will return the actual
+     * server certificate from the client_cert_cb callback.
+     */
+    if (!s->server && SSL_IS_TLS13(s) && s->s3->tmp.cert_req == 1)
+        ret = MSG_PROCESS_CONTINUE_PROCESSING;
+    else
+        ret = MSG_PROCESS_CONTINUE_READING;
+ err:
+    BIO_free(s->s3->handshake_buffer);
+    s->s3->handshake_buffer = NULL;
+    EVP_MD_CTX_free(mctx);
+#ifndef OPENSSL_NO_GOST
+    OPENSSL_free(gost_data);
+#endif
+    return ret;
+}
+
+int tls_construct_finished(SSL *s, WPACKET *pkt)
+{
+    size_t finish_md_len;
+    const char *sender;
+    size_t slen;
+
+    /* This is a real handshake so make sure we clean it up at the end */
+    if (!s->server && s->post_handshake_auth != SSL_PHA_REQUESTED)
+        s->statem.cleanuphand = 1;
+
+    /*
+     * We only change the keys if we didn't already do this when we sent the
+     * client certificate
+     */
+    if (SSL_IS_TLS13(s)
+            && !s->server
+            && s->s3->tmp.cert_req == 0
+            && (!s->method->ssl3_enc->change_cipher_state(s,
+                    SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_CLIENT_WRITE))) {;
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    if (s->server) {
+        sender = s->method->ssl3_enc->server_finished_label;
+        slen = s->method->ssl3_enc->server_finished_label_len;
+    } else {
+        sender = s->method->ssl3_enc->client_finished_label;
+        slen = s->method->ssl3_enc->client_finished_label_len;
+    }
+
+    finish_md_len = s->method->ssl3_enc->final_finish_mac(s,
+                                                          sender, slen,
+                                                          s->s3->tmp.finish_md);
+    if (finish_md_len == 0) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    s->s3->tmp.finish_md_len = finish_md_len;
+
+    if (!WPACKET_memcpy(pkt, s->s3->tmp.finish_md, finish_md_len)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_FINISHED,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /*
+     * Log the master secret, if logging is enabled. We don't log it for
+     * TLSv1.3: there's a different key schedule for that.
+     */
+    if (!SSL_IS_TLS13(s) && !ssl_log_secret(s, MASTER_SECRET_LABEL,
+                                            s->session->master_key,
+                                            s->session->master_key_length)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    /*
+     * Copy the finished so we can use it for renegotiation checks
+     */
+    if (!ossl_assert(finish_md_len <= EVP_MAX_MD_SIZE)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_FINISHED,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    if (!s->server) {
+        memcpy(s->s3->previous_client_finished, s->s3->tmp.finish_md,
+               finish_md_len);
+        s->s3->previous_client_finished_len = finish_md_len;
+    } else {
+        memcpy(s->s3->previous_server_finished, s->s3->tmp.finish_md,
+               finish_md_len);
+        s->s3->previous_server_finished_len = finish_md_len;
+    }
+
+    return 1;
+}
+
+int tls_construct_key_update(SSL *s, WPACKET *pkt)
+{
+    if (!WPACKET_put_bytes_u8(pkt, s->key_update)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_KEY_UPDATE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    s->key_update = SSL_KEY_UPDATE_NONE;
+    return 1;
+}
+
+MSG_PROCESS_RETURN tls_process_key_update(SSL *s, PACKET *pkt)
+{
+    unsigned int updatetype;
+
+    /*
+     * A KeyUpdate message signals a key change so the end of the message must
+     * be on a record boundary.
+     */
+    if (RECORD_LAYER_processed_read_pending(&s->rlayer)) {
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_TLS_PROCESS_KEY_UPDATE,
+                 SSL_R_NOT_ON_RECORD_BOUNDARY);
+        return MSG_PROCESS_ERROR;
+    }
+
+    if (!PACKET_get_1(pkt, &updatetype)
+            || PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_KEY_UPDATE,
+                 SSL_R_BAD_KEY_UPDATE);
+        return MSG_PROCESS_ERROR;
+    }
+
+    /*
+     * There are only two defined key update types. Fail if we get a value we
+     * didn't recognise.
+     */
+    if (updatetype != SSL_KEY_UPDATE_NOT_REQUESTED
+            && updatetype != SSL_KEY_UPDATE_REQUESTED) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_KEY_UPDATE,
+                 SSL_R_BAD_KEY_UPDATE);
+        return MSG_PROCESS_ERROR;
+    }
+
+    /*
+     * If we get a request for us to update our sending keys too then, we need
+     * to additionally send a KeyUpdate message. However that message should
+     * not also request an update (otherwise we get into an infinite loop).
+     */
+    if (updatetype == SSL_KEY_UPDATE_REQUESTED)
+        s->key_update = SSL_KEY_UPDATE_NOT_REQUESTED;
+
+    if (!tls13_update_key(s, 0)) {
+        /* SSLfatal() already called */
+        return MSG_PROCESS_ERROR;
+    }
+
+    return MSG_PROCESS_FINISHED_READING;
+}
+
+/*
+ * ssl3_take_mac calculates the Finished MAC for the handshakes messages seen
+ * to far.
+ */
+int ssl3_take_mac(SSL *s)
+{
+    const char *sender;
+    size_t slen;
+
+    if (!s->server) {
+        sender = s->method->ssl3_enc->server_finished_label;
+        slen = s->method->ssl3_enc->server_finished_label_len;
+    } else {
+        sender = s->method->ssl3_enc->client_finished_label;
+        slen = s->method->ssl3_enc->client_finished_label_len;
+    }
+
+    s->s3->tmp.peer_finish_md_len =
+        s->method->ssl3_enc->final_finish_mac(s, sender, slen,
+                                              s->s3->tmp.peer_finish_md);
+
+    if (s->s3->tmp.peer_finish_md_len == 0) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    return 1;
+}
+
+MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, PACKET *pkt)
+{
+    size_t remain;
+
+    remain = PACKET_remaining(pkt);
+    /*
+     * 'Change Cipher Spec' is just a single byte, which should already have
+     * been consumed by ssl_get_message() so there should be no bytes left,
+     * unless we're using DTLS1_BAD_VER, which has an extra 2 bytes
+     */
+    if (SSL_IS_DTLS(s)) {
+        if ((s->version == DTLS1_BAD_VER
+             && remain != DTLS1_CCS_HEADER_LENGTH + 1)
+            || (s->version != DTLS1_BAD_VER
+                && remain != DTLS1_CCS_HEADER_LENGTH - 1)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC,
+                    SSL_R_BAD_CHANGE_CIPHER_SPEC);
+            return MSG_PROCESS_ERROR;
+        }
+    } else {
+        if (remain != 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC,
+                     SSL_R_BAD_CHANGE_CIPHER_SPEC);
+            return MSG_PROCESS_ERROR;
+        }
+    }
+
+    /* Check we have a cipher to change to */
+    if (s->s3->tmp.new_cipher == NULL) {
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+                 SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC, SSL_R_CCS_RECEIVED_EARLY);
+        return MSG_PROCESS_ERROR;
+    }
+
+    s->s3->change_cipher_spec = 1;
+    if (!ssl3_do_change_cipher_spec(s)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC,
+                 ERR_R_INTERNAL_ERROR);
+        return MSG_PROCESS_ERROR;
+    }
+
+    if (SSL_IS_DTLS(s)) {
+        dtls1_reset_seq_numbers(s, SSL3_CC_READ);
+
+        if (s->version == DTLS1_BAD_VER)
+            s->d1->handshake_read_seq++;
+
+#ifndef OPENSSL_NO_SCTP
+        /*
+         * Remember that a CCS has been received, so that an old key of
+         * SCTP-Auth can be deleted when a CCS is sent. Will be ignored if no
+         * SCTP is used
+         */
+        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD, 1, NULL);
+#endif
+    }
+
+    return MSG_PROCESS_CONTINUE_READING;
+}
+
+MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt)
+{
+    size_t md_len;
+
+
+    /* This is a real handshake so make sure we clean it up at the end */
+    if (s->server) {
+        /*
+        * To get this far we must have read encrypted data from the client. We
+        * no longer tolerate unencrypted alerts. This value is ignored if less
+        * than TLSv1.3
+        */
+        s->statem.enc_read_state = ENC_READ_STATE_VALID;
+        if (s->post_handshake_auth != SSL_PHA_REQUESTED)
+            s->statem.cleanuphand = 1;
+        if (SSL_IS_TLS13(s) && !tls13_save_handshake_digest_for_pha(s)) {
+                /* SSLfatal() already called */
+                return MSG_PROCESS_ERROR;
+        }
+    }
+
+    /*
+     * In TLSv1.3 a Finished message signals a key change so the end of the
+     * message must be on a record boundary.
+     */
+    if (SSL_IS_TLS13(s) && RECORD_LAYER_processed_read_pending(&s->rlayer)) {
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_TLS_PROCESS_FINISHED,
+                 SSL_R_NOT_ON_RECORD_BOUNDARY);
+        return MSG_PROCESS_ERROR;
+    }
+
+    /* If this occurs, we have missed a message */
+    if (!SSL_IS_TLS13(s) && !s->s3->change_cipher_spec) {
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_TLS_PROCESS_FINISHED,
+                 SSL_R_GOT_A_FIN_BEFORE_A_CCS);
+        return MSG_PROCESS_ERROR;
+    }
+    s->s3->change_cipher_spec = 0;
+
+    md_len = s->s3->tmp.peer_finish_md_len;
+
+    if (md_len != PACKET_remaining(pkt)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_FINISHED,
+                 SSL_R_BAD_DIGEST_LENGTH);
+        return MSG_PROCESS_ERROR;
+    }
+
+    if (CRYPTO_memcmp(PACKET_data(pkt), s->s3->tmp.peer_finish_md,
+                      md_len) != 0) {
+        SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_F_TLS_PROCESS_FINISHED,
+                 SSL_R_DIGEST_CHECK_FAILED);
+        return MSG_PROCESS_ERROR;
+    }
+
+    /*
+     * Copy the finished so we can use it for renegotiation checks
+     */
+    if (!ossl_assert(md_len <= EVP_MAX_MD_SIZE)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_FINISHED,
+                 ERR_R_INTERNAL_ERROR);
+        return MSG_PROCESS_ERROR;
+    }
+    if (s->server) {
+        memcpy(s->s3->previous_client_finished, s->s3->tmp.peer_finish_md,
+               md_len);
+        s->s3->previous_client_finished_len = md_len;
+    } else {
+        memcpy(s->s3->previous_server_finished, s->s3->tmp.peer_finish_md,
+               md_len);
+        s->s3->previous_server_finished_len = md_len;
+    }
+
+    /*
+     * In TLS1.3 we also have to change cipher state and do any final processing
+     * of the initial server flight (if we are a client)
+     */
+    if (SSL_IS_TLS13(s)) {
+        if (s->server) {
+            if (s->post_handshake_auth != SSL_PHA_REQUESTED &&
+                    !s->method->ssl3_enc->change_cipher_state(s,
+                    SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_SERVER_READ)) {
+                /* SSLfatal() already called */
+                return MSG_PROCESS_ERROR;
+            }
+        } else {
+            /* TLS 1.3 gets the secret size from the handshake md */
+            size_t dummy;
+            if (!s->method->ssl3_enc->generate_master_secret(s,
+                    s->master_secret, s->handshake_secret, 0,
+                    &dummy)) {
+                /* SSLfatal() already called */
+                return MSG_PROCESS_ERROR;
+            }
+            if (!s->method->ssl3_enc->change_cipher_state(s,
+                    SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_CLIENT_READ)) {
+                /* SSLfatal() already called */
+                return MSG_PROCESS_ERROR;
+            }
+            if (!tls_process_initial_server_flight(s)) {
+                /* SSLfatal() already called */
+                return MSG_PROCESS_ERROR;
+            }
+        }
+    }
+
+    return MSG_PROCESS_FINISHED_READING;
+}
+
+int tls_construct_change_cipher_spec(SSL *s, WPACKET *pkt)
+{
+    if (!WPACKET_put_bytes_u8(pkt, SSL3_MT_CCS)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+/* Add a certificate to the WPACKET */
+static int ssl_add_cert_to_wpacket(SSL *s, WPACKET *pkt, X509 *x, int chain)
+{
+    int len;
+    unsigned char *outbytes;
+
+    len = i2d_X509(x, NULL);
+    if (len < 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ADD_CERT_TO_WPACKET,
+                 ERR_R_BUF_LIB);
+        return 0;
+    }
+    if (!WPACKET_sub_allocate_bytes_u24(pkt, len, &outbytes)
+            || i2d_X509(x, &outbytes) != len) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ADD_CERT_TO_WPACKET,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (SSL_IS_TLS13(s)
+            && !tls_construct_extensions(s, pkt, SSL_EXT_TLS1_3_CERTIFICATE, x,
+                                         chain)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    return 1;
+}
+
+/* Add certificate chain to provided WPACKET */
+static int ssl_add_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk)
+{
+    int i, chain_count;
+    X509 *x;
+    STACK_OF(X509) *extra_certs;
+    STACK_OF(X509) *chain = NULL;
+    X509_STORE *chain_store;
+
+    if (cpk == NULL || cpk->x509 == NULL)
+        return 1;
+
+    x = cpk->x509;
+
+    /*
+     * If we have a certificate specific chain use it, else use parent ctx.
+     */
+    if (cpk->chain != NULL)
+        extra_certs = cpk->chain;
+    else
+        extra_certs = s->ctx->extra_certs;
+
+    if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || extra_certs)
+        chain_store = NULL;
+    else if (s->cert->chain_store)
+        chain_store = s->cert->chain_store;
+    else
+        chain_store = s->ctx->cert_store;
+
+    if (chain_store != NULL) {
+        X509_STORE_CTX *xs_ctx = X509_STORE_CTX_new();
+
+        if (xs_ctx == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ADD_CERT_CHAIN,
+                     ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        if (!X509_STORE_CTX_init(xs_ctx, chain_store, x, NULL)) {
+            X509_STORE_CTX_free(xs_ctx);
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ADD_CERT_CHAIN,
+                     ERR_R_X509_LIB);
+            return 0;
+        }
+        /*
+         * It is valid for the chain not to be complete (because normally we
+         * don't include the root cert in the chain). Therefore we deliberately
+         * ignore the error return from this call. We're not actually verifying
+         * the cert - we're just building as much of the chain as we can
+         */
+        (void)X509_verify_cert(xs_ctx);
+        /* Don't leave errors in the queue */
+        ERR_clear_error();
+        chain = X509_STORE_CTX_get0_chain(xs_ctx);
+        i = ssl_security_cert_chain(s, chain, NULL, 0);
+        if (i != 1) {
+#if 0
+            /* Dummy error calls so mkerr generates them */
+            SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, SSL_R_EE_KEY_TOO_SMALL);
+            SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, SSL_R_CA_KEY_TOO_SMALL);
+            SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, SSL_R_CA_MD_TOO_WEAK);
+#endif
+            X509_STORE_CTX_free(xs_ctx);
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ADD_CERT_CHAIN, i);
+            return 0;
+        }
+        chain_count = sk_X509_num(chain);
+        for (i = 0; i < chain_count; i++) {
+            x = sk_X509_value(chain, i);
+
+            if (!ssl_add_cert_to_wpacket(s, pkt, x, i)) {
+                /* SSLfatal() already called */
+                X509_STORE_CTX_free(xs_ctx);
+                return 0;
+            }
+        }
+        X509_STORE_CTX_free(xs_ctx);
+    } else {
+        i = ssl_security_cert_chain(s, extra_certs, x, 0);
+        if (i != 1) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ADD_CERT_CHAIN, i);
+            return 0;
+        }
+        if (!ssl_add_cert_to_wpacket(s, pkt, x, 0)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+        for (i = 0; i < sk_X509_num(extra_certs); i++) {
+            x = sk_X509_value(extra_certs, i);
+            if (!ssl_add_cert_to_wpacket(s, pkt, x, i + 1)) {
+                /* SSLfatal() already called */
+                return 0;
+            }
+        }
+    }
+    return 1;
+}
+
+unsigned long ssl3_output_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk)
+{
+    if (!WPACKET_start_sub_packet_u24(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_OUTPUT_CERT_CHAIN,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (!ssl_add_cert_chain(s, pkt, cpk))
+        return 0;
+
+    if (!WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_OUTPUT_CERT_CHAIN,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+/*
+ * Tidy up after the end of a handshake. In the case of SCTP this may result
+ * in NBIO events. If |clearbufs| is set then init_buf and the wbio buffer is
+ * freed up as well.
+ */
+WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs, int stop)
+{
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
+    int cleanuphand = s->statem.cleanuphand;
+
+    if (clearbufs) {
+        if (!SSL_IS_DTLS(s)
+#ifndef OPENSSL_NO_SCTP
+            /*
+             * RFC6083: SCTP provides a reliable and in-sequence transport service for DTLS
+             * messages that require it. Therefore, DTLS procedures for retransmissions
+             * MUST NOT be used.
+             * Hence the init_buf can be cleared when DTLS over SCTP as transport is used.
+             */
+            || BIO_dgram_is_sctp(SSL_get_wbio(s))
+#endif
+            ) {
+            /*
+             * We don't do this in DTLS over UDP because we may still need the init_buf
+             * in case there are any unexpected retransmits
+             */
+            BUF_MEM_free(s->init_buf);
+            s->init_buf = NULL;
+        }
+
+        if (!ssl_free_wbio_buffer(s)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_FINISH_HANDSHAKE,
+                     ERR_R_INTERNAL_ERROR);
+            return WORK_ERROR;
+        }
+        s->init_num = 0;
+    }
+
+    if (SSL_IS_TLS13(s) && !s->server
+            && s->post_handshake_auth == SSL_PHA_REQUESTED)
+        s->post_handshake_auth = SSL_PHA_EXT_SENT;
+
+    /*
+     * Only set if there was a Finished message and this isn't after a TLSv1.3
+     * post handshake exchange
+     */
+    if (cleanuphand) {
+        /* skipped if we just sent a HelloRequest */
+        s->renegotiate = 0;
+        s->new_session = 0;
+        s->statem.cleanuphand = 0;
+        s->ext.ticket_expected = 0;
+
+        ssl3_cleanup_key_block(s);
+
+        if (s->server) {
+            /*
+             * In TLSv1.3 we update the cache as part of constructing the
+             * NewSessionTicket
+             */
+            if (!SSL_IS_TLS13(s))
+                ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
+
+            /* N.B. s->ctx may not equal s->session_ctx */
+            tsan_counter(&s->ctx->stats.sess_accept_good);
+            s->handshake_func = ossl_statem_accept;
+        } else {
+            if (SSL_IS_TLS13(s)) {
+                /*
+                 * We encourage applications to only use TLSv1.3 tickets once,
+                 * so we remove this one from the cache.
+                 */
+                if ((s->session_ctx->session_cache_mode
+                     & SSL_SESS_CACHE_CLIENT) != 0)
+                    SSL_CTX_remove_session(s->session_ctx, s->session);
+            } else {
+                /*
+                 * In TLSv1.3 we update the cache as part of processing the
+                 * NewSessionTicket
+                 */
+                ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
+            }
+            if (s->hit)
+                tsan_counter(&s->session_ctx->stats.sess_hit);
+
+            s->handshake_func = ossl_statem_connect;
+            tsan_counter(&s->session_ctx->stats.sess_connect_good);
+        }
+
+        if (SSL_IS_DTLS(s)) {
+            /* done with handshaking */
+            s->d1->handshake_read_seq = 0;
+            s->d1->handshake_write_seq = 0;
+            s->d1->next_handshake_write_seq = 0;
+            dtls1_clear_received_buffer(s);
+        }
+    }
+
+    if (s->info_callback != NULL)
+        cb = s->info_callback;
+    else if (s->ctx->info_callback != NULL)
+        cb = s->ctx->info_callback;
+
+    /* The callback may expect us to not be in init at handshake done */
+    ossl_statem_set_in_init(s, 0);
+
+    if (cb != NULL) {
+        if (cleanuphand
+                || !SSL_IS_TLS13(s)
+                || SSL_IS_FIRST_HANDSHAKE(s))
+            cb(s, SSL_CB_HANDSHAKE_DONE, 1);
+    }
+
+    if (!stop) {
+        /* If we've got more work to do we go back into init */
+        ossl_statem_set_in_init(s, 1);
+        return WORK_FINISHED_CONTINUE;
+    }
+
+    return WORK_FINISHED_STOP;
+}
+
+int tls_get_message_header(SSL *s, int *mt)
+{
+    /* s->init_num < SSL3_HM_HEADER_LENGTH */
+    int skip_message, i, recvd_type;
+    unsigned char *p;
+    size_t l, readbytes;
+
+    p = (unsigned char *)s->init_buf->data;
+
+    do {
+        while (s->init_num < SSL3_HM_HEADER_LENGTH) {
+            i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type,
+                                          &p[s->init_num],
+                                          SSL3_HM_HEADER_LENGTH - s->init_num,
+                                          0, &readbytes);
+            if (i <= 0) {
+                s->rwstate = SSL_READING;
+                return 0;
+            }
+            if (recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
+                /*
+                 * A ChangeCipherSpec must be a single byte and may not occur
+                 * in the middle of a handshake message.
+                 */
+                if (s->init_num != 0 || readbytes != 1 || p[0] != SSL3_MT_CCS) {
+                    SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+                             SSL_F_TLS_GET_MESSAGE_HEADER,
+                             SSL_R_BAD_CHANGE_CIPHER_SPEC);
+                    return 0;
+                }
+                if (s->statem.hand_state == TLS_ST_BEFORE
+                        && (s->s3->flags & TLS1_FLAGS_STATELESS) != 0) {
+                    /*
+                     * We are stateless and we received a CCS. Probably this is
+                     * from a client between the first and second ClientHellos.
+                     * We should ignore this, but return an error because we do
+                     * not return success until we see the second ClientHello
+                     * with a valid cookie.
+                     */
+                    return 0;
+                }
+                s->s3->tmp.message_type = *mt = SSL3_MT_CHANGE_CIPHER_SPEC;
+                s->init_num = readbytes - 1;
+                s->init_msg = s->init_buf->data;
+                s->s3->tmp.message_size = readbytes;
+                return 1;
+            } else if (recvd_type != SSL3_RT_HANDSHAKE) {
+                SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+                         SSL_F_TLS_GET_MESSAGE_HEADER,
+                         SSL_R_CCS_RECEIVED_EARLY);
+                return 0;
+            }
+            s->init_num += readbytes;
+        }
+
+        skip_message = 0;
+        if (!s->server)
+            if (s->statem.hand_state != TLS_ST_OK
+                    && p[0] == SSL3_MT_HELLO_REQUEST)
+                /*
+                 * The server may always send 'Hello Request' messages --
+                 * we are doing a handshake anyway now, so ignore them if
+                 * their format is correct. Does not count for 'Finished'
+                 * MAC.
+                 */
+                if (p[1] == 0 && p[2] == 0 && p[3] == 0) {
+                    s->init_num = 0;
+                    skip_message = 1;
+
+                    if (s->msg_callback)
+                        s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+                                        p, SSL3_HM_HEADER_LENGTH, s,
+                                        s->msg_callback_arg);
+                }
+    } while (skip_message);
+    /* s->init_num == SSL3_HM_HEADER_LENGTH */
+
+    *mt = *p;
+    s->s3->tmp.message_type = *(p++);
+
+    if (RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
+        /*
+         * Only happens with SSLv3+ in an SSLv2 backward compatible
+         * ClientHello
+         *
+         * Total message size is the remaining record bytes to read
+         * plus the SSL3_HM_HEADER_LENGTH bytes that we already read
+         */
+        l = RECORD_LAYER_get_rrec_length(&s->rlayer)
+            + SSL3_HM_HEADER_LENGTH;
+        s->s3->tmp.message_size = l;
+
+        s->init_msg = s->init_buf->data;
+        s->init_num = SSL3_HM_HEADER_LENGTH;
+    } else {
+        n2l3(p, l);
+        /* BUF_MEM_grow takes an 'int' parameter */
+        if (l > (INT_MAX - SSL3_HM_HEADER_LENGTH)) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_GET_MESSAGE_HEADER,
+                     SSL_R_EXCESSIVE_MESSAGE_SIZE);
+            return 0;
+        }
+        s->s3->tmp.message_size = l;
+
+        s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH;
+        s->init_num = 0;
+    }
+
+    return 1;
+}
+
+int tls_get_message_body(SSL *s, size_t *len)
+{
+    size_t n, readbytes;
+    unsigned char *p;
+    int i;
+
+    if (s->s3->tmp.message_type == SSL3_MT_CHANGE_CIPHER_SPEC) {
+        /* We've already read everything in */
+        *len = (unsigned long)s->init_num;
+        return 1;
+    }
+
+    p = s->init_msg;
+    n = s->s3->tmp.message_size - s->init_num;
+    while (n > 0) {
+        i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
+                                      &p[s->init_num], n, 0, &readbytes);
+        if (i <= 0) {
+            s->rwstate = SSL_READING;
+            *len = 0;
+            return 0;
+        }
+        s->init_num += readbytes;
+        n -= readbytes;
+    }
+
+    /*
+     * If receiving Finished, record MAC of prior handshake messages for
+     * Finished verification.
+     */
+    if (*(s->init_buf->data) == SSL3_MT_FINISHED && !ssl3_take_mac(s)) {
+        /* SSLfatal() already called */
+        *len = 0;
+        return 0;
+    }
+
+    /* Feed this message into MAC computation. */
+    if (RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
+        if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+                             s->init_num)) {
+            /* SSLfatal() already called */
+            *len = 0;
+            return 0;
+        }
+        if (s->msg_callback)
+            s->msg_callback(0, SSL2_VERSION, 0, s->init_buf->data,
+                            (size_t)s->init_num, s, s->msg_callback_arg);
+    } else {
+        /*
+         * We defer feeding in the HRR until later. We'll do it as part of
+         * processing the message
+         * The TLsv1.3 handshake transcript stops at the ClientFinished
+         * message.
+         */
+#define SERVER_HELLO_RANDOM_OFFSET  (SSL3_HM_HEADER_LENGTH + 2)
+        /* KeyUpdate and NewSessionTicket do not need to be added */
+        if (!SSL_IS_TLS13(s) || (s->s3->tmp.message_type != SSL3_MT_NEWSESSION_TICKET
+                                 && s->s3->tmp.message_type != SSL3_MT_KEY_UPDATE)) {
+            if (s->s3->tmp.message_type != SSL3_MT_SERVER_HELLO
+                    || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE
+                    || memcmp(hrrrandom,
+                              s->init_buf->data + SERVER_HELLO_RANDOM_OFFSET,
+                              SSL3_RANDOM_SIZE) != 0) {
+                if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+                                     s->init_num + SSL3_HM_HEADER_LENGTH)) {
+                    /* SSLfatal() already called */
+                    *len = 0;
+                    return 0;
+                }
+            }
+        }
+        if (s->msg_callback)
+            s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data,
+                            (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, s,
+                            s->msg_callback_arg);
+    }
+
+    *len = s->init_num;
+    return 1;
+}
+
+static const X509ERR2ALERT x509table[] = {
+    {X509_V_ERR_APPLICATION_VERIFICATION, SSL_AD_HANDSHAKE_FAILURE},
+    {X509_V_ERR_CA_KEY_TOO_SMALL, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_EC_KEY_EXPLICIT_PARAMS, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_CA_MD_TOO_WEAK, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_CERT_CHAIN_TOO_LONG, SSL_AD_UNKNOWN_CA},
+    {X509_V_ERR_CERT_HAS_EXPIRED, SSL_AD_CERTIFICATE_EXPIRED},
+    {X509_V_ERR_CERT_NOT_YET_VALID, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_CERT_REJECTED, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_CERT_REVOKED, SSL_AD_CERTIFICATE_REVOKED},
+    {X509_V_ERR_CERT_SIGNATURE_FAILURE, SSL_AD_DECRYPT_ERROR},
+    {X509_V_ERR_CERT_UNTRUSTED, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_CRL_HAS_EXPIRED, SSL_AD_CERTIFICATE_EXPIRED},
+    {X509_V_ERR_CRL_NOT_YET_VALID, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_CRL_SIGNATURE_FAILURE, SSL_AD_DECRYPT_ERROR},
+    {X509_V_ERR_DANE_NO_MATCH, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, SSL_AD_UNKNOWN_CA},
+    {X509_V_ERR_EE_KEY_TOO_SMALL, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_EMAIL_MISMATCH, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_HOSTNAME_MISMATCH, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_INVALID_CA, SSL_AD_UNKNOWN_CA},
+    {X509_V_ERR_INVALID_CALL, SSL_AD_INTERNAL_ERROR},
+    {X509_V_ERR_INVALID_PURPOSE, SSL_AD_UNSUPPORTED_CERTIFICATE},
+    {X509_V_ERR_IP_ADDRESS_MISMATCH, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_OUT_OF_MEM, SSL_AD_INTERNAL_ERROR},
+    {X509_V_ERR_PATH_LENGTH_EXCEEDED, SSL_AD_UNKNOWN_CA},
+    {X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, SSL_AD_UNKNOWN_CA},
+    {X509_V_ERR_STORE_LOOKUP, SSL_AD_INTERNAL_ERROR},
+    {X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE, SSL_AD_BAD_CERTIFICATE},
+    {X509_V_ERR_UNABLE_TO_GET_CRL, SSL_AD_UNKNOWN_CA},
+    {X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER, SSL_AD_UNKNOWN_CA},
+    {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT, SSL_AD_UNKNOWN_CA},
+    {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, SSL_AD_UNKNOWN_CA},
+    {X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, SSL_AD_UNKNOWN_CA},
+    {X509_V_ERR_UNSPECIFIED, SSL_AD_INTERNAL_ERROR},
+
+    /* Last entry; return this if we don't find the value above. */
+    {X509_V_OK, SSL_AD_CERTIFICATE_UNKNOWN}
+};
+
+int ssl_x509err2alert(int x509err)
+{
+    const X509ERR2ALERT *tp;
+
+    for (tp = x509table; tp->x509err != X509_V_OK; ++tp)
+        if (tp->x509err == x509err)
+            break;
+    return tp->alert;
+}
+
+int ssl_allow_compression(SSL *s)
+{
+    if (s->options & SSL_OP_NO_COMPRESSION)
+        return 0;
+    return ssl_security(s, SSL_SECOP_COMPRESSION, 0, 0, NULL);
+}
+
+static int version_cmp(const SSL *s, int a, int b)
+{
+    int dtls = SSL_IS_DTLS(s);
+
+    if (a == b)
+        return 0;
+    if (!dtls)
+        return a < b ? -1 : 1;
+    return DTLS_VERSION_LT(a, b) ? -1 : 1;
+}
+
+typedef struct {
+    int version;
+    const SSL_METHOD *(*cmeth) (void);
+    const SSL_METHOD *(*smeth) (void);
+} version_info;
+
+#if TLS_MAX_VERSION != TLS1_3_VERSION
+# error Code needs update for TLS_method() support beyond TLS1_3_VERSION.
+#endif
+
+/* Must be in order high to low */
+static const version_info tls_version_table[] = {
+#ifndef OPENSSL_NO_TLS1_3
+    {TLS1_3_VERSION, tlsv1_3_client_method, tlsv1_3_server_method},
+#else
+    {TLS1_3_VERSION, NULL, NULL},
+#endif
+#ifndef OPENSSL_NO_TLS1_2
+    {TLS1_2_VERSION, tlsv1_2_client_method, tlsv1_2_server_method},
+#else
+    {TLS1_2_VERSION, NULL, NULL},
+#endif
+#ifndef OPENSSL_NO_TLS1_1
+    {TLS1_1_VERSION, tlsv1_1_client_method, tlsv1_1_server_method},
+#else
+    {TLS1_1_VERSION, NULL, NULL},
+#endif
+#ifndef OPENSSL_NO_TLS1
+    {TLS1_VERSION, tlsv1_client_method, tlsv1_server_method},
+#else
+    {TLS1_VERSION, NULL, NULL},
+#endif
+#ifndef OPENSSL_NO_SSL3
+    {SSL3_VERSION, sslv3_client_method, sslv3_server_method},
+#else
+    {SSL3_VERSION, NULL, NULL},
+#endif
+    {0, NULL, NULL},
+};
+
+#if DTLS_MAX_VERSION != DTLS1_2_VERSION
+# error Code needs update for DTLS_method() support beyond DTLS1_2_VERSION.
+#endif
+
+/* Must be in order high to low */
+static const version_info dtls_version_table[] = {
+#ifndef OPENSSL_NO_DTLS1_2
+    {DTLS1_2_VERSION, dtlsv1_2_client_method, dtlsv1_2_server_method},
+#else
+    {DTLS1_2_VERSION, NULL, NULL},
+#endif
+#ifndef OPENSSL_NO_DTLS1
+    {DTLS1_VERSION, dtlsv1_client_method, dtlsv1_server_method},
+    {DTLS1_BAD_VER, dtls_bad_ver_client_method, NULL},
+#else
+    {DTLS1_VERSION, NULL, NULL},
+    {DTLS1_BAD_VER, NULL, NULL},
+#endif
+    {0, NULL, NULL},
+};
+
+/*
+ * ssl_method_error - Check whether an SSL_METHOD is enabled.
+ *
+ * @s: The SSL handle for the candidate method
+ * @method: the intended method.
+ *
+ * Returns 0 on success, or an SSL error reason on failure.
+ */
+static int ssl_method_error(const SSL *s, const SSL_METHOD *method)
+{
+    int version = method->version;
+
+    if ((s->min_proto_version != 0 &&
+         version_cmp(s, version, s->min_proto_version) < 0) ||
+        ssl_security(s, SSL_SECOP_VERSION, 0, version, NULL) == 0)
+        return SSL_R_VERSION_TOO_LOW;
+
+    if (s->max_proto_version != 0 &&
+        version_cmp(s, version, s->max_proto_version) > 0)
+        return SSL_R_VERSION_TOO_HIGH;
+
+    if ((s->options & method->mask) != 0)
+        return SSL_R_UNSUPPORTED_PROTOCOL;
+    if ((method->flags & SSL_METHOD_NO_SUITEB) != 0 && tls1_suiteb(s))
+        return SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE;
+
+    return 0;
+}
+
+/*
+ * Only called by servers. Returns 1 if the server has a TLSv1.3 capable
+ * certificate type, or has PSK or a certificate callback configured, or has
+ * a servername callback configured. Otherwise returns 0.
+ */
+static int is_tls13_capable(const SSL *s)
+{
+    int i;
+#ifndef OPENSSL_NO_EC
+    int curve;
+    EC_KEY *eckey;
+#endif
+
+    if (!ossl_assert(s->ctx != NULL) || !ossl_assert(s->session_ctx != NULL))
+        return 0;
+
+    /*
+     * A servername callback can change the available certs, so if a servername
+     * cb is set then we just assume TLSv1.3 will be ok
+     */
+    if (s->ctx->ext.servername_cb != NULL
+            || s->session_ctx->ext.servername_cb != NULL)
+        return 1;
+
+#ifndef OPENSSL_NO_PSK
+    if (s->psk_server_callback != NULL)
+        return 1;
+#endif
+
+    if (s->psk_find_session_cb != NULL || s->cert->cert_cb != NULL)
+        return 1;
+
+    for (i = 0; i < SSL_PKEY_NUM; i++) {
+        /* Skip over certs disallowed for TLSv1.3 */
+        switch (i) {
+        case SSL_PKEY_DSA_SIGN:
+        case SSL_PKEY_GOST01:
+        case SSL_PKEY_GOST12_256:
+        case SSL_PKEY_GOST12_512:
+            continue;
+        default:
+            break;
+        }
+        if (!ssl_has_cert(s, i))
+            continue;
+#ifndef OPENSSL_NO_EC
+        if (i != SSL_PKEY_ECC)
+            return 1;
+        /*
+         * Prior to TLSv1.3 sig algs allowed any curve to be used. TLSv1.3 is
+         * more restrictive so check that our sig algs are consistent with this
+         * EC cert. See section 4.2.3 of RFC8446.
+         */
+        eckey = EVP_PKEY_get0_EC_KEY(s->cert->pkeys[SSL_PKEY_ECC].privatekey);
+        if (eckey == NULL)
+            continue;
+        curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey));
+        if (tls_check_sigalg_curve(s, curve))
+            return 1;
+#else
+        return 1;
+#endif
+    }
+
+    return 0;
+}
+
+/*
+ * ssl_version_supported - Check that the specified `version` is supported by
+ * `SSL *` instance
+ *
+ * @s: The SSL handle for the candidate method
+ * @version: Protocol version to test against
+ *
+ * Returns 1 when supported, otherwise 0
+ */
+int ssl_version_supported(const SSL *s, int version, const SSL_METHOD **meth)
+{
+    const version_info *vent;
+    const version_info *table;
+
+    switch (s->method->version) {
+    default:
+        /* Version should match method version for non-ANY method */
+        return version_cmp(s, version, s->version) == 0;
+    case TLS_ANY_VERSION:
+        table = tls_version_table;
+        break;
+    case DTLS_ANY_VERSION:
+        table = dtls_version_table;
+        break;
+    }
+
+    for (vent = table;
+         vent->version != 0 && version_cmp(s, version, vent->version) <= 0;
+         ++vent) {
+        if (vent->cmeth != NULL
+                && version_cmp(s, version, vent->version) == 0
+                && ssl_method_error(s, vent->cmeth()) == 0
+                && (!s->server
+                    || version != TLS1_3_VERSION
+                    || is_tls13_capable(s))) {
+            if (meth != NULL)
+                *meth = vent->cmeth();
+            return 1;
+        }
+    }
+    return 0;
+}
+
+/*
+ * ssl_check_version_downgrade - In response to RFC7507 SCSV version
+ * fallback indication from a client check whether we're using the highest
+ * supported protocol version.
+ *
+ * @s server SSL handle.
+ *
+ * Returns 1 when using the highest enabled version, 0 otherwise.
+ */
+int ssl_check_version_downgrade(SSL *s)
+{
+    const version_info *vent;
+    const version_info *table;
+
+    /*
+     * Check that the current protocol is the highest enabled version
+     * (according to s->ctx->method, as version negotiation may have changed
+     * s->method).
+     */
+    if (s->version == s->ctx->method->version)
+        return 1;
+
+    /*
+     * Apparently we're using a version-flexible SSL_METHOD (not at its
+     * highest protocol version).
+     */
+    if (s->ctx->method->version == TLS_method()->version)
+        table = tls_version_table;
+    else if (s->ctx->method->version == DTLS_method()->version)
+        table = dtls_version_table;
+    else {
+        /* Unexpected state; fail closed. */
+        return 0;
+    }
+
+    for (vent = table; vent->version != 0; ++vent) {
+        if (vent->smeth != NULL && ssl_method_error(s, vent->smeth()) == 0)
+            return s->version == vent->version;
+    }
+    return 0;
+}
+
+/*
+ * ssl_set_version_bound - set an upper or lower bound on the supported (D)TLS
+ * protocols, provided the initial (D)TLS method is version-flexible.  This
+ * function sanity-checks the proposed value and makes sure the method is
+ * version-flexible, then sets the limit if all is well.
+ *
+ * @method_version: The version of the current SSL_METHOD.
+ * @version: the intended limit.
+ * @bound: pointer to limit to be updated.
+ *
+ * Returns 1 on success, 0 on failure.
+ */
+int ssl_set_version_bound(int method_version, int version, int *bound)
+{
+    int valid_tls;
+    int valid_dtls;
+
+    if (version == 0) {
+        *bound = version;
+        return 1;
+    }
+
+    valid_tls = version >= SSL3_VERSION && version <= TLS_MAX_VERSION;
+    valid_dtls =
+        DTLS_VERSION_LE(version, DTLS_MAX_VERSION) &&
+        DTLS_VERSION_GE(version, DTLS1_BAD_VER);
+
+    if (!valid_tls && !valid_dtls)
+        return 0;
+
+    /*-
+     * Restrict TLS methods to TLS protocol versions.
+     * Restrict DTLS methods to DTLS protocol versions.
+     * Note, DTLS version numbers are decreasing, use comparison macros.
+     *
+     * Note that for both lower-bounds we use explicit versions, not
+     * (D)TLS_MIN_VERSION.  This is because we don't want to break user
+     * configurations.  If the MIN (supported) version ever rises, the user's
+     * "floor" remains valid even if no longer available.  We don't expect the
+     * MAX ceiling to ever get lower, so making that variable makes sense.
+     *
+     * We ignore attempts to set bounds on version-inflexible methods,
+     * returning success.
+     */
+    switch (method_version) {
+    default:
+        break;
+
+    case TLS_ANY_VERSION:
+        if (valid_tls)
+            *bound = version;
+        break;
+
+    case DTLS_ANY_VERSION:
+        if (valid_dtls)
+            *bound = version;
+        break;
+    }
+    return 1;
+}
+
+static void check_for_downgrade(SSL *s, int vers, DOWNGRADE *dgrd)
+{
+    if (vers == TLS1_2_VERSION
+            && ssl_version_supported(s, TLS1_3_VERSION, NULL)) {
+        *dgrd = DOWNGRADE_TO_1_2;
+    } else if (!SSL_IS_DTLS(s)
+            && vers < TLS1_2_VERSION
+               /*
+                * We need to ensure that a server that disables TLSv1.2
+                * (creating a hole between TLSv1.3 and TLSv1.1) can still
+                * complete handshakes with clients that support TLSv1.2 and
+                * below. Therefore we do not enable the sentinel if TLSv1.3 is
+                * enabled and TLSv1.2 is not.
+                */
+            && ssl_version_supported(s, TLS1_2_VERSION, NULL)) {
+        *dgrd = DOWNGRADE_TO_1_1;
+    } else {
+        *dgrd = DOWNGRADE_NONE;
+    }
+}
+
+/*
+ * ssl_choose_server_version - Choose server (D)TLS version.  Called when the
+ * client HELLO is received to select the final server protocol version and
+ * the version specific method.
+ *
+ * @s: server SSL handle.
+ *
+ * Returns 0 on success or an SSL error reason number on failure.
+ */
+int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello, DOWNGRADE *dgrd)
+{
+    /*-
+     * With version-flexible methods we have an initial state with:
+     *
+     *   s->method->version == (D)TLS_ANY_VERSION,
+     *   s->version == (D)TLS_MAX_VERSION.
+     *
+     * So we detect version-flexible methods via the method version, not the
+     * handle version.
+     */
+    int server_version = s->method->version;
+    int client_version = hello->legacy_version;
+    const version_info *vent;
+    const version_info *table;
+    int disabled = 0;
+    RAW_EXTENSION *suppversions;
+
+    s->client_version = client_version;
+
+    switch (server_version) {
+    default:
+        if (!SSL_IS_TLS13(s)) {
+            if (version_cmp(s, client_version, s->version) < 0)
+                return SSL_R_WRONG_SSL_VERSION;
+            *dgrd = DOWNGRADE_NONE;
+            /*
+             * If this SSL handle is not from a version flexible method we don't
+             * (and never did) check min/max FIPS or Suite B constraints.  Hope
+             * that's OK.  It is up to the caller to not choose fixed protocol
+             * versions they don't want.  If not, then easy to fix, just return
+             * ssl_method_error(s, s->method)
+             */
+            return 0;
+        }
+        /*
+         * Fall through if we are TLSv1.3 already (this means we must be after
+         * a HelloRetryRequest
+         */
+        /* fall thru */
+    case TLS_ANY_VERSION:
+        table = tls_version_table;
+        break;
+    case DTLS_ANY_VERSION:
+        table = dtls_version_table;
+        break;
+    }
+
+    suppversions = &hello->pre_proc_exts[TLSEXT_IDX_supported_versions];
+
+    /* If we did an HRR then supported versions is mandatory */
+    if (!suppversions->present && s->hello_retry_request != SSL_HRR_NONE)
+        return SSL_R_UNSUPPORTED_PROTOCOL;
+
+    if (suppversions->present && !SSL_IS_DTLS(s)) {
+        unsigned int candidate_vers = 0;
+        unsigned int best_vers = 0;
+        const SSL_METHOD *best_method = NULL;
+        PACKET versionslist;
+
+        suppversions->parsed = 1;
+
+        if (!PACKET_as_length_prefixed_1(&suppversions->data, &versionslist)) {
+            /* Trailing or invalid data? */
+            return SSL_R_LENGTH_MISMATCH;
+        }
+
+        /*
+         * The TLSv1.3 spec says the client MUST set this to TLS1_2_VERSION.
+         * The spec only requires servers to check that it isn't SSLv3:
+         * "Any endpoint receiving a Hello message with
+         * ClientHello.legacy_version or ServerHello.legacy_version set to
+         * 0x0300 MUST abort the handshake with a "protocol_version" alert."
+         * We are slightly stricter and require that it isn't SSLv3 or lower.
+         * We tolerate TLSv1 and TLSv1.1.
+         */
+        if (client_version <= SSL3_VERSION)
+            return SSL_R_BAD_LEGACY_VERSION;
+
+        while (PACKET_get_net_2(&versionslist, &candidate_vers)) {
+            if (version_cmp(s, candidate_vers, best_vers) <= 0)
+                continue;
+            if (ssl_version_supported(s, candidate_vers, &best_method))
+                best_vers = candidate_vers;
+        }
+        if (PACKET_remaining(&versionslist) != 0) {
+            /* Trailing data? */
+            return SSL_R_LENGTH_MISMATCH;
+        }
+
+        if (best_vers > 0) {
+            if (s->hello_retry_request != SSL_HRR_NONE) {
+                /*
+                 * This is after a HelloRetryRequest so we better check that we
+                 * negotiated TLSv1.3
+                 */
+                if (best_vers != TLS1_3_VERSION)
+                    return SSL_R_UNSUPPORTED_PROTOCOL;
+                return 0;
+            }
+            check_for_downgrade(s, best_vers, dgrd);
+            s->version = best_vers;
+            s->method = best_method;
+            return 0;
+        }
+        return SSL_R_UNSUPPORTED_PROTOCOL;
+    }
+
+    /*
+     * If the supported versions extension isn't present, then the highest
+     * version we can negotiate is TLSv1.2
+     */
+    if (version_cmp(s, client_version, TLS1_3_VERSION) >= 0)
+        client_version = TLS1_2_VERSION;
+
+    /*
+     * No supported versions extension, so we just use the version supplied in
+     * the ClientHello.
+     */
+    for (vent = table; vent->version != 0; ++vent) {
+        const SSL_METHOD *method;
+
+        if (vent->smeth == NULL ||
+            version_cmp(s, client_version, vent->version) < 0)
+            continue;
+        method = vent->smeth();
+        if (ssl_method_error(s, method) == 0) {
+            check_for_downgrade(s, vent->version, dgrd);
+            s->version = vent->version;
+            s->method = method;
+            return 0;
+        }
+        disabled = 1;
+    }
+    return disabled ? SSL_R_UNSUPPORTED_PROTOCOL : SSL_R_VERSION_TOO_LOW;
+}
+
+/*
+ * ssl_choose_client_version - Choose client (D)TLS version.  Called when the
+ * server HELLO is received to select the final client protocol version and
+ * the version specific method.
+ *
+ * @s: client SSL handle.
+ * @version: The proposed version from the server's HELLO.
+ * @extensions: The extensions received
+ *
+ * Returns 1 on success or 0 on error.
+ */
+int ssl_choose_client_version(SSL *s, int version, RAW_EXTENSION *extensions)
+{
+    const version_info *vent;
+    const version_info *table;
+    int ret, ver_min, ver_max, real_max, origv;
+
+    origv = s->version;
+    s->version = version;
+
+    /* This will overwrite s->version if the extension is present */
+    if (!tls_parse_extension(s, TLSEXT_IDX_supported_versions,
+                             SSL_EXT_TLS1_2_SERVER_HELLO
+                             | SSL_EXT_TLS1_3_SERVER_HELLO, extensions,
+                             NULL, 0)) {
+        s->version = origv;
+        return 0;
+    }
+
+    if (s->hello_retry_request != SSL_HRR_NONE
+            && s->version != TLS1_3_VERSION) {
+        s->version = origv;
+        SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_F_SSL_CHOOSE_CLIENT_VERSION,
+                 SSL_R_WRONG_SSL_VERSION);
+        return 0;
+    }
+
+    switch (s->method->version) {
+    default:
+        if (s->version != s->method->version) {
+            s->version = origv;
+            SSLfatal(s, SSL_AD_PROTOCOL_VERSION,
+                     SSL_F_SSL_CHOOSE_CLIENT_VERSION,
+                     SSL_R_WRONG_SSL_VERSION);
+            return 0;
+        }
+        /*
+         * If this SSL handle is not from a version flexible method we don't
+         * (and never did) check min/max, FIPS or Suite B constraints.  Hope
+         * that's OK.  It is up to the caller to not choose fixed protocol
+         * versions they don't want.  If not, then easy to fix, just return
+         * ssl_method_error(s, s->method)
+         */
+        return 1;
+    case TLS_ANY_VERSION:
+        table = tls_version_table;
+        break;
+    case DTLS_ANY_VERSION:
+        table = dtls_version_table;
+        break;
+    }
+
+    ret = ssl_get_min_max_version(s, &ver_min, &ver_max, &real_max);
+    if (ret != 0) {
+        s->version = origv;
+        SSLfatal(s, SSL_AD_PROTOCOL_VERSION,
+                 SSL_F_SSL_CHOOSE_CLIENT_VERSION, ret);
+        return 0;
+    }
+    if (SSL_IS_DTLS(s) ? DTLS_VERSION_LT(s->version, ver_min)
+                       : s->version < ver_min) {
+        s->version = origv;
+        SSLfatal(s, SSL_AD_PROTOCOL_VERSION,
+                 SSL_F_SSL_CHOOSE_CLIENT_VERSION, SSL_R_UNSUPPORTED_PROTOCOL);
+        return 0;
+    } else if (SSL_IS_DTLS(s) ? DTLS_VERSION_GT(s->version, ver_max)
+                              : s->version > ver_max) {
+        s->version = origv;
+        SSLfatal(s, SSL_AD_PROTOCOL_VERSION,
+                 SSL_F_SSL_CHOOSE_CLIENT_VERSION, SSL_R_UNSUPPORTED_PROTOCOL);
+        return 0;
+    }
+
+    if ((s->mode & SSL_MODE_SEND_FALLBACK_SCSV) == 0)
+        real_max = ver_max;
+
+    /* Check for downgrades */
+    if (s->version == TLS1_2_VERSION && real_max > s->version) {
+        if (memcmp(tls12downgrade,
+                   s->s3->server_random + SSL3_RANDOM_SIZE
+                                        - sizeof(tls12downgrade),
+                   sizeof(tls12downgrade)) == 0) {
+            s->version = origv;
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_SSL_CHOOSE_CLIENT_VERSION,
+                     SSL_R_INAPPROPRIATE_FALLBACK);
+            return 0;
+        }
+    } else if (!SSL_IS_DTLS(s)
+               && s->version < TLS1_2_VERSION
+               && real_max > s->version) {
+        if (memcmp(tls11downgrade,
+                   s->s3->server_random + SSL3_RANDOM_SIZE
+                                        - sizeof(tls11downgrade),
+                   sizeof(tls11downgrade)) == 0) {
+            s->version = origv;
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_SSL_CHOOSE_CLIENT_VERSION,
+                     SSL_R_INAPPROPRIATE_FALLBACK);
+            return 0;
+        }
+    }
+
+    for (vent = table; vent->version != 0; ++vent) {
+        if (vent->cmeth == NULL || s->version != vent->version)
+            continue;
+
+        s->method = vent->cmeth();
+        return 1;
+    }
+
+    s->version = origv;
+    SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_F_SSL_CHOOSE_CLIENT_VERSION,
+             SSL_R_UNSUPPORTED_PROTOCOL);
+    return 0;
+}
+
+/*
+ * ssl_get_min_max_version - get minimum and maximum protocol version
+ * @s: The SSL connection
+ * @min_version: The minimum supported version
+ * @max_version: The maximum supported version
+ * @real_max:    The highest version below the lowest compile time version hole
+ *               where that hole lies above at least one run-time enabled
+ *               protocol.
+ *
+ * Work out what version we should be using for the initial ClientHello if the
+ * version is initially (D)TLS_ANY_VERSION.  We apply any explicit SSL_OP_NO_xxx
+ * options, the MinProtocol and MaxProtocol configuration commands, any Suite B
+ * constraints and any floor imposed by the security level here,
+ * so we don't advertise the wrong protocol version to only reject the outcome later.
+ *
+ * Computing the right floor matters.  If, e.g., TLS 1.0 and 1.2 are enabled,
+ * TLS 1.1 is disabled, but the security level, Suite-B  and/or MinProtocol
+ * only allow TLS 1.2, we want to advertise TLS1.2, *not* TLS1.
+ *
+ * Returns 0 on success or an SSL error reason number on failure.  On failure
+ * min_version and max_version will also be set to 0.
+ */
+int ssl_get_min_max_version(const SSL *s, int *min_version, int *max_version,
+                            int *real_max)
+{
+    int version, tmp_real_max;
+    int hole;
+    const SSL_METHOD *single = NULL;
+    const SSL_METHOD *method;
+    const version_info *table;
+    const version_info *vent;
+
+    switch (s->method->version) {
+    default:
+        /*
+         * If this SSL handle is not from a version flexible method we don't
+         * (and never did) check min/max FIPS or Suite B constraints.  Hope
+         * that's OK.  It is up to the caller to not choose fixed protocol
+         * versions they don't want.  If not, then easy to fix, just return
+         * ssl_method_error(s, s->method)
+         */
+        *min_version = *max_version = s->version;
+        /*
+         * Providing a real_max only makes sense where we're using a version
+         * flexible method.
+         */
+        if (!ossl_assert(real_max == NULL))
+            return ERR_R_INTERNAL_ERROR;
+        return 0;
+    case TLS_ANY_VERSION:
+        table = tls_version_table;
+        break;
+    case DTLS_ANY_VERSION:
+        table = dtls_version_table;
+        break;
+    }
+
+    /*
+     * SSL_OP_NO_X disables all protocols above X *if* there are some protocols
+     * below X enabled. This is required in order to maintain the "version
+     * capability" vector contiguous. Any versions with a NULL client method
+     * (protocol version client is disabled at compile-time) is also a "hole".
+     *
+     * Our initial state is hole == 1, version == 0.  That is, versions above
+     * the first version in the method table are disabled (a "hole" above
+     * the valid protocol entries) and we don't have a selected version yet.
+     *
+     * Whenever "hole == 1", and we hit an enabled method, its version becomes
+     * the selected version, and the method becomes a candidate "single"
+     * method.  We're no longer in a hole, so "hole" becomes 0.
+     *
+     * If "hole == 0" and we hit an enabled method, then "single" is cleared,
+     * as we support a contiguous range of at least two methods.  If we hit
+     * a disabled method, then hole becomes true again, but nothing else
+     * changes yet, because all the remaining methods may be disabled too.
+     * If we again hit an enabled method after the new hole, it becomes
+     * selected, as we start from scratch.
+     */
+    *min_version = version = 0;
+    hole = 1;
+    if (real_max != NULL)
+        *real_max = 0;
+    tmp_real_max = 0;
+    for (vent = table; vent->version != 0; ++vent) {
+        /*
+         * A table entry with a NULL client method is still a hole in the
+         * "version capability" vector.
+         */
+        if (vent->cmeth == NULL) {
+            hole = 1;
+            tmp_real_max = 0;
+            continue;
+        }
+        method = vent->cmeth();
+
+        if (hole == 1 && tmp_real_max == 0)
+            tmp_real_max = vent->version;
+
+        if (ssl_method_error(s, method) != 0) {
+            hole = 1;
+        } else if (!hole) {
+            single = NULL;
+            *min_version = method->version;
+        } else {
+            if (real_max != NULL && tmp_real_max != 0)
+                *real_max = tmp_real_max;
+            version = (single = method)->version;
+            *min_version = version;
+            hole = 0;
+        }
+    }
+
+    *max_version = version;
+
+    /* Fail if everything is disabled */
+    if (version == 0)
+        return SSL_R_NO_PROTOCOLS_AVAILABLE;
+
+    return 0;
+}
+
+/*
+ * ssl_set_client_hello_version - Work out what version we should be using for
+ * the initial ClientHello.legacy_version field.
+ *
+ * @s: client SSL handle.
+ *
+ * Returns 0 on success or an SSL error reason number on failure.
+ */
+int ssl_set_client_hello_version(SSL *s)
+{
+    int ver_min, ver_max, ret;
+
+    /*
+     * In a renegotiation we always send the same client_version that we sent
+     * last time, regardless of which version we eventually negotiated.
+     */
+    if (!SSL_IS_FIRST_HANDSHAKE(s))
+        return 0;
+
+    ret = ssl_get_min_max_version(s, &ver_min, &ver_max, NULL);
+
+    if (ret != 0)
+        return ret;
+
+    s->version = ver_max;
+
+    /* TLS1.3 always uses TLS1.2 in the legacy_version field */
+    if (!SSL_IS_DTLS(s) && ver_max > TLS1_2_VERSION)
+        ver_max = TLS1_2_VERSION;
+
+    s->client_version = ver_max;
+    return 0;
+}
+
+/*
+ * Checks a list of |groups| to determine if the |group_id| is in it. If it is
+ * and |checkallow| is 1 then additionally check if the group is allowed to be
+ * used. Returns 1 if the group is in the list (and allowed if |checkallow| is
+ * 1) or 0 otherwise.
+ */
+#ifndef OPENSSL_NO_EC
+int check_in_list(SSL *s, uint16_t group_id, const uint16_t *groups,
+                  size_t num_groups, int checkallow)
+{
+    size_t i;
+
+    if (groups == NULL || num_groups == 0)
+        return 0;
+
+    for (i = 0; i < num_groups; i++) {
+        uint16_t group = groups[i];
+
+        if (group_id == group
+                && (!checkallow
+                    || tls_curve_allowed(s, group, SSL_SECOP_CURVE_CHECK))) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+#endif
+
+/* Replace ClientHello1 in the transcript hash with a synthetic message */
+int create_synthetic_message_hash(SSL *s, const unsigned char *hashval,
+                                  size_t hashlen, const unsigned char *hrr,
+                                  size_t hrrlen)
+{
+    unsigned char hashvaltmp[EVP_MAX_MD_SIZE];
+    unsigned char msghdr[SSL3_HM_HEADER_LENGTH];
+
+    memset(msghdr, 0, sizeof(msghdr));
+
+    if (hashval == NULL) {
+        hashval = hashvaltmp;
+        hashlen = 0;
+        /* Get the hash of the initial ClientHello */
+        if (!ssl3_digest_cached_records(s, 0)
+                || !ssl_handshake_hash(s, hashvaltmp, sizeof(hashvaltmp),
+                                       &hashlen)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+    }
+
+    /* Reinitialise the transcript hash */
+    if (!ssl3_init_finished_mac(s)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    /* Inject the synthetic message_hash message */
+    msghdr[0] = SSL3_MT_MESSAGE_HASH;
+    msghdr[SSL3_HM_HEADER_LENGTH - 1] = (unsigned char)hashlen;
+    if (!ssl3_finish_mac(s, msghdr, SSL3_HM_HEADER_LENGTH)
+            || !ssl3_finish_mac(s, hashval, hashlen)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    /*
+     * Now re-inject the HRR and current message if appropriate (we just deleted
+     * it when we reinitialised the transcript hash above). Only necessary after
+     * receiving a ClientHello2 with a cookie.
+     */
+    if (hrr != NULL
+            && (!ssl3_finish_mac(s, hrr, hrrlen)
+                || !ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+                                    s->s3->tmp.message_size
+                                    + SSL3_HM_HEADER_LENGTH))) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    return 1;
+}
+
+static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b)
+{
+    return X509_NAME_cmp(*a, *b);
+}
+
+int parse_ca_names(SSL *s, PACKET *pkt)
+{
+    STACK_OF(X509_NAME) *ca_sk = sk_X509_NAME_new(ca_dn_cmp);
+    X509_NAME *xn = NULL;
+    PACKET cadns;
+
+    if (ca_sk == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_PARSE_CA_NAMES,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    /* get the CA RDNs */
+    if (!PACKET_get_length_prefixed_2(pkt, &cadns)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,SSL_F_PARSE_CA_NAMES,
+                 SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    while (PACKET_remaining(&cadns)) {
+        const unsigned char *namestart, *namebytes;
+        unsigned int name_len;
+
+        if (!PACKET_get_net_2(&cadns, &name_len)
+            || !PACKET_get_bytes(&cadns, &namebytes, name_len)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_PARSE_CA_NAMES,
+                     SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        namestart = namebytes;
+        if ((xn = d2i_X509_NAME(NULL, &namebytes, name_len)) == NULL) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_PARSE_CA_NAMES,
+                     ERR_R_ASN1_LIB);
+            goto err;
+        }
+        if (namebytes != (namestart + name_len)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_PARSE_CA_NAMES,
+                     SSL_R_CA_DN_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        if (!sk_X509_NAME_push(ca_sk, xn)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_PARSE_CA_NAMES,
+                     ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+        xn = NULL;
+    }
+
+    sk_X509_NAME_pop_free(s->s3->tmp.peer_ca_names, X509_NAME_free);
+    s->s3->tmp.peer_ca_names = ca_sk;
+
+    return 1;
+
+ err:
+    sk_X509_NAME_pop_free(ca_sk, X509_NAME_free);
+    X509_NAME_free(xn);
+    return 0;
+}
+
+const STACK_OF(X509_NAME) *get_ca_names(SSL *s)
+{
+    const STACK_OF(X509_NAME) *ca_sk = NULL;;
+
+    if (s->server) {
+        ca_sk = SSL_get_client_CA_list(s);
+        if (ca_sk != NULL && sk_X509_NAME_num(ca_sk) == 0)
+            ca_sk = NULL;
+    }
+
+    if (ca_sk == NULL)
+        ca_sk = SSL_get0_CA_list(s);
+
+    return ca_sk;
+}
+
+int construct_ca_names(SSL *s, const STACK_OF(X509_NAME) *ca_sk, WPACKET *pkt)
+{
+    /* Start sub-packet for client CA list */
+    if (!WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_CA_NAMES,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (ca_sk != NULL) {
+        int i;
+
+        for (i = 0; i < sk_X509_NAME_num(ca_sk); i++) {
+            unsigned char *namebytes;
+            X509_NAME *name = sk_X509_NAME_value(ca_sk, i);
+            int namelen;
+
+            if (name == NULL
+                    || (namelen = i2d_X509_NAME(name, NULL)) < 0
+                    || !WPACKET_sub_allocate_bytes_u16(pkt, namelen,
+                                                       &namebytes)
+                    || i2d_X509_NAME(name, &namebytes) != namelen) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_CA_NAMES,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
+    }
+
+    if (!WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_CA_NAMES,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+/* Create a buffer containing data to be signed for server key exchange */
+size_t construct_key_exchange_tbs(SSL *s, unsigned char **ptbs,
+                                  const void *param, size_t paramlen)
+{
+    size_t tbslen = 2 * SSL3_RANDOM_SIZE + paramlen;
+    unsigned char *tbs = OPENSSL_malloc(tbslen);
+
+    if (tbs == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_KEY_EXCHANGE_TBS,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    memcpy(tbs, s->s3->client_random, SSL3_RANDOM_SIZE);
+    memcpy(tbs + SSL3_RANDOM_SIZE, s->s3->server_random, SSL3_RANDOM_SIZE);
+
+    memcpy(tbs + SSL3_RANDOM_SIZE * 2, param, paramlen);
+
+    *ptbs = tbs;
+    return tbslen;
+}
+
+/*
+ * Saves the current handshake digest for Post-Handshake Auth,
+ * Done after ClientFinished is processed, done exactly once
+ */
+int tls13_save_handshake_digest_for_pha(SSL *s)
+{
+    if (s->pha_dgst == NULL) {
+        if (!ssl3_digest_cached_records(s, 1))
+            /* SSLfatal() already called */
+            return 0;
+
+        s->pha_dgst = EVP_MD_CTX_new();
+        if (s->pha_dgst == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS13_SAVE_HANDSHAKE_DIGEST_FOR_PHA,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        if (!EVP_MD_CTX_copy_ex(s->pha_dgst,
+                                s->s3->handshake_dgst)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS13_SAVE_HANDSHAKE_DIGEST_FOR_PHA,
+                     ERR_R_INTERNAL_ERROR);
+            EVP_MD_CTX_free(s->pha_dgst);
+            s->pha_dgst = NULL;
+            return 0;
+        }
+    }
+    return 1;
+}
+
+/*
+ * Restores the Post-Handshake Auth handshake digest
+ * Done just before sending/processing the Cert Request
+ */
+int tls13_restore_handshake_digest_for_pha(SSL *s)
+{
+    if (s->pha_dgst == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS13_RESTORE_HANDSHAKE_DIGEST_FOR_PHA,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    if (!EVP_MD_CTX_copy_ex(s->s3->handshake_dgst,
+                            s->pha_dgst)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS13_RESTORE_HANDSHAKE_DIGEST_FOR_PHA,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    return 1;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_local.h b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_local.h
new file mode 100644
index 0000000..eae8805
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_local.h
@@ -0,0 +1,422 @@
+/*
+ * Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*****************************************************************************
+ *                                                                           *
+ * The following definitions are PRIVATE to the state machine. They should   *
+ * NOT be used outside of the state machine.                                 *
+ *                                                                           *
+ *****************************************************************************/
+
+/* Max message length definitions */
+
+/* The spec allows for a longer length than this, but we limit it */
+#define HELLO_VERIFY_REQUEST_MAX_LENGTH 258
+#define END_OF_EARLY_DATA_MAX_LENGTH    0
+#define SERVER_HELLO_MAX_LENGTH         20000
+#define HELLO_RETRY_REQUEST_MAX_LENGTH  20000
+#define ENCRYPTED_EXTENSIONS_MAX_LENGTH 20000
+#define SESSION_TICKET_MAX_LENGTH_TLS13 131338
+#define SESSION_TICKET_MAX_LENGTH_TLS12 65541
+#define SERVER_KEY_EXCH_MAX_LENGTH      102400
+#define SERVER_HELLO_DONE_MAX_LENGTH    0
+#define KEY_UPDATE_MAX_LENGTH           1
+#define CCS_MAX_LENGTH                  1
+/* Max should actually be 36 but we are generous */
+#define FINISHED_MAX_LENGTH             64
+
+/* Dummy message type */
+#define SSL3_MT_DUMMY   -1
+
+extern const unsigned char hrrrandom[];
+
+/* Message processing return codes */
+typedef enum {
+    /* Something bad happened */
+    MSG_PROCESS_ERROR,
+    /* We've finished reading - swap to writing */
+    MSG_PROCESS_FINISHED_READING,
+    /*
+     * We've completed the main processing of this message but there is some
+     * post processing to be done.
+     */
+    MSG_PROCESS_CONTINUE_PROCESSING,
+    /* We've finished this message - read the next message */
+    MSG_PROCESS_CONTINUE_READING
+} MSG_PROCESS_RETURN;
+
+typedef int (*confunc_f) (SSL *s, WPACKET *pkt);
+
+int ssl3_take_mac(SSL *s);
+int check_in_list(SSL *s, uint16_t group_id, const uint16_t *groups,
+                  size_t num_groups, int checkallow);
+int create_synthetic_message_hash(SSL *s, const unsigned char *hashval,
+                                  size_t hashlen, const unsigned char *hrr,
+                                  size_t hrrlen);
+int parse_ca_names(SSL *s, PACKET *pkt);
+const STACK_OF(X509_NAME) *get_ca_names(SSL *s);
+int construct_ca_names(SSL *s, const STACK_OF(X509_NAME) *ca_sk, WPACKET *pkt);
+size_t construct_key_exchange_tbs(SSL *s, unsigned char **ptbs,
+                                  const void *param, size_t paramlen);
+
+/*
+ * TLS/DTLS client state machine functions
+ */
+int ossl_statem_client_read_transition(SSL *s, int mt);
+WRITE_TRAN ossl_statem_client_write_transition(SSL *s);
+WORK_STATE ossl_statem_client_pre_work(SSL *s, WORK_STATE wst);
+WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst);
+int ossl_statem_client_construct_message(SSL *s, WPACKET *pkt,
+                                         confunc_f *confunc, int *mt);
+size_t ossl_statem_client_max_message_size(SSL *s);
+MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt);
+WORK_STATE ossl_statem_client_post_process_message(SSL *s, WORK_STATE wst);
+
+/*
+ * TLS/DTLS server state machine functions
+ */
+int ossl_statem_server_read_transition(SSL *s, int mt);
+WRITE_TRAN ossl_statem_server_write_transition(SSL *s);
+WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst);
+WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst);
+int ossl_statem_server_construct_message(SSL *s, WPACKET *pkt,
+                                         confunc_f *confunc,int *mt);
+size_t ossl_statem_server_max_message_size(SSL *s);
+MSG_PROCESS_RETURN ossl_statem_server_process_message(SSL *s, PACKET *pkt);
+WORK_STATE ossl_statem_server_post_process_message(SSL *s, WORK_STATE wst);
+
+/* Functions for getting new message data */
+__owur int tls_get_message_header(SSL *s, int *mt);
+__owur int tls_get_message_body(SSL *s, size_t *len);
+__owur int dtls_get_message(SSL *s, int *mt, size_t *len);
+
+/* Message construction and processing functions */
+__owur int tls_process_initial_server_flight(SSL *s);
+__owur MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt);
+__owur int tls_construct_change_cipher_spec(SSL *s, WPACKET *pkt);
+__owur int dtls_construct_change_cipher_spec(SSL *s, WPACKET *pkt);
+
+__owur int tls_construct_finished(SSL *s, WPACKET *pkt);
+__owur int tls_construct_key_update(SSL *s, WPACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_key_update(SSL *s, PACKET *pkt);
+__owur WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs,
+                                       int stop);
+__owur WORK_STATE dtls_wait_for_dry(SSL *s);
+
+/* some client-only functions */
+__owur int tls_construct_client_hello(SSL *s, WPACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt);
+__owur int tls_process_cert_status_body(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt);
+__owur int tls_construct_cert_verify(SSL *s, WPACKET *pkt);
+__owur WORK_STATE tls_prepare_client_certificate(SSL *s, WORK_STATE wst);
+__owur int tls_construct_client_certificate(SSL *s, WPACKET *pkt);
+__owur int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey);
+__owur int tls_construct_client_key_exchange(SSL *s, WPACKET *pkt);
+__owur int tls_client_key_exchange_post_work(SSL *s);
+__owur int tls_construct_cert_status_body(SSL *s, WPACKET *pkt);
+__owur int tls_construct_cert_status(SSL *s, WPACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt);
+__owur int ssl3_check_cert_and_algorithm(SSL *s);
+#ifndef OPENSSL_NO_NEXTPROTONEG
+__owur int tls_construct_next_proto(SSL *s, WPACKET *pkt);
+#endif
+__owur MSG_PROCESS_RETURN tls_process_hello_req(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt);
+__owur int tls_construct_end_of_early_data(SSL *s, WPACKET *pkt);
+
+/* some server-only functions */
+__owur MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt);
+__owur WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst);
+__owur int tls_construct_server_hello(SSL *s, WPACKET *pkt);
+__owur int dtls_construct_hello_verify_request(SSL *s, WPACKET *pkt);
+__owur int tls_construct_server_certificate(SSL *s, WPACKET *pkt);
+__owur int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt);
+__owur int tls_construct_certificate_request(SSL *s, WPACKET *pkt);
+__owur int tls_construct_server_done(SSL *s, WPACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt);
+__owur WORK_STATE tls_post_process_client_key_exchange(SSL *s, WORK_STATE wst);
+__owur MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt);
+#ifndef OPENSSL_NO_NEXTPROTONEG
+__owur MSG_PROCESS_RETURN tls_process_next_proto(SSL *s, PACKET *pkt);
+#endif
+__owur int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt);
+MSG_PROCESS_RETURN tls_process_end_of_early_data(SSL *s, PACKET *pkt);
+
+
+/* Extension processing */
+
+typedef enum ext_return_en {
+    EXT_RETURN_FAIL,
+    EXT_RETURN_SENT,
+    EXT_RETURN_NOT_SENT
+} EXT_RETURN;
+
+__owur int tls_validate_all_contexts(SSL *s, unsigned int thisctx,
+                                     RAW_EXTENSION *exts);
+__owur int extension_is_relevant(SSL *s, unsigned int extctx,
+                                 unsigned int thisctx);
+__owur int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
+                                  RAW_EXTENSION **res, size_t *len, int init);
+__owur int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
+                               RAW_EXTENSION *exts,  X509 *x, size_t chainidx);
+__owur int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts,
+                                    X509 *x, size_t chainidx, int fin);
+__owur int should_add_extension(SSL *s, unsigned int extctx,
+                                unsigned int thisctx, int max_version);
+__owur int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
+                                    X509 *x, size_t chainidx);
+
+__owur int tls_psk_do_binder(SSL *s, const EVP_MD *md,
+                             const unsigned char *msgstart,
+                             size_t binderoffset, const unsigned char *binderin,
+                             unsigned char *binderout,
+                             SSL_SESSION *sess, int sign, int external);
+
+/* Server Extension processing */
+int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx);
+int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx);
+int tls_parse_ctos_maxfragmentlen(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+#ifndef OPENSSL_NO_SRP
+int tls_parse_ctos_srp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx);
+#endif
+int tls_parse_ctos_early_data(SSL *s, PACKET *pkt, unsigned int context,
+                              X509 *x, size_t chainidx);
+#ifndef OPENSSL_NO_EC
+int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx);
+int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, unsigned int context,
+                                    X509 *x, size_t chainidxl);
+#endif
+int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+int tls_parse_ctos_sig_algs_cert(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx);
+int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx);
+#ifndef OPENSSL_NO_OCSP
+int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int tls_parse_ctos_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx);
+#endif
+int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                        size_t chainidx);
+#ifndef OPENSSL_NO_SRTP
+int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx);
+#endif
+int tls_parse_ctos_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx);
+int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                             size_t chainidx);
+int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                          size_t chainidx);
+int tls_parse_ctos_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx);
+int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx);
+int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx);
+int tls_parse_ctos_post_handshake_auth(SSL *, PACKET *pkt, unsigned int context,
+                                       X509 *x, size_t chainidx);
+
+EXT_RETURN tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
+                                          size_t chainidx);
+EXT_RETURN tls_construct_stoc_server_name(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
+                                          size_t chainidx);
+EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt,
+                                         unsigned int context, X509 *x,
+                                         size_t chainidx);
+EXT_RETURN tls_construct_stoc_maxfragmentlen(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx);
+#ifndef OPENSSL_NO_EC
+EXT_RETURN tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx);
+#endif
+EXT_RETURN tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt,
+                                               unsigned int context, X509 *x,
+                                               size_t chainidx);
+EXT_RETURN tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx);
+#ifndef OPENSSL_NO_OCSP
+EXT_RETURN tls_construct_stoc_status_request(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx);
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+EXT_RETURN tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx);
+#endif
+EXT_RETURN tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx);
+#ifndef OPENSSL_NO_SRTP
+EXT_RETURN tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
+                                X509 *x, size_t chainidx);
+#endif
+EXT_RETURN tls_construct_stoc_etm(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+EXT_RETURN tls_construct_stoc_ems(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+EXT_RETURN tls_construct_stoc_supported_versions(SSL *s, WPACKET *pkt,
+                                                 unsigned int context, X509 *x,
+                                                 size_t chainidx);
+EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt,
+                                        unsigned int context, X509 *x,
+                                        size_t chainidx);
+EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context,
+                                     X509 *x, size_t chainidx);
+/*
+ * Not in public headers as this is not an official extension. Only used when
+ * SSL_OP_CRYPTOPRO_TLSEXT_BUG is set.
+ */
+#define TLSEXT_TYPE_cryptopro_bug      0xfde8
+EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx);
+EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+
+/* Client Extension processing */
+EXT_RETURN tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx);
+EXT_RETURN tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx);
+EXT_RETURN tls_construct_ctos_maxfragmentlen(SSL *s, WPACKET *pkt, unsigned int context,
+                                             X509 *x, size_t chainidx);
+#ifndef OPENSSL_NO_SRP
+EXT_RETURN tls_construct_ctos_srp(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx);
+#endif
+#ifndef OPENSSL_NO_EC
+EXT_RETURN tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx);
+EXT_RETURN tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
+                                               unsigned int context, X509 *x,
+                                               size_t chainidx);
+#endif
+EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt,
+                                         unsigned int context, X509 *x,
+                                         size_t chainidx);
+EXT_RETURN tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx);
+EXT_RETURN tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt,
+                                       unsigned int context, X509 *x,
+                                       size_t chainidx);
+#ifndef OPENSSL_NO_OCSP
+EXT_RETURN tls_construct_ctos_status_request(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx);
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+EXT_RETURN tls_construct_ctos_npn(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+#endif
+EXT_RETURN tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx);
+#ifndef OPENSSL_NO_SRTP
+EXT_RETURN tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
+                                       X509 *x, size_t chainidx);
+#endif
+EXT_RETURN tls_construct_ctos_etm(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+#ifndef OPENSSL_NO_CT
+EXT_RETURN tls_construct_ctos_sct(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+#endif
+EXT_RETURN tls_construct_ctos_ems(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+EXT_RETURN tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt,
+                                                 unsigned int context, X509 *x,
+                                                 size_t chainidx);
+EXT_RETURN tls_construct_ctos_key_share(SSL *s, WPACKET *pkt,
+                                        unsigned int context, X509 *x,
+                                        size_t chainidx);
+EXT_RETURN tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx);
+EXT_RETURN tls_construct_ctos_cookie(SSL *s, WPACKET *pkt, unsigned int context,
+                                     X509 *x, size_t chainidx);
+EXT_RETURN tls_construct_ctos_padding(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
+                                      size_t chainidx);
+EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt, unsigned int context,
+                                                  X509 *x, size_t chainidx);
+
+int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx);
+int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx);
+int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
+                              X509 *x, size_t chainidx);
+int tls_parse_stoc_maxfragmentlen(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+#ifndef OPENSSL_NO_EC
+int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx);
+#endif
+int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+#ifndef OPENSSL_NO_OCSP
+int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx);
+#endif
+#ifndef OPENSSL_NO_CT
+int tls_parse_stoc_sct(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx);
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int tls_parse_stoc_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx);
+#endif
+int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                        size_t chainidx);
+#ifndef OPENSSL_NO_SRTP
+int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx);
+#endif
+int tls_parse_stoc_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx);
+int tls_parse_stoc_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx);
+int tls_parse_stoc_supported_versions(SSL *s, PACKET *pkt, unsigned int context,
+                                      X509 *x, size_t chainidx);
+int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                             size_t chainidx);
+int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx);
+int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx);
+
+int tls_handle_alpn(SSL *s);
+
+int tls13_save_handshake_digest_for_pha(SSL *s);
+int tls13_restore_handshake_digest_for_pha(SSL *s);
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_srvr.c b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_srvr.c
new file mode 100644
index 0000000..43f77a5
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/statem/statem_srvr.c
@@ -0,0 +1,4308 @@
+/*
+ * 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.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include "../ssl_local.h"
+#include "statem_local.h"
+#include "internal/constant_time.h"
+#include "internal/cryptlib.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/x509.h>
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#include <openssl/md5.h>
+#include <openssl/asn1t.h>
+
+#define TICKET_NONCE_SIZE       8
+
+typedef struct {
+  ASN1_TYPE *kxBlob;
+  ASN1_TYPE *opaqueBlob;
+} GOST_KX_MESSAGE;
+
+DECLARE_ASN1_FUNCTIONS(GOST_KX_MESSAGE)
+
+ASN1_SEQUENCE(GOST_KX_MESSAGE) = {
+  ASN1_SIMPLE(GOST_KX_MESSAGE,  kxBlob, ASN1_ANY),
+  ASN1_OPT(GOST_KX_MESSAGE, opaqueBlob, ASN1_ANY),
+} ASN1_SEQUENCE_END(GOST_KX_MESSAGE)
+
+IMPLEMENT_ASN1_FUNCTIONS(GOST_KX_MESSAGE)
+
+static int tls_construct_encrypted_extensions(SSL *s, WPACKET *pkt);
+
+/*
+ * ossl_statem_server13_read_transition() encapsulates the logic for the allowed
+ * handshake state transitions when a TLSv1.3 server is reading messages from
+ * the client. The message type that the client has sent is provided in |mt|.
+ * The current state is in |s->statem.hand_state|.
+ *
+ * Return values are 1 for success (transition allowed) and  0 on error
+ * (transition not allowed)
+ */
+static int ossl_statem_server13_read_transition(SSL *s, int mt)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    /*
+     * Note: There is no case for TLS_ST_BEFORE because at that stage we have
+     * not negotiated TLSv1.3 yet, so that case is handled by
+     * ossl_statem_server_read_transition()
+     */
+    switch (st->hand_state) {
+    default:
+        break;
+
+    case TLS_ST_EARLY_DATA:
+        if (s->hello_retry_request == SSL_HRR_PENDING) {
+            if (mt == SSL3_MT_CLIENT_HELLO) {
+                st->hand_state = TLS_ST_SR_CLNT_HELLO;
+                return 1;
+            }
+            break;
+        } else if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
+            if (mt == SSL3_MT_END_OF_EARLY_DATA) {
+                st->hand_state = TLS_ST_SR_END_OF_EARLY_DATA;
+                return 1;
+            }
+            break;
+        }
+        /* Fall through */
+
+    case TLS_ST_SR_END_OF_EARLY_DATA:
+    case TLS_ST_SW_FINISHED:
+        if (s->s3->tmp.cert_request) {
+            if (mt == SSL3_MT_CERTIFICATE) {
+                st->hand_state = TLS_ST_SR_CERT;
+                return 1;
+            }
+        } else {
+            if (mt == SSL3_MT_FINISHED) {
+                st->hand_state = TLS_ST_SR_FINISHED;
+                return 1;
+            }
+        }
+        break;
+
+    case TLS_ST_SR_CERT:
+        if (s->session->peer == NULL) {
+            if (mt == SSL3_MT_FINISHED) {
+                st->hand_state = TLS_ST_SR_FINISHED;
+                return 1;
+            }
+        } else {
+            if (mt == SSL3_MT_CERTIFICATE_VERIFY) {
+                st->hand_state = TLS_ST_SR_CERT_VRFY;
+                return 1;
+            }
+        }
+        break;
+
+    case TLS_ST_SR_CERT_VRFY:
+        if (mt == SSL3_MT_FINISHED) {
+            st->hand_state = TLS_ST_SR_FINISHED;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_OK:
+        /*
+         * Its never ok to start processing handshake messages in the middle of
+         * early data (i.e. before we've received the end of early data alert)
+         */
+        if (s->early_data_state == SSL_EARLY_DATA_READING)
+            break;
+
+        if (mt == SSL3_MT_CERTIFICATE
+                && s->post_handshake_auth == SSL_PHA_REQUESTED) {
+            st->hand_state = TLS_ST_SR_CERT;
+            return 1;
+        }
+
+        if (mt == SSL3_MT_KEY_UPDATE) {
+            st->hand_state = TLS_ST_SR_KEY_UPDATE;
+            return 1;
+        }
+        break;
+    }
+
+    /* No valid transition found */
+    return 0;
+}
+
+/*
+ * ossl_statem_server_read_transition() encapsulates the logic for the allowed
+ * handshake state transitions when the server is reading messages from the
+ * client. The message type that the client has sent is provided in |mt|. The
+ * current state is in |s->statem.hand_state|.
+ *
+ * Return values are 1 for success (transition allowed) and  0 on error
+ * (transition not allowed)
+ */
+int ossl_statem_server_read_transition(SSL *s, int mt)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    if (SSL_IS_TLS13(s)) {
+        if (!ossl_statem_server13_read_transition(s, mt))
+            goto err;
+        return 1;
+    }
+
+    switch (st->hand_state) {
+    default:
+        break;
+
+    case TLS_ST_BEFORE:
+    case TLS_ST_OK:
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        if (mt == SSL3_MT_CLIENT_HELLO) {
+            st->hand_state = TLS_ST_SR_CLNT_HELLO;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_SW_SRVR_DONE:
+        /*
+         * If we get a CKE message after a ServerDone then either
+         * 1) We didn't request a Certificate
+         * OR
+         * 2) If we did request one then
+         *      a) We allow no Certificate to be returned
+         *      AND
+         *      b) We are running SSL3 (in TLS1.0+ the client must return a 0
+         *         list if we requested a certificate)
+         */
+        if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE) {
+            if (s->s3->tmp.cert_request) {
+                if (s->version == SSL3_VERSION) {
+                    if ((s->verify_mode & SSL_VERIFY_PEER)
+                        && (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
+                        /*
+                         * This isn't an unexpected message as such - we're just
+                         * not going to accept it because we require a client
+                         * cert.
+                         */
+                        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                                 SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION,
+                                 SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+                        return 0;
+                    }
+                    st->hand_state = TLS_ST_SR_KEY_EXCH;
+                    return 1;
+                }
+            } else {
+                st->hand_state = TLS_ST_SR_KEY_EXCH;
+                return 1;
+            }
+        } else if (s->s3->tmp.cert_request) {
+            if (mt == SSL3_MT_CERTIFICATE) {
+                st->hand_state = TLS_ST_SR_CERT;
+                return 1;
+            }
+        }
+        break;
+
+    case TLS_ST_SR_CERT:
+        if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE) {
+            st->hand_state = TLS_ST_SR_KEY_EXCH;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_SR_KEY_EXCH:
+        /*
+         * We should only process a CertificateVerify message if we have
+         * received a Certificate from the client. If so then |s->session->peer|
+         * will be non NULL. In some instances a CertificateVerify message is
+         * not required even if the peer has sent a Certificate (e.g. such as in
+         * the case of static DH). In that case |st->no_cert_verify| should be
+         * set.
+         */
+        if (s->session->peer == NULL || st->no_cert_verify) {
+            if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+                /*
+                 * For the ECDH ciphersuites when the client sends its ECDH
+                 * pub key in a certificate, the CertificateVerify message is
+                 * not sent. Also for GOST ciphersuites when the client uses
+                 * its key from the certificate for key exchange.
+                 */
+                st->hand_state = TLS_ST_SR_CHANGE;
+                return 1;
+            }
+        } else {
+            if (mt == SSL3_MT_CERTIFICATE_VERIFY) {
+                st->hand_state = TLS_ST_SR_CERT_VRFY;
+                return 1;
+            }
+        }
+        break;
+
+    case TLS_ST_SR_CERT_VRFY:
+        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_SR_CHANGE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_SR_CHANGE:
+#ifndef OPENSSL_NO_NEXTPROTONEG
+        if (s->s3->npn_seen) {
+            if (mt == SSL3_MT_NEXT_PROTO) {
+                st->hand_state = TLS_ST_SR_NEXT_PROTO;
+                return 1;
+            }
+        } else {
+#endif
+            if (mt == SSL3_MT_FINISHED) {
+                st->hand_state = TLS_ST_SR_FINISHED;
+                return 1;
+            }
+#ifndef OPENSSL_NO_NEXTPROTONEG
+        }
+#endif
+        break;
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    case TLS_ST_SR_NEXT_PROTO:
+        if (mt == SSL3_MT_FINISHED) {
+            st->hand_state = TLS_ST_SR_FINISHED;
+            return 1;
+        }
+        break;
+#endif
+
+    case TLS_ST_SW_FINISHED:
+        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_SR_CHANGE;
+            return 1;
+        }
+        break;
+    }
+
+ err:
+    /* No valid transition found */
+    if (SSL_IS_DTLS(s) && mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+        BIO *rbio;
+
+        /*
+         * CCS messages don't have a message sequence number so this is probably
+         * because of an out-of-order CCS. We'll just drop it.
+         */
+        s->init_num = 0;
+        s->rwstate = SSL_READING;
+        rbio = SSL_get_rbio(s);
+        BIO_clear_retry_flags(rbio);
+        BIO_set_retry_read(rbio);
+        return 0;
+    }
+    SSLfatal(s, SSL3_AD_UNEXPECTED_MESSAGE,
+             SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION,
+             SSL_R_UNEXPECTED_MESSAGE);
+    return 0;
+}
+
+/*
+ * Should we send a ServerKeyExchange message?
+ *
+ * Valid return values are:
+ *   1: Yes
+ *   0: No
+ */
+static int send_server_key_exchange(SSL *s)
+{
+    unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    /*
+     * only send a ServerKeyExchange if DH or fortezza but we have a
+     * sign only certificate PSK: may send PSK identity hints For
+     * ECC ciphersuites, we send a serverKeyExchange message only if
+     * the cipher suite is either ECDH-anon or ECDHE. In other cases,
+     * the server certificate contains the server's public key for
+     * key exchange.
+     */
+    if (alg_k & (SSL_kDHE | SSL_kECDHE)
+        /*
+         * PSK: send ServerKeyExchange if PSK identity hint if
+         * provided
+         */
+#ifndef OPENSSL_NO_PSK
+        /* Only send SKE if we have identity hint for plain PSK */
+        || ((alg_k & (SSL_kPSK | SSL_kRSAPSK))
+            && s->cert->psk_identity_hint)
+        /* For other PSK always send SKE */
+        || (alg_k & (SSL_PSK & (SSL_kDHEPSK | SSL_kECDHEPSK)))
+#endif
+#ifndef OPENSSL_NO_SRP
+        /* SRP: send ServerKeyExchange */
+        || (alg_k & SSL_kSRP)
+#endif
+        ) {
+        return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * Should we send a CertificateRequest message?
+ *
+ * Valid return values are:
+ *   1: Yes
+ *   0: No
+ */
+int send_certificate_request(SSL *s)
+{
+    if (
+           /* don't request cert unless asked for it: */
+           s->verify_mode & SSL_VERIFY_PEER
+           /*
+            * don't request if post-handshake-only unless doing
+            * post-handshake in TLSv1.3:
+            */
+           && (!SSL_IS_TLS13(s) || !(s->verify_mode & SSL_VERIFY_POST_HANDSHAKE)
+               || s->post_handshake_auth == SSL_PHA_REQUEST_PENDING)
+           /*
+            * if SSL_VERIFY_CLIENT_ONCE is set, don't request cert
+            * a second time:
+            */
+           && (s->certreqs_sent < 1 ||
+               !(s->verify_mode & SSL_VERIFY_CLIENT_ONCE))
+           /*
+            * never request cert in anonymous ciphersuites (see
+            * section "Certificate request" in SSL 3 drafts and in
+            * RFC 2246):
+            */
+           && (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+               /*
+                * ... except when the application insists on
+                * verification (against the specs, but statem_clnt.c accepts
+                * this for SSL 3)
+                */
+               || (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
+           /* don't request certificate for SRP auth */
+           && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aSRP)
+           /*
+            * With normal PSK Certificates and Certificate Requests
+            * are omitted
+            */
+           && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * ossl_statem_server13_write_transition() works out what handshake state to
+ * move to next when a TLSv1.3 server is writing messages to be sent to the
+ * client.
+ */
+static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    /*
+     * No case for TLS_ST_BEFORE, because at that stage we have not negotiated
+     * TLSv1.3 yet, so that is handled by ossl_statem_server_write_transition()
+     */
+
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_OSSL_STATEM_SERVER13_WRITE_TRANSITION,
+                 ERR_R_INTERNAL_ERROR);
+        return WRITE_TRAN_ERROR;
+
+    case TLS_ST_OK:
+        if (s->key_update != SSL_KEY_UPDATE_NONE) {
+            st->hand_state = TLS_ST_SW_KEY_UPDATE;
+            return WRITE_TRAN_CONTINUE;
+        }
+        if (s->post_handshake_auth == SSL_PHA_REQUEST_PENDING) {
+            st->hand_state = TLS_ST_SW_CERT_REQ;
+            return WRITE_TRAN_CONTINUE;
+        }
+        /* Try to read from the client instead */
+        return WRITE_TRAN_FINISHED;
+
+    case TLS_ST_SR_CLNT_HELLO:
+        st->hand_state = TLS_ST_SW_SRVR_HELLO;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_SRVR_HELLO:
+        if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0
+                && s->hello_retry_request != SSL_HRR_COMPLETE)
+            st->hand_state = TLS_ST_SW_CHANGE;
+        else if (s->hello_retry_request == SSL_HRR_PENDING)
+            st->hand_state = TLS_ST_EARLY_DATA;
+        else
+            st->hand_state = TLS_ST_SW_ENCRYPTED_EXTENSIONS;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_CHANGE:
+        if (s->hello_retry_request == SSL_HRR_PENDING)
+            st->hand_state = TLS_ST_EARLY_DATA;
+        else
+            st->hand_state = TLS_ST_SW_ENCRYPTED_EXTENSIONS;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_ENCRYPTED_EXTENSIONS:
+        if (s->hit)
+            st->hand_state = TLS_ST_SW_FINISHED;
+        else if (send_certificate_request(s))
+            st->hand_state = TLS_ST_SW_CERT_REQ;
+        else
+            st->hand_state = TLS_ST_SW_CERT;
+
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_CERT_REQ:
+        if (s->post_handshake_auth == SSL_PHA_REQUEST_PENDING) {
+            s->post_handshake_auth = SSL_PHA_REQUESTED;
+            st->hand_state = TLS_ST_OK;
+        } else {
+            st->hand_state = TLS_ST_SW_CERT;
+        }
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_CERT:
+        st->hand_state = TLS_ST_SW_CERT_VRFY;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_CERT_VRFY:
+        st->hand_state = TLS_ST_SW_FINISHED;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_FINISHED:
+        st->hand_state = TLS_ST_EARLY_DATA;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_EARLY_DATA:
+        return WRITE_TRAN_FINISHED;
+
+    case TLS_ST_SR_FINISHED:
+        /*
+         * Technically we have finished the handshake at this point, but we're
+         * going to remain "in_init" for now and write out any session tickets
+         * immediately.
+         */
+        if (s->post_handshake_auth == SSL_PHA_REQUESTED) {
+            s->post_handshake_auth = SSL_PHA_EXT_RECEIVED;
+        } else if (!s->ext.ticket_expected) {
+            /*
+             * If we're not going to renew the ticket then we just finish the
+             * handshake at this point.
+             */
+            st->hand_state = TLS_ST_OK;
+            return WRITE_TRAN_CONTINUE;
+        }
+        if (s->num_tickets > s->sent_tickets)
+            st->hand_state = TLS_ST_SW_SESSION_TICKET;
+        else
+            st->hand_state = TLS_ST_OK;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SR_KEY_UPDATE:
+    case TLS_ST_SW_KEY_UPDATE:
+        st->hand_state = TLS_ST_OK;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_SESSION_TICKET:
+        /* In a resumption we only ever send a maximum of one new ticket.
+         * Following an initial handshake we send the number of tickets we have
+         * been configured for.
+         */
+        if (s->hit || s->num_tickets <= s->sent_tickets) {
+            /* We've written enough tickets out. */
+            st->hand_state = TLS_ST_OK;
+        }
+        return WRITE_TRAN_CONTINUE;
+    }
+}
+
+/*
+ * ossl_statem_server_write_transition() works out what handshake state to move
+ * to next when the server is writing messages to be sent to the client.
+ */
+WRITE_TRAN ossl_statem_server_write_transition(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    /*
+     * Note that before the ClientHello we don't know what version we are going
+     * to negotiate yet, so we don't take this branch until later
+     */
+
+    if (SSL_IS_TLS13(s))
+        return ossl_statem_server13_write_transition(s);
+
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_OSSL_STATEM_SERVER_WRITE_TRANSITION,
+                 ERR_R_INTERNAL_ERROR);
+        return WRITE_TRAN_ERROR;
+
+    case TLS_ST_OK:
+        if (st->request_state == TLS_ST_SW_HELLO_REQ) {
+            /* We must be trying to renegotiate */
+            st->hand_state = TLS_ST_SW_HELLO_REQ;
+            st->request_state = TLS_ST_BEFORE;
+            return WRITE_TRAN_CONTINUE;
+        }
+        /* Must be an incoming ClientHello */
+        if (!tls_setup_handshake(s)) {
+            /* SSLfatal() already called */
+            return WRITE_TRAN_ERROR;
+        }
+        /* Fall through */
+
+    case TLS_ST_BEFORE:
+        /* Just go straight to trying to read from the client */
+        return WRITE_TRAN_FINISHED;
+
+    case TLS_ST_SW_HELLO_REQ:
+        st->hand_state = TLS_ST_OK;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SR_CLNT_HELLO:
+        if (SSL_IS_DTLS(s) && !s->d1->cookie_verified
+            && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)) {
+            st->hand_state = DTLS_ST_SW_HELLO_VERIFY_REQUEST;
+        } else if (s->renegotiate == 0 && !SSL_IS_FIRST_HANDSHAKE(s)) {
+            /* We must have rejected the renegotiation */
+            st->hand_state = TLS_ST_OK;
+            return WRITE_TRAN_CONTINUE;
+        } else {
+            st->hand_state = TLS_ST_SW_SRVR_HELLO;
+        }
+        return WRITE_TRAN_CONTINUE;
+
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        return WRITE_TRAN_FINISHED;
+
+    case TLS_ST_SW_SRVR_HELLO:
+        if (s->hit) {
+            if (s->ext.ticket_expected)
+                st->hand_state = TLS_ST_SW_SESSION_TICKET;
+            else
+                st->hand_state = TLS_ST_SW_CHANGE;
+        } else {
+            /* Check if it is anon DH or anon ECDH, */
+            /* normal PSK or SRP */
+            if (!(s->s3->tmp.new_cipher->algorithm_auth &
+                  (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
+                st->hand_state = TLS_ST_SW_CERT;
+            } else if (send_server_key_exchange(s)) {
+                st->hand_state = TLS_ST_SW_KEY_EXCH;
+            } else if (send_certificate_request(s)) {
+                st->hand_state = TLS_ST_SW_CERT_REQ;
+            } else {
+                st->hand_state = TLS_ST_SW_SRVR_DONE;
+            }
+        }
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_CERT:
+        if (s->ext.status_expected) {
+            st->hand_state = TLS_ST_SW_CERT_STATUS;
+            return WRITE_TRAN_CONTINUE;
+        }
+        /* Fall through */
+
+    case TLS_ST_SW_CERT_STATUS:
+        if (send_server_key_exchange(s)) {
+            st->hand_state = TLS_ST_SW_KEY_EXCH;
+            return WRITE_TRAN_CONTINUE;
+        }
+        /* Fall through */
+
+    case TLS_ST_SW_KEY_EXCH:
+        if (send_certificate_request(s)) {
+            st->hand_state = TLS_ST_SW_CERT_REQ;
+            return WRITE_TRAN_CONTINUE;
+        }
+        /* Fall through */
+
+    case TLS_ST_SW_CERT_REQ:
+        st->hand_state = TLS_ST_SW_SRVR_DONE;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_SRVR_DONE:
+        return WRITE_TRAN_FINISHED;
+
+    case TLS_ST_SR_FINISHED:
+        if (s->hit) {
+            st->hand_state = TLS_ST_OK;
+            return WRITE_TRAN_CONTINUE;
+        } else if (s->ext.ticket_expected) {
+            st->hand_state = TLS_ST_SW_SESSION_TICKET;
+        } else {
+            st->hand_state = TLS_ST_SW_CHANGE;
+        }
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_SESSION_TICKET:
+        st->hand_state = TLS_ST_SW_CHANGE;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_CHANGE:
+        st->hand_state = TLS_ST_SW_FINISHED;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_FINISHED:
+        if (s->hit) {
+            return WRITE_TRAN_FINISHED;
+        }
+        st->hand_state = TLS_ST_OK;
+        return WRITE_TRAN_CONTINUE;
+    }
+}
+
+/*
+ * Perform any pre work that needs to be done prior to sending a message from
+ * the server to the client.
+ */
+WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch (st->hand_state) {
+    default:
+        /* No pre work to be done */
+        break;
+
+    case TLS_ST_SW_HELLO_REQ:
+        s->shutdown = 0;
+        if (SSL_IS_DTLS(s))
+            dtls1_clear_sent_buffer(s);
+        break;
+
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        s->shutdown = 0;
+        if (SSL_IS_DTLS(s)) {
+            dtls1_clear_sent_buffer(s);
+            /* We don't buffer this message so don't use the timer */
+            st->use_timer = 0;
+        }
+        break;
+
+    case TLS_ST_SW_SRVR_HELLO:
+        if (SSL_IS_DTLS(s)) {
+            /*
+             * Messages we write from now on should be buffered and
+             * retransmitted if necessary, so we need to use the timer now
+             */
+            st->use_timer = 1;
+        }
+        break;
+
+    case TLS_ST_SW_SRVR_DONE:
+#ifndef OPENSSL_NO_SCTP
+        if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) {
+            /* Calls SSLfatal() as required */
+            return dtls_wait_for_dry(s);
+        }
+#endif
+        return WORK_FINISHED_CONTINUE;
+
+    case TLS_ST_SW_SESSION_TICKET:
+        if (SSL_IS_TLS13(s) && s->sent_tickets == 0) {
+            /*
+             * Actually this is the end of the handshake, but we're going
+             * straight into writing the session ticket out. So we finish off
+             * the handshake, but keep the various buffers active.
+             *
+             * Calls SSLfatal as required.
+             */
+            return tls_finish_handshake(s, wst, 0, 0);
+        } if (SSL_IS_DTLS(s)) {
+            /*
+             * We're into the last flight. We don't retransmit the last flight
+             * unless we need to, so we don't use the timer
+             */
+            st->use_timer = 0;
+        }
+        break;
+
+    case TLS_ST_SW_CHANGE:
+        if (SSL_IS_TLS13(s))
+            break;
+        /* Writes to s->session are only safe for initial handshakes */
+        if (s->session->cipher == NULL) {
+            s->session->cipher = s->s3->tmp.new_cipher;
+        } else if (s->session->cipher != s->s3->tmp.new_cipher) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_OSSL_STATEM_SERVER_PRE_WORK,
+                     ERR_R_INTERNAL_ERROR);
+            return WORK_ERROR;
+        }
+        if (!s->method->ssl3_enc->setup_key_block(s)) {
+            /* SSLfatal() already called */
+            return WORK_ERROR;
+        }
+        if (SSL_IS_DTLS(s)) {
+            /*
+             * We're into the last flight. We don't retransmit the last flight
+             * unless we need to, so we don't use the timer. This might have
+             * already been set to 0 if we sent a NewSessionTicket message,
+             * but we'll set it again here in case we didn't.
+             */
+            st->use_timer = 0;
+        }
+        return WORK_FINISHED_CONTINUE;
+
+    case TLS_ST_EARLY_DATA:
+        if (s->early_data_state != SSL_EARLY_DATA_ACCEPTING
+                && (s->s3->flags & TLS1_FLAGS_STATELESS) == 0)
+            return WORK_FINISHED_CONTINUE;
+        /* Fall through */
+
+    case TLS_ST_OK:
+        /* Calls SSLfatal() as required */
+        return tls_finish_handshake(s, wst, 1, 1);
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+static ossl_inline int conn_is_closed(void)
+{
+    switch (get_last_sys_error()) {
+#if defined(EPIPE)
+    case EPIPE:
+        return 1;
+#endif
+#if defined(ECONNRESET)
+    case ECONNRESET:
+        return 1;
+#endif
+#if defined(WSAECONNRESET)
+    case WSAECONNRESET:
+        return 1;
+#endif
+    default:
+        return 0;
+    }
+}
+
+/*
+ * Perform any work that needs to be done after sending a message from the
+ * server to the client.
+ */
+WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    s->init_num = 0;
+
+    switch (st->hand_state) {
+    default:
+        /* No post work to be done */
+        break;
+
+    case TLS_ST_SW_HELLO_REQ:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+        if (!ssl3_init_finished_mac(s)) {
+            /* SSLfatal() already called */
+            return WORK_ERROR;
+        }
+        break;
+
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+        /* HelloVerifyRequest resets Finished MAC */
+        if (s->version != DTLS1_BAD_VER && !ssl3_init_finished_mac(s)) {
+            /* SSLfatal() already called */
+            return WORK_ERROR;
+        }
+        /*
+         * The next message should be another ClientHello which we need to
+         * treat like it was the first packet
+         */
+        s->first_packet = 1;
+        break;
+
+    case TLS_ST_SW_SRVR_HELLO:
+        if (SSL_IS_TLS13(s) && s->hello_retry_request == SSL_HRR_PENDING) {
+            if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) == 0
+                    && statem_flush(s) != 1)
+                return WORK_MORE_A;
+            break;
+        }
+#ifndef OPENSSL_NO_SCTP
+        if (SSL_IS_DTLS(s) && s->hit) {
+            unsigned char sctpauthkey[64];
+            char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+            size_t labellen;
+
+            /*
+             * Add new shared key for SCTP-Auth, will be ignored if no
+             * SCTP used.
+             */
+            memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
+                   sizeof(DTLS1_SCTP_AUTH_LABEL));
+
+            /* Don't include the terminating zero. */
+            labellen = sizeof(labelbuffer) - 1;
+            if (s->mode & SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG)
+                labellen += 1;
+
+            if (SSL_export_keying_material(s, sctpauthkey,
+                                           sizeof(sctpauthkey), labelbuffer,
+                                           labellen, NULL, 0,
+                                           0) <= 0) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_OSSL_STATEM_SERVER_POST_WORK,
+                         ERR_R_INTERNAL_ERROR);
+                return WORK_ERROR;
+            }
+
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+                     sizeof(sctpauthkey), sctpauthkey);
+        }
+#endif
+        if (!SSL_IS_TLS13(s)
+                || ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0
+                    && s->hello_retry_request != SSL_HRR_COMPLETE))
+            break;
+        /* Fall through */
+
+    case TLS_ST_SW_CHANGE:
+        if (s->hello_retry_request == SSL_HRR_PENDING) {
+            if (!statem_flush(s))
+                return WORK_MORE_A;
+            break;
+        }
+
+        if (SSL_IS_TLS13(s)) {
+            if (!s->method->ssl3_enc->setup_key_block(s)
+                || !s->method->ssl3_enc->change_cipher_state(s,
+                        SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
+                /* SSLfatal() already called */
+                return WORK_ERROR;
+            }
+
+            if (s->ext.early_data != SSL_EARLY_DATA_ACCEPTED
+                && !s->method->ssl3_enc->change_cipher_state(s,
+                        SSL3_CC_HANDSHAKE |SSL3_CHANGE_CIPHER_SERVER_READ)) {
+                /* SSLfatal() already called */
+                return WORK_ERROR;
+            }
+            /*
+             * We don't yet know whether the next record we are going to receive
+             * is an unencrypted alert, an encrypted alert, or an encrypted
+             * handshake message. We temporarily tolerate unencrypted alerts.
+             */
+            s->statem.enc_read_state = ENC_READ_STATE_ALLOW_PLAIN_ALERTS;
+            break;
+        }
+
+#ifndef OPENSSL_NO_SCTP
+        if (SSL_IS_DTLS(s) && !s->hit) {
+            /*
+             * Change to new shared key of SCTP-Auth, will be ignored if
+             * no SCTP used.
+             */
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+                     0, NULL);
+        }
+#endif
+        if (!s->method->ssl3_enc->change_cipher_state(s,
+                                                      SSL3_CHANGE_CIPHER_SERVER_WRITE))
+        {
+            /* SSLfatal() already called */
+            return WORK_ERROR;
+        }
+
+        if (SSL_IS_DTLS(s))
+            dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
+        break;
+
+    case TLS_ST_SW_SRVR_DONE:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+        break;
+
+    case TLS_ST_SW_FINISHED:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+#ifndef OPENSSL_NO_SCTP
+        if (SSL_IS_DTLS(s) && s->hit) {
+            /*
+             * Change to new shared key of SCTP-Auth, will be ignored if
+             * no SCTP used.
+             */
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+                     0, NULL);
+        }
+#endif
+        if (SSL_IS_TLS13(s)) {
+            /* TLS 1.3 gets the secret size from the handshake md */
+            size_t dummy;
+            if (!s->method->ssl3_enc->generate_master_secret(s,
+                        s->master_secret, s->handshake_secret, 0,
+                        &dummy)
+                || !s->method->ssl3_enc->change_cipher_state(s,
+                        SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_SERVER_WRITE))
+            /* SSLfatal() already called */
+            return WORK_ERROR;
+        }
+        break;
+
+    case TLS_ST_SW_CERT_REQ:
+        if (s->post_handshake_auth == SSL_PHA_REQUEST_PENDING) {
+            if (statem_flush(s) != 1)
+                return WORK_MORE_A;
+        }
+        break;
+
+    case TLS_ST_SW_KEY_UPDATE:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+        if (!tls13_update_key(s, 1)) {
+            /* SSLfatal() already called */
+            return WORK_ERROR;
+        }
+        break;
+
+    case TLS_ST_SW_SESSION_TICKET:
+        clear_sys_error();
+        if (SSL_IS_TLS13(s) && statem_flush(s) != 1) {
+            if (SSL_get_error(s, 0) == SSL_ERROR_SYSCALL
+                    && conn_is_closed()) {
+                /*
+                 * We ignore connection closed errors in TLSv1.3 when sending a
+                 * NewSessionTicket and behave as if we were successful. This is
+                 * so that we are still able to read data sent to us by a client
+                 * that closes soon after the end of the handshake without
+                 * waiting to read our post-handshake NewSessionTickets.
+                 */
+                s->rwstate = SSL_NOTHING;
+                break;
+            }
+
+            return WORK_MORE_A;
+        }
+        break;
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+/*
+ * Get the message construction function and message type for sending from the
+ * server
+ *
+ * Valid return values are:
+ *   1: Success
+ *   0: Error
+ */
+int ossl_statem_server_construct_message(SSL *s, WPACKET *pkt,
+                                         confunc_f *confunc, int *mt)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_OSSL_STATEM_SERVER_CONSTRUCT_MESSAGE,
+                 SSL_R_BAD_HANDSHAKE_STATE);
+        return 0;
+
+    case TLS_ST_SW_CHANGE:
+        if (SSL_IS_DTLS(s))
+            *confunc = dtls_construct_change_cipher_spec;
+        else
+            *confunc = tls_construct_change_cipher_spec;
+        *mt = SSL3_MT_CHANGE_CIPHER_SPEC;
+        break;
+
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        *confunc = dtls_construct_hello_verify_request;
+        *mt = DTLS1_MT_HELLO_VERIFY_REQUEST;
+        break;
+
+    case TLS_ST_SW_HELLO_REQ:
+        /* No construction function needed */
+        *confunc = NULL;
+        *mt = SSL3_MT_HELLO_REQUEST;
+        break;
+
+    case TLS_ST_SW_SRVR_HELLO:
+        *confunc = tls_construct_server_hello;
+        *mt = SSL3_MT_SERVER_HELLO;
+        break;
+
+    case TLS_ST_SW_CERT:
+        *confunc = tls_construct_server_certificate;
+        *mt = SSL3_MT_CERTIFICATE;
+        break;
+
+    case TLS_ST_SW_CERT_VRFY:
+        *confunc = tls_construct_cert_verify;
+        *mt = SSL3_MT_CERTIFICATE_VERIFY;
+        break;
+
+
+    case TLS_ST_SW_KEY_EXCH:
+        *confunc = tls_construct_server_key_exchange;
+        *mt = SSL3_MT_SERVER_KEY_EXCHANGE;
+        break;
+
+    case TLS_ST_SW_CERT_REQ:
+        *confunc = tls_construct_certificate_request;
+        *mt = SSL3_MT_CERTIFICATE_REQUEST;
+        break;
+
+    case TLS_ST_SW_SRVR_DONE:
+        *confunc = tls_construct_server_done;
+        *mt = SSL3_MT_SERVER_DONE;
+        break;
+
+    case TLS_ST_SW_SESSION_TICKET:
+        *confunc = tls_construct_new_session_ticket;
+        *mt = SSL3_MT_NEWSESSION_TICKET;
+        break;
+
+    case TLS_ST_SW_CERT_STATUS:
+        *confunc = tls_construct_cert_status;
+        *mt = SSL3_MT_CERTIFICATE_STATUS;
+        break;
+
+    case TLS_ST_SW_FINISHED:
+        *confunc = tls_construct_finished;
+        *mt = SSL3_MT_FINISHED;
+        break;
+
+    case TLS_ST_EARLY_DATA:
+        *confunc = NULL;
+        *mt = SSL3_MT_DUMMY;
+        break;
+
+    case TLS_ST_SW_ENCRYPTED_EXTENSIONS:
+        *confunc = tls_construct_encrypted_extensions;
+        *mt = SSL3_MT_ENCRYPTED_EXTENSIONS;
+        break;
+
+    case TLS_ST_SW_KEY_UPDATE:
+        *confunc = tls_construct_key_update;
+        *mt = SSL3_MT_KEY_UPDATE;
+        break;
+    }
+
+    return 1;
+}
+
+/*
+ * Maximum size (excluding the Handshake header) of a ClientHello message,
+ * calculated as follows:
+ *
+ *  2 + # client_version
+ *  32 + # only valid length for random
+ *  1 + # length of session_id
+ *  32 + # maximum size for session_id
+ *  2 + # length of cipher suites
+ *  2^16-2 + # maximum length of cipher suites array
+ *  1 + # length of compression_methods
+ *  2^8-1 + # maximum length of compression methods
+ *  2 + # length of extensions
+ *  2^16-1 # maximum length of extensions
+ */
+#define CLIENT_HELLO_MAX_LENGTH         131396
+
+#define CLIENT_KEY_EXCH_MAX_LENGTH      2048
+#define NEXT_PROTO_MAX_LENGTH           514
+
+/*
+ * Returns the maximum allowed length for the current message that we are
+ * reading. Excludes the message header.
+ */
+size_t ossl_statem_server_max_message_size(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        return 0;
+
+    case TLS_ST_SR_CLNT_HELLO:
+        return CLIENT_HELLO_MAX_LENGTH;
+
+    case TLS_ST_SR_END_OF_EARLY_DATA:
+        return END_OF_EARLY_DATA_MAX_LENGTH;
+
+    case TLS_ST_SR_CERT:
+        return s->max_cert_list;
+
+    case TLS_ST_SR_KEY_EXCH:
+        return CLIENT_KEY_EXCH_MAX_LENGTH;
+
+    case TLS_ST_SR_CERT_VRFY:
+        return SSL3_RT_MAX_PLAIN_LENGTH;
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    case TLS_ST_SR_NEXT_PROTO:
+        return NEXT_PROTO_MAX_LENGTH;
+#endif
+
+    case TLS_ST_SR_CHANGE:
+        return CCS_MAX_LENGTH;
+
+    case TLS_ST_SR_FINISHED:
+        return FINISHED_MAX_LENGTH;
+
+    case TLS_ST_SR_KEY_UPDATE:
+        return KEY_UPDATE_MAX_LENGTH;
+    }
+}
+
+/*
+ * Process a message that the server has received from the client.
+ */
+MSG_PROCESS_RETURN ossl_statem_server_process_message(SSL *s, PACKET *pkt)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_OSSL_STATEM_SERVER_PROCESS_MESSAGE,
+                 ERR_R_INTERNAL_ERROR);
+        return MSG_PROCESS_ERROR;
+
+    case TLS_ST_SR_CLNT_HELLO:
+        return tls_process_client_hello(s, pkt);
+
+    case TLS_ST_SR_END_OF_EARLY_DATA:
+        return tls_process_end_of_early_data(s, pkt);
+
+    case TLS_ST_SR_CERT:
+        return tls_process_client_certificate(s, pkt);
+
+    case TLS_ST_SR_KEY_EXCH:
+        return tls_process_client_key_exchange(s, pkt);
+
+    case TLS_ST_SR_CERT_VRFY:
+        return tls_process_cert_verify(s, pkt);
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    case TLS_ST_SR_NEXT_PROTO:
+        return tls_process_next_proto(s, pkt);
+#endif
+
+    case TLS_ST_SR_CHANGE:
+        return tls_process_change_cipher_spec(s, pkt);
+
+    case TLS_ST_SR_FINISHED:
+        return tls_process_finished(s, pkt);
+
+    case TLS_ST_SR_KEY_UPDATE:
+        return tls_process_key_update(s, pkt);
+
+    }
+}
+
+/*
+ * Perform any further processing required following the receipt of a message
+ * from the client
+ */
+WORK_STATE ossl_statem_server_post_process_message(SSL *s, WORK_STATE wst)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_OSSL_STATEM_SERVER_POST_PROCESS_MESSAGE,
+                 ERR_R_INTERNAL_ERROR);
+        return WORK_ERROR;
+
+    case TLS_ST_SR_CLNT_HELLO:
+        return tls_post_process_client_hello(s, wst);
+
+    case TLS_ST_SR_KEY_EXCH:
+        return tls_post_process_client_key_exchange(s, wst);
+    }
+}
+
+#ifndef OPENSSL_NO_SRP
+/* Returns 1 on success, 0 for retryable error, -1 for fatal error */
+static int ssl_check_srp_ext_ClientHello(SSL *s)
+{
+    int ret;
+    int al = SSL_AD_UNRECOGNIZED_NAME;
+
+    if ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) &&
+        (s->srp_ctx.TLS_ext_srp_username_callback != NULL)) {
+        if (s->srp_ctx.login == NULL) {
+            /*
+             * RFC 5054 says SHOULD reject, we do so if There is no srp
+             * login name
+             */
+            SSLfatal(s, SSL_AD_UNKNOWN_PSK_IDENTITY,
+                     SSL_F_SSL_CHECK_SRP_EXT_CLIENTHELLO,
+                     SSL_R_PSK_IDENTITY_NOT_FOUND);
+            return -1;
+        } else {
+            ret = SSL_srp_server_param_with_username(s, &al);
+            if (ret < 0)
+                return 0;
+            if (ret == SSL3_AL_FATAL) {
+                SSLfatal(s, al, SSL_F_SSL_CHECK_SRP_EXT_CLIENTHELLO,
+                         al == SSL_AD_UNKNOWN_PSK_IDENTITY
+                         ? SSL_R_PSK_IDENTITY_NOT_FOUND
+                         : SSL_R_CLIENTHELLO_TLSEXT);
+                return -1;
+            }
+        }
+    }
+    return 1;
+}
+#endif
+
+int dtls_raw_hello_verify_request(WPACKET *pkt, unsigned char *cookie,
+                                  size_t cookie_len)
+{
+    /* Always use DTLS 1.0 version: see RFC 6347 */
+    if (!WPACKET_put_bytes_u16(pkt, DTLS1_VERSION)
+            || !WPACKET_sub_memcpy_u8(pkt, cookie, cookie_len))
+        return 0;
+
+    return 1;
+}
+
+int dtls_construct_hello_verify_request(SSL *s, WPACKET *pkt)
+{
+    unsigned int cookie_leni;
+    if (s->ctx->app_gen_cookie_cb == NULL ||
+        s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
+                                  &cookie_leni) == 0 ||
+        cookie_leni > 255) {
+        SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_DTLS_CONSTRUCT_HELLO_VERIFY_REQUEST,
+                 SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
+        return 0;
+    }
+    s->d1->cookie_len = cookie_leni;
+
+    if (!dtls_raw_hello_verify_request(pkt, s->d1->cookie,
+                                              s->d1->cookie_len)) {
+        SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_DTLS_CONSTRUCT_HELLO_VERIFY_REQUEST,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_EC
+/*-
+ * ssl_check_for_safari attempts to fingerprint Safari using OS X
+ * SecureTransport using the TLS extension block in |hello|.
+ * Safari, since 10.6, sends exactly these extensions, in this order:
+ *   SNI,
+ *   elliptic_curves
+ *   ec_point_formats
+ *   signature_algorithms (for TLSv1.2 only)
+ *
+ * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8,
+ * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them.
+ * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from
+ * 10.8..10.8.3 (which don't work).
+ */
+static void ssl_check_for_safari(SSL *s, const CLIENTHELLO_MSG *hello)
+{
+    static const unsigned char kSafariExtensionsBlock[] = {
+        0x00, 0x0a,             /* elliptic_curves extension */
+        0x00, 0x08,             /* 8 bytes */
+        0x00, 0x06,             /* 6 bytes of curve ids */
+        0x00, 0x17,             /* P-256 */
+        0x00, 0x18,             /* P-384 */
+        0x00, 0x19,             /* P-521 */
+
+        0x00, 0x0b,             /* ec_point_formats */
+        0x00, 0x02,             /* 2 bytes */
+        0x01,                   /* 1 point format */
+        0x00,                   /* uncompressed */
+        /* The following is only present in TLS 1.2 */
+        0x00, 0x0d,             /* signature_algorithms */
+        0x00, 0x0c,             /* 12 bytes */
+        0x00, 0x0a,             /* 10 bytes */
+        0x05, 0x01,             /* SHA-384/RSA */
+        0x04, 0x01,             /* SHA-256/RSA */
+        0x02, 0x01,             /* SHA-1/RSA */
+        0x04, 0x03,             /* SHA-256/ECDSA */
+        0x02, 0x03,             /* SHA-1/ECDSA */
+    };
+    /* Length of the common prefix (first two extensions). */
+    static const size_t kSafariCommonExtensionsLength = 18;
+    unsigned int type;
+    PACKET sni, tmppkt;
+    size_t ext_len;
+
+    tmppkt = hello->extensions;
+
+    if (!PACKET_forward(&tmppkt, 2)
+        || !PACKET_get_net_2(&tmppkt, &type)
+        || !PACKET_get_length_prefixed_2(&tmppkt, &sni)) {
+        return;
+    }
+
+    if (type != TLSEXT_TYPE_server_name)
+        return;
+
+    ext_len = TLS1_get_client_version(s) >= TLS1_2_VERSION ?
+        sizeof(kSafariExtensionsBlock) : kSafariCommonExtensionsLength;
+
+    s->s3->is_probably_safari = PACKET_equal(&tmppkt, kSafariExtensionsBlock,
+                                             ext_len);
+}
+#endif                          /* !OPENSSL_NO_EC */
+
+MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
+{
+    /* |cookie| will only be initialized for DTLS. */
+    PACKET session_id, compression, extensions, cookie;
+    static const unsigned char null_compression = 0;
+    CLIENTHELLO_MSG *clienthello = NULL;
+
+    /* Check if this is actually an unexpected renegotiation ClientHello */
+    if (s->renegotiate == 0 && !SSL_IS_FIRST_HANDSHAKE(s)) {
+        if (!ossl_assert(!SSL_IS_TLS13(s))) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        if ((s->options & SSL_OP_NO_RENEGOTIATION) != 0
+                || (!s->s3->send_connection_binding
+                    && (s->options
+                        & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) == 0)) {
+            ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION);
+            return MSG_PROCESS_FINISHED_READING;
+        }
+        s->renegotiate = 1;
+        s->new_session = 1;
+    }
+
+    clienthello = OPENSSL_zalloc(sizeof(*clienthello));
+    if (clienthello == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /*
+     * First, parse the raw ClientHello data into the CLIENTHELLO_MSG structure.
+     */
+    clienthello->isv2 = RECORD_LAYER_is_sslv2_record(&s->rlayer);
+    PACKET_null_init(&cookie);
+
+    if (clienthello->isv2) {
+        unsigned int mt;
+
+        if (!SSL_IS_FIRST_HANDSHAKE(s)
+                || s->hello_retry_request != SSL_HRR_NONE) {
+            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+                     SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNEXPECTED_MESSAGE);
+            goto err;
+        }
+
+        /*-
+         * An SSLv3/TLSv1 backwards-compatible CLIENT-HELLO in an SSLv2
+         * header is sent directly on the wire, not wrapped as a TLS
+         * record. Our record layer just processes the message length and passes
+         * the rest right through. Its format is:
+         * Byte  Content
+         * 0-1   msg_length - decoded by the record layer
+         * 2     msg_type - s->init_msg points here
+         * 3-4   version
+         * 5-6   cipher_spec_length
+         * 7-8   session_id_length
+         * 9-10  challenge_length
+         * ...   ...
+         */
+
+        if (!PACKET_get_1(pkt, &mt)
+            || mt != SSL2_MT_CLIENT_HELLO) {
+            /*
+             * Should never happen. We should have tested this in the record
+             * layer in order to have determined that this is a SSLv2 record
+             * in the first place
+             */
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+
+    if (!PACKET_get_net_2(pkt, &clienthello->legacy_version)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                 SSL_R_LENGTH_TOO_SHORT);
+        goto err;
+    }
+
+    /* Parse the message and load client random. */
+    if (clienthello->isv2) {
+        /*
+         * Handle an SSLv2 backwards compatible ClientHello
+         * Note, this is only for SSLv3+ using the backward compatible format.
+         * Real SSLv2 is not supported, and is rejected below.
+         */
+        unsigned int ciphersuite_len, session_id_len, challenge_len;
+        PACKET challenge;
+
+        if (!PACKET_get_net_2(pkt, &ciphersuite_len)
+            || !PACKET_get_net_2(pkt, &session_id_len)
+            || !PACKET_get_net_2(pkt, &challenge_len)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                     SSL_R_RECORD_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        if (session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        if (!PACKET_get_sub_packet(pkt, &clienthello->ciphersuites,
+                                   ciphersuite_len)
+            || !PACKET_copy_bytes(pkt, clienthello->session_id, session_id_len)
+            || !PACKET_get_sub_packet(pkt, &challenge, challenge_len)
+            /* No extensions. */
+            || PACKET_remaining(pkt) != 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                     SSL_R_RECORD_LENGTH_MISMATCH);
+            goto err;
+        }
+        clienthello->session_id_len = session_id_len;
+
+        /* Load the client random and compression list. We use SSL3_RANDOM_SIZE
+         * here rather than sizeof(clienthello->random) because that is the limit
+         * for SSLv3 and it is fixed. It won't change even if
+         * sizeof(clienthello->random) does.
+         */
+        challenge_len = challenge_len > SSL3_RANDOM_SIZE
+                        ? SSL3_RANDOM_SIZE : challenge_len;
+        memset(clienthello->random, 0, SSL3_RANDOM_SIZE);
+        if (!PACKET_copy_bytes(&challenge,
+                               clienthello->random + SSL3_RANDOM_SIZE -
+                               challenge_len, challenge_len)
+            /* Advertise only null compression. */
+            || !PACKET_buf_init(&compression, &null_compression, 1)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        PACKET_null_init(&clienthello->extensions);
+    } else {
+        /* Regular ClientHello. */
+        if (!PACKET_copy_bytes(pkt, clienthello->random, SSL3_RANDOM_SIZE)
+            || !PACKET_get_length_prefixed_1(pkt, &session_id)
+            || !PACKET_copy_all(&session_id, clienthello->session_id,
+                    SSL_MAX_SSL_SESSION_ID_LENGTH,
+                    &clienthello->session_id_len)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                     SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        if (SSL_IS_DTLS(s)) {
+            if (!PACKET_get_length_prefixed_1(pkt, &cookie)) {
+                SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                         SSL_R_LENGTH_MISMATCH);
+                goto err;
+            }
+            if (!PACKET_copy_all(&cookie, clienthello->dtls_cookie,
+                                 DTLS1_COOKIE_LENGTH,
+                                 &clienthello->dtls_cookie_len)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            /*
+             * If we require cookies and this ClientHello doesn't contain one,
+             * just return since we do not want to allocate any memory yet.
+             * So check cookie length...
+             */
+            if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) {
+                if (clienthello->dtls_cookie_len == 0) {
+                    OPENSSL_free(clienthello);
+                    return MSG_PROCESS_FINISHED_READING;
+                }
+            }
+        }
+
+        if (!PACKET_get_length_prefixed_2(pkt, &clienthello->ciphersuites)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                     SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        if (!PACKET_get_length_prefixed_1(pkt, &compression)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                     SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        /* Could be empty. */
+        if (PACKET_remaining(pkt) == 0) {
+            PACKET_null_init(&clienthello->extensions);
+        } else {
+            if (!PACKET_get_length_prefixed_2(pkt, &clienthello->extensions)
+                    || PACKET_remaining(pkt) != 0) {
+                SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                         SSL_R_LENGTH_MISMATCH);
+                goto err;
+            }
+        }
+    }
+
+    if (!PACKET_copy_all(&compression, clienthello->compressions,
+                         MAX_COMPRESSIONS_SIZE,
+                         &clienthello->compressions_len)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /* Preserve the raw extensions PACKET for later use */
+    extensions = clienthello->extensions;
+    if (!tls_collect_extensions(s, &extensions, SSL_EXT_CLIENT_HELLO,
+                                &clienthello->pre_proc_exts,
+                                &clienthello->pre_proc_exts_len, 1)) {
+        /* SSLfatal already been called */
+        goto err;
+    }
+    s->clienthello = clienthello;
+
+    return MSG_PROCESS_CONTINUE_PROCESSING;
+
+ err:
+    if (clienthello != NULL)
+        OPENSSL_free(clienthello->pre_proc_exts);
+    OPENSSL_free(clienthello);
+
+    return MSG_PROCESS_ERROR;
+}
+
+static int tls_early_post_process_client_hello(SSL *s)
+{
+    unsigned int j;
+    int i, al = SSL_AD_INTERNAL_ERROR;
+    int protverr;
+    size_t loop;
+    unsigned long id;
+#ifndef OPENSSL_NO_COMP
+    SSL_COMP *comp = NULL;
+#endif
+    const SSL_CIPHER *c;
+    STACK_OF(SSL_CIPHER) *ciphers = NULL;
+    STACK_OF(SSL_CIPHER) *scsvs = NULL;
+    CLIENTHELLO_MSG *clienthello = s->clienthello;
+    DOWNGRADE dgrd = DOWNGRADE_NONE;
+
+    /* Finished parsing the ClientHello, now we can start processing it */
+    /* Give the ClientHello callback a crack at things */
+    if (s->ctx->client_hello_cb != NULL) {
+        /* A failure in the ClientHello callback terminates the connection. */
+        switch (s->ctx->client_hello_cb(s, &al, s->ctx->client_hello_cb_arg)) {
+        case SSL_CLIENT_HELLO_SUCCESS:
+            break;
+        case SSL_CLIENT_HELLO_RETRY:
+            s->rwstate = SSL_CLIENT_HELLO_CB;
+            return -1;
+        case SSL_CLIENT_HELLO_ERROR:
+        default:
+            SSLfatal(s, al,
+                     SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                     SSL_R_CALLBACK_FAILED);
+            goto err;
+        }
+    }
+
+    /* Set up the client_random */
+    memcpy(s->s3->client_random, clienthello->random, SSL3_RANDOM_SIZE);
+
+    /* Choose the version */
+
+    if (clienthello->isv2) {
+        if (clienthello->legacy_version == SSL2_VERSION
+                || (clienthello->legacy_version & 0xff00)
+                   != (SSL3_VERSION_MAJOR << 8)) {
+            /*
+             * This is real SSLv2 or something completely unknown. We don't
+             * support it.
+             */
+            SSLfatal(s, SSL_AD_PROTOCOL_VERSION,
+                     SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                     SSL_R_UNKNOWN_PROTOCOL);
+            goto err;
+        }
+        /* SSLv3/TLS */
+        s->client_version = clienthello->legacy_version;
+    }
+    /*
+     * Do SSL/TLS version negotiation if applicable. For DTLS we just check
+     * versions are potentially compatible. Version negotiation comes later.
+     */
+    if (!SSL_IS_DTLS(s)) {
+        protverr = ssl_choose_server_version(s, clienthello, &dgrd);
+    } else if (s->method->version != DTLS_ANY_VERSION &&
+               DTLS_VERSION_LT((int)clienthello->legacy_version, s->version)) {
+        protverr = SSL_R_VERSION_TOO_LOW;
+    } else {
+        protverr = 0;
+    }
+
+    if (protverr) {
+        if (SSL_IS_FIRST_HANDSHAKE(s)) {
+            /* like ssl3_get_record, send alert using remote version number */
+            s->version = s->client_version = clienthello->legacy_version;
+        }
+        SSLfatal(s, SSL_AD_PROTOCOL_VERSION,
+                 SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO, protverr);
+        goto err;
+    }
+
+    /* TLSv1.3 specifies that a ClientHello must end on a record boundary */
+    if (SSL_IS_TLS13(s) && RECORD_LAYER_processed_read_pending(&s->rlayer)) {
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+                 SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                 SSL_R_NOT_ON_RECORD_BOUNDARY);
+        goto err;
+    }
+
+    if (SSL_IS_DTLS(s)) {
+        /* Empty cookie was already handled above by returning early. */
+        if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) {
+            if (s->ctx->app_verify_cookie_cb != NULL) {
+                if (s->ctx->app_verify_cookie_cb(s, clienthello->dtls_cookie,
+                        clienthello->dtls_cookie_len) == 0) {
+                    SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                             SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                             SSL_R_COOKIE_MISMATCH);
+                    goto err;
+                    /* else cookie verification succeeded */
+                }
+                /* default verification */
+            } else if (s->d1->cookie_len != clienthello->dtls_cookie_len
+                    || memcmp(clienthello->dtls_cookie, s->d1->cookie,
+                              s->d1->cookie_len) != 0) {
+                SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                         SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                         SSL_R_COOKIE_MISMATCH);
+                goto err;
+            }
+            s->d1->cookie_verified = 1;
+        }
+        if (s->method->version == DTLS_ANY_VERSION) {
+            protverr = ssl_choose_server_version(s, clienthello, &dgrd);
+            if (protverr != 0) {
+                s->version = s->client_version;
+                SSLfatal(s, SSL_AD_PROTOCOL_VERSION,
+                         SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO, protverr);
+                goto err;
+            }
+        }
+    }
+
+    s->hit = 0;
+
+    if (!ssl_cache_cipherlist(s, &clienthello->ciphersuites,
+                              clienthello->isv2) ||
+        !bytes_to_cipher_list(s, &clienthello->ciphersuites, &ciphers, &scsvs,
+                              clienthello->isv2, 1)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    s->s3->send_connection_binding = 0;
+    /* Check what signalling cipher-suite values were received. */
+    if (scsvs != NULL) {
+        for(i = 0; i < sk_SSL_CIPHER_num(scsvs); i++) {
+            c = sk_SSL_CIPHER_value(scsvs, i);
+            if (SSL_CIPHER_get_id(c) == SSL3_CK_SCSV) {
+                if (s->renegotiate) {
+                    /* SCSV is fatal if renegotiating */
+                    SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                             SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                             SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
+                    goto err;
+                }
+                s->s3->send_connection_binding = 1;
+            } else if (SSL_CIPHER_get_id(c) == SSL3_CK_FALLBACK_SCSV &&
+                       !ssl_check_version_downgrade(s)) {
+                /*
+                 * This SCSV indicates that the client previously tried
+                 * a higher version.  We should fail if the current version
+                 * is an unexpected downgrade, as that indicates that the first
+                 * connection may have been tampered with in order to trigger
+                 * an insecure downgrade.
+                 */
+                SSLfatal(s, SSL_AD_INAPPROPRIATE_FALLBACK,
+                         SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                         SSL_R_INAPPROPRIATE_FALLBACK);
+                goto err;
+            }
+        }
+    }
+
+    /* For TLSv1.3 we must select the ciphersuite *before* session resumption */
+    if (SSL_IS_TLS13(s)) {
+        const SSL_CIPHER *cipher =
+            ssl3_choose_cipher(s, ciphers, SSL_get_ciphers(s));
+
+        if (cipher == NULL) {
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                     SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                     SSL_R_NO_SHARED_CIPHER);
+            goto err;
+        }
+        if (s->hello_retry_request == SSL_HRR_PENDING
+                && (s->s3->tmp.new_cipher == NULL
+                    || s->s3->tmp.new_cipher->id != cipher->id)) {
+            /*
+             * A previous HRR picked a different ciphersuite to the one we
+             * just selected. Something must have changed.
+             */
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                     SSL_R_BAD_CIPHER);
+            goto err;
+        }
+        s->s3->tmp.new_cipher = cipher;
+    }
+
+    /* We need to do this before getting the session */
+    if (!tls_parse_extension(s, TLSEXT_IDX_extended_master_secret,
+                             SSL_EXT_CLIENT_HELLO,
+                             clienthello->pre_proc_exts, NULL, 0)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    /*
+     * We don't allow resumption in a backwards compatible ClientHello.
+     * TODO(openssl-team): in TLS1.1+, session_id MUST be empty.
+     *
+     * Versions before 0.9.7 always allow clients to resume sessions in
+     * renegotiation. 0.9.7 and later allow this by default, but optionally
+     * ignore resumption requests with flag
+     * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (it's a new flag rather
+     * than a change to default behavior so that applications relying on
+     * this for security won't even compile against older library versions).
+     * 1.0.1 and later also have a function SSL_renegotiate_abbreviated() to
+     * request renegotiation but not a new session (s->new_session remains
+     * unset): for servers, this essentially just means that the
+     * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION setting will be
+     * ignored.
+     */
+    if (clienthello->isv2 ||
+        (s->new_session &&
+         (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION))) {
+        if (!ssl_get_new_session(s, 1)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else {
+        i = ssl_get_prev_session(s, clienthello);
+        if (i == 1) {
+            /* previous session */
+            s->hit = 1;
+        } else if (i == -1) {
+            /* SSLfatal() already called */
+            goto err;
+        } else {
+            /* i == 0 */
+            if (!ssl_get_new_session(s, 1)) {
+                /* SSLfatal() already called */
+                goto err;
+            }
+        }
+    }
+
+    if (SSL_IS_TLS13(s)) {
+        memcpy(s->tmp_session_id, s->clienthello->session_id,
+               s->clienthello->session_id_len);
+        s->tmp_session_id_len = s->clienthello->session_id_len;
+    }
+
+    /*
+     * If it is a hit, check that the cipher is in the list. In TLSv1.3 we check
+     * ciphersuite compatibility with the session as part of resumption.
+     */
+    if (!SSL_IS_TLS13(s) && s->hit) {
+        j = 0;
+        id = s->session->cipher->id;
+
+#ifdef CIPHER_DEBUG
+        fprintf(stderr, "client sent %d ciphers\n", sk_SSL_CIPHER_num(ciphers));
+#endif
+        for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
+            c = sk_SSL_CIPHER_value(ciphers, i);
+#ifdef CIPHER_DEBUG
+            fprintf(stderr, "client [%2d of %2d]:%s\n",
+                    i, sk_SSL_CIPHER_num(ciphers), SSL_CIPHER_get_name(c));
+#endif
+            if (c->id == id) {
+                j = 1;
+                break;
+            }
+        }
+        if (j == 0) {
+            /*
+             * we need to have the cipher in the cipher list if we are asked
+             * to reuse it
+             */
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                     SSL_R_REQUIRED_CIPHER_MISSING);
+            goto err;
+        }
+    }
+
+    for (loop = 0; loop < clienthello->compressions_len; loop++) {
+        if (clienthello->compressions[loop] == 0)
+            break;
+    }
+
+    if (loop >= clienthello->compressions_len) {
+        /* no compress */
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                 SSL_R_NO_COMPRESSION_SPECIFIED);
+        goto err;
+    }
+
+#ifndef OPENSSL_NO_EC
+    if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
+        ssl_check_for_safari(s, clienthello);
+#endif                          /* !OPENSSL_NO_EC */
+
+    /* TLS extensions */
+    if (!tls_parse_all_extensions(s, SSL_EXT_CLIENT_HELLO,
+                                  clienthello->pre_proc_exts, NULL, 0, 1)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    /*
+     * Check if we want to use external pre-shared secret for this handshake
+     * for not reused session only. We need to generate server_random before
+     * calling tls_session_secret_cb in order to allow SessionTicket
+     * processing to use it in key derivation.
+     */
+    {
+        unsigned char *pos;
+        pos = s->s3->server_random;
+        if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE, dgrd) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+
+    if (!s->hit
+            && s->version >= TLS1_VERSION
+            && !SSL_IS_TLS13(s)
+            && !SSL_IS_DTLS(s)
+            && s->ext.session_secret_cb) {
+        const SSL_CIPHER *pref_cipher = NULL;
+        /*
+         * s->session->master_key_length is a size_t, but this is an int for
+         * backwards compat reasons
+         */
+        int master_key_length;
+
+        master_key_length = sizeof(s->session->master_key);
+        if (s->ext.session_secret_cb(s, s->session->master_key,
+                                     &master_key_length, ciphers,
+                                     &pref_cipher,
+                                     s->ext.session_secret_cb_arg)
+                && master_key_length > 0) {
+            s->session->master_key_length = master_key_length;
+            s->hit = 1;
+            s->peer_ciphers = ciphers;
+            s->session->verify_result = X509_V_OK;
+
+            ciphers = NULL;
+
+            /* check if some cipher was preferred by call back */
+            if (pref_cipher == NULL)
+                pref_cipher = ssl3_choose_cipher(s, s->peer_ciphers,
+                                                 SSL_get_ciphers(s));
+            if (pref_cipher == NULL) {
+                SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                         SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                         SSL_R_NO_SHARED_CIPHER);
+                goto err;
+            }
+
+            s->session->cipher = pref_cipher;
+            sk_SSL_CIPHER_free(s->cipher_list);
+            s->cipher_list = sk_SSL_CIPHER_dup(s->peer_ciphers);
+            sk_SSL_CIPHER_free(s->cipher_list_by_id);
+            s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->peer_ciphers);
+        }
+    }
+
+    /*
+     * Worst case, we will use the NULL compression, but if we have other
+     * options, we will now look for them.  We have complen-1 compression
+     * algorithms from the client, starting at q.
+     */
+    s->s3->tmp.new_compression = NULL;
+    if (SSL_IS_TLS13(s)) {
+        /*
+         * We already checked above that the NULL compression method appears in
+         * the list. Now we check there aren't any others (which is illegal in
+         * a TLSv1.3 ClientHello.
+         */
+        if (clienthello->compressions_len != 1) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                     SSL_R_INVALID_COMPRESSION_ALGORITHM);
+            goto err;
+        }
+    }
+#ifndef OPENSSL_NO_COMP
+    /* This only happens if we have a cache hit */
+    else if (s->session->compress_meth != 0) {
+        int m, comp_id = s->session->compress_meth;
+        unsigned int k;
+        /* Perform sanity checks on resumed compression algorithm */
+        /* Can't disable compression */
+        if (!ssl_allow_compression(s)) {
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                     SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                     SSL_R_INCONSISTENT_COMPRESSION);
+            goto err;
+        }
+        /* Look for resumed compression method */
+        for (m = 0; m < sk_SSL_COMP_num(s->ctx->comp_methods); m++) {
+            comp = sk_SSL_COMP_value(s->ctx->comp_methods, m);
+            if (comp_id == comp->id) {
+                s->s3->tmp.new_compression = comp;
+                break;
+            }
+        }
+        if (s->s3->tmp.new_compression == NULL) {
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                     SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                     SSL_R_INVALID_COMPRESSION_ALGORITHM);
+            goto err;
+        }
+        /* Look for resumed method in compression list */
+        for (k = 0; k < clienthello->compressions_len; k++) {
+            if (clienthello->compressions[k] == comp_id)
+                break;
+        }
+        if (k >= clienthello->compressions_len) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                     SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING);
+            goto err;
+        }
+    } else if (s->hit) {
+        comp = NULL;
+    } else if (ssl_allow_compression(s) && s->ctx->comp_methods) {
+        /* See if we have a match */
+        int m, nn, v, done = 0;
+        unsigned int o;
+
+        nn = sk_SSL_COMP_num(s->ctx->comp_methods);
+        for (m = 0; m < nn; m++) {
+            comp = sk_SSL_COMP_value(s->ctx->comp_methods, m);
+            v = comp->id;
+            for (o = 0; o < clienthello->compressions_len; o++) {
+                if (v == clienthello->compressions[o]) {
+                    done = 1;
+                    break;
+                }
+            }
+            if (done)
+                break;
+        }
+        if (done)
+            s->s3->tmp.new_compression = comp;
+        else
+            comp = NULL;
+    }
+#else
+    /*
+     * If compression is disabled we'd better not try to resume a session
+     * using compression.
+     */
+    if (s->session->compress_meth != 0) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                 SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                 SSL_R_INCONSISTENT_COMPRESSION);
+        goto err;
+    }
+#endif
+
+    /*
+     * Given s->peer_ciphers and SSL_get_ciphers, we must pick a cipher
+     */
+
+    if (!s->hit || SSL_IS_TLS13(s)) {
+        sk_SSL_CIPHER_free(s->peer_ciphers);
+        s->peer_ciphers = ciphers;
+        if (ciphers == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        ciphers = NULL;
+    }
+
+    if (!s->hit) {
+#ifdef OPENSSL_NO_COMP
+        s->session->compress_meth = 0;
+#else
+        s->session->compress_meth = (comp == NULL) ? 0 : comp->id;
+#endif
+        if (!tls1_set_server_sigalgs(s)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    }
+
+    sk_SSL_CIPHER_free(ciphers);
+    sk_SSL_CIPHER_free(scsvs);
+    OPENSSL_free(clienthello->pre_proc_exts);
+    OPENSSL_free(s->clienthello);
+    s->clienthello = NULL;
+    return 1;
+ err:
+    sk_SSL_CIPHER_free(ciphers);
+    sk_SSL_CIPHER_free(scsvs);
+    OPENSSL_free(clienthello->pre_proc_exts);
+    OPENSSL_free(s->clienthello);
+    s->clienthello = NULL;
+
+    return 0;
+}
+
+/*
+ * Call the status request callback if needed. Upon success, returns 1.
+ * Upon failure, returns 0.
+ */
+static int tls_handle_status_request(SSL *s)
+{
+    s->ext.status_expected = 0;
+
+    /*
+     * If status request then ask callback what to do. Note: this must be
+     * called after servername callbacks in case the certificate has changed,
+     * and must be called after the cipher has been chosen because this may
+     * influence which certificate is sent
+     */
+    if (s->ext.status_type != TLSEXT_STATUSTYPE_nothing && s->ctx != NULL
+            && s->ctx->ext.status_cb != NULL) {
+        int ret;
+
+        /* If no certificate can't return certificate status */
+        if (s->s3->tmp.cert != NULL) {
+            /*
+             * Set current certificate to one we will use so SSL_get_certificate
+             * et al can pick it up.
+             */
+            s->cert->key = s->s3->tmp.cert;
+            ret = s->ctx->ext.status_cb(s, s->ctx->ext.status_arg);
+            switch (ret) {
+                /* We don't want to send a status request response */
+            case SSL_TLSEXT_ERR_NOACK:
+                s->ext.status_expected = 0;
+                break;
+                /* status request response should be sent */
+            case SSL_TLSEXT_ERR_OK:
+                if (s->ext.ocsp.resp)
+                    s->ext.status_expected = 1;
+                break;
+                /* something bad happened */
+            case SSL_TLSEXT_ERR_ALERT_FATAL:
+            default:
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_HANDLE_STATUS_REQUEST,
+                         SSL_R_CLIENTHELLO_TLSEXT);
+                return 0;
+            }
+        }
+    }
+
+    return 1;
+}
+
+/*
+ * Call the alpn_select callback if needed. Upon success, returns 1.
+ * Upon failure, returns 0.
+ */
+int tls_handle_alpn(SSL *s)
+{
+    const unsigned char *selected = NULL;
+    unsigned char selected_len = 0;
+
+    if (s->ctx->ext.alpn_select_cb != NULL && s->s3->alpn_proposed != NULL) {
+        int r = s->ctx->ext.alpn_select_cb(s, &selected, &selected_len,
+                                           s->s3->alpn_proposed,
+                                           (unsigned int)s->s3->alpn_proposed_len,
+                                           s->ctx->ext.alpn_select_cb_arg);
+
+        if (r == SSL_TLSEXT_ERR_OK) {
+            OPENSSL_free(s->s3->alpn_selected);
+            s->s3->alpn_selected = OPENSSL_memdup(selected, selected_len);
+            if (s->s3->alpn_selected == NULL) {
+                s->s3->alpn_selected_len = 0;
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_HANDLE_ALPN,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+            s->s3->alpn_selected_len = selected_len;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+            /* ALPN takes precedence over NPN. */
+            s->s3->npn_seen = 0;
+#endif
+
+            /* Check ALPN is consistent with session */
+            if (s->session->ext.alpn_selected == NULL
+                        || selected_len != s->session->ext.alpn_selected_len
+                        || memcmp(selected, s->session->ext.alpn_selected,
+                                  selected_len) != 0) {
+                /* Not consistent so can't be used for early_data */
+                s->ext.early_data_ok = 0;
+
+                if (!s->hit) {
+                    /*
+                     * This is a new session and so alpn_selected should have
+                     * been initialised to NULL. We should update it with the
+                     * selected ALPN.
+                     */
+                    if (!ossl_assert(s->session->ext.alpn_selected == NULL)) {
+                        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                                 SSL_F_TLS_HANDLE_ALPN,
+                                 ERR_R_INTERNAL_ERROR);
+                        return 0;
+                    }
+                    s->session->ext.alpn_selected = OPENSSL_memdup(selected,
+                                                                   selected_len);
+                    if (s->session->ext.alpn_selected == NULL) {
+                        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                                 SSL_F_TLS_HANDLE_ALPN,
+                                 ERR_R_INTERNAL_ERROR);
+                        return 0;
+                    }
+                    s->session->ext.alpn_selected_len = selected_len;
+                }
+            }
+
+            return 1;
+        } else if (r != SSL_TLSEXT_ERR_NOACK) {
+            SSLfatal(s, SSL_AD_NO_APPLICATION_PROTOCOL, SSL_F_TLS_HANDLE_ALPN,
+                     SSL_R_NO_APPLICATION_PROTOCOL);
+            return 0;
+        }
+        /*
+         * If r == SSL_TLSEXT_ERR_NOACK then behave as if no callback was
+         * present.
+         */
+    }
+
+    /* Check ALPN is consistent with session */
+    if (s->session->ext.alpn_selected != NULL) {
+        /* Not consistent so can't be used for early_data */
+        s->ext.early_data_ok = 0;
+    }
+
+    return 1;
+}
+
+WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
+{
+    const SSL_CIPHER *cipher;
+
+    if (wst == WORK_MORE_A) {
+        int rv = tls_early_post_process_client_hello(s);
+        if (rv == 0) {
+            /* SSLfatal() was already called */
+            goto err;
+        }
+        if (rv < 0)
+            return WORK_MORE_A;
+        wst = WORK_MORE_B;
+    }
+    if (wst == WORK_MORE_B) {
+        if (!s->hit || SSL_IS_TLS13(s)) {
+            /* Let cert callback update server certificates if required */
+            if (!s->hit && s->cert->cert_cb != NULL) {
+                int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg);
+                if (rv == 0) {
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                             SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
+                             SSL_R_CERT_CB_ERROR);
+                    goto err;
+                }
+                if (rv < 0) {
+                    s->rwstate = SSL_X509_LOOKUP;
+                    return WORK_MORE_B;
+                }
+                s->rwstate = SSL_NOTHING;
+            }
+
+            /* In TLSv1.3 we selected the ciphersuite before resumption */
+            if (!SSL_IS_TLS13(s)) {
+                cipher =
+                    ssl3_choose_cipher(s, s->peer_ciphers, SSL_get_ciphers(s));
+
+                if (cipher == NULL) {
+                    SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                             SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
+                             SSL_R_NO_SHARED_CIPHER);
+                    goto err;
+                }
+                s->s3->tmp.new_cipher = cipher;
+            }
+            if (!s->hit) {
+                if (!tls_choose_sigalg(s, 1)) {
+                    /* SSLfatal already called */
+                    goto err;
+                }
+                /* check whether we should disable session resumption */
+                if (s->not_resumable_session_cb != NULL)
+                    s->session->not_resumable =
+                        s->not_resumable_session_cb(s,
+                            ((s->s3->tmp.new_cipher->algorithm_mkey
+                              & (SSL_kDHE | SSL_kECDHE)) != 0));
+                if (s->session->not_resumable)
+                    /* do not send a session ticket */
+                    s->ext.ticket_expected = 0;
+            }
+        } else {
+            /* Session-id reuse */
+            s->s3->tmp.new_cipher = s->session->cipher;
+        }
+
+        /*-
+         * we now have the following setup.
+         * client_random
+         * cipher_list          - our preferred list of ciphers
+         * ciphers              - the clients preferred list of ciphers
+         * compression          - basically ignored right now
+         * ssl version is set   - sslv3
+         * s->session           - The ssl session has been setup.
+         * s->hit               - session reuse flag
+         * s->s3->tmp.new_cipher- the new cipher to use.
+         */
+
+        /*
+         * Call status_request callback if needed. Has to be done after the
+         * certificate callbacks etc above.
+         */
+        if (!tls_handle_status_request(s)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+        /*
+         * Call alpn_select callback if needed.  Has to be done after SNI and
+         * cipher negotiation (HTTP/2 restricts permitted ciphers). In TLSv1.3
+         * we already did this because cipher negotiation happens earlier, and
+         * we must handle ALPN before we decide whether to accept early_data.
+         */
+        if (!SSL_IS_TLS13(s) && !tls_handle_alpn(s)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+
+        wst = WORK_MORE_C;
+    }
+#ifndef OPENSSL_NO_SRP
+    if (wst == WORK_MORE_C) {
+        int ret;
+        if ((ret = ssl_check_srp_ext_ClientHello(s)) == 0) {
+            /*
+             * callback indicates further work to be done
+             */
+            s->rwstate = SSL_X509_LOOKUP;
+            return WORK_MORE_C;
+        }
+        if (ret < 0) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    }
+#endif
+
+    return WORK_FINISHED_STOP;
+ err:
+    return WORK_ERROR;
+}
+
+int tls_construct_server_hello(SSL *s, WPACKET *pkt)
+{
+    int compm;
+    size_t sl, len;
+    int version;
+    unsigned char *session_id;
+    int usetls13 = SSL_IS_TLS13(s) || s->hello_retry_request == SSL_HRR_PENDING;
+
+    version = usetls13 ? TLS1_2_VERSION : s->version;
+    if (!WPACKET_put_bytes_u16(pkt, version)
+               /*
+                * Random stuff. Filling of the server_random takes place in
+                * tls_process_client_hello()
+                */
+            || !WPACKET_memcpy(pkt,
+                               s->hello_retry_request == SSL_HRR_PENDING
+                                   ? hrrrandom : s->s3->server_random,
+                               SSL3_RANDOM_SIZE)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_SERVER_HELLO,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /*-
+     * There are several cases for the session ID to send
+     * back in the server hello:
+     * - For session reuse from the session cache,
+     *   we send back the old session ID.
+     * - If stateless session reuse (using a session ticket)
+     *   is successful, we send back the client's "session ID"
+     *   (which doesn't actually identify the session).
+     * - If it is a new session, we send back the new
+     *   session ID.
+     * - However, if we want the new session to be single-use,
+     *   we send back a 0-length session ID.
+     * - In TLSv1.3 we echo back the session id sent to us by the client
+     *   regardless
+     * s->hit is non-zero in either case of session reuse,
+     * so the following won't overwrite an ID that we're supposed
+     * to send back.
+     */
+    if (s->session->not_resumable ||
+        (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)
+         && !s->hit))
+        s->session->session_id_length = 0;
+
+    if (usetls13) {
+        sl = s->tmp_session_id_len;
+        session_id = s->tmp_session_id;
+    } else {
+        sl = s->session->session_id_length;
+        session_id = s->session->session_id;
+    }
+
+    if (sl > sizeof(s->session->session_id)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_SERVER_HELLO,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /* set up the compression method */
+#ifdef OPENSSL_NO_COMP
+    compm = 0;
+#else
+    if (usetls13 || s->s3->tmp.new_compression == NULL)
+        compm = 0;
+    else
+        compm = s->s3->tmp.new_compression->id;
+#endif
+
+    if (!WPACKET_sub_memcpy_u8(pkt, session_id, sl)
+            || !s->method->put_cipher_by_char(s->s3->tmp.new_cipher, pkt, &len)
+            || !WPACKET_put_bytes_u8(pkt, compm)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_SERVER_HELLO,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (!tls_construct_extensions(s, pkt,
+                                  s->hello_retry_request == SSL_HRR_PENDING
+                                      ? SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST
+                                      : (SSL_IS_TLS13(s)
+                                          ? SSL_EXT_TLS1_3_SERVER_HELLO
+                                          : SSL_EXT_TLS1_2_SERVER_HELLO),
+                                  NULL, 0)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    if (s->hello_retry_request == SSL_HRR_PENDING) {
+        /* Ditch the session. We'll create a new one next time around */
+        SSL_SESSION_free(s->session);
+        s->session = NULL;
+        s->hit = 0;
+
+        /*
+         * Re-initialise the Transcript Hash. We're going to prepopulate it with
+         * a synthetic message_hash in place of ClientHello1.
+         */
+        if (!create_synthetic_message_hash(s, NULL, 0, NULL, 0)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+    } else if (!(s->verify_mode & SSL_VERIFY_PEER)
+                && !ssl3_digest_cached_records(s, 0)) {
+        /* SSLfatal() already called */;
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_server_done(SSL *s, WPACKET *pkt)
+{
+    if (!s->s3->tmp.cert_request) {
+        if (!ssl3_digest_cached_records(s, 0)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+    }
+    return 1;
+}
+
+int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt)
+{
+#ifndef OPENSSL_NO_DH
+    EVP_PKEY *pkdh = NULL;
+#endif
+#ifndef OPENSSL_NO_EC
+    unsigned char *encodedPoint = NULL;
+    size_t encodedlen = 0;
+    int curve_id = 0;
+#endif
+    const SIGALG_LOOKUP *lu = s->s3->tmp.sigalg;
+    int i;
+    unsigned long type;
+    const BIGNUM *r[4];
+    EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
+    EVP_PKEY_CTX *pctx = NULL;
+    size_t paramlen, paramoffset;
+
+    if (!WPACKET_get_total_written(pkt, &paramoffset)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (md_ctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    type = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    r[0] = r[1] = r[2] = r[3] = NULL;
+#ifndef OPENSSL_NO_PSK
+    /* Plain PSK or RSAPSK nothing to do */
+    if (type & (SSL_kPSK | SSL_kRSAPSK)) {
+    } else
+#endif                          /* !OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_DH
+    if (type & (SSL_kDHE | SSL_kDHEPSK)) {
+        CERT *cert = s->cert;
+
+        EVP_PKEY *pkdhp = NULL;
+        DH *dh;
+
+        if (s->cert->dh_tmp_auto) {
+            DH *dhp = ssl_get_auto_dh(s);
+            pkdh = EVP_PKEY_new();
+            if (pkdh == NULL || dhp == NULL) {
+                DH_free(dhp);
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                         ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            EVP_PKEY_assign_DH(pkdh, dhp);
+            pkdhp = pkdh;
+        } else {
+            pkdhp = cert->dh_tmp;
+        }
+        if ((pkdhp == NULL) && (s->cert->dh_tmp_cb != NULL)) {
+            DH *dhp = s->cert->dh_tmp_cb(s, 0, 1024);
+            pkdh = ssl_dh_to_pkey(dhp);
+            if (pkdh == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                         ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            pkdhp = pkdh;
+        }
+        if (pkdhp == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     SSL_R_MISSING_TMP_DH_KEY);
+            goto err;
+        }
+        if (!ssl_security(s, SSL_SECOP_TMP_DH,
+                          EVP_PKEY_security_bits(pkdhp), 0, pkdhp)) {
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     SSL_R_DH_KEY_TOO_SMALL);
+            goto err;
+        }
+        if (s->s3->tmp.pkey != NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        s->s3->tmp.pkey = ssl_generate_pkey(pkdhp);
+        if (s->s3->tmp.pkey == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, 0, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        dh = EVP_PKEY_get0_DH(s->s3->tmp.pkey);
+        if (dh == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        EVP_PKEY_free(pkdh);
+        pkdh = NULL;
+
+        DH_get0_pqg(dh, &r[0], NULL, &r[1]);
+        DH_get0_key(dh, &r[2], NULL);
+    } else
+#endif
+#ifndef OPENSSL_NO_EC
+    if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
+
+        if (s->s3->tmp.pkey != NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        /* Get NID of appropriate shared curve */
+        curve_id = tls1_shared_group(s, -2);
+        if (curve_id == 0) {
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
+            goto err;
+        }
+        s->s3->tmp.pkey = ssl_generate_pkey_group(s, curve_id);
+        /* Generate a new key for this curve */
+        if (s->s3->tmp.pkey == NULL) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+
+        /* Encode the public key. */
+        encodedlen = EVP_PKEY_get1_tls_encodedpoint(s->s3->tmp.pkey,
+                                                    &encodedPoint);
+        if (encodedlen == 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_EC_LIB);
+            goto err;
+        }
+
+        /*
+         * We'll generate the serverKeyExchange message explicitly so we
+         * can set these to NULLs
+         */
+        r[0] = NULL;
+        r[1] = NULL;
+        r[2] = NULL;
+        r[3] = NULL;
+    } else
+#endif                          /* !OPENSSL_NO_EC */
+#ifndef OPENSSL_NO_SRP
+    if (type & SSL_kSRP) {
+        if ((s->srp_ctx.N == NULL) ||
+            (s->srp_ctx.g == NULL) ||
+            (s->srp_ctx.s == NULL) || (s->srp_ctx.B == NULL)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     SSL_R_MISSING_SRP_PARAM);
+            goto err;
+        }
+        r[0] = s->srp_ctx.N;
+        r[1] = s->srp_ctx.g;
+        r[2] = s->srp_ctx.s;
+        r[3] = s->srp_ctx.B;
+    } else
+#endif
+    {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                 SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
+        goto err;
+    }
+
+    if (((s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP)) != 0)
+        || ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) != 0) {
+        lu = NULL;
+    } else if (lu == NULL) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+#ifndef OPENSSL_NO_PSK
+    if (type & SSL_PSK) {
+        size_t len = (s->cert->psk_identity_hint == NULL)
+                        ? 0 : strlen(s->cert->psk_identity_hint);
+
+        /*
+         * It should not happen that len > PSK_MAX_IDENTITY_LEN - we already
+         * checked this when we set the identity hint - but just in case
+         */
+        if (len > PSK_MAX_IDENTITY_LEN
+                || !WPACKET_sub_memcpy_u16(pkt, s->cert->psk_identity_hint,
+                                           len)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+#endif
+
+    for (i = 0; i < 4 && r[i] != NULL; i++) {
+        unsigned char *binval;
+        int res;
+
+#ifndef OPENSSL_NO_SRP
+        if ((i == 2) && (type & SSL_kSRP)) {
+            res = WPACKET_start_sub_packet_u8(pkt);
+        } else
+#endif
+            res = WPACKET_start_sub_packet_u16(pkt);
+
+        if (!res) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+#ifndef OPENSSL_NO_DH
+        /*-
+         * for interoperability with some versions of the Microsoft TLS
+         * stack, we need to zero pad the DHE pub key to the same length
+         * as the prime
+         */
+        if ((i == 2) && (type & (SSL_kDHE | SSL_kDHEPSK))) {
+            size_t len = BN_num_bytes(r[0]) - BN_num_bytes(r[2]);
+
+            if (len > 0) {
+                if (!WPACKET_allocate_bytes(pkt, len, &binval)) {
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                             SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                             ERR_R_INTERNAL_ERROR);
+                    goto err;
+                }
+                memset(binval, 0, len);
+            }
+        }
+#endif
+        if (!WPACKET_allocate_bytes(pkt, BN_num_bytes(r[i]), &binval)
+                || !WPACKET_close(pkt)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        BN_bn2bin(r[i], binval);
+    }
+
+#ifndef OPENSSL_NO_EC
+    if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
+        /*
+         * We only support named (not generic) curves. In this situation, the
+         * ServerKeyExchange message has: [1 byte CurveType], [2 byte CurveName]
+         * [1 byte length of encoded point], followed by the actual encoded
+         * point itself
+         */
+        if (!WPACKET_put_bytes_u8(pkt, NAMED_CURVE_TYPE)
+                || !WPACKET_put_bytes_u8(pkt, 0)
+                || !WPACKET_put_bytes_u8(pkt, curve_id)
+                || !WPACKET_sub_memcpy_u8(pkt, encodedPoint, encodedlen)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        OPENSSL_free(encodedPoint);
+        encodedPoint = NULL;
+    }
+#endif
+
+    /* not anonymous */
+    if (lu != NULL) {
+        EVP_PKEY *pkey = s->s3->tmp.cert->privatekey;
+        const EVP_MD *md;
+        unsigned char *sigbytes1, *sigbytes2, *tbs;
+        size_t siglen, tbslen;
+        int rv;
+
+        if (pkey == NULL || !tls1_lookup_md(lu, &md)) {
+            /* Should never happen */
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        /* Get length of the parameters we have written above */
+        if (!WPACKET_get_length(pkt, &paramlen)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        /* send signature algorithm */
+        if (SSL_USE_SIGALGS(s) && !WPACKET_put_bytes_u16(pkt, lu->sigalg)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        /*
+         * Create the signature. We don't know the actual length of the sig
+         * until after we've created it, so we reserve enough bytes for it
+         * up front, and then properly allocate them in the WPACKET
+         * afterwards.
+         */
+        siglen = EVP_PKEY_size(pkey);
+        if (!WPACKET_sub_reserve_bytes_u16(pkt, siglen, &sigbytes1)
+            || EVP_DigestSignInit(md_ctx, &pctx, md, NULL, pkey) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        if (lu->sig == EVP_PKEY_RSA_PSS) {
+            if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0
+                || EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, RSA_PSS_SALTLEN_DIGEST) <= 0) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                        ERR_R_EVP_LIB);
+                goto err;
+            }
+        }
+        tbslen = construct_key_exchange_tbs(s, &tbs,
+                                            s->init_buf->data + paramoffset,
+                                            paramlen);
+        if (tbslen == 0) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+        rv = EVP_DigestSign(md_ctx, sigbytes1, &siglen, tbs, tbslen);
+        OPENSSL_free(tbs);
+        if (rv <= 0 || !WPACKET_sub_allocate_bytes_u16(pkt, siglen, &sigbytes2)
+            || sigbytes1 != sigbytes2) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+
+    EVP_MD_CTX_free(md_ctx);
+    return 1;
+ err:
+#ifndef OPENSSL_NO_DH
+    EVP_PKEY_free(pkdh);
+#endif
+#ifndef OPENSSL_NO_EC
+    OPENSSL_free(encodedPoint);
+#endif
+    EVP_MD_CTX_free(md_ctx);
+    return 0;
+}
+
+int tls_construct_certificate_request(SSL *s, WPACKET *pkt)
+{
+    if (SSL_IS_TLS13(s)) {
+        /* Send random context when doing post-handshake auth */
+        if (s->post_handshake_auth == SSL_PHA_REQUEST_PENDING) {
+            OPENSSL_free(s->pha_context);
+            s->pha_context_len = 32;
+            if ((s->pha_context = OPENSSL_malloc(s->pha_context_len)) == NULL) {
+                s->pha_context_len = 0;
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+            if (RAND_bytes(s->pha_context, s->pha_context_len) <= 0
+                    || !WPACKET_sub_memcpy_u8(pkt, s->pha_context,
+                                              s->pha_context_len)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+            /* reset the handshake hash back to just after the ClientFinished */
+            if (!tls13_restore_handshake_digest_for_pha(s)) {
+                /* SSLfatal() already called */
+                return 0;
+            }
+        } else {
+            if (!WPACKET_put_bytes_u8(pkt, 0)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
+
+        if (!tls_construct_extensions(s, pkt,
+                                      SSL_EXT_TLS1_3_CERTIFICATE_REQUEST, NULL,
+                                      0)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+        goto done;
+    }
+
+    /* get the list of acceptable cert types */
+    if (!WPACKET_start_sub_packet_u8(pkt)
+        || !ssl3_get_req_cert_type(s, pkt) || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (SSL_USE_SIGALGS(s)) {
+        const uint16_t *psigs;
+        size_t nl = tls12_get_psigalgs(s, 1, &psigs);
+
+        if (!WPACKET_start_sub_packet_u16(pkt)
+                || !WPACKET_set_flags(pkt, WPACKET_FLAGS_NON_ZERO_LENGTH)
+                || !tls12_copy_sigalgs(s, pkt, psigs, nl)
+                || !WPACKET_close(pkt)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+
+    if (!construct_ca_names(s, get_ca_names(s), pkt)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+ done:
+    s->certreqs_sent++;
+    s->s3->tmp.cert_request = 1;
+    return 1;
+}
+
+static int tls_process_cke_psk_preamble(SSL *s, PACKET *pkt)
+{
+#ifndef OPENSSL_NO_PSK
+    unsigned char psk[PSK_MAX_PSK_LEN];
+    size_t psklen;
+    PACKET psk_identity;
+
+    if (!PACKET_get_length_prefixed_2(pkt, &psk_identity)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE,
+                 SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+    if (PACKET_remaining(&psk_identity) > PSK_MAX_IDENTITY_LEN) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE,
+                 SSL_R_DATA_LENGTH_TOO_LONG);
+        return 0;
+    }
+    if (s->psk_server_callback == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE,
+                 SSL_R_PSK_NO_SERVER_CB);
+        return 0;
+    }
+
+    if (!PACKET_strndup(&psk_identity, &s->session->psk_identity)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    psklen = s->psk_server_callback(s, s->session->psk_identity,
+                                    psk, sizeof(psk));
+
+    if (psklen > PSK_MAX_PSK_LEN) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    } else if (psklen == 0) {
+        /*
+         * PSK related to the given identity not found
+         */
+        SSLfatal(s, SSL_AD_UNKNOWN_PSK_IDENTITY,
+                 SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE,
+                 SSL_R_PSK_IDENTITY_NOT_FOUND);
+        return 0;
+    }
+
+    OPENSSL_free(s->s3->tmp.psk);
+    s->s3->tmp.psk = OPENSSL_memdup(psk, psklen);
+    OPENSSL_cleanse(psk, psklen);
+
+    if (s->s3->tmp.psk == NULL) {
+        s->s3->tmp.psklen = 0;
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    s->s3->tmp.psklen = psklen;
+
+    return 1;
+#else
+    /* Should never happen */
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+static int tls_process_cke_rsa(SSL *s, PACKET *pkt)
+{
+#ifndef OPENSSL_NO_RSA
+    unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH];
+    int decrypt_len;
+    unsigned char decrypt_good, version_good;
+    size_t j, padding_len;
+    PACKET enc_premaster;
+    RSA *rsa = NULL;
+    unsigned char *rsa_decrypt = NULL;
+    int ret = 0;
+
+    rsa = EVP_PKEY_get0_RSA(s->cert->pkeys[SSL_PKEY_RSA].privatekey);
+    if (rsa == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
+                 SSL_R_MISSING_RSA_CERTIFICATE);
+        return 0;
+    }
+
+    /* SSLv3 and pre-standard DTLS omit the length bytes. */
+    if (s->version == SSL3_VERSION || s->version == DTLS1_BAD_VER) {
+        enc_premaster = *pkt;
+    } else {
+        if (!PACKET_get_length_prefixed_2(pkt, &enc_premaster)
+            || PACKET_remaining(pkt) != 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
+                     SSL_R_LENGTH_MISMATCH);
+            return 0;
+        }
+    }
+
+    /*
+     * We want to be sure that the plaintext buffer size makes it safe to
+     * iterate over the entire size of a premaster secret
+     * (SSL_MAX_MASTER_KEY_LENGTH). Reject overly short RSA keys because
+     * their ciphertext cannot accommodate a premaster secret anyway.
+     */
+    if (RSA_size(rsa) < SSL_MAX_MASTER_KEY_LENGTH) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
+                 RSA_R_KEY_SIZE_TOO_SMALL);
+        return 0;
+    }
+
+    rsa_decrypt = OPENSSL_malloc(RSA_size(rsa));
+    if (rsa_decrypt == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    /*
+     * We must not leak whether a decryption failure occurs because of
+     * Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246,
+     * section 7.4.7.1). The code follows that advice of the TLS RFC and
+     * generates a random premaster secret for the case that the decrypt
+     * fails. See https://tools.ietf.org/html/rfc5246#section-7.4.7.1
+     */
+
+    if (RAND_priv_bytes(rand_premaster_secret,
+                      sizeof(rand_premaster_secret)) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /*
+     * Decrypt with no padding. PKCS#1 padding will be removed as part of
+     * the timing-sensitive code below.
+     */
+     /* TODO(size_t): Convert this function */
+    decrypt_len = (int)RSA_private_decrypt((int)PACKET_remaining(&enc_premaster),
+                                           PACKET_data(&enc_premaster),
+                                           rsa_decrypt, rsa, RSA_NO_PADDING);
+    if (decrypt_len < 0) {
+        SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /* Check the padding. See RFC 3447, section 7.2.2. */
+
+    /*
+     * The smallest padded premaster is 11 bytes of overhead. Small keys
+     * are publicly invalid, so this may return immediately. This ensures
+     * PS is at least 8 bytes.
+     */
+    if (decrypt_len < 11 + SSL_MAX_MASTER_KEY_LENGTH) {
+        SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
+                 SSL_R_DECRYPTION_FAILED);
+        goto err;
+    }
+
+    padding_len = decrypt_len - SSL_MAX_MASTER_KEY_LENGTH;
+    decrypt_good = constant_time_eq_int_8(rsa_decrypt[0], 0) &
+        constant_time_eq_int_8(rsa_decrypt[1], 2);
+    for (j = 2; j < padding_len - 1; j++) {
+        decrypt_good &= ~constant_time_is_zero_8(rsa_decrypt[j]);
+    }
+    decrypt_good &= constant_time_is_zero_8(rsa_decrypt[padding_len - 1]);
+
+    /*
+     * If the version in the decrypted pre-master secret is correct then
+     * version_good will be 0xff, otherwise it'll be zero. The
+     * Klima-Pokorny-Rosa extension of Bleichenbacher's attack
+     * (http://eprint.iacr.org/2003/052/) exploits the version number
+     * check as a "bad version oracle". Thus version checks are done in
+     * constant time and are treated like any other decryption error.
+     */
+    version_good =
+        constant_time_eq_8(rsa_decrypt[padding_len],
+                           (unsigned)(s->client_version >> 8));
+    version_good &=
+        constant_time_eq_8(rsa_decrypt[padding_len + 1],
+                           (unsigned)(s->client_version & 0xff));
+
+    /*
+     * The premaster secret must contain the same version number as the
+     * ClientHello to detect version rollback attacks (strangely, the
+     * protocol does not offer such protection for DH ciphersuites).
+     * However, buggy clients exist that send the negotiated protocol
+     * version instead if the server does not support the requested
+     * protocol version. If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such
+     * clients.
+     */
+    if (s->options & SSL_OP_TLS_ROLLBACK_BUG) {
+        unsigned char workaround_good;
+        workaround_good = constant_time_eq_8(rsa_decrypt[padding_len],
+                                             (unsigned)(s->version >> 8));
+        workaround_good &=
+            constant_time_eq_8(rsa_decrypt[padding_len + 1],
+                               (unsigned)(s->version & 0xff));
+        version_good |= workaround_good;
+    }
+
+    /*
+     * Both decryption and version must be good for decrypt_good to
+     * remain non-zero (0xff).
+     */
+    decrypt_good &= version_good;
+
+    /*
+     * Now copy rand_premaster_secret over from p using
+     * decrypt_good_mask. If decryption failed, then p does not
+     * contain valid plaintext, however, a check above guarantees
+     * it is still sufficiently large to read from.
+     */
+    for (j = 0; j < sizeof(rand_premaster_secret); j++) {
+        rsa_decrypt[padding_len + j] =
+            constant_time_select_8(decrypt_good,
+                                   rsa_decrypt[padding_len + j],
+                                   rand_premaster_secret[j]);
+    }
+
+    if (!ssl_generate_master_secret(s, rsa_decrypt + padding_len,
+                                    sizeof(rand_premaster_secret), 0)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    ret = 1;
+ err:
+    OPENSSL_free(rsa_decrypt);
+    return ret;
+#else
+    /* Should never happen */
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+static int tls_process_cke_dhe(SSL *s, PACKET *pkt)
+{
+#ifndef OPENSSL_NO_DH
+    EVP_PKEY *skey = NULL;
+    DH *cdh;
+    unsigned int i;
+    BIGNUM *pub_key;
+    const unsigned char *data;
+    EVP_PKEY *ckey = NULL;
+    int ret = 0;
+
+    if (!PACKET_get_net_2(pkt, &i) || PACKET_remaining(pkt) != i) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_DHE,
+               SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
+        goto err;
+    }
+    skey = s->s3->tmp.pkey;
+    if (skey == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_DHE,
+                 SSL_R_MISSING_TMP_DH_KEY);
+        goto err;
+    }
+
+    if (PACKET_remaining(pkt) == 0L) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_DHE,
+                 SSL_R_MISSING_TMP_DH_KEY);
+        goto err;
+    }
+    if (!PACKET_get_bytes(pkt, &data, i)) {
+        /* We already checked we have enough data */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_DHE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    ckey = EVP_PKEY_new();
+    if (ckey == NULL || EVP_PKEY_copy_parameters(ckey, skey) == 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_DHE,
+                 SSL_R_BN_LIB);
+        goto err;
+    }
+
+    cdh = EVP_PKEY_get0_DH(ckey);
+    pub_key = BN_bin2bn(data, i, NULL);
+    if (pub_key == NULL || cdh == NULL || !DH_set0_key(cdh, pub_key, NULL)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_DHE,
+                 ERR_R_INTERNAL_ERROR);
+        BN_free(pub_key);
+        goto err;
+    }
+
+    if (ssl_derive(s, skey, ckey, 1) == 0) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    ret = 1;
+    EVP_PKEY_free(s->s3->tmp.pkey);
+    s->s3->tmp.pkey = NULL;
+ err:
+    EVP_PKEY_free(ckey);
+    return ret;
+#else
+    /* Should never happen */
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_DHE,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+static int tls_process_cke_ecdhe(SSL *s, PACKET *pkt)
+{
+#ifndef OPENSSL_NO_EC
+    EVP_PKEY *skey = s->s3->tmp.pkey;
+    EVP_PKEY *ckey = NULL;
+    int ret = 0;
+
+    if (PACKET_remaining(pkt) == 0L) {
+        /* We don't support ECDH client auth */
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS_PROCESS_CKE_ECDHE,
+                 SSL_R_MISSING_TMP_ECDH_KEY);
+        goto err;
+    } else {
+        unsigned int i;
+        const unsigned char *data;
+
+        /*
+         * Get client's public key from encoded point in the
+         * ClientKeyExchange message.
+         */
+
+        /* Get encoded point length */
+        if (!PACKET_get_1(pkt, &i) || !PACKET_get_bytes(pkt, &data, i)
+            || PACKET_remaining(pkt) != 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_ECDHE,
+                     SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+        if (skey == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_ECDHE,
+                     SSL_R_MISSING_TMP_ECDH_KEY);
+            goto err;
+        }
+
+        ckey = EVP_PKEY_new();
+        if (ckey == NULL || EVP_PKEY_copy_parameters(ckey, skey) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_ECDHE,
+                     ERR_R_EVP_LIB);
+            goto err;
+        }
+        if (EVP_PKEY_set1_tls_encodedpoint(ckey, data, i) == 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_ECDHE,
+                     ERR_R_EC_LIB);
+            goto err;
+        }
+    }
+
+    if (ssl_derive(s, skey, ckey, 1) == 0) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    ret = 1;
+    EVP_PKEY_free(s->s3->tmp.pkey);
+    s->s3->tmp.pkey = NULL;
+ err:
+    EVP_PKEY_free(ckey);
+
+    return ret;
+#else
+    /* Should never happen */
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_ECDHE,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+static int tls_process_cke_srp(SSL *s, PACKET *pkt)
+{
+#ifndef OPENSSL_NO_SRP
+    unsigned int i;
+    const unsigned char *data;
+
+    if (!PACKET_get_net_2(pkt, &i)
+        || !PACKET_get_bytes(pkt, &data, i)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_SRP,
+                 SSL_R_BAD_SRP_A_LENGTH);
+        return 0;
+    }
+    if ((s->srp_ctx.A = BN_bin2bn(data, i, NULL)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_SRP,
+                 ERR_R_BN_LIB);
+        return 0;
+    }
+    if (BN_ucmp(s->srp_ctx.A, s->srp_ctx.N) >= 0 || BN_is_zero(s->srp_ctx.A)) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_CKE_SRP,
+                 SSL_R_BAD_SRP_PARAMETERS);
+        return 0;
+    }
+    OPENSSL_free(s->session->srp_username);
+    s->session->srp_username = OPENSSL_strdup(s->srp_ctx.login);
+    if (s->session->srp_username == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_SRP,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (!srp_generate_server_master_secret(s)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    return 1;
+#else
+    /* Should never happen */
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_SRP,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+static int tls_process_cke_gost(SSL *s, PACKET *pkt)
+{
+#ifndef OPENSSL_NO_GOST
+    EVP_PKEY_CTX *pkey_ctx;
+    EVP_PKEY *client_pub_pkey = NULL, *pk = NULL;
+    unsigned char premaster_secret[32];
+    const unsigned char *start;
+    size_t outlen = 32, inlen;
+    unsigned long alg_a;
+    GOST_KX_MESSAGE *pKX = NULL;
+    const unsigned char *ptr;
+    int ret = 0;
+
+    /* Get our certificate private key */
+    alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+    if (alg_a & SSL_aGOST12) {
+        /*
+         * New GOST ciphersuites have SSL_aGOST01 bit too
+         */
+        pk = s->cert->pkeys[SSL_PKEY_GOST12_512].privatekey;
+        if (pk == NULL) {
+            pk = s->cert->pkeys[SSL_PKEY_GOST12_256].privatekey;
+        }
+        if (pk == NULL) {
+            pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
+        }
+    } else if (alg_a & SSL_aGOST01) {
+        pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
+    }
+
+    pkey_ctx = EVP_PKEY_CTX_new(pk, NULL);
+    if (pkey_ctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    if (EVP_PKEY_decrypt_init(pkey_ctx) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    /*
+     * If client certificate is present and is of the same type, maybe
+     * use it for key exchange.  Don't mind errors from
+     * EVP_PKEY_derive_set_peer, because it is completely valid to use a
+     * client certificate for authorization only.
+     */
+    client_pub_pkey = X509_get0_pubkey(s->session->peer);
+    if (client_pub_pkey) {
+        if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
+            ERR_clear_error();
+    }
+
+    ptr = PACKET_data(pkt);
+    /* Some implementations provide extra data in the opaqueBlob
+     * We have nothing to do with this blob so we just skip it */
+    pKX = d2i_GOST_KX_MESSAGE(NULL, &ptr, PACKET_remaining(pkt));
+    if (pKX == NULL
+       || pKX->kxBlob == NULL
+       || ASN1_TYPE_get(pKX->kxBlob) != V_ASN1_SEQUENCE) {
+         SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_GOST,
+                  SSL_R_DECRYPTION_FAILED);
+         goto err;
+    }
+
+    if (!PACKET_forward(pkt, ptr - PACKET_data(pkt))) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST,
+                 SSL_R_DECRYPTION_FAILED);
+        goto err;
+    }
+
+    if (PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST,
+                 SSL_R_DECRYPTION_FAILED);
+        goto err;
+    }
+
+    inlen = pKX->kxBlob->value.sequence->length;
+    start = pKX->kxBlob->value.sequence->data;
+
+    if (EVP_PKEY_decrypt(pkey_ctx, premaster_secret, &outlen, start,
+                         inlen) <= 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_GOST,
+                 SSL_R_DECRYPTION_FAILED);
+        goto err;
+    }
+    /* Generate master secret */
+    if (!ssl_generate_master_secret(s, premaster_secret,
+                                    sizeof(premaster_secret), 0)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+    /* Check if pubkey from client certificate was used */
+    if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2,
+                          NULL) > 0)
+        s->statem.no_cert_verify = 1;
+
+    ret = 1;
+ err:
+    EVP_PKEY_CTX_free(pkey_ctx);
+    GOST_KX_MESSAGE_free(pKX);
+    return ret;
+#else
+    /* Should never happen */
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
+MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt)
+{
+    unsigned long alg_k;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    /* For PSK parse and retrieve identity, obtain PSK key */
+    if ((alg_k & SSL_PSK) && !tls_process_cke_psk_preamble(s, pkt)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    if (alg_k & SSL_kPSK) {
+        /* Identity extracted earlier: should be nothing left */
+        if (PACKET_remaining(pkt) != 0) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                     SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+        /* PSK handled by ssl_generate_master_secret */
+        if (!ssl_generate_master_secret(s, NULL, 0, 0)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
+        if (!tls_process_cke_rsa(s, pkt)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
+        if (!tls_process_cke_dhe(s, pkt)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
+        if (!tls_process_cke_ecdhe(s, pkt)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else if (alg_k & SSL_kSRP) {
+        if (!tls_process_cke_srp(s, pkt)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else if (alg_k & SSL_kGOST) {
+        if (!tls_process_cke_gost(s, pkt)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                 SSL_R_UNKNOWN_CIPHER_TYPE);
+        goto err;
+    }
+
+    return MSG_PROCESS_CONTINUE_PROCESSING;
+ err:
+#ifndef OPENSSL_NO_PSK
+    OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen);
+    s->s3->tmp.psk = NULL;
+    s->s3->tmp.psklen = 0;
+#endif
+    return MSG_PROCESS_ERROR;
+}
+
+WORK_STATE tls_post_process_client_key_exchange(SSL *s, WORK_STATE wst)
+{
+#ifndef OPENSSL_NO_SCTP
+    if (wst == WORK_MORE_A) {
+        if (SSL_IS_DTLS(s)) {
+            unsigned char sctpauthkey[64];
+            char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+            size_t labellen;
+            /*
+             * Add new shared key for SCTP-Auth, will be ignored if no SCTP
+             * used.
+             */
+            memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
+                   sizeof(DTLS1_SCTP_AUTH_LABEL));
+
+            /* Don't include the terminating zero. */
+            labellen = sizeof(labelbuffer) - 1;
+            if (s->mode & SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG)
+                labellen += 1;
+
+            if (SSL_export_keying_material(s, sctpauthkey,
+                                           sizeof(sctpauthkey), labelbuffer,
+                                           labellen, NULL, 0,
+                                           0) <= 0) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE,
+                         ERR_R_INTERNAL_ERROR);
+                return WORK_ERROR;
+            }
+
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+                     sizeof(sctpauthkey), sctpauthkey);
+        }
+    }
+#endif
+
+    if (s->statem.no_cert_verify || !s->session->peer) {
+        /*
+         * No certificate verify or no peer certificate so we no longer need
+         * the handshake_buffer
+         */
+        if (!ssl3_digest_cached_records(s, 0)) {
+            /* SSLfatal() already called */
+            return WORK_ERROR;
+        }
+        return WORK_FINISHED_CONTINUE;
+    } else {
+        if (!s->s3->handshake_buffer) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE,
+                     ERR_R_INTERNAL_ERROR);
+            return WORK_ERROR;
+        }
+        /*
+         * For sigalgs freeze the handshake buffer. If we support
+         * extms we've done this already so this is a no-op
+         */
+        if (!ssl3_digest_cached_records(s, 1)) {
+            /* SSLfatal() already called */
+            return WORK_ERROR;
+        }
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt)
+{
+    int i;
+    MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR;
+    X509 *x = NULL;
+    unsigned long l;
+    const unsigned char *certstart, *certbytes;
+    STACK_OF(X509) *sk = NULL;
+    PACKET spkt, context;
+    size_t chainidx;
+    SSL_SESSION *new_sess = NULL;
+
+    /*
+     * To get this far we must have read encrypted data from the client. We no
+     * longer tolerate unencrypted alerts. This value is ignored if less than
+     * TLSv1.3
+     */
+    s->statem.enc_read_state = ENC_READ_STATE_VALID;
+
+    if ((sk = sk_X509_new_null()) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (SSL_IS_TLS13(s) && (!PACKET_get_length_prefixed_1(pkt, &context)
+                            || (s->pha_context == NULL && PACKET_remaining(&context) != 0)
+                            || (s->pha_context != NULL &&
+                                !PACKET_equal(&context, s->pha_context, s->pha_context_len)))) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                 SSL_R_INVALID_CONTEXT);
+        goto err;
+    }
+
+    if (!PACKET_get_length_prefixed_3(pkt, &spkt)
+            || PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                 SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    for (chainidx = 0; PACKET_remaining(&spkt) > 0; chainidx++) {
+        if (!PACKET_get_net_3(&spkt, &l)
+            || !PACKET_get_bytes(&spkt, &certbytes, l)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                     SSL_R_CERT_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        certstart = certbytes;
+        x = d2i_X509(NULL, (const unsigned char **)&certbytes, l);
+        if (x == NULL) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_ASN1_LIB);
+            goto err;
+        }
+        if (certbytes != (certstart + l)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR,
+                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                     SSL_R_CERT_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        if (SSL_IS_TLS13(s)) {
+            RAW_EXTENSION *rawexts = NULL;
+            PACKET extensions;
+
+            if (!PACKET_get_length_prefixed_2(&spkt, &extensions)) {
+                SSLfatal(s, SSL_AD_DECODE_ERROR,
+                         SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                         SSL_R_BAD_LENGTH);
+                goto err;
+            }
+            if (!tls_collect_extensions(s, &extensions,
+                                        SSL_EXT_TLS1_3_CERTIFICATE, &rawexts,
+                                        NULL, chainidx == 0)
+                || !tls_parse_all_extensions(s, SSL_EXT_TLS1_3_CERTIFICATE,
+                                             rawexts, x, chainidx,
+                                             PACKET_remaining(&spkt) == 0)) {
+                OPENSSL_free(rawexts);
+                goto err;
+            }
+            OPENSSL_free(rawexts);
+        }
+
+        if (!sk_X509_push(sk, x)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                     ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+        x = NULL;
+    }
+
+    if (sk_X509_num(sk) <= 0) {
+        /* TLS does not mind 0 certs returned */
+        if (s->version == SSL3_VERSION) {
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                     SSL_R_NO_CERTIFICATES_RETURNED);
+            goto err;
+        }
+        /* Fail for TLS only if we required a certificate */
+        else if ((s->verify_mode & SSL_VERIFY_PEER) &&
+                 (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
+            SSLfatal(s, SSL_AD_CERTIFICATE_REQUIRED,
+                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                     SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+            goto err;
+        }
+        /* No client certificate so digest cached records */
+        if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, 0)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else {
+        EVP_PKEY *pkey;
+        i = ssl_verify_cert_chain(s, sk);
+        if (i <= 0) {
+            SSLfatal(s, ssl_x509err2alert(s->verify_result),
+                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                     SSL_R_CERTIFICATE_VERIFY_FAILED);
+            goto err;
+        }
+        if (i > 1) {
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, i);
+            goto err;
+        }
+        pkey = X509_get0_pubkey(sk_X509_value(sk, 0));
+        if (pkey == NULL) {
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                     SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+            goto err;
+        }
+    }
+
+    /*
+     * Sessions must be immutable once they go into the session cache. Otherwise
+     * we can get multi-thread problems. Therefore we don't "update" sessions,
+     * we replace them with a duplicate. Here, we need to do this every time
+     * a new certificate is received via post-handshake authentication, as the
+     * session may have already gone into the session cache.
+     */
+
+    if (s->post_handshake_auth == SSL_PHA_REQUESTED) {
+        if ((new_sess = ssl_session_dup(s->session, 0)) == 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                     ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        SSL_SESSION_free(s->session);
+        s->session = new_sess;
+    }
+
+    X509_free(s->session->peer);
+    s->session->peer = sk_X509_shift(sk);
+    s->session->verify_result = s->verify_result;
+
+    sk_X509_pop_free(s->session->peer_chain, X509_free);
+    s->session->peer_chain = sk;
+    sk = NULL;
+
+    /*
+     * Freeze the handshake buffer. For <TLS1.3 we do this after the CKE
+     * message
+     */
+    if (SSL_IS_TLS13(s) && !ssl3_digest_cached_records(s, 1)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    /*
+     * Inconsistency alert: cert_chain does *not* include the peer's own
+     * certificate, while we do include it in statem_clnt.c
+     */
+
+    /* Save the current hash state for when we receive the CertificateVerify */
+    if (SSL_IS_TLS13(s)) {
+        if (!ssl_handshake_hash(s, s->cert_verify_hash,
+                                sizeof(s->cert_verify_hash),
+                                &s->cert_verify_hash_len)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+
+        /* Resend session tickets */
+        s->sent_tickets = 0;
+    }
+
+    ret = MSG_PROCESS_CONTINUE_READING;
+
+ err:
+    X509_free(x);
+    sk_X509_pop_free(sk, X509_free);
+    return ret;
+}
+
+int tls_construct_server_certificate(SSL *s, WPACKET *pkt)
+{
+    CERT_PKEY *cpk = s->s3->tmp.cert;
+
+    if (cpk == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /*
+     * In TLSv1.3 the certificate chain is always preceded by a 0 length context
+     * for the server Certificate message
+     */
+    if (SSL_IS_TLS13(s) && !WPACKET_put_bytes_u8(pkt, 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    if (!ssl3_output_cert_chain(s, pkt, cpk)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    return 1;
+}
+
+static int create_ticket_prequel(SSL *s, WPACKET *pkt, uint32_t age_add,
+                                 unsigned char *tick_nonce)
+{
+    uint32_t timeout = (uint32_t)s->session->timeout;
+
+    /*
+     * Ticket lifetime hint:
+     * In TLSv1.3 we reset the "time" field above, and always specify the
+     * timeout, limited to a 1 week period per RFC8446.
+     * For TLSv1.2 this is advisory only and we leave this unspecified for
+     * resumed session (for simplicity).
+     */
+#define ONE_WEEK_SEC (7 * 24 * 60 * 60)
+
+    if (SSL_IS_TLS13(s)) {
+        if (s->session->timeout > ONE_WEEK_SEC)
+            timeout = ONE_WEEK_SEC;
+    } else if (s->hit)
+        timeout = 0;
+
+    if (!WPACKET_put_bytes_u32(pkt, timeout)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CREATE_TICKET_PREQUEL,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (SSL_IS_TLS13(s)) {
+        if (!WPACKET_put_bytes_u32(pkt, age_add)
+                || !WPACKET_sub_memcpy_u8(pkt, tick_nonce, TICKET_NONCE_SIZE)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CREATE_TICKET_PREQUEL,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+
+    /* Start the sub-packet for the actual ticket data */
+    if (!WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CREATE_TICKET_PREQUEL,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+static int construct_stateless_ticket(SSL *s, WPACKET *pkt, uint32_t age_add,
+                                      unsigned char *tick_nonce)
+{
+    unsigned char *senc = NULL;
+    EVP_CIPHER_CTX *ctx = NULL;
+    HMAC_CTX *hctx = NULL;
+    unsigned char *p, *encdata1, *encdata2, *macdata1, *macdata2;
+    const unsigned char *const_p;
+    int len, slen_full, slen, lenfinal;
+    SSL_SESSION *sess;
+    unsigned int hlen;
+    SSL_CTX *tctx = s->session_ctx;
+    unsigned char iv[EVP_MAX_IV_LENGTH];
+    unsigned char key_name[TLSEXT_KEYNAME_LENGTH];
+    int iv_len, ok = 0;
+    size_t macoffset, macendoffset;
+
+    /* get session encoding length */
+    slen_full = i2d_SSL_SESSION(s->session, NULL);
+    /*
+     * Some length values are 16 bits, so forget it if session is too
+     * long
+     */
+    if (slen_full == 0 || slen_full > 0xFF00) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_STATELESS_TICKET,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    senc = OPENSSL_malloc(slen_full);
+    if (senc == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_CONSTRUCT_STATELESS_TICKET, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    ctx = EVP_CIPHER_CTX_new();
+    hctx = HMAC_CTX_new();
+    if (ctx == NULL || hctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_STATELESS_TICKET,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    p = senc;
+    if (!i2d_SSL_SESSION(s->session, &p)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_STATELESS_TICKET,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /*
+     * create a fresh copy (not shared with other threads) to clean up
+     */
+    const_p = senc;
+    sess = d2i_SSL_SESSION(NULL, &const_p, slen_full);
+    if (sess == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_STATELESS_TICKET,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    slen = i2d_SSL_SESSION(sess, NULL);
+    if (slen == 0 || slen > slen_full) {
+        /* shouldn't ever happen */
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_STATELESS_TICKET,
+                 ERR_R_INTERNAL_ERROR);
+        SSL_SESSION_free(sess);
+        goto err;
+    }
+    p = senc;
+    if (!i2d_SSL_SESSION(sess, &p)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_STATELESS_TICKET,
+                 ERR_R_INTERNAL_ERROR);
+        SSL_SESSION_free(sess);
+        goto err;
+    }
+    SSL_SESSION_free(sess);
+
+    /*
+     * Initialize HMAC and cipher contexts. If callback present it does
+     * all the work otherwise use generated values from parent ctx.
+     */
+    if (tctx->ext.ticket_key_cb) {
+        /* if 0 is returned, write an empty ticket */
+        int ret = tctx->ext.ticket_key_cb(s, key_name, iv, ctx,
+                                             hctx, 1);
+
+        if (ret == 0) {
+
+            /* Put timeout and length */
+            if (!WPACKET_put_bytes_u32(pkt, 0)
+                    || !WPACKET_put_bytes_u16(pkt, 0)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_CONSTRUCT_STATELESS_TICKET,
+                         ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            OPENSSL_free(senc);
+            EVP_CIPHER_CTX_free(ctx);
+            HMAC_CTX_free(hctx);
+            return 1;
+        }
+        if (ret < 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_STATELESS_TICKET,
+                     SSL_R_CALLBACK_FAILED);
+            goto err;
+        }
+        iv_len = EVP_CIPHER_CTX_iv_length(ctx);
+    } else {
+        const EVP_CIPHER *cipher = EVP_aes_256_cbc();
+
+        iv_len = EVP_CIPHER_iv_length(cipher);
+        if (RAND_bytes(iv, iv_len) <= 0
+                || !EVP_EncryptInit_ex(ctx, cipher, NULL,
+                                       tctx->ext.secure->tick_aes_key, iv)
+                || !HMAC_Init_ex(hctx, tctx->ext.secure->tick_hmac_key,
+                                 sizeof(tctx->ext.secure->tick_hmac_key),
+                                 EVP_sha256(), NULL)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_STATELESS_TICKET,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        memcpy(key_name, tctx->ext.tick_key_name,
+               sizeof(tctx->ext.tick_key_name));
+    }
+
+    if (!create_ticket_prequel(s, pkt, age_add, tick_nonce)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    if (!WPACKET_get_total_written(pkt, &macoffset)
+               /* Output key name */
+            || !WPACKET_memcpy(pkt, key_name, sizeof(key_name))
+               /* output IV */
+            || !WPACKET_memcpy(pkt, iv, iv_len)
+            || !WPACKET_reserve_bytes(pkt, slen + EVP_MAX_BLOCK_LENGTH,
+                                      &encdata1)
+               /* Encrypt session data */
+            || !EVP_EncryptUpdate(ctx, encdata1, &len, senc, slen)
+            || !WPACKET_allocate_bytes(pkt, len, &encdata2)
+            || encdata1 != encdata2
+            || !EVP_EncryptFinal(ctx, encdata1 + len, &lenfinal)
+            || !WPACKET_allocate_bytes(pkt, lenfinal, &encdata2)
+            || encdata1 + len != encdata2
+            || len + lenfinal > slen + EVP_MAX_BLOCK_LENGTH
+            || !WPACKET_get_total_written(pkt, &macendoffset)
+            || !HMAC_Update(hctx,
+                            (unsigned char *)s->init_buf->data + macoffset,
+                            macendoffset - macoffset)
+            || !WPACKET_reserve_bytes(pkt, EVP_MAX_MD_SIZE, &macdata1)
+            || !HMAC_Final(hctx, macdata1, &hlen)
+            || hlen > EVP_MAX_MD_SIZE
+            || !WPACKET_allocate_bytes(pkt, hlen, &macdata2)
+            || macdata1 != macdata2) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_CONSTRUCT_STATELESS_TICKET, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /* Close the sub-packet created by create_ticket_prequel() */
+    if (!WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_STATELESS_TICKET,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    ok = 1;
+ err:
+    OPENSSL_free(senc);
+    EVP_CIPHER_CTX_free(ctx);
+    HMAC_CTX_free(hctx);
+    return ok;
+}
+
+static int construct_stateful_ticket(SSL *s, WPACKET *pkt, uint32_t age_add,
+                                     unsigned char *tick_nonce)
+{
+    if (!create_ticket_prequel(s, pkt, age_add, tick_nonce)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    if (!WPACKET_memcpy(pkt, s->session->session_id,
+                        s->session->session_id_length)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_STATEFUL_TICKET,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt)
+{
+    SSL_CTX *tctx = s->session_ctx;
+    unsigned char tick_nonce[TICKET_NONCE_SIZE];
+    union {
+        unsigned char age_add_c[sizeof(uint32_t)];
+        uint32_t age_add;
+    } age_add_u;
+
+    age_add_u.age_add = 0;
+
+    if (SSL_IS_TLS13(s)) {
+        size_t i, hashlen;
+        uint64_t nonce;
+        static const unsigned char nonce_label[] = "resumption";
+        const EVP_MD *md = ssl_handshake_md(s);
+        int hashleni = EVP_MD_size(md);
+
+        /* Ensure cast to size_t is safe */
+        if (!ossl_assert(hashleni >= 0)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        hashlen = (size_t)hashleni;
+
+        /*
+         * If we already sent one NewSessionTicket, or we resumed then
+         * s->session may already be in a cache and so we must not modify it.
+         * Instead we need to take a copy of it and modify that.
+         */
+        if (s->sent_tickets != 0 || s->hit) {
+            SSL_SESSION *new_sess = ssl_session_dup(s->session, 0);
+
+            if (new_sess == NULL) {
+                /* SSLfatal already called */
+                goto err;
+            }
+
+            SSL_SESSION_free(s->session);
+            s->session = new_sess;
+        }
+
+        if (!ssl_generate_session_id(s, s->session)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+        if (RAND_bytes(age_add_u.age_add_c, sizeof(age_add_u)) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        s->session->ext.tick_age_add = age_add_u.age_add;
+
+        nonce = s->next_ticket_nonce;
+        for (i = TICKET_NONCE_SIZE; i > 0; i--) {
+            tick_nonce[i - 1] = (unsigned char)(nonce & 0xff);
+            nonce >>= 8;
+        }
+
+        if (!tls13_hkdf_expand(s, md, s->resumption_master_secret,
+                               nonce_label,
+                               sizeof(nonce_label) - 1,
+                               tick_nonce,
+                               TICKET_NONCE_SIZE,
+                               s->session->master_key,
+                               hashlen, 1)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+        s->session->master_key_length = hashlen;
+
+        s->session->time = (long)time(NULL);
+        if (s->s3->alpn_selected != NULL) {
+            OPENSSL_free(s->session->ext.alpn_selected);
+            s->session->ext.alpn_selected =
+                OPENSSL_memdup(s->s3->alpn_selected, s->s3->alpn_selected_len);
+            if (s->session->ext.alpn_selected == NULL) {
+                s->session->ext.alpn_selected_len = 0;
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET,
+                         ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+            s->session->ext.alpn_selected_len = s->s3->alpn_selected_len;
+        }
+        s->session->ext.max_early_data = s->max_early_data;
+    }
+
+    if (tctx->generate_ticket_cb != NULL &&
+        tctx->generate_ticket_cb(s, tctx->ticket_cb_data) == 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    /*
+     * If we are using anti-replay protection then we behave as if
+     * SSL_OP_NO_TICKET is set - we are caching tickets anyway so there
+     * is no point in using full stateless tickets.
+     */
+    if (SSL_IS_TLS13(s)
+            && ((s->options & SSL_OP_NO_TICKET) != 0
+                || (s->max_early_data > 0
+                    && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0))) {
+        if (!construct_stateful_ticket(s, pkt, age_add_u.age_add, tick_nonce)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else if (!construct_stateless_ticket(s, pkt, age_add_u.age_add,
+                                           tick_nonce)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    if (SSL_IS_TLS13(s)) {
+        if (!tls_construct_extensions(s, pkt,
+                                      SSL_EXT_TLS1_3_NEW_SESSION_TICKET,
+                                      NULL, 0)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+        /*
+         * Increment both |sent_tickets| and |next_ticket_nonce|. |sent_tickets|
+         * gets reset to 0 if we send more tickets following a post-handshake
+         * auth, but |next_ticket_nonce| does not.
+         */
+        s->sent_tickets++;
+        s->next_ticket_nonce++;
+        ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
+    }
+
+    return 1;
+ err:
+    return 0;
+}
+
+/*
+ * In TLSv1.3 this is called from the extensions code, otherwise it is used to
+ * create a separate message. Returns 1 on success or 0 on failure.
+ */
+int tls_construct_cert_status_body(SSL *s, WPACKET *pkt)
+{
+    if (!WPACKET_put_bytes_u8(pkt, s->ext.status_type)
+            || !WPACKET_sub_memcpy_u24(pkt, s->ext.ocsp.resp,
+                                       s->ext.ocsp.resp_len)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_STATUS_BODY,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_cert_status(SSL *s, WPACKET *pkt)
+{
+    if (!tls_construct_cert_status_body(s, pkt)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+/*
+ * tls_process_next_proto reads a Next Protocol Negotiation handshake message.
+ * It sets the next_proto member in s if found
+ */
+MSG_PROCESS_RETURN tls_process_next_proto(SSL *s, PACKET *pkt)
+{
+    PACKET next_proto, padding;
+    size_t next_proto_len;
+
+    /*-
+     * The payload looks like:
+     *   uint8 proto_len;
+     *   uint8 proto[proto_len];
+     *   uint8 padding_len;
+     *   uint8 padding[padding_len];
+     */
+    if (!PACKET_get_length_prefixed_1(pkt, &next_proto)
+        || !PACKET_get_length_prefixed_1(pkt, &padding)
+        || PACKET_remaining(pkt) > 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_NEXT_PROTO,
+                 SSL_R_LENGTH_MISMATCH);
+        return MSG_PROCESS_ERROR;
+    }
+
+    if (!PACKET_memdup(&next_proto, &s->ext.npn, &next_proto_len)) {
+        s->ext.npn_len = 0;
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_NEXT_PROTO,
+                 ERR_R_INTERNAL_ERROR);
+        return MSG_PROCESS_ERROR;
+    }
+
+    s->ext.npn_len = (unsigned char)next_proto_len;
+
+    return MSG_PROCESS_CONTINUE_READING;
+}
+#endif
+
+static int tls_construct_encrypted_extensions(SSL *s, WPACKET *pkt)
+{
+    if (!tls_construct_extensions(s, pkt, SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
+                                  NULL, 0)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    return 1;
+}
+
+MSG_PROCESS_RETURN tls_process_end_of_early_data(SSL *s, PACKET *pkt)
+{
+    if (PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_END_OF_EARLY_DATA,
+                 SSL_R_LENGTH_MISMATCH);
+        return MSG_PROCESS_ERROR;
+    }
+
+    if (s->early_data_state != SSL_EARLY_DATA_READING
+            && s->early_data_state != SSL_EARLY_DATA_READ_RETRY) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_END_OF_EARLY_DATA,
+                 ERR_R_INTERNAL_ERROR);
+        return MSG_PROCESS_ERROR;
+    }
+
+    /*
+     * EndOfEarlyData signals a key change so the end of the message must be on
+     * a record boundary.
+     */
+    if (RECORD_LAYER_processed_read_pending(&s->rlayer)) {
+        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+                 SSL_F_TLS_PROCESS_END_OF_EARLY_DATA,
+                 SSL_R_NOT_ON_RECORD_BOUNDARY);
+        return MSG_PROCESS_ERROR;
+    }
+
+    s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
+    if (!s->method->ssl3_enc->change_cipher_state(s,
+                SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_READ)) {
+        /* SSLfatal() already called */
+        return MSG_PROCESS_ERROR;
+    }
+
+    return MSG_PROCESS_CONTINUE_READING;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/t1_enc.c b/ap/lib/libssl/openssl-1.1.1o/ssl/t1_enc.c
new file mode 100644
index 0000000..f8e53d4
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/t1_enc.c
@@ -0,0 +1,680 @@
+/*
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include "ssl_local.h"
+#include <openssl/comp.h>
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+#include <openssl/rand.h>
+
+/* seed1 through seed5 are concatenated */
+static int tls1_PRF(SSL *s,
+                    const void *seed1, size_t seed1_len,
+                    const void *seed2, size_t seed2_len,
+                    const void *seed3, size_t seed3_len,
+                    const void *seed4, size_t seed4_len,
+                    const void *seed5, size_t seed5_len,
+                    const unsigned char *sec, size_t slen,
+                    unsigned char *out, size_t olen, int fatal)
+{
+    const EVP_MD *md = ssl_prf_md(s);
+    EVP_PKEY_CTX *pctx = NULL;
+    int ret = 0;
+
+    if (md == NULL) {
+        /* Should never happen */
+        if (fatal)
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_PRF,
+                     ERR_R_INTERNAL_ERROR);
+        else
+            SSLerr(SSL_F_TLS1_PRF, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, NULL);
+    if (pctx == NULL || EVP_PKEY_derive_init(pctx) <= 0
+        || EVP_PKEY_CTX_set_tls1_prf_md(pctx, md) <= 0
+        || EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, sec, (int)slen) <= 0
+        || EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, seed1, (int)seed1_len) <= 0
+        || EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, seed2, (int)seed2_len) <= 0
+        || EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, seed3, (int)seed3_len) <= 0
+        || EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, seed4, (int)seed4_len) <= 0
+        || EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, seed5, (int)seed5_len) <= 0
+        || EVP_PKEY_derive(pctx, out, &olen) <= 0) {
+        if (fatal)
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_PRF,
+                     ERR_R_INTERNAL_ERROR);
+        else
+            SSLerr(SSL_F_TLS1_PRF, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    ret = 1;
+
+ err:
+    EVP_PKEY_CTX_free(pctx);
+    return ret;
+}
+
+static int tls1_generate_key_block(SSL *s, unsigned char *km, size_t num)
+{
+    int ret;
+
+    /* Calls SSLfatal() as required */
+    ret = tls1_PRF(s,
+                   TLS_MD_KEY_EXPANSION_CONST,
+                   TLS_MD_KEY_EXPANSION_CONST_SIZE, s->s3->server_random,
+                   SSL3_RANDOM_SIZE, s->s3->client_random, SSL3_RANDOM_SIZE,
+                   NULL, 0, NULL, 0, s->session->master_key,
+                   s->session->master_key_length, km, num, 1);
+
+    return ret;
+}
+
+int tls1_change_cipher_state(SSL *s, int which)
+{
+    unsigned char *p, *mac_secret;
+    unsigned char *ms, *key, *iv;
+    EVP_CIPHER_CTX *dd;
+    const EVP_CIPHER *c;
+#ifndef OPENSSL_NO_COMP
+    const SSL_COMP *comp;
+#endif
+    const EVP_MD *m;
+    int mac_type;
+    size_t *mac_secret_size;
+    EVP_MD_CTX *mac_ctx;
+    EVP_PKEY *mac_key;
+    size_t n, i, j, k, cl;
+    int reuse_dd = 0;
+
+    c = s->s3->tmp.new_sym_enc;
+    m = s->s3->tmp.new_hash;
+    mac_type = s->s3->tmp.new_mac_pkey_type;
+#ifndef OPENSSL_NO_COMP
+    comp = s->s3->tmp.new_compression;
+#endif
+
+    if (which & SSL3_CC_READ) {
+        if (s->ext.use_etm)
+            s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC_READ;
+        else
+            s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC_READ;
+
+        if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
+            s->mac_flags |= SSL_MAC_FLAG_READ_MAC_STREAM;
+        else
+            s->mac_flags &= ~SSL_MAC_FLAG_READ_MAC_STREAM;
+
+        if (s->enc_read_ctx != NULL) {
+            reuse_dd = 1;
+        } else if ((s->enc_read_ctx = EVP_CIPHER_CTX_new()) == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                     ERR_R_MALLOC_FAILURE);
+            goto err;
+        } else {
+            /*
+             * make sure it's initialised in case we exit later with an error
+             */
+            EVP_CIPHER_CTX_reset(s->enc_read_ctx);
+        }
+        dd = s->enc_read_ctx;
+        mac_ctx = ssl_replace_hash(&s->read_hash, NULL);
+        if (mac_ctx == NULL)
+            goto err;
+#ifndef OPENSSL_NO_COMP
+        COMP_CTX_free(s->expand);
+        s->expand = NULL;
+        if (comp != NULL) {
+            s->expand = COMP_CTX_new(comp->method);
+            if (s->expand == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                         SSL_R_COMPRESSION_LIBRARY_ERROR);
+                goto err;
+            }
+        }
+#endif
+        /*
+         * this is done by dtls1_reset_seq_numbers for DTLS
+         */
+        if (!SSL_IS_DTLS(s))
+            RECORD_LAYER_reset_read_sequence(&s->rlayer);
+        mac_secret = &(s->s3->read_mac_secret[0]);
+        mac_secret_size = &(s->s3->read_mac_secret_size);
+    } else {
+        s->statem.enc_write_state = ENC_WRITE_STATE_INVALID;
+        if (s->ext.use_etm)
+            s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC_WRITE;
+        else
+            s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC_WRITE;
+
+        if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
+            s->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_STREAM;
+        else
+            s->mac_flags &= ~SSL_MAC_FLAG_WRITE_MAC_STREAM;
+        if (s->enc_write_ctx != NULL && !SSL_IS_DTLS(s)) {
+            reuse_dd = 1;
+        } else if ((s->enc_write_ctx = EVP_CIPHER_CTX_new()) == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                     ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+        dd = s->enc_write_ctx;
+        if (SSL_IS_DTLS(s)) {
+            mac_ctx = EVP_MD_CTX_new();
+            if (mac_ctx == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                         ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+            s->write_hash = mac_ctx;
+        } else {
+            mac_ctx = ssl_replace_hash(&s->write_hash, NULL);
+            if (mac_ctx == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                         ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+        }
+#ifndef OPENSSL_NO_COMP
+        COMP_CTX_free(s->compress);
+        s->compress = NULL;
+        if (comp != NULL) {
+            s->compress = COMP_CTX_new(comp->method);
+            if (s->compress == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                        SSL_R_COMPRESSION_LIBRARY_ERROR);
+                goto err;
+            }
+        }
+#endif
+        /*
+         * this is done by dtls1_reset_seq_numbers for DTLS
+         */
+        if (!SSL_IS_DTLS(s))
+            RECORD_LAYER_reset_write_sequence(&s->rlayer);
+        mac_secret = &(s->s3->write_mac_secret[0]);
+        mac_secret_size = &(s->s3->write_mac_secret_size);
+    }
+
+    if (reuse_dd)
+        EVP_CIPHER_CTX_reset(dd);
+
+    p = s->s3->tmp.key_block;
+    i = *mac_secret_size = s->s3->tmp.new_mac_secret_size;
+
+    /* TODO(size_t): convert me */
+    cl = EVP_CIPHER_key_length(c);
+    j = cl;
+    /* Was j=(exp)?5:EVP_CIPHER_key_length(c); */
+    /* If GCM/CCM mode only part of IV comes from PRF */
+    if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE)
+        k = EVP_GCM_TLS_FIXED_IV_LEN;
+    else if (EVP_CIPHER_mode(c) == EVP_CIPH_CCM_MODE)
+        k = EVP_CCM_TLS_FIXED_IV_LEN;
+    else
+        k = EVP_CIPHER_iv_length(c);
+    if ((which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) ||
+        (which == SSL3_CHANGE_CIPHER_SERVER_READ)) {
+        ms = &(p[0]);
+        n = i + i;
+        key = &(p[n]);
+        n += j + j;
+        iv = &(p[n]);
+        n += k + k;
+    } else {
+        n = i;
+        ms = &(p[n]);
+        n += i + j;
+        key = &(p[n]);
+        n += j + k;
+        iv = &(p[n]);
+        n += k;
+    }
+
+    if (n > s->s3->tmp.key_block_length) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    memcpy(mac_secret, ms, i);
+
+    if (!(EVP_CIPHER_flags(c) & EVP_CIPH_FLAG_AEAD_CIPHER)) {
+        /* TODO(size_t): Convert this function */
+        mac_key = EVP_PKEY_new_mac_key(mac_type, NULL, mac_secret,
+                                               (int)*mac_secret_size);
+        if (mac_key == NULL
+            || EVP_DigestSignInit(mac_ctx, NULL, m, NULL, mac_key) <= 0) {
+            EVP_PKEY_free(mac_key);
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        EVP_PKEY_free(mac_key);
+    }
+#ifdef SSL_DEBUG
+    printf("which = %04X\nmac key=", which);
+    {
+        size_t z;
+        for (z = 0; z < i; z++)
+            printf("%02X%c", ms[z], ((z + 1) % 16) ? ' ' : '\n');
+    }
+#endif
+
+    if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE) {
+        if (!EVP_CipherInit_ex(dd, c, NULL, key, NULL, (which & SSL3_CC_WRITE))
+            || !EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_GCM_SET_IV_FIXED, (int)k,
+                                    iv)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    } else if (EVP_CIPHER_mode(c) == EVP_CIPH_CCM_MODE) {
+        int taglen;
+        if (s->s3->tmp.
+            new_cipher->algorithm_enc & (SSL_AES128CCM8 | SSL_AES256CCM8))
+            taglen = EVP_CCM8_TLS_TAG_LEN;
+        else
+            taglen = EVP_CCM_TLS_TAG_LEN;
+        if (!EVP_CipherInit_ex(dd, c, NULL, NULL, NULL, (which & SSL3_CC_WRITE))
+            || !EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL)
+            || !EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_AEAD_SET_TAG, taglen, NULL)
+            || !EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_CCM_SET_IV_FIXED, (int)k, iv)
+            || !EVP_CipherInit_ex(dd, NULL, NULL, key, NULL, -1)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    } else {
+        if (!EVP_CipherInit_ex(dd, c, NULL, key, iv, (which & SSL3_CC_WRITE))) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+    /* Needed for "composite" AEADs, such as RC4-HMAC-MD5 */
+    if ((EVP_CIPHER_flags(c) & EVP_CIPH_FLAG_AEAD_CIPHER) && *mac_secret_size
+        && !EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_AEAD_SET_MAC_KEY,
+                                (int)*mac_secret_size, mac_secret)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
+
+#ifdef SSL_DEBUG
+    printf("which = %04X\nkey=", which);
+    {
+        int z;
+        for (z = 0; z < EVP_CIPHER_key_length(c); z++)
+            printf("%02X%c", key[z], ((z + 1) % 16) ? ' ' : '\n');
+    }
+    printf("\niv=");
+    {
+        size_t z;
+        for (z = 0; z < k; z++)
+            printf("%02X%c", iv[z], ((z + 1) % 16) ? ' ' : '\n');
+    }
+    printf("\n");
+#endif
+
+    return 1;
+ err:
+    return 0;
+}
+
+int tls1_setup_key_block(SSL *s)
+{
+    unsigned char *p;
+    const EVP_CIPHER *c;
+    const EVP_MD *hash;
+    SSL_COMP *comp;
+    int mac_type = NID_undef;
+    size_t num, mac_secret_size = 0;
+    int ret = 0;
+
+    if (s->s3->tmp.key_block_length != 0)
+        return 1;
+
+    if (!ssl_cipher_get_evp(s->session, &c, &hash, &mac_type, &mac_secret_size,
+                            &comp, s->ext.use_etm)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_SETUP_KEY_BLOCK,
+                 SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
+        return 0;
+    }
+
+    s->s3->tmp.new_sym_enc = c;
+    s->s3->tmp.new_hash = hash;
+    s->s3->tmp.new_mac_pkey_type = mac_type;
+    s->s3->tmp.new_mac_secret_size = mac_secret_size;
+    num = EVP_CIPHER_key_length(c) + mac_secret_size + EVP_CIPHER_iv_length(c);
+    num *= 2;
+
+    ssl3_cleanup_key_block(s);
+
+    if ((p = OPENSSL_malloc(num)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_SETUP_KEY_BLOCK,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    s->s3->tmp.key_block_length = num;
+    s->s3->tmp.key_block = p;
+
+#ifdef SSL_DEBUG
+    printf("client random\n");
+    {
+        int z;
+        for (z = 0; z < SSL3_RANDOM_SIZE; z++)
+            printf("%02X%c", s->s3->client_random[z],
+                   ((z + 1) % 16) ? ' ' : '\n');
+    }
+    printf("server random\n");
+    {
+        int z;
+        for (z = 0; z < SSL3_RANDOM_SIZE; z++)
+            printf("%02X%c", s->s3->server_random[z],
+                   ((z + 1) % 16) ? ' ' : '\n');
+    }
+    printf("master key\n");
+    {
+        size_t z;
+        for (z = 0; z < s->session->master_key_length; z++)
+            printf("%02X%c", s->session->master_key[z],
+                   ((z + 1) % 16) ? ' ' : '\n');
+    }
+#endif
+    if (!tls1_generate_key_block(s, p, num)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+#ifdef SSL_DEBUG
+    printf("\nkey block\n");
+    {
+        size_t z;
+        for (z = 0; z < num; z++)
+            printf("%02X%c", p[z], ((z + 1) % 16) ? ' ' : '\n');
+    }
+#endif
+
+    if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)
+        && s->method->version <= TLS1_VERSION) {
+        /*
+         * enable vulnerability countermeasure for CBC ciphers with known-IV
+         * problem (http://www.openssl.org/~bodo/tls-cbc.txt)
+         */
+        s->s3->need_empty_fragments = 1;
+
+        if (s->session->cipher != NULL) {
+            if (s->session->cipher->algorithm_enc == SSL_eNULL)
+                s->s3->need_empty_fragments = 0;
+
+#ifndef OPENSSL_NO_RC4
+            if (s->session->cipher->algorithm_enc == SSL_RC4)
+                s->s3->need_empty_fragments = 0;
+#endif
+        }
+    }
+
+    ret = 1;
+ err:
+    return ret;
+}
+
+size_t tls1_final_finish_mac(SSL *s, const char *str, size_t slen,
+                             unsigned char *out)
+{
+    size_t hashlen;
+    unsigned char hash[EVP_MAX_MD_SIZE];
+
+    if (!ssl3_digest_cached_records(s, 0)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    if (!ssl_handshake_hash(s, hash, sizeof(hash), &hashlen)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+
+    if (!tls1_PRF(s, str, slen, hash, hashlen, NULL, 0, NULL, 0, NULL, 0,
+                  s->session->master_key, s->session->master_key_length,
+                  out, TLS1_FINISH_MAC_LENGTH, 1)) {
+        /* SSLfatal() already called */
+        return 0;
+    }
+    OPENSSL_cleanse(hash, hashlen);
+    return TLS1_FINISH_MAC_LENGTH;
+}
+
+int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
+                                size_t len, size_t *secret_size)
+{
+    if (s->session->flags & SSL_SESS_FLAG_EXTMS) {
+        unsigned char hash[EVP_MAX_MD_SIZE * 2];
+        size_t hashlen;
+        /*
+         * Digest cached records keeping record buffer (if present): this won't
+         * affect client auth because we're freezing the buffer at the same
+         * point (after client key exchange and before certificate verify)
+         */
+        if (!ssl3_digest_cached_records(s, 1)
+                || !ssl_handshake_hash(s, hash, sizeof(hash), &hashlen)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+#ifdef SSL_DEBUG
+        fprintf(stderr, "Handshake hashes:\n");
+        BIO_dump_fp(stderr, (char *)hash, hashlen);
+#endif
+        if (!tls1_PRF(s,
+                      TLS_MD_EXTENDED_MASTER_SECRET_CONST,
+                      TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE,
+                      hash, hashlen,
+                      NULL, 0,
+                      NULL, 0,
+                      NULL, 0, p, len, out,
+                      SSL3_MASTER_SECRET_SIZE, 1)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+        OPENSSL_cleanse(hash, hashlen);
+    } else {
+        if (!tls1_PRF(s,
+                      TLS_MD_MASTER_SECRET_CONST,
+                      TLS_MD_MASTER_SECRET_CONST_SIZE,
+                      s->s3->client_random, SSL3_RANDOM_SIZE,
+                      NULL, 0,
+                      s->s3->server_random, SSL3_RANDOM_SIZE,
+                      NULL, 0, p, len, out,
+                      SSL3_MASTER_SECRET_SIZE, 1)) {
+           /* SSLfatal() already called */
+            return 0;
+        }
+    }
+#ifdef SSL_DEBUG
+    fprintf(stderr, "Premaster Secret:\n");
+    BIO_dump_fp(stderr, (char *)p, len);
+    fprintf(stderr, "Client Random:\n");
+    BIO_dump_fp(stderr, (char *)s->s3->client_random, SSL3_RANDOM_SIZE);
+    fprintf(stderr, "Server Random:\n");
+    BIO_dump_fp(stderr, (char *)s->s3->server_random, SSL3_RANDOM_SIZE);
+    fprintf(stderr, "Master Secret:\n");
+    BIO_dump_fp(stderr, (char *)s->session->master_key,
+                SSL3_MASTER_SECRET_SIZE);
+#endif
+
+    *secret_size = SSL3_MASTER_SECRET_SIZE;
+    return 1;
+}
+
+int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen,
+                                const char *label, size_t llen,
+                                const unsigned char *context,
+                                size_t contextlen, int use_context)
+{
+    unsigned char *val = NULL;
+    size_t vallen = 0, currentvalpos;
+    int rv;
+
+    /*
+     * construct PRF arguments we construct the PRF argument ourself rather
+     * than passing separate values into the TLS PRF to ensure that the
+     * concatenation of values does not create a prohibited label.
+     */
+    vallen = llen + SSL3_RANDOM_SIZE * 2;
+    if (use_context) {
+        vallen += 2 + contextlen;
+    }
+
+    val = OPENSSL_malloc(vallen);
+    if (val == NULL)
+        goto err2;
+    currentvalpos = 0;
+    memcpy(val + currentvalpos, (unsigned char *)label, llen);
+    currentvalpos += llen;
+    memcpy(val + currentvalpos, s->s3->client_random, SSL3_RANDOM_SIZE);
+    currentvalpos += SSL3_RANDOM_SIZE;
+    memcpy(val + currentvalpos, s->s3->server_random, SSL3_RANDOM_SIZE);
+    currentvalpos += SSL3_RANDOM_SIZE;
+
+    if (use_context) {
+        val[currentvalpos] = (contextlen >> 8) & 0xff;
+        currentvalpos++;
+        val[currentvalpos] = contextlen & 0xff;
+        currentvalpos++;
+        if ((contextlen > 0) || (context != NULL)) {
+            memcpy(val + currentvalpos, context, contextlen);
+        }
+    }
+
+    /*
+     * disallow prohibited labels note that SSL3_RANDOM_SIZE > max(prohibited
+     * label len) = 15, so size of val > max(prohibited label len) = 15 and
+     * the comparisons won't have buffer overflow
+     */
+    if (memcmp(val, TLS_MD_CLIENT_FINISH_CONST,
+               TLS_MD_CLIENT_FINISH_CONST_SIZE) == 0)
+        goto err1;
+    if (memcmp(val, TLS_MD_SERVER_FINISH_CONST,
+               TLS_MD_SERVER_FINISH_CONST_SIZE) == 0)
+        goto err1;
+    if (memcmp(val, TLS_MD_MASTER_SECRET_CONST,
+               TLS_MD_MASTER_SECRET_CONST_SIZE) == 0)
+        goto err1;
+    if (memcmp(val, TLS_MD_EXTENDED_MASTER_SECRET_CONST,
+               TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE) == 0)
+        goto err1;
+    if (memcmp(val, TLS_MD_KEY_EXPANSION_CONST,
+               TLS_MD_KEY_EXPANSION_CONST_SIZE) == 0)
+        goto err1;
+
+    rv = tls1_PRF(s,
+                  val, vallen,
+                  NULL, 0,
+                  NULL, 0,
+                  NULL, 0,
+                  NULL, 0,
+                  s->session->master_key, s->session->master_key_length,
+                  out, olen, 0);
+
+    goto ret;
+ err1:
+    SSLerr(SSL_F_TLS1_EXPORT_KEYING_MATERIAL, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL);
+    rv = 0;
+    goto ret;
+ err2:
+    SSLerr(SSL_F_TLS1_EXPORT_KEYING_MATERIAL, ERR_R_MALLOC_FAILURE);
+    rv = 0;
+ ret:
+    OPENSSL_clear_free(val, vallen);
+    return rv;
+}
+
+int tls1_alert_code(int code)
+{
+    switch (code) {
+    case SSL_AD_CLOSE_NOTIFY:
+        return SSL3_AD_CLOSE_NOTIFY;
+    case SSL_AD_UNEXPECTED_MESSAGE:
+        return SSL3_AD_UNEXPECTED_MESSAGE;
+    case SSL_AD_BAD_RECORD_MAC:
+        return SSL3_AD_BAD_RECORD_MAC;
+    case SSL_AD_DECRYPTION_FAILED:
+        return TLS1_AD_DECRYPTION_FAILED;
+    case SSL_AD_RECORD_OVERFLOW:
+        return TLS1_AD_RECORD_OVERFLOW;
+    case SSL_AD_DECOMPRESSION_FAILURE:
+        return SSL3_AD_DECOMPRESSION_FAILURE;
+    case SSL_AD_HANDSHAKE_FAILURE:
+        return SSL3_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_NO_CERTIFICATE:
+        return -1;
+    case SSL_AD_BAD_CERTIFICATE:
+        return SSL3_AD_BAD_CERTIFICATE;
+    case SSL_AD_UNSUPPORTED_CERTIFICATE:
+        return SSL3_AD_UNSUPPORTED_CERTIFICATE;
+    case SSL_AD_CERTIFICATE_REVOKED:
+        return SSL3_AD_CERTIFICATE_REVOKED;
+    case SSL_AD_CERTIFICATE_EXPIRED:
+        return SSL3_AD_CERTIFICATE_EXPIRED;
+    case SSL_AD_CERTIFICATE_UNKNOWN:
+        return SSL3_AD_CERTIFICATE_UNKNOWN;
+    case SSL_AD_ILLEGAL_PARAMETER:
+        return SSL3_AD_ILLEGAL_PARAMETER;
+    case SSL_AD_UNKNOWN_CA:
+        return TLS1_AD_UNKNOWN_CA;
+    case SSL_AD_ACCESS_DENIED:
+        return TLS1_AD_ACCESS_DENIED;
+    case SSL_AD_DECODE_ERROR:
+        return TLS1_AD_DECODE_ERROR;
+    case SSL_AD_DECRYPT_ERROR:
+        return TLS1_AD_DECRYPT_ERROR;
+    case SSL_AD_EXPORT_RESTRICTION:
+        return TLS1_AD_EXPORT_RESTRICTION;
+    case SSL_AD_PROTOCOL_VERSION:
+        return TLS1_AD_PROTOCOL_VERSION;
+    case SSL_AD_INSUFFICIENT_SECURITY:
+        return TLS1_AD_INSUFFICIENT_SECURITY;
+    case SSL_AD_INTERNAL_ERROR:
+        return TLS1_AD_INTERNAL_ERROR;
+    case SSL_AD_USER_CANCELLED:
+        return TLS1_AD_USER_CANCELLED;
+    case SSL_AD_NO_RENEGOTIATION:
+        return TLS1_AD_NO_RENEGOTIATION;
+    case SSL_AD_UNSUPPORTED_EXTENSION:
+        return TLS1_AD_UNSUPPORTED_EXTENSION;
+    case SSL_AD_CERTIFICATE_UNOBTAINABLE:
+        return TLS1_AD_CERTIFICATE_UNOBTAINABLE;
+    case SSL_AD_UNRECOGNIZED_NAME:
+        return TLS1_AD_UNRECOGNIZED_NAME;
+    case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE:
+        return TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+    case SSL_AD_BAD_CERTIFICATE_HASH_VALUE:
+        return TLS1_AD_BAD_CERTIFICATE_HASH_VALUE;
+    case SSL_AD_UNKNOWN_PSK_IDENTITY:
+        return TLS1_AD_UNKNOWN_PSK_IDENTITY;
+    case SSL_AD_INAPPROPRIATE_FALLBACK:
+        return TLS1_AD_INAPPROPRIATE_FALLBACK;
+    case SSL_AD_NO_APPLICATION_PROTOCOL:
+        return TLS1_AD_NO_APPLICATION_PROTOCOL;
+    case SSL_AD_CERTIFICATE_REQUIRED:
+        return SSL_AD_HANDSHAKE_FAILURE;
+    case SSL_AD_MISSING_EXTENSION:
+        return SSL_AD_HANDSHAKE_FAILURE;
+    default:
+        return -1;
+    }
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/t1_lib.c b/ap/lib/libssl/openssl-1.1.1o/ssl/t1_lib.c
new file mode 100644
index 0000000..5f657f8
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/t1_lib.c
@@ -0,0 +1,2923 @@
+/*
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/ocsp.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#include "internal/nelem.h"
+#include "ssl_local.h"
+#include <openssl/ct.h>
+
+static const SIGALG_LOOKUP *find_sig_alg(SSL *s, X509 *x, EVP_PKEY *pkey);
+static int tls12_sigalg_allowed(const SSL *s, int op, const SIGALG_LOOKUP *lu);
+
+SSL3_ENC_METHOD const TLSv1_enc_data = {
+    tls1_enc,
+    tls1_mac,
+    tls1_setup_key_block,
+    tls1_generate_master_secret,
+    tls1_change_cipher_state,
+    tls1_final_finish_mac,
+    TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE,
+    TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE,
+    tls1_alert_code,
+    tls1_export_keying_material,
+    0,
+    ssl3_set_handshake_header,
+    tls_close_construct_packet,
+    ssl3_handshake_write
+};
+
+SSL3_ENC_METHOD const TLSv1_1_enc_data = {
+    tls1_enc,
+    tls1_mac,
+    tls1_setup_key_block,
+    tls1_generate_master_secret,
+    tls1_change_cipher_state,
+    tls1_final_finish_mac,
+    TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE,
+    TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE,
+    tls1_alert_code,
+    tls1_export_keying_material,
+    SSL_ENC_FLAG_EXPLICIT_IV,
+    ssl3_set_handshake_header,
+    tls_close_construct_packet,
+    ssl3_handshake_write
+};
+
+SSL3_ENC_METHOD const TLSv1_2_enc_data = {
+    tls1_enc,
+    tls1_mac,
+    tls1_setup_key_block,
+    tls1_generate_master_secret,
+    tls1_change_cipher_state,
+    tls1_final_finish_mac,
+    TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE,
+    TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE,
+    tls1_alert_code,
+    tls1_export_keying_material,
+    SSL_ENC_FLAG_EXPLICIT_IV | SSL_ENC_FLAG_SIGALGS | SSL_ENC_FLAG_SHA256_PRF
+        | SSL_ENC_FLAG_TLS1_2_CIPHERS,
+    ssl3_set_handshake_header,
+    tls_close_construct_packet,
+    ssl3_handshake_write
+};
+
+SSL3_ENC_METHOD const TLSv1_3_enc_data = {
+    tls13_enc,
+    tls1_mac,
+    tls13_setup_key_block,
+    tls13_generate_master_secret,
+    tls13_change_cipher_state,
+    tls13_final_finish_mac,
+    TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE,
+    TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE,
+    tls13_alert_code,
+    tls13_export_keying_material,
+    SSL_ENC_FLAG_SIGALGS | SSL_ENC_FLAG_SHA256_PRF,
+    ssl3_set_handshake_header,
+    tls_close_construct_packet,
+    ssl3_handshake_write
+};
+
+long tls1_default_timeout(void)
+{
+    /*
+     * 2 hours, the 24 hours mentioned in the TLSv1 spec is way too long for
+     * http, the cache would over fill
+     */
+    return (60 * 60 * 2);
+}
+
+int tls1_new(SSL *s)
+{
+    if (!ssl3_new(s))
+        return 0;
+    if (!s->method->ssl_clear(s))
+        return 0;
+
+    return 1;
+}
+
+void tls1_free(SSL *s)
+{
+    OPENSSL_free(s->ext.session_ticket);
+    ssl3_free(s);
+}
+
+int tls1_clear(SSL *s)
+{
+    if (!ssl3_clear(s))
+        return 0;
+
+    if (s->method->version == TLS_ANY_VERSION)
+        s->version = TLS_MAX_VERSION;
+    else
+        s->version = s->method->version;
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_EC
+
+/*
+ * Table of curve information.
+ * Do not delete entries or reorder this array! It is used as a lookup
+ * table: the index of each entry is one less than the TLS curve id.
+ */
+static const TLS_GROUP_INFO nid_list[] = {
+    {NID_sect163k1, 80, TLS_CURVE_CHAR2}, /* sect163k1 (1) */
+    {NID_sect163r1, 80, TLS_CURVE_CHAR2}, /* sect163r1 (2) */
+    {NID_sect163r2, 80, TLS_CURVE_CHAR2}, /* sect163r2 (3) */
+    {NID_sect193r1, 80, TLS_CURVE_CHAR2}, /* sect193r1 (4) */
+    {NID_sect193r2, 80, TLS_CURVE_CHAR2}, /* sect193r2 (5) */
+    {NID_sect233k1, 112, TLS_CURVE_CHAR2}, /* sect233k1 (6) */
+    {NID_sect233r1, 112, TLS_CURVE_CHAR2}, /* sect233r1 (7) */
+    {NID_sect239k1, 112, TLS_CURVE_CHAR2}, /* sect239k1 (8) */
+    {NID_sect283k1, 128, TLS_CURVE_CHAR2}, /* sect283k1 (9) */
+    {NID_sect283r1, 128, TLS_CURVE_CHAR2}, /* sect283r1 (10) */
+    {NID_sect409k1, 192, TLS_CURVE_CHAR2}, /* sect409k1 (11) */
+    {NID_sect409r1, 192, TLS_CURVE_CHAR2}, /* sect409r1 (12) */
+    {NID_sect571k1, 256, TLS_CURVE_CHAR2}, /* sect571k1 (13) */
+    {NID_sect571r1, 256, TLS_CURVE_CHAR2}, /* sect571r1 (14) */
+    {NID_secp160k1, 80, TLS_CURVE_PRIME}, /* secp160k1 (15) */
+    {NID_secp160r1, 80, TLS_CURVE_PRIME}, /* secp160r1 (16) */
+    {NID_secp160r2, 80, TLS_CURVE_PRIME}, /* secp160r2 (17) */
+    {NID_secp192k1, 80, TLS_CURVE_PRIME}, /* secp192k1 (18) */
+    {NID_X9_62_prime192v1, 80, TLS_CURVE_PRIME}, /* secp192r1 (19) */
+    {NID_secp224k1, 112, TLS_CURVE_PRIME}, /* secp224k1 (20) */
+    {NID_secp224r1, 112, TLS_CURVE_PRIME}, /* secp224r1 (21) */
+    {NID_secp256k1, 128, TLS_CURVE_PRIME}, /* secp256k1 (22) */
+    {NID_X9_62_prime256v1, 128, TLS_CURVE_PRIME}, /* secp256r1 (23) */
+    {NID_secp384r1, 192, TLS_CURVE_PRIME}, /* secp384r1 (24) */
+    {NID_secp521r1, 256, TLS_CURVE_PRIME}, /* secp521r1 (25) */
+    {NID_brainpoolP256r1, 128, TLS_CURVE_PRIME}, /* brainpoolP256r1 (26) */
+    {NID_brainpoolP384r1, 192, TLS_CURVE_PRIME}, /* brainpoolP384r1 (27) */
+    {NID_brainpoolP512r1, 256, TLS_CURVE_PRIME}, /* brainpool512r1 (28) */
+    {EVP_PKEY_X25519, 128, TLS_CURVE_CUSTOM}, /* X25519 (29) */
+    {EVP_PKEY_X448, 224, TLS_CURVE_CUSTOM}, /* X448 (30) */
+};
+
+static const unsigned char ecformats_default[] = {
+    TLSEXT_ECPOINTFORMAT_uncompressed,
+    TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime,
+    TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2
+};
+
+/* The default curves */
+static const uint16_t eccurves_default[] = {
+    29,                      /* X25519 (29) */
+    23,                      /* secp256r1 (23) */
+    30,                      /* X448 (30) */
+    25,                      /* secp521r1 (25) */
+    24,                      /* secp384r1 (24) */
+};
+
+static const uint16_t suiteb_curves[] = {
+    TLSEXT_curve_P_256,
+    TLSEXT_curve_P_384
+};
+
+const TLS_GROUP_INFO *tls1_group_id_lookup(uint16_t group_id)
+{
+    /* ECC curves from RFC 4492 and RFC 7027 */
+    if (group_id < 1 || group_id > OSSL_NELEM(nid_list))
+        return NULL;
+    return &nid_list[group_id - 1];
+}
+
+static uint16_t tls1_nid2group_id(int nid)
+{
+    size_t i;
+    for (i = 0; i < OSSL_NELEM(nid_list); i++) {
+        if (nid_list[i].nid == nid)
+            return (uint16_t)(i + 1);
+    }
+    return 0;
+}
+
+/*
+ * Set *pgroups to the supported groups list and *pgroupslen to
+ * the number of groups supported.
+ */
+void tls1_get_supported_groups(SSL *s, const uint16_t **pgroups,
+                               size_t *pgroupslen)
+{
+
+    /* For Suite B mode only include P-256, P-384 */
+    switch (tls1_suiteb(s)) {
+    case SSL_CERT_FLAG_SUITEB_128_LOS:
+        *pgroups = suiteb_curves;
+        *pgroupslen = OSSL_NELEM(suiteb_curves);
+        break;
+
+    case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
+        *pgroups = suiteb_curves;
+        *pgroupslen = 1;
+        break;
+
+    case SSL_CERT_FLAG_SUITEB_192_LOS:
+        *pgroups = suiteb_curves + 1;
+        *pgroupslen = 1;
+        break;
+
+    default:
+        if (s->ext.supportedgroups == NULL) {
+            *pgroups = eccurves_default;
+            *pgroupslen = OSSL_NELEM(eccurves_default);
+        } else {
+            *pgroups = s->ext.supportedgroups;
+            *pgroupslen = s->ext.supportedgroups_len;
+        }
+        break;
+    }
+}
+
+/* See if curve is allowed by security callback */
+int tls_curve_allowed(SSL *s, uint16_t curve, int op)
+{
+    const TLS_GROUP_INFO *cinfo = tls1_group_id_lookup(curve);
+    unsigned char ctmp[2];
+
+    if (cinfo == NULL)
+        return 0;
+# ifdef OPENSSL_NO_EC2M
+    if (cinfo->flags & TLS_CURVE_CHAR2)
+        return 0;
+# endif
+    ctmp[0] = curve >> 8;
+    ctmp[1] = curve & 0xff;
+    return ssl_security(s, op, cinfo->secbits, cinfo->nid, (void *)ctmp);
+}
+
+/* Return 1 if "id" is in "list" */
+static int tls1_in_list(uint16_t id, const uint16_t *list, size_t listlen)
+{
+    size_t i;
+    for (i = 0; i < listlen; i++)
+        if (list[i] == id)
+            return 1;
+    return 0;
+}
+
+/*-
+ * For nmatch >= 0, return the id of the |nmatch|th shared group or 0
+ * if there is no match.
+ * For nmatch == -1, return number of matches
+ * For nmatch == -2, return the id of the group to use for
+ * a tmp key, or 0 if there is no match.
+ */
+uint16_t tls1_shared_group(SSL *s, int nmatch)
+{
+    const uint16_t *pref, *supp;
+    size_t num_pref, num_supp, i;
+    int k;
+
+    /* Can't do anything on client side */
+    if (s->server == 0)
+        return 0;
+    if (nmatch == -2) {
+        if (tls1_suiteb(s)) {
+            /*
+             * For Suite B ciphersuite determines curve: we already know
+             * these are acceptable due to previous checks.
+             */
+            unsigned long cid = s->s3->tmp.new_cipher->id;
+
+            if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+                return TLSEXT_curve_P_256;
+            if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
+                return TLSEXT_curve_P_384;
+            /* Should never happen */
+            return 0;
+        }
+        /* If not Suite B just return first preference shared curve */
+        nmatch = 0;
+    }
+    /*
+     * If server preference set, our groups are the preference order
+     * otherwise peer decides.
+     */
+    if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) {
+        tls1_get_supported_groups(s, &pref, &num_pref);
+        tls1_get_peer_groups(s, &supp, &num_supp);
+    } else {
+        tls1_get_peer_groups(s, &pref, &num_pref);
+        tls1_get_supported_groups(s, &supp, &num_supp);
+    }
+
+    for (k = 0, i = 0; i < num_pref; i++) {
+        uint16_t id = pref[i];
+
+        if (!tls1_in_list(id, supp, num_supp)
+            || !tls_curve_allowed(s, id, SSL_SECOP_CURVE_SHARED))
+                    continue;
+        if (nmatch == k)
+            return id;
+         k++;
+    }
+    if (nmatch == -1)
+        return k;
+    /* Out of range (nmatch > k). */
+    return 0;
+}
+
+int tls1_set_groups(uint16_t **pext, size_t *pextlen,
+                    int *groups, size_t ngroups)
+{
+    uint16_t *glist;
+    size_t i;
+    /*
+     * Bitmap of groups included to detect duplicates: only works while group
+     * ids < 32
+     */
+    unsigned long dup_list = 0;
+
+    if (ngroups == 0) {
+        SSLerr(SSL_F_TLS1_SET_GROUPS, SSL_R_BAD_LENGTH);
+        return 0;
+    }
+    if ((glist = OPENSSL_malloc(ngroups * sizeof(*glist))) == NULL) {
+        SSLerr(SSL_F_TLS1_SET_GROUPS, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    for (i = 0; i < ngroups; i++) {
+        unsigned long idmask;
+        uint16_t id;
+        /* TODO(TLS1.3): Convert for DH groups */
+        id = tls1_nid2group_id(groups[i]);
+        idmask = 1L << id;
+        if (!id || (dup_list & idmask)) {
+            OPENSSL_free(glist);
+            return 0;
+        }
+        dup_list |= idmask;
+        glist[i] = id;
+    }
+    OPENSSL_free(*pext);
+    *pext = glist;
+    *pextlen = ngroups;
+    return 1;
+}
+
+# define MAX_CURVELIST   OSSL_NELEM(nid_list)
+
+typedef struct {
+    size_t nidcnt;
+    int nid_arr[MAX_CURVELIST];
+} nid_cb_st;
+
+static int nid_cb(const char *elem, int len, void *arg)
+{
+    nid_cb_st *narg = arg;
+    size_t i;
+    int nid;
+    char etmp[20];
+    if (elem == NULL)
+        return 0;
+    if (narg->nidcnt == MAX_CURVELIST)
+        return 0;
+    if (len > (int)(sizeof(etmp) - 1))
+        return 0;
+    memcpy(etmp, elem, len);
+    etmp[len] = 0;
+    nid = EC_curve_nist2nid(etmp);
+    if (nid == NID_undef)
+        nid = OBJ_sn2nid(etmp);
+    if (nid == NID_undef)
+        nid = OBJ_ln2nid(etmp);
+    if (nid == NID_undef)
+        return 0;
+    for (i = 0; i < narg->nidcnt; i++)
+        if (narg->nid_arr[i] == nid)
+            return 0;
+    narg->nid_arr[narg->nidcnt++] = nid;
+    return 1;
+}
+
+/* Set groups based on a colon separate list */
+int tls1_set_groups_list(uint16_t **pext, size_t *pextlen, const char *str)
+{
+    nid_cb_st ncb;
+    ncb.nidcnt = 0;
+    if (!CONF_parse_list(str, ':', 1, nid_cb, &ncb))
+        return 0;
+    if (pext == NULL)
+        return 1;
+    return tls1_set_groups(pext, pextlen, ncb.nid_arr, ncb.nidcnt);
+}
+/* Return group id of a key */
+static uint16_t tls1_get_group_id(EVP_PKEY *pkey)
+{
+    EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
+    const EC_GROUP *grp;
+
+    if (ec == NULL)
+        return 0;
+    grp = EC_KEY_get0_group(ec);
+    return tls1_nid2group_id(EC_GROUP_get_curve_name(grp));
+}
+
+/* Check a key is compatible with compression extension */
+static int tls1_check_pkey_comp(SSL *s, EVP_PKEY *pkey)
+{
+    const EC_KEY *ec;
+    const EC_GROUP *grp;
+    unsigned char comp_id;
+    size_t i;
+
+    /* If not an EC key nothing to check */
+    if (EVP_PKEY_id(pkey) != EVP_PKEY_EC)
+        return 1;
+    ec = EVP_PKEY_get0_EC_KEY(pkey);
+    grp = EC_KEY_get0_group(ec);
+
+    /* Get required compression id */
+    if (EC_KEY_get_conv_form(ec) == POINT_CONVERSION_UNCOMPRESSED) {
+            comp_id = TLSEXT_ECPOINTFORMAT_uncompressed;
+    } else if (SSL_IS_TLS13(s)) {
+            /*
+             * ec_point_formats extension is not used in TLSv1.3 so we ignore
+             * this check.
+             */
+            return 1;
+    } else {
+        int field_type = EC_METHOD_get_field_type(EC_GROUP_method_of(grp));
+
+        if (field_type == NID_X9_62_prime_field)
+            comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
+        else if (field_type == NID_X9_62_characteristic_two_field)
+            comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
+        else
+            return 0;
+    }
+    /*
+     * If point formats extension present check it, otherwise everything is
+     * supported (see RFC4492).
+     */
+    if (s->ext.peer_ecpointformats == NULL)
+        return 1;
+
+    for (i = 0; i < s->ext.peer_ecpointformats_len; i++) {
+        if (s->ext.peer_ecpointformats[i] == comp_id)
+            return 1;
+    }
+    return 0;
+}
+
+/* Check a group id matches preferences */
+int tls1_check_group_id(SSL *s, uint16_t group_id, int check_own_groups)
+    {
+    const uint16_t *groups;
+    size_t groups_len;
+
+    if (group_id == 0)
+        return 0;
+
+    /* Check for Suite B compliance */
+    if (tls1_suiteb(s) && s->s3->tmp.new_cipher != NULL) {
+        unsigned long cid = s->s3->tmp.new_cipher->id;
+
+        if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) {
+            if (group_id != TLSEXT_curve_P_256)
+                return 0;
+        } else if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) {
+            if (group_id != TLSEXT_curve_P_384)
+                return 0;
+        } else {
+            /* Should never happen */
+            return 0;
+        }
+    }
+
+    if (check_own_groups) {
+        /* Check group is one of our preferences */
+        tls1_get_supported_groups(s, &groups, &groups_len);
+        if (!tls1_in_list(group_id, groups, groups_len))
+            return 0;
+    }
+
+    if (!tls_curve_allowed(s, group_id, SSL_SECOP_CURVE_CHECK))
+        return 0;
+
+    /* For clients, nothing more to check */
+    if (!s->server)
+        return 1;
+
+    /* Check group is one of peers preferences */
+    tls1_get_peer_groups(s, &groups, &groups_len);
+
+    /*
+     * RFC 4492 does not require the supported elliptic curves extension
+     * so if it is not sent we can just choose any curve.
+     * It is invalid to send an empty list in the supported groups
+     * extension, so groups_len == 0 always means no extension.
+     */
+    if (groups_len == 0)
+            return 1;
+    return tls1_in_list(group_id, groups, groups_len);
+}
+
+void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
+                         size_t *num_formats)
+{
+    /*
+     * If we have a custom point format list use it otherwise use default
+     */
+    if (s->ext.ecpointformats) {
+        *pformats = s->ext.ecpointformats;
+        *num_formats = s->ext.ecpointformats_len;
+    } else {
+        *pformats = ecformats_default;
+        /* For Suite B we don't support char2 fields */
+        if (tls1_suiteb(s))
+            *num_formats = sizeof(ecformats_default) - 1;
+        else
+            *num_formats = sizeof(ecformats_default);
+    }
+}
+
+/*
+ * Check cert parameters compatible with extensions: currently just checks EC
+ * certificates have compatible curves and compression.
+ */
+static int tls1_check_cert_param(SSL *s, X509 *x, int check_ee_md)
+{
+    uint16_t group_id;
+    EVP_PKEY *pkey;
+    pkey = X509_get0_pubkey(x);
+    if (pkey == NULL)
+        return 0;
+    /* If not EC nothing to do */
+    if (EVP_PKEY_id(pkey) != EVP_PKEY_EC)
+        return 1;
+    /* Check compression */
+    if (!tls1_check_pkey_comp(s, pkey))
+        return 0;
+    group_id = tls1_get_group_id(pkey);
+    /*
+     * For a server we allow the certificate to not be in our list of supported
+     * groups.
+     */
+    if (!tls1_check_group_id(s, group_id, !s->server))
+        return 0;
+    /*
+     * Special case for suite B. We *MUST* sign using SHA256+P-256 or
+     * SHA384+P-384.
+     */
+    if (check_ee_md && tls1_suiteb(s)) {
+        int check_md;
+        size_t i;
+
+        /* Check to see we have necessary signing algorithm */
+        if (group_id == TLSEXT_curve_P_256)
+            check_md = NID_ecdsa_with_SHA256;
+        else if (group_id == TLSEXT_curve_P_384)
+            check_md = NID_ecdsa_with_SHA384;
+        else
+            return 0;           /* Should never happen */
+        for (i = 0; i < s->shared_sigalgslen; i++) {
+            if (check_md == s->shared_sigalgs[i]->sigandhash)
+                return 1;;
+        }
+        return 0;
+    }
+    return 1;
+}
+
+/*
+ * tls1_check_ec_tmp_key - Check EC temporary key compatibility
+ * @s: SSL connection
+ * @cid: Cipher ID we're considering using
+ *
+ * Checks that the kECDHE cipher suite we're considering using
+ * is compatible with the client extensions.
+ *
+ * Returns 0 when the cipher can't be used or 1 when it can.
+ */
+int tls1_check_ec_tmp_key(SSL *s, unsigned long cid)
+{
+    /* If not Suite B just need a shared group */
+    if (!tls1_suiteb(s))
+        return tls1_shared_group(s, 0) != 0;
+    /*
+     * If Suite B, AES128 MUST use P-256 and AES256 MUST use P-384, no other
+     * curves permitted.
+     */
+    if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+        return tls1_check_group_id(s, TLSEXT_curve_P_256, 1);
+    if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
+        return tls1_check_group_id(s, TLSEXT_curve_P_384, 1);
+
+    return 0;
+}
+
+#else
+
+static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md)
+{
+    return 1;
+}
+
+#endif                          /* OPENSSL_NO_EC */
+
+/* Default sigalg schemes */
+static const uint16_t tls12_sigalgs[] = {
+#ifndef OPENSSL_NO_EC
+    TLSEXT_SIGALG_ecdsa_secp256r1_sha256,
+    TLSEXT_SIGALG_ecdsa_secp384r1_sha384,
+    TLSEXT_SIGALG_ecdsa_secp521r1_sha512,
+    TLSEXT_SIGALG_ed25519,
+    TLSEXT_SIGALG_ed448,
+#endif
+
+    TLSEXT_SIGALG_rsa_pss_pss_sha256,
+    TLSEXT_SIGALG_rsa_pss_pss_sha384,
+    TLSEXT_SIGALG_rsa_pss_pss_sha512,
+    TLSEXT_SIGALG_rsa_pss_rsae_sha256,
+    TLSEXT_SIGALG_rsa_pss_rsae_sha384,
+    TLSEXT_SIGALG_rsa_pss_rsae_sha512,
+
+    TLSEXT_SIGALG_rsa_pkcs1_sha256,
+    TLSEXT_SIGALG_rsa_pkcs1_sha384,
+    TLSEXT_SIGALG_rsa_pkcs1_sha512,
+
+#ifndef OPENSSL_NO_EC
+    TLSEXT_SIGALG_ecdsa_sha224,
+    TLSEXT_SIGALG_ecdsa_sha1,
+#endif
+    TLSEXT_SIGALG_rsa_pkcs1_sha224,
+    TLSEXT_SIGALG_rsa_pkcs1_sha1,
+#ifndef OPENSSL_NO_DSA
+    TLSEXT_SIGALG_dsa_sha224,
+    TLSEXT_SIGALG_dsa_sha1,
+
+    TLSEXT_SIGALG_dsa_sha256,
+    TLSEXT_SIGALG_dsa_sha384,
+    TLSEXT_SIGALG_dsa_sha512,
+#endif
+#ifndef OPENSSL_NO_GOST
+    TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256,
+    TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512,
+    TLSEXT_SIGALG_gostr34102001_gostr3411,
+#endif
+};
+
+#ifndef OPENSSL_NO_EC
+static const uint16_t suiteb_sigalgs[] = {
+    TLSEXT_SIGALG_ecdsa_secp256r1_sha256,
+    TLSEXT_SIGALG_ecdsa_secp384r1_sha384
+};
+#endif
+
+static const SIGALG_LOOKUP sigalg_lookup_tbl[] = {
+#ifndef OPENSSL_NO_EC
+    {"ecdsa_secp256r1_sha256", TLSEXT_SIGALG_ecdsa_secp256r1_sha256,
+     NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_EC, SSL_PKEY_ECC,
+     NID_ecdsa_with_SHA256, NID_X9_62_prime256v1},
+    {"ecdsa_secp384r1_sha384", TLSEXT_SIGALG_ecdsa_secp384r1_sha384,
+     NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_EC, SSL_PKEY_ECC,
+     NID_ecdsa_with_SHA384, NID_secp384r1},
+    {"ecdsa_secp521r1_sha512", TLSEXT_SIGALG_ecdsa_secp521r1_sha512,
+     NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_EC, SSL_PKEY_ECC,
+     NID_ecdsa_with_SHA512, NID_secp521r1},
+    {"ed25519", TLSEXT_SIGALG_ed25519,
+     NID_undef, -1, EVP_PKEY_ED25519, SSL_PKEY_ED25519,
+     NID_undef, NID_undef},
+    {"ed448", TLSEXT_SIGALG_ed448,
+     NID_undef, -1, EVP_PKEY_ED448, SSL_PKEY_ED448,
+     NID_undef, NID_undef},
+    {NULL, TLSEXT_SIGALG_ecdsa_sha224,
+     NID_sha224, SSL_MD_SHA224_IDX, EVP_PKEY_EC, SSL_PKEY_ECC,
+     NID_ecdsa_with_SHA224, NID_undef},
+    {NULL, TLSEXT_SIGALG_ecdsa_sha1,
+     NID_sha1, SSL_MD_SHA1_IDX, EVP_PKEY_EC, SSL_PKEY_ECC,
+     NID_ecdsa_with_SHA1, NID_undef},
+#endif
+    {"rsa_pss_rsae_sha256", TLSEXT_SIGALG_rsa_pss_rsae_sha256,
+     NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA,
+     NID_undef, NID_undef},
+    {"rsa_pss_rsae_sha384", TLSEXT_SIGALG_rsa_pss_rsae_sha384,
+     NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA,
+     NID_undef, NID_undef},
+    {"rsa_pss_rsae_sha512", TLSEXT_SIGALG_rsa_pss_rsae_sha512,
+     NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA,
+     NID_undef, NID_undef},
+    {"rsa_pss_pss_sha256", TLSEXT_SIGALG_rsa_pss_pss_sha256,
+     NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA_PSS_SIGN,
+     NID_undef, NID_undef},
+    {"rsa_pss_pss_sha384", TLSEXT_SIGALG_rsa_pss_pss_sha384,
+     NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA_PSS_SIGN,
+     NID_undef, NID_undef},
+    {"rsa_pss_pss_sha512", TLSEXT_SIGALG_rsa_pss_pss_sha512,
+     NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA_PSS_SIGN,
+     NID_undef, NID_undef},
+    {"rsa_pkcs1_sha256", TLSEXT_SIGALG_rsa_pkcs1_sha256,
+     NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA,
+     NID_sha256WithRSAEncryption, NID_undef},
+    {"rsa_pkcs1_sha384", TLSEXT_SIGALG_rsa_pkcs1_sha384,
+     NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA,
+     NID_sha384WithRSAEncryption, NID_undef},
+    {"rsa_pkcs1_sha512", TLSEXT_SIGALG_rsa_pkcs1_sha512,
+     NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA,
+     NID_sha512WithRSAEncryption, NID_undef},
+    {"rsa_pkcs1_sha224", TLSEXT_SIGALG_rsa_pkcs1_sha224,
+     NID_sha224, SSL_MD_SHA224_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA,
+     NID_sha224WithRSAEncryption, NID_undef},
+    {"rsa_pkcs1_sha1", TLSEXT_SIGALG_rsa_pkcs1_sha1,
+     NID_sha1, SSL_MD_SHA1_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA,
+     NID_sha1WithRSAEncryption, NID_undef},
+#ifndef OPENSSL_NO_DSA
+    {NULL, TLSEXT_SIGALG_dsa_sha256,
+     NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN,
+     NID_dsa_with_SHA256, NID_undef},
+    {NULL, TLSEXT_SIGALG_dsa_sha384,
+     NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN,
+     NID_undef, NID_undef},
+    {NULL, TLSEXT_SIGALG_dsa_sha512,
+     NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN,
+     NID_undef, NID_undef},
+    {NULL, TLSEXT_SIGALG_dsa_sha224,
+     NID_sha224, SSL_MD_SHA224_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN,
+     NID_undef, NID_undef},
+    {NULL, TLSEXT_SIGALG_dsa_sha1,
+     NID_sha1, SSL_MD_SHA1_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN,
+     NID_dsaWithSHA1, NID_undef},
+#endif
+#ifndef OPENSSL_NO_GOST
+    {NULL, TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256,
+     NID_id_GostR3411_2012_256, SSL_MD_GOST12_256_IDX,
+     NID_id_GostR3410_2012_256, SSL_PKEY_GOST12_256,
+     NID_undef, NID_undef},
+    {NULL, TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512,
+     NID_id_GostR3411_2012_512, SSL_MD_GOST12_512_IDX,
+     NID_id_GostR3410_2012_512, SSL_PKEY_GOST12_512,
+     NID_undef, NID_undef},
+    {NULL, TLSEXT_SIGALG_gostr34102001_gostr3411,
+     NID_id_GostR3411_94, SSL_MD_GOST94_IDX,
+     NID_id_GostR3410_2001, SSL_PKEY_GOST01,
+     NID_undef, NID_undef}
+#endif
+};
+/* Legacy sigalgs for TLS < 1.2 RSA TLS signatures */
+static const SIGALG_LOOKUP legacy_rsa_sigalg = {
+    "rsa_pkcs1_md5_sha1", 0,
+     NID_md5_sha1, SSL_MD_MD5_SHA1_IDX,
+     EVP_PKEY_RSA, SSL_PKEY_RSA,
+     NID_undef, NID_undef
+};
+
+/*
+ * Default signature algorithm values used if signature algorithms not present.
+ * From RFC5246. Note: order must match certificate index order.
+ */
+static const uint16_t tls_default_sigalg[] = {
+    TLSEXT_SIGALG_rsa_pkcs1_sha1, /* SSL_PKEY_RSA */
+    0, /* SSL_PKEY_RSA_PSS_SIGN */
+    TLSEXT_SIGALG_dsa_sha1, /* SSL_PKEY_DSA_SIGN */
+    TLSEXT_SIGALG_ecdsa_sha1, /* SSL_PKEY_ECC */
+    TLSEXT_SIGALG_gostr34102001_gostr3411, /* SSL_PKEY_GOST01 */
+    TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256, /* SSL_PKEY_GOST12_256 */
+    TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512, /* SSL_PKEY_GOST12_512 */
+    0, /* SSL_PKEY_ED25519 */
+    0, /* SSL_PKEY_ED448 */
+};
+
+/* Lookup TLS signature algorithm */
+static const SIGALG_LOOKUP *tls1_lookup_sigalg(uint16_t sigalg)
+{
+    size_t i;
+    const SIGALG_LOOKUP *s;
+
+    for (i = 0, s = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl);
+         i++, s++) {
+        if (s->sigalg == sigalg)
+            return s;
+    }
+    return NULL;
+}
+/* Lookup hash: return 0 if invalid or not enabled */
+int tls1_lookup_md(const SIGALG_LOOKUP *lu, const EVP_MD **pmd)
+{
+    const EVP_MD *md;
+    if (lu == NULL)
+        return 0;
+    /* lu->hash == NID_undef means no associated digest */
+    if (lu->hash == NID_undef) {
+        md = NULL;
+    } else {
+        md = ssl_md(lu->hash_idx);
+        if (md == NULL)
+            return 0;
+    }
+    if (pmd)
+        *pmd = md;
+    return 1;
+}
+
+/*
+ * Check if key is large enough to generate RSA-PSS signature.
+ *
+ * The key must greater than or equal to 2 * hash length + 2.
+ * SHA512 has a hash length of 64 bytes, which is incompatible
+ * with a 128 byte (1024 bit) key.
+ */
+#define RSA_PSS_MINIMUM_KEY_SIZE(md) (2 * EVP_MD_size(md) + 2)
+static int rsa_pss_check_min_key_size(const RSA *rsa, const SIGALG_LOOKUP *lu)
+{
+    const EVP_MD *md;
+
+    if (rsa == NULL)
+        return 0;
+    if (!tls1_lookup_md(lu, &md) || md == NULL)
+        return 0;
+    if (RSA_size(rsa) < RSA_PSS_MINIMUM_KEY_SIZE(md))
+        return 0;
+    return 1;
+}
+
+/*
+ * Returns a signature algorithm when the peer did not send a list of supported
+ * signature algorithms. The signature algorithm is fixed for the certificate
+ * type. |idx| is a certificate type index (SSL_PKEY_*). When |idx| is -1 the
+ * certificate type from |s| will be used.
+ * Returns the signature algorithm to use, or NULL on error.
+ */
+static const SIGALG_LOOKUP *tls1_get_legacy_sigalg(const SSL *s, int idx)
+{
+    if (idx == -1) {
+        if (s->server) {
+            size_t i;
+
+            /* Work out index corresponding to ciphersuite */
+            for (i = 0; i < SSL_PKEY_NUM; i++) {
+                const SSL_CERT_LOOKUP *clu = ssl_cert_lookup_by_idx(i);
+
+                if (clu->amask & s->s3->tmp.new_cipher->algorithm_auth) {
+                    idx = i;
+                    break;
+                }
+            }
+
+            /*
+             * Some GOST ciphersuites allow more than one signature algorithms
+             * */
+            if (idx == SSL_PKEY_GOST01 && s->s3->tmp.new_cipher->algorithm_auth != SSL_aGOST01) {
+                int real_idx;
+
+                for (real_idx = SSL_PKEY_GOST12_512; real_idx >= SSL_PKEY_GOST01;
+                     real_idx--) {
+                    if (s->cert->pkeys[real_idx].privatekey != NULL) {
+                        idx = real_idx;
+                        break;
+                    }
+                }
+            }
+        } else {
+            idx = s->cert->key - s->cert->pkeys;
+        }
+    }
+    if (idx < 0 || idx >= (int)OSSL_NELEM(tls_default_sigalg))
+        return NULL;
+    if (SSL_USE_SIGALGS(s) || idx != SSL_PKEY_RSA) {
+        const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(tls_default_sigalg[idx]);
+
+        if (!tls1_lookup_md(lu, NULL))
+            return NULL;
+        if (!tls12_sigalg_allowed(s, SSL_SECOP_SIGALG_SUPPORTED, lu))
+            return NULL;
+        return lu;
+    }
+    if (!tls12_sigalg_allowed(s, SSL_SECOP_SIGALG_SUPPORTED, &legacy_rsa_sigalg))
+        return NULL;
+    return &legacy_rsa_sigalg;
+}
+/* Set peer sigalg based key type */
+int tls1_set_peer_legacy_sigalg(SSL *s, const EVP_PKEY *pkey)
+{
+    size_t idx;
+    const SIGALG_LOOKUP *lu;
+
+    if (ssl_cert_lookup_by_pkey(pkey, &idx) == NULL)
+        return 0;
+    lu = tls1_get_legacy_sigalg(s, idx);
+    if (lu == NULL)
+        return 0;
+    s->s3->tmp.peer_sigalg = lu;
+    return 1;
+}
+
+size_t tls12_get_psigalgs(SSL *s, int sent, const uint16_t **psigs)
+{
+    /*
+     * If Suite B mode use Suite B sigalgs only, ignore any other
+     * preferences.
+     */
+#ifndef OPENSSL_NO_EC
+    switch (tls1_suiteb(s)) {
+    case SSL_CERT_FLAG_SUITEB_128_LOS:
+        *psigs = suiteb_sigalgs;
+        return OSSL_NELEM(suiteb_sigalgs);
+
+    case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
+        *psigs = suiteb_sigalgs;
+        return 1;
+
+    case SSL_CERT_FLAG_SUITEB_192_LOS:
+        *psigs = suiteb_sigalgs + 1;
+        return 1;
+    }
+#endif
+    /*
+     *  We use client_sigalgs (if not NULL) if we're a server
+     *  and sending a certificate request or if we're a client and
+     *  determining which shared algorithm to use.
+     */
+    if ((s->server == sent) && s->cert->client_sigalgs != NULL) {
+        *psigs = s->cert->client_sigalgs;
+        return s->cert->client_sigalgslen;
+    } else if (s->cert->conf_sigalgs) {
+        *psigs = s->cert->conf_sigalgs;
+        return s->cert->conf_sigalgslen;
+    } else {
+        *psigs = tls12_sigalgs;
+        return OSSL_NELEM(tls12_sigalgs);
+    }
+}
+
+#ifndef OPENSSL_NO_EC
+/*
+ * Called by servers only. Checks that we have a sig alg that supports the
+ * specified EC curve.
+ */
+int tls_check_sigalg_curve(const SSL *s, int curve)
+{
+   const uint16_t *sigs;
+   size_t siglen, i;
+
+    if (s->cert->conf_sigalgs) {
+        sigs = s->cert->conf_sigalgs;
+        siglen = s->cert->conf_sigalgslen;
+    } else {
+        sigs = tls12_sigalgs;
+        siglen = OSSL_NELEM(tls12_sigalgs);
+    }
+
+    for (i = 0; i < siglen; i++) {
+        const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(sigs[i]);
+
+        if (lu == NULL)
+            continue;
+        if (lu->sig == EVP_PKEY_EC
+                && lu->curve != NID_undef
+                && curve == lu->curve)
+            return 1;
+    }
+
+    return 0;
+}
+#endif
+
+/*
+ * Return the number of security bits for the signature algorithm, or 0 on
+ * error.
+ */
+static int sigalg_security_bits(const SIGALG_LOOKUP *lu)
+{
+    const EVP_MD *md = NULL;
+    int secbits = 0;
+
+    if (!tls1_lookup_md(lu, &md))
+        return 0;
+    if (md != NULL)
+    {
+        /* Security bits: half digest bits */
+        secbits = EVP_MD_size(md) * 4;
+    } else {
+        /* Values from https://tools.ietf.org/html/rfc8032#section-8.5 */
+        if (lu->sigalg == TLSEXT_SIGALG_ed25519)
+            secbits = 128;
+        else if (lu->sigalg == TLSEXT_SIGALG_ed448)
+            secbits = 224;
+    }
+    return secbits;
+}
+
+/*
+ * Check signature algorithm is consistent with sent supported signature
+ * algorithms and if so set relevant digest and signature scheme in
+ * s.
+ */
+int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey)
+{
+    const uint16_t *sent_sigs;
+    const EVP_MD *md = NULL;
+    char sigalgstr[2];
+    size_t sent_sigslen, i, cidx;
+    int pkeyid = EVP_PKEY_id(pkey);
+    const SIGALG_LOOKUP *lu;
+    int secbits = 0;
+
+    /* Should never happen */
+    if (pkeyid == -1)
+        return -1;
+    if (SSL_IS_TLS13(s)) {
+        /* Disallow DSA for TLS 1.3 */
+        if (pkeyid == EVP_PKEY_DSA) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS12_CHECK_PEER_SIGALG,
+                     SSL_R_WRONG_SIGNATURE_TYPE);
+            return 0;
+        }
+        /* Only allow PSS for TLS 1.3 */
+        if (pkeyid == EVP_PKEY_RSA)
+            pkeyid = EVP_PKEY_RSA_PSS;
+    }
+    lu = tls1_lookup_sigalg(sig);
+    /*
+     * Check sigalgs is known. Disallow SHA1/SHA224 with TLS 1.3. Check key type
+     * is consistent with signature: RSA keys can be used for RSA-PSS
+     */
+    if (lu == NULL
+        || (SSL_IS_TLS13(s) && (lu->hash == NID_sha1 || lu->hash == NID_sha224))
+        || (pkeyid != lu->sig
+        && (lu->sig != EVP_PKEY_RSA_PSS || pkeyid != EVP_PKEY_RSA))) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS12_CHECK_PEER_SIGALG,
+                 SSL_R_WRONG_SIGNATURE_TYPE);
+        return 0;
+    }
+    /* Check the sigalg is consistent with the key OID */
+    if (!ssl_cert_lookup_by_nid(EVP_PKEY_id(pkey), &cidx)
+            || lu->sig_idx != (int)cidx) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS12_CHECK_PEER_SIGALG,
+                 SSL_R_WRONG_SIGNATURE_TYPE);
+        return 0;
+    }
+
+#ifndef OPENSSL_NO_EC
+    if (pkeyid == EVP_PKEY_EC) {
+
+        /* Check point compression is permitted */
+        if (!tls1_check_pkey_comp(s, pkey)) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_F_TLS12_CHECK_PEER_SIGALG,
+                     SSL_R_ILLEGAL_POINT_COMPRESSION);
+            return 0;
+        }
+
+        /* For TLS 1.3 or Suite B check curve matches signature algorithm */
+        if (SSL_IS_TLS13(s) || tls1_suiteb(s)) {
+            EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
+            int curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
+
+            if (lu->curve != NID_undef && curve != lu->curve) {
+                SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                         SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_CURVE);
+                return 0;
+            }
+        }
+        if (!SSL_IS_TLS13(s)) {
+            /* Check curve matches extensions */
+            if (!tls1_check_group_id(s, tls1_get_group_id(pkey), 1)) {
+                SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                         SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_CURVE);
+                return 0;
+            }
+            if (tls1_suiteb(s)) {
+                /* Check sigalg matches a permissible Suite B value */
+                if (sig != TLSEXT_SIGALG_ecdsa_secp256r1_sha256
+                    && sig != TLSEXT_SIGALG_ecdsa_secp384r1_sha384) {
+                    SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                             SSL_F_TLS12_CHECK_PEER_SIGALG,
+                             SSL_R_WRONG_SIGNATURE_TYPE);
+                    return 0;
+                }
+            }
+        }
+    } else if (tls1_suiteb(s)) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS12_CHECK_PEER_SIGALG,
+                 SSL_R_WRONG_SIGNATURE_TYPE);
+        return 0;
+    }
+#endif
+
+    /* Check signature matches a type we sent */
+    sent_sigslen = tls12_get_psigalgs(s, 1, &sent_sigs);
+    for (i = 0; i < sent_sigslen; i++, sent_sigs++) {
+        if (sig == *sent_sigs)
+            break;
+    }
+    /* Allow fallback to SHA1 if not strict mode */
+    if (i == sent_sigslen && (lu->hash != NID_sha1
+        || s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS12_CHECK_PEER_SIGALG,
+                 SSL_R_WRONG_SIGNATURE_TYPE);
+        return 0;
+    }
+    if (!tls1_lookup_md(lu, &md)) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS12_CHECK_PEER_SIGALG,
+                 SSL_R_UNKNOWN_DIGEST);
+        return 0;
+    }
+    /*
+     * Make sure security callback allows algorithm. For historical
+     * reasons we have to pass the sigalg as a two byte char array.
+     */
+    sigalgstr[0] = (sig >> 8) & 0xff;
+    sigalgstr[1] = sig & 0xff;
+    secbits = sigalg_security_bits(lu);
+    if (secbits == 0 ||
+        !ssl_security(s, SSL_SECOP_SIGALG_CHECK, secbits,
+                      md != NULL ? EVP_MD_type(md) : NID_undef,
+                      (void *)sigalgstr)) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS12_CHECK_PEER_SIGALG,
+                 SSL_R_WRONG_SIGNATURE_TYPE);
+        return 0;
+    }
+    /* Store the sigalg the peer uses */
+    s->s3->tmp.peer_sigalg = lu;
+    return 1;
+}
+
+int SSL_get_peer_signature_type_nid(const SSL *s, int *pnid)
+{
+    if (s->s3->tmp.peer_sigalg == NULL)
+        return 0;
+    *pnid = s->s3->tmp.peer_sigalg->sig;
+    return 1;
+}
+
+int SSL_get_signature_type_nid(const SSL *s, int *pnid)
+{
+    if (s->s3->tmp.sigalg == NULL)
+        return 0;
+    *pnid = s->s3->tmp.sigalg->sig;
+    return 1;
+}
+
+/*
+ * Set a mask of disabled algorithms: an algorithm is disabled if it isn't
+ * supported, doesn't appear in supported signature algorithms, isn't supported
+ * by the enabled protocol versions or by the security level.
+ *
+ * This function should only be used for checking which ciphers are supported
+ * by the client.
+ *
+ * Call ssl_cipher_disabled() to check that it's enabled or not.
+ */
+int ssl_set_client_disabled(SSL *s)
+{
+    s->s3->tmp.mask_a = 0;
+    s->s3->tmp.mask_k = 0;
+    ssl_set_sig_mask(&s->s3->tmp.mask_a, s, SSL_SECOP_SIGALG_MASK);
+    if (ssl_get_min_max_version(s, &s->s3->tmp.min_ver,
+                                &s->s3->tmp.max_ver, NULL) != 0)
+        return 0;
+#ifndef OPENSSL_NO_PSK
+    /* with PSK there must be client callback set */
+    if (!s->psk_client_callback) {
+        s->s3->tmp.mask_a |= SSL_aPSK;
+        s->s3->tmp.mask_k |= SSL_PSK;
+    }
+#endif                          /* OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_SRP
+    if (!(s->srp_ctx.srp_Mask & SSL_kSRP)) {
+        s->s3->tmp.mask_a |= SSL_aSRP;
+        s->s3->tmp.mask_k |= SSL_kSRP;
+    }
+#endif
+    return 1;
+}
+
+/*
+ * ssl_cipher_disabled - check that a cipher is disabled or not
+ * @s: SSL connection that you want to use the cipher on
+ * @c: cipher to check
+ * @op: Security check that you want to do
+ * @ecdhe: If set to 1 then TLSv1 ECDHE ciphers are also allowed in SSLv3
+ *
+ * Returns 1 when it's disabled, 0 when enabled.
+ */
+int ssl_cipher_disabled(const SSL *s, const SSL_CIPHER *c, int op, int ecdhe)
+{
+    if (c->algorithm_mkey & s->s3->tmp.mask_k
+        || c->algorithm_auth & s->s3->tmp.mask_a)
+        return 1;
+    if (s->s3->tmp.max_ver == 0)
+        return 1;
+    if (!SSL_IS_DTLS(s)) {
+        int min_tls = c->min_tls;
+
+        /*
+         * For historical reasons we will allow ECHDE to be selected by a server
+         * in SSLv3 if we are a client
+         */
+        if (min_tls == TLS1_VERSION && ecdhe
+                && (c->algorithm_mkey & (SSL_kECDHE | SSL_kECDHEPSK)) != 0)
+            min_tls = SSL3_VERSION;
+
+        if ((min_tls > s->s3->tmp.max_ver) || (c->max_tls < s->s3->tmp.min_ver))
+            return 1;
+    }
+    if (SSL_IS_DTLS(s) && (DTLS_VERSION_GT(c->min_dtls, s->s3->tmp.max_ver)
+                           || DTLS_VERSION_LT(c->max_dtls, s->s3->tmp.min_ver)))
+        return 1;
+
+    return !ssl_security(s, op, c->strength_bits, 0, (void *)c);
+}
+
+int tls_use_ticket(SSL *s)
+{
+    if ((s->options & SSL_OP_NO_TICKET))
+        return 0;
+    return ssl_security(s, SSL_SECOP_TICKET, 0, 0, NULL);
+}
+
+int tls1_set_server_sigalgs(SSL *s)
+{
+    size_t i;
+
+    /* Clear any shared signature algorithms */
+    OPENSSL_free(s->shared_sigalgs);
+    s->shared_sigalgs = NULL;
+    s->shared_sigalgslen = 0;
+    /* Clear certificate validity flags */
+    for (i = 0; i < SSL_PKEY_NUM; i++)
+        s->s3->tmp.valid_flags[i] = 0;
+    /*
+     * If peer sent no signature algorithms check to see if we support
+     * the default algorithm for each certificate type
+     */
+    if (s->s3->tmp.peer_cert_sigalgs == NULL
+            && s->s3->tmp.peer_sigalgs == NULL) {
+        const uint16_t *sent_sigs;
+        size_t sent_sigslen = tls12_get_psigalgs(s, 1, &sent_sigs);
+
+        for (i = 0; i < SSL_PKEY_NUM; i++) {
+            const SIGALG_LOOKUP *lu = tls1_get_legacy_sigalg(s, i);
+            size_t j;
+
+            if (lu == NULL)
+                continue;
+            /* Check default matches a type we sent */
+            for (j = 0; j < sent_sigslen; j++) {
+                if (lu->sigalg == sent_sigs[j]) {
+                        s->s3->tmp.valid_flags[i] = CERT_PKEY_SIGN;
+                        break;
+                }
+            }
+        }
+        return 1;
+    }
+
+    if (!tls1_process_sigalgs(s)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLS1_SET_SERVER_SIGALGS, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    if (s->shared_sigalgs != NULL)
+        return 1;
+
+    /* Fatal error if no shared signature algorithms */
+    SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS1_SET_SERVER_SIGALGS,
+             SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS);
+    return 0;
+}
+
+/*-
+ * Gets the ticket information supplied by the client if any.
+ *
+ *   hello: The parsed ClientHello data
+ *   ret: (output) on return, if a ticket was decrypted, then this is set to
+ *       point to the resulting session.
+ */
+SSL_TICKET_STATUS tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
+                                             SSL_SESSION **ret)
+{
+    size_t size;
+    RAW_EXTENSION *ticketext;
+
+    *ret = NULL;
+    s->ext.ticket_expected = 0;
+
+    /*
+     * If tickets disabled or not supported by the protocol version
+     * (e.g. TLSv1.3) behave as if no ticket present to permit stateful
+     * resumption.
+     */
+    if (s->version <= SSL3_VERSION || !tls_use_ticket(s))
+        return SSL_TICKET_NONE;
+
+    ticketext = &hello->pre_proc_exts[TLSEXT_IDX_session_ticket];
+    if (!ticketext->present)
+        return SSL_TICKET_NONE;
+
+    size = PACKET_remaining(&ticketext->data);
+
+    return tls_decrypt_ticket(s, PACKET_data(&ticketext->data), size,
+                              hello->session_id, hello->session_id_len, ret);
+}
+
+/*-
+ * tls_decrypt_ticket attempts to decrypt a session ticket.
+ *
+ * If s->tls_session_secret_cb is set and we're not doing TLSv1.3 then we are
+ * expecting a pre-shared key ciphersuite, in which case we have no use for
+ * session tickets and one will never be decrypted, nor will
+ * s->ext.ticket_expected be set to 1.
+ *
+ * Side effects:
+ *   Sets s->ext.ticket_expected to 1 if the server will have to issue
+ *   a new session ticket to the client because the client indicated support
+ *   (and s->tls_session_secret_cb is NULL) but the client either doesn't have
+ *   a session ticket or we couldn't use the one it gave us, or if
+ *   s->ctx->ext.ticket_key_cb asked to renew the client's ticket.
+ *   Otherwise, s->ext.ticket_expected is set to 0.
+ *
+ *   etick: points to the body of the session ticket extension.
+ *   eticklen: the length of the session tickets extension.
+ *   sess_id: points at the session ID.
+ *   sesslen: the length of the session ID.
+ *   psess: (output) on return, if a ticket was decrypted, then this is set to
+ *       point to the resulting session.
+ */
+SSL_TICKET_STATUS tls_decrypt_ticket(SSL *s, const unsigned char *etick,
+                                     size_t eticklen, const unsigned char *sess_id,
+                                     size_t sesslen, SSL_SESSION **psess)
+{
+    SSL_SESSION *sess = NULL;
+    unsigned char *sdec;
+    const unsigned char *p;
+    int slen, renew_ticket = 0, declen;
+    SSL_TICKET_STATUS ret = SSL_TICKET_FATAL_ERR_OTHER;
+    size_t mlen;
+    unsigned char tick_hmac[EVP_MAX_MD_SIZE];
+    HMAC_CTX *hctx = NULL;
+    EVP_CIPHER_CTX *ctx = NULL;
+    SSL_CTX *tctx = s->session_ctx;
+
+    if (eticklen == 0) {
+        /*
+         * The client will accept a ticket but doesn't currently have
+         * one (TLSv1.2 and below), or treated as a fatal error in TLSv1.3
+         */
+        ret = SSL_TICKET_EMPTY;
+        goto end;
+    }
+    if (!SSL_IS_TLS13(s) && s->ext.session_secret_cb) {
+        /*
+         * Indicate that the ticket couldn't be decrypted rather than
+         * generating the session from ticket now, trigger
+         * abbreviated handshake based on external mechanism to
+         * calculate the master secret later.
+         */
+        ret = SSL_TICKET_NO_DECRYPT;
+        goto end;
+    }
+
+    /* Need at least keyname + iv */
+    if (eticklen < TLSEXT_KEYNAME_LENGTH + EVP_MAX_IV_LENGTH) {
+        ret = SSL_TICKET_NO_DECRYPT;
+        goto end;
+    }
+
+    /* Initialize session ticket encryption and HMAC contexts */
+    hctx = HMAC_CTX_new();
+    if (hctx == NULL) {
+        ret = SSL_TICKET_FATAL_ERR_MALLOC;
+        goto end;
+    }
+    ctx = EVP_CIPHER_CTX_new();
+    if (ctx == NULL) {
+        ret = SSL_TICKET_FATAL_ERR_MALLOC;
+        goto end;
+    }
+    if (tctx->ext.ticket_key_cb) {
+        unsigned char *nctick = (unsigned char *)etick;
+        int rv = tctx->ext.ticket_key_cb(s, nctick,
+                                         nctick + TLSEXT_KEYNAME_LENGTH,
+                                         ctx, hctx, 0);
+        if (rv < 0) {
+            ret = SSL_TICKET_FATAL_ERR_OTHER;
+            goto end;
+        }
+        if (rv == 0) {
+            ret = SSL_TICKET_NO_DECRYPT;
+            goto end;
+        }
+        if (rv == 2)
+            renew_ticket = 1;
+    } else {
+        /* Check key name matches */
+        if (memcmp(etick, tctx->ext.tick_key_name,
+                   TLSEXT_KEYNAME_LENGTH) != 0) {
+            ret = SSL_TICKET_NO_DECRYPT;
+            goto end;
+        }
+        if (HMAC_Init_ex(hctx, tctx->ext.secure->tick_hmac_key,
+                         sizeof(tctx->ext.secure->tick_hmac_key),
+                         EVP_sha256(), NULL) <= 0
+            || EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL,
+                                  tctx->ext.secure->tick_aes_key,
+                                  etick + TLSEXT_KEYNAME_LENGTH) <= 0) {
+            ret = SSL_TICKET_FATAL_ERR_OTHER;
+            goto end;
+        }
+        if (SSL_IS_TLS13(s))
+            renew_ticket = 1;
+    }
+    /*
+     * Attempt to process session ticket, first conduct sanity and integrity
+     * checks on ticket.
+     */
+    mlen = HMAC_size(hctx);
+    if (mlen == 0) {
+        ret = SSL_TICKET_FATAL_ERR_OTHER;
+        goto end;
+    }
+
+    /* Sanity check ticket length: must exceed keyname + IV + HMAC */
+    if (eticklen <=
+        TLSEXT_KEYNAME_LENGTH + EVP_CIPHER_CTX_iv_length(ctx) + mlen) {
+        ret = SSL_TICKET_NO_DECRYPT;
+        goto end;
+    }
+    eticklen -= mlen;
+    /* Check HMAC of encrypted ticket */
+    if (HMAC_Update(hctx, etick, eticklen) <= 0
+        || HMAC_Final(hctx, tick_hmac, NULL) <= 0) {
+        ret = SSL_TICKET_FATAL_ERR_OTHER;
+        goto end;
+    }
+
+    if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen)) {
+        ret = SSL_TICKET_NO_DECRYPT;
+        goto end;
+    }
+    /* Attempt to decrypt session data */
+    /* Move p after IV to start of encrypted ticket, update length */
+    p = etick + TLSEXT_KEYNAME_LENGTH + EVP_CIPHER_CTX_iv_length(ctx);
+    eticklen -= TLSEXT_KEYNAME_LENGTH + EVP_CIPHER_CTX_iv_length(ctx);
+    sdec = OPENSSL_malloc(eticklen);
+    if (sdec == NULL || EVP_DecryptUpdate(ctx, sdec, &slen, p,
+                                          (int)eticklen) <= 0) {
+        OPENSSL_free(sdec);
+        ret = SSL_TICKET_FATAL_ERR_OTHER;
+        goto end;
+    }
+    if (EVP_DecryptFinal(ctx, sdec + slen, &declen) <= 0) {
+        OPENSSL_free(sdec);
+        ret = SSL_TICKET_NO_DECRYPT;
+        goto end;
+    }
+    slen += declen;
+    p = sdec;
+
+    sess = d2i_SSL_SESSION(NULL, &p, slen);
+    slen -= p - sdec;
+    OPENSSL_free(sdec);
+    if (sess) {
+        /* Some additional consistency checks */
+        if (slen != 0) {
+            SSL_SESSION_free(sess);
+            sess = NULL;
+            ret = SSL_TICKET_NO_DECRYPT;
+            goto end;
+        }
+        /*
+         * The session ID, if non-empty, is used by some clients to detect
+         * that the ticket has been accepted. So we copy it to the session
+         * structure. If it is empty set length to zero as required by
+         * standard.
+         */
+        if (sesslen) {
+            memcpy(sess->session_id, sess_id, sesslen);
+            sess->session_id_length = sesslen;
+        }
+        if (renew_ticket)
+            ret = SSL_TICKET_SUCCESS_RENEW;
+        else
+            ret = SSL_TICKET_SUCCESS;
+        goto end;
+    }
+    ERR_clear_error();
+    /*
+     * For session parse failure, indicate that we need to send a new ticket.
+     */
+    ret = SSL_TICKET_NO_DECRYPT;
+
+ end:
+    EVP_CIPHER_CTX_free(ctx);
+    HMAC_CTX_free(hctx);
+
+    /*
+     * If set, the decrypt_ticket_cb() is called unless a fatal error was
+     * detected above. The callback is responsible for checking |ret| before it
+     * performs any action
+     */
+    if (s->session_ctx->decrypt_ticket_cb != NULL
+            && (ret == SSL_TICKET_EMPTY
+                || ret == SSL_TICKET_NO_DECRYPT
+                || ret == SSL_TICKET_SUCCESS
+                || ret == SSL_TICKET_SUCCESS_RENEW)) {
+        size_t keyname_len = eticklen;
+        int retcb;
+
+        if (keyname_len > TLSEXT_KEYNAME_LENGTH)
+            keyname_len = TLSEXT_KEYNAME_LENGTH;
+        retcb = s->session_ctx->decrypt_ticket_cb(s, sess, etick, keyname_len,
+                                                  ret,
+                                                  s->session_ctx->ticket_cb_data);
+        switch (retcb) {
+        case SSL_TICKET_RETURN_ABORT:
+            ret = SSL_TICKET_FATAL_ERR_OTHER;
+            break;
+
+        case SSL_TICKET_RETURN_IGNORE:
+            ret = SSL_TICKET_NONE;
+            SSL_SESSION_free(sess);
+            sess = NULL;
+            break;
+
+        case SSL_TICKET_RETURN_IGNORE_RENEW:
+            if (ret != SSL_TICKET_EMPTY && ret != SSL_TICKET_NO_DECRYPT)
+                ret = SSL_TICKET_NO_DECRYPT;
+            /* else the value of |ret| will already do the right thing */
+            SSL_SESSION_free(sess);
+            sess = NULL;
+            break;
+
+        case SSL_TICKET_RETURN_USE:
+        case SSL_TICKET_RETURN_USE_RENEW:
+            if (ret != SSL_TICKET_SUCCESS
+                    && ret != SSL_TICKET_SUCCESS_RENEW)
+                ret = SSL_TICKET_FATAL_ERR_OTHER;
+            else if (retcb == SSL_TICKET_RETURN_USE)
+                ret = SSL_TICKET_SUCCESS;
+            else
+                ret = SSL_TICKET_SUCCESS_RENEW;
+            break;
+
+        default:
+            ret = SSL_TICKET_FATAL_ERR_OTHER;
+        }
+    }
+
+    if (s->ext.session_secret_cb == NULL || SSL_IS_TLS13(s)) {
+        switch (ret) {
+        case SSL_TICKET_NO_DECRYPT:
+        case SSL_TICKET_SUCCESS_RENEW:
+        case SSL_TICKET_EMPTY:
+            s->ext.ticket_expected = 1;
+        }
+    }
+
+    *psess = sess;
+
+    return ret;
+}
+
+/* Check to see if a signature algorithm is allowed */
+static int tls12_sigalg_allowed(const SSL *s, int op, const SIGALG_LOOKUP *lu)
+{
+    unsigned char sigalgstr[2];
+    int secbits;
+
+    /* See if sigalgs is recognised and if hash is enabled */
+    if (!tls1_lookup_md(lu, NULL))
+        return 0;
+    /* DSA is not allowed in TLS 1.3 */
+    if (SSL_IS_TLS13(s) && lu->sig == EVP_PKEY_DSA)
+        return 0;
+    /* TODO(OpenSSL1.2) fully axe DSA/etc. in ClientHello per TLS 1.3 spec */
+    if (!s->server && !SSL_IS_DTLS(s) && s->s3->tmp.min_ver >= TLS1_3_VERSION
+        && (lu->sig == EVP_PKEY_DSA || lu->hash_idx == SSL_MD_SHA1_IDX
+            || lu->hash_idx == SSL_MD_MD5_IDX
+            || lu->hash_idx == SSL_MD_SHA224_IDX))
+        return 0;
+
+    /* See if public key algorithm allowed */
+    if (ssl_cert_is_disabled(lu->sig_idx))
+        return 0;
+
+    if (lu->sig == NID_id_GostR3410_2012_256
+            || lu->sig == NID_id_GostR3410_2012_512
+            || lu->sig == NID_id_GostR3410_2001) {
+        /* We never allow GOST sig algs on the server with TLSv1.3 */
+        if (s->server && SSL_IS_TLS13(s))
+            return 0;
+        if (!s->server
+                && s->method->version == TLS_ANY_VERSION
+                && s->s3->tmp.max_ver >= TLS1_3_VERSION) {
+            int i, num;
+            STACK_OF(SSL_CIPHER) *sk;
+
+            /*
+             * We're a client that could negotiate TLSv1.3. We only allow GOST
+             * sig algs if we could negotiate TLSv1.2 or below and we have GOST
+             * ciphersuites enabled.
+             */
+
+            if (s->s3->tmp.min_ver >= TLS1_3_VERSION)
+                return 0;
+
+            sk = SSL_get_ciphers(s);
+            num = sk != NULL ? sk_SSL_CIPHER_num(sk) : 0;
+            for (i = 0; i < num; i++) {
+                const SSL_CIPHER *c;
+
+                c = sk_SSL_CIPHER_value(sk, i);
+                /* Skip disabled ciphers */
+                if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED, 0))
+                    continue;
+
+                if ((c->algorithm_mkey & SSL_kGOST) != 0)
+                    break;
+            }
+            if (i == num)
+                return 0;
+        }
+    }
+
+    /* Finally see if security callback allows it */
+    secbits = sigalg_security_bits(lu);
+    sigalgstr[0] = (lu->sigalg >> 8) & 0xff;
+    sigalgstr[1] = lu->sigalg & 0xff;
+    return ssl_security(s, op, secbits, lu->hash, (void *)sigalgstr);
+}
+
+/*
+ * Get a mask of disabled public key algorithms based on supported signature
+ * algorithms. For example if no signature algorithm supports RSA then RSA is
+ * disabled.
+ */
+
+void ssl_set_sig_mask(uint32_t *pmask_a, SSL *s, int op)
+{
+    const uint16_t *sigalgs;
+    size_t i, sigalgslen;
+    uint32_t disabled_mask = SSL_aRSA | SSL_aDSS | SSL_aECDSA;
+    /*
+     * Go through all signature algorithms seeing if we support any
+     * in disabled_mask.
+     */
+    sigalgslen = tls12_get_psigalgs(s, 1, &sigalgs);
+    for (i = 0; i < sigalgslen; i++, sigalgs++) {
+        const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(*sigalgs);
+        const SSL_CERT_LOOKUP *clu;
+
+        if (lu == NULL)
+            continue;
+
+        clu = ssl_cert_lookup_by_idx(lu->sig_idx);
+	if (clu == NULL)
+		continue;
+
+        /* If algorithm is disabled see if we can enable it */
+        if ((clu->amask & disabled_mask) != 0
+                && tls12_sigalg_allowed(s, op, lu))
+            disabled_mask &= ~clu->amask;
+    }
+    *pmask_a |= disabled_mask;
+}
+
+int tls12_copy_sigalgs(SSL *s, WPACKET *pkt,
+                       const uint16_t *psig, size_t psiglen)
+{
+    size_t i;
+    int rv = 0;
+
+    for (i = 0; i < psiglen; i++, psig++) {
+        const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(*psig);
+
+        if (!tls12_sigalg_allowed(s, SSL_SECOP_SIGALG_SUPPORTED, lu))
+            continue;
+        if (!WPACKET_put_bytes_u16(pkt, *psig))
+            return 0;
+        /*
+         * If TLS 1.3 must have at least one valid TLS 1.3 message
+         * signing algorithm: i.e. neither RSA nor SHA1/SHA224
+         */
+        if (rv == 0 && (!SSL_IS_TLS13(s)
+            || (lu->sig != EVP_PKEY_RSA
+                && lu->hash != NID_sha1
+                && lu->hash != NID_sha224)))
+            rv = 1;
+    }
+    if (rv == 0)
+        SSLerr(SSL_F_TLS12_COPY_SIGALGS, SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM);
+    return rv;
+}
+
+/* Given preference and allowed sigalgs set shared sigalgs */
+static size_t tls12_shared_sigalgs(SSL *s, const SIGALG_LOOKUP **shsig,
+                                   const uint16_t *pref, size_t preflen,
+                                   const uint16_t *allow, size_t allowlen)
+{
+    const uint16_t *ptmp, *atmp;
+    size_t i, j, nmatch = 0;
+    for (i = 0, ptmp = pref; i < preflen; i++, ptmp++) {
+        const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(*ptmp);
+
+        /* Skip disabled hashes or signature algorithms */
+        if (!tls12_sigalg_allowed(s, SSL_SECOP_SIGALG_SHARED, lu))
+            continue;
+        for (j = 0, atmp = allow; j < allowlen; j++, atmp++) {
+            if (*ptmp == *atmp) {
+                nmatch++;
+                if (shsig)
+                    *shsig++ = lu;
+                break;
+            }
+        }
+    }
+    return nmatch;
+}
+
+/* Set shared signature algorithms for SSL structures */
+static int tls1_set_shared_sigalgs(SSL *s)
+{
+    const uint16_t *pref, *allow, *conf;
+    size_t preflen, allowlen, conflen;
+    size_t nmatch;
+    const SIGALG_LOOKUP **salgs = NULL;
+    CERT *c = s->cert;
+    unsigned int is_suiteb = tls1_suiteb(s);
+
+    OPENSSL_free(s->shared_sigalgs);
+    s->shared_sigalgs = NULL;
+    s->shared_sigalgslen = 0;
+    /* If client use client signature algorithms if not NULL */
+    if (!s->server && c->client_sigalgs && !is_suiteb) {
+        conf = c->client_sigalgs;
+        conflen = c->client_sigalgslen;
+    } else if (c->conf_sigalgs && !is_suiteb) {
+        conf = c->conf_sigalgs;
+        conflen = c->conf_sigalgslen;
+    } else
+        conflen = tls12_get_psigalgs(s, 0, &conf);
+    if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || is_suiteb) {
+        pref = conf;
+        preflen = conflen;
+        allow = s->s3->tmp.peer_sigalgs;
+        allowlen = s->s3->tmp.peer_sigalgslen;
+    } else {
+        allow = conf;
+        allowlen = conflen;
+        pref = s->s3->tmp.peer_sigalgs;
+        preflen = s->s3->tmp.peer_sigalgslen;
+    }
+    nmatch = tls12_shared_sigalgs(s, NULL, pref, preflen, allow, allowlen);
+    if (nmatch) {
+        if ((salgs = OPENSSL_malloc(nmatch * sizeof(*salgs))) == NULL) {
+            SSLerr(SSL_F_TLS1_SET_SHARED_SIGALGS, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        nmatch = tls12_shared_sigalgs(s, salgs, pref, preflen, allow, allowlen);
+    } else {
+        salgs = NULL;
+    }
+    s->shared_sigalgs = salgs;
+    s->shared_sigalgslen = nmatch;
+    return 1;
+}
+
+int tls1_save_u16(PACKET *pkt, uint16_t **pdest, size_t *pdestlen)
+{
+    unsigned int stmp;
+    size_t size, i;
+    uint16_t *buf;
+
+    size = PACKET_remaining(pkt);
+
+    /* Invalid data length */
+    if (size == 0 || (size & 1) != 0)
+        return 0;
+
+    size >>= 1;
+
+    if ((buf = OPENSSL_malloc(size * sizeof(*buf))) == NULL)  {
+        SSLerr(SSL_F_TLS1_SAVE_U16, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    for (i = 0; i < size && PACKET_get_net_2(pkt, &stmp); i++)
+        buf[i] = stmp;
+
+    if (i != size) {
+        OPENSSL_free(buf);
+        return 0;
+    }
+
+    OPENSSL_free(*pdest);
+    *pdest = buf;
+    *pdestlen = size;
+
+    return 1;
+}
+
+int tls1_save_sigalgs(SSL *s, PACKET *pkt, int cert)
+{
+    /* Extension ignored for inappropriate versions */
+    if (!SSL_USE_SIGALGS(s))
+        return 1;
+    /* Should never happen */
+    if (s->cert == NULL)
+        return 0;
+
+    if (cert)
+        return tls1_save_u16(pkt, &s->s3->tmp.peer_cert_sigalgs,
+                             &s->s3->tmp.peer_cert_sigalgslen);
+    else
+        return tls1_save_u16(pkt, &s->s3->tmp.peer_sigalgs,
+                             &s->s3->tmp.peer_sigalgslen);
+
+}
+
+/* Set preferred digest for each key type */
+
+int tls1_process_sigalgs(SSL *s)
+{
+    size_t i;
+    uint32_t *pvalid = s->s3->tmp.valid_flags;
+
+    if (!tls1_set_shared_sigalgs(s))
+        return 0;
+
+    for (i = 0; i < SSL_PKEY_NUM; i++)
+        pvalid[i] = 0;
+
+    for (i = 0; i < s->shared_sigalgslen; i++) {
+        const SIGALG_LOOKUP *sigptr = s->shared_sigalgs[i];
+        int idx = sigptr->sig_idx;
+
+        /* Ignore PKCS1 based sig algs in TLSv1.3 */
+        if (SSL_IS_TLS13(s) && sigptr->sig == EVP_PKEY_RSA)
+            continue;
+        /* If not disabled indicate we can explicitly sign */
+        if (pvalid[idx] == 0 && !ssl_cert_is_disabled(idx))
+            pvalid[idx] = CERT_PKEY_EXPLICIT_SIGN | CERT_PKEY_SIGN;
+    }
+    return 1;
+}
+
+int SSL_get_sigalgs(SSL *s, int idx,
+                    int *psign, int *phash, int *psignhash,
+                    unsigned char *rsig, unsigned char *rhash)
+{
+    uint16_t *psig = s->s3->tmp.peer_sigalgs;
+    size_t numsigalgs = s->s3->tmp.peer_sigalgslen;
+    if (psig == NULL || numsigalgs > INT_MAX)
+        return 0;
+    if (idx >= 0) {
+        const SIGALG_LOOKUP *lu;
+
+        if (idx >= (int)numsigalgs)
+            return 0;
+        psig += idx;
+        if (rhash != NULL)
+            *rhash = (unsigned char)((*psig >> 8) & 0xff);
+        if (rsig != NULL)
+            *rsig = (unsigned char)(*psig & 0xff);
+        lu = tls1_lookup_sigalg(*psig);
+        if (psign != NULL)
+            *psign = lu != NULL ? lu->sig : NID_undef;
+        if (phash != NULL)
+            *phash = lu != NULL ? lu->hash : NID_undef;
+        if (psignhash != NULL)
+            *psignhash = lu != NULL ? lu->sigandhash : NID_undef;
+    }
+    return (int)numsigalgs;
+}
+
+int SSL_get_shared_sigalgs(SSL *s, int idx,
+                           int *psign, int *phash, int *psignhash,
+                           unsigned char *rsig, unsigned char *rhash)
+{
+    const SIGALG_LOOKUP *shsigalgs;
+    if (s->shared_sigalgs == NULL
+        || idx < 0
+        || idx >= (int)s->shared_sigalgslen
+        || s->shared_sigalgslen > INT_MAX)
+        return 0;
+    shsigalgs = s->shared_sigalgs[idx];
+    if (phash != NULL)
+        *phash = shsigalgs->hash;
+    if (psign != NULL)
+        *psign = shsigalgs->sig;
+    if (psignhash != NULL)
+        *psignhash = shsigalgs->sigandhash;
+    if (rsig != NULL)
+        *rsig = (unsigned char)(shsigalgs->sigalg & 0xff);
+    if (rhash != NULL)
+        *rhash = (unsigned char)((shsigalgs->sigalg >> 8) & 0xff);
+    return (int)s->shared_sigalgslen;
+}
+
+/* Maximum possible number of unique entries in sigalgs array */
+#define TLS_MAX_SIGALGCNT (OSSL_NELEM(sigalg_lookup_tbl) * 2)
+
+typedef struct {
+    size_t sigalgcnt;
+    /* TLSEXT_SIGALG_XXX values */
+    uint16_t sigalgs[TLS_MAX_SIGALGCNT];
+} sig_cb_st;
+
+static void get_sigorhash(int *psig, int *phash, const char *str)
+{
+    if (strcmp(str, "RSA") == 0) {
+        *psig = EVP_PKEY_RSA;
+    } else if (strcmp(str, "RSA-PSS") == 0 || strcmp(str, "PSS") == 0) {
+        *psig = EVP_PKEY_RSA_PSS;
+    } else if (strcmp(str, "DSA") == 0) {
+        *psig = EVP_PKEY_DSA;
+    } else if (strcmp(str, "ECDSA") == 0) {
+        *psig = EVP_PKEY_EC;
+    } else {
+        *phash = OBJ_sn2nid(str);
+        if (*phash == NID_undef)
+            *phash = OBJ_ln2nid(str);
+    }
+}
+/* Maximum length of a signature algorithm string component */
+#define TLS_MAX_SIGSTRING_LEN   40
+
+static int sig_cb(const char *elem, int len, void *arg)
+{
+    sig_cb_st *sarg = arg;
+    size_t i;
+    const SIGALG_LOOKUP *s;
+    char etmp[TLS_MAX_SIGSTRING_LEN], *p;
+    int sig_alg = NID_undef, hash_alg = NID_undef;
+    if (elem == NULL)
+        return 0;
+    if (sarg->sigalgcnt == TLS_MAX_SIGALGCNT)
+        return 0;
+    if (len > (int)(sizeof(etmp) - 1))
+        return 0;
+    memcpy(etmp, elem, len);
+    etmp[len] = 0;
+    p = strchr(etmp, '+');
+    /*
+     * We only allow SignatureSchemes listed in the sigalg_lookup_tbl;
+     * if there's no '+' in the provided name, look for the new-style combined
+     * name.  If not, match both sig+hash to find the needed SIGALG_LOOKUP.
+     * Just sig+hash is not unique since TLS 1.3 adds rsa_pss_pss_* and
+     * rsa_pss_rsae_* that differ only by public key OID; in such cases
+     * we will pick the _rsae_ variant, by virtue of them appearing earlier
+     * in the table.
+     */
+    if (p == NULL) {
+        for (i = 0, s = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl);
+             i++, s++) {
+            if (s->name != NULL && strcmp(etmp, s->name) == 0) {
+                sarg->sigalgs[sarg->sigalgcnt++] = s->sigalg;
+                break;
+            }
+        }
+        if (i == OSSL_NELEM(sigalg_lookup_tbl))
+            return 0;
+    } else {
+        *p = 0;
+        p++;
+        if (*p == 0)
+            return 0;
+        get_sigorhash(&sig_alg, &hash_alg, etmp);
+        get_sigorhash(&sig_alg, &hash_alg, p);
+        if (sig_alg == NID_undef || hash_alg == NID_undef)
+            return 0;
+        for (i = 0, s = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl);
+             i++, s++) {
+            if (s->hash == hash_alg && s->sig == sig_alg) {
+                sarg->sigalgs[sarg->sigalgcnt++] = s->sigalg;
+                break;
+            }
+        }
+        if (i == OSSL_NELEM(sigalg_lookup_tbl))
+            return 0;
+    }
+
+    /* Reject duplicates */
+    for (i = 0; i < sarg->sigalgcnt - 1; i++) {
+        if (sarg->sigalgs[i] == sarg->sigalgs[sarg->sigalgcnt - 1]) {
+            sarg->sigalgcnt--;
+            return 0;
+        }
+    }
+    return 1;
+}
+
+/*
+ * Set supported signature algorithms based on a colon separated list of the
+ * form sig+hash e.g. RSA+SHA512:DSA+SHA512
+ */
+int tls1_set_sigalgs_list(CERT *c, const char *str, int client)
+{
+    sig_cb_st sig;
+    sig.sigalgcnt = 0;
+    if (!CONF_parse_list(str, ':', 1, sig_cb, &sig))
+        return 0;
+    if (c == NULL)
+        return 1;
+    return tls1_set_raw_sigalgs(c, sig.sigalgs, sig.sigalgcnt, client);
+}
+
+int tls1_set_raw_sigalgs(CERT *c, const uint16_t *psigs, size_t salglen,
+                     int client)
+{
+    uint16_t *sigalgs;
+
+    if ((sigalgs = OPENSSL_malloc(salglen * sizeof(*sigalgs))) == NULL) {
+        SSLerr(SSL_F_TLS1_SET_RAW_SIGALGS, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    memcpy(sigalgs, psigs, salglen * sizeof(*sigalgs));
+
+    if (client) {
+        OPENSSL_free(c->client_sigalgs);
+        c->client_sigalgs = sigalgs;
+        c->client_sigalgslen = salglen;
+    } else {
+        OPENSSL_free(c->conf_sigalgs);
+        c->conf_sigalgs = sigalgs;
+        c->conf_sigalgslen = salglen;
+    }
+
+    return 1;
+}
+
+int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen, int client)
+{
+    uint16_t *sigalgs, *sptr;
+    size_t i;
+
+    if (salglen & 1)
+        return 0;
+    if ((sigalgs = OPENSSL_malloc((salglen / 2) * sizeof(*sigalgs))) == NULL) {
+        SSLerr(SSL_F_TLS1_SET_SIGALGS, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    for (i = 0, sptr = sigalgs; i < salglen; i += 2) {
+        size_t j;
+        const SIGALG_LOOKUP *curr;
+        int md_id = *psig_nids++;
+        int sig_id = *psig_nids++;
+
+        for (j = 0, curr = sigalg_lookup_tbl; j < OSSL_NELEM(sigalg_lookup_tbl);
+             j++, curr++) {
+            if (curr->hash == md_id && curr->sig == sig_id) {
+                *sptr++ = curr->sigalg;
+                break;
+            }
+        }
+
+        if (j == OSSL_NELEM(sigalg_lookup_tbl))
+            goto err;
+    }
+
+    if (client) {
+        OPENSSL_free(c->client_sigalgs);
+        c->client_sigalgs = sigalgs;
+        c->client_sigalgslen = salglen / 2;
+    } else {
+        OPENSSL_free(c->conf_sigalgs);
+        c->conf_sigalgs = sigalgs;
+        c->conf_sigalgslen = salglen / 2;
+    }
+
+    return 1;
+
+ err:
+    OPENSSL_free(sigalgs);
+    return 0;
+}
+
+static int tls1_check_sig_alg(SSL *s, X509 *x, int default_nid)
+{
+    int sig_nid, use_pc_sigalgs = 0;
+    size_t i;
+    const SIGALG_LOOKUP *sigalg;
+    size_t sigalgslen;
+    if (default_nid == -1)
+        return 1;
+    sig_nid = X509_get_signature_nid(x);
+    if (default_nid)
+        return sig_nid == default_nid ? 1 : 0;
+
+    if (SSL_IS_TLS13(s) && s->s3->tmp.peer_cert_sigalgs != NULL) {
+        /*
+         * If we're in TLSv1.3 then we only get here if we're checking the
+         * chain. If the peer has specified peer_cert_sigalgs then we use them
+         * otherwise we default to normal sigalgs.
+         */
+        sigalgslen = s->s3->tmp.peer_cert_sigalgslen;
+        use_pc_sigalgs = 1;
+    } else {
+        sigalgslen = s->shared_sigalgslen;
+    }
+    for (i = 0; i < sigalgslen; i++) {
+        sigalg = use_pc_sigalgs
+                 ? tls1_lookup_sigalg(s->s3->tmp.peer_cert_sigalgs[i])
+                 : s->shared_sigalgs[i];
+        if (sigalg != NULL && sig_nid == sigalg->sigandhash)
+            return 1;
+    }
+    return 0;
+}
+
+/* Check to see if a certificate issuer name matches list of CA names */
+static int ssl_check_ca_name(STACK_OF(X509_NAME) *names, X509 *x)
+{
+    X509_NAME *nm;
+    int i;
+    nm = X509_get_issuer_name(x);
+    for (i = 0; i < sk_X509_NAME_num(names); i++) {
+        if (!X509_NAME_cmp(nm, sk_X509_NAME_value(names, i)))
+            return 1;
+    }
+    return 0;
+}
+
+/*
+ * Check certificate chain is consistent with TLS extensions and is usable by
+ * server. This servers two purposes: it allows users to check chains before
+ * passing them to the server and it allows the server to check chains before
+ * attempting to use them.
+ */
+
+/* Flags which need to be set for a certificate when strict mode not set */
+
+#define CERT_PKEY_VALID_FLAGS \
+        (CERT_PKEY_EE_SIGNATURE|CERT_PKEY_EE_PARAM)
+/* Strict mode flags */
+#define CERT_PKEY_STRICT_FLAGS \
+         (CERT_PKEY_VALID_FLAGS|CERT_PKEY_CA_SIGNATURE|CERT_PKEY_CA_PARAM \
+         | CERT_PKEY_ISSUER_NAME|CERT_PKEY_CERT_TYPE)
+
+int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
+                     int idx)
+{
+    int i;
+    int rv = 0;
+    int check_flags = 0, strict_mode;
+    CERT_PKEY *cpk = NULL;
+    CERT *c = s->cert;
+    uint32_t *pvalid;
+    unsigned int suiteb_flags = tls1_suiteb(s);
+    /* idx == -1 means checking server chains */
+    if (idx != -1) {
+        /* idx == -2 means checking client certificate chains */
+        if (idx == -2) {
+            cpk = c->key;
+            idx = (int)(cpk - c->pkeys);
+        } else
+            cpk = c->pkeys + idx;
+        pvalid = s->s3->tmp.valid_flags + idx;
+        x = cpk->x509;
+        pk = cpk->privatekey;
+        chain = cpk->chain;
+        strict_mode = c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT;
+        /* If no cert or key, forget it */
+        if (!x || !pk)
+            goto end;
+    } else {
+        size_t certidx;
+
+        if (!x || !pk)
+            return 0;
+
+        if (ssl_cert_lookup_by_pkey(pk, &certidx) == NULL)
+            return 0;
+        idx = certidx;
+        pvalid = s->s3->tmp.valid_flags + idx;
+
+        if (c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)
+            check_flags = CERT_PKEY_STRICT_FLAGS;
+        else
+            check_flags = CERT_PKEY_VALID_FLAGS;
+        strict_mode = 1;
+    }
+
+    if (suiteb_flags) {
+        int ok;
+        if (check_flags)
+            check_flags |= CERT_PKEY_SUITEB;
+        ok = X509_chain_check_suiteb(NULL, x, chain, suiteb_flags);
+        if (ok == X509_V_OK)
+            rv |= CERT_PKEY_SUITEB;
+        else if (!check_flags)
+            goto end;
+    }
+
+    /*
+     * Check all signature algorithms are consistent with signature
+     * algorithms extension if TLS 1.2 or later and strict mode.
+     */
+    if (TLS1_get_version(s) >= TLS1_2_VERSION && strict_mode) {
+        int default_nid;
+        int rsign = 0;
+        if (s->s3->tmp.peer_cert_sigalgs != NULL
+                || s->s3->tmp.peer_sigalgs != NULL) {
+            default_nid = 0;
+        /* If no sigalgs extension use defaults from RFC5246 */
+        } else {
+            switch (idx) {
+            case SSL_PKEY_RSA:
+                rsign = EVP_PKEY_RSA;
+                default_nid = NID_sha1WithRSAEncryption;
+                break;
+
+            case SSL_PKEY_DSA_SIGN:
+                rsign = EVP_PKEY_DSA;
+                default_nid = NID_dsaWithSHA1;
+                break;
+
+            case SSL_PKEY_ECC:
+                rsign = EVP_PKEY_EC;
+                default_nid = NID_ecdsa_with_SHA1;
+                break;
+
+            case SSL_PKEY_GOST01:
+                rsign = NID_id_GostR3410_2001;
+                default_nid = NID_id_GostR3411_94_with_GostR3410_2001;
+                break;
+
+            case SSL_PKEY_GOST12_256:
+                rsign = NID_id_GostR3410_2012_256;
+                default_nid = NID_id_tc26_signwithdigest_gost3410_2012_256;
+                break;
+
+            case SSL_PKEY_GOST12_512:
+                rsign = NID_id_GostR3410_2012_512;
+                default_nid = NID_id_tc26_signwithdigest_gost3410_2012_512;
+                break;
+
+            default:
+                default_nid = -1;
+                break;
+            }
+        }
+        /*
+         * If peer sent no signature algorithms extension and we have set
+         * preferred signature algorithms check we support sha1.
+         */
+        if (default_nid > 0 && c->conf_sigalgs) {
+            size_t j;
+            const uint16_t *p = c->conf_sigalgs;
+            for (j = 0; j < c->conf_sigalgslen; j++, p++) {
+                const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(*p);
+
+                if (lu != NULL && lu->hash == NID_sha1 && lu->sig == rsign)
+                    break;
+            }
+            if (j == c->conf_sigalgslen) {
+                if (check_flags)
+                    goto skip_sigs;
+                else
+                    goto end;
+            }
+        }
+        /* Check signature algorithm of each cert in chain */
+        if (SSL_IS_TLS13(s)) {
+            /*
+             * We only get here if the application has called SSL_check_chain(),
+             * so check_flags is always set.
+             */
+            if (find_sig_alg(s, x, pk) != NULL)
+                rv |= CERT_PKEY_EE_SIGNATURE;
+        } else if (!tls1_check_sig_alg(s, x, default_nid)) {
+            if (!check_flags)
+                goto end;
+        } else
+            rv |= CERT_PKEY_EE_SIGNATURE;
+        rv |= CERT_PKEY_CA_SIGNATURE;
+        for (i = 0; i < sk_X509_num(chain); i++) {
+            if (!tls1_check_sig_alg(s, sk_X509_value(chain, i), default_nid)) {
+                if (check_flags) {
+                    rv &= ~CERT_PKEY_CA_SIGNATURE;
+                    break;
+                } else
+                    goto end;
+            }
+        }
+    }
+    /* Else not TLS 1.2, so mark EE and CA signing algorithms OK */
+    else if (check_flags)
+        rv |= CERT_PKEY_EE_SIGNATURE | CERT_PKEY_CA_SIGNATURE;
+ skip_sigs:
+    /* Check cert parameters are consistent */
+    if (tls1_check_cert_param(s, x, 1))
+        rv |= CERT_PKEY_EE_PARAM;
+    else if (!check_flags)
+        goto end;
+    if (!s->server)
+        rv |= CERT_PKEY_CA_PARAM;
+    /* In strict mode check rest of chain too */
+    else if (strict_mode) {
+        rv |= CERT_PKEY_CA_PARAM;
+        for (i = 0; i < sk_X509_num(chain); i++) {
+            X509 *ca = sk_X509_value(chain, i);
+            if (!tls1_check_cert_param(s, ca, 0)) {
+                if (check_flags) {
+                    rv &= ~CERT_PKEY_CA_PARAM;
+                    break;
+                } else
+                    goto end;
+            }
+        }
+    }
+    if (!s->server && strict_mode) {
+        STACK_OF(X509_NAME) *ca_dn;
+        int check_type = 0;
+        switch (EVP_PKEY_id(pk)) {
+        case EVP_PKEY_RSA:
+            check_type = TLS_CT_RSA_SIGN;
+            break;
+        case EVP_PKEY_DSA:
+            check_type = TLS_CT_DSS_SIGN;
+            break;
+        case EVP_PKEY_EC:
+            check_type = TLS_CT_ECDSA_SIGN;
+            break;
+        }
+        if (check_type) {
+            const uint8_t *ctypes = s->s3->tmp.ctype;
+            size_t j;
+
+            for (j = 0; j < s->s3->tmp.ctype_len; j++, ctypes++) {
+                if (*ctypes == check_type) {
+                    rv |= CERT_PKEY_CERT_TYPE;
+                    break;
+                }
+            }
+            if (!(rv & CERT_PKEY_CERT_TYPE) && !check_flags)
+                goto end;
+        } else {
+            rv |= CERT_PKEY_CERT_TYPE;
+        }
+
+        ca_dn = s->s3->tmp.peer_ca_names;
+
+        if (ca_dn == NULL
+            || sk_X509_NAME_num(ca_dn) == 0
+            || ssl_check_ca_name(ca_dn, x))
+            rv |= CERT_PKEY_ISSUER_NAME;
+        else
+            for (i = 0; i < sk_X509_num(chain); i++) {
+                X509 *xtmp = sk_X509_value(chain, i);
+
+                if (ssl_check_ca_name(ca_dn, xtmp)) {
+                    rv |= CERT_PKEY_ISSUER_NAME;
+                    break;
+                }
+            }
+
+        if (!check_flags && !(rv & CERT_PKEY_ISSUER_NAME))
+            goto end;
+    } else
+        rv |= CERT_PKEY_ISSUER_NAME | CERT_PKEY_CERT_TYPE;
+
+    if (!check_flags || (rv & check_flags) == check_flags)
+        rv |= CERT_PKEY_VALID;
+
+ end:
+
+    if (TLS1_get_version(s) >= TLS1_2_VERSION)
+        rv |= *pvalid & (CERT_PKEY_EXPLICIT_SIGN | CERT_PKEY_SIGN);
+    else
+        rv |= CERT_PKEY_SIGN | CERT_PKEY_EXPLICIT_SIGN;
+
+    /*
+     * When checking a CERT_PKEY structure all flags are irrelevant if the
+     * chain is invalid.
+     */
+    if (!check_flags) {
+        if (rv & CERT_PKEY_VALID) {
+            *pvalid = rv;
+        } else {
+            /* Preserve sign and explicit sign flag, clear rest */
+            *pvalid &= CERT_PKEY_EXPLICIT_SIGN | CERT_PKEY_SIGN;
+            return 0;
+        }
+    }
+    return rv;
+}
+
+/* Set validity of certificates in an SSL structure */
+void tls1_set_cert_validity(SSL *s)
+{
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_RSA);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_RSA_PSS_SIGN);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DSA_SIGN);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ECC);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_GOST01);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_GOST12_256);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_GOST12_512);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ED25519);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ED448);
+}
+
+/* User level utility function to check a chain is suitable */
+int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain)
+{
+    return tls1_check_chain(s, x, pk, chain, -1);
+}
+
+#ifndef OPENSSL_NO_DH
+DH *ssl_get_auto_dh(SSL *s)
+{
+    DH *dhp = NULL;
+    BIGNUM *p = NULL, *g = NULL;
+    int dh_secbits = 80, sec_level_bits;
+
+    if (s->cert->dh_tmp_auto != 2) {
+        if (s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL | SSL_aPSK)) {
+            if (s->s3->tmp.new_cipher->strength_bits == 256)
+                dh_secbits = 128;
+            else
+                dh_secbits = 80;
+        } else {
+            if (s->s3->tmp.cert == NULL)
+                return NULL;
+            dh_secbits = EVP_PKEY_security_bits(s->s3->tmp.cert->privatekey);
+        }
+    }
+
+    dhp = DH_new();
+    if (dhp == NULL)
+        return NULL;
+    g = BN_new();
+    if (g == NULL || !BN_set_word(g, 2)) {
+        DH_free(dhp);
+        BN_free(g);
+        return NULL;
+    }
+
+    /* Do not pick a prime that is too weak for the current security level */
+    sec_level_bits = ssl_get_security_level_bits(s, NULL, NULL);
+    if (dh_secbits < sec_level_bits)
+        dh_secbits = sec_level_bits;
+
+    if (dh_secbits >= 192)
+        p = BN_get_rfc3526_prime_8192(NULL);
+    else if (dh_secbits >= 152)
+        p = BN_get_rfc3526_prime_4096(NULL);
+    else if (dh_secbits >= 128)
+        p = BN_get_rfc3526_prime_3072(NULL);
+    else if (dh_secbits >= 112)
+        p = BN_get_rfc3526_prime_2048(NULL);
+    else
+        p = BN_get_rfc2409_prime_1024(NULL);
+    if (p == NULL || !DH_set0_pqg(dhp, p, NULL, g)) {
+        DH_free(dhp);
+        BN_free(p);
+        BN_free(g);
+        return NULL;
+    }
+    return dhp;
+}
+#endif
+
+static int ssl_security_cert_key(SSL *s, SSL_CTX *ctx, X509 *x, int op)
+{
+    int secbits = -1;
+    EVP_PKEY *pkey = X509_get0_pubkey(x);
+    if (pkey) {
+        /*
+         * If no parameters this will return -1 and fail using the default
+         * security callback for any non-zero security level. This will
+         * reject keys which omit parameters but this only affects DSA and
+         * omission of parameters is never (?) done in practice.
+         */
+        secbits = EVP_PKEY_security_bits(pkey);
+    }
+    if (s)
+        return ssl_security(s, op, secbits, 0, x);
+    else
+        return ssl_ctx_security(ctx, op, secbits, 0, x);
+}
+
+static int ssl_security_cert_sig(SSL *s, SSL_CTX *ctx, X509 *x, int op)
+{
+    /* Lookup signature algorithm digest */
+    int secbits, nid, pknid;
+    /* Don't check signature if self signed */
+    if ((X509_get_extension_flags(x) & EXFLAG_SS) != 0)
+        return 1;
+    if (!X509_get_signature_info(x, &nid, &pknid, &secbits, NULL))
+        secbits = -1;
+    /* If digest NID not defined use signature NID */
+    if (nid == NID_undef)
+        nid = pknid;
+    if (s)
+        return ssl_security(s, op, secbits, nid, x);
+    else
+        return ssl_ctx_security(ctx, op, secbits, nid, x);
+}
+
+int ssl_security_cert(SSL *s, SSL_CTX *ctx, X509 *x, int vfy, int is_ee)
+{
+    if (vfy)
+        vfy = SSL_SECOP_PEER;
+    if (is_ee) {
+        if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_EE_KEY | vfy))
+            return SSL_R_EE_KEY_TOO_SMALL;
+    } else {
+        if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_CA_KEY | vfy))
+            return SSL_R_CA_KEY_TOO_SMALL;
+    }
+    if (!ssl_security_cert_sig(s, ctx, x, SSL_SECOP_CA_MD | vfy))
+        return SSL_R_CA_MD_TOO_WEAK;
+    return 1;
+}
+
+/*
+ * Check security of a chain, if |sk| includes the end entity certificate then
+ * |x| is NULL. If |vfy| is 1 then we are verifying a peer chain and not sending
+ * one to the peer. Return values: 1 if ok otherwise error code to use
+ */
+
+int ssl_security_cert_chain(SSL *s, STACK_OF(X509) *sk, X509 *x, int vfy)
+{
+    int rv, start_idx, i;
+    if (x == NULL) {
+        x = sk_X509_value(sk, 0);
+        if (x == NULL)
+            return ERR_R_INTERNAL_ERROR;
+        start_idx = 1;
+    } else
+        start_idx = 0;
+
+    rv = ssl_security_cert(s, NULL, x, vfy, 1);
+    if (rv != 1)
+        return rv;
+
+    for (i = start_idx; i < sk_X509_num(sk); i++) {
+        x = sk_X509_value(sk, i);
+        rv = ssl_security_cert(s, NULL, x, vfy, 0);
+        if (rv != 1)
+            return rv;
+    }
+    return 1;
+}
+
+/*
+ * For TLS 1.2 servers check if we have a certificate which can be used
+ * with the signature algorithm "lu" and return index of certificate.
+ */
+
+static int tls12_get_cert_sigalg_idx(const SSL *s, const SIGALG_LOOKUP *lu)
+{
+    int sig_idx = lu->sig_idx;
+    const SSL_CERT_LOOKUP *clu = ssl_cert_lookup_by_idx(sig_idx);
+
+    /* If not recognised or not supported by cipher mask it is not suitable */
+    if (clu == NULL
+            || (clu->amask & s->s3->tmp.new_cipher->algorithm_auth) == 0
+            || (clu->nid == EVP_PKEY_RSA_PSS
+                && (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kRSA) != 0))
+        return -1;
+
+    return s->s3->tmp.valid_flags[sig_idx] & CERT_PKEY_VALID ? sig_idx : -1;
+}
+
+/*
+ * Checks the given cert against signature_algorithm_cert restrictions sent by
+ * the peer (if any) as well as whether the hash from the sigalg is usable with
+ * the key.
+ * Returns true if the cert is usable and false otherwise.
+ */
+static int check_cert_usable(SSL *s, const SIGALG_LOOKUP *sig, X509 *x,
+                             EVP_PKEY *pkey)
+{
+    const SIGALG_LOOKUP *lu;
+    int mdnid, pknid, default_mdnid;
+    size_t i;
+
+    /* If the EVP_PKEY reports a mandatory digest, allow nothing else. */
+    ERR_set_mark();
+    if (EVP_PKEY_get_default_digest_nid(pkey, &default_mdnid) == 2 &&
+        sig->hash != default_mdnid)
+            return 0;
+
+    /* If it didn't report a mandatory NID, for whatever reasons,
+     * just clear the error and allow all hashes to be used. */
+    ERR_pop_to_mark();
+
+    if (s->s3->tmp.peer_cert_sigalgs != NULL) {
+        for (i = 0; i < s->s3->tmp.peer_cert_sigalgslen; i++) {
+            lu = tls1_lookup_sigalg(s->s3->tmp.peer_cert_sigalgs[i]);
+            if (lu == NULL
+                || !X509_get_signature_info(x, &mdnid, &pknid, NULL, NULL))
+                continue;
+            /*
+             * TODO this does not differentiate between the
+             * rsa_pss_pss_* and rsa_pss_rsae_* schemes since we do not
+             * have a chain here that lets us look at the key OID in the
+             * signing certificate.
+             */
+            if (mdnid == lu->hash && pknid == lu->sig)
+                return 1;
+        }
+        return 0;
+    }
+    return 1;
+}
+
+/*
+ * Returns true if |s| has a usable certificate configured for use
+ * with signature scheme |sig|.
+ * "Usable" includes a check for presence as well as applying
+ * the signature_algorithm_cert restrictions sent by the peer (if any).
+ * Returns false if no usable certificate is found.
+ */
+static int has_usable_cert(SSL *s, const SIGALG_LOOKUP *sig, int idx)
+{
+    /* TLS 1.2 callers can override sig->sig_idx, but not TLS 1.3 callers. */
+    if (idx == -1)
+        idx = sig->sig_idx;
+    if (!ssl_has_cert(s, idx))
+        return 0;
+
+    return check_cert_usable(s, sig, s->cert->pkeys[idx].x509,
+                             s->cert->pkeys[idx].privatekey);
+}
+
+/*
+ * Returns true if the supplied cert |x| and key |pkey| is usable with the
+ * specified signature scheme |sig|, or false otherwise.
+ */
+static int is_cert_usable(SSL *s, const SIGALG_LOOKUP *sig, X509 *x,
+                          EVP_PKEY *pkey)
+{
+    size_t idx;
+
+    if (ssl_cert_lookup_by_pkey(pkey, &idx) == NULL)
+        return 0;
+
+    /* Check the key is consistent with the sig alg */
+    if ((int)idx != sig->sig_idx)
+        return 0;
+
+    return check_cert_usable(s, sig, x, pkey);
+}
+
+/*
+ * Find a signature scheme that works with the supplied certificate |x| and key
+ * |pkey|. |x| and |pkey| may be NULL in which case we additionally look at our
+ * available certs/keys to find one that works.
+ */
+static const SIGALG_LOOKUP *find_sig_alg(SSL *s, X509 *x, EVP_PKEY *pkey)
+{
+    const SIGALG_LOOKUP *lu = NULL;
+    size_t i;
+#ifndef OPENSSL_NO_EC
+    int curve = -1;
+#endif
+    EVP_PKEY *tmppkey;
+
+    /* Look for a shared sigalgs matching possible certificates */
+    for (i = 0; i < s->shared_sigalgslen; i++) {
+        lu = s->shared_sigalgs[i];
+
+        /* Skip SHA1, SHA224, DSA and RSA if not PSS */
+        if (lu->hash == NID_sha1
+            || lu->hash == NID_sha224
+            || lu->sig == EVP_PKEY_DSA
+            || lu->sig == EVP_PKEY_RSA)
+            continue;
+        /* Check that we have a cert, and signature_algorithms_cert */
+        if (!tls1_lookup_md(lu, NULL))
+            continue;
+        if ((pkey == NULL && !has_usable_cert(s, lu, -1))
+                || (pkey != NULL && !is_cert_usable(s, lu, x, pkey)))
+            continue;
+
+        tmppkey = (pkey != NULL) ? pkey
+                                 : s->cert->pkeys[lu->sig_idx].privatekey;
+
+        if (lu->sig == EVP_PKEY_EC) {
+#ifndef OPENSSL_NO_EC
+            if (curve == -1) {
+                EC_KEY *ec = EVP_PKEY_get0_EC_KEY(tmppkey);
+                curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
+            }
+            if (lu->curve != NID_undef && curve != lu->curve)
+                continue;
+#else
+            continue;
+#endif
+        } else if (lu->sig == EVP_PKEY_RSA_PSS) {
+            /* validate that key is large enough for the signature algorithm */
+            if (!rsa_pss_check_min_key_size(EVP_PKEY_get0(tmppkey), lu))
+                continue;
+        }
+        break;
+    }
+
+    if (i == s->shared_sigalgslen)
+        return NULL;
+
+    return lu;
+}
+
+/*
+ * Choose an appropriate signature algorithm based on available certificates
+ * Sets chosen certificate and signature algorithm.
+ *
+ * For servers if we fail to find a required certificate it is a fatal error,
+ * an appropriate error code is set and a TLS alert is sent.
+ *
+ * For clients fatalerrs is set to 0. If a certificate is not suitable it is not
+ * a fatal error: we will either try another certificate or not present one
+ * to the server. In this case no error is set.
+ */
+int tls_choose_sigalg(SSL *s, int fatalerrs)
+{
+    const SIGALG_LOOKUP *lu = NULL;
+    int sig_idx = -1;
+
+    s->s3->tmp.cert = NULL;
+    s->s3->tmp.sigalg = NULL;
+
+    if (SSL_IS_TLS13(s)) {
+        lu = find_sig_alg(s, NULL, NULL);
+        if (lu == NULL) {
+            if (!fatalerrs)
+                return 1;
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS_CHOOSE_SIGALG,
+                     SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM);
+            return 0;
+        }
+    } else {
+        /* If ciphersuite doesn't require a cert nothing to do */
+        if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aCERT))
+            return 1;
+        if (!s->server && !ssl_has_cert(s, s->cert->key - s->cert->pkeys))
+                return 1;
+
+        if (SSL_USE_SIGALGS(s)) {
+            size_t i;
+            if (s->s3->tmp.peer_sigalgs != NULL) {
+#ifndef OPENSSL_NO_EC
+                int curve;
+
+                /* For Suite B need to match signature algorithm to curve */
+                if (tls1_suiteb(s)) {
+                    EC_KEY *ec = EVP_PKEY_get0_EC_KEY(s->cert->pkeys[SSL_PKEY_ECC].privatekey);
+                    curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
+                } else {
+                    curve = -1;
+                }
+#endif
+
+                /*
+                 * Find highest preference signature algorithm matching
+                 * cert type
+                 */
+                for (i = 0; i < s->shared_sigalgslen; i++) {
+                    lu = s->shared_sigalgs[i];
+
+                    if (s->server) {
+                        if ((sig_idx = tls12_get_cert_sigalg_idx(s, lu)) == -1)
+                            continue;
+                    } else {
+                        int cc_idx = s->cert->key - s->cert->pkeys;
+
+                        sig_idx = lu->sig_idx;
+                        if (cc_idx != sig_idx)
+                            continue;
+                    }
+                    /* Check that we have a cert, and sig_algs_cert */
+                    if (!has_usable_cert(s, lu, sig_idx))
+                        continue;
+                    if (lu->sig == EVP_PKEY_RSA_PSS) {
+                        /* validate that key is large enough for the signature algorithm */
+                        EVP_PKEY *pkey = s->cert->pkeys[sig_idx].privatekey;
+
+                        if (!rsa_pss_check_min_key_size(EVP_PKEY_get0(pkey), lu))
+                            continue;
+                    }
+#ifndef OPENSSL_NO_EC
+                    if (curve == -1 || lu->curve == curve)
+#endif
+                        break;
+                }
+#ifndef OPENSSL_NO_GOST
+                /*
+                 * Some Windows-based implementations do not send GOST algorithms indication
+                 * in supported_algorithms extension, so when we have GOST-based ciphersuite,
+                 * we have to assume GOST support.
+                 */
+                if (i == s->shared_sigalgslen && s->s3->tmp.new_cipher->algorithm_auth & (SSL_aGOST01 | SSL_aGOST12)) {
+                  if ((lu = tls1_get_legacy_sigalg(s, -1)) == NULL) {
+                    if (!fatalerrs)
+                      return 1;
+                    SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                             SSL_F_TLS_CHOOSE_SIGALG,
+                             SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM);
+                    return 0;
+                  } else {
+                    i = 0;
+                    sig_idx = lu->sig_idx;
+                  }
+                }
+#endif
+                if (i == s->shared_sigalgslen) {
+                    if (!fatalerrs)
+                        return 1;
+                    SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                             SSL_F_TLS_CHOOSE_SIGALG,
+                             SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM);
+                    return 0;
+                }
+            } else {
+                /*
+                 * If we have no sigalg use defaults
+                 */
+                const uint16_t *sent_sigs;
+                size_t sent_sigslen;
+
+                if ((lu = tls1_get_legacy_sigalg(s, -1)) == NULL) {
+                    if (!fatalerrs)
+                        return 1;
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CHOOSE_SIGALG,
+                             ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+
+                /* Check signature matches a type we sent */
+                sent_sigslen = tls12_get_psigalgs(s, 1, &sent_sigs);
+                for (i = 0; i < sent_sigslen; i++, sent_sigs++) {
+                    if (lu->sigalg == *sent_sigs
+                            && has_usable_cert(s, lu, lu->sig_idx))
+                        break;
+                }
+                if (i == sent_sigslen) {
+                    if (!fatalerrs)
+                        return 1;
+                    SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                             SSL_F_TLS_CHOOSE_SIGALG,
+                             SSL_R_WRONG_SIGNATURE_TYPE);
+                    return 0;
+                }
+            }
+        } else {
+            if ((lu = tls1_get_legacy_sigalg(s, -1)) == NULL) {
+                if (!fatalerrs)
+                    return 1;
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CHOOSE_SIGALG,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
+    }
+    if (sig_idx == -1)
+        sig_idx = lu->sig_idx;
+    s->s3->tmp.cert = &s->cert->pkeys[sig_idx];
+    s->cert->key = s->s3->tmp.cert;
+    s->s3->tmp.sigalg = lu;
+    return 1;
+}
+
+int SSL_CTX_set_tlsext_max_fragment_length(SSL_CTX *ctx, uint8_t mode)
+{
+    if (mode != TLSEXT_max_fragment_length_DISABLED
+            && !IS_MAX_FRAGMENT_LENGTH_EXT_VALID(mode)) {
+        SSLerr(SSL_F_SSL_CTX_SET_TLSEXT_MAX_FRAGMENT_LENGTH,
+               SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH);
+        return 0;
+    }
+
+    ctx->ext.max_fragment_len_mode = mode;
+    return 1;
+}
+
+int SSL_set_tlsext_max_fragment_length(SSL *ssl, uint8_t mode)
+{
+    if (mode != TLSEXT_max_fragment_length_DISABLED
+            && !IS_MAX_FRAGMENT_LENGTH_EXT_VALID(mode)) {
+        SSLerr(SSL_F_SSL_SET_TLSEXT_MAX_FRAGMENT_LENGTH,
+               SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH);
+        return 0;
+    }
+
+    ssl->ext.max_fragment_len_mode = mode;
+    return 1;
+}
+
+uint8_t SSL_SESSION_get_max_fragment_length(const SSL_SESSION *session)
+{
+    return session->ext.max_fragment_len_mode;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/t1_trce.c b/ap/lib/libssl/openssl-1.1.1o/ssl/t1_trce.c
new file mode 100644
index 0000000..e2c397b
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/t1_trce.c
@@ -0,0 +1,1578 @@
+/*
+ * Copyright 2012-2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "ssl_local.h"
+
+#ifndef OPENSSL_NO_SSL_TRACE
+
+/* Packet trace support for OpenSSL */
+
+typedef struct {
+    int num;
+    const char *name;
+} ssl_trace_tbl;
+
+# define ssl_trace_str(val, tbl) \
+    do_ssl_trace_str(val, tbl, OSSL_NELEM(tbl))
+
+# define ssl_trace_list(bio, indent, msg, msglen, value, table) \
+    do_ssl_trace_list(bio, indent, msg, msglen, value, \
+                      table, OSSL_NELEM(table))
+
+static const char *do_ssl_trace_str(int val, const ssl_trace_tbl *tbl,
+                                    size_t ntbl)
+{
+    size_t i;
+
+    for (i = 0; i < ntbl; i++, tbl++) {
+        if (tbl->num == val)
+            return tbl->name;
+    }
+    return "UNKNOWN";
+}
+
+static int do_ssl_trace_list(BIO *bio, int indent,
+                             const unsigned char *msg, size_t msglen,
+                             size_t vlen, const ssl_trace_tbl *tbl, size_t ntbl)
+{
+    int val;
+
+    if (msglen % vlen)
+        return 0;
+    while (msglen) {
+        val = msg[0];
+        if (vlen == 2)
+            val = (val << 8) | msg[1];
+        BIO_indent(bio, indent, 80);
+        BIO_printf(bio, "%s (%d)\n", do_ssl_trace_str(val, tbl, ntbl), val);
+        msg += vlen;
+        msglen -= vlen;
+    }
+    return 1;
+}
+
+/* Version number */
+
+static const ssl_trace_tbl ssl_version_tbl[] = {
+    {SSL3_VERSION, "SSL 3.0"},
+    {TLS1_VERSION, "TLS 1.0"},
+    {TLS1_1_VERSION, "TLS 1.1"},
+    {TLS1_2_VERSION, "TLS 1.2"},
+    {TLS1_3_VERSION, "TLS 1.3"},
+    {DTLS1_VERSION, "DTLS 1.0"},
+    {DTLS1_2_VERSION, "DTLS 1.2"},
+    {DTLS1_BAD_VER, "DTLS 1.0 (bad)"}
+};
+
+static const ssl_trace_tbl ssl_content_tbl[] = {
+    {SSL3_RT_CHANGE_CIPHER_SPEC, "ChangeCipherSpec"},
+    {SSL3_RT_ALERT, "Alert"},
+    {SSL3_RT_HANDSHAKE, "Handshake"},
+    {SSL3_RT_APPLICATION_DATA, "ApplicationData"},
+};
+
+/* Handshake types, sorted by ascending id  */
+static const ssl_trace_tbl ssl_handshake_tbl[] = {
+    {SSL3_MT_HELLO_REQUEST, "HelloRequest"},
+    {SSL3_MT_CLIENT_HELLO, "ClientHello"},
+    {SSL3_MT_SERVER_HELLO, "ServerHello"},
+    {DTLS1_MT_HELLO_VERIFY_REQUEST, "HelloVerifyRequest"},
+    {SSL3_MT_NEWSESSION_TICKET, "NewSessionTicket"},
+    {SSL3_MT_END_OF_EARLY_DATA, "EndOfEarlyData"},
+    {SSL3_MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions"},
+    {SSL3_MT_CERTIFICATE, "Certificate"},
+    {SSL3_MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange"},
+    {SSL3_MT_CERTIFICATE_REQUEST, "CertificateRequest"},
+    {SSL3_MT_SERVER_DONE, "ServerHelloDone"},
+    {SSL3_MT_CERTIFICATE_VERIFY, "CertificateVerify"},
+    {SSL3_MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange"},
+    {SSL3_MT_FINISHED, "Finished"},
+    {SSL3_MT_CERTIFICATE_URL, "CertificateUrl"},
+    {SSL3_MT_CERTIFICATE_STATUS, "CertificateStatus"},
+    {SSL3_MT_SUPPLEMENTAL_DATA, "SupplementalData"},
+    {SSL3_MT_KEY_UPDATE, "KeyUpdate"},
+# ifndef OPENSSL_NO_NEXTPROTONEG
+    {SSL3_MT_NEXT_PROTO, "NextProto"},
+# endif
+    {SSL3_MT_MESSAGE_HASH, "MessageHash"}
+};
+
+/* Cipher suites */
+static const ssl_trace_tbl ssl_ciphers_tbl[] = {
+    {0x0000, "TLS_NULL_WITH_NULL_NULL"},
+    {0x0001, "TLS_RSA_WITH_NULL_MD5"},
+    {0x0002, "TLS_RSA_WITH_NULL_SHA"},
+    {0x0003, "TLS_RSA_EXPORT_WITH_RC4_40_MD5"},
+    {0x0004, "TLS_RSA_WITH_RC4_128_MD5"},
+    {0x0005, "TLS_RSA_WITH_RC4_128_SHA"},
+    {0x0006, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"},
+    {0x0007, "TLS_RSA_WITH_IDEA_CBC_SHA"},
+    {0x0008, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"},
+    {0x0009, "TLS_RSA_WITH_DES_CBC_SHA"},
+    {0x000A, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
+    {0x000B, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"},
+    {0x000C, "TLS_DH_DSS_WITH_DES_CBC_SHA"},
+    {0x000D, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"},
+    {0x000E, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"},
+    {0x000F, "TLS_DH_RSA_WITH_DES_CBC_SHA"},
+    {0x0010, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"},
+    {0x0011, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"},
+    {0x0012, "TLS_DHE_DSS_WITH_DES_CBC_SHA"},
+    {0x0013, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"},
+    {0x0014, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"},
+    {0x0015, "TLS_DHE_RSA_WITH_DES_CBC_SHA"},
+    {0x0016, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"},
+    {0x0017, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"},
+    {0x0018, "TLS_DH_anon_WITH_RC4_128_MD5"},
+    {0x0019, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"},
+    {0x001A, "TLS_DH_anon_WITH_DES_CBC_SHA"},
+    {0x001B, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"},
+    {0x001D, "SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA"},
+    {0x001E, "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA"},
+    {0x001F, "TLS_KRB5_WITH_3DES_EDE_CBC_SHA"},
+    {0x0020, "TLS_KRB5_WITH_RC4_128_SHA"},
+    {0x0021, "TLS_KRB5_WITH_IDEA_CBC_SHA"},
+    {0x0022, "TLS_KRB5_WITH_DES_CBC_MD5"},
+    {0x0023, "TLS_KRB5_WITH_3DES_EDE_CBC_MD5"},
+    {0x0024, "TLS_KRB5_WITH_RC4_128_MD5"},
+    {0x0025, "TLS_KRB5_WITH_IDEA_CBC_MD5"},
+    {0x0026, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA"},
+    {0x0027, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA"},
+    {0x0028, "TLS_KRB5_EXPORT_WITH_RC4_40_SHA"},
+    {0x0029, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5"},
+    {0x002A, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5"},
+    {0x002B, "TLS_KRB5_EXPORT_WITH_RC4_40_MD5"},
+    {0x002C, "TLS_PSK_WITH_NULL_SHA"},
+    {0x002D, "TLS_DHE_PSK_WITH_NULL_SHA"},
+    {0x002E, "TLS_RSA_PSK_WITH_NULL_SHA"},
+    {0x002F, "TLS_RSA_WITH_AES_128_CBC_SHA"},
+    {0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"},
+    {0x0031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"},
+    {0x0032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"},
+    {0x0033, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"},
+    {0x0034, "TLS_DH_anon_WITH_AES_128_CBC_SHA"},
+    {0x0035, "TLS_RSA_WITH_AES_256_CBC_SHA"},
+    {0x0036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"},
+    {0x0037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"},
+    {0x0038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"},
+    {0x0039, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
+    {0x003A, "TLS_DH_anon_WITH_AES_256_CBC_SHA"},
+    {0x003B, "TLS_RSA_WITH_NULL_SHA256"},
+    {0x003C, "TLS_RSA_WITH_AES_128_CBC_SHA256"},
+    {0x003D, "TLS_RSA_WITH_AES_256_CBC_SHA256"},
+    {0x003E, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"},
+    {0x003F, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"},
+    {0x0040, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"},
+    {0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA"},
+    {0x0042, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA"},
+    {0x0043, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA"},
+    {0x0044, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA"},
+    {0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA"},
+    {0x0046, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA"},
+    {0x0067, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"},
+    {0x0068, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"},
+    {0x0069, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"},
+    {0x006A, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"},
+    {0x006B, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
+    {0x006C, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"},
+    {0x006D, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"},
+    {0x0081, "TLS_GOSTR341001_WITH_28147_CNT_IMIT"},
+    {0x0083, "TLS_GOSTR341001_WITH_NULL_GOSTR3411"},
+    {0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA"},
+    {0x0085, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA"},
+    {0x0086, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA"},
+    {0x0087, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA"},
+    {0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA"},
+    {0x0089, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA"},
+    {0x008A, "TLS_PSK_WITH_RC4_128_SHA"},
+    {0x008B, "TLS_PSK_WITH_3DES_EDE_CBC_SHA"},
+    {0x008C, "TLS_PSK_WITH_AES_128_CBC_SHA"},
+    {0x008D, "TLS_PSK_WITH_AES_256_CBC_SHA"},
+    {0x008E, "TLS_DHE_PSK_WITH_RC4_128_SHA"},
+    {0x008F, "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"},
+    {0x0090, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"},
+    {0x0091, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"},
+    {0x0092, "TLS_RSA_PSK_WITH_RC4_128_SHA"},
+    {0x0093, "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"},
+    {0x0094, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"},
+    {0x0095, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"},
+    {0x0096, "TLS_RSA_WITH_SEED_CBC_SHA"},
+    {0x0097, "TLS_DH_DSS_WITH_SEED_CBC_SHA"},
+    {0x0098, "TLS_DH_RSA_WITH_SEED_CBC_SHA"},
+    {0x0099, "TLS_DHE_DSS_WITH_SEED_CBC_SHA"},
+    {0x009A, "TLS_DHE_RSA_WITH_SEED_CBC_SHA"},
+    {0x009B, "TLS_DH_anon_WITH_SEED_CBC_SHA"},
+    {0x009C, "TLS_RSA_WITH_AES_128_GCM_SHA256"},
+    {0x009D, "TLS_RSA_WITH_AES_256_GCM_SHA384"},
+    {0x009E, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"},
+    {0x009F, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"},
+    {0x00A0, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"},
+    {0x00A1, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"},
+    {0x00A2, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"},
+    {0x00A3, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"},
+    {0x00A4, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"},
+    {0x00A5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"},
+    {0x00A6, "TLS_DH_anon_WITH_AES_128_GCM_SHA256"},
+    {0x00A7, "TLS_DH_anon_WITH_AES_256_GCM_SHA384"},
+    {0x00A8, "TLS_PSK_WITH_AES_128_GCM_SHA256"},
+    {0x00A9, "TLS_PSK_WITH_AES_256_GCM_SHA384"},
+    {0x00AA, "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256"},
+    {0x00AB, "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384"},
+    {0x00AC, "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"},
+    {0x00AD, "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384"},
+    {0x00AE, "TLS_PSK_WITH_AES_128_CBC_SHA256"},
+    {0x00AF, "TLS_PSK_WITH_AES_256_CBC_SHA384"},
+    {0x00B0, "TLS_PSK_WITH_NULL_SHA256"},
+    {0x00B1, "TLS_PSK_WITH_NULL_SHA384"},
+    {0x00B2, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256"},
+    {0x00B3, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384"},
+    {0x00B4, "TLS_DHE_PSK_WITH_NULL_SHA256"},
+    {0x00B5, "TLS_DHE_PSK_WITH_NULL_SHA384"},
+    {0x00B6, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"},
+    {0x00B7, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"},
+    {0x00B8, "TLS_RSA_PSK_WITH_NULL_SHA256"},
+    {0x00B9, "TLS_RSA_PSK_WITH_NULL_SHA384"},
+    {0x00BA, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0x00BB, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0x00BC, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0x00BD, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0x00BE, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0x00BF, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0x00C0, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256"},
+    {0x00C1, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256"},
+    {0x00C2, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256"},
+    {0x00C3, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256"},
+    {0x00C4, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256"},
+    {0x00C5, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256"},
+    {0x00FF, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"},
+    {0x5600, "TLS_FALLBACK_SCSV"},
+    {0xC001, "TLS_ECDH_ECDSA_WITH_NULL_SHA"},
+    {0xC002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"},
+    {0xC003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"},
+    {0xC004, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"},
+    {0xC005, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"},
+    {0xC006, "TLS_ECDHE_ECDSA_WITH_NULL_SHA"},
+    {0xC007, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"},
+    {0xC008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"},
+    {0xC009, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"},
+    {0xC00A, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"},
+    {0xC00B, "TLS_ECDH_RSA_WITH_NULL_SHA"},
+    {0xC00C, "TLS_ECDH_RSA_WITH_RC4_128_SHA"},
+    {0xC00D, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"},
+    {0xC00E, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"},
+    {0xC00F, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"},
+    {0xC010, "TLS_ECDHE_RSA_WITH_NULL_SHA"},
+    {0xC011, "TLS_ECDHE_RSA_WITH_RC4_128_SHA"},
+    {0xC012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"},
+    {0xC013, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"},
+    {0xC014, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
+    {0xC015, "TLS_ECDH_anon_WITH_NULL_SHA"},
+    {0xC016, "TLS_ECDH_anon_WITH_RC4_128_SHA"},
+    {0xC017, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"},
+    {0xC018, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"},
+    {0xC019, "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"},
+    {0xC01A, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA"},
+    {0xC01B, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA"},
+    {0xC01C, "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA"},
+    {0xC01D, "TLS_SRP_SHA_WITH_AES_128_CBC_SHA"},
+    {0xC01E, "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA"},
+    {0xC01F, "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA"},
+    {0xC020, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA"},
+    {0xC021, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA"},
+    {0xC022, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA"},
+    {0xC023, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"},
+    {0xC024, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"},
+    {0xC025, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"},
+    {0xC026, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"},
+    {0xC027, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"},
+    {0xC028, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"},
+    {0xC029, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"},
+    {0xC02A, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"},
+    {0xC02B, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"},
+    {0xC02C, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"},
+    {0xC02D, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"},
+    {0xC02E, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"},
+    {0xC02F, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"},
+    {0xC030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"},
+    {0xC031, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"},
+    {0xC032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"},
+    {0xC033, "TLS_ECDHE_PSK_WITH_RC4_128_SHA"},
+    {0xC034, "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA"},
+    {0xC035, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA"},
+    {0xC036, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA"},
+    {0xC037, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256"},
+    {0xC038, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384"},
+    {0xC039, "TLS_ECDHE_PSK_WITH_NULL_SHA"},
+    {0xC03A, "TLS_ECDHE_PSK_WITH_NULL_SHA256"},
+    {0xC03B, "TLS_ECDHE_PSK_WITH_NULL_SHA384"},
+    {0xC03C, "TLS_RSA_WITH_ARIA_128_CBC_SHA256"},
+    {0xC03D, "TLS_RSA_WITH_ARIA_256_CBC_SHA384"},
+    {0xC03E, "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256"},
+    {0xC03F, "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384"},
+    {0xC040, "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256"},
+    {0xC041, "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384"},
+    {0xC042, "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256"},
+    {0xC043, "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384"},
+    {0xC044, "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256"},
+    {0xC045, "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384"},
+    {0xC046, "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256"},
+    {0xC047, "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384"},
+    {0xC048, "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256"},
+    {0xC049, "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384"},
+    {0xC04A, "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256"},
+    {0xC04B, "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384"},
+    {0xC04C, "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256"},
+    {0xC04D, "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384"},
+    {0xC04E, "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256"},
+    {0xC04F, "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384"},
+    {0xC050, "TLS_RSA_WITH_ARIA_128_GCM_SHA256"},
+    {0xC051, "TLS_RSA_WITH_ARIA_256_GCM_SHA384"},
+    {0xC052, "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256"},
+    {0xC053, "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384"},
+    {0xC054, "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256"},
+    {0xC055, "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384"},
+    {0xC056, "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256"},
+    {0xC057, "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384"},
+    {0xC058, "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256"},
+    {0xC059, "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384"},
+    {0xC05A, "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256"},
+    {0xC05B, "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384"},
+    {0xC05C, "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256"},
+    {0xC05D, "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384"},
+    {0xC05E, "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256"},
+    {0xC05F, "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384"},
+    {0xC060, "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256"},
+    {0xC061, "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384"},
+    {0xC062, "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256"},
+    {0xC063, "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384"},
+    {0xC064, "TLS_PSK_WITH_ARIA_128_CBC_SHA256"},
+    {0xC065, "TLS_PSK_WITH_ARIA_256_CBC_SHA384"},
+    {0xC066, "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256"},
+    {0xC067, "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384"},
+    {0xC068, "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256"},
+    {0xC069, "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384"},
+    {0xC06A, "TLS_PSK_WITH_ARIA_128_GCM_SHA256"},
+    {0xC06B, "TLS_PSK_WITH_ARIA_256_GCM_SHA384"},
+    {0xC06C, "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256"},
+    {0xC06D, "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384"},
+    {0xC06E, "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256"},
+    {0xC06F, "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384"},
+    {0xC070, "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256"},
+    {0xC071, "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384"},
+    {0xC072, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0xC073, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"},
+    {0xC074, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0xC075, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"},
+    {0xC076, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0xC077, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384"},
+    {0xC078, "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0xC079, "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384"},
+    {0xC07A, "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256"},
+    {0xC07B, "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384"},
+    {0xC07C, "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"},
+    {0xC07D, "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"},
+    {0xC07E, "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256"},
+    {0xC07F, "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384"},
+    {0xC080, "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256"},
+    {0xC081, "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384"},
+    {0xC082, "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256"},
+    {0xC083, "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384"},
+    {0xC084, "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256"},
+    {0xC085, "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384"},
+    {0xC086, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"},
+    {0xC087, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"},
+    {0xC088, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"},
+    {0xC089, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"},
+    {0xC08A, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"},
+    {0xC08B, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"},
+    {0xC08C, "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256"},
+    {0xC08D, "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384"},
+    {0xC08E, "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256"},
+    {0xC08F, "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384"},
+    {0xC090, "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256"},
+    {0xC091, "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384"},
+    {0xC092, "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256"},
+    {0xC093, "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384"},
+    {0xC094, "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0xC095, "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384"},
+    {0xC096, "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0xC097, "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"},
+    {0xC098, "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0xC099, "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384"},
+    {0xC09A, "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"},
+    {0xC09B, "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"},
+    {0xC09C, "TLS_RSA_WITH_AES_128_CCM"},
+    {0xC09D, "TLS_RSA_WITH_AES_256_CCM"},
+    {0xC09E, "TLS_DHE_RSA_WITH_AES_128_CCM"},
+    {0xC09F, "TLS_DHE_RSA_WITH_AES_256_CCM"},
+    {0xC0A0, "TLS_RSA_WITH_AES_128_CCM_8"},
+    {0xC0A1, "TLS_RSA_WITH_AES_256_CCM_8"},
+    {0xC0A2, "TLS_DHE_RSA_WITH_AES_128_CCM_8"},
+    {0xC0A3, "TLS_DHE_RSA_WITH_AES_256_CCM_8"},
+    {0xC0A4, "TLS_PSK_WITH_AES_128_CCM"},
+    {0xC0A5, "TLS_PSK_WITH_AES_256_CCM"},
+    {0xC0A6, "TLS_DHE_PSK_WITH_AES_128_CCM"},
+    {0xC0A7, "TLS_DHE_PSK_WITH_AES_256_CCM"},
+    {0xC0A8, "TLS_PSK_WITH_AES_128_CCM_8"},
+    {0xC0A9, "TLS_PSK_WITH_AES_256_CCM_8"},
+    {0xC0AA, "TLS_PSK_DHE_WITH_AES_128_CCM_8"},
+    {0xC0AB, "TLS_PSK_DHE_WITH_AES_256_CCM_8"},
+    {0xC0AC, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM"},
+    {0xC0AD, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM"},
+    {0xC0AE, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"},
+    {0xC0AF, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8"},
+    {0xCCA8, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"},
+    {0xCCA9, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"},
+    {0xCCAA, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256"},
+    {0xCCAB, "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256"},
+    {0xCCAC, "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256"},
+    {0xCCAD, "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256"},
+    {0xCCAE, "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256"},
+    {0x1301, "TLS_AES_128_GCM_SHA256"},
+    {0x1302, "TLS_AES_256_GCM_SHA384"},
+    {0x1303, "TLS_CHACHA20_POLY1305_SHA256"},
+    {0x1304, "TLS_AES_128_CCM_SHA256"},
+    {0x1305, "TLS_AES_128_CCM_8_SHA256"},
+    {0xFEFE, "SSL_RSA_FIPS_WITH_DES_CBC_SHA"},
+    {0xFEFF, "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA"},
+    {0xFF85, "GOST2012-GOST8912-GOST8912"},
+    {0xFF87, "GOST2012-NULL-GOST12"},
+};
+
+/* Compression methods */
+static const ssl_trace_tbl ssl_comp_tbl[] = {
+    {0x0000, "No Compression"},
+    {0x0001, "Zlib Compression"}
+};
+
+/* Extensions sorted by ascending id */
+static const ssl_trace_tbl ssl_exts_tbl[] = {
+    {TLSEXT_TYPE_server_name, "server_name"},
+    {TLSEXT_TYPE_max_fragment_length, "max_fragment_length"},
+    {TLSEXT_TYPE_client_certificate_url, "client_certificate_url"},
+    {TLSEXT_TYPE_trusted_ca_keys, "trusted_ca_keys"},
+    {TLSEXT_TYPE_truncated_hmac, "truncated_hmac"},
+    {TLSEXT_TYPE_status_request, "status_request"},
+    {TLSEXT_TYPE_user_mapping, "user_mapping"},
+    {TLSEXT_TYPE_client_authz, "client_authz"},
+    {TLSEXT_TYPE_server_authz, "server_authz"},
+    {TLSEXT_TYPE_cert_type, "cert_type"},
+    {TLSEXT_TYPE_supported_groups, "supported_groups"},
+    {TLSEXT_TYPE_ec_point_formats, "ec_point_formats"},
+    {TLSEXT_TYPE_srp, "srp"},
+    {TLSEXT_TYPE_signature_algorithms, "signature_algorithms"},
+    {TLSEXT_TYPE_use_srtp, "use_srtp"},
+    {TLSEXT_TYPE_heartbeat, "tls_heartbeat"},
+    {TLSEXT_TYPE_application_layer_protocol_negotiation,
+     "application_layer_protocol_negotiation"},
+    {TLSEXT_TYPE_signed_certificate_timestamp, "signed_certificate_timestamps"},
+    {TLSEXT_TYPE_padding, "padding"},
+    {TLSEXT_TYPE_encrypt_then_mac, "encrypt_then_mac"},
+    {TLSEXT_TYPE_extended_master_secret, "extended_master_secret"},
+    {TLSEXT_TYPE_session_ticket, "session_ticket"},
+    {TLSEXT_TYPE_psk, "psk"},
+    {TLSEXT_TYPE_early_data, "early_data"},
+    {TLSEXT_TYPE_supported_versions, "supported_versions"},
+    {TLSEXT_TYPE_cookie, "cookie_ext"},
+    {TLSEXT_TYPE_psk_kex_modes, "psk_key_exchange_modes"},
+    {TLSEXT_TYPE_certificate_authorities, "certificate_authorities"},
+    {TLSEXT_TYPE_post_handshake_auth, "post_handshake_auth"},
+    {TLSEXT_TYPE_signature_algorithms_cert, "signature_algorithms_cert"},
+    {TLSEXT_TYPE_key_share, "key_share"},
+    {TLSEXT_TYPE_renegotiate, "renegotiate"},
+# ifndef OPENSSL_NO_NEXTPROTONEG
+    {TLSEXT_TYPE_next_proto_neg, "next_proto_neg"},
+# endif
+};
+
+static const ssl_trace_tbl ssl_groups_tbl[] = {
+    {1, "sect163k1 (K-163)"},
+    {2, "sect163r1"},
+    {3, "sect163r2 (B-163)"},
+    {4, "sect193r1"},
+    {5, "sect193r2"},
+    {6, "sect233k1 (K-233)"},
+    {7, "sect233r1 (B-233)"},
+    {8, "sect239k1"},
+    {9, "sect283k1 (K-283)"},
+    {10, "sect283r1 (B-283)"},
+    {11, "sect409k1 (K-409)"},
+    {12, "sect409r1 (B-409)"},
+    {13, "sect571k1 (K-571)"},
+    {14, "sect571r1 (B-571)"},
+    {15, "secp160k1"},
+    {16, "secp160r1"},
+    {17, "secp160r2"},
+    {18, "secp192k1"},
+    {19, "secp192r1 (P-192)"},
+    {20, "secp224k1"},
+    {21, "secp224r1 (P-224)"},
+    {22, "secp256k1"},
+    {23, "secp256r1 (P-256)"},
+    {24, "secp384r1 (P-384)"},
+    {25, "secp521r1 (P-521)"},
+    {26, "brainpoolP256r1"},
+    {27, "brainpoolP384r1"},
+    {28, "brainpoolP512r1"},
+    {29, "ecdh_x25519"},
+    {30, "ecdh_x448"},
+    {256, "ffdhe2048"},
+    {257, "ffdhe3072"},
+    {258, "ffdhe4096"},
+    {259, "ffdhe6144"},
+    {260, "ffdhe8192"},
+    {0xFF01, "arbitrary_explicit_prime_curves"},
+    {0xFF02, "arbitrary_explicit_char2_curves"}
+};
+
+static const ssl_trace_tbl ssl_point_tbl[] = {
+    {0, "uncompressed"},
+    {1, "ansiX962_compressed_prime"},
+    {2, "ansiX962_compressed_char2"}
+};
+
+static const ssl_trace_tbl ssl_mfl_tbl[] = {
+    {0, "disabled"},
+    {1, "max_fragment_length := 2^9 (512 bytes)"},
+    {2, "max_fragment_length := 2^10 (1024 bytes)"},
+    {3, "max_fragment_length := 2^11 (2048 bytes)"},
+    {4, "max_fragment_length := 2^12 (4096 bytes)"}
+};
+
+static const ssl_trace_tbl ssl_sigalg_tbl[] = {
+    {TLSEXT_SIGALG_ecdsa_secp256r1_sha256, "ecdsa_secp256r1_sha256"},
+    {TLSEXT_SIGALG_ecdsa_secp384r1_sha384, "ecdsa_secp384r1_sha384"},
+    {TLSEXT_SIGALG_ecdsa_secp521r1_sha512, "ecdsa_secp521r1_sha512"},
+    {TLSEXT_SIGALG_ecdsa_sha224, "ecdsa_sha224"},
+    {TLSEXT_SIGALG_ed25519, "ed25519"},
+    {TLSEXT_SIGALG_ed448, "ed448"},
+    {TLSEXT_SIGALG_ecdsa_sha1, "ecdsa_sha1"},
+    {TLSEXT_SIGALG_rsa_pss_rsae_sha256, "rsa_pss_rsae_sha256"},
+    {TLSEXT_SIGALG_rsa_pss_rsae_sha384, "rsa_pss_rsae_sha384"},
+    {TLSEXT_SIGALG_rsa_pss_rsae_sha512, "rsa_pss_rsae_sha512"},
+    {TLSEXT_SIGALG_rsa_pss_pss_sha256, "rsa_pss_pss_sha256"},
+    {TLSEXT_SIGALG_rsa_pss_pss_sha384, "rsa_pss_pss_sha384"},
+    {TLSEXT_SIGALG_rsa_pss_pss_sha512, "rsa_pss_pss_sha512"},
+    {TLSEXT_SIGALG_rsa_pkcs1_sha256, "rsa_pkcs1_sha256"},
+    {TLSEXT_SIGALG_rsa_pkcs1_sha384, "rsa_pkcs1_sha384"},
+    {TLSEXT_SIGALG_rsa_pkcs1_sha512, "rsa_pkcs1_sha512"},
+    {TLSEXT_SIGALG_rsa_pkcs1_sha224, "rsa_pkcs1_sha224"},
+    {TLSEXT_SIGALG_rsa_pkcs1_sha1, "rsa_pkcs1_sha1"},
+    {TLSEXT_SIGALG_dsa_sha256, "dsa_sha256"},
+    {TLSEXT_SIGALG_dsa_sha384, "dsa_sha384"},
+    {TLSEXT_SIGALG_dsa_sha512, "dsa_sha512"},
+    {TLSEXT_SIGALG_dsa_sha224, "dsa_sha224"},
+    {TLSEXT_SIGALG_dsa_sha1, "dsa_sha1"},
+    {TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256, "gost2012_256"},
+    {TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512, "gost2012_512"},
+    {TLSEXT_SIGALG_gostr34102001_gostr3411, "gost2001_gost94"},
+};
+
+static const ssl_trace_tbl ssl_ctype_tbl[] = {
+    {1, "rsa_sign"},
+    {2, "dss_sign"},
+    {3, "rsa_fixed_dh"},
+    {4, "dss_fixed_dh"},
+    {5, "rsa_ephemeral_dh"},
+    {6, "dss_ephemeral_dh"},
+    {20, "fortezza_dms"},
+    {64, "ecdsa_sign"},
+    {65, "rsa_fixed_ecdh"},
+    {66, "ecdsa_fixed_ecdh"}
+};
+
+static const ssl_trace_tbl ssl_psk_kex_modes_tbl[] = {
+    {TLSEXT_KEX_MODE_KE, "psk_ke"},
+    {TLSEXT_KEX_MODE_KE_DHE, "psk_dhe_ke"}
+};
+
+static const ssl_trace_tbl ssl_key_update_tbl[] = {
+    {SSL_KEY_UPDATE_NOT_REQUESTED, "update_not_requested"},
+    {SSL_KEY_UPDATE_REQUESTED, "update_requested"}
+};
+
+static void ssl_print_hex(BIO *bio, int indent, const char *name,
+                          const unsigned char *msg, size_t msglen)
+{
+    size_t i;
+
+    BIO_indent(bio, indent, 80);
+    BIO_printf(bio, "%s (len=%d): ", name, (int)msglen);
+    for (i = 0; i < msglen; i++)
+        BIO_printf(bio, "%02X", msg[i]);
+    BIO_puts(bio, "\n");
+}
+
+static int ssl_print_hexbuf(BIO *bio, int indent, const char *name, size_t nlen,
+                            const unsigned char **pmsg, size_t *pmsglen)
+{
+    size_t blen;
+    const unsigned char *p = *pmsg;
+
+    if (*pmsglen < nlen)
+        return 0;
+    blen = p[0];
+    if (nlen > 1)
+        blen = (blen << 8) | p[1];
+    if (*pmsglen < nlen + blen)
+        return 0;
+    p += nlen;
+    ssl_print_hex(bio, indent, name, p, blen);
+    *pmsg += blen + nlen;
+    *pmsglen -= blen + nlen;
+    return 1;
+}
+
+static int ssl_print_version(BIO *bio, int indent, const char *name,
+                             const unsigned char **pmsg, size_t *pmsglen,
+                             unsigned int *version)
+{
+    int vers;
+
+    if (*pmsglen < 2)
+        return 0;
+    vers = ((*pmsg)[0] << 8) | (*pmsg)[1];
+    if (version != NULL)
+        *version = vers;
+    BIO_indent(bio, indent, 80);
+    BIO_printf(bio, "%s=0x%x (%s)\n",
+               name, vers, ssl_trace_str(vers, ssl_version_tbl));
+    *pmsg += 2;
+    *pmsglen -= 2;
+    return 1;
+}
+
+static int ssl_print_random(BIO *bio, int indent,
+                            const unsigned char **pmsg, size_t *pmsglen)
+{
+    unsigned int tm;
+    const unsigned char *p = *pmsg;
+
+    if (*pmsglen < 32)
+        return 0;
+    tm = ((unsigned int)p[0] << 24)
+         | ((unsigned int)p[1] << 16)
+         | ((unsigned int)p[2] << 8)
+         | (unsigned int)p[3];
+    p += 4;
+    BIO_indent(bio, indent, 80);
+    BIO_puts(bio, "Random:\n");
+    BIO_indent(bio, indent + 2, 80);
+    BIO_printf(bio, "gmt_unix_time=0x%08X\n", tm);
+    ssl_print_hex(bio, indent + 2, "random_bytes", p, 28);
+    *pmsg += 32;
+    *pmsglen -= 32;
+    return 1;
+}
+
+static int ssl_print_signature(BIO *bio, int indent, const SSL *ssl,
+                               const unsigned char **pmsg, size_t *pmsglen)
+{
+    if (*pmsglen < 2)
+        return 0;
+    if (SSL_USE_SIGALGS(ssl)) {
+        const unsigned char *p = *pmsg;
+        unsigned int sigalg = (p[0] << 8) | p[1];
+
+        BIO_indent(bio, indent, 80);
+        BIO_printf(bio, "Signature Algorithm: %s (0x%04x)\n",
+                   ssl_trace_str(sigalg, ssl_sigalg_tbl), sigalg);
+        *pmsg += 2;
+        *pmsglen -= 2;
+    }
+    return ssl_print_hexbuf(bio, indent, "Signature", 2, pmsg, pmsglen);
+}
+
+static int ssl_print_extension(BIO *bio, int indent, int server,
+                               unsigned char mt, int extype,
+                               const unsigned char *ext, size_t extlen)
+{
+    size_t xlen, share_len;
+    unsigned int sigalg;
+    uint32_t max_early_data;
+
+    BIO_indent(bio, indent, 80);
+    BIO_printf(bio, "extension_type=%s(%d), length=%d\n",
+               ssl_trace_str(extype, ssl_exts_tbl), extype, (int)extlen);
+    switch (extype) {
+    case TLSEXT_TYPE_max_fragment_length:
+        if (extlen < 1)
+            return 0;
+        xlen = extlen;
+        return ssl_trace_list(bio, indent + 2, ext, xlen, 1, ssl_mfl_tbl);
+
+    case TLSEXT_TYPE_ec_point_formats:
+        if (extlen < 1)
+            return 0;
+        xlen = ext[0];
+        if (extlen != xlen + 1)
+            return 0;
+        return ssl_trace_list(bio, indent + 2, ext + 1, xlen, 1, ssl_point_tbl);
+
+    case TLSEXT_TYPE_supported_groups:
+        if (extlen < 2)
+            return 0;
+        xlen = (ext[0] << 8) | ext[1];
+        if (extlen != xlen + 2)
+            return 0;
+        return ssl_trace_list(bio, indent + 2, ext + 2, xlen, 2, ssl_groups_tbl);
+    case TLSEXT_TYPE_application_layer_protocol_negotiation:
+        if (extlen < 2)
+            return 0;
+        xlen = (ext[0] << 8) | ext[1];
+        if (extlen != xlen + 2)
+            return 0;
+        ext += 2;
+        while (xlen > 0) {
+            size_t plen = *ext++;
+
+            if (plen + 1 > xlen)
+                return 0;
+            BIO_indent(bio, indent + 2, 80);
+            BIO_write(bio, ext, plen);
+            BIO_puts(bio, "\n");
+            ext += plen;
+            xlen -= plen + 1;
+        }
+        return 1;
+
+    case TLSEXT_TYPE_signature_algorithms:
+
+        if (extlen < 2)
+            return 0;
+        xlen = (ext[0] << 8) | ext[1];
+        if (extlen != xlen + 2)
+            return 0;
+        if (xlen & 1)
+            return 0;
+        ext += 2;
+        while (xlen > 0) {
+            BIO_indent(bio, indent + 2, 80);
+            sigalg = (ext[0] << 8) | ext[1];
+            BIO_printf(bio, "%s (0x%04x)\n",
+                       ssl_trace_str(sigalg, ssl_sigalg_tbl), sigalg);
+            xlen -= 2;
+            ext += 2;
+        }
+        break;
+
+    case TLSEXT_TYPE_renegotiate:
+        if (extlen < 1)
+            return 0;
+        xlen = ext[0];
+        if (xlen + 1 != extlen)
+            return 0;
+        ext++;
+        if (xlen) {
+            if (server) {
+                if (xlen & 1)
+                    return 0;
+                xlen >>= 1;
+            }
+            ssl_print_hex(bio, indent + 4, "client_verify_data", ext, xlen);
+            if (server) {
+                ext += xlen;
+                ssl_print_hex(bio, indent + 4, "server_verify_data", ext, xlen);
+            }
+        } else {
+            BIO_indent(bio, indent + 4, 80);
+            BIO_puts(bio, "<EMPTY>\n");
+        }
+        break;
+
+    case TLSEXT_TYPE_heartbeat:
+        return 0;
+
+    case TLSEXT_TYPE_session_ticket:
+        if (extlen != 0)
+            ssl_print_hex(bio, indent + 4, "ticket", ext, extlen);
+        break;
+
+    case TLSEXT_TYPE_key_share:
+        if (server && extlen == 2) {
+            int group_id;
+
+            /* We assume this is an HRR, otherwise this is an invalid key_share */
+            group_id = (ext[0] << 8) | ext[1];
+            BIO_indent(bio, indent + 4, 80);
+            BIO_printf(bio, "NamedGroup: %s (%d)\n",
+                       ssl_trace_str(group_id, ssl_groups_tbl), group_id);
+            break;
+        }
+        if (extlen < 2)
+            return 0;
+        if (server) {
+            xlen = extlen;
+        } else {
+            xlen = (ext[0] << 8) | ext[1];
+            if (extlen != xlen + 2)
+                return 0;
+            ext += 2;
+        }
+        for (; xlen > 0; ext += share_len, xlen -= share_len) {
+            int group_id;
+
+            if (xlen < 4)
+                return 0;
+            group_id = (ext[0] << 8) | ext[1];
+            share_len = (ext[2] << 8) | ext[3];
+            ext += 4;
+            xlen -= 4;
+            if (xlen < share_len)
+                return 0;
+            BIO_indent(bio, indent + 4, 80);
+            BIO_printf(bio, "NamedGroup: %s (%d)\n",
+                       ssl_trace_str(group_id, ssl_groups_tbl), group_id);
+            ssl_print_hex(bio, indent + 4, "key_exchange: ", ext, share_len);
+        }
+        break;
+
+    case TLSEXT_TYPE_supported_versions:
+        if (server) {
+            int version;
+
+            if (extlen != 2)
+                return 0;
+            version = (ext[0] << 8) | ext[1];
+            BIO_indent(bio, indent + 4, 80);
+            BIO_printf(bio, "%s (%d)\n",
+                       ssl_trace_str(version, ssl_version_tbl), version);
+            break;
+        }
+        if (extlen < 1)
+            return 0;
+        xlen = ext[0];
+        if (extlen != xlen + 1)
+            return 0;
+        return ssl_trace_list(bio, indent + 2, ext + 1, xlen, 2,
+                              ssl_version_tbl);
+
+    case TLSEXT_TYPE_psk_kex_modes:
+        if (extlen < 1)
+            return 0;
+        xlen = ext[0];
+        if (extlen != xlen + 1)
+            return 0;
+        return ssl_trace_list(bio, indent + 2, ext + 1, xlen, 1,
+                              ssl_psk_kex_modes_tbl);
+
+    case TLSEXT_TYPE_early_data:
+        if (mt != SSL3_MT_NEWSESSION_TICKET)
+            break;
+        if (extlen != 4)
+            return 0;
+        max_early_data = ((unsigned int)ext[0] << 24)
+                         | ((unsigned int)ext[1] << 16)
+                         | ((unsigned int)ext[2] << 8)
+                         | (unsigned int)ext[3];
+        BIO_indent(bio, indent + 2, 80);
+        BIO_printf(bio, "max_early_data=%u\n", max_early_data);
+        break;
+
+    default:
+        BIO_dump_indent(bio, (const char *)ext, extlen, indent + 2);
+    }
+    return 1;
+}
+
+static int ssl_print_extensions(BIO *bio, int indent, int server,
+                                unsigned char mt, const unsigned char **msgin,
+                                size_t *msginlen)
+{
+    size_t extslen, msglen = *msginlen;
+    const unsigned char *msg = *msgin;
+
+    BIO_indent(bio, indent, 80);
+    if (msglen == 0) {
+        BIO_puts(bio, "No extensions\n");
+        return 1;
+    }
+    if (msglen < 2)
+        return 0;
+    extslen = (msg[0] << 8) | msg[1];
+    msglen -= 2;
+    msg += 2;
+    if (extslen == 0) {
+        BIO_puts(bio, "No extensions\n");
+        *msgin = msg;
+        *msginlen = msglen;
+        return 1;
+    }
+    if (extslen > msglen)
+        return 0;
+    BIO_printf(bio, "extensions, length = %d\n", (int)extslen);
+    msglen -= extslen;
+    while (extslen > 0) {
+        int extype;
+        size_t extlen;
+        if (extslen < 4)
+            return 0;
+        extype = (msg[0] << 8) | msg[1];
+        extlen = (msg[2] << 8) | msg[3];
+        if (extslen < extlen + 4) {
+            BIO_printf(bio, "extensions, extype = %d, extlen = %d\n", extype,
+                       (int)extlen);
+            BIO_dump_indent(bio, (const char *)msg, extslen, indent + 2);
+            return 0;
+        }
+        msg += 4;
+        if (!ssl_print_extension(bio, indent + 2, server, mt, extype, msg,
+                                 extlen))
+            return 0;
+        msg += extlen;
+        extslen -= extlen + 4;
+    }
+
+    *msgin = msg;
+    *msginlen = msglen;
+    return 1;
+}
+
+static int ssl_print_client_hello(BIO *bio, const SSL *ssl, int indent,
+                                  const unsigned char *msg, size_t msglen)
+{
+    size_t len;
+    unsigned int cs;
+
+    if (!ssl_print_version(bio, indent, "client_version", &msg, &msglen, NULL))
+        return 0;
+    if (!ssl_print_random(bio, indent, &msg, &msglen))
+        return 0;
+    if (!ssl_print_hexbuf(bio, indent, "session_id", 1, &msg, &msglen))
+        return 0;
+    if (SSL_IS_DTLS(ssl)) {
+        if (!ssl_print_hexbuf(bio, indent, "cookie", 1, &msg, &msglen))
+            return 0;
+    }
+    if (msglen < 2)
+        return 0;
+    len = (msg[0] << 8) | msg[1];
+    msg += 2;
+    msglen -= 2;
+    BIO_indent(bio, indent, 80);
+    BIO_printf(bio, "cipher_suites (len=%d)\n", (int)len);
+    if (msglen < len || len & 1)
+        return 0;
+    while (len > 0) {
+        cs = (msg[0] << 8) | msg[1];
+        BIO_indent(bio, indent + 2, 80);
+        BIO_printf(bio, "{0x%02X, 0x%02X} %s\n",
+                   msg[0], msg[1], ssl_trace_str(cs, ssl_ciphers_tbl));
+        msg += 2;
+        msglen -= 2;
+        len -= 2;
+    }
+    if (msglen < 1)
+        return 0;
+    len = msg[0];
+    msg++;
+    msglen--;
+    if (msglen < len)
+        return 0;
+    BIO_indent(bio, indent, 80);
+    BIO_printf(bio, "compression_methods (len=%d)\n", (int)len);
+    while (len > 0) {
+        BIO_indent(bio, indent + 2, 80);
+        BIO_printf(bio, "%s (0x%02X)\n",
+                   ssl_trace_str(msg[0], ssl_comp_tbl), msg[0]);
+        msg++;
+        msglen--;
+        len--;
+    }
+    if (!ssl_print_extensions(bio, indent, 0, SSL3_MT_CLIENT_HELLO, &msg,
+                              &msglen))
+        return 0;
+    return 1;
+}
+
+static int dtls_print_hello_vfyrequest(BIO *bio, int indent,
+                                       const unsigned char *msg, size_t msglen)
+{
+    if (!ssl_print_version(bio, indent, "server_version", &msg, &msglen, NULL))
+        return 0;
+    if (!ssl_print_hexbuf(bio, indent, "cookie", 1, &msg, &msglen))
+        return 0;
+    return 1;
+}
+
+static int ssl_print_server_hello(BIO *bio, int indent,
+                                  const unsigned char *msg, size_t msglen)
+{
+    unsigned int cs;
+    unsigned int vers;
+
+    if (!ssl_print_version(bio, indent, "server_version", &msg, &msglen, &vers))
+        return 0;
+    if (!ssl_print_random(bio, indent, &msg, &msglen))
+        return 0;
+    if (vers != TLS1_3_VERSION
+            && !ssl_print_hexbuf(bio, indent, "session_id", 1, &msg, &msglen))
+        return 0;
+    if (msglen < 2)
+        return 0;
+    cs = (msg[0] << 8) | msg[1];
+    BIO_indent(bio, indent, 80);
+    BIO_printf(bio, "cipher_suite {0x%02X, 0x%02X} %s\n",
+               msg[0], msg[1], ssl_trace_str(cs, ssl_ciphers_tbl));
+    msg += 2;
+    msglen -= 2;
+    if (vers != TLS1_3_VERSION) {
+        if (msglen < 1)
+            return 0;
+        BIO_indent(bio, indent, 80);
+        BIO_printf(bio, "compression_method: %s (0x%02X)\n",
+                   ssl_trace_str(msg[0], ssl_comp_tbl), msg[0]);
+        msg++;
+        msglen--;
+    }
+    if (!ssl_print_extensions(bio, indent, 1, SSL3_MT_SERVER_HELLO, &msg,
+                              &msglen))
+        return 0;
+    return 1;
+}
+
+static int ssl_get_keyex(const char **pname, const SSL *ssl)
+{
+    unsigned long alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey;
+
+    if (alg_k & SSL_kRSA) {
+        *pname = "rsa";
+        return SSL_kRSA;
+    }
+    if (alg_k & SSL_kDHE) {
+        *pname = "DHE";
+        return SSL_kDHE;
+    }
+    if (alg_k & SSL_kECDHE) {
+        *pname = "ECDHE";
+        return SSL_kECDHE;
+    }
+    if (alg_k & SSL_kPSK) {
+        *pname = "PSK";
+        return SSL_kPSK;
+    }
+    if (alg_k & SSL_kRSAPSK) {
+        *pname = "RSAPSK";
+        return SSL_kRSAPSK;
+    }
+    if (alg_k & SSL_kDHEPSK) {
+        *pname = "DHEPSK";
+        return SSL_kDHEPSK;
+    }
+    if (alg_k & SSL_kECDHEPSK) {
+        *pname = "ECDHEPSK";
+        return SSL_kECDHEPSK;
+    }
+    if (alg_k & SSL_kSRP) {
+        *pname = "SRP";
+        return SSL_kSRP;
+    }
+    if (alg_k & SSL_kGOST) {
+        *pname = "GOST";
+        return SSL_kGOST;
+    }
+    *pname = "UNKNOWN";
+    return 0;
+}
+
+static int ssl_print_client_keyex(BIO *bio, int indent, const SSL *ssl,
+                                  const unsigned char *msg, size_t msglen)
+{
+    const char *algname;
+    int id = ssl_get_keyex(&algname, ssl);
+
+    BIO_indent(bio, indent, 80);
+    BIO_printf(bio, "KeyExchangeAlgorithm=%s\n", algname);
+    if (id & SSL_PSK) {
+        if (!ssl_print_hexbuf(bio, indent + 2,
+                              "psk_identity", 2, &msg, &msglen))
+            return 0;
+    }
+    switch (id) {
+
+    case SSL_kRSA:
+    case SSL_kRSAPSK:
+        if (TLS1_get_version(ssl) == SSL3_VERSION) {
+            ssl_print_hex(bio, indent + 2,
+                          "EncryptedPreMasterSecret", msg, msglen);
+        } else {
+            if (!ssl_print_hexbuf(bio, indent + 2,
+                                  "EncryptedPreMasterSecret", 2, &msg, &msglen))
+                return 0;
+        }
+        break;
+
+    case SSL_kDHE:
+    case SSL_kDHEPSK:
+        if (!ssl_print_hexbuf(bio, indent + 2, "dh_Yc", 2, &msg, &msglen))
+            return 0;
+        break;
+
+    case SSL_kECDHE:
+    case SSL_kECDHEPSK:
+        if (!ssl_print_hexbuf(bio, indent + 2, "ecdh_Yc", 1, &msg, &msglen))
+            return 0;
+        break;
+
+    }
+
+    return !msglen;
+}
+
+static int ssl_print_server_keyex(BIO *bio, int indent, const SSL *ssl,
+                                  const unsigned char *msg, size_t msglen)
+{
+    const char *algname;
+    int id = ssl_get_keyex(&algname, ssl);
+
+    BIO_indent(bio, indent, 80);
+    BIO_printf(bio, "KeyExchangeAlgorithm=%s\n", algname);
+    if (id & SSL_PSK) {
+        if (!ssl_print_hexbuf(bio, indent + 2,
+                              "psk_identity_hint", 2, &msg, &msglen))
+            return 0;
+    }
+    switch (id) {
+    case SSL_kRSA:
+
+        if (!ssl_print_hexbuf(bio, indent + 2, "rsa_modulus", 2, &msg, &msglen))
+            return 0;
+        if (!ssl_print_hexbuf(bio, indent + 2, "rsa_exponent", 2,
+                              &msg, &msglen))
+            return 0;
+        break;
+
+    case SSL_kDHE:
+    case SSL_kDHEPSK:
+        if (!ssl_print_hexbuf(bio, indent + 2, "dh_p", 2, &msg, &msglen))
+            return 0;
+        if (!ssl_print_hexbuf(bio, indent + 2, "dh_g", 2, &msg, &msglen))
+            return 0;
+        if (!ssl_print_hexbuf(bio, indent + 2, "dh_Ys", 2, &msg, &msglen))
+            return 0;
+        break;
+
+# ifndef OPENSSL_NO_EC
+    case SSL_kECDHE:
+    case SSL_kECDHEPSK:
+        if (msglen < 1)
+            return 0;
+        BIO_indent(bio, indent + 2, 80);
+        if (msg[0] == EXPLICIT_PRIME_CURVE_TYPE)
+            BIO_puts(bio, "explicit_prime\n");
+        else if (msg[0] == EXPLICIT_CHAR2_CURVE_TYPE)
+            BIO_puts(bio, "explicit_char2\n");
+        else if (msg[0] == NAMED_CURVE_TYPE) {
+            int curve;
+            if (msglen < 3)
+                return 0;
+            curve = (msg[1] << 8) | msg[2];
+            BIO_printf(bio, "named_curve: %s (%d)\n",
+                       ssl_trace_str(curve, ssl_groups_tbl), curve);
+            msg += 3;
+            msglen -= 3;
+            if (!ssl_print_hexbuf(bio, indent + 2, "point", 1, &msg, &msglen))
+                return 0;
+        } else {
+            BIO_printf(bio, "UNKNOWN CURVE PARAMETER TYPE %d\n", msg[0]);
+            return 0;
+        }
+        break;
+# endif
+
+    case SSL_kPSK:
+    case SSL_kRSAPSK:
+        break;
+    }
+    if (!(id & SSL_PSK))
+        ssl_print_signature(bio, indent, ssl, &msg, &msglen);
+    return !msglen;
+}
+
+static int ssl_print_certificate(BIO *bio, int indent,
+                                 const unsigned char **pmsg, size_t *pmsglen)
+{
+    size_t msglen = *pmsglen;
+    size_t clen;
+    X509 *x;
+    const unsigned char *p = *pmsg, *q;
+
+    if (msglen < 3)
+        return 0;
+    clen = (p[0] << 16) | (p[1] << 8) | p[2];
+    if (msglen < clen + 3)
+        return 0;
+    q = p + 3;
+    BIO_indent(bio, indent, 80);
+    BIO_printf(bio, "ASN.1Cert, length=%d", (int)clen);
+    x = d2i_X509(NULL, &q, clen);
+    if (!x)
+        BIO_puts(bio, "<UNPARSEABLE CERTIFICATE>\n");
+    else {
+        BIO_puts(bio, "\n------details-----\n");
+        X509_print_ex(bio, x, XN_FLAG_ONELINE, 0);
+        PEM_write_bio_X509(bio, x);
+        /* Print certificate stuff */
+        BIO_puts(bio, "------------------\n");
+        X509_free(x);
+    }
+    if (q != p + 3 + clen) {
+        BIO_puts(bio, "<TRAILING GARBAGE AFTER CERTIFICATE>\n");
+    }
+    *pmsg += clen + 3;
+    *pmsglen -= clen + 3;
+    return 1;
+}
+
+static int ssl_print_certificates(BIO *bio, const SSL *ssl, int server,
+                                  int indent, const unsigned char *msg,
+                                  size_t msglen)
+{
+    size_t clen;
+
+    if (SSL_IS_TLS13(ssl)
+            && !ssl_print_hexbuf(bio, indent, "context", 1, &msg, &msglen))
+        return 0;
+
+    if (msglen < 3)
+        return 0;
+    clen = (msg[0] << 16) | (msg[1] << 8) | msg[2];
+    if (msglen != clen + 3)
+        return 0;
+    msg += 3;
+    BIO_indent(bio, indent, 80);
+    BIO_printf(bio, "certificate_list, length=%d\n", (int)clen);
+    while (clen > 0) {
+        if (!ssl_print_certificate(bio, indent + 2, &msg, &clen))
+            return 0;
+        if (SSL_IS_TLS13(ssl)
+            && !ssl_print_extensions(bio, indent + 2, server,
+                                     SSL3_MT_CERTIFICATE, &msg, &clen))
+            return 0;
+
+    }
+    return 1;
+}
+
+static int ssl_print_cert_request(BIO *bio, int indent, const SSL *ssl,
+                                  const unsigned char *msg, size_t msglen)
+{
+    size_t xlen;
+    unsigned int sigalg;
+
+    if (SSL_IS_TLS13(ssl)) {
+        if (!ssl_print_hexbuf(bio, indent, "request_context", 1, &msg, &msglen))
+            return 0;
+        if (!ssl_print_extensions(bio, indent, 1,
+                                  SSL3_MT_CERTIFICATE_REQUEST, &msg, &msglen))
+            return 0;
+        return 1;
+    } else {
+        if (msglen < 1)
+            return 0;
+        xlen = msg[0];
+        if (msglen < xlen + 1)
+            return 0;
+        msg++;
+        BIO_indent(bio, indent, 80);
+        BIO_printf(bio, "certificate_types (len=%d)\n", (int)xlen);
+        if (!ssl_trace_list(bio, indent + 2, msg, xlen, 1, ssl_ctype_tbl))
+            return 0;
+        msg += xlen;
+        msglen -= xlen + 1;
+    }
+    if (SSL_USE_SIGALGS(ssl)) {
+        if (msglen < 2)
+            return 0;
+        xlen = (msg[0] << 8) | msg[1];
+        if (msglen < xlen + 2 || (xlen & 1))
+            return 0;
+        msg += 2;
+        msglen -= xlen + 2;
+        BIO_indent(bio, indent, 80);
+        BIO_printf(bio, "signature_algorithms (len=%d)\n", (int)xlen);
+        while (xlen > 0) {
+            BIO_indent(bio, indent + 2, 80);
+            sigalg = (msg[0] << 8) | msg[1];
+            BIO_printf(bio, "%s (0x%04x)\n",
+                       ssl_trace_str(sigalg, ssl_sigalg_tbl), sigalg);
+            xlen -= 2;
+            msg += 2;
+        }
+        msg += xlen;
+    }
+
+    if (msglen < 2)
+        return 0;
+    xlen = (msg[0] << 8) | msg[1];
+    BIO_indent(bio, indent, 80);
+    if (msglen < xlen + 2)
+        return 0;
+    msg += 2;
+    msglen -= 2 + xlen;
+    BIO_printf(bio, "certificate_authorities (len=%d)\n", (int)xlen);
+    while (xlen > 0) {
+        size_t dlen;
+        X509_NAME *nm;
+        const unsigned char *p;
+        if (xlen < 2)
+            return 0;
+        dlen = (msg[0] << 8) | msg[1];
+        if (xlen < dlen + 2)
+            return 0;
+        msg += 2;
+        BIO_indent(bio, indent + 2, 80);
+        BIO_printf(bio, "DistinguishedName (len=%d): ", (int)dlen);
+        p = msg;
+        nm = d2i_X509_NAME(NULL, &p, dlen);
+        if (!nm) {
+            BIO_puts(bio, "<UNPARSEABLE DN>\n");
+        } else {
+            X509_NAME_print_ex(bio, nm, 0, XN_FLAG_ONELINE);
+            BIO_puts(bio, "\n");
+            X509_NAME_free(nm);
+        }
+        xlen -= dlen + 2;
+        msg += dlen;
+    }
+    if (SSL_IS_TLS13(ssl)) {
+        if (!ssl_print_hexbuf(bio, indent, "request_extensions", 2,
+                              &msg, &msglen))
+            return 0;
+    }
+    return msglen == 0;
+}
+
+static int ssl_print_ticket(BIO *bio, int indent, const SSL *ssl,
+                            const unsigned char *msg, size_t msglen)
+{
+    unsigned int tick_life;
+
+    if (msglen == 0) {
+        BIO_indent(bio, indent + 2, 80);
+        BIO_puts(bio, "No Ticket\n");
+        return 1;
+    }
+    if (msglen < 4)
+        return 0;
+    tick_life = ((unsigned int)msg[0] << 24)
+                | ((unsigned int)msg[1] << 16)
+                | ((unsigned int)msg[2] << 8)
+                | (unsigned int)msg[3];
+    msglen -= 4;
+    msg += 4;
+    BIO_indent(bio, indent + 2, 80);
+    BIO_printf(bio, "ticket_lifetime_hint=%u\n", tick_life);
+    if (SSL_IS_TLS13(ssl)) {
+        unsigned int ticket_age_add;
+
+        if (msglen < 4)
+            return 0;
+        ticket_age_add =
+            ((unsigned int)msg[0] << 24)
+            | ((unsigned int)msg[1] << 16)
+            | ((unsigned int)msg[2] << 8)
+            | (unsigned int)msg[3];
+        msglen -= 4;
+        msg += 4;
+        BIO_indent(bio, indent + 2, 80);
+        BIO_printf(bio, "ticket_age_add=%u\n", ticket_age_add);
+        if (!ssl_print_hexbuf(bio, indent + 2, "ticket_nonce", 1, &msg,
+                              &msglen))
+            return 0;
+    }
+    if (!ssl_print_hexbuf(bio, indent + 2, "ticket", 2, &msg, &msglen))
+        return 0;
+    if (SSL_IS_TLS13(ssl)
+            && !ssl_print_extensions(bio, indent + 2, 0,
+                                     SSL3_MT_NEWSESSION_TICKET, &msg, &msglen))
+        return 0;
+    if (msglen)
+        return 0;
+    return 1;
+}
+
+static int ssl_print_handshake(BIO *bio, const SSL *ssl, int server,
+                               const unsigned char *msg, size_t msglen,
+                               int indent)
+{
+    size_t hlen;
+    unsigned char htype;
+
+    if (msglen < 4)
+        return 0;
+    htype = msg[0];
+    hlen = (msg[1] << 16) | (msg[2] << 8) | msg[3];
+    BIO_indent(bio, indent, 80);
+    BIO_printf(bio, "%s, Length=%d\n",
+               ssl_trace_str(htype, ssl_handshake_tbl), (int)hlen);
+    msg += 4;
+    msglen -= 4;
+    if (SSL_IS_DTLS(ssl)) {
+        if (msglen < 8)
+            return 0;
+        BIO_indent(bio, indent, 80);
+        BIO_printf(bio, "message_seq=%d, fragment_offset=%d, "
+                   "fragment_length=%d\n",
+                   (msg[0] << 8) | msg[1],
+                   (msg[2] << 16) | (msg[3] << 8) | msg[4],
+                   (msg[5] << 16) | (msg[6] << 8) | msg[7]);
+        msg += 8;
+        msglen -= 8;
+    }
+    if (msglen < hlen)
+        return 0;
+    switch (htype) {
+    case SSL3_MT_CLIENT_HELLO:
+        if (!ssl_print_client_hello(bio, ssl, indent + 2, msg, msglen))
+            return 0;
+        break;
+
+    case DTLS1_MT_HELLO_VERIFY_REQUEST:
+        if (!dtls_print_hello_vfyrequest(bio, indent + 2, msg, msglen))
+            return 0;
+        break;
+
+    case SSL3_MT_SERVER_HELLO:
+        if (!ssl_print_server_hello(bio, indent + 2, msg, msglen))
+            return 0;
+        break;
+
+    case SSL3_MT_SERVER_KEY_EXCHANGE:
+        if (!ssl_print_server_keyex(bio, indent + 2, ssl, msg, msglen))
+            return 0;
+        break;
+
+    case SSL3_MT_CLIENT_KEY_EXCHANGE:
+        if (!ssl_print_client_keyex(bio, indent + 2, ssl, msg, msglen))
+            return 0;
+        break;
+
+    case SSL3_MT_CERTIFICATE:
+        if (!ssl_print_certificates(bio, ssl, server, indent + 2, msg, msglen))
+            return 0;
+        break;
+
+    case SSL3_MT_CERTIFICATE_VERIFY:
+        if (!ssl_print_signature(bio, indent + 2, ssl, &msg, &msglen))
+            return 0;
+        break;
+
+    case SSL3_MT_CERTIFICATE_REQUEST:
+        if (!ssl_print_cert_request(bio, indent + 2, ssl, msg, msglen))
+            return 0;
+        break;
+
+    case SSL3_MT_FINISHED:
+        ssl_print_hex(bio, indent + 2, "verify_data", msg, msglen);
+        break;
+
+    case SSL3_MT_SERVER_DONE:
+        if (msglen != 0)
+            ssl_print_hex(bio, indent + 2, "unexpected value", msg, msglen);
+        break;
+
+    case SSL3_MT_NEWSESSION_TICKET:
+        if (!ssl_print_ticket(bio, indent + 2, ssl, msg, msglen))
+            return 0;
+        break;
+
+    case SSL3_MT_ENCRYPTED_EXTENSIONS:
+        if (!ssl_print_extensions(bio, indent + 2, 1,
+                                  SSL3_MT_ENCRYPTED_EXTENSIONS, &msg, &msglen))
+            return 0;
+        break;
+
+    case SSL3_MT_KEY_UPDATE:
+        if (msglen != 1) {
+            ssl_print_hex(bio, indent + 2, "unexpected value", msg, msglen);
+            return 0;
+        }
+        if (!ssl_trace_list(bio, indent + 2, msg, msglen, 1,
+                            ssl_key_update_tbl))
+            return 0;
+        break;
+
+    default:
+        BIO_indent(bio, indent + 2, 80);
+        BIO_puts(bio, "Unsupported, hex dump follows:\n");
+        BIO_dump_indent(bio, (const char *)msg, msglen, indent + 4);
+    }
+    return 1;
+}
+
+void SSL_trace(int write_p, int version, int content_type,
+               const void *buf, size_t msglen, SSL *ssl, void *arg)
+{
+    const unsigned char *msg = buf;
+    BIO *bio = arg;
+
+    switch (content_type) {
+    case SSL3_RT_HEADER:
+        {
+            int hvers;
+
+            /* avoid overlapping with length at the end of buffer */
+            if (msglen < (size_t)(SSL_IS_DTLS(ssl) ?
+                     DTLS1_RT_HEADER_LENGTH : SSL3_RT_HEADER_LENGTH)) {
+                BIO_puts(bio, write_p ? "Sent" : "Received");
+                ssl_print_hex(bio, 0, " too short message", msg, msglen);
+                break;
+            }
+            hvers = msg[1] << 8 | msg[2];
+            BIO_puts(bio, write_p ? "Sent" : "Received");
+            BIO_printf(bio, " Record\nHeader:\n  Version = %s (0x%x)\n",
+                       ssl_trace_str(hvers, ssl_version_tbl), hvers);
+            if (SSL_IS_DTLS(ssl)) {
+                BIO_printf(bio,
+                           "  epoch=%d, sequence_number=%04x%04x%04x\n",
+                           (msg[3] << 8 | msg[4]),
+                           (msg[5] << 8 | msg[6]),
+                           (msg[7] << 8 | msg[8]), (msg[9] << 8 | msg[10]));
+            }
+
+            BIO_printf(bio, "  Content Type = %s (%d)\n  Length = %d",
+                       ssl_trace_str(msg[0], ssl_content_tbl), msg[0],
+                       msg[msglen - 2] << 8 | msg[msglen - 1]);
+        }
+        break;
+
+    case SSL3_RT_INNER_CONTENT_TYPE:
+        BIO_printf(bio, "  Inner Content Type = %s (%d)",
+                   ssl_trace_str(msg[0], ssl_content_tbl), msg[0]);
+        break;
+
+    case SSL3_RT_HANDSHAKE:
+        if (!ssl_print_handshake(bio, ssl, ssl->server ? write_p : !write_p,
+                                 msg, msglen, 4))
+            BIO_printf(bio, "Message length parse error!\n");
+        break;
+
+    case SSL3_RT_CHANGE_CIPHER_SPEC:
+        if (msglen == 1 && msg[0] == 1)
+            BIO_puts(bio, "    change_cipher_spec (1)\n");
+        else
+            ssl_print_hex(bio, 4, "unknown value", msg, msglen);
+        break;
+
+    case SSL3_RT_ALERT:
+        if (msglen != 2)
+            BIO_puts(bio, "    Illegal Alert Length\n");
+        else {
+            BIO_printf(bio, "    Level=%s(%d), description=%s(%d)\n",
+                       SSL_alert_type_string_long(msg[0] << 8),
+                       msg[0], SSL_alert_desc_string_long(msg[1]), msg[1]);
+        }
+
+    }
+
+    BIO_puts(bio, "\n");
+}
+
+#endif
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/tls13_enc.c b/ap/lib/libssl/openssl-1.1.1o/ssl/tls13_enc.c
new file mode 100644
index 0000000..ff85df4
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/tls13_enc.c
@@ -0,0 +1,884 @@
+/*
+ * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdlib.h>
+#include "ssl_local.h"
+#include "internal/cryptlib.h"
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+
+#define TLS13_MAX_LABEL_LEN     249
+
+/* Always filled with zeros */
+static const unsigned char default_zeros[EVP_MAX_MD_SIZE];
+
+/*
+ * Given a |secret|; a |label| of length |labellen|; and |data| of length
+ * |datalen| (e.g. typically a hash of the handshake messages), derive a new
+ * secret |outlen| bytes long and store it in the location pointed to be |out|.
+ * The |data| value may be zero length. Any errors will be treated as fatal if
+ * |fatal| is set. Returns 1 on success  0 on failure.
+ */
+int tls13_hkdf_expand(SSL *s, const EVP_MD *md, const unsigned char *secret,
+                             const unsigned char *label, size_t labellen,
+                             const unsigned char *data, size_t datalen,
+                             unsigned char *out, size_t outlen, int fatal)
+{
+#ifdef CHARSET_EBCDIC
+    static const unsigned char label_prefix[] = { 0x74, 0x6C, 0x73, 0x31, 0x33, 0x20, 0x00 };
+#else
+    static const unsigned char label_prefix[] = "tls13 ";
+#endif
+    EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
+    int ret;
+    size_t hkdflabellen;
+    size_t hashlen;
+    /*
+     * 2 bytes for length of derived secret + 1 byte for length of combined
+     * prefix and label + bytes for the label itself + 1 byte length of hash
+     * + bytes for the hash itself
+     */
+    unsigned char hkdflabel[sizeof(uint16_t) + sizeof(uint8_t)
+                            + (sizeof(label_prefix) - 1) + TLS13_MAX_LABEL_LEN
+                            + 1 + EVP_MAX_MD_SIZE];
+    WPACKET pkt;
+
+    if (pctx == NULL)
+        return 0;
+
+    if (labellen > TLS13_MAX_LABEL_LEN) {
+        if (fatal) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_HKDF_EXPAND,
+                     ERR_R_INTERNAL_ERROR);
+        } else {
+            /*
+             * Probably we have been called from SSL_export_keying_material(),
+             * or SSL_export_keying_material_early().
+             */
+            SSLerr(SSL_F_TLS13_HKDF_EXPAND, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL);
+        }
+        EVP_PKEY_CTX_free(pctx);
+        return 0;
+    }
+
+    hashlen = EVP_MD_size(md);
+
+    if (!WPACKET_init_static_len(&pkt, hkdflabel, sizeof(hkdflabel), 0)
+            || !WPACKET_put_bytes_u16(&pkt, outlen)
+            || !WPACKET_start_sub_packet_u8(&pkt)
+            || !WPACKET_memcpy(&pkt, label_prefix, sizeof(label_prefix) - 1)
+            || !WPACKET_memcpy(&pkt, label, labellen)
+            || !WPACKET_close(&pkt)
+            || !WPACKET_sub_memcpy_u8(&pkt, data, (data == NULL) ? 0 : datalen)
+            || !WPACKET_get_total_written(&pkt, &hkdflabellen)
+            || !WPACKET_finish(&pkt)) {
+        EVP_PKEY_CTX_free(pctx);
+        WPACKET_cleanup(&pkt);
+        if (fatal)
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_HKDF_EXPAND,
+                     ERR_R_INTERNAL_ERROR);
+        else
+            SSLerr(SSL_F_TLS13_HKDF_EXPAND, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    ret = EVP_PKEY_derive_init(pctx) <= 0
+            || EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY)
+               <= 0
+            || EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0
+            || EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, hashlen) <= 0
+            || EVP_PKEY_CTX_add1_hkdf_info(pctx, hkdflabel, hkdflabellen) <= 0
+            || EVP_PKEY_derive(pctx, out, &outlen) <= 0;
+
+    EVP_PKEY_CTX_free(pctx);
+
+    if (ret != 0) {
+        if (fatal)
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_HKDF_EXPAND,
+                     ERR_R_INTERNAL_ERROR);
+        else
+            SSLerr(SSL_F_TLS13_HKDF_EXPAND, ERR_R_INTERNAL_ERROR);
+    }
+
+    return ret == 0;
+}
+
+/*
+ * Given a |secret| generate a |key| of length |keylen| bytes. Returns 1 on
+ * success  0 on failure.
+ */
+int tls13_derive_key(SSL *s, const EVP_MD *md, const unsigned char *secret,
+                     unsigned char *key, size_t keylen)
+{
+#ifdef CHARSET_EBCDIC
+  static const unsigned char keylabel[] ={ 0x6B, 0x65, 0x79, 0x00 };
+#else
+  static const unsigned char keylabel[] = "key";
+#endif
+
+    return tls13_hkdf_expand(s, md, secret, keylabel, sizeof(keylabel) - 1,
+                             NULL, 0, key, keylen, 1);
+}
+
+/*
+ * Given a |secret| generate an |iv| of length |ivlen| bytes. Returns 1 on
+ * success  0 on failure.
+ */
+int tls13_derive_iv(SSL *s, const EVP_MD *md, const unsigned char *secret,
+                    unsigned char *iv, size_t ivlen)
+{
+#ifdef CHARSET_EBCDIC
+  static const unsigned char ivlabel[] = { 0x69, 0x76, 0x00 };
+#else
+  static const unsigned char ivlabel[] = "iv";
+#endif
+
+    return tls13_hkdf_expand(s, md, secret, ivlabel, sizeof(ivlabel) - 1,
+                             NULL, 0, iv, ivlen, 1);
+}
+
+int tls13_derive_finishedkey(SSL *s, const EVP_MD *md,
+                             const unsigned char *secret,
+                             unsigned char *fin, size_t finlen)
+{
+#ifdef CHARSET_EBCDIC
+  static const unsigned char finishedlabel[] = { 0x66, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64, 0x00 };
+#else
+  static const unsigned char finishedlabel[] = "finished";
+#endif
+
+    return tls13_hkdf_expand(s, md, secret, finishedlabel,
+                             sizeof(finishedlabel) - 1, NULL, 0, fin, finlen, 1);
+}
+
+/*
+ * Given the previous secret |prevsecret| and a new input secret |insecret| of
+ * length |insecretlen|, generate a new secret and store it in the location
+ * pointed to by |outsecret|. Returns 1 on success  0 on failure.
+ */
+int tls13_generate_secret(SSL *s, const EVP_MD *md,
+                          const unsigned char *prevsecret,
+                          const unsigned char *insecret,
+                          size_t insecretlen,
+                          unsigned char *outsecret)
+{
+    size_t mdlen, prevsecretlen;
+    int mdleni;
+    int ret;
+    EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
+#ifdef CHARSET_EBCDIC
+    static const char derived_secret_label[] = { 0x64, 0x65, 0x72, 0x69, 0x76, 0x65, 0x64, 0x00 };
+#else
+    static const char derived_secret_label[] = "derived";
+#endif
+    unsigned char preextractsec[EVP_MAX_MD_SIZE];
+
+    if (pctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_GENERATE_SECRET,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    mdleni = EVP_MD_size(md);
+    /* Ensure cast to size_t is safe */
+    if (!ossl_assert(mdleni >= 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_GENERATE_SECRET,
+                 ERR_R_INTERNAL_ERROR);
+        EVP_PKEY_CTX_free(pctx);
+        return 0;
+    }
+    mdlen = (size_t)mdleni;
+
+    if (insecret == NULL) {
+        insecret = default_zeros;
+        insecretlen = mdlen;
+    }
+    if (prevsecret == NULL) {
+        prevsecret = default_zeros;
+        prevsecretlen = 0;
+    } else {
+        EVP_MD_CTX *mctx = EVP_MD_CTX_new();
+        unsigned char hash[EVP_MAX_MD_SIZE];
+
+        /* The pre-extract derive step uses a hash of no messages */
+        if (mctx == NULL
+                || EVP_DigestInit_ex(mctx, md, NULL) <= 0
+                || EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_GENERATE_SECRET,
+                     ERR_R_INTERNAL_ERROR);
+            EVP_MD_CTX_free(mctx);
+            EVP_PKEY_CTX_free(pctx);
+            return 0;
+        }
+        EVP_MD_CTX_free(mctx);
+
+        /* Generate the pre-extract secret */
+        if (!tls13_hkdf_expand(s, md, prevsecret,
+                               (unsigned char *)derived_secret_label,
+                               sizeof(derived_secret_label) - 1, hash, mdlen,
+                               preextractsec, mdlen, 1)) {
+            /* SSLfatal() already called */
+            EVP_PKEY_CTX_free(pctx);
+            return 0;
+        }
+
+        prevsecret = preextractsec;
+        prevsecretlen = mdlen;
+    }
+
+    ret = EVP_PKEY_derive_init(pctx) <= 0
+            || EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY)
+               <= 0
+            || EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0
+            || EVP_PKEY_CTX_set1_hkdf_key(pctx, insecret, insecretlen) <= 0
+            || EVP_PKEY_CTX_set1_hkdf_salt(pctx, prevsecret, prevsecretlen)
+               <= 0
+            || EVP_PKEY_derive(pctx, outsecret, &mdlen)
+               <= 0;
+
+    if (ret != 0)
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_GENERATE_SECRET,
+                 ERR_R_INTERNAL_ERROR);
+
+    EVP_PKEY_CTX_free(pctx);
+    if (prevsecret == preextractsec)
+        OPENSSL_cleanse(preextractsec, mdlen);
+    return ret == 0;
+}
+
+/*
+ * Given an input secret |insecret| of length |insecretlen| generate the
+ * handshake secret. This requires the early secret to already have been
+ * generated. Returns 1 on success  0 on failure.
+ */
+int tls13_generate_handshake_secret(SSL *s, const unsigned char *insecret,
+                                size_t insecretlen)
+{
+    /* Calls SSLfatal() if required */
+    return tls13_generate_secret(s, ssl_handshake_md(s), s->early_secret,
+                                 insecret, insecretlen,
+                                 (unsigned char *)&s->handshake_secret);
+}
+
+/*
+ * Given the handshake secret |prev| of length |prevlen| generate the master
+ * secret and store its length in |*secret_size|. Returns 1 on success  0 on
+ * failure.
+ */
+int tls13_generate_master_secret(SSL *s, unsigned char *out,
+                                 unsigned char *prev, size_t prevlen,
+                                 size_t *secret_size)
+{
+    const EVP_MD *md = ssl_handshake_md(s);
+
+    *secret_size = EVP_MD_size(md);
+    /* Calls SSLfatal() if required */
+    return tls13_generate_secret(s, md, prev, NULL, 0, out);
+}
+
+/*
+ * Generates the mac for the Finished message. Returns the length of the MAC or
+ * 0 on error.
+ */
+size_t tls13_final_finish_mac(SSL *s, const char *str, size_t slen,
+                             unsigned char *out)
+{
+    const EVP_MD *md = ssl_handshake_md(s);
+    unsigned char hash[EVP_MAX_MD_SIZE];
+    size_t hashlen, ret = 0;
+    EVP_PKEY *key = NULL;
+    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
+
+    if (!ssl_handshake_hash(s, hash, sizeof(hash), &hashlen)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    if (str == s->method->ssl3_enc->server_finished_label) {
+        key = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
+                                           s->server_finished_secret, hashlen);
+    } else if (SSL_IS_FIRST_HANDSHAKE(s)) {
+        key = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
+                                           s->client_finished_secret, hashlen);
+    } else {
+        unsigned char finsecret[EVP_MAX_MD_SIZE];
+
+        if (!tls13_derive_finishedkey(s, ssl_handshake_md(s),
+                                      s->client_app_traffic_secret,
+                                      finsecret, hashlen))
+            goto err;
+
+        key = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, finsecret,
+                                           hashlen);
+        OPENSSL_cleanse(finsecret, sizeof(finsecret));
+    }
+
+    if (key == NULL
+            || ctx == NULL
+            || EVP_DigestSignInit(ctx, NULL, md, NULL, key) <= 0
+            || EVP_DigestSignUpdate(ctx, hash, hashlen) <= 0
+            || EVP_DigestSignFinal(ctx, out, &hashlen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_FINAL_FINISH_MAC,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    ret = hashlen;
+ err:
+    EVP_PKEY_free(key);
+    EVP_MD_CTX_free(ctx);
+    return ret;
+}
+
+/*
+ * There isn't really a key block in TLSv1.3, but we still need this function
+ * for initialising the cipher and hash. Returns 1 on success or 0 on failure.
+ */
+int tls13_setup_key_block(SSL *s)
+{
+    const EVP_CIPHER *c;
+    const EVP_MD *hash;
+
+    s->session->cipher = s->s3->tmp.new_cipher;
+    if (!ssl_cipher_get_evp(s->session, &c, &hash, NULL, NULL, NULL, 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_SETUP_KEY_BLOCK,
+                 SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
+        return 0;
+    }
+
+    s->s3->tmp.new_sym_enc = c;
+    s->s3->tmp.new_hash = hash;
+
+    return 1;
+}
+
+static int derive_secret_key_and_iv(SSL *s, int sending, const EVP_MD *md,
+                                    const EVP_CIPHER *ciph,
+                                    const unsigned char *insecret,
+                                    const unsigned char *hash,
+                                    const unsigned char *label,
+                                    size_t labellen, unsigned char *secret,
+                                    unsigned char *iv, EVP_CIPHER_CTX *ciph_ctx)
+{
+    unsigned char key[EVP_MAX_KEY_LENGTH];
+    size_t ivlen, keylen, taglen;
+    int hashleni = EVP_MD_size(md);
+    size_t hashlen;
+
+    /* Ensure cast to size_t is safe */
+    if (!ossl_assert(hashleni >= 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DERIVE_SECRET_KEY_AND_IV,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+    hashlen = (size_t)hashleni;
+
+    if (!tls13_hkdf_expand(s, md, insecret, label, labellen, hash, hashlen,
+                           secret, hashlen, 1)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    /* TODO(size_t): convert me */
+    keylen = EVP_CIPHER_key_length(ciph);
+    if (EVP_CIPHER_mode(ciph) == EVP_CIPH_CCM_MODE) {
+        uint32_t algenc;
+
+        ivlen = EVP_CCM_TLS_IV_LEN;
+        if (s->s3->tmp.new_cipher != NULL) {
+            algenc = s->s3->tmp.new_cipher->algorithm_enc;
+        } else if (s->session->cipher != NULL) {
+            /* We've not selected a cipher yet - we must be doing early data */
+            algenc = s->session->cipher->algorithm_enc;
+        } else if (s->psksession != NULL && s->psksession->cipher != NULL) {
+            /* We must be doing early data with out-of-band PSK */
+            algenc = s->psksession->cipher->algorithm_enc;
+        } else {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DERIVE_SECRET_KEY_AND_IV,
+                     ERR_R_EVP_LIB);
+            goto err;
+        }
+        if (algenc & (SSL_AES128CCM8 | SSL_AES256CCM8))
+            taglen = EVP_CCM8_TLS_TAG_LEN;
+         else
+            taglen = EVP_CCM_TLS_TAG_LEN;
+    } else {
+        ivlen = EVP_CIPHER_iv_length(ciph);
+        taglen = 0;
+    }
+
+    if (!tls13_derive_key(s, md, secret, key, keylen)
+            || !tls13_derive_iv(s, md, secret, iv, ivlen)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    if (EVP_CipherInit_ex(ciph_ctx, ciph, NULL, NULL, NULL, sending) <= 0
+        || !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_IVLEN, ivlen, NULL)
+        || (taglen != 0 && !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_TAG,
+                                                taglen, NULL))
+        || EVP_CipherInit_ex(ciph_ctx, NULL, NULL, key, NULL, -1) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DERIVE_SECRET_KEY_AND_IV,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+
+    return 1;
+ err:
+    OPENSSL_cleanse(key, sizeof(key));
+    return 0;
+}
+
+int tls13_change_cipher_state(SSL *s, int which)
+{
+#ifdef CHARSET_EBCDIC
+  static const unsigned char client_early_traffic[]       = {0x63, 0x20, 0x65, 0x20,       /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
+  static const unsigned char client_handshake_traffic[]   = {0x63, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
+  static const unsigned char client_application_traffic[] = {0x63, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
+  static const unsigned char server_handshake_traffic[]   = {0x73, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
+  static const unsigned char server_application_traffic[] = {0x73, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
+  static const unsigned char exporter_master_secret[] = {0x65, 0x78, 0x70, 0x20,                    /* master*/  0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00};
+  static const unsigned char resumption_master_secret[] = {0x72, 0x65, 0x73, 0x20,                  /* master*/  0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00};
+  static const unsigned char early_exporter_master_secret[] = {0x65, 0x20, 0x65, 0x78, 0x70, 0x20,  /* master*/  0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00};
+#else
+    static const unsigned char client_early_traffic[] = "c e traffic";
+    static const unsigned char client_handshake_traffic[] = "c hs traffic";
+    static const unsigned char client_application_traffic[] = "c ap traffic";
+    static const unsigned char server_handshake_traffic[] = "s hs traffic";
+    static const unsigned char server_application_traffic[] = "s ap traffic";
+    static const unsigned char exporter_master_secret[] = "exp master";
+    static const unsigned char resumption_master_secret[] = "res master";
+    static const unsigned char early_exporter_master_secret[] = "e exp master";
+#endif
+    unsigned char *iv;
+    unsigned char secret[EVP_MAX_MD_SIZE];
+    unsigned char hashval[EVP_MAX_MD_SIZE];
+    unsigned char *hash = hashval;
+    unsigned char *insecret;
+    unsigned char *finsecret = NULL;
+    const char *log_label = NULL;
+    EVP_CIPHER_CTX *ciph_ctx;
+    size_t finsecretlen = 0;
+    const unsigned char *label;
+    size_t labellen, hashlen = 0;
+    int ret = 0;
+    const EVP_MD *md = NULL;
+    const EVP_CIPHER *cipher = NULL;
+
+    if (which & SSL3_CC_READ) {
+        if (s->enc_read_ctx != NULL) {
+            EVP_CIPHER_CTX_reset(s->enc_read_ctx);
+        } else {
+            s->enc_read_ctx = EVP_CIPHER_CTX_new();
+            if (s->enc_read_ctx == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+        }
+        ciph_ctx = s->enc_read_ctx;
+        iv = s->read_iv;
+
+        RECORD_LAYER_reset_read_sequence(&s->rlayer);
+    } else {
+        s->statem.enc_write_state = ENC_WRITE_STATE_INVALID;
+        if (s->enc_write_ctx != NULL) {
+            EVP_CIPHER_CTX_reset(s->enc_write_ctx);
+        } else {
+            s->enc_write_ctx = EVP_CIPHER_CTX_new();
+            if (s->enc_write_ctx == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+        }
+        ciph_ctx = s->enc_write_ctx;
+        iv = s->write_iv;
+
+        RECORD_LAYER_reset_write_sequence(&s->rlayer);
+    }
+
+    if (((which & SSL3_CC_CLIENT) && (which & SSL3_CC_WRITE))
+            || ((which & SSL3_CC_SERVER) && (which & SSL3_CC_READ))) {
+        if (which & SSL3_CC_EARLY) {
+            EVP_MD_CTX *mdctx = NULL;
+            long handlen;
+            void *hdata;
+            unsigned int hashlenui;
+            const SSL_CIPHER *sslcipher = SSL_SESSION_get0_cipher(s->session);
+
+            insecret = s->early_secret;
+            label = client_early_traffic;
+            labellen = sizeof(client_early_traffic) - 1;
+            log_label = CLIENT_EARLY_LABEL;
+
+            handlen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+            if (handlen <= 0) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS13_CHANGE_CIPHER_STATE,
+                         SSL_R_BAD_HANDSHAKE_LENGTH);
+                goto err;
+            }
+
+            if (s->early_data_state == SSL_EARLY_DATA_CONNECTING
+                    && s->max_early_data > 0
+                    && s->session->ext.max_early_data == 0) {
+                /*
+                 * If we are attempting to send early data, and we've decided to
+                 * actually do it but max_early_data in s->session is 0 then we
+                 * must be using an external PSK.
+                 */
+                if (!ossl_assert(s->psksession != NULL
+                        && s->max_early_data ==
+                           s->psksession->ext.max_early_data)) {
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                             SSL_F_TLS13_CHANGE_CIPHER_STATE,
+                             ERR_R_INTERNAL_ERROR);
+                    goto err;
+                }
+                sslcipher = SSL_SESSION_get0_cipher(s->psksession);
+            }
+            if (sslcipher == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS13_CHANGE_CIPHER_STATE, SSL_R_BAD_PSK);
+                goto err;
+            }
+
+            /*
+             * We need to calculate the handshake digest using the digest from
+             * the session. We haven't yet selected our ciphersuite so we can't
+             * use ssl_handshake_md().
+             */
+            mdctx = EVP_MD_CTX_new();
+            if (mdctx == NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+            cipher = EVP_get_cipherbynid(SSL_CIPHER_get_cipher_nid(sslcipher));
+            md = ssl_md(sslcipher->algorithm2);
+            if (md == NULL || !EVP_DigestInit_ex(mdctx, md, NULL)
+                    || !EVP_DigestUpdate(mdctx, hdata, handlen)
+                    || !EVP_DigestFinal_ex(mdctx, hashval, &hashlenui)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+                EVP_MD_CTX_free(mdctx);
+                goto err;
+            }
+            hashlen = hashlenui;
+            EVP_MD_CTX_free(mdctx);
+
+            if (!tls13_hkdf_expand(s, md, insecret,
+                                   early_exporter_master_secret,
+                                   sizeof(early_exporter_master_secret) - 1,
+                                   hashval, hashlen,
+                                   s->early_exporter_master_secret, hashlen,
+                                   1)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                         SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+
+            if (!ssl_log_secret(s, EARLY_EXPORTER_SECRET_LABEL,
+                                s->early_exporter_master_secret, hashlen)) {
+                /* SSLfatal() already called */
+                goto err;
+            }
+        } else if (which & SSL3_CC_HANDSHAKE) {
+            insecret = s->handshake_secret;
+            finsecret = s->client_finished_secret;
+            finsecretlen = EVP_MD_size(ssl_handshake_md(s));
+            label = client_handshake_traffic;
+            labellen = sizeof(client_handshake_traffic) - 1;
+            log_label = CLIENT_HANDSHAKE_LABEL;
+            /*
+             * The handshake hash used for the server read/client write handshake
+             * traffic secret is the same as the hash for the server
+             * write/client read handshake traffic secret. However, if we
+             * processed early data then we delay changing the server
+             * read/client write cipher state until later, and the handshake
+             * hashes have moved on. Therefore we use the value saved earlier
+             * when we did the server write/client read change cipher state.
+             */
+            hash = s->handshake_traffic_hash;
+        } else {
+            insecret = s->master_secret;
+            label = client_application_traffic;
+            labellen = sizeof(client_application_traffic) - 1;
+            log_label = CLIENT_APPLICATION_LABEL;
+            /*
+             * For this we only use the handshake hashes up until the server
+             * Finished hash. We do not include the client's Finished, which is
+             * what ssl_handshake_hash() would give us. Instead we use the
+             * previously saved value.
+             */
+            hash = s->server_finished_hash;
+        }
+    } else {
+        /* Early data never applies to client-read/server-write */
+        if (which & SSL3_CC_HANDSHAKE) {
+            insecret = s->handshake_secret;
+            finsecret = s->server_finished_secret;
+            finsecretlen = EVP_MD_size(ssl_handshake_md(s));
+            label = server_handshake_traffic;
+            labellen = sizeof(server_handshake_traffic) - 1;
+            log_label = SERVER_HANDSHAKE_LABEL;
+        } else {
+            insecret = s->master_secret;
+            label = server_application_traffic;
+            labellen = sizeof(server_application_traffic) - 1;
+            log_label = SERVER_APPLICATION_LABEL;
+        }
+    }
+
+    if (!(which & SSL3_CC_EARLY)) {
+        md = ssl_handshake_md(s);
+        cipher = s->s3->tmp.new_sym_enc;
+        if (!ssl3_digest_cached_records(s, 1)
+                || !ssl_handshake_hash(s, hashval, sizeof(hashval), &hashlen)) {
+            /* SSLfatal() already called */;
+            goto err;
+        }
+    }
+
+    /*
+     * Save the hash of handshakes up to now for use when we calculate the
+     * client application traffic secret
+     */
+    if (label == server_application_traffic)
+        memcpy(s->server_finished_hash, hashval, hashlen);
+
+    if (label == server_handshake_traffic)
+        memcpy(s->handshake_traffic_hash, hashval, hashlen);
+
+    if (label == client_application_traffic) {
+        /*
+         * We also create the resumption master secret, but this time use the
+         * hash for the whole handshake including the Client Finished
+         */
+        if (!tls13_hkdf_expand(s, ssl_handshake_md(s), insecret,
+                               resumption_master_secret,
+                               sizeof(resumption_master_secret) - 1,
+                               hashval, hashlen, s->resumption_master_secret,
+                               hashlen, 1)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    }
+
+    if (!derive_secret_key_and_iv(s, which & SSL3_CC_WRITE, md, cipher,
+                                  insecret, hash, label, labellen, secret, iv,
+                                  ciph_ctx)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    if (label == server_application_traffic) {
+        memcpy(s->server_app_traffic_secret, secret, hashlen);
+        /* Now we create the exporter master secret */
+        if (!tls13_hkdf_expand(s, ssl_handshake_md(s), insecret,
+                               exporter_master_secret,
+                               sizeof(exporter_master_secret) - 1,
+                               hash, hashlen, s->exporter_master_secret,
+                               hashlen, 1)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+
+        if (!ssl_log_secret(s, EXPORTER_SECRET_LABEL, s->exporter_master_secret,
+                            hashlen)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else if (label == client_application_traffic)
+        memcpy(s->client_app_traffic_secret, secret, hashlen);
+
+    if (!ssl_log_secret(s, log_label, secret, hashlen)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    if (finsecret != NULL
+            && !tls13_derive_finishedkey(s, ssl_handshake_md(s), secret,
+                                         finsecret, finsecretlen)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    if (!s->server && label == client_early_traffic)
+        s->statem.enc_write_state = ENC_WRITE_STATE_WRITE_PLAIN_ALERTS;
+    else
+        s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
+    ret = 1;
+ err:
+    OPENSSL_cleanse(secret, sizeof(secret));
+    return ret;
+}
+
+int tls13_update_key(SSL *s, int sending)
+{
+#ifdef CHARSET_EBCDIC
+  static const unsigned char application_traffic[] = { 0x74, 0x72 ,0x61 ,0x66 ,0x66 ,0x69 ,0x63 ,0x20 ,0x75 ,0x70 ,0x64, 0x00};
+#else
+  static const unsigned char application_traffic[] = "traffic upd";
+#endif
+    const EVP_MD *md = ssl_handshake_md(s);
+    size_t hashlen = EVP_MD_size(md);
+    unsigned char *insecret, *iv;
+    unsigned char secret[EVP_MAX_MD_SIZE];
+    EVP_CIPHER_CTX *ciph_ctx;
+    int ret = 0;
+
+    if (s->server == sending)
+        insecret = s->server_app_traffic_secret;
+    else
+        insecret = s->client_app_traffic_secret;
+
+    if (sending) {
+        s->statem.enc_write_state = ENC_WRITE_STATE_INVALID;
+        iv = s->write_iv;
+        ciph_ctx = s->enc_write_ctx;
+        RECORD_LAYER_reset_write_sequence(&s->rlayer);
+    } else {
+        iv = s->read_iv;
+        ciph_ctx = s->enc_read_ctx;
+        RECORD_LAYER_reset_read_sequence(&s->rlayer);
+    }
+
+    if (!derive_secret_key_and_iv(s, sending, ssl_handshake_md(s),
+                                  s->s3->tmp.new_sym_enc, insecret, NULL,
+                                  application_traffic,
+                                  sizeof(application_traffic) - 1, secret, iv,
+                                  ciph_ctx)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    memcpy(insecret, secret, hashlen);
+
+    s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
+    ret = 1;
+ err:
+    OPENSSL_cleanse(secret, sizeof(secret));
+    return ret;
+}
+
+int tls13_alert_code(int code)
+{
+    /* There are 2 additional alerts in TLSv1.3 compared to TLSv1.2 */
+    if (code == SSL_AD_MISSING_EXTENSION || code == SSL_AD_CERTIFICATE_REQUIRED)
+        return code;
+
+    return tls1_alert_code(code);
+}
+
+int tls13_export_keying_material(SSL *s, unsigned char *out, size_t olen,
+                                 const char *label, size_t llen,
+                                 const unsigned char *context,
+                                 size_t contextlen, int use_context)
+{
+    unsigned char exportsecret[EVP_MAX_MD_SIZE];
+#ifdef CHARSET_EBCDIC
+    static const unsigned char exporterlabel[] = {0x65, 0x78, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x72, 0x00};
+#else
+    static const unsigned char exporterlabel[] = "exporter";
+#endif
+    unsigned char hash[EVP_MAX_MD_SIZE], data[EVP_MAX_MD_SIZE];
+    const EVP_MD *md = ssl_handshake_md(s);
+    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
+    unsigned int hashsize, datalen;
+    int ret = 0;
+
+    if (ctx == NULL || !ossl_statem_export_allowed(s))
+        goto err;
+
+    if (!use_context)
+        contextlen = 0;
+
+    if (EVP_DigestInit_ex(ctx, md, NULL) <= 0
+            || EVP_DigestUpdate(ctx, context, contextlen) <= 0
+            || EVP_DigestFinal_ex(ctx, hash, &hashsize) <= 0
+            || EVP_DigestInit_ex(ctx, md, NULL) <= 0
+            || EVP_DigestFinal_ex(ctx, data, &datalen) <= 0
+            || !tls13_hkdf_expand(s, md, s->exporter_master_secret,
+                                  (const unsigned char *)label, llen,
+                                  data, datalen, exportsecret, hashsize, 0)
+            || !tls13_hkdf_expand(s, md, exportsecret, exporterlabel,
+                                  sizeof(exporterlabel) - 1, hash, hashsize,
+                                  out, olen, 0))
+        goto err;
+
+    ret = 1;
+ err:
+    EVP_MD_CTX_free(ctx);
+    return ret;
+}
+
+int tls13_export_keying_material_early(SSL *s, unsigned char *out, size_t olen,
+                                       const char *label, size_t llen,
+                                       const unsigned char *context,
+                                       size_t contextlen)
+{
+#ifdef CHARSET_EBCDIC
+  static const unsigned char exporterlabel[] = {0x65, 0x78, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x72, 0x00};
+#else
+  static const unsigned char exporterlabel[] = "exporter";
+#endif
+    unsigned char exportsecret[EVP_MAX_MD_SIZE];
+    unsigned char hash[EVP_MAX_MD_SIZE], data[EVP_MAX_MD_SIZE];
+    const EVP_MD *md;
+    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
+    unsigned int hashsize, datalen;
+    int ret = 0;
+    const SSL_CIPHER *sslcipher;
+
+    if (ctx == NULL || !ossl_statem_export_early_allowed(s))
+        goto err;
+
+    if (!s->server && s->max_early_data > 0
+            && s->session->ext.max_early_data == 0)
+        sslcipher = SSL_SESSION_get0_cipher(s->psksession);
+    else
+        sslcipher = SSL_SESSION_get0_cipher(s->session);
+
+    md = ssl_md(sslcipher->algorithm2);
+
+    /*
+     * Calculate the hash value and store it in |data|. The reason why
+     * the empty string is used is that the definition of TLS-Exporter
+     * is like so:
+     *
+     * TLS-Exporter(label, context_value, key_length) =
+     *     HKDF-Expand-Label(Derive-Secret(Secret, label, ""),
+     *                       "exporter", Hash(context_value), key_length)
+     *
+     * Derive-Secret(Secret, Label, Messages) =
+     *       HKDF-Expand-Label(Secret, Label,
+     *                         Transcript-Hash(Messages), Hash.length)
+     *
+     * Here Transcript-Hash is the cipher suite hash algorithm.
+     */
+    if (EVP_DigestInit_ex(ctx, md, NULL) <= 0
+            || EVP_DigestUpdate(ctx, context, contextlen) <= 0
+            || EVP_DigestFinal_ex(ctx, hash, &hashsize) <= 0
+            || EVP_DigestInit_ex(ctx, md, NULL) <= 0
+            || EVP_DigestFinal_ex(ctx, data, &datalen) <= 0
+            || !tls13_hkdf_expand(s, md, s->early_exporter_master_secret,
+                                  (const unsigned char *)label, llen,
+                                  data, datalen, exportsecret, hashsize, 0)
+            || !tls13_hkdf_expand(s, md, exportsecret, exporterlabel,
+                                  sizeof(exporterlabel) - 1, hash, hashsize,
+                                  out, olen, 0))
+        goto err;
+
+    ret = 1;
+ err:
+    EVP_MD_CTX_free(ctx);
+    return ret;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/ssl/tls_srp.c b/ap/lib/libssl/openssl-1.1.1o/ssl/tls_srp.c
new file mode 100644
index 0000000..ede7427
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/ssl/tls_srp.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright 2004-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright (c) 2004, EdelKey Project. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ *
+ * Originally written by Christophe Renou and Peter Sylvester,
+ * for the EdelKey project.
+ */
+
+#include <openssl/crypto.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include "ssl_local.h"
+
+#ifndef OPENSSL_NO_SRP
+# include <openssl/srp.h>
+
+int SSL_CTX_SRP_CTX_free(struct ssl_ctx_st *ctx)
+{
+    if (ctx == NULL)
+        return 0;
+    OPENSSL_free(ctx->srp_ctx.login);
+    OPENSSL_free(ctx->srp_ctx.info);
+    BN_free(ctx->srp_ctx.N);
+    BN_free(ctx->srp_ctx.g);
+    BN_free(ctx->srp_ctx.s);
+    BN_free(ctx->srp_ctx.B);
+    BN_free(ctx->srp_ctx.A);
+    BN_free(ctx->srp_ctx.a);
+    BN_free(ctx->srp_ctx.b);
+    BN_free(ctx->srp_ctx.v);
+    memset(&ctx->srp_ctx, 0, sizeof(ctx->srp_ctx));
+    ctx->srp_ctx.strength = SRP_MINIMAL_N;
+    return 1;
+}
+
+int SSL_SRP_CTX_free(struct ssl_st *s)
+{
+    if (s == NULL)
+        return 0;
+    OPENSSL_free(s->srp_ctx.login);
+    OPENSSL_free(s->srp_ctx.info);
+    BN_free(s->srp_ctx.N);
+    BN_free(s->srp_ctx.g);
+    BN_free(s->srp_ctx.s);
+    BN_free(s->srp_ctx.B);
+    BN_free(s->srp_ctx.A);
+    BN_free(s->srp_ctx.a);
+    BN_free(s->srp_ctx.b);
+    BN_free(s->srp_ctx.v);
+    memset(&s->srp_ctx, 0, sizeof(s->srp_ctx));
+    s->srp_ctx.strength = SRP_MINIMAL_N;
+    return 1;
+}
+
+int SSL_SRP_CTX_init(struct ssl_st *s)
+{
+    SSL_CTX *ctx;
+
+    if ((s == NULL) || ((ctx = s->ctx) == NULL))
+        return 0;
+
+    memset(&s->srp_ctx, 0, sizeof(s->srp_ctx));
+
+    s->srp_ctx.SRP_cb_arg = ctx->srp_ctx.SRP_cb_arg;
+    /* set client Hello login callback */
+    s->srp_ctx.TLS_ext_srp_username_callback =
+        ctx->srp_ctx.TLS_ext_srp_username_callback;
+    /* set SRP N/g param callback for verification */
+    s->srp_ctx.SRP_verify_param_callback =
+        ctx->srp_ctx.SRP_verify_param_callback;
+    /* set SRP client passwd callback */
+    s->srp_ctx.SRP_give_srp_client_pwd_callback =
+        ctx->srp_ctx.SRP_give_srp_client_pwd_callback;
+
+    s->srp_ctx.strength = ctx->srp_ctx.strength;
+
+    if (((ctx->srp_ctx.N != NULL) &&
+         ((s->srp_ctx.N = BN_dup(ctx->srp_ctx.N)) == NULL)) ||
+        ((ctx->srp_ctx.g != NULL) &&
+         ((s->srp_ctx.g = BN_dup(ctx->srp_ctx.g)) == NULL)) ||
+        ((ctx->srp_ctx.s != NULL) &&
+         ((s->srp_ctx.s = BN_dup(ctx->srp_ctx.s)) == NULL)) ||
+        ((ctx->srp_ctx.B != NULL) &&
+         ((s->srp_ctx.B = BN_dup(ctx->srp_ctx.B)) == NULL)) ||
+        ((ctx->srp_ctx.A != NULL) &&
+         ((s->srp_ctx.A = BN_dup(ctx->srp_ctx.A)) == NULL)) ||
+        ((ctx->srp_ctx.a != NULL) &&
+         ((s->srp_ctx.a = BN_dup(ctx->srp_ctx.a)) == NULL)) ||
+        ((ctx->srp_ctx.v != NULL) &&
+         ((s->srp_ctx.v = BN_dup(ctx->srp_ctx.v)) == NULL)) ||
+        ((ctx->srp_ctx.b != NULL) &&
+         ((s->srp_ctx.b = BN_dup(ctx->srp_ctx.b)) == NULL))) {
+        SSLerr(SSL_F_SSL_SRP_CTX_INIT, ERR_R_BN_LIB);
+        goto err;
+    }
+    if ((ctx->srp_ctx.login != NULL) &&
+        ((s->srp_ctx.login = OPENSSL_strdup(ctx->srp_ctx.login)) == NULL)) {
+        SSLerr(SSL_F_SSL_SRP_CTX_INIT, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    if ((ctx->srp_ctx.info != NULL) &&
+        ((s->srp_ctx.info = BUF_strdup(ctx->srp_ctx.info)) == NULL)) {
+        SSLerr(SSL_F_SSL_SRP_CTX_INIT, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    s->srp_ctx.srp_Mask = ctx->srp_ctx.srp_Mask;
+
+    return 1;
+ err:
+    OPENSSL_free(s->srp_ctx.login);
+    OPENSSL_free(s->srp_ctx.info);
+    BN_free(s->srp_ctx.N);
+    BN_free(s->srp_ctx.g);
+    BN_free(s->srp_ctx.s);
+    BN_free(s->srp_ctx.B);
+    BN_free(s->srp_ctx.A);
+    BN_free(s->srp_ctx.a);
+    BN_free(s->srp_ctx.b);
+    BN_free(s->srp_ctx.v);
+    memset(&s->srp_ctx, 0, sizeof(s->srp_ctx));
+    return 0;
+}
+
+int SSL_CTX_SRP_CTX_init(struct ssl_ctx_st *ctx)
+{
+    if (ctx == NULL)
+        return 0;
+
+    memset(&ctx->srp_ctx, 0, sizeof(ctx->srp_ctx));
+    ctx->srp_ctx.strength = SRP_MINIMAL_N;
+
+    return 1;
+}
+
+/* server side */
+int SSL_srp_server_param_with_username(SSL *s, int *ad)
+{
+    unsigned char b[SSL_MAX_MASTER_KEY_LENGTH];
+    int al;
+
+    *ad = SSL_AD_UNKNOWN_PSK_IDENTITY;
+    if ((s->srp_ctx.TLS_ext_srp_username_callback != NULL) &&
+        ((al =
+          s->srp_ctx.TLS_ext_srp_username_callback(s, ad,
+                                                   s->srp_ctx.SRP_cb_arg)) !=
+         SSL_ERROR_NONE))
+        return al;
+
+    *ad = SSL_AD_INTERNAL_ERROR;
+    if ((s->srp_ctx.N == NULL) ||
+        (s->srp_ctx.g == NULL) ||
+        (s->srp_ctx.s == NULL) || (s->srp_ctx.v == NULL))
+        return SSL3_AL_FATAL;
+
+    if (RAND_priv_bytes(b, sizeof(b)) <= 0)
+        return SSL3_AL_FATAL;
+    s->srp_ctx.b = BN_bin2bn(b, sizeof(b), NULL);
+    OPENSSL_cleanse(b, sizeof(b));
+
+    /* Calculate:  B = (kv + g^b) % N  */
+
+    return ((s->srp_ctx.B =
+             SRP_Calc_B(s->srp_ctx.b, s->srp_ctx.N, s->srp_ctx.g,
+                        s->srp_ctx.v)) !=
+            NULL) ? SSL_ERROR_NONE : SSL3_AL_FATAL;
+}
+
+/*
+ * If the server just has the raw password, make up a verifier entry on the
+ * fly
+ */
+int SSL_set_srp_server_param_pw(SSL *s, const char *user, const char *pass,
+                                const char *grp)
+{
+    SRP_gN *GN = SRP_get_default_gN(grp);
+    if (GN == NULL)
+        return -1;
+    s->srp_ctx.N = BN_dup(GN->N);
+    s->srp_ctx.g = BN_dup(GN->g);
+    BN_clear_free(s->srp_ctx.v);
+    s->srp_ctx.v = NULL;
+    BN_clear_free(s->srp_ctx.s);
+    s->srp_ctx.s = NULL;
+    if (!SRP_create_verifier_BN
+        (user, pass, &s->srp_ctx.s, &s->srp_ctx.v, GN->N, GN->g))
+        return -1;
+
+    return 1;
+}
+
+int SSL_set_srp_server_param(SSL *s, const BIGNUM *N, const BIGNUM *g,
+                             BIGNUM *sa, BIGNUM *v, char *info)
+{
+    if (N != NULL) {
+        if (s->srp_ctx.N != NULL) {
+            if (!BN_copy(s->srp_ctx.N, N)) {
+                BN_free(s->srp_ctx.N);
+                s->srp_ctx.N = NULL;
+            }
+        } else
+            s->srp_ctx.N = BN_dup(N);
+    }
+    if (g != NULL) {
+        if (s->srp_ctx.g != NULL) {
+            if (!BN_copy(s->srp_ctx.g, g)) {
+                BN_free(s->srp_ctx.g);
+                s->srp_ctx.g = NULL;
+            }
+        } else
+            s->srp_ctx.g = BN_dup(g);
+    }
+    if (sa != NULL) {
+        if (s->srp_ctx.s != NULL) {
+            if (!BN_copy(s->srp_ctx.s, sa)) {
+                BN_free(s->srp_ctx.s);
+                s->srp_ctx.s = NULL;
+            }
+        } else
+            s->srp_ctx.s = BN_dup(sa);
+    }
+    if (v != NULL) {
+        if (s->srp_ctx.v != NULL) {
+            if (!BN_copy(s->srp_ctx.v, v)) {
+                BN_free(s->srp_ctx.v);
+                s->srp_ctx.v = NULL;
+            }
+        } else
+            s->srp_ctx.v = BN_dup(v);
+    }
+    if (info != NULL) {
+        if (s->srp_ctx.info)
+            OPENSSL_free(s->srp_ctx.info);
+        if ((s->srp_ctx.info = BUF_strdup(info)) == NULL)
+            return -1;
+    }
+
+    if (!(s->srp_ctx.N) ||
+        !(s->srp_ctx.g) || !(s->srp_ctx.s) || !(s->srp_ctx.v))
+        return -1;
+
+    return 1;
+}
+
+int srp_generate_server_master_secret(SSL *s)
+{
+    BIGNUM *K = NULL, *u = NULL;
+    int ret = -1, tmp_len = 0;
+    unsigned char *tmp = NULL;
+
+    if (!SRP_Verify_A_mod_N(s->srp_ctx.A, s->srp_ctx.N))
+        goto err;
+    if ((u = SRP_Calc_u(s->srp_ctx.A, s->srp_ctx.B, s->srp_ctx.N)) == NULL)
+        goto err;
+    if ((K = SRP_Calc_server_key(s->srp_ctx.A, s->srp_ctx.v, u, s->srp_ctx.b,
+                                 s->srp_ctx.N)) == NULL)
+        goto err;
+
+    tmp_len = BN_num_bytes(K);
+    if ((tmp = OPENSSL_malloc(tmp_len)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_SRP_GENERATE_SERVER_MASTER_SECRET, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    BN_bn2bin(K, tmp);
+    /* Calls SSLfatal() as required */
+    ret = ssl_generate_master_secret(s, tmp, tmp_len, 1);
+ err:
+    BN_clear_free(K);
+    BN_clear_free(u);
+    return ret;
+}
+
+/* client side */
+int srp_generate_client_master_secret(SSL *s)
+{
+    BIGNUM *x = NULL, *u = NULL, *K = NULL;
+    int ret = -1, tmp_len = 0;
+    char *passwd = NULL;
+    unsigned char *tmp = NULL;
+
+    /*
+     * Checks if b % n == 0
+     */
+    if (SRP_Verify_B_mod_N(s->srp_ctx.B, s->srp_ctx.N) == 0
+            || (u = SRP_Calc_u(s->srp_ctx.A, s->srp_ctx.B, s->srp_ctx.N))
+               == NULL
+            || s->srp_ctx.SRP_give_srp_client_pwd_callback == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_SRP_GENERATE_CLIENT_MASTER_SECRET, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    if ((passwd = s->srp_ctx.SRP_give_srp_client_pwd_callback(s,
+                                                      s->srp_ctx.SRP_cb_arg))
+            == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_SRP_GENERATE_CLIENT_MASTER_SECRET,
+                 SSL_R_CALLBACK_FAILED);
+        goto err;
+    }
+    if ((x = SRP_Calc_x(s->srp_ctx.s, s->srp_ctx.login, passwd)) == NULL
+            || (K = SRP_Calc_client_key(s->srp_ctx.N, s->srp_ctx.B,
+                                        s->srp_ctx.g, x,
+                                        s->srp_ctx.a, u)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_SRP_GENERATE_CLIENT_MASTER_SECRET, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    tmp_len = BN_num_bytes(K);
+    if ((tmp = OPENSSL_malloc(tmp_len)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_SRP_GENERATE_CLIENT_MASTER_SECRET, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    BN_bn2bin(K, tmp);
+    /* Calls SSLfatal() as required */
+    ret = ssl_generate_master_secret(s, tmp, tmp_len, 1);
+ err:
+    BN_clear_free(K);
+    BN_clear_free(x);
+    if (passwd != NULL)
+        OPENSSL_clear_free(passwd, strlen(passwd));
+    BN_clear_free(u);
+    return ret;
+}
+
+int srp_verify_server_param(SSL *s)
+{
+    SRP_CTX *srp = &s->srp_ctx;
+    /*
+     * Sanity check parameters: we can quickly check B % N == 0 by checking B
+     * != 0 since B < N
+     */
+    if (BN_ucmp(srp->g, srp->N) >= 0 || BN_ucmp(srp->B, srp->N) >= 0
+        || BN_is_zero(srp->B)) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SRP_VERIFY_SERVER_PARAM,
+                 SSL_R_BAD_DATA);
+        return 0;
+    }
+
+    if (BN_num_bits(srp->N) < srp->strength) {
+        SSLfatal(s, SSL_AD_INSUFFICIENT_SECURITY, SSL_F_SRP_VERIFY_SERVER_PARAM,
+                 SSL_R_INSUFFICIENT_SECURITY);
+        return 0;
+    }
+
+    if (srp->SRP_verify_param_callback) {
+        if (srp->SRP_verify_param_callback(s, srp->SRP_cb_arg) <= 0) {
+            SSLfatal(s, SSL_AD_INSUFFICIENT_SECURITY,
+                     SSL_F_SRP_VERIFY_SERVER_PARAM,
+                     SSL_R_CALLBACK_FAILED);
+            return 0;
+        }
+    } else if (!SRP_check_known_gN_param(srp->g, srp->N)) {
+        SSLfatal(s, SSL_AD_INSUFFICIENT_SECURITY, SSL_F_SRP_VERIFY_SERVER_PARAM,
+                 SSL_R_INSUFFICIENT_SECURITY);
+        return 0;
+    }
+
+    return 1;
+}
+
+int SRP_Calc_A_param(SSL *s)
+{
+    unsigned char rnd[SSL_MAX_MASTER_KEY_LENGTH];
+
+    if (RAND_priv_bytes(rnd, sizeof(rnd)) <= 0)
+        return 0;
+    s->srp_ctx.a = BN_bin2bn(rnd, sizeof(rnd), s->srp_ctx.a);
+    OPENSSL_cleanse(rnd, sizeof(rnd));
+
+    if (!(s->srp_ctx.A = SRP_Calc_A(s->srp_ctx.a, s->srp_ctx.N, s->srp_ctx.g)))
+        return 0;
+
+    return 1;
+}
+
+BIGNUM *SSL_get_srp_g(SSL *s)
+{
+    if (s->srp_ctx.g != NULL)
+        return s->srp_ctx.g;
+    return s->ctx->srp_ctx.g;
+}
+
+BIGNUM *SSL_get_srp_N(SSL *s)
+{
+    if (s->srp_ctx.N != NULL)
+        return s->srp_ctx.N;
+    return s->ctx->srp_ctx.N;
+}
+
+char *SSL_get_srp_username(SSL *s)
+{
+    if (s->srp_ctx.login != NULL)
+        return s->srp_ctx.login;
+    return s->ctx->srp_ctx.login;
+}
+
+char *SSL_get_srp_userinfo(SSL *s)
+{
+    if (s->srp_ctx.info != NULL)
+        return s->srp_ctx.info;
+    return s->ctx->srp_ctx.info;
+}
+
+# define tls1_ctx_ctrl ssl3_ctx_ctrl
+# define tls1_ctx_callback_ctrl ssl3_ctx_callback_ctrl
+
+int SSL_CTX_set_srp_username(SSL_CTX *ctx, char *name)
+{
+    return tls1_ctx_ctrl(ctx, SSL_CTRL_SET_TLS_EXT_SRP_USERNAME, 0, name);
+}
+
+int SSL_CTX_set_srp_password(SSL_CTX *ctx, char *password)
+{
+    return tls1_ctx_ctrl(ctx, SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD, 0, password);
+}
+
+int SSL_CTX_set_srp_strength(SSL_CTX *ctx, int strength)
+{
+    return tls1_ctx_ctrl(ctx, SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH, strength,
+                         NULL);
+}
+
+int SSL_CTX_set_srp_verify_param_callback(SSL_CTX *ctx,
+                                          int (*cb) (SSL *, void *))
+{
+    return tls1_ctx_callback_ctrl(ctx, SSL_CTRL_SET_SRP_VERIFY_PARAM_CB,
+                                  (void (*)(void))cb);
+}
+
+int SSL_CTX_set_srp_cb_arg(SSL_CTX *ctx, void *arg)
+{
+    return tls1_ctx_ctrl(ctx, SSL_CTRL_SET_SRP_ARG, 0, arg);
+}
+
+int SSL_CTX_set_srp_username_callback(SSL_CTX *ctx,
+                                      int (*cb) (SSL *, int *, void *))
+{
+    return tls1_ctx_callback_ctrl(ctx, SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB,
+                                  (void (*)(void))cb);
+}
+
+int SSL_CTX_set_srp_client_pwd_callback(SSL_CTX *ctx,
+                                        char *(*cb) (SSL *, void *))
+{
+    return tls1_ctx_callback_ctrl(ctx, SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB,
+                                  (void (*)(void))cb);
+}
+
+#endif