Index: azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/internal.c
===================================================================
--- azure_iot_hub_f767zi/trunk/wolfssl-4.4.0/src/internal.c	(revision 457)
+++ azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/internal.c	(revision 464)
@@ -38,4 +38,27 @@
  *     certificates. This also allows loading intermediate CA's as trusted
  *     and ignoring no signer failures for CA's up the chain to root.
+ * WOLFSSL_DTLS_RESEND_ONLY_TIMEOUT:
+ *     Enable resending the previous DTLS handshake flight only on a network
+ *     read timeout. By default we resend in two more cases, when we receive:
+ *     - an out of order last msg of the peer's flight
+ *     - a duplicate of the first msg from the peer's flight
+ * WOLFSSL_NO_DEF_TICKET_ENC_CB:
+ *     No default ticket encryption callback.
+ *     Server only.
+ *     Application must set its own callback to use session tickets.
+ * WOLFSSL_TICKET_ENC_CHACHA20_POLY1305
+ *     Use ChaCha20-Poly1305 to encrypt/decrypt session tickets in default
+ *     callback. Default algorithm if none defined and algorithms compiled in.
+ *     Server only.
+ * WOLFSSL_TICKET_ENC_AES128_GCM
+ *     Use AES128-GCM to encrypt/decrypt session tickets in default callback.
+ *     Server only. Default algorithm if ChaCha20/Poly1305 not compiled in.
+ * WOLFSSL_TICKET_ENC_AES256_GCM
+ *     Use AES256-GCM to encrypt/decrypt session tickets in default callback.
+ *     Server only.
+ * WOLFSSL_TICKET_DECRYPT_NO_CREATE
+ *     Default callback will not request creation of new ticket on successful
+ *     decryption.
+ *     Server only.
  */
 
@@ -73,5 +96,9 @@
     defined(CHACHA_AEAD_TEST) || defined(WOLFSSL_SESSION_EXPORT_DEBUG)
     #ifndef NO_STDIO_FILESYSTEM
-        #include <stdio.h>
+        #ifdef FUSION_RTOS
+            #include <fclstdio.h>
+        #else
+            #include <stdio.h>
+        #endif
     #endif
 #endif
@@ -125,7 +152,22 @@
         static int SendHelloVerifyRequest(WOLFSSL*, const byte*, byte);
     #endif /* WOLFSSL_DTLS */
-#endif
+
+#endif /* !NO_WOLFSSL_SERVER */
 
 #endif /* !WOLFSSL_NO_TLS12 */
+
+#ifndef NO_WOLFSSL_SERVER
+    #if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
+        static int TicketEncCbCtx_Init(WOLFSSL_CTX* ctx,
+                                       TicketEncCbCtx* keyCtx);
+        static void TicketEncCbCtx_Free(TicketEncCbCtx* keyCtx);
+        static int DefTicketEncCb(WOLFSSL* ssl,
+                                  byte key_name[WOLFSSL_TICKET_NAME_SZ],
+                                  byte iv[WOLFSSL_TICKET_IV_SZ],
+                                  byte mac[WOLFSSL_TICKET_MAC_SZ],
+                                  int enc, byte* ticket, int inLen, int* outLen,
+                                  void* userCtx);
+    #endif
+#endif
 
 #ifdef WOLFSSL_DTLS
@@ -162,5 +204,5 @@
 #if !defined(NO_OLD_TLS) && !defined(WOLFSSL_AEAD_ONLY)
 static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
-                    int padSz, int content, int verify);
+                    int padSz, int content, int verify, int epochOrder);
 
 #endif
@@ -205,6 +247,4 @@
 static WC_INLINE int IsEncryptionOn(WOLFSSL* ssl, int isSend)
 {
-    (void)isSend;
-
     #ifdef WOLFSSL_DTLS
     /* For DTLS, epoch 0 is always not encrypted. */
@@ -213,12 +253,6 @@
     #endif /* WOLFSSL_DTLS */
 
-#ifdef WOLFSSL_TLS13
-    if (isSend)
-        return ssl->encrypt.setup;
-    else
-        return ssl->decrypt.setup;
-#else
-    return ssl->keys.encryptionOn;
-#endif
+    return ssl->keys.encryptionOn &&
+        (isSend ? ssl->encrypt.setup : ssl->decrypt.setup);
 }
 
@@ -229,13 +263,9 @@
 static WC_INLINE int IsDtlsNotSctpMode(WOLFSSL* ssl)
 {
-    int result = ssl->options.dtls;
-
-    if (result) {
 #ifdef WOLFSSL_SCTP
-        result = !ssl->options.dtlsSctp;
-#endif
-    }
-
-    return result;
+    return ssl->options.dtls && !ssl->options.dtlsSctp;
+#else
+    return ssl->options.dtls;
+#endif
 }
 #endif /* DTLS || !WOLFSSL_NO_TLS12 */
@@ -363,5 +393,5 @@
     {
         (void)opaque;
-        return XMALLOC(item * size, opaque, DYNAMIC_TYPE_LIBZ);
+        return (void *)XMALLOC(item * size, opaque, DYNAMIC_TYPE_LIBZ);
     }
 
@@ -641,5 +671,5 @@
 }
 
-static int ImportCipherSpecState(WOLFSSL* ssl, byte* exp, word32 len, byte ver)
+static int ImportCipherSpecState(WOLFSSL* ssl, const byte* exp, word32 len, byte ver)
 {
     word32 idx = 0;
@@ -678,5 +708,5 @@
 
 
-static int ImportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver)
+static int ImportKeyState(WOLFSSL* ssl, const byte* exp, word32 len, byte ver)
 {
     word32 idx = 0;
@@ -911,4 +941,5 @@
     exp[idx++] = options->createTicket;
     exp[idx++] = options->useTicket;
+    exp[idx++] = options->noTicketTls12;
 #ifdef WOLFSSL_TLS13
     if (ver > DTLS_EXPORT_VERSION_3) {
@@ -974,5 +1005,5 @@
 /* copy items from Export struct to Options struct
  * On success returns size of buffer used on failure returns a negative value */
-static int dtls_export_load(WOLFSSL* ssl, byte* exp, word32 len, byte ver)
+static int dtls_export_load(WOLFSSL* ssl, const byte* exp, word32 len, byte ver)
 {
     int idx = 0;
@@ -1076,4 +1107,5 @@
     options->createTicket  = exp[idx++]; /* Server to create new Ticket */
     options->useTicket     = exp[idx++]; /* Use Ticket not session cache */
+    options->noTicketTls12 = exp[idx++]; /* Server won't create new Ticket */
 #ifdef WOLFSSL_TLS13
     if (ver > DTLS_EXPORT_VERSION_3) {
@@ -1156,5 +1188,5 @@
 
 
-static int ImportPeerInfo(WOLFSSL* ssl, byte* buf, word32 len, byte ver)
+static int ImportPeerInfo(WOLFSSL* ssl, const byte* buf, word32 len, byte ver)
 {
     word16 idx = 0;
@@ -1358,5 +1390,5 @@
 
 /* On success return amount of buffer consumed */
-int wolfSSL_dtls_import_state_internal(WOLFSSL* ssl, byte* buf, word32 sz)
+int wolfSSL_dtls_import_state_internal(WOLFSSL* ssl, const byte* buf, word32 sz)
 {
     word32 idx    = 0;
@@ -1425,10 +1457,10 @@
 
     WOLFSSL_LEAVE("wolfSSL_dtls_import_state_internal", ret);
-    return ret;
+    return idx;
 }
 
 
 /* On success return amount of buffer consumed */
-int wolfSSL_dtls_import_internal(WOLFSSL* ssl, byte* buf, word32 sz)
+int wolfSSL_dtls_import_internal(WOLFSSL* ssl, const byte* buf, word32 sz)
 {
     word32 idx    = 0;
@@ -1551,15 +1583,15 @@
 
     SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE);
-
+    /* make sure is a valid suite used */
+    if (wolfSSL_get_cipher(ssl) == NULL) {
+        WOLFSSL_MSG("Can not match cipher suite imported");
+        return MATCH_SUITE_ERROR;
+    }
+
+#ifndef WOLFSSL_AEAD_ONLY
     /* set hmac function to use when verifying */
     if (ssl->options.tls == 1 || ssl->options.tls1_1 == 1 ||
             ssl->options.dtls == 1) {
         ssl->hmac = TLS_hmac;
-    }
-
-    /* make sure is a valid suite used */
-    if (wolfSSL_get_cipher(ssl) == NULL) {
-        WOLFSSL_MSG("Can not match cipher suite imported");
-        return MATCH_SUITE_ERROR;
     }
 
@@ -1570,4 +1602,5 @@
         return SANITY_CIPHER_E;
     }
+#endif /* !WOLFSSL_AEAD_ONLY */
 
     return idx;
@@ -1659,4 +1692,8 @@
         return BAD_MUTEX_E;
     }
+
+#ifndef NO_CERTS
+    ctx->privateKeyDevId = INVALID_DEVID;
+#endif
 
 #ifndef NO_DH
@@ -1782,4 +1819,10 @@
 
 #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER)
+#ifndef WOLFSSL_NO_DEF_TICKET_ENC_CB
+    ret = TicketEncCbCtx_Init(ctx, &ctx->ticketKeyCtx);
+    if (ret != 0) return ret;
+    ctx->ticketEncCb = DefTicketEncCb;
+    ctx->ticketEncCtx = (void*)&ctx->ticketKeyCtx;
+#endif
     ctx->ticketHint = SESSION_TICKET_HINT_DEFAULT;
 #endif
@@ -1791,4 +1834,8 @@
 #ifdef WOLFSSL_EARLY_DATA
     ctx->maxEarlyDataSz = MAX_EARLY_DATA_SZ;
+#endif
+
+#if defined(WOLFSSL_TLS13) && !defined(HAVE_SUPPORTED_CURVES)
+    ctx->noPskDheKe = 1;
 #endif
 
@@ -1848,6 +1895,5 @@
     #ifdef KEEP_OUR_CERT
         if (ctx->ourCert && ctx->ownOurCert) {
-            FreeX509(ctx->ourCert);
-            XFREE(ctx->ourCert, ctx->heap, DYNAMIC_TYPE_X509);
+            wolfSSL_X509_free(ctx->ourCert);
             ctx->ourCert = NULL;
         }
@@ -1857,8 +1903,4 @@
     ctx->cm = NULL;
     #ifdef OPENSSL_EXTRA
-    /* ctx->cm was free'd so cm of x509 store should now be NULL */
-        if (ctx->x509_store_pt != NULL) {
-            ctx->x509_store_pt->cm = NULL;
-        }
         wolfSSL_X509_STORE_free(ctx->x509_store_pt);
         while (ctx->ca_names != NULL) {
@@ -1870,9 +1912,7 @@
     #endif
     #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
-        while (ctx->x509Chain != NULL) {
-            WOLFSSL_STACK *next = ctx->x509Chain->next;
-            wolfSSL_X509_free(ctx->x509Chain->data.x509);
-            XFREE(ctx->x509Chain, NULL, DYNAMIC_TYPE_OPENSSL);
-            ctx->x509Chain = next;
+        if (ctx->x509Chain) {
+            wolfSSL_sk_X509_free(ctx->x509Chain);
+            ctx->x509Chain = NULL;
         }
     #endif
@@ -1908,4 +1948,14 @@
         ctx->alpn_cli_protos = NULL;
     }
+#endif
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+    #ifndef NO_DH
+    if (ctx->staticKE.dhKey)
+        FreeDer(&ctx->staticKE.dhKey);
+    #endif
+    #ifdef HAVE_ECC
+    if (ctx->staticKE.ecKey)
+        FreeDer(&ctx->staticKE.ecKey);
+    #endif
 #endif
 #ifdef WOLFSSL_STATIC_MEMORY
@@ -1943,4 +1993,8 @@
         WOLFSSL_MSG("CTX ref count down to 0, doing full free");
         SSL_CtxResourceFree(ctx);
+#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) && \
+    !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
+        TicketEncCbCtx_Free(&ctx->ticketKeyCtx);
+#endif
         wc_FreeMutex(&ctx->countMutex);
 #ifdef WOLFSSL_STATIC_MEMORY
@@ -3334,7 +3388,8 @@
 #ifndef NO_CERTS
 
-void InitX509Name(WOLFSSL_X509_NAME* name, int dynamicFlag)
+void InitX509Name(WOLFSSL_X509_NAME* name, int dynamicFlag, void* heap)
 {
     (void)dynamicFlag;
+    (void)heap;
 
     if (name != NULL) {
@@ -3342,11 +3397,9 @@
         name->dynamicName = 0;
         name->sz = 0;
+        name->heap = heap;
 #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
-        XMEMSET(&name->fullName, 0, sizeof(DecodedName));
-        XMEMSET(&name->cnEntry,  0, sizeof(WOLFSSL_X509_NAME_ENTRY));
-        XMEMSET(&name->extra,    0, sizeof(name->extra));
-        name->cnEntry.value = &(name->cnEntry.data); /* point to internal data*/
-        name->cnEntry.nid = ASN_COMMON_NAME;
+        XMEMSET(name->entry, 0, sizeof(name->entry));
         name->x509 = NULL;
+        name->entrySz = 0;
 #endif /* OPENSSL_EXTRA */
     }
@@ -3354,9 +3407,9 @@
 
 
-void FreeX509Name(WOLFSSL_X509_NAME* name, void* heap)
+void FreeX509Name(WOLFSSL_X509_NAME* name)
 {
     if (name != NULL) {
         if (name->dynamicName) {
-            XFREE(name->name, heap, DYNAMIC_TYPE_SUBJECT_CN);
+            XFREE(name->name, name->heap, DYNAMIC_TYPE_SUBJECT_CN);
             name->name = NULL;
         }
@@ -3364,19 +3417,13 @@
         {
             int i;
-            if (name->fullName.fullName != NULL) {
-                XFREE(name->fullName.fullName, heap, DYNAMIC_TYPE_X509);
-                name->fullName.fullName = NULL;
-            }
             for (i = 0; i < MAX_NAME_ENTRIES; i++) {
-                /* free ASN1 string data */
-                if (name->extra[i].set && name->extra[i].data.data != NULL) {
-                    XFREE(name->extra[i].data.data, heap, DYNAMIC_TYPE_OPENSSL);
+                if (name->entry[i].set) {
+                    wolfSSL_ASN1_OBJECT_free(name->entry[i].object);
+                    wolfSSL_ASN1_STRING_free(name->entry[i].value);
                 }
             }
-            wolfSSL_ASN1_OBJECT_free(&name->cnEntry.object);
         }
 #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
     }
-    (void)heap;
 }
 
@@ -3393,6 +3440,6 @@
 
     x509->heap = heap;
-    InitX509Name(&x509->issuer, 0);
-    InitX509Name(&x509->subject, 0);
+    InitX509Name(&x509->issuer, 0, heap);
+    InitX509Name(&x509->subject, 0, heap);
     x509->dynamicMemory  = (byte)dynamicFlag;
     #if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)
@@ -3409,6 +3456,6 @@
         return;
 
-    FreeX509Name(&x509->issuer, x509->heap);
-    FreeX509Name(&x509->subject, x509->heap);
+    FreeX509Name(&x509->issuer);
+    FreeX509Name(&x509->subject);
     if (x509->pubKey.buffer) {
         XFREE(x509->pubKey.buffer, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY);
@@ -3434,4 +3481,7 @@
             wolfSSL_sk_X509_EXTENSION_free(x509->ext_sk);
         }
+        if (x509->ext_sk_full != NULL) {
+            wolfSSL_sk_X509_EXTENSION_free(x509->ext_sk_full);
+        }
         #endif /* OPENSSL_ALL || WOLFSSL_QT */
         #ifdef OPENSSL_EXTRA
@@ -3460,4 +3510,9 @@
         }
     #endif /* OPENSSL_ALL */
+    #if defined(WOLFSSL_CERT_REQ) && defined(OPENSSL_ALL)
+        if (x509->challengePwAttr) {
+            wolfSSL_X509_ATTRIBUTE_free(x509->challengePwAttr);
+        }
+    #endif /* WOLFSSL_CERT_REQ */
     if (x509->altNames) {
         FreeAltNames(x509->altNames, x509->heap);
@@ -3571,6 +3626,5 @@
 #ifndef NO_RSA
 #ifndef WOLFSSL_NO_TLS12
-#if !defined(NO_WOLFSSL_SERVER) || (!defined(NO_WOLFSSL_CLIENT) && \
-                                               !defined(WOLFSSL_NO_CLIENT_AUTH))
+#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT)
 static int TypeHash(int hashAlgo)
 {
@@ -4257,5 +4311,11 @@
 #endif
     {
-        ret = wc_ecc_shared_secret(priv_key, pub_key, out, outlen);
+#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
+    !defined(HAVE_SELFTEST)
+        ret = wc_ecc_set_rng(priv_key, ssl->rng);
+        if (ret == 0)
+#endif
+            ret = wc_ecc_shared_secret(priv_key, pub_key, out, outlen);
     }
 
@@ -4288,9 +4348,10 @@
 
     /* get key size */
-    if (peer == NULL) {
+    if (peer == NULL || peer->dp == NULL) {
         keySz = ssl->eccTempKeySz;
     }
     else {
         keySz = peer->dp->size;
+        ecc_curve = peer->dp->id;
     }
 
@@ -5259,4 +5320,62 @@
     ssl->ctx     = ctx; /* only for passing to calls, options could change */
     ssl->version = ctx->method->version;
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
+    ssl->options.mask = ctx->mask;
+#endif
+#ifdef OPENSSL_EXTRA
+    if (ssl->version.minor == TLSv1_3_MINOR &&
+     (ssl->options.mask & SSL_OP_NO_TLSv1_3) == SSL_OP_NO_TLSv1_3) {
+        if (!ctx->method->downgrade) {
+            WOLFSSL_MSG("\tInconsistent protocol options. TLS 1.3 set but not "
+                        "allowed and downgrading disabled.");
+            return VERSION_ERROR;
+        }
+        WOLFSSL_MSG("\tOption set to not allow TLSv1.3, Downgrading");
+        ssl->version.minor = TLSv1_2_MINOR;
+    }
+    if (ssl->version.minor == TLSv1_2_MINOR &&
+     (ssl->options.mask & SSL_OP_NO_TLSv1_2) == SSL_OP_NO_TLSv1_2) {
+        if (!ctx->method->downgrade) {
+            WOLFSSL_MSG("\tInconsistent protocol options. TLS 1.2 set but not "
+                        "allowed and downgrading disabled.");
+            return VERSION_ERROR;
+        }
+        WOLFSSL_MSG("\tOption set to not allow TLSv1.2, Downgrading");
+        ssl->version.minor = TLSv1_1_MINOR;
+    }
+    if (ssl->version.minor == TLSv1_1_MINOR &&
+     (ssl->options.mask & SSL_OP_NO_TLSv1_1) == SSL_OP_NO_TLSv1_1) {
+        if (!ctx->method->downgrade) {
+            WOLFSSL_MSG("\tInconsistent protocol options. TLS 1.1 set but not "
+                        "allowed and downgrading disabled.");
+            return VERSION_ERROR;
+        }
+        WOLFSSL_MSG("\tOption set to not allow TLSv1.1, Downgrading");
+        ssl->options.tls1_1 = 0;
+        ssl->version.minor = TLSv1_MINOR;
+    }
+    if (ssl->version.minor == TLSv1_MINOR &&
+        (ssl->options.mask & SSL_OP_NO_TLSv1) == SSL_OP_NO_TLSv1) {
+        if (!ctx->method->downgrade) {
+            WOLFSSL_MSG("\tInconsistent protocol options. TLS 1 set but not "
+                        "allowed and downgrading disabled.");
+            return VERSION_ERROR;
+        }
+        WOLFSSL_MSG("\tOption set to not allow TLSv1, Downgrading");
+        ssl->options.tls    = 0;
+        ssl->options.tls1_1 = 0;
+        ssl->version.minor = SSLv3_MINOR;
+    }
+    if (ssl->version.minor == SSLv3_MINOR &&
+        (ssl->options.mask & SSL_OP_NO_SSLv3) == SSL_OP_NO_SSLv3) {
+        WOLFSSL_MSG("\tError, option set to not allow SSLv3");
+        return VERSION_ERROR;
+    }
+
+    if (ssl->version.minor < ssl->options.minDowngrade) {
+        WOLFSSL_MSG("\tversion below minimum allowed, fatal error");
+        return VERSION_ERROR;
+    }
+#endif
 
 #ifdef HAVE_ECC
@@ -5269,5 +5388,4 @@
 
 #ifdef OPENSSL_EXTRA
-    ssl->options.mask = ctx->mask;
     ssl->CBIS         = ctx->CBIS;
 #endif
@@ -5285,7 +5403,8 @@
 
 #ifndef NO_PSK
-    ssl->options.havePSK   = ctx->havePSK;
+    ssl->options.havePSK       = ctx->havePSK;
     ssl->options.client_psk_cb = ctx->client_psk_cb;
     ssl->options.server_psk_cb = ctx->server_psk_cb;
+    ssl->options.psk_ctx       = ctx->psk_ctx;
 #ifdef WOLFSSL_TLS13
     ssl->options.client_psk_tls13_cb = ctx->client_psk_tls13_cb;
@@ -5350,4 +5469,5 @@
     ssl->buffers.keyType  = ctx->privateKeyType;
     ssl->buffers.keyId    = ctx->privateKeyId;
+    ssl->buffers.keyLabel = ctx->privateKeyLabel;
     ssl->buffers.keySz    = ctx->privateKeySz;
     ssl->buffers.keyDevId = ctx->privateKeyDevId;
@@ -5391,4 +5511,11 @@
         }
     }  /* writeDup check */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
+    if (ctx->mask != 0 && wolfSSL_set_options(ssl, ctx->mask) == 0) {
+        WOLFSSL_MSG("wolfSSL_set_options error");
+        return BAD_FUNC_ARG;
+    }
+#endif
 
 #ifdef WOLFSSL_SESSION_EXPORT
@@ -5687,4 +5814,8 @@
 #endif
 
+#if defined(WOLFSSL_OPENVPN) && defined(HAVE_KEYING_MATERIAL)
+    /* Save arrays by default for OpenVPN */
+    ssl->options.saveArrays = 1;
+#endif
 
     ssl->cipher.ssl = ssl;
@@ -5695,4 +5826,8 @@
     ssl->options.useClientOrder = ctx->useClientOrder;
     ssl->options.mutualAuth = ctx->mutualAuth;
+
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+    ssl->staticKE = ctx->staticKE;
+#endif
 
 #ifdef WOLFSSL_TLS13
@@ -5871,4 +6006,5 @@
 
 #ifdef HAVE_SESSION_TICKET
+    ssl->options.noTicketTls12 = ctx->noTicketTls12;
     ssl->session.ticket = ssl->session.staticTicket;
 #endif
@@ -6045,5 +6181,5 @@
 
     /* Allocate memory for key */
-    *pKey = XMALLOC(sz, ssl->heap, type);
+    *pKey = (void *)XMALLOC(sz, ssl->heap, type);
     if (*pKey == NULL) {
         return MEMORY_E;
@@ -6192,4 +6328,5 @@
         ssl->async.freeArgs = NULL;
     }
+    FreeBuildMsgArgs(ssl, &ssl->async.buildArgs);
 #endif
 }
@@ -6289,4 +6426,5 @@
 #endif /* WOLFSSL_DTLS */
 #ifdef OPENSSL_EXTRA
+#ifndef NO_BIO
     if (ssl->biord != ssl->biowr)        /* only free write if different */
         wolfSSL_BIO_free(ssl->biowr);
@@ -6294,4 +6432,5 @@
     ssl->biowr = NULL;
     ssl->biord = NULL;
+#endif
 #endif
 #ifdef HAVE_LIBZ
@@ -6424,4 +6563,14 @@
     }
 #endif
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+    #ifndef NO_DH
+    if (ssl->staticKE.dhKey && ssl->staticKE.dhKey != ssl->ctx->staticKE.dhKey)
+        FreeDer(&ssl->staticKE.dhKey);
+    #endif
+    #ifdef HAVE_ECC
+    if (ssl->staticKE.ecKey && ssl->staticKE.ecKey != ssl->ctx->staticKE.ecKey)
+        FreeDer(&ssl->staticKE.ecKey);
+    #endif
+#endif
 
 #ifdef WOLFSSL_STATIC_MEMORY
@@ -6471,4 +6620,15 @@
 void FreeHandshakeResources(WOLFSSL* ssl)
 {
+    WOLFSSL_ENTER("FreeHandshakeResources");
+
+#ifdef WOLFSSL_DTLS
+    /* DTLS_POOL */
+    if (ssl->options.dtls) {
+        DtlsMsgPoolReset(ssl);
+        DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap);
+        ssl->dtls_rx_msg_list = NULL;
+        ssl->dtls_rx_msg_list_sz = 0;
+    }
+#endif
 
 #ifdef HAVE_SECURE_RENEGOTIATION
@@ -6515,14 +6675,4 @@
         }
     }
-
-#ifdef WOLFSSL_DTLS
-    /* DTLS_POOL */
-    if (ssl->options.dtls) {
-        DtlsMsgPoolReset(ssl);
-        DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap);
-        ssl->dtls_rx_msg_list = NULL;
-        ssl->dtls_rx_msg_list_sz = 0;
-    }
-#endif
 
 #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) && \
@@ -6566,23 +6716,24 @@
     #ifdef HAVE_ECC
         dtype = DYNAMIC_TYPE_ECC;
+    #elif defined(HAVE_CURVE25519)
+        dtype = DYNAMIC_TYPE_CURVE25519;
+    #else
+        dtype = DYNAMIC_TYPE_CURVE448;
     #endif
-    #ifdef HAVE_CURVE25519
-    #ifdef HAVE_ECC
+    #if defined(HAVE_ECC) && defined(HAVE_CURVE25519)
         if (ssl->peerX25519KeyPresent ||
                               ssl->eccTempKeyPresent == DYNAMIC_TYPE_CURVE25519)
-    #endif /* HAVE_ECC */
          {
             dtype = DYNAMIC_TYPE_CURVE25519;
          }
-    #endif /* HAVE_CURVE25519 */
-    #ifdef HAVE_CURVE448
-    #ifdef HAVE_ECC
+    #endif
+    #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                          defined(HAVE_CURVE448)
         if (ssl->peerX448KeyPresent ||
                                 ssl->eccTempKeyPresent == DYNAMIC_TYPE_CURVE448)
-    #endif /* HAVE_ECC */
          {
             dtype = DYNAMIC_TYPE_CURVE448;
          }
-    #endif /* HAVE_CURVE448 */
+    #endif
         FreeKey(ssl, dtype, (void**)&ssl->eccTempKey);
         ssl->eccTempKeyPresent = 0;
@@ -6701,4 +6852,5 @@
 
 #if !defined(NO_OLD_TLS) || defined(WOLFSSL_DTLS) || \
+    !defined(WOLFSSL_NO_TLS12) || \
     ((defined(HAVE_CHACHA) || defined(HAVE_AESCCM) || defined(HAVE_AESGCM)) \
      && defined(HAVE_AEAD))
@@ -6730,4 +6882,7 @@
 static WC_INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2])
 {
+#ifdef HAVE_SECURE_RENEGOTIATION
+    order = DtlsCheckOrder(ssl, order);
+#endif
     if (order == PREV_ORDER) {
         /* Previous epoch case */
@@ -6775,4 +6930,7 @@
 {
     word32 seq;
+#ifdef HAVE_SECURE_RENEGOTIATION
+    order = DtlsCheckOrder(ssl, order);
+#endif
 
     if (order == PREV_ORDER) {
@@ -6801,5 +6959,5 @@
 
 #if defined(WOLFSSL_DTLS) || !defined(WOLFSSL_NO_TLS12)
-static WC_INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
+void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
 {
     word32 seq[2] = {0, 0};
@@ -6818,5 +6976,5 @@
 }
 #endif /* WOLFSSL_DTLS || !WOLFSSL_NO_TLS12 */
-#endif /* !NO_OLD_TLS || WOLFSSL_DTLS ||
+#endif /* !NO_OLD_TLS || WOLFSSL_DTLS || !WOLFSSL_NO_TLS12 ||
         *     ((HAVE_CHACHA || HAVE_AESCCM || HAVE_AESGCM) && HAVE_AEAD) */
 
@@ -6833,4 +6991,5 @@
 {
     DtlsMsg* msg;
+    WOLFSSL_ENTER("DtlsMsgNew()");
 
     (void)heap;
@@ -6858,4 +7017,5 @@
 {
     (void)heap;
+    WOLFSSL_ENTER("DtlsMsgDelete()");
 
     if (item != NULL) {
@@ -6876,4 +7036,5 @@
 {
     DtlsMsg* next;
+    WOLFSSL_ENTER("DtlsMsgListDelete()");
     while (head) {
         next = head->next;
@@ -6883,4 +7044,27 @@
 }
 
+/**
+ * Drop messages when they are no longer going to be retransmitted
+ */
+void DtlsTxMsgListClean(WOLFSSL* ssl)
+{
+    DtlsMsg* head = ssl->dtls_tx_msg_list;
+    DtlsMsg* next;
+    WOLFSSL_ENTER("DtlsTxMsgListClean()");
+    while (head) {
+        next = head->next;
+        if (VerifyForTxDtlsMsgDelete(ssl, head))
+            DtlsMsgDelete(head, ssl->heap);
+        else
+            /* Stored packets should be in order so break on first failed
+             * verify */
+            break;
+        ssl->dtls_tx_msg_list_sz--;
+        /* Reset timer as deleting a node means that state has progressed */
+        ssl->dtls_timeout = ssl->dtls_timeout_init;
+        head = next;
+    }
+    ssl->dtls_tx_msg_list = head;
+}
 
 /* Create a DTLS Fragment from *begin - end, adjust new *begin and bytesLeft */
@@ -6890,4 +7074,6 @@
     DtlsFrag* newFrag;
     word32 added = end - *begin + 1;
+
+    WOLFSSL_ENTER("CreateFragment()");
 
     (void)heap;
@@ -6908,7 +7094,8 @@
 
 
-int DtlsMsgSet(DtlsMsg* msg, word32 seq, const byte* data, byte type,
+int DtlsMsgSet(DtlsMsg* msg, word32 seq, word16 epoch, const byte* data, byte type,
                                    word32 fragOffset, word32 fragSz, void* heap)
 {
+    WOLFSSL_ENTER("DtlsMsgSet()");
     if (msg != NULL && data != NULL && msg->fragSz <= msg->sz &&
                                              (fragOffset + fragSz) <= msg->sz) {
@@ -6921,4 +7108,5 @@
 
         msg->seq = seq;
+        msg->epoch = epoch;
         msg->type = type;
 
@@ -7009,7 +7197,8 @@
 
 
-DtlsMsg* DtlsMsgFind(DtlsMsg* head, word32 seq)
+DtlsMsg* DtlsMsgFind(DtlsMsg* head, word32 epoch, word32 seq)
 {
-    while (head != NULL && head->seq != seq) {
+    WOLFSSL_ENTER("DtlsMsgFind()");
+    while (head != NULL && !(head->epoch == epoch && head->seq == seq)) {
         head = head->next;
     }
@@ -7018,5 +7207,5 @@
 
 
-void DtlsMsgStore(WOLFSSL* ssl, word32 seq, const byte* data,
+void DtlsMsgStore(WOLFSSL* ssl, word32 epoch, word32 seq, const byte* data,
         word32 dataSz, byte type, word32 fragOffset, word32 fragSz, void* heap)
 {
@@ -7039,12 +7228,13 @@
 
     DtlsMsg* head = ssl->dtls_rx_msg_list;
+    WOLFSSL_ENTER("DtlsMsgStore()");
 
     if (head != NULL) {
-        DtlsMsg* cur = DtlsMsgFind(head, seq);
+        DtlsMsg* cur = DtlsMsgFind(head, epoch, seq);
         if (cur == NULL) {
             cur = DtlsMsgNew(dataSz, heap);
             if (cur != NULL) {
-                if (DtlsMsgSet(cur, seq, data, type,
-                                                fragOffset, fragSz, heap) < 0) {
+                if (DtlsMsgSet(cur, seq, epoch, data, type,
+                                               fragOffset, fragSz, heap) < 0) {
                     DtlsMsgDelete(cur, heap);
                 }
@@ -7057,10 +7247,12 @@
         else {
             /* If this fails, the data is just dropped. */
-            DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz, heap);
+            DtlsMsgSet(cur, seq, epoch, data, type, fragOffset,
+                    fragSz, heap);
         }
     }
     else {
         head = DtlsMsgNew(dataSz, heap);
-        if (DtlsMsgSet(head, seq, data, type, fragOffset, fragSz, heap) < 0) {
+        if (DtlsMsgSet(head, seq, epoch, data, type, fragOffset,
+                    fragSz, heap) < 0) {
             DtlsMsgDelete(head, heap);
             head = NULL;
@@ -7078,5 +7270,7 @@
 DtlsMsg* DtlsMsgInsert(DtlsMsg* head, DtlsMsg* item)
 {
-    if (head == NULL || item->seq < head->seq) {
+    WOLFSSL_ENTER("DtlsMsgInsert()");
+    if (head == NULL || (item->epoch <= head->epoch &&
+                         item->seq   <  head->seq)) {
         item->next = head;
         head = item;
@@ -7089,5 +7283,6 @@
         DtlsMsg* prev = head;
         while (cur) {
-            if (item->seq < cur->seq) {
+            if (item->epoch <= cur->epoch &&
+                item->seq   <  cur->seq) {
                 item->next = cur;
                 prev->next = item;
@@ -7106,6 +7301,11 @@
 
 
-/* DtlsMsgPoolSave() adds the message to the end of the stored transmit list. */
-int DtlsMsgPoolSave(WOLFSSL* ssl, const byte* data, word32 dataSz)
+/**
+ * DtlsMsgPoolSave() adds the message to the end of the stored transmit
+ * list. Must be called BEFORE BuildMessage or DtlsSEQIncrement or
+ * anything else that increments ssl->keys.dtls_handshake_number.
+ */
+int DtlsMsgPoolSave(WOLFSSL* ssl, const byte* data, word32 dataSz,
+                    enum HandShakeType type)
 {
     DtlsMsg* item;
@@ -7126,5 +7326,7 @@
         XMEMCPY(item->buf, data, dataSz);
         item->sz = dataSz;
-        item->seq = ssl->keys.dtls_epoch;
+        item->epoch = ssl->keys.dtls_epoch;
+        item->seq = ssl->keys.dtls_handshake_number;
+        item->type = type;
 
         if (cur == NULL)
@@ -7149,4 +7351,5 @@
 {
     int result = -1;
+    WOLFSSL_ENTER("DtlsMsgPoolTimeout()");
     if (ssl->dtls_timeout <  ssl->dtls_timeout_max) {
         ssl->dtls_timeout *= DTLS_TIMEOUT_MULTIPLIER;
@@ -7168,6 +7371,6 @@
         ssl->dtls_tx_msg = NULL;
         ssl->dtls_tx_msg_list_sz = 0;
-        ssl->dtls_timeout = ssl->dtls_timeout_init;
-    }
+    }
+    ssl->dtls_timeout = ssl->dtls_timeout_init;
 }
 
@@ -7186,5 +7389,41 @@
              ((!ssl->options.verifyPeer) && (type == client_key_exchange)))) ||
             ((ssl->options.side == WOLFSSL_CLIENT_END) &&
-             (type == server_hello))));
+             (type == hello_request || type == server_hello))));
+}
+
+
+/**
+ * Verify if message `item` from `ssl->dtls_tx_msg_list` should be deleted
+ * depending on the current state of the handshake negotiation.
+ */
+int VerifyForTxDtlsMsgDelete(WOLFSSL* ssl, DtlsMsg* item)
+{
+    WOLFSSL_ENTER("VerifyForTxDtlsMsgDelete()");
+    if (item->epoch < ssl->keys.dtls_epoch - 1)
+        /* Messages not from current or previous epoch can be deleted */
+        return 1;
+    switch (ssl->options.side) {
+    case WOLFSSL_CLIENT_END:
+        if (item->type == client_hello &&
+                ssl->options.serverState >= SERVER_HELLODONE_COMPLETE)
+            return 1; /* client can forget first client_hello if received full
+                       * flight of packets from server */
+        else
+            return 0;
+    case WOLFSSL_SERVER_END:
+        if (ssl->options.clientState >= CLIENT_HELLO_COMPLETE &&
+                item->type == hello_request)
+            return 1; /* Server can forget HelloRequest if client sent a valid
+                       * ClientHello */
+        if (ssl->options.clientState >= CLIENT_FINISHED_COMPLETE &&
+                item->type <= server_hello_done)
+            return 1; /* server can forget everything up to ServerHelloDone if
+                       * a client finished message has been received and
+                       * successfully processed */
+        else
+            return 0;
+    default:
+        return 0;
+    }
 }
 
@@ -7196,4 +7435,5 @@
     int ret = 0;
     DtlsMsg* pool;
+    int epochOrder;
 
     WOLFSSL_ENTER("DtlsMsgPoolSend()");
@@ -7203,5 +7443,6 @@
     if (pool != NULL) {
         if ((ssl->options.side == WOLFSSL_SERVER_END &&
-             !(ssl->options.acceptState == SERVER_HELLO_DONE ||
+             !(ssl->options.acceptState == ACCEPT_BEGIN_RENEG ||
+               ssl->options.acceptState == SERVER_HELLO_DONE ||
                ssl->options.acceptState == ACCEPT_FINISHED_DONE ||
                ssl->options.acceptState == ACCEPT_THIRD_REPLY_DONE)) ||
@@ -7218,7 +7459,6 @@
 
         while (pool != NULL) {
-            if (pool->seq == 0) {
+            if (pool->epoch == 0) {
                 DtlsRecordLayerHeader* dtls;
-                int epochOrder;
 
                 dtls = (DtlsRecordLayerHeader*)pool->buf;
@@ -7238,10 +7478,12 @@
                 }
 
-                XMEMCPY(ssl->buffers.outputBuffer.buffer,
+                XMEMCPY(ssl->buffers.outputBuffer.buffer +
+                        ssl->buffers.outputBuffer.idx +
+                        ssl->buffers.outputBuffer.length,
                         pool->buf, pool->sz);
-                ssl->buffers.outputBuffer.idx = 0;
-                ssl->buffers.outputBuffer.length = pool->sz;
-            }
-            else if (pool->seq == ssl->keys.dtls_epoch) {
+                ssl->buffers.outputBuffer.length += pool->sz;
+            }
+            else {
+                /* Handle sending packets from previous epoch */
                 byte*  input;
                 byte*  output;
@@ -7251,4 +7493,24 @@
                 inputSz = pool->sz;
                 sendSz = inputSz + MAX_MSG_EXTRA;
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+                /*
+                 * CUR_ORDER will use ssl->secure_renegotiation from epoch 2+.
+                 * ssl->keys otherwise
+                 * PREV_ORDER will always use ssl->keys
+                 */
+                if (DtlsSCRKeysSet(ssl)) {
+                    if (pool->epoch == ssl->secure_renegotiation->tmp_keys.dtls_epoch)
+                        epochOrder = CUR_ORDER;
+                    else
+                        epochOrder = PREV_ORDER;
+                }
+                else {
+                    epochOrder = CUR_ORDER;
+                }
+#else
+                epochOrder = CUR_ORDER;
+#endif
+
 
                 if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) {
@@ -7259,6 +7521,13 @@
                 output = ssl->buffers.outputBuffer.buffer +
                          ssl->buffers.outputBuffer.length;
-                sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
-                                      handshake, 0, 0, 0);
+                if (inputSz != ENUM_LEN)
+                    sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
+                                          handshake, 0, 0, 0, epochOrder);
+                else
+                    /* inputSz == ENUM_LEN must mean that this is a change cipher
+                     * spec message */
+                    sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
+                                          change_cipher_spec, 0, 0, 0, epochOrder);
+
                 if (sendSz < 0) {
                     WOLFSSL_ERROR(BUILD_MSG_ERROR);
@@ -7269,9 +7538,7 @@
             }
 
-            ret = SendBuffered(ssl);
-            if (ret < 0) {
-                WOLFSSL_ERROR(ret);
-                return ret;
-            }
+
+            if (!ssl->options.groupMessages)
+                ret = SendBuffered(ssl);
 
             /**
@@ -7284,12 +7551,13 @@
              */
             if (sendOnlyFirstPacket &&
-                ssl->options.side == WOLFSSL_SERVER_END) {
-
+                ssl->options.side == WOLFSSL_SERVER_END)
                 pool = NULL;
-            }
             else
                 pool = pool->next;
             ssl->dtls_tx_msg = pool;
         }
+
+        if (ret == 0 && ssl->options.groupMessages)
+            ret = SendBuffered(ssl);
     }
 
@@ -7398,6 +7666,6 @@
     word32 LowResTimer(void)
     {
-        const uint32_t systemTickTimeInHz = 1000000 / systemTickInMicroseconds();
-        uint32_t *systemTickPtr = systemTickPointer();
+        const word32 systemTickTimeInHz = 1000000 / systemTickInMicroseconds();
+        word32 *systemTickPtr = systemTickPointer();
 
         return (word32) *systemTickPtr/systemTickTimeInHz;
@@ -7543,4 +7811,12 @@
     {
         return k_uptime_get() / 1000;
+    }
+
+#elif defined(WOLFSSL_LINUXKM)
+    #include <linux/time.h>
+    #include <linux/ktime.h>
+    word32 LowResTimer(void)
+    {
+        return (word32)ktime_get_real_ns();
     }
 
@@ -7590,25 +7866,21 @@
 #endif /* (HAVE_ED25519 || HAVE_ED448) && !WOLFSSL_NO_CLIENT_AUTH */
 
-#ifndef NO_CERTS
-int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz)
+int HashRaw(WOLFSSL* ssl, const byte* data, int sz)
 {
     int ret = 0;
 
-    (void)output;
+    (void)data;
     (void)sz;
 
-    if (ssl->hsHashes == NULL)
+    if (ssl->hsHashes == NULL) {
         return BAD_FUNC_ARG;
-
-#ifdef HAVE_FUZZER
-    if (ssl->fuzzerCb)
-        ssl->fuzzerCb(ssl, output, sz, FUZZ_HASH, ssl->fuzzerCtx);
-#endif
+    }
+
 #ifndef NO_OLD_TLS
     #ifndef NO_SHA
-        wc_ShaUpdate(&ssl->hsHashes->hashSha, output, sz);
+        wc_ShaUpdate(&ssl->hsHashes->hashSha, data, sz);
     #endif
     #ifndef NO_MD5
-        wc_Md5Update(&ssl->hsHashes->hashMd5, output, sz);
+        wc_Md5Update(&ssl->hsHashes->hashMd5, data, sz);
     #endif
 #endif /* NO_OLD_TLS */
@@ -7616,15 +7888,15 @@
     if (IsAtLeastTLSv1_2(ssl)) {
     #ifndef NO_SHA256
-        ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, output, sz);
+        ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, data, sz);
         if (ret != 0)
             return ret;
     #endif
     #ifdef WOLFSSL_SHA384
-        ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, output, sz);
+        ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, data, sz);
         if (ret != 0)
             return ret;
     #endif
     #ifdef WOLFSSL_SHA512
-        ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, output, sz);
+        ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, data, sz);
         if (ret != 0)
             return ret;
@@ -7633,5 +7905,5 @@
                ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \
                 (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH)))
-        ret = EdDSA_Update(ssl, output, sz);
+        ret = EdDSA_Update(ssl, data, sz);
         if (ret != 0)
             return ret;
@@ -7641,11 +7913,8 @@
     return ret;
 }
-#endif /* NO_CERTS */
-
 
 /* add output to md5 and sha handshake hashes, exclude record header */
 int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz)
 {
-    int ret = 0;
     const byte* adj;
 
@@ -7666,39 +7935,6 @@
     }
 #endif
-#ifndef NO_OLD_TLS
-    #ifndef NO_SHA
-        wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz);
-    #endif
-    #ifndef NO_MD5
-        wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz);
-    #endif
-#endif
-
-    if (IsAtLeastTLSv1_2(ssl)) {
-    #ifndef NO_SHA256
-        ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    #ifdef WOLFSSL_SHA384
-        ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    #ifdef WOLFSSL_SHA512
-        ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \
-               ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \
-                (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH)))
-        ret = EdDSA_Update(ssl, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    }
-
-    return ret;
+
+    return HashRaw(ssl, adj, sz);
 }
 
@@ -7707,11 +7943,12 @@
 int HashInput(WOLFSSL* ssl, const byte* input, int sz)
 {
-    int ret = 0;
     const byte* adj;
+
+    if (ssl->hsHashes == NULL) {
+        return BAD_FUNC_ARG;
+    }
 
     adj = input - HANDSHAKE_HEADER_SZ;
     sz += HANDSHAKE_HEADER_SZ;
-
-    (void)adj;
 
 #ifdef WOLFSSL_DTLS
@@ -7722,50 +7959,14 @@
 #endif
 
-    if (ssl->hsHashes == NULL) {
-        return BAD_FUNC_ARG;
-    }
-
-#ifndef NO_OLD_TLS
-    #ifndef NO_SHA
-        wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz);
-    #endif
-    #ifndef NO_MD5
-        wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz);
-    #endif
-#endif
-
-    if (IsAtLeastTLSv1_2(ssl)) {
-    #ifndef NO_SHA256
-        ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    #ifdef WOLFSSL_SHA384
-        ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    #ifdef WOLFSSL_SHA512
-        ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \
-               ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \
-                (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH)))
-        ret = EdDSA_Update(ssl, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    }
-
-    return ret;
+    return HashRaw(ssl, adj, sz);
 }
 
 
 /* add record layer header for message */
-static void AddRecordHeader(byte* output, word32 length, byte type, WOLFSSL* ssl)
+static void AddRecordHeader(byte* output, word32 length, byte type, WOLFSSL* ssl, int epochOrder)
 {
     RecordLayerHeader* rl;
+
+    (void)epochOrder;
 
     /* record layer header */
@@ -7778,9 +7979,5 @@
 #ifdef WOLFSSL_TLS13
     if (IsAtLeastTLSv1_3(ssl->version)) {
-#ifdef WOLFSSL_TLS13_DRAFT_18
-        rl->pvMinor = TLSv1_MINOR;
-#else
         rl->pvMinor = TLSv1_2_MINOR;
-#endif
     }
     else
@@ -7806,5 +8003,5 @@
         /* dtls record layer header extensions */
         dtls = (DtlsRecordLayerHeader*)output;
-        WriteSEQ(ssl, 0, dtls->sequence_number);
+        WriteSEQ(ssl, epochOrder, dtls->sequence_number);
         c16toa((word16)length, dtls->length);
 #endif
@@ -7858,5 +8055,5 @@
 #endif
 
-    AddRecordHeader(output, length + lengthAdj, handshake, ssl);
+    AddRecordHeader(output, length + lengthAdj, handshake, ssl, CUR_ORDER);
     AddHandShakeHeader(output + outputAdj, length, 0, length, type, ssl);
 }
@@ -7881,5 +8078,5 @@
 #endif
 
-    AddRecordHeader(output, fragSz + lengthAdj, handshake, ssl);
+    AddRecordHeader(output, fragSz + lengthAdj, handshake, ssl, CUR_ORDER);
     AddHandShakeHeader(output + outputAdj, length, fragOffset, fragSz, type, ssl);
 }
@@ -7904,4 +8101,5 @@
             case WOLFSSL_CBIO_ERR_GENERAL:        /* general/unknown error */
                 #if defined(OPENSSL_ALL) || defined(WOLFSSL_APACHE_HTTPD)
+                #ifndef NO_BIO
                     if (ssl->biord) {
                         /* If retry and read flags are set, return WANT_READ */
@@ -7911,4 +8109,5 @@
                         }
                     }
+                #endif
                 #endif
                 return -1;
@@ -7953,5 +8152,5 @@
             #ifdef WOLFSSL_DTLS
                 if (IsDtlsNotSctpMode(ssl) &&
-                    !ssl->options.handShakeDone &&
+                    ssl->options.handShakeState != HANDSHAKE_DONE &&
                     DtlsMsgPoolTimeout(ssl) == 0 &&
                     DtlsMsgPoolSend(ssl, 0) == 0) {
@@ -8236,5 +8435,8 @@
 
 
-/* check available size into output buffer, make room if needed */
+/* Check available size into output buffer, make room if needed.
+ * This function needs to be called before anything gets put
+ * into the output buffers since it flushes pending data if it
+ * predicts that the msg will exceed MTU. */
 int CheckAvailableSize(WOLFSSL *ssl, int size)
 {
@@ -8243,4 +8445,17 @@
         return BAD_FUNC_ARG;
     }
+
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls &&
+            size + ssl->buffers.outputBuffer.length -
+            ssl->buffers.outputBuffer.idx > ssl->dtls_expected_rx) {
+        int ret;
+        WOLFSSL_MSG("CheckAvailableSize() flushing buffer "
+                    "to make room for new message");
+        if ((ret = SendBuffered(ssl)) != 0) {
+            return ret;
+        }
+    }
+#endif
 
     if (ssl->buffers.outputBuffer.bufferSize - ssl->buffers.outputBuffer.length
@@ -8297,7 +8512,12 @@
 
 #ifdef WOLFSSL_DTLS
-    if (IsDtlsNotSctpMode(ssl) && !DtlsCheckWindow(ssl)) {
+    if (IsDtlsNotSctpMode(ssl)) {
+        if (!DtlsCheckWindow(ssl) ||
+                (rh->type == application_data && ssl->keys.curEpoch == 0) ||
+                (rh->type == alert && ssl->options.handShakeDone &&
+                        ssl->keys.curEpoch == 0 && ssl->keys.dtls_epoch != 0)) {
             WOLFSSL_LEAVE("GetRecordHeader()", SEQUENCE_ERROR);
             return SEQUENCE_ERROR;
+        }
     }
 #endif
@@ -8309,9 +8529,5 @@
     if (rh->pvMajor != ssl->version.major ||
         (rh->pvMinor != ssl->version.minor &&
-#ifdef WOLFSSL_TLS13_DRAFT_18
-         (!IsAtLeastTLSv1_3(ssl->version) || rh->pvMinor != TLSv1_MINOR)
-#else
          (!IsAtLeastTLSv1_3(ssl->version) || rh->pvMinor != TLSv1_2_MINOR)
-#endif
         ))
 #endif
@@ -9281,30 +9497,4 @@
 
 
-/* try to find an altName match to domain, return 1 on success */
-int CheckAltNames(DecodedCert* dCert, char* domain)
-{
-    int        match = 0;
-    DNS_entry* altName = NULL;
-
-    WOLFSSL_MSG("Checking AltNames");
-
-    if (dCert)
-        altName = dCert->altNames;
-
-    while (altName) {
-        WOLFSSL_MSG("\tindividual AltName check");
-
-        if (MatchDomainName(altName->name, altName->len, domain)){
-            match = 1;
-            break;
-        }
-
-        altName = altName->next;
-    }
-
-    return match;
-}
-
-#ifdef OPENSSL_EXTRA
 /* Check that alternative names, if they exists, match the domain.
  * Fail if there are wild patterns and they didn't match.
@@ -9314,10 +9504,14 @@
  * domain   Domain name to compare against.
  * checkCN  Whether to check the common name.
- * returns whether there was a problem in matching.
+ * returns  1 : match was found.
+ *          0 : no match found.
+ *         -1 : No matches and wild pattern match failed.
  */
-static int CheckForAltNames(DecodedCert* dCert, char* domain, int* checkCN)
+int CheckForAltNames(DecodedCert* dCert, const char* domain, int* checkCN)
 {
-    int        match;
+    int match = 0;
     DNS_entry* altName = NULL;
+    char *buf;
+    word32 len;
 
     WOLFSSL_MSG("Checking AltNames");
@@ -9326,18 +9520,57 @@
         altName = dCert->altNames;
 
-    *checkCN = altName == NULL;
-    match = 0;
+    if (checkCN != NULL) {
+        *checkCN = (altName == NULL) ? 1 : 0;
+    }
+
     while (altName) {
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_IP_ALT_NAME)
+        char name[WOLFSSL_MAX_IPSTR] = {0};
+#endif
+
         WOLFSSL_MSG("\tindividual AltName check");
 
-        if (MatchDomainName(altName->name, altName->len, domain)) {
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_IP_ALT_NAME)
+        /* check if alt name is stored as IP addr octet */
+        if (altName->type == ASN_IP_TYPE) {
+            char tmp[4];
+            int i;
+            word32 idx = 0;
+            for (i = 0; (idx < WOLFSSL_MAX_IPSTR) && (i < altName->len); i++) {
+                XMEMSET(tmp, 0, sizeof(tmp));
+                XSNPRINTF(tmp, sizeof(tmp), (altName->len <= 4) ? "%u" : "%02X",
+                        altName->name[i]);
+                idx += (word32)XSTRLEN(tmp);
+                XSTRNCAT(name, tmp, (altName->len <= 4) ? 3 : 2);
+                if ((idx < WOLFSSL_MAX_IPSTR ) && ((i + 1) < altName->len)) {
+                    name[idx++] = (altName->len <= 4) ? '.' : ':';
+                }
+            }
+            if (idx >= WOLFSSL_MAX_IPSTR) {
+                idx = WOLFSSL_MAX_IPSTR -1;
+            }
+            name[idx] = '\0';
+            buf = name;
+            len = (word32)XSTRLEN(name);
+        }
+        else
+#endif /* OPENSSL_ALL || WOLFSSL_IP_ALT_NAME */
+        {
+            buf = altName->name;
+            len = altName->len;
+        }
+
+        if (MatchDomainName(buf, len, domain)) {
             match = 1;
-            *checkCN = 0;
+            if (checkCN != NULL) {
+                *checkCN = 0;
+            }
+            WOLFSSL_MSG("\tmatch found");
             break;
         }
         /* No matches and wild pattern match failed. */
-        else if (altName->name && altName->len >=1 &&
-                altName->name[0] == '*' && match == 0) {
+        else if (buf && (len >=1) && (buf[0] == '*')) {
             match = -1;
+            WOLFSSL_MSG("\twildcard match failed");
         }
 
@@ -9345,6 +9578,7 @@
     }
 
-    return match != -1;
+    return match;
 }
+
 
 /* Check the domain name matches the subject alternative name or the subject
@@ -9356,27 +9590,33 @@
  * returns DOMAIN_NAME_MISMATCH when no match found and 0 on success.
  */
-int CheckHostName(DecodedCert* dCert, char *domainName, size_t domainNameLen)
+int CheckHostName(DecodedCert* dCert, const char *domainName, size_t domainNameLen)
 {
     int checkCN;
+    int ret = DOMAIN_NAME_MISMATCH;
 
     /* Assume name is NUL terminated. */
     (void)domainNameLen;
 
-    if (CheckForAltNames(dCert, domainName, &checkCN) == 0) {
-        WOLFSSL_MSG("DomainName match on alt names failed too");
-        return DOMAIN_NAME_MISMATCH;
-    }
+    if (CheckForAltNames(dCert, domainName, &checkCN) != 1) {
+        WOLFSSL_MSG("DomainName match on alt names failed");
+    }
+    else {
+        ret = 0;
+    }
+
     if (checkCN == 1) {
         if (MatchDomainName(dCert->subjectCN, dCert->subjectCNLen,
-                            domainName) == 0) {
+                            domainName) == 1) {
+            ret = 0;
+        }
+        else {
             WOLFSSL_MSG("DomainName match on common name failed");
-            return DOMAIN_NAME_MISMATCH;
-        }
-    }
-
-    return 0;
+        }
+    }
+
+    return ret;
 }
 
-int CheckIPAddr(DecodedCert* dCert, char* ipasc)
+int CheckIPAddr(DecodedCert* dCert, const char* ipasc)
 {
     WOLFSSL_MSG("Checking IPAddr");
@@ -9384,5 +9624,5 @@
     return CheckHostName(dCert, ipasc, (size_t)XSTRLEN(ipasc));
 }
-#endif
+
 
 #ifdef SESSION_CERTS
@@ -9415,4 +9655,9 @@
         return BAD_FUNC_ARG;
 
+    if (x509->issuer.name == NULL || x509->subject.name == NULL) {
+        WOLFSSL_MSG("Either init was not called on X509 or programming error");
+        return BAD_FUNC_ARG;
+    }
+
     x509->version = dCert->version + 1;
 
@@ -9421,15 +9666,9 @@
     x509->issuer.sz = (int)XSTRLEN(x509->issuer.name) + 1;
 #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
-    if (dCert->issuerName.fullName != NULL) {
-        XMEMCPY(&x509->issuer.fullName,
-                                       &dCert->issuerName, sizeof(DecodedName));
-        x509->issuer.fullName.fullName = (char*)XMALLOC(
-                        dCert->issuerName.fullNameLen, x509->heap,
-                        DYNAMIC_TYPE_X509);
-        if (x509->issuer.fullName.fullName != NULL)
-            XMEMCPY(x509->issuer.fullName.fullName,
-                     dCert->issuerName.fullName, dCert->issuerName.fullNameLen);
-    }
-    x509->issuer.x509 = x509;
+    if (dCert->issuerName != NULL) {
+        wolfSSL_X509_set_issuer_name(x509,
+                (WOLFSSL_X509_NAME*)dCert->issuerName);
+        x509->issuer.x509 = x509;
+    }
 #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
 
@@ -9438,14 +9677,9 @@
     x509->subject.sz = (int)XSTRLEN(x509->subject.name) + 1;
 #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
-    if (dCert->subjectName.fullName != NULL) {
-        XMEMCPY(&x509->subject.fullName,
-                                      &dCert->subjectName, sizeof(DecodedName));
-        x509->subject.fullName.fullName = (char*)XMALLOC(
-                 dCert->subjectName.fullNameLen, x509->heap, DYNAMIC_TYPE_X509);
-        if (x509->subject.fullName.fullName != NULL)
-            XMEMCPY(x509->subject.fullName.fullName,
-                   dCert->subjectName.fullName, dCert->subjectName.fullNameLen);
-    }
-    x509->subject.x509 = x509;
+    if (dCert->subjectName != NULL) {
+        wolfSSL_X509_set_subject_name(x509,
+                (WOLFSSL_X509_NAME*)dCert->subjectName);
+        x509->subject.x509 = x509;
+    }
 #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
 #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
@@ -9466,4 +9700,38 @@
     else
         x509->subjectCN[0] = '\0';
+
+#ifdef WOLFSSL_CERT_REQ
+    x509->isCSR = dCert->isCSR;
+    /* CSR attributes */
+    if (dCert->cPwd) {
+        if (dCert->cPwdLen < CTC_NAME_SIZE) {
+            XMEMCPY(x509->challengePw, dCert->cPwd, dCert->cPwdLen);
+            x509->challengePw[dCert->cPwdLen] = '\0';
+#ifdef OPENSSL_ALL
+            if (x509->challengePwAttr) {
+                wolfSSL_X509_ATTRIBUTE_free(x509->challengePwAttr);
+            }
+            x509->challengePwAttr = wolfSSL_X509_ATTRIBUTE_new();
+            if (x509->challengePwAttr) {
+                x509->challengePwAttr->value->value.asn1_string =
+                        wolfSSL_ASN1_STRING_new();
+                if (wolfSSL_ASN1_STRING_set(
+                        x509->challengePwAttr->value->value.asn1_string,
+                        dCert->cPwd, dCert->cPwdLen) != WOLFSSL_SUCCESS) {
+                    ret = MEMORY_E;
+                }
+                x509->challengePwAttr->value->type = V_ASN1_PRINTABLESTRING;
+            }
+            else {
+                ret = MEMORY_E;
+            }
+#endif
+        }
+        else {
+            WOLFSSL_MSG("Challenge password too long");
+            ret = MEMORY_E;
+        }
+    }
+#endif
 
 #ifdef WOLFSSL_SEP
@@ -9729,10 +9997,13 @@
     int ret = 0;
     OcspRequest* request;
+    WOLFSSL_ENTER("ProcessCSR");
 
     #ifdef WOLFSSL_SMALL_STACK
         CertStatus* status;
+        OcspEntry* single;
         OcspResponse* response;
     #else
         CertStatus status[1];
+        OcspEntry single[1];
         OcspResponse response[1];
     #endif
@@ -9764,13 +10035,17 @@
     #ifdef WOLFSSL_SMALL_STACK
         status = (CertStatus*)XMALLOC(sizeof(CertStatus), ssl->heap,
-                                                      DYNAMIC_TYPE_OCSP_STATUS);
+                                                    DYNAMIC_TYPE_OCSP_STATUS);
+        single = (OcspEntry*)XMALLOC(sizeof(OcspEntry), ssl->heap,
+                                                    DYNAMIC_TYPE_OCSP_ENTRY);
         response = (OcspResponse*)XMALLOC(sizeof(OcspResponse), ssl->heap,
-                                                     DYNAMIC_TYPE_OCSP_REQUEST);
-
-        if (status == NULL || response == NULL) {
+                                                    DYNAMIC_TYPE_OCSP_REQUEST);
+
+        if (status == NULL || single == NULL || response == NULL) {
             if (status)
-                XFREE(status, NULL, DYNAMIC_TYPE_OCSP_STATUS);
+                XFREE(status, ssl->heap, DYNAMIC_TYPE_OCSP_STATUS);
+            if (single)
+                XFREE(single, ssl->heap, DYNAMIC_TYPE_OCSP_ENTRY);
             if (response)
-                XFREE(response, NULL, DYNAMIC_TYPE_OCSP_REQUEST);
+                XFREE(response, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
 
             return MEMORY_ERROR;
@@ -9778,5 +10053,5 @@
     #endif
 
-    InitOcspResponse(response, status, input +*inOutIdx, status_length);
+    InitOcspResponse(response, single, status, input +*inOutIdx, status_length, ssl->heap);
 
     if (OcspResponseDecode(response, ssl->ctx->cm, ssl->heap, 0) != 0)
@@ -9786,8 +10061,13 @@
     else if (response->responseStatus != OCSP_SUCCESSFUL)
         ret = BAD_CERTIFICATE_STATUS_ERROR;
-    else if (response->status->status == CERT_REVOKED)
+    else if (response->single->status->status == CERT_REVOKED)
         ret = OCSP_CERT_REVOKED;
-    else if (response->status->status != CERT_GOOD)
+    else if (response->single->status->status != CERT_GOOD)
         ret = BAD_CERTIFICATE_STATUS_ERROR;
+
+    else {
+        XMEMCPY(ssl->ocspProducedDate, response->producedDate, sizeof ssl->ocspProducedDate);
+        ssl->ocspProducedDateFormat = response->producedDateFormat;
+    }
 
     *inOutIdx += status_length;
@@ -9795,7 +10075,9 @@
     #ifdef WOLFSSL_SMALL_STACK
         XFREE(status,   ssl->heap, DYNAMIC_TYPE_OCSP_STATUS);
+        XFREE(single,   ssl->heap, DYNAMIC_TYPE_OCSP_ENTRY);
         XFREE(response, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
     #endif
 
+    WOLFSSL_LEAVE("ProcessCSR", ret);
     return ret;
 }
@@ -9876,4 +10158,6 @@
     if (ret == ASN_AFTER_DATE_E || ret == ASN_BEFORE_DATE_E) {
         alertWhy = certificate_expired;
+    } else if (ret == ASN_NO_SIGNER_E) {
+        alertWhy = unknown_ca;
     }
 #if (defined(OPENSSL_ALL) || defined(WOLFSSL_APACHE_HTTPD))
@@ -9911,5 +10195,11 @@
 {
     int verify_ok = 0, use_cb = 0;
-    void *heap = (ssl != NULL) ? ssl->heap : cm->heap;
+    void *heap;
+
+    if (cm == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    heap = (ssl != NULL) ? ssl->heap : cm->heap;
 
     /* Determine if verify was okay */
@@ -9942,5 +10232,5 @@
         /* If altNames names is present, then subject common name is ignored */
         if (args->dCert->altNames != NULL) {
-            if (CheckAltNames(args->dCert, ssl->param->hostName) == 0 ) {
+            if (CheckForAltNames(args->dCert, ssl->param->hostName, NULL) != 1) {
                 if (ret == 0) {
                     ret = DOMAIN_NAME_MISMATCH;
@@ -9995,4 +10285,7 @@
         char domain[ASN_NAME_MAX];
     #endif
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+        int x509Free = 0;
+    #endif
 
     #ifdef WOLFSSL_SMALL_STACK
@@ -10044,5 +10337,6 @@
         store->certs = args->certs;
         store->totalCerts = args->totalCerts;
-    #if defined(HAVE_EX_DATA) || defined(FORTRESS)
+    #if (defined(HAVE_EX_DATA) || defined(FORTRESS)) && \
+        (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL))
         if (wolfSSL_CRYPTO_set_ex_data(&store->ex_data, 0, ssl)
                 != WOLFSSL_SUCCESS) {
@@ -10101,4 +10395,5 @@
                 if (CopyDecodedToX509(x509, args->dCert) == 0) {
                     store->current_cert = x509;
+                    x509Free = 1;
                 }
                 else {
@@ -10113,5 +10408,5 @@
     #ifndef NO_WOLFSSL_CM_VERIFY
         /* non-zero return code indicates failure override */
-        if ((cm != NULL) && (cm->verifyCallback != NULL)) {
+        if (cm->verifyCallback != NULL) {
             store->userCtx = cm;
             if (cm->verifyCallback(verify_ok, store)) {
@@ -10167,6 +10462,7 @@
         }
     #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
-        if (args->certIdx > 0)
+        if (x509Free) {
             FreeX509(x509);
+        }
     #endif
     #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
@@ -10562,12 +10858,4 @@
 
             /* allocate buffer for certs */
-        #ifdef OPENSSL_EXTRA
-            args->certs = (buffer*)XMALLOC(sizeof(buffer) *
-                    (ssl->verifyDepth + 1), ssl->heap, DYNAMIC_TYPE_DER);
-            if (args->certs == NULL) {
-                ERROR_OUT(MEMORY_E, exit_ppc);
-            }
-            XMEMSET(args->certs, 0, sizeof(buffer) * (ssl->verifyDepth + 1));
-        #else
             args->certs = (buffer*)XMALLOC(sizeof(buffer) * MAX_CHAIN_DEPTH,
                                             ssl->heap, DYNAMIC_TYPE_DER);
@@ -10576,5 +10864,4 @@
             }
             XMEMSET(args->certs, 0, sizeof(buffer) * MAX_CHAIN_DEPTH);
-        #endif /* OPENSSL_EXTRA */
 
             /* Certificate List */
@@ -10597,8 +10884,12 @@
                 word32 certSz;
 
+
             #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
-                if (args->totalCerts > ssl->verifyDepth) {
+                if (args->totalCerts >= MAX_CHAIN_DEPTH) {
                     ssl->peerVerifyRet = X509_V_ERR_CERT_CHAIN_TOO_LONG;
-                    ERROR_OUT(MAX_CHAIN_ERROR, exit_ppc);
+                    ret = MAX_CHAIN_ERROR;
+                    WOLFSSL_MSG("Too many certs for MAX_CHAIN_DEPTH");
+                    break; /* break out to avoid reading more certs then buffer
+                            * can hold */
                 }
             #else
@@ -10636,4 +10927,7 @@
                     word16 extSz;
 
+                    if (args->exts == NULL) {
+                        ERROR_OUT(BUFFER_ERROR, exit_ppc);
+                    }
                     if ((args->idx - args->begin) + OPAQUE16_LEN > totalSz) {
                         ERROR_OUT(BUFFER_ERROR, exit_ppc);
@@ -10664,5 +10958,6 @@
             args->certIdx = 0; /* select peer cert (first one) */
 
-            if (args->count == 0 && ssl->options.mutualAuth &&
+            if (args->count == 0 && (ssl->options.mutualAuth ||
+                 (ssl->options.failNoCert && IsAtLeastTLSv1_3(ssl->version))) &&
                                       ssl->options.side == WOLFSSL_SERVER_END) {
                 ret = NO_PEER_CERT;
@@ -10837,7 +11132,20 @@
                     }
             #endif /* HAVE_OCSP || HAVE_CRL */
-
+            #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+                    if (ret == 0 &&
+                        /* extend the limit "+1" until reaching
+                         * an ultimately trusted issuer.*/
+                        args->count > (ssl->verifyDepth + 1)) {
+                        ssl->peerVerifyRet = X509_V_ERR_CERT_CHAIN_TOO_LONG;
+                        ret = MAX_CHAIN_ERROR;
+                    }
+            #endif
                     /* Do verify callback */
                     ret = DoVerifyCallback(ssl->ctx->cm, ssl, ret, args);
+                    if (ssl->options.verifyNone &&
+                              (ret == CRL_MISSING || ret == CRL_CERT_REVOKED)) {
+                        WOLFSSL_MSG("Ignoring CRL problem based on verify setting");
+                        ret = ssl->error = 0;
+                    }
 
                 #ifdef WOLFSSL_ALT_CERT_CHAINS
@@ -10853,5 +11161,6 @@
                             }
 
-                            ret = 0; /* clear error and continue */
+                            ret = 0; /* clear errors and continue */
+                            args->verifyErr = 0;
                         }
 
@@ -10951,10 +11260,21 @@
                 #endif /* SESSION_CERTS && WOLFSSL_ALT_CERT_CHAINS */
 
+                    /* Check peer's certificate version number. TLS 1.2 / 1.3
+                     * requires the clients certificate be version 3 unless a
+                     * different version has been negotiated using RFC 7250 */
+                    if ((ret == 0) &&
+                            (ssl->options.side == WOLFSSL_SERVER_END)) {
+                        if (args->dCert->version != WOLFSSL_X509_V3) {
+                            WOLFSSL_MSG("Peers certificate was not version 3!");
+                            args->lastErr = ASN_VERSION_E;
+                            /* setting last error but not considering it fatal
+                             * giving the user a chance to override */
+                        }
+                    }
+
                     /* check if fatal error */
                     if (args->verifyErr) {
                         args->fatal = 1;
-                        if (ret == 0) {
-                            ret = args->lastErr;
-                        }
+                        ret = args->lastErr;
                     }
                     else {
@@ -10964,6 +11284,9 @@
                 else if (ret == ASN_PARSE_E || ret == BUFFER_E) {
                     WOLFSSL_MSG("Got Peer cert ASN PARSE or BUFFER ERROR");
+                #if defined(WOLFSSL_EXTRA_ALERTS) || defined(OPENSSL_EXTRA) || \
+                                               defined(OPENSSL_EXTRA_X509_SMALL)
+                    DoCertFatalAlert(ssl, ret);
+                #endif
                 #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
-                    SendAlert(ssl, alert_fatal, bad_certificate);
                     ssl->peerVerifyRet = X509_V_ERR_CERT_REJECTED;
                 #endif
@@ -10980,10 +11303,18 @@
                         /* check if fatal error */
                         args->fatal = (args->verifyErr) ? 1 : 0;
+                    #if defined(WOLFSSL_EXTRA_ALERTS) || \
+                                                     defined(OPENSSL_EXTRA) || \
+                                               defined(OPENSSL_EXTRA_X509_SMALL)
+                        if (args->fatal)
+                            DoCertFatalAlert(ssl, ret);
+                    #endif
                     }
                     else {
                         WOLFSSL_MSG("\tNo callback override available, fatal");
                         args->fatal = 1;
-                    #ifdef OPENSSL_EXTRA
-                        SendAlert(ssl, alert_fatal, bad_certificate);
+                    #if defined(WOLFSSL_EXTRA_ALERTS) || \
+                                                     defined(OPENSSL_EXTRA) || \
+                                               defined(OPENSSL_EXTRA_X509_SMALL)
+                        DoCertFatalAlert(ssl, ret);
                     #endif
                     }
@@ -11042,5 +11373,5 @@
                                                     args->dCert, ssl->heap);
                             doLookup = 0;
-                        #if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+                        #if defined(WOLFSSL_TLS13)
                             if (ssl->options.tls1_3) {
                                 TLSX* ext = TLSX_Find(ssl->extensions,
@@ -11057,4 +11388,10 @@
                             }
                         #endif
+                        }
+                        /* Ensure a stapling response was seen */
+                        else if (ssl->options.tls1_3 &&
+                                                 ssl->ctx->cm->ocspMustStaple) {
+                             ret = OCSP_CERT_UNKNOWN;
+                             goto exit_ppc;
                         }
                 #endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
@@ -11115,4 +11452,11 @@
                     int copyRet = 0;
 
+                    #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+                        if (ssl->options.handShakeDone) {
+                            FreeX509(&ssl->peerCert);
+                            InitX509(&ssl->peerCert, 0, ssl->heap);
+                        }
+                        else
+                    #endif
                     #ifdef HAVE_SECURE_RENEGOTIATION
                         if (ssl->secure_renegotiation &&
@@ -11120,6 +11464,10 @@
                             /* free old peer cert */
                             FreeX509(&ssl->peerCert);
+                            InitX509(&ssl->peerCert, 0, ssl->heap);
                         }
+                        else
                     #endif
+                        {
+                        }
 
                     /* set X509 format for peer cert */
@@ -11202,6 +11550,7 @@
                      * alternative name extension MUST be used." */
                     if (args->dCert->altNames) {
-                        if (CheckAltNames(args->dCert,
-                                (char*)ssl->buffers.domainName.buffer) == 0 ) {
+                        if (CheckForAltNames(args->dCert,
+                                (char*)ssl->buffers.domainName.buffer,
+                                NULL) != 1) {
                             WOLFSSL_MSG("DomainName match on alt names failed");
                             /* try to get peer key still */
@@ -11224,6 +11573,7 @@
                                 (char*)ssl->buffers.domainName.buffer) == 0) {
                         WOLFSSL_MSG("DomainName match on common name failed");
-                        if (CheckAltNames(args->dCert,
-                                 (char*)ssl->buffers.domainName.buffer) == 0 ) {
+                        if (CheckForAltNames(args->dCert,
+                                 (char*)ssl->buffers.domainName.buffer,
+                                 NULL) != 1) {
                             WOLFSSL_MSG(
                                 "DomainName match on alt names failed too");
@@ -11279,5 +11629,6 @@
                     #ifdef HAVE_PK_CALLBACKS
                         #ifndef NO_RSA
-                            #ifdef HAVE_SECURE_RENEGOTIATION
+                            #if defined(HAVE_SECURE_RENEGOTIATION) || \
+                                            defined(WOLFSSL_POST_HANDSHAKE_AUTH)
                             if (ssl->buffers.peerRsaKey.buffer) {
                                 XFREE(ssl->buffers.peerRsaKey.buffer,
@@ -11357,4 +11708,7 @@
                             ssl->peerEccDsaKeyPresent = 1;
                     #ifdef HAVE_PK_CALLBACKS
+                            if (ssl->buffers.peerEccDsaKey.buffer)
+                                XFREE(ssl->buffers.peerEccDsaKey.buffer,
+                                      ssl->heap, DYNAMIC_TYPE_ECC);
                             ssl->buffers.peerEccDsaKey.buffer =
                                    (byte*)XMALLOC(args->dCert->pubKeySize,
@@ -11381,4 +11735,8 @@
                             WOLFSSL_MSG("Peer ECC key is too small");
                         }
+
+                        /* populate curve oid - if missing */
+                        if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->ecdhCurveOID == 0)
+                            ssl->ecdhCurveOID = args->dCert->pkCurveOID;
                         break;
                     }
@@ -11431,4 +11789,8 @@
                             WOLFSSL_MSG("Peer ECC key is too small");
                         }
+
+                        /* populate curve oid - if missing */
+                        if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->ecdhCurveOID == 0)
+                            ssl->ecdhCurveOID = ECC_X25519_OID;
                         break;
                     }
@@ -11480,4 +11842,8 @@
                             WOLFSSL_MSG("Peer ECC key is too small");
                         }
+
+                        /* populate curve oid - if missing */
+                        if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->ecdhCurveOID == 0)
+                            ssl->ecdhCurveOID = ECC_X448_OID;
                         break;
                     }
@@ -11573,5 +11939,13 @@
 #endif /* WOLFSSL_ASYNC_CRYPT || WOLFSSL_NONBLOCK_OCSP */
 
+#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLFSSL_NONBLOCK_OCSP) || \
+    defined(WOLFSSL_SMALL_STACK)
+    if (args)
+    {
+        FreeProcPeerCertArgs(ssl, args);
+    }
+#else
     FreeProcPeerCertArgs(ssl, args);
+#endif /* WOLFSSL_ASYNC_CRYPT || WOLFSSL_NONBLOCK_OCSP || WOLFSSL_SMALL_STACK */
 
 #if defined(WOLFSSL_ASYNC_CRYPT)
@@ -11667,8 +12041,10 @@
 
             #ifdef WOLFSSL_SMALL_STACK
-                CertStatus* status;
+                CertStatus*   status;
+                OcspEntry*    single;
                 OcspResponse* response;
             #else
-                CertStatus status[1];
+                CertStatus   status[1];
+                OcspEntry    single[1];
                 OcspResponse response[1];
             #endif
@@ -11686,10 +12062,14 @@
                 status = (CertStatus*)XMALLOC(sizeof(CertStatus), ssl->heap,
                                                        DYNAMIC_TYPE_OCSP_STATUS);
+                single = (OcspEntry*)XMALLOC(sizeof(OcspEntry), ssl->heap,
+                                                              DYNAMIC_TYPE_OCSP_ENTRY);
                 response = (OcspResponse*)XMALLOC(sizeof(OcspResponse), ssl->heap,
-                                                       DYNAMIC_TYPE_OCSP_REQUEST);
-
-                if (status == NULL || response == NULL) {
+                                                             DYNAMIC_TYPE_OCSP_REQUEST);
+
+                if (status == NULL || single == NULL || response == NULL) {
                     if (status)
                         XFREE(status, ssl->heap, DYNAMIC_TYPE_OCSP_STATUS);
+                    if (single)
+                        XFREE(single, ssl->heap, DYNAMIC_TYPE_OCSP_ENTRY);
                     if (response)
                         XFREE(response, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
@@ -11715,11 +12095,11 @@
 
                 if (status_length) {
-                    InitOcspResponse(response, status, input +*inOutIdx,
-                                                                 status_length);
+                    InitOcspResponse(response, single, status, input +*inOutIdx,
+                                     status_length, ssl->heap);
 
                     if ((OcspResponseDecode(response, ssl->ctx->cm, ssl->heap,
                                                                         0) != 0)
                     ||  (response->responseStatus != OCSP_SUCCESSFUL)
-                    ||  (response->status->status != CERT_GOOD))
+                    ||  (response->single->status->status != CERT_GOOD))
                         ret = BAD_CERTIFICATE_STATUS_ERROR;
 
@@ -11735,4 +12115,5 @@
                             ret = BAD_CERTIFICATE_STATUS_ERROR;
                     }
+                    FreeOcspResponse(response);
 
                     *inOutIdx   += status_length;
@@ -11747,4 +12128,5 @@
             #ifdef WOLFSSL_SMALL_STACK
                 XFREE(status,   NULL, DYNAMIC_TYPE_OCSP_STATUS);
+                XFREE(single,   NULL, DYNAMIC_TYPE_OCSP_ENTRY);
                 XFREE(response, NULL, DYNAMIC_TYPE_OCSP_REQUEST);
             #endif
@@ -11805,8 +12187,11 @@
 
     if (IsEncryptionOn(ssl, 0)) {
+        /* If size == totalSz then we are in DtlsMsgDrain so no need to worry
+         * about padding */
     #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
         if (ssl->options.startedETMRead) {
             word32 digestSz = MacSize(ssl);
-            if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz)
+            if (size != totalSz &&
+                    *inOutIdx + ssl->keys.padSz + digestSz > totalSz)
                 return BUFFER_E;
             *inOutIdx += ssl->keys.padSz + digestSz;
@@ -11816,5 +12201,6 @@
         {
             /* access beyond input + size should be checked against totalSz */
-            if (*inOutIdx + ssl->keys.padSz > totalSz)
+            if (size != totalSz &&
+                    *inOutIdx + ssl->keys.padSz > totalSz)
                 return BUFFER_E;
 
@@ -11852,5 +12238,8 @@
         return BUFFER_ERROR;
 
-    /* check against totalSz */
+    /* check against totalSz
+     * If size == totalSz then we are in DtlsMsgDrain so no need to worry about
+     * padding */
+    if (size != totalSz) {
     #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
         if (ssl->options.startedETMRead) {
@@ -11864,4 +12253,5 @@
                 return BUFFER_E;
         }
+    }
 
     #ifdef WOLFSSL_CALLBACKS
@@ -11892,4 +12282,12 @@
     }
 #endif
+#ifdef OPENSSL_ALL
+    if (ssl->options.side == WOLFSSL_CLIENT_END)
+        XMEMCPY(ssl->serverFinished,
+                input + *inOutIdx, TLS_FINISHED_SZ);
+    else
+        XMEMCPY(ssl->clientFinished,
+                input + *inOutIdx, TLS_FINISHED_SZ);
+#endif
 
     /* force input exhaustion at ProcessReply consuming padSz */
@@ -11934,5 +12332,10 @@
 #ifdef WOLFSSL_DTLS
     if (ssl->options.dtls) {
-        DtlsMsgPoolReset(ssl);
+        if ((!ssl->options.resuming && ssl->options.side == WOLFSSL_CLIENT_END) ||
+             (ssl->options.resuming && ssl->options.side == WOLFSSL_SERVER_END)){
+            DtlsMsgPoolReset(ssl);
+            ssl->keys.dtls_handshake_number = 0;
+            ssl->keys.dtls_expected_peer_handshake_number = 0;
+        }
     }
 #endif
@@ -12085,4 +12488,20 @@
                 }
 #endif
+#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
+                                     defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+                /* Check that a status request extension was seen as the
+                 * CertificateStatus wasn't when an OCSP staple is required.
+                 */
+                if (
+    #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+                     !ssl->status_request &&
+    #endif
+    #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+                     !ssl->status_request_v2 &&
+    #endif
+                                                 ssl->ctx->cm->ocspMustStaple) {
+                    return OCSP_CERT_UNKNOWN;
+                }
+                #endif
             }
 
@@ -12180,4 +12599,12 @@
                 return DUPLICATE_MSG_E;
             }
+#ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls) {
+                if (ssl->keys.curEpoch == 0) {
+                    WOLFSSL_MSG("Finished received with epoch 0");
+                    return SEQUENCE_ERROR;
+                }
+            }
+#endif
             ssl->msgsReceived.got_finished = 1;
 
@@ -12194,7 +12621,4 @@
             if (ssl->msgsReceived.got_change_cipher) {
                 WOLFSSL_MSG("Duplicate ChangeCipher received");
-    #ifdef WOLFSSL_EXTRA_ALERTS
-                SendAlert(ssl, alert_fatal, unexpected_message);
-    #endif
                 return DUPLICATE_MSG_E;
             }
@@ -12244,5 +12668,6 @@
                         ssl->options.havePeerCert) {
 
-                        if (!ssl->options.havePeerVerify) {
+                        if (!ssl->options.havePeerVerify ||
+                                !ssl->msgsReceived.got_certificate_verify) {
                             WOLFSSL_MSG("client didn't send cert verify");
                             #ifdef WOLFSSL_DTLS
@@ -12297,5 +12722,5 @@
 #endif
 
-#if !defined(WOLFSSL_NO_SERVER) && \
+#if !defined(NO_WOLFSSL_SERVER) && \
     defined(HAVE_SECURE_RENEGOTIATION) && \
     defined(HAVE_SERVER_RENEGOTIATION_INFO)
@@ -12404,4 +12829,23 @@
         WOLFSSL_MSG("processing hello verify request");
         ret = DoHelloVerifyRequest(ssl, input,inOutIdx, size);
+        if (IsEncryptionOn(ssl, 0)) {
+        #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+            if (ssl->options.startedETMRead) {
+                word32 digestSz = MacSize(ssl);
+                if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz)
+                    return BUFFER_E;
+                *inOutIdx += ssl->keys.padSz + digestSz;
+            }
+            else
+        #endif
+            {
+                /* access beyond input + size should be checked against totalSz
+                 */
+                if (*inOutIdx + ssl->keys.padSz > totalSz)
+                    return BUFFER_E;
+
+                *inOutIdx += ssl->keys.padSz;
+            }
+        }
         break;
 
@@ -12511,9 +12955,12 @@
         }
     #endif
+        /* If size == totalSz then we are in DtlsMsgDrain so no need to worry
+         * about padding */
         if (IsEncryptionOn(ssl, 0)) {
         #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
             if (ssl->options.startedETMRead) {
                 word32 digestSz = MacSize(ssl);
-                if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz)
+                if (size != totalSz &&
+                        *inOutIdx + ssl->keys.padSz + digestSz > totalSz)
                     return BUFFER_E;
                 *inOutIdx += ssl->keys.padSz + digestSz;
@@ -12524,7 +12971,7 @@
                 /* access beyond input + size should be checked against totalSz
                  */
-                if (*inOutIdx + ssl->keys.padSz > totalSz)
+                if (size != totalSz &&
+                        *inOutIdx + ssl->keys.padSz > totalSz)
                     return BUFFER_E;
-
                 *inOutIdx += ssl->keys.padSz;
             }
@@ -12565,5 +13012,22 @@
     #endif
     ) {
-        ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+        if (IsEncryptionOn(ssl, 0)) {
+            word32 extra = ssl->keys.padSz;
+
+        #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+            if (ssl->options.startedETMRead)
+                extra += MacSize(ssl);
+        #endif
+
+            if (extra > ssl->buffers.inputBuffer.idx)
+                return BUFFER_E;
+
+            ssl->buffers.inputBuffer.idx -= extra;
+            ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+            ssl->buffers.inputBuffer.idx += extra;
+        }
+        else {
+            ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+        }
     }
 
@@ -12776,6 +13240,13 @@
 #endif
     else if (curLT) {
-        word32 idx = diff / DTLS_WORD_BITS;
-        word32 newDiff = diff % DTLS_WORD_BITS;
+        word32 idx;
+        word32 newDiff;
+        if (diff == 0) {
+            WOLFSSL_MSG("DTLS sanity check failed");
+            return 0;
+        }
+        diff--;
+        idx = diff / DTLS_WORD_BITS;
+        newDiff = diff % DTLS_WORD_BITS;
 
         /* verify idx is valid for window array */
@@ -12797,5 +13268,5 @@
 #ifdef WOLFSSL_MULTICAST
 static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first,
-                                         word32 second, word32 max)
+                                         word32 second, word32 high)
 {
     word32 newCur = 0;
@@ -12805,6 +13276,6 @@
     else if (cur < second)
         newCur = second;
-    else if (cur < max)
-        newCur = max;
+    else if (cur < high)
+        newCur = high;
 
     return newCur;
@@ -12880,9 +13351,9 @@
     if (cur_hi == *next_hi) {
         curLT = cur_lo < *next_lo;
-        diff = curLT ? *next_lo - cur_lo : cur_lo - *next_lo;
+        diff = curLT ? *next_lo - cur_lo - 1 : cur_lo - *next_lo + 1;
     }
     else {
         curLT = cur_hi < *next_hi;
-        diff = curLT ? cur_lo - *next_lo : *next_lo - cur_lo;
+        diff = curLT ? cur_lo - *next_lo - 1 : *next_lo - cur_lo + 1;
     }
 
@@ -12902,5 +13373,4 @@
 
             temp = 0;
-            diff++;
             idx = diff / DTLS_WORD_BITS;
             newDiff = diff % DTLS_WORD_BITS;
@@ -12943,10 +13413,12 @@
             ret == 0) {
         word32 idx = 0;
-        ssl->keys.dtls_expected_peer_handshake_number++;
-        ret = DoHandShakeMsgType(ssl, item->msg,
-                                 &idx, item->type, item->sz, item->sz);
+        if ((ret = DoHandShakeMsgType(ssl, item->msg, &idx, item->type,
+                                      item->sz, item->sz)) == 0) {
+            if (item->type != finished)
+                ssl->keys.dtls_expected_peer_handshake_number++;
+            DtlsTxMsgListClean(ssl);
+        }
     #ifdef WOLFSSL_ASYNC_CRYPT
         if (ret == WC_PENDING_E) {
-            ssl->keys.dtls_expected_peer_handshake_number--;
             break;
         }
@@ -12970,17 +13442,7 @@
     word32 fragOffset, fragSz;
     int ret = 0;
+    int ignoreFinished = 0;
 
     WOLFSSL_ENTER("DoDtlsHandShakeMsg()");
-
-    /* process any pending DTLS messages - this flow can happen with async */
-    if (ssl->dtls_rx_msg_list != NULL) {
-        ret = DtlsMsgDrain(ssl);
-        if (ret != 0)
-            return ret;
-
-        /* if done processing fragment exit with success */
-        if (totalSz == *inOutIdx)
-            return ret;
-    }
 
     /* parse header */
@@ -13003,4 +13465,17 @@
         WOLFSSL_ERROR(INCOMPLETE_DATA);
         return INCOMPLETE_DATA;
+    }
+
+    if (type == finished && ssl->keys.dtls_peer_handshake_number >=
+                            ssl->keys.dtls_expected_peer_handshake_number &&
+                            ssl->keys.curEpoch == ssl->keys.dtls_epoch) {
+        /* finished msg should be ignore from the current epoch
+         * if it comes from a previous handshake */
+        if (ssl->options.side == WOLFSSL_CLIENT_END) {
+            ignoreFinished = ssl->options.connectState < FINISHED_DONE;
+        }
+        else {
+            ignoreFinished = ssl->options.acceptState < ACCEPT_FINISHED_DONE;
+        }
     }
 
@@ -13015,5 +13490,10 @@
      */
     if (ssl->keys.dtls_peer_handshake_number >
-                                ssl->keys.dtls_expected_peer_handshake_number) {
+            ssl->keys.dtls_expected_peer_handshake_number &&
+            /* Only client_hello shouldn't be ignored if the handshake
+             * num is greater */
+            (type == client_hello ||
+                    ssl->options.handShakeState != HANDSHAKE_DONE) &&
+            !ignoreFinished) {
         /* Current message is out of order. It will get stored in the list.
          * Storing also takes care of defragmentation. If the messages is a
@@ -13025,12 +13505,36 @@
          * the client could be sending multiple new client hello messages
          * with newer and newer cookies.) */
+        WOLFSSL_MSG("Current message is out of order");
         if (type != client_hello) {
             if (ssl->dtls_rx_msg_list_sz < DTLS_POOL_SZ) {
-                DtlsMsgStore(ssl, ssl->keys.dtls_peer_handshake_number,
+                DtlsMsgStore(ssl, ssl->keys.curEpoch,
+                             ssl->keys.dtls_peer_handshake_number,
                              input + *inOutIdx, size, type,
                              fragOffset, fragSz, ssl->heap);
             }
             *inOutIdx += fragSz;
+            #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+            if (ssl->options.startedETMRead && ssl->keys.curEpoch != 0) {
+                word32 digestSz = MacSize(ssl);
+                if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz)
+                    return BUFFER_E;
+                *inOutIdx += digestSz;
+            }
+            else
+            #endif
+            {
+                if (*inOutIdx + ssl->keys.padSz > totalSz) {
+                    WOLFSSL_ERROR(BUFFER_E);
+                    return BUFFER_E;
+                }
+            }
+            *inOutIdx += ssl->keys.padSz;
             ret = 0;
+            #ifndef WOLFSSL_DTLS_RESEND_ONLY_TIMEOUT
+            /* If we receive an out of order last flight msg then retransmit */
+            if (type == server_hello_done || type == finished) {
+                ret = DtlsMsgPoolSend(ssl, 0);
+            }
+            #endif
         }
         else {
@@ -13043,25 +13547,30 @@
     }
     else if (ssl->keys.dtls_peer_handshake_number <
-                                ssl->keys.dtls_expected_peer_handshake_number) {
+                ssl->keys.dtls_expected_peer_handshake_number ||
+            /* ignore all handshake messages if we are done with the
+             * handshake */
+            (ssl->keys.dtls_peer_handshake_number >
+                ssl->keys.dtls_expected_peer_handshake_number &&
+                ssl->options.handShakeState == HANDSHAKE_DONE) ||
+            ignoreFinished) {
         /* Already saw this message and processed it. It can be ignored. */
+        WOLFSSL_MSG("Already saw this message and processed it");
         *inOutIdx += fragSz;
-        if(type == finished ) {
         #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
-            if (ssl->options.startedETMRead) {
-                word32 digestSz = MacSize(ssl);
-                if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz)
-                    return BUFFER_E;
-                *inOutIdx += ssl->keys.padSz + digestSz;
-            }
-            else
+        if (ssl->options.startedETMRead && ssl->keys.curEpoch != 0) {
+            word32 digestSz = MacSize(ssl);
+            if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz)
+                return BUFFER_E;
+            *inOutIdx += digestSz;
+        }
+        else
         #endif
-            {
-                if (*inOutIdx + ssl->keys.padSz > totalSz) {
-                    WOLFSSL_ERROR(BUFFER_E);
-                    return BUFFER_E;
-                }
-                *inOutIdx += ssl->keys.padSz;
-            }
-        }
+        {
+            if (*inOutIdx + ssl->keys.padSz > totalSz) {
+                WOLFSSL_ERROR(BUFFER_E);
+                return BUFFER_E;
+            }
+        }
+        #ifndef WOLFSSL_DTLS_RESEND_ONLY_TIMEOUT
         if (IsDtlsNotSctpMode(ssl) &&
             VerifyForDtlsMsgPoolSend(ssl, type, fragOffset)) {
@@ -13069,4 +13578,6 @@
             ret = DtlsMsgPoolSend(ssl, 0);
         }
+        #endif
+        *inOutIdx += ssl->keys.padSz;
     }
     else if (fragSz < size) {
@@ -13074,10 +13585,21 @@
          * be pointing to the message with this fragment in it. Check it to see
          * if it is completed. */
+        WOLFSSL_MSG("Branch is in order, but fragmented");
         if (ssl->dtls_rx_msg_list_sz < DTLS_POOL_SZ) {
-            DtlsMsgStore(ssl, ssl->keys.dtls_peer_handshake_number,
+            DtlsMsgStore(ssl, ssl->keys.curEpoch,
+                         ssl->keys.dtls_peer_handshake_number,
                          input + *inOutIdx, size, type,
                          fragOffset, fragSz, ssl->heap);
         }
         *inOutIdx += fragSz;
+        *inOutIdx += ssl->keys.padSz;
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+        if (ssl->options.startedETMRead && ssl->keys.curEpoch != 0) {
+            word32 digestSz = MacSize(ssl);
+            if (*inOutIdx + digestSz > totalSz)
+                return BUFFER_E;
+            *inOutIdx += digestSz;
+        }
+#endif
         ret = 0;
         if (ssl->dtls_rx_msg_list != NULL &&
@@ -13086,8 +13608,37 @@
     }
     else {
-        /* This branch is in order next, and a complete message. */
+        /* This branch is in order next, and a complete message. On success
+         * clean the tx list. */
+#ifdef WOLFSSL_ASYNC_CRYPT
+        word32 idx = *inOutIdx;
+#endif
+        WOLFSSL_MSG("Branch is in order and a complete message");
+#ifdef WOLFSSL_ASYNC_CRYPT
+        /* In async mode always store the message and process it with
+         * DtlsMsgDrain because in case of a WC_PENDING_E it will be
+         * easier this way. */
+        if (ssl->dtls_rx_msg_list_sz < DTLS_POOL_SZ) {
+            DtlsMsgStore(ssl, ssl->keys.curEpoch,
+                         ssl->keys.dtls_peer_handshake_number,
+                         input + idx, size, type,
+                         fragOffset, fragSz, ssl->heap);
+        }
+        if (idx + fragSz + ssl->keys.padSz > totalSz)
+            return BUFFER_E;
+        *inOutIdx = idx + fragSz + ssl->keys.padSz;
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+        if (ssl->options.startedETMRead && ssl->keys.curEpoch != 0) {
+            word32 digestSz = MacSize(ssl);
+            if (*inOutIdx + digestSz > totalSz)
+                return BUFFER_E;
+            *inOutIdx += digestSz;
+        }
+#endif
+        ret = DtlsMsgDrain(ssl);
+#else
         ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz);
         if (ret == 0) {
-            if (type != client_hello || !IsDtlsNotSctpMode(ssl))
+            DtlsTxMsgListClean(ssl);
+            if (type != finished)
                 ssl->keys.dtls_expected_peer_handshake_number++;
             if (ssl->dtls_rx_msg_list != NULL) {
@@ -13095,4 +13646,5 @@
             }
         }
+#endif
     }
 
@@ -13106,8 +13658,8 @@
 #ifdef HAVE_AEAD
 
-#if !defined(NO_PUBLIC_GCM_SET_IV) && \
-    (((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \
-    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) || \
-    (defined(HAVE_POLY1305) && defined(HAVE_CHACHA)))
+#if (!defined(NO_PUBLIC_GCM_SET_IV) && \
+    ((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2)))) || \
+    (defined(HAVE_POLY1305) && defined(HAVE_CHACHA))
 static WC_INLINE void AeadIncrementExpIV(WOLFSSL* ssl)
 {
@@ -13882,6 +14434,14 @@
             c16toa(sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size,
                                     ssl->decrypt.additional + AEAD_LEN_OFFSET);
-            XMEMCPY(ssl->decrypt.nonce, ssl->keys.aead_dec_imp_IV,
-                                                            AESGCM_IMP_IV_SZ);
+
+        #if defined(WOLFSSL_DTLS) && defined(HAVE_SECURE_RENEGOTIATION)
+            if (ssl->options.dtls && IsDtlsMsgSCRKeys(ssl))
+                XMEMCPY(ssl->decrypt.nonce,
+                        ssl->secure_renegotiation->tmp_keys.aead_dec_imp_IV,
+                        AESGCM_IMP_IV_SZ);
+            else
+        #endif
+                XMEMCPY(ssl->decrypt.nonce, ssl->keys.aead_dec_imp_IV,
+                        AESGCM_IMP_IV_SZ);
             XMEMCPY(ssl->decrypt.nonce + AESGCM_IMP_IV_SZ, input,
                                                             AESGCM_EXP_IV_SZ);
@@ -14007,4 +14567,29 @@
         case CIPHER_STATE_DO:
         {
+        #if defined(WOLFSSL_DTLS) && defined(HAVE_SECURE_RENEGOTIATION)
+            if (ssl->options.dtls && DtlsSCRKeysSet(ssl)) {
+                /* For epochs >1 the current cipher parameters are located in
+                 * ssl->secure_renegotiation->tmp_keys. Previous cipher
+                 * parameters and for epoch 1 use ssl->keys */
+                if (ssl->keys.curEpoch ==
+                        ssl->secure_renegotiation->tmp_keys.dtls_epoch) {
+                    if (ssl->decrypt.src != SCR) {
+                        ssl->secure_renegotiation->cache_status =
+                                SCR_CACHE_NEEDED;
+                        if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0)
+                            break;
+                    }
+                }
+                else {
+                    if (ssl->decrypt.src != KEYS) {
+                        ssl->secure_renegotiation->cache_status =
+                                SCR_CACHE_NULL;
+                        if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0)
+                            break;
+                    }
+                }
+            }
+        #endif
+
             ret = DecryptDo(ssl, plain, input, sz);
 
@@ -14242,5 +14827,5 @@
      * the size to make sure is valid. */
     ret = ssl->hmac(ssl, verify, input, pLen - macSz - padLen - 1, padLen,
-                                                                    content, 1);
+                                                                    content, 1, PEER_ORDER);
     good |= MaskMac(input, pLen, ssl->specs.hash_size, verify);
 
@@ -14275,16 +14860,29 @@
 #ifdef WOLFSSL_EARLY_DATA
     if (ssl->options.tls1_3 && ssl->options.handShakeDone == 0) {
-        if (ssl->options.side == WOLFSSL_SERVER_END &&
-                          ssl->earlyData != no_early_data &&
-                          ssl->options.clientState < CLIENT_FINISHED_COMPLETE) {
+        int process = 0;
+
+        if (ssl->options.side == WOLFSSL_SERVER_END) {
             ssl->earlyDataSz += ssl->curSize;
-            if (ssl->earlyDataSz <= ssl->options.maxEarlyDataSz) {
+            if ((ssl->earlyData != no_early_data) &&
+                          (ssl->options.clientState == CLIENT_HELLO_COMPLETE)) {
+                process = 1;
+            }
+            if (!process && (ssl->earlyDataSz <= ssl->options.maxEarlyDataSz)) {
                 WOLFSSL_MSG("Ignoring EarlyData!");
                 *inOutIdx = ssl->buffers.inputBuffer.length;
                 return 0;
             }
-            WOLFSSL_MSG("Too much EarlyData!");
-        }
-    }
+            if (ssl->earlyDataSz > ssl->options.maxEarlyDataSz) {
+                WOLFSSL_MSG("Too much EarlyData!");
+                process = 0;
+            }
+        }
+        if (!process) {
+            WOLFSSL_MSG("Received App data before a handshake completed");
+            SendAlert(ssl, alert_fatal, unexpected_message);
+            return OUT_OF_ORDER_E;
+        }
+    }
+    else
 #endif
     if (ssl->options.handShakeDone == 0) {
@@ -14360,4 +14958,14 @@
 
     *inOutIdx = idx;
+#ifdef HAVE_SECURE_RENEGOTIATION
+    if (IsSCR(ssl)) {
+        /* Reset the processReply state since
+         * we finished processing this message. */
+        ssl->options.processReply = doProcessInit;
+        /* If we are in a secure renegotiation then APP DATA is treated
+         * differently */
+        return APP_DATA_READY;
+    }
+#endif
     return 0;
 }
@@ -14533,5 +15141,5 @@
     }
 
-    ret  = ssl->hmac(ssl, verify, input, msgSz - digestSz, -1, content, 1);
+    ret  = ssl->hmac(ssl, verify, input, msgSz - digestSz, -1, content, 1, PEER_ORDER);
     ret |= ConstantCompare(verify, input + msgSz - digestSz, digestSz);
     if (ret != 0) {
@@ -14586,6 +15194,6 @@
             }
             PadCheck(dummy, (byte)pad, MAX_PAD_SIZE);  /* timing only */
-            ret = ssl->hmac(ssl, verify, input, msgSz - digestSz - pad - 1, pad,
-                                                                    content, 1);
+            ret = ssl->hmac(ssl, verify, input, msgSz - digestSz - pad - 1,
+                            pad, content, 1, PEER_ORDER);
             if (ConstantCompare(verify, input + msgSz - digestSz - pad - 1,
                                 digestSz) != 0)
@@ -14596,5 +15204,6 @@
     }
     else if (ssl->specs.cipher_type == stream) {
-        ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, -1, content, 1);
+        ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, -1, content, 1,
+                        PEER_ORDER);
         if (ConstantCompare(verify, input + msgSz - digestSz, digestSz) != 0){
             return VERIFY_MAC_ERROR;
@@ -14639,4 +15248,7 @@
 
     if (ssl->error != 0 && ssl->error != WANT_READ && ssl->error != WANT_WRITE
+    #ifdef HAVE_SECURE_RENEGOTIATION
+        && ssl->error != APP_DATA_READY
+    #endif
     #ifdef WOLFSSL_ASYNC_CRYPT
         && ssl->error != WC_PENDING_E
@@ -14649,4 +15261,15 @@
         return ssl->error;
     }
+
+#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_ASYNC_CRYPT)
+    /* process any pending DTLS messages - this flow can happen with async */
+    if (ssl->dtls_rx_msg_list != NULL) {
+        ret = DtlsMsgDrain(ssl);
+        if (ret != 0) {
+            WOLFSSL_ERROR(ret);
+            return ret;
+        }
+    }
+#endif
 
     for (;;) {
@@ -14770,10 +15393,4 @@
 #endif /* WOLFSSL_DTLS_DROP_STATS */
 
-                if (IsDtlsNotSctpMode(ssl) && ssl->options.dtlsHsRetain) {
-                    ret = DtlsMsgPoolSend(ssl, 0);
-                    if (ret != 0)
-                        return ret;
-                }
-
                 continue;
             }
@@ -14819,5 +15436,7 @@
 
             if (IsEncryptionOn(ssl, 0)) {
+#if defined(WOLFSSL_TLS13) || defined(WOLFSSL_EXTRA_ALERTS)
                 int tooLong = 0;
+#endif
 
 #ifdef WOLFSSL_TLS13
@@ -14832,11 +15451,11 @@
                     tooLong = ssl->curSize > MAX_TLS_CIPHER_SZ;
 #endif
+#if defined(WOLFSSL_TLS13) || defined(WOLFSSL_EXTRA_ALERTS)
                 if (tooLong) {
                     WOLFSSL_MSG("Encrypted data too long");
-#if defined(WOLFSSL_TLS13) || defined(WOLFSSL_EXTRA_ALERTS)
                     SendAlert(ssl, alert_fatal, record_overflow);
-#endif
                     return BUFFER_ERROR;
                 }
+#endif
             }
             ssl->keys.padSz = 0;
@@ -14888,11 +15507,7 @@
         case decryptMessage:
 
-#if !defined(WOLFSSL_TLS13) || defined(WOLFSSL_TLS13_DRAFT_18)
-            if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0)
-#else
             if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0 &&
                                         (!IsAtLeastTLSv1_3(ssl->version) ||
                                          ssl->curRL.type != change_cipher_spec))
-#endif
             {
                 bufferStatic* in = &ssl->buffers.inputBuffer;
@@ -14937,8 +15552,11 @@
                                       in->buffer + in->idx,
                                       ssl->curSize - digestSz);
-                         ssl->keys.padSz =
-                              in->buffer[in->idx + ssl->curSize - digestSz - 1];
-                         ssl->keys.padSz += 1;
-                         ssl->keys.decryptedCur = 1;
+                        if (ret == 0) {
+                            ssl->keys.padSz =
+                                    in->buffer[in->idx + ssl->curSize -
+                                               digestSz - 1];
+                            ssl->keys.padSz += 1;
+                            ssl->keys.decryptedCur = 1;
+                        }
                     }
                     else
@@ -14957,12 +15575,4 @@
                     {
                 #ifdef WOLFSSL_TLS13
-                    #if defined(WOLFSSL_TLS13_DRAFT_18) || \
-                        defined(WOLFSSL_TLS13_DRAFT_22) || \
-                        defined(WOLFSSL_TLS13_DRAFT_23)
-                        ret = DecryptTls13(ssl,
-                                           in->buffer + in->idx,
-                                           in->buffer + in->idx,
-                                           ssl->curSize, NULL, 0);
-                    #else
                         ret = DecryptTls13(ssl,
                                         in->buffer + in->idx,
@@ -14970,5 +15580,4 @@
                                         ssl->curSize,
                                         (byte*)&ssl->curRL, RECORD_HEADER_SZ);
-                    #endif
                 #else
                         ret = DECRYPT_ERROR;
@@ -15041,11 +15650,7 @@
         case verifyMessage:
 
-#if !defined(WOLFSSL_TLS13) || defined(WOLFSSL_TLS13_DRAFT_18)
-            if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0)
-#else
             if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0 &&
                                         (!IsAtLeastTLSv1_3(ssl->version) ||
                                          ssl->curRL.type != change_cipher_spec))
-#endif
             {
                 if (!atomicUser
@@ -15091,4 +15696,11 @@
                     word16 i = (word16)(ssl->buffers.inputBuffer.length -
                                         ssl->keys.padSz);
+
+                    /* sanity check on underflow */
+                    if (ssl->keys.padSz >= ssl->buffers.inputBuffer.length) {
+                        WOLFSSL_ERROR(DECRYPT_ERROR);
+                        return DECRYPT_ERROR;
+                    }
+
                     /* Remove padding from end of plain text. */
                     for (--i; i > ssl->buffers.inputBuffer.idx; i--) {
@@ -15111,7 +15723,13 @@
        #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
             if (IsEncryptionOn(ssl, 0) && ssl->options.startedETMRead) {
-                if (ssl->buffers.inputBuffer.length - ssl->keys.padSz -
-                                              ssl->buffers.inputBuffer.idx -
-                                              MacSize(ssl) > MAX_PLAINTEXT_SZ) {
+                if ((ssl->buffers.inputBuffer.length -
+                        ssl->keys.padSz -
+                        MacSize(ssl) -
+                        ssl->buffers.inputBuffer.idx > MAX_PLAINTEXT_SZ)
+#ifdef WOLFSSL_ASYNC_CRYPT
+                        && ssl->buffers.inputBuffer.length !=
+                                ssl->buffers.inputBuffer.idx
+#endif
+                                ) {
                     WOLFSSL_MSG("Plaintext too long - Encrypt-Then-MAC");
             #if defined(WOLFSSL_EXTRA_ALERTS)
@@ -15123,6 +15741,12 @@
             else
        #endif
-            if (ssl->buffers.inputBuffer.length - ssl->keys.padSz -
-                              ssl->buffers.inputBuffer.idx > MAX_PLAINTEXT_SZ) {
+            if (ssl->buffers.inputBuffer.length -
+                    ssl->keys.padSz -
+                    ssl->buffers.inputBuffer.idx > MAX_PLAINTEXT_SZ
+#ifdef WOLFSSL_ASYNC_CRYPT
+                        && ssl->buffers.inputBuffer.length !=
+                                ssl->buffers.inputBuffer.idx
+#endif
+                                ) {
                 WOLFSSL_MSG("Plaintext too long");
 #if defined(WOLFSSL_TLS13) || defined(WOLFSSL_EXTRA_ALERTS)
@@ -15132,9 +15756,9 @@
             }
 
-        #ifdef WOLFSSL_DTLS
+#ifdef WOLFSSL_DTLS
             if (IsDtlsNotSctpMode(ssl)) {
                 DtlsUpdateWindow(ssl);
             }
-        #endif /* WOLFSSL_DTLS */
+#endif /* WOLFSSL_DTLS */
 
             WOLFSSL_MSG("received record layer msg");
@@ -15142,4 +15766,5 @@
             switch (ssl->curRL.type) {
                 case handshake :
+                    WOLFSSL_MSG("got HANDSHAKE");
                     /* debugging in DoHandShakeMsg */
                     if (ssl->options.dtls) {
@@ -15151,5 +15776,9 @@
 #endif
                     }
-                    else if (!IsAtLeastTLSv1_3(ssl->version)) {
+                    else if (!IsAtLeastTLSv1_3(ssl->version)
+#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_TLS12)
+                            || !TLSv1_3_Capable(ssl)
+#endif
+                            ) {
 #ifndef WOLFSSL_NO_TLS12
                         ret = DoHandShakeMsg(ssl,
@@ -15163,4 +15792,5 @@
                     else {
 #ifdef WOLFSSL_TLS13
+                        ssl->msgsReceived.got_change_cipher = 0;
                         ret = DoTls13HandShakeMsg(ssl,
                                             ssl->buffers.inputBuffer.buffer,
@@ -15182,5 +15812,13 @@
 #endif
                     }
-                    if (ret != 0) {
+                    if (ret != 0
+#ifdef WOLFSSL_ASYNC_CRYPT
+                    /* In async case, on pending, move onto next message.
+                     * Current message should have been DtlsMsgStore'ed and
+                     * should be processed with DtlsMsgDrain */
+                            && (!ssl->options.dtls
+                                || ret != WC_PENDING_E)
+#endif
+                    ) {
                         WOLFSSL_ERROR(ret);
                         return ret;
@@ -15198,5 +15836,6 @@
                                 change_cipher_spec,
                                 ssl->buffers.inputBuffer.buffer +
-                                ssl->buffers.inputBuffer.idx - RECORD_HEADER_SZ,
+                                ssl->buffers.inputBuffer.idx - RECORD_HEADER_SZ -
+                                (ssl->options.dtls ? DTLS_RECORD_EXTRA : 0),
                                 1 + RECORD_HEADER_SZ, READ_PROTO, ssl->heap);
                             #ifdef WOLFSSL_CALLBACKS
@@ -15207,10 +15846,4 @@
 
 #ifdef WOLFSSL_TLS13
-    #ifdef WOLFSSL_TLS13_DRAFT_18
-                    if (IsAtLeastTLSv1_3(ssl->version)) {
-                        SendAlert(ssl, alert_fatal, illegal_parameter);
-                        return UNKNOWN_RECORD_TYPE;
-                    }
-    #else
                     if (IsAtLeastTLSv1_3(ssl->version)) {
                         word32 i = ssl->buffers.inputBuffer.idx;
@@ -15225,10 +15858,54 @@
                         }
                         ssl->buffers.inputBuffer.idx++;
+                        if (!ssl->msgsReceived.got_change_cipher) {
+                            ssl->msgsReceived.got_change_cipher = 1;
+                        }
+                        else {
+                            SendAlert(ssl, alert_fatal, illegal_parameter);
+                            return UNKNOWN_RECORD_TYPE;
+                        }
                         break;
                     }
-    #endif
 #endif
 
 #ifndef WOLFSSL_NO_TLS12
+                    if (ssl->buffers.inputBuffer.buffer[
+                            ssl->buffers.inputBuffer.idx] != 1) {
+                        WOLFSSL_MSG("ChangeCipher msg wrong value");
+                        return LENGTH_ERROR;
+                    }
+
+                    if (IsEncryptionOn(ssl, 0) && ssl->options.handShakeDone) {
+#ifdef HAVE_AEAD
+                        if (ssl->specs.cipher_type == aead) {
+                            if (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha)
+                                ssl->curSize -= AESGCM_EXP_IV_SZ;
+                            ssl->buffers.inputBuffer.idx += ssl->specs.aead_mac_size;
+                            ssl->curSize -= ssl->specs.aead_mac_size;
+                        }
+                        else
+#endif
+                        {
+                            ssl->buffers.inputBuffer.idx += ssl->keys.padSz;
+                            ssl->curSize -= (word16)ssl->keys.padSz;
+                            ssl->curSize -= ssl->specs.iv_size;
+                        }
+
+            #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+                        if (ssl->options.startedETMRead) {
+                            word32 digestSz = MacSize(ssl);
+                            ssl->buffers.inputBuffer.idx += digestSz;
+                            ssl->curSize -= digestSz;
+                        }
+            #endif
+                    }
+
+                    if (ssl->curSize != 1) {
+                        WOLFSSL_MSG("Malicious or corrupted ChangeCipher msg");
+                        return LENGTH_ERROR;
+                    }
+
+                    ssl->buffers.inputBuffer.idx++;
+
                     ret = SanityCheckMsgReceived(ssl, change_cipher_hs);
                     if (ret != 0) {
@@ -15243,17 +15920,6 @@
                             if (ret != DUPLICATE_MSG_E && ret != OUT_OF_ORDER_E)
                                 return ret;
-
-                            if (IsDtlsNotSctpMode(ssl)) {
-                                ret = DtlsMsgPoolSend(ssl, 1);
-                                if (ret != 0)
-                                    return ret;
-                            }
-
-                            if (ssl->curSize != 1) {
-                                WOLFSSL_MSG("Malicious or corrupted"
-                                            " duplicate ChangeCipher msg");
-                                return LENGTH_ERROR;
-                            }
-                            ssl->buffers.inputBuffer.idx++;
+                            /* Reset error */
+                            ret = 0;
                             break;
                         #endif /* WOLFSSL_DTLS */
@@ -15261,22 +15927,4 @@
                     }
 
-                    if (IsEncryptionOn(ssl, 0) && ssl->options.handShakeDone) {
-                        ssl->buffers.inputBuffer.idx += ssl->keys.padSz;
-                        ssl->curSize -= (word16) ssl->buffers.inputBuffer.idx;
-            #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
-                        if (ssl->options.startedETMRead) {
-                            word32 digestSz = MacSize(ssl);
-                            ssl->buffers.inputBuffer.idx += digestSz;
-                            ssl->curSize -= digestSz;
-                        }
-            #endif
-                    }
-
-                    if (ssl->curSize != 1) {
-                        WOLFSSL_MSG("Malicious or corrupted ChangeCipher msg");
-                        return LENGTH_ERROR;
-                    }
-
-                    ssl->buffers.inputBuffer.idx++;
                     ssl->keys.encryptionOn = 1;
 
@@ -15332,6 +15980,19 @@
                     #ifdef WOLFSSL_DTLS
                         if (ssl->options.dtls && ssl->options.dtlsHsRetain) {
+                        #ifdef HAVE_SECURE_RENEGOTIATION
+                            /*
+                             * Only free HS resources when not in the process of a
+                             * secure renegotiation and we have received APP DATA
+                             * from the current epoch
+                             */
+                            if (!IsSCR(ssl) && (DtlsUseSCRKeys(ssl)
+                                    || !DtlsSCRKeysSet(ssl))) {
+                                FreeHandshakeResources(ssl);
+                                ssl->options.dtlsHsRetain = 0;
+                            }
+                        #else
                             FreeHandshakeResources(ssl);
                             ssl->options.dtlsHsRetain = 0;
+                        #endif
                         }
                     #endif
@@ -15367,4 +16028,8 @@
                     if (type == decrypt_error)
                         return FATAL_ERROR;
+
+                    /* Reset error if we got an alert level in ret */
+                    if (ret > 0)
+                        ret = 0;
                     break;
 
@@ -15376,7 +16041,13 @@
             ssl->options.processReply = doProcessInit;
 
-            /* input exhausted? */
-            if (ssl->buffers.inputBuffer.idx >= ssl->buffers.inputBuffer.length)
-                return 0;
+            /* input exhausted */
+            if (ssl->buffers.inputBuffer.idx >= ssl->buffers.inputBuffer.length
+#ifdef WOLFSSL_DTLS
+                /* If app data was processed then return now to avoid
+                 * dropping any app data. */
+                || (ssl->options.dtls && ssl->curRL.type == application_data)
+#endif
+                )
+                return ret;
 
             /* more messages per record */
@@ -15413,14 +16084,17 @@
                     }
                 }
-
-                continue;
             }
             /* more records */
             else {
                 WOLFSSL_MSG("More records in input");
-                ssl->options.processReply = doProcessInit;
-                continue;
-            }
-
+            }
+#ifdef WOLFSSL_ASYNC_CRYPT
+            /* We are setup to read next message/record but we had an error
+             * (probably WC_PENDING_E) so return that so it can be handled
+             * by higher layers. */
+            if (ret != 0)
+                return ret;
+#endif
+            continue;
         default:
             WOLFSSL_MSG("Bad process input state, programming error");
@@ -15432,4 +16106,6 @@
 
 
+#if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) || \
+             (defined(WOLFSSL_TLS13) && defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT))
 int SendChangeCipher(WOLFSSL* ssl)
 {
@@ -15474,5 +16150,5 @@
              ssl->buffers.outputBuffer.length;
 
-    AddRecordHeader(output, 1, change_cipher_spec, ssl);
+    AddRecordHeader(output, 1, change_cipher_spec, ssl, CUR_ORDER);
 
     output[idx] = 1;             /* turn it on */
@@ -15483,17 +16159,24 @@
 
         input[0] = 1;  /* turn it on */
+    #ifdef WOLFSSL_DTLS
+        if (IsDtlsNotSctpMode(ssl) &&
+                (ret = DtlsMsgPoolSave(ssl, input, inputSz, change_cipher_hs)) != 0) {
+            return ret;
+        }
+    #endif
         sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
-                              change_cipher_spec, 0, 0, 0);
+                              change_cipher_spec, 0, 0, 0, CUR_ORDER);
         if (sendSz < 0) {
             return sendSz;
         }
     }
-
     #ifdef WOLFSSL_DTLS
+    else {
         if (IsDtlsNotSctpMode(ssl)) {
+            if ((ret = DtlsMsgPoolSave(ssl, output, sendSz, change_cipher_hs)) != 0)
+                return ret;
             DtlsSEQIncrement(ssl, CUR_ORDER);
-            if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0)
-                return ret;
-        }
+        }
+    }
     #endif
     #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
@@ -15505,4 +16188,17 @@
     ssl->buffers.outputBuffer.length += sendSz;
 
+#ifdef WOLFSSL_TLS13
+    if (!ssl->options.tls1_3)
+#endif
+    {
+        /* setup encrypt keys */
+        if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
+            return ret;
+
+    #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+        ssl->options.startedETMWrite = ssl->options.encThenMac;
+    #endif
+    }
+
     if (ssl->options.groupMessages)
         return 0;
@@ -15517,9 +16213,10 @@
         return SendBuffered(ssl);
 }
+#endif
 
 
 #if !defined(NO_OLD_TLS) && !defined(WOLFSSL_AEAD_ONLY)
 static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
-                    int padLen, int content, int verify)
+                    int padLen, int content, int verify, int epochOrder)
 {
     byte   result[WC_MAX_DIGEST_SIZE];
@@ -15534,5 +16231,5 @@
     byte seq[SEQ_SZ];
     byte conLen[ENUM_LEN + LENGTH_SZ];     /* content & length */
-    const byte* macSecret = wolfSSL_GetMacSecret(ssl, verify);
+    const byte* macSecret = NULL;
 
     (void)padLen;
@@ -15543,8 +16240,17 @@
 #endif
 
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls)
+        macSecret = wolfSSL_GetDtlsMacSecret(ssl, verify, epochOrder);
+    else
+        macSecret = wolfSSL_GetMacSecret(ssl, verify);
+#else
+    macSecret = wolfSSL_GetMacSecret(ssl, verify);
+#endif
+
     XMEMSET(seq, 0, SEQ_SZ);
     conLen[0] = (byte)content;
     c16toa((word16)sz, &conLen[ENUM_LEN]);
-    WriteSEQ(ssl, verify, seq);
+    WriteSEQ(ssl, epochOrder, seq);
 
     if (ssl->specs.mac_algorithm == md5_mac) {
@@ -15635,7 +16341,4 @@
 }
 #endif /* !NO_OLD_TLS && !WOLFSSL_AEAD_ONLY */
-
-
-#ifndef NO_CERTS
 
 #if !defined(NO_MD5) && !defined(NO_OLD_TLS)
@@ -15781,29 +16484,11 @@
 }
 
-#endif /* !NO_CERTS */
-
 #ifndef WOLFSSL_NO_TLS12
-/* Persistable BuildMessage arguments */
-typedef struct BuildMsgArgs {
-    word32 digestSz;
-    word32 sz;
-    word32 pad;
-    word32 idx;
-    word32 headerSz;
-    word16 size;
-    word32 ivSz;      /* TLSv1.1  IV */
-    byte*  iv;
-} BuildMsgArgs;
-
-static void FreeBuildMsgArgs(WOLFSSL* ssl, void* pArgs)
+void FreeBuildMsgArgs(WOLFSSL* ssl, BuildMsgArgs* args)
 {
-    BuildMsgArgs* args = (BuildMsgArgs*)pArgs;
-
-    (void)ssl;
-    (void)args;
-
-    if (args->iv) {
-        XFREE(args->iv, ssl->heap, DYNAMIC_TYPE_SALT);
-        args->iv = NULL;
+    if (args) {
+        if (ssl && args->iv)
+            XFREE(args->iv, ssl->heap, DYNAMIC_TYPE_SALT);
+        XMEMSET(args, 0, sizeof(BuildMsgArgs));
     }
 }
@@ -15812,5 +16497,6 @@
 /* Build SSL Message, encrypted */
 int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input,
-             int inSz, int type, int hashOutput, int sizeOnly, int asyncOkay)
+             int inSz, int type, int hashOutput, int sizeOnly, int asyncOkay,
+             int epochOrder)
 {
 #ifndef WOLFSSL_NO_TLS12
@@ -15819,7 +16505,5 @@
     BuildMsgArgs  lcl_args;
 #ifdef WOLFSSL_ASYNC_CRYPT
-    args = (BuildMsgArgs*)ssl->async.args;
-    typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1];
-    (void)sizeof(args_test);
+    args = &ssl->async.buildArgs;
 #endif
 #endif
@@ -15830,4 +16514,6 @@
         return BAD_FUNC_ARG;
     }
+
+    (void)epochOrder;
 
 #ifdef WOLFSSL_NO_TLS12
@@ -15867,7 +16553,4 @@
         args->idx  = RECORD_HEADER_SZ;
         args->headerSz = RECORD_HEADER_SZ;
-    #ifdef WOLFSSL_ASYNC_CRYPT
-        ssl->async.freeArgs = FreeBuildMsgArgs;
-    #endif
     }
 
@@ -15883,4 +16566,46 @@
                 ERROR_OUT(BAD_FUNC_ARG, exit_buildmsg);
             }
+        #if defined(WOLFSSL_DTLS) && defined(HAVE_SECURE_RENEGOTIATION)
+            if (ssl->options.dtls && DtlsSCRKeysSet(ssl)) {
+                /* For epochs >1 the current cipher parameters are located in
+                 * ssl->secure_renegotiation->tmp_keys. Previous cipher
+                 * parameters and for epoch 1 use ssl->keys */
+                switch (epochOrder) {
+                case PREV_ORDER:
+                    if (ssl->encrypt.src != KEYS) {
+                        ssl->secure_renegotiation->cache_status =
+                                SCR_CACHE_NULL;
+                        if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
+                            ERROR_OUT(ret, exit_buildmsg);
+                    }
+                    break;
+                case CUR_ORDER:
+                    if (ssl->keys.dtls_epoch ==
+                            ssl->secure_renegotiation->tmp_keys.dtls_epoch) {
+                        if (ssl->encrypt.src != SCR) {
+                            ssl->secure_renegotiation->cache_status =
+                                    SCR_CACHE_NEEDED;
+                            if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY))
+                                    != 0)
+                                ERROR_OUT(ret, exit_buildmsg);
+                        }
+                    }
+                    else {
+                        if (ssl->encrypt.src != KEYS) {
+                            ssl->secure_renegotiation->cache_status =
+                                    SCR_CACHE_NULL;
+                            if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY))
+                                    != 0)
+                                ERROR_OUT(ret, exit_buildmsg);
+                        }
+                    }
+                    break;
+                default:
+                    WOLFSSL_MSG("BuildMessage only supports PREV_ORDER and "
+                                "CUR_ORDER");
+                    ERROR_OUT(BAD_FUNC_ARG, exit_buildmsg);
+                }
+            }
+        #endif
 
             ssl->options.buildMsgState = BUILD_MSG_SIZE;
@@ -15970,5 +16695,5 @@
 
             args->size = (word16)(args->sz - args->headerSz);    /* include mac and digest */
-            AddRecordHeader(output, args->size, (byte)type, ssl);
+            AddRecordHeader(output, args->size, (byte)type, ssl, epochOrder);
 
             /* write to output */
@@ -16065,5 +16790,5 @@
                     ret = ssl->hmac(ssl, hmac,
                                      output + args->headerSz + args->ivSz, inSz,
-                                     -1, type, 0);
+                                     -1, type, 0, epochOrder);
                     XMEMCPY(output + args->idx, hmac, args->digestSz);
 
@@ -16076,5 +16801,5 @@
                 {
                     ret = ssl->hmac(ssl, output + args->idx, output +
-                                args->headerSz + args->ivSz, inSz, -1, type, 0);
+                                args->headerSz + args->ivSz, inSz, -1, type, 0, epochOrder);
                 }
             }
@@ -16088,4 +16813,23 @@
         case BUILD_MSG_ENCRYPT:
         {
+    #if defined(HAVE_SECURE_RENEGOTIATION) && defined(WOLFSSL_DTLS)
+            /* If we want the PREV_ORDER then modify CUR_ORDER sequence number
+             * for all encryption algos that use it for encryption parameters */
+            word16 dtls_epoch = 0;
+            word16 dtls_sequence_number_hi = 0;
+            word32 dtls_sequence_number_lo = 0;
+            int swap_seq = ssl->options.dtls && epochOrder == PREV_ORDER &&
+                    DtlsUseSCRKeys(ssl);
+            if (swap_seq) {
+                dtls_epoch = ssl->keys.dtls_epoch;
+                dtls_sequence_number_hi = ssl->keys.dtls_sequence_number_hi;
+                dtls_sequence_number_lo = ssl->keys.dtls_sequence_number_lo;
+                ssl->keys.dtls_epoch--;
+                ssl->keys.dtls_sequence_number_hi =
+                        ssl->keys.dtls_prev_sequence_number_hi;
+                ssl->keys.dtls_sequence_number_lo =
+                        ssl->keys.dtls_prev_sequence_number_lo;
+            }
+    #endif
     #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
             if (ssl->options.startedETMWrite) {
@@ -16100,4 +16844,12 @@
                                 output + args->headerSz, args->size, asyncOkay);
             }
+    #if defined(HAVE_SECURE_RENEGOTIATION) && defined(WOLFSSL_DTLS)
+            /* Restore sequence numbers */
+            if (swap_seq) {
+                ssl->keys.dtls_epoch = dtls_epoch;
+                ssl->keys.dtls_sequence_number_hi = dtls_sequence_number_hi;
+                ssl->keys.dtls_sequence_number_lo = dtls_sequence_number_lo;
+            }
+    #endif
             if (ret != 0)
                 goto exit_buildmsg;
@@ -16129,5 +16881,5 @@
                     ret = ssl->hmac(ssl, hmac, output + args->headerSz,
                                     args->ivSz + inSz + args->pad + 1, -1, type,
-                                    0);
+                                    0, epochOrder);
                     XMEMCPY(output + args->idx + args->pad + 1, hmac,
                                                                 args->digestSz);
@@ -16143,5 +16895,5 @@
                                     output + args->headerSz,
                                     args->ivSz + inSz + args->pad + 1, -1, type,
-                                    0);
+                                    0, epochOrder);
                 }
             }
@@ -16165,5 +16917,5 @@
     #ifdef WOLFSSL_DTLS
         if (ret == 0 && ssl->options.dtls)
-            DtlsSEQIncrement(ssl, CUR_ORDER);
+            DtlsSEQIncrement(ssl, epochOrder);
     #endif
 
@@ -16174,7 +16926,4 @@
     /* Final cleanup */
     FreeBuildMsgArgs(ssl, args);
-#ifdef WOLFSSL_ASYNC_CRYPT
-    ssl->async.freeArgs = NULL;
-#endif
 
     return ret;
@@ -16199,12 +16948,4 @@
     WOLFSSL_ENTER("SendFinished");
 
-    /* setup encrypt keys */
-    if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
-        return ret;
-
-    #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
-        ssl->options.startedETMWrite = ssl->options.encThenMac;
-    #endif
-
     /* check for available size */
     outputSz = sizeof(input) + MAX_MSG_EXTRA;
@@ -16247,8 +16988,16 @@
     }
 #endif
+#ifdef OPENSSL_ALL
+    if (ssl->options.side == WOLFSSL_CLIENT_END)
+        XMEMCPY(ssl->clientFinished,
+                hashes, TLS_FINISHED_SZ);
+    else
+        XMEMCPY(ssl->serverFinished,
+                hashes, TLS_FINISHED_SZ);
+#endif
 
     #ifdef WOLFSSL_DTLS
         if (IsDtlsNotSctpMode(ssl)) {
-            if ((ret = DtlsMsgPoolSave(ssl, input, headerSz + finishedSz)) != 0)
+            if ((ret = DtlsMsgPoolSave(ssl, input, headerSz + finishedSz, finished)) != 0)
                 return ret;
         }
@@ -16256,5 +17005,5 @@
 
     sendSz = BuildMessage(ssl, output, outputSz, input, headerSz + finishedSz,
-                                                          handshake, 1, 0, 0);
+                                                          handshake, 1, 0, 0, CUR_ORDER);
     if (sendSz < 0)
         return BUILD_MSG_ERROR;
@@ -16298,4 +17047,14 @@
 
     ret = SendBuffered(ssl);
+
+#ifdef WOLFSSL_DTLS
+    if ((!ssl->options.resuming &&
+            ssl->options.side == WOLFSSL_SERVER_END) ||
+        (ssl->options.resuming &&
+            ssl->options.side == WOLFSSL_CLIENT_END)) {
+        ssl->keys.dtls_handshake_number = 0;
+        ssl->keys.dtls_expected_peer_handshake_number = 0;
+    }
+#endif
 
     WOLFSSL_LEAVE("SendFinished", ret);
@@ -16443,4 +17202,15 @@
 #endif /* !NO_WOLFSSL_SERVER */
 
+#if (!defined(WOLFSSL_NO_TLS12) && !defined(NO_CERTS)) \
+    || (defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER))
+static int cipherExtraData(WOLFSSL* ssl)
+{
+    /* Cipher data that may be added by BuildMessage */
+    return ssl->specs.hash_size + ssl->specs.block_size +
+            ssl->specs.aead_mac_size + ssl->specs.iv_size +
+            ssl->specs.pad_size;
+}
+#endif
+
 #ifndef WOLFSSL_NO_TLS12
 
@@ -16554,4 +17324,7 @@
         }
 
+        if (IsEncryptionOn(ssl, 1))
+            sendSz += cipherExtraData(ssl);
+
         /* check for available size */
         if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
@@ -16566,5 +17339,5 @@
                 AddFragHeaders(output, fragSz, 0, payloadSz, certificate, ssl);
                 if (!IsEncryptionOn(ssl, 1))
-                    HashOutputRaw(ssl, output + RECORD_HEADER_SZ,
+                    HashRaw(ssl, output + RECORD_HEADER_SZ,
                                   HANDSHAKE_HEADER_SZ);
             }
@@ -16572,8 +17345,7 @@
             #ifdef WOLFSSL_DTLS
                 AddHeaders(output, payloadSz, certificate, ssl);
-                if (!IsEncryptionOn(ssl, 1))
-                    HashOutputRaw(ssl,
-                                  output + RECORD_HEADER_SZ + DTLS_RECORD_EXTRA,
-                                  HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA);
+                HashRaw(ssl,
+                        output + RECORD_HEADER_SZ + DTLS_RECORD_EXTRA,
+                        HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA);
                 /* Adding the headers increments these, decrement them for
                  * actual message header. */
@@ -16586,6 +17358,6 @@
             /* list total */
             c32to24(listSz, output + i);
-            if (!IsEncryptionOn(ssl, 1))
-                HashOutputRaw(ssl, output + i, CERT_HEADER_SZ);
+            if (ssl->options.dtls || !IsEncryptionOn(ssl, 1))
+                HashRaw(ssl, output + i, CERT_HEADER_SZ);
             i += CERT_HEADER_SZ;
             length -= CERT_HEADER_SZ;
@@ -16593,14 +17365,14 @@
             if (certSz) {
                 c32to24(certSz, output + i);
-                if (!IsEncryptionOn(ssl, 1))
-                    HashOutputRaw(ssl, output + i, CERT_HEADER_SZ);
+                if (ssl->options.dtls || !IsEncryptionOn(ssl, 1))
+                    HashRaw(ssl, output + i, CERT_HEADER_SZ);
                 i += CERT_HEADER_SZ;
                 length -= CERT_HEADER_SZ;
                 fragSz -= CERT_HEADER_SZ;
 
-                if (!IsEncryptionOn(ssl, 1)) {
-                    HashOutputRaw(ssl, ssl->buffers.certificate->buffer, certSz);
+                if (ssl->options.dtls || !IsEncryptionOn(ssl, 1)) {
+                    HashRaw(ssl, ssl->buffers.certificate->buffer, certSz);
                     if (certChainSz)
-                        HashOutputRaw(ssl, ssl->buffers.certChain->buffer,
+                        HashRaw(ssl, ssl->buffers.certChain->buffer,
                                       certChainSz);
                 }
@@ -16609,5 +17381,5 @@
         else {
             if (!ssl->options.dtls) {
-                AddRecordHeader(output, fragSz, handshake, ssl);
+                AddRecordHeader(output, fragSz, handshake, ssl, CUR_ORDER);
             }
             else {
@@ -16642,5 +17414,10 @@
         if (IsEncryptionOn(ssl, 1)) {
             byte* input = NULL;
-            int   inputSz = i - RECORD_HEADER_SZ; /* build msg adds rec hdr */
+            int   inputSz = i; /* build msg adds rec hdr */
+            int   recordHeaderSz = RECORD_HEADER_SZ;
+
+            if (ssl->options.dtls)
+                recordHeaderSz += DTLS_RECORD_EXTRA;
+            inputSz -= recordHeaderSz;
 
             if (inputSz < 0) {
@@ -16654,12 +17431,26 @@
                 if (input == NULL)
                     return MEMORY_E;
-                XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
-            }
-
+                XMEMCPY(input, output + recordHeaderSz, inputSz);
+            }
+
+#ifndef WOLFSSL_DTLS
             sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
-                                                          handshake, 1, 0, 0);
-
-            if (inputSz > 0)
-                XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+                                                          handshake, 1, 0, 0, CUR_ORDER);
+#else
+            if (!ssl->options.dtls)
+                sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
+                                                              handshake, 1, 0, 0, CUR_ORDER);
+            else /* DTLS 1.2 has to ignore fragmentation in hashing so we need to
+                  * calculate the hash ourselves above */ {
+                if ((ret = DtlsMsgPoolSave(ssl, input, inputSz, certificate)) != 0) {
+                    XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+                    return ret;
+                }
+                sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
+                                                              handshake, 0, 0, 0, CUR_ORDER);
+            }
+#endif
+
+            XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
 
             if (sendSz < 0)
@@ -16667,16 +17458,14 @@
         }
         else {
+            sendSz = i;
         #ifdef WOLFSSL_DTLS
+            if (IsDtlsNotSctpMode(ssl)) {
+                if ((ret = DtlsMsgPoolSave(ssl, output, sendSz, certificate)) != 0)
+                    return ret;
+            }
             if (ssl->options.dtls)
                 DtlsSEQIncrement(ssl, CUR_ORDER);
         #endif
         }
-
-    #ifdef WOLFSSL_DTLS
-        if (IsDtlsNotSctpMode(ssl)) {
-            if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0)
-                return ret;
-        }
-    #endif
 
     #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
@@ -16720,5 +17509,5 @@
     word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
     word32 dnLen = 0;
-#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY)
     WOLF_STACK_OF(WOLFSSL_X509_NAME)* names;
 #endif
@@ -16733,5 +17522,5 @@
         reqSz += LENGTH_SZ + ssl->suites->hashSigAlgoSz;
 
-#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY)
     /* Certificate Authorities */
     names = ssl->ctx->ca_names;
@@ -16762,4 +17551,8 @@
     #endif
     }
+
+    if (IsEncryptionOn(ssl, 1))
+        sendSz += cipherExtraData(ssl);
+
     /* check for available size */
     if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
@@ -16798,5 +17591,5 @@
     c16toa((word16)dnLen, &output[i]);  /* auth's */
     i += REQ_HEADER_SZ;
-#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY)
     names = ssl->ctx->ca_names;
     while (names != NULL) {
@@ -16815,6 +17608,16 @@
 
         if (IsEncryptionOn(ssl, 1)) {
-            byte* input;
-            int   inputSz = i - RECORD_HEADER_SZ; /* build msg adds rec hdr */
+            byte* input = NULL;
+            int   inputSz = i; /* build msg adds rec hdr */
+            int   recordHeaderSz = RECORD_HEADER_SZ;
+
+            if (ssl->options.dtls)
+                recordHeaderSz += DTLS_RECORD_EXTRA;
+            inputSz -= recordHeaderSz;
+
+            if (inputSz <= 0) {
+                WOLFSSL_MSG("Send Cert Req bad inputSz");
+                return BUFFER_E;
+            }
 
             input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
@@ -16822,7 +17625,14 @@
                 return MEMORY_E;
 
-            XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+            XMEMCPY(input, output + recordHeaderSz, inputSz);
+            #ifdef WOLFSSL_DTLS
+            if (IsDtlsNotSctpMode(ssl) &&
+                    (ret = DtlsMsgPoolSave(ssl, input, inputSz, certificate_request)) != 0) {
+                XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+                return ret;
+            }
+            #endif
             sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
-                                  handshake, 1, 0, 0);
+                                  handshake, 1, 0, 0, CUR_ORDER);
             XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
 
@@ -16830,11 +17640,12 @@
                 return sendSz;
         } else {
+            sendSz = i;
             #ifdef WOLFSSL_DTLS
+                if (IsDtlsNotSctpMode(ssl)) {
+                    if ((ret = DtlsMsgPoolSave(ssl, output, sendSz, certificate_request)) != 0)
+                        return ret;
+                }
                 if (ssl->options.dtls)
                     DtlsSEQIncrement(ssl, CUR_ORDER);
-                if (IsDtlsNotSctpMode(ssl)) {
-                    if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0)
-                        return ret;
-                }
             #endif
             ret = HashOutput(ssl, output, sendSz, 0);
@@ -16919,13 +17730,21 @@
         if (IsEncryptionOn(ssl, 1)) {
             byte* input;
-            int   inputSz = idx - RECORD_HEADER_SZ;
-
+            int   inputSz = idx; /* build msg adds rec hdr */
+            int   recordHeaderSz = RECORD_HEADER_SZ;
+
+            if (ssl->options.dtls)
+                recordHeaderSz += DTLS_RECORD_EXTRA;
+            inputSz -= recordHeaderSz;
             input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
             if (input == NULL)
                 return MEMORY_E;
 
-            XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
-            sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
-                                                           handshake, 1, 0, 0);
+            XMEMCPY(input, output + recordHeaderSz, inputSz);
+            #ifdef WOLFSSL_DTLS
+                ret = DtlsMsgPoolSave(ssl, input, inputSz, certificate_status);
+            #endif
+            if (ret == 0)
+                sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
+                                      handshake, 1, 0, 0, CUR_ORDER);
             XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
 
@@ -16935,14 +17754,11 @@
         else {
             #ifdef WOLFSSL_DTLS
-                if (ssl->options.dtls)
+                if (ret == 0 && IsDtlsNotSctpMode(ssl))
+                    ret = DtlsMsgPoolSave(ssl, output, sendSz, certificate_status);
+                if (ret == 0 && ssl->options.dtls)
                     DtlsSEQIncrement(ssl, CUR_ORDER);
             #endif
             ret = HashOutput(ssl, output, sendSz, 0);
         }
-
-    #ifdef WOLFSSL_DTLS
-        if (ret == 0 && IsDtlsNotSctpMode(ssl))
-            ret = DtlsMsgPoolSave(ssl, output, sendSz);
-    #endif
 
     #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
@@ -17047,4 +17863,5 @@
                 DecodedCert  cert[1];
             #endif
+                DerBuffer* chain;
 
             #ifdef WOLFSSL_SMALL_STACK
@@ -17063,12 +17880,18 @@
                 }
 
-                while (idx + OPAQUE24_LEN < ssl->buffers.certChain->length) {
-                    c24to32(ssl->buffers.certChain->buffer + idx, &der.length);
+                /* use certChain if available, otherwise use peer certificate */
+                chain = ssl->buffers.certChain;
+                if (chain == NULL) {
+                    chain = ssl->buffers.certificate;
+                }
+
+                while (chain && idx + OPAQUE24_LEN < chain->length) {
+                    c24to32(chain->buffer + idx, &der.length);
                     idx += OPAQUE24_LEN;
 
-                    der.buffer = ssl->buffers.certChain->buffer + idx;
+                    der.buffer = chain->buffer + idx;
                     idx += der.length;
 
-                    if (idx > ssl->buffers.certChain->length)
+                    if (idx > chain->length)
                         break;
 
@@ -17148,7 +17971,60 @@
 
 
+
+#if defined(HAVE_SECURE_RENEGOTIATION) && defined(WOLFSSL_DTLS)
+/**
+ * Check if the SCR keys are set in ssl->secure_renegotiation->tmp_keys.
+ */
+int DtlsSCRKeysSet(WOLFSSL* ssl)
+{
+    return ssl->secure_renegotiation &&
+           ssl->secure_renegotiation->tmp_keys.dtls_epoch != 0;
+}
+
+/**
+ * ssl->keys contains the current cipher parameters only for epoch 1. For
+ * epochs >1 ssl->secure_renegotiation->tmp_keys contains the current
+ * cipher parameters. This function checks if the message currently being
+ * processed should use ssl->keys or ssl->secure_renegotiation->tmp_keys.
+ */
+int IsDtlsMsgSCRKeys(WOLFSSL* ssl)
+{
+    return DtlsSCRKeysSet(ssl) &&
+           ssl->keys.curEpoch ==
+                   ssl->secure_renegotiation->tmp_keys.dtls_epoch;
+}
+
+/**
+ * ssl->keys contains the current cipher parameters only for epoch 1. For
+ * epochs >1 ssl->secure_renegotiation->tmp_keys contains the current
+ * cipher parameters. This function checks if the message currently being
+ * built should use ssl->keys or ssl->secure_renegotiation->tmp_keys.
+ */
+int DtlsUseSCRKeys(WOLFSSL* ssl)
+{
+    return DtlsSCRKeysSet(ssl) &&
+           ssl->secure_renegotiation->tmp_keys.dtls_epoch ==
+                   ssl->keys.dtls_epoch;
+}
+
+/**
+ * If ssl->secure_renegotiation->tmp_keys.dtls_epoch > ssl->keys.dtls_epoch
+ * then PREV_ORDER refers to the current epoch.
+ * */
+int DtlsCheckOrder(WOLFSSL* ssl, int order)
+{
+    if (order == PREV_ORDER && ssl->secure_renegotiation &&
+            ssl->secure_renegotiation->tmp_keys.dtls_epoch > ssl->keys.dtls_epoch) {
+        return CUR_ORDER;
+    }
+    else {
+        return order;
+    }
+}
+#endif /* HAVE_SECURE_RENEGOTIATION && WOLFSSL_DTLS */
+
 /* If secure renegotiation is disabled, this will always return false.
  * Otherwise it checks to see if we are currently renegotiating. */
-static WC_INLINE int IsSCR(WOLFSSL* ssl)
+int IsSCR(WOLFSSL* ssl)
 {
 #ifndef HAVE_SECURE_RENEGOTIATION
@@ -17156,6 +18032,7 @@
 #else /* HAVE_SECURE_RENEGOTIATION */
     if (ssl->secure_renegotiation &&
-            ssl->secure_renegotiation->enabled &&
-            ssl->options.handShakeState != HANDSHAKE_DONE)
+            ssl->secure_renegotiation->enabled &&  /* Is SCR enabled? */
+            ssl->options.handShakeDone && /* At least one handshake done? */
+            ssl->options.handShakeState != HANDSHAKE_DONE) /* Currently handshaking? */
         return 1;
 #endif /* HAVE_SECURE_RENEGOTIATION */
@@ -17197,5 +18074,6 @@
         if (ssl->options.handShakeState == HANDSHAKE_DONE) {
             WOLFSSL_MSG("handshake complete, trying to send early data");
-            return BUILD_MSG_ERROR;
+            ssl->error = BUILD_MSG_ERROR;
+            return WOLFSSL_FATAL_ERROR;
         }
     #ifdef WOLFSSL_EARLY_DATA_GROUP
@@ -17264,7 +18142,9 @@
         len = wolfSSL_GetMaxRecordSize(ssl, sz - sent);
 
-#ifdef WOLFSSL_DTLS
-        if (IsDtlsNotSctpMode(ssl)) {
-            len = min(len, MAX_UDP_SIZE);
+#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_DTLS_SIZE_CHECK)
+        if (ssl->options.dtls && (len < sz - sent)) {
+            ssl->error = DTLS_SIZE_ERROR;
+            WOLFSSL_ERROR(ssl->error);
+            return ssl->error;
         }
 #endif
@@ -17295,5 +18175,5 @@
         if (!ssl->options.tls1_3) {
             sendSz = BuildMessage(ssl, out, outputSz, sendBuffer, buffSz,
-                                  application_data, 0, 0, 1);
+                                  application_data, 0, 0, 1, CUR_ORDER);
         }
         else {
@@ -17353,9 +18233,5 @@
 
     /* reset error state */
-    if (ssl->error == WANT_READ
-    #ifdef WOLFSSL_ASYNC_CRYPT
-        || ssl->error == WC_PENDING_E
-    #endif
-    ) {
+    if (ssl->error == WANT_READ) {
         ssl->error = 0;
     }
@@ -17370,5 +18246,12 @@
 #endif /* WOLFSSL_DTLS */
 
-    if (ssl->error != 0 && ssl->error != WANT_WRITE) {
+    if (ssl->error != 0 && ssl->error != WANT_WRITE
+#ifdef WOLFSSL_ASYNC_CRYPT
+            && ssl->error != WC_PENDING_E
+#endif
+#ifdef HAVE_SECURE_RENEGOTIATION
+            && ssl->error != APP_DATA_READY
+#endif
+    ) {
         WOLFSSL_MSG("User calling wolfSSL_read in error state, not allowed");
         return ssl->error;
@@ -17380,15 +18263,29 @@
     else
 #endif
-    if (ssl->options.handShakeState != HANDSHAKE_DONE) {
-        int err;
-        WOLFSSL_MSG("Handshake not complete, trying to finish");
-        if ( (err = wolfSSL_negotiate(ssl)) != WOLFSSL_SUCCESS) {
-        #ifdef WOLFSSL_ASYNC_CRYPT
-            /* if async would block return WANT_WRITE */
-            if (ssl->error == WC_PENDING_E) {
-                return WOLFSSL_CBIO_ERR_WANT_READ;
-            }
-        #endif
-            return  err;
+    {
+        int negotiate = 0;
+#ifdef HAVE_SECURE_RENEGOTIATION
+        if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled) {
+            if (ssl->options.handShakeState != HANDSHAKE_DONE
+                && ssl->buffers.clearOutputBuffer.length == 0)
+                negotiate = 1;
+        }
+        else
+#endif
+        if (ssl->options.handShakeState != HANDSHAKE_DONE)
+            negotiate = 1;
+
+        if (negotiate) {
+            int err;
+            WOLFSSL_MSG("Handshake not complete, trying to finish");
+            if ( (err = wolfSSL_negotiate(ssl)) != WOLFSSL_SUCCESS) {
+            #ifdef WOLFSSL_ASYNC_CRYPT
+                /* if async would block return WANT_WRITE */
+                if (ssl->error == WC_PENDING_E) {
+                    return WOLFSSL_CBIO_ERR_WANT_READ;
+                }
+            #endif
+                return err;
+            }
         }
     }
@@ -17397,9 +18294,10 @@
 startScr:
     if (ssl->secure_renegotiation && ssl->secure_renegotiation->startScr) {
-        int err;
+        int ret;
         WOLFSSL_MSG("Need to start scr, server requested");
-        if ( (err = wolfSSL_Rehandshake(ssl)) != WOLFSSL_SUCCESS)
-            return  err;
+        ret = wolfSSL_Rehandshake(ssl);
         ssl->secure_renegotiation->startScr = 0;  /* only start once */
+        if (ret != WOLFSSL_SUCCESS)
+            return ret;
     }
 #endif
@@ -17410,5 +18308,5 @@
             if (ssl->error == ZERO_RETURN) {
                 WOLFSSL_MSG("Zero return, no more data coming");
-                return 0;         /* no more data coming */
+                return 0; /* no more data coming */
             }
             if (ssl->error == SOCKET_ERROR_E) {
@@ -17417,5 +18315,5 @@
                     ssl->error = SOCKET_PEER_CLOSED_E;
                     WOLFSSL_ERROR(ssl->error);
-                    return 0;     /* peer reset or closed */
+                    return 0; /* peer reset or closed */
                 }
             }
@@ -17427,11 +18325,35 @@
                 goto startScr;
             }
+            if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled &&
+                    ssl->options.handShakeState != HANDSHAKE_DONE
+                    && ssl->buffers.clearOutputBuffer.length == 0) {
+                /* ProcessReply processed a handshake packet and not any APP DATA
+                 * so let's move the handshake along */
+                int err;
+                WOLFSSL_MSG("Handshake not complete, trying to finish");
+                if ( (err = wolfSSL_negotiate(ssl)) != WOLFSSL_SUCCESS) {
+                #ifdef WOLFSSL_ASYNC_CRYPT
+                    /* if async would block return WANT_WRITE */
+                    if (ssl->error == WC_PENDING_E) {
+                        return WOLFSSL_CBIO_ERR_WANT_READ;
+                    }
+                #endif
+                    return err;
+                }
+            }
         #endif
-    }
-
-    if (sz < (int)ssl->buffers.clearOutputBuffer.length)
-        size = sz;
-    else
-        size = ssl->buffers.clearOutputBuffer.length;
+    #ifdef WOLFSSL_TLS13
+        if (IsAtLeastTLSv1_3(ssl->version) && ssl->options.handShakeDone &&
+                                         ssl->curRL.type == handshake && peek) {
+            WOLFSSL_MSG("Got Handshake Messge in APP data");
+            if (ssl->buffers.inputBuffer.length == 0) {
+                ssl->error = WOLFSSL_ERROR_WANT_READ;
+                return 0;
+            }
+        }
+    #endif
+    }
+
+    size = min(sz, (int)ssl->buffers.clearOutputBuffer.length);
 
     XMEMCPY(output, ssl->buffers.clearOutputBuffer.buffer, size);
@@ -17522,14 +18444,15 @@
     }
 
-    /* only send encrypted alert if handshake actually complete, otherwise
-       other side may not be able to handle it */
-    if (IsEncryptionOn(ssl, 1) && (IsAtLeastTLSv1_3(ssl->version) ||
-                                                  ssl->options.handShakeDone)) {
+    /* send encrypted alert if encryption is on - can be a rehandshake over
+     * an existing encrypted channel.
+     * TLS 1.3 encrypts handshake packets after the ServerHello
+     */
+    if (IsEncryptionOn(ssl, 1)) {
         sendSz = BuildMessage(ssl, output, outputSz, input, ALERT_SIZE, alert,
-                                                                       0, 0, 0);
+                                                                       0, 0, 0, CUR_ORDER);
     }
     else {
 
-        AddRecordHeader(output, ALERT_SIZE, alert, ssl);
+        AddRecordHeader(output, ALERT_SIZE, alert, ssl, CUR_ORDER);
         output += RECORD_HEADER_SZ;
         #ifdef WOLFSSL_DTLS
@@ -18000,4 +18923,10 @@
         return "TLS1.3 Secret Callback Error";
 
+    case DTLS_SIZE_ERROR:
+        return "DTLS trying to send too much in single datagram error";
+
+    case NO_CERT_ERROR:
+        return "TLS1.3 No Certificate Set Error";
+
     default :
         return "unknown error number";
@@ -18013,17 +18942,49 @@
 }
 
-#ifndef NO_ERROR_STRINGS
-    #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
-        #define SUITE_INFO(x,y,z,w,v,u) {(x),(y),(z),(w),(v),(u)}
+#ifdef NO_CIPHER_SUITE_ALIASES
+    #ifndef NO_ERROR_STRINGS
+        #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
+            #define SUITE_INFO(x,y,z,w,v,u) {(x),(y),(z),(w),(v),(u),WOLFSSL_CIPHER_SUITE_FLAG_NONE}
+            #define SUITE_ALIAS(x,z,w,v,u)
+        #else
+            #define SUITE_INFO(x,y,z,w,v,u) {(x),(y),(z),(w),WOLFSSL_CIPHER_SUITE_FLAG_NONE}
+            #define SUITE_ALIAS(x,z,w,v,u)
+        #endif
     #else
-        #define SUITE_INFO(x,y,z,w,v,u) {(x),(y),(z),(w)}
+        #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
+            #define SUITE_INFO(x,y,z,w,v,u) {(x),(z),(w),(v),(u),WOLFSSL_CIPHER_SUITE_FLAG_NONE}
+            #define SUITE_ALIAS(x,z,w,v,u)
+        #else
+            #define SUITE_INFO(x,y,z,w,v,u) {(x),(z),(w),WOLFSSL_CIPHER_SUITE_FLAG_NONE}
+            #define SUITE_ALIAS(x,z,w,v,u)
+        #endif
     #endif
-#else
-    #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
-        #define SUITE_INFO(x,y,z,w,v,u) {(x),(z),(w),(v),(u)}
+#else /* !NO_CIPHER_SUITE_ALIASES */
+
+    /* note that the comma is included at the end of the SUITE_ALIAS() macro
+     * definitions, to allow aliases to be gated out by the above null macros
+     * in the NO_CIPHER_SUITE_ALIASES section.
+     */
+
+    #ifndef NO_ERROR_STRINGS
+        #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) || \
+            defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX)
+            #define SUITE_INFO(x,y,z,w,v,u) {(x),(y),(z),(w),(v),(u),WOLFSSL_CIPHER_SUITE_FLAG_NONE}
+            #define SUITE_ALIAS(x,z,w,v,u) {(x),"",(z),(w),(v),(u),WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS},
+        #else
+            #define SUITE_INFO(x,y,z,w,v,u) {(x),(y),(z),(w),WOLFSSL_CIPHER_SUITE_FLAG_NONE}
+            #define SUITE_ALIAS(x,z,w,v,u) {(x),"",(z),(w),WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS},
+        #endif
     #else
-        #define SUITE_INFO(x,y,z,w,v,u) {(x),(z),(w)}
+        #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) || \
+            defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX)
+            #define SUITE_INFO(x,y,z,w,v,u) {(x),(z),(w),(v),(u),WOLFSSL_CIPHER_SUITE_FLAG_NONE}
+            #define SUITE_ALIAS(x,z,w,v,u) {(x),(z),(w),(v),(u),WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS},
+        #else
+            #define SUITE_INFO(x,y,z,w,v,u) {(x),(z),(w),WOLFSSL_CIPHER_SUITE_FLAG_NONE}
+            #define SUITE_ALIAS(x,z,w,v,u) {(x),(z),(w),WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS},
+        #endif
     #endif
-#endif
+#endif /* NO_CIPHER_SUITE_ALIASES */
 
 static const CipherSuiteInfo cipher_names[] =
@@ -18048,4 +19009,5 @@
 #ifdef BUILD_TLS_AES_128_CCM_8_SHA256
     SUITE_INFO("TLS13-AES128-CCM-8-SHA256","TLS_AES_128_CCM_8_SHA256",TLS13_BYTE,TLS_AES_128_CCM_8_SHA256,TLSv1_3_MINOR, SSLv3_MAJOR),
+    SUITE_ALIAS("TLS13-AES128-CCM8-SHA256",TLS13_BYTE,TLS_AES_128_CCM_8_SHA256,TLSv1_3_MINOR, SSLv3_MAJOR)
 #endif
 
@@ -18158,8 +19120,10 @@
 #ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8
     SUITE_INFO("PSK-AES128-CCM-8","TLS_PSK_WITH_AES_128_CCM_8",ECC_BYTE,TLS_PSK_WITH_AES_128_CCM_8,TLSv1_MINOR,SSLv3_MAJOR),
+    SUITE_ALIAS("PSK-AES128-CCM8",ECC_BYTE,TLS_PSK_WITH_AES_128_CCM_8,TLSv1_MINOR,SSLv3_MAJOR)
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8
     SUITE_INFO("PSK-AES256-CCM-8","TLS_PSK_WITH_AES_256_CCM_8",ECC_BYTE,TLS_PSK_WITH_AES_256_CCM_8,TLSv1_MINOR,SSLv3_MAJOR),
+    SUITE_ALIAS("PSK-AES256-CCM8",ECC_BYTE,TLS_PSK_WITH_AES_256_CCM_8,TLSv1_MINOR,SSLv3_MAJOR)
 #endif
 
@@ -18214,8 +19178,10 @@
 #ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8
     SUITE_INFO("AES128-CCM-8","TLS_RSA_WITH_AES_128_CCM_8",ECC_BYTE,TLS_RSA_WITH_AES_128_CCM_8, TLSv1_2_MINOR, SSLv3_MAJOR),
+    SUITE_ALIAS("AES128-CCM8",ECC_BYTE,TLS_RSA_WITH_AES_128_CCM_8, TLSv1_2_MINOR, SSLv3_MAJOR)
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8
     SUITE_INFO("AES256-CCM-8","TLS_RSA_WITH_AES_256_CCM_8",ECC_BYTE,TLS_RSA_WITH_AES_256_CCM_8, TLSv1_2_MINOR, SSLv3_MAJOR),
+    SUITE_ALIAS("AES256-CCM8",ECC_BYTE,TLS_RSA_WITH_AES_256_CCM_8, TLSv1_2_MINOR, SSLv3_MAJOR)
 #endif
 
@@ -18226,8 +19192,10 @@
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
     SUITE_INFO("ECDHE-ECDSA-AES128-CCM-8","TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, TLSv1_2_MINOR, SSLv3_MAJOR),
+    SUITE_ALIAS("ECDHE-ECDSA-AES128-CCM8",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, TLSv1_2_MINOR, SSLv3_MAJOR)
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
     SUITE_INFO("ECDHE-ECDSA-AES256-CCM-8","TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, TLSv1_2_MINOR, SSLv3_MAJOR),
+    SUITE_ALIAS("ECDHE-ECDSA-AES256-CCM8",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, TLSv1_2_MINOR, SSLv3_MAJOR)
 #endif
 
@@ -18525,5 +19493,9 @@
     for (i = 0; i < GetCipherNamesSize(); i++) {
         if ((cipher_names[i].cipherSuite0 == cipherSuite0) &&
-            (cipher_names[i].cipherSuite  == cipherSuite)) {
+            (cipher_names[i].cipherSuite  == cipherSuite)
+#ifndef NO_CIPHER_SUITE_ALIASES
+            && (! (cipher_names[i].flags & WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS))
+#endif
+            ) {
             nameInternal = cipher_names[i].name;
             break;
@@ -18542,4 +19514,9 @@
     n3 = n[3];
     n4 = n[4];
+
+#ifdef HAVE_NTRU
+    if (XSTRNCMP(n0,"NTRU",4) == 0)
+        return "NTRU";
+#endif
 
     if (XSTRNCMP(n0,"ECDHE",5) == 0 && XSTRNCMP(n1,"PSK",3) == 0)
@@ -18578,4 +19555,9 @@
     n2 = n[2];
 
+#ifdef HAVE_NTRU
+    if (XSTRNCMP(n0,"NTRU",4) == 0)
+        return "NTRU";
+#endif
+
     if ((XSTRNCMP(n0,"AES128",6) == 0) || (XSTRNCMP(n0,"AES256",6) == 0)  ||
         ((XSTRNCMP(n0,"TLS13",5) == 0) && ((XSTRNCMP(n1,"AES128",6) == 0) ||
@@ -18591,4 +19573,6 @@
     else if (XSTRNCMP(n1,"ECDSA",5) == 0)
         authStr = "ECDSA";
+    else if (XSTRNCMP(n0,"ADH",3) == 0)
+        authStr = "None";
     else
         authStr = "unknown";
@@ -18640,8 +19624,11 @@
              (XSTRNCMP(n2,"CAMELLIA128",11) == 0))
         encStr = "CAMELLIA(128)";
-    else if ((XSTRNCMP(n0,"RC4",3) == 0) || (XSTRNCMP(n2,"RC4",3) == 0))
+    else if ((XSTRNCMP(n0,"RC4",3) == 0) || (XSTRNCMP(n1,"RC4",3) == 0) ||
+            (XSTRNCMP(n2,"RC4",3) == 0))
         encStr = "RC4";
-    else if (((XSTRNCMP(n0,"DES",3) == 0)  || (XSTRNCMP(n2,"DES",3) == 0)) &&
-             ((XSTRNCMP(n1,"CBC3",4) == 0) || (XSTRNCMP(n3,"CBC3",4) == 0)))
+    else if (((XSTRNCMP(n0,"DES",3) == 0)  || (XSTRNCMP(n1,"DES",3) == 0) ||
+              (XSTRNCMP(n2,"DES",3) == 0)) &&
+             ((XSTRNCMP(n1,"CBC3",4) == 0) || (XSTRNCMP(n2,"CBC3",4) == 0) ||
+              (XSTRNCMP(n3,"CBC3",4) == 0)))
         encStr = "3DES";
     else if ((XSTRNCMP(n1,"CHACHA20",8) == 0 && XSTRNCMP(n2,"POLY1305",8) == 0) ||
@@ -18733,5 +19720,9 @@
     for (i = 0; i < GetCipherNamesSize(); i++) {
         if ((cipher_names[i].cipherSuite0 == cipherSuite0) &&
-            (cipher_names[i].cipherSuite  == cipherSuite)) {
+            (cipher_names[i].cipherSuite  == cipherSuite)
+#ifndef NO_CIPHER_SUITE_ALIASES
+            && (! (cipher_names[i].flags & WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS))
+#endif
+            ) {
             nameIana = cipher_names[i].name_iana;
             break;
@@ -18765,14 +19756,24 @@
 
 int GetCipherSuiteFromName(const char* name, byte* cipherSuite0,
-                           byte* cipherSuite)
+                           byte* cipherSuite, int* flags)
 {
     int           ret = BAD_FUNC_ARG;
     int           i;
-    unsigned long len = (unsigned long)XSTRLEN(name);
+    unsigned long len;
+    const char*   nameDelim;
+
+    /* Support trailing : */
+    nameDelim = XSTRSTR(name, ":");
+    if (nameDelim)
+        len = (unsigned long)(nameDelim - name);
+    else
+        len = (unsigned long)XSTRLEN(name);
 
     for (i = 0; i < GetCipherNamesSize(); i++) {
-        if (XSTRNCMP(name, cipher_names[i].name, len) == 0) {
+        if ((XSTRNCMP(name, cipher_names[i].name, len) == 0) &&
+            (cipher_names[i].name[len] == 0)) {
             *cipherSuite0 = cipher_names[i].cipherSuite0;
             *cipherSuite  = cipher_names[i].cipherSuite;
+            *flags = cipher_names[i].flags;
             ret = 0;
             break;
@@ -18912,87 +19913,144 @@
 
 #if !defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS)
+static int MatchSigAlgo(WOLFSSL* ssl, int sigAlgo)
+{
+#ifdef HAVE_ED25519
+    if (ssl->pkCurveOID == ECC_ED25519_OID) {
+        /* Certificate has Ed25519 key, only match with Ed25519 sig alg  */
+        return sigAlgo == ed25519_sa_algo;
+    }
+#endif
+#ifdef HAVE_ED448
+    if (ssl->pkCurveOID == ECC_ED448_OID) {
+        /* Certificate has Ed448 key, only match with Ed448 sig alg  */
+        return sigAlgo == ed448_sa_algo;
+    }
+#endif
+#ifdef WC_RSA_PSS
+    /* RSA certificate and PSS sig alg. */
+    if (ssl->suites->sigAlgo == rsa_sa_algo) {
+    #if defined(WOLFSSL_TLS13)
+        /* TLS 1.3 only supports RSA-PSS. */
+        if (IsAtLeastTLSv1_3(ssl->version))
+            return sigAlgo == rsa_pss_sa_algo;
+    #endif
+        /* TLS 1.2 and below - RSA-PSS allowed. */
+        if (sigAlgo == rsa_pss_sa_algo)
+            return 1;
+    }
+#endif
+    /* Signature algorithm matches certificate. */
+    return sigAlgo == ssl->suites->sigAlgo;
+}
+
+#if defined(HAVE_ECC) && defined(WOLFSSL_TLS13) || \
+                                              defined(USE_ECDSA_KEYSZ_HASH_ALGO)
+static int CmpEccStrength(int hashAlgo, int curveSz)
+{
+    int dgstSz = GetMacDigestSize(hashAlgo);
+    if (dgstSz <= 0)
+        return -1;
+    return dgstSz - (curveSz & (~0x3));
+}
+#endif
+
+static byte MinHashAlgo(WOLFSSL* ssl)
+{
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+        return sha256_mac;
+    }
+#endif
+#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_ALLOW_TLS_SHA1)
+    if (IsAtLeastTLSv1_2(ssl)) {
+        return sha256_mac;
+    }
+#endif /* WOLFSSL_NO_TLS12 */
+    return sha_mac;
+}
+
 int PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, word32 hashSigAlgoSz)
 {
     word32 i;
     int ret = MATCH_SUITE_ERROR;
-
-    ssl->suites->sigAlgo = ssl->specs.sig_algo;
+    byte minHash;
 
     /* set defaults */
     if (IsAtLeastTLSv1_3(ssl->version)) {
-        ssl->suites->hashAlgo = sha256_mac;
     #ifndef NO_CERTS
+        /* TLS 1.3 cipher suites don't have public key algorithms in them.
+         * Using the one in the certificate - if any.
+         */
         ssl->suites->sigAlgo = ssl->buffers.keyType;
     #endif
     }
-#ifndef WOLFSSL_NO_TLS12
-    else if (IsAtLeastTLSv1_2(ssl)) {
-    #ifdef WOLFSSL_ALLOW_TLS_SHA1
-        ssl->suites->hashAlgo = sha_mac;
-    #else
-        ssl->suites->hashAlgo = sha256_mac;
-    #endif
-    }
-    else {
-        ssl->suites->hashAlgo = sha_mac;
-    }
-#endif
-
+    else
+        ssl->suites->sigAlgo = ssl->specs.sig_algo;
+    if (ssl->suites->sigAlgo == 0) {
+        /* PSK ciphersuite - get digest to use from cipher suite */
+        ssl->suites->hashAlgo = ssl->specs.mac_algorithm;
+        return 0;
+    }
+    ssl->suites->hashAlgo = minHash = MinHashAlgo(ssl);
+
+    /* No list means go with the defaults. */
     if (hashSigAlgoSz == 0)
         return 0;
 
-    /* i+1 since peek a byte ahead for type */
+    /* i+1 since two bytes used to describe hash and signature algorithm */
     for (i = 0; (i+1) < hashSigAlgoSz; i += HELLO_EXT_SIGALGO_SZ) {
         byte hashAlgo = 0, sigAlgo = 0;
 
         DecodeSigAlg(&hashSigAlgo[i], &hashAlgo, &sigAlgo);
+        /* Keep looking if hash algorithm not strong enough. */
+        if (hashAlgo < minHash)
+            continue;
+        /* Keep looking if signature algorithm isn't supported by cert. */
+        if (!MatchSigAlgo(ssl, sigAlgo))
+            continue;
+
     #ifdef HAVE_ED25519
         if (ssl->pkCurveOID == ECC_ED25519_OID) {
-            if (sigAlgo != ed25519_sa_algo)
-                continue;
-            if (sigAlgo == ed25519_sa_algo &&
-                                      ssl->suites->sigAlgo == ecc_dsa_sa_algo) {
-                ssl->suites->sigAlgo = sigAlgo;
-                ssl->suites->hashAlgo = sha512_mac;
-                ret = 0;
-                break;
-            }
+            /* Matched Ed25519 - set chosen and finished. */
+            ssl->suites->sigAlgo = sigAlgo;
+            ssl->suites->hashAlgo = hashAlgo;
+            ret = 0;
+            break;
         }
     #endif
     #ifdef HAVE_ED448
         if (ssl->pkCurveOID == ECC_ED448_OID) {
-            if (sigAlgo != ed448_sa_algo)
+            /* Matched Ed448 - set chosen and finished. */
+            ssl->suites->sigAlgo = sigAlgo;
+            ssl->suites->hashAlgo = hashAlgo;
+            ret = 0;
+            break;
+        }
+    #endif
+
+    #if defined(WOLFSSL_ECDSA_MATCH_HASH) && defined(USE_ECDSA_KEYSZ_HASH_ALGO)
+        #error "WOLFSSL_ECDSA_MATCH_HASH and USE_ECDSA_KEYSZ_HASH_ALGO cannot "
+               "be used together"
+    #endif
+
+    #if defined(HAVE_ECC) && (defined(WOLFSSL_TLS13) || \
+                                              defined(WOLFSSL_ECDSA_MATCH_HASH))
+        if (sigAlgo == ecc_dsa_sa_algo
+        #ifndef WOLFSSL_ECDSA_MATCH_HASH
+            && IsAtLeastTLSv1_3(ssl->version)
+        #endif
+            ) {
+            /* Must be exact match. */
+            if (CmpEccStrength(hashAlgo, ssl->buffers.keySz) != 0)
                 continue;
 
-            if (sigAlgo == ed448_sa_algo &&
-                                      ssl->suites->sigAlgo == ecc_dsa_sa_algo) {
-                ssl->suites->sigAlgo = sigAlgo;
-                ssl->suites->hashAlgo = sha512_mac;
-                ret = 0;
-                break;
-            }
-        }
-    #endif
-    #if defined(WOLFSSL_TLS13) && defined(HAVE_ECC)
-        if (IsAtLeastTLSv1_3(ssl->version) && sigAlgo == ssl->suites->sigAlgo &&
-                                                   sigAlgo == ecc_dsa_sa_algo) {
-
-            int digestSz = GetMacDigestSize(hashAlgo);
-            if (digestSz <= 0)
-                continue;
-
-            /* TLS 1.3 signature algorithms for ECDSA match hash length with
-             * key size.
-             */
-            if (digestSz != ssl->buffers.keySz)
-                continue;
-
+            /* Matched ECDSA exaclty - set chosen and finished. */
             ssl->suites->hashAlgo = hashAlgo;
             ssl->suites->sigAlgo = sigAlgo;
             ret = 0;
-            break; /* done selected sig/hash algorithms */
-        }
-        else
+            break;
+        }
     #endif
+
     /* For ECDSA the `USE_ECDSA_KEYSZ_HASH_ALGO` build option will choose a hash
      * algorithm that matches the ephemeral ECDHE key size or the next highest
@@ -19001,12 +20059,13 @@
      */
     #if defined(HAVE_ECC) && defined(USE_ECDSA_KEYSZ_HASH_ALGO)
-        if (sigAlgo == ssl->suites->sigAlgo && sigAlgo == ecc_dsa_sa_algo) {
-            int digestSz = GetMacDigestSize(hashAlgo);
-            if (digestSz <= 0)
+        if (sigAlgo == ecc_dsa_sa_algo) {
+            int cmp = CmpEccStrength(hashAlgo, ssl->eccTempKeySz);
+
+            /* Keep looking if digest not strong enough. */
+            if (cmp < 0)
                 continue;
 
-            /* For ecc_dsa_sa_algo, pick hash algo that is curve size unless
-                algorithm in not compiled in, then choose next highest */
-            if (digestSz == ssl->eccTempKeySz) {
+            /* Looking for exact match or next highest. */
+            if (ret != 0 || hashAlgo <= ssl->suites->hashAlgo) {
                 ssl->suites->hashAlgo = hashAlgo;
                 ssl->suites->sigAlgo = sigAlgo;
@@ -19015,68 +20074,47 @@
             #endif
                 ret = 0;
-                break; /* done selected sig/hash algorithms */
-            }
-            /* not strong enough, so keep checking hashSigAlso list */
-            if (digestSz < ssl->eccTempKeySz)
+            }
+
+            /* Continue looking if not the same strength. */
+            if (cmp > 0)
                 continue;
-
-            /* mark as highest and check remainder of hashSigAlgo list */
-            ssl->suites->hashAlgo = hashAlgo;
-            ssl->suites->sigAlgo = sigAlgo;
-            ret = 0;
-        }
-        else
+            /* Exact match - finished. */
+            break;
+        }
     #endif
-    #ifdef WC_RSA_PSS
-        if (IsAtLeastTLSv1_3(ssl->version) &&
-                                          ssl->suites->sigAlgo == rsa_sa_algo &&
-                                          sigAlgo != rsa_pss_sa_algo) {
-            continue;
-        }
-        else if (sigAlgo == ssl->suites->sigAlgo ||
-                                        (sigAlgo == rsa_pss_sa_algo &&
-                                         (ssl->suites->sigAlgo == rsa_sa_algo)))
-    #else
-        if (sigAlgo == ssl->suites->sigAlgo)
-    #endif
-        {
-            /* pick highest available between both server and client */
-            switch (hashAlgo) {
-                case sha_mac:
-            #ifdef WOLFSSL_SHA224
-                case sha224_mac:
+
+        switch (hashAlgo) {
+        #ifndef NO_SHA
+            case sha_mac:
+        #endif
+        #ifdef WOLFSSL_SHA224
+            case sha224_mac:
+        #endif
+        #ifndef NO_SHA256
+            case sha256_mac:
+        #endif
+        #ifdef WOLFSSL_SHA384
+            case sha384_mac:
+        #endif
+        #ifdef WOLFSSL_SHA512
+            case sha512_mac:
+        #endif
+            #ifdef WOLFSSL_STRONGEST_HASH_SIG
+            /* Is hash algorithm weaker than chosen/min? */
+                if (hashAlgo < ssl->suites->hashAlgo)
+                    break;
+            #else
+                /* Is hash algorithm stonger than last chosen? */
+                if (ret == 0 && hashAlgo > ssl->suites->hashAlgo)
+                    break;
             #endif
-            #ifndef NO_SHA256
-                case sha256_mac:
-            #endif
-            #ifdef WOLFSSL_SHA384
-                case sha384_mac:
-            #endif
-            #ifdef WOLFSSL_SHA512
-                case sha512_mac:
-            #endif
-                    /* not strong enough, so keep checking hashSigAlso list */
-                    if (hashAlgo < ssl->suites->hashAlgo) {
-                        ret = 0;
-                        continue;
-                    }
-                    /* mark as highest and check remainder of hashSigAlgo list */
-                    ssl->suites->hashAlgo = hashAlgo;
-                    ssl->suites->sigAlgo = sigAlgo;
-                    break;
-                default:
-                    continue;
-            }
-            ret = 0;
-            break;
-        }
-#if defined(WOLFSSL_TLS13)
-        else if (ssl->specs.sig_algo == 0 && IsAtLeastTLSv1_3(ssl->version)) {
-        }
-#endif
-        else if (ssl->specs.sig_algo == 0)
-        {
-            ssl->suites->hashAlgo = ssl->specs.mac_algorithm;
-            ret = 0;
+                /* The chosen one - but keep looking. */
+                ssl->suites->hashAlgo = hashAlgo;
+                ssl->suites->sigAlgo = sigAlgo;
+                ret = 0;
+                break;
+            default:
+                /* Support for hash algorithm not compiled in. */
+                break;
         }
     }
@@ -19107,5 +20145,9 @@
         int sz = GetCipherNamesSize();
 
-        for (i = 0; i < sz; i++)
+        for (i = 0; i < sz; i++) {
+#ifndef NO_CIPHER_SUITE_ALIASES
+            if (cipher_names[i].flags & WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS)
+                continue;
+#endif
             if (info->ssl->options.cipherSuite ==
                                             (byte)cipher_names[i].cipherSuite) {
@@ -19116,4 +20158,5 @@
                 break;
             }
+        }
 
         /* error max and min are negative numbers */
@@ -19279,4 +20322,74 @@
 #if !defined(NO_CERTS)
 
+#ifdef WOLF_CRYPTO_CB
+/* Create a private key for a device.
+ *
+ * pkey    Key object.
+ * data    Data to identify key.
+ * length  Length of data.
+ * hsType  Type of the key to create.
+ * heap    Custom heap to use for mallocs/frees
+ * devId   Id for device.
+ * return  0 on success.
+ * return  NOT_COMPILED_IN if algorithm type not supported.
+ * return  MEMORY_E on memory allocation failure.
+ * return  other internal error
+ */
+int CreateDevPrivateKey(void** pkey, byte* data, word32 length, int hsType,
+                        int label, int id, void* heap, int devId)
+{
+    int ret = NOT_COMPILED_IN;
+
+    if (hsType == DYNAMIC_TYPE_RSA) {
+#ifndef NO_RSA
+        RsaKey* rsaKey;
+
+        rsaKey = (RsaKey*)XMALLOC(sizeof(RsaKey), heap, DYNAMIC_TYPE_RSA);
+        if (rsaKey == NULL) {
+            return MEMORY_E;
+        }
+
+        if (label) {
+            ret = wc_InitRsaKey_Label(rsaKey, (char*)data, heap, devId);
+        }
+        else if (id) {
+            ret = wc_InitRsaKey_Id(rsaKey, data, length, heap, devId);
+        }
+        if (ret == 0) {
+            *pkey = (void*)rsaKey;
+        }
+        else {
+            XFREE(rsaKey, heap, DYNAMIC_TYPE_RSA);
+        }
+#endif
+    }
+    else if (hsType == DYNAMIC_TYPE_ECC) {
+#ifdef HAVE_ECC
+        ecc_key* ecKey;
+
+        ecKey = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, DYNAMIC_TYPE_ECC);
+        if (ecKey == NULL) {
+            return MEMORY_E;
+        }
+
+        if (label) {
+            ret = wc_ecc_init_label(ecKey, (char*)data, heap, devId);
+        }
+        else if (id) {
+            ret = wc_ecc_init_id(ecKey, data, length, heap, devId);
+        }
+        if (ret == 0) {
+            *pkey = (void*)ecKey;
+        }
+        else {
+            XFREE(ecKey, heap, DYNAMIC_TYPE_ECC);
+        }
+#endif
+    }
+
+    return ret;
+}
+#endif
+
 /* Decode the private key - RSA/ECC/Ed25519/Ed448 - and creates a key object.
  * The signature type is set as well.
@@ -19309,5 +20422,6 @@
 
 #ifdef HAVE_PKCS11
-    if (ssl->buffers.keyDevId != INVALID_DEVID && ssl->buffers.keyId) {
+    if (ssl->buffers.keyDevId != INVALID_DEVID && (ssl->buffers.keyId ||
+                                                       ssl->buffers.keyLabel)) {
         if (ssl->buffers.keyType == rsa_sa_algo)
             ssl->hsType = DYNAMIC_TYPE_RSA;
@@ -19321,7 +20435,15 @@
         if (ssl->buffers.keyType == rsa_sa_algo) {
     #ifndef NO_RSA
-            ret = wc_InitRsaKey_Id((RsaKey*)ssl->hsKey,
-                             ssl->buffers.key->buffer, ssl->buffers.key->length,
-                             ssl->heap, ssl->buffers.keyDevId);
+            if (ssl->buffers.keyLabel) {
+                ret = wc_InitRsaKey_Label((RsaKey*)ssl->hsKey,
+                                          (char*)ssl->buffers.key->buffer,
+                                          ssl->heap, ssl->buffers.keyDevId);
+            }
+            else if (ssl->buffers.keyId) {
+                ret = wc_InitRsaKey_Id((RsaKey*)ssl->hsKey,
+                                       ssl->buffers.key->buffer,
+                                       ssl->buffers.key->length, ssl->heap,
+                                       ssl->buffers.keyDevId);
+            }
             if (ret == 0) {
                 if (ssl->buffers.keySz < ssl->options.minRsaKeySz) {
@@ -19339,7 +20461,15 @@
         else if (ssl->buffers.keyType == ecc_dsa_sa_algo) {
     #ifdef HAVE_ECC
-            ret = wc_ecc_init_id((ecc_key*)ssl->hsKey, ssl->buffers.key->buffer,
-                                 ssl->buffers.key->length, ssl->heap,
-                                 ssl->buffers.keyDevId);
+            if (ssl->buffers.keyLabel) {
+                ret = wc_ecc_init_label((ecc_key*)ssl->hsKey,
+                                        (char*)ssl->buffers.key->buffer,
+                                        ssl->heap, ssl->buffers.keyDevId);
+            }
+            else if (ssl->buffers.keyId) {
+                ret = wc_ecc_init_id((ecc_key*)ssl->hsKey,
+                                     ssl->buffers.key->buffer,
+                                     ssl->buffers.key->length, ssl->heap,
+                                     ssl->buffers.keyDevId);
+            }
             if (ret == 0) {
                 if (ssl->buffers.keySz < ssl->options.minEccKeySz) {
@@ -19532,4 +20662,28 @@
 
 #endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */
+
+#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_TLS12)
+    /* returns 1 if able to do TLS 1.3 otherwise 0 */
+    int TLSv1_3_Capable(WOLFSSL* ssl)
+    {
+    #ifndef WOLFSSL_TLS13
+        return 0;
+    #else
+        int ret = 0;
+
+        if (IsAtLeastTLSv1_3(ssl->ctx->method->version)) {
+            ret = 1;
+        }
+
+        #ifdef OPENSSL_EXTRA
+        if ((wolfSSL_get_options(ssl) & SSL_OP_NO_TLSv1_3)) {
+            /* option set at run time to disable TLS 1.3 */
+            ret = 0;
+        }
+        #endif
+        return ret;
+    #endif
+    }
+#endif /* WOLFSSL_TLS13 */
 
 /* client only parts */
@@ -19731,13 +20885,24 @@
         if (IsEncryptionOn(ssl, 1)) {
             byte* input;
-            int   inputSz = idx - RECORD_HEADER_SZ; /* build msg adds rec hdr */
-
+            int   inputSz = idx; /* build msg adds rec hdr */
+            int   recordHeaderSz = RECORD_HEADER_SZ;
+
+            if (ssl->options.dtls)
+                recordHeaderSz += DTLS_RECORD_EXTRA;
+            inputSz -= recordHeaderSz;
             input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
             if (input == NULL)
                 return MEMORY_E;
 
-            XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+            XMEMCPY(input, output + recordHeaderSz, inputSz);
+            #ifdef WOLFSSL_DTLS
+            if (IsDtlsNotSctpMode(ssl) &&
+                    (ret = DtlsMsgPoolSave(ssl, input, inputSz, client_hello)) != 0) {
+                XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+                return ret;
+            }
+            #endif
             sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
-                                  handshake, 1, 0, 0);
+                                  handshake, 1, 0, 0, CUR_ORDER);
             XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
 
@@ -19747,5 +20912,5 @@
             #ifdef WOLFSSL_DTLS
                 if (IsDtlsNotSctpMode(ssl)) {
-                    if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0)
+                    if ((ret = DtlsMsgPoolSave(ssl, output, sendSz, client_hello)) != 0)
                         return ret;
                 }
@@ -20196,28 +21361,4 @@
         return ret;
     }
-
-#ifdef WOLFSSL_TLS13
-    /* returns 1 if able to do TLS 1.3 otherwise 0 */
-    static int TLSv1_3_Capable(WOLFSSL* ssl)
-    {
-    #ifndef WOLFSSL_TLS13
-        return 0;
-    #else
-        int ret = 0;
-
-        if (IsAtLeastTLSv1_3(ssl->ctx->method->version)) {
-            ret = 1;
-        }
-
-        #ifdef OPENSSL_EXTRA
-        if ((wolfSSL_get_options(ssl) & SSL_OP_NO_TLSv1_3)) {
-            /* option set at run time to disable TLS 1.3 */
-            ret = 0;
-        }
-        #endif
-        return ret;
-    #endif
-    }
-#endif /* WOLFSSL_TLS13 */
 
     int CompleteServerHello(WOLFSSL* ssl)
@@ -20244,5 +21385,9 @@
     #endif
             if (ssl->ctx->method->version.major == SSLv3_MAJOR &&
-                             ssl->ctx->method->version.minor == TLSv1_2_MINOR) {
+                                ssl->ctx->method->version.minor == TLSv1_2_MINOR
+#ifdef OPENSSL_EXTRA
+                          && (wolfSSL_get_options(ssl) & SSL_OP_NO_TLSv1_2) == 0
+#endif
+            ) {
                 /* TLS v1.2 capable client not allowed to downgrade when
                  * connecting to TLS v1.2 capable server.
@@ -20286,14 +21431,8 @@
             }
         }
-    #ifdef WOLFSSL_DTLS
-        if (ssl->options.dtls) {
-            DtlsMsgPoolReset(ssl);
-        }
-    #endif
-
         return SetCipherSpecs(ssl);
     }
 
-#endif /* WOLFSSL_NO_TLS12 */
+#endif /* !WOLFSSL_NO_TLS12 */
 
 
@@ -20481,5 +21620,5 @@
 
         switch (tlsCurveId) {
-    #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)
+    #if (defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 160
         #ifndef NO_ECC_SECP
             case WOLFSSL_ECC_SECP160R1: return ECC_SECP160R1_OID;
@@ -20492,5 +21631,5 @@
         #endif /* HAVE_ECC_KOBLITZ */
     #endif
-    #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)
+    #if (defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 192
         #ifndef NO_ECC_SECP
             case WOLFSSL_ECC_SECP192R1: return ECC_SECP192R1_OID;
@@ -20500,5 +21639,5 @@
         #endif /* HAVE_ECC_KOBLITZ */
     #endif
-    #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)
+    #if (defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 224
         #ifndef NO_ECC_SECP
             case WOLFSSL_ECC_SECP224R1: return ECC_SECP224R1_OID;
@@ -20508,8 +21647,8 @@
         #endif /* HAVE_ECC_KOBLITZ */
     #endif
-        #ifdef HAVE_CURVE25519
+        #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
             case WOLFSSL_ECC_X25519: return ECC_X25519_OID;
         #endif
-    #if !defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)
+    #if (!defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256
         #ifndef NO_ECC_SECP
             case WOLFSSL_ECC_SECP256R1: return ECC_SECP256R1_OID;
@@ -20522,8 +21661,8 @@
         #endif /* HAVE_ECC_BRAINPOOL */
     #endif
-        #ifdef HAVE_CURVE448
+        #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
             case WOLFSSL_ECC_X448: return ECC_X448_OID;
         #endif
-    #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+    #if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384
         #ifndef NO_ECC_SECP
             case WOLFSSL_ECC_SECP384R1: return ECC_SECP384R1_OID;
@@ -20533,10 +21672,10 @@
         #endif /* HAVE_ECC_BRAINPOOL */
     #endif
-    #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)
+    #if (defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 512
         #ifdef HAVE_ECC_BRAINPOOL
             case WOLFSSL_ECC_BRAINPOOLP512R1: return ECC_BRAINPOOLP512R1_OID;
         #endif /* HAVE_ECC_BRAINPOOL */
     #endif
-    #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+    #if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521
         #ifndef NO_ECC_SECP
             case WOLFSSL_ECC_SECP521R1: return ECC_SECP521R1_OID;
@@ -20548,17 +21687,17 @@
     }
 
-#endif /* HAVE_ECC */
+#endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */
 
 /* Persistable DoServerKeyExchange arguments */
 typedef struct DskeArgs {
     byte*  output; /* not allocated */
-#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \
-                                                             defined(HAVE_ED448)
+#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+                                                          defined(HAVE_CURVE448)
     byte*  verifySig;
 #endif
     word32 idx;
     word32 begin;
-#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \
-                                                             defined(HAVE_ED448)
+#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+                                                          defined(HAVE_CURVE448)
     word16 verifySigSz;
 #endif
@@ -20578,6 +21717,6 @@
     (void)args;
 
-#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \
-                                                             defined(HAVE_ED448)
+#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+                                                          defined(HAVE_CURVE448)
     if (args->verifySig) {
         XFREE(args->verifySig, ssl->heap, DYNAMIC_TYPE_SIGNATURE);
@@ -20598,9 +21737,24 @@
 #endif
 
-    ssl->buffers.weOwnDH = 1;
-
-    ssl->buffers.serverDH_P.buffer = NULL;
-    ssl->buffers.serverDH_G.buffer = NULL;
-    ssl->buffers.serverDH_Pub.buffer = NULL;
+    if (ssl->buffers.weOwnDH) {
+        if (ssl->buffers.serverDH_P.buffer) {
+            XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
+                    DYNAMIC_TYPE_PUBLIC_KEY);
+            ssl->buffers.serverDH_P.buffer = NULL;
+        }
+
+        if (ssl->buffers.serverDH_G.buffer) {
+            XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap,
+                    DYNAMIC_TYPE_PUBLIC_KEY);
+            ssl->buffers.serverDH_G.buffer = NULL;
+        }
+
+    }
+
+    if (ssl->buffers.serverDH_Pub.buffer) {
+        XFREE(ssl->buffers.serverDH_Pub.buffer, ssl->heap,
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        ssl->buffers.serverDH_Pub.buffer = NULL;
+    }
 
     /* p */
@@ -20644,4 +21798,7 @@
     /* g */
     if ((args->idx - args->begin) + OPAQUE16_LEN > size) {
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        ssl->buffers.serverDH_P.buffer = NULL;
         ERROR_OUT(BUFFER_ERROR, exit_gdpk);
     }
@@ -20651,5 +21808,17 @@
 
     if ((args->idx - args->begin) + length > size) {
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        ssl->buffers.serverDH_P.buffer = NULL;
         ERROR_OUT(BUFFER_ERROR, exit_gdpk);
+    }
+
+    if (length > ssl->options.maxDhKeySz) {
+        WOLFSSL_MSG("Server using a DH key generator that is too big");
+        SendAlert(ssl, alert_fatal, handshake_failure);
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        ssl->buffers.serverDH_P.buffer = NULL;
+        ERROR_OUT(DH_KEY_SIZE_E, exit_gdpk);
     }
 
@@ -20660,4 +21829,7 @@
     }
     else {
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        ssl->buffers.serverDH_P.buffer = NULL;
         ERROR_OUT(MEMORY_ERROR, exit_gdpk);
     }
@@ -20669,4 +21841,10 @@
     /* pub */
     if ((args->idx - args->begin) + OPAQUE16_LEN > size) {
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        ssl->buffers.serverDH_P.buffer = NULL;
+        XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap,
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        ssl->buffers.serverDH_G.buffer = NULL;
         ERROR_OUT(BUFFER_ERROR, exit_gdpk);
     }
@@ -20676,5 +21854,23 @@
 
     if ((args->idx - args->begin) + length > size) {
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        ssl->buffers.serverDH_P.buffer = NULL;
+        XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap,
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        ssl->buffers.serverDH_G.buffer = NULL;
         ERROR_OUT(BUFFER_ERROR, exit_gdpk);
+    }
+
+    if (length > ssl->options.maxDhKeySz) {
+        WOLFSSL_MSG("Server using a public DH key that is too big");
+        SendAlert(ssl, alert_fatal, handshake_failure);
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        ssl->buffers.serverDH_P.buffer = NULL;
+        XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap,
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        ssl->buffers.serverDH_G.buffer = NULL;
+        ERROR_OUT(DH_KEY_SIZE_E, exit_gdpk);
     }
 
@@ -20685,4 +21881,10 @@
     }
     else {
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        ssl->buffers.serverDH_P.buffer = NULL;
+        XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap,
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        ssl->buffers.serverDH_G.buffer = NULL;
         ERROR_OUT(MEMORY_ERROR, exit_gdpk);
     }
@@ -20690,4 +21892,5 @@
     XMEMCPY(ssl->buffers.serverDH_Pub.buffer, input + args->idx,
                                                         length);
+    ssl->buffers.weOwnDH = 1;
     args->idx += length;
 
@@ -21216,6 +22419,6 @@
                 case ecc_diffie_hellman_kea:
                 {
-            #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(HAVE_ED25519) \
-                                                     && !defined(HAVE_ED448)
+            #if defined(NO_DH) && !defined(HAVE_ECC) && \
+                            !defined(HAVE_CURVE25519) && !defined(HAVE_CURVE448)
                     ERROR_OUT(NOT_COMPILED_IN, exit_dske);
             #else
@@ -21389,6 +22592,6 @@
                 case ecc_diffie_hellman_kea:
                 {
-            #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(HAVE_ED25519) \
-                                                     && !defined(HAVE_ED448)
+            #if defined(NO_DH) && !defined(HAVE_ECC) && \
+                            !defined(HAVE_CURVE25519) && !defined(HAVE_CURVE448)
                     ERROR_OUT(NOT_COMPILED_IN, exit_dske);
             #else
@@ -21563,6 +22766,6 @@
                 case ecc_diffie_hellman_kea:
                 {
-            #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(HAVE_ED25519) \
-                                                     && !defined(HAVE_ED448)
+            #if defined(NO_DH) && !defined(HAVE_ECC) && \
+                            !defined(HAVE_CURVE25519) && !defined(HAVE_CURVE448)
                     ERROR_OUT(NOT_COMPILED_IN, exit_dske);
             #else
@@ -22624,7 +23827,6 @@
                     XMEMCPY(args->output, ssl->arrays->client_identity, esSz);
                     args->output += esSz;
+                    args->length = args->encSz - esSz - OPAQUE16_LEN;
                     args->encSz = esSz + OPAQUE16_LEN;
-
-                    args->length = 0;
 
                     ret = AllocKey(ssl, DYNAMIC_TYPE_DH,
@@ -23297,5 +24499,9 @@
 
             if (IsEncryptionOn(ssl, 1)) {
-                args->inputSz = idx - RECORD_HEADER_SZ; /* buildmsg adds rechdr */
+                int recordHeaderSz = RECORD_HEADER_SZ;
+
+                if (ssl->options.dtls)
+                    recordHeaderSz += DTLS_RECORD_EXTRA;
+                args->inputSz = idx - recordHeaderSz; /* buildmsg adds rechdr */
                 args->input = (byte*)XMALLOC(args->inputSz, ssl->heap,
                                                        DYNAMIC_TYPE_IN_BUFFER);
@@ -23304,5 +24510,5 @@
                 }
 
-                XMEMCPY(args->input, args->output + RECORD_HEADER_SZ,
+                XMEMCPY(args->input, args->output + recordHeaderSz,
                                                                 args->inputSz);
             }
@@ -23316,6 +24522,12 @@
         {
             if (IsEncryptionOn(ssl, 1)) {
+            #ifdef WOLFSSL_DTLS
+                if (IsDtlsNotSctpMode(ssl) &&
+                        (ret = DtlsMsgPoolSave(ssl, args->input, args->inputSz, client_key_exchange)) != 0) {
+                    goto exit_scke;
+                }
+            #endif
                 ret = BuildMessage(ssl, args->output, args->sendSz,
-                            args->input, args->inputSz, handshake, 1, 0, 0);
+                            args->input, args->inputSz, handshake, 1, 0, 0, CUR_ORDER);
                 XFREE(args->input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
                 args->input = NULL; /* make sure its not double free'd on cleanup */
@@ -23328,4 +24540,9 @@
             else {
             #ifdef WOLFSSL_DTLS
+                if (IsDtlsNotSctpMode(ssl)) {
+                    if ((ret = DtlsMsgPoolSave(ssl, args->output, args->sendSz, client_key_exchange)) != 0) {
+                        goto exit_scke;
+                    }
+                }
                 if (ssl->options.dtls)
                     DtlsSEQIncrement(ssl, CUR_ORDER);
@@ -23337,12 +24554,4 @@
                 goto exit_scke;
             }
-
-        #ifdef WOLFSSL_DTLS
-            if (IsDtlsNotSctpMode(ssl)) {
-                if ((ret = DtlsMsgPoolSave(ssl, args->output, args->sendSz)) != 0) {
-                    goto exit_scke;
-                }
-            }
-        #endif
 
         #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
@@ -23397,4 +24606,615 @@
 
 #endif /* !WOLFSSL_NO_TLS12 */
+
+#ifndef NO_CERTS
+
+#ifndef WOLFSSL_NO_TLS12
+
+#ifndef WOLFSSL_NO_CLIENT_AUTH
+typedef struct ScvArgs {
+    byte*  output; /* not allocated */
+#ifndef NO_RSA
+    byte*  verifySig;
+#endif
+    byte*  verify; /* not allocated */
+    byte*  input;
+    word32 idx;
+    word32 extraSz;
+    word32 sigSz;
+    int    sendSz;
+    int    inputSz;
+    word16 length;
+    byte   sigAlgo;
+} ScvArgs;
+
+static void FreeScvArgs(WOLFSSL* ssl, void* pArgs)
+{
+    ScvArgs* args = (ScvArgs*)pArgs;
+
+    (void)ssl;
+
+#ifndef NO_RSA
+    if (args->verifySig) {
+        XFREE(args->verifySig, ssl->heap, DYNAMIC_TYPE_SIGNATURE);
+        args->verifySig = NULL;
+    }
+#endif
+    if (args->input) {
+        XFREE(args->input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+        args->input = NULL;
+    }
+}
+
+/* handle generation of certificate_verify (15) */
+int SendCertificateVerify(WOLFSSL* ssl)
+{
+    int ret = 0;
+#ifdef WOLFSSL_ASYNC_CRYPT
+    ScvArgs* args = (ScvArgs*)ssl->async.args;
+    typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1];
+    (void)sizeof(args_test);
+#else
+    ScvArgs  args[1];
+#endif
+
+    WOLFSSL_START(WC_FUNC_CERTIFICATE_VERIFY_SEND);
+    WOLFSSL_ENTER("SendCertificateVerify");
+
+#ifdef WOLFSSL_ASYNC_CRYPT
+    /* BuildMessage does its own Pop */
+    if (ssl->error != WC_PENDING_E ||
+            ssl->options.asyncState != TLS_ASYNC_END)
+        ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState);
+    if (ret != WC_NOT_PENDING_E) {
+        /* Check for error */
+        if (ret < 0)
+            goto exit_scv;
+    }
+    else
+#endif
+    {
+        /* Reset state */
+        ret = 0;
+        ssl->options.asyncState = TLS_ASYNC_BEGIN;
+        XMEMSET(args, 0, sizeof(ScvArgs));
+    #ifdef WOLFSSL_ASYNC_CRYPT
+        ssl->async.freeArgs = FreeScvArgs;
+    #endif
+    }
+
+    switch(ssl->options.asyncState)
+    {
+        case TLS_ASYNC_BEGIN:
+        {
+            if (ssl->options.sendVerify == SEND_BLANK_CERT) {
+                return 0;  /* sent blank cert, can't verify */
+            }
+
+            args->sendSz = MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA;
+            if (IsEncryptionOn(ssl, 1)) {
+                args->sendSz += MAX_MSG_EXTRA;
+            }
+
+            /* check for available size */
+            if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) {
+                goto exit_scv;
+            }
+
+            /* get output buffer */
+            args->output = ssl->buffers.outputBuffer.buffer +
+                           ssl->buffers.outputBuffer.length;
+
+            /* Advance state and proceed */
+            ssl->options.asyncState = TLS_ASYNC_BUILD;
+        } /* case TLS_ASYNC_BEGIN */
+        FALL_THROUGH;
+
+        case TLS_ASYNC_BUILD:
+        {
+            ret = BuildCertHashes(ssl, &ssl->hsHashes->certHashes);
+            if (ret != 0) {
+                goto exit_scv;
+            }
+
+            if (ssl->buffers.key == NULL) {
+            #ifdef HAVE_PK_CALLBACKS
+                if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx))
+                    args->length = GetPrivateKeySigSize(ssl);
+                else
+            #endif
+                    ERROR_OUT(NO_PRIVATE_KEY, exit_scv);
+            }
+            else {
+                /* Decode private key. */
+                ret = DecodePrivateKey(ssl, &args->length);
+                if (ret != 0) {
+                    goto exit_scv;
+                }
+            }
+
+            if (args->length == 0) {
+                ERROR_OUT(NO_PRIVATE_KEY, exit_scv);
+            }
+
+            /* idx is used to track verify pointer offset to output */
+            args->idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+            args->verify = &args->output[RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ];
+            args->extraSz = 0;  /* tls 1.2 hash/sig */
+
+            /* build encoded signature buffer */
+            ssl->buffers.sig.length = MAX_ENCODED_SIG_SZ;
+            ssl->buffers.sig.buffer = (byte*)XMALLOC(ssl->buffers.sig.length,
+                                        ssl->heap, DYNAMIC_TYPE_SIGNATURE);
+            if (ssl->buffers.sig.buffer == NULL) {
+                ERROR_OUT(MEMORY_E, exit_scv);
+            }
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls) {
+                args->idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                args->verify += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+            }
+        #endif
+
+    #ifndef NO_OLD_TLS
+        #ifndef NO_SHA
+            /* old tls default */
+            SetDigest(ssl, sha_mac);
+        #endif
+    #else
+        #ifndef NO_SHA256
+            /* new tls default */
+            SetDigest(ssl, sha256_mac);
+        #endif
+    #endif /* !NO_OLD_TLS */
+
+            if (ssl->hsType == DYNAMIC_TYPE_RSA) {
+        #ifdef WC_RSA_PSS
+                if (IsAtLeastTLSv1_2(ssl) &&
+                                (ssl->pssAlgo & (1 << ssl->suites->hashAlgo))) {
+                    args->sigAlgo = rsa_pss_sa_algo;
+                }
+                else
+        #endif
+                    args->sigAlgo = rsa_sa_algo;
+            }
+            else if (ssl->hsType == DYNAMIC_TYPE_ECC)
+                args->sigAlgo = ecc_dsa_sa_algo;
+            else if (ssl->hsType == DYNAMIC_TYPE_ED25519)
+                args->sigAlgo = ed25519_sa_algo;
+            else if (ssl->hsType == DYNAMIC_TYPE_ED448)
+                args->sigAlgo = ed448_sa_algo;
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+                EncodeSigAlg(ssl->suites->hashAlgo, args->sigAlgo,
+                             args->verify);
+                args->extraSz = HASH_SIG_SIZE;
+                SetDigest(ssl, ssl->suites->hashAlgo);
+            }
+        #ifndef NO_OLD_TLS
+            else {
+                /* if old TLS load MD5 and SHA hash as value to sign */
+                XMEMCPY(ssl->buffers.sig.buffer,
+                    (byte*)ssl->hsHashes->certHashes.md5, FINISHED_SZ);
+            }
+        #endif
+
+        #ifndef NO_RSA
+            if (args->sigAlgo == rsa_sa_algo) {
+                ssl->buffers.sig.length = FINISHED_SZ;
+                args->sigSz = ENCRYPT_LEN;
+
+                if (IsAtLeastTLSv1_2(ssl)) {
+                    ssl->buffers.sig.length = wc_EncodeSignature(
+                            ssl->buffers.sig.buffer, ssl->buffers.digest.buffer,
+                            ssl->buffers.digest.length,
+                            TypeHash(ssl->suites->hashAlgo));
+                }
+
+                /* prepend hdr */
+                c16toa(args->length, args->verify + args->extraSz);
+            }
+            #ifdef WC_RSA_PSS
+            else if (args->sigAlgo == rsa_pss_sa_algo) {
+                XMEMCPY(ssl->buffers.sig.buffer, ssl->buffers.digest.buffer,
+                        ssl->buffers.digest.length);
+                ssl->buffers.sig.length = ssl->buffers.digest.length;
+                args->sigSz = ENCRYPT_LEN;
+
+                /* prepend hdr */
+                c16toa(args->length, args->verify + args->extraSz);
+            }
+            #endif
+        #endif /* !NO_RSA */
+        #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)
+            if (args->sigAlgo == ed25519_sa_algo) {
+                ret = Ed25519CheckPubKey(ssl);
+                if (ret != 0)
+                    goto exit_scv;
+            }
+        #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */
+        #if defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH)
+            if (args->sigAlgo == ed448_sa_algo) {
+                ret = Ed448CheckPubKey(ssl);
+                if (ret != 0)
+                    goto exit_scv;
+            }
+        #endif /* HAVE_ED448 && !NO_ED448_CLIENT_AUTH */
+
+            /* Advance state and proceed */
+            ssl->options.asyncState = TLS_ASYNC_DO;
+        } /* case TLS_ASYNC_BUILD */
+        FALL_THROUGH;
+
+        case TLS_ASYNC_DO:
+        {
+        #ifdef HAVE_ECC
+           if (ssl->hsType == DYNAMIC_TYPE_ECC) {
+                ecc_key* key = (ecc_key*)ssl->hsKey;
+
+                ret = EccSign(ssl,
+                    ssl->buffers.digest.buffer, ssl->buffers.digest.length,
+                    ssl->buffers.sig.buffer, (word32*)&ssl->buffers.sig.length,
+                    key,
+            #ifdef HAVE_PK_CALLBACKS
+                    ssl->buffers.key
+            #else
+                    NULL
+            #endif
+                );
+            }
+        #endif /* HAVE_ECC */
+        #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)
+           if (ssl->hsType == DYNAMIC_TYPE_ED25519) {
+                ed25519_key* key = (ed25519_key*)ssl->hsKey;
+
+                ret = Ed25519Sign(ssl,
+                    ssl->hsHashes->messages, ssl->hsHashes->length,
+                    ssl->buffers.sig.buffer, (word32*)&ssl->buffers.sig.length,
+                    key,
+            #ifdef HAVE_PK_CALLBACKS
+                    ssl->buffers.key
+            #else
+                    NULL
+            #endif
+                );
+            }
+        #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */
+        #if defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH)
+           if (ssl->hsType == DYNAMIC_TYPE_ED448) {
+                ed448_key* key = (ed448_key*)ssl->hsKey;
+
+                ret = Ed448Sign(ssl,
+                    ssl->hsHashes->messages, ssl->hsHashes->length,
+                    ssl->buffers.sig.buffer, (word32*)&ssl->buffers.sig.length,
+                    key,
+            #ifdef HAVE_PK_CALLBACKS
+                    ssl->buffers.key
+            #else
+                    NULL
+            #endif
+                );
+            }
+        #endif /* HAVE_ED448 && !NO_ED448_CLIENT_AUTH */
+        #ifndef NO_RSA
+            if (ssl->hsType == DYNAMIC_TYPE_RSA) {
+                RsaKey* key = (RsaKey*)ssl->hsKey;
+
+                /* restore verify pointer */
+                args->verify = &args->output[args->idx];
+
+                ret = RsaSign(ssl,
+                    ssl->buffers.sig.buffer, ssl->buffers.sig.length,
+                    args->verify + args->extraSz + VERIFY_HEADER, &args->sigSz,
+                    args->sigAlgo, ssl->suites->hashAlgo, key,
+                    ssl->buffers.key
+                );
+            }
+        #endif /* !NO_RSA */
+
+            /* Check for error */
+            if (ret != 0) {
+                goto exit_scv;
+            }
+
+            /* Advance state and proceed */
+            ssl->options.asyncState = TLS_ASYNC_VERIFY;
+        } /* case TLS_ASYNC_DO */
+        FALL_THROUGH;
+
+        case TLS_ASYNC_VERIFY:
+        {
+            /* restore verify pointer */
+            args->verify = &args->output[args->idx];
+
+            switch (ssl->hsType) {
+        #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448)
+            #ifdef HAVE_ECC
+                case DYNAMIC_TYPE_ECC:
+            #endif
+            #ifdef HAVE_ED25519
+                case DYNAMIC_TYPE_ED25519:
+            #endif
+            #ifdef HAVE_ED448
+                case DYNAMIC_TYPE_ED448:
+            #endif
+                    args->length = (word16)ssl->buffers.sig.length;
+                    /* prepend hdr */
+                    c16toa(args->length, args->verify + args->extraSz);
+                    XMEMCPY(args->verify + args->extraSz + VERIFY_HEADER,
+                            ssl->buffers.sig.buffer, ssl->buffers.sig.length);
+                    break;
+        #endif
+            #ifndef NO_RSA
+                case DYNAMIC_TYPE_RSA:
+                {
+                    RsaKey* key = (RsaKey*)ssl->hsKey;
+
+                    if (args->verifySig == NULL) {
+                        args->verifySig = (byte*)XMALLOC(args->sigSz, ssl->heap,
+                                          DYNAMIC_TYPE_SIGNATURE);
+                        if (args->verifySig == NULL) {
+                            ERROR_OUT(MEMORY_E, exit_scv);
+                        }
+                        XMEMCPY(args->verifySig, args->verify + args->extraSz +
+                                                    VERIFY_HEADER, args->sigSz);
+                    }
+
+                    /* check for signature faults */
+                    ret = VerifyRsaSign(ssl,
+                        args->verifySig, args->sigSz,
+                        ssl->buffers.sig.buffer, ssl->buffers.sig.length,
+                        args->sigAlgo, ssl->suites->hashAlgo, key,
+                        ssl->buffers.key
+                    );
+                    break;
+                }
+            #endif /* !NO_RSA */
+                default:
+                    break;
+            }
+
+            /* Check for error */
+            if (ret != 0) {
+                goto exit_scv;
+            }
+
+            /* Advance state and proceed */
+            ssl->options.asyncState = TLS_ASYNC_FINALIZE;
+        } /* case TLS_ASYNC_VERIFY */
+        FALL_THROUGH;
+
+        case TLS_ASYNC_FINALIZE:
+        {
+            if (args->output == NULL) {
+                ERROR_OUT(BUFFER_ERROR, exit_scv);
+            }
+            AddHeaders(args->output, (word32)args->length + args->extraSz +
+                                        VERIFY_HEADER, certificate_verify, ssl);
+
+            args->sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ +
+                           (word32)args->length + args->extraSz + VERIFY_HEADER;
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls) {
+                args->sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+            }
+        #endif
+
+            if (IsEncryptionOn(ssl, 1)) {
+                int recordHeaderSz = RECORD_HEADER_SZ;
+
+                if (ssl->options.dtls)
+                    recordHeaderSz += DTLS_RECORD_EXTRA;
+                args->inputSz = args->sendSz - recordHeaderSz;
+                                /* build msg adds rec hdr */
+                args->input = (byte*)XMALLOC(args->inputSz, ssl->heap,
+                                                       DYNAMIC_TYPE_IN_BUFFER);
+                if (args->input == NULL) {
+                    ERROR_OUT(MEMORY_E, exit_scv);
+                }
+
+                XMEMCPY(args->input, args->output + recordHeaderSz,
+                                                                args->inputSz);
+            }
+
+            /* Advance state and proceed */
+            ssl->options.asyncState = TLS_ASYNC_END;
+        } /* case TLS_ASYNC_FINALIZE */
+        FALL_THROUGH;
+
+        case TLS_ASYNC_END:
+        {
+            if (IsEncryptionOn(ssl, 1)) {
+            #ifdef WOLFSSL_DTLS
+                if (IsDtlsNotSctpMode(ssl) &&
+                        (ret = DtlsMsgPoolSave(ssl, args->input, args->inputSz, certificate_verify)) != 0) {
+                    goto exit_scv;
+                }
+            #endif
+                ret = BuildMessage(ssl, args->output,
+                                      MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA,
+                                      args->input, args->inputSz, handshake,
+                                      1, 0, 1, CUR_ORDER);
+            #ifdef WOLFSSL_ASYNC_CRYPT
+                if (ret == WC_PENDING_E)
+                    goto exit_scv;
+            #endif
+
+                XFREE(args->input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+                args->input = NULL;  /* make sure its not double free'd on cleanup */
+
+                if (ret >= 0) {
+                    args->sendSz = ret;
+                    ret = 0;
+                }
+            }
+            else {
+            #ifdef WOLFSSL_DTLS
+                if (IsDtlsNotSctpMode(ssl)) {
+                    ret = DtlsMsgPoolSave(ssl, args->output, args->sendSz, certificate_verify);
+                }
+                if (ret == 0 && ssl->options.dtls)
+                    DtlsSEQIncrement(ssl, CUR_ORDER);
+            #endif
+                if (ret == 0)
+                    ret = HashOutput(ssl, args->output, args->sendSz, 0);
+            }
+
+            if (ret != 0) {
+                goto exit_scv;
+            }
+
+        #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
+            if (ssl->hsInfoOn)
+                AddPacketName(ssl, "CertificateVerify");
+            if (ssl->toInfoOn)
+                AddPacketInfo(ssl, "CertificateVerify", handshake,
+                            args->output, args->sendSz, WRITE_PROTO, ssl->heap);
+        #endif
+
+            ssl->buffers.outputBuffer.length += args->sendSz;
+
+            if (!ssl->options.groupMessages) {
+                ret = SendBuffered(ssl);
+            }
+            break;
+        }
+        default:
+            ret = INPUT_CASE_ERROR;
+    } /* switch(ssl->options.asyncState) */
+
+exit_scv:
+
+    WOLFSSL_LEAVE("SendCertificateVerify", ret);
+    WOLFSSL_END(WC_FUNC_CERTIFICATE_VERIFY_SEND);
+
+#ifdef WOLFSSL_ASYNC_CRYPT
+    /* Handle async operation */
+    if (ret == WC_PENDING_E) {
+        return ret;
+    }
+#endif /* WOLFSSL_ASYNC_CRYPT */
+
+    /* Digest is not allocated, so do this to prevent free */
+    ssl->buffers.digest.buffer = NULL;
+    ssl->buffers.digest.length = 0;
+
+    /* Final cleanup */
+    FreeScvArgs(ssl, args);
+    FreeKeyExchange(ssl);
+
+    return ret;
+}
+#endif /* WOLFSSL_NO_CLIENT_AUTH */
+
+#endif /* WOLFSSL_NO_TLS12 */
+
+#endif /* NO_CERTS */
+
+
+#ifdef HAVE_SESSION_TICKET
+int SetTicket(WOLFSSL* ssl, const byte* ticket, word32 length)
+{
+    /* Free old dynamic ticket if we already had one */
+    if (ssl->session.isDynamic) {
+        XFREE(ssl->session.ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK);
+        ssl->session.ticket = ssl->session.staticTicket;
+        ssl->session.isDynamic = 0;
+    }
+
+    if (length > sizeof(ssl->session.staticTicket)) {
+        byte* sessionTicket =
+                   (byte*)XMALLOC(length, ssl->heap, DYNAMIC_TYPE_SESSION_TICK);
+        if (sessionTicket == NULL)
+            return MEMORY_E;
+        ssl->session.ticket = sessionTicket;
+        ssl->session.isDynamic = 1;
+    }
+    ssl->session.ticketLen = (word16)length;
+
+    if (length > 0) {
+        XMEMCPY(ssl->session.ticket, ticket, length);
+        if (ssl->session_ticket_cb != NULL) {
+            ssl->session_ticket_cb(ssl,
+                                   ssl->session.ticket, ssl->session.ticketLen,
+                                   ssl->session_ticket_ctx);
+        }
+        /* Create a fake sessionID based on the ticket, this will
+         * supersede the existing session cache info. */
+        ssl->options.haveSessionId = 1;
+#ifdef WOLFSSL_TLS13
+        if (ssl->options.tls1_3) {
+            XMEMCPY(ssl->session.sessionID,
+                                 ssl->session.ticket + length - ID_LEN, ID_LEN);
+        }
+        else
+#endif
+            XMEMCPY(ssl->arrays->sessionID,
+                                 ssl->session.ticket + length - ID_LEN, ID_LEN);
+    }
+
+    return 0;
+}
+
+#ifndef WOLFSSL_NO_TLS12
+
+/* handle processing of session_ticket (4) */
+static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
+    word32 size)
+{
+    word32 begin = *inOutIdx;
+    word32 lifetime;
+    word16 length;
+    int    ret;
+
+    if (ssl->expect_session_ticket == 0) {
+        WOLFSSL_MSG("Unexpected session ticket");
+        return SESSION_TICKET_EXPECT_E;
+    }
+
+    if (OPAQUE32_LEN > size)
+        return BUFFER_ERROR;
+
+    ato32(input + *inOutIdx, &lifetime);
+    *inOutIdx += OPAQUE32_LEN;
+
+    if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+        return BUFFER_ERROR;
+
+    ato16(input + *inOutIdx, &length);
+    *inOutIdx += OPAQUE16_LEN;
+
+    if ((*inOutIdx - begin) + length > size)
+        return BUFFER_ERROR;
+
+    if ((ret = SetTicket(ssl, input + *inOutIdx, length)) != 0)
+        return ret;
+    *inOutIdx += length;
+    if (length > 0) {
+        ssl->timeout = lifetime;
+#ifndef NO_SESSION_CACHE
+        AddSession(ssl);
+#endif
+    }
+
+    if (IsEncryptionOn(ssl, 0)) {
+        *inOutIdx += ssl->keys.padSz;
+    #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+        if (ssl->options.startedETMRead)
+            *inOutIdx += MacSize(ssl);
+    #endif
+    }
+
+    ssl->expect_session_ticket = 0;
+
+    return 0;
+}
+
+#endif /* !WOLFSSL_NO_TLS12 */
+
+#endif /* HAVE_SESSION_TICKET */
+
+#endif /* NO_WOLFSSL_CLIENT */
 
 #ifndef NO_CERTS
@@ -23443,602 +25263,5 @@
 #endif /* HAVE_PK_CALLBACKS */
 
-#ifndef WOLFSSL_NO_TLS12
-
-#ifndef WOLFSSL_NO_CLIENT_AUTH
-typedef struct ScvArgs {
-    byte*  output; /* not allocated */
-#ifndef NO_RSA
-    byte*  verifySig;
-#endif
-    byte*  verify; /* not allocated */
-    byte*  input;
-    word32 idx;
-    word32 extraSz;
-    word32 sigSz;
-    int    sendSz;
-    int    inputSz;
-    word16 length;
-    byte   sigAlgo;
-} ScvArgs;
-
-static void FreeScvArgs(WOLFSSL* ssl, void* pArgs)
-{
-    ScvArgs* args = (ScvArgs*)pArgs;
-
-    (void)ssl;
-
-#ifndef NO_RSA
-    if (args->verifySig) {
-        XFREE(args->verifySig, ssl->heap, DYNAMIC_TYPE_SIGNATURE);
-        args->verifySig = NULL;
-    }
-#endif
-    if (args->input) {
-        XFREE(args->input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
-        args->input = NULL;
-    }
-}
-
-/* handle generation of certificate_verify (15) */
-int SendCertificateVerify(WOLFSSL* ssl)
-{
-    int ret = 0;
-#ifdef WOLFSSL_ASYNC_CRYPT
-    ScvArgs* args = (ScvArgs*)ssl->async.args;
-    typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1];
-    (void)sizeof(args_test);
-#else
-    ScvArgs  args[1];
-#endif
-
-    WOLFSSL_START(WC_FUNC_CERTIFICATE_VERIFY_SEND);
-    WOLFSSL_ENTER("SendCertificateVerify");
-
-#ifdef WOLFSSL_ASYNC_CRYPT
-    ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState);
-    if (ret != WC_NOT_PENDING_E) {
-        /* Check for error */
-        if (ret < 0)
-            goto exit_scv;
-    }
-    else
-#endif
-    {
-        /* Reset state */
-        ret = 0;
-        ssl->options.asyncState = TLS_ASYNC_BEGIN;
-        XMEMSET(args, 0, sizeof(ScvArgs));
-    #ifdef WOLFSSL_ASYNC_CRYPT
-        ssl->async.freeArgs = FreeScvArgs;
-    #endif
-    }
-
-    switch(ssl->options.asyncState)
-    {
-        case TLS_ASYNC_BEGIN:
-        {
-            if (ssl->options.sendVerify == SEND_BLANK_CERT) {
-                return 0;  /* sent blank cert, can't verify */
-            }
-
-            args->sendSz = MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA;
-            if (IsEncryptionOn(ssl, 1)) {
-                args->sendSz += MAX_MSG_EXTRA;
-            }
-
-            /* check for available size */
-            if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) {
-                goto exit_scv;
-            }
-
-            /* get output buffer */
-            args->output = ssl->buffers.outputBuffer.buffer +
-                           ssl->buffers.outputBuffer.length;
-
-            /* Advance state and proceed */
-            ssl->options.asyncState = TLS_ASYNC_BUILD;
-        } /* case TLS_ASYNC_BEGIN */
-        FALL_THROUGH;
-
-        case TLS_ASYNC_BUILD:
-        {
-            ret = BuildCertHashes(ssl, &ssl->hsHashes->certHashes);
-            if (ret != 0) {
-                goto exit_scv;
-            }
-
-            if (ssl->buffers.key == NULL) {
-            #ifdef HAVE_PK_CALLBACKS
-                if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx))
-                    args->length = GetPrivateKeySigSize(ssl);
-                else
-            #endif
-                    ERROR_OUT(NO_PRIVATE_KEY, exit_scv);
-            }
-            else {
-                /* Decode private key. */
-                ret = DecodePrivateKey(ssl, &args->length);
-                if (ret != 0) {
-                    goto exit_scv;
-                }
-            }
-
-            if (args->length == 0) {
-                ERROR_OUT(NO_PRIVATE_KEY, exit_scv);
-            }
-
-            /* idx is used to track verify pointer offset to output */
-            args->idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
-            args->verify = &args->output[RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ];
-            args->extraSz = 0;  /* tls 1.2 hash/sig */
-
-            /* build encoded signature buffer */
-            ssl->buffers.sig.length = MAX_ENCODED_SIG_SZ;
-            ssl->buffers.sig.buffer = (byte*)XMALLOC(ssl->buffers.sig.length,
-                                        ssl->heap, DYNAMIC_TYPE_SIGNATURE);
-            if (ssl->buffers.sig.buffer == NULL) {
-                ERROR_OUT(MEMORY_E, exit_scv);
-            }
-
-        #ifdef WOLFSSL_DTLS
-            if (ssl->options.dtls) {
-                args->idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
-                args->verify += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
-            }
-        #endif
-
-    #ifndef NO_OLD_TLS
-        #ifndef NO_SHA
-            /* old tls default */
-            SetDigest(ssl, sha_mac);
-        #endif
-    #else
-        #ifndef NO_SHA256
-            /* new tls default */
-            SetDigest(ssl, sha256_mac);
-        #endif
-    #endif /* !NO_OLD_TLS */
-
-            if (ssl->hsType == DYNAMIC_TYPE_RSA) {
-        #ifdef WC_RSA_PSS
-                if (IsAtLeastTLSv1_2(ssl) &&
-                                (ssl->pssAlgo & (1 << ssl->suites->hashAlgo))) {
-                    args->sigAlgo = rsa_pss_sa_algo;
-                }
-                else
-        #endif
-                    args->sigAlgo = rsa_sa_algo;
-            }
-            else if (ssl->hsType == DYNAMIC_TYPE_ECC)
-                args->sigAlgo = ecc_dsa_sa_algo;
-            else if (ssl->hsType == DYNAMIC_TYPE_ED25519)
-                args->sigAlgo = ed25519_sa_algo;
-            else if (ssl->hsType == DYNAMIC_TYPE_ED448)
-                args->sigAlgo = ed448_sa_algo;
-
-            if (IsAtLeastTLSv1_2(ssl)) {
-                EncodeSigAlg(ssl->suites->hashAlgo, args->sigAlgo,
-                             args->verify);
-                args->extraSz = HASH_SIG_SIZE;
-                SetDigest(ssl, ssl->suites->hashAlgo);
-            }
-        #ifndef NO_OLD_TLS
-            else {
-                /* if old TLS load MD5 and SHA hash as value to sign */
-                XMEMCPY(ssl->buffers.sig.buffer,
-                    (byte*)ssl->hsHashes->certHashes.md5, FINISHED_SZ);
-            }
-        #endif
-
-        #ifndef NO_RSA
-            if (args->sigAlgo == rsa_sa_algo) {
-                ssl->buffers.sig.length = FINISHED_SZ;
-                args->sigSz = ENCRYPT_LEN;
-
-                if (IsAtLeastTLSv1_2(ssl)) {
-                    ssl->buffers.sig.length = wc_EncodeSignature(
-                            ssl->buffers.sig.buffer, ssl->buffers.digest.buffer,
-                            ssl->buffers.digest.length,
-                            TypeHash(ssl->suites->hashAlgo));
-                }
-
-                /* prepend hdr */
-                c16toa(args->length, args->verify + args->extraSz);
-            }
-            #ifdef WC_RSA_PSS
-            else if (args->sigAlgo == rsa_pss_sa_algo) {
-                XMEMCPY(ssl->buffers.sig.buffer, ssl->buffers.digest.buffer,
-                        ssl->buffers.digest.length);
-                ssl->buffers.sig.length = ssl->buffers.digest.length;
-                args->sigSz = ENCRYPT_LEN;
-
-                /* prepend hdr */
-                c16toa(args->length, args->verify + args->extraSz);
-            }
-            #endif
-        #endif /* !NO_RSA */
-        #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)
-            if (args->sigAlgo == ed25519_sa_algo) {
-                ret = Ed25519CheckPubKey(ssl);
-                if (ret != 0)
-                    goto exit_scv;
-            }
-        #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */
-        #if defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH)
-            if (args->sigAlgo == ed448_sa_algo) {
-                ret = Ed448CheckPubKey(ssl);
-                if (ret != 0)
-                    goto exit_scv;
-            }
-        #endif /* HAVE_ED448 && !NO_ED448_CLIENT_AUTH */
-
-            /* Advance state and proceed */
-            ssl->options.asyncState = TLS_ASYNC_DO;
-        } /* case TLS_ASYNC_BUILD */
-        FALL_THROUGH;
-
-        case TLS_ASYNC_DO:
-        {
-        #ifdef HAVE_ECC
-           if (ssl->hsType == DYNAMIC_TYPE_ECC) {
-                ecc_key* key = (ecc_key*)ssl->hsKey;
-
-                ret = EccSign(ssl,
-                    ssl->buffers.digest.buffer, ssl->buffers.digest.length,
-                    ssl->buffers.sig.buffer, (word32*)&ssl->buffers.sig.length,
-                    key,
-            #ifdef HAVE_PK_CALLBACKS
-                    ssl->buffers.key
-            #else
-                    NULL
-            #endif
-                );
-            }
-        #endif /* HAVE_ECC */
-        #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)
-           if (ssl->hsType == DYNAMIC_TYPE_ED25519) {
-                ed25519_key* key = (ed25519_key*)ssl->hsKey;
-
-                ret = Ed25519Sign(ssl,
-                    ssl->hsHashes->messages, ssl->hsHashes->length,
-                    ssl->buffers.sig.buffer, (word32*)&ssl->buffers.sig.length,
-                    key,
-            #ifdef HAVE_PK_CALLBACKS
-                    ssl->buffers.key
-            #else
-                    NULL
-            #endif
-                );
-            }
-        #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */
-        #if defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH)
-           if (ssl->hsType == DYNAMIC_TYPE_ED448) {
-                ed448_key* key = (ed448_key*)ssl->hsKey;
-
-                ret = Ed448Sign(ssl,
-                    ssl->hsHashes->messages, ssl->hsHashes->length,
-                    ssl->buffers.sig.buffer, (word32*)&ssl->buffers.sig.length,
-                    key,
-            #ifdef HAVE_PK_CALLBACKS
-                    ssl->buffers.key
-            #else
-                    NULL
-            #endif
-                );
-            }
-        #endif /* HAVE_ED448 && !NO_ED448_CLIENT_AUTH */
-        #ifndef NO_RSA
-            if (ssl->hsType == DYNAMIC_TYPE_RSA) {
-                RsaKey* key = (RsaKey*)ssl->hsKey;
-
-                /* restore verify pointer */
-                args->verify = &args->output[args->idx];
-
-                ret = RsaSign(ssl,
-                    ssl->buffers.sig.buffer, ssl->buffers.sig.length,
-                    args->verify + args->extraSz + VERIFY_HEADER, &args->sigSz,
-                    args->sigAlgo, ssl->suites->hashAlgo, key,
-                    ssl->buffers.key
-                );
-            }
-        #endif /* !NO_RSA */
-
-            /* Check for error */
-            if (ret != 0) {
-                goto exit_scv;
-            }
-
-            /* Advance state and proceed */
-            ssl->options.asyncState = TLS_ASYNC_VERIFY;
-        } /* case TLS_ASYNC_DO */
-        FALL_THROUGH;
-
-        case TLS_ASYNC_VERIFY:
-        {
-            /* restore verify pointer */
-            args->verify = &args->output[args->idx];
-
-            switch (ssl->hsType) {
-        #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448)
-            #ifdef HAVE_ECC
-                case DYNAMIC_TYPE_ECC:
-            #endif
-            #ifdef HAVE_ED25519
-                case DYNAMIC_TYPE_ED25519:
-            #endif
-            #ifdef HAVE_ED448
-                case DYNAMIC_TYPE_ED448:
-            #endif
-                    args->length = (word16)ssl->buffers.sig.length;
-                    /* prepend hdr */
-                    c16toa(args->length, args->verify + args->extraSz);
-                    XMEMCPY(args->verify + args->extraSz + VERIFY_HEADER,
-                            ssl->buffers.sig.buffer, ssl->buffers.sig.length);
-                    break;
-        #endif
-            #ifndef NO_RSA
-                case DYNAMIC_TYPE_RSA:
-                {
-                    RsaKey* key = (RsaKey*)ssl->hsKey;
-
-                    if (args->verifySig == NULL) {
-                        args->verifySig = (byte*)XMALLOC(args->sigSz, ssl->heap,
-                                          DYNAMIC_TYPE_SIGNATURE);
-                        if (args->verifySig == NULL) {
-                            ERROR_OUT(MEMORY_E, exit_scv);
-                        }
-                        XMEMCPY(args->verifySig, args->verify + args->extraSz +
-                                                    VERIFY_HEADER, args->sigSz);
-                    }
-
-                    /* check for signature faults */
-                    ret = VerifyRsaSign(ssl,
-                        args->verifySig, args->sigSz,
-                        ssl->buffers.sig.buffer, ssl->buffers.sig.length,
-                        args->sigAlgo, ssl->suites->hashAlgo, key,
-                        ssl->buffers.key
-                    );
-                    break;
-                }
-            #endif /* !NO_RSA */
-                default:
-                    break;
-            }
-
-            /* Check for error */
-            if (ret != 0) {
-                goto exit_scv;
-            }
-
-            /* Advance state and proceed */
-            ssl->options.asyncState = TLS_ASYNC_FINALIZE;
-        } /* case TLS_ASYNC_VERIFY */
-        FALL_THROUGH;
-
-        case TLS_ASYNC_FINALIZE:
-        {
-            if (args->output == NULL) {
-                ERROR_OUT(BUFFER_ERROR, exit_scv);
-            }
-            AddHeaders(args->output, (word32)args->length + args->extraSz +
-                                        VERIFY_HEADER, certificate_verify, ssl);
-
-            args->sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ +
-                           (word32)args->length + args->extraSz + VERIFY_HEADER;
-
-        #ifdef WOLFSSL_DTLS
-            if (ssl->options.dtls) {
-                args->sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
-            }
-        #endif
-
-            if (IsEncryptionOn(ssl, 1)) {
-                args->inputSz = args->sendSz - RECORD_HEADER_SZ;
-                                /* build msg adds rec hdr */
-                args->input = (byte*)XMALLOC(args->inputSz, ssl->heap,
-                                                       DYNAMIC_TYPE_IN_BUFFER);
-                if (args->input == NULL) {
-                    ERROR_OUT(MEMORY_E, exit_scv);
-                }
-
-                XMEMCPY(args->input, args->output + RECORD_HEADER_SZ,
-                                                                args->inputSz);
-            }
-
-            /* Advance state and proceed */
-            ssl->options.asyncState = TLS_ASYNC_END;
-        } /* case TLS_ASYNC_FINALIZE */
-        FALL_THROUGH;
-
-        case TLS_ASYNC_END:
-        {
-            if (IsEncryptionOn(ssl, 1)) {
-                ret = BuildMessage(ssl, args->output,
-                                      MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA,
-                                      args->input, args->inputSz, handshake,
-                                      1, 0, 1);
-            #ifdef WOLFSSL_ASYNC_CRYPT
-                if (ret == WC_PENDING_E)
-                    goto exit_scv;
-            #endif
-
-                XFREE(args->input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
-                args->input = NULL;  /* make sure its not double free'd on cleanup */
-
-                if (ret >= 0) {
-                    args->sendSz = ret;
-                    ret = 0;
-                }
-            }
-            else {
-            #ifdef WOLFSSL_DTLS
-                if (ssl->options.dtls)
-                    DtlsSEQIncrement(ssl, CUR_ORDER);
-            #endif
-                ret = HashOutput(ssl, args->output, args->sendSz, 0);
-            }
-
-            if (ret != 0) {
-                goto exit_scv;
-            }
-
-        #ifdef WOLFSSL_DTLS
-            if (IsDtlsNotSctpMode(ssl)) {
-                ret = DtlsMsgPoolSave(ssl, args->output, args->sendSz);
-            }
-        #endif
-
-
-        #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
-            if (ssl->hsInfoOn)
-                AddPacketName(ssl, "CertificateVerify");
-            if (ssl->toInfoOn)
-                AddPacketInfo(ssl, "CertificateVerify", handshake,
-                            args->output, args->sendSz, WRITE_PROTO, ssl->heap);
-        #endif
-
-            ssl->buffers.outputBuffer.length += args->sendSz;
-
-            if (!ssl->options.groupMessages) {
-                ret = SendBuffered(ssl);
-            }
-            break;
-        }
-        default:
-            ret = INPUT_CASE_ERROR;
-    } /* switch(ssl->options.asyncState) */
-
-exit_scv:
-
-    WOLFSSL_LEAVE("SendCertificateVerify", ret);
-    WOLFSSL_END(WC_FUNC_CERTIFICATE_VERIFY_SEND);
-
-#ifdef WOLFSSL_ASYNC_CRYPT
-    /* Handle async operation */
-    if (ret == WC_PENDING_E) {
-        return ret;
-    }
-#endif /* WOLFSSL_ASYNC_CRYPT */
-
-    /* Digest is not allocated, so do this to prevent free */
-    ssl->buffers.digest.buffer = NULL;
-    ssl->buffers.digest.length = 0;
-
-    /* Final cleanup */
-    FreeScvArgs(ssl, args);
-    FreeKeyExchange(ssl);
-
-    return ret;
-}
-#endif /* WOLFSSL_NO_CLIENT_AUTH */
-
-#endif /* WOLFSSL_NO_TLS12 */
-
 #endif /* NO_CERTS */
-
-
-#ifdef HAVE_SESSION_TICKET
-int SetTicket(WOLFSSL* ssl, const byte* ticket, word32 length)
-{
-    /* Free old dynamic ticket if we already had one */
-    if (ssl->session.isDynamic) {
-        XFREE(ssl->session.ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK);
-        ssl->session.ticket = ssl->session.staticTicket;
-        ssl->session.isDynamic = 0;
-    }
-
-    if (length > sizeof(ssl->session.staticTicket)) {
-        byte* sessionTicket =
-                   (byte*)XMALLOC(length, ssl->heap, DYNAMIC_TYPE_SESSION_TICK);
-        if (sessionTicket == NULL)
-            return MEMORY_E;
-        ssl->session.ticket = sessionTicket;
-        ssl->session.isDynamic = 1;
-    }
-    ssl->session.ticketLen = (word16)length;
-
-    if (length > 0) {
-        XMEMCPY(ssl->session.ticket, ticket, length);
-        if (ssl->session_ticket_cb != NULL) {
-            ssl->session_ticket_cb(ssl,
-                                   ssl->session.ticket, ssl->session.ticketLen,
-                                   ssl->session_ticket_ctx);
-        }
-        /* Create a fake sessionID based on the ticket, this will
-         * supersede the existing session cache info. */
-        ssl->options.haveSessionId = 1;
-#ifdef WOLFSSL_TLS13
-        if (ssl->options.tls1_3) {
-            XMEMCPY(ssl->session.sessionID,
-                                 ssl->session.ticket + length - ID_LEN, ID_LEN);
-        }
-        else
-#endif
-            XMEMCPY(ssl->arrays->sessionID,
-                                 ssl->session.ticket + length - ID_LEN, ID_LEN);
-    }
-
-    return 0;
-}
-
-#ifndef WOLFSSL_NO_TLS12
-
-/* handle processing of session_ticket (4) */
-static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
-    word32 size)
-{
-    word32 begin = *inOutIdx;
-    word32 lifetime;
-    word16 length;
-    int    ret;
-
-    if (ssl->expect_session_ticket == 0) {
-        WOLFSSL_MSG("Unexpected session ticket");
-        return SESSION_TICKET_EXPECT_E;
-    }
-
-    if (OPAQUE32_LEN > size)
-        return BUFFER_ERROR;
-
-    ato32(input + *inOutIdx, &lifetime);
-    *inOutIdx += OPAQUE32_LEN;
-
-    if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
-        return BUFFER_ERROR;
-
-    ato16(input + *inOutIdx, &length);
-    *inOutIdx += OPAQUE16_LEN;
-
-    if ((*inOutIdx - begin) + length > size)
-        return BUFFER_ERROR;
-
-    if ((ret = SetTicket(ssl, input + *inOutIdx, length)) != 0)
-        return ret;
-    *inOutIdx += length;
-    if (length > 0) {
-        ssl->timeout = lifetime;
-#ifndef NO_SESSION_CACHE
-        AddSession(ssl);
-#endif
-    }
-
-    if (IsEncryptionOn(ssl, 0)) {
-        *inOutIdx += ssl->keys.padSz;
-    #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
-        if (ssl->options.startedETMRead)
-            *inOutIdx += MacSize(ssl);
-    #endif
-    }
-
-    ssl->expect_session_ticket = 0;
-
-    return 0;
-}
-
-#endif /* !WOLFSSL_NO_TLS12 */
-
-#endif /* HAVE_SESSION_TICKET */
-
-#endif /* NO_WOLFSSL_CLIENT */
 
 #ifdef HAVE_ECC
@@ -24046,5 +25269,5 @@
     word16 GetCurveByOID(int oidSum) {
         switch(oidSum) {
-    #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)
+    #if (defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 160
         #ifndef NO_ECC_SECP
             case ECC_SECP160R1_OID:
@@ -24060,5 +25283,5 @@
         #endif /* HAVE_ECC_KOBLITZ */
     #endif
-    #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)
+    #if (defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 192
         #ifndef NO_ECC_SECP
             case ECC_SECP192R1_OID:
@@ -24070,5 +25293,5 @@
         #endif /* HAVE_ECC_KOBLITZ */
     #endif
-    #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)
+    #if (defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 224
         #ifndef NO_ECC_SECP
             case ECC_SECP224R1_OID:
@@ -24080,5 +25303,5 @@
         #endif /* HAVE_ECC_KOBLITZ */
     #endif
-    #if !defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)
+    #if (!defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256
         #ifndef NO_ECC_SECP
             case ECC_SECP256R1_OID:
@@ -24094,5 +25317,5 @@
         #endif /* HAVE_ECC_BRAINPOOL */
     #endif
-    #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+    #if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384
         #ifndef NO_ECC_SECP
             case ECC_SECP384R1_OID:
@@ -24104,5 +25327,5 @@
         #endif /* HAVE_ECC_BRAINPOOL */
     #endif
-    #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)
+    #if (defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 512
         #ifdef HAVE_ECC_BRAINPOOL
             case ECC_BRAINPOOLP512R1_OID:
@@ -24110,5 +25333,5 @@
         #endif /* HAVE_ECC_BRAINPOOL */
     #endif
-    #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+    #if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521
         #ifndef NO_ECC_SECP
             case ECC_SECP521R1_OID:
@@ -24190,8 +25413,12 @@
         #ifdef WOLFSSL_DTLS
         if (ssl->options.dtls) {
-            /* Server Hello should use the same sequence number as the
-             * Client Hello. */
-            ssl->keys.dtls_sequence_number_hi = ssl->keys.curSeq_hi;
-            ssl->keys.dtls_sequence_number_lo = ssl->keys.curSeq_lo;
+            if (((ssl->keys.dtls_sequence_number_hi == ssl->keys.curSeq_hi &&
+                  ssl->keys.dtls_sequence_number_lo < ssl->keys.curSeq_lo) ||
+                 (ssl->keys.dtls_sequence_number_hi < ssl->keys.curSeq_hi))) {
+                /* Server Hello should use the same sequence number as the
+                 * Client Hello if available. */
+                ssl->keys.dtls_sequence_number_hi = ssl->keys.curSeq_hi;
+                ssl->keys.dtls_sequence_number_lo = ssl->keys.curSeq_lo;
+            }
             idx    += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
             sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
@@ -24236,4 +25463,7 @@
             if (ssl->ctx->method->version.major == SSLv3_MAJOR &&
                           ssl->ctx->method->version.minor == TLSv1_2_MINOR &&
+#ifdef OPENSSL_EXTRA
+                          (wolfSSL_get_options(ssl) & SSL_OP_NO_TLSv1_2) == 0 &&
+#endif
                                                        !IsAtLeastTLSv1_2(ssl)) {
                 /* TLS v1.2 capable server downgraded. */
@@ -24306,13 +25536,24 @@
         if (IsEncryptionOn(ssl, 1)) {
             byte* input;
-            int   inputSz = idx - RECORD_HEADER_SZ; /* build msg adds rec hdr */
-
+            int   inputSz = idx; /* build msg adds rec hdr */
+            int   recordHeaderSz = RECORD_HEADER_SZ;
+
+            if (ssl->options.dtls)
+                recordHeaderSz += DTLS_RECORD_EXTRA;
+            inputSz -= recordHeaderSz;
             input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
             if (input == NULL)
                 return MEMORY_E;
 
-            XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+            XMEMCPY(input, output + recordHeaderSz, inputSz);
+            #ifdef WOLFSSL_DTLS
+            if (IsDtlsNotSctpMode(ssl) &&
+                    (ret = DtlsMsgPoolSave(ssl, input, inputSz, server_hello)) != 0) {
+                XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+                return ret;
+            }
+            #endif
             sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
-                                  handshake, 1, 0, 0);
+                                  handshake, 1, 0, 0, CUR_ORDER);
             XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
 
@@ -24321,4 +25562,8 @@
         } else {
             #ifdef WOLFSSL_DTLS
+                if (IsDtlsNotSctpMode(ssl)) {
+                    if ((ret = DtlsMsgPoolSave(ssl, output, sendSz, server_hello)) != 0)
+                        return ret;
+                }
                 if (ssl->options.dtls)
                     DtlsSEQIncrement(ssl, CUR_ORDER);
@@ -24340,11 +25585,4 @@
         ssl->buffers.outputBuffer.length += sendSz;
 
-    #ifdef WOLFSSL_DTLS
-        if (IsDtlsNotSctpMode(ssl)) {
-            if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0)
-                return ret;
-        }
-    #endif
-
         if (ssl->options.groupMessages)
             ret = 0;
@@ -24376,5 +25614,5 @@
         byte*  output; /* not allocated */
     #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \
-                                           (!defined(NO_DH) && !defined(NO_RSA))
+                                                                !defined(NO_RSA)
         byte*  sigDataBuf;
     #endif
@@ -24391,5 +25629,5 @@
         word32 sigSz;
     #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \
-                                           (!defined(NO_DH) && !defined(NO_RSA))
+                                                                !defined(NO_RSA)
         word32 sigDataSz;
     #endif
@@ -24534,4 +25772,6 @@
                                 ERROR_OUT(MEMORY_E, exit_sske);
                             }
+                            ssl->buffers.serverDH_Pub.length =
+                                ssl->buffers.serverDH_P.length + OPAQUE16_LEN;
                         }
 
@@ -24544,4 +25784,6 @@
                                 ERROR_OUT(MEMORY_E, exit_sske);
                             }
+                            ssl->buffers.serverDH_Priv.length =
+                                ssl->buffers.serverDH_P.length + OPAQUE16_LEN;
                         }
 
@@ -25535,6 +26777,6 @@
                     }
                 #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && !NO_PSK */
-                #if defined(HAVE_ECC) || defined(HAVE_ED25519) || \
-                                                             defined(HAVE_ED448)
+                #if defined(HAVE_ECC)  || defined(HAVE_CURVE25519) || \
+                                                          defined(HAVE_CURVE448)
                     case ecc_diffie_hellman_kea:
                     {
@@ -25859,5 +27101,6 @@
                 if (IsEncryptionOn(ssl, 1)) {
                     args->inputSz = args->length + HANDSHAKE_HEADER_SZ;
-                                                     /* buildmsg adds rechdr */
+                    if (ssl->options.dtls)
+                        args->inputSz += DTLS_HANDSHAKE_EXTRA;
                     args->input = (byte*)XMALLOC(args->inputSz, ssl->heap,
                                                         DYNAMIC_TYPE_IN_BUFFER);
@@ -25870,8 +27113,20 @@
                     }
 
-                    XMEMCPY(args->input, args->output + RECORD_HEADER_SZ,
+                    if (!ssl->options.dtls)
+                        XMEMCPY(args->input, args->output + RECORD_HEADER_SZ,
                                                                  args->inputSz);
+                    else
+                        XMEMCPY(args->input, args->output + DTLS_RECORD_HEADER_SZ,
+                                                                 args->inputSz);
+
+                    #ifdef WOLFSSL_DTLS
+                    if (IsDtlsNotSctpMode(ssl) &&
+                        (ret = DtlsMsgPoolSave(ssl, args->input, args->inputSz, server_key_exchange))
+                            != 0) {
+                        goto exit_sske;
+                    }
+                    #endif
                     ret = BuildMessage(ssl, args->output, args->sendSz,
-                                args->input, args->inputSz, handshake, 1, 0, 0);
+                                args->input, args->inputSz, handshake, 1, 0, 0, CUR_ORDER);
                     XFREE(args->input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
                     args->input = NULL;
@@ -25887,5 +27142,5 @@
                     if (IsDtlsNotSctpMode(ssl)) {
                         if ((ret = DtlsMsgPoolSave(ssl,
-                                            args->output, args->sendSz)) != 0) {
+                                            args->output, args->sendSz, server_key_exchange)) != 0) {
                             goto exit_sske;
                         }
@@ -25943,4 +27198,8 @@
 
         /* Final cleanup */
+        if (args->input != NULL) {
+            XFREE(args->input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+            args->input = NULL;
+        }
         FreeSskeArgs(ssl, args);
         FreeKeyExchange(ssl);
@@ -26098,5 +27357,6 @@
 #ifdef WOLFSSL_TLS13
         if (IsAtLeastTLSv1_3(ssl->version) &&
-            ssl->options.side == WOLFSSL_SERVER_END) {
+                                      ssl->options.side == WOLFSSL_SERVER_END) {
+    #ifdef HAVE_SUPPORTED_CURVES
             /* Try to establish a key share. */
             int ret = TLSX_KeyShare_Establish(ssl);
@@ -26105,4 +27365,5 @@
             else if (ret != 0)
                 return 0;
+    #endif
         }
         else if (first == TLS13_BYTE || (first == ECC_BYTE &&
@@ -26288,4 +27549,7 @@
         if (clSuites.suiteSz > WOLFSSL_MAX_SUITE_SZ)
             return BUFFER_ERROR;
+        /* Make sure the suiteSz is a multiple of 3. (Old Client Hello) */
+        if (clSuites.suiteSz % 3 != 0)
+            return BUFFER_ERROR;
         clSuites.hashSigAlgoSz = 0;
 
@@ -26427,4 +27691,7 @@
                 SendAlert(ssl, alert_fatal, handshake_failure);
             #endif
+                #ifdef HAVE_EXT_CACHE
+                    wolfSSL_SESSION_free(session);
+                #endif
                 return EXT_MASTER_SECRET_NEEDED_E;
             }
@@ -26519,5 +27786,5 @@
         ssl->chVersion = pv;   /* store */
 #ifdef WOLFSSL_DTLS
-        if (IsDtlsNotSctpMode(ssl)) {
+        if (IsDtlsNotSctpMode(ssl) && !IsSCR(ssl) && !ssl->options.resuming) {
             #if defined(NO_SHA) && defined(NO_SHA256)
                 #error "DTLS needs either SHA or SHA-256"
@@ -26535,11 +27802,11 @@
                                 ssl->buffers.dtlsCookieSecret.buffer,
                                 ssl->buffers.dtlsCookieSecret.length);
-            if (ret != 0) return ret;
+            if (ret != 0) goto out;
             ret = wc_HmacUpdate(&cookieHmac,
                                 (const byte*)ssl->buffers.dtlsCtx.peer.sa,
                                 ssl->buffers.dtlsCtx.peer.sz);
-            if (ret != 0) return ret;
+            if (ret != 0) goto out;
             ret = wc_HmacUpdate(&cookieHmac, input + i, OPAQUE16_LEN);
-            if (ret != 0) return ret;
+            if (ret != 0) goto out;
         }
 #endif /* WOLFSSL_DTLS */
@@ -26561,9 +27828,11 @@
             if (!ssl->options.downgrade) {
                 WOLFSSL_MSG("Client trying to connect with lesser version");
-                return VERSION_ERROR;
+                ret = VERSION_ERROR;
+                goto out;
             }
             if (pv.minor < ssl->options.minDowngrade) {
                 WOLFSSL_MSG("\tversion below minimum allowed, fatal error");
-                return VERSION_ERROR;
+                ret = VERSION_ERROR;
+                goto out;
             }
 
@@ -26634,10 +27903,12 @@
                 (ssl->options.mask & SSL_OP_NO_SSLv3) == SSL_OP_NO_SSLv3) {
                 WOLFSSL_MSG("\tError, option set to not allow SSLv3");
-                return VERSION_ERROR;
+                ret = VERSION_ERROR;
+                goto out;
             }
 
             if (ssl->version.minor < ssl->options.minDowngrade) {
                 WOLFSSL_MSG("\tversion below minimum allowed, fatal error");
-                return VERSION_ERROR;
+                ret = VERSION_ERROR;
+                goto out;
             }
 
@@ -26669,7 +27940,7 @@
         XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN);
 #ifdef WOLFSSL_DTLS
-        if (IsDtlsNotSctpMode(ssl)) {
+        if (IsDtlsNotSctpMode(ssl) && !IsSCR(ssl) && !ssl->options.resuming) {
             ret = wc_HmacUpdate(&cookieHmac, input + i, RAN_LEN);
-            if (ret != 0) return ret;
+            if (ret != 0) goto out;
         }
 #endif /* WOLFSSL_DTLS */
@@ -26697,12 +27968,15 @@
 
         if (b == ID_LEN || bogusID) {
-            if ((i - begin) + b > helloSz)
-                return BUFFER_ERROR;
+            if ((i - begin) + b > helloSz) {
+                ret = BUFFER_ERROR;
+                goto out;
+            }
 
             XMEMCPY(ssl->arrays->sessionID, input + i, b);
 #ifdef WOLFSSL_DTLS
-            if (IsDtlsNotSctpMode(ssl)) {
+            if (IsDtlsNotSctpMode(ssl) && !IsSCR(ssl) &&
+                    !ssl->options.resuming) {
                 ret = wc_HmacUpdate(&cookieHmac, input + i - 1, b + 1);
-                if (ret != 0) return ret;
+                if (ret != 0) goto out;
             }
 #endif /* WOLFSSL_DTLS */
@@ -26714,5 +27988,6 @@
         else if (b) {
             WOLFSSL_MSG("Invalid session ID size");
-            return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */
+            ret = BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */
+            goto out;
         }
 
@@ -26721,15 +27996,21 @@
             if (ssl->options.dtls) {
 
-                if ((i - begin) + OPAQUE8_LEN > helloSz)
-                    return BUFFER_ERROR;
+                if ((i - begin) + OPAQUE8_LEN > helloSz) {
+                    ret = BUFFER_ERROR;
+                    goto out;
+                }
 
                 peerCookieSz = input[i++];
 
                 if (peerCookieSz) {
-                    if (peerCookieSz > MAX_COOKIE_LEN)
-                        return BUFFER_ERROR;
-
-                    if ((i - begin) + peerCookieSz > helloSz)
-                        return BUFFER_ERROR;
+                    if (peerCookieSz > MAX_COOKIE_LEN) {
+                        ret = BUFFER_ERROR;
+                        goto out;
+                    }
+
+                    if ((i - begin) + peerCookieSz > helloSz) {
+                        ret = BUFFER_ERROR;
+                        goto out;
+                    }
 
                     XMEMCPY(peerCookie, input + i, peerCookieSz);
@@ -26741,16 +28022,28 @@
 
         /* suites */
-        if ((i - begin) + OPAQUE16_LEN > helloSz)
-            return BUFFER_ERROR;
+        if ((i - begin) + OPAQUE16_LEN > helloSz) {
+            ret = BUFFER_ERROR;
+            goto out;
+        }
 
         ato16(&input[i], &clSuites.suiteSz);
         i += OPAQUE16_LEN;
 
+        /* Cipher suite lists are always multiples of two in length. */
+        if (clSuites.suiteSz % 2 != 0) {
+            ret = BUFFER_ERROR;
+            goto out;
+        }
+
         /* suites and compression length check */
-        if ((i - begin) + clSuites.suiteSz + OPAQUE8_LEN > helloSz)
-            return BUFFER_ERROR;
-
-        if (clSuites.suiteSz > WOLFSSL_MAX_SUITE_SZ)
-            return BUFFER_ERROR;
+        if ((i - begin) + clSuites.suiteSz + OPAQUE8_LEN > helloSz) {
+            ret = BUFFER_ERROR;
+            goto out;
+        }
+
+        if (clSuites.suiteSz > WOLFSSL_MAX_SUITE_SZ) {
+            ret = BUFFER_ERROR;
+            goto out;
+        }
 
         XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz);
@@ -26764,5 +28057,5 @@
             ret = TLSX_AddEmptyRenegotiationInfo(&ssl->extensions, ssl->heap);
             if (ret != WOLFSSL_SUCCESS)
-                return ret;
+                goto out;
 
             extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO);
@@ -26781,5 +28074,6 @@
                 WOLFSSL_MSG("Client trying to connect with lesser version");
                 SendAlert(ssl, alert_fatal, inappropriate_fallback);
-                return VERSION_ERROR;
+                ret = VERSION_ERROR;
+                goto out;
             }
         }
@@ -26787,9 +28081,9 @@
 
 #ifdef WOLFSSL_DTLS
-        if (IsDtlsNotSctpMode(ssl)) {
+        if (IsDtlsNotSctpMode(ssl) && !IsSCR(ssl) && !ssl->options.resuming) {
             ret = wc_HmacUpdate(&cookieHmac,
                                     input + i - OPAQUE16_LEN,
                                     clSuites.suiteSz + OPAQUE16_LEN);
-            if (ret != 0) return ret;
+            if (ret != 0) goto out;
         }
 #endif /* WOLFSSL_DTLS */
@@ -26800,6 +28094,8 @@
         b = input[i++];
 
-        if ((i - begin) + b > helloSz)
-            return BUFFER_ERROR;
+        if ((i - begin) + b > helloSz) {
+            ret = BUFFER_ERROR;
+            goto out;
+        }
 
         if (b == 0) {
@@ -26808,36 +28104,41 @@
             SendAlert(ssl, alert_fatal, decode_error);
 #endif
-            return COMPRESSION_ERROR;
+            ret = COMPRESSION_ERROR;
+            goto out;
         }
 
 #ifdef WOLFSSL_DTLS
         if (IsDtlsNotSctpMode(ssl)) {
-            byte newCookie[MAX_COOKIE_LEN];
-
-            ret = wc_HmacUpdate(&cookieHmac, input + i - 1, b + 1);
-            if (ret != 0) return ret;
-            ret = wc_HmacFinal(&cookieHmac, newCookie);
-            if (ret != 0) return ret;
-
-            /* If a cookie callback is set, call it to overwrite the cookie.
-             * This should be deprecated. The code now calculates the cookie
-             * using an HMAC as expected. */
-            if (ssl->ctx->CBIOCookie != NULL &&
-                ssl->ctx->CBIOCookie(ssl, newCookie, cookieSz,
-                                             ssl->IOCB_CookieCtx) != cookieSz) {
-                return COOKIE_ERROR;
-            }
-
-            /* Check the cookie, see if we progress the state machine. */
-            if (peerCookieSz != cookieSz ||
-                XMEMCMP(peerCookie, newCookie, cookieSz) != 0) {
-
-                /* Send newCookie to client in a HelloVerifyRequest message
-                 * and let the state machine alone. */
-                ssl->msgsReceived.got_client_hello = 0;
-                ssl->keys.dtls_handshake_number = 0;
-                ssl->keys.dtls_expected_peer_handshake_number = 0;
-                *inOutIdx += helloSz;
-                return SendHelloVerifyRequest(ssl, newCookie, cookieSz);
+            if (!IsSCR(ssl) && !ssl->options.resuming) {
+                byte newCookie[MAX_COOKIE_LEN];
+
+                ret = wc_HmacUpdate(&cookieHmac, input + i - 1, b + 1);
+                if (ret != 0) goto out;
+                ret = wc_HmacFinal(&cookieHmac, newCookie);
+                if (ret != 0) goto out;
+
+                /* If a cookie callback is set, call it to overwrite the cookie.
+                 * This should be deprecated. The code now calculates the cookie
+                 * using an HMAC as expected. */
+                if (ssl->ctx->CBIOCookie != NULL &&
+                    ssl->ctx->CBIOCookie(ssl, newCookie, cookieSz,
+                                                 ssl->IOCB_CookieCtx) != cookieSz) {
+                    ret = COOKIE_ERROR;
+                    goto out;
+                }
+
+                /* Check the cookie, see if we progress the state machine. */
+                if (peerCookieSz != cookieSz ||
+                    XMEMCMP(peerCookie, newCookie, cookieSz) != 0) {
+
+                    /* Send newCookie to client in a HelloVerifyRequest message
+                     * and let the state machine alone. */
+                    ssl->msgsReceived.got_client_hello = 0;
+                    ssl->keys.dtls_handshake_number = 0;
+                    ssl->keys.dtls_expected_peer_handshake_number = 0;
+                    *inOutIdx += helloSz;
+                    ret = SendHelloVerifyRequest(ssl, newCookie, cookieSz);
+                    goto out;
+                }
             }
 
@@ -26845,5 +28146,5 @@
              * verify request. */
             ret = HashInput(ssl, input + *inOutIdx, helloSz);
-            if (ret != 0) return ret;
+            if (ret != 0) goto out;
         }
 #endif /* WOLFSSL_DTLS */
@@ -26877,5 +28178,6 @@
                 SendAlert(ssl, alert_fatal, illegal_parameter);
 #endif
-                return COMPRESSION_ERROR;
+                ret = COMPRESSION_ERROR;
+                goto out;
             }
         }
@@ -26900,15 +28202,19 @@
                 /* auto populate extensions supported unless user defined */
                 if ((ret = TLSX_PopulateExtensions(ssl, 1)) != 0)
-                    return ret;
-#endif
-
-                if ((i - begin) + OPAQUE16_LEN > helloSz)
-                    return BUFFER_ERROR;
+                    goto out;
+#endif
+
+                if ((i - begin) + OPAQUE16_LEN > helloSz) {
+                    ret = BUFFER_ERROR;
+                    goto out;
+                }
 
                 ato16(&input[i], &totalExtSz);
                 i += OPAQUE16_LEN;
 
-                if ((i - begin) + totalExtSz > helloSz)
-                    return BUFFER_ERROR;
+                if ((i - begin) + totalExtSz > helloSz) {
+                    ret = BUFFER_ERROR;
+                    goto out;
+                }
 
 #ifdef HAVE_TLS_EXTENSIONS
@@ -26916,5 +28222,5 @@
                 if ((ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz,
                                       client_hello, &clSuites)))
-                    return ret;
+                    goto out;
     #ifdef WOLFSSL_TLS13
                 if (TLSX_Find(ssl->extensions,
@@ -26922,10 +28228,11 @@
                     WOLFSSL_MSG(
                             "Client attempting to connect with higher version");
-                    return VERSION_ERROR;
+                    ret = VERSION_ERROR;
+                    goto out;
                 }
     #endif
-    #if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+    #ifdef HAVE_SNI
                 if((ret=SNI_Callback(ssl)))
-                    return ret;
+                    goto out;
                 ssl->options.side = WOLFSSL_SERVER_END;
     #endif
@@ -26936,6 +28243,8 @@
                     word16 extId, extSz;
 
-                    if (OPAQUE16_LEN + OPAQUE16_LEN > totalExtSz)
-                        return BUFFER_ERROR;
+                    if (OPAQUE16_LEN + OPAQUE16_LEN > totalExtSz) {
+                        ret = BUFFER_ERROR;
+                        goto out;
+                    }
 
                     ato16(&input[i], &extId);
@@ -26944,6 +28253,8 @@
                     i += OPAQUE16_LEN;
 
-                    if (OPAQUE16_LEN + OPAQUE16_LEN + extSz > totalExtSz)
-                        return BUFFER_ERROR;
+                    if (OPAQUE16_LEN + OPAQUE16_LEN + extSz > totalExtSz) {
+                        ret = BUFFER_ERROR;
+                        goto out;
+                    }
 
                     if (extId == HELLO_EXT_SIG_ALGO) {
@@ -26953,6 +28264,13 @@
                         i += OPAQUE16_LEN;
 
-                        if (OPAQUE16_LEN + hashSigAlgoSz > extSz)
-                            return BUFFER_ERROR;
+                        if (OPAQUE16_LEN + hashSigAlgoSz > extSz) {
+                            ret = BUFFER_ERROR;
+                            goto out;
+                        }
+
+                        if (hashSigAlgoSz % 2 != 0) {
+                            ret = BUFFER_ERROR;
+                            goto out;
+                        }
 
                         clSuites.hashSigAlgoSz = hashSigAlgoSz;
@@ -26991,12 +28309,5 @@
             ret = HandleTlsResumption(ssl, bogusID, &clSuites);
             if (ret != 0)
-                return ret;
-
-            #ifdef HAVE_SECURE_RENEGOTIATION
-            if (ssl->secure_renegotiation &&
-                    ssl->secure_renegotiation->enabled &&
-                    IsEncryptionOn(ssl, 0))
-                ssl->secure_renegotiation->startScr = 1;
-            #endif
+                goto out;
 
             if (ssl->options.clientState == CLIENT_KEYEXCHANGE_COMPLETE) {
@@ -27004,5 +28315,5 @@
                 WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO);
 
-                return ret;
+                goto out;
             }
         }
@@ -27015,5 +28326,5 @@
             ret = TLSX_SupportedFFDHE_Set(ssl);
             if (ret != 0)
-                return ret;
+                goto out;
         }
     #endif
@@ -27028,12 +28339,16 @@
 #endif
 
-#ifdef HAVE_SECURE_RENEGOTIATION
-        if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled &&
-                IsEncryptionOn(ssl, 0)) {
-            ssl->secure_renegotiation->startScr = 1;
-        }
+#ifdef WOLFSSL_DTLS
+        if (ret == 0 && ssl->options.dtls)
+            DtlsMsgPoolReset(ssl);
 #endif
         WOLFSSL_LEAVE("DoClientHello", ret);
         WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO);
+
+    out:
+
+#ifdef WOLFSSL_DTLS
+        wc_HmacFree(&cookieHmac);
+#endif
 
         return ret;
@@ -27483,4 +28798,10 @@
             byte* input;
             int   inputSz = HANDSHAKE_HEADER_SZ; /* build msg adds rec hdr */
+            int   recordHeaderSz = RECORD_HEADER_SZ;
+
+            if (ssl->options.dtls) {
+                recordHeaderSz += DTLS_RECORD_EXTRA;
+                inputSz += DTLS_HANDSHAKE_EXTRA;
+            }
 
             input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
@@ -27488,7 +28809,14 @@
                 return MEMORY_E;
 
-            XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+            XMEMCPY(input, output + recordHeaderSz, inputSz);
+            #ifdef WOLFSSL_DTLS
+            if (IsDtlsNotSctpMode(ssl) &&
+                    (ret = DtlsMsgPoolSave(ssl, input, inputSz, server_hello_done)) != 0) {
+                XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+                return ret;
+            }
+            #endif
             sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
-                                  handshake, 1, 0, 0);
+                                  handshake, 1, 0, 0, CUR_ORDER);
             XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
 
@@ -27498,5 +28826,5 @@
             #ifdef WOLFSSL_DTLS
                 if (IsDtlsNotSctpMode(ssl)) {
-                    if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0)
+                    if ((ret = DtlsMsgPoolSave(ssl, output, sendSz, server_hello_done)) != 0)
                         return ret;
                 }
@@ -27546,7 +28874,5 @@
         word32          ageAdd;                /* Obfuscation of age */
         word16          namedGroup;            /* Named group used */
-    #ifndef WOLFSSL_TLS13_DRAFT_18
         TicketNonce     ticketNonce;           /* Ticket nonce */
-    #endif
     #ifdef WOLFSSL_EARLY_DATA
         word32          maxEarlyDataSz;        /* Max size of early data */
@@ -27555,4 +28881,5 @@
     } InternalTicket;
 
+    /* RFC 5077 defines this for session tickets */
     /* fit within SESSION_TICKET_LEN */
     typedef struct ExternalTicket {
@@ -27604,13 +28931,8 @@
             /* Resumption master secret. */
             XMEMCPY(it.msecret, ssl->session.masterSecret, SECRET_LEN);
-    #ifndef WOLFSSL_TLS13_DRAFT_18
             XMEMCPY(&it.ticketNonce, &ssl->session.ticketNonce,
                                                            sizeof(TicketNonce));
-    #endif
-#endif
-        }
-
-        /* build external */
-        XMEMCPY(et->enc_ticket, &it, sizeof(InternalTicket));
+#endif
+        }
 
         /* encrypt */
@@ -27620,11 +28942,19 @@
         }
         else {
+            /* build external */
+            XMEMCPY(et->enc_ticket, &it, sizeof(InternalTicket));
+
             ret = ssl->ctx->ticketEncCb(ssl, et->key_name, et->iv, et->mac, 1,
                                     et->enc_ticket, sizeof(InternalTicket),
                                     &encLen, ssl->ctx->ticketEncCtx);
+            if (ret != WOLFSSL_TICKET_RET_OK) {
+                ForceZero(et->enc_ticket, sizeof(it));
+            }
         }
         if (ret == WOLFSSL_TICKET_RET_OK) {
             if (encLen < (int)sizeof(InternalTicket) ||
                 encLen > WOLFSSL_TICKET_ENC_SZ) {
+                ForceZero(&it, sizeof(it));
+                ForceZero(et->enc_ticket, sizeof(it));
                 WOLFSSL_MSG("Bad user ticket encrypt size");
                 return BAD_TICKET_KEY_CB_SZ;
@@ -27635,8 +28965,11 @@
             /* internal ticket can't be the same if encrypted */
             if (XMEMCMP(et->enc_ticket, &it, sizeof(InternalTicket)) == 0) {
+                ForceZero(&it, sizeof(it));
+                ForceZero(et->enc_ticket, sizeof(it));
                 WOLFSSL_MSG("User ticket encrypt didn't encrypt");
                 return BAD_TICKET_ENCRYPT;
             }
 
+            ForceZero(&it, sizeof(it));
             XMEMSET(zeros, 0, sizeof(zeros));
 
@@ -27676,5 +29009,5 @@
     {
         ExternalTicket* et;
-        InternalTicket* it;
+        InternalTicket  it;
         int             ret;
         int             outLen;
@@ -27690,5 +29023,4 @@
 
         et = (ExternalTicket*)input;
-        it = (InternalTicket*)et->enc_ticket;
 
         /* decrypt */
@@ -27714,12 +29046,25 @@
         }
 
+        /* copy the decrypted ticket to avoid alignment issues */
+        XMEMCPY(&it, et->enc_ticket, sizeof(InternalTicket));
+        ForceZero(et->enc_ticket, sizeof(it));
+
         /* get master secret */
         if (ret == WOLFSSL_TICKET_RET_OK || ret == WOLFSSL_TICKET_RET_CREATE) {
-            if (ssl->version.minor < it->pv.minor) {
+            if (ssl->version.minor < it.pv.minor) {
+                ForceZero(&it, sizeof(it));
                 WOLFSSL_MSG("Ticket has greater version");
                 return VERSION_ERROR;
             }
-            else if (ssl->version.minor > it->pv.minor) {
+            else if (ssl->version.minor > it.pv.minor) {
+                if (IsAtLeastTLSv1_3(it.pv) != IsAtLeastTLSv1_3(ssl->version)) {
+                    ForceZero(&it, sizeof(it));
+                    WOLFSSL_MSG("Tickets cannot be shared between "
+                                               "TLS 1.3 and TLS 1.2 and lower");
+                    return VERSION_ERROR;
+                }
+
                 if (!ssl->options.downgrade) {
+                    ForceZero(&it, sizeof(it));
                     WOLFSSL_MSG("Ticket has lesser version");
                     return VERSION_ERROR;
@@ -27728,18 +29073,20 @@
                 WOLFSSL_MSG("Downgrading protocol due to ticket");
 
-                if (it->pv.minor < ssl->options.minDowngrade)
+                if (it.pv.minor < ssl->options.minDowngrade) {
+                    ForceZero(&it, sizeof(it));
                     return VERSION_ERROR;
-                ssl->version.minor = it->pv.minor;
+                }
+                ssl->version.minor = it.pv.minor;
             }
 
 
             if (!IsAtLeastTLSv1_3(ssl->version)) {
-                XMEMCPY(ssl->arrays->masterSecret, it->msecret, SECRET_LEN);
+                XMEMCPY(ssl->arrays->masterSecret, it.msecret, SECRET_LEN);
                 /* Copy the haveExtendedMasterSecret property from the ticket to
                  * the saved session, so the property may be checked later. */
-                ssl->session.haveEMS = it->haveEMS;
+                ssl->session.haveEMS = it.haveEMS;
             #ifndef NO_RESUME_SUITE_CHECK
-                ssl->session.cipherSuite0 = it->suite[0];
-                ssl->session.cipherSuite = it->suite[1];
+                ssl->session.cipherSuite0 = it.suite[0];
+                ssl->session.cipherSuite = it.suite[1];
             #endif
             }
@@ -27747,21 +29094,21 @@
 #ifdef WOLFSSL_TLS13
                 /* Restore information to renegotiate. */
-                ssl->session.ticketSeen = it->timestamp;
-                ssl->session.ticketAdd = it->ageAdd;
-                ssl->session.cipherSuite0 = it->suite[0];
-                ssl->session.cipherSuite = it->suite[1];
+                ssl->session.ticketSeen = it.timestamp;
+                ssl->session.ticketAdd = it.ageAdd;
+                ssl->session.cipherSuite0 = it.suite[0];
+                ssl->session.cipherSuite = it.suite[1];
     #ifdef WOLFSSL_EARLY_DATA
-                ssl->session.maxEarlyDataSz = it->maxEarlyDataSz;
+                ssl->session.maxEarlyDataSz = it.maxEarlyDataSz;
     #endif
                 /* Resumption master secret. */
-                XMEMCPY(ssl->session.masterSecret, it->msecret, SECRET_LEN);
-    #ifndef WOLFSSL_TLS13_DRAFT_18
-                XMEMCPY(&ssl->session.ticketNonce, &it->ticketNonce,
+                XMEMCPY(ssl->session.masterSecret, it.msecret, SECRET_LEN);
+                XMEMCPY(&ssl->session.ticketNonce, &it.ticketNonce,
                                                            sizeof(TicketNonce));
-    #endif
-                ssl->session.namedGroup = it->namedGroup;
-#endif
-            }
-        }
+                ssl->session.namedGroup = it.namedGroup;
+#endif
+            }
+        }
+
+        ForceZero(&it, sizeof(it));
 
         WOLFSSL_LEAVE("DoClientTicket", ret);
@@ -27802,4 +29149,8 @@
         #endif
         }
+
+        if (IsEncryptionOn(ssl, 1) && ssl->options.handShakeDone)
+            sendSz += cipherExtraData(ssl);
+
         /* check for available size */
         if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
@@ -27826,13 +29177,17 @@
         if (IsEncryptionOn(ssl, 1) && ssl->options.handShakeDone) {
             byte* input;
-            int   inputSz = idx - RECORD_HEADER_SZ; /* build msg adds rec hdr */
-
+            int   inputSz = idx; /* build msg adds rec hdr */
+            int   recordHeaderSz = RECORD_HEADER_SZ;
+
+            if (ssl->options.dtls)
+                recordHeaderSz += DTLS_RECORD_EXTRA;
+            inputSz -= recordHeaderSz;
             input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
             if (input == NULL)
                 return MEMORY_E;
 
-            XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+            XMEMCPY(input, output + recordHeaderSz, inputSz);
             sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
-                                  handshake, 1, 0, 0);
+                                  handshake, 1, 0, 0, CUR_ORDER);
             XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
 
@@ -27843,5 +29198,5 @@
             #ifdef WOLFSSL_DTLS
             if (ssl->options.dtls) {
-                if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0)
+                if ((ret = DtlsMsgPoolSave(ssl, output, sendSz, session_ticket)) != 0)
                     return ret;
 
@@ -27856,5 +29211,6 @@
         ssl->buffers.outputBuffer.length += sendSz;
 
-        ret = SendBuffered(ssl);
+        if (!ssl->options.groupMessages)
+            ret = SendBuffered(ssl);
 
         WOLFSSL_LEAVE("SendTicket", ret);
@@ -27863,4 +29219,433 @@
         return ret;
     }
+
+#ifndef WOLFSSL_NO_DEF_TICKET_ENC_CB
+
+/* Initialize the context for session ticket encryption.
+ *
+ * @param [in]  ctx     SSL context.
+ * @param [in]  keyCtx  Context for session ticket encryption.
+ * @return  0 on success.
+ * @return  BAD_MUTEX_E when initializing mutex fails.
+ */
+static int TicketEncCbCtx_Init(WOLFSSL_CTX* ctx, TicketEncCbCtx* keyCtx)
+{
+    int ret = 0;
+
+    XMEMSET(keyCtx, 0, sizeof(*keyCtx));
+    keyCtx->ctx = ctx;
+
+#ifndef SINGLE_THREADED
+    ret = wc_InitMutex(&keyCtx->mutex);
+#endif
+
+    return ret;
+}
+
+/* Setup the session ticket encryption context for this.
+ *
+ * Initialize RNG, generate name, generate primeary key and set primary key
+ * expirary.
+ *
+ * @param [in]  keyCtx  Context for session ticket encryption.
+ * @param [in]  heap    Dynamic memory allocation hint.
+ * @param [in]  devId   Device identifier.
+ * @return  0 on success.
+ * @return  Other value when random number generator fails.
+ */
+static int TicketEncCbCtx_Setup(TicketEncCbCtx* keyCtx, void* heap, int devId)
+{
+    int ret;
+
+#ifndef SINGLE_THREADED
+    ret = 0;
+
+    /* Check that key wasn't set up while waiting. */
+    if (keyCtx->expirary[0] == 0)
+#endif
+    {
+        ret = wc_InitRng_ex(&keyCtx->rng, heap, devId);
+        if (ret == 0) {
+            ret = wc_RNG_GenerateBlock(&keyCtx->rng, keyCtx->name,
+                                       sizeof(keyCtx->name));
+        }
+        if (ret == 0) {
+            /* Mask of the bottom bit - used for index of key. */
+            keyCtx->name[WOLFSSL_TICKET_NAME_SZ - 1] &= 0xfe;
+
+            /* Generate initial primary key. */
+            ret = wc_RNG_GenerateBlock(&keyCtx->rng, keyCtx->key[0],
+                                       WOLFSSL_TICKET_KEY_SZ);
+        }
+        if (ret == 0) {
+            keyCtx->expirary[0] = LowResTimer() + WOLFSSL_TICKET_KEY_LIFETIME;
+        }
+    }
+
+    return ret;
+}
+/* Free the context for session ticket encryption.
+ *
+ * Zeroize keys and name.
+ *
+ * @param [in]  keyCtx  Context for session ticket encryption.
+ */
+static void TicketEncCbCtx_Free(TicketEncCbCtx* keyCtx)
+{
+    /* Zeroize sensitive data. */
+    ForceZero(keyCtx->name, sizeof(keyCtx->name));
+    ForceZero(keyCtx->key[0], sizeof(keyCtx->key[0]));
+    ForceZero(keyCtx->key[1], sizeof(keyCtx->key[1]));
+
+#ifndef SINGLE_THREADED
+    wc_FreeMutex(&keyCtx->mutex);
+#endif
+    wc_FreeRng(&keyCtx->rng);
+}
+
+#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && \
+    !defined(WOLFSSL_TICKET_ENC_AES128_GCM) && \
+    !defined(WOLFSSL_TICKET_ENC_AES256_GCM)
+/* Ticket encryption/decryption implementation.
+ *
+ * @param [in]   key     Key for encryption/decryption.
+ * @param [in]   keyLen  Length of key in bytes.
+ * @param [in]   iv      IV/Nonce for encryption/decryption.
+ * @param [in]   aad     Additional authentication data.
+ * @param [in]   aadSz   Length of additional authentication data.
+ * @param [in]   in      Data to encrypt/decrypt.
+ * @param [in]   inLen   Length of encrypted data.
+ * @param [out]  out     Resulting data from encrypt/decrypt.
+ * @param [out]  outLen  Size of resulting data.
+ * @param [in]   tag     Authentication tag for encrypted data.
+ * @param [in]   heap    Dynamic memory allocation data hint.
+ * @param [in]   enc     1 when encrypting, 0 when decrypting.
+ * @return  0 on success.
+ * @return  Other value when encryption/decryption fails.
+ */
+static int TicketEncDec(byte* key, int keyLen, byte* iv, byte* aad, int aadSz,
+                        byte* in, int inLen, byte* out, int* outLen, byte* tag,
+                        void* heap, int enc)
+{
+    int ret;
+
+    (void)keyLen;
+    (void)heap;
+
+    if (enc) {
+        ret = wc_ChaCha20Poly1305_Encrypt(key, iv, aad, aadSz, in, inLen, out,
+                                          tag);
+    }
+    else {
+        ret = wc_ChaCha20Poly1305_Decrypt(key, iv, aad, aadSz, in, inLen, tag,
+                                          out);
+    }
+
+    *outLen = inLen;
+
+    return ret;
+}
+#elif defined(HAVE_AESGCM)
+/* Ticket encryption/decryption implementation.
+ *
+ * @param [in]   key     Key for encryption/decryption.
+ * @param [in]   keyLen  Length of key in bytes.
+ * @param [in]   iv      IV/Nonce for encryption/decryption.
+ * @param [in]   aad     Additional authentication data.
+ * @param [in]   aadSz   Length of additional authentication data.
+ * @param [in]   in      Data to encrypt/decrypt.
+ * @param [in]   inLen   Length of encrypted data.
+ * @param [out]  out     Resulting data from encrypt/decrypt.
+ * @param [out]  outLen  Size of resulting data.
+ * @param [in]   tag     Authentication tag for encrypted data.
+ * @param [in]   heap    Dynamic memory allocation data hint.
+ * @param [in]   enc     1 when encrypting, 0 when decrypting.
+ * @return  0 on success.
+ * @return  MEMORY_E when dynamic memory allocation fails.
+ * @return  Other value when encryption/decryption fails.
+ */
+static int TicketEncDec(byte* key, int keyLen, byte* iv, byte* aad, int aadSz,
+                        byte* in, int inLen, byte* out, int* outLen, byte* tag,
+                        void* heap, int enc)
+{
+    int ret;
+#ifdef WOLFSSL_SMALL_STACK
+    Aes* aes;
+#else
+    Aes aes[1];
+#endif
+
+    (void)heap;
+
+#ifdef WOLFSSL_SMALL_STACK
+    aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (aes == NULL)
+        return MEMORY_E;
+#endif
+
+    if (enc) {
+        ret = wc_AesInit(aes, NULL, INVALID_DEVID);
+        if (ret == 0) {
+            ret = wc_AesGcmSetKey(aes, key, keyLen);
+        }
+        if (ret == 0) {
+            ret = wc_AesGcmEncrypt(aes, in, out, inLen, iv, GCM_NONCE_MID_SZ,
+                                   tag, AES_BLOCK_SIZE, aad, aadSz);
+        }
+        wc_AesFree(aes);
+    }
+    else {
+        ret = wc_AesInit(aes, NULL, INVALID_DEVID);
+        if (ret == 0) {
+            ret = wc_AesGcmSetKey(aes, key, keyLen);
+        }
+        if (ret == 0) {
+            ret = wc_AesGcmDecrypt(aes, in, out, inLen, iv, GCM_NONCE_MID_SZ,
+                                   tag, AES_BLOCK_SIZE, aad, aadSz);
+        }
+        wc_AesFree(aes);
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(aes, heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    *outLen = inLen;
+
+    return ret;
+}
+#else
+    #error "No encryption algorithm available for default ticket encryption."
+#endif
+
+/* Choose a key to use for encryption.
+ *
+ * Generate a new key if the current ones are expired.
+ * If the secondary key has not been used and the primary key has expired then
+ * generate a new primary key.
+ * 
+ * @param [in]   Ticket encryption callback context.
+ * @param [in]   Session ticket lifetime.
+ * @param [out]  Index of key to use for encryption.
+ * @return  0 on success.
+ * @return  Other value when random number generation fails.
+ */
+static int TicketEncCbCtx_ChooseKey(TicketEncCbCtx* keyCtx, int ticketHint,
+                                    int* keyIdx)
+{
+    int ret = 0;
+
+    /* Get new current time as lock may have taken some time. */
+    word32 now = LowResTimer();
+
+    /* Check expirary of primary key for encrypt. */
+    if (keyCtx->expirary[0] >= now + ticketHint) {
+        *keyIdx = 0;
+    }
+    /* Check expirary of primary key for encrypt. */
+    else if (keyCtx->expirary[1] >= now + ticketHint) {
+        *keyIdx = 1;
+    }
+    /* No key available to use. */
+    else {
+        int genKey;
+
+        /* Generate which ever key is expired for decrypt - primary first. */
+        if (keyCtx->expirary[0] < now) {
+            genKey = 0;
+        }
+        else if (keyCtx->expirary[1] < now) {
+            genKey = 1;
+        }
+        /* Timeouts and expirary should not allow this to happen. */
+        else {
+            return BAD_STATE_E;
+        }
+
+        /* Generate the required key */
+        ret = wc_RNG_GenerateBlock(&keyCtx->rng, keyCtx->key[genKey],
+                                   WOLFSSL_TICKET_KEY_SZ);
+        if (ret == 0) {
+            keyCtx->expirary[genKey] = now + WOLFSSL_TICKET_KEY_LIFETIME;
+            *keyIdx = genKey;
+        }
+    }
+
+    return ret;
+}
+
+/* Default Session Ticket encryption/decryption callback.
+ *
+ * Use ChaCha20-Poly1305 or AES-GCM to encrypt/decrypt the ticket.
+ * Two keys are used:
+ *  - When the first expires for encryption, then use the other.
+ *  - Don't encrypt with key if the ticket lifetime will go beyond expirary.
+ *  - Generate a new primary key when primary key expired for decrypt and
+ *    no secondary key is activate for encryption.
+ *  - Generate a new secondary key when expired and needed.
+ *  - Calculate expirary starting from first encrypted ticket.
+ *  - Key name has last bit set to indicate index of key.
+ * Keys expire for decryption after ticket key lifetime from the first encrypted
+ * ticket.
+ * Keys can only be use for encryption while the ticket hint does not exceed
+ * the key lifetime.
+ * Lifetime of a key must be greater than the lifetime of a ticket. This means
+ * that if one ticket is only valid for decryption, then the other will be
+ * valid for encryption.
+ * AAD = key_name | iv | ticket len (16-bits network order)
+ *
+ * @param [in]      ssl       SSL connection.
+ * @param [in,out]  key_name  Name of key from client.
+ *                            Encrypt: name of key returned.
+ *                            Decrypt: name from ticket message to check.
+ * @param [in]      iv        IV to use in encryption/decryption.
+ * @param [in]      mac       MAC for authentication of encrypted data.
+ * @param [in]      enc       1 when encrypting ticket, 0 when decrypting.
+ * @param [in,out]  ticket    Encrypted/decrypted session ticket bytes.
+ * @param [in]      inLen     Length of incoming ticket.
+ * @param [out]     outLen    Length of outgoing ticket.
+ * @param [in]      userCtx   Context for encryption/decryption of ticket.
+ * @return  WOLFSSL_TICKET_RET_OK when successful.
+ * @return  WOLFSSL_TICKET_RET_CREATE when successful and a new ticket is to
+ *          be created for TLS 1.2 and below.
+ * @return  WOLFSSL_TICKET_RET_REJECT when failed to produce valid encrypted or
+ *          decrypted ticket.
+ * @return  WOLFSSL_TICKET_RET_FATAL when key name does not match.
+ */
+static int DefTicketEncCb(WOLFSSL* ssl, byte key_name[WOLFSSL_TICKET_NAME_SZ],
+                          byte iv[WOLFSSL_TICKET_IV_SZ],
+                          byte mac[WOLFSSL_TICKET_MAC_SZ],
+                          int enc, byte* ticket, int inLen, int* outLen,
+                          void* userCtx)
+{
+    int ret;
+    TicketEncCbCtx* keyCtx = (TicketEncCbCtx*)userCtx;
+    WOLFSSL_CTX* ctx = keyCtx->ctx;
+    word16 sLen = XHTONS(inLen);
+    byte aad[WOLFSSL_TICKET_NAME_SZ + WOLFSSL_TICKET_IV_SZ + sizeof(sLen)];
+    int  aadSz = WOLFSSL_TICKET_NAME_SZ + WOLFSSL_TICKET_IV_SZ + sizeof(sLen);
+    byte* p = aad;
+    int keyIdx = 0;
+
+    /* Check we have setup the RNG, name and primary key. */
+    if (keyCtx->expirary[0] == 0) {
+#ifndef SINGLE_THREADED
+        /* Lock around access to expirary and key - stop initial key being
+         * generated twice at the same time. */
+        if (wc_LockMutex(&keyCtx->mutex) != 0) {
+            WOLFSSL_MSG("Couldn't lock key context mutex");
+            return WOLFSSL_TICKET_RET_REJECT;
+        }
+#endif
+        /* Sets expirary of primary key in setup. */
+        ret = TicketEncCbCtx_Setup(keyCtx, ssl->ctx->heap, ssl->ctx->devId);
+#ifndef SINGLE_THREADED
+        wc_UnLockMutex(&keyCtx->mutex);
+#endif
+        if (ret != 0)
+            return ret;
+    }
+
+    if (enc) {
+        /* Return the name of the key - missing key index. */
+        XMEMCPY(key_name, keyCtx->name, WOLFSSL_TICKET_NAME_SZ);
+
+        /* Generate a new IV into buffer to be returned.
+         * Don't use the RNG in keyCtx as it's for generating private data. */
+        ret = wc_RNG_GenerateBlock(ssl->rng, iv, WOLFSSL_TICKET_IV_SZ);
+        if (ret != 0) {
+            return WOLFSSL_TICKET_RET_REJECT;
+        }
+    }
+    else {
+        /* Mask of last bit that is the key index. */
+        byte lastByte = key_name[WOLFSSL_TICKET_NAME_SZ - 1] & 0xfe;
+
+        /* For decryption, see if we know this key - check all but last byte. */
+        if (XMEMCMP(key_name, keyCtx->name, WOLFSSL_TICKET_NAME_SZ - 1) != 0) {
+            return WOLFSSL_TICKET_RET_FATAL;
+        }
+        /* Ensure last byte without index bit matches too. */
+        if (lastByte != keyCtx->name[WOLFSSL_TICKET_NAME_SZ - 1]) {
+            return WOLFSSL_TICKET_RET_FATAL;
+        }
+    }
+
+    /* Build AAD from: key name, iv, and length of ticket. */
+    XMEMCPY(p, keyCtx->name, WOLFSSL_TICKET_NAME_SZ);
+    p += WOLFSSL_TICKET_NAME_SZ;
+    XMEMCPY(p, iv, WOLFSSL_TICKET_IV_SZ);
+    p += WOLFSSL_TICKET_IV_SZ;
+    XMEMCPY(p, &sLen, sizeof(sLen));
+
+    /* Encrypt ticket. */
+    if (enc) {
+        word32 now;
+
+        now = LowResTimer();
+        /* As long as encryption expirary isn't imminent - no lock. */
+        if (keyCtx->expirary[0] > now + ctx->ticketHint) {
+            keyIdx = 0;
+        }
+        else if (keyCtx->expirary[1] > now + ctx->ticketHint) {
+            keyIdx = 1;
+        }
+        else {
+#ifndef SINGLE_THREADED
+            /* Lock around access to expirary and key - stop key being generated
+             * twice at the same time. */
+            if (wc_LockMutex(&keyCtx->mutex) != 0) {
+                WOLFSSL_MSG("Couldn't lock key context mutex");
+                return WOLFSSL_TICKET_RET_REJECT;
+            }
+#endif
+            ret = TicketEncCbCtx_ChooseKey(keyCtx, ctx->ticketHint, &keyIdx);
+#ifndef SINGLE_THREADED
+            wc_UnLockMutex(&keyCtx->mutex);
+#endif
+            if (ret != 0) {
+                return WOLFSSL_TICKET_RET_REJECT;
+            }
+        }
+        /* Set the name of the key to the index chosen. */
+        key_name[WOLFSSL_TICKET_NAME_SZ - 1] |= keyIdx;
+        /* Update AAD too. */
+        aad[WOLFSSL_TICKET_NAME_SZ - 1] |= keyIdx;
+
+        /* Encrypt ticket data. */
+        ret = TicketEncDec(keyCtx->key[keyIdx], WOLFSSL_TICKET_KEY_SZ, iv, aad,
+                           aadSz, ticket, inLen, ticket, outLen, mac, ssl->heap,
+                           1);
+        if (ret != 0) return WOLFSSL_TICKET_RET_REJECT;
+    }
+    /* Decrypt ticket. */
+    else {
+        /* Get index of key from name. */
+        keyIdx = key_name[WOLFSSL_TICKET_NAME_SZ - 1] & 0x1;
+        /* Update AAD with index. */
+        aad[WOLFSSL_TICKET_NAME_SZ - 1] |= keyIdx;
+
+        /* Check expirary */
+        if (keyCtx->expirary[keyIdx] <= LowResTimer()) {
+            return WOLFSSL_TICKET_RET_REJECT;
+        }
+
+        /* Decrypt ticket data. */
+        ret = TicketEncDec(keyCtx->key[keyIdx], WOLFSSL_TICKET_KEY_SZ, iv, aad,
+                           aadSz, ticket, inLen, ticket, outLen, mac, ssl->heap,
+                           0);
+        if (ret != 0) {
+            return WOLFSSL_TICKET_RET_REJECT;
+        }
+    }
+
+#ifndef WOLFSSL_TICKET_DECRYPT_NO_CREATE
+    if (!IsAtLeastTLSv1_3(ssl->version) && !enc)
+        return WOLFSSL_TICKET_RET_CREATE;
+#endif
+    return WOLFSSL_TICKET_RET_OK;
+}
+
+#endif /* !WOLFSSL_NO_DEF_TICKET_ENC_CB */
 
 #endif /* HAVE_SESSION_TICKET */
@@ -27885,4 +29670,7 @@
             sendSz += MAX_MSG_EXTRA;
 
+        if (ssl->options.dtls)
+            sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+
         /* check for available size */
         if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
@@ -27898,4 +29686,10 @@
             byte* input;
             int   inputSz = HANDSHAKE_HEADER_SZ; /* build msg adds rec hdr */
+            int   recordHeaderSz = RECORD_HEADER_SZ;
+
+            if (ssl->options.dtls) {
+                recordHeaderSz += DTLS_RECORD_EXTRA;
+                inputSz += DTLS_HANDSHAKE_EXTRA;
+            }
 
             input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
@@ -27903,7 +29697,14 @@
                 return MEMORY_E;
 
-            XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+            XMEMCPY(input, output + recordHeaderSz, inputSz);
+            #ifdef WOLFSSL_DTLS
+            if (IsDtlsNotSctpMode(ssl) &&
+                    (ret = DtlsMsgPoolSave(ssl, input, inputSz, hello_request)) != 0) {
+                XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+                return ret;
+            }
+            #endif
             sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
-                                  handshake, 0, 0, 0);
+                                  handshake, 0, 0, 0, CUR_ORDER);
             XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
 
@@ -27935,4 +29736,9 @@
         int   ret;
 
+        /* are we in scr */
+        if (IsEncryptionOn(ssl, 1)) {
+            sendSz += MAX_MSG_EXTRA;
+        }
+
         /* check for available size */
         if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
@@ -27970,4 +29776,28 @@
                           sendSz, WRITE_PROTO, ssl->heap);
 #endif
+
+        /* are we in scr */
+        if (IsEncryptionOn(ssl, 1)) {
+            byte* input;
+            int   inputSz = HANDSHAKE_HEADER_SZ + length; /* build msg adds rec hdr */
+            int   recordHeaderSz = RECORD_HEADER_SZ;
+
+            if (ssl->options.dtls) {
+                recordHeaderSz += DTLS_RECORD_EXTRA;
+                inputSz += DTLS_HANDSHAKE_EXTRA;
+            }
+
+            input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+            if (input == NULL)
+                return MEMORY_E;
+
+            XMEMCPY(input, output + recordHeaderSz, inputSz);
+            sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
+                                  handshake, 0, 0, 0, CUR_ORDER);
+            XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+
+            if (sendSz < 0)
+                return sendSz;
+        }
 
         ssl->buffers.outputBuffer.length += sendSz;
@@ -28054,5 +29884,5 @@
                 }
 
-            #ifndef NO_CERTS
+            #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH)
                 if (ssl->options.verifyPeer && ssl->options.failNoCert) {
                     if (!ssl->options.havePeerCert) {
@@ -28069,5 +29899,5 @@
                     }
                 }
-            #endif /* !NO_CERTS */
+            #endif /* !NO_CERTS && !WOLFSSL_NO_CLIENT_AUTH */
 
             #if defined(WOLFSSL_CALLBACKS)
@@ -28254,4 +30084,9 @@
                         if (ssl->arrays->psk_keySz == 0 ||
                                 ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) {
+                            #if defined(WOLFSSL_EXTRA_ALERTS) || \
+                                defined(WOLFSSL_PSK_IDENTITY_ALERT)
+                                SendAlert(ssl, alert_fatal,
+                                        unknown_psk_identity);
+                            #endif
                             ERROR_OUT(PSK_KEY_ERROR, exit_dcke);
                         }
@@ -28507,4 +30342,11 @@
 
                         ssl->peerEccKeyPresent = 1;
+
+                    #if defined(WOLFSSL_TLS13) || defined(HAVE_FFDHE)
+                        /* client_hello may have sent FFEDH2048, which sets namedGroup,
+                            but that is not being used, so clear it */
+                        /* resolves issue with server side wolfSSL_get_curve_name */
+                        ssl->namedGroup = 0;
+                    #endif
                 #endif /* HAVE_ECC */
 
@@ -29127,4 +30969,9 @@
                         if (ssl->arrays->psk_keySz == 0 ||
                                 ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) {
+                            #if defined(WOLFSSL_EXTRA_ALERTS) || \
+                                defined(WOLFSSL_PSK_IDENTITY_ALERT)
+                                SendAlert(ssl, alert_fatal,
+                                        unknown_psk_identity);
+                            #endif
                             ERROR_OUT(PSK_KEY_ERROR, exit_dcke);
                         }
@@ -29242,5 +31089,5 @@
 
                 ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
-            #ifndef NO_CERTS
+            #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH)
                 if (ssl->options.verifyPeer) {
                     ret = BuildCertHashes(ssl, &ssl->hsHashes->certHashes);
@@ -29283,6 +31130,5 @@
 #endif /* !WOLFSSL_NO_TLS12 */
 
-#if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \
-    defined(WOLFSSL_HAPROXY)
+#ifdef HAVE_SNI
     int SNI_Callback(WOLFSSL* ssl)
     {
@@ -29300,5 +31146,5 @@
         return 0;
     }
-#endif /* OPENSSL_ALL || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */
+#endif /* HAVE_SNI */
 
 #endif /* NO_WOLFSSL_SERVER */
@@ -29412,6 +31258,14 @@
 #endif /* HAVE_MAX_FRAGMENT */
 #ifdef WOLFSSL_DTLS
-    if ((ssl->options.dtls) && (maxFragment > MAX_UDP_SIZE)) {
-        maxFragment = MAX_UDP_SIZE;
+    if (IsDtlsNotSctpMode(ssl)) {
+        if (maxFragment > MAX_UDP_SIZE) {
+            maxFragment = MAX_UDP_SIZE;
+        }
+    #if defined(WOLFSSL_DTLS_MTU)
+        if (maxFragment >
+                        ssl->dtlsMtuSz - RECORD_HEADER_SZ - DTLS_RECORD_EXTRA) {
+            maxFragment = ssl->dtlsMtuSz - RECORD_HEADER_SZ - DTLS_RECORD_EXTRA;
+        }
+    #endif
     }
 #endif
