Index: azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/bio.c
===================================================================
--- azure_iot_hub_f767zi/trunk/wolfssl-4.4.0/src/bio.c	(revision 457)
+++ azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/bio.c	(revision 464)
@@ -160,20 +160,18 @@
 static int wolfSSL_BIO_MD_read(WOLFSSL_BIO* bio, void* buf, int sz)
 {
-    int ret = sz;
-
     if (wolfSSL_EVP_MD_CTX_type((WOLFSSL_EVP_MD_CTX*)bio->ptr) == NID_hmac) {
         if (wolfSSL_EVP_DigestSignUpdate((WOLFSSL_EVP_MD_CTX*)bio->ptr, buf,
                         sz) != WOLFSSL_SUCCESS)
         {
-            ret = WOLFSSL_FATAL_ERROR;
+            return WOLFSSL_FATAL_ERROR;
         }
     }
     else {
-        if (wolfSSL_EVP_DigestUpdate((WOLFSSL_EVP_MD_CTX*)bio->ptr, buf, ret)
+        if (wolfSSL_EVP_DigestUpdate((WOLFSSL_EVP_MD_CTX*)bio->ptr, buf, sz)
                 != WOLFSSL_SUCCESS) {
-            ret = WOLFSSL_FATAL_ERROR;
-        }
-    }
-    return ret;
+            return WOLFSSL_FATAL_ERROR;
+        }
+    }
+    return sz;
 }
 #endif /* WOLFCRYPT_ONLY */
@@ -232,5 +230,11 @@
     #ifndef NO_FILESYSTEM
         if (bio && bio->type == WOLFSSL_BIO_FILE) {
-            ret = (int)XFREAD(buf, 1, len, (XFILE)bio->ptr);
+            if (bio->ptr)
+                ret = (int)XFREAD(buf, 1, len, (XFILE)bio->ptr);
+        #if !defined(USE_WINDOWS_API) && !defined(NO_WOLFSSL_DIR)\
+            && !defined(WOLFSSL_NUCLEUS) && !defined(WOLFSSL_NUCLEUS_1_2)
+            else
+                ret = (int)XREAD(bio->num, buf, len);
+        #endif
         }
     #endif
@@ -574,9 +578,9 @@
 
         /* write bios */
-        if (bio && bio->type == WOLFSSL_BIO_BIO) {
+        if (bio->type == WOLFSSL_BIO_BIO) {
             ret = wolfSSL_BIO_BIO_write(bio, data, len);
         }
 
-        if (bio && bio->type == WOLFSSL_BIO_MEMORY) {
+        if (bio->type == WOLFSSL_BIO_MEMORY) {
             ret = wolfSSL_BIO_MEMORY_write(bio, data, len);
         }
@@ -584,10 +588,16 @@
     #ifndef NO_FILESYSTEM
         if (bio && bio->type == WOLFSSL_BIO_FILE) {
-            ret = (int)XFWRITE(data, 1, len, (XFILE)bio->ptr);
+            if (bio->ptr)
+                ret = (int)XFWRITE(data, 1, len, (XFILE)bio->ptr);
+        #if !defined(USE_WINDOWS_API) && !defined(NO_WOLFSSL_DIR)\
+            && !defined(WOLFSSL_NUCLEUS) && !defined(WOLFSSL_NUCLEUS_1_2)
+            else
+                ret = (int)XWRITE(bio->num, data, len);
+        #endif
         }
     #endif
 
     #ifndef WOLFCRYPT_ONLY
-        if (bio && bio->type == WOLFSSL_BIO_SSL) {
+        if (bio->type == WOLFSSL_BIO_SSL) {
             /* already got eof, again is error */
             if (front->eof) {
@@ -599,5 +609,5 @@
         }
 
-        if (bio && bio->type == WOLFSSL_BIO_MD) {
+        if (bio->type == WOLFSSL_BIO_MD) {
             if (bio->next != NULL) { /* data passing through MD BIO */
                 ret = wolfSSL_BIO_MD_write(bio, data, len);
@@ -608,8 +618,4 @@
         /* advance to the next bio in list */
         bio = bio->next;
-    }
-
-    if (frmt != NULL) {
-        XFREE(frmt, front->heap, DYNAMIC_TYPE_TMP_BUFFER);
     }
 
@@ -619,4 +625,8 @@
                                  WOLFSSL_BIO_CB_WRITE | WOLFSSL_BIO_CB_RETURN,
                                  (const char*)data, 0, 0, ret);
+    }
+
+    if (frmt != NULL) {
+        XFREE(frmt, front->heap, DYNAMIC_TYPE_TMP_BUFFER);
     }
 
@@ -943,9 +953,11 @@
     }
 
-    if (bio->type == WOLFSSL_BIO_MD) {
-        /* MD is a wrapper only get next bio */
+    if (bio->type == WOLFSSL_BIO_MD ||
+            bio->type == WOLFSSL_BIO_BASE64) {
+        /* these are wrappers only, get next bio */
         while (bio->next != NULL) {
             bio = bio->next;
-            if (bio->type != WOLFSSL_BIO_MD) {
+            if (bio->type == WOLFSSL_BIO_MD ||
+                    bio->type == WOLFSSL_BIO_BASE64) {
                 break;
             }
@@ -1308,4 +1320,5 @@
                 const WOLFSSL_EVP_MD* md =
                     wolfSSL_EVP_MD_CTX_md((WOLFSSL_EVP_MD_CTX*)bio->ptr);
+                wolfSSL_EVP_MD_CTX_cleanup((WOLFSSL_EVP_MD_CTX*)bio->ptr);
                 wolfSSL_EVP_MD_CTX_init((WOLFSSL_EVP_MD_CTX*)bio->ptr);
                 wolfSSL_EVP_DigestInit((WOLFSSL_EVP_MD_CTX*)bio->ptr, md);
@@ -1322,4 +1335,29 @@
 
 #ifndef NO_FILESYSTEM
+/**
+ * Creates a new file BIO object
+ * @param fd file descriptor for to use for the new object
+ * @param close_flag BIO_NOCLOSE or BIO_CLOSE
+ * @return New BIO object or NULL on failure
+ */
+WOLFSSL_BIO *wolfSSL_BIO_new_fd(int fd, int close_flag)
+{
+    WOLFSSL_BIO* bio;
+
+    bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file());
+    if (!bio) {
+        WOLFSSL_MSG("wolfSSL_BIO_new error");
+        return NULL;
+    }
+
+    if (wolfSSL_BIO_set_fd(bio, fd, close_flag) != WOLFSSL_SUCCESS) {
+        wolfSSL_BIO_free(bio);
+        WOLFSSL_MSG("wolfSSL_BIO_set_fp error");
+        return NULL;
+    }
+
+    return bio;
+}
+
 long wolfSSL_BIO_set_fp(WOLFSSL_BIO *bio, XFILE fp, int c)
 {
@@ -1528,4 +1566,5 @@
 long wolfSSL_BIO_set_nbio(WOLFSSL_BIO* bio, long on)
 {
+    int ret = 0;
     #ifndef WOLFSSL_DTLS
     (void)on;
@@ -1539,7 +1578,7 @@
                 int flag = XFCNTL(bio->num, F_GETFL, 0);
                 if (on)
-                    XFCNTL(bio->num, F_SETFL, flag | O_NONBLOCK);
+                    ret = XFCNTL(bio->num, F_SETFL, flag | O_NONBLOCK);
                 else
-                    XFCNTL(bio->num, F_SETFL, flag & ~O_NONBLOCK);
+                    ret = XFCNTL(bio->num, F_SETFL, flag & ~O_NONBLOCK);
             }
         #endif
@@ -1555,6 +1594,8 @@
             break;
     }
-
-    return 1;
+    if (ret != -1)
+        return 1;
+    else
+        return 0;
 }
 
@@ -1678,4 +1719,5 @@
 int wolfSSL_BIO_get_mem_data(WOLFSSL_BIO* bio, void* p)
 {
+    WOLFSSL_BIO* mem_bio;
     WOLFSSL_ENTER("wolfSSL_BIO_get_mem_data");
 
@@ -1683,9 +1725,17 @@
         return WOLFSSL_FATAL_ERROR;
 
+    mem_bio = bio;
+    /* Return pointer from last memory BIO in chain */
+    while (bio->next) {
+        bio = bio->next;
+        if (bio->type == WOLFSSL_BIO_MEMORY)
+            mem_bio = bio;
+    }
+
     if (p) {
-        *(byte**)p = (byte*)bio->ptr;
-    }
-
-    return bio->num;
+        *(byte**)p = (byte*)mem_bio->ptr;
+    }
+
+    return mem_bio->num;
 }
 
Index: azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/crl.c
===================================================================
--- azure_iot_hub_f767zi/trunk/wolfssl-4.4.0/src/crl.c	(revision 457)
+++ azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/crl.c	(revision 464)
@@ -35,5 +35,7 @@
 #include <wolfssl/error-ssl.h>
 
-#include <string.h>
+#ifndef WOLFSSL_LINUXKM
+    #include <string.h>
+#endif
 
 #ifdef HAVE_CRL_MONITOR
@@ -491,25 +493,254 @@
 
 #if defined(OPENSSL_EXTRA) && defined(HAVE_CRL)
+/* helper function to create a new dynamic WOLFSSL_X509_CRL structure */
+static WOLFSSL_X509_CRL* wolfSSL_X509_crl_new(WOLFSSL_CERT_MANAGER* cm)
+{
+    WOLFSSL_X509_CRL* ret;
+
+    ret = (WOLFSSL_X509_CRL*)XMALLOC(sizeof(WOLFSSL_X509_CRL), cm->heap,
+                DYNAMIC_TYPE_CRL);
+    if (ret != NULL) {
+        if (InitCRL(ret, cm) < 0) {
+            WOLFSSL_MSG("Unable to initialize new CRL structure");
+            XFREE(ret, cm->heap, DYNAMIC_TYPE_CRL);
+            ret = NULL;
+        }
+    }
+    return ret;
+}
+
+
+/* returns head of copied list that was alloc'd */
+static RevokedCert *DupRevokedCertList(RevokedCert* in, void* heap)
+{
+    RevokedCert* head = NULL;
+    RevokedCert* current = in;
+    RevokedCert* prev = NULL;
+    while (current) {
+        RevokedCert* tmp = (RevokedCert*)XMALLOC(sizeof(RevokedCert), heap,
+                DYNAMIC_TYPE_REVOKED);
+        if (tmp != NULL) {
+            XMEMCPY(tmp->serialNumber, current->serialNumber,
+                    EXTERNAL_SERIAL_SIZE);
+            tmp->serialSz = current->serialSz;
+            tmp->next = NULL;
+            if (prev != NULL)
+                prev->next = tmp;
+            if (head == NULL)
+                head = tmp;
+            prev = tmp;
+        }
+        else {
+            WOLFSSL_MSG("Failed to allocate new RevokedCert structure");
+            /* free up any existing list */
+            while (head != NULL) {
+                current = head;
+                head = head->next;
+                XFREE(current, heap, DYNAMIC_TYPE_REVOKED);
+            }
+            return NULL;
+        }
+        current = current->next;
+    }
+
+    (void)heap;
+    return head;
+}
+
+
+/* returns a deep copy of ent on success and null on fail */
+static CRL_Entry* DupCRL_Entry(const CRL_Entry* ent, void* heap)
+{
+    CRL_Entry *dupl;
+
+    dupl = (CRL_Entry*)XMALLOC(sizeof(CRL_Entry), heap, DYNAMIC_TYPE_CRL_ENTRY);
+    if (dupl == NULL) {
+        WOLFSSL_MSG("alloc CRL Entry failed");
+        return NULL;
+    }
+    XMEMSET(dupl, 0, sizeof(CRL_Entry));
+
+    XMEMCPY(dupl->issuerHash, ent->issuerHash, CRL_DIGEST_SIZE);
+    XMEMCPY(dupl->lastDate, ent->lastDate, MAX_DATE_SIZE);
+    XMEMCPY(dupl->nextDate, ent->nextDate, MAX_DATE_SIZE);
+    dupl->lastDateFormat = ent->lastDateFormat;
+    dupl->nextDateFormat = ent->nextDateFormat;
+    dupl->certs = DupRevokedCertList(ent->certs, heap);
+
+    dupl->totalCerts = ent->totalCerts;
+    dupl->verified = ent->verified;
+
+    if (!ent->verified) {
+        dupl->tbsSz = ent->tbsSz;
+        dupl->signatureSz = ent->signatureSz;
+        dupl->signatureOID = ent->signatureOID;
+        dupl->toBeSigned = (byte*)XMALLOC(dupl->tbsSz, heap,
+                                          DYNAMIC_TYPE_CRL_ENTRY);
+        if (dupl->toBeSigned == NULL) {
+            FreeCRL_Entry(dupl, heap);
+            XFREE(dupl, heap, DYNAMIC_TYPE_CRL_ENTRY);
+            return NULL;
+        }
+
+        dupl->signature = (byte*)XMALLOC(dupl->signatureSz, heap,
+                                         DYNAMIC_TYPE_CRL_ENTRY);
+        if (dupl->signature == NULL) {
+            FreeCRL_Entry(dupl, heap);
+            XFREE(dupl, heap, DYNAMIC_TYPE_CRL_ENTRY);
+            return NULL;
+        }
+        XMEMCPY(dupl->toBeSigned, ent->toBeSigned, dupl->tbsSz);
+        XMEMCPY(dupl->signature, ent->signature, dupl->signatureSz);
+    #ifndef NO_SKID
+        dupl->extAuthKeyIdSet = ent->extAuthKeyIdSet;
+        if (dupl->extAuthKeyIdSet)
+            XMEMCPY(dupl->extAuthKeyId, ent->extAuthKeyId, KEYID_SIZE);
+    #endif
+    }
+    else {
+        dupl->toBeSigned = NULL;
+        dupl->tbsSz = 0;
+        dupl->signature = NULL;
+        dupl->signatureSz = 0;
+    }
+
+    return dupl;
+}
+
+
+/* returns the head of a deep copy of the list on success and null on fail */
+static CRL_Entry* DupCRL_list(CRL_Entry* crl, void* heap)
+{
+    CRL_Entry* current;
+    CRL_Entry* head = NULL;
+    CRL_Entry* prev = NULL;
+
+    current = crl;
+    while (current != NULL) {
+        CRL_Entry* tmp = DupCRL_Entry(current, heap);
+        if (tmp != NULL) {
+            tmp->next = NULL;
+            if (head == NULL)
+                head = tmp;
+            if (prev != NULL)
+                prev->next = tmp;
+            prev = tmp;
+        }
+        else {
+            WOLFSSL_MSG("Failed to allocate new CRL_Entry structure");
+            /* free up any existing list */
+            while (head != NULL) {
+                current = head;
+                head = head->next;
+                FreeCRL_Entry(current, heap);
+            }
+
+            return NULL;
+        }
+        current = current->next;
+    }
+    return head;
+}
+
+
+/* Duplicates everything except the parent cm pointed to.
+ * Expects that Init has already been done to 'dupl'
+ * return 0 on success */
+static int DupX509_CRL(WOLFSSL_X509_CRL *dupl, const WOLFSSL_X509_CRL* crl)
+{
+    if (dupl == NULL || crl == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (crl->monitors[0].path) {
+        int pathSz = (int)XSTRLEN(crl->monitors[0].path) + 1;
+        dupl->monitors[0].path = (char*)XMALLOC(pathSz, dupl->heap,
+                DYNAMIC_TYPE_CRL_MONITOR);
+        if (dupl->monitors[0].path != NULL) {
+            XSTRNCPY(dupl->monitors[0].path, crl->monitors[0].path, pathSz);
+        }
+        else {
+            return MEMORY_E;
+        }
+    }
+
+    if (crl->monitors[1].path) {
+        int pathSz = (int)XSTRLEN(crl->monitors[1].path) + 1;
+        dupl->monitors[1].path = (char*)XMALLOC(pathSz, dupl->heap,
+                DYNAMIC_TYPE_CRL_MONITOR);
+        if (dupl->monitors[1].path != NULL) {
+            XSTRNCPY(dupl->monitors[1].path, crl->monitors[1].path, pathSz);
+        }
+        else {
+            if (dupl->monitors[0].path != NULL) {
+                XFREE(dupl->monitors[0].path, dupl->heap,
+                        DYNAMIC_TYPE_CRL_MONITOR);
+            }
+            return MEMORY_E;
+        }
+    }
+
+    dupl->crlList = DupCRL_list(crl->crlList, dupl->heap);
+#ifdef HAVE_CRL_IO
+    dupl->crlIOCb = crl->crlIOCb;
+#endif
+
+    return 0;
+}
+
+/* returns WOLFSSL_SUCCESS on success. Does not take ownership of newcrl */
 int wolfSSL_X509_STORE_add_crl(WOLFSSL_X509_STORE *store, WOLFSSL_X509_CRL *newcrl)
 {
     CRL_Entry   *crle;
-    WOLFSSL_CRL *crl;
+    WOLFSSL_X509_CRL *crl;
 
     WOLFSSL_ENTER("wolfSSL_X509_STORE_add_crl");
-    if (store == NULL || newcrl == NULL)
+    if (store == NULL || newcrl == NULL || store->cm == NULL)
         return BAD_FUNC_ARG;
 
-    crl = store->crl;
-    crle = newcrl->crlList;
-
-    if (wc_LockMutex(&crl->crlLock) != 0)
-    {
-        WOLFSSL_MSG("wc_LockMutex failed");
-        return BAD_MUTEX_E;
-    }
-    crle->next = crl->crlList;
-    crl->crlList = crle;
-    newcrl->crlList = NULL;
-    wc_UnLockMutex(&crl->crlLock);
+    if (store->cm->crl == NULL) {
+        crl = wolfSSL_X509_crl_new(store->cm);
+        if (DupX509_CRL(crl, newcrl) != 0) {
+            FreeCRL(crl, 1);
+            return WOLFSSL_FAILURE;
+        }
+        store->crl = store->cm->crl = crl;
+        if (wolfSSL_CertManagerEnableCRL(store->cm, WOLFSSL_CRL_CHECKALL)
+                != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("wolfSSL_CertManagerEnableCRL error");
+            return WOLFSSL_FAILURE;
+        }
+        return WOLFSSL_SUCCESS;
+    }
+
+    /* find tail of current list and add new list */
+    crl  = store->cm->crl;
+    crle = crl->crlList;
+    if (newcrl->crlList != NULL) {
+        CRL_Entry *tail = crle;
+        CRL_Entry *toAdd;
+
+        if (wc_LockMutex(&crl->crlLock) != 0)
+        {
+            WOLFSSL_MSG("wc_LockMutex failed");
+            return BAD_MUTEX_E;
+        }
+
+        toAdd = DupCRL_list(newcrl->crlList, crl->heap);
+        if (tail == NULL) {
+            crl->crlList = toAdd;
+        }
+        else {
+            while (tail->next != NULL) tail = tail->next;
+            tail->next = toAdd;
+        }
+        wc_UnLockMutex(&crl->crlLock);
+    }
+
+    if (wolfSSL_CertManagerEnableCRL(store->cm, WOLFSSL_CRL_CHECKALL)
+            != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("wolfSSL_CertManagerEnableCRL error");
+        return WOLFSSL_FAILURE;
+    }
 
     WOLFSSL_LEAVE("wolfSSL_X509_STORE_add_crl", WOLFSSL_SUCCESS);
@@ -882,5 +1113,15 @@
 
         if (FD_ISSET(crl->mfd, &readfds)) {
+            word64 r64;
+            int    rlen;
+
             WOLFSSL_MSG("got custom shutdown event, breaking out");
+
+            /* read out the bytes written to the event to clean up */
+            rlen = (int) read(crl->mfd, &r64, sizeof(r64));
+            if (rlen < 0) {
+                WOLFSSL_MSG("read custom event failure");
+            }
+
             break;
         }
@@ -961,5 +1202,5 @@
 #else /* HAVE_CRL_MONITOR */
 
-#ifndef NO_FILESYSTEM
+#if !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR)
 
 static int StartMonitorCRL(WOLFSSL_CRL* crl)
@@ -973,5 +1214,5 @@
 }
 
-#endif /* NO_FILESYSTEM */
+#endif /* !NO_FILESYSTEM && !NO_WOLFSSL_DIR */
 
 #endif  /* HAVE_CRL_MONITOR */
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
Index: azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/keys.c
===================================================================
--- azure_iot_hub_f767zi/trunk/wolfssl-4.4.0/src/keys.c	(revision 457)
+++ azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/keys.c	(revision 464)
@@ -1075,5 +1075,5 @@
         ssl->specs.pad_size              = PAD_SHA;
         ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = WC_SHA256_DIGEST_SIZE / 2;
+        ssl->specs.key_size              = WC_SHA256_DIGEST_SIZE;
         ssl->specs.block_size            = 0;
         ssl->specs.iv_size               = HMAC_NONCE_SZ;
@@ -1093,5 +1093,5 @@
         ssl->specs.pad_size              = PAD_SHA;
         ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = WC_SHA384_DIGEST_SIZE / 2;
+        ssl->specs.key_size              = WC_SHA384_DIGEST_SIZE;
         ssl->specs.block_size            = 0;
         ssl->specs.iv_size               = HMAC_NONCE_SZ;
@@ -2910,4 +2910,13 @@
             }
 
+            if (enc) {
+                if (wc_HmacInit(enc->hmac, heap, devId) != 0) {
+                    WOLFSSL_MSG("HmacInit failed in SetKeys");
+                    XFREE(enc->hmac, heap, DYNAMIC_TYPE_CIPHER);
+                    enc->hmac = NULL;
+                    return ASYNC_INIT_E;
+                }
+            }
+
             if (dec && dec->hmac == NULL) {
                 dec->hmac = (Hmac*)XMALLOC(sizeof(Hmac), heap,
@@ -2917,13 +2926,9 @@
             }
 
-            if (enc) {
-                if (wc_HmacInit(enc->hmac, heap, devId) != 0) {
-                    WOLFSSL_MSG("HmacInit failed in SetKeys");
-                    return ASYNC_INIT_E;
-                }
-            }
             if (dec) {
                 if (wc_HmacInit(dec->hmac, heap, devId) != 0) {
                     WOLFSSL_MSG("HmacInit failed in SetKeys");
+                    XFREE(dec->hmac, heap, DYNAMIC_TYPE_CIPHER);
+                    dec->hmac = NULL;
                     return ASYNC_INIT_E;
                 }
@@ -2932,4 +2937,6 @@
             if (side == WOLFSSL_CLIENT_END) {
                 if (enc) {
+                    XMEMCPY(keys->aead_enc_imp_IV, keys->client_write_IV,
+                            HMAC_NONCE_SZ);
                     hmacRet = wc_HmacSetKey(enc->hmac, hashType,
                                        keys->client_write_key, specs->key_size);
@@ -2937,4 +2944,6 @@
                 }
                 if (dec) {
+                    XMEMCPY(keys->aead_dec_imp_IV, keys->server_write_IV,
+                            HMAC_NONCE_SZ);
                     hmacRet = wc_HmacSetKey(dec->hmac, hashType,
                                        keys->server_write_key, specs->key_size);
@@ -2944,4 +2953,6 @@
             else {
                 if (enc) {
+                    XMEMCPY(keys->aead_enc_imp_IV, keys->server_write_IV,
+                            HMAC_NONCE_SZ);
                     hmacRet = wc_HmacSetKey(enc->hmac, hashType,
                                        keys->server_write_key, specs->key_size);
@@ -2949,4 +2960,6 @@
                 }
                 if (dec) {
+                    XMEMCPY(keys->aead_dec_imp_IV, keys->client_write_IV,
+                            HMAC_NONCE_SZ);
                     hmacRet = wc_HmacSetKey(dec->hmac, hashType,
                                        keys->client_write_key, specs->key_size);
@@ -3059,5 +3072,9 @@
     if (ssl->secure_renegotiation && ssl->secure_renegotiation->cache_status) {
         keys = &ssl->secure_renegotiation->tmp_keys;
-        copy = 1;
+#ifdef WOLFSSL_DTLS
+        /* For DTLS, copy is done in StoreKeys */
+        if (!ssl->options.dtls)
+#endif
+            copy = 1;
     }
 #endif /* HAVE_SECURE_RENEGOTIATION */
@@ -3134,4 +3151,13 @@
 
 #ifdef HAVE_SECURE_RENEGOTIATION
+#ifdef WOLFSSL_DTLS
+    if (ret == 0 && ssl->options.dtls) {
+        if (wc_encrypt)
+            wc_encrypt->src = keys == &ssl->keys ? KEYS : SCR;
+        if (wc_decrypt)
+            wc_decrypt->src = keys == &ssl->keys ? KEYS : SCR;
+    }
+#endif
+
     if (copy) {
         int clientCopy = 0;
@@ -3210,9 +3236,24 @@
     int sz, i = 0;
     Keys* keys = &ssl->keys;
+#ifdef WOLFSSL_DTLS
+    /* In case of DTLS, ssl->keys is updated here */
+    int scr_copy = 0;
+#endif
 
 #ifdef HAVE_SECURE_RENEGOTIATION
-    if (ssl->secure_renegotiation && ssl->secure_renegotiation->cache_status ==
-                                                            SCR_CACHE_NEEDED) {
+    if (ssl->secure_renegotiation &&
+            ssl->secure_renegotiation->cache_status == SCR_CACHE_NEEDED) {
         keys = &ssl->secure_renegotiation->tmp_keys;
+#ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            /* epoch is incremented after StoreKeys is called */
+            ssl->secure_renegotiation->tmp_keys.dtls_epoch = ssl->keys.dtls_epoch + 1;
+            /* we only need to copy keys on second and future renegotiations */
+            if (ssl->keys.dtls_epoch > 1)
+                scr_copy = 1;
+            ssl->encrypt.src = KEYS_NOT_SET;
+            ssl->decrypt.src = KEYS_NOT_SET;
+        }
+#endif
         CacheStatusPP(ssl->secure_renegotiation);
     }
@@ -3225,4 +3266,13 @@
             sz = ssl->specs.hash_size;
     #ifndef WOLFSSL_AEAD_ONLY
+
+    #ifdef WOLFSSL_DTLS
+            if (scr_copy) {
+                XMEMCPY(ssl->keys.client_write_MAC_secret,
+                        keys->client_write_MAC_secret, sz);
+                XMEMCPY(ssl->keys.server_write_MAC_secret,
+                        keys->server_write_MAC_secret, sz);
+            }
+    #endif
             XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz);
             XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz);
@@ -3231,4 +3281,12 @@
         }
         sz = ssl->specs.key_size;
+    #ifdef WOLFSSL_DTLS
+        if (scr_copy) {
+            XMEMCPY(ssl->keys.client_write_key,
+                    keys->client_write_key, sz);
+            XMEMCPY(ssl->keys.server_write_key,
+                    keys->server_write_key, sz);
+        }
+    #endif
         XMEMCPY(keys->client_write_key, &keyData[i], sz);
         XMEMCPY(keys->server_write_key, &keyData[i], sz);
@@ -3236,4 +3294,12 @@
 
         sz = ssl->specs.iv_size;
+    #ifdef WOLFSSL_DTLS
+        if (scr_copy) {
+            XMEMCPY(ssl->keys.client_write_IV,
+                    keys->client_write_IV, sz);
+            XMEMCPY(ssl->keys.server_write_IV,
+                    keys->server_write_IV, sz);
+        }
+    #endif
         XMEMCPY(keys->client_write_IV, &keyData[i], sz);
         XMEMCPY(keys->server_write_IV, &keyData[i], sz);
@@ -3242,4 +3308,10 @@
         if (ssl->specs.cipher_type == aead) {
             /* Initialize the AES-GCM/CCM explicit IV to a zero. */
+        #ifdef WOLFSSL_DTLS
+            if (scr_copy) {
+                XMEMCPY(ssl->keys.aead_exp_IV,
+                        keys->aead_exp_IV, AEAD_MAX_EXP_SZ);
+            }
+        #endif
             XMEMSET(keys->aead_exp_IV, 0, AEAD_MAX_EXP_SZ);
         }
@@ -3254,4 +3326,9 @@
         if (side & PROVISION_CLIENT) {
     #ifndef WOLFSSL_AEAD_ONLY
+        #ifdef WOLFSSL_DTLS
+            if (scr_copy)
+                XMEMCPY(ssl->keys.client_write_MAC_secret,
+                        keys->client_write_MAC_secret, sz);
+        #endif
             XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz);
     #endif
@@ -3260,4 +3337,9 @@
         if (side & PROVISION_SERVER) {
     #ifndef WOLFSSL_AEAD_ONLY
+        #ifdef WOLFSSL_DTLS
+            if (scr_copy)
+                XMEMCPY(ssl->keys.server_write_MAC_secret,
+                        keys->server_write_MAC_secret, sz);
+        #endif
             XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz);
     #endif
@@ -3267,8 +3349,18 @@
     sz = ssl->specs.key_size;
     if (side & PROVISION_CLIENT) {
+    #ifdef WOLFSSL_DTLS
+        if (scr_copy)
+            XMEMCPY(ssl->keys.client_write_key,
+                    keys->client_write_key, sz);
+    #endif
         XMEMCPY(keys->client_write_key, &keyData[i], sz);
         i += sz;
     }
     if (side & PROVISION_SERVER) {
+    #ifdef WOLFSSL_DTLS
+        if (scr_copy)
+            XMEMCPY(ssl->keys.server_write_key,
+                    keys->server_write_key, sz);
+    #endif
         XMEMCPY(keys->server_write_key, &keyData[i], sz);
         i += sz;
@@ -3277,13 +3369,29 @@
     sz = ssl->specs.iv_size;
     if (side & PROVISION_CLIENT) {
+    #ifdef WOLFSSL_DTLS
+        if (scr_copy)
+            XMEMCPY(ssl->keys.client_write_IV,
+                    keys->client_write_IV, sz);
+    #endif
         XMEMCPY(keys->client_write_IV, &keyData[i], sz);
         i += sz;
     }
-    if (side & PROVISION_SERVER)
+    if (side & PROVISION_SERVER) {
+    #ifdef WOLFSSL_DTLS
+        if (scr_copy)
+            XMEMCPY(ssl->keys.server_write_IV,
+                    keys->server_write_IV, sz);
+    #endif
         XMEMCPY(keys->server_write_IV, &keyData[i], sz);
+    }
 
 #ifdef HAVE_AEAD
     if (ssl->specs.cipher_type == aead) {
         /* Initialize the AES-GCM/CCM explicit IV to a zero. */
+    #ifdef WOLFSSL_DTLS
+        if (scr_copy)
+            XMEMMOVE(ssl->keys.aead_exp_IV,
+                    keys->aead_exp_IV, AEAD_MAX_EXP_SZ);
+    #endif
         XMEMSET(keys->aead_exp_IV, 0, AEAD_MAX_EXP_SZ);
     }
@@ -3342,5 +3450,5 @@
     }
 #endif
-
+    XMEMSET(shaOutput, 0, WC_SHA_DIGEST_SIZE);
     ret = wc_InitMd5(md5);
     if (ret == 0) {
@@ -3472,4 +3580,5 @@
     }
 #endif
+    XMEMSET(shaOutput, 0, WC_SHA_DIGEST_SIZE);
 
     ret = wc_InitMd5(md5);
Index: azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/ocsp.c
===================================================================
--- azure_iot_hub_f767zi/trunk/wolfssl-4.4.0/src/ocsp.c	(revision 457)
+++ azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/ocsp.c	(revision 464)
@@ -76,4 +76,7 @@
     CertStatus *status, *next;
 
+    if (entry == NULL)
+        return;
+
     WOLFSSL_ENTER("FreeOcspEntry");
 
@@ -83,4 +86,14 @@
         if (status->rawOcspResponse)
             XFREE(status->rawOcspResponse, heap, DYNAMIC_TYPE_OCSP_STATUS);
+
+#ifdef OPENSSL_EXTRA
+        if (status->serialInt) {
+            if (status->serialInt->isDynamic) {
+                XFREE(status->serialInt->data, NULL, DYNAMIC_TYPE_OPENSSL);
+            }
+            XFREE(status->serialInt, NULL, DYNAMIC_TYPE_OPENSSL);
+        }
+        status->serialInt = NULL;
+#endif
 
         XFREE(status, heap, DYNAMIC_TYPE_OCSP_STATUS);
@@ -273,7 +286,9 @@
 #ifdef WOLFSSL_SMALL_STACK
     CertStatus*   newStatus;
+    OcspEntry*    newSingle;
     OcspResponse* ocspResponse;
 #else
     CertStatus    newStatus[1];
+    OcspEntry     newSingle[1];
     OcspResponse  ocspResponse[1];
 #endif
@@ -283,11 +298,14 @@
 #ifdef WOLFSSL_SMALL_STACK
     newStatus = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL,
-                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                                                       DYNAMIC_TYPE_OCSP_STATUS);
+    newSingle = (OcspEntry*)XMALLOC(sizeof(OcspEntry), NULL,
+                                                       DYNAMIC_TYPE_OCSP_ENTRY);
     ocspResponse = (OcspResponse*)XMALLOC(sizeof(OcspResponse), NULL,
-                                                       DYNAMIC_TYPE_TMP_BUFFER);
-
-    if (newStatus == NULL || ocspResponse == NULL) {
-        if (newStatus) XFREE(newStatus, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        if (ocspResponse) XFREE(ocspResponse, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                                                       DYNAMIC_TYPE_OCSP_REQUEST);
+
+    if (newStatus == NULL || newSingle == NULL || ocspResponse == NULL) {
+        if (newStatus) XFREE(newStatus, NULL, DYNAMIC_TYPE_OCSP_STATUS);
+        if (newSingle) XFREE(newSingle, NULL, DYNAMIC_TYPE_OCSP_ENTRY);
+        if (ocspResponse) XFREE(ocspResponse, NULL, DYNAMIC_TYPE_OCSP_REQUEST);
 
         WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR);
@@ -295,7 +313,7 @@
     }
 #endif
-    XMEMSET(newStatus, 0, sizeof(CertStatus));
-
-    InitOcspResponse(ocspResponse, newStatus, response, responseSz);
+    InitOcspResponse(ocspResponse, newSingle, newStatus, response, responseSz,
+                     ocsp->cm->heap);
+
     ret = OcspResponseDecode(ocspResponse, ocsp->cm, ocsp->cm->heap, 0);
     if (ret != 0) {
@@ -326,5 +344,5 @@
     }
 
-    ret = xstat2err(ocspResponse->status->status);
+    ret = xstat2err(ocspResponse->single->status->status);
     if (ret == 0) {
         validated = 1;
@@ -343,6 +361,6 @@
 
         /* Replace existing certificate entry with updated */
-        newStatus->next = status->next;
-        XMEMCPY(status, newStatus, sizeof(CertStatus));
+        newSingle->status->next = status->next;
+        XMEMCPY(status, newSingle->status, sizeof(CertStatus));
     }
     else {
@@ -351,5 +369,5 @@
                                       ocsp->cm->heap, DYNAMIC_TYPE_OCSP_STATUS);
         if (status != NULL) {
-            XMEMCPY(status, newStatus, sizeof(CertStatus));
+            XMEMCPY(status, newSingle->status, sizeof(CertStatus));
             status->next  = entry->status;
             entry->status = status;
@@ -380,6 +398,7 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(newStatus,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    XFREE(ocspResponse, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(newStatus,    NULL, DYNAMIC_TYPE_OCSP_STATUS);
+    XFREE(newSingle,    NULL, DYNAMIC_TYPE_OCSP_ENTRY);
+    XFREE(ocspResponse, NULL, DYNAMIC_TYPE_OCSP_REQUEST);
 #endif
     return ret;
@@ -454,4 +473,5 @@
     else {
         /* cert doesn't have extAuthInfo, assuming CERT_GOOD */
+        WOLFSSL_MSG("Cert has no OCSP URL, assuming CERT_GOOD");
         return 0;
     }
@@ -493,5 +513,5 @@
 
 #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \
-    defined(WOLFSSL_APACHE_HTTPD)
+    defined(WOLFSSL_APACHE_HTTPD) || defined(HAVE_LIGHTY)
 
 int wolfSSL_OCSP_resp_find_status(WOLFSSL_OCSP_BASICRESP *bs,
@@ -500,19 +520,30 @@
     WOLFSSL_ASN1_TIME** nextupd)
 {
+    WOLFSSL_OCSP_SINGLERESP* single;
+
     if (bs == NULL || id == NULL)
         return WOLFSSL_FAILURE;
 
-    /* Only supporting one certificate status in asn.c. */
-    if (CompareOcspReqResp(id, bs) != 0)
+    single = bs->single;
+    while (single != NULL) {
+        if ((XMEMCMP(single->status->serial, id->status->serial, single->status->serialSz) == 0)
+         && (XMEMCMP(single->issuerHash, id->issuerHash, OCSP_DIGEST_SIZE) == 0)
+         && (XMEMCMP(single->issuerKeyHash, id->issuerKeyHash, OCSP_DIGEST_SIZE) == 0)) {
+            break;
+        }
+        single = single->next;
+    }
+
+    if (single == NULL)
         return WOLFSSL_FAILURE;
 
     if (status != NULL)
-        *status = bs->status->status;
+        *status = single->status->status;
     if (thisupd != NULL)
-        *thisupd = &bs->status->thisDateParsed;
+        *thisupd = &single->status->thisDateParsed;
     if (nextupd != NULL)
-        *nextupd = &bs->status->nextDateParsed;
-
-    /* TODO: Not needed for Nginx. */
+        *nextupd = &single->status->nextDateParsed;
+
+    /* TODO: Not needed for Nginx or httpd */
     if (reason != NULL)
         *reason = 0;
@@ -550,5 +581,5 @@
 void wolfSSL_OCSP_CERTID_free(WOLFSSL_OCSP_CERTID* certId)
 {
-    FreeOcspRequest(certId);
+    FreeOcspEntry(certId, NULL);
     XFREE(certId, NULL, DYNAMIC_TYPE_OPENSSL);
 }
@@ -559,4 +590,5 @@
 {
     WOLFSSL_OCSP_CERTID* certId;
+    CertStatus* certStatus;
     DecodedCert cert;
     WOLFSSL_CERT_MANAGER* cm;
@@ -581,20 +613,34 @@
     certId = (WOLFSSL_OCSP_CERTID*)XMALLOC(sizeof(WOLFSSL_OCSP_CERTID), NULL,
                                            DYNAMIC_TYPE_OPENSSL);
-    if (certId != NULL) {
-        InitDecodedCert(&cert, subject->derCert->buffer,
-                        subject->derCert->length, NULL);
-        if (ParseCertRelative(&cert, CERT_TYPE, VERIFY_OCSP, cm) != 0) {
+    certStatus = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL,
+                                           DYNAMIC_TYPE_OPENSSL);
+
+    if (certId == NULL || certStatus == NULL) {
+        if (certId)
             XFREE(certId, NULL, DYNAMIC_TYPE_OPENSSL);
-            certId = NULL;
-        }
-        else {
-            ret = InitOcspRequest(certId, &cert, 0, NULL);
-            if (ret != 0) {
-                XFREE(certId, NULL, DYNAMIC_TYPE_OPENSSL);
-                certId = NULL;
-            }
-        }
-        FreeDecodedCert(&cert);
-    }
+        if (certStatus)
+            XFREE(certStatus, NULL, DYNAMIC_TYPE_OPENSSL);
+
+        return NULL;
+    }
+
+    XMEMSET(certId, 0, sizeof(WOLFSSL_OCSP_CERTID));
+    XMEMSET(certStatus, 0, sizeof(CertStatus));
+
+    certId->status = certStatus;
+
+    InitDecodedCert(&cert, subject->derCert->buffer,
+                    subject->derCert->length, NULL);
+    if (ParseCertRelative(&cert, CERT_TYPE, VERIFY_OCSP, cm) != 0) {
+        XFREE(certId, NULL, DYNAMIC_TYPE_OPENSSL);
+        certId = NULL;
+    }
+    else {
+        XMEMCPY(certId->issuerHash, cert.issuerHash, OCSP_DIGEST_SIZE);
+        XMEMCPY(certId->issuerKeyHash, cert.issuerKeyHash, OCSP_DIGEST_SIZE);
+        XMEMCPY(certId->status->serial, cert.serial, cert.serialSz);
+        certId->status->serialSz = cert.serialSz;
+    }
+    FreeDecodedCert(&cert);
 
     wolfSSL_CertManagerFree(cm);
@@ -636,11 +682,19 @@
 void wolfSSL_OCSP_RESPONSE_free(OcspResponse* response)
 {
-    if (response->status != NULL)
-        XFREE(response->status, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (response == NULL)
+        return;
+
+    if (response->single != NULL) {
+        FreeOcspEntry(response->single, NULL);
+        XFREE(response->single, NULL, DYNAMIC_TYPE_OCSP_ENTRY);
+    }
+
     if (response->source != NULL)
         XFREE(response->source, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    XFREE(response, NULL, DYNAMIC_TYPE_OPENSSL);
-}
-
+
+    XFREE(response, NULL, DYNAMIC_TYPE_OCSP_REQUEST);
+}
+
+#ifndef NO_BIO
 OcspResponse* wolfSSL_d2i_OCSP_RESPONSE_bio(WOLFSSL_BIO* bio,
     OcspResponse** response)
@@ -707,4 +761,5 @@
     return ret;
 }
+#endif /* !NO_BIO */
 
 OcspResponse* wolfSSL_d2i_OCSP_RESPONSE(OcspResponse** response,
@@ -722,5 +777,5 @@
     if (resp == NULL) {
         resp = (OcspResponse*)XMALLOC(sizeof(OcspResponse), NULL,
-                                      DYNAMIC_TYPE_OPENSSL);
+                                      DYNAMIC_TYPE_OCSP_REQUEST);
         if (resp == NULL)
             return NULL;
@@ -730,14 +785,24 @@
     resp->source = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER);
     if (resp->source == NULL) {
-        XFREE(resp, NULL, DYNAMIC_TYPE_OPENSSL);
+        XFREE(resp, NULL, DYNAMIC_TYPE_OCSP_REQUEST);
         return NULL;
     }
-    resp->status = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL,
-                                                       DYNAMIC_TYPE_TMP_BUFFER);
-    if (resp->status == NULL) {
+    resp->single = (OcspEntry*)XMALLOC(sizeof(OcspEntry), NULL,
+                                      DYNAMIC_TYPE_OCSP_ENTRY);
+    if (resp->single == NULL) {
         XFREE(resp->source, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        XFREE(resp, NULL, DYNAMIC_TYPE_OPENSSL);
+        XFREE(resp, NULL, DYNAMIC_TYPE_OCSP_REQUEST);
         return NULL;
     }
+    XMEMSET(resp->single, 0, sizeof(OcspEntry));
+    resp->single->status = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL,
+                                      DYNAMIC_TYPE_OCSP_STATUS);
+    if (resp->single->status == NULL) {
+        XFREE(resp->source, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(resp, NULL, DYNAMIC_TYPE_OCSP_REQUEST);
+        XFREE(resp->single, NULL, DYNAMIC_TYPE_OCSP_ENTRY);
+        return NULL;
+    }
+    XMEMSET(resp->single->status, 0, sizeof(CertStatus));
 
     XMEMCPY(resp->source, *data, len);
@@ -795,14 +860,14 @@
 
     bs = (WOLFSSL_OCSP_BASICRESP*)XMALLOC(sizeof(WOLFSSL_OCSP_BASICRESP), NULL,
-                                          DYNAMIC_TYPE_OPENSSL);
+                                          DYNAMIC_TYPE_OCSP_REQUEST);
     if (bs == NULL)
         return NULL;
 
     XMEMCPY(bs, response, sizeof(OcspResponse));
-    bs->status = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL,
-                                      DYNAMIC_TYPE_TMP_BUFFER);
+    bs->single = (OcspEntry*)XMALLOC(sizeof(OcspEntry), NULL,
+                                    DYNAMIC_TYPE_OCSP_ENTRY);
     bs->source = (byte*)XMALLOC(bs->maxIdx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    if (bs->status == NULL || bs->source == NULL) {
-        if (bs->status) XFREE(bs->status, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (bs->single == NULL || bs->source == NULL) {
+        if (bs->single) XFREE(bs->single, NULL, DYNAMIC_TYPE_OCSP_ENTRY);
         if (bs->source) XFREE(bs->source, NULL, DYNAMIC_TYPE_TMP_BUFFER);
         wolfSSL_OCSP_RESPONSE_free(bs);
@@ -810,5 +875,5 @@
     }
     else {
-        XMEMCPY(bs->status, response->status, sizeof(CertStatus));
+        XMEMCPY(bs->single, response->single, sizeof(OcspEntry));
         XMEMCPY(bs->source, response->source, response->maxIdx);
     }
@@ -851,21 +916,8 @@
         return NULL;
 
-    FreeOcspRequest(req);
-    XMEMCPY(req, cid, sizeof(OcspRequest));
-
-    if (cid->serial != NULL) {
-        req->serial = (byte*)XMALLOC(cid->serialSz, NULL,
-                                     DYNAMIC_TYPE_OCSP_REQUEST);
-        req->url = (byte*)XMALLOC(cid->urlSz, NULL, DYNAMIC_TYPE_OCSP_REQUEST);
-        if (req->serial == NULL || req->url == NULL) {
-            FreeOcspRequest(req);
-            return NULL;
-        }
-
-        XMEMCPY(req->serial, cid->serial, cid->serialSz);
-        XMEMCPY(req->url, cid->url, cid->urlSz);
-    }
-
-    wolfSSL_OCSP_REQUEST_free(cid);
+    XMEMCPY(req->issuerHash, cid->issuerHash, KEYID_SIZE);
+    XMEMCPY(req->issuerKeyHash, cid->issuerKeyHash, KEYID_SIZE);
+    XMEMCPY(req->serial, cid->status->serial, cid->status->serialSz);
+    req->serialSz = cid->status->serialSz;
 
     return req;
@@ -876,10 +928,9 @@
     WOLFSSL_OCSP_CERTID* certId;
 
-    if (id == NULL) {
+    if (id == NULL)
         return NULL;
-    }
 
     certId = (WOLFSSL_OCSP_CERTID*)XMALLOC(sizeof(WOLFSSL_OCSP_CERTID),
-        id->heap, DYNAMIC_TYPE_OPENSSL);
+        NULL, DYNAMIC_TYPE_OPENSSL);
     if (certId) {
         XMEMCPY(certId, id, sizeof(WOLFSSL_OCSP_CERTID));
@@ -890,4 +941,5 @@
 
 #if defined(OPENSSL_ALL) || defined(APACHE_HTTPD)
+#ifndef NO_BIO
 int wolfSSL_i2d_OCSP_REQUEST_bio(WOLFSSL_BIO* out,
         WOLFSSL_OCSP_REQUEST *req)
@@ -923,4 +975,89 @@
     return WOLFSSL_FAILURE;
 }
+#endif /* !NO_BIO */
+
+int wolfSSL_i2d_OCSP_CERTID(WOLFSSL_OCSP_CERTID* id, unsigned char** data)
+{
+    if (id == NULL || data == NULL)
+        return WOLFSSL_FAILURE;
+
+    if (*data != NULL) {
+        XMEMCPY(*data, id->rawCertId, id->rawCertIdSize);
+        *data = *data + id->rawCertIdSize;
+    }
+    else {
+        *data = (unsigned char*)XMALLOC(id->rawCertIdSize, NULL, DYNAMIC_TYPE_OPENSSL);
+        if (*data == NULL) {
+            return WOLFSSL_FAILURE;
+        }
+        XMEMCPY(*data, id->rawCertId, id->rawCertIdSize);
+    }
+
+    return id->rawCertIdSize;
+}
+
+const WOLFSSL_OCSP_CERTID* wolfSSL_OCSP_SINGLERESP_get0_id(const WOLFSSL_OCSP_SINGLERESP *single)
+{
+    return single;
+}
+
+int wolfSSL_OCSP_single_get0_status(WOLFSSL_OCSP_SINGLERESP *single,
+                                    int *reason,
+                                    WOLFSSL_ASN1_TIME **revtime,
+                                    WOLFSSL_ASN1_TIME **thisupd,
+                                    WOLFSSL_ASN1_TIME **nextupd)
+{
+    if (single == NULL)
+        return WOLFSSL_FAILURE;
+
+    if (thisupd != NULL)
+        *thisupd = &single->status->thisDateParsed;
+    if (nextupd != NULL)
+        *nextupd = &single->status->nextDateParsed;
+
+    if (reason != NULL)
+        *reason = 0;
+    if (revtime != NULL)
+        *revtime = NULL;
+
+    return single->status->status;
+}
+
+int wolfSSL_OCSP_resp_count(WOLFSSL_OCSP_BASICRESP *bs)
+{
+    WOLFSSL_OCSP_SINGLERESP* single;
+    int count = 0;
+
+    if (bs == NULL)
+        return WOLFSSL_FAILURE;
+
+    single = bs->single;
+    while(single != NULL)
+    {
+        ++count;
+        single = single->next;
+    }
+
+    return count;
+}
+
+WOLFSSL_OCSP_SINGLERESP* wolfSSL_OCSP_resp_get0(WOLFSSL_OCSP_BASICRESP *bs, int idx)
+{
+    WOLFSSL_OCSP_SINGLERESP* single;
+    int currIdx = 0;
+
+    if (bs == NULL)
+        return NULL;
+
+    single = bs->single;
+    while(single != NULL && currIdx != idx)
+    {
+        single = single->next;
+        ++currIdx;
+    }
+
+    return single;
+}
+
 #endif /* OPENSSL_ALL || APACHE_HTTPD */
 
@@ -980,7 +1117,7 @@
             return 0;
 
-        if (cid->serialSz > (WOLFSSL_ASN1_INTEGER_MAX - 2)) {
+        if (cid->status->serialSz > (WOLFSSL_ASN1_INTEGER_MAX - 2)) {
             /* allocate data buffer, +2 for type and length */
-            ser->data = (unsigned char*)XMALLOC(cid->serialSz + 2, NULL,
+            ser->data = (unsigned char*)XMALLOC(cid->status->serialSz + 2, NULL,
                 DYNAMIC_TYPE_OPENSSL);
             if (ser->data == NULL) {
@@ -988,5 +1125,5 @@
                 return 0;
             }
-            ser->dataMax = cid->serialSz + 2;
+            ser->dataMax = cid->status->serialSz + 2;
             ser->isDynamic = 1;
         } else {
@@ -998,14 +1135,14 @@
         #ifdef WOLFSSL_QT
             /* Serial number starts at 0 index of ser->data */
-            XMEMCPY(&ser->data[i], cid->serial, cid->serialSz);
-            ser->length = cid->serialSz;
+            XMEMCPY(&ser->data[i], cid->status->serial, cid->status->serialSz);
+            ser->length = cid->status->serialSz;
         #else
             ser->data[i++] = ASN_INTEGER;
-            i += SetLength(cid->serialSz, ser->data + i);
-            XMEMCPY(&ser->data[i], cid->serial, cid->serialSz);
+            i += SetLength(cid->status->serialSz, ser->data + i);
+            XMEMCPY(&ser->data[i], cid->status->serial, cid->status->serialSz);
         #endif
 
-        cid->serialInt = ser;
-        *serial = cid->serialInt;
+        cid->status->serialInt = ser;
+        *serial = ser;
     }
 
Index: azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/sniffer.c
===================================================================
--- azure_iot_hub_f767zi/trunk/wolfssl-4.4.0/src/sniffer.c	(revision 457)
+++ azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/sniffer.c	(revision 464)
@@ -26,6 +26,42 @@
 
 #include <wolfssl/wolfcrypt/settings.h>
-
-#ifndef WOLFCRYPT_ONLY
+#include <wolfssl/wolfcrypt/wc_port.h>
+
+/* xctime */
+#ifndef XCTIME
+   #define XCTIME ctime
+#endif
+
+/* only in this file, to avoid confusing future ports leave
+ * these defines here. Do not move to wc_port.h */
+#ifdef USER_CUSTOM_SNIFFX
+    /* To be implemented in user_settings.h */
+#elif defined(FUSION_RTOS)
+    #include <fcl_network.h>
+    #define XINET_NTOA FNS_INET_NTOA
+    #define XINET_ATON FNS_INET_ATON
+    #define XINET_PTON(a,b,c,d) FNS_INET_PTON((a),(b),(c),(d),NULL)
+    #define XINET_NTOP(a,b,c,d) FNS_INET_NTOP((a),(b),(c),(d),NULL)
+    #define XINET_ADDR FNS_INET_ADDR
+    #define XHTONS FNS_HTONS
+    #define XNTOHS FNS_NTOHS
+    #define XHTONL FNS_HTONL
+    #define XNTOHL FNS_NTOHL
+    #define XINADDR_NONE FNS_INADDR_NONE
+#else
+    /* default */
+    #define XINET_NTOA inet_ntoa
+    #define XINET_ATON inet_aton
+    #define XINET_PTON(a,b,c) inet_pton((a),(b),(c))
+    #define XINET_NTOP inet_ntop
+    #define XINET_ADDR inet_addr
+    #define XHTONS htons
+    #define XNTOHS ntohs
+    #define XHTONL htonl
+    #define XNTOHL ntohl
+    #define XINADDR_NONE INADDR_NONE
+#endif
+
+#if !defined(WOLFCRYPT_ONLY) && !defined(NO_FILESYSTEM)
 #ifdef WOLFSSL_SNIFFER
 
@@ -33,8 +69,15 @@
 #include <time.h>
 
-#ifndef _WIN32
-  #include <arpa/inet.h>
+#ifdef FUSION_RTOS
+    #include <fns_inet.h>
+    #ifdef TCP_PROTOCOL
+        #undef TCP_PROTOCOL
+    #endif
 #else
-  #include <WS2tcpip.h>
+    #ifndef _WIN32
+        #include <arpa/inet.h>
+    #else
+        #include <WS2tcpip.h>
+    #endif
 #endif
 
@@ -45,5 +88,4 @@
 #endif
 
-#include <wolfssl/openssl/ssl.h>
 #include <wolfssl/internal.h>
 #include <wolfssl/error-ssl.h>
@@ -91,11 +133,34 @@
     HASH_SIZE          = 499, /* Session Hash Table Rows */
     PSEUDO_HDR_SZ      = 12,  /* TCP Pseudo Header size in bytes */
-    FATAL_ERROR_STATE  =  1,  /* SnifferSession fatal error state */
+    FATAL_ERROR_STATE  = 1,   /* SnifferSession fatal error state */
     TICKET_HINT_LEN    = 4,   /* Session Ticket Hint length */
-    EXT_TYPE_SZ        = 2,   /* Extension length */
+    TICKET_HINT_AGE_LEN= 4,   /* Session Ticket Age add length */        
+    EXT_TYPE_SZ        = 2,   /* Extension type length */
     MAX_INPUT_SZ       = MAX_RECORD_SIZE + COMP_EXTRA + MAX_MSG_EXTRA +
                          MTU_EXTRA,  /* Max input sz of reassembly */
-    EXT_MASTER_SECRET  = 0x17, /* Extended Master Secret Extension ID */
-    TICKET_EXT_ID      = 0x23 /* Session Ticket Extension ID */
+
+    /* TLS Extensions */
+    EXT_SERVER_NAME                = 0x0000, /* a.k.a. SNI  */
+    EXT_MAX_FRAGMENT_LENGTH        = 0x0001,
+    EXT_TRUSTED_CA_KEYS            = 0x0003,
+    EXT_TRUNCATED_HMAC             = 0x0004,
+    EXT_STATUS_REQUEST             = 0x0005, /* a.k.a. OCSP stapling   */
+    EXT_SUPPORTED_GROUPS           = 0x000a, /* a.k.a. Supported Curves */
+    EXT_EC_POINT_FORMATS           = 0x000b,
+    EXT_SIGNATURE_ALGORITHMS       = 0x000d,
+    EXT_APPLICATION_LAYER_PROTOCOL = 0x0010, /* a.k.a. ALPN */
+    EXT_STATUS_REQUEST_V2          = 0x0011, /* a.k.a. OCSP stapling v2 */
+    EXT_ENCRYPT_THEN_MAC           = 0x0016, /* RFC 7366 */
+    EXT_MASTER_SECRET              = 0x0017, /* Extended Master Secret Extension ID */
+    EXT_TICKET_ID                  = 0x0023, /* Session Ticket Extension ID */
+    EXT_PRE_SHARED_KEY             = 0x0029,
+    EXT_EARLY_DATA                 = 0x002a,
+    EXT_SUPPORTED_VERSIONS         = 0x002b,
+    EXT_COOKIE                     = 0x002c,
+    EXT_PSK_KEY_EXCHANGE_MODES     = 0x002d,
+    EXT_POST_HANDSHAKE_AUTH        = 0x0031,
+    EXT_SIGNATURE_ALGORITHMS_CERT  = 0x0032,
+    EXT_KEY_SHARE                  = 0x0033,
+    EXT_RENEGOTIATION_INFO         = 0xff01
 };
 
@@ -139,5 +204,5 @@
 
 static WOLFSSL_GLOBAL int TraceOn = 0;         /* Trace is off by default */
-static WOLFSSL_GLOBAL FILE* TraceFile = 0;
+static WOLFSSL_GLOBAL XFILE TraceFile = 0;
 
 
@@ -276,5 +341,7 @@
     "No data destination Error",
     "Store data callback failed",
-    "Loading chain input"
+    "Loading chain input",
+    "Got encrypted extension",
+    "Got Hello Retry Request",
 };
 
@@ -319,4 +386,5 @@
     byte*            key;                        /* DER private key */
     word32           keySz;                      /* size of DER private key */
+    int              isEphemeralKey;
     struct NamedKey* next;                       /* for list */
 } NamedKey;
@@ -336,5 +404,5 @@
 /* Sniffer Server holds info for each server/port monitored */
 typedef struct SnifferServer {
-    SSL_CTX*       ctx;                          /* SSL context */
+    WOLFSSL_CTX*   ctx;                          /* SSL context */
     char           address[MAX_SERVER_ADDRESS];  /* passed in server address */
     IpAddrInfo     server;                       /* network order address */
@@ -365,14 +433,15 @@
     byte           expectEms;       /* expect extended master secret */
 #endif
+    byte           gotFinished;     /* processed finished */
 } Flags;
 
 
 /* Out of Order FIN capture */
-typedef struct FinCaputre {
+typedef struct FinCapture {
     word32 cliFinSeq;               /* client relative sequence FIN  0 is no */
     word32 srvFinSeq;               /* server relative sequence FIN, 0 is no */
     byte   cliCounted;              /* did we count yet, detects duplicates */
     byte   srvCounted;              /* did we count yet, detects duplicates */
-} FinCaputre;
+} FinCapture;
 
 
@@ -385,5 +454,5 @@
     wc_Md5 hashMd5;
 #endif
-#endif
+#endif /* !NO_OLD_TLS */
 #ifndef NO_SHA256
     wc_Sha256 hashSha256;
@@ -393,4 +462,14 @@
 #endif
 } HsHashes;
+
+typedef struct KeyShareInfo {
+    word16      named_group;
+    int         key_len;
+    const byte* key;
+
+    /* additional info */
+    int         dh_key_bits;
+    int         curve_id;
+} KeyShareInfo;
 
 
@@ -398,6 +477,6 @@
 typedef struct SnifferSession {
     SnifferServer* context;         /* server context */
-    SSL*           sslServer;       /* SSL server side decode */
-    SSL*           sslClient;       /* SSL client side decode */
+    WOLFSSL*       sslServer;       /* SSL server side decode */
+    WOLFSSL*       sslClient;       /* SSL client side decode */
     IpAddrInfo     server;          /* server address in network byte order */
     IpAddrInfo     client;          /* client address in network byte order */
@@ -408,7 +487,7 @@
     word32         cliExpected;     /* client expected sequence (relative) */
     word32         srvExpected;     /* server expected sequence (relative) */
-    FinCaputre     finCaputre;      /* retain out of order FIN s */
+    FinCapture     finCapture;      /* retain out of order FIN s */
     Flags          flags;           /* session flags */
-    time_t         lastUsed;          /* last used ticks */
+    time_t         lastUsed;        /* last used ticks */
     word32         keySz;           /* size of the private key */
     PacketBuffer*  cliReassemblyList; /* client out of order packets */
@@ -416,11 +495,22 @@
     word32         cliReassemblyMemory; /* client packet memory used */
     word32         srvReassemblyMemory; /* server packet memory used */
-    struct SnifferSession* next;      /* for hash table list */
-    byte*          ticketID;          /* mac ID of session ticket */
+    struct SnifferSession* next;    /* for hash table list */
+    byte*          ticketID;        /* mac ID of session ticket */
+#ifdef HAVE_MAX_FRAGMENT
+    byte*          tlsFragBuf;
+    word32         tlsFragOffset;
+    word32         tlsFragSize;
+#endif
 #ifdef HAVE_SNI
     const char*    sni;             /* server name indication */
 #endif
 #ifdef HAVE_EXTENDED_MASTER
-    HsHashes*       hash;
+    HsHashes*      hash;
+#endif
+#ifdef WOLFSSL_TLS13
+    byte*          cliKeyShare;
+    word32         cliKeyShareSz;
+    KeyShareInfo   srvKs;
+    KeyShareInfo   cliKs;
 #endif
 } SnifferSession;
@@ -559,5 +649,5 @@
         wc_FreeMutex(&srv->namedKeysMutex);
 #endif
-        SSL_CTX_free(srv->ctx);
+        wolfSSL_CTX_free(srv->ctx);
     }
     XFREE(srv, NULL, DYNAMIC_TYPE_SNIFFER_SERVER);
@@ -595,6 +685,6 @@
 {
     if (session) {
-        SSL_free(session->sslClient);
-        SSL_free(session->sslServer);
+        wolfSSL_free(session->sslClient);
+        wolfSSL_free(session->sslServer);
 
         FreePacketList(session->cliReassemblyList);
@@ -604,4 +694,14 @@
 #ifdef HAVE_EXTENDED_MASTER
         XFREE(session->hash, NULL, DYNAMIC_TYPE_HASHES);
+#endif
+#ifdef WOLFSSL_TLS13
+        if (session->cliKeyShare)
+            XFREE(session->cliKeyShare, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+#ifdef HAVE_MAX_FRAGMENT
+        if (session->tlsFragBuf) {
+            XFREE(session->tlsFragBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            session->tlsFragBuf = NULL;
+        }
 #endif
     }
@@ -622,11 +722,5 @@
     wc_LockMutex(&SessionMutex);
 
-    srv = ServerList;
-    while (srv) {
-        removeServer = srv;
-        srv = srv->next;
-        FreeSnifferServer(removeServer);
-    }
-
+    /* Free sessions (wolfSSL objects) first */
     for (i = 0; i < HASH_SIZE; i++) {
         session = SessionTable[i];
@@ -637,4 +731,14 @@
         }
     }
+    SessionCount = 0;
+
+    /* Then server (wolfSSL_CTX) */
+    srv = ServerList;
+    while (srv) {
+        removeServer = srv;
+        srv = srv->next;
+        FreeSnifferServer(removeServer);
+    }
+    ServerList = NULL;    
 
     wc_UnLockMutex(&SessionMutex);
@@ -656,5 +760,5 @@
     if (TraceFile) {
         TraceOn = 0;
-        fclose(TraceFile);
+        XFCLOSE(TraceFile);
         TraceFile = NULL;
     }
@@ -678,9 +782,8 @@
 #endif
 #ifndef NO_MD5
-    if (ret == 0) {
+    if (ret == 0)
         ret = wc_InitMd5(&hash->hashMd5);
-    }
-#endif
-#endif
+#endif
+#endif /* !NO_OLD_TLS */
 #ifndef NO_SHA256
     if (ret == 0)
@@ -694,5 +797,4 @@
     return ret;
 }
-
 
 static int HashUpdate(HsHashes* hash, const byte* input, int sz)
@@ -709,9 +811,8 @@
 #endif
 #ifndef NO_MD5
-    if (ret == 0) {
+    if (ret == 0)
         ret = wc_Md5Update(&hash->hashMd5, input, sz);
-    }
-#endif
-#endif
+#endif
+#endif /* !NO_OLD_TLS */
 #ifndef NO_SHA256
     if (ret == 0)
@@ -726,21 +827,19 @@
 }
 
-
 static int HashCopy(HS_Hashes* d, HsHashes* s)
 {
 #ifndef NO_OLD_TLS
 #ifndef NO_SHA
-        XMEMCPY(&d->hashSha, &s->hashSha, sizeof(wc_Sha));
+    XMEMCPY(&d->hashSha, &s->hashSha, sizeof(wc_Sha));
 #endif
 #ifndef NO_MD5
-        XMEMCPY(&d->hashMd5, &s->hashMd5, sizeof(wc_Md5));
-#endif
-#endif
-
+    XMEMCPY(&d->hashMd5, &s->hashMd5, sizeof(wc_Md5));
+#endif
+#endif /* !NO_OLD_TLS */
 #ifndef NO_SHA256
-        XMEMCPY(&d->hashSha256, &s->hashSha256, sizeof(wc_Sha256));
+    XMEMCPY(&d->hashSha256, &s->hashSha256, sizeof(wc_Sha256));
 #endif
 #ifdef WOLFSSL_SHA384
-        XMEMCPY(&d->hashSha384, &s->hashSha384, sizeof(wc_Sha384));
+    XMEMCPY(&d->hashSha384, &s->hashSha384, sizeof(wc_Sha384));
 #endif
 
@@ -766,7 +865,7 @@
 
 /* Initialize FIN Capture */
-static void InitFinCapture(FinCaputre* cap)
-{
-    XMEMSET(cap, 0, sizeof(FinCaputre));
+static void InitFinCapture(FinCapture* cap)
+{
+    XMEMSET(cap, 0, sizeof(FinCapture));
 }
 
@@ -777,5 +876,5 @@
     XMEMSET(session, 0, sizeof(SnifferSession));
     InitFlags(&session->flags);
-    InitFinCapture(&session->finCaputre);
+    InitFinCapture(&session->finCapture);
 }
 
@@ -900,7 +999,7 @@
         char myBuffer[MAX_ERROR_LEN];
         GetError(idx, myBuffer);
-        fprintf(TraceFile, "\t%s\n", myBuffer);
+        XFPRINTF(TraceFile, "\t%s\n", myBuffer);
 #ifdef DEBUG_SNIFFER
-        fprintf(stderr,    "\t%s\n", myBuffer);
+        XFPRINTF(stderr,    "\t%s\n", myBuffer);
 #endif
     }
@@ -912,6 +1011,6 @@
 {
     if (TraceOn) {
-        time_t ticks = time(NULL);
-        fprintf(TraceFile, "\n%s", ctime(&ticks));
+        time_t ticks = XTIME(NULL);
+        XFPRINTF(TraceFile, "\n%s", XCTIME(&ticks));
     }
 }
@@ -922,6 +1021,6 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tTrying to install a new Sniffer Server with\n");
-        fprintf(TraceFile, "\tserver: %s, port: %d, keyFile: %s\n", srv, port,
+        XFPRINTF(TraceFile, "\tTrying to install a new Sniffer Server with\n");
+        XFPRINTF(TraceFile, "\tserver: %s, port: %d, keyFile: %s\n", srv, port,
                                                                     keyFile);
     }
@@ -936,7 +1035,10 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tTrying to install a new Sniffer Server with\n");
-        fprintf(TraceFile, "\tname: %s, server: %s, port: %d, keyFile: %s\n",
-                                                      name, srv, port, keyFile);
+        XFPRINTF(TraceFile, "\tTrying to install a new Sniffer Server with\n");
+        XFPRINTF(TraceFile, "\tname: %s, server: %s, port: %d, keyFile: %s\n",
+		name ? name : "",
+		srv ? srv : "",
+		port,
+		keyFile ? keyFile : "");
     }
 }
@@ -950,5 +1052,5 @@
     if (TraceOn) {
         static word32 packetNumber = 0;
-        fprintf(TraceFile, "\tGot a Packet to decode, packet %u\n",
+        XFPRINTF(TraceFile, "\tGot a Packet to decode, packet %u\n",
                 ++packetNumber);
     }
@@ -959,5 +1061,5 @@
 static const char* IpToS(int version, void* src, char* dst)
 {
-    return inet_ntop(version, src, dst, TRACE_MSG_SZ);
+    return XINET_NTOP(version, src, dst, TRACE_MSG_SZ);
 }
 
@@ -969,5 +1071,5 @@
         char src[TRACE_MSG_SZ];
         char dst[TRACE_MSG_SZ];
-        fprintf(TraceFile, "\tdst:%s src:%s\n",
+        XFPRINTF(TraceFile, "\tdst:%s src:%s\n",
                 IpToS(AF_INET, &iphdr->dst, dst),
                 IpToS(AF_INET, &iphdr->src, src));
@@ -982,5 +1084,5 @@
         char src[TRACE_MSG_SZ];
         char dst[TRACE_MSG_SZ];
-        fprintf(TraceFile, "\tdst: %s src: %s\n",
+        XFPRINTF(TraceFile, "\tdst: %s src: %s\n",
                 IpToS(AF_INET6, iphdr->dst, dst),
                 IpToS(AF_INET6, iphdr->src, src));
@@ -993,6 +1095,6 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tdstPort:%u srcPort:%u\n", ntohs(tcphdr->dstPort),
-                ntohs(tcphdr->srcPort));
+        XFPRINTF(TraceFile, "\tdstPort:%u srcPort:%u\n", XNTOHS(tcphdr->dstPort),
+                XNTOHS(tcphdr->srcPort));
     }
 }
@@ -1003,5 +1105,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tSequence:%u, payload length:%d\n", seq, len);
+        XFPRINTF(TraceFile, "\tSequence:%u, payload length:%d\n", seq, len);
     }
 }
@@ -1012,5 +1114,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tAck:%u Expected:%u\n", ack, expected);
+        XFPRINTF(TraceFile, "\tAck:%u Expected:%u\n", ack, expected);
     }
 }
@@ -1021,5 +1123,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tExpected sequence:%u, received sequence:%u\n",
+        XFPRINTF(TraceFile, "\tExpected sequence:%u, received sequence:%u\n",
                 expected, got);
     }
@@ -1031,5 +1133,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tServer SYN, Sequence Start:%u\n", seq);
+        XFPRINTF(TraceFile, "\tServer SYN, Sequence Start:%u\n", seq);
     }
 }
@@ -1040,5 +1142,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tClient SYN, Sequence Start:%u\n", seq);
+        XFPRINTF(TraceFile, "\tClient SYN, Sequence Start:%u\n", seq);
     }
 }
@@ -1049,5 +1151,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tClient FIN capture:%u, current SEQ:%u\n",
+        XFPRINTF(TraceFile, "\tClient FIN capture:%u, current SEQ:%u\n",
                 finSeq, relSeq);
     }
@@ -1059,5 +1161,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tServer FIN capture:%u, current SEQ:%u\n",
+        XFPRINTF(TraceFile, "\tServer FIN capture:%u, current SEQ:%u\n",
                 finSeq, relSeq);
     }
@@ -1069,5 +1171,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\t%d bytes of SSL App data processed\n", bytes);
+        XFPRINTF(TraceFile, "\t%d bytes of SSL App data processed\n", bytes);
     }
 }
@@ -1078,5 +1180,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile,
+        XFPRINTF(TraceFile,
                 "\t%d bytes added to %d existing bytes in User Buffer\n",
                 newBytes, existingBytes);
@@ -1089,5 +1191,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tFound a stale session\n");
+        XFPRINTF(TraceFile, "\tFound a stale session\n");
     }
 }
@@ -1098,5 +1200,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tTrying to find Stale Sessions\n");
+        XFPRINTF(TraceFile, "\tTrying to find Stale Sessions\n");
     }
 }
@@ -1107,5 +1209,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tRemoved it\n");
+        XFPRINTF(TraceFile, "\tRemoved it\n");
     }
 }
@@ -1117,5 +1219,5 @@
     if (TraceOn) {
         if (sslInfo != NULL && sslInfo->isValid) {
-            fprintf(TraceFile,
+            XFPRINTF(TraceFile,
                     "\tver:(%u %u) suiteId:(%02x %02x) suiteName:(%s) "
                     #ifdef HAVE_SNI
@@ -1143,5 +1245,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tAdding %d to %s\n", add, name);
+        XFPRINTF(TraceFile, "\tAdding %d to %s\n", add, name);
     }
 }
@@ -1310,5 +1412,5 @@
 {
     SnifferSession* session;
-    time_t          currTime = time(NULL);
+    time_t          currTime = XTIME(NULL);
     word32          row = SessionHash(ipInfo, tcpInfo);
 
@@ -1358,5 +1460,5 @@
 
 static int LoadKeyFile(byte** keyBuf, word32* keyBufSz,
-                const char* keyFile, int typeKey,
+                const char* keyFile, int keySz, int typeKey,
                 const char* password)
 {
@@ -1364,5 +1466,5 @@
     long fileSz = 0;
     XFILE file;
-    int ret;
+    int ret = -1;
 
     if (keyBuf == NULL || keyBufSz == NULL || keyFile == NULL) {
@@ -1370,29 +1472,41 @@
     }
 
-    file = XFOPEN(keyFile, "rb");
-    if (file == XBADFILE) return -1;
-    if(XFSEEK(file, 0, XSEEK_END) != 0) {
+    if (keySz == 0) {
+        /* load from file */
+        file = XFOPEN(keyFile, "rb");
+        if (file == XBADFILE) return -1;
+        if(XFSEEK(file, 0, XSEEK_END) != 0) {
+            XFCLOSE(file);
+            return -1;
+        }
+        fileSz = XFTELL(file);
+        if (fileSz > MAX_WOLFSSL_FILE_SIZE || fileSz < 0) {
+            XFCLOSE(file);
+            return -1;
+        }
+        XREWIND(file);
+
+        loadBuf = (byte*)XMALLOC(fileSz, NULL, DYNAMIC_TYPE_FILE);
+        if (loadBuf == NULL) {
+            XFCLOSE(file);
+            return -1;
+        }
+
+        ret = (int)XFREAD(loadBuf, 1, fileSz, file);
         XFCLOSE(file);
-        return -1;
-    }
-    fileSz = XFTELL(file);
-    if (fileSz > MAX_WOLFSSL_FILE_SIZE || fileSz < 0) {
-        XFCLOSE(file);
-        return -1;
-    }
-    XREWIND(file);
-
-    loadBuf = (byte*)XMALLOC(fileSz, NULL, DYNAMIC_TYPE_FILE);
-    if (loadBuf == NULL) {
-        XFCLOSE(file);
-        return -1;
-    }
-
-    ret = (int)XFREAD(loadBuf, 1, fileSz, file);
-    XFCLOSE(file);
-
-    if (ret != fileSz) {
-        XFREE(loadBuf, NULL, DYNAMIC_TYPE_FILE);
-        return -1;
+
+        if (ret != fileSz) {
+            XFREE(loadBuf, NULL, DYNAMIC_TYPE_FILE);
+            return -1;
+        }
+    }
+    else {
+        /* use buffer directly */
+        loadBuf = (byte*)XMALLOC(keySz, NULL, DYNAMIC_TYPE_FILE);
+        if (loadBuf == NULL) {
+            return -1;
+        }
+        fileSz = keySz;
+        XMEMCPY(loadBuf, keyFile, fileSz);        
     }
 
@@ -1450,5 +1564,5 @@
     }
     InitSnifferServer(sniffer);
-    sniffer->ctx = SSL_CTX_new(TLSv1_2_client_method());
+    sniffer->ctx = wolfSSL_CTX_new(SSLv23_client_method());
     if (!sniffer->ctx) {
         SetError(MEMORY_STR, error, NULL, 0);
@@ -1469,5 +1583,6 @@
 
 static int SetNamedPrivateKey(const char* name, const char* address, int port,
-            const char* keyFile, int typeKey, const char* password, char* error)
+    const char* keyFile, int keySz, int typeKey, const char* password,
+    char* error, int isEphemeralKey)
 {
     SnifferServer* sniffer;
@@ -1498,7 +1613,7 @@
         XSTRNCPY(namedKey->name, name, namedKey->nameSz);
         namedKey->name[MAX_SERVER_NAME-1] = '\0';
-
+        namedKey->isEphemeralKey = isEphemeralKey;
         ret = LoadKeyFile(&namedKey->key, &namedKey->keySz,
-                          keyFile, type, password);
+                          keyFile, keySz, type, password);
         if (ret < 0) {
             SetError(KEY_FILE_STR, error, NULL, 0);
@@ -1510,7 +1625,12 @@
 
     serverIp.version = IPV4;
-    serverIp.ip4 = inet_addr(address);
-    if (serverIp.ip4 == INADDR_NONE) {
-        if (inet_pton(AF_INET6, address, serverIp.ip6) == 1) {
+    serverIp.ip4 = XINET_ADDR(address);
+    if (serverIp.ip4 == XINADDR_NONE) {
+    #ifdef FUSION_RTOS
+        if (XINET_PTON(AF_INET6, address, serverIp.ip6,
+                       sizeof(serverIp.ip4)) == 1) {
+    #else
+        if (XINET_PTON(AF_INET6, address, serverIp.ip6) == 1) {
+    #endif
             serverIp.version = IPV6;
         }
@@ -1540,5 +1660,5 @@
         sniffer->port = port;
 
-        sniffer->ctx = SSL_CTX_new(TLSv1_2_client_method());
+        sniffer->ctx = wolfSSL_CTX_new(SSLv23_client_method());
         if (!sniffer->ctx) {
             SetError(MEMORY_STR, error, NULL, 0);
@@ -1554,10 +1674,30 @@
         if (password) {
     #ifdef WOLFSSL_ENCRYPTED_KEYS
-            SSL_CTX_set_default_passwd_cb(sniffer->ctx, SetPassword);
-            SSL_CTX_set_default_passwd_cb_userdata(
+            wolfSSL_CTX_set_default_passwd_cb(sniffer->ctx, SetPassword);
+            wolfSSL_CTX_set_default_passwd_cb_userdata(
                                                  sniffer->ctx, (void*)password);
     #endif
         }
-        ret = SSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type);
+
+    #ifdef WOLFSSL_STATIC_EPHEMERAL
+        if (isEphemeralKey) {
+            /* auto detect key type with WC_PK_TYPE_NONE */
+            /* keySz == 0 mean load file */
+            ret = wolfSSL_CTX_set_ephemeral_key(sniffer->ctx, WC_PK_TYPE_NONE, 
+                keyFile, 0, type);
+            if (ret == 0)
+                ret = WOLFSSL_SUCCESS;
+        }
+        else
+    #endif
+        {
+            if (keySz == 0) {
+                ret = wolfSSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type);
+            }
+            else {
+                ret = wolfSSL_CTX_use_PrivateKey_buffer(sniffer->ctx,
+                                            (const byte*)keyFile, keySz, type);
+            }
+        }
         if (ret != WOLFSSL_SUCCESS) {
             SetError(KEY_FILE_STR, error, NULL, 0);
@@ -1589,5 +1729,4 @@
 
 #ifdef HAVE_SNI
-
 /* Sets the private key for a specific name, server and port  */
 /* returns 0 on success, -1 on error */
@@ -1603,6 +1742,6 @@
 
     wc_LockMutex(&ServerListMutex);
-    ret = SetNamedPrivateKey(name, address, port, keyFile,
-                             typeKey, password, error);
+    ret = SetNamedPrivateKey(name, address, port, keyFile, 0,
+                             typeKey, password, error, 0);
     wc_UnLockMutex(&ServerListMutex);
 
@@ -1613,11 +1752,31 @@
 }
 
-#endif
-
+int ssl_SetNamedPrivateKeyBuffer(const char* name,
+                                 const char* address, int port,
+                                 const char* keyBuf, int keySz, int typeKey, 
+                                 const char* password, char* error)
+{
+    int ret;
+
+    TraceHeader();
+    TraceSetNamedServer(name, address, port, NULL);
+
+    wc_LockMutex(&ServerListMutex);
+    ret = SetNamedPrivateKey(name, address, port, keyBuf, keySz,
+                             typeKey, password, error, 0);
+    wc_UnLockMutex(&ServerListMutex);
+
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+
+    return ret;
+}
+#endif /* HAVE_SNI */
 
 /* Sets the private key for a specific server and port  */
 /* returns 0 on success, -1 on error */
-int ssl_SetPrivateKey(const char* address, int port, const char* keyFile,
-                      int typeKey, const char* password, char* error)
+int ssl_SetPrivateKey(const char* address, int port, 
+                      const char* keyFile, int typeKey, 
+                      const char* password, char* error)
 {
     int ret;
@@ -1627,6 +1786,6 @@
 
     wc_LockMutex(&ServerListMutex);
-    ret = SetNamedPrivateKey(NULL, address, port, keyFile,
-                             typeKey, password, error);
+    ret = SetNamedPrivateKey(NULL, address, port, keyFile, 0,
+                             typeKey, password, error, 0);
     wc_UnLockMutex(&ServerListMutex);
 
@@ -1637,4 +1796,113 @@
 }
 
+int ssl_SetPrivateKeyBuffer(const char* address, int port,
+                            const char* keyBuf, int keySz, int typeKey, 
+                            const char* password, char* error)
+{
+    int ret;
+
+    TraceHeader();
+    TraceSetServer(address, port, "from buffer");
+
+    wc_LockMutex(&ServerListMutex);
+    ret = SetNamedPrivateKey(NULL, address, port, keyBuf, keySz,
+                             typeKey, password, error, 0);
+    wc_UnLockMutex(&ServerListMutex);
+
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+
+    return ret;
+}
+
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+#ifdef HAVE_SNI
+/* Sets the ephemeral key for a specific name, server and port  */
+/* returns 0 on success, -1 on error */
+int ssl_SetNamedEphemeralKey(const char* name,
+                             const char* address, int port,
+                             const char* keyFile, int typeKey,
+                             const char* password, char* error)
+{
+    int ret;
+    
+    TraceHeader();
+    TraceSetNamedServer(name, address, port, keyFile);
+    
+    wc_LockMutex(&ServerListMutex);
+    ret = SetNamedPrivateKey(name, address, port, keyFile, 0,
+                             typeKey, password, error, 1);
+    wc_UnLockMutex(&ServerListMutex);
+    
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+    
+    return ret;
+}
+
+int ssl_SetNamedEphemeralKeyBuffer(const char* name,
+                                   const char* address, int port,
+                                   const char* keyBuf, int keySz, int typeKey, 
+                                   const char* password, char* error)
+{
+    int ret;
+    
+    TraceHeader();
+    TraceSetNamedServer(name, address, port, NULL);
+    
+    wc_LockMutex(&ServerListMutex);
+    ret = SetNamedPrivateKey(name, address, port, keyBuf, keySz,
+                             typeKey, password, error, 1);
+    wc_UnLockMutex(&ServerListMutex);
+    
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+    
+    return ret;
+}
+#endif /* HAVE_SNI */
+
+/* Sets the ephemeral key for a specific server and port  */
+/* returns 0 on success, -1 on error */
+int ssl_SetEphemeralKey(const char* address, int port, 
+                        const char* keyFile, int typeKey, 
+                        const char* password, char* error)
+{
+    int ret;
+    
+    TraceHeader();
+    TraceSetServer(address, port, keyFile);
+    
+    wc_LockMutex(&ServerListMutex);
+    ret = SetNamedPrivateKey(NULL, address, port, keyFile, 0,
+                             typeKey, password, error, 1);
+    wc_UnLockMutex(&ServerListMutex);
+    
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+    
+    return ret;
+}
+
+int ssl_SetEphemeralKeyBuffer(const char* address, int port, 
+                              const char* keyBuf, int keySz, int typeKey, 
+                              const char* password, char* error)
+{
+    int ret;
+    
+    TraceHeader();
+    TraceSetServer(address, port, "from buffer");
+    
+    wc_LockMutex(&ServerListMutex);
+    ret = SetNamedPrivateKey(NULL, address, port, keyBuf, keySz,
+                             typeKey, password, error, 1);
+    wc_UnLockMutex(&ServerListMutex);
+    
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+    
+    return ret;
+}
+#endif /* WOLFSSL_STATIC_EPHEMERAL */
 
 /* Check IP Header for IPV6, TCP, and a registered server address */
@@ -1677,6 +1945,6 @@
 
     info->length = exthdrsz;
-    info->total = ntohs(iphdr->length) + info->length;
-        /* IPv6 doesn't include its own header size in the length like v4. */
+    info->total = XNTOHS(iphdr->length) + info->length;
+    /* IPv6 doesn't include its own header size in the length like v4. */
     info->src.version = IPV6;
     XMEMCPY(info->src.ip6, iphdr->src, sizeof(info->src.ip6));
@@ -1693,5 +1961,5 @@
 static int CheckIpHdr(IpHdr* iphdr, IpInfo* info, int length, char* error)
 {
-    int    version = IP_V(iphdr);
+    int version = IP_V(iphdr);
 
     if (version == IPV6)
@@ -1719,5 +1987,5 @@
 
     info->length  = IP_HL(iphdr);
-    info->total   = ntohs(iphdr->length);
+    info->total   = XNTOHS(iphdr->length);
     info->src.version = IPV4;
     info->src.ip4 = iphdr->src;
@@ -1738,8 +2006,8 @@
     TraceTcp(tcphdr);
     Trace(TCP_CHECK_STR);
-    info->srcPort   = ntohs(tcphdr->srcPort);
-    info->dstPort   = ntohs(tcphdr->dstPort);
+    info->srcPort   = XNTOHS(tcphdr->srcPort);
+    info->dstPort   = XNTOHS(tcphdr->dstPort);
     info->length    = TCP_LEN(tcphdr);
-    info->sequence  = ntohl(tcphdr->sequence);
+    info->sequence  = XNTOHL(tcphdr->sequence);
     info->fin       = tcphdr->flags & TCP_FIN;
     info->rst       = tcphdr->flags & TCP_RST;
@@ -1747,5 +2015,5 @@
     info->ack       = tcphdr->flags & TCP_ACK;
     if (info->ack)
-        info->ackNumber = ntohl(tcphdr->ack);
+        info->ackNumber = XNTOHL(tcphdr->ack);
 
 #ifndef WOLFSSL_SNIFFER_WATCH
@@ -1802,5 +2070,5 @@
             }
             sslInfo->keySize = session->keySz;
-            #ifdef HAVE_SNI
+        #ifdef HAVE_SNI
             if (NULL != session->sni) {
                 XSTRNCPY((char*)sslInfo->serverNameIndication,
@@ -1809,5 +2077,5 @@
                          [sizeof(sslInfo->serverNameIndication) - 1] = '\0';
             }
-            #endif
+        #endif
             TraceSessionInfo(sslInfo);
         }
@@ -1826,40 +2094,79 @@
 }
 
-
-/* Process Client Key Exchange, RSA or static ECDH */
-static int ProcessClientKeyExchange(const byte* input, int* sslBytes,
-                                    SnifferSession* session, char* error)
+#ifdef SHOW_SECRETS
+static void PrintSecret(const char* desc, const byte* buf, int sz)
+{
+    int i;
+    printf("%s: ", desc);
+    for (i = 0; i < sz; i++) {
+        printf("%02x", buf[i]);
+    }
+    printf("\n");
+}
+
+static void ShowTlsSecrets(SnifferSession* session)
+{
+    PrintSecret("server master secret", session->sslServer->arrays->masterSecret, SECRET_LEN);
+    PrintSecret("client master secret", session->sslClient->arrays->masterSecret, SECRET_LEN);
+    printf("server suite = %d\n", session->sslServer->options.cipherSuite);
+    printf("client suite = %d\n", session->sslClient->options.cipherSuite);
+}
+#endif /* SHOW_SECRETS */
+
+
+/* Process Keys */
+
+/* contains static ephemeral keys */
+typedef struct {
+#ifndef NO_DH
+    DerBuffer* dhKey;
+#endif
+#ifdef HAVE_ECC
+    DerBuffer* ecKey;
+#endif
+#if !defined(NO_RSA) && defined(WOLFSSL_STATIC_RSA)
+    DerBuffer* rsaKey;
+#endif
+} KeyBuffers_t;
+
+static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, 
+    char* error, KeyShareInfo* ksInfo, KeyBuffers_t* keys)
 {
     word32 idx = 0;
-    int tryEcc = 0;
     int ret;
-
-    if (session->sslServer->buffers.key == NULL ||
-        session->sslServer->buffers.key->buffer == NULL ||
-        session->sslServer->buffers.key->length == 0) {
-
-        SetError(RSA_KEY_MISSING_STR, error, session, FATAL_ERROR_STATE);
-        return -1;
-    }
-
-    {
+    DerBuffer* keyBuf;
+#ifdef HAVE_ECC
+    int useEccCurveId = ECC_CURVE_DEF;
+    if (ksInfo && ksInfo->curve_id != 0)
+        useEccCurveId = ksInfo->curve_id;
+#endif
+
+#ifndef NO_RSA
+    /* Static RSA */
+    if (ksInfo == NULL && keys->rsaKey) {
         RsaKey key;
         int length;
 
+        keyBuf = keys->rsaKey;
+
         ret = wc_InitRsaKey(&key, 0);
         if (ret == 0) {
-            ret = wc_RsaPrivateKeyDecode(
-                    session->sslServer->buffers.key->buffer,
-                    &idx, &key, session->sslServer->buffers.key->length);
+            ret = wc_RsaPrivateKeyDecode(keyBuf->buffer, &idx, &key, keyBuf->length);
             if (ret != 0) {
-                tryEcc = 1;
-                #ifndef HAVE_ECC
-                    SetError(RSA_DECODE_STR, error, session, FATAL_ERROR_STATE);
-                #else
-                    /* If we can do ECC, this isn't fatal. Not loading an ECC
-                     * key will be fatal, though. */
-                    SetError(RSA_DECODE_STR, error, session, 0);
-                #endif
-            }
+            #ifndef HAVE_ECC
+                SetError(RSA_DECODE_STR, error, session, FATAL_ERROR_STATE);
+            #else
+                /* If we can do ECC, this isn't fatal. Not loading an ECC
+                    * key will be fatal, though. */
+                SetError(RSA_DECODE_STR, error, session, 0);
+                if (keys->ecKey == NULL)
+                    keys->ecKey = session->sslServer->buffers.key; /* try ECC */
+            #endif
+            }
+        #ifdef HAVE_ECC
+            else {
+                useEccCurveId = -1; /* don't try loading ECC */
+            }
+        #endif
         }
 
@@ -1909,11 +2216,104 @@
         wc_FreeRsaKey(&key);
     }
-
-    if (tryEcc) {
+#endif /* !NO_RSA */
+
+#if !defined(NO_DH) && defined(WOLFSSL_DH_EXTRA)
+    /* Static DH Key */
+    if (ksInfo && ksInfo->dh_key_bits != 0 && keys->dhKey) {
+        DhKey dhKey;
+        const DhParams* params;
+        word32 privKeySz;
+        byte privKey[52]; /* max for TLS */
+        
+        keyBuf = keys->dhKey;
+
+        /* get DH params */
+        switch (ksInfo->named_group) {
+        #ifdef HAVE_FFDHE_2048
+            case WOLFSSL_FFDHE_2048:
+                params = wc_Dh_ffdhe2048_Get();
+                privKeySz = 29;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_3072
+            case WOLFSSL_FFDHE_3072:
+                params = wc_Dh_ffdhe3072_Get();
+                privKeySz = 34;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_4096
+            case WOLFSSL_FFDHE_4096:
+                params = wc_Dh_ffdhe4096_Get();
+                privKeySz = 39;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_6144
+            case WOLFSSL_FFDHE_6144:
+                params = wc_Dh_ffdhe6144_Get();
+                privKeySz = 46;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_8192
+            case WOLFSSL_FFDHE_8192:
+                params = wc_Dh_ffdhe8192_Get();
+                privKeySz = 52;
+                break;
+        #endif
+            default:
+                return BAD_FUNC_ARG;
+        }
+
+        ret = wc_InitDhKey(&dhKey);
+        if (ret == 0) {
+            ret = wc_DhSetKey(&dhKey,
+                (byte*)params->p, params->p_len,
+                (byte*)params->g, params->g_len);
+            if (ret == 0) {
+                ret = wc_DhKeyDecode(keyBuf->buffer, &idx, &dhKey, 
+                    keyBuf->length);
+            }
+            if (ret == 0) {
+                ret = wc_DhExportKeyPair(&dhKey, privKey, &privKeySz, NULL, 
+                    NULL);
+            }
+
+            /* Derive secret from private key and peer's public key */
+            do {
+            #ifdef WOLFSSL_ASYNC_CRYPT
+                ret = wc_AsyncWait(ret, &dhPriv.asyncDev,
+                        WC_ASYNC_FLAG_CALL_AGAIN);
+            #endif
+                if (ret >= 0) {
+                    ret = wc_DhAgree(&dhKey,
+                        session->sslServer->arrays->preMasterSecret,
+                        &session->sslServer->arrays->preMasterSz,
+                        privKey, privKeySz,
+                        input, *sslBytes);
+                }
+            } while (ret == WC_PENDING_E);
+
+            wc_FreeDhKey(&dhKey);
+        
+            /* left-padded with zeros up to the size of the prime */
+            if (params->p_len > session->sslServer->arrays->preMasterSz) {
+                word32 diff = params->p_len - session->sslServer->arrays->preMasterSz;
+                XMEMMOVE(session->sslServer->arrays->preMasterSecret + diff,
+                        session->sslServer->arrays->preMasterSecret, 
+                        session->sslServer->arrays->preMasterSz);
+                XMEMSET(session->sslServer->arrays->preMasterSecret, 0, diff);
+                session->sslServer->arrays->preMasterSz = params->p_len;
+            }
+        }
+    }
+#endif /* !NO_DH && WOLFSSL_DH_EXTRA */
+
 #ifdef HAVE_ECC
+    /* Static ECC Key */
+    if (useEccCurveId >= ECC_CURVE_DEF && keys->ecKey) {
         ecc_key key;
         ecc_key pubKey;
         int length, keyInit = 0, pubKeyInit = 0;
 
+        keyBuf = keys->ecKey;
         idx = 0;
         ret = wc_ecc_init(&key);
@@ -1922,9 +2322,16 @@
             ret = wc_ecc_init(&pubKey);
         }
+
+    #if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
+        (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
+        !defined(HAVE_SELFTEST)
+        if (ret == 0) {
+            ret = wc_ecc_set_rng(&key, session->sslServer->rng);
+        }
+    #endif
+
         if (ret == 0) {
             pubKeyInit = 1;
-            ret = wc_EccPrivateKeyDecode(
-                    session->sslServer->buffers.key->buffer,
-                    &idx, &key, session->sslServer->buffers.key->length);
+            ret = wc_EccPrivateKeyDecode(keyBuf->buffer, &idx, &key, keyBuf->length);
             if (ret != 0) {
                 SetError(ECC_DECODE_STR, error, session, FATAL_ERROR_STATE);
@@ -1936,17 +2343,21 @@
             /* The length should be 2 times the key size (x and y), plus 1
              * for the type byte. */
-            if (IsTLS(session->sslServer)) {
+            if (!IsAtLeastTLSv1_3(session->sslServer->version)) {
                 input += 1; /* Don't include the TLS length for the key. */
             }
 
-            if (length + 1 > *sslBytes) {
-                SetError(PARTIAL_INPUT_STR,
-                        error, session, FATAL_ERROR_STATE);
+            if (length > *sslBytes) {
+                SetError(PARTIAL_INPUT_STR, error, session, FATAL_ERROR_STATE);
                 ret = -1;
             }
+
+            /* if curve not provided in key share data, then use private key curve */
+            if (useEccCurveId == ECC_CURVE_DEF && key.dp) {
+                useEccCurveId = key.dp->id;
+            }
         }
 
         if (ret == 0) {
-            ret = wc_ecc_import_x963_ex(input, length, &pubKey, ECC_CURVE_DEF);
+            ret = wc_ecc_import_x963_ex(input, length, &pubKey, useEccCurveId);
             if (ret != 0) {
                 SetError(ECC_PUB_DECODE_STR, error, session, FATAL_ERROR_STATE);
@@ -1983,6 +2394,6 @@
         if (pubKeyInit)
             wc_ecc_free(&pubKey);
-#endif
-    }
+    }
+#endif /* HAVE_ECC */
 
     /* store for client side as well */
@@ -1993,13 +2404,9 @@
         session->sslServer->arrays->preMasterSz;
 
-    #ifdef SHOW_SECRETS
-    {
-        word32 i;
-        printf("pre master secret: ");
-        for (i = 0; i < session->sslServer->arrays->preMasterSz; i++)
-            printf("%02x", session->sslServer->arrays->preMasterSecret[i]);
-        printf("\n");
-    }
-    #endif
+#ifdef SHOW_SECRETS
+    PrintSecret("pre master secret", 
+                session->sslServer->arrays->preMasterSecret, 
+                session->sslServer->arrays->preMasterSz);
+#endif
 
     if (SetCipherSpecs(session->sslServer) != 0) {
@@ -2013,9 +2420,29 @@
     }
 
-    ret  = MakeMasterSecret(session->sslServer);
-    ret += MakeMasterSecret(session->sslClient);
-    ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE);
-    ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE);
-
+#ifdef WOLFSSL_TLS13
+    /* TLS v1.3 derive handshake key */
+    if (IsAtLeastTLSv1_3(session->sslServer->version)) {
+        ret  = DeriveEarlySecret(session->sslServer);
+        ret += DeriveEarlySecret(session->sslClient);
+        ret += DeriveHandshakeSecret(session->sslServer);
+        ret += DeriveHandshakeSecret(session->sslClient);
+        ret += DeriveTls13Keys(session->sslServer, handshake_key, ENCRYPT_AND_DECRYPT_SIDE, 1);
+        ret += DeriveTls13Keys(session->sslClient, handshake_key, ENCRYPT_AND_DECRYPT_SIDE, 1);
+    #ifdef WOLFSSL_EARLY_DATA
+        ret += SetKeysSide(session->sslServer, DECRYPT_SIDE_ONLY);
+        ret += SetKeysSide(session->sslClient, DECRYPT_SIDE_ONLY);
+    #else
+        ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE);
+        ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE);
+    #endif
+    }
+    else
+#endif
+    {
+        ret  = MakeMasterSecret(session->sslServer);
+        ret += MakeMasterSecret(session->sslClient);
+        ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE);
+        ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE);
+    }
     if (ret != 0) {
         SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE);
@@ -2024,19 +2451,8 @@
 
 #ifdef SHOW_SECRETS
-    {
-        int i;
-        printf("server master secret: ");
-        for (i = 0; i < SECRET_LEN; i++)
-            printf("%02x", session->sslServer->arrays->masterSecret[i]);
-        printf("\n");
-
-        printf("client master secret: ");
-        for (i = 0; i < SECRET_LEN; i++)
-            printf("%02x", session->sslClient->arrays->masterSecret[i]);
-        printf("\n");
-
-        printf("server suite = %d\n", session->sslServer->options.cipherSuite);
-        printf("client suite = %d\n", session->sslClient->options.cipherSuite);
-    }
+    #ifdef WOLFSSL_TLS13
+    if (!IsAtLeastTLSv1_3(session->sslServer->version))
+    #endif
+        ShowTlsSecrets(session);
 #endif
 
@@ -2046,4 +2462,155 @@
 }
 
+/* Process Client Key Exchange, static RSA  */
+static int ProcessClientKeyExchange(const byte* input, int* sslBytes,
+                            SnifferSession* session, char* error)
+{
+    KeyBuffers_t keys;
+
+    if (session->sslServer->buffers.key == NULL ||
+        session->sslServer->buffers.key->buffer == NULL ||
+        session->sslServer->buffers.key->length == 0) {
+
+        SetError(RSA_KEY_MISSING_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    XMEMSET(&keys, 0, sizeof(keys));
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+    #ifndef NO_DH
+    keys.dhKey = session->sslServer->staticKE.dhKey;
+    #endif
+    #ifdef HAVE_ECC
+    keys.ecKey = session->sslServer->staticKE.ecKey;
+    #endif
+#endif
+    keys.rsaKey = session->sslServer->buffers.key;
+    return SetupKeys(input, sslBytes, session, error, NULL, &keys);
+}
+
+#ifdef WOLFSSL_TLS13
+static int ProcessKeyShare(KeyShareInfo* info, const byte* input, int len,
+    word16 filter_group)
+{
+    int index = 0;
+    while (index < len) {
+        /* clear info (reset dh_key_bits and curve_id) */
+        XMEMSET(info, 0, sizeof(KeyShareInfo));
+
+        /* Named group and public key */
+        info->named_group = (word16)((input[index] << 8) | input[index+1]);
+        index += OPAQUE16_LEN;
+        info->key_len = 0;
+        info->key = NULL;
+        /* If key was provided... (a hello_retry_request will not send a key) */
+        if (index + 2 <= len) {
+            info->key_len = (word16)((input[index] << 8) | input[index+1]);
+            index += OPAQUE16_LEN;
+            if (info->key_len == 0 || info->key_len > len - index) {
+                return -1;
+            }
+            info->key = &input[index];
+            index += info->key_len;
+        }
+
+        switch (info->named_group) {
+    #ifndef NO_DH
+        #ifdef HAVE_FFDHE_2048
+            case WOLFSSL_FFDHE_2048:
+                info->dh_key_bits = 2048;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_3072
+            case WOLFSSL_FFDHE_3072:
+                info->dh_key_bits = 3072;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_4096
+            case WOLFSSL_FFDHE_4096:
+                info->dh_key_bits = 4096;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_6144
+            case WOLFSSL_FFDHE_6144:
+                info->dh_key_bits = 6144;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_8192
+            case WOLFSSL_FFDHE_8192:
+                info->dh_key_bits = 8192;
+                break;
+        #endif
+    #endif /* !NO_DH */
+    #ifdef HAVE_ECC
+        #if !defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+            case WOLFSSL_ECC_SECP256R1:
+                info->curve_id = ECC_SECP256R1;
+                break;
+            #endif /* !NO_ECC_SECP */
+        #endif
+        #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+            case WOLFSSL_ECC_SECP384R1:
+                info->curve_id = ECC_SECP384R1;
+                break;
+            #endif /* !NO_ECC_SECP */
+        #endif
+        #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+            case WOLFSSL_ECC_SECP521R1:
+                info->curve_id = ECC_SECP521R1;
+                break;
+            #endif /* !NO_ECC_SECP */
+        #endif
+    #endif /* HAVE_ECC */
+        #ifdef HAVE_CURVE25519
+            case WOLFSSL_ECC_X25519:
+                info->curve_id = ECC_X25519;
+                break;
+        #endif
+        #ifdef HAVE_X448
+            case WOLFSSL_ECC_X448:
+                info->curve_id = ECC_X448;
+                break;
+        #endif
+            default:
+                /* do not throw error here, keep iterating the client key share */
+                break;
+        }
+
+        if (filter_group == 0 || filter_group == info->named_group) {
+            return 0;
+        }
+    }
+    return NO_PEER_KEY; /* unsupported key type */
+}
+
+static int ProcessServerKeyShare(SnifferSession* session, const byte* input, int len,
+    char* error)
+{
+    int ret;
+
+    if (session->cliKeyShare == NULL || session->cliKeyShareSz == 0) {
+        /* session->cliKeyShareSz could not be provided yet if the client_hello 
+            did not send a key share to force a hello_retry_request */
+        return 0;
+    }
+
+    /* Get server_hello key share (and key) */
+    ret = ProcessKeyShare(&session->srvKs, input, len, 0);
+    if (ret == 0 && session->srvKs.key_len > 0) {
+        /* Get client_hello key share */
+        ret = ProcessKeyShare(&session->cliKs, session->cliKeyShare,
+            session->cliKeyShareSz, session->srvKs.named_group);
+    }
+    if (ret != 0) {
+        SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    return ret;
+} 
+#endif /* WOLFSSL_TLS13 */
 
 /* Process Session Ticket */
@@ -2053,30 +2620,200 @@
     word16 len;
 
-    /* make sure can read through hint and len */
-    if (TICKET_HINT_LEN + LENGTH_SZ > *sslBytes) {
+#ifdef WOLFSSL_TLS13
+    WOLFSSL* ssl;
+
+    if (session->flags.side == WOLFSSL_SERVER_END)
+        ssl = session->sslServer;
+    else
+        ssl = session->sslClient;
+#endif
+
+    /* make sure can read through hint len */
+    if (TICKET_HINT_LEN > *sslBytes) {
         SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
         return -1;
     }
-
-    input     += TICKET_HINT_LEN;  /* skip over hint */
+    input     += TICKET_HINT_LEN; /* skip over hint len */
     *sslBytes -= TICKET_HINT_LEN;
 
-    len = (word16)((input[0] << 8) | input[1]);
-    input     += LENGTH_SZ;
-    *sslBytes -= LENGTH_SZ;
-
-    /* make sure can read through ticket */
-    if (len > *sslBytes || len < ID_LEN) {
+#ifdef WOLFSSL_TLS13
+    /* TLS v1.3 has hint age and nonce */
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+        /* make sure can read through hint age and nonce len */
+        if (TICKET_HINT_AGE_LEN + 1 > *sslBytes) {
+            SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        input     += TICKET_HINT_AGE_LEN; /* skip over hint age */
+        *sslBytes -= TICKET_HINT_AGE_LEN;
+
+        /* ticket nonce */
+        len = input[0];
+        if (len > MAX_TICKET_NONCE_SZ) {
+            SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        input += OPAQUE8_LEN;
+        *sslBytes -= OPAQUE8_LEN;
+    #ifdef HAVE_SESSION_TICKET
+        /* store nonce in server for DeriveResumptionPSK */
+        session->sslServer->session.ticketNonce.len = len;
+        if (len > 0)
+            XMEMCPY(&session->sslServer->session.ticketNonce.data, input, len);
+    #endif
+        input += len;
+        *sslBytes -= len;
+    }
+#endif
+
+    /* make sure can read through len */
+    if (OPAQUE16_LEN > *sslBytes) {
         SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
         return -1;
     }
 
-    /* store session with macID as sessionID */
-    session->sslServer->options.haveSessionId = 1;
-    XMEMCPY(session->sslServer->arrays->sessionID, input + len - ID_LEN,ID_LEN);
+    len = (word16)((input[0] << 8) | input[1]);
+    input     += OPAQUE16_LEN;
+    *sslBytes -= OPAQUE16_LEN;
+
+    /* make sure can read through ticket */
+    if (len > *sslBytes) {
+        SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+#ifdef WOLFSSL_TLS13
+    /* TLS v1.3 has hint age and nonce */
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+    #ifdef HAVE_SESSION_TICKET
+        if (SetTicket(ssl, input, len) != 0) {
+            SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        /* set haveSessionId to use the wolfSession cache */
+        ssl->options.haveSessionId = 1;
+
+        /* Use the wolf Session cache to retain resumption secret */
+        if (session->flags.cached == 0) {
+            WOLFSSL_SESSION* sess = GetSession(ssl, NULL, 0);
+            if (sess == NULL) {
+                AddSession(ssl); /* don't re add */
+            #ifdef WOLFSSL_SNIFFER_STATS
+                INC_STAT(SnifferStats.sslResumptionInserts);
+            #endif
+            }
+            session->flags.cached = 1;
+        }
+    #endif /* HAVE_SESSION_TICKET */
+    }
+    else
+#endif /* WOLFSSL_TLS13 */
+    {
+        /* capture last part of sessionID as macID (32 bytes) */
+        if (len < ID_LEN) {
+            SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        /* store session with macID as sessionID */
+        session->sslServer->options.haveSessionId = 1;
+        XMEMCPY(session->sslServer->arrays->sessionID, 
+            input + len - ID_LEN, ID_LEN);
+    }
 
     return 0;
 }
 
+static int DoResume(SnifferSession* session, char* error)
+{
+    int ret = 0;
+    WOLFSSL_SESSION* resume;
+
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(session->sslServer->version)) {
+        resume = GetSession(session->sslServer, 
+                            session->sslServer->session.masterSecret, 0);
+    }
+    else
+#endif
+    {
+        resume = GetSession(session->sslServer,
+                            session->sslServer->arrays->masterSecret, 0);
+    }
+    if (resume == NULL) {
+        /* a session id without resume is okay with hello_retry_request */
+    #ifdef WOLFSSL_SNIFFER_STATS
+        INC_STAT(SnifferStats.sslStandardConns);
+    #endif
+        return 0;
+    }
+
+    /* make sure client has master secret too */
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(session->sslServer->version)) {
+        XMEMCPY(session->sslClient->session.masterSecret,
+                session->sslServer->session.masterSecret, SECRET_LEN);
+    }
+    else
+#endif
+    {
+        XMEMCPY(session->sslClient->arrays->masterSecret,
+                session->sslServer->arrays->masterSecret, SECRET_LEN);
+    }
+    session->flags.resuming = 1;
+
+    Trace(SERVER_DID_RESUMPTION_STR);
+#ifdef WOLFSSL_SNIFFER_STATS
+    INC_STAT(SnifferStats.sslResumedConns);
+    INC_STAT(SnifferStats.sslResumptionValid);
+#endif
+    if (SetCipherSpecs(session->sslServer) != 0) {
+        SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    if (SetCipherSpecs(session->sslClient) != 0) {
+        SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(session->sslServer->version)) {
+    #ifdef HAVE_SESSION_TICKET
+        /* Resumption PSK is resumption master secret. */
+        session->sslServer->arrays->psk_keySz = session->sslServer->specs.hash_size;
+        session->sslClient->arrays->psk_keySz = session->sslClient->specs.hash_size;
+        ret  = DeriveResumptionPSK(session->sslServer, session->sslServer->session.ticketNonce.data, 
+            session->sslServer->session.ticketNonce.len, session->sslServer->arrays->psk_key);
+        /* Copy resumption PSK to client */
+        XMEMCPY(session->sslClient->arrays->psk_key, 
+            session->sslServer->arrays->psk_key,
+            session->sslServer->arrays->psk_keySz);
+    #endif
+        /* handshake key setup below and traffic keys done in SetupKeys */
+    }
+    else
+#endif
+    {
+        if (IsTLS(session->sslServer)) {
+            ret =  DeriveTlsKeys(session->sslServer);
+            ret += DeriveTlsKeys(session->sslClient);
+        }
+        else {
+#ifndef NO_OLD_TLS
+            ret =  DeriveKeys(session->sslServer);
+            ret += DeriveKeys(session->sslClient);
+#endif
+        }
+        ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE);
+        ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE);
+    }
+
+    if (ret != 0) {
+        SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    return ret;
+}
 
 /* Process Server Hello */
@@ -2084,17 +2821,18 @@
                               SnifferSession* session, char* error)
 {
+    int             ret = 0;
     ProtocolVersion pv;
     byte            b, b0;
     int             toRead = VERSION_SZ + RAN_LEN + ENUM_LEN;
-    int             doResume     = 0;
+    int             doResume = 0;
+    const byte*     inputHello = input;
     int             initialBytes = *sslBytes;
 
     (void)msgSz;
-    (void)initialBytes;
 
     /* make sure we didn't miss ClientHello */
-    if (session->flags.clientHello == 0) {
-        SetError(MISSED_CLIENT_HELLO_STR, error, session, FATAL_ERROR_STATE);
-        return -1;
+    if (session->flags.clientHello == 0 || session->sslClient->arrays == NULL) {
+        SetError(MISSED_CLIENT_HELLO_STR, error, session, 0);
+        return 0; /* do not throw error, just ignore packet */
     }
 
@@ -2111,8 +2849,12 @@
     session->sslServer->version = pv;
     session->sslClient->version = pv;
+    if (pv.minor >= TLSv1_MINOR) {
+        session->sslServer->options.tls = 1;
+        session->sslClient->options.tls = 1;
+    }
 
     XMEMCPY(session->sslServer->arrays->serverRandom, input, RAN_LEN);
     XMEMCPY(session->sslClient->arrays->serverRandom, input, RAN_LEN);
-    input    += RAN_LEN;
+    input     += RAN_LEN;
     *sslBytes -= RAN_LEN;
 
@@ -2126,4 +2868,7 @@
     }
     if (b) {
+    #ifdef WOLFSSL_TLS13
+        XMEMCPY(session->sslServer->session.sessionID, input, ID_LEN);
+    #endif
         XMEMCPY(session->sslServer->arrays->sessionID, input, ID_LEN);
         session->sslServer->options.haveSessionId = 1;
@@ -2169,5 +2914,4 @@
     }
 
-#ifdef HAVE_EXTENDED_MASTER
     /* extensions */
     if ((initialBytes - *sslBytes) < msgSz) {
@@ -2190,13 +2934,12 @@
 
         while (len >= EXT_TYPE_SZ + LENGTH_SZ) {
-            byte   extType[EXT_TYPE_SZ];
+            word16 extType;
             word16 extLen;
 
-            extType[0] = input[0];
-            extType[1] = input[1];
+            extType    = (word16)((input[0] << 8) | input[1]);
             input     += EXT_TYPE_SZ;
             *sslBytes -= EXT_TYPE_SZ;
 
-            extLen = (word16)((input[0] << 8) | input[1]);
+            extLen     = (word16)((input[0] << 8) | input[1]);
             input     += LENGTH_SZ;
             *sslBytes -= LENGTH_SZ;
@@ -2209,6 +2952,62 @@
             }
 
-            if (extType[0] == 0x00 && extType[1] == EXT_MASTER_SECRET) {
+            switch (extType) {
+        #ifdef WOLFSSL_TLS13
+            case EXT_KEY_SHARE:
+                ret = ProcessServerKeyShare(session, input, extLen, error);
+                if (ret != 0) {
+                    SetError(SERVER_HELLO_INPUT_STR, error, session, 
+                        FATAL_ERROR_STATE);
+                    return -1;
+                }
+                break;
+        #endif
+        #ifdef HAVE_SESSION_TICKET
+            case EXT_PRE_SHARED_KEY:
+                /* indicates we want to use resumption */
+                session->sslServer->options.resuming = 1;
+                session->sslClient->options.resuming = 1;
+            #ifdef WOLFSSL_TLS13
+                /* default nonce to len = 1, data = 0 */
+                session->sslServer->session.ticketNonce.len = 1;
+                session->sslServer->session.ticketNonce.data[0] = 0;
+                session->sslClient->session.ticketNonce.len = 1;
+                session->sslClient->session.ticketNonce.data[0] = 0;
+            #endif
+                break;
+        #endif
+        #ifdef HAVE_MAX_FRAGMENT
+            case EXT_MAX_FRAGMENT_LENGTH:
+            {
+                word16 max_fragment = MAX_RECORD_SIZE;
+                switch (input[0]) {
+                    case WOLFSSL_MFL_2_8 : max_fragment =  256; break;
+                    case WOLFSSL_MFL_2_9 : max_fragment =  512; break;
+                    case WOLFSSL_MFL_2_10: max_fragment = 1024; break;
+                    case WOLFSSL_MFL_2_11: max_fragment = 2048; break;
+                    case WOLFSSL_MFL_2_12: max_fragment = 4096; break;
+                    case WOLFSSL_MFL_2_13: max_fragment = 8192; break;
+                    default: break;
+                }
+                session->sslServer->max_fragment = max_fragment;
+                session->sslClient->max_fragment = max_fragment;
+                break;
+            }
+        #endif
+            case EXT_SUPPORTED_VERSIONS:
+                session->sslServer->version.major = input[0];
+                session->sslServer->version.minor = input[1];
+                session->sslClient->version.major = input[0];
+                session->sslClient->version.minor = input[1];
+                if (IsAtLeastTLSv1_3(session->sslServer->version)) {
+                    /* The server side handshake encryption is on for future packets */
+                    session->flags.serverCipherOn = 1;
+                }
+                break;
+            case EXT_MASTER_SECRET:
+            #ifdef HAVE_EXTENDED_MASTER
                 session->flags.expectEms = 1;
+            #endif
+                break;
             }
 
@@ -2219,4 +3018,5 @@
     }
 
+#ifdef HAVE_EXTENDED_MASTER
     if (!session->flags.expectEms) {
         XFREE(session->hash, NULL, DYNAMIC_TYPE_HASHES);
@@ -2227,11 +3027,13 @@
     if (session->sslServer->options.haveSessionId) {
         if (XMEMCMP(session->sslServer->arrays->sessionID,
-                    session->sslClient->arrays->sessionID, ID_LEN) == 0)
+                session->sslClient->arrays->sessionID, ID_LEN) == 0) {
             doResume = 1;
-    }
+        }    
+    }        
     else if (session->sslClient->options.haveSessionId == 0 &&
              session->sslServer->options.haveSessionId == 0 &&
-             session->ticketID)
+             session->ticketID) {
         doResume = 1;
+    }
 
     if (session->ticketID && doResume) {
@@ -2242,49 +3044,34 @@
     }
 
-    if (doResume ) {
-        int ret = 0;
-        SSL_SESSION* resume = GetSession(session->sslServer,
-                                  session->sslServer->arrays->masterSecret, 0);
-        if (resume == NULL) {
-#ifdef WOLFSSL_SNIFFER_STATS
-            INC_STAT(SnifferStats.sslResumeMisses);
-#endif
-            SetError(BAD_SESSION_RESUME_STR, error, session, FATAL_ERROR_STATE);
-            return -1;
-        }
-        /* make sure client has master secret too */
-        XMEMCPY(session->sslClient->arrays->masterSecret,
-               session->sslServer->arrays->masterSecret, SECRET_LEN);
-        session->flags.resuming = 1;
-
-        Trace(SERVER_DID_RESUMPTION_STR);
-#ifdef WOLFSSL_SNIFFER_STATS
-        INC_STAT(SnifferStats.sslResumedConns);
-        INC_STAT(SnifferStats.sslResumptionValid);
-#endif
-        if (SetCipherSpecs(session->sslServer) != 0) {
-            SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
-            return -1;
-        }
-
-        if (SetCipherSpecs(session->sslClient) != 0) {
-            SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
-            return -1;
-        }
-
-        if (session->sslServer->options.tls) {
-            ret =  DeriveTlsKeys(session->sslServer);
-            ret += DeriveTlsKeys(session->sslClient);
-        }
-        else {
-            ret =  DeriveKeys(session->sslServer);
-            ret += DeriveKeys(session->sslClient);
-        }
-        ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE);
-        ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE);
-
+#ifdef WOLFSSL_TLS13
+    /* Is TLS v1.3 hello_retry_request? */
+    if (IsAtLeastTLSv1_3(session->sslServer->version) && session->srvKs.key_len == 0) {
+        Trace(GOT_HELLO_RETRY_REQ_STR);
+
+        /* do not compute keys yet */
+        session->flags.serverCipherOn = 0;
+
+        /* make sure the mac and digest size are set */
+        SetCipherSpecs(session->sslServer);
+        SetCipherSpecs(session->sslClient);
+
+        /* reset hashes */
+        RestartHandshakeHash(session->sslServer);
+        RestartHandshakeHash(session->sslClient);
+
+        doResume = 0;
+    }
+#endif
+
+    /* hash server_hello */
+    HashRaw(session->sslServer, inputHello - HANDSHAKE_HEADER_SZ, 
+        initialBytes + HANDSHAKE_HEADER_SZ);
+    HashRaw(session->sslClient, inputHello - HANDSHAKE_HEADER_SZ, 
+        initialBytes + HANDSHAKE_HEADER_SZ);
+
+    if (doResume) {
+        ret = DoResume(session, error);
         if (ret != 0) {
-            SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE);
-            return -1;
+            return ret;
         }
     }
@@ -2294,15 +3081,38 @@
 #endif
     }
+
 #ifdef SHOW_SECRETS
-    {
-        int i;
-        printf("cipher suite = 0x%02x\n",
-               session->sslServer->options.cipherSuite);
-        printf("server random: ");
-        for (i = 0; i < RAN_LEN; i++)
-            printf("%02x", session->sslServer->arrays->serverRandom[i]);
-        printf("\n");
-    }
-#endif
+    printf("cipher suite = 0x%02x\n", session->sslServer->options.cipherSuite);
+    PrintSecret("server random", session->sslServer->arrays->serverRandom, RAN_LEN);
+#endif
+
+#ifdef WOLFSSL_TLS13
+    /* Setup handshake keys */
+    if (IsAtLeastTLSv1_3(session->sslServer->version) && session->srvKs.key_len > 0) {
+        KeyBuffers_t keys;
+        XMEMSET(&keys, 0, sizeof(keys));
+        keys.rsaKey = session->sslServer->buffers.key;
+    #ifdef WOLFSSL_STATIC_EPHEMERAL
+        #ifndef NO_DH
+        keys.dhKey = session->sslServer->staticKE.dhKey;
+        #endif
+        #ifdef HAVE_ECC
+        keys.ecKey = session->sslServer->staticKE.ecKey;
+        #endif
+    #endif
+        ret = SetupKeys(session->cliKs.key, &session->cliKs.key_len, 
+            session, error, &session->cliKs, &keys);
+        if (ret != 0) {
+            SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            return ret;
+        }
+
+        if (session->flags.side == WOLFSSL_SERVER_END)
+            session->flags.serverCipherOn = 1;
+        else
+            session->flags.clientCipherOn = 1;
+    }
+#endif
+
     return 0;
 }
@@ -2313,7 +3123,12 @@
                               SnifferSession* session, char* error)
 {
+    int ret = 0;
     byte   bLen;
     word16 len;
     int    toRead = VERSION_SZ + RAN_LEN + ENUM_LEN;
+    const byte* inputHello = input;
+    int inputHelloSz = *sslBytes;
+    WOLFSSL* ssl = session->sslServer;
+    int didHash = 0;
 
 #ifdef HAVE_SNI
@@ -2321,5 +3136,4 @@
         byte name[MAX_SERVER_NAME];
         word32 nameSz = sizeof(name);
-        int ret;
 
         ret = wolfSSL_SNI_GetFromBuffer(
@@ -2339,7 +3153,21 @@
                 if (nameSz == namedKey->nameSz &&
                            XSTRNCMP((char*)name, namedKey->name, nameSz) == 0) {
-                    if (wolfSSL_use_PrivateKey_buffer(session->sslServer,
-                                            namedKey->key, namedKey->keySz,
-                                            WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS) {
+                #ifdef WOLFSSL_STATIC_EPHEMERAL
+                    if (namedKey->isEphemeralKey) {
+                        /* auto detect key type with WC_PK_TYPE_NONE */
+                        ret = wolfSSL_set_ephemeral_key(ssl, 
+                            WC_PK_TYPE_NONE, (const char*)namedKey->key, 
+                            namedKey->keySz, WOLFSSL_FILETYPE_ASN1);
+                        if (ret == 0)
+                            ret = WOLFSSL_SUCCESS;
+                    }
+                    else
+                #endif
+                    {
+                        ret = wolfSSL_use_PrivateKey_buffer(ssl,
+                            namedKey->key, namedKey->keySz, 
+                            WOLFSSL_FILETYPE_ASN1);
+                    }
+                    if (ret != WOLFSSL_SUCCESS) {
                         wc_UnLockMutex(&session->context->namedKeysMutex);
                         SetError(CLIENT_HELLO_LATE_KEY_STR, error, session,
@@ -2355,4 +3183,9 @@
             wc_UnLockMutex(&session->context->namedKeysMutex);
         }
+        /* SSLv3 does not support the SNI TLS Extension and may return SNI_UNSUPPORTED */
+        if (ret > 0 || ret == SNI_UNSUPPORTED) {
+            /* make sure WOLFSSL_SUCCESS is converted to zero error code */
+            ret = 0;
+        }
     }
 #endif
@@ -2385,15 +3218,13 @@
         }
         Trace(CLIENT_RESUME_TRY_STR);
+#ifdef WOLFSSL_TLS13
+        XMEMCPY(session->sslClient->session.sessionID, input, ID_LEN);
+#endif
         XMEMCPY(session->sslClient->arrays->sessionID, input, ID_LEN);
         session->sslClient->options.haveSessionId = 1;
     }
+
 #ifdef SHOW_SECRETS
-    {
-        int i;
-        printf("client random: ");
-        for (i = 0; i < RAN_LEN; i++)
-            printf("%02x", session->sslServer->arrays->clientRandom[i]);
-        printf("\n");
-    }
+    PrintSecret("client random", ssl->arrays->clientRandom, RAN_LEN);
 #endif
 
@@ -2450,13 +3281,12 @@
 
     while (len >= EXT_TYPE_SZ + LENGTH_SZ) {
-        byte   extType[EXT_TYPE_SZ];
+        word16 extType;
         word16 extLen;
 
-        extType[0] = input[0];
-        extType[1] = input[1];
+        extType    = (word16)((input[0] << 8) | input[1]);
         input     += EXT_TYPE_SZ;
         *sslBytes -= EXT_TYPE_SZ;
 
-        extLen = (word16)((input[0] << 8) | input[1]);
+        extLen     = (word16)((input[0] << 8) | input[1]);
         input     += LENGTH_SZ;
         *sslBytes -= LENGTH_SZ;
@@ -2468,6 +3298,88 @@
         }
 
-        if (extType[0] == 0x00 && extType[1] == TICKET_EXT_ID) {
-
+        switch (extType) {
+    #ifdef WOLFSSL_TLS13
+        case EXT_KEY_SHARE:
+        {
+            word16 ksLen = (word16)((input[0] << 8) | input[1]);
+            if (ksLen + OPAQUE16_LEN > extLen) {
+                SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+                return -1;
+            }
+            /* cache key share data till server_hello */
+            session->cliKeyShareSz = ksLen;
+            session->cliKeyShare = (byte*)XMALLOC(ksLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            if (session->cliKeyShare == NULL) {
+                SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
+                break;
+            }
+            XMEMCPY(session->cliKeyShare, &input[2], ksLen);
+            break;
+        }
+        #ifdef HAVE_SESSION_TICKET
+        case EXT_PRE_SHARED_KEY:
+        {
+            word16 idsLen, idLen, bindersLen, idx = 0;
+            word32 ticketAge;
+            const byte *identity, *binders;
+
+            idsLen = (word16)((input[idx] << 8) | input[idx+1]);
+            if (idsLen + OPAQUE16_LEN + idx > extLen) {
+                SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+                return -1;
+            }
+            idx += OPAQUE16_LEN;
+
+            /* PSK identity */
+            idLen = (word16)((input[idx] << 8) | input[idx+1]);
+            if (idLen + OPAQUE16_LEN + idx > extLen) {
+                SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+                return -1;
+            }
+            idx += OPAQUE16_LEN;
+            identity = &input[idx];
+            idx += idLen;
+
+            /* Obfuscated Ticket Age 32-bits */
+            ticketAge = (word32)((input[idx] << 24) | (input[idx+1] << 16) | 
+                                 (input[idx+2] << 8) | input[idx+3]);
+            (void)ticketAge; /* not used */
+            idx += OPAQUE32_LEN;
+
+            /* binders - all binders */
+            bindersLen = (word16)((input[idx] << 8) | input[idx+1]);
+            if (bindersLen + OPAQUE16_LEN + idx > extLen) {
+                SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+                return -1;
+            }
+            idx += OPAQUE16_LEN;
+            binders = &input[idx];
+            bindersLen += OPAQUE16_LEN; /* includes 2 bytes for total len */
+            (void)binders; /* not used */
+
+            /* Hash data up to binders for deriving binders in PSK extension. */
+            HashRaw(session->sslServer, inputHello - HANDSHAKE_HEADER_SZ, 
+                inputHelloSz - bindersLen + HANDSHAKE_HEADER_SZ);
+            HashRaw(session->sslClient, inputHello - HANDSHAKE_HEADER_SZ, 
+                inputHelloSz - bindersLen + HANDSHAKE_HEADER_SZ);
+
+            /* call to decrypt session ticket */
+            if (DoClientTicket(ssl, identity, idLen) != 0) {
+                /* we aren't decrypting the resumption, since we know the master secret */
+                /* ignore errors */
+            }
+            ssl->options.resuming  = 1;
+
+            /* Hash the rest of the ClientHello. */
+            HashRaw(session->sslServer, inputHello + inputHelloSz - bindersLen, bindersLen);
+            HashRaw(session->sslClient, inputHello + inputHelloSz - bindersLen, bindersLen);
+            didHash = 1;
+            break;
+        }
+        #endif /* HAVE_SESSION_TICKET */
+    #endif /* WOLFSSL_TLS13 */
+        case EXT_SUPPORTED_VERSIONS:
+            break;
+        case EXT_TICKET_ID:
             /* make sure can read through ticket if there is a non blank one */
             if (extLen && extLen < ID_LEN) {
@@ -2476,7 +3388,6 @@
                 return -1;
             }
-
             if (extLen) {
-                if (session->ticketID == 0) {
+                if (session->ticketID == NULL) {
                     session->ticketID = (byte*)XMALLOC(ID_LEN,
                             NULL, DYNAMIC_TYPE_SNIFFER_TICKET_ID);
@@ -2489,4 +3400,5 @@
                 XMEMCPY(session->ticketID, input + extLen - ID_LEN, ID_LEN);
             }
+            break;
         }
 
@@ -2496,9 +3408,57 @@
     }
 
-    return 0;
+    if (!didHash) {
+        HashRaw(session->sslServer, inputHello - HANDSHAKE_HEADER_SZ, 
+            inputHelloSz + HANDSHAKE_HEADER_SZ);
+        HashRaw(session->sslClient, inputHello - HANDSHAKE_HEADER_SZ, 
+            inputHelloSz + HANDSHAKE_HEADER_SZ);
+    }
+
+    (void)ssl;
+
+    return ret;
 }
 
 
 #ifdef WOLFSSL_SNIFFER_WATCH
+
+static int KeyWatchCall(SnifferSession* session, const byte* data, int dataSz,
+    char* error)
+{
+    int ret;
+    Sha256 sha;
+    byte digest[SHA256_DIGEST_SIZE];
+
+    if (WatchCb == NULL) {
+        SetError(WATCH_CB_MISSING_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    ret = wc_InitSha256(&sha);
+    if (ret == 0)
+        ret = wc_Sha256Update(&sha, data, dataSz);
+    if (ret == 0)
+        ret = wc_Sha256Final(&sha, digest);
+    if (ret != 0) {
+        SetError(WATCH_HASH_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    ret = WatchCb((void*)session, digest, sizeof(digest),
+            data, dataSz, WatchCbCtx, error);
+    if (ret != 0) {
+#ifdef WOLFSSL_SNIFFER_STATS
+        INC_STAT(SnifferStats.sslKeysUnmatched);
+#endif
+        SetError(WATCH_FAIL_STR, error, session, FATAL_ERROR_STATE);
+        ret = -1;
+    }
+    else {
+#ifdef WOLFSSL_SNIFFER_STATS
+        INC_STAT(SnifferStats.sslKeyMatches);
+#endif
+    }
+    return ret;
+}
 
 /* Process Certificate */
@@ -2506,10 +3466,6 @@
         SnifferSession* session, char* error)
 {
-    Sha256 sha;
-    const byte* certChain;
     word32 certChainSz;
     word32 certSz;
-    int ret;
-    byte digest[SHA256_DIGEST_SIZE];
 
     /* If the receiver is the server, this is the client certificate message,
@@ -2518,13 +3474,17 @@
         return 0;
 
-    if (WatchCb == NULL) {
-        SetError(WATCH_CB_MISSING_STR, error, session, FATAL_ERROR_STATE);
-        return -1;
-    }
-
     if (*sslBytes < CERT_HEADER_SZ) {
         SetError(BAD_CERT_MSG_STR, error, session, FATAL_ERROR_STATE);
         return -1;
     }
+
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(session->sslServer->version)) {
+        /* skip 1 byte (Request context len) */
+        input += OPAQUE8_LEN;
+        *sslBytes -= OPAQUE8_LEN;
+    }
+#endif
+
     ato24(input, &certChainSz);
     *sslBytes -= CERT_HEADER_SZ;
@@ -2535,5 +3495,4 @@
         return -1;
     }
-    certChain = input;
 
     ato24(input, &certSz);
@@ -2546,30 +3505,5 @@
     *sslBytes -= certChainSz;
 
-    ret = wc_InitSha256(&sha);
-    if (ret == 0)
-        ret = wc_Sha256Update(&sha, input, certSz);
-    if (ret == 0)
-        ret = wc_Sha256Final(&sha, digest);
-    if (ret != 0) {
-        SetError(WATCH_HASH_STR, error, session, FATAL_ERROR_STATE);
-        return -1;
-    }
-
-    ret = WatchCb((void*)session, digest, sizeof(digest),
-            certChain, certChainSz, WatchCbCtx, error);
-    if (ret != 0) {
-#ifdef WOLFSSL_SNIFFER_STATS
-        INC_STAT(SnifferStats.sslKeysUnmatched);
-#endif
-        SetError(WATCH_FAIL_STR, error, session, FATAL_ERROR_STATE);
-        return -1;
-    }
-    else {
-#ifdef WOLFSSL_SNIFFER_STATS
-        INC_STAT(SnifferStats.sslKeyMatches);
-#endif
-    }
-
-    return 0;
+    return KeyWatchCall(session, input, certSz, error);
 }
 
@@ -2581,5 +3515,5 @@
                            SnifferSession* session, char* error)
 {
-    SSL*   ssl;
+    WOLFSSL* ssl;
     word32 inOutIdx = 0;
     int    ret;
@@ -2590,6 +3524,18 @@
         ssl = session->sslClient;
 
-    ret = DoFinished(ssl, input, &inOutIdx, (word32) size, (word32) *sslBytes,
-                                                                         SNIFF);
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+        ret = DoTls13Finished(ssl, input, &inOutIdx, (word32)size, 
+            (word32)*sslBytes, SNIFF);
+
+        ssl->options.handShakeState = HANDSHAKE_DONE;
+        ssl->options.handShakeDone  = 1;
+    }
+    else
+#endif
+    {
+        ret = DoFinished(ssl, input, &inOutIdx, (word32)size, 
+            (word32)*sslBytes, SNIFF);
+    }
     *sslBytes -= (int)inOutIdx;
 
@@ -2612,4 +3558,60 @@
     }
 
+#ifdef WOLFSSL_TLS13
+    /* Derive TLS v1.3 traffic keys */
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+        if (!session->flags.gotFinished) {
+            /* When either side gets "finished" derive master secret and keys */
+            ret  = DeriveMasterSecret(session->sslServer);
+            ret += DeriveMasterSecret(session->sslClient);
+        #ifdef WOLFSSL_EARLY_DATA
+            ret += DeriveTls13Keys(session->sslServer, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, ssl->earlyData == no_early_data);
+            ret += DeriveTls13Keys(session->sslClient, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, ssl->earlyData == no_early_data);
+        #else
+            ret += DeriveTls13Keys(session->sslServer, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, 1);
+            ret += DeriveTls13Keys(session->sslClient, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, 1);
+        #endif
+
+            if (ret != 0) {
+                SetError(BAD_FINISHED_MSG, error, session, FATAL_ERROR_STATE);
+                return -1;
+            }
+
+            session->flags.gotFinished = 1;
+        #ifdef SHOW_SECRETS
+            ShowTlsSecrets(session);    
+        #endif
+        }
+
+        if (session->flags.side == WOLFSSL_SERVER_END) {
+            /* finished from client to server */
+            ret  = SetKeysSide(session->sslServer, DECRYPT_SIDE_ONLY);
+            ret += SetKeysSide(session->sslClient, ENCRYPT_SIDE_ONLY);
+
+        #ifdef HAVE_SESSION_TICKET
+            /* derive resumption secret for next session - on finished (from client) */
+            ret += DeriveResumptionSecret(session->sslClient, session->sslClient->session.masterSecret);
+
+            /* copy resumption secret to server */
+            XMEMCPY(session->sslServer->session.masterSecret,
+                session->sslClient->session.masterSecret, SECRET_LEN);
+            #ifdef SHOW_SECRETS
+            PrintSecret("resumption secret", session->sslClient->session.masterSecret, SECRET_LEN);
+            #endif
+        #endif
+        }
+        else {
+            /* finished from server to client */
+            ret  = SetKeysSide(session->sslServer, ENCRYPT_SIDE_ONLY);
+            ret += SetKeysSide(session->sslClient, DECRYPT_SIDE_ONLY);
+        }
+
+        if (ret != 0) {
+            SetError(BAD_FINISHED_MSG, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+    }
+#endif
+
     /* If receiving a finished message from one side, free the resources
      * from the other side's tracker. */
@@ -2625,10 +3627,30 @@
 /* Process HandShake input */
 static int DoHandShake(const byte* input, int* sslBytes,
-                       SnifferSession* session, char* error)
+                       SnifferSession* session, char* error, word16 rhSize)
 {
     byte type;
     int  size;
     int  ret = 0;
-    int  startBytes;
+    WOLFSSL* ssl;
+    int startBytes;
+
+    (void)rhSize;
+
+#ifdef HAVE_MAX_FRAGMENT
+    if (session->tlsFragBuf) {
+        XMEMCPY(session->tlsFragBuf + session->tlsFragOffset, input, rhSize);
+        session->tlsFragOffset += rhSize;
+        *sslBytes -= rhSize;
+
+        if (session->tlsFragOffset < session->tlsFragSize) {
+            return 0;
+        }
+
+        /* reassembled complete fragment */
+        input = session->tlsFragBuf;
+        *sslBytes = session->tlsFragSize;
+        rhSize = session->tlsFragSize;
+    }
+#endif
 
     if (*sslBytes < HANDSHAKE_HEADER_SZ) {
@@ -2649,12 +3671,57 @@
     }
 
-    /* A session's arrays are released when the handshake is completed. */
-    if (session->sslServer->arrays == NULL &&
-        session->sslClient->arrays == NULL) {
-
-        SetError(NO_SECURE_RENEGOTIATION, error, session, FATAL_ERROR_STATE);
-        return -1;
-    }
-
+    if (session->flags.side == WOLFSSL_SERVER_END)
+        ssl = session->sslServer;
+    else
+        ssl = session->sslClient;
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+    if (!IsAtLeastTLSv1_3(ssl->version)) {
+        /* A session's arrays are released when the handshake is completed. */
+        if (session->sslServer->arrays == NULL &&
+            session->sslClient->arrays == NULL) {
+
+            SetError(NO_SECURE_RENEGOTIATION, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+    }
+#endif
+
+#ifdef HAVE_MAX_FRAGMENT
+    if (rhSize < size) {
+        /* partial fragment, let's reassemble */
+        if (session->tlsFragBuf == NULL) {
+            session->tlsFragOffset = 0;
+            session->tlsFragSize = size + HANDSHAKE_HEADER_SZ;
+            session->tlsFragBuf = (byte*)XMALLOC(session->tlsFragSize, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            if (session->tlsFragBuf == NULL) {
+                SetError(MEMORY_STR, error, NULL, 0);
+                return 0;
+            }
+
+            /* include the handshake header */
+            input -= HANDSHAKE_HEADER_SZ;
+            *sslBytes += HANDSHAKE_HEADER_SZ;
+        }
+
+        XMEMCPY(session->tlsFragBuf + session->tlsFragOffset, input, rhSize);
+        session->tlsFragOffset += rhSize;
+        *sslBytes -= rhSize;
+        return 0;
+    }
+#endif
+
+#ifdef WOLFSSL_TLS13
+    if (type != client_hello && type != server_hello) {
+        /* For resumption the hash is before / after client_hello PSK binder */
+        /* hash the packet including header */
+        /* TLS v1.3 requires the hash for the handshake and transfer key derivation */
+        /* we hash even for non TLS v1.3, since we don't know if its actually 
+            TLS v1.3 till later at EXT_SUPPORTED_VERSIONS in server_hello */
+        /* hello retry request restarts hash prior to server_hello hash calc */
+        HashRaw(session->sslServer, input - HANDSHAKE_HEADER_SZ, size + HANDSHAKE_HEADER_SZ);
+        HashRaw(session->sslClient, input - HANDSHAKE_HEADER_SZ, size + HANDSHAKE_HEADER_SZ);
+    }
+#endif
 #ifdef HAVE_EXTENDED_MASTER
     if (session->hash) {
@@ -2662,5 +3729,6 @@
             SetError(EXTENDED_MASTER_HASH_STR, error,
                      session, FATAL_ERROR_STATE);
-            return -1;
+            ret = -1;
+            goto exit;
         }
     }
@@ -2694,4 +3762,8 @@
             ret = -1;
             break;
+        case encrypted_extensions:
+            Trace(GOT_ENC_EXT_STR);
+            ssl->msgsReceived.got_encrypted_extensions = 1;
+            break;
         case certificate:
             Trace(GOT_CERT_STR);
@@ -2753,6 +3825,17 @@
         default:
             SetError(GOT_UNKNOWN_HANDSHAKE_STR, error, session, 0);
-            return -1;
-    }
+            ret = -1;
+            break;
+    }
+
+#ifdef HAVE_EXTENDED_MASTER
+exit:
+#endif
+#ifdef HAVE_MAX_FRAGMENT
+    if (session->tlsFragBuf) {
+        XFREE(session->tlsFragBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        session->tlsFragBuf = NULL;
+    }
+#endif
 
     *sslBytes = startBytes - size;  /* actual bytes of full process */
@@ -2763,5 +3846,5 @@
 
 /* Decrypt input into plain output, 0 on success */
-static int Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz)
+static int Decrypt(WOLFSSL* ssl, byte* output, const byte* input, word32 sz)
 {
     int ret = 0;
@@ -2814,16 +3897,25 @@
         #endif
 
-        #ifdef HAVE_AESGCM
+        #if defined(HAVE_AESGCM) || defined(HAVE_AESCCM)
         case wolfssl_aes_gcm:
-            if (sz >= (word32)(AESGCM_EXP_IV_SZ + ssl->specs.aead_mac_size))
-            {
-                /* scratch buffer, sniffer ignores auth tag*/
+        case wolfssl_aes_ccm: /* GCM AEAD macros use same size as CCM */
+            if (sz >= (word32)(AESGCM_EXP_IV_SZ + ssl->specs.aead_mac_size)) {
+                /* scratch buffer, sniffer ignores auth tag */
+                wc_AesAuthEncryptFunc aes_auth_fn;
                 byte authTag[WOLFSSL_MIN_AUTH_TAG_SZ];
-
                 byte nonce[AESGCM_NONCE_SZ];
                 XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, AESGCM_IMP_IV_SZ);
                 XMEMCPY(nonce + AESGCM_IMP_IV_SZ, input, AESGCM_EXP_IV_SZ);
 
-                if (wc_AesGcmEncrypt(ssl->decrypt.aes,
+                /* use encrypt because we don't care about authtag */
+            #if defined(BUILD_AESGCM) && defined(HAVE_AESCCM)
+                aes_auth_fn = (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm)
+                                ? wc_AesGcmEncrypt : wc_AesCcmEncrypt;
+            #elif defined(BUILD_AESGCM)
+                aes_auth_fn = wc_AesGcmEncrypt;
+            #else
+                aes_auth_fn = wc_AesCcmEncrypt;
+            #endif
+                if (aes_auth_fn(ssl->decrypt.aes,
                             output,
                             input + AESGCM_EXP_IV_SZ,
@@ -2842,5 +3934,5 @@
             }
             break;
-         #endif
+        #endif
 
         #ifdef HAVE_NULL_CIPHER
@@ -2861,10 +3953,19 @@
 
 /* Decrypt input message into output, adjust output steam if needed */
-static const byte* DecryptMessage(SSL* ssl, const byte* input, word32 sz,
-                                  byte* output, int* error, int* advance)
+static const byte* DecryptMessage(WOLFSSL* ssl, const byte* input, word32 sz,
+                byte* output, int* error, int* advance, RecordLayerHeader* rh)
 {
     int ivExtra = 0;
-
-    int ret = Decrypt(ssl, output, input, sz);
+    int ret;
+    
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+        ret = DecryptTls13(ssl, output, input, sz, (byte*)rh, RECORD_HEADER_SZ);
+    }
+    else
+#endif
+    {
+        ret = Decrypt(ssl, output, input, sz);
+    }
     if (ret != 0) {
         *error = ret;
@@ -2873,5 +3974,5 @@
     ssl->keys.encryptSz = sz;
     if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) {
-        output += ssl->specs.block_size;     /* go past TLSv1.1 IV */
+        output += ssl->specs.block_size; /* go past TLSv1.1 IV */
         ivExtra = ssl->specs.block_size;
         *advance = ssl->specs.block_size;
@@ -2887,4 +3988,19 @@
     if (ssl->specs.cipher_type == block)
         ssl->keys.padSz += *(output + sz - ivExtra - 1) + 1;
+
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+        word16 i = (word16)(sz - ssl->keys.padSz);
+        /* Remove padding from end of plain text. */
+        for (--i; i > 0; i--) {
+            if (output[i] != 0)
+                break;
+        }
+        /* Get the real content type from the end of the data. */
+        rh->type = output[i];
+        ssl->keys.padSz = sz - i;
+    }
+#endif
+    (void)rh;
 
     return output;
@@ -2943,5 +4059,5 @@
         while (session) {
             SnifferSession* next = session->next;
-            if (time(NULL) >= session->lastUsed + WOLFSSL_SNIFFER_TIMEOUT) {
+            if (XTIME(NULL) >= session->lastUsed + WOLFSSL_SNIFFER_TIMEOUT) {
                 TraceStaleSession();
                 RemoveSession(session, NULL, NULL, i);
@@ -2992,5 +4108,5 @@
     session->cliSeqStart = tcpInfo->sequence;
     session->cliExpected = 1;  /* relative */
-    session->lastUsed= time(NULL);
+    session->lastUsed= XTIME(NULL);
     session->keySz = 0;
 #ifdef HAVE_SNI
@@ -3005,5 +4121,5 @@
     }
 
-    session->sslServer = SSL_new(session->context->ctx);
+    session->sslServer = wolfSSL_new(session->context->ctx);
     if (session->sslServer == NULL) {
         SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE);
@@ -3011,7 +4127,7 @@
         return 0;
     }
-    session->sslClient = SSL_new(session->context->ctx);
+    session->sslClient = wolfSSL_new(session->context->ctx);
     if (session->sslClient == NULL) {
-        SSL_free(session->sslServer);
+        wolfSSL_free(session->sslServer);
         session->sslServer = 0;
 
@@ -3152,4 +4268,7 @@
                   int length, const byte** sslFrame, int* sslBytes, char* error)
 {
+    IpHdr* iphdr = (IpHdr*)packet;
+    int version;
+
     TraceHeader();
     TracePacket();
@@ -3160,4 +4279,15 @@
         return -1;
     }
+
+    version = IP_V(iphdr);
+    if (version != IPV6 && version != IPV4) {
+        /* Is this VLAN IEEE 802.1Q Frame? TPID = 0x8100 */
+        if (packet[2] == 0x81 && packet[3] == 0x00) {
+            /* trim VLAN header and try again */
+            packet += 8;
+            length -= 8;
+        }
+    }
+
     if (CheckIpHdr((IpHdr*)packet, ipInfo, length, error) != 0)
         return -1;
@@ -3177,4 +4307,5 @@
         return -1;
     }
+    
     /* We only care about the data in the TCP/IP record. There may be extra
      * data after the IP record for the FCS for Ethernet. */
@@ -3372,10 +4503,10 @@
 {
     if (session->flags.side == WOLFSSL_SERVER_END) {
-        if (session->finCaputre.cliCounted == 0)
-            session->finCaputre.cliFinSeq = sequence;
+        if (session->finCapture.cliCounted == 0)
+            session->finCapture.cliFinSeq = sequence;
     }
     else {
-        if (session->finCaputre.srvCounted == 0)
-            session->finCaputre.srvFinSeq = sequence;
+        if (session->finCapture.srvCounted == 0)
+            session->finCapture.srvFinSeq = sequence;
     }
     return 1;
@@ -3513,5 +4644,5 @@
                                     &session->cliReassemblyMemory :
                                     &session->srvReassemblyMemory;
-    SSL*                 ssl = (session->flags.side == WOLFSSL_SERVER_END) ?
+    WOLFSSL*             ssl = (session->flags.side == WOLFSSL_SERVER_END) ?
                                     session->sslServer :
                                     session->sslClient;
@@ -3589,4 +4720,6 @@
     word32*   expected = (session->flags.side == WOLFSSL_SERVER_END) ?
                                 &session->srvExpected : &session->cliExpected;
+    word32    seqStart = (session->flags.side == WOLFSSL_SERVER_END) ?
+                                session->srvSeqStart : session->cliSeqStart;
     PacketBuffer* list = (session->flags.side == WOLFSSL_SERVER_END) ?
                                 session->srvReassemblyList :
@@ -3596,14 +4729,14 @@
                                 &session->flags.cliSkipPartial;
 
+    if (tcpInfo->ackNumber < seqStart) {
+        return -1; /* do not fix sequence - could be ack on unseen seq */
+    }
     *skipPartial = 1;
+    
     if (list != NULL)
         *expected = list->begin;
-    else {
-        word32 seqStart = (session->flags.side == WOLFSSL_SERVER_END) ?
-                                session->srvSeqStart : session->cliSeqStart;
-        word32     real = tcpInfo->ackNumber - seqStart;
-
-        *expected = real;
-    }
+    else
+        *expected = tcpInfo->ackNumber - seqStart;
+
 
     return 1;
@@ -3646,6 +4779,6 @@
                         &session->flags.srvAckFault;
 
-    /* init SEQ from server to client */
-    if (tcpInfo->syn && tcpInfo->ack) {
+    /* init SEQ from server to client - if not ack fault */
+    if (tcpInfo->syn && tcpInfo->ack && !*ackFault) {
         session->srvSeqStart = tcpInfo->sequence;
         session->srvExpected = 1;
@@ -3694,5 +4827,5 @@
 {
     word32 length;
-    SSL*  ssl = ((*session)->flags.side == WOLFSSL_SERVER_END) ?
+    WOLFSSL* ssl = ((*session)->flags.side == WOLFSSL_SERVER_END) ?
                                   (*session)->sslServer : (*session)->sslClient;
     byte  skipPartial = ((*session)->flags.side == WOLFSSL_SERVER_END) ?
@@ -3758,5 +4891,5 @@
 
         Trace(CHAIN_INPUT_STR);
-        headerSz = (word32)*sslFrame - (word32)chain[0].iov_base;
+        headerSz = (word32)((const byte*)*sslFrame - (const byte*)chain[0].iov_base);
         remainder = *sslBytes;
 
@@ -3833,5 +4966,5 @@
                                   &session->cliExpected : &session->srvExpected;
     /* buffer is on receiving end */
-    word32*        length = (session->flags.side == WOLFSSL_SERVER_END) ?
+    word32*          length = (session->flags.side == WOLFSSL_SERVER_END) ?
                                &session->sslServer->buffers.inputBuffer.length :
                                &session->sslClient->buffers.inputBuffer.length;
@@ -3839,8 +4972,8 @@
                                &session->sslServer->buffers.inputBuffer.buffer :
                                &session->sslClient->buffers.inputBuffer.buffer;
-    word32*       bufferSize = (session->flags.side == WOLFSSL_SERVER_END) ?
+    word32*      bufferSize = (session->flags.side == WOLFSSL_SERVER_END) ?
                            &session->sslServer->buffers.inputBuffer.bufferSize :
                            &session->sslClient->buffers.inputBuffer.bufferSize;
-    SSL*               ssl  = (session->flags.side == WOLFSSL_SERVER_END) ?
+    WOLFSSL*           ssl  = (session->flags.side == WOLFSSL_SERVER_END) ?
                             session->sslServer : session->sslClient;
     word32*     reassemblyMemory = (session->flags.side == WOLFSSL_SERVER_END) ?
@@ -3904,6 +5037,6 @@
     int               notEnough;        /* notEnough bytes yet flag */
     int               decrypted = 0;    /* was current msg decrypted */
-    SSL*              ssl = (session->flags.side == WOLFSSL_SERVER_END) ?
-                                        session->sslServer : session->sslClient;
+    WOLFSSL*          ssl = (session->flags.side == WOLFSSL_SERVER_END) ?
+                            session->sslServer : session->sslClient;
 doMessage:
     notEnough = 0;
@@ -3951,4 +5084,9 @@
                                                session->flags.clientCipherOn)) {
         int ivAdvance = 0;  /* TLSv1.1 advance amount */
+
+        /* change_cipher_spec is not encrypted */
+        if (rh.type == change_cipher_spec) {
+            goto doPart;
+        }
         if (ssl->decrypt.setup != 1) {
             SetError(DECRYPT_KEYS_NOT_SETUP, error, session, FATAL_ERROR_STATE);
@@ -3959,7 +5097,8 @@
             return -1;
         }
+
         sslFrame = DecryptMessage(ssl, sslFrame, rhSize,
                                   ssl->buffers.outputBuffer.buffer, &errCode,
-                                  &ivAdvance);
+                                  &ivAdvance, &rh);
         recordEnd = sslFrame - ivAdvance + rhSize;  /* sslFrame moved so
                                                        should recordEnd */
@@ -3992,6 +5131,6 @@
 
                 Trace(GOT_HANDSHAKE_STR);
-                ret = DoHandShake(sslFrame, &sslBytes, session, error);
-                if (ret != 0) {
+                ret = DoHandShake(sslFrame, &sslBytes, session, error, rhSize);
+                if (ret != 0 || sslBytes > startIdx) {
                     if (session->flags.fatalError == 0)
                         SetError(BAD_HANDSHAKE_STR, error, session,
@@ -4008,6 +5147,15 @@
             break;
         case change_cipher_spec:
-            if (session->flags.side == WOLFSSL_SERVER_END)
-                session->flags.serverCipherOn = 1;
+            if (session->flags.side == WOLFSSL_SERVER_END) {
+            #ifdef WOLFSSL_TLS13
+                if (IsAtLeastTLSv1_3(session->sslServer->version) && session->srvKs.key_len == 0) {
+                    session->flags.serverCipherOn = 0;
+                }
+                else
+            #endif
+                {
+                    session->flags.serverCipherOn = 1;
+                }
+            }
             else
                 session->flags.clientCipherOn = 1;
@@ -4146,19 +5294,19 @@
 {
     int ret = 0;
-    if (session->finCaputre.cliFinSeq && session->finCaputre.cliFinSeq <=
+    if (session->finCapture.cliFinSeq && session->finCapture.cliFinSeq <=
                                          session->cliExpected) {
-        if (session->finCaputre.cliCounted == 0) {
+        if (session->finCapture.cliCounted == 0) {
             session->flags.finCount += 1;
-            session->finCaputre.cliCounted = 1;
-            TraceClientFin(session->finCaputre.cliFinSeq, session->cliExpected);
-        }
-    }
-
-    if (session->finCaputre.srvFinSeq && session->finCaputre.srvFinSeq <=
+            session->finCapture.cliCounted = 1;
+            TraceClientFin(session->finCapture.cliFinSeq, session->cliExpected);
+        }
+    }
+
+    if (session->finCapture.srvFinSeq && session->finCapture.srvFinSeq <=
                                          session->srvExpected) {
-        if (session->finCaputre.srvCounted == 0) {
+        if (session->finCapture.srvCounted == 0) {
             session->flags.finCount += 1;
-            session->finCaputre.srvCounted = 1;
-            TraceServerFin(session->finCaputre.srvFinSeq, session->srvExpected);
+            session->finCapture.srvCounted = 1;
+            TraceServerFin(session->finCapture.srvFinSeq, session->srvExpected);
         }
     }
@@ -4581,5 +5729,5 @@
                                           WOLFSSL_FILETYPE_ASN1;
 
-    ret = LoadKeyFile(&keyBuf, &keyBufSz, keyFile, keyType, password);
+    ret = LoadKeyFile(&keyBuf, &keyBufSz, keyFile, 0, keyType, password);
     if (ret < 0) {
         SetError(KEY_FILE_STR, error, NULL, 0);
Index: azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/ssl.c
===================================================================
--- azure_iot_hub_f767zi/trunk/wolfssl-4.4.0/src/ssl.c	(revision 457)
+++ azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/ssl.c	(revision 464)
@@ -35,8 +35,4 @@
     defined(OPENSSL_EXTRA_X509_SMALL)
 
-#ifdef HAVE_ERRNO_H
-    #include <errno.h>
-#endif
-
 #include <wolfssl/internal.h>
 #include <wolfssl/error-ssl.h>
@@ -49,9 +45,13 @@
 #endif
 
+#ifdef HAVE_ERRNO_H
+    #include <errno.h>
+#endif
+
 
 #if !defined(WOLFSSL_ALLOW_NO_SUITES) && !defined(WOLFCRYPT_ONLY)
     #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(WOLFSSL_STATIC_RSA) \
                 && !defined(WOLFSSL_STATIC_DH) && !defined(WOLFSSL_STATIC_PSK) \
-                && !defined(HAVE_ED25519) && !defined(HAVE_ED448)
+                && !defined(HAVE_CURVE25519) && !defined(HAVE_CURVE448)
         #error "No cipher suites defined because DH disabled, ECC disabled, and no static suites defined. Please see top of README"
     #endif
@@ -96,5 +96,4 @@
     #include <wolfssl/openssl/rc4.h>
     #include <wolfssl/openssl/stack.h>
-    #include <wolfssl/openssl/x509v3.h>
     #include <wolfssl/openssl/x509_vfy.h>
     /* openssl headers end, wolfssl internal headers next */
@@ -102,4 +101,5 @@
     #include <wolfssl/wolfcrypt/random.h>
     #include <wolfssl/wolfcrypt/des3.h>
+    #include <wolfssl/wolfcrypt/ecc.h>
     #include <wolfssl/wolfcrypt/md4.h>
     #include <wolfssl/wolfcrypt/md5.h>
@@ -111,4 +111,6 @@
     #if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL)
         #include <wolfssl/openssl/ocsp.h>
+        #include <wolfssl/openssl/lhash.h>
+        #include <wolfssl/openssl/txt_db.h>
     #endif /* WITH_STUNNEL */
     #if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)
@@ -126,8 +128,11 @@
     #endif /* OPENSSL_ALL && HAVE_PKCS7 */
 #endif
+
 #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+    #include <wolfssl/openssl/x509v3.h>
     int SetIndividualInternal(WOLFSSL_BIGNUM* bn, mp_int* mpi);
     int SetIndividualExternal(WOLFSSL_BIGNUM** bn, mp_int* mpi);
     int oid2nid(word32 oid, int grp);
+    word32 nid2oid(int nid, int grp);
 #endif
 
@@ -143,4 +148,6 @@
 #define WOLFSSL_EVP_INCLUDED
 #include "wolfcrypt/src/evp.c"
+
+#ifndef WOLFCRYPT_ONLY
 
 #ifdef OPENSSL_EXTRA
@@ -148,6 +155,4 @@
 static WOLFSSL_BIGNUM* bn_one = NULL;
 #endif
-
-#ifndef WOLFCRYPT_ONLY
 
 #if defined(OPENSSL_EXTRA) && defined(HAVE_ECC)
@@ -190,5 +195,5 @@
 #ifdef WOLFSSL_SESSION_EXPORT
 #ifdef WOLFSSL_DTLS
-int wolfSSL_dtls_import(WOLFSSL* ssl, unsigned char* buf, unsigned int sz)
+int wolfSSL_dtls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz)
 {
     WOLFSSL_ENTER("wolfSSL_session_import");
@@ -402,5 +407,5 @@
                            && !defined(NO_SHA256) && !defined(WC_NO_RNG)
         else {
-            ctx->srp = (Srp*) XMALLOC(sizeof(Srp), heap, DYNAMIC_TYPE_SRP);
+            ctx->srp = (Srp*)XMALLOC(sizeof(Srp), heap, DYNAMIC_TYPE_SRP);
             if (ctx->srp == NULL){
                 WOLFSSL_MSG("Init CTX failed");
@@ -439,5 +444,5 @@
 {
     int refCount = SSL_CTX_RefCount(ctx, 1);
-    return ((refCount > 1) ? 1 : 0);
+    return ((refCount > 1) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE);
 }
 #endif
@@ -450,5 +455,5 @@
 #if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) \
 && !defined(NO_SHA256) && !defined(WC_NO_RNG)
-        if (ctx->srp != NULL){
+        if (ctx->srp != NULL) {
             if (ctx->srp_password != NULL){
                 XFREE(ctx->srp_password, ctx->heap, DYNAMIC_TYPE_SRP);
@@ -903,4 +908,8 @@
     /* Add each member to the buffer delimited by a : */
     for (i = 0; i < ciphersSz; i++) {
+#ifndef NO_CIPHER_SUITE_ALIASES
+        if (ciphers[i].flags & WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS)
+            continue;
+#endif
         cipherNameSz = (int)XSTRLEN(ciphers[i].name_iana);
         if (cipherNameSz + 1 < len) {
@@ -1165,5 +1174,5 @@
 #ifdef WOLFSSL_DTLS
 static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first,
-                                         word32 second, word32 max)
+                                         word32 second, word32 high)
 {
     word32 newCur = 0;
@@ -1173,6 +1182,6 @@
     else if (cur < second)
         newCur = second;
-    else if (cur < max)
-        newCur = max;
+    else if (cur < high)
+        newCur = high;
 
     return newCur;
@@ -1500,5 +1509,5 @@
 int wolfSSL_CTX_load_static_memory(WOLFSSL_CTX** ctx, wolfSSL_method_func method,
                                    unsigned char* buf, unsigned int sz,
-                                   int flag, int max)
+                                   int flag, int maxSz)
 {
     WOLFSSL_HEAP*      heap;
@@ -1559,13 +1568,13 @@
     /* determine what max applies too */
     if (flag & WOLFMEM_IO_POOL || flag & WOLFMEM_IO_POOL_FIXED) {
-        heap->maxIO = max;
+        heap->maxIO = maxSz;
     }
     else { /* general memory used in handshakes */
-        heap->maxHa = max;
+        heap->maxHa = maxSz;
     }
 
     heap->flag |= flag;
 
-    (void)max;
+    (void)maxSz;
     (void)method;
 
@@ -1648,5 +1657,5 @@
         return INPUT_SIZE_E;
 
-    return BuildMessage(ssl, NULL, 0, NULL, inSz, application_data, 0, 1, 0);
+    return BuildMessage(ssl, NULL, 0, NULL, inSz, application_data, 0, 1, 0, CUR_ORDER);
 }
 
@@ -1679,5 +1688,5 @@
 }
 
-#endif /* !NO_RSA */
+#endif /* HAVE_ECC */
 
 #ifndef NO_RSA
@@ -1985,5 +1994,5 @@
     #ifdef OPENSSL_EXTRA
     if (ssl->CBIS != NULL) {
-        ssl->CBIS(ssl, SSL_CB_WRITE, SSL_SUCCESS);
+        ssl->CBIS(ssl, SSL_CB_WRITE, WOLFSSL_SUCCESS);
         ssl->cbmode = SSL_CB_WRITE;
     }
@@ -2025,5 +2034,5 @@
         if (ssl->options.dtlsSctp)
 #endif
-#if defined(WOLLSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)
+#if defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)
             ssl->dtls_expected_rx = max(ssl->dtls_expected_rx, ssl->dtlsMtuSz);
 #endif
@@ -2077,5 +2086,5 @@
     #ifdef OPENSSL_EXTRA
     if (ssl->CBIS != NULL) {
-        ssl->CBIS(ssl, SSL_CB_READ, SSL_SUCCESS);
+        ssl->CBIS(ssl, SSL_CB_READ, WOLFSSL_SUCCESS);
         ssl->cbmode = SSL_CB_READ;
     }
@@ -2368,11 +2377,8 @@
 
 /* Elliptic Curves */
-#if defined(HAVE_SUPPORTED_CURVES) && !defined(NO_WOLFSSL_CLIENT)
-
-int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name)
-{
-    if (ssl == NULL)
-        return BAD_FUNC_ARG;
-
+#if defined(HAVE_SUPPORTED_CURVES)
+
+static int isValidCurveGroup(word16 name)
+{
     switch (name) {
         case WOLFSSL_ECC_SECP160K1:
@@ -2398,9 +2404,15 @@
         case WOLFSSL_FFDHE_6144:
         case WOLFSSL_FFDHE_8192:
-            break;
+            return 1;
 
         default:
-            return BAD_FUNC_ARG;
-    }
+            return 0;
+    }
+}
+
+int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name)
+{
+    if (ssl == NULL || !isValidCurveGroup(name))
+        return BAD_FUNC_ARG;
 
     ssl->options.userCurves = 1;
@@ -2412,35 +2424,7 @@
 int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name)
 {
-    if (ctx == NULL)
+    if (ctx == NULL || !isValidCurveGroup(name))
         return BAD_FUNC_ARG;
 
-    switch (name) {
-        case WOLFSSL_ECC_SECP160K1:
-        case WOLFSSL_ECC_SECP160R1:
-        case WOLFSSL_ECC_SECP160R2:
-        case WOLFSSL_ECC_SECP192K1:
-        case WOLFSSL_ECC_SECP192R1:
-        case WOLFSSL_ECC_SECP224K1:
-        case WOLFSSL_ECC_SECP224R1:
-        case WOLFSSL_ECC_SECP256K1:
-        case WOLFSSL_ECC_SECP256R1:
-        case WOLFSSL_ECC_SECP384R1:
-        case WOLFSSL_ECC_SECP521R1:
-        case WOLFSSL_ECC_BRAINPOOLP256R1:
-        case WOLFSSL_ECC_BRAINPOOLP384R1:
-        case WOLFSSL_ECC_BRAINPOOLP512R1:
-        case WOLFSSL_ECC_X25519:
-        case WOLFSSL_ECC_X448:
-        case WOLFSSL_FFDHE_2048:
-        case WOLFSSL_FFDHE_3072:
-        case WOLFSSL_FFDHE_4096:
-        case WOLFSSL_FFDHE_6144:
-        case WOLFSSL_FFDHE_8192:
-            break;
-
-        default:
-            return BAD_FUNC_ARG;
-    }
-
     ctx->userCurves = 1;
 
@@ -2448,5 +2432,77 @@
 }
 
-#endif /* HAVE_SUPPORTED_CURVES && !NO_WOLFSSL_CLIENT */
+#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_TLS13)
+int  wolfSSL_CTX_set1_groups(WOLFSSL_CTX* ctx, int* groups,
+                                        int count)
+{
+    int i;
+    int _groups[WOLFSSL_MAX_GROUP_COUNT];
+    WOLFSSL_ENTER("wolfSSL_CTX_set1_groups");
+    if (count == 0) {
+        WOLFSSL_MSG("Group count is zero");
+        return WOLFSSL_FAILURE;
+    }
+    for (i = 0; i < count; i++) {
+        if (isValidCurveGroup((word16)groups[i])) {
+            _groups[i] = groups[i];
+        }
+#ifdef HAVE_ECC
+        else {
+            /* groups may be populated with curve NIDs */
+            int oid = nid2oid(groups[i], oidCurveType);
+            int name = (int)GetCurveByOID(oid);
+            if (name == 0) {
+                WOLFSSL_MSG("Invalid group name");
+                return WOLFSSL_FAILURE;
+            }
+            _groups[i] = name;
+        }
+#else
+        else {
+            WOLFSSL_MSG("Invalid group name");
+            return WOLFSSL_FAILURE;
+        }
+#endif
+    }
+    return wolfSSL_CTX_set_groups(ctx, _groups, count) == WOLFSSL_SUCCESS ?
+            WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
+}
+
+int  wolfSSL_set1_groups(WOLFSSL* ssl, int* groups, int count)
+{
+    int i;
+    int _groups[WOLFSSL_MAX_GROUP_COUNT];
+    WOLFSSL_ENTER("wolfSSL_CTX_set1_groups");
+    if (count == 0) {
+        WOLFSSL_MSG("Group count is zero");
+        return WOLFSSL_FAILURE;
+    }
+    for (i = 0; i < count; i++) {
+        if (isValidCurveGroup((word16)groups[i])) {
+            _groups[i] = groups[i];
+        }
+#ifdef HAVE_ECC
+        else {
+            /* groups may be populated with curve NIDs */
+            int oid = nid2oid(groups[i], oidCurveType);
+            int name = (int)GetCurveByOID(oid);
+            if (name == 0) {
+                WOLFSSL_MSG("Invalid group name");
+                return WOLFSSL_FAILURE;
+            }
+            _groups[i] = name;
+        }
+#else
+        else {
+            WOLFSSL_MSG("Invalid group name");
+            return WOLFSSL_FAILURE;
+        }
+#endif
+    }
+    return wolfSSL_set_groups(ssl, _groups, count) == WOLFSSL_SUCCESS ?
+            WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
+}
+#endif /* OPENSSL_EXTRA && WOLFSSL_TLS13 */
+#endif /* HAVE_SUPPORTED_CURVES */
 
 /* QSH quantum safe handshake */
@@ -2509,5 +2565,5 @@
                     word32 protocol_name_listSz, byte options)
 {
-    char    *list, *ptr, *token[WOLFSSL_MAX_ALPN_NUMBER]={NULL};
+    char    *list, *ptr, *token[WOLFSSL_MAX_ALPN_NUMBER+1]={NULL};
     word16  len;
     int     idx = 0;
@@ -2664,6 +2720,17 @@
 
         if (ssl->options.handShakeState != HANDSHAKE_DONE) {
-            WOLFSSL_MSG("Can't renegotiate until previous handshake complete");
-            return SECURE_RENEGOTIATION_E;
+            if (!ssl->options.handShakeDone) {
+                WOLFSSL_MSG("Can't renegotiate until initial "
+                            "handshake complete");
+                return SECURE_RENEGOTIATION_E;
+            }
+            else {
+                WOLFSSL_MSG("Renegotiation already started. "
+                            "Moving it forward.");
+                ret = wolfSSL_negotiate(ssl);
+                if (ret == WOLFSSL_SUCCESS)
+                    ssl->secure_rene_count++;
+                return ret;
+            }
         }
 
@@ -2707,5 +2774,6 @@
     }
     ret = wolfSSL_negotiate(ssl);
-    ssl->secure_rene_count++;
+    if (ret == WOLFSSL_SUCCESS)
+        ssl->secure_rene_count++;
     return ret;
 }
@@ -2769,6 +2837,28 @@
 #endif /* HAVE_SECURE_RENEGOTIATION */
 
+#if defined(HAVE_SESSION_TICKET)
 /* Session Ticket */
-#if !defined(NO_WOLFSSL_SERVER) && defined(HAVE_SESSION_TICKET)
+
+#if !defined(NO_WOLFSSL_SERVER)
+int wolfSSL_CTX_NoTicketTLSv12(WOLFSSL_CTX* ctx)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    ctx->noTicketTls12 = 1;
+
+    return WOLFSSL_SUCCESS;
+}
+
+int wolfSSL_NoTicketTLSv12(WOLFSSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    ssl->options.noTicketTls12 = 1;
+
+    return WOLFSSL_SUCCESS;
+}
+
 /* WOLFSSL_SUCCESS on ok */
 int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb)
@@ -2804,8 +2894,7 @@
 }
 
-#endif /* !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET) */
-
-/* Session Ticket */
-#if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET)
+#endif /* !NO_WOLFSSL_SERVER */
+
+#if !defined(NO_WOLFSSL_CLIENT)
 int wolfSSL_UseSessionTicket(WOLFSSL* ssl)
 {
@@ -2888,5 +2977,7 @@
     return WOLFSSL_SUCCESS;
 }
-#endif
+#endif /* !NO_WOLFSSL_CLIENT */
+
+#endif /* HAVE_SESSION_TICKET */
 
 
@@ -3023,5 +3114,5 @@
     }
 
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
     /* reset WOLFSSL structure state for possible re-use */
     if (ret == WOLFSSL_SUCCESS) {
@@ -3121,5 +3212,5 @@
 char* wolfSSL_ERR_error_string(unsigned long errNumber, char* data)
 {
-    static wcchar msg = "Please supply a buffer for error string";
+    static char tmp[WOLFSSL_MAX_ERROR_SZ] = {0};
 
     WOLFSSL_ENTER("ERR_error_string");
@@ -3128,6 +3219,8 @@
         return data;
     }
-
-    return (char*)msg;
+    else {
+        SetErrorString((int)errNumber, tmp);
+        return tmp;
+    }
 }
 
@@ -3228,4 +3321,55 @@
     return 0;
 }
+
+#ifdef WOLFSSL_DTLS
+const byte* wolfSSL_GetDtlsMacSecret(WOLFSSL* ssl, int verify, int epochOrder)
+{
+#ifndef WOLFSSL_AEAD_ONLY
+    Keys* keys = NULL;
+
+    (void)epochOrder;
+
+    if (ssl == NULL)
+        return NULL;
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+    switch (epochOrder) {
+    case PEER_ORDER:
+        if (IsDtlsMsgSCRKeys(ssl))
+            keys = &ssl->secure_renegotiation->tmp_keys;
+        else
+            keys = &ssl->keys;
+        break;
+    case PREV_ORDER:
+        keys = &ssl->keys;
+        break;
+    case CUR_ORDER:
+        if (DtlsUseSCRKeys(ssl))
+            keys = &ssl->secure_renegotiation->tmp_keys;
+        else
+            keys = &ssl->keys;
+        break;
+    default:
+        WOLFSSL_MSG("Unknown epoch order");
+        return NULL;
+    }
+#else
+    keys = &ssl->keys;
+#endif
+
+    if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) ||
+         (ssl->options.side == WOLFSSL_SERVER_END &&  verify) )
+        return keys->client_write_MAC_secret;
+    else
+        return keys->server_write_MAC_secret;
+#else
+    (void)ssl;
+    (void)verify;
+    (void)epochOrder;
+
+    return NULL;
+#endif
+}
+#endif /* WOLFSSL_DTLS */
 
 const byte* wolfSSL_GetMacSecret(WOLFSSL* ssl, int verify)
@@ -3527,6 +3671,12 @@
     if (cm) {
         XMEMSET(cm, 0, sizeof(WOLFSSL_CERT_MANAGER));
+        cm->refCount = 1;
 
         if (wc_InitMutex(&cm->caLock) != 0) {
+            WOLFSSL_MSG("Bad mutex init");
+            wolfSSL_CertManagerFree(cm);
+            return NULL;
+        }
+        if (wc_InitMutex(&cm->refMutex) != 0) {
             WOLFSSL_MSG("Bad mutex init");
             wolfSSL_CertManagerFree(cm);
@@ -3564,33 +3714,60 @@
 void wolfSSL_CertManagerFree(WOLFSSL_CERT_MANAGER* cm)
 {
+    int doFree = 0;
     WOLFSSL_ENTER("wolfSSL_CertManagerFree");
 
     if (cm) {
-        #ifdef HAVE_CRL
-            if (cm->crl)
-                FreeCRL(cm->crl, 1);
-        #endif
-        #ifdef HAVE_OCSP
-            if (cm->ocsp)
-                FreeOCSP(cm->ocsp, 1);
-            XFREE(cm->ocspOverrideURL, cm->heap, DYNAMIC_TYPE_URL);
-        #if !defined(NO_WOLFSSL_SERVER) && \
-            (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
-             defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2))
-            if (cm->ocsp_stapling)
-                FreeOCSP(cm->ocsp_stapling, 1);
-        #endif
-        #endif
-        FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap);
-        wc_FreeMutex(&cm->caLock);
-
-        #ifdef WOLFSSL_TRUST_PEER_CERT
-        FreeTrustedPeerTable(cm->tpTable, TP_TABLE_SIZE, cm->heap);
-        wc_FreeMutex(&cm->tpLock);
-        #endif
-
-        XFREE(cm, cm->heap, DYNAMIC_TYPE_CERT_MANAGER);
-    }
-
+        if (wc_LockMutex(&cm->refMutex) != 0) {
+            WOLFSSL_MSG("Couldn't lock cm mutex");
+        }
+        cm->refCount--;
+        if (cm->refCount == 0)
+            doFree = 1;
+        wc_UnLockMutex(&cm->refMutex);
+        if (doFree) {
+            #ifdef HAVE_CRL
+                if (cm->crl)
+                    FreeCRL(cm->crl, 1);
+            #endif
+            #ifdef HAVE_OCSP
+                if (cm->ocsp)
+                    FreeOCSP(cm->ocsp, 1);
+                XFREE(cm->ocspOverrideURL, cm->heap, DYNAMIC_TYPE_URL);
+            #if !defined(NO_WOLFSSL_SERVER) && \
+                (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
+                 defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2))
+                if (cm->ocsp_stapling)
+                    FreeOCSP(cm->ocsp_stapling, 1);
+            #endif
+            #endif
+            FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap);
+            wc_FreeMutex(&cm->caLock);
+
+            #ifdef WOLFSSL_TRUST_PEER_CERT
+            FreeTrustedPeerTable(cm->tpTable, TP_TABLE_SIZE, cm->heap);
+            wc_FreeMutex(&cm->tpLock);
+            #endif
+            if (wc_FreeMutex(&cm->refMutex) != 0) {
+                WOLFSSL_MSG("Couldn't free refMutex mutex");
+            }
+            XFREE(cm, cm->heap, DYNAMIC_TYPE_CERT_MANAGER);
+        }
+    }
+
+}
+
+int wolfSSL_CertManager_up_ref(WOLFSSL_CERT_MANAGER* cm)
+{
+    if (cm) {
+        if (wc_LockMutex(&cm->refMutex) != 0) {
+            WOLFSSL_MSG("Failed to lock cm mutex");
+        }
+        cm->refCount++;
+        wc_UnLockMutex(&cm->refMutex);
+
+        return WOLFSSL_SUCCESS;
+    }
+
+    return WOLFSSL_FAILURE;
 }
 
@@ -3657,5 +3834,5 @@
             if (CopyDecodedToX509(x509, dCert) == 0) {
 
-                if (wolfSSL_sk_X509_push(sk, x509) != SSL_SUCCESS) {
+                if (wolfSSL_sk_X509_push(sk, x509) != WOLFSSL_SUCCESS) {
                     WOLFSSL_MSG("Unable to load x509 into stack");
                     FreeX509(x509);
@@ -3756,5 +3933,5 @@
         if (CopyDecodedToX509(x509, dCert) == 0) {
 
-            if (wolfSSL_sk_X509_push(sk, x509) != SSL_SUCCESS) {
+            if (wolfSSL_sk_X509_push(sk, x509) != WOLFSSL_SUCCESS) {
                 WOLFSSL_MSG("Unable to load x509 into stack");
                 wolfSSL_X509_free(x509);
@@ -3841,5 +4018,5 @@
     WOLFSSL_ENTER("wolfSSL_ERR_print_errors_fp");
     SetErrorString(err, data);
-    fprintf(fp, "%s", data);
+    XFPRINTF(fp, "%s", data);
 }
 
@@ -3988,5 +4165,5 @@
 
 /* Function to get version as WOLFSSL_ enum value for wolfSSL_SetVersion */
-int wolfSSL_GetVersion(WOLFSSL* ssl)
+int wolfSSL_GetVersion(const WOLFSSL* ssl)
 {
     if (ssl == NULL)
@@ -4089,5 +4266,5 @@
 {
     return ((word32)hashID[0] << 24) | ((word32)hashID[1] << 16) |
-        (hashID[2] <<  8) | hashID[3];
+           ((word32)hashID[2] <<  8) |  (word32)hashID[3];
 }
 
@@ -4254,8 +4431,10 @@
     Signer* ret = NULL;
     Signer* signers;
-    word32  row = HashSigner(hash);
-
-    if (cm == NULL)
+    word32  row = 0;
+
+    if (cm == NULL || hash == NULL)
         return NULL;
+
+    row = HashSigner(hash);
 
     if (wc_LockMutex(&cm->caLock) != 0)
@@ -4374,5 +4553,5 @@
         /* add trusted peer signature */
         peerCert->sigLen = cert->sigLength;
-        peerCert->sig = XMALLOC(cert->sigLength, cm->heap,
+        peerCert->sig = (byte *)XMALLOC(cert->sigLength, cm->heap,
                                                         DYNAMIC_TYPE_SIGNATURE);
         if (peerCert->sig == NULL) {
@@ -4733,4 +4912,11 @@
 #endif /* NO_SESSION_CACHE */
 
+#if defined(OPENSSL_EXTRA) || \
+    (defined(OPENSSL_EXTRA_X509_SMALL) && !defined(NO_RSA))
+static WC_RNG globalRNG;
+static int initGlobalRNG = 0;
+static wolfSSL_Mutex globalRNGMutex;
+#endif
+
 WOLFSSL_ABI
 int wolfSSL_Init(void)
@@ -4744,4 +4930,12 @@
             return WC_INIT_E;
         }
+
+#if defined(OPENSSL_EXTRA) || \
+    (defined(OPENSSL_EXTRA_X509_SMALL) && !defined(NO_RSA))
+        if (wc_InitMutex(&globalRNGMutex) != 0) {
+            WOLFSSL_MSG("Bad Init Mutex rng");
+            return BAD_MUTEX_E;
+        }
+#endif
 
 #ifdef OPENSSL_EXTRA
@@ -4960,5 +5154,5 @@
             return MEMORY_E;
     #endif
-
+        
         ret = wc_InitRsaKey_ex(key, heap, devId);
         if (ret == 0) {
@@ -5341,9 +5535,6 @@
                 FreeDer(&ssl->buffers.certificate);
             #ifdef KEEP_OUR_CERT
-                FreeX509(ssl->ourCert);
-                if (ssl->ourCert) {
-                    XFREE(ssl->ourCert, ssl->heap, DYNAMIC_TYPE_X509);
-                    ssl->ourCert = NULL;
-                }
+                wolfSSL_X509_free(ssl->ourCert);
+                ssl->ourCert = NULL;
             #endif
             }
@@ -5358,8 +5549,6 @@
         #ifdef KEEP_OUR_CERT
             if (ctx->ourCert) {
-                if (ctx->ownOurCert) {
-                    FreeX509(ctx->ourCert);
-                    XFREE(ctx->ourCert, ctx->heap, DYNAMIC_TYPE_X509);
-                }
+                if (ctx->ownOurCert)
+                    wolfSSL_X509_free(ctx->ourCert);
                 ctx->ourCert = NULL;
             }
@@ -5448,6 +5637,13 @@
         if (ret != 0)
             return ret;
-        if (keyFormat == 0)
+        if (keyFormat == 0) {
+#ifdef OPENSSL_EXTRA
+            /* Reaching this point probably means that the
+             * decryption password is wrong */
+            if (info->passwd_cb)
+                EVPerr(0, EVP_R_BAD_DECRYPT);
+#endif
             return WOLFSSL_BAD_FILE;
+        }
 
         (void)devId;
@@ -5459,5 +5655,5 @@
         DecodedCert  cert[1];
     #endif
-    #ifdef HAVE_PK_CALLBACKS
+    #if defined(HAVE_PKCS11) || defined(HAVE_PK_CALLBACKS)
         int keyType = 0;
     #endif
@@ -5567,14 +5763,6 @@
         #ifndef NO_RSA
             case RSAk:
-            #ifdef HAVE_PK_CALLBACKS
+            #if defined(HAVE_PKCS11) || defined(HAVE_PK_CALLBACKS)
                 keyType = rsa_sa_algo;
-            #endif
-            #ifdef HAVE_PKCS11
-                if (ctx) {
-                    ctx->privateKeyType = rsa_sa_algo;
-                }
-                else {
-                    ssl->buffers.keyType = rsa_sa_algo;
-                }
             #endif
                 /* Determine RSA key size by parsing public key */
@@ -5603,14 +5791,6 @@
         #ifdef HAVE_ECC
             case ECDSAk:
-            #ifdef HAVE_PK_CALLBACKS
+            #if defined(HAVE_PKCS11) || defined(HAVE_PK_CALLBACKS)
                 keyType = ecc_dsa_sa_algo;
-            #endif
-            #ifdef HAVE_PKCS11
-                if (ctx) {
-                    ctx->privateKeyType = ecc_dsa_sa_algo;
-                }
-                else {
-                    ssl->buffers.keyType = ecc_dsa_sa_algo;
-                }
             #endif
                 /* Determine ECC key size based on curve */
@@ -5636,14 +5816,6 @@
         #ifdef HAVE_ED25519
             case ED25519k:
-            #ifdef HAVE_PK_CALLBACKS
+            #if defined(HAVE_PKCS11) || defined(HAVE_PK_CALLBACKS)
                 keyType = ed25519_sa_algo;
-            #endif
-            #ifdef HAVE_PKCS11
-                if (ctx) {
-                    ctx->privateKeyType = ed25519_sa_algo;
-                }
-                else {
-                    ssl->buffers.keyType = ed25519_sa_algo;
-                }
             #endif
                 /* ED25519 is fixed key size */
@@ -5667,14 +5839,6 @@
         #ifdef HAVE_ED448
             case ED448k:
-            #ifdef HAVE_PK_CALLBACKS
+            #if defined(HAVE_PKCS11) || defined(HAVE_PK_CALLBACKS)
                 keyType = ed448_sa_algo;
-            #endif
-            #ifdef HAVE_PKCS11
-                if (ctx) {
-                    ctx->privateKeyType = ed448_sa_algo;
-                }
-                else {
-                    ssl->buffers.keyType = ed448_sa_algo;
-                }
             #endif
                 /* ED448 is fixed key size */
@@ -5702,10 +5866,18 @@
         }
 
-    #ifdef HAVE_PK_CALLBACKS
-        if (ssl && ssl->buffers.keyType == 0) {
+    #if defined(HAVE_PKCS11) || defined(HAVE_PK_CALLBACKS)
+        if (ssl
+        #ifdef HAVE_PK_CALLBACKS
+                && ssl->buffers.keyType == 0
+        #endif
+            ) {
             ssl->buffers.keyType = keyType;
             ssl->buffers.keySz = keySz;
         }
-        else if (ctx && ctx->privateKeyType == 0) {
+        else if (ctx
+        #ifdef HAVE_PK_CALLBACKS
+                     && ctx->privateKeyType == 0
+        #endif
+            ) {
             ctx->privateKeyType = keyType;
             ctx->privateKeySz = keySz;
@@ -5724,5 +5896,6 @@
 
     if (done == 1) {
-    #ifndef NO_WOLFSSL_CM_VERIFY
+    #if !defined(NO_WOLFSSL_CM_VERIFY) && (!defined(NO_WOLFSSL_CLIENT) || \
+                                           !defined(WOLFSSL_NO_CLIENT_AUTH))
         if ((type == CA_TYPE) || (type == CERT_TYPE)) {
             /* Call to over-ride status */
@@ -6013,4 +6186,5 @@
 #endif /* NO_WOLFSSL_CM_VERIFY */
 
+#if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH)
 /* Verify the certificate, WOLFSSL_SUCCESS for ok, < 0 for error */
 int CM_VerifyBuffer_ex(WOLFSSL_CERT_MANAGER* cm, const byte* buff,
@@ -6119,4 +6293,6 @@
     return CM_VerifyBuffer_ex(cm, buff, sz, format, 0);
 }
+#endif /* !NO_WOLFSSL_CLIENT || !WOLFSSL_NO_CLIENT_AUTH */
+
 /* turn on OCSP if off and compiled in, set options */
 int wolfSSL_CertManagerEnableOCSP(WOLFSSL_CERT_MANAGER* cm, int options)
@@ -6236,4 +6412,48 @@
 }
 
+/* require OCSP stapling response */
+int wolfSSL_CertManagerEnableOCSPMustStaple(WOLFSSL_CERT_MANAGER* cm)
+{
+    int ret;
+
+    WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSPMustStaple");
+
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
+ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+    #ifndef NO_WOLFSSL_CLIENT
+        cm->ocspMustStaple = 1;
+    #endif
+    ret = WOLFSSL_SUCCESS;
+#else
+    ret = NOT_COMPILED_IN;
+#endif
+
+    return ret;
+}
+
+int wolfSSL_CertManagerDisableOCSPMustStaple(WOLFSSL_CERT_MANAGER* cm)
+{
+    int ret;
+
+    WOLFSSL_ENTER("wolfSSL_CertManagerDisableOCSPMustStaple");
+
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
+ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+    #ifndef NO_WOLFSSL_CLIENT
+        cm->ocspMustStaple = 0;
+    #endif
+    ret = WOLFSSL_SUCCESS;
+#else
+    ret = NOT_COMPILED_IN;
+#endif
+    return ret;
+}
+
 #ifdef HAVE_OCSP
 /* check CRL if enabled, WOLFSSL_SUCCESS  */
@@ -6256,5 +6476,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT);
+    cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap, DYNAMIC_TYPE_DCERT);
     if (cert == NULL)
         return MEMORY_E;
@@ -6272,5 +6492,5 @@
     FreeDecodedCert(cert);
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(cert, NULL, DYNAMIC_TYPE_DCERT);
+    XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT);
 #endif
 
@@ -6453,4 +6673,22 @@
     if (ctx)
         return wolfSSL_CertManagerDisableOCSPStapling(ctx->cm);
+    else
+        return BAD_FUNC_ARG;
+}
+
+int wolfSSL_CTX_EnableOCSPMustStaple(WOLFSSL_CTX* ctx)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSPMustStaple");
+    if (ctx)
+        return wolfSSL_CertManagerEnableOCSPMustStaple(ctx->cm);
+    else
+        return BAD_FUNC_ARG;
+}
+
+int wolfSSL_CTX_DisableOCSPMustStaple(WOLFSSL_CTX* ctx)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSPMustStaple");
+    if (ctx)
+        return wolfSSL_CertManagerDisableOCSPMustStaple(ctx->cm);
     else
         return BAD_FUNC_ARG;
@@ -6517,5 +6755,5 @@
     }
 
-    if ( (ret = (int)XFREAD(myBuffer, 1, sz, file)) != sz)
+    if ((size_t)XFREAD(myBuffer, 1, sz, file) != (size_t)sz)
         ret = WOLFSSL_BAD_FILE;
     else {
@@ -6693,4 +6931,5 @@
 
 
+#if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH)
 /* Verify the certificate, WOLFSSL_SUCCESS for ok, < 0 for error */
 int wolfSSL_CertManagerVerify(WOLFSSL_CERT_MANAGER* cm, const char* fname,
@@ -6734,5 +6973,5 @@
     }
 
-    if ( (ret = (int)XFREAD(myBuffer, 1, sz, file)) != sz)
+    if ((size_t)XFREAD(myBuffer, 1, sz, file) != (size_t)sz)
         ret = WOLFSSL_BAD_FILE;
     else
@@ -6745,5 +6984,5 @@
     return ret;
 }
-
+#endif
 
 /* like load verify locations, 1 for success, < 0 for error */
@@ -6779,4 +7018,419 @@
     return ret;
 }
+
+
+#endif /* NO_FILESYSTEM */
+
+#ifdef HAVE_CRL
+
+/* check CRL if enabled, WOLFSSL_SUCCESS  */
+int wolfSSL_CertManagerCheckCRL(WOLFSSL_CERT_MANAGER* cm, byte* der, int sz)
+{
+    int ret = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* cert = NULL;
+#else
+    DecodedCert  cert[1];
+#endif
+
+    WOLFSSL_ENTER("wolfSSL_CertManagerCheckCRL");
+
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    if (cm->crlEnabled == 0)
+        return WOLFSSL_SUCCESS;
+
+#ifdef WOLFSSL_SMALL_STACK
+    cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT);
+    if (cert == NULL)
+        return MEMORY_E;
+#endif
+
+    InitDecodedCert(cert, der, sz, NULL);
+
+    if ((ret = ParseCertRelative(cert, CERT_TYPE, VERIFY_CRL, cm)) != 0) {
+        WOLFSSL_MSG("ParseCert failed");
+    }
+    else if ((ret = CheckCertCRL(cm->crl, cert)) != 0) {
+        WOLFSSL_MSG("CheckCertCRL failed");
+    }
+
+    FreeDecodedCert(cert);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(cert, NULL, DYNAMIC_TYPE_DCERT);
+#endif
+
+    return ret == 0 ? WOLFSSL_SUCCESS : ret;
+}
+
+
+int wolfSSL_CertManagerSetCRL_Cb(WOLFSSL_CERT_MANAGER* cm, CbMissingCRL cb)
+{
+    WOLFSSL_ENTER("wolfSSL_CertManagerSetCRL_Cb");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    cm->cbMissingCRL = cb;
+
+    return WOLFSSL_SUCCESS;
+}
+
+#ifdef HAVE_CRL_IO
+int wolfSSL_CertManagerSetCRL_IOCb(WOLFSSL_CERT_MANAGER* cm, CbCrlIO cb)
+{
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    cm->crl->crlIOCb = cb;
+
+    return WOLFSSL_SUCCESS;
+}
+#endif
+
+#ifndef NO_FILESYSTEM
+int wolfSSL_CertManagerLoadCRL(WOLFSSL_CERT_MANAGER* cm, const char* path,
+                              int type, int monitor)
+{
+    WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRL");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    if (cm->crl == NULL) {
+        if (wolfSSL_CertManagerEnableCRL(cm, 0) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("Enable CRL failed");
+            return WOLFSSL_FATAL_ERROR;
+        }
+    }
+
+    return LoadCRL(cm->crl, path, type, monitor);
+}
+#endif
+
+int wolfSSL_EnableCRL(WOLFSSL* ssl, int options)
+{
+    WOLFSSL_ENTER("wolfSSL_EnableCRL");
+    if (ssl)
+        return wolfSSL_CertManagerEnableCRL(ssl->ctx->cm, options);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_DisableCRL(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("wolfSSL_DisableCRL");
+    if (ssl)
+        return wolfSSL_CertManagerDisableCRL(ssl->ctx->cm);
+    else
+        return BAD_FUNC_ARG;
+}
+
+#ifndef NO_FILESYSTEM
+int wolfSSL_LoadCRL(WOLFSSL* ssl, const char* path, int type, int monitor)
+{
+    WOLFSSL_ENTER("wolfSSL_LoadCRL");
+    if (ssl)
+        return wolfSSL_CertManagerLoadCRL(ssl->ctx->cm, path, type, monitor);
+    else
+        return BAD_FUNC_ARG;
+}
+#endif
+
+
+int wolfSSL_SetCRL_Cb(WOLFSSL* ssl, CbMissingCRL cb)
+{
+    WOLFSSL_ENTER("wolfSSL_SetCRL_Cb");
+    if (ssl)
+        return wolfSSL_CertManagerSetCRL_Cb(ssl->ctx->cm, cb);
+    else
+        return BAD_FUNC_ARG;
+}
+
+#ifdef HAVE_CRL_IO
+int wolfSSL_SetCRL_IOCb(WOLFSSL* ssl, CbCrlIO cb)
+{
+    WOLFSSL_ENTER("wolfSSL_SetCRL_Cb");
+    if (ssl)
+        return wolfSSL_CertManagerSetCRL_IOCb(ssl->ctx->cm, cb);
+    else
+        return BAD_FUNC_ARG;
+}
+#endif
+
+int wolfSSL_CTX_EnableCRL(WOLFSSL_CTX* ctx, int options)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_EnableCRL");
+    if (ctx)
+        return wolfSSL_CertManagerEnableCRL(ctx->cm, options);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_CTX_DisableCRL(WOLFSSL_CTX* ctx)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_DisableCRL");
+    if (ctx)
+        return wolfSSL_CertManagerDisableCRL(ctx->cm);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+#ifndef NO_FILESYSTEM
+int wolfSSL_CTX_LoadCRL(WOLFSSL_CTX* ctx, const char* path,
+                        int type, int monitor)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL");
+    if (ctx)
+        return wolfSSL_CertManagerLoadCRL(ctx->cm, path, type, monitor);
+    else
+        return BAD_FUNC_ARG;
+}
+#endif
+
+
+int wolfSSL_CTX_SetCRL_Cb(WOLFSSL_CTX* ctx, CbMissingCRL cb)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_Cb");
+    if (ctx)
+        return wolfSSL_CertManagerSetCRL_Cb(ctx->cm, cb);
+    else
+        return BAD_FUNC_ARG;
+}
+
+#ifdef HAVE_CRL_IO
+int wolfSSL_CTX_SetCRL_IOCb(WOLFSSL_CTX* ctx, CbCrlIO cb)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_IOCb");
+    if (ctx)
+        return wolfSSL_CertManagerSetCRL_IOCb(ctx->cm, cb);
+    else
+        return BAD_FUNC_ARG;
+}
+#endif
+
+
+#endif /* HAVE_CRL */
+
+
+#ifndef NO_FILESYSTEM
+
+
+#ifdef WOLFSSL_DER_LOAD
+
+/* Add format parameter to allow DER load of CA files */
+int wolfSSL_CTX_der_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
+                                          int format)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_der_load_verify_locations");
+    if (ctx == NULL || file == NULL)
+        return WOLFSSL_FAILURE;
+
+    if (ProcessFile(ctx, file, format, CA_TYPE, NULL, 0, NULL,
+                    GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) {
+        return WOLFSSL_SUCCESS;
+    }
+
+    return WOLFSSL_FAILURE;
+}
+
+#endif /* WOLFSSL_DER_LOAD */
+
+
+
+WOLFSSL_ABI
+int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX* ctx, const char* file,
+                                     int format)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_file");
+
+    if (ProcessFile(ctx, file, format, CERT_TYPE, NULL, 0, NULL,
+                    GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) {
+        return WOLFSSL_SUCCESS;
+    }
+
+    return WOLFSSL_FAILURE;
+}
+
+
+WOLFSSL_ABI
+int wolfSSL_CTX_use_PrivateKey_file(WOLFSSL_CTX* ctx, const char* file,
+                                    int format)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_file");
+
+    if (ProcessFile(ctx, file, format, PRIVATEKEY_TYPE, NULL, 0, NULL,
+                    GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) {
+        return WOLFSSL_SUCCESS;
+    }
+
+    return WOLFSSL_FAILURE;
+}
+
+
+#endif /* NO_FILESYSTEM */
+
+
+/* Sets the max chain depth when verifying a certificate chain. Default depth
+ * is set to MAX_CHAIN_DEPTH.
+ *
+ * ctx   WOLFSSL_CTX structure to set depth in
+ * depth max depth
+ */
+void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx, int depth) {
+    WOLFSSL_ENTER("wolfSSL_CTX_set_verify_depth");
+
+    if (ctx == NULL || depth < 0 || depth > MAX_CHAIN_DEPTH) {
+        WOLFSSL_MSG("Bad depth argument, too large or less than 0");
+        return;
+    }
+
+    ctx->verifyDepth = (byte)depth;
+}
+
+
+/* get cert chaining depth using ssl struct */
+long wolfSSL_get_verify_depth(WOLFSSL* ssl)
+{
+    if(ssl == NULL) {
+        return BAD_FUNC_ARG;
+    }
+#ifndef OPENSSL_EXTRA
+    return MAX_CHAIN_DEPTH;
+#else
+    return ssl->options.verifyDepth;
+#endif
+}
+
+
+/* get cert chaining depth using ctx struct */
+long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx)
+{
+    if (ctx == NULL) {
+        return BAD_FUNC_ARG;
+    }
+#ifndef OPENSSL_EXTRA
+    return MAX_CHAIN_DEPTH;
+#else
+    return ctx->verifyDepth;
+#endif
+}
+
+
+#ifndef NO_FILESYSTEM
+
+
+WOLFSSL_ABI
+int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX* ctx, const char* file)
+{
+    /* process up to MAX_CHAIN_DEPTH plus subject cert */
+    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file");
+
+    if (ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, NULL, 1, NULL,
+                    GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) {
+        return WOLFSSL_SUCCESS;
+    }
+
+   return WOLFSSL_FAILURE;
+}
+
+
+int wolfSSL_CTX_use_certificate_chain_file_format(WOLFSSL_CTX* ctx,
+                                                  const char* file, int format)
+{
+    /* process up to MAX_CHAIN_DEPTH plus subject cert */
+    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file_format");
+
+    if (ProcessFile(ctx, file, format, CERT_TYPE, NULL, 1, NULL,
+                    GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) {
+        return WOLFSSL_SUCCESS;
+    }
+
+   return WOLFSSL_FAILURE;
+}
+
+
+#ifndef NO_DH
+
+/* server Diffie-Hellman parameters */
+static int wolfSSL_SetTmpDH_file_wrapper(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
+                                        const char* fname, int format)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    byte   staticBuffer[1]; /* force heap usage */
+#else
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+#endif
+    byte*  myBuffer = staticBuffer;
+    int    dynamic = 0;
+    int    ret;
+    long   sz = 0;
+    XFILE  file;
+
+    if (ctx == NULL || fname == NULL)
+        return BAD_FUNC_ARG;
+
+    file = XFOPEN(fname, "rb");
+    if (file == XBADFILE) return WOLFSSL_BAD_FILE;
+    if(XFSEEK(file, 0, XSEEK_END) != 0) {
+        XFCLOSE(file);
+        return WOLFSSL_BAD_FILE;
+    }
+    sz = XFTELL(file);
+    XREWIND(file);
+
+    if (sz > MAX_WOLFSSL_FILE_SIZE || sz <= 0) {
+        WOLFSSL_MSG("SetTmpDH file size error");
+        XFCLOSE(file);
+        return WOLFSSL_BAD_FILE;
+    }
+
+    if (sz > (long)sizeof(staticBuffer)) {
+        WOLFSSL_MSG("Getting dynamic buffer");
+        myBuffer = (byte*) XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE);
+        if (myBuffer == NULL) {
+            XFCLOSE(file);
+            return WOLFSSL_BAD_FILE;
+        }
+        dynamic = 1;
+    }
+
+    if ((size_t)XFREAD(myBuffer, 1, sz, file) != (size_t)sz)
+        ret = WOLFSSL_BAD_FILE;
+    else {
+        if (ssl)
+            ret = wolfSSL_SetTmpDH_buffer(ssl, myBuffer, sz, format);
+        else
+            ret = wolfSSL_CTX_SetTmpDH_buffer(ctx, myBuffer, sz, format);
+    }
+
+    XFCLOSE(file);
+    if (dynamic)
+        XFREE(myBuffer, ctx->heap, DYNAMIC_TYPE_FILE);
+
+    return ret;
+}
+
+/* server Diffie-Hellman parameters */
+int wolfSSL_SetTmpDH_file(WOLFSSL* ssl, const char* fname, int format)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    return wolfSSL_SetTmpDH_file_wrapper(ssl->ctx, ssl, fname, format);
+}
+
+
+/* server Diffie-Hellman parameters */
+int wolfSSL_CTX_SetTmpDH_file(WOLFSSL_CTX* ctx, const char* fname, int format)
+{
+    return wolfSSL_SetTmpDH_file_wrapper(ctx, NULL, fname, format);
+}
+
+#endif /* NO_DH */
+
+#endif /* NO_FILESYSTEM */
 
 #ifndef NO_CHECK_PRIVATE_KEY
@@ -6799,5 +7453,5 @@
     WOLFSSL_ENTER("wolfSSL_CTX_check_private_key");
 
-    if (ctx == NULL) {
+    if (ctx == NULL || ctx->certificate == NULL) {
         return WOLFSSL_FAILURE;
     }
@@ -6823,5 +7477,49 @@
     size = ctx->privateKey->length;
     buff = ctx->privateKey->buffer;
-    ret  = wc_CheckPrivateKey(buff, size, der);
+#ifdef WOLF_CRYPTO_CB
+    if (ctx->privateKeyDevId != INVALID_DEVID) {
+        int type = 0;
+        void *pkey = NULL;
+
+        if (der->keyOID == RSAk) {
+            type = DYNAMIC_TYPE_RSA;
+        }
+        else if (der->keyOID == ECDSAk) {
+            type = DYNAMIC_TYPE_ECC;
+        }
+        ret = CreateDevPrivateKey(&pkey, buff, size, type, ctx->privateKeyLabel,
+                                  ctx->privateKeyId, ctx->heap,
+                                  ctx->privateKeyDevId);
+        if (ret == 0 && der->keyOID == RSAk) {
+            ret = wc_CryptoCb_RsaCheckPrivKey((RsaKey*)pkey, der->publicKey,
+                                              der->pubKeySize);
+            wc_FreeRsaKey((RsaKey*)pkey);
+        }
+        else if (ret == 0 && der->keyOID == ECDSAk) {
+            ret = wc_CryptoCb_EccCheckPrivKey((ecc_key*)pkey, der->publicKey,
+                                              der->pubKeySize);
+            wc_ecc_free((ecc_key*)pkey);
+        }
+        if (pkey != NULL) {
+            XFREE(pkey, ctx->heap, type);
+        }
+        if (ret == 0) {
+            ret = WOLFSSL_SUCCESS;
+        }
+        else {
+            ret = WOLFSSL_FAILURE;
+        }
+    }
+    else
+#endif
+    {
+        ret = wc_CheckPrivateKeyCert(buff, size, der);
+        if (ret == 1) {
+            ret = WOLFSSL_SUCCESS;
+        }
+        else {
+            ret = WOLFSSL_FAILURE;
+        }
+    }
     FreeDecodedCert(der);
 #ifdef WOLFSSL_SMALL_STACK
@@ -6829,10 +7527,5 @@
 #endif
 
-    if (ret == 1) {
-        return WOLFSSL_SUCCESS;
-    }
-    else {
-        return WOLFSSL_FAILURE;
-    }
+    return ret;
 #else
     WOLFSSL_MSG("NO_CERTS is defined, can not check private key");
@@ -6842,403 +7535,7 @@
 #endif /* !NO_CHECK_PRIVATE_KEY */
 
-
-#ifdef HAVE_CRL
-
-/* check CRL if enabled, WOLFSSL_SUCCESS  */
-int wolfSSL_CertManagerCheckCRL(WOLFSSL_CERT_MANAGER* cm, byte* der, int sz)
-{
-    int ret = 0;
-#ifdef WOLFSSL_SMALL_STACK
-    DecodedCert* cert = NULL;
-#else
-    DecodedCert  cert[1];
-#endif
-
-    WOLFSSL_ENTER("wolfSSL_CertManagerCheckCRL");
-
-    if (cm == NULL)
-        return BAD_FUNC_ARG;
-
-    if (cm->crlEnabled == 0)
-        return WOLFSSL_SUCCESS;
-
-#ifdef WOLFSSL_SMALL_STACK
-    cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT);
-    if (cert == NULL)
-        return MEMORY_E;
-#endif
-
-    InitDecodedCert(cert, der, sz, NULL);
-
-    if ((ret = ParseCertRelative(cert, CERT_TYPE, VERIFY_CRL, cm)) != 0) {
-        WOLFSSL_MSG("ParseCert failed");
-    }
-    else if ((ret = CheckCertCRL(cm->crl, cert)) != 0) {
-        WOLFSSL_MSG("CheckCertCRL failed");
-    }
-
-    FreeDecodedCert(cert);
-#ifdef WOLFSSL_SMALL_STACK
-    XFREE(cert, NULL, DYNAMIC_TYPE_DCERT);
-#endif
-
-    return ret == 0 ? WOLFSSL_SUCCESS : ret;
-}
-
-
-int wolfSSL_CertManagerSetCRL_Cb(WOLFSSL_CERT_MANAGER* cm, CbMissingCRL cb)
-{
-    WOLFSSL_ENTER("wolfSSL_CertManagerSetCRL_Cb");
-    if (cm == NULL)
-        return BAD_FUNC_ARG;
-
-    cm->cbMissingCRL = cb;
-
-    return WOLFSSL_SUCCESS;
-}
-
-#ifdef HAVE_CRL_IO
-int wolfSSL_CertManagerSetCRL_IOCb(WOLFSSL_CERT_MANAGER* cm, CbCrlIO cb)
-{
-    if (cm == NULL)
-        return BAD_FUNC_ARG;
-
-    cm->crl->crlIOCb = cb;
-
-    return WOLFSSL_SUCCESS;
-}
-#endif
-
-int wolfSSL_CertManagerLoadCRL(WOLFSSL_CERT_MANAGER* cm, const char* path,
-                              int type, int monitor)
-{
-    WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRL");
-    if (cm == NULL)
-        return BAD_FUNC_ARG;
-
-    if (cm->crl == NULL) {
-        if (wolfSSL_CertManagerEnableCRL(cm, 0) != WOLFSSL_SUCCESS) {
-            WOLFSSL_MSG("Enable CRL failed");
-            return WOLFSSL_FATAL_ERROR;
-        }
-    }
-
-    return LoadCRL(cm->crl, path, type, monitor);
-}
-
-int wolfSSL_EnableCRL(WOLFSSL* ssl, int options)
-{
-    WOLFSSL_ENTER("wolfSSL_EnableCRL");
-    if (ssl)
-        return wolfSSL_CertManagerEnableCRL(ssl->ctx->cm, options);
-    else
-        return BAD_FUNC_ARG;
-}
-
-
-int wolfSSL_DisableCRL(WOLFSSL* ssl)
-{
-    WOLFSSL_ENTER("wolfSSL_DisableCRL");
-    if (ssl)
-        return wolfSSL_CertManagerDisableCRL(ssl->ctx->cm);
-    else
-        return BAD_FUNC_ARG;
-}
-
-int wolfSSL_LoadCRL(WOLFSSL* ssl, const char* path, int type, int monitor)
-{
-    WOLFSSL_ENTER("wolfSSL_LoadCRL");
-    if (ssl)
-        return wolfSSL_CertManagerLoadCRL(ssl->ctx->cm, path, type, monitor);
-    else
-        return BAD_FUNC_ARG;
-}
-
-
-int wolfSSL_SetCRL_Cb(WOLFSSL* ssl, CbMissingCRL cb)
-{
-    WOLFSSL_ENTER("wolfSSL_SetCRL_Cb");
-    if (ssl)
-        return wolfSSL_CertManagerSetCRL_Cb(ssl->ctx->cm, cb);
-    else
-        return BAD_FUNC_ARG;
-}
-
-#ifdef HAVE_CRL_IO
-int wolfSSL_SetCRL_IOCb(WOLFSSL* ssl, CbCrlIO cb)
-{
-    WOLFSSL_ENTER("wolfSSL_SetCRL_Cb");
-    if (ssl)
-        return wolfSSL_CertManagerSetCRL_IOCb(ssl->ctx->cm, cb);
-    else
-        return BAD_FUNC_ARG;
-}
-#endif
-
-int wolfSSL_CTX_EnableCRL(WOLFSSL_CTX* ctx, int options)
-{
-    WOLFSSL_ENTER("wolfSSL_CTX_EnableCRL");
-    if (ctx)
-        return wolfSSL_CertManagerEnableCRL(ctx->cm, options);
-    else
-        return BAD_FUNC_ARG;
-}
-
-
-int wolfSSL_CTX_DisableCRL(WOLFSSL_CTX* ctx)
-{
-    WOLFSSL_ENTER("wolfSSL_CTX_DisableCRL");
-    if (ctx)
-        return wolfSSL_CertManagerDisableCRL(ctx->cm);
-    else
-        return BAD_FUNC_ARG;
-}
-
-
-int wolfSSL_CTX_LoadCRL(WOLFSSL_CTX* ctx, const char* path,
-                        int type, int monitor)
-{
-    WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL");
-    if (ctx)
-        return wolfSSL_CertManagerLoadCRL(ctx->cm, path, type, monitor);
-    else
-        return BAD_FUNC_ARG;
-}
-
-
-int wolfSSL_CTX_SetCRL_Cb(WOLFSSL_CTX* ctx, CbMissingCRL cb)
-{
-    WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_Cb");
-    if (ctx)
-        return wolfSSL_CertManagerSetCRL_Cb(ctx->cm, cb);
-    else
-        return BAD_FUNC_ARG;
-}
-
-#ifdef HAVE_CRL_IO
-int wolfSSL_CTX_SetCRL_IOCb(WOLFSSL_CTX* ctx, CbCrlIO cb)
-{
-    WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_IOCb");
-    if (ctx)
-        return wolfSSL_CertManagerSetCRL_IOCb(ctx->cm, cb);
-    else
-        return BAD_FUNC_ARG;
-}
-#endif
-
-
-#endif /* HAVE_CRL */
-
-
-#ifdef WOLFSSL_DER_LOAD
-
-/* Add format parameter to allow DER load of CA files */
-int wolfSSL_CTX_der_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
-                                          int format)
-{
-    WOLFSSL_ENTER("wolfSSL_CTX_der_load_verify_locations");
-    if (ctx == NULL || file == NULL)
-        return WOLFSSL_FAILURE;
-
-    if (ProcessFile(ctx, file, format, CA_TYPE, NULL, 0, NULL,
-                    GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) {
-        return WOLFSSL_SUCCESS;
-    }
-
-    return WOLFSSL_FAILURE;
-}
-
-#endif /* WOLFSSL_DER_LOAD */
-
-
-
-WOLFSSL_ABI
-int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX* ctx, const char* file,
-                                     int format)
-{
-    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_file");
-
-    if (ProcessFile(ctx, file, format, CERT_TYPE, NULL, 0, NULL,
-                    GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) {
-        return WOLFSSL_SUCCESS;
-    }
-
-    return WOLFSSL_FAILURE;
-}
-
-
-WOLFSSL_ABI
-int wolfSSL_CTX_use_PrivateKey_file(WOLFSSL_CTX* ctx, const char* file,
-                                    int format)
-{
-    WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_file");
-
-    if (ProcessFile(ctx, file, format, PRIVATEKEY_TYPE, NULL, 0, NULL,
-                    GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) {
-        return WOLFSSL_SUCCESS;
-    }
-
-    return WOLFSSL_FAILURE;
-}
-
-
-/* Sets the max chain depth when verifying a certificate chain. Default depth
- * is set to MAX_CHAIN_DEPTH.
- *
- * ctx   WOLFSSL_CTX structure to set depth in
- * depth max depth
- */
-void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx, int depth) {
-    WOLFSSL_ENTER("wolfSSL_CTX_set_verify_depth");
-
-    if (ctx == NULL || depth < 0 || depth > MAX_CHAIN_DEPTH) {
-        WOLFSSL_MSG("Bad depth argument, too large or less than 0");
-        return;
-    }
-
-    ctx->verifyDepth = (byte)depth;
-}
-
-
-/* get cert chaining depth using ssl struct */
-long wolfSSL_get_verify_depth(WOLFSSL* ssl)
-{
-    if(ssl == NULL) {
-        return BAD_FUNC_ARG;
-    }
-#ifndef OPENSSL_EXTRA
-    return MAX_CHAIN_DEPTH;
-#else
-    return ssl->options.verifyDepth;
-#endif
-}
-
-
-/* get cert chaining depth using ctx struct */
-long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx)
-{
-    if (ctx == NULL) {
-        return BAD_FUNC_ARG;
-    }
-#ifndef OPENSSL_EXTRA
-    return MAX_CHAIN_DEPTH;
-#else
-    return ctx->verifyDepth;
-#endif
-}
-
-
-WOLFSSL_ABI
-int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX* ctx, const char* file)
-{
-    /* process up to MAX_CHAIN_DEPTH plus subject cert */
-    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file");
-
-    if (ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, NULL, 1, NULL,
-                    GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) {
-        return WOLFSSL_SUCCESS;
-    }
-
-   return WOLFSSL_FAILURE;
-}
-
-
-int wolfSSL_CTX_use_certificate_chain_file_format(WOLFSSL_CTX* ctx,
-                                                  const char* file, int format)
-{
-    /* process up to MAX_CHAIN_DEPTH plus subject cert */
-    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file_format");
-
-    if (ProcessFile(ctx, file, format, CERT_TYPE, NULL, 1, NULL,
-                    GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) {
-        return WOLFSSL_SUCCESS;
-    }
-
-   return WOLFSSL_FAILURE;
-}
-
-
-#ifndef NO_DH
-
-/* server Diffie-Hellman parameters */
-static int wolfSSL_SetTmpDH_file_wrapper(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
-                                        const char* fname, int format)
-{
-#ifdef WOLFSSL_SMALL_STACK
-    byte   staticBuffer[1]; /* force heap usage */
-#else
-    byte   staticBuffer[FILE_BUFFER_SIZE];
-#endif
-    byte*  myBuffer = staticBuffer;
-    int    dynamic = 0;
-    int    ret;
-    long   sz = 0;
-    XFILE  file;
-
-    if (ctx == NULL || fname == NULL)
-        return BAD_FUNC_ARG;
-
-    file = XFOPEN(fname, "rb");
-    if (file == XBADFILE) return WOLFSSL_BAD_FILE;
-    if(XFSEEK(file, 0, XSEEK_END) != 0) {
-        XFCLOSE(file);
-        return WOLFSSL_BAD_FILE;
-    }
-    sz = XFTELL(file);
-    XREWIND(file);
-
-    if (sz > MAX_WOLFSSL_FILE_SIZE || sz <= 0) {
-        WOLFSSL_MSG("SetTmpDH file size error");
-        XFCLOSE(file);
-        return WOLFSSL_BAD_FILE;
-    }
-
-    if (sz > (long)sizeof(staticBuffer)) {
-        WOLFSSL_MSG("Getting dynamic buffer");
-        myBuffer = (byte*) XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE);
-        if (myBuffer == NULL) {
-            XFCLOSE(file);
-            return WOLFSSL_BAD_FILE;
-        }
-        dynamic = 1;
-    }
-
-    if ( (ret = (int)XFREAD(myBuffer, 1, sz, file)) != sz)
-        ret = WOLFSSL_BAD_FILE;
-    else {
-        if (ssl)
-            ret = wolfSSL_SetTmpDH_buffer(ssl, myBuffer, sz, format);
-        else
-            ret = wolfSSL_CTX_SetTmpDH_buffer(ctx, myBuffer, sz, format);
-    }
-
-    XFCLOSE(file);
-    if (dynamic)
-        XFREE(myBuffer, ctx->heap, DYNAMIC_TYPE_FILE);
-
-    return ret;
-}
-
-/* server Diffie-Hellman parameters */
-int wolfSSL_SetTmpDH_file(WOLFSSL* ssl, const char* fname, int format)
-{
-    if (ssl == NULL)
-        return BAD_FUNC_ARG;
-
-    return wolfSSL_SetTmpDH_file_wrapper(ssl->ctx, ssl, fname, format);
-}
-
-
-/* server Diffie-Hellman parameters */
-int wolfSSL_CTX_SetTmpDH_file(WOLFSSL_CTX* ctx, const char* fname, int format)
-{
-    return wolfSSL_SetTmpDH_file_wrapper(ctx, NULL, fname, format);
-}
-
-#endif /* NO_DH */
-
-#endif /* NO_FILESYSTEM */
-
 #ifdef OPENSSL_EXTRA
+
+#ifndef NO_BIO
 /* put SSL type in extra for now, not very common */
 
@@ -7327,5 +7624,5 @@
     (void)out;
 
-    memSz = wolfSSL_BIO_pending(bio);
+    memSz = wolfSSL_BIO_get_len(bio);
     if (memSz <= 0) {
         return NULL;
@@ -7347,4 +7644,6 @@
     return pkey;
 }
+
+#endif /* !NO_BIO */
 
 
@@ -7414,4 +7713,7 @@
                 return pkey;
             }
+            else {
+                WOLFSSL_MSG("RSA wolfSSL_EVP_PKEY_new error");
+            }
         }
         wc_FreeRsaKey(&rsa);
@@ -7458,4 +7760,7 @@
                 return pkey;
             }
+            else {
+                WOLFSSL_MSG("ECC wolfSSL_EVP_PKEY_new error");
+            }
         }
         wc_ecc_free(&ecc);
@@ -7505,4 +7810,7 @@
                 return pkey;
             }
+            else {
+                WOLFSSL_MSG("DSA wolfSSL_EVP_PKEY_new error");
+            }
         }
         wc_FreeDsaKey(&dsa);
@@ -7511,4 +7819,6 @@
 
     #if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL))
+    #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
+        (HAVE_FIPS_VERSION > 2))
     {
         DhKey dh;
@@ -7551,10 +7861,52 @@
                 return pkey;
             }
+            else {
+                WOLFSSL_MSG("DH wolfSSL_EVP_PKEY_new error");
+            }
         }
         wc_FreeDhKey(&dh);
     }
+    #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
     #endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */
 
+    if (pkey == NULL) {
+        WOLFSSL_MSG("wolfSSL_d2i_PUBKEY couldn't determine key type");
+    }
+
     return pkey;
+}
+
+/* helper function to get raw pointer to DER buffer from WOLFSSL_EVP_PKEY */
+static int wolfSSL_EVP_PKEY_get_der(const WOLFSSL_EVP_PKEY* key, unsigned char** der)
+{
+    unsigned char* pt;
+    int sz;
+
+    if (!key || !key->pkey_sz)
+        return WOLFSSL_FATAL_ERROR;
+
+    sz = key->pkey_sz;
+    if (der) {
+        pt = (unsigned char*)key->pkey.ptr;
+        if (*der) {
+            /* since this function signature has no size value passed in it is
+             * assumed that the user has allocated a large enough buffer */
+            XMEMCPY(*der, pt, sz);
+            *der += sz;
+        }
+        else {
+            *der = (unsigned char*)XMALLOC(sz, NULL, DYNAMIC_TYPE_OPENSSL);
+            if (*der == NULL) {
+                return WOLFSSL_FATAL_ERROR;
+            }
+            XMEMCPY(*der, pt, sz);
+        }
+    }
+    return sz;
+}
+
+int wolfSSL_i2d_PUBKEY(const WOLFSSL_EVP_PKEY *key, unsigned char **der)
+{
+    return wolfSSL_EVP_PKEY_get_der(key, der);
 }
 
@@ -7638,5 +7990,5 @@
             if (wolfSSL_RSA_LoadDer_ex(local->rsa,
                       (const unsigned char*)local->pkey.ptr, local->pkey_sz,
-                      WOLFSSL_RSA_LOAD_PRIVATE) != SSL_SUCCESS) {
+                      WOLFSSL_RSA_LOAD_PRIVATE) != WOLFSSL_SUCCESS) {
                 wolfSSL_EVP_PKEY_free(local);
                 return NULL;
@@ -7654,5 +8006,5 @@
             if (wolfSSL_EC_KEY_LoadDer(local->ecc,
                       (const unsigned char*)local->pkey.ptr, local->pkey_sz)
-                      != SSL_SUCCESS) {
+                      != WOLFSSL_SUCCESS) {
                 wolfSSL_EVP_PKEY_free(local);
                 return NULL;
@@ -7660,5 +8012,5 @@
             break;
 #endif /* HAVE_ECC */
-#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH)
 #ifndef NO_DSA
         case EVP_PKEY_DSA:
@@ -7671,5 +8023,5 @@
             if (wolfSSL_DSA_LoadDer(local->dsa,
                     (const unsigned char*)local->pkey.ptr, local->pkey_sz)
-                    != SSL_SUCCESS) {
+                    != WOLFSSL_SUCCESS) {
                 wolfSSL_EVP_PKEY_free(local);
                 return NULL;
@@ -7678,4 +8030,5 @@
 #endif /* NO_DSA */
 #ifndef NO_DH
+#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2))
         case EVP_PKEY_DH:
             local->ownDh = 1;
@@ -7687,11 +8040,12 @@
             if (wolfSSL_DH_LoadDer(local->dh,
                       (const unsigned char*)local->pkey.ptr, local->pkey_sz)
-                      != SSL_SUCCESS) {
+                      != WOLFSSL_SUCCESS) {
                 wolfSSL_EVP_PKEY_free(local);
                 return NULL;
             }
             break;
+#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
 #endif /* HAVE_DH */
-#endif /* WOLFSSL_QT || OPENSSL_ALL */
+#endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH */
         default:
             WOLFSSL_MSG("Unsupported key type");
@@ -7745,5 +8099,40 @@
     size = ssl->buffers.key->length;
     buff = ssl->buffers.key->buffer;
-    ret  = wc_CheckPrivateKey(buff, size, &der);
+#ifdef WOLF_CRYPTO_CB
+    if (ssl->buffers.keyDevId != INVALID_DEVID) {
+        int type = 0;
+        void *pkey = NULL;
+
+        if (der.keyOID == RSAk) {
+            type = DYNAMIC_TYPE_RSA;
+        }
+        else if (der.keyOID == ECDSAk) {
+            type = DYNAMIC_TYPE_ECC;
+        }
+        ret = CreateDevPrivateKey(&pkey, buff, size, type,
+                                  ssl->buffers.keyLabel,
+                                  ssl->buffers.keyId, ssl->heap,
+                                  ssl->buffers.keyDevId);
+        if (ret == 0 && der.keyOID == RSAk) {
+            ret = wc_CryptoCb_RsaCheckPrivKey((RsaKey*)pkey, der.publicKey,
+                                              der.pubKeySize);
+            if (ret == 0)
+                ret = 1;
+            wc_FreeRsaKey((RsaKey*)pkey);
+        }
+        else if (ret == 0 && der.keyOID == ECDSAk) {
+            ret = wc_CryptoCb_EccCheckPrivKey((ecc_key*)pkey, der.publicKey,
+                                              der.pubKeySize);
+            if (ret == 0)
+                ret = 1;
+            wc_ecc_free((ecc_key*)pkey);
+        }
+        if (pkey != NULL) {
+            XFREE(pkey, ssl->heap, type);
+        }
+    }
+    else
+#endif
+        ret  = wc_CheckPrivateKeyCert(buff, size, &der);
     FreeDecodedCert(&der);
     return ret;
@@ -7776,5 +8165,10 @@
     InitDecodedCert(&cert, rawCert, (word32)outSz, 0);
 
-    if (ParseCert(&cert, CA_TYPE, NO_VERIFY, NULL) < 0) {
+    if (ParseCert(&cert,
+#ifdef WOLFSSL_CERT_REQ
+            passedCert->isCSR ? CERTREQ_TYPE :
+#endif
+                    CA_TYPE,
+            NO_VERIFY, NULL) < 0) {
         WOLFSSL_MSG("\tCertificate parsing failed");
         return WOLFSSL_FAILURE;
@@ -7790,14 +8184,19 @@
     }
 
-    if (input[idx++] != ASN_EXTENSIONS) {
-        WOLFSSL_MSG("\tfail: should be an EXTENSIONS");
-        FreeDecodedCert(&cert);
-        return WOLFSSL_FAILURE;
-    }
-
-    if (GetLength(input, &idx, &length, sz) < 0) {
-        WOLFSSL_MSG("\tfail: invalid length");
-        FreeDecodedCert(&cert);
-        return WOLFSSL_FAILURE;
+#ifdef WOLFSSL_CERT_REQ
+    if (!passedCert->isCSR)
+#endif
+    {
+        if (input[idx++] != ASN_EXTENSIONS) {
+            WOLFSSL_MSG("\tfail: should be an EXTENSIONS");
+            FreeDecodedCert(&cert);
+            return WOLFSSL_FAILURE;
+        }
+
+        if (GetLength(input, &idx, &length, sz) < 0) {
+            WOLFSSL_MSG("\tfail: invalid length");
+            FreeDecodedCert(&cert);
+            return WOLFSSL_FAILURE;
+        }
     }
 
@@ -7824,7 +8223,8 @@
 WOLFSSL_X509_EXTENSION* wolfSSL_X509_EXTENSION_new(void)
 {
+    WOLFSSL_X509_EXTENSION* newExt;
+
     WOLFSSL_ENTER("wolfSSL_X509_EXTENSION_new");
 
-    WOLFSSL_X509_EXTENSION* newExt;
     newExt = (WOLFSSL_X509_EXTENSION*)XMALLOC(sizeof(WOLFSSL_X509_EXTENSION),
               NULL, DYNAMIC_TYPE_X509_EXT);
@@ -7965,4 +8365,65 @@
 
     return WOLFSSL_SUCCESS;
+}
+
+static WOLFSSL_STACK* generateExtStack(const WOLFSSL_X509 *x)
+{
+    int numOfExt, i;
+    WOLFSSL_X509 *x509 = (WOLFSSL_X509*)x;
+    WOLFSSL_STACK* ret;
+    WOLFSSL_STACK* tmp;
+
+    if (!x509) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    /* Save x509->ext_sk */
+    tmp = x509->ext_sk;
+    x509->ext_sk = NULL;
+    numOfExt = wolfSSL_X509_get_ext_count(x509);
+
+    for (i = 0; i < numOfExt; i++) {
+        /* Build the extension stack */
+        (void)wolfSSL_X509_set_ext(x509, i);
+    }
+
+    /* Restore */
+    ret = x509->ext_sk;
+    x509->ext_sk = tmp;
+    return ret;
+}
+
+/**
+ * @param x Certificate to extract extensions from
+ * @return STACK_OF(X509_EXTENSION)*
+ */
+const WOLFSSL_STACK *wolfSSL_X509_get0_extensions(const WOLFSSL_X509 *x)
+{
+    int numOfExt;
+    WOLFSSL_X509 *x509 = (WOLFSSL_X509*)x;
+    WOLFSSL_ENTER("wolfSSL_X509_get0_extensions");
+
+    if (!x509) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    numOfExt = wolfSSL_X509_get_ext_count(x509);
+
+    if (numOfExt != wolfSSL_sk_num(x509->ext_sk_full)) {
+        wolfSSL_sk_free(x509->ext_sk_full);
+        x509->ext_sk_full = generateExtStack(x);
+    }
+
+    return x509->ext_sk_full;
+}
+
+/**
+ * Caller is responsible for freeing the returned stack.
+ */
+const WOLFSSL_STACK *wolfSSL_X509_REQ_get_extensions(const WOLFSSL_X509 *x)
+{
+    return generateExtStack(x);
 }
 
@@ -7991,4 +8452,29 @@
    ext = wolfSSL_X509_set_ext((WOLFSSL_X509*) x509, loc);
    return ext;
+}
+
+int wolfSSL_X509_get_ext_by_OBJ(const WOLFSSL_X509 *x,
+        const WOLFSSL_ASN1_OBJECT *obj, int lastpos)
+{
+    const WOLF_STACK_OF(WOLFSSL_X509_EXTENSION) *sk;
+
+    if (!x || !obj) {
+        WOLFSSL_MSG("Bad parameter");
+        return -1;
+    }
+
+    sk = wolfSSL_X509_get0_extensions(x);
+    if (!sk) {
+        WOLFSSL_MSG("No extensions");
+        return -1;
+    }
+    lastpos++;
+    if (lastpos < 0)
+        lastpos = 0;
+    for (; lastpos < wolfSSL_sk_num(sk); lastpos++)
+        if (wolfSSL_OBJ_cmp((WOLFSSL_ASN1_OBJECT*)wolfSSL_sk_value(sk,
+                        lastpos), obj) == 0)
+            return lastpos;
+    return -1;
 }
 
@@ -8037,5 +8523,10 @@
     InitDecodedCert( &cert, rawCert, (word32)outSz, 0);
 
-    if (ParseCert(&cert, CA_TYPE, NO_VERIFY, NULL) < 0) {
+    if (ParseCert(&cert,
+#ifdef WOLFSSL_CERT_REQ
+            x509->isCSR ? CERTREQ_TYPE :
+#endif
+                    CA_TYPE,
+            NO_VERIFY, NULL) < 0) {
         WOLFSSL_MSG("\tCertificate parsing failed");
         wolfSSL_X509_EXTENSION_free(ext);
@@ -8053,16 +8544,21 @@
     }
 
-    if (input[idx++] != ASN_EXTENSIONS) {
-        WOLFSSL_MSG("\tfail: should be an EXTENSIONS");
-        wolfSSL_X509_EXTENSION_free(ext);
-        FreeDecodedCert(&cert);
-        return NULL;
-    }
-
-    if (GetLength(input, &idx, &length, sz) < 0) {
-        WOLFSSL_MSG("\tfail: invalid length");
-        wolfSSL_X509_EXTENSION_free(ext);
-        FreeDecodedCert(&cert);
-        return NULL;
+#ifdef WOLFSSL_CERT_REQ
+    if (!x509->isCSR)
+#endif
+    {
+        if (input[idx++] != ASN_EXTENSIONS) {
+            WOLFSSL_MSG("\tfail: should be an EXTENSIONS");
+            wolfSSL_X509_EXTENSION_free(ext);
+            FreeDecodedCert(&cert);
+            return NULL;
+        }
+
+        if (GetLength(input, &idx, &length, sz) < 0) {
+            WOLFSSL_MSG("\tfail: invalid length");
+            wolfSSL_X509_EXTENSION_free(ext);
+            FreeDecodedCert(&cert);
+            return NULL;
+        }
     }
 
@@ -8281,11 +8777,11 @@
                     break;
 
-                sk = (WOLF_STACK_OF(WOLFSSL_GENERAL_NAME)*)XMALLOC(
-                          sizeof(WOLF_STACK_OF(WOLFSSL_GENERAL_NAME)), NULL,
-                                                         DYNAMIC_TYPE_ASN1);
+                sk = (WOLFSSL_GENERAL_NAMES*)XMALLOC(
+                          sizeof(WOLFSSL_GENERAL_NAMES), NULL,
+                          DYNAMIC_TYPE_ASN1);
                 if (sk == NULL) {
                     return NULL;
                 }
-                XMEMSET(sk, 0, sizeof(WOLF_STACK_OF(WOLFSSL_GENERAL_NAME)));
+                XMEMSET(sk, 0, sizeof(WOLFSSL_GENERAL_NAMES));
                 sk->type = STACK_TYPE_GEN_NAME;
 
@@ -8374,4 +8870,5 @@
                         wolfSSL_X509_EXTENSION_free(ext);
                         FreeDecodedCert(&cert);
+                        XFREE(oidBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
                         return NULL;
                     }
@@ -8433,4 +8930,103 @@
 }
 
+/**
+ * @param str String to copy
+ * @param buf Output buffer. If this contains a pointer then it is free'd
+ *            with the DYNAMIC_TYPE_X509_EXT hint.
+ * @param len Output length
+ * @return WOLFSSL_SUCCESS on sucess and WOLFSSL_FAILURE on error
+ */
+static int asn1_string_copy_to_buffer(WOLFSSL_ASN1_STRING* str, byte** buf,
+        word32* len, void* heap) {
+    if (!str || !buf || !len) {
+        return WOLFSSL_FAILURE;
+    }
+    if (str->data && str->length > 0) {
+        if (*buf)
+            XFREE(*buf, heap, DYNAMIC_TYPE_X509_EXT);
+        *len = 0;
+        *buf = (byte*)XMALLOC(str->length, heap,
+                DYNAMIC_TYPE_X509_EXT);
+        if (!*buf) {
+            WOLFSSL_MSG("malloc error");
+            return WOLFSSL_FAILURE;
+        }
+        *len = str->length;
+        XMEMCPY(*buf, str->data, str->length);
+    }
+
+    (void)heap;
+    return WOLFSSL_SUCCESS;
+}
+
+int wolfSSL_X509_add_ext(WOLFSSL_X509 *x509, WOLFSSL_X509_EXTENSION *ext, int loc)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_add_ext");
+
+    if (!x509 || !ext || !ext->obj || loc >= 0) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    switch (ext->obj->type) {
+    case NID_authority_key_identifier:
+        if (asn1_string_copy_to_buffer(&ext->value, &x509->authKeyId,
+                &x509->authKeyIdSz, x509->heap) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("asn1_string_copy_to_buffer error");
+            return WOLFSSL_FAILURE;
+        }
+        x509->authKeyIdCrit = ext->crit;
+        break;
+    case NID_subject_key_identifier:
+        if (asn1_string_copy_to_buffer(&ext->value, &x509->subjKeyId,
+                &x509->subjKeyIdSz, x509->heap) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("asn1_string_copy_to_buffer error");
+            return WOLFSSL_FAILURE;
+        }
+        x509->subjKeyIdCrit = ext->crit;
+        break;
+    case NID_subject_alt_name:
+    {
+        WOLFSSL_GENERAL_NAMES* gns = ext->ext_sk;
+        while (gns) {
+            WOLFSSL_GENERAL_NAME* gn = gns->data.gn;
+            if (!gn || !gn->d.ia5 ||
+                wolfSSL_X509_add_altname_ex(x509, gn->d.ia5->data,
+                    gn->d.ia5->length, gn->type) != WOLFSSL_SUCCESS) {
+                WOLFSSL_MSG("Subject alternative name missing extension");
+                return WOLFSSL_FAILURE;
+            }
+            gns = gns->next;
+        }
+        x509->subjAltNameSet = 1;
+        x509->subjAltNameCrit = ext->crit;
+        break;
+    }
+    case NID_key_usage:
+        if (ext && ext->value.data &&
+                ext->value.length == sizeof(word16)) {
+            x509->keyUsage = *(word16*)ext->value.data;
+            x509->keyUsageCrit = ext->crit;
+            x509->keyUsageSet = 1;
+        }
+        break;
+    case NID_basic_constraints:
+        if (ext->obj) {
+            x509->isCa = ext->obj->ca;
+            x509->basicConstCrit = ext->crit;
+            if (ext->obj->pathlen)
+                x509->pathLength = ext->obj->pathlen->length;
+            x509->basicConstSet = 1;
+        }
+        break;
+    default:
+        WOLFSSL_MSG("Unsupported extension to add");
+        return WOLFSSL_FAILURE;
+    }
+
+    return WOLFSSL_SUCCESS;
+}
+
+#ifndef NO_BIO
 /* Return 0 on success and 1 on failure. Copies ext data to bio, using indent
  *  to pad the output. flag is ignored. */
@@ -8443,5 +9039,5 @@
     const int sz = CTC_NAME_SIZE*2;
     int rc = WOLFSSL_FAILURE;
-    char tmp[CTC_NAME_SIZE*2];
+    char tmp[CTC_NAME_SIZE*2] = {0};
     WOLFSSL_ENTER("wolfSSL_X509V3_EXT_print");
 
@@ -8458,5 +9054,5 @@
 
     str = wolfSSL_X509_EXTENSION_get_data(ext);
-    if (obj == NULL) {
+    if (str == NULL) {
         WOLFSSL_MSG("Error getting ASN1_STRING from X509_EXTENSION");
         return rc;
@@ -8537,4 +9133,19 @@
     return rc;
 }
+#endif /* !NO_BIO */
+
+#ifndef NO_WOLFSSL_STUB
+int wolfSSL_X509V3_EXT_add_nconf(WOLFSSL_CONF *conf, WOLFSSL_X509V3_CTX *ctx,
+        const char *section, WOLFSSL_X509 *cert)
+{
+    WOLFSSL_ENTER("wolfSSL_X509V3_EXT_add_nconf");
+    WOLFSSL_STUB("wolfSSL_X509V3_EXT_add_nconf");
+    (void)conf;
+    (void)ctx;
+    (void)section;
+    (void)cert;
+    return WOLFSSL_SUCCESS;
+}
+#endif
 
 /* Returns crit flag in X509_EXTENSION object */
@@ -8571,9 +9182,6 @@
         return NULL;
     }
-    /* Initialize all methods to NULL */
-    method.d2i = NULL;
-    method.i2v = NULL;
-    method.i2s = NULL;
-    method.i2r = NULL;
+    /* Initialize method to 0 */
+    XMEMSET(&method, 0, sizeof(struct WOLFSSL_v3_ext_method));
 
     nid = ex->obj->nid;
@@ -8582,5 +9190,5 @@
         return NULL;
     }
-
+    XMEMSET(&method, 0, sizeof(WOLFSSL_v3_ext_method));
     switch (nid) {
         case NID_basic_constraints:
@@ -8588,4 +9196,7 @@
         case NID_subject_key_identifier:
             method.i2s = (X509V3_EXT_I2S)wolfSSL_i2s_ASN1_STRING;
+            break;
+        case NID_subject_alt_name:
+            WOLFSSL_MSG("i2v function not yet implemented for Subject Alternative Name");
             break;
         case NID_key_usage:
@@ -8666,7 +9277,5 @@
             WOLFSSL_MSG("basicConstraints");
             /* Allocate new BASIC_CONSTRAINTS structure */
-            bc = (WOLFSSL_BASIC_CONSTRAINTS*)
-                  XMALLOC(sizeof(WOLFSSL_BASIC_CONSTRAINTS), NULL,
-                  DYNAMIC_TYPE_X509_EXT);
+            bc = wolfSSL_BASIC_CONSTRAINTS_new();
             if (bc == NULL) {
                 WOLFSSL_MSG("Failed to malloc basic constraints");
@@ -8679,5 +9288,5 @@
                 if (bc->pathlen == NULL) {
                     WOLFSSL_MSG("Failed to duplicate ASN1_INTEGER");
-                    XFREE(bc, NULL, DYNAMIC_TYPE_X509_EXT);
+                    wolfSSL_BASIC_CONSTRAINTS_free(bc);
                     return NULL;
                 }
@@ -8932,5 +9541,10 @@
     InitDecodedCert( &cert, rawCert, (word32)outSz, 0);
 
-    if (ParseCert(&cert, CA_TYPE, NO_VERIFY, NULL) < 0) {
+    if (ParseCert(&cert,
+#ifdef WOLFSSL_CERT_REQ
+            x509->isCSR ? CERTREQ_TYPE :
+#endif
+            CA_TYPE,
+            NO_VERIFY, NULL) < 0) {
         WOLFSSL_MSG("\tCertificate parsing failed");
         return WOLFSSL_FATAL_ERROR;
@@ -8946,14 +9560,19 @@
     }
 
-    if (input[idx++] != ASN_EXTENSIONS) {
-        WOLFSSL_MSG("\tfail: should be an EXTENSIONS");
-        FreeDecodedCert(&cert);
-        return WOLFSSL_FATAL_ERROR;
-    }
-
-    if (GetLength(input, &idx, &length, sz) < 0) {
-        WOLFSSL_MSG("\tfail: invalid length");
-        FreeDecodedCert(&cert);
-        return WOLFSSL_FATAL_ERROR;
+#ifdef WOLFSSL_CERT_REQ
+    if (!x509->isCSR)
+#endif
+    {
+        if (input[idx++] != ASN_EXTENSIONS) {
+            WOLFSSL_MSG("\tfail: should be an EXTENSIONS");
+            FreeDecodedCert(&cert);
+            return WOLFSSL_FATAL_ERROR;
+        }
+
+        if (GetLength(input, &idx, &length, sz) < 0) {
+            WOLFSSL_MSG("\tfail: invalid length");
+            FreeDecodedCert(&cert);
+            return WOLFSSL_FATAL_ERROR;
+        }
     }
 
@@ -9003,4 +9622,9 @@
 
 #endif /* OPENSSL_ALL */
+
+#endif /* !NO_CERTS */
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 
 WOLFSSL_ASN1_BIT_STRING* wolfSSL_ASN1_BIT_STRING_new(void)
@@ -9059,4 +9683,5 @@
     WOLFSSL_ASN1_OBJECT* obj = NULL;
     WOLFSSL_GENERAL_NAME* gn = NULL;
+    WOLFSSL_BASIC_CONSTRAINTS* bc = NULL;
 
     WOLFSSL_ENTER("wolfSSL_X509_get_ext_d2i");
@@ -9073,25 +9698,33 @@
         case BASIC_CA_OID:
             if (x509->basicConstSet) {
-                obj = wolfSSL_ASN1_OBJECT_new();
-                if (obj == NULL) {
-                    WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                WOLFSSL_ASN1_INTEGER* a;
+
+                bc = wolfSSL_BASIC_CONSTRAINTS_new();
+                if (!bc) {
+                    WOLFSSL_MSG("wolfSSL_BASIC_CONSTRAINTS_new error");
                     return NULL;
                 }
+
+                a = wolfSSL_ASN1_INTEGER_new();
+                if (!a) {
+                    WOLFSSL_MSG("wolfSSL_ASN1_INTEGER_new error");
+                    wolfSSL_BASIC_CONSTRAINTS_free(bc);
+                    return NULL;
+                }
+                a->length = x509->pathLength;
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) || \
+        defined(WOLFSSL_APACHE_HTTPD)
+                bc->ca = x509->isCa;
+#endif
+                bc->pathlen = a;
                 if (c != NULL) {
                     *c = x509->basicConstCrit;
                 }
-                obj->type = BASIC_CA_OID;
-                obj->grp  = oidCertExtType;
-                obj->nid  = nid;
-                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
-            #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) || \
-                    defined(WOLFSSL_APACHE_HTTPD)
-                obj->ca = x509->isCa;
-            #endif
             }
             else {
                 WOLFSSL_MSG("No Basic Constraint set");
             }
-            return obj;
+            return bc;
 
         case ALT_NAMES_OID:
@@ -9099,11 +9732,11 @@
             DNS_entry* dns = NULL;
             /* Malloc GENERAL_NAME stack */
-            sk = (WOLF_STACK_OF(WOLFSSL_GENERAL_NAME)*)XMALLOC(
-                        sizeof(WOLF_STACK_OF(WOLFSSL_GENERAL_NAME)), NULL,
+            sk = (WOLFSSL_GENERAL_NAMES*)XMALLOC(
+                        sizeof(WOLFSSL_GENERAL_NAMES), NULL,
                                                          DYNAMIC_TYPE_ASN1);
             if (sk == NULL) {
                 return NULL;
             }
-            XMEMSET(sk, 0, sizeof(WOLF_STACK_OF(WOLFSSL_GENERAL_NAME)));
+            XMEMSET(sk, 0, sizeof(WOLFSSL_GENERAL_NAMES));
             sk->type = STACK_TYPE_GEN_NAME;
 
@@ -9140,14 +9773,13 @@
 
                     dns = dns->next;
-                    /* last dns in list add at end of function */
-                    if (dns != NULL) {
-                        if (wolfSSL_sk_GENERAL_NAME_push(sk, gn) !=
-                                                          WOLFSSL_SUCCESS) {
-                            WOLFSSL_MSG("Error pushing ASN1 object onto stack");
-                            wolfSSL_GENERAL_NAME_free(gn);
-                            wolfSSL_sk_free(sk);
-                            sk = NULL;
-                        }
+                    if (wolfSSL_sk_GENERAL_NAME_push(sk, gn) !=
+                                                      WOLFSSL_SUCCESS) {
+                        WOLFSSL_MSG("Error pushing ASN1 object onto stack");
+                        wolfSSL_GENERAL_NAME_free(gn);
+                        wolfSSL_sk_free(sk);
+                        sk = NULL;
                     }
+                    /* null so that it doesn't get pushed again after switch */
+                    gn = NULL;
                 }
             }
@@ -9173,6 +9805,4 @@
                 obj->obj   = x509->CRLInfo;
                 obj->objSz = x509->CRLInfoSz;
-                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
-                obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA ;
             }
             else {
@@ -9195,6 +9825,4 @@
                 obj->obj   = x509->authInfo;
                 obj->objSz = x509->authInfoSz;
-                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
-                obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA;
             }
             else {
@@ -9205,4 +9833,10 @@
         case AUTH_KEY_OID:
             if (x509->authKeyIdSet) {
+                WOLFSSL_AUTHORITY_KEYID* akey = wolfSSL_AUTHORITY_KEYID_new();
+                if (!akey) {
+                    WOLFSSL_MSG("Issue creating WOLFSSL_AUTHORITY_KEYID struct");
+                    return NULL;
+                }
+
                 if (c != NULL) {
                     *c = x509->authKeyIdCrit;
@@ -9211,4 +9845,5 @@
                 if (obj == NULL) {
                     WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                    wolfSSL_AUTHORITY_KEYID_free(akey);
                     return NULL;
                 }
@@ -9217,6 +9852,6 @@
                 obj->obj   = x509->authKeyId;
                 obj->objSz = x509->authKeyIdSz;
-                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
-                obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA;
+                akey->issuer = obj;
+                return akey;
             }
             else {
@@ -9239,6 +9874,4 @@
                 obj->obj   = x509->subjKeyId;
                 obj->objSz = x509->subjKeyIdSz;
-                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
-                obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA;
             }
             else {
@@ -9278,6 +9911,4 @@
                     obj->obj   = (byte*)(x509->certPolicies[i]);
                     obj->objSz = MAX_CERTPOL_SZ;
-                    obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
-                    obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA;
                     if (wolfSSL_sk_ASN1_OBJECT_push(sk, obj)
                                                            != WOLFSSL_SUCCESS) {
@@ -9298,6 +9929,4 @@
                 obj->obj   = (byte*)(x509->certPolicies[i]);
                 obj->objSz = MAX_CERTPOL_SZ;
-                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
-                obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA;
             }
             else {
@@ -9316,5 +9945,4 @@
                 obj->type  = CERT_POLICY_OID;
                 obj->grp   = oidCertExtType;
-                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
             }
             else {
@@ -9328,5 +9956,5 @@
         case KEY_USAGE_OID:
         {
-            WOLFSSL_ASN1_BIT_STRING* bit_str = NULL;
+            WOLFSSL_ASN1_STRING* asn1str = NULL;
             if (x509->keyUsageSet) {
                 if (c != NULL) {
@@ -9334,19 +9962,18 @@
                 }
 
-                bit_str = wolfSSL_ASN1_BIT_STRING_new();
-                if (bit_str == NULL) {
-                    WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_BIT_STRING struct");
+                asn1str = wolfSSL_ASN1_STRING_new();
+                if (asn1str == NULL) {
+                    WOLFSSL_MSG("Failed to malloc ASN1_STRING");
                     return NULL;
                 }
 
-                bit_str->type = KEY_USAGE_OID;
-                bit_str->flags = 0;
-                bit_str->length = sizeof(word16);
-                bit_str->data = (byte*)XMALLOC(bit_str->length, NULL, DYNAMIC_TYPE_OPENSSL);
-                if (bit_str->data == NULL) {
-                    wolfSSL_ASN1_BIT_STRING_free(bit_str);
+                if (wolfSSL_ASN1_STRING_set(asn1str, &x509->keyUsage,
+                        sizeof(word16)) != WOLFSSL_SUCCESS) {
+                    WOLFSSL_MSG("wolfSSL_ASN1_STRING_set error");
+                    wolfSSL_ASN1_STRING_free(asn1str);
                     return NULL;
                 }
-                XMEMCPY(bit_str->data, &x509->keyUsage, bit_str->length);
+
+                asn1str->type = KEY_USAGE_OID;
             }
             else {
@@ -9354,5 +9981,5 @@
             }
             /* don't add stack of and return bit string directly */
-            return bit_str;
+            return asn1str;
         }
         case INHIBIT_ANY_OID:
@@ -9379,6 +10006,4 @@
                 obj->obj   = x509->extKeyUsageSrc;
                 obj->objSz = x509->extKeyUsageSz;
-                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
-                obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA;
             }
             else {
@@ -9426,16 +10051,19 @@
         }
     }
-    if (obj && wolfSSL_sk_ASN1_OBJECT_push(sk, obj) == WOLFSSL_SUCCESS) {
-        /* obj pushed successfully on stack */
-    }
-    else if (gn && wolfSSL_sk_GENERAL_NAME_push(sk, gn) == WOLFSSL_SUCCESS) {
-        /* gn pushed successfully on stack */
-    }
-    else {
-        /* Nothing to push or push failed */
-        WOLFSSL_MSG("Error pushing ASN1_OBJECT or GENERAL_NAME object onto stack "
-                    "or nothing to push.");
-        goto err;
-    }
+    if (obj) {
+        if (wolfSSL_sk_ASN1_OBJECT_push(sk, obj) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("Error pushing ASN1_OBJECT object onto "
+                        "stack.");
+            goto err;
+        }
+    }
+    else if (gn) {
+        if (wolfSSL_sk_GENERAL_NAME_push(sk, gn) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("Error pushing GENERAL_NAME object onto "
+                        "stack.");
+            goto err;
+        }
+    }
+
     ret = sk;
 
@@ -9452,24 +10080,22 @@
     }
     if (sk) {
-        wolfSSL_sk_ASN1_OBJECT_free(sk);
+        wolfSSL_sk_free(sk);
     }
     return NULL;
 }
-
-
-int wolfSSL_X509_add_altname(WOLFSSL_X509* x509, const char* name, int type)
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#ifdef OPENSSL_EXTRA
+#ifndef NO_CERTS
+int wolfSSL_X509_add_altname_ex(WOLFSSL_X509* x509, const char* name,
+        word32 nameSz, int type)
 {
     DNS_entry* newAltName = NULL;
     char* nameCopy = NULL;
-    word32 nameSz;
 
     if (x509 == NULL)
         return WOLFSSL_FAILURE;
 
-    if (name == NULL)
-        return WOLFSSL_SUCCESS;
-
-    nameSz = (word32)XSTRLEN(name);
-    if (nameSz == 0)
+    if ((name == NULL) || (nameSz == 0))
         return WOLFSSL_SUCCESS;
 
@@ -9485,5 +10111,7 @@
     }
 
-    XMEMCPY(nameCopy, name, nameSz + 1);
+    XMEMCPY(nameCopy, name, nameSz);
+
+    nameCopy[nameSz] = '\0';
 
     newAltName->next = x509->altNames;
@@ -9496,13 +10124,30 @@
 }
 
+int wolfSSL_X509_add_altname(WOLFSSL_X509* x509, const char* name, int type)
+{
+    word32 nameSz;
+
+    if (name == NULL)
+        return WOLFSSL_SUCCESS;
+
+    nameSz = (word32)XSTRLEN(name);
+    if (nameSz == 0)
+        return WOLFSSL_SUCCESS;
+
+    if (type == ASN_IP_TYPE) {
+        WOLFSSL_MSG("Type not supported, use wolfSSL_X509_add_altname_ex");
+        return WOLFSSL_FAILURE;
+    }
+
+    return wolfSSL_X509_add_altname_ex(x509, name, nameSz, type);
+}
 
 #ifndef NO_WOLFSSL_STUB
-int wolfSSL_X509_add_ext(WOLFSSL_X509 *x509, WOLFSSL_X509_EXTENSION *ext, int loc)
-{
-    WOLFSSL_STUB("wolfSSL_X509_add_ext");
+WOLFSSL_X509_EXTENSION *wolfSSL_X509_delete_ext(WOLFSSL_X509 *x509, int loc)
+{
+    WOLFSSL_STUB("wolfSSL_X509_delete_ext");
     (void)x509;
-    (void)ext;
     (void)loc;
-    return WOLFSSL_FAILURE;
+    return NULL;
 }
 
@@ -9533,4 +10178,184 @@
 #endif /* !NO_WOLFSSL_STUB */
 
+#if defined(OPENSSL_ALL)
+static void wolfSSL_X509V3_EXT_METHOD_populate(WOLFSSL_v3_ext_method *method,
+                                               int nid)
+{
+    if (!method)
+        return;
+
+    WOLFSSL_ENTER("wolfSSL_X509V3_EXT_METHOD_populate");
+    switch (nid) {
+    case NID_subject_key_identifier:
+        method->i2s = (X509V3_EXT_I2S)wolfSSL_i2s_ASN1_STRING;
+        FALL_THROUGH;
+    case NID_authority_key_identifier:
+    case NID_key_usage:
+    case NID_certificate_policies:
+    case NID_policy_mappings:
+    case NID_subject_alt_name:
+    case NID_issuer_alt_name:
+    case NID_basic_constraints:
+    case NID_name_constraints:
+    case NID_policy_constraints:
+    case NID_ext_key_usage:
+    case NID_crl_distribution_points:
+    case NID_inhibit_any_policy:
+    case NID_info_access:
+        WOLFSSL_MSG("Nothing to populate for current NID");
+        break;
+    default:
+        WOLFSSL_MSG("Unknown or unsupported NID");
+        break;
+    }
+
+    return;
+}
+
+/**
+ * @param nid One of the NID_* constants defined in asn.h
+ * @param crit
+ * @param data This data is copied to the returned extension.
+ * @return
+ */
+WOLFSSL_X509_EXTENSION *wolfSSL_X509V3_EXT_i2d(int nid, int crit,
+                                               void *data)
+{
+    WOLFSSL_X509_EXTENSION *ext = NULL;
+    WOLFSSL_ASN1_STRING* asn1str = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_X509V3_EXT_i2d");
+
+    if (!data) {
+        return NULL;
+    }
+
+    if (!(ext = wolfSSL_X509_EXTENSION_new())) {
+        return NULL;
+    }
+
+    wolfSSL_X509V3_EXT_METHOD_populate(&ext->ext_method, nid);
+
+    switch (nid) {
+    case NID_subject_key_identifier:
+        /* WOLFSSL_ASN1_STRING */
+    case NID_key_usage:
+        /* WOLFSSL_ASN1_STRING */
+    {
+        asn1str = (WOLFSSL_ASN1_STRING*)data;
+        ext->value = *asn1str;
+        if (asn1str->isDynamic) {
+            ext->value.data = (char*)XMALLOC(asn1str->length, NULL,
+                                             DYNAMIC_TYPE_OPENSSL);
+            if (!ext->value.data) {
+                WOLFSSL_MSG("malloc failed");
+                /* Zero so that no existing memory is freed */
+                XMEMSET(&ext->value, 0, sizeof(WOLFSSL_ASN1_STRING));
+                goto err_cleanup;
+            }
+            XMEMCPY(ext->value.data, asn1str->data, asn1str->length);
+        }
+        else {
+            ext->value.data = ext->value.strData;
+        }
+        break;
+    }
+    case NID_subject_alt_name:
+        /* typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES */
+    case NID_issuer_alt_name:
+        /* typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES */
+    case NID_ext_key_usage:
+        /* typedef STACK_OF(ASN1_OBJECT) EXTENDED_KEY_USAGE */
+    case NID_info_access:
+        /* typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS */
+    {
+        WOLFSSL_STACK* sk = (WOLFSSL_STACK*)data;
+
+        if (ext->ext_sk) {
+            wolfSSL_sk_free(ext->ext_sk);
+        }
+
+        if (!(ext->ext_sk = wolfSSL_sk_dup(sk))) {
+            WOLFSSL_MSG("wolfSSL_sk_dup failed");
+            goto err_cleanup;
+        }
+        break;
+    }
+    case NID_basic_constraints:
+    {
+        /* WOLFSSL_BASIC_CONSTRAINTS */
+        WOLFSSL_BASIC_CONSTRAINTS* bc = (WOLFSSL_BASIC_CONSTRAINTS*)data;
+
+        if (!(ext->obj = wolfSSL_ASN1_OBJECT_new())) {
+            WOLFSSL_MSG("wolfSSL_ASN1_OBJECT_new failed");
+            goto err_cleanup;
+        }
+
+        ext->obj->ca = bc->ca;
+        if (bc->pathlen) {
+            ext->obj->pathlen = wolfSSL_ASN1_INTEGER_dup(bc->pathlen);
+            if (!ext->obj->pathlen) {
+                WOLFSSL_MSG("wolfSSL_ASN1_INTEGER_dup failed");
+                goto err_cleanup;
+            }
+        }
+        break;
+    }
+    case NID_authority_key_identifier:
+    {
+        /* AUTHORITY_KEYID */
+        WOLFSSL_AUTHORITY_KEYID* akey = (WOLFSSL_AUTHORITY_KEYID*)data;
+
+        if (akey->keyid) {
+            if (wolfSSL_ASN1_STRING_set(&ext->value, akey->keyid->data,
+                                    akey->keyid->length) != WOLFSSL_SUCCESS) {
+                WOLFSSL_MSG("wolfSSL_ASN1_STRING_set failed");
+                goto err_cleanup;
+            }
+            ext->value.type = akey->keyid->type;
+        }
+        else if (akey->issuer) {
+            ext->obj = wolfSSL_ASN1_OBJECT_dup(akey->issuer);
+            if (!ext->obj) {
+                WOLFSSL_MSG("wolfSSL_ASN1_OBJECT_dup failed");
+                goto err_cleanup;
+            }
+        }
+        else {
+            WOLFSSL_MSG("NID_authority_key_identifier empty data");
+            goto err_cleanup;
+        }
+        break;
+    }
+    case NID_inhibit_any_policy:
+        /* ASN1_INTEGER */
+    case NID_certificate_policies:
+        /* STACK_OF(POLICYINFO) */
+    case NID_policy_mappings:
+        /* STACK_OF(POLICY_MAPPING) */
+    case NID_name_constraints:
+        /* NAME_CONSTRAINTS */
+    case NID_policy_constraints:
+        /* POLICY_CONSTRAINTS */
+    case NID_crl_distribution_points:
+        /* typedef STACK_OF(DIST_POINT) CRL_DIST_POINTS */
+    default:
+        WOLFSSL_MSG("Unknown or unsupported NID");
+        break;
+    }
+
+    ext->crit = crit;
+
+    return ext;
+err_cleanup:
+    if (ext) {
+        wolfSSL_X509_EXTENSION_free(ext);
+    }
+    if (asn1str) {
+        wolfSSL_ASN1_STRING_free(asn1str);
+    }
+    return NULL;
+}
+
 /* Returns pointer to ASN1_OBJECT from an X509_EXTENSION object */
 WOLFSSL_ASN1_OBJECT* wolfSSL_X509_EXTENSION_get_object \
@@ -9542,4 +10367,5 @@
     return ext->obj;
 }
+#endif /* OPENSSL_ALL */
 
 /* Returns pointer to ASN1_STRING in X509_EXTENSION object */
@@ -9749,5 +10575,5 @@
 #ifdef HAVE_ECC
 
-/* Set Temp CTX EC-DHE size in octets, should be 20 - 66 for 160 - 521 bit */
+/* Set Temp CTX EC-DHE size in octets, can be 14 - 66 (112 - 521 bit) */
 int wolfSSL_CTX_SetTmpEC_DHE_Sz(WOLFSSL_CTX* ctx, word16 sz)
 {
@@ -9755,4 +10581,5 @@
         return BAD_FUNC_ARG;
 
+    /* if 0 then get from loaded private key */
     if (sz == 0) {
         /* applies only to ECDSA */
@@ -9778,8 +10605,12 @@
 
 
-/* Set Temp SSL EC-DHE size in octets, should be 20 - 66 for 160 - 521 bit */
+/* Set Temp SSL EC-DHE size in octets, can be 14 - 66 (112 - 521 bit) */
 int wolfSSL_SetTmpEC_DHE_Sz(WOLFSSL* ssl, word16 sz)
 {
-    if (ssl == NULL || sz < ECC_MINSIZE || sz > ECC_MAXSIZE)
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    /* check size */
+    if (sz < ECC_MINSIZE || sz > ECC_MAXSIZE)
         return BAD_FUNC_ARG;
 
@@ -9886,21 +10717,22 @@
         return;
 
-    if (mode & WOLFSSL_VERIFY_PEER) {
-        ctx->verifyPeer = 1;
-        ctx->verifyNone = 0;  /* in case previously set */
-    }
+    ctx->verifyPeer     = 0;
+    ctx->verifyNone     = 0;
+    ctx->failNoCert     = 0;
+    ctx->failNoCertxPSK = 0;
 
     if (mode == WOLFSSL_VERIFY_NONE) {
         ctx->verifyNone = 1;
-        ctx->verifyPeer = 0;  /* in case previously set */
-    }
-
-    if (mode & WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
-        ctx->failNoCert = 1;
-    }
-
-    if (mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK) {
-        ctx->failNoCert    = 0; /* fail on all is set to fail on PSK */
-        ctx->failNoCertxPSK = 1;
+    }
+    else {
+        if (mode & WOLFSSL_VERIFY_PEER) {
+            ctx->verifyPeer = 1;
+        }
+        if (mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK) {
+            ctx->failNoCertxPSK = 1;
+        }
+        if (mode & WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+            ctx->failNoCert = 1;
+        }
     }
 
@@ -9928,20 +10760,22 @@
         return;
 
-    if (mode & WOLFSSL_VERIFY_PEER) {
-        ssl->options.verifyPeer = 1;
-        ssl->options.verifyNone = 0;  /* in case previously set */
-    }
+    ssl->options.verifyPeer     = 0;
+    ssl->options.verifyNone     = 0;
+    ssl->options.failNoCert     = 0;
+    ssl->options.failNoCertxPSK = 0;
 
     if (mode == WOLFSSL_VERIFY_NONE) {
         ssl->options.verifyNone = 1;
-        ssl->options.verifyPeer = 0;  /* in case previously set */
-    }
-
-    if (mode & WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT)
-        ssl->options.failNoCert = 1;
-
-    if (mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK) {
-        ssl->options.failNoCert    = 0; /* fail on all is set to fail on PSK */
-        ssl->options.failNoCertxPSK = 1;
+    }
+    else {
+        if (mode & WOLFSSL_VERIFY_PEER) {
+            ssl->options.verifyPeer = 1;
+        }
+        if (mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK) {
+            ssl->options.failNoCertxPSK = 1;
+        }
+        if (mode & WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+            ssl->options.failNoCert = 1;
+        }
     }
 
@@ -9964,4 +10798,32 @@
 }
 
+#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
+    defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
+/* For TLS v1.3 send handshake messages after handshake completes. */
+/* Returns 1=WOLFSSL_SUCCESS or 0=WOLFSSL_FAILURE */
+int wolfSSL_verify_client_post_handshake(WOLFSSL* ssl)
+{
+    int ret = wolfSSL_request_certificate(ssl);
+    return (ret == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
+}
+
+int wolfSSL_CTX_set_post_handshake_auth(WOLFSSL_CTX* ctx, int val)
+{
+    int ret = wolfSSL_CTX_allow_post_handshake_auth(ctx);
+    if (ret == 0) {
+        ctx->postHandshakeAuth = (val != 0);
+    }
+    return (ret == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
+}
+int wolfSSL_set_post_handshake_auth(WOLFSSL* ssl, int val)
+{
+    int ret = wolfSSL_allow_post_handshake_auth(ssl);
+    if (ret == 0) {
+        ssl->options.postHandshakeAuth = (val != 0);
+    }
+    return (ret == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
+}
+#endif /* OPENSSL_EXTRA && !NO_CERTS && WOLFSSL_TLS13 && WOLFSSL_POST_HANDSHAKE_AUTH */
+
 /* store user ctx for verify callback */
 void wolfSSL_SetCertCbCtx(WOLFSSL* ssl, void* ctx)
@@ -10093,5 +10955,5 @@
             if (SetSession(ssl, session) != WOLFSSL_SUCCESS) {
     #ifdef HAVE_EXT_CACHE
-                wolfSSL_SESSION_free(session);
+                FreeSession(session, 0);
     #endif
                 WOLFSSL_MSG("SetSession failed");
@@ -10109,5 +10971,5 @@
     #ifdef HAVE_EXT_CACHE
     else
-        wolfSSL_SESSION_free(session);
+        FreeSession(session, 0);
     #endif
 
@@ -11065,4 +11927,118 @@
 }
 
+#ifdef HAVE_KEYING_MATERIAL
+
+#define TLS_PRF_LABEL_CLIENT_FINISHED     "client finished"
+#define TLS_PRF_LABEL_SERVER_FINISHED     "server finished"
+#define TLS_PRF_LABEL_MASTER_SECRET       "master secret"
+#define TLS_PRF_LABEL_EXT_MASTER_SECRET   "extended master secret"
+#define TLS_PRF_LABEL_KEY_EXPANSION       "key expansion"
+
+static const struct ForbiddenLabels {
+    const char* label;
+    size_t labelLen;
+} forbiddenLabels[] = {
+    {TLS_PRF_LABEL_CLIENT_FINISHED, XSTR_SIZEOF(TLS_PRF_LABEL_CLIENT_FINISHED)},
+    {TLS_PRF_LABEL_SERVER_FINISHED, XSTR_SIZEOF(TLS_PRF_LABEL_SERVER_FINISHED)},
+    {TLS_PRF_LABEL_MASTER_SECRET, XSTR_SIZEOF(TLS_PRF_LABEL_MASTER_SECRET)},
+    {TLS_PRF_LABEL_EXT_MASTER_SECRET, XSTR_SIZEOF(TLS_PRF_LABEL_EXT_MASTER_SECRET)},
+    {TLS_PRF_LABEL_KEY_EXPANSION, XSTR_SIZEOF(TLS_PRF_LABEL_KEY_EXPANSION)},
+    {NULL, 0},
+};
+
+/**
+ * Implement RFC 5705
+ * TLS 1.3 uses a different exporter definition (section 7.5 of RFC 8446)
+ * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on error
+ */
+int wolfSSL_export_keying_material(WOLFSSL *ssl,
+        unsigned char *out, size_t outLen,
+        const char *label, size_t labelLen,
+        const unsigned char *context, size_t contextLen,
+        int use_context)
+{
+    byte*  seed = NULL;
+    word32 seedLen;
+    const struct ForbiddenLabels* fl;
+
+    WOLFSSL_ENTER("wolfSSL_export_keying_material");
+
+    if (ssl == NULL || out == NULL || label == NULL ||
+            (use_context && contextLen && context == NULL)) {
+        WOLFSSL_MSG("Bad argument");
+        return WOLFSSL_FAILURE;
+    }
+
+    /* clientRandom + serverRandom
+     * OR
+     * clientRandom + serverRandom + ctx len encoding + ctx */
+    seedLen = !use_context ? (word32)SEED_LEN :
+                             (word32)SEED_LEN + 2 + (word32)contextLen;
+
+    if (ssl->options.saveArrays == 0 || ssl->arrays == NULL) {
+        WOLFSSL_MSG("To export keying material wolfSSL needs to keep handshake "
+                    "data. Call wolfSSL_KeepArrays before attempting to "
+                    "export keyig material.");
+        return WOLFSSL_FAILURE;
+    }
+
+    /* check forbidden labels */
+    for (fl = &forbiddenLabels[0]; fl->label != NULL; fl++) {
+        if (labelLen >= fl->labelLen &&
+                XMEMCMP(label, fl->label, fl->labelLen) == 0) {
+            WOLFSSL_MSG("Forbidden label");
+            return WOLFSSL_FAILURE;
+        }
+    }
+
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+        /* Path for TLS 1.3 */
+        if (!use_context) {
+            contextLen = 0;
+            context = (byte*)""; /* Give valid pointer for 0 length memcpy */
+        }
+
+        if (Tls13_Exporter(ssl, out, (word32)outLen, label, labelLen,
+                context, contextLen) != 0) {
+            WOLFSSL_MSG("Tls13_Exporter error");
+            return WOLFSSL_FAILURE;
+        }
+        return WOLFSSL_SUCCESS;
+    }
+#endif
+
+    /* Path for <=TLS 1.2 */
+    seed = (byte*)XMALLOC(seedLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (seed == NULL) {
+        WOLFSSL_MSG("malloc error");
+        return WOLFSSL_FAILURE;
+    }
+
+    XMEMCPY(seed,           ssl->arrays->clientRandom, RAN_LEN);
+    XMEMCPY(seed + RAN_LEN, ssl->arrays->serverRandom, RAN_LEN);
+
+    if (use_context) {
+        /* Encode len in big endian */
+        seed[SEED_LEN    ] = (contextLen >> 8) & 0xFF;
+        seed[SEED_LEN + 1] = (contextLen) & 0xFF;
+        if (contextLen) {
+            /* 0 length context is allowed */
+            XMEMCPY(seed + SEED_LEN + 2, context, contextLen);
+        }
+    }
+
+    if (wc_PRF_TLS(out, (word32)outLen, ssl->arrays->masterSecret, SECRET_LEN,
+            (byte*)label, (word32)labelLen, seed, seedLen, IsAtLeastTLSv1_2(ssl),
+            ssl->specs.mac_algorithm, ssl->heap, ssl->devId) != 0) {
+        WOLFSSL_MSG("wc_PRF_TLS error");
+        XFREE(seed, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return WOLFSSL_FAILURE;
+    }
+
+    XFREE(seed, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    return WOLFSSL_SUCCESS;
+}
+#endif /* HAVE_KEYING_MATERIAL */
 
 int wolfSSL_dtls_get_using_nonblock(WOLFSSL* ssl)
@@ -11192,5 +12168,5 @@
         return WOLFSSL_FATAL_ERROR;
 
-    if (!ssl->options.handShakeDone &&
+    if ((IsSCR(ssl) || !ssl->options.handShakeDone) &&
         (DtlsMsgPoolTimeout(ssl) < 0 || DtlsMsgPoolSend(ssl, 0) < 0)) {
 
@@ -11344,5 +12320,5 @@
     #endif
 
-    #ifdef WOLFSSL_ALLOW_SSLV3
+    #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS)
     WOLFSSL_METHOD* wolfSSLv3_client_method(void)
     {
@@ -11360,5 +12336,5 @@
         return method;
     }
-    #endif /* WOLFSSL_ALLOW_SSLV3 */
+    #endif /* WOLFSSL_ALLOW_SSLV3 && !NO_OLD_TLS */
 
 
@@ -11444,5 +12420,5 @@
     #ifdef OPENSSL_EXTRA
         if (ssl->CBIS != NULL) {
-            ssl->CBIS(ssl, SSL_ST_CONNECT, SSL_SUCCESS);
+            ssl->CBIS(ssl, SSL_ST_CONNECT, WOLFSSL_SUCCESS);
             ssl->cbmode = SSL_CB_WRITE;
         }
@@ -11473,5 +12449,5 @@
         if (ssl->buffers.outputBuffer.length > 0
         #ifdef WOLFSSL_ASYNC_CRYPT
-            /* do not send buffered or advance state if last error was an 
+            /* do not send buffered or advance state if last error was an
                 async pending operation */
             && ssl->error != WC_PENDING_E
@@ -11635,4 +12611,5 @@
             FALL_THROUGH;
 
+    #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS)
         case FIRST_REPLY_SECOND :
             #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH)
@@ -11682,5 +12659,5 @@
 
         case SECOND_REPLY_DONE:
-#ifndef NO_HANDSHAKE_DONE_CB
+        #ifndef NO_HANDSHAKE_DONE_CB
             if (ssl->hsDoneCb) {
                 int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx);
@@ -11691,5 +12668,5 @@
                 }
             }
-#endif /* NO_HANDSHAKE_DONE_CB */
+        #endif /* NO_HANDSHAKE_DONE_CB */
 
             if (!ssl->options.dtls) {
@@ -11698,12 +12675,21 @@
                 }
             }
-#ifdef WOLFSSL_DTLS
+        #ifdef WOLFSSL_DTLS
             else {
                 ssl->options.dtlsHsRetain = 1;
             }
-#endif /* WOLFSSL_DTLS */
+        #endif /* WOLFSSL_DTLS */
+
+        #if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_SECURE_RENEGOTIATION)
+            /* This may be necessary in async so that we don't try to
+             * renegotiate again */
+            if (ssl->secure_renegotiation && ssl->secure_renegotiation->startScr) {
+                ssl->secure_renegotiation->startScr = 0;
+            }
+        #endif /* WOLFSSL_ASYNC_CRYPT && HAVE_SECURE_RENEGOTIATION */
 
             WOLFSSL_LEAVE("SSL_connect()", WOLFSSL_SUCCESS);
             return WOLFSSL_SUCCESS;
+    #endif /* !WOLFSSL_NO_TLS12 || !NO_OLD_TLS */
 
         default:
@@ -11711,5 +12697,5 @@
             return WOLFSSL_FATAL_ERROR; /* unknown connect state */
         }
-    #endif /* !WOLFSSL_NO_TLS12 */
+    #endif /* !WOLFSSL_NO_TLS12 || !NO_OLD_TLS || !WOLFSSL_TLS13 */
     }
 
@@ -11728,5 +12714,5 @@
     #endif
 
-    #ifdef WOLFSSL_ALLOW_SSLV3
+    #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS)
     WOLFSSL_METHOD* wolfSSLv3_server_method(void)
     {
@@ -11746,5 +12732,5 @@
         return method;
     }
-    #endif /* WOLFSSL_ALLOW_SSLV3 */
+    #endif /* WOLFSSL_ALLOW_SSLV3 && !NO_OLD_TLS */
 
     WOLFSSL_METHOD* wolfSSLv23_server_method(void)
@@ -11785,4 +12771,5 @@
 
 
+    WOLFSSL_ABI
     int wolfSSL_accept(WOLFSSL* ssl)
     {
@@ -11877,5 +12864,5 @@
         if (ssl->buffers.outputBuffer.length > 0
         #ifdef WOLFSSL_ASYNC_CRYPT
-            /* do not send buffered or advance state if last error was an 
+            /* do not send buffered or advance state if last error was an
                 async pending operation */
             && ssl->error != WC_PENDING_E
@@ -12020,5 +13007,5 @@
         case ACCEPT_SECOND_REPLY_DONE :
 #ifdef HAVE_SESSION_TICKET
-            if (ssl->options.createTicket) {
+            if (ssl->options.createTicket && !ssl->options.noTicketTls12) {
                 if ( (ssl->error = SendTicket(ssl)) != 0) {
                     WOLFSSL_ERROR(ssl->error);
@@ -12084,4 +13071,12 @@
             }
 #endif /* WOLFSSL_DTLS */
+
+#if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_SECURE_RENEGOTIATION)
+            /* This may be necessary in async so that we don't try to
+             * renegotiate again */
+            if (ssl->secure_renegotiation && ssl->secure_renegotiation->startScr) {
+                ssl->secure_renegotiation->startScr = 0;
+            }
+#endif /* WOLFSSL_ASYNC_CRYPT && HAVE_SECURE_RENEGOTIATION */
 
 #ifdef WOLFSSL_SESSION_EXPORT
@@ -12423,5 +13418,6 @@
 
         current = &SessionCache[row].Sessions[idx];
-        if (XMEMCMP(current->sessionID, id, ID_LEN) == 0) {
+        if (XMEMCMP(current->sessionID, id, ID_LEN) == 0 &&
+                current->side == ssl->options.side) {
             WOLFSSL_MSG("Found a session match");
             if (LowResTimer() < (current->bornOn + current->timeout)) {
@@ -12508,8 +13504,7 @@
     copyInto->ticketSeen     = copyFrom->ticketSeen;
     copyInto->ticketAdd      = copyFrom->ticketAdd;
-#ifndef WOLFSSL_TLS13_DRAFT_18
+    copyInto->side           = copyFrom->side;
     XMEMCPY(&copyInto->ticketNonce, &copyFrom->ticketNonce,
                                                            sizeof(TicketNonce));
-#endif
 #ifdef WOLFSSL_EARLY_DATA
     copyInto->maxEarlyDataSz = copyFrom->maxEarlyDataSz;
@@ -12619,4 +13614,5 @@
     word32 idx = 0;
     int    error = 0;
+    const byte* id = NULL;
 #ifdef HAVE_SESSION_TICKET
     byte*  tmpBuff = NULL;
@@ -12626,4 +13622,7 @@
     int i;
     int overwrite = 0;
+#ifdef HAVE_EXT_CACHE
+    int cbRet = 0;
+#endif
 
     if (ssl->options.sessionCacheOff)
@@ -12638,8 +13637,19 @@
 #endif
 
+#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
+    if (ssl->options.tls1_3)
+        id = ssl->session.sessionID;
+    else
+#endif
+    if (ssl->arrays)
+        id = ssl->arrays->sessionID;
+    if (id == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
 #ifdef HAVE_SESSION_TICKET
     ticLen = ssl->session.ticketLen;
     /* Alloc Memory here so if Malloc fails can exit outside of lock */
-    if(ticLen > SESSION_TICKET_LEN) {
+    if (ticLen > SESSION_TICKET_LEN) {
         tmpBuff = (byte*)XMALLOC(ticLen, ssl->heap,
                 DYNAMIC_TYPE_SESSION_TICK);
@@ -12652,6 +13662,5 @@
     if (ssl->options.internalCacheOff) {
         /* Create a new session object to be stored. */
-        session = (WOLFSSL_SESSION*)XMALLOC(sizeof(WOLFSSL_SESSION), NULL,
-                                            DYNAMIC_TYPE_OPENSSL);
+        session = wolfSSL_SESSION_new();
         if (session == NULL) {
 #ifdef HAVE_SESSION_TICKET
@@ -12660,6 +13669,4 @@
             return MEMORY_E;
         }
-        XMEMSET(session, 0, sizeof(WOLFSSL_SESSION));
-        session->isAlloced = 1;
     }
     else
@@ -12668,15 +13675,5 @@
         /* Use the session object in the cache for external cache if required.
          */
-#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
-        if (ssl->options.tls1_3) {
-            row = HashSession(ssl->session.sessionID, ID_LEN, &error) %
-                    SESSION_ROWS;
-        }
-        else
-#endif
-        {
-            row = HashSession(ssl->arrays->sessionID, ID_LEN, &error) %
-                    SESSION_ROWS;
-        }
+        row = HashSession(id, ID_LEN, &error) % SESSION_ROWS;
         if (error != 0) {
             WOLFSSL_MSG("Hash session failed");
@@ -12695,19 +13692,10 @@
 
         for (i=0; i<SESSIONS_PER_ROW; i++) {
-            if (ssl->options.tls1_3) {
-                if (XMEMCMP(ssl->session.sessionID, SessionCache[row].Sessions[i].sessionID, ID_LEN) == 0) {
-                    WOLFSSL_MSG("Session already exists. Overwriting.");
-                    overwrite = 1;
-                    idx = i;
-                    break;
-                }
-            }
-            else {
-                if (XMEMCMP(ssl->arrays->sessionID, SessionCache[row].Sessions[i].sessionID, ID_LEN) == 0) {
-                    WOLFSSL_MSG("Session already exists. Overwriting.");
-                    overwrite = 1;
-                    idx = i;
-                    break;
-                }
+            if (XMEMCMP(id, SessionCache[row].Sessions[i].sessionID, ID_LEN) == 0 &&
+                    SessionCache[row].Sessions[i].side == ssl->options.side) {
+                WOLFSSL_MSG("Session already exists. Overwriting.");
+                overwrite = 1;
+                idx = i;
+                break;
             }
         }
@@ -12722,20 +13710,19 @@
     }
 
-    if (!ssl->options.tls1_3)
+    session->side = (byte)ssl->options.side;
+
+#ifdef WOLFSSL_TLS13
+    if (ssl->options.tls1_3) {
+        XMEMCPY(session->masterSecret, ssl->session.masterSecret, SECRET_LEN);
+        session->sessionIDSz = ID_LEN;
+    }
+    else
+#endif
+    {
         XMEMCPY(session->masterSecret, ssl->arrays->masterSecret, SECRET_LEN);
-    else
-        XMEMCPY(session->masterSecret, ssl->session.masterSecret, SECRET_LEN);
+        session->sessionIDSz = ssl->arrays->sessionIDSz;
+    }
+    XMEMCPY(session->sessionID, id, ID_LEN);
     session->haveEMS = ssl->options.haveEMS;
-#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
-    if (ssl->options.tls1_3) {
-        XMEMCPY(session->sessionID, ssl->session.sessionID, ID_LEN);
-        session->sessionIDSz = ID_LEN;
-    }
-    else
-#endif
-    {
-        XMEMCPY(session->sessionID, ssl->arrays->sessionID, ID_LEN);
-        session->sessionIDSz = ssl->arrays->sessionIDSz;
-    }
 
 #ifdef OPENSSL_EXTRA
@@ -12758,5 +13745,5 @@
     if (error == 0) {
         /* Cleanup cache row's old Dynamic buff if exists */
-        if(session->isDynamic) {
+        if (session->isDynamic) {
             XFREE(session->ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK);
             session->ticket = NULL;
@@ -12820,8 +13807,6 @@
         session->ticketSeen     = ssl->session.ticketSeen;
         session->ticketAdd      = ssl->session.ticketAdd;
-#ifndef WOLFSSL_TLS13_DRAFT_18
         XMEMCPY(&session->ticketNonce, &ssl->session.ticketNonce,
                                                            sizeof(TicketNonce));
-#endif
     #ifdef WOLFSSL_EARLY_DATA
         session->maxEarlyDataSz = ssl->session.maxEarlyDataSz;
@@ -12906,7 +13891,7 @@
 #ifdef HAVE_EXT_CACHE
     if (error == 0 && ssl->ctx->new_sess_cb != NULL)
-        ssl->ctx->new_sess_cb(ssl, session);
-    if (ssl->options.internalCacheOff)
-        wolfSSL_SESSION_free(session);
+        cbRet = ssl->ctx->new_sess_cb(ssl, session);
+    if (ssl->options.internalCacheOff && cbRet == 0)
+        FreeSession(session, 1);
 #endif
 
@@ -13453,5 +14438,4 @@
     }
 
-
     void wolfSSL_set_psk_client_callback(WOLFSSL* ssl,wc_psk_client_callback cb)
     {
@@ -13479,5 +14463,4 @@
     }
 
-
     void wolfSSL_CTX_set_psk_server_callback(WOLFSSL_CTX* ctx,
                                          wc_psk_server_callback cb)
@@ -13489,5 +14472,4 @@
         ctx->server_psk_cb = cb;
     }
-
 
     void wolfSSL_set_psk_server_callback(WOLFSSL* ssl,wc_psk_server_callback cb)
@@ -13515,5 +14497,4 @@
     }
 
-
     const char* wolfSSL_get_psk_identity_hint(const WOLFSSL* ssl)
     {
@@ -13536,5 +14517,4 @@
         return ssl->arrays->client_identity;
     }
-
 
     int wolfSSL_CTX_use_psk_identity_hint(WOLFSSL_CTX* ctx, const char* hint)
@@ -13554,5 +14534,4 @@
     }
 
-
     int wolfSSL_use_psk_identity_hint(WOLFSSL* ssl, const char* hint)
     {
@@ -13572,4 +14551,26 @@
     }
 
+    void* wolfSSL_get_psk_callback_ctx(WOLFSSL* ssl)
+    {
+        return ssl ? ssl->options.psk_ctx : NULL;
+    }
+    void* wolfSSL_CTX_get_psk_callback_ctx(WOLFSSL_CTX* ctx)
+    {
+        return ctx ? ctx->psk_ctx : NULL;
+    }
+    int wolfSSL_set_psk_callback_ctx(WOLFSSL* ssl, void* psk_ctx)
+    {
+        if (ssl == NULL)
+            return WOLFSSL_FAILURE;
+        ssl->options.psk_ctx = psk_ctx;
+        return WOLFSSL_SUCCESS;
+    }
+    int wolfSSL_CTX_set_psk_callback_ctx(WOLFSSL_CTX* ctx, void* psk_ctx)
+    {
+        if (ctx == NULL)
+            return WOLFSSL_FAILURE;
+        ctx->psk_ctx = psk_ctx;
+        return WOLFSSL_SUCCESS;
+    }
 #endif /* NO_PSK */
 
@@ -13601,4 +14602,5 @@
     {
         int verify;
+        int ret = WOLFSSL_FAILURE;
 
         WOLFSSL_ENTER("wolfSSL_CTX_load_verify_buffer_ex");
@@ -13609,9 +14611,11 @@
 
         if (format == WOLFSSL_FILETYPE_PEM)
-            return ProcessChainBuffer(ctx, in, sz, format, CA_TYPE, NULL,
+            ret = ProcessChainBuffer(ctx, in, sz, format, CA_TYPE, NULL,
                                       verify);
         else
-            return ProcessBuffer(ctx, in, sz, format, CA_TYPE, NULL, NULL,
+            ret = ProcessBuffer(ctx, in, sz, format, CA_TYPE, NULL, NULL,
                                  userChain, verify);
+        WOLFSSL_LEAVE("wolfSSL_CTX_load_verify_buffer_ex", ret);
+        return ret;
     }
 
@@ -13659,7 +14663,11 @@
                                  const unsigned char* in, long sz, int format)
     {
+        int ret = WOLFSSL_FAILURE;
+
         WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_buffer");
-        return ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 0,
+        ret = ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 0,
                              GET_VERIFY_SETTING_CTX(ctx));
+        WOLFSSL_LEAVE("wolfSSL_CTX_use_certificate_buffer", ret);
+        return ret;
     }
 
@@ -13668,7 +14676,11 @@
                                  const unsigned char* in, long sz, int format)
     {
+        int ret = WOLFSSL_FAILURE;
+
         WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_buffer");
-        return ProcessBuffer(ctx, in, sz, format, PRIVATEKEY_TYPE, NULL, NULL,
+        ret = ProcessBuffer(ctx, in, sz, format, PRIVATEKEY_TYPE, NULL, NULL,
                              0, GET_VERIFY_SETTING_CTX(ctx));
+        WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_buffer", ret);
+        return ret;
     }
 
@@ -13676,4 +14688,15 @@
     int wolfSSL_CTX_use_PrivateKey_id(WOLFSSL_CTX* ctx, const unsigned char* id,
                                       long sz, int devId, long keySz)
+    {
+        int ret = wolfSSL_CTX_use_PrivateKey_Id(ctx, id, sz, devId);
+
+        if (ret == WOLFSSL_SUCCESS)
+            ctx->privateKeySz = (word32)keySz;
+
+        return ret;
+    }
+
+    int wolfSSL_CTX_use_PrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id,
+                                      long sz, int devId)
     {
         int ret = WOLFSSL_FAILURE;
@@ -13684,5 +14707,26 @@
             XMEMCPY(ctx->privateKey->buffer, id, sz);
             ctx->privateKeyId = 1;
-            ctx->privateKeySz = (word32)keySz;
+            if (devId != INVALID_DEVID)
+                ctx->privateKeyDevId = devId;
+            else
+                ctx->privateKeyDevId = ctx->devId;
+
+            ret = WOLFSSL_SUCCESS;
+        }
+
+        return ret;
+    }
+
+    int wolfSSL_CTX_use_PrivateKey_Label(WOLFSSL_CTX* ctx, const char* label,
+                                         int devId)
+    {
+        int ret = WOLFSSL_FAILURE;
+        word32 sz = (word32)XSTRLEN(label) + 1;
+
+        FreeDer(&ctx->privateKey);
+        if (AllocDer(&ctx->privateKey, (word32)sz, PRIVATEKEY_TYPE,
+                                                              ctx->heap) == 0) {
+            XMEMCPY(ctx->privateKey->buffer, label, sz);
+            ctx->privateKeyLabel = 1;
             if (devId != INVALID_DEVID)
                 ctx->privateKeyDevId = devId;
@@ -13839,7 +14883,18 @@
     }
 
-#ifdef HAVE_PKCS11
+#ifdef WOLF_CRYPTO_CB
     int wolfSSL_use_PrivateKey_id(WOLFSSL* ssl, const unsigned char* id,
                                   long sz, int devId, long keySz)
+    {
+        int ret = wolfSSL_use_PrivateKey_Id(ssl, id, sz, devId);
+
+        if (ret == WOLFSSL_SUCCESS)
+            ssl->buffers.keySz = (word32)keySz;
+
+        return ret;
+    }
+
+    int wolfSSL_use_PrivateKey_Id(WOLFSSL* ssl, const unsigned char* id,
+                                  long sz, int devId)
     {
         int ret = WOLFSSL_FAILURE;
@@ -13852,5 +14907,27 @@
             ssl->buffers.weOwnKey = 1;
             ssl->buffers.keyId = 1;
-            ssl->buffers.keySz = (word32)keySz;
+            if (devId != INVALID_DEVID)
+                ssl->buffers.keyDevId = devId;
+            else
+                ssl->buffers.keyDevId = ssl->devId;
+
+            ret = WOLFSSL_SUCCESS;
+        }
+
+        return ret;
+    }
+
+    int wolfSSL_use_PrivateKey_Label(WOLFSSL* ssl, const char* label, int devId)
+    {
+        int ret = WOLFSSL_FAILURE;
+        word32 sz = (word32)XSTRLEN(label) + 1;
+
+        if (ssl->buffers.weOwnKey)
+            FreeDer(&ssl->buffers.key);
+        if (AllocDer(&ssl->buffers.key, (word32)sz, PRIVATEKEY_TYPE,
+                                                            ssl->heap) == 0) {
+            XMEMCPY(ssl->buffers.key->buffer, label, sz);
+            ssl->buffers.weOwnKey = 1;
+            ssl->buffers.keyLabel = 1;
             if (devId != INVALID_DEVID)
                 ssl->buffers.keyDevId = devId;
@@ -13897,9 +14974,6 @@
             FreeDer(&ssl->buffers.certificate);
             #ifdef KEEP_OUR_CERT
-                FreeX509(ssl->ourCert);
-                if (ssl->ourCert) {
-                    XFREE(ssl->ourCert, ssl->heap, DYNAMIC_TYPE_X509);
-                    ssl->ourCert = NULL;
-                }
+            wolfSSL_X509_free(ssl->ourCert);
+            ssl->ourCert = NULL;
             #endif
             ssl->buffers.weOwnCert = 0;
@@ -13999,5 +15073,5 @@
 #endif
 
-#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA)
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
     void wolfSSL_CTX_set_quiet_shutdown(WOLFSSL_CTX* ctx, int mode)
     {
@@ -14014,7 +15088,8 @@
             ssl->options.quietShutdown = 1;
     }
-#endif
+#endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA || WOLFSSL_WPAS_SMALL */
 
 #ifdef OPENSSL_EXTRA
+#ifndef NO_BIO
     void wolfSSL_set_bio(WOLFSSL* ssl, WOLFSSL_BIO* rd, WOLFSSL_BIO* wr)
     {
@@ -14070,5 +15145,6 @@
         }
     }
-#endif
+#endif /* !NO_BIO */
+#endif /* OPENSSL_EXTRA */
 
 #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) || defined(HAVE_WEBSERVER)
@@ -14167,4 +15243,5 @@
 
 #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+#ifndef NO_BIO
     #if !defined(NO_RSA) && !defined(NO_CERTS)
     WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file(const char* fname)
@@ -14184,5 +15261,5 @@
         WOLFSSL_ENTER("wolfSSL_load_client_CA_file");
 
-        bio = wolfSSL_BIO_new_file(fname, "r");
+        bio = wolfSSL_BIO_new_file(fname, "rb");
         if (bio == NULL)
             return NULL;
@@ -14201,9 +15278,11 @@
             /* Need a persistent copy of the subject name. */
             node->data.name = wolfSSL_X509_NAME_dup(subjectName);
-            /*
-             * Original cert will be freed so make sure not to try to access
-             * it in the future.
-             */
-            node->data.name->x509 = NULL;
+            if (node->data.name != NULL) {
+                /*
+                * Original cert will be freed so make sure not to try to access
+                * it in the future.
+                */
+                node->data.name->x509 = NULL;
+            }
 
             /* Put node on the front of the list. */
@@ -14237,5 +15316,6 @@
     }
     #endif
-#endif
+#endif /* !NO_BIO */
+#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */
 
 #ifdef OPENSSL_EXTRA
@@ -14285,5 +15365,5 @@
         node->next = ctx->ca_names;
         ctx->ca_names = node;
-        return SSL_SUCCESS;
+        return WOLFSSL_SUCCESS;
     }
     #endif
@@ -14323,5 +15403,4 @@
         int r = 0;
         SrpSide srp_side = SRP_CLIENT_SIDE;
-        WC_RNG rng;
         byte salt[SRP_SALT_SIZE];
 
@@ -14339,8 +15418,8 @@
         }
 
-        if (wc_SrpInit(ctx->srp, SRP_TYPE_SHA256, srp_side) < 0){
-            WOLFSSL_MSG("Init CTX failed");
+        if (wc_SrpInit(ctx->srp, SRP_TYPE_SHA256, srp_side) < 0) {
+            WOLFSSL_MSG("Init SRP CTX failed");
             XFREE(ctx->srp, ctx->heap, DYNAMIC_TYPE_SRP);
-            wolfSSL_CTX_free(ctx);
+            ctx->srp = NULL;
             return SSL_FAILURE;
         }
@@ -14354,5 +15433,6 @@
         /* if wolfSSL_CTX_set_srp_password has already been called, */
         /* execute wc_SrpSetPassword here */
-        if (ctx->srp_password != NULL){
+        if (ctx->srp_password != NULL) {
+            WC_RNG rng;
             if (wc_InitRng(&rng) < 0){
                 WOLFSSL_MSG("wc_InitRng failed");
@@ -14360,8 +15440,52 @@
             }
             XMEMSET(salt, 0, sizeof(salt)/sizeof(salt[0]));
-            if (wc_RNG_GenerateBlock(&rng, salt,
-                                     sizeof(salt)/sizeof(salt[0])) <  0){
+            r = wc_RNG_GenerateBlock(&rng, salt, sizeof(salt)/sizeof(salt[0]));
+            wc_FreeRng(&rng);
+            if (r <  0) {
+                WOLFSSL_MSG("wc_RNG_GenerateBlock failed");   
+                return SSL_FAILURE;
+            }
+
+            if (wc_SrpSetParams(ctx->srp, srp_N, sizeof(srp_N)/sizeof(srp_N[0]),
+                                srp_g, sizeof(srp_g)/sizeof(srp_g[0]),
+                                salt, sizeof(salt)/sizeof(salt[0])) < 0) {
+                WOLFSSL_MSG("wc_SrpSetParam failed");
+                return SSL_FAILURE;
+            }
+            r = wc_SrpSetPassword(ctx->srp,
+                     (const byte*)ctx->srp_password,
+                     (word32)XSTRLEN((char *)ctx->srp_password));
+            if (r < 0) {
+                WOLFSSL_MSG("fail to set srp password.");
+                return SSL_FAILURE;
+            }
+            
+            XFREE(ctx->srp_password, ctx->heap, DYNAMIC_TYPE_SRP);
+            ctx->srp_password = NULL;
+        }
+
+        return WOLFSSL_SUCCESS;
+    }
+
+    int wolfSSL_CTX_set_srp_password(WOLFSSL_CTX* ctx, char* password)
+    {
+        int r;
+        byte salt[SRP_SALT_SIZE];
+
+        WOLFSSL_ENTER("wolfSSL_CTX_set_srp_password");
+        if (ctx == NULL || ctx->srp == NULL || password == NULL)
+            return SSL_FAILURE;
+
+        if (ctx->srp->user != NULL) {
+            WC_RNG rng;
+            if (wc_InitRng(&rng) < 0) {
+                WOLFSSL_MSG("wc_InitRng failed");
+                return SSL_FAILURE;
+            }
+            XMEMSET(salt, 0, sizeof(salt)/sizeof(salt[0]));
+            r = wc_RNG_GenerateBlock(&rng, salt, sizeof(salt)/sizeof(salt[0]));
+            wc_FreeRng(&rng);
+            if (r <  0) {
                 WOLFSSL_MSG("wc_RNG_GenerateBlock failed");
-                wc_FreeRng(&rng);
                 return SSL_FAILURE;
             }
@@ -14373,48 +15497,4 @@
                 return SSL_FAILURE;
             }
-            r = wc_SrpSetPassword(ctx->srp,
-                     (const byte*)ctx->srp_password,
-                     (word32)XSTRLEN((char *)ctx->srp_password));
-            if (r < 0) {
-                WOLFSSL_MSG("fail to set srp password.");
-                return SSL_FAILURE;
-            }
-            wc_FreeRng(&rng);
-            XFREE(ctx->srp_password, ctx->heap, DYNAMIC_TYPE_SRP);
-            ctx->srp_password = NULL;
-        }
-
-        return SSL_SUCCESS;
-    }
-
-    int wolfSSL_CTX_set_srp_password(WOLFSSL_CTX* ctx, char* password)
-    {
-        int r;
-        WC_RNG rng;
-        byte salt[SRP_SALT_SIZE];
-
-        WOLFSSL_ENTER("wolfSSL_CTX_set_srp_password");
-        if (ctx == NULL || ctx->srp == NULL || password == NULL)
-            return SSL_FAILURE;
-
-        if (ctx->srp->user != NULL){
-            if (wc_InitRng(&rng) < 0){
-                WOLFSSL_MSG("wc_InitRng failed");
-                return SSL_FAILURE;
-            }
-            XMEMSET(salt, 0, sizeof(salt)/sizeof(salt[0]));
-            if (wc_RNG_GenerateBlock(&rng, salt,
-                                     sizeof(salt)/sizeof(salt[0])) <  0){
-                WOLFSSL_MSG("wc_RNG_GenerateBlock failed");
-                wc_FreeRng(&rng);
-                return SSL_FAILURE;
-            }
-            if (wc_SrpSetParams(ctx->srp, srp_N, sizeof(srp_N)/sizeof(srp_N[0]),
-                                srp_g, sizeof(srp_g)/sizeof(srp_g[0]),
-                                salt, sizeof(salt)/sizeof(salt[0])) < 0){
-                WOLFSSL_MSG("wc_SrpSetParam failed");
-                wc_FreeRng(&rng);
-                return SSL_FAILURE;
-            }
             r = wc_SrpSetPassword(ctx->srp, (const byte*)password,
                                   (word32)XSTRLEN(password));
@@ -14443,5 +15523,33 @@
             XMEMCPY(ctx->srp_password, password, XSTRLEN(password) + 1);
         }
-        return SSL_SUCCESS;
+        return WOLFSSL_SUCCESS;
+    }
+
+    /**
+     * The modulus passed to wc_SrpSetParams in ssl.c is constant so check
+     * that the requested strength is less than or equal to the size of the
+     * static modulus size.
+     * @param ctx Not used
+     * @param strength Minimum number of bits for the modulus
+     * @return 1 if strength is less than or equal to static modulus
+     *         0 if strength is greater than static modulus
+     */
+    int  wolfSSL_CTX_set_srp_strength(WOLFSSL_CTX *ctx, int strength)
+    {
+        (void)ctx;
+        WOLFSSL_ENTER("wolfSSL_CTX_set_srp_strength");
+        if (strength > (int)(sizeof(srp_N)*8)) {
+            WOLFSSL_MSG("Bad Parameter");
+            return WOLFSSL_FAILURE;
+        }
+        return WOLFSSL_SUCCESS;
+    }
+
+    char* wolfSSL_get_srp_username(WOLFSSL *ssl)
+    {
+        if (ssl && ssl->ctx && ssl->ctx->srp) {
+            return (char*) ssl->ctx->srp->user;
+        }
+        return NULL;
     }
     #endif /* WOLFCRYPT_HAVE_SRP && !NO_SHA256 && !WC_NO_RNG */
@@ -14457,4 +15565,7 @@
     }
 
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 
     /* store keys returns WOLFSSL_SUCCESS or -1 on error */
@@ -14477,7 +15588,4 @@
     }
 
-#endif /* OPENSSL_EXTRA */
-
-#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA)
     void wolfSSL_set_accept_state(WOLFSSL* ssl)
     {
@@ -14515,5 +15623,5 @@
     }
 
-#endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA */
+#endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA || WOLFSSL_WPAS_SMALL */
 
     /* return true if connection established */
@@ -14564,6 +15672,4 @@
 #endif
 
-#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
-
     static long wolf_set_options(long old_op, long op);
     long wolfSSL_CTX_set_options(WOLFSSL_CTX* ctx, long opt)
@@ -14578,6 +15684,4 @@
         return ctx->mask;
     }
-
-#endif
 
 #ifdef OPENSSL_EXTRA
@@ -14612,7 +15716,7 @@
         return WOLFSSL_SUCCESS;
     }
-
-#ifndef NO_CERTS
-
+#endif /* OPENSSL_EXTRA */
+
+#if !defined(NO_CERTS) && (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL))
     WOLFSSL_X509_STORE* wolfSSL_CTX_get_cert_store(WOLFSSL_CTX* ctx)
     {
@@ -14626,8 +15730,12 @@
     void wolfSSL_CTX_set_cert_store(WOLFSSL_CTX* ctx, WOLFSSL_X509_STORE* str)
     {
-        if (ctx == NULL || str == NULL) {
+        if (ctx == NULL || str == NULL || ctx->cm == str->cm) {
             return;
         }
 
+        if (wolfSSL_CertManager_up_ref(str->cm) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("wolfSSL_CertManager_up_ref error");
+            return;
+        }
         /* free cert manager if have one */
         if (ctx->cm != NULL) {
@@ -14635,10 +15743,7 @@
         }
         ctx->cm               = str->cm;
+        ctx->x509_store.cm    = str->cm;
 
         /* free existing store if it exists */
-        if (ctx->x509_store_pt != NULL) {
-            /* cert manager was free'd a little earlier in this function */
-            ctx->x509_store_pt->cm = NULL;
-        }
         wolfSSL_X509_STORE_free(ctx->x509_store_pt);
         ctx->x509_store.cache = str->cache;
@@ -14674,5 +15779,8 @@
         return WOLFSSL_FATAL_ERROR;
     }
-
+#endif /* !NO_CERTS && (OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL) */
+
+#ifdef OPENSSL_EXTRA
+#ifndef NO_CERTS
     void wolfSSL_X509_STORE_CTX_set_verify_cb(WOLFSSL_X509_STORE_CTX *ctx,
                                   WOLFSSL_X509_STORE_CTX_verify_cb verify_cb)
@@ -14693,9 +15801,8 @@
         }
     }
-#endif
-
-
+#endif /* WOLFSSL_QT || OPENSSL_ALL */
 #endif /* !NO_CERTS */
 
+#ifndef NO_BIO
     WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_md(void)
     {
@@ -14736,7 +15843,16 @@
         /* wolfSSL has internal buffer, compatibility only */
         WOLFSSL_ENTER("BIO_set_write_buffer_size");
+        WOLFSSL_MSG("Buffer resize failed");
         WOLFSSL_STUB("BIO_set_write_buffer_size");
         (void)bio;
-        return size;
+        (void) size;
+
+        /* Even though this is only a STUB at the moment many user applications
+         * may attempt to use this. OpenSSL documentation specifies the return
+         * "return 1 if the buffer was successfully resized or 0 for failure."
+         * since wolfSSL does not resize the buffer will always return failure
+         * by default due to memory concerns until this stub is promoted to
+         * a non-stub function */
+        return WOLFSSL_FAILURE; /* 0, no resize happened */
     }
     #endif
@@ -14801,4 +15917,82 @@
     }
 
+    /**
+     * Create new socket BIO object. This is a pure TCP connection with
+     * no SSL or TLS protection.
+     * @param str IP address to connect to
+     * @return New BIO object or NULL on failure
+     */
+    WOLFSSL_BIO *wolfSSL_BIO_new_connect(const char *str)
+    {
+        WOLFSSL_BIO *bio;
+        WOLFSSL_ENTER("wolfSSL_BIO_new_connect");
+        bio = wolfSSL_BIO_new(wolfSSL_BIO_s_socket());
+        if (bio) {
+            bio->ip = str;
+            bio->type  = WOLFSSL_BIO_SOCKET;
+        }
+        return bio;
+    }
+
+    /**
+     * Set the port to connect to in the BIO object
+     * @param b BIO object
+     * @param port destination port
+     * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure
+     */
+    long wolfSSL_BIO_set_conn_port(WOLFSSL_BIO *b, char* port)
+    {
+        int p;
+        WOLFSSL_ENTER("wolfSSL_BIO_set_conn_port");
+
+        if (!b || !port) {
+            WOLFSSL_ENTER("Bad parameter");
+            return WOLFSSL_FAILURE;
+        }
+
+        p = XATOI(port);
+        if (!p || p < 0) {
+            WOLFSSL_ENTER("Port parsing error");
+            return WOLFSSL_FAILURE;
+        }
+
+        b->port = (word16)p;
+        return WOLFSSL_SUCCESS;
+    }
+
+#ifdef HAVE_HTTP_CLIENT
+    /**
+     * Attempt to connect to the destination address and port
+     * @param b BIO object
+     * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure
+     */
+    long wolfSSL_BIO_do_connect(WOLFSSL_BIO *b)
+    {
+        SOCKET_T sfd = SOCKET_INVALID;
+        WOLFSSL_ENTER("wolfSSL_BIO_do_connect");
+
+        if (!b) {
+            WOLFSSL_ENTER("Bad parameter");
+            return WOLFSSL_FAILURE;
+        }
+
+        while (b && b->type != WOLFSSL_BIO_SOCKET)
+            b = b->next;
+
+        if (!b) {
+            WOLFSSL_ENTER("No socket BIO in chain");
+            return WOLFSSL_FAILURE;
+        }
+
+        if (wolfIO_TcpConnect(&sfd, b->ip, b->port, 0) < 0 ) {
+            WOLFSSL_ENTER("wolfIO_TcpConnect error");
+            return WOLFSSL_FAILURE;
+        }
+
+        b->num = sfd;
+        b->shutdown = BIO_CLOSE;
+        return WOLFSSL_SUCCESS;
+    }
+#endif /* HAVE_HTTP_CLIENT */
 
     int wolfSSL_BIO_eof(WOLFSSL_BIO* b)
@@ -14868,4 +16062,5 @@
             bio->method = method;
             bio->shutdown = BIO_CLOSE; /* default to close things */
+            bio->num = -1; /* Default to invalid socket */
             bio->init = 1;
             if (method->type != WOLFSSL_BIO_FILE &&
@@ -14903,5 +16098,5 @@
         WOLFSSL_BIO* bio = NULL;
 
-        if (buf == NULL || len < 0) {
+        if (buf == NULL) {
             return bio;
         }
@@ -14912,4 +16107,7 @@
         }
 
+        if (len < 0) {
+            len = (int)XSTRLEN((const char*)buf);
+        }
         bio->num = bio->wrSz = len;
         bio->ptr = (byte*)XMALLOC(len, 0, DYNAMIC_TYPE_OPENSSL);
@@ -14965,5 +16163,5 @@
                 if (bio->type == WOLFSSL_BIO_SOCKET && bio->num)
                     CloseSocket(bio->num);
-            #endif
+             #endif
             }
 
@@ -14973,4 +16171,10 @@
                     XFCLOSE((XFILE)bio->ptr);
                 }
+            #if !defined(USE_WINDOWS_API) && !defined(NO_WOLFSSL_DIR)\
+                && !defined(WOLFSSL_NUCLEUS) && !defined(WOLFSSL_NUCLEUS_1_2)
+                else if (bio->num != -1) {
+                    XCLOSE(bio->num);
+                }
+            #endif
             }
         #endif
@@ -15031,4 +16235,5 @@
         return top;
     }
+#endif /* !NO_BIO */
 #endif /* OPENSSL_EXTRA */
 
@@ -15141,4 +16346,5 @@
 
 #if (defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE))
+#ifndef NO_BIO
     /* print out and clear all errors */
     void wolfSSL_ERR_print_errors(WOLFSSL_BIO* bio)
@@ -15167,11 +16373,12 @@
         }
         } while (ret >= 0);
-    }
+        wolfSSL_BIO_write(bio, "", 1);
+    }
+#endif /* !NO_BIO */
 #endif /* OPENSSL_EXTRA || DEBUG_WOLFSSL_VERBOSE */
 
 #endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */
 
-#ifdef OPENSSL_EXTRA
-
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 #if !defined(NO_WOLFSSL_SERVER)
 size_t wolfSSL_get_server_random(const WOLFSSL *ssl, unsigned char *out,
@@ -15204,6 +16411,9 @@
     return size;
 }
-
-
+#endif /* !NO_WOLFSSL_SERVER */
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#ifdef OPENSSL_EXTRA
+#if !defined(NO_WOLFSSL_SERVER)
 /* Used to get the peer ephemeral public key sent during the connection
  * NOTE: currently wolfSSL_KeepHandshakeResources(WOLFSSL* ssl) must be called
@@ -15261,4 +16471,17 @@
 #endif /* !NO_WOLFSSL_SERVER */
 
+static int sanityCheckProtoVersion(WOLFSSL_CTX* ctx)
+{
+    if ((ctx->mask & WOLFSSL_OP_NO_SSLv3) &&
+            (ctx->mask & WOLFSSL_OP_NO_TLSv1) &&
+            (ctx->mask & WOLFSSL_OP_NO_TLSv1_1) &&
+            (ctx->mask & WOLFSSL_OP_NO_TLSv1_2) &&
+            (ctx->mask & WOLFSSL_OP_NO_TLSv1_3)) {
+        WOLFSSL_MSG("All TLS versions disabled");
+        return WOLFSSL_FAILURE;
+    }
+    return WOLFSSL_SUCCESS;
+}
+
 int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version)
 {
@@ -15266,5 +16489,5 @@
 
     if (ctx == NULL) {
-        return BAD_FUNC_ARG;
+        return WOLFSSL_FAILURE;
     }
 
@@ -15308,8 +16531,42 @@
 #endif
         default:
-            return BAD_FUNC_ARG;
-    }
-
-    return WOLFSSL_SUCCESS;
+            WOLFSSL_MSG("Unrecognized protocol version or not compiled in");
+            return WOLFSSL_FAILURE;
+    }
+
+    switch (version) {
+#ifndef NO_TLS
+    case TLS1_3_VERSION:
+        wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_2);
+        FALL_THROUGH;
+    case TLS1_2_VERSION:
+        wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_1);
+        FALL_THROUGH;
+    case TLS1_1_VERSION:
+        wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1);
+        FALL_THROUGH;
+    case TLS1_VERSION:
+        wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_SSLv3);
+        break;
+#endif
+#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS)
+    case SSL3_VERSION:
+    case SSL2_VERSION:
+        /* Nothing to do here */
+#endif
+        break;
+#ifdef WOLFSSL_DTLS
+#ifndef NO_OLD_TLS
+    case DTLS1_VERSION:
+#endif
+    case DTLS1_2_VERSION:
+        break;
+#endif
+    default:
+        WOLFSSL_MSG("Unrecognized protocol version or not compiled in");
+        return WOLFSSL_FAILURE;
+    }
+
+    return sanityCheckProtoVersion(ctx);
 }
 
@@ -15318,11 +16575,48 @@
     WOLFSSL_ENTER("wolfSSL_CTX_set_max_proto_version");
 
-    /* supported only at compile-time only */
-    (void)ctx;
-    (void)ver;
-    return WOLFSSL_SUCCESS;
-}
-
-
+    if (!ctx || !ctx->method) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    switch (ver) {
+    case SSL2_VERSION:
+        WOLFSSL_MSG("wolfSSL does not support SSLv2");
+        return WOLFSSL_FAILURE;
+#if (defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS)) || !defined(NO_TLS)
+    case SSL3_VERSION:
+        wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1);
+        FALL_THROUGH;
+    case TLS1_VERSION:
+        wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_1);
+        FALL_THROUGH;
+    case TLS1_1_VERSION:
+        wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_2);
+        FALL_THROUGH;
+    case TLS1_2_VERSION:
+        wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_3);
+        FALL_THROUGH;
+    case TLS1_3_VERSION:
+        /* Nothing to do here */
+        break;
+#endif
+#ifdef WOLFSSL_DTLS
+#ifndef NO_OLD_TLS
+    case DTLS1_VERSION:
+#endif
+    case DTLS1_2_VERSION:
+        break;
+#endif
+    default:
+        WOLFSSL_MSG("Unrecognized protocol version or not compiled in");
+        return WOLFSSL_FAILURE;
+    }
+
+    return sanityCheckProtoVersion(ctx);
+}
+
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 #if !defined(NO_WOLFSSL_CLIENT)
 /* Return the amount of random bytes copied over or error case.
@@ -15363,6 +16657,7 @@
 }
 #endif /* !NO_WOLFSSL_CLIENT */
-
-
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#ifdef OPENSSL_EXTRA
     unsigned long wolfSSLeay(void)
     {
@@ -15775,5 +17070,5 @@
 
         WOLFSSL_ENTER("SHA3_256_Init");
-        ret = wc_InitSha3_256((wc_Sha3*)sha3_256, NULL, 0);
+        ret = wc_InitSha3_256((wc_Sha3*)sha3_256, NULL, INVALID_DEVID);
 
         /* return 1 on success, 0 otherwise */
@@ -16465,5 +17760,10 @@
 
         /* OpenSSL compat, no ret */
-        wc_Des_SetKey(&myDes, (const byte*)schedule, (const byte*)ivec, !enc);
+        if (wc_Des_SetKey(&myDes, (const byte*)schedule,
+                         (const byte*)ivec, !enc) != 0) {
+            WOLFSSL_MSG("wc_Des_SetKey return error.");
+            return;
+        }
+
         lb_sz = length%DES_BLOCK_SIZE;
         blk   = length/DES_BLOCK_SIZE;
@@ -16509,4 +17809,7 @@
     }
 
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
     int wolfSSL_clear(WOLFSSL* ssl)
     {
@@ -16525,5 +17828,5 @@
         ssl->options.handShakeState  = NULL_STATE;
         ssl->options.handShakeDone = 0;
-        /* ssl->options.processReply = doProcessInit; */
+        ssl->options.processReply = 0; /* doProcessInit */
 
         ssl->keys.encryptionOn = 0;
@@ -16590,18 +17893,5 @@
     }
 
-    long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION* ses, long t)
-    {
-        word32 tmptime;
-        if (!ses || t < 0)
-            return BAD_FUNC_ARG;
-
-        tmptime = t & 0xFFFFFFFF;
-
-        ses->timeout = tmptime;
-
-        return WOLFSSL_SUCCESS;
-    }
-
-#endif
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
 
 #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
@@ -16672,5 +17962,5 @@
      * sid_ctx_len length of sid_ctx buffer
      *
-     * Returns SSL_SUCCESS in success case and SSL_FAILURE when failing
+     * Returns WOLFSSL_SUCCESS in success case and SSL_FAILURE when failing
      */
     int wolfSSL_CTX_set_session_id_context(WOLFSSL_CTX* ctx,
@@ -16687,5 +17977,5 @@
         ctx->sessionCtxSz = (byte)sid_ctx_len;
 
-        return SSL_SUCCESS;
+        return WOLFSSL_SUCCESS;
     }
 
@@ -16699,5 +17989,5 @@
      * len  length of sid_ctx buffer
      *
-     * Returns SSL_SUCCESS in success case and SSL_FAILURE when failing
+     * Returns WOLFSSL_SUCCESS in success case and SSL_FAILURE when failing
      */
     int wolfSSL_set_session_id_context(WOLFSSL* ssl, const unsigned char* id,
@@ -16712,5 +18002,5 @@
         ssl->sessionCtxSz = (byte)len;
 
-        return SSL_SUCCESS;
+        return WOLFSSL_SUCCESS;
     }
 
@@ -17146,5 +18436,5 @@
         entry = wolfSSL_X509_NAME_get_entry(name, i);
         if (entry == NULL) {
-            WOLFSSL_MSG("X509_NAME_get_entry failed");
+            WOLFSSL_MSG("wolfSSL_X509_NAME_get_entry failed");
             return NULL;
         }
@@ -17152,5 +18442,5 @@
                                                                    sizeof(buf));
         if (nameSz < 0) {
-            WOLFSSL_MSG("X509_NAME_get_text_by_NID failed");
+            WOLFSSL_MSG("wolfSSL_X509_NAME_get_text_by_NID failed");
             return NULL;
         }
@@ -17226,4 +18516,10 @@
 {
     WOLFSSL_X509* newX509 = NULL;
+    WOLFSSL_ENTER("wolfSSL_d2i_X509");
+
+    if (in == NULL) {
+        WOLFSSL_MSG("NULL input for wolfSSL_d2i_X509");
+        return NULL;
+    }
 
     newX509 = wolfSSL_X509_d2i(x509, *in, len);
@@ -17234,12 +18530,19 @@
 }
 
-
-WOLFSSL_X509* wolfSSL_X509_d2i(WOLFSSL_X509** x509, const byte* in, int len)
+static WOLFSSL_X509* d2i_X509orX509REQ(WOLFSSL_X509** x509,
+                                        const byte* in, int len, int req)
 {
     WOLFSSL_X509 *newX509 = NULL;
+    int type = req ? CERTREQ_TYPE : CERT_TYPE;
 
     WOLFSSL_ENTER("wolfSSL_X509_d2i");
 
-    if (in != NULL && len != 0) {
+    if (in != NULL && len != 0
+    #ifndef WOLFSSL_CERT_REQ
+            && req == 0
+    #else
+            && (req == 0 || req == 1)
+    #endif
+            ) {
     #ifdef WOLFSSL_SMALL_STACK
         DecodedCert* cert;
@@ -17256,5 +18559,8 @@
 
         InitDecodedCert(cert, (byte*)in, len, NULL);
-        if (ParseCertRelative(cert, CERT_TYPE, 0, NULL) == 0) {
+    #ifdef WOLFSSL_CERT_REQ
+        cert->isCSR = req;
+    #endif
+        if (ParseCertRelative(cert, type, 0, NULL) == 0) {
             newX509 = wolfSSL_X509_new();
             if (newX509 != NULL) {
@@ -17276,265 +18582,307 @@
     return newX509;
 }
+
+int wolfSSL_X509_get_isCA(WOLFSSL_X509* x509)
+{
+    int isCA = 0;
+
+    WOLFSSL_ENTER("wolfSSL_X509_get_isCA");
+
+    if (x509 != NULL)
+        isCA = x509->isCa;
+
+    WOLFSSL_LEAVE("wolfSSL_X509_get_isCA", isCA);
+
+    return isCA;
+}
+
+WOLFSSL_X509* wolfSSL_X509_d2i(WOLFSSL_X509** x509, const byte* in, int len)
+{
+    return d2i_X509orX509REQ(x509, in, len, 0);
+}
+
+#ifdef WOLFSSL_CERT_REQ
+WOLFSSL_X509* wolfSSL_X509_REQ_d2i(WOLFSSL_X509** x509,
+        const unsigned char* in, int len)
+{
+    return d2i_X509orX509REQ(x509, in, len, 1);
+}
+#endif
 #endif /* KEEP_PEER_CERT || SESSION_CERTS || OPENSSL_EXTRA ||
           OPENSSL_EXTRA_X509_SMALL */
 
-
-
-#if defined(OPENSSL_ALL) || defined(KEEP_OUR_CERT) || defined(KEEP_PEER_CERT) || \
-    defined(SESSION_CERTS)
-    /* return the next, if any, altname from the peer cert */
-    WOLFSSL_ABI
-    char* wolfSSL_X509_get_next_altname(WOLFSSL_X509* cert)
-    {
-        char* ret = NULL;
-        WOLFSSL_ENTER("wolfSSL_X509_get_next_altname");
-
-        /* don't have any to work with */
-        if (cert == NULL || cert->altNames == NULL)
-            return NULL;
-
-        /* already went through them */
-        if (cert->altNamesNext == NULL)
-            return NULL;
-
-        ret = cert->altNamesNext->name;
-        cert->altNamesNext = cert->altNamesNext->next;
-
-        return ret;
-    }
-
-    int wolfSSL_X509_get_isCA(WOLFSSL_X509* x509)
-    {
-        int isCA = 0;
-
-        WOLFSSL_ENTER("wolfSSL_X509_get_isCA");
-
-        if (x509 != NULL)
-            isCA = x509->isCa;
-
-        WOLFSSL_LEAVE("wolfSSL_X509_get_isCA", isCA);
-
-        return isCA;
-    }
-
-    int wolfSSL_X509_get_signature(WOLFSSL_X509* x509,
-                                                 unsigned char* buf, int* bufSz)
-    {
-        WOLFSSL_ENTER("wolfSSL_X509_get_signature");
-        if (x509 == NULL || bufSz == NULL || (*bufSz < (int)x509->sig.length &&
-                    buf != NULL))
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+/* returns the number of entries in the WOLFSSL_X509_NAME */
+int wolfSSL_X509_NAME_entry_count(WOLFSSL_X509_NAME* name)
+{
+    int count = 0;
+
+    WOLFSSL_ENTER("wolfSSL_X509_NAME_entry_count");
+
+    if (name != NULL)
+        count = name->entrySz;
+
+    WOLFSSL_LEAVE("wolfSSL_X509_NAME_entry_count", count);
+    return count;
+}
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
+
+#if defined(OPENSSL_EXTRA) || \
+    defined(KEEP_OUR_CERT) || defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
+
+/* return the next, if any, altname from the peer cert */
+WOLFSSL_ABI
+char* wolfSSL_X509_get_next_altname(WOLFSSL_X509* cert)
+{
+    char* ret = NULL;
+    WOLFSSL_ENTER("wolfSSL_X509_get_next_altname");
+
+    /* don't have any to work with */
+    if (cert == NULL || cert->altNames == NULL)
+        return NULL;
+
+    /* already went through them */
+    if (cert->altNamesNext == NULL)
+        return NULL;
+
+    ret = cert->altNamesNext->name;
+    cert->altNamesNext = cert->altNamesNext->next;
+
+    return ret;
+}
+
+int wolfSSL_X509_get_signature(WOLFSSL_X509* x509,
+                                                unsigned char* buf, int* bufSz)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_get_signature");
+    if (x509 == NULL || bufSz == NULL || (*bufSz < (int)x509->sig.length &&
+                buf != NULL))
+        return WOLFSSL_FATAL_ERROR;
+
+    if (buf != NULL)
+        XMEMCPY(buf, x509->sig.buffer, x509->sig.length);
+    *bufSz = x509->sig.length;
+
+    return WOLFSSL_SUCCESS;
+}
+
+
+/* Getter function that copies over the DER public key buffer to "buf" and
+    * sets the size in bufSz. If "buf" is NULL then just bufSz is set to needed
+    * buffer size. "bufSz" passed in should initially be set by the user to be
+    * the size of "buf". This gets checked to make sure the buffer is large
+    * enough to hold the public key.
+    *
+    * Note: this is the X.509 form of key with "header" info.
+    * return WOLFSSL_SUCCESS on success
+    */
+int wolfSSL_X509_get_pubkey_buffer(WOLFSSL_X509* x509,
+                                            unsigned char* buf, int* bufSz)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* cert;
+#else
+    DecodedCert cert[1];
+#endif
+    word32 idx;
+    const byte*  der;
+    int length = 0;
+    int    ret, derSz = 0;
+    int badDate = 0;
+    const byte* pubKeyX509 = NULL;
+    int   pubKeyX509Sz = 0;
+
+    WOLFSSL_ENTER("wolfSSL_X509_get_pubkey_buffer");
+    if (x509 == NULL || bufSz == NULL) {
+        WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", BAD_FUNC_ARG);
+        return WOLFSSL_FATAL_ERROR;
+    }
+
+
+#ifdef WOLFSSL_SMALL_STACK
+    cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert),
+                                    x509->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (cert == NULL) {
+        WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", MEMORY_E);
+        return WOLFSSL_FATAL_ERROR;
+    }
+#endif
+
+    der = wolfSSL_X509_get_der(x509, &derSz);
+    InitDecodedCert(cert, der, derSz, NULL);
+    ret = wc_GetPubX509(cert, 0, &badDate);
+    if (ret >= 0) {
+        idx = cert->srcIdx;
+        pubKeyX509 = cert->source + cert->srcIdx;
+        ret = GetSequence(cert->source, &cert->srcIdx, &length,
+                cert->maxIdx);
+        pubKeyX509Sz = length + (cert->srcIdx - idx);
+    }
+
+    FreeDecodedCert(cert);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(cert, x509->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    if (ret < 0) {
+        WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", ret);
+        return WOLFSSL_FATAL_ERROR;
+    }
+
+    if (buf != NULL) {
+        if (pubKeyX509Sz > *bufSz) {
+            WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", BUFFER_E);
             return WOLFSSL_FATAL_ERROR;
-
-        if (buf != NULL)
-            XMEMCPY(buf, x509->sig.buffer, x509->sig.length);
-        *bufSz = x509->sig.length;
-
-        return WOLFSSL_SUCCESS;
-    }
-
-
-    /* Getter function that copies over the DER public key buffer to "buf" and
-     * sets the size in bufSz. If "buf" is NULL then just bufSz is set to needed
-     * buffer size. "bufSz" passed in should initially be set by the user to be
-     * the size of "buf". This gets checked to make sure the buffer is large
-     * enough to hold the public key.
-     *
-     * Note: this is the X.509 form of key with "header" info.
-     * return WOLFSSL_SUCCESS on success
-     */
-    int wolfSSL_X509_get_pubkey_buffer(WOLFSSL_X509* x509,
-                                                unsigned char* buf, int* bufSz)
-    {
-    #ifdef WOLFSSL_SMALL_STACK
-        DecodedCert* cert;
-    #else
-        DecodedCert cert[1];
-    #endif
-        word32 idx;
-        const byte*  der;
-        int length = 0;
-        int    ret, derSz = 0;
-        int badDate = 0;
-        const byte* pubKeyX509 = NULL;
-        int   pubKeyX509Sz = 0;
-
-        WOLFSSL_ENTER("wolfSSL_X509_get_pubkey_buffer");
-        if (x509 == NULL || bufSz == NULL) {
-            WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", BAD_FUNC_ARG);
-            return WOLFSSL_FATAL_ERROR;
-        }
-
-
-    #ifdef WOLFSSL_SMALL_STACK
-        cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert),
-                                       x509->heap, DYNAMIC_TYPE_TMP_BUFFER);
-        if (cert == NULL) {
-            WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", MEMORY_E);
-            return WOLFSSL_FATAL_ERROR;
-        }
-    #endif
-
-        der = wolfSSL_X509_get_der(x509, &derSz);
-        InitDecodedCert(cert, der, derSz, NULL);
-        ret = wc_GetPubX509(cert, 0, &badDate);
-        if (ret >= 0) {
-            idx = cert->srcIdx;
-            pubKeyX509 = cert->source + cert->srcIdx;
-            ret = GetSequence(cert->source, &cert->srcIdx, &length,
-                    cert->maxIdx);
-            pubKeyX509Sz = length + (cert->srcIdx - idx);
-        }
-
-        FreeDecodedCert(cert);
-    #ifdef WOLFSSL_SMALL_STACK
-        XFREE(cert, x509->heap, DYNAMIC_TYPE_TMP_BUFFER);
-    #endif
-
-        if (ret < 0) {
-            WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", ret);
-            return WOLFSSL_FATAL_ERROR;
-        }
-
-        if (buf != NULL) {
-            if (pubKeyX509Sz > *bufSz) {
-                WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", BUFFER_E);
-                return WOLFSSL_FATAL_ERROR;
-            }
-            XMEMCPY(buf, pubKeyX509, pubKeyX509Sz);
-        }
-        *bufSz = pubKeyX509Sz;
-
-        return WOLFSSL_SUCCESS;
-    }
-
-
-    /* Getter function for the public key OID value
-     * return public key OID stored in WOLFSSL_X509 structure */
-    int wolfSSL_X509_get_pubkey_type(WOLFSSL_X509* x509)
-    {
-        if (x509 == NULL)
-            return WOLFSSL_FAILURE;
-        return x509->pubKeyOID;
-    }
-
-    /* write X509 serial number in unsigned binary to buffer
-       buffer needs to be at least EXTERNAL_SERIAL_SIZE (32) for all cases
-       return WOLFSSL_SUCCESS on success */
-    int wolfSSL_X509_get_serial_number(WOLFSSL_X509* x509,
-                                       byte* in, int* inOutSz)
-    {
-        WOLFSSL_ENTER("wolfSSL_X509_get_serial_number");
-        if (x509 == NULL || in == NULL ||
-                                   inOutSz == NULL || *inOutSz < x509->serialSz)
-            return BAD_FUNC_ARG;
-
+        }
+        XMEMCPY(buf, pubKeyX509, pubKeyX509Sz);
+    }
+    *bufSz = pubKeyX509Sz;
+
+    return WOLFSSL_SUCCESS;
+}
+
+
+/* Getter function for the public key OID value
+    * return public key OID stored in WOLFSSL_X509 structure */
+int wolfSSL_X509_get_pubkey_type(WOLFSSL_X509* x509)
+{
+    if (x509 == NULL)
+        return WOLFSSL_FAILURE;
+    return x509->pubKeyOID;
+}
+
+#endif /* OPENSSL_EXTRA || KEEP_OUR_CERT || KEEP_PEER_CERT || SESSION_CERTS */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \
+    defined(KEEP_OUR_CERT) || defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
+
+/* write X509 serial number in unsigned binary to buffer
+    buffer needs to be at least EXTERNAL_SERIAL_SIZE (32) for all cases
+    return WOLFSSL_SUCCESS on success */
+int wolfSSL_X509_get_serial_number(WOLFSSL_X509* x509,
+                                    byte* in, int* inOutSz)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_get_serial_number");
+    if (x509 == NULL || inOutSz == NULL) {
+        WOLFSSL_MSG("Null argument passed in");
+        return BAD_FUNC_ARG;
+    }
+
+    if (in != NULL) {
+        if (*inOutSz < x509->serialSz) {
+            WOLFSSL_MSG("Serial buffer too small");
+            return BUFFER_E;
+        }
         XMEMCPY(in, x509->serial, x509->serialSz);
-        *inOutSz = x509->serialSz;
-
-        return WOLFSSL_SUCCESS;
-    }
-
-    /* not an openssl compatibility function - getting for derCert */
-    const byte* wolfSSL_X509_get_der(WOLFSSL_X509* x509, int* outSz)
-    {
-        WOLFSSL_ENTER("wolfSSL_X509_get_der");
-
-        if (x509 == NULL || x509->derCert == NULL || outSz == NULL)
-            return NULL;
-
-        *outSz = (int)x509->derCert->length;
-        return x509->derCert->buffer;
-    }
-
-    /* used by JSSE (not a standard compatibility function) */
-    /* this is not thread safe */
-    WOLFSSL_ABI
-    const byte* wolfSSL_X509_notBefore(WOLFSSL_X509* x509)
-    {
-        static byte notBeforeData[CTC_DATE_SIZE]; /* temp buffer for date */
-        WOLFSSL_ENTER("wolfSSL_X509_notBefore");
-
-        if (x509 == NULL)
-            return NULL;
-
-        XMEMSET(notBeforeData, 0, sizeof(notBeforeData));
-        notBeforeData[0] = (byte)x509->notBefore.type;
-        notBeforeData[1] = (byte)x509->notBefore.length;
-        XMEMCPY(&notBeforeData[2], x509->notBefore.data, x509->notBefore.length);
-
-        return notBeforeData;
-    }
-    /* used by JSSE (not a standard compatibility function) */
-    /* this is not thread safe */
-    WOLFSSL_ABI
-    const byte* wolfSSL_X509_notAfter(WOLFSSL_X509* x509)
-    {
-        static byte notAfterData[CTC_DATE_SIZE]; /* temp buffer for date */
-        WOLFSSL_ENTER("wolfSSL_X509_notAfter");
-
-        if (x509 == NULL)
-            return NULL;
-
-        XMEMSET(notAfterData, 0, sizeof(notAfterData));
-        notAfterData[0] = (byte)x509->notAfter.type;
-        notAfterData[1] = (byte)x509->notAfter.length;
-        XMEMCPY(&notAfterData[2], x509->notAfter.data, x509->notAfter.length);
-
-        return notAfterData;
-    }
-
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) && !defined(NO_WOLFSSL_STUB)
-    WOLFSSL_ASN1_TIME* wolfSSL_X509_gmtime_adj(WOLFSSL_ASN1_TIME *s, long adj)
-    {
-        (void) s;
-        (void) adj;
-        WOLFSSL_STUB("wolfSSL_X509_gmtime_adj");
+    }
+    *inOutSz = x509->serialSz;
+
+    return WOLFSSL_SUCCESS;
+}
+
+/* not an openssl compatibility function - getting for derCert */
+const byte* wolfSSL_X509_get_der(WOLFSSL_X509* x509, int* outSz)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_get_der");
+
+    if (x509 == NULL || x509->derCert == NULL || outSz == NULL)
         return NULL;
-    }
-    #endif
-
-    /* get the buffer to be signed (tbs) from the WOLFSSL_X509 certificate
-     *
-     * outSz : gets set to the size of the buffer
-     * returns a pointer to the internal buffer at the location of TBS on
-     *         on success and NULL on failure.
-     */
-    const unsigned char* wolfSSL_X509_get_tbs(WOLFSSL_X509* x509, int* outSz)
-    {
-        int sz = 0, len;
-        unsigned int idx = 0, tmpIdx;
-        const unsigned char* der = NULL;
-        const unsigned char* tbs = NULL;
-
-        if (x509 == NULL || outSz == NULL) {
-            return NULL;
-        }
-
-        der = wolfSSL_X509_get_der(x509, &sz);
-        if (der == NULL) {
-            return NULL;
-        }
-
-        if (GetSequence(der, &idx, &len, sz) < 0) {
-            return NULL;
-        }
-        tbs = der + idx;
-        tmpIdx = idx;
-        if (GetSequence(der, &idx, &len, sz) < 0) {
-            return NULL;
-        }
-        *outSz = len + (idx - tmpIdx);
-        return tbs;
-    }
-
-    int wolfSSL_X509_version(WOLFSSL_X509* x509)
-    {
-        WOLFSSL_ENTER("wolfSSL_X509_version");
-
-        if (x509 == NULL)
-            return 0;
-
-        return x509->version;
-    }
+
+    *outSz = (int)x509->derCert->length;
+    return x509->derCert->buffer;
+}
+
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL || KEEP_OUR_CERT || KEEP_PEER_CERT || SESSION_CERTS */
+
+#ifdef OPENSSL_EXTRA
+
+/* used by JSSE (not a standard compatibility function) */
+WOLFSSL_ABI
+const byte* wolfSSL_X509_notBefore(WOLFSSL_X509* x509)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_notBefore");
+
+    if (x509 == NULL)
+        return NULL;
+
+    XMEMSET(x509->notBeforeData, 0, sizeof(x509->notBeforeData));
+    x509->notBeforeData[0] = (byte)x509->notBefore.type;
+    x509->notBeforeData[1] = (byte)x509->notBefore.length;
+    XMEMCPY(&x509->notBeforeData[2], x509->notBefore.data, x509->notBefore.length);
+
+    return x509->notBeforeData;
+}
+
+/* used by JSSE (not a standard compatibility function) */
+WOLFSSL_ABI
+const byte* wolfSSL_X509_notAfter(WOLFSSL_X509* x509)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_notAfter");
+
+    if (x509 == NULL)
+        return NULL;
+
+    XMEMSET(x509->notAfterData, 0, sizeof(x509->notAfterData));
+    x509->notAfterData[0] = (byte)x509->notAfter.type;
+    x509->notAfterData[1] = (byte)x509->notAfter.length;
+    XMEMCPY(&x509->notAfterData[2], x509->notAfter.data, x509->notAfter.length);
+
+    return x509->notAfterData;
+}
+
+
+#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) && !defined(NO_WOLFSSL_STUB)
+WOLFSSL_ASN1_TIME* wolfSSL_X509_gmtime_adj(WOLFSSL_ASN1_TIME *s, long adj)
+{
+    (void) s;
+    (void) adj;
+    WOLFSSL_STUB("wolfSSL_X509_gmtime_adj");
+    return NULL;
+}
+#endif
+
+/* get the buffer to be signed (tbs) from the WOLFSSL_X509 certificate
+    *
+    * outSz : gets set to the size of the buffer
+    * returns a pointer to the internal buffer at the location of TBS on
+    *         on success and NULL on failure.
+    */
+const unsigned char* wolfSSL_X509_get_tbs(WOLFSSL_X509* x509, int* outSz)
+{
+    int sz = 0, len;
+    unsigned int idx = 0, tmpIdx;
+    const unsigned char* der = NULL;
+    const unsigned char* tbs = NULL;
+
+    if (x509 == NULL || outSz == NULL) {
+        return NULL;
+    }
+
+    der = wolfSSL_X509_get_der(x509, &sz);
+    if (der == NULL) {
+        return NULL;
+    }
+
+    if (GetSequence(der, &idx, &len, sz) < 0) {
+        return NULL;
+    }
+    tbs = der + idx;
+    tmpIdx = idx;
+    if (GetSequence(der, &idx, &len, sz) < 0) {
+        return NULL;
+    }
+    *outSz = len + (idx - tmpIdx);
+    return tbs;
+}
+
+int wolfSSL_X509_version(WOLFSSL_X509* x509)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_version");
+
+    if (x509 == NULL)
+        return 0;
+
+    return x509->version;
+}
 
 #ifdef WOLFSSL_SEP
@@ -17628,4 +18976,5 @@
 
 #endif /* WOLFSSL_SEP */
+#endif /* OPENSSL_EXTRA */
 
 /* require OPENSSL_EXTRA since wolfSSL_X509_free is wrapped by OPENSSL_EXTRA */
@@ -17657,5 +19006,4 @@
 int wolfSSL_sk_X509_push(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk, WOLFSSL_X509* x509)
 {
-    WOLFSSL_STACK* node;
     WOLFSSL_ENTER("wolfSSL_sk_X509_push");
 
@@ -17664,29 +19012,5 @@
     }
 
-    /* no previous values in stack */
-    if (sk->data.x509 == NULL) {
-        sk->data.x509 = x509;
-        sk->num += 1;
-        return WOLFSSL_SUCCESS;
-    }
-
-    /* stack already has value(s) create a new node and add more */
-    node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL,
-                                                             DYNAMIC_TYPE_X509);
-    if (node == NULL) {
-        WOLFSSL_MSG("Memory error");
-        return WOLFSSL_FAILURE;
-    }
-    XMEMSET(node, 0, sizeof(WOLFSSL_STACK));
-
-    /* push new x509 onto head of stack */
-    node->data.x509 = sk->data.x509;
-    node->next      = sk->next;
-    node->type      = sk->type;
-    sk->next        = node;
-    sk->data.x509   = x509;
-    sk->num        += 1;
-
-    return WOLFSSL_SUCCESS;
+    return wolfSSL_sk_push(sk, x509);
 }
 
@@ -17753,5 +19077,7 @@
 #endif
 
-
+#endif /* !NO_CERTS && OPENSSL_EXTRA */
+
+#if !defined(NO_CERTS) && (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL))
 /* Free's all nodes in X509 stack. This is different then wolfSSL_sk_X509_free
  * in that it allows for choosing the function to use when freeing an X509s.
@@ -17804,44 +19130,14 @@
 }
 
-#endif /* NO_CERTS && OPENSSL_EXTRA */
-
-#if defined(OPENSSL_ALL) || defined (WOLFSSL_QT)
+#endif /* !NO_CERTS && (OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL) */
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
 /* return 1 on success 0 on fail */
 int wolfSSL_sk_ACCESS_DESCRIPTION_push(WOLF_STACK_OF(ACCESS_DESCRIPTION)* sk,
                                               WOLFSSL_ACCESS_DESCRIPTION* access)
 {
-    WOLFSSL_STACK* node;
-
     WOLFSSL_ENTER("wolfSSL_sk_ACCESS_DESCRIPTION_push");
 
-    if (sk == NULL || access == NULL) {
-        return WOLFSSL_FAILURE;
-    }
-
-    /* no previous values in stack */
-    if (sk->data.access == NULL) {
-        sk->data.access = access;
-        sk->num += 1;
-        return WOLFSSL_SUCCESS;
-    }
-
-    /* stack already has value(s) create a new node and add more */
-    node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL,
-                                   DYNAMIC_TYPE_ASN1);
-    if (node == NULL) {
-        WOLFSSL_MSG("Memory error");
-        return WOLFSSL_FAILURE;
-    }
-    XMEMSET(node, 0, sizeof(WOLFSSL_STACK));
-
-    /* push new obj onto head of stack */
-    node->data.access  = sk->data.access;
-    node->next         = sk->next;
-    node->type         = sk->type;
-    sk->next           = node;
-    sk->data.access    = access;
-    sk->num            += 1;
-
-    return WOLFSSL_SUCCESS;
+    return wolfSSL_sk_push(sk, access);
 }
 
@@ -17913,7 +19209,7 @@
     /* access = NULL, don't try to access or double free it */
 }
-#endif
-
-#ifdef OPENSSL_EXTRA
+#endif /* OPENSSL_ALL || WOLFSSL_QT */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 
 /* create a generic wolfSSL stack node
@@ -17967,37 +19263,88 @@
 int wolfSSL_sk_push(WOLFSSL_STACK* sk, const void *data)
 {
-    int ret = WOLFSSL_FAILURE;
+    WOLFSSL_STACK* node;
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
+    WOLFSSL_CIPHER ciph;
+#endif
     WOLFSSL_ENTER("wolfSSL_sk_push");
 
+    if (!sk) {
+        return WOLFSSL_FAILURE;
+    }
+
+    /* Check if empty data */
     switch (sk->type) {
-    #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
-        case STACK_TYPE_X509:
-            ret = wolfSSL_sk_X509_push(sk, (WOLFSSL_X509*) data);
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
+        case STACK_TYPE_CIPHER:
+            /* check if entire struct is zero */
+            XMEMSET(&ciph, 0, sizeof(WOLFSSL_CIPHER));
+            if (XMEMCMP(&sk->data.cipher, &ciph,
+                    sizeof(WOLFSSL_CIPHER)) == 0) {
+                sk->data.cipher = *(WOLFSSL_CIPHER*)data;
+                sk->num = 1;
+                if (sk->hash_fn) {
+                    sk->hash = sk->hash_fn(&sk->data.cipher);
+                }
+                return WOLFSSL_SUCCESS;
+            }
             break;
-        #ifndef NO_WOLFSSL_STUB
+#endif
+        default:
+            /* All other types are pointers */
+            if (!sk->data.generic) {
+                sk->data.generic = (void*)data;
+                sk->num = 1;
+#ifdef OPENSSL_ALL
+                if (sk->hash_fn) {
+                    sk->hash = sk->hash_fn(sk->data.generic);
+                }
+#endif
+                return WOLFSSL_SUCCESS;
+            }
+            break;
+    }
+
+    /* stack already has value(s) create a new node and add more */
+    node = wolfSSL_sk_new_node(sk->heap);
+    if (!node) {
+        WOLFSSL_MSG("Memory error");
+        return WOLFSSL_FAILURE;
+    }
+
+    /* push new x509 onto head of stack */
+    node->next      = sk->next;
+    node->type      = sk->type;
+    sk->next        = node;
+    sk->num        += 1;
+
+#ifdef OPENSSL_ALL
+    node->comp = sk->comp;
+    node->hash_fn = sk->hash_fn;
+    node->hash = sk->hash;
+    sk->hash = 0;
+#endif
+    switch (sk->type) {
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
         case STACK_TYPE_CIPHER:
-            ret = wolfSSL_sk_CIPHER_push(sk, (WOLFSSL_CIPHER*) data);
+            node->data.cipher = sk->data.cipher;
+            sk->data.cipher = *(WOLFSSL_CIPHER*)data;
+            if (sk->hash_fn) {
+                sk->hash = sk->hash_fn(&sk->data.cipher);
+            }
             break;
-        #endif
-        case STACK_TYPE_GEN_NAME:
-            ret = wolfSSL_sk_ASN1_OBJECT_push(sk, (WOLFSSL_ASN1_OBJECT*) data);
+#endif
+        default:
+            /* All other types are pointers */
+            node->data.generic = sk->data.generic;
+            sk->data.generic = (void*)data;
+#ifdef OPENSSL_ALL
+            if (sk->hash_fn) {
+                sk->hash = sk->hash_fn(sk->data.generic);
+            }
+#endif
             break;
-        case STACK_TYPE_ACCESS_DESCRIPTION:
-            ret = wolfSSL_sk_ACCESS_DESCRIPTION_push(sk,
-                                            (WOLFSSL_ACCESS_DESCRIPTION*) data);
-            break;
-        case STACK_TYPE_NULL:
-            ret = wolfSSL_sk_GENERIC_push(sk, (void*) data);
-            break;
-        case STACK_TYPE_OBJ:
-            ret = wolfSSL_sk_ASN1_OBJECT_push(sk, (WOLFSSL_ASN1_OBJECT*) data);
-            break;
-    #endif
-        default:
-            ret = wolfSSL_sk_ASN1_OBJECT_push(sk, (WOLFSSL_ASN1_OBJECT*) data);
-            break;
-    }
-
-    return ret;
+    }
+
+    return WOLFSSL_SUCCESS;
 }
 
@@ -18024,7 +19371,69 @@
 }
 
+static WOLFSSL_GENERAL_NAME* wolfSSL_GENERAL_NAME_dup(WOLFSSL_GENERAL_NAME* gn)
+{
+    WOLFSSL_GENERAL_NAME* dupl = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_GENERAL_NAME_dup");
+
+    if (!gn) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    if (!(dupl = wolfSSL_GENERAL_NAME_new())) {
+        WOLFSSL_MSG("wolfSSL_GENERAL_NAME_new error");
+        return NULL;
+    }
+
+    switch (gn->type) {
+    /* WOLFSSL_ASN1_STRING types */
+    case GEN_DNS:
+        if (!(dupl->d.dNSName = wolfSSL_ASN1_STRING_dup(gn->d.dNSName))) {
+            WOLFSSL_MSG("wolfSSL_ASN1_STRING_dup error");
+            goto error;
+        }
+        break;
+    case GEN_IPADD:
+        if (!(dupl->d.iPAddress = wolfSSL_ASN1_STRING_dup(gn->d.iPAddress))) {
+            WOLFSSL_MSG("wolfSSL_ASN1_STRING_dup error");
+            goto error;
+        }
+        break;
+    case GEN_EMAIL:
+        if (!(dupl->d.rfc822Name = wolfSSL_ASN1_STRING_dup(gn->d.rfc822Name))) {
+            WOLFSSL_MSG("wolfSSL_ASN1_STRING_dup error");
+            goto error;
+        }
+        break;
+    case GEN_URI:
+        if (!(dupl->d.uniformResourceIdentifier =
+                wolfSSL_ASN1_STRING_dup(gn->d.uniformResourceIdentifier))) {
+            WOLFSSL_MSG("wolfSSL_ASN1_STRING_dup error");
+            goto error;
+        }
+        break;
+    case GEN_OTHERNAME:
+    case GEN_X400:
+    case GEN_DIRNAME:
+    case GEN_EDIPARTY:
+    case GEN_RID:
+    default:
+        WOLFSSL_MSG("Unrecognized or unsupported GENERAL_NAME type");
+        goto error;
+    }
+
+    return dupl;
+error:
+    if (dupl) {
+        wolfSSL_GENERAL_NAME_free(dupl);
+    }
+    return NULL;
+}
+
+
 /* return 1 on success 0 on fail */
-int wolfSSL_sk_GENERAL_NAME_push(WOLF_STACK_OF(WOLFSSL_GENERAL_NAME)* sk,
-                                                      WOLFSSL_GENERAL_NAME* gn)
+int wolfSSL_sk_GENERAL_NAME_push(WOLFSSL_GENERAL_NAMES* sk,
+                                 WOLFSSL_GENERAL_NAME* gn)
 {
     WOLFSSL_STACK* node;
@@ -18061,4 +19470,8 @@
     return WOLFSSL_SUCCESS;
 }
+
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#ifdef OPENSSL_EXTRA
 
 /* Returns the general name at index i from the stack
@@ -18101,4 +19514,8 @@
 }
 
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
+
 /* Frees all nodes in a GENERAL NAME stack
  *
@@ -18146,6 +19563,7 @@
     wolfSSL_sk_GENERAL_NAME_pop_free(sk, NULL);
 }
-
-
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#ifdef OPENSSL_EXTRA
 /* returns the number of nodes in stack on success and WOLFSSL_FATAL_ERROR
  * on fail */
@@ -18203,5 +19621,7 @@
     return NULL;
 }
-
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 /* Frees GENERAL_NAME objects.
 */
@@ -18233,9 +19653,9 @@
     }
 }
-
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#ifdef OPENSSL_EXTRA
 void wolfSSL_GENERAL_NAMES_free(WOLFSSL_GENERAL_NAMES *gens)
 {
-    WOLFSSL_STACK* node;
-
     WOLFSSL_ENTER("wolfSSL_GENERAL_NAMES_free");
 
@@ -18244,23 +19664,785 @@
     }
 
+    wolfSSL_sk_free(gens);
+}
+
+#if defined(OPENSSL_ALL)
+
+void *wolfSSL_lh_retrieve(WOLFSSL_STACK *sk, void *data)
+{
+    unsigned long hash;
+
+    WOLFSSL_ENTER("wolfSSL_lh_retrieve");
+
+    if (!sk || !data) {
+        WOLFSSL_MSG("Bad parameters");
+        return NULL;
+    }
+
+    if (!sk->hash_fn) {
+        WOLFSSL_MSG("No hash function defined");
+        return NULL;
+    }
+
+    hash = sk->hash_fn(data);
+
+    while (sk) {
+        /* Calc hash if not done so yet */
+        if (!sk->hash) {
+            switch (sk->type) {
+                case STACK_TYPE_CIPHER:
+                    sk->hash = sk->hash_fn(&sk->data.cipher);
+                    break;
+                default:
+                    sk->hash = sk->hash_fn(sk->data.generic);
+                    break;
+            }
+        }
+        if (sk->hash == hash) {
+            switch (sk->type) {
+                case STACK_TYPE_CIPHER:
+                    return &sk->data.cipher;
+                default:
+                    return sk->data.generic;
+            }
+        }
+        sk = sk->next;
+    }
+
+    return NULL;
+}
+
+/**
+ * This is the same hashing algo for WOLFSSL_CONF_VALUE as OpenSSL
+ */
+static unsigned long wolfSSL_CONF_VALUE_hash(const WOLFSSL_CONF_VALUE *val)
+{
+    if (val)
+        return (wolfSSL_LH_strhash(val->section) << 2) ^
+                wolfSSL_LH_strhash(val->name);
+    else
+        return 0;
+}
+
+static int wolfssl_conf_value_cmp(const WOLFSSL_CONF_VALUE *a,
+                                  const WOLFSSL_CONF_VALUE *b)
+{
+    int cmp_val;
+
+    if (!a || !b) {
+        return WOLFSSL_FATAL_ERROR;
+    }
+
+    if (a->section != b->section) {
+        if ((cmp_val = XSTRCMP(a->section, b->section)) != 0) {
+            return cmp_val;
+        }
+    }
+
+    if (a->name && b->name) {
+        return XSTRCMP(a->name, b->name);
+    }
+    else if (a->name == b->name) {
+        return 0;
+    }
+    else {
+        return a->name ? 1 : -1;
+    }
+}
+
+/* Use MD5 for hashing as OpenSSL uses a hash algorithm that is
+ * "not as good as MD5, but still good" so using MD5 should
+ * be good enough for this application. The produced hashes don't
+ * need to line up between OpenSSL and wolfSSL. The hashes are for
+ * internal indexing only */
+unsigned long wolfSSL_LH_strhash(const char *str)
+{
+    unsigned long ret = 0;
+    int strLen;
+    byte digest[WC_MD5_DIGEST_SIZE];
+    WOLFSSL_ENTER("wolfSSL_LH_strhash");
+
+    if (!str)
+        return 0;
+
+#ifndef NO_MD5
+    strLen = (int)XSTRLEN(str);
+    if (wc_Md5Hash((const byte*)str, strLen, digest) != 0) {
+        WOLFSSL_MSG("wc_Md5Hash error");
+        return 0;
+    }
+    /* Take first 4 bytes in small endian as unsigned long */
+    ret  =  (unsigned int)digest[0];
+    ret |= ((unsigned int)digest[1] << 8 );
+    ret |= ((unsigned int)digest[2] << 16);
+    ret |= ((unsigned int)digest[3] << 24);
+#else
+    WOLFSSL_MSG("No md5 available for wolfSSL_LH_strhash");
+#endif
+    return ret;
+}
+
+WOLFSSL_CONF_VALUE *wolfSSL_lh_WOLFSSL_CONF_VALUE_retrieve(
+        WOLF_LHASH_OF(WOLFSSL_CONF_VALUE) *sk, WOLFSSL_CONF_VALUE *data)
+{
+    WOLFSSL_ENTER("wolfSSL_lh_WOLFSSL_CONF_VALUE_retrieve");
+
+    if (!sk || !data) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    return (WOLFSSL_CONF_VALUE*)wolfSSL_lh_retrieve(sk, data);
+}
+
+int wolfSSL_CONF_modules_load(const WOLFSSL_CONF *cnf, const char *appname,
+                      unsigned long flags)
+{
+    WOLFSSL_ENTER("wolfSSL_CONF_modules_load");
+    WOLFSSL_MSG("All wolfSSL modules are already compiled in. "
+                "wolfSSL_CONF_modules_load doesn't load anything new.");
+    (void)cnf;
+    (void)appname;
+    (void)flags;
+    return WOLFSSL_SUCCESS;
+}
+
+WOLFSSL_CONF_VALUE *wolfSSL_CONF_VALUE_new(void)
+{
+    WOLFSSL_CONF_VALUE* ret;
+
+    WOLFSSL_ENTER("wolfSSL_CONF_new");
+
+    ret = (WOLFSSL_CONF_VALUE*)XMALLOC(sizeof(WOLFSSL_CONF_VALUE),
+            NULL, DYNAMIC_TYPE_OPENSSL);
+    if (ret)
+        XMEMSET(ret, 0, sizeof(WOLFSSL_CONF_VALUE));
+    return ret;
+}
+
+int wolfSSL_CONF_add_string(WOLFSSL_CONF *conf,
+        WOLFSSL_CONF_VALUE *section, WOLFSSL_CONF_VALUE *value)
+{
+    WOLF_STACK_OF(WOLFSSL_CONF_VALUE) *sk = NULL;
+
+    if (!conf || !section || !value) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    sk = (WOLF_STACK_OF(WOLFSSL_CONF_VALUE) *)section->value;
+    value->section = section->section;
+
+    if (wolfSSL_sk_CONF_VALUE_push(sk, value) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("wolfSSL_sk_CONF_VALUE_push error");
+        return WOLFSSL_FAILURE;
+    }
+    if (wolfSSL_sk_CONF_VALUE_push(conf->data, value) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("wolfSSL_sk_CONF_VALUE_push error");
+        return WOLFSSL_FAILURE;
+    }
+
+    return WOLFSSL_SUCCESS;
+}
+
+WOLFSSL_CONF_VALUE *wolfSSL_CONF_new_section(WOLFSSL_CONF *conf,
+        const char *section)
+{
+    WOLFSSL_CONF_VALUE* ret = NULL;
+    WOLF_STACK_OF(WOLFSSL_CONF_VALUE) *sk = NULL;
+    int slen;
+
+    WOLFSSL_ENTER("wolfSSL_CONF_new_section");
+
+    if (!conf || !section) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    slen = (int)XSTRLEN(section);
+
+    if (!(ret = wolfSSL_CONF_VALUE_new())) {
+        WOLFSSL_MSG("wolfSSL_CONF_new error");
+        goto error;
+    }
+
+    if (!(ret->section = (char*)XMALLOC(slen+1, NULL, DYNAMIC_TYPE_OPENSSL))) {
+        WOLFSSL_MSG("section malloc error");
+        goto error;
+    }
+    XMEMCPY(ret->section, section, slen+1);
+
+    if (!(sk = wolfSSL_sk_CONF_VALUE_new(NULL))) {
+        WOLFSSL_MSG("wolfSSL_sk_CONF_VALUE_new error");
+        goto error;
+    }
+
+    ret->value = (char*)sk;
+
+    if (wolfSSL_sk_CONF_VALUE_push(conf->data, ret) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("wolfSSL_sk_CONF_VALUE_push error");
+        goto error;
+    }
+
+    return ret;
+error:
+    if (ret) {
+        /* NULL so that wolfSSL_X509V3_conf_free doesn't attempt to free it */
+        ret->value = NULL;
+        wolfSSL_X509V3_conf_free(ret);
+    }
+    if (sk) {
+        wolfSSL_sk_CONF_VALUE_free(sk);
+    }
+    return NULL;
+}
+
+WOLFSSL_CONF_VALUE *wolfSSL_CONF_get_section(WOLFSSL_CONF *conf,
+        const char *section)
+{
+    WOLF_STACK_OF(WOLFSSL_CONF_VALUE) *sk = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_CONF_get_section");
+
+    if (!conf || !section) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    sk = conf->data;
+
+    while (sk) {
+        WOLFSSL_CONF_VALUE* val = sk->data.conf;
+        if (val) {
+            if (!val->name && XSTRCMP(section, val->section) == 0) {
+                return val;
+            }
+        }
+        sk = sk->next;
+    }
+
+    return NULL;
+}
+
+WOLFSSL_CONF *wolfSSL_NCONF_new(void *meth)
+{
+    WOLFSSL_CONF* ret;
+    WOLFSSL_ENTER("wolfSSL_NCONF_new");
+
+    if (meth) {
+        WOLFSSL_MSG("wolfSSL does not support CONF_METHOD");
+    }
+
+    ret = (WOLFSSL_CONF*)XMALLOC(sizeof(WOLFSSL_CONF), NULL, DYNAMIC_TYPE_OPENSSL);
+    if (ret) {
+        XMEMSET(ret, 0, sizeof(WOLFSSL_CONF));
+        ret->data = wolfSSL_sk_CONF_VALUE_new(NULL);
+        if (!ret->data) {
+            wolfSSL_NCONF_free(ret);
+            return NULL;
+        }
+    }
+    return ret;
+}
+
+char *wolfSSL_NCONF_get_string(const WOLFSSL_CONF *conf,
+        const char *group, const char *name)
+{
+    WOLFSSL_CONF_VALUE find_val;
+    WOLFSSL_CONF_VALUE *val;
+    WOLFSSL_ENTER("wolfSSL_NCONF_get_string");
+
+    if (!conf) {
+#ifdef HAVE_SECURE_GETENV
+        return secure_getenv(name);
+#else
+        WOLFSSL_MSG("Missing secure_getenv");
+        return NULL;
+#endif
+    }
+
+    find_val.name = (char *)name;
+    if (group) {
+        find_val.section = (char *)group;
+        val = wolfSSL_lh_WOLFSSL_CONF_VALUE_retrieve(conf->data, &find_val);
+        if (val)
+            return val->value;
+        if (XSTRCMP(group, "ENV") == 0) {
+#ifdef HAVE_SECURE_GETENV
+            return secure_getenv(name);
+#else
+        WOLFSSL_MSG("Missing secure_getenv");
+            return NULL;
+#endif
+        }
+    }
+
+    find_val.section = (char *)"default";
+    val = wolfSSL_lh_WOLFSSL_CONF_VALUE_retrieve(conf->data, &find_val);
+    if (val)
+        return val->value;
+    else
+        return NULL;
+}
+
+int wolfSSL_NCONF_get_number(const CONF *conf, const char *group,
+        const char *name, long *result)
+{
+    char *str;
+    WOLFSSL_ENTER("wolfSSL_NCONF_get_number");
+
+    if (!conf || !name || !result) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (!(str = wolfSSL_NCONF_get_string(conf, group, name))) {
+        WOLFSSL_MSG("wolfSSL_NCONF_get_string error");
+        return WOLFSSL_FAILURE;
+    }
+
+    *result = atol(str);
+    return WOLFSSL_SUCCESS;
+}
+
+/**
+ * The WOLFSSL_CONF->value member is treated as a
+ * WOLFSSL_STACK_OF(WOLFSSL_CONF_VALUE) which becomes
+ * the return value.
+ * @param conf
+ * @param section
+ * @return WOLFSSL_STACK_OF(WOLFSSL_CONF_VALUE)
+ */
+WOLFSSL_STACK *wolfSSL_NCONF_get_section(
+        const WOLFSSL_CONF *conf, const char *section)
+{
+    WOLFSSL_CONF_VALUE *val;
+    WOLFSSL_CONF_VALUE find_val;
+
+    WOLFSSL_ENTER("wolfSSL_NCONF_get_section");
+
+    if (!conf || !section) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    find_val.name = NULL;
+    find_val.section = (char*)section;
+    val = wolfSSL_lh_WOLFSSL_CONF_VALUE_retrieve(conf->data, &find_val);
+    if (val)
+        return (WOLFSSL_STACK*)val->value;
+    else
+        return NULL;
+}
+
+static WOLFSSL_CONF_VALUE *wolfSSL_CONF_VALUE_new_values(char* section,
+        char* name, char* value)
+{
+    WOLFSSL_CONF_VALUE* ret;
+    int len;
+
+    WOLFSSL_ENTER("wolfSSL_CONF_VALUE_new_values");
+
+    if (!(ret = wolfSSL_CONF_VALUE_new())) {
+        WOLFSSL_MSG("wolfSSL_CONF_VALUE_new error");
+        return NULL;
+    }
+
+    if (section) {
+        len = (int)XSTRLEN(section);
+        ret->section = (char*)XMALLOC(len+1, NULL, DYNAMIC_TYPE_OPENSSL);
+        if (!ret->section) {
+            WOLFSSL_MSG("malloc error");
+            wolfSSL_X509V3_conf_free(ret);
+            return NULL;
+        }
+        XMEMCPY(ret->section, section, len+1);
+    }
+
+    if (name) {
+        len = (int)XSTRLEN(name);
+        ret->name = (char*)XMALLOC(len+1, NULL, DYNAMIC_TYPE_OPENSSL);
+        if (!ret->name) {
+            WOLFSSL_MSG("malloc error");
+            wolfSSL_X509V3_conf_free(ret);
+            return NULL;
+        }
+        XMEMCPY(ret->name, name, len+1);
+    }
+
+    if (value) {
+        len = (int)XSTRLEN(value);
+        ret->value = (char*)XMALLOC(len+1, NULL, DYNAMIC_TYPE_OPENSSL);
+        if (!ret->value) {
+            WOLFSSL_MSG("malloc error");
+            wolfSSL_X509V3_conf_free(ret);
+            return NULL;
+        }
+        XMEMCPY(ret->value, value, len+1);
+    }
+
+    return ret;
+}
+
+static char* expandValue(WOLFSSL_CONF *conf, const char* section,
+        char *str)
+{
+    int strLen = (int)XSTRLEN(str);
+    char* ret = NULL;
+
+    /* Check to see if there is anything to expand */
+    if (XSTRNSTR(str, "$", strLen)) {
+        int idx = 0;
+        char* strIdx = str;
+        ret = (char*)XMALLOC(strLen + 1, NULL, DYNAMIC_TYPE_OPENSSL);
+        if (!ret) {
+            WOLFSSL_MSG("malloc error");
+            return str;
+        }
+
+        while (*strIdx) {
+            if (*strIdx == '$') {
+                /* Expand variable */
+                char* startIdx = ++strIdx;
+                char* endIdx;
+                const char* s = section;
+                const char* value;
+                char prevValue;
+
+                if (*startIdx == '{') {
+                    /* First read the section.
+                     * format: ${section_name::var_name} */
+                    s = ++startIdx;
+                    while (*strIdx && *strIdx != ':') strIdx++;
+                    if (!*strIdx || s == strIdx || strIdx[1] != ':') {
+                        WOLFSSL_MSG("invalid section name in "
+                                    "variable expansion");
+                        goto expand_cleanup;
+                    }
+                    *strIdx = '\0';
+                    strIdx += 2;
+                    startIdx = strIdx;
+                }
+                while (*strIdx && (XISALNUM(*strIdx) || *strIdx == '_'))
+                    strIdx++;
+                endIdx = strIdx;
+                if (startIdx == endIdx) {
+                    WOLFSSL_MSG("invalid variable name in config");
+                    goto expand_cleanup;
+                }
+                if (s != section) {
+                    /* We are expecting a trailing '}' */
+                    if (*strIdx != '}') {
+                        WOLFSSL_MSG("Missing '}' in variable");
+                        goto expand_cleanup;
+                    }
+                    strIdx++;
+                }
+                /* Save char value at the end of the name so that we can place
+                 * a null char there. */
+                prevValue = *endIdx;
+                *endIdx = '\0';
+                value = wolfSSL_NCONF_get_string(conf, s, startIdx);
+                *endIdx = prevValue;
+                /* Skip copy if no value or zero-length value */
+                if (value && *value) {
+                    int valueLen = (int)XSTRLEN(value);
+                    char* newRet;
+                    /* This will allocate slightly more memory than necessary
+                     * but better be safe */
+                    strLen += valueLen;
+                    newRet = (char*)XREALLOC(ret, strLen + 1, NULL,
+                            DYNAMIC_TYPE_OPENSSL);
+                    if (!newRet) {
+                        WOLFSSL_MSG("realloc error");
+                        goto expand_cleanup;
+                    }
+                    ret = newRet;
+                    XMEMCPY(ret + idx, value, valueLen);
+                    idx += valueLen;
+                }
+            }
+            else {
+                ret[idx++] = *strIdx++;
+            }
+        }
+        ret[idx] = '\0';
+    }
+
+    return ret ? ret : str;
+
+expand_cleanup:
+    if (ret)
+        XFREE(ret, NULL, DYNAMIC_TYPE_OPENSSL);
+    return NULL;
+}
+
+#define SKIP_WHITESPACE(idx, max_idx) \
+    while (idx < max_idx && (*idx == ' ' || *idx == '\t')) \
+        {idx++;}
+int wolfSSL_NCONF_load(WOLFSSL_CONF *conf, const char *file, long *eline)
+{
+    int ret = WOLFSSL_FAILURE;
+    WOLFSSL_BIO *in = NULL;
+    char* buf = NULL;
+    char* idx = NULL;
+    char* bufEnd = NULL;
+    CONF_VALUE* section = NULL;
+    long line = 0;
+    int bufLen = 0;
+
+    if (!conf || !file) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    /* Open file */
+    if (!(in = wolfSSL_BIO_new_file(file, "rb"))) {
+        WOLFSSL_MSG("wolfSSL_BIO_new_file error");
+        return WOLFSSL_FAILURE;
+    }
+
+    /* Read file */
+    bufLen = wolfSSL_BIO_get_len(in);
+    if (bufLen <= 0) {
+        WOLFSSL_MSG("wolfSSL_BIO_get_len error");
+        goto cleanup;
+    }
+    if (!(buf = (char*)XMALLOC(bufLen + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER))) {
+        WOLFSSL_MSG("malloc error");
+        goto cleanup;
+    }
+    if (wolfSSL_BIO_read(in, buf, bufLen) != bufLen) {
+        WOLFSSL_MSG("wolfSSL_BIO_read error");
+        goto cleanup;
+    }
+
+    if (!(section = wolfSSL_CONF_new_section(conf, "default"))) {
+        WOLFSSL_MSG("wolfSSL_CONF_new_section error");
+        goto cleanup;
+    }
+
+    /* LETS START READING SOME CONFIGS */
+    idx = buf;
+    bufEnd = buf + bufLen;
+    while (idx < bufEnd) {
+        char* lineEnd = XSTRNSTR(idx, "\n", (unsigned int)(bufEnd - idx));
+        char* maxIdx;
+        if (!lineEnd)
+            lineEnd = bufEnd; /* Last line in file */
+        maxIdx = XSTRNSTR(idx, "#", (unsigned int)(lineEnd - idx));
+        if (!maxIdx)
+            maxIdx = lineEnd;
+        line++;
+        SKIP_WHITESPACE(idx, maxIdx);
+        if (idx == maxIdx) {
+            /* Empty line */
+            idx = lineEnd + 1;
+            continue;
+        }
+
+        if (*idx == '[') {
+            /* New section. Spaces not allowed in section name. */
+            char* sectionName;
+            int sectionNameLen;
+
+            if (idx < maxIdx)
+                idx++;
+            else {
+                WOLFSSL_MSG("Invalid section definition.");
+                goto cleanup;
+            }
+
+            SKIP_WHITESPACE(idx, maxIdx);
+            sectionName = idx;
+            /* Find end of section name */
+            while (idx < maxIdx && *idx != ' ' && *idx != ']')
+                idx++;
+            sectionNameLen = (int)(idx - sectionName);
+            SKIP_WHITESPACE(idx, maxIdx);
+
+            if (*idx != ']') {
+                WOLFSSL_MSG("Section definition error. "
+                            "Closing brace not found.");
+                goto cleanup;
+            }
+
+            sectionName[sectionNameLen] = '\0';
+            if (!(section = wolfSSL_CONF_get_section(conf, sectionName)))
+                section = wolfSSL_CONF_new_section(conf, sectionName);
+        }
+        else {
+            char* name;
+            int   nameLen;
+            char* value;
+            char* exValue; /* expanded value */
+            int   valueLen;
+            WOLFSSL_CONF_VALUE* newVal = NULL;
+
+            SKIP_WHITESPACE(idx, maxIdx);
+            name = idx;
+            /* Find end of name */
+            while (idx < maxIdx && *idx != ' ' && *idx != '=')
+                idx++;
+            nameLen = (int)(idx - name);
+            SKIP_WHITESPACE(idx, maxIdx);
+            if (*idx != '=') {
+                WOLFSSL_MSG("Missing equals sign");
+                goto cleanup;
+            }
+            idx++;
+            SKIP_WHITESPACE(idx, maxIdx);
+            value = idx;
+            /* Find end of value */
+            idx = maxIdx-1;
+            while (idx >= value && (*idx == ' ' || *idx == '\t'))
+                idx--;
+            valueLen = (int)(idx - value + 1);
+
+            /* Sanity checks */
+            if (nameLen <= 0 || valueLen <= 0) {
+                WOLFSSL_MSG("Sanity checks failed");
+                goto cleanup;
+            }
+            name[nameLen] = '\0';
+            value[valueLen] = '\0';
+
+            if (!(exValue = expandValue(conf, section->section, value))) {
+                WOLFSSL_MSG("Variable expansion failed");
+                goto cleanup;
+            }
+
+            if (!(newVal = wolfSSL_CONF_VALUE_new_values(NULL,
+                    name, exValue))) {
+                WOLFSSL_MSG("wolfSSL_CONF_VALUE_new_values error");
+                if (exValue != value)
+                    XFREE(exValue, NULL, DYNAMIC_TYPE_OPENSSL);
+                goto cleanup;
+            }
+
+            if (exValue != value)
+                XFREE(exValue, NULL, DYNAMIC_TYPE_OPENSSL);
+
+            if (wolfSSL_CONF_add_string(conf, section, newVal) !=
+                    WOLFSSL_SUCCESS) {
+                WOLFSSL_MSG("wolfSSL_CONF_add_string error");
+                goto cleanup;
+            }
+        }
+        idx = lineEnd + 1;
+    }
+
+    ret = WOLFSSL_SUCCESS;
+cleanup:
+    if (in)
+        wolfSSL_BIO_free(in);
+    if (buf)
+        XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (eline)
+        *eline = line;
+    return ret;
+}
+
+
+void wolfSSL_NCONF_free(WOLFSSL_CONF *conf)
+{
+    WOLFSSL_ENTER("wolfSSL_NCONF_free");
+    if (conf) {
+        wolfSSL_sk_CONF_VALUE_free(conf->data);
+        XFREE(conf, NULL, DYNAMIC_TYPE_OPENSSL);
+    }
+}
+
+void wolfSSL_X509V3_conf_free(WOLFSSL_CONF_VALUE *val)
+{
+    WOLF_STACK_OF(WOLFSSL_CONF_VALUE) *sk = NULL;
+
+    if (val) {
+        if (val->name) {
+            /* Not a section. Don't free section as it is a shared pointer. */
+            XFREE(val->name, NULL, DYNAMIC_TYPE_OPENSSL);
+            if (val->value)
+                XFREE(val->value, NULL, DYNAMIC_TYPE_OPENSSL);
+        }
+        else {
+            /* Section so val->value is a stack */
+            if (val->section)
+                XFREE(val->section, NULL, DYNAMIC_TYPE_OPENSSL);
+            /* Only free the stack structures. The contained conf values
+             * will be freed in wolfSSL_NCONF_free */
+            sk = (WOLF_STACK_OF(WOLFSSL_CONF_VALUE)*)val->value;
+            while (sk) {
+                WOLF_STACK_OF(WOLFSSL_CONF_VALUE) *tmp = sk->next;
+                XFREE(sk, NULL, DYNAMIC_TYPE_OPENSSL);
+                sk = tmp;
+            }
+        }
+        XFREE(val, NULL, DYNAMIC_TYPE_OPENSSL);
+    }
+}
+
+WOLFSSL_STACK *wolfSSL_sk_CONF_VALUE_new(wolf_sk_compare_cb compFunc)
+{
+    WOLFSSL_STACK* ret;
+    WOLFSSL_ENTER("wolfSSL_sk_CONF_VALUE_new");
+    ret = wolfSSL_sk_new_node(NULL);
+    if (!ret)
+        return NULL;
+    ret->comp = compFunc ? compFunc : (wolf_sk_compare_cb)wolfssl_conf_value_cmp;
+    ret->hash_fn = (wolf_sk_hash_cb)wolfSSL_CONF_VALUE_hash;
+    ret->type = STACK_TYPE_CONF_VALUE;
+    return ret;
+}
+
+/* Free the structure for WOLFSSL_CONF_VALUE stack
+ *
+ * sk  stack to free nodes in
+ */
+void wolfSSL_sk_CONF_VALUE_free(WOLF_STACK_OF(WOLFSSL_CONF_VALUE)* sk)
+{
+    WOLFSSL_STACK* tmp;
+    WOLFSSL_ENTER("wolfSSL_sk_CONF_VALUE_free");
+
+    if (sk == NULL)
+        return;
+
     /* parse through stack freeing each node */
-    node = gens->next;
-    while (gens->num > 1) {
-        WOLFSSL_STACK* tmp = node;
-        node = node->next;
-
-        wolfSSL_ASN1_OBJECT_free(tmp->data.obj);
-        XFREE(tmp, NULL, DYNAMIC_TYPE_ASN1);
-        gens->num -= 1;
-    }
-
-    /* free head of stack */
-    if (gens->num == 1) {
-        wolfSSL_ASN1_OBJECT_free(gens->data.obj);
-    }
-    XFREE(gens, NULL, DYNAMIC_TYPE_ASN1);
-}
-
-#if defined(OPENSSL_ALL)
+    while (sk) {
+        tmp = sk->next;
+        wolfSSL_X509V3_conf_free(sk->data.conf);
+        XFREE(sk, NULL, DYNAMIC_TYPE_OPENSSL);
+        sk = tmp;
+    }
+}
+
+int wolfSSL_sk_CONF_VALUE_num(const WOLFSSL_STACK *sk)
+{
+    WOLFSSL_ENTER("wolfSSL_sk_CONF_VALUE_num");
+    if (sk)
+        return wolfSSL_sk_num(sk);
+    return 0;
+}
+
+WOLFSSL_CONF_VALUE *wolfSSL_sk_CONF_VALUE_value(const WOLFSSL_STACK *sk, int i)
+{
+    WOLFSSL_ENTER("wolfSSL_sk_CONF_VALUE_value");
+    if (sk)
+        return (WOLFSSL_CONF_VALUE*)wolfSSL_sk_value(sk, i);
+    return NULL;
+}
+
+/* return 1 on success 0 on fail */
+int wolfSSL_sk_CONF_VALUE_push(WOLF_STACK_OF(WOLFSSL_CONF_VALUE)* sk,
+        WOLFSSL_CONF_VALUE* val)
+{
+    WOLFSSL_ENTER("wolfSSL_sk_CONF_VALUE_push");
+
+    if (sk == NULL || val == NULL) {
+        return WOLFSSL_FAILURE;
+    }
+
+    return wolfSSL_sk_push(sk, val);
+}
+
 WOLF_STACK_OF(WOLFSSL_X509_EXTENSION)* wolfSSL_sk_X509_EXTENSION_new_null(void)
 {
@@ -18507,4 +20689,5 @@
 }
 
+#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2))
 /* Converts DER encoded DH parameters to a WOLFSSL_DH structure.
  *
@@ -18555,4 +20738,5 @@
     return newDH;
 }
+#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
 
 /* Converts internal WOLFSSL_DH structure to DER encoded DH.
@@ -18605,7 +20789,5 @@
 #endif /* OPENSSL_EXTRA */
 
-#ifndef NO_FILESYSTEM
-
-#ifndef NO_STDIO_FILESYSTEM
+#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)
 
 WOLFSSL_X509* wolfSSL_X509_d2i_fp(WOLFSSL_X509** x509, XFILE file)
@@ -18645,6 +20827,10 @@
 }
 
-#endif /* NO_STDIO_FILESYSTEM */
-
+#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \
+    defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
+    
+#ifndef NO_FILESYSTEM
 WOLFSSL_ABI
 WOLFSSL_X509* wolfSSL_X509_load_certificate_file(const char* fname, int format)
@@ -18711,11 +20897,10 @@
     return x509;
 }
-
-#endif /* NO_FILESYSTEM */
-
-
-WOLFSSL_X509* wolfSSL_X509_load_certificate_buffer(
-    const unsigned char* buf, int sz, int format)
-{
+#endif /* !NO_FILESYSTEM */
+
+static WOLFSSL_X509* loadX509orX509REQFromBuffer(
+    const unsigned char* buf, int sz, int format, int type)
+{
+
     int ret;
     WOLFSSL_X509* x509 = NULL;
@@ -18726,5 +20911,5 @@
     if (format == WOLFSSL_FILETYPE_PEM) {
     #ifdef WOLFSSL_PEM_TO_DER
-        if (PemToDer(buf, sz, CERT_TYPE, &der, NULL, NULL, NULL) != 0) {
+        if (PemToDer(buf, sz, type, &der, NULL, NULL, NULL) != 0) {
             FreeDer(&der);
         }
@@ -18734,5 +20919,5 @@
     }
     else {
-        ret = AllocDer(&der, (word32)sz, CERT_TYPE, NULL);
+        ret = AllocDer(&der, (word32)sz, type, NULL);
         if (ret == 0) {
             XMEMCPY(der->buffer, buf, sz);
@@ -18756,5 +20941,5 @@
         {
             InitDecodedCert(cert, der->buffer, der->length, NULL);
-            if (ParseCertRelative(cert, CERT_TYPE, 0, NULL) == 0) {
+            if (ParseCertRelative(cert, type, 0, NULL) == 0) {
                 x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL,
                                                              DYNAMIC_TYPE_X509);
@@ -18779,4 +20964,20 @@
     return x509;
 }
+
+WOLFSSL_X509* wolfSSL_X509_load_certificate_buffer(
+    const unsigned char* buf, int sz, int format)
+{
+    return loadX509orX509REQFromBuffer(buf, sz,
+            format, CERT_TYPE);
+}
+
+#ifdef WOLFSSL_CERT_REQ
+WOLFSSL_X509* wolfSSL_X509_REQ_load_certificate_buffer(
+    const unsigned char* buf, int sz, int format)
+{
+    return loadX509orX509REQFromBuffer(buf, sz,
+            format, CERTREQ_TYPE);
+}
+#endif
 
 #endif /* KEEP_PEER_CERT || SESSION_CERTS */
@@ -18826,10 +21027,30 @@
     return NULL;
 }
+
+WOLFSSL_X509* wolfSSL_CTX_get0_certificate(WOLFSSL_CTX* ctx)
+{
+    if (ctx) {
+        if (ctx->ourCert == NULL) {
+            if (ctx->certificate == NULL) {
+                WOLFSSL_MSG("Ctx Certificate buffer not set!");
+                return NULL;
+            }
+            #ifndef WOLFSSL_X509_STORE_CERTS
+            ctx->ourCert = wolfSSL_X509_d2i(NULL,
+                                           ctx->certificate->buffer,
+                                           ctx->certificate->length);
+            #endif
+            ctx->ownOurCert = 1;
+        }
+        return ctx->ourCert;
+    }
+    return NULL;
+}
 #endif /* OPENSSL_EXTRA && KEEP_OUR_CERT */
 #endif /* NO_CERTS */
 
 
-#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
-#ifndef NO_ASN
+#if !defined(NO_ASN) && (defined(OPENSSL_EXTRA) || \
+        defined(OPENSSL_EXTRA_X509_SMALL))
 void wolfSSL_ASN1_OBJECT_free(WOLFSSL_ASN1_OBJECT* obj)
 {
@@ -18853,9 +21074,5 @@
     }
 }
-#endif /* NO_ASN */
-#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
-
-#ifdef OPENSSL_EXTRA
-#ifndef NO_ASN
+
 WOLFSSL_ASN1_OBJECT* wolfSSL_ASN1_OBJECT_new(void)
 {
@@ -18877,4 +21094,42 @@
 }
 
+WOLFSSL_ASN1_OBJECT* wolfSSL_ASN1_OBJECT_dup(WOLFSSL_ASN1_OBJECT* obj)
+{
+    WOLFSSL_ASN1_OBJECT* dupl = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_ASN1_OBJECT_dup");
+
+    if (!obj) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+    dupl = wolfSSL_ASN1_OBJECT_new();
+    if (!dupl) {
+        WOLFSSL_MSG("wolfSSL_ASN1_OBJECT_new error");
+        return NULL;
+    }
+    /* Copy data */
+    XMEMCPY(dupl->sName, obj->sName, WOLFSSL_MAX_SNAME);
+    dupl->type = obj->type;
+    dupl->grp = obj->grp;
+    dupl->nid = obj->nid;
+    dupl->objSz = obj->objSz;
+    if (obj->obj) {
+        dupl->obj = (const unsigned char*)XMALLOC(
+                obj->objSz, NULL, DYNAMIC_TYPE_ASN1);
+        if (!dupl->obj) {
+            WOLFSSL_MSG("ASN1 obj malloc error");
+            wolfSSL_ASN1_OBJECT_free(dupl);
+            return NULL;
+        }
+        XMEMCPY((byte*)dupl->obj, obj->obj, obj->objSz);
+        dupl->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA;
+    }
+    return dupl;
+}
+#endif /* !NO_ASN && (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */
+
+#ifndef NO_ASN
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 /* Creates and returns a new WOLFSSL_CIPHER stack. */
 WOLFSSL_STACK* wolfSSL_sk_new_asn1_obj(void)
@@ -18895,6 +21150,4 @@
                                               WOLFSSL_ASN1_OBJECT* obj)
 {
-    WOLFSSL_STACK* node;
-
     WOLFSSL_ENTER("wolfSSL_sk_ASN1_OBJECT_push");
 
@@ -18903,29 +21156,5 @@
     }
 
-    /* no previous values in stack */
-    if (sk->data.obj == NULL) {
-        sk->data.obj = obj;
-        sk->num += 1;
-        return WOLFSSL_SUCCESS;
-    }
-
-    /* stack already has value(s) create a new node and add more */
-    node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL,
-                                                             DYNAMIC_TYPE_ASN1);
-    if (node == NULL) {
-        WOLFSSL_MSG("Memory error");
-        return WOLFSSL_FAILURE;
-    }
-    XMEMSET(node, 0, sizeof(WOLFSSL_STACK));
-
-    /* push new obj onto head of stack */
-    node->data.obj  = sk->data.obj;
-    node->next      = sk->next;
-    node->type      = sk->type;
-    sk->next        = node;
-    sk->data.obj    = obj;
-    sk->num        += 1;
-
-    return WOLFSSL_SUCCESS;
+    return wolfSSL_sk_push(sk, obj);
 }
 
@@ -19015,4 +21244,10 @@
 }
 
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+#endif /* !NO_ASN */
+
+#ifdef OPENSSL_EXTRA
+#ifndef NO_ASN
+
 int wolfSSL_ASN1_STRING_to_UTF8(unsigned char **out, WOLFSSL_ASN1_STRING *in)
 {
@@ -19045,4 +21280,42 @@
 }
 
+int wolfSSL_ASN1_UNIVERSALSTRING_to_string(WOLFSSL_ASN1_STRING *s)
+{
+    char *idx;
+    char *copy;
+    WOLFSSL_ENTER("wolfSSL_ASN1_UNIVERSALSTRING_to_string");
+
+    if (!s) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (s->type != V_ASN1_UNIVERSALSTRING) {
+        WOLFSSL_MSG("Input is not a universal string");
+        return WOLFSSL_FAILURE;
+    }
+
+    if ((s->length % 4) != 0) {
+        WOLFSSL_MSG("Input string must be divisible by 4");
+        return WOLFSSL_FAILURE;
+    }
+
+    for (idx = s->data; idx < s->data + s->length; idx += 4)
+        if ((idx[0] != '\0') || (idx[1] != '\0') || (idx[2] != '\0'))
+            break;
+
+    if (idx != s->data + s->length) {
+        WOLFSSL_MSG("Wrong string format");
+        return WOLFSSL_FAILURE;
+    }
+
+    for (copy = idx = s->data; idx < s->data + s->length; idx += 4)
+        *copy++ = idx[3];
+    *copy = '\0';
+    s->length /= 4;
+    s->type = V_ASN1_PRINTABLESTRING;
+    return WOLFSSL_SUCCESS;
+}
+
 /* Returns string representation of ASN1_STRING */
 char* wolfSSL_i2s_ASN1_STRING(WOLFSSL_v3_ext_method *method,
@@ -19089,5 +21362,7 @@
 }
 #endif /* NO_ASN */
-
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 void wolfSSL_set_connect_state(WOLFSSL* ssl)
 {
@@ -19116,5 +21391,5 @@
     }
 }
-#endif /* OPENSSL_EXTRA */
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
 
 
@@ -19144,4 +21419,55 @@
 
 #if defined(OPENSSL_EXTRA) || defined(HAVE_EXT_CACHE)
+
+/* return a new malloc'd session with default settings on success */
+static WOLFSSL_SESSION* NewSession(void)
+{
+    WOLFSSL_SESSION* ret = NULL;
+
+    ret = (WOLFSSL_SESSION*)XMALLOC(sizeof(WOLFSSL_SESSION), NULL,
+            DYNAMIC_TYPE_OPENSSL);
+    if (ret != NULL) {
+        XMEMSET(ret, 0, sizeof(WOLFSSL_SESSION));
+        ret->isAlloced = 1;
+    }
+    return ret;
+}
+
+WOLFSSL_SESSION* wolfSSL_SESSION_new(void)
+{
+    WOLFSSL_SESSION* ret = NewSession();
+
+#ifdef OPENSSL_EXTRA
+    if (ret != NULL) {
+        if (wc_InitMutex(&ret->refMutex) != 0) {
+            WOLFSSL_MSG("Error setting up session reference mutex");
+            XFREE(ret, NULL, DYNAMIC_TYPE_OPENSSL);
+            return NULL;
+        }
+        ret->refCount = 1;
+    }
+#endif
+
+    return ret;
+}
+
+/* add one to session reference count
+ * return WOFLSSL_SUCCESS on success and WOLFSSL_FAILURE on error */
+int wolfSSL_SESSION_up_ref(WOLFSSL_SESSION* session)
+{
+    if (session == NULL)
+        return WOLFSSL_FAILURE;
+
+#ifdef OPENSSL_EXTRA
+    if (wc_LockMutex(&session->refMutex) != 0) {
+        WOLFSSL_MSG("Failed to lock session mutex");
+    }
+    session->refCount++;
+    wc_UnLockMutex(&session->refMutex);
+#endif
+    return WOLFSSL_SUCCESS;
+}
+
+
 WOLFSSL_SESSION* wolfSSL_SESSION_dup(WOLFSSL_SESSION* session)
 {
@@ -19160,9 +21486,16 @@
 #endif
 
-    copy = (WOLFSSL_SESSION*)XMALLOC(sizeof(WOLFSSL_SESSION), NULL,
-            DYNAMIC_TYPE_OPENSSL);
+    copy = NewSession();
     if (copy != NULL) {
         XMEMCPY(copy, session, sizeof(WOLFSSL_SESSION));
         copy->isAlloced = 1;
+#ifdef OPENSSL_EXTRA
+        if (wc_InitMutex(&copy->refMutex) != 0) {
+            WOLFSSL_MSG("Error setting up session reference mutex");
+            XFREE(copy, NULL, DYNAMIC_TYPE_OPENSSL);
+            return NULL;
+        }
+        copy->refCount = 1;
+#endif
 #ifdef HAVE_SESSION_TICKET
         if (session->isDynamic) {
@@ -19187,5 +21520,5 @@
 }
 
-void wolfSSL_SESSION_free(WOLFSSL_SESSION* session)
+void FreeSession(WOLFSSL_SESSION* session, int isAlloced)
 {
     if (session == NULL)
@@ -19195,9 +21528,25 @@
     if (session->peer) {
         wolfSSL_X509_free(session->peer);
-    }
-#endif
-
-#ifdef HAVE_EXT_CACHE
-    if (session->isAlloced) {
+        session->peer = NULL;
+    }
+#endif
+
+#ifdef OPENSSL_EXTRA
+    /* refCount will always be 1 or more if created externally.
+     * Internal cache sessions don't initialize a refMutex. */
+    if (session->refCount > 0) {
+        if (wc_LockMutex(&session->refMutex) != 0) {
+            WOLFSSL_MSG("Failed to lock session mutex");
+        }
+        if (session->refCount > 1) {
+            session->refCount--;
+            wc_UnLockMutex(&session->refMutex);
+            return;
+        }
+        wc_UnLockMutex(&session->refMutex);
+    }
+#endif
+#if defined(HAVE_EXT_CACHE) || defined(OPENSSL_EXTRA)
+    if (isAlloced) {
     #ifdef HAVE_SESSION_TICKET
         if (session->isDynamic)
@@ -19209,11 +21558,24 @@
     /* No need to free since cache is static */
     (void)session;
-#endif
-}
-#endif
+    (void)isAlloced;
+#endif
+}
+
+void wolfSSL_SESSION_free(WOLFSSL_SESSION* session)
+{
+    if (session == NULL)
+        return;
+    
+#if defined(HAVE_EXT_CACHE) || defined(OPENSSL_EXTRA)
+    FreeSession(session, session->isAlloced);
+#else
+    FreeSession(session, 0);
+#endif
+}
+#endif /* OPENSSL_EXTRA || HAVE_EXT_CACHE */
 
 
 /* helper function that takes in a protocol version struct and returns string */
-static const char* wolfSSL_internal_get_version(ProtocolVersion* version)
+static const char* wolfSSL_internal_get_version(const ProtocolVersion* version)
 {
     WOLFSSL_ENTER("wolfSSL_get_version");
@@ -19225,36 +21587,14 @@
     if (version->major == SSLv3_MAJOR) {
         switch (version->minor) {
-        #ifndef NO_OLD_TLS
-            #ifdef WOLFSSL_ALLOW_SSLV3
             case SSLv3_MINOR :
                 return "SSLv3";
-            #endif
-            #ifdef WOLFSSL_ALLOW_TLSV10
             case TLSv1_MINOR :
                 return "TLSv1";
-            #endif
             case TLSv1_1_MINOR :
                 return "TLSv1.1";
-        #endif
             case TLSv1_2_MINOR :
                 return "TLSv1.2";
-        #ifdef WOLFSSL_TLS13
             case TLSv1_3_MINOR :
-            #ifdef WOLFSSL_TLS13_DRAFT
-                #ifdef WOLFSSL_TLS13_DRAFT_18
-                    return "TLSv1.3 (Draft 18)";
-                #elif defined(WOLFSSL_TLS13_DRAFT_22)
-                    return "TLSv1.3 (Draft 22)";
-                #elif defined(WOLFSSL_TLS13_DRAFT_23)
-                    return "TLSv1.3 (Draft 23)";
-                #elif defined(WOLFSSL_TLS13_DRAFT_26)
-                    return "TLSv1.3 (Draft 26)";
-                #else
-                    return "TLSv1.3 (Draft 28)";
-                #endif
-            #else
                 return "TLSv1.3";
-            #endif
-        #endif
             default:
                 return "unknown";
@@ -19277,5 +21617,5 @@
 
 
-const char* wolfSSL_get_version(WOLFSSL* ssl)
+const char* wolfSSL_get_version(const WOLFSSL* ssl)
 {
     if (ssl == NULL) {
@@ -19293,4 +21633,11 @@
     return LIBWOLFSSL_VERSION_STRING;
 }
+
+#ifdef OPENSSL_EXTRA
+const char* wolfSSL_OpenSSL_version(void)
+{
+    return "wolfSSL " LIBWOLFSSL_VERSION_STRING;
+}
+#endif
 
 
@@ -19394,4 +21741,14 @@
 }
 
+int wolfSSL_get_cipher_suite_from_name(const char* name, byte* cipherSuite0,
+                                       byte* cipherSuite, int *flags) {
+    if ((name == NULL) ||
+        (cipherSuite0 == NULL) ||
+        (cipherSuite == NULL) ||
+        (flags == NULL))
+        return BAD_FUNC_ARG;
+    return GetCipherSuiteFromName(name, cipherSuite0, cipherSuite, flags);
+}
+
 
 #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
@@ -19410,17 +21767,12 @@
 }
 
-#ifndef NO_WOLFSSL_STUB
-/* Keep as stubs for now */
 /* return 1 on success 0 on fail */
 int wolfSSL_sk_CIPHER_push(WOLF_STACK_OF(WOLFSSL_CIPHER)* sk,
                                                       WOLFSSL_CIPHER* cipher)
 {
-    WOLFSSL_STUB("wolfSSL_sk_CIPHER_push");
-    (void)sk;
-    (void)cipher;
-    return 0;
-}
-
-
+    return wolfSSL_sk_push(sk, cipher);
+}
+
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_CIPHER* wolfSSL_sk_CIPHER_pop(WOLF_STACK_OF(WOLFSSL_CIPHER)* sk)
 {
@@ -19488,4 +21840,265 @@
     /* free head of stack */
     XFREE(sk, NULL, DYNAMIC_TYPE_ASN1);
+}
+
+/**
+ * This function reads a tab delimetered CSV input and returns
+ * a populated WOLFSSL_TXT_DB structure.
+ * @param in Tab delimetered CSV input
+ * @param num Number of fields in each row.
+ * @return
+ */
+WOLFSSL_TXT_DB *wolfSSL_TXT_DB_read(WOLFSSL_BIO *in, int num)
+{
+    WOLFSSL_TXT_DB *ret = NULL;
+    char *buf = NULL;
+    char *bufEnd = NULL;
+    char *idx = NULL;
+    char* lineEnd = NULL;
+    int bufSz;
+    int failed = 1;
+    /* Space in front of str reserved for field pointers + \0 */
+    int fieldsSz = (num + 1) * sizeof(char *);
+    WOLFSSL_ENTER("wolfSSL_TXT_DB_read");
+
+    if (!in || num <= 0 || num > WOLFSSL_TXT_DB_MAX_FIELDS) {
+        WOLFSSL_MSG("Bad parameter or too many fields");
+        return NULL;
+    }
+
+    if (!(ret = (WOLFSSL_TXT_DB*)XMALLOC(sizeof(WOLFSSL_TXT_DB), NULL,
+            DYNAMIC_TYPE_OPENSSL))) {
+        WOLFSSL_MSG("malloc error");
+        goto error;
+    }
+    XMEMSET (ret, 0, sizeof(WOLFSSL_TXT_DB));
+    ret->num_fields = num;
+
+    if (!(ret->data = wolfSSL_sk_WOLFSSL_STRING_new())) {
+        WOLFSSL_MSG("wolfSSL_sk_WOLFSSL_STRING_new error");
+        goto error;
+    }
+
+    bufSz = wolfSSL_BIO_get_len(in);
+    if (bufSz <= 0 ||
+            !(buf = (char*)XMALLOC(bufSz+1, NULL,
+                    DYNAMIC_TYPE_TMP_BUFFER))) {
+        WOLFSSL_MSG("malloc error or no data in BIO");
+        goto error;
+    }
+
+    if (wolfSSL_BIO_read(in, buf, bufSz) != bufSz) {
+        WOLFSSL_MSG("malloc error or no data in BIO");
+        goto error;
+    }
+
+    buf[bufSz] = '\0';
+    idx = buf;
+    for (bufEnd = buf + bufSz; idx < bufEnd; idx = lineEnd + 1) {
+        char* strBuf = NULL;
+        char** fieldPtr = NULL;
+        int fieldPtrIdx = 0;
+        char* fieldCheckIdx = NULL;
+        lineEnd = XSTRNSTR(idx, "\n", (unsigned int)(bufEnd - idx));
+        if (!lineEnd)
+            lineEnd = bufEnd;
+        if (idx == lineEnd) /* empty line */
+            continue;
+        if (*idx == '#')
+            continue;
+        *lineEnd = '\0';
+        strBuf = (char*)XMALLOC(fieldsSz + lineEnd - idx + 1, NULL,
+                                DYNAMIC_TYPE_OPENSSL);
+        if (!strBuf) {
+            WOLFSSL_MSG("malloc error");
+            goto error;
+        }
+        XMEMCPY(strBuf + fieldsSz, idx, lineEnd - idx + 1); /* + 1 for NULL */
+        XMEMSET(strBuf, 0, fieldsSz);
+        /* Check for appropriate number of fields */
+        fieldPtr = (char**)strBuf;
+        fieldCheckIdx = strBuf + fieldsSz;
+        fieldPtr[fieldPtrIdx++] = fieldCheckIdx;
+        while (*fieldCheckIdx != '\0') {
+            /* Handle escaped tabs */
+            if (*fieldCheckIdx == '\t' && fieldCheckIdx[-1] != '\\') {
+                fieldPtr[fieldPtrIdx++] = fieldCheckIdx + 1;
+                *fieldCheckIdx = '\0';
+                if (fieldPtrIdx > num) {
+                    WOLFSSL_MSG("too many fields");
+                    XFREE(strBuf, NULL, DYNAMIC_TYPE_OPENSSL);
+                    goto error;
+                }
+            }
+            fieldCheckIdx++;
+        }
+        if (fieldPtrIdx != num) {
+            WOLFSSL_MSG("wrong number of fields");
+            XFREE(strBuf, NULL, DYNAMIC_TYPE_OPENSSL);
+            goto error;
+        }
+        if (wolfSSL_sk_push(ret->data, strBuf) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("wolfSSL_sk_push error");
+            XFREE(strBuf, NULL, DYNAMIC_TYPE_OPENSSL);
+            goto error;
+        }
+    }
+
+    failed = 0;
+error:
+    if (failed && ret) {
+        XFREE(ret, NULL, DYNAMIC_TYPE_OPENSSL);
+        ret = NULL;
+    }
+    if (buf) {
+        XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+    return ret;
+}
+
+long wolfSSL_TXT_DB_write(WOLFSSL_BIO *out, WOLFSSL_TXT_DB *db)
+{
+    const WOLF_STACK_OF(WOLFSSL_STRING)* data;
+    long totalLen = 0;
+    char buf[512]; /* Should be more than enough for a single row */
+    char* bufEnd = buf + sizeof(buf);
+    int sz;
+    int i;
+
+    WOLFSSL_ENTER("wolfSSL_TXT_DB_write");
+
+    if (!out || !db || !db->num_fields) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    data = db->data;
+    while (data) {
+        char** fields = (char**)data->data.string;
+        char* idx = buf;
+
+        if (!fields) {
+            WOLFSSL_MSG("Missing row");
+            return WOLFSSL_FAILURE;
+        }
+
+        for (i = 0; i < db->num_fields; i++) {
+            const char* fieldValue = fields[i];
+            if (!fieldValue) {
+                fieldValue = "";
+            }
+
+            /* Copy over field escaping tabs */
+            while (*fieldValue != '\0') {
+                if (idx+1 < bufEnd) {
+                    if (*fieldValue == '\t')
+                        *idx++ = '\\';
+                    *idx++ = *fieldValue++;
+                }
+                else {
+                    WOLFSSL_MSG("Data row is too big");
+                    return WOLFSSL_FAILURE;
+                }
+            }
+            if (idx < bufEnd) {
+                *idx++ = '\t';
+            }
+            else {
+                WOLFSSL_MSG("Data row is too big");
+                return WOLFSSL_FAILURE;
+            }
+        }
+        idx[-1] = '\n';
+        sz = (int)(idx - buf);
+
+        if (wolfSSL_BIO_write(out, buf, sz) != sz) {
+            WOLFSSL_MSG("wolfSSL_BIO_write error");
+            return WOLFSSL_FAILURE;
+        }
+        totalLen += sz;
+
+        data = data->next;
+    }
+
+    return totalLen;
+}
+
+int wolfSSL_TXT_DB_insert(WOLFSSL_TXT_DB *db, WOLFSSL_STRING *row)
+{
+    WOLFSSL_ENTER("wolfSSL_TXT_DB_insert");
+
+    if (!db || !row || !db->data) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (wolfSSL_sk_push(db->data, row) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("wolfSSL_sk_push error");
+        return WOLFSSL_FAILURE;
+    }
+
+    return WOLFSSL_SUCCESS;
+}
+
+void wolfSSL_TXT_DB_free(WOLFSSL_TXT_DB *db)
+{
+    WOLFSSL_ENTER("wolfSSL_TXT_DB_free");
+    if (db) {
+        if (db->data) {
+            wolfSSL_sk_free(db->data);
+        }
+        XFREE(db, NULL, DYNAMIC_TYPE_OPENSSL);
+    }
+}
+
+int wolfSSL_TXT_DB_create_index(WOLFSSL_TXT_DB *db, int field,
+        void* qual, wolf_sk_hash_cb hash, wolf_sk_compare_cb cmp)
+{
+    WOLFSSL_ENTER("wolfSSL_TXT_DB_create_index");
+    (void)qual;
+
+    if (!db || !hash || !cmp || field >= db->num_fields || field < 0) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    db->hash_fn[field] = hash;
+    db->comp[field] = cmp;
+
+    return WOLFSSL_SUCCESS;
+}
+
+WOLFSSL_STRING *wolfSSL_TXT_DB_get_by_index(WOLFSSL_TXT_DB *db, int idx,
+        WOLFSSL_STRING *value)
+{
+    WOLFSSL_ENTER("wolfSSL_TXT_DB_get_by_index");
+
+    if (!db || !db->data || idx < 0 || idx >= db->num_fields) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    if (!db->hash_fn[idx] || !db->comp[idx]) {
+        WOLFSSL_MSG("Missing hash or cmp functions");
+        return NULL;
+    }
+
+    /* If first data struct has correct hash and cmp function then
+     * assume others do too */
+    if (db->data->hash_fn != db->hash_fn[idx] ||
+            db->data->comp != db->comp[idx]) {
+        /* Set the hash and comp functions */
+        WOLF_STACK_OF(WOLFSSL_STRING)* data = db->data;
+        while (data) {
+            if (data->comp != db->comp[idx] ||
+                    data->hash_fn != db->hash_fn[idx]) {
+                data->comp = db->comp[idx];
+                data->hash_fn = db->hash_fn[idx];
+                data->hash = 0;
+            }
+            data= data->next;
+        }
+    }
+    return (WOLFSSL_STRING*) wolfSSL_lh_retrieve(db->data, value);
 }
 #endif
@@ -19585,12 +22198,13 @@
 {
     WOLFSSL_ENTER("wolfSSL_X509_get_subject_name");
-    if (cert && cert->subject.sz != 0)
+    if (cert)
         return &cert->subject;
     return NULL;
 }
 
-#if defined(OPENSSL_EXTRA) && !defined(NO_SHA)
+#if defined(OPENSSL_EXTRA) && (!defined(NO_SHA) || !defined(NO_SHA256))
 /******************************************************************************
 * wolfSSL_X509_subject_name_hash - compute the hash digest of the raw subject name
+* This function prefers SHA-1 (if available) for compatibility
 *
 * RETURNS:
@@ -19602,34 +22216,57 @@
 unsigned long wolfSSL_X509_subject_name_hash(const WOLFSSL_X509* x509)
 {
-    word32 ret = 0;
-    int retHash;
+    unsigned long ret = 0;
+    int retHash = NOT_COMPILED_IN;
     WOLFSSL_X509_NAME *subjectName = NULL;
-
-#ifdef WOLFSSL_PIC32MZ_HASH
-        byte digest[PIC32_DIGEST_SIZE];
-#else
-        byte digest[WC_SHA_DIGEST_SIZE];
-#endif
-
-    if (x509 == NULL){
-        return WOLFSSL_FAILURE;
+    byte digest[WC_MAX_DIGEST_SIZE];
+
+    if (x509 == NULL) {
+        return ret;
     }
 
     subjectName = wolfSSL_X509_get_subject_name((WOLFSSL_X509*)x509);
-
-    if (subjectName != NULL){
+    if (subjectName != NULL) {
+    #ifndef NO_SHA
         retHash = wc_ShaHash((const byte*)subjectName->name,
                              (word32)subjectName->sz, digest);
-
-        if(retHash != 0){
-            WOLFSSL_MSG("Hash of X509 subjectName has failed");
-            return WOLFSSL_FAILURE;
-        }
-        ret = MakeWordFromHash(digest);
-    }
-
-    return (unsigned long)ret;
-}
-#endif
+    #elif !defined(NO_SHA256)
+        retHash = wc_Sha256Hash((const byte*)subjectName->name,
+                                (word32)subjectName->sz, digest);
+    #endif
+        if (retHash == 0) {
+            ret = (unsigned long)MakeWordFromHash(digest);
+        }
+    }
+
+    return ret;
+}
+
+unsigned long wolfSSL_X509_issuer_name_hash(const WOLFSSL_X509* x509)
+{
+    unsigned long ret = 0;
+    int retHash = NOT_COMPILED_IN;
+    WOLFSSL_X509_NAME *issuerName = NULL;
+    byte digest[WC_MAX_DIGEST_SIZE];
+
+    if (x509 == NULL) {
+        return ret;
+    }
+
+    issuerName = wolfSSL_X509_get_issuer_name((WOLFSSL_X509*)x509);
+    if (issuerName != NULL) {
+    #ifndef NO_SHA
+        retHash = wc_ShaHash((const byte*)issuerName->name,
+                             (word32)issuerName->sz, digest);
+    #elif !defined(NO_SHA256)
+        retHash = wc_Sha256Hash((const byte*)issuerName->name,
+                                (word32)issuerName->sz, digest);
+    #endif
+        if (retHash == 0) {
+            ret = (unsigned long)MakeWordFromHash(digest);
+        }
+    }
+    return ret;
+}
+#endif /* OPENSSL_EXTRA && (!NO_SHA || !NO_SHA256) */
 
 WOLFSSL_ABI
@@ -19657,6 +22294,35 @@
 #if defined(OPENSSL_EXTRA_X509_SMALL)
 
+/* Searches for the first ENTRY of type NID
+ * idx is the location to start searching from, the value at when the entry was
+ *     found is stored into idx
+ * returns a pointer to the entry on success and null on fail */
+static WOLFSSL_X509_NAME_ENTRY* GetEntryByNID(WOLFSSL_X509_NAME* name, int nid,
+        int* idx)
+{
+    int i;
+    WOLFSSL_X509_NAME_ENTRY* ret = NULL;
+
+    /* and index of less than 0 is assumed to be starting from 0 */
+    if (*idx < 0) {
+        *idx = 0;
+    }
+
+    for (i = *idx; i < MAX_NAME_ENTRIES; i++) {
+        if (name->entry[i].nid == nid) {
+            ret = &name->entry[i];
+            *idx = i;
+            break;
+        }
+    }
+    return ret;
+}
+
+
 /* Used to get a string from the WOLFSSL_X509_NAME structure that
- * corresponds with the NID value passed in.
+ * corresponds with the NID value passed in. This finds the first entry with
+ * matching NID value, if searching for the case where there is multiple
+ * entries with the same NID value than other functions should be used
+ * (i.e. wolfSSL_X509_NAME_get_index_by_NID, wolfSSL_X509_NAME_get_entry)
  *
  * name structure to get string from
@@ -19674,63 +22340,32 @@
                                       int nid, char* buf, int len)
 {
-    char *text = NULL;
+    WOLFSSL_X509_NAME_ENTRY* e;
+    unsigned char *text = NULL;
     int textSz = 0;
+    int idx    = 0;
 
     WOLFSSL_ENTER("wolfSSL_X509_NAME_get_text_by_NID");
 
-    switch (nid) {
-        case ASN_COMMON_NAME:
-            text = name->fullName.fullName + name->fullName.cnIdx;
-            textSz = name->fullName.cnLen;
-            break;
-        case ASN_SUR_NAME:
-            text = name->fullName.fullName + name->fullName.snIdx;
-            textSz = name->fullName.snLen;
-            break;
-        case ASN_SERIAL_NUMBER:
-            text = name->fullName.fullName + name->fullName.serialIdx;
-            textSz = name->fullName.serialLen;
-            break;
-        case ASN_COUNTRY_NAME:
-            text = name->fullName.fullName + name->fullName.cIdx;
-            textSz = name->fullName.cLen;
-            break;
-        case ASN_LOCALITY_NAME:
-            text = name->fullName.fullName + name->fullName.lIdx;
-            textSz = name->fullName.lLen;
-            break;
-        case ASN_STATE_NAME:
-            text = name->fullName.fullName + name->fullName.stIdx;
-            textSz = name->fullName.stLen;
-            break;
-        case ASN_ORG_NAME:
-            text = name->fullName.fullName + name->fullName.oIdx;
-            textSz = name->fullName.oLen;
-            break;
-        case ASN_ORGUNIT_NAME:
-            text = name->fullName.fullName + name->fullName.ouIdx;
-            textSz = name->fullName.ouLen;
-            break;
-        case ASN_DOMAIN_COMPONENT:
-            text = name->fullName.fullName + name->fullName.dcIdx[0];
-            textSz = name->fullName.dcLen[0];
-            break;
-        case NID_emailAddress:
-            text = name->fullName.fullName + name->fullName.emailIdx;
-            textSz = name->fullName.emailLen;
-            break;
-    #ifdef WOLFSSL_CERT_EXT
-        case ASN_BUS_CAT:
-            text = name->fullName.fullName + name->fullName.bcIdx;
-            textSz = name->fullName.bcLen;
-            break;
-    #endif
-        default:
-            WOLFSSL_MSG("Entry type not found");
-            return WOLFSSL_FATAL_ERROR;
+    if (name == NULL) {
+        WOLFSSL_MSG("NULL argument passed in");
+        return WOLFSSL_FATAL_ERROR;
+    }
+
+    e = GetEntryByNID(name, nid, &idx);
+    if (e == NULL) {
+        WOLFSSL_MSG("Entry type not found");
+        return WOLFSSL_FATAL_ERROR;
+    }
+    text   = wolfSSL_ASN1_STRING_data(e->value);
+    textSz = wolfSSL_ASN1_STRING_length(e->value);
+
+    if (text == NULL) {
+        WOLFSSL_MSG("Unable to get entry text");
+        return WOLFSSL_FATAL_ERROR;
     }
 
     /* if buf is NULL return size of buffer needed (minus null char) */
     if (buf == NULL) {
+        WOLFSSL_MSG("Buffer is NULL, returning buffer size only");
         return textSz;
     }
@@ -19795,5 +22430,5 @@
                 if (wolfSSL_RSA_LoadDer_ex(key->rsa,
                             (const unsigned char*)key->pkey.ptr, key->pkey_sz,
-                            WOLFSSL_RSA_LOAD_PUBLIC) != SSL_SUCCESS) {
+                            WOLFSSL_RSA_LOAD_PUBLIC) != WOLFSSL_SUCCESS) {
                     wolfSSL_EVP_PKEY_free(key);
                     return NULL;
@@ -19823,5 +22458,5 @@
                 }
 
-                if (SetECKeyExternal(key->ecc) != SSL_SUCCESS) {
+                if (SetECKeyExternal(key->ecc) != WOLFSSL_SUCCESS) {
                     WOLFSSL_MSG("SetECKeyExternal failed");
                     wolfSSL_EVP_PKEY_free(key);
@@ -19844,5 +22479,5 @@
                 if (wolfSSL_DSA_LoadDer_ex(key->dsa,
                             (const unsigned char*)key->pkey.ptr, key->pkey_sz, \
-                            WOLFSSL_DSA_LOAD_PUBLIC) != SSL_SUCCESS) {
+                            WOLFSSL_DSA_LOAD_PUBLIC) != WOLFSSL_SUCCESS) {
                     wolfSSL_DSA_free(key->dsa);
                     key->dsa = NULL;
@@ -19861,9 +22496,9 @@
 /* End of smaller subset of X509 compatibility functions. Avoid increasing the
  * size of this subset and its memory usage */
-#endif /* OPENSSL_EXTRA_X509_SMALL */
+#endif /* OPENSSL_EXTRA_X509_SMALL || KEEP_PEER_CERT || SESSION_CERTS */
 
 #if defined(OPENSSL_ALL)
 /* Takes two WOLFSSL_X509* certificates and performs a Sha hash of each, if the
-   * has values are the same, then it will do an XMEMCMP to confirm they are
+   * hash values are the same, then it will do an XMEMCMP to confirm they are
    * identical. Returns a 0 when certificates match, returns a negative number
    * when certificates are not a match.
@@ -19873,17 +22508,7 @@
         const byte* derA;
         const byte* derB;
-        int retHashA;
-        int retHashB;
         int outSzA = 0;
         int outSzB = 0;
 
-        #ifdef WOLFSSL_PIC32MZ_HASH
-            byte digestA[PIC32_DIGEST_SIZE];
-            byte digestB[PIC32_DIGEST_SIZE];
-        #else
-            byte digestA[WC_SHA_DIGEST_SIZE];
-            byte digestB[WC_SHA_DIGEST_SIZE];
-        #endif
-
         if (a == NULL || b == NULL){
             return BAD_FUNC_ARG;
@@ -19891,49 +22516,25 @@
 
         derA = wolfSSL_X509_get_der((WOLFSSL_X509*)a, &outSzA);
-        if(derA == NULL){
+        if (derA == NULL){
             WOLFSSL_MSG("wolfSSL_X509_get_der - certificate A has failed");
             return WOLFSSL_FATAL_ERROR;
         }
         derB = wolfSSL_X509_get_der((WOLFSSL_X509*)b, &outSzB);
-        if(derB == NULL){
+        if (derB == NULL){
             WOLFSSL_MSG("wolfSSL_X509_get_der - certificate B has failed");
             return WOLFSSL_FATAL_ERROR;
         }
 
-        retHashA = wc_ShaHash(derA, (word32)outSzA, digestA);
-        if(retHashA != 0){
-            WOLFSSL_MSG("Hash of certificate A has failed");
-            return WOLFSSL_FATAL_ERROR;
-        }
-        retHashB = wc_ShaHash(derB, (word32)outSzB, digestB);
-        if(retHashB != 0){
-            WOLFSSL_MSG("Hash of certificate B has failed");
-            return WOLFSSL_FATAL_ERROR;
-        }
-
-        if (outSzA == outSzB){
-            #ifdef WOLFSSL_PIC32MZ_HASH
-            if(XMEMCMP(digestA, digestB, PIC32_DIGEST_SIZE) != 0){
-                return WOLFSSL_FATAL_ERROR;
-            }
-            #else
-            if(XMEMCMP(digestA, digestB, WC_SHA_DIGEST_SIZE) != 0){
-                return WOLFSSL_FATAL_ERROR;
-            }
-            #endif
-            else{
-                WOLFSSL_LEAVE("wolfSSL_X509_cmp", 0);
-                return 0;
-            }
-        }
-        else{
+        if (outSzA != outSzB || XMEMCMP(derA, derB, outSzA) != 0) {
             WOLFSSL_LEAVE("wolfSSL_X509_cmp", WOLFSSL_FATAL_ERROR);
             return WOLFSSL_FATAL_ERROR;
         }
-    }
-#endif
-
-#if defined(OPENSSL_EXTRA)
-#if !defined(NO_CERTS)
+
+        WOLFSSL_LEAVE("wolfSSL_X509_cmp", 0);
+        return 0;
+    }
+#endif /* OPENSSL_ALL */
+
+#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS)
     int wolfSSL_X509_ext_isSet_by_NID(WOLFSSL_X509* x509, int nid)
     {
@@ -20092,21 +22693,12 @@
         return id;
     }
-
-
-    int wolfSSL_X509_NAME_entry_count(WOLFSSL_X509_NAME* name)
-    {
-        int count = 0;
-
-        WOLFSSL_ENTER("wolfSSL_X509_NAME_entry_count");
-
-        if (name != NULL)
-            count = name->fullName.locSz;
-
-        WOLFSSL_LEAVE("wolfSSL_X509_NAME_entry_count", count);
-        return count;
-    }
-
-
-
+#endif /* !NO_CERTS && OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \
+    defined(OPENSSL_EXTRA_X509_SMALL)
+
+    /* Looks up the index of the first entry encountered with matching NID
+     * The search starts from index 'pos'
+     * returns a negative value on failure and positive index value on success*/
     int wolfSSL_X509_NAME_get_index_by_NID(WOLFSSL_X509_NAME* name,
                                           int nid, int pos)
@@ -20116,10 +22708,6 @@
         WOLFSSL_ENTER("wolfSSL_X509_NAME_get_index_by_NID");
 
-        if (name == NULL || pos >= DN_NAMES_MAX + DOMAIN_COMPONENT_MAX) {
+        if (name == NULL) {
             return BAD_FUNC_ARG;
-        }
-
-        if (value == NID_emailAddress) {
-            value = ASN_EMAIL_NAME;
         }
 
@@ -20129,7 +22717,6 @@
         }
 
-        for (;i < name->fullName.locSz &&
-                i < DN_NAMES_MAX + DOMAIN_COMPONENT_MAX; i++) {
-            if (name->fullName.loc[i] == value) {
+        for (;i < name->entrySz && i < MAX_NAME_ENTRIES; i++) {
+            if (name->entry[i].nid == value) {
                 return i;
             }
@@ -20169,4 +22756,38 @@
     }
 
+    /**
+     * Used to duplicate a passed in WOLFSSL_ASN1_STRING*
+     * @param asn1 WOLFSSL_ASN1_STRING* to be duplicated
+     * @return WOLFSSL_ASN1_STRING* the duplicate struct or NULL on error
+     */
+    WOLFSSL_ASN1_STRING* wolfSSL_ASN1_STRING_dup(WOLFSSL_ASN1_STRING* asn1)
+    {
+        WOLFSSL_ASN1_STRING* dupl = NULL;
+
+        WOLFSSL_ENTER("wolfSSL_ASN1_STRING_dup");
+        if (!asn1) {
+            WOLFSSL_MSG("Bad parameter");
+            return NULL;
+        }
+
+        dupl = wolfSSL_ASN1_STRING_new();
+        if (!dupl) {
+            WOLFSSL_MSG("wolfSSL_ASN1_STRING_new error");
+            return NULL;
+        }
+
+        dupl->type = asn1->type;
+        dupl->flags = asn1->flags;
+
+        if (wolfSSL_ASN1_STRING_set(dupl, asn1->data, asn1->length)
+                != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("wolfSSL_ASN1_STRING_set error");
+            wolfSSL_ASN1_STRING_free(dupl);
+            return NULL;
+        }
+
+        return dupl;
+    }
+
 
     /* used to free a WOLFSSL_ASN1_STRING structure */
@@ -20183,4 +22804,27 @@
     }
 
+    int wolfSSL_ASN1_STRING_cmp(const WOLFSSL_ASN1_STRING *a, const WOLFSSL_ASN1_STRING *b)
+    {
+        int i;
+        WOLFSSL_ENTER("wolfSSL_ASN1_STRING_cmp");
+
+        if (!a || !b) {
+            return WOLFSSL_FATAL_ERROR;
+        }
+
+        if (a->length != b->length) {
+            return a->length - b->length;
+        }
+
+        if ((i = XMEMCMP(a->data, b->data, a->length)) != 0) {
+            return i;
+        }
+
+        return a->type - b->type;
+    }
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#if !defined(NO_CERTS) && (defined(OPENSSL_EXTRA) || \
+    defined(OPENSSL_EXTRA_X509_SMALL))
 
     /* Creates a new WOLFSSL_ASN1_STRING structure given the input type.
@@ -20224,4 +22868,8 @@
     }
 
+#endif /* !NO_CERTS && OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \
+    defined(OPENSSL_EXTRA_X509_SMALL)
     /* if dataSz is negative then use XSTRLEN to find length of data
      * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure */
@@ -20239,5 +22887,5 @@
 
         if (dataSz < 0) {
-            sz = (int)XSTRLEN((const char*)data) + 1; /* +1 for null */
+            sz = (int)XSTRLEN((const char*)data);
         }
         else {
@@ -20255,7 +22903,7 @@
         }
 
-        if (sz > CTC_NAME_SIZE) {
+        if (sz + 1 > CTC_NAME_SIZE) { /* account for null char */
             /* create new data buffer and copy over */
-            asn1->data = (char*)XMALLOC(sz, NULL, DYNAMIC_TYPE_OPENSSL);
+            asn1->data = (char*)XMALLOC(sz + 1, NULL, DYNAMIC_TYPE_OPENSSL);
             if (asn1->data == NULL) {
                 return WOLFSSL_FAILURE;
@@ -20276,5 +22924,8 @@
         return WOLFSSL_SUCCESS;
     }
-
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#ifndef NO_CERTS
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
 
     unsigned char* wolfSSL_ASN1_STRING_data(WOLFSSL_ASN1_STRING* asn)
@@ -20302,5 +22953,7 @@
         }
     }
-
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
+
+#ifdef OPENSSL_EXTRA
 #ifndef NO_WOLFSSL_STUB
     WOLFSSL_ASN1_STRING* wolfSSL_d2i_DISPLAYTEXT(WOLFSSL_ASN1_STRING **asn,
@@ -20315,4 +22968,5 @@
 #endif
 
+#ifndef NO_BIO
 #ifdef XSNPRINTF /* a snprintf function needs to be available */
     /* Writes the human readable form of x509 to bio.
@@ -20328,9 +22982,7 @@
         WOLFSSL_ENTER("wolfSSL_X509_print_ex");
 
-    #ifndef NO_WOLFSSL_STUB
         /* flags currently not supported */
         (void)nmflags;
         (void)cflag;
-    #endif
 
         if (bio == NULL || x509 == NULL) {
@@ -21003,8 +23655,79 @@
     }
 
+#ifndef NO_FILESYSTEM
+    int wolfSSL_X509_print_fp(XFILE fp, WOLFSSL_X509 *x509)
+    {
+        WOLFSSL_BIO* bio;
+        int ret;
+
+        WOLFSSL_ENTER("wolfSSL_X509_print_fp");
+
+        if (!fp || !x509) {
+            WOLFSSL_MSG("Bad parameter");
+            return WOLFSSL_FAILURE;
+        }
+
+        if (!(bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file()))) {
+            WOLFSSL_MSG("wolfSSL_BIO_new wolfSSL_BIO_s_file error");
+            return WOLFSSL_FAILURE;
+        }
+
+        if (wolfSSL_BIO_set_fp(bio, fp, BIO_NOCLOSE) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("wolfSSL_BIO_set_fp error");
+            return WOLFSSL_FAILURE;
+        }
+
+        ret = wolfSSL_X509_print(bio, x509);
+
+        wolfSSL_BIO_free(bio);
+
+        return ret;
+    }
+#endif /* NO_FILESYSTEM */
+
 #endif /* XSNPRINTF */
-
-#endif /* NO_CERTS */
-
+#endif /* !NO_BIO */
+
+    int wolfSSL_X509_signature_print(WOLFSSL_BIO *bp,
+            const WOLFSSL_X509_ALGOR *sigalg, const WOLFSSL_ASN1_STRING *sig)
+    {
+        (void)sig;
+
+        WOLFSSL_ENTER("wolfSSL_X509_signature_print");
+
+        if (!bp || !sigalg) {
+            WOLFSSL_MSG("Bad parameter");
+            return WOLFSSL_FAILURE;
+        }
+
+        if (wolfSSL_BIO_puts(bp, "    Signature Algorithm: ") <= 0) {
+            WOLFSSL_MSG("wolfSSL_BIO_puts error");
+            return WOLFSSL_FAILURE;
+        }
+
+        if (wolfSSL_i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0) {
+            WOLFSSL_MSG("wolfSSL_i2a_ASN1_OBJECT error");
+            return WOLFSSL_FAILURE;
+        }
+
+        return WOLFSSL_SUCCESS;
+    }
+
+#ifndef NO_WOLFSSL_STUB
+    void wolfSSL_X509_get0_signature(const WOLFSSL_ASN1_BIT_STRING **psig,
+            const WOLFSSL_X509_ALGOR **palg, const WOLFSSL_X509 *x509)
+    {
+        (void)psig;
+        (void)palg;
+        (void)x509;
+        WOLFSSL_STUB("wolfSSL_X509_get0_signature");
+    }
+#endif
+
+#endif /* OPENSSL_EXTRA */
+
+#endif /* !NO_CERTS */
+
+#ifdef OPENSSL_EXTRA
 #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
 /* Creates cipher->description based on cipher->offset
@@ -21039,4 +23762,6 @@
 
     offset = cipher->offset;
+    if (offset >= (unsigned long)GetCipherNamesSize())
+        return WOLFSSL_FAILURE;
     pv.major = cipher_names[offset].major;
     pv.minor = cipher_names[offset].minor;
@@ -21126,5 +23851,5 @@
     return WOLFSSL_SUCCESS;
 }
-#endif
+#endif /* OPENSSL_ALL || WOLFSSL_QT */
 
 char* wolfSSL_CIPHER_description(const WOLFSSL_CIPHER* cipher, char* in,
@@ -21444,4 +24169,6 @@
 
 
+#ifndef NO_BIO
+
 /* Removes a WOLFSSL_BIO struct from the WOLFSSL_BIO linked list.
  *
@@ -21526,13 +24253,13 @@
 {
     WOLFSSL_ENTER("wolfSSL_BIO_set_ex_data");
-    #ifdef HAVE_EX_DATA
+#ifdef HAVE_EX_DATA
     if (bio != NULL && idx < MAX_EX_DATA) {
         return wolfSSL_CRYPTO_set_ex_data(&bio->ex_data, idx, data);
     }
-    #else
+#else
     (void)bio;
     (void)idx;
     (void)data;
-    #endif
+#endif
     return WOLFSSL_FAILURE;
 }
@@ -21548,14 +24275,16 @@
 {
     WOLFSSL_ENTER("wolfSSL_BIO_get_ex_data");
-    #ifdef HAVE_EX_DATA
+#ifdef HAVE_EX_DATA
     if (bio != NULL && idx < MAX_EX_DATA && idx >= 0) {
         return wolfSSL_CRYPTO_get_ex_data(&bio->ex_data, idx);
     }
-    #else
+#else
     (void)bio;
     (void)idx;
-    #endif
+#endif
     return NULL;
 }
+
+#endif /* !NO_BIO */
 
 #ifndef NO_WOLFSSL_STUB
@@ -21632,10 +24361,14 @@
 #endif
 
-
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 const char* wolfSSL_X509_verify_cert_error_string(long err)
 {
     return wolfSSL_ERR_reason_error_string(err);
 }
-
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#ifdef OPENSSL_EXTRA
 
 #ifndef NO_WOLFSSL_STUB
@@ -21669,5 +24402,5 @@
         return BAD_FUNC_ARG;
 
-    fp = XFOPEN(file, "r");
+    fp = XFOPEN(file, "rb");
     if (fp == XBADFILE)
         return BAD_FUNC_ARG;
@@ -21769,4 +24502,35 @@
 
 
+int wolfSSL_X509_LOOKUP_ctrl(WOLFSSL_X509_LOOKUP *ctx, int cmd,
+        const char *argc, long argl, char **ret)
+{
+    /* control commands:
+     * X509_L_FILE_LOAD, X509_L_ADD_DIR, X509_L_ADD_STORE, X509_L_LOAD_STORE
+     */
+
+    /* returns -1 if the X509_LOOKUP doesn't have an associated X509_LOOKUP_METHOD */
+
+
+
+    if (ctx != NULL) {
+        switch (cmd) {
+        case WOLFSSL_X509_L_FILE_LOAD:
+        case WOLFSSL_X509_L_ADD_DIR:
+        case WOLFSSL_X509_L_ADD_STORE:
+        case WOLFSSL_X509_L_LOAD_STORE:
+            return WOLFSSL_SUCCESS;
+
+        default:
+            break;
+        }
+
+    }
+
+    (void)argc; (void)argl; (void)ret;
+
+    return WOLFSSL_FAILURE;
+}
+
+
 WOLFSSL_X509_LOOKUP* wolfSSL_X509_STORE_add_lookup(WOLFSSL_X509_STORE* store,
                                                WOLFSSL_X509_LOOKUP_METHOD* m)
@@ -21783,6 +24547,62 @@
 }
 
+#if !defined(NO_CERTS) && defined(WOLFSSL_CERT_GEN)
+static int wolfssl_x509_make_der(WOLFSSL_X509* x509, int req,
+        unsigned char* der, int* derSz, int includeSig);
+#endif
 
 #ifndef NO_CERTS
+#ifdef WOLFSSL_CERT_GEN
+#ifndef NO_BIO
+/* Converts the X509 to DER format and outputs it into bio.
+ *
+ * bio  is the structure to hold output DER
+ * x509 certificate to create DER from
+ * req  if set then a CSR is generated
+ *
+ * returns WOLFSSL_SUCCESS on success
+ */
+static int loadX509orX509REQFromBio(WOLFSSL_BIO* bio, WOLFSSL_X509* x509, int req)
+{
+    int ret = WOLFSSL_FAILURE;
+    /* Get large buffer to hold cert der */
+    int derSz = X509_BUFFER_SZ;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* der;
+#else
+    byte der[X509_BUFFER_SZ];
+#endif
+    WOLFSSL_ENTER("wolfSSL_i2d_X509_bio");
+
+    if (bio == NULL || x509 == NULL) {
+        return WOLFSSL_FAILURE;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    der = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (!der) {
+        WOLFSSL_MSG("malloc failed");
+        return WOLFSSL_FAILURE;
+    }
+#endif
+
+    if (wolfssl_x509_make_der(x509, req, der, &derSz, 1) != WOLFSSL_SUCCESS) {
+        goto cleanup;
+    }
+
+    if (wolfSSL_BIO_write(bio, der, derSz) != derSz) {
+        goto cleanup;
+    }
+
+    ret = WOLFSSL_SUCCESS;
+cleanup:
+    #ifdef WOLFSSL_SMALL_STACK
+    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+
+    return ret;
+}
+#endif /* !NO_BIO */
+
 /* Converts the X509 to DER format and outputs it into bio.
  *
@@ -21794,22 +24614,14 @@
 int wolfSSL_i2d_X509_bio(WOLFSSL_BIO* bio, WOLFSSL_X509* x509)
 {
-    WOLFSSL_ENTER("wolfSSL_i2d_X509_bio");
-
-    if (bio == NULL || x509 == NULL) {
-        return WOLFSSL_FAILURE;
-    }
-
-    if (x509->derCert != NULL) {
-        word32 len = x509->derCert->length;
-        byte*  der = x509->derCert->buffer;
-
-        if (wolfSSL_BIO_write(bio, der, len) == (int)len) {
-            return SSL_SUCCESS;
-        }
-    }
-
-    return WOLFSSL_FAILURE;
-}
-
+    return loadX509orX509REQFromBio(bio, x509, 0);
+}
+
+#ifdef WOLFSSL_CERT_REQ
+int wolfSSL_i2d_X509_REQ_bio(WOLFSSL_BIO* bio, WOLFSSL_X509* x509)
+{
+    return loadX509orX509REQFromBio(bio, x509, 1);
+}
+#endif /* WOLFSSL_CERT_REQ */
+#endif /* WOLFSSL_CERT_GEN */
 
 /* Converts an internal structure to a DER buffer
@@ -21854,18 +24666,18 @@
 }
 
-
-/* Converts the DER from bio and creates a WOLFSSL_X509 structure from it.
- *
- * bio  is the structure holding DER
- * x509 certificate to create from DER. Can be NULL
- *
- * returns pointer to WOLFSSL_X509 structure on success and NULL on fail
+#ifndef NO_BIO
+/**
+ * Converts the DER from bio and creates a WOLFSSL_X509 structure from it.
+ * @param bio  is the structure holding DER
+ * @param x509 certificate to create from DER. Can be NULL
+ * @param req  1 for a CSR and 0 for a x509 cert
+ * @return pointer to WOLFSSL_X509 structure on success and NULL on fail
  */
-WOLFSSL_X509* wolfSSL_d2i_X509_bio(WOLFSSL_BIO* bio, WOLFSSL_X509** x509)
+static WOLFSSL_X509* d2i_X509orX509REQ_bio(WOLFSSL_BIO* bio,
+                                            WOLFSSL_X509** x509, int req)
 {
     WOLFSSL_X509* localX509 = NULL;
-    unsigned char* mem  = NULL;
-    int    ret;
-    word32 size;
+    byte* mem  = NULL;
+    int    size;
 
     WOLFSSL_ENTER("wolfSSL_d2i_X509_bio");
@@ -21876,13 +24688,34 @@
     }
 
-    ret = wolfSSL_BIO_get_mem_data(bio, &mem);
-    if (mem == NULL || ret <= 0) {
-        WOLFSSL_MSG("Failed to get data from bio struct");
+    size = wolfSSL_BIO_get_len(bio);
+    if (size == 0) {
+        WOLFSSL_MSG("wolfSSL_BIO_get_len error. Possibly no pending data.");
         return NULL;
     }
-    size = ret;
-
-    localX509 = wolfSSL_X509_d2i(NULL, mem, size);
+
+    if (!(mem = (byte*)XMALLOC(size, NULL, DYNAMIC_TYPE_OPENSSL))) {
+        WOLFSSL_MSG("malloc error");
+        return NULL;
+    }
+
+    if ((size = wolfSSL_BIO_read(bio, mem, size)) == 0) {
+        WOLFSSL_MSG("wolfSSL_BIO_read error");
+        XFREE(mem, NULL, DYNAMIC_TYPE_OPENSSL);
+        return NULL;
+    }
+
+    if (req) {
+#ifdef WOLFSSL_CERT_REQ
+        localX509 = wolfSSL_X509_REQ_d2i(NULL, mem, size);
+#else
+        WOLFSSL_MSG("CSR not compiled in");
+#endif
+    }
+    else {
+        localX509 = wolfSSL_X509_d2i(NULL, mem, size);
+    }
     if (localX509 == NULL) {
+        WOLFSSL_MSG("wolfSSL_X509_d2i error");
+        XFREE(mem, NULL, DYNAMIC_TYPE_OPENSSL);
         return NULL;
     }
@@ -21892,9 +24725,23 @@
     }
 
+    XFREE(mem, NULL, DYNAMIC_TYPE_OPENSSL);
     return localX509;
 }
-
+#endif /* !NO_BIO */
+
+WOLFSSL_X509* wolfSSL_d2i_X509_bio(WOLFSSL_BIO* bio, WOLFSSL_X509** x509)
+{
+    return d2i_X509orX509REQ_bio(bio, x509, 0);
+}
+
+#ifdef WOLFSSL_CERT_REQ
+WOLFSSL_X509* wolfSSL_d2i_X509_REQ_bio(WOLFSSL_BIO* bio, WOLFSSL_X509** x509)
+{
+    return d2i_X509orX509REQ_bio(bio, x509, 1);
+}
+#endif
 
 #if !defined(NO_ASN) && !defined(NO_PWDBASED)
+#ifndef NO_BIO
 WC_PKCS12* wolfSSL_d2i_PKCS12_bio(WOLFSSL_BIO* bio, WC_PKCS12** pkcs12)
 {
@@ -21965,5 +24812,5 @@
         if ((certSz > 0) && (certDer != NULL)) {
             if (wolfSSL_BIO_write(bio, certDer, certSz) == (int)certSz) {
-                ret = SSL_SUCCESS;
+                ret = WOLFSSL_SUCCESS;
             }
         }
@@ -21976,38 +24823,15 @@
     return ret;
 }
-
-/* helper function to get raw pointer to DER buffer from WOLFSSL_EVP_PKEY */
-static int wolfSSL_EVP_PKEY_get_der(WOLFSSL_EVP_PKEY* key, unsigned char** der)
-{
-    if (!key)
-        return WOLFSSL_FAILURE;
-    if (der)
-        *der = (unsigned char*)key->pkey.ptr;
-    return key->pkey_sz;
-}
+#endif /* !NO_BIO */
 
 /* Copies unencrypted DER key buffer into "der". If "der" is null then the size
- * of buffer needed is returned
+ * of buffer needed is returned. If *der == NULL then it allocates a buffer.
  * NOTE: This also advances the "der" pointer to be at the end of buffer.
  *
  * Returns size of key buffer on success
  */
-int wolfSSL_i2d_PrivateKey(WOLFSSL_EVP_PKEY* key, unsigned char** der)
-{
-    if (key == NULL) {
-        return WOLFSSL_FATAL_ERROR;
-    }
-
-    if (key->pkey_sz <= 0 || !key->pkey.ptr) {
-        return WOLFSSL_FATAL_ERROR;
-    }
-
-    if (der != NULL) {
-        /* since this function signature has no size value passed in it is
-         * assumed that the user has allocated a large enough buffer */
-        XMEMCPY(*der, key->pkey.ptr, key->pkey_sz);
-        *der += key->pkey_sz;
-    }
-    return key->pkey_sz;
+int wolfSSL_i2d_PrivateKey(const WOLFSSL_EVP_PKEY* key, unsigned char** der)
+{
+    return wolfSSL_EVP_PKEY_get_der(key, der);
 }
 
@@ -22035,11 +24859,9 @@
     WC_DerCertList* list = NULL;
     word32 passSz;
-    byte* keyDer;
+    byte* keyDer = NULL;
     word32 keyDerSz;
     byte* certDer;
     int certDerSz;
 
-    int ret;
-
     WOLFSSL_ENTER("wolfSSL_PKCS12_create()");
 
@@ -22050,9 +24872,6 @@
     passSz = (word32)XSTRLEN(pass);
 
-    if ((ret = wolfSSL_EVP_PKEY_get_der(pkey, &keyDer)) < 0) {
-        WOLFSSL_LEAVE("wolfSSL_PKCS12_create", ret);
-        return NULL;
-    }
-    keyDerSz = ret;
+    keyDer = (byte*)pkey->pkey.ptr;
+    keyDerSz = pkey->pkey_sz;
 
     certDer = (byte*)wolfSSL_X509_get_der(cert, &certDerSz);
@@ -22191,5 +25010,5 @@
             }
             else {
-                if ((ret = CopyDecodedToX509(x509, &DeCert)) != 0) {
+                if (CopyDecodedToX509(x509, &DeCert) != 0) {
                     WOLFSSL_MSG("Failed to copy decoded cert");
                     FreeDecodedCert(&DeCert);
@@ -22262,5 +25081,5 @@
             WOLFSSL_MSG("Issue with parsing certificate");
         }
-        if ((ret = CopyDecodedToX509(*cert, &DeCert)) != 0) {
+        if (CopyDecodedToX509(*cert, &DeCert) != 0) {
             WOLFSSL_MSG("Failed to copy decoded cert");
             FreeDecodedCert(&DeCert);
@@ -22315,6 +25134,6 @@
                         return WOLFSSL_FAILURE;
                     }
-                    if ((ret = wolfSSL_RSA_LoadDer_ex((*pkey)->rsa, pk, pkSz,
-                                    WOLFSSL_RSA_LOAD_PRIVATE)) != SSL_SUCCESS) {
+                    if (wolfSSL_RSA_LoadDer_ex((*pkey)->rsa, pk, pkSz,
+                                    WOLFSSL_RSA_LOAD_PRIVATE) != SSL_SUCCESS) {
                         WOLFSSL_MSG("issue loading RSA key");
                         wolfSSL_X509_free(*cert); *cert = NULL;
@@ -22391,5 +25210,18 @@
     return WOLFSSL_SUCCESS;
 }
-#endif /* !defined(NO_ASN) && !defined(NO_PWDBASED) */
+
+int wolfSSL_PKCS12_verify_mac(WC_PKCS12 *pkcs12, const char *psw,
+        int pswLen)
+{
+    WOLFSSL_ENTER("wolfSSL_PKCS12_verify_mac");
+
+    if (!pkcs12) {
+        return WOLFSSL_FAILURE;
+    }
+
+    return wc_PKCS12_verify_ex(pkcs12, (const byte*)psw, pswLen) == 0 ?
+            WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
+}
+#endif /* !NO_ASN && !NO_PWDBASED */
 
 
@@ -22424,5 +25256,4 @@
 
         XMEMSET(sk, 0, sizeof(WOLFSSL_STACK));
-        ctx->chain = sk;
 
         for (i = 0; i < c->count && i < MAX_CHAIN_DEPTH; i++) {
@@ -22435,5 +25266,5 @@
             }
 
-            if (wolfSSL_sk_X509_push(sk, x509) != SSL_SUCCESS) {
+            if (wolfSSL_sk_X509_push(sk, x509) != WOLFSSL_SUCCESS) {
                 WOLFSSL_MSG("Unable to load x509 into stack");
                 wolfSSL_sk_X509_free(sk);
@@ -22455,5 +25286,5 @@
                     if (issuer != NULL && wolfSSL_X509_NAME_cmp(&x509->issuer,
                                 &x509->subject) != 0) {
-                        if (wolfSSL_sk_X509_push(sk, issuer) != SSL_SUCCESS) {
+                        if (wolfSSL_sk_X509_push(sk, issuer) != WOLFSSL_SUCCESS) {
                             WOLFSSL_MSG("Unable to load CA x509 into stack");
                             wolfSSL_sk_X509_free(sk);
@@ -22474,5 +25305,5 @@
         }
 #endif
-
+        ctx->chain = sk;
     }
 #endif /* SESSION_CERTS */
@@ -22480,48 +25311,4 @@
     return ctx->chain;
 }
-
-/* make shallow copy of the stack, data pointers are copied by reference */
-WOLFSSL_STACK* wolfSSL_sk_X509_dup(WOLFSSL_STACK* sk)
-{
-    unsigned long i;
-    WOLFSSL_STACK* dup = NULL;
-    WOLFSSL_STACK* node = NULL;
-    WOLFSSL_STACK *dIdx = NULL, *sIdx = sk;
-
-    if (sk == NULL) {
-        return NULL;
-    }
-
-    for (i = 0; i < sk->num; i++) {
-
-        node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL,
-                                         DYNAMIC_TYPE_X509);
-        if (node == NULL) {
-            if (i != 0) {
-                wolfSSL_sk_free(dup);
-            }
-            WOLFSSL_MSG("Memory error");
-            return NULL;
-        }
-        XMEMSET(node, 0, sizeof(WOLFSSL_STACK));
-
-        /* copy sk node to new node, data by reference */
-        node->data.x509 = sIdx->data.x509;
-        node->num = sIdx->num;
-
-        /* insert node into list, progress idx */
-        if (i == 0) {
-            dup = node;
-        } else {
-            dIdx->next = node;
-        }
-
-        dIdx = node;
-        sIdx = sIdx->next;
-    }
-
-    return dup;
-}
-
 
 /* like X509_STORE_CTX_get_chain(), but return a copy with data reference
@@ -22529,7 +25316,5 @@
 WOLFSSL_STACK* wolfSSL_X509_STORE_CTX_get1_chain(WOLFSSL_X509_STORE_CTX* ctx)
 {
-    unsigned long i;
     WOLFSSL_STACK* ref;
-    WOLFSSL_STACK* dup;
 
     if (ctx == NULL) {
@@ -22544,23 +25329,16 @@
 
     /* create duplicate of ctx chain */
-    dup = wolfSSL_sk_X509_dup(ref);
-    if (dup == NULL) {
-        return NULL;
-    }
-
-    /* increase ref counts of inner data X509 */
-    ref = dup;
-    for (i = 0; i < dup->num && ref != NULL; i++) {
-        if (wc_LockMutex(&ref->data.x509->refMutex) != 0) {
-            WOLFSSL_MSG("Failed to lock x509 mutex");
-        }
-        ref->data.x509->refCount++;
-        wc_UnLockMutex(&ref->data.x509->refMutex);
-        ref = ref->next;
-    }
-
-    return dup;
-}
-
+    return wolfSSL_sk_dup(ref);
+}
+
+#ifndef NO_WOLFSSL_STUB
+WOLFSSL_X509_STORE_CTX *wolfSSL_X509_STORE_CTX_get0_parent_ctx(
+                                                   WOLFSSL_X509_STORE_CTX *ctx)
+{
+    (void)ctx;
+    WOLFSSL_STUB("wolfSSL_X509_STORE_CTX_get0_parent_ctx");
+    return NULL;
+}
+#endif
 
 int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509)
@@ -22591,5 +25369,8 @@
     return result;
 }
-
+#endif /* !NO_CERTS */
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 WOLFSSL_X509_STORE* wolfSSL_X509_STORE_new(void)
 {
@@ -22608,17 +25389,13 @@
 
 #ifdef HAVE_CRL
-    store->crl = NULL;
-    if ((store->crl = (WOLFSSL_X509_CRL *)XMALLOC(sizeof(WOLFSSL_X509_CRL),
-                                        NULL, DYNAMIC_TYPE_TMP_BUFFER)) == NULL)
-        goto err_exit;
-    if (InitCRL(store->crl, NULL) < 0)
-        goto err_exit;
-#endif
-
-#ifdef OPENSSL_EXTRA
+    store->crl = store->cm->crl;
+#endif
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
     if ((store->param = (WOLFSSL_X509_VERIFY_PARAM*)XMALLOC(
                            sizeof(WOLFSSL_X509_VERIFY_PARAM),
-                           NULL,DYNAMIC_TYPE_OPENSSL)) == NULL)
+                           NULL, DYNAMIC_TYPE_OPENSSL)) == NULL) {
         goto err_exit;
+    }
 
 #endif
@@ -22635,23 +25412,25 @@
 }
 
-
 void wolfSSL_X509_STORE_free(WOLFSSL_X509_STORE* store)
 {
     if (store != NULL && store->isDynamic) {
-        if (store->cm != NULL)
+        if (store->cm != NULL) {
             wolfSSL_CertManagerFree(store->cm);
-#ifdef HAVE_CRL
-        if (store->crl != NULL)
-            wolfSSL_X509_CRL_free(store->crl);
-#endif
+            store->cm = NULL;
+        }
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
+        if (store->param != NULL) {
+            XFREE(store->param, NULL, DYNAMIC_TYPE_OPENSSL);
+            store->param = NULL;
+        }
+#endif
+        XFREE(store, NULL, DYNAMIC_TYPE_X509_STORE);
+    }
+}
+
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
 #ifdef OPENSSL_EXTRA
-        if (store->param != NULL)
-            XFREE(store->param, NULL, DYNAMIC_TYPE_OPENSSL);
-#endif
-        XFREE(store, NULL, DYNAMIC_TYPE_X509_STORE);
-    }
-}
-
-
+#ifndef NO_CERTS
 int wolfSSL_X509_STORE_set_flags(WOLFSSL_X509_STORE* store, unsigned long flag)
 {
@@ -22666,7 +25445,4 @@
         ret = wolfSSL_CertManagerEnableCRL(store->cm, (int)flag);
     }
-
-    (void)store;
-    (void)flag;
 
     return ret;
@@ -22763,5 +25539,5 @@
         }
 #endif
-        return SSL_SUCCESS;
+        return WOLFSSL_SUCCESS;
     }
     return WOLFSSL_FATAL_ERROR;
@@ -22769,33 +25545,42 @@
 
 
+/* free's extra data */
 void wolfSSL_X509_STORE_CTX_free(WOLFSSL_X509_STORE_CTX* ctx)
 {
     WOLFSSL_ENTER("X509_STORE_CTX_free");
     if (ctx != NULL) {
-    #if !defined(OPENSSL_ALL) && !defined(WOLFSSL_QT)
-        if (ctx->store != NULL)
-            wolfSSL_X509_STORE_free(ctx->store);
-        #ifndef WOLFSSL_KEEP_STORE_CERTS
-        if (ctx->current_cert != NULL)
-            wolfSSL_FreeX509(ctx->current_cert);
-        #endif
-    #endif /* !OPENSSL_ALL && !WOLFSSL_QT */
+    #ifdef OPENSSL_EXTRA
+        if (ctx->param != NULL){
+            XFREE(ctx->param,NULL,DYNAMIC_TYPE_OPENSSL);
+            ctx->param = NULL;
+        }
+    #endif
+        XFREE(ctx, NULL, DYNAMIC_TYPE_X509_CTX);
+    }
+}
+
+
+void wolfSSL_X509_STORE_CTX_cleanup(WOLFSSL_X509_STORE_CTX* ctx)
+{
+    if (ctx != NULL) {
 #ifdef OPENSSL_EXTRA
         if (ctx->param != NULL){
             XFREE(ctx->param,NULL,DYNAMIC_TYPE_OPENSSL);
-        }
-#endif
-        XFREE(ctx, NULL, DYNAMIC_TYPE_X509_CTX);
-    }
-}
-
-
-void wolfSSL_X509_STORE_CTX_cleanup(WOLFSSL_X509_STORE_CTX* ctx)
-{
-    (void)ctx;
-    /* Do nothing */
-}
-
-#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
+            ctx->param = NULL;
+        }
+#endif
+        wolfSSL_X509_STORE_CTX_init(ctx, NULL, NULL, NULL);
+    }
+}
+
+
+void wolfSSL_X509_STORE_CTX_trusted_stack(WOLFSSL_X509_STORE_CTX *ctx, WOLF_STACK_OF(WOLFSSL_X509) *sk)
+{
+    if (ctx != NULL) {
+        ctx->chain = sk;
+    }
+}
+
+
 /* Returns corresponding X509 error from internal ASN error <e> */
 static int GetX509Error(int e)
@@ -22823,5 +25608,4 @@
     }
 }
-#endif
 
 /* Verifies certificate chain using WOLFSSL_X509_STORE_CTX
@@ -22831,9 +25615,8 @@
 {
     int ret = 0;
-#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
     int depth = 0;
     int error;
     byte *afterDate, *beforeDate;
-#endif
+
     WOLFSSL_ENTER("wolfSSL_X509_verify_cert");
 
@@ -22845,5 +25628,4 @@
                     WOLFSSL_FILETYPE_ASN1);
 
-#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
         /* If there was an error, process it and add it to CTX */
         if (ret < 0) {
@@ -22856,5 +25638,8 @@
             wolfSSL_X509_STORE_CTX_set_error(ctx, error);
             wolfSSL_X509_STORE_CTX_set_error_depth(ctx, depth);
-            ctx->store->verify_cb(0, ctx);
+        #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
+            if (ctx->store && ctx->store->verify_cb)
+                ctx->store->verify_cb(0, ctx);
+        #endif
         }
 
@@ -22867,10 +25652,10 @@
         beforeDate = ctx->current_cert->notBefore.data;
 
-        if (ValidateDate(afterDate, ctx->current_cert->notAfter.type,
+        if (XVALIDATE_DATE(afterDate, (byte)ctx->current_cert->notAfter.type,
                                                                    AFTER) < 1) {
             error = X509_V_ERR_CERT_HAS_EXPIRED;
         }
-        else if (ValidateDate(beforeDate, ctx->current_cert->notBefore.type,
-                                                                  BEFORE) < 1) {
+        else if (XVALIDATE_DATE(beforeDate,
+                    (byte)ctx->current_cert->notBefore.type, BEFORE) < 1) {
             error = X509_V_ERR_CERT_NOT_YET_VALID;
         }
@@ -22879,18 +25664,23 @@
             wolfSSL_X509_STORE_CTX_set_error(ctx, error);
             wolfSSL_X509_STORE_CTX_set_error_depth(ctx, depth);
+        #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
             if (ctx->store && ctx->store->verify_cb)
                 ctx->store->verify_cb(0, ctx);
-        }
-#endif /* OPENSSL_ALL || WOLFSSL_QT */
-        return ret;
+        #endif
+        }
+
+        /* OpenSSL returns 0 when a chain can't be built */
+        if (ret == ASN_NO_SIGNER_E)
+            return WOLFSSL_FAILURE;
+        else
+            return ret;
     }
     return WOLFSSL_FATAL_ERROR;
 }
-
 
 /* Use the public key to verify the signature. Note: this only verifies
  * the certificate signature.
  * returns WOLFSSL_SUCCESS on successful signature verification */
-int wolfSSL_X509_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey)
+static int verifyX509orX509REQ(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey, int req)
 {
     int ret;
@@ -22899,4 +25689,6 @@
     int type;
 
+    (void)req;
+
     if (x509 == NULL || pkey == NULL) {
         return WOLFSSL_FATAL_ERROR;
@@ -22927,6 +25719,12 @@
     }
 
-    ret = CheckCertSignaturePubKey(der, derSz, x509->heap,
-            (unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, type);
+#ifdef WOLFSSL_CERT_REQ
+    if (req)
+        ret = CheckCSRSignaturePubKey(der, derSz, x509->heap,
+                (unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, type);
+    else
+#endif
+        ret = CheckCertSignaturePubKey(der, derSz, x509->heap,
+                (unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, type);
     if (ret == 0) {
         return WOLFSSL_SUCCESS;
@@ -22934,5 +25732,17 @@
     return WOLFSSL_FAILURE;
 }
-#endif /* NO_CERTS */
+
+int wolfSSL_X509_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey)
+{
+    return verifyX509orX509REQ(x509, pkey, 0);
+}
+
+#ifdef WOLFSSL_CERT_REQ
+int wolfSSL_X509_REQ_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey)
+{
+    return verifyX509orX509REQ(x509, pkey, 1);
+}
+#endif /* WOLFSSL_CERT_REQ */
+#endif /* !NO_CERTS */
 
 #if !defined(NO_FILESYSTEM)
@@ -23051,6 +25861,6 @@
         WOLFSSL_MSG("Bad argument value");
     } else {
-        newcrl = (WOLFSSL_X509_CRL*)XMALLOC(sizeof(WOLFSSL_X509_CRL), NULL,
-                DYNAMIC_TYPE_TMP_BUFFER);
+        newcrl =(WOLFSSL_X509_CRL*)XMALLOC(sizeof(WOLFSSL_X509_CRL), NULL,
+                DYNAMIC_TYPE_CRL);
         if (newcrl == NULL){
             WOLFSSL_MSG("New CRL allocation failed");
@@ -23080,14 +25890,18 @@
     return newcrl;
 }
-
+#endif /* HAVE_CRL */
+#endif /* OPENSSL_EXTRA */
+
+#if defined(HAVE_CRL) && (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL))
 void wolfSSL_X509_CRL_free(WOLFSSL_X509_CRL *crl)
 {
     WOLFSSL_ENTER("wolfSSL_X509_CRL_free");
 
-    FreeCRL(crl, 1);
-    return;
-}
-#endif /* HAVE_CRL */
-
+    if (crl)
+        FreeCRL(crl, 1);
+}
+#endif /* HAVE_CRL && (OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL) */
+
+#ifdef OPENSSL_EXTRA
 #ifndef NO_WOLFSSL_STUB
 WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_lastUpdate(WOLFSSL_X509_CRL* crl)
@@ -23180,4 +25994,66 @@
 }
 #endif
+
+
+WOLFSSL_X509_VERIFY_PARAM* wolfSSL_X509_VERIFY_PARAM_new(void)
+{
+    WOLFSSL_X509_VERIFY_PARAM *param = NULL;
+    param = (WOLFSSL_X509_VERIFY_PARAM*)XMALLOC(
+            sizeof(WOLFSSL_X509_VERIFY_PARAM), NULL, DYNAMIC_TYPE_OPENSSL);
+    if (param != NULL)
+        XMEMSET(param, 0, sizeof(WOLFSSL_X509_VERIFY_PARAM ));
+
+    return(param);
+}
+
+
+void wolfSSL_X509_VERIFY_PARAM_free(WOLFSSL_X509_VERIFY_PARAM *param)
+{
+    if (param != NULL)
+        XFREE(param, NULL, DYNAMIC_TYPE_OPENSSL);
+}
+
+
+/* Sets flags by OR'ing with existing value. */
+int wolfSSL_X509_VERIFY_PARAM_set_flags(WOLFSSL_X509_VERIFY_PARAM *param,
+        unsigned long flags)
+{
+    int ret = WOLFSSL_FAILURE;
+
+    if (param != NULL) {
+        param->flags |= flags;
+        ret = WOLFSSL_SUCCESS;
+    }
+
+    return ret;
+}
+
+
+int wolfSSL_X509_VERIFY_PARAM_get_flags(WOLFSSL_X509_VERIFY_PARAM *param)
+{
+    int ret = 0;
+
+    if (param != NULL) {
+        ret = (int)param->flags;
+    }
+
+    return ret;
+}
+
+
+int wolfSSL_X509_VERIFY_PARAM_clear_flags(WOLFSSL_X509_VERIFY_PARAM *param,
+        unsigned long flags)
+{
+    int ret = WOLFSSL_FAILURE;
+
+    if (param != NULL) {
+        param->flags &= ~flags;
+        ret = WOLFSSL_SUCCESS;
+    }
+
+    return ret;
+}
+
+
 /******************************************************************************
 * wolfSSL_X509_VERIFY_PARAM_set1_host - sets the DNS hostname to name
@@ -23369,6 +26245,6 @@
 #endif /* !NO_ASN_TIME */
 
-#if defined(OPENSSL_EXTRA) && !defined(NO_ASN_TIME) && !defined(USER_TIME) && \
-    !defined(TIME_OVERRIDES)
+#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) && \
+    !defined(NO_ASN_TIME) && !defined(USER_TIME) && !defined(TIME_OVERRIDES)
 WOLFSSL_ASN1_TIME *wolfSSL_X509_time_adj_ex(WOLFSSL_ASN1_TIME *asnTime,
     int offset_day, long offset_sec, time_t *in_tm)
@@ -23415,4 +26291,7 @@
 #endif
 
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 /* Used to create a new WOLFSSL_ASN1_INTEGER structure.
  * returns a pointer to new structure on success and NULL on failure
@@ -23454,32 +26333,32 @@
 WOLFSSL_ASN1_INTEGER* wolfSSL_ASN1_INTEGER_dup(const WOLFSSL_ASN1_INTEGER* src)
 {
-    WOLFSSL_ASN1_INTEGER* dup;
+    WOLFSSL_ASN1_INTEGER* copy;
     WOLFSSL_ENTER("wolfSSL_ASN1_INTEGER_dup");
     if (!src)
         return NULL;
 
-    dup = wolfSSL_ASN1_INTEGER_new();
-
-    if (dup == NULL)
+    copy = wolfSSL_ASN1_INTEGER_new();
+
+    if (copy == NULL)
         return NULL;
 
-    dup->negative  = src->negative;
-    dup->dataMax   = src->dataMax;
-    dup->isDynamic = src->isDynamic;
+    copy->negative  = src->negative;
+    copy->dataMax   = src->dataMax;
+    copy->isDynamic = src->isDynamic;
 #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
-    dup->length    = src->length;
-#endif
-    XSTRNCPY((char*)dup->intData,(const char*)src->intData,WOLFSSL_ASN1_INTEGER_MAX);
-
-    if (dup->isDynamic && src->data && dup->dataMax) {
-        dup->data = (unsigned char*)
+    copy->length    = src->length;
+#endif
+    XSTRNCPY((char*)copy->intData,(const char*)src->intData,WOLFSSL_ASN1_INTEGER_MAX);
+
+    if (copy->isDynamic && src->data && copy->dataMax) {
+        copy->data = (unsigned char*)
             XMALLOC(src->dataMax,NULL,DYNAMIC_TYPE_OPENSSL);
-        if (dup->data == NULL) {
-            wolfSSL_ASN1_INTEGER_free(dup);
+        if (copy->data == NULL) {
+            wolfSSL_ASN1_INTEGER_free(copy);
             return NULL;
         }
-        XMEMCPY(dup->data,src->data,dup->dataMax);
-    }
-    return dup;
+        XMEMCPY(copy->data, src->data, copy->dataMax);
+    }
+    return copy;
 }
 
@@ -23589,9 +26468,10 @@
 }
 
-#endif /* OPENSSL_EXTRA */
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
 
 #if defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) || \
     defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)
 #ifndef NO_ASN_TIME
+#ifndef NO_BIO
 int wolfSSL_ASN1_TIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_TIME* asnTime)
 {
@@ -23609,5 +26489,5 @@
                 sizeof(buf)) == NULL) {
         XMEMSET(buf, 0, MAX_TIME_STRING_SZ);
-        XMEMCPY(buf, "Bad time value", 14);
+        XSTRNCPY(buf, "Bad time value", sizeof(buf)-1);
         ret = WOLFSSL_FAILURE;
     }
@@ -23620,4 +26500,5 @@
     return ret;
 }
+#endif /* !NO_BIO */
 
 char* wolfSSL_ASN1_TIME_to_string(WOLFSSL_ASN1_TIME* t, char* buf, int len)
@@ -23668,19 +26549,24 @@
 #endif
 
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 /* get X509_STORE_CTX ex_data, max idx is MAX_EX_DATA */
 void* wolfSSL_X509_STORE_CTX_get_ex_data(WOLFSSL_X509_STORE_CTX* ctx, int idx)
 {
     WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_get_ex_data");
-    #if defined(HAVE_EX_DATA) || defined(FORTRESS)
+#if defined(HAVE_EX_DATA) || defined(FORTRESS)
     if (ctx != NULL) {
         return wolfSSL_CRYPTO_get_ex_data(&ctx->ex_data, idx);
     }
-    #else
+#else
     (void)ctx;
     (void)idx;
-    #endif
+#endif
     return NULL;
 }
-
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#ifdef OPENSSL_EXTRA
 
 /* set X509_STORE_CTX ex_data, max idx is MAX_EX_DATA. Return WOLFSSL_SUCCESS
@@ -23690,14 +26576,14 @@
 {
     WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_set_ex_data");
-    #if defined(HAVE_EX_DATA) || defined(FORTRESS)
+#if defined(HAVE_EX_DATA) || defined(FORTRESS)
     if (ctx != NULL)
     {
         return wolfSSL_CRYPTO_set_ex_data(&ctx->ex_data, idx, data);
     }
-    #else
+#else
     (void)ctx;
     (void)idx;
     (void)data;
-    #endif
+#endif
     return WOLFSSL_FAILURE;
 }
@@ -23733,5 +26619,7 @@
 }
 
-
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 /* Gets an index to store SSL structure at.
  *
@@ -23745,6 +26633,7 @@
     return 0;
 }
-
-
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#ifdef OPENSSL_EXTRA
 /* Set an error stat in the X509 STORE CTX
  *
@@ -23799,5 +26688,8 @@
 int wolfSSL_ERR_GET_LIB(unsigned long err)
 {
-    switch (err) {
+    unsigned long value;
+
+    value = (err & 0xFFFFFFL);
+    switch (value) {
     case PEM_R_NO_START_LINE:
     case PEM_R_PROBLEMS_GETTING_PASSWORD:
@@ -24523,5 +27415,4 @@
 #endif /* OPENSSL_EXTRA */
 
-#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
 static long wolf_set_options(long old_op, long op)
 {
@@ -24546,17 +27437,17 @@
 #endif
 
-    if ((op & SSL_OP_NO_TLSv1_2) == SSL_OP_NO_TLSv1_2) {
+    if ((op & WOLFSSL_OP_NO_TLSv1_2) == WOLFSSL_OP_NO_TLSv1_2) {
         WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_2");
     }
 
-    if ((op & SSL_OP_NO_TLSv1_1) == SSL_OP_NO_TLSv1_1) {
+    if ((op & WOLFSSL_OP_NO_TLSv1_1) == WOLFSSL_OP_NO_TLSv1_1) {
         WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_1");
     }
 
-    if ((op & SSL_OP_NO_TLSv1) == SSL_OP_NO_TLSv1) {
+    if ((op & WOLFSSL_OP_NO_TLSv1) == WOLFSSL_OP_NO_TLSv1) {
         WOLFSSL_MSG("\tSSL_OP_NO_TLSv1");
     }
 
-    if ((op & SSL_OP_NO_SSLv3) == SSL_OP_NO_SSLv3) {
+    if ((op & WOLFSSL_OP_NO_SSLv3) == WOLFSSL_OP_NO_SSLv3) {
         WOLFSSL_MSG("\tSSL_OP_NO_SSLv3");
     }
@@ -24576,7 +27467,6 @@
     return old_op | op;
 }
-#endif
-
-#ifdef OPENSSL_EXTRA
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 long wolfSSL_set_options(WOLFSSL* ssl, long op)
 {
@@ -24632,8 +27522,9 @@
 #endif
 
-    InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK,
-                       ssl->options.haveDH, ssl->options.haveNTRU,
-                       ssl->options.haveECDSAsig, ssl->options.haveECC,
-                       ssl->options.haveStaticECC, ssl->options.side);
+    if (ssl->suites != NULL && ssl->options.side != WOLFSSL_NEITHER_END)
+        InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK,
+                           ssl->options.haveDH, ssl->options.haveNTRU,
+                           ssl->options.haveECDSAsig, ssl->options.haveECC,
+                           ssl->options.haveStaticECC, ssl->options.side);
 
     return ssl->options.mask;
@@ -24648,4 +27539,53 @@
     return ssl->options.mask;
 }
+
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#if defined(HAVE_SECURE_RENEGOTIATION) \
+        || defined(HAVE_SERVER_RENEGOTIATION_INFO)
+/* clears the counter for number of renegotiations done
+ * returns the current count before it is cleared */
+long wolfSSL_clear_num_renegotiations(WOLFSSL *s)
+{
+    long total;
+
+    WOLFSSL_ENTER("wolfSSL_clear_num_renegotiations");
+    if (s == NULL)
+        return 0;
+
+    total = s->secure_rene_count;
+    s->secure_rene_count = 0;
+    return total;
+}
+
+
+/* return the number of renegotiations since wolfSSL_new */
+long wolfSSL_total_renegotiations(WOLFSSL *s)
+{
+    WOLFSSL_ENTER("wolfSSL_total_renegotiations");
+    return wolfSSL_num_renegotiations(s);
+}
+
+
+/* return the number of renegotiations since wolfSSL_new */
+long wolfSSL_num_renegotiations(WOLFSSL* s)
+{
+    if (s == NULL) {
+        return 0;
+    }
+
+    return s->secure_rene_count;
+}
+
+
+/* Is there a renegotiation currently in progress? */
+int  wolfSSL_SSL_renegotiate_pending(WOLFSSL *s)
+{
+    return s && s->options.handShakeDone &&
+            s->options.handShakeState != HANDSHAKE_DONE ? 1 : 0;
+}
+#endif /* HAVE_SECURE_RENEGOTIATION || HAVE_SERVER_RENEGOTIATION_INFO */
+
+#ifdef OPENSSL_EXTRA
 
 long wolfSSL_clear_options(WOLFSSL* ssl, long opt)
@@ -24659,41 +27599,4 @@
 
 
-#if defined(HAVE_SECURE_RENEGOTIATION) \
-        || defined(HAVE_SERVER_RENEGOTIATION_INFO)
-/* clears the counter for number of renegotiations done
- * returns the current count before it is cleared */
-long wolfSSL_clear_num_renegotiations(WOLFSSL *s)
-{
-    long total;
-
-    WOLFSSL_ENTER("wolfSSL_clear_num_renegotiations");
-    if (s == NULL)
-        return 0;
-
-    total = s->secure_rene_count;
-    s->secure_rene_count = 0;
-    return total;
-}
-
-
-/* return the number of renegotiations since wolfSSL_new */
-long wolfSSL_total_renegotiations(WOLFSSL *s)
-{
-    WOLFSSL_ENTER("wolfSSL_total_renegotiations");
-    return wolfSSL_num_renegotiations(s);
-}
-
-
-/* return the number of renegotiations since wolfSSL_new */
-long wolfSSL_num_renegotiations(WOLFSSL* s)
-{
-    if (s == NULL) {
-        return 0;
-    }
-
-    return s->secure_rene_count;
-}
-#endif /* HAVE_SECURE_RENEGOTIATION || HAVE_SERVER_RENEGOTIATION_INFO */
-
 #ifndef NO_DH
 long wolfSSL_set_tmp_dh(WOLFSSL *ssl, WOLFSSL_DH *dh)
@@ -24752,7 +27655,7 @@
 
 #if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY)
-const unsigned char *SSL_SESSION_get0_id_context(const SSL_SESSION *sess, unsigned int *sid_ctx_length)
-{
-    const byte *c = wolfSSL_SESSION_get_id((SSL_SESSION *)sess, sid_ctx_length);
+const unsigned char *SSL_SESSION_get0_id_context(const WOLFSSL_SESSION *sess, unsigned int *sid_ctx_length)
+{
+    const byte *c = wolfSSL_SESSION_get_id((WOLFSSL_SESSION *)sess, sid_ctx_length);
     return c;
 }
@@ -24966,11 +27869,11 @@
     switch (type) {
         case V_ASN1_OBJECT:
-            a->value.object = value;
+            a->value.object = (WOLFSSL_ASN1_OBJECT*)value;
             break;
         case V_ASN1_UTCTIME:
-            a->value.utctime = value;
+            a->value.utctime = (WOLFSSL_ASN1_TIME*)value;
             break;
         case V_ASN1_GENERALIZEDTIME:
-            a->value.generalizedtime = value;
+            a->value.generalizedtime = (WOLFSSL_ASN1_TIME*)value;
             break;
         default:
@@ -25014,4 +27917,11 @@
                 wolfSSL_ASN1_TIME_free(at->value.generalizedtime);
                 break;
+            case V_ASN1_UTF8STRING:
+            case V_ASN1_PRINTABLESTRING:
+            case V_ASN1_T61STRING:
+            case V_ASN1_IA5STRING:
+            case V_ASN1_UNIVERSALSTRING:
+                wolfSSL_ASN1_STRING_free(at->value.asn1_string);
+                break;
             default:
                 WOLFSSL_MSG("Unknown or unsupported ASN1_TYPE");
@@ -25104,7 +28014,7 @@
         *ppkalg = pub->algor->algorithm;
     if (pk)
-        wolfSSL_EVP_PKEY_get_der(pub->pkey, (unsigned char **)pk);
+        *pk = (unsigned char*)pub->pkey->pkey.ptr;
     if (ppklen)
-        *ppklen = wolfSSL_EVP_PKEY_get_der(pub->pkey, NULL);
+        *ppklen = pub->pkey->pkey_sz;
 
     return WOLFSSL_SUCCESS;
@@ -25115,6 +28025,10 @@
 {
     WOLFSSL_ENTER("wolfSSL_X509_PUBKEY_get");
-    if(key == NULL || key->pkey == NULL){
+    if (key == NULL || key->pkey == NULL) {
         WOLFSSL_LEAVE("wolfSSL_X509_PUBKEY_get", BAD_FUNC_ARG);
+        return NULL;
+    }
+    if (wolfSSL_EVP_PKEY_up_ref(key->pkey) != WOLFSSL_SUCCESS) {
+        WOLFSSL_LEAVE("wolfSSL_X509_PUBKEY_get", BAD_MUTEX_E);
         return NULL;
     }
@@ -25203,4 +28117,126 @@
 #endif
 
+WOLFSSL_ASN1_OBJECT *wolfSSL_d2i_ASN1_OBJECT(WOLFSSL_ASN1_OBJECT **a,
+                                             const unsigned char **der,
+                                             long length)
+{
+    const unsigned char *d;
+    long len;
+    int tag, cls;
+    WOLFSSL_ASN1_OBJECT* ret = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_d2i_ASN1_OBJECT");
+
+    if (!der || !*der || length <= 0) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    d = *der;
+
+    if (wolfSSL_ASN1_get_object(&d, &len, &tag, &cls, length) & 0x80) {
+        WOLFSSL_MSG("wolfSSL_ASN1_get_object error");
+        return NULL;
+    }
+    /* d now points to value */
+
+    if (tag != ASN_OBJECT_ID) {
+        WOLFSSL_MSG("Not an ASN object");
+        return NULL;
+    }
+
+    ret = wolfSSL_c2i_ASN1_OBJECT(a, &d, len);
+    if (ret)
+        *der = d;
+    return ret;
+}
+
+/**
+ * Parse an ASN1 encoded input and output information about the parsed object
+ * @param in    ASN1 encoded data. *in is moved to the value of the ASN1 object
+ * @param len   Length of parsed ASN1 object
+ * @param tag   Tag value of parsed ASN1 object
+ * @param cls   Class of parsed ASN1 object
+ * @param inLen Length of *in buffer
+ * @return int  Depends on which bits are set in the returned int:
+ *              0x80 an error occurred during parsing
+ *              0x20 parsed object is constructed
+ *              0x01 the parsed object length is infinite
+ */
+int wolfSSL_ASN1_get_object(const unsigned char **in, long *len, int *tag,
+                            int *cls, long inLen)
+{
+    word32 inOutIdx = 0;
+    int l;
+    byte t;
+    int ret = 0x80;
+
+    WOLFSSL_ENTER("wolfSSL_ASN1_get_object");
+
+    if (!in || !*in || !len || !tag || !cls || inLen == 0) {
+        WOLFSSL_MSG("Bad parameter");
+        return ret;
+    }
+
+    if (GetASNTag(*in, &inOutIdx, &t, (word32)inLen) != 0) {
+        WOLFSSL_MSG("GetASNTag error");
+        return ret;
+    }
+
+    if (GetLength(*in, &inOutIdx, &l, (word32)inLen) < 0) {
+        WOLFSSL_MSG("GetLength error");
+        return ret;
+    }
+
+    *tag = t & 0x1F; /* Tag number is 5 lsb */
+    *cls = t & 0xC0; /* Class is 2 msb */
+    *len = l;
+    ret = t & ASN_CONSTRUCTED;
+
+    if (l > (int)(inLen - inOutIdx)) {
+        /* Still return other values but indicate error in msb */
+        ret |= 0x80;
+    }
+
+    *in += inOutIdx;
+    return ret;
+}
+
+WOLFSSL_ASN1_OBJECT *wolfSSL_c2i_ASN1_OBJECT(WOLFSSL_ASN1_OBJECT **a,
+        const unsigned char **pp, long len)
+{
+    WOLFSSL_ASN1_OBJECT* ret = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_c2i_ASN1_OBJECT");
+
+    if (!pp || !*pp || len <= 0) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    if (!(ret = wolfSSL_ASN1_OBJECT_new())) {
+        WOLFSSL_MSG("wolfSSL_ASN1_OBJECT_new error");
+        return NULL;
+    }
+
+    ret->obj = (const unsigned char*)XMALLOC(len, NULL, DYNAMIC_TYPE_ASN1);
+    if (!ret->obj) {
+        WOLFSSL_MSG("error allocating asn data memory");
+        wolfSSL_ASN1_OBJECT_free(ret);
+        return NULL;
+    }
+
+    XMEMCPY((byte*)ret->obj, *pp, len);
+    ret->objSz = (unsigned int)len;
+    ret->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA;
+
+    *pp += len;
+
+    if (a)
+        *a = ret;
+    return ret;
+}
+
+#ifndef NO_BIO
 /* Return number of bytes written to BIO on success. 0 on failure. */
 WOLFSSL_API int wolfSSL_i2a_ASN1_OBJECT(WOLFSSL_BIO *bp,
@@ -25244,29 +28280,76 @@
     return WOLFSSL_FAILURE;
 }
+#endif /* !NO_BIO */
+
+/* Returns object data for an ASN1_OBJECT */
+/* If pp is NULL then only the size is returned */
+/* If pp has pointer to pointer then its used directly */
+/* If pp has pointer to pointer that is NULL then new variable is allocated */
+/* Failure returns WOLFSSL_FAILURE (0) */
+int wolfSSL_i2d_ASN1_OBJECT(WOLFSSL_ASN1_OBJECT *a, unsigned char **pp)
+{
+    byte *p;
+
+    WOLFSSL_ENTER("wolfSSL_i2d_ASN1_OBJECT");
+
+    if (!a || !a->obj) {
+        WOLFSSL_MSG("Bad parameters");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (!pp)
+        return a->objSz;
+
+    if (*pp)
+        p = *pp;
+    else {
+        p = (byte*)XMALLOC(a->objSz, NULL, DYNAMIC_TYPE_OPENSSL);
+        if (!p) {
+            WOLFSSL_MSG("Bad malloc");
+            return WOLFSSL_FAILURE;
+        }
+    }
+
+    XMEMCPY(p, a->obj, a->objSz);
+    *pp = p + a->objSz;
+    return a->objSz;
+}
 
 #if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY)
-#ifndef NO_WOLFSSL_STUB
-/*** TBD ***/
-WOLFSSL_API size_t SSL_get_finished(const WOLFSSL *s, void *buf, size_t count)
-{
-    (void)s;
-    (void)buf;
-    (void)count;
-    WOLFSSL_STUB("SSL_get_finished");
-    return WOLFSSL_FAILURE;
-}
-#endif
-
-#ifndef NO_WOLFSSL_STUB
-/*** TBD ***/
-WOLFSSL_API size_t SSL_get_peer_finished(const WOLFSSL *s, void *buf, size_t count)
-{
-    (void)s;
-    (void)buf;
-    (void)count;
-    WOLFSSL_STUB("SSL_get_peer_finished");
-    return WOLFSSL_FAILURE;
-}
-#endif
+WOLFSSL_API size_t wolfSSL_get_finished(const WOLFSSL *ssl, void *buf, size_t count)
+{
+    WOLFSSL_ENTER("SSL_get_finished");
+
+    if (!ssl || !buf || count < TLS_FINISHED_SZ) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (ssl->options.side == WOLFSSL_SERVER_END)
+        XMEMCPY(buf, ssl->serverFinished,
+                TLS_FINISHED_SZ);
+    else
+        XMEMCPY(buf, ssl->clientFinished,
+                TLS_FINISHED_SZ);
+    return TLS_FINISHED_SZ;
+}
+
+WOLFSSL_API size_t wolfSSL_get_peer_finished(const WOLFSSL *ssl, void *buf, size_t count)
+{
+    WOLFSSL_ENTER("SSL_get_peer_finished");
+
+    if (!ssl || !buf || count < TLS_FINISHED_SZ) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (ssl->options.side == WOLFSSL_CLIENT_END)
+        XMEMCPY(buf, ssl->serverFinished,
+                TLS_FINISHED_SZ);
+    else
+        XMEMCPY(buf, ssl->clientFinished,
+                TLS_FINISHED_SZ);
+    return TLS_FINISHED_SZ;
+}
 #endif /* WOLFSSL_HAPROXY */
 
@@ -25375,4 +28458,5 @@
             if (readCtx == NULL) {
                 WOLFSSL_MSG("Memory error");
+                wolfSSL_CTX_free(ctx);
                 return WOLFSSL_FAILURE;
             }
@@ -25417,14 +28501,9 @@
 #endif /* !NO_FILESYSTEM && !NO_WOLFSSL_DIR */
 
-#ifndef NO_WOLFSSL_STUB
-/*** TBD ***/
-WOLFSSL_API WOLFSSL_CIPHER* wolfSSL_sk_SSL_CIPHER_value(void *ciphers, int idx)
-{
-    (void)ciphers;
-    (void)idx;
-    WOLFSSL_STUB("wolfSSL_sk_SSL_CIPHER_value");
-    return NULL;
-}
-#endif
+WOLFSSL_API WOLFSSL_CIPHER* wolfSSL_sk_SSL_CIPHER_value(WOLFSSL_STACK* sk, int i)
+{
+    WOLFSSL_ENTER("wolfSSL_sk_SSL_CIPHER_value");
+    return (WOLFSSL_CIPHER*)wolfSSL_sk_value(sk, i);
+}
 
 WOLFSSL_API void ERR_load_SSL_strings(void)
@@ -25594,5 +28673,5 @@
 
 #ifdef WOLFSSL_SESSION_STATS
-    if (wolfSSL_get_session_stats(NULL, &total, NULL, NULL) != SSL_SUCCESS) {
+    if (wolfSSL_get_session_stats(NULL, &total, NULL, NULL) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("Error getting session stats");
     }
@@ -25672,5 +28751,5 @@
         }
         c32to24(derSz, chain + idx);
-        idx += OPAQUE24_LEN,
+        idx += OPAQUE24_LEN;
         XMEMCPY(chain + idx, der, derSz);
         idx += derSz;
@@ -26308,4 +29387,6 @@
 #endif
 
+#ifndef NO_BIO
+
 #if !defined(NO_FILESYSTEM) && defined (OPENSSL_EXTRA)
 /* returns amount printed on success, negative in fail case */
@@ -26323,9 +29404,12 @@
                 return -1;
             }
-            ret = vfprintf((XFILE)bio->ptr, format, args);
+            ret = XVFPRINTF((XFILE)bio->ptr, format, args);
             break;
 
         case WOLFSSL_BIO_MEMORY:
-    #if defined(OPENSSL_EXTRA) && !defined(_WIN32)
+    /* In Visual Studio versions prior to Visual Studio 2013, the va_* symbols
+       aren't defined. If using Visual Studio 2013 or later, define
+       HAVE_VA_COPY. */
+    #if defined(OPENSSL_EXTRA) && (!defined(_WIN32) || defined(HAVE_VA_COPY))
         case WOLFSSL_BIO_SSL:
             {
@@ -26334,6 +29418,11 @@
                 va_list copy;
 
-                va_copy(copy, args);
-                count = vsnprintf(NULL, 0, format, args);
+                #ifdef FUSION_RTOS
+                   copy = args;    /* hack, depends on internal implementation
+                                    * of va_list in VisualDSP++ */
+                #else
+                    va_copy(copy, args);
+                #endif
+                count = XVSNPRINTF(NULL, 0, format, args);
                 if (count >= 0)
                 {
@@ -26342,5 +29431,5 @@
                     if (pt != NULL)
                     {
-                        count = vsnprintf(pt, count + 1, format, copy);
+                        count = XVSNPRINTF(pt, count + 1, format, copy);
                         if (count >= 0)
                         {
@@ -26377,5 +29466,5 @@
 }
 
-#endif /* !defined(NO_FILESYSTEM) && defined (OPENSSL_EXTRA) */
+#endif /* !NO_FILESYSTEM && OPENSSL_EXTRA */
 
 #if !defined(NO_FILESYSTEM) && defined(__clang__)
@@ -26398,22 +29487,22 @@
 
         if (!buf) {
-            return fputs("\tNULL", (XFILE)bio->ptr);
-        }
-
-        sprintf(line, "\t");
+            return XFPUTS("\tNULL", (XFILE)bio->ptr);
+        }
+
+        XSPRINTF(line, "\t");
         for (i = 0; i < LINE_LEN; i++) {
             if (i < length)
-                sprintf(line + 1 + i * 3,"%02x ", buf[i]);
+                XSPRINTF(line + 1 + i * 3,"%02x ", buf[i]);
             else
-                sprintf(line + 1 + i * 3, "   ");
-        }
-        sprintf(line + 1 + LINE_LEN * 3, "| ");
+                XSPRINTF(line + 1 + i * 3, "   ");
+        }
+        XSPRINTF(line + 1 + LINE_LEN * 3, "| ");
         for (i = 0; i < LINE_LEN; i++) {
             if (i < length) {
-                sprintf(line + 3 + LINE_LEN * 3 + i,
+                XSPRINTF(line + 3 + LINE_LEN * 3 + i,
                      "%c", 31 < buf[i] && buf[i] < 127 ? buf[i] : '.');
             }
         }
-        ret += fputs(line, (XFILE)bio->ptr);
+        ret += XFPUTS(line, (XFILE)bio->ptr);
 
         if (length > LINE_LEN)
@@ -26442,4 +29531,6 @@
     return wolfSSL_ASN1_TIME_print(bio, a);
 }
+
+#endif /* !NO_BIO */
 
 /* Checks the ASN1 syntax of "a"
@@ -26472,5 +29563,5 @@
 }
 
-WOLFSSL_API WOLFSSL_ASN1_TIME *wolfSSL_ASN1_TIME_set(WOLFSSL_ASN1_TIME *s, time_t t)
+WOLFSSL_ASN1_TIME *wolfSSL_ASN1_TIME_set(WOLFSSL_ASN1_TIME *s, time_t t)
 {
     WOLFSSL_STUB("wolfSSL_ASN1_TIME_set");
@@ -26479,5 +29570,29 @@
     return s;
 }
+
+int wolfSSL_ASN1_TIME_set_string(WOLFSSL_ASN1_TIME *s, const char *str)
+{
+    int slen;
+    WOLFSSL_ENTER("wolfSSL_ASN1_TIME_set_string");
+
+    if (!str) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+    slen = (int)XSTRLEN(str)+1;
+    if (slen > CTC_DATE_SIZE) {
+        WOLFSSL_MSG("Date string too long");
+        return WOLFSSL_FAILURE;
+    }
+    if (s) {
+        XMEMCPY(s->data, str, slen);
+        s->length = slen;
+        s->type = slen == ASN_UTC_TIME_SIZE ? ASN_UTC_TIME : ASN_GENERALIZED_TIME;
+    }
+    return WOLFSSL_SUCCESS;
+}
 #endif /* !NO_WOLFSSL_STUB */
+
+#ifndef NO_BIO
 
 /* Return the month as a string.
@@ -26527,4 +29642,5 @@
     return 0;
 }
+#endif /* !NO_BIO */
 
 void wolfSSL_ASN1_GENERALIZEDTIME_free(WOLFSSL_ASN1_TIME* asn1Time)
@@ -26536,5 +29652,8 @@
 }
 
-int wolfSSL_sk_num(WOLFSSL_STACK* sk)
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
+int wolfSSL_sk_num(const WOLFSSL_STACK* sk)
 {
     WOLFSSL_ENTER("wolfSSL_sk_num");
@@ -26544,9 +29663,6 @@
 }
 
-void* wolfSSL_sk_value(WOLFSSL_STACK* sk, int i)
-{
-#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
-    int offset = i;
-#endif
+void* wolfSSL_sk_value(const WOLFSSL_STACK* sk, int i)
+{
     WOLFSSL_ENTER("wolfSSL_sk_value");
 
@@ -26560,7 +29676,4 @@
             return (void*)sk->data.x509;
         case STACK_TYPE_CIPHER:
-        #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
-            sk->data.cipher.offset = offset;
-        #endif
             return (void*)&sk->data.cipher;
         case STACK_TYPE_GEN_NAME:
@@ -26572,10 +29685,98 @@
         case STACK_TYPE_X509_EXT:
             return (void*)sk->data.ext;
+    #ifdef OPENSSL_EXTRA
         case STACK_TYPE_CONF_VALUE:
-            return (void*)sk->data.conf->value;
+            return (void*)sk->data.conf;
+    #endif
         case STACK_TYPE_NULL:
         default:
             return (void*)sk->data.generic;
     }
+}
+
+/* copies over data of "in" to "out" */
+static void wolfSSL_CIPHER_copy(WOLFSSL_CIPHER* in, WOLFSSL_CIPHER* out)
+{
+    if (in == NULL || out == NULL)
+        return;
+
+    *out = *in;
+}
+
+WOLFSSL_STACK* wolfSSL_sk_dup(WOLFSSL_STACK* sk)
+{
+
+    WOLFSSL_STACK* ret = NULL;
+    WOLFSSL_STACK* last = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_sk_dup");
+
+    while (sk) {
+        WOLFSSL_STACK* cur = wolfSSL_sk_new_node(sk->heap);
+
+        if (!cur) {
+            WOLFSSL_MSG("wolfSSL_sk_new_node error");
+            goto error;
+        }
+
+        if (!ret) {
+            /* Set first node */
+            ret = cur;
+        }
+
+        if (last) {
+            last->next = cur;
+        }
+
+        XMEMCPY(cur, sk, sizeof(WOLFSSL_STACK));
+
+        /* We will allocate new memory for this */
+        XMEMSET(&cur->data, 0, sizeof(cur->data));
+        cur->next = NULL;
+
+        switch (sk->type) {
+            case STACK_TYPE_X509:
+                cur->data.x509 = wolfSSL_X509_dup(sk->data.x509);
+                if (!cur->data.x509) {
+                    WOLFSSL_MSG("wolfSSL_X509_dup error");
+                    goto error;
+                }
+                break;
+            case STACK_TYPE_CIPHER:
+                wolfSSL_CIPHER_copy(&sk->data.cipher, &cur->data.cipher);
+                break;
+            case STACK_TYPE_GEN_NAME:
+                cur->data.gn = wolfSSL_GENERAL_NAME_dup(sk->data.gn);
+                if (!cur->data.gn) {
+                    WOLFSSL_MSG("wolfSSL_GENERAL_NAME_new error");
+                    goto error;
+                }
+                break;
+            case STACK_TYPE_OBJ:
+                cur->data.obj = wolfSSL_ASN1_OBJECT_dup(sk->data.obj);
+                if (!cur->data.obj) {
+                    WOLFSSL_MSG("wolfSSL_ASN1_OBJECT_dup error");
+                    goto error;
+                }
+                break;
+            case STACK_TYPE_ACCESS_DESCRIPTION:
+            case STACK_TYPE_X509_EXT:
+            case STACK_TYPE_CONF_VALUE:
+            case STACK_TYPE_NULL:
+            default:
+                WOLFSSL_MSG("Unsupported stack type");
+                goto error;
+        }
+
+        sk = sk->next;
+        last = cur;
+    }
+    return ret;
+
+error:
+    if (ret) {
+        wolfSSL_sk_GENERAL_NAME_free(ret);
+    }
+    return NULL;
 }
 
@@ -26610,4 +29811,10 @@
             wolfSSL_sk_ASN1_OBJECT_free(sk);
             break;
+        #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \
+            defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)
+        case STACK_TYPE_STRING:
+            wolfSSL_sk_WOLFSSL_STRING_free(sk);
+            break;
+        #endif
         #ifdef OPENSSL_ALL
         case STACK_TYPE_X509_INFO:
@@ -26626,4 +29833,5 @@
     }
 }
+
 /* Frees each node in the stack and frees the stack.
  * Does not free any internal members of the stack nodes.
@@ -26657,36 +29865,7 @@
 int wolfSSL_sk_GENERIC_push(WOLFSSL_STACK* sk, void* generic)
 {
-    WOLFSSL_STACK* node;
-
     WOLFSSL_ENTER("wolfSSL_sk_GENERIC_push");
 
-    if (sk == NULL || generic == NULL) {
-        return WOLFSSL_FAILURE;
-    }
-
-    /* no previous values in stack */
-    if (sk->data.generic == NULL) {
-        sk->data.generic = generic;
-        sk->num += 1;
-        return WOLFSSL_SUCCESS;
-    }
-
-    /* stack already has value(s) create a new node and add more */
-    node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK),NULL,DYNAMIC_TYPE_SSL);
-    if (node == NULL) {
-        WOLFSSL_MSG("Memory error");
-        return WOLFSSL_FAILURE;
-    }
-    XMEMSET(node, 0, sizeof(WOLFSSL_STACK));
-
-    /* push new node onto head of stack */
-    node->type         = sk->type;
-    node->data.generic = sk->data.generic;
-    node->next         = sk->next;
-    sk->next           = node;
-    sk->data.generic   = generic;
-    sk->num           += 1;
-
-    return WOLFSSL_SUCCESS;
+    return wolfSSL_sk_push(sk, generic);
 }
 void wolfSSL_sk_GENERIC_free(WOLFSSL_STACK* sk)
@@ -26694,5 +29873,7 @@
     wolfSSL_sk_GENERIC_pop_free(sk, NULL);
 }
-
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#ifdef OPENSSL_EXTRA
 
 /* Free all nodes in a stack */
@@ -26747,32 +29928,7 @@
     }
 }
-
-#if defined(OPENSSL_ALL)
-/* Free the structure for WOLFSSL_CONF_VALUE stack
- *
- * sk  stack to free nodes in
- */
-void wolfSSL_sk_CONF_VALUE_free(WOLF_STACK_OF(WOLFSSL_CONF_VALUE)* sk)
-{
-    WOLFSSL_STACK* node;
-    WOLFSSL_STACK* tmp;
-    WOLFSSL_ENTER("wolfSSL_sk_CONF_VALUE_free");
-
-    if (sk == NULL)
-        return;
-
-    /* parse through stack freeing each node */
-    node = sk->next;
-    while (node) {
-        tmp  = node;
-        node = node->next;
-        XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL);
-    }
-
-    /* free head of stack */
-    XFREE(sk, NULL, DYNAMIC_TYPE_ASN1);
-}
-#endif
-
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
 /* Creates and returns a new null stack. */
 WOLFSSL_STACK* wolfSSL_sk_new_null(void)
@@ -26794,4 +29950,18 @@
 }
 
+WOLFSSL_BASIC_CONSTRAINTS* wolfSSL_BASIC_CONSTRAINTS_new(void)
+{
+    WOLFSSL_BASIC_CONSTRAINTS* bc;
+    bc = (WOLFSSL_BASIC_CONSTRAINTS*)
+          XMALLOC(sizeof(WOLFSSL_BASIC_CONSTRAINTS), NULL,
+          DYNAMIC_TYPE_X509_EXT);
+    if (bc == NULL) {
+        WOLFSSL_MSG("Failed to malloc basic constraints");
+        return NULL;
+    }
+    XMEMSET(bc, 0, sizeof(WOLFSSL_BASIC_CONSTRAINTS));
+    return bc;
+}
+
 /* frees the wolfSSL_BASIC_CONSTRAINTS object */
 void wolfSSL_BASIC_CONSTRAINTS_free(WOLFSSL_BASIC_CONSTRAINTS *bc)
@@ -26808,4 +29978,16 @@
 }
 
+WOLFSSL_AUTHORITY_KEYID* wolfSSL_AUTHORITY_KEYID_new(void)
+{
+    WOLFSSL_AUTHORITY_KEYID* akey = (WOLFSSL_AUTHORITY_KEYID*)XMALLOC(
+          sizeof(WOLFSSL_AUTHORITY_KEYID), NULL, DYNAMIC_TYPE_OPENSSL);
+    if (!akey) {
+        WOLFSSL_MSG("Issue creating WOLFSSL_AUTHORITY_KEYID struct");
+        return NULL;
+    }
+    XMEMSET(akey, 0, sizeof(WOLFSSL_AUTHORITY_KEYID));
+    return akey;
+}
+
 /* frees the wolfSSL_AUTHORITY_KEYID object */
 void wolfSSL_AUTHORITY_KEYID_free(WOLFSSL_AUTHORITY_KEYID *id)
@@ -26835,7 +30017,8 @@
 }
 
-#endif /* OPENSSL_EXTRA */
-
-#if defined(OPENSSL_EXTRA) || defined(HAVE_EXT_CACHE)
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#if !defined(NO_SESSION_CACHE) && (defined(OPENSSL_EXTRA) || \
+        defined(HAVE_EXT_CACHE))
 /* stunnel 4.28 needs
  *
@@ -26881,7 +30064,5 @@
 #endif
 }
-#endif /* OPENSSL_EXTRA || HAVE_EXT_CACHE */
-
-#ifdef OPENSSL_EXTRA
+
 
 /*
@@ -26906,7 +30087,8 @@
     }
 
-    /* bornOn | timeout | sessionID len | sessionID | masterSecret | haveEMS */
-    size += OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN + sess->sessionIDSz +
-            SECRET_LEN + OPAQUE8_LEN;
+    /* side | bornOn | timeout | sessionID len | sessionID | masterSecret |
+     * haveEMS  */
+    size += OPAQUE8_LEN + OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN +
+            sess->sessionIDSz + SECRET_LEN + OPAQUE8_LEN;
 #ifdef SESSION_CERTS
     /* Peer chain */
@@ -26941,8 +30123,6 @@
     /* ticketSeen | ticketAdd */
     size += OPAQUE32_LEN + OPAQUE32_LEN;
-#ifndef WOLFSSL_TLS13_DRAFT_18
     /* ticketNonce */
     size += OPAQUE8_LEN + sess->ticketNonce.len;
-#endif
 #endif
 #ifdef WOLFSSL_EARLY_DATA
@@ -26962,4 +30142,5 @@
         data = *p;
 
+        data[idx++] = sess->side;
         c32toa(sess->bornOn, data + idx); idx += OPAQUE32_LEN;
         c32toa(sess->timeout, data + idx); idx += OPAQUE32_LEN;
@@ -27009,9 +30190,7 @@
     c32toa(sess->ticketAdd, data + idx);
     idx += OPAQUE32_LEN;
-#ifndef WOLFSSL_TLS13_DRAFT_18
     data[idx++] = sess->ticketNonce.len;
     XMEMCPY(data + idx, sess->ticketNonce.data, sess->ticketNonce.len);
     idx += sess->ticketNonce.len;
-#endif
 #endif
 #ifdef WOLFSSL_EARLY_DATA
@@ -27071,10 +30250,7 @@
 
     if (s == NULL) {
-        s = (WOLFSSL_SESSION*)XMALLOC(sizeof(WOLFSSL_SESSION), NULL,
-                                      DYNAMIC_TYPE_OPENSSL);
+        s = wolfSSL_SESSION_new();
         if (s == NULL)
             return NULL;
-        XMEMSET(s, 0, sizeof(WOLFSSL_SESSION));
-        s->isAlloced = 1;
 #ifdef HAVE_SESSION_TICKET
         s->isDynamic = 0;
@@ -27085,9 +30261,10 @@
     data = (byte*)*p;
 
-    /* bornOn | timeout | sessionID len */
-    if (i < OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN) {
+    /* side | bornOn | timeout | sessionID len */
+    if (i < OPAQUE8_LEN + OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN) {
         ret = BUFFER_ERROR;
         goto end;
     }
+    s->side = data[idx++];
     ato32(data + idx, &s->bornOn); idx += OPAQUE32_LEN;
     ato32(data + idx, &s->timeout); idx += OPAQUE32_LEN;
@@ -27194,5 +30371,4 @@
     ato32(data + idx, &s->ticketAdd);
     idx += OPAQUE32_LEN;
-#ifndef WOLFSSL_TLS13_DRAFT_18
     if (i - idx < OPAQUE8_LEN) {
         ret = BUFFER_ERROR;
@@ -27207,5 +30383,4 @@
     XMEMCPY(s->ticketNonce.data, data + idx, s->ticketNonce.len);
     idx += s->ticketNonce.len;
-#endif
 #endif
 #ifdef WOLFSSL_EARLY_DATA
@@ -27256,10 +30431,11 @@
 
 end:
-    if (ret != 0 && (sess == NULL || *sess != s))
+    if (ret != 0 && (sess == NULL || *sess != s)) {
         wolfSSL_SESSION_free(s);
+        s = NULL;
+    }
 #endif
     return s;
 }
-
 
 long wolfSSL_SESSION_get_timeout(const WOLFSSL_SESSION* sess)
@@ -27282,6 +30458,18 @@
 }
 
-
-#endif /* OPENSSL_EXTRA */
+long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION* ses, long t)
+{
+    word32 tmptime;
+    if (!ses || t < 0)
+        return BAD_FUNC_ARG;
+
+    tmptime = t & 0xFFFFFFFF;
+
+    ses->timeout = tmptime;
+
+    return WOLFSSL_SUCCESS;
+}
+
+#endif /* !NO_SESSION_CACHE && OPENSSL_EXTRA || HAVE_EXT_CACHE */
 
 
@@ -27367,5 +30555,4 @@
 #endif
 #endif /* OPENSSL_EXTRA */
-#endif /* !WOLFCRYPT_ONLY */
 #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
 const WOLFSSL_ObjectInfo wolfssl_object_info[] = {
@@ -27441,4 +30628,8 @@
     { NID_jurisdictionStateOrProvinceName, NID_jurisdictionStateOrProvinceName,
             oidCertNameType, "jurisdictionST", "jurisdictionStateOrProvinceName"},
+#ifdef WOLFSSL_CERT_REQ
+    { NID_pkcs9_challengePassword, CHALLENGE_PASSWORD_OID,
+            oidCsrAttrType, "challengePassword", "challengePassword"},
+#endif
 #endif
 #ifdef OPENSSL_EXTRA /* OPENSSL_EXTRA_X509_SMALL only needs the above */
@@ -27470,4 +30661,6 @@
         #ifndef NO_SHA
         { CTC_SHAwDSA, CTC_SHAwDSA, oidSigType, "DSA-SHA1", "dsaWithSHA1"},
+        { CTC_SHA256wDSA, CTC_SHA256wDSA, oidSigType, "dsa_with_SHA256",
+                                                        "dsa_with_SHA256"},
         #endif
     #endif /* NO_DSA */
@@ -27540,4 +30733,10 @@
         { NID_dhKeyAgreement, DHk, oidKeyType, "dhKeyAgreement", "dhKeyAgreement"},
     #endif
+    #ifdef HAVE_ED448
+        { NID_ED448, ED448k,  oidKeyType, "ED448", "ED448"},
+    #endif
+    #ifdef HAVE_ED25519
+        { NID_ED25519, ED25519k,  oidKeyType, "ED25519", "ED25519"},
+    #endif
 
         /* oidCurveType */
@@ -27676,9 +30875,4 @@
 const size_t wolfssl_object_info_sz = WOLFSSL_OBJECT_INFO_SZ;
 #endif
-#if defined(OPENSSL_EXTRA) || \
-    (defined(OPENSSL_EXTRA_X509_SMALL) && !defined(NO_RSA))
-static WC_RNG globalRNG;
-static int initGlobalRNG = 0;
-#endif
 #if defined(OPENSSL_EXTRA) && \
     !defined(NO_RSA) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA)
@@ -27728,18 +30922,21 @@
 }
 #endif
-#ifndef WOLFCRYPT_ONLY
 
 #ifdef OPENSSL_EXTRA
 
-/* Not thread safe! Can be called multiple times.
- * Checks if the global RNG has been created. If not then one is created.
+/* Checks if the global RNG has been created. If not then one is created.
  *
- * Returns SSL_SUCCESS when no error is encountered.
+ * Returns WOLFSSL_SUCCESS when no error is encountered.
  */
 static int wolfSSL_RAND_Init(void)
 {
+    if (wc_LockMutex(&globalRNGMutex) != 0) {
+        WOLFSSL_MSG("Bad Lock Mutex rng");
+        return 0;
+    }
     if (initGlobalRNG == 0) {
         if (wc_InitRng(&globalRNG) < 0) {
             WOLFSSL_MSG("wolfSSL Init Global RNG failed");
+            wc_UnLockMutex(&globalRNGMutex);
             return 0;
         }
@@ -27747,9 +30944,10 @@
     }
 
-    return SSL_SUCCESS;
-}
-
-
-/* SSL_SUCCESS on ok */
+    wc_UnLockMutex(&globalRNGMutex);
+    return WOLFSSL_SUCCESS;
+}
+
+
+/* WOLFSSL_SUCCESS on ok */
 int wolfSSL_RAND_seed(const void* seed, int len)
 {
@@ -27860,5 +31058,5 @@
         bytes = 1024; /* default size of buf */
 
-        if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != SSL_SUCCESS) {
+        if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) {
             WOLFSSL_MSG("No RNG to use");
         #ifdef WOLFSSL_SMALL_STACK
@@ -27904,5 +31102,4 @@
 
 /* This collects entropy from the path nm and seeds the global PRNG with it.
- * Makes a call to wolfSSL_RAND_Init which is not thread safe.
  *
  * nm is the file path to the egd server
@@ -28017,6 +31214,10 @@
 
     if (bytes > 0 && ret == WOLFSSL_SUCCESS) {
-        wolfSSL_RAND_Init(); /* call to check global RNG is created */
-        if (wc_RNG_DRBG_Reseed(&globalRNG, (const byte*) buf, bytes)
+        /* call to check global RNG is created */
+        if (wolfSSL_RAND_Init() != SSL_SUCCESS) {
+            WOLFSSL_MSG("Error with initializing global RNG structure");
+            ret = WOLFSSL_FATAL_ERROR;
+        }
+        else if (wc_RNG_DRBG_Reseed(&globalRNG, (const byte*) buf, bytes)
                 != 0) {
             WOLFSSL_MSG("Error with reseeding DRBG structure");
@@ -28024,5 +31225,5 @@
         }
         #ifdef SHOW_SECRETS
-        { /* print out entropy found */
+        else { /* print out entropy found only when no error occured */
             word32 i;
             printf("EGD Entropy = ");
@@ -28062,8 +31263,13 @@
     WOLFSSL_ENTER("wolfSSL_RAND_Cleanup()");
 
+    if (wc_LockMutex(&globalRNGMutex) != 0) {
+        WOLFSSL_MSG("Bad Lock Mutex rng");
+        return;
+    }
     if (initGlobalRNG != 0) {
         wc_FreeRng(&globalRNG);
         initGlobalRNG = 0;
     }
+    wc_UnLockMutex(&globalRNGMutex);
 }
 
@@ -28075,5 +31281,5 @@
 
 
-/* SSL_SUCCESS on ok */
+/* WOLFSSL_SUCCESS on ok */
 int wolfSSL_RAND_bytes(unsigned char* buf, int num)
 {
@@ -28086,4 +31292,6 @@
     WC_RNG  tmpRNG[1];
 #endif
+    int used_global = 0;
+    int blockCount = 0;
 
     WOLFSSL_ENTER("wolfSSL_RAND_bytes");
@@ -28095,6 +31303,13 @@
 #endif
 
-    if (initGlobalRNG)
+    if (initGlobalRNG) {
+        if (wc_LockMutex(&globalRNGMutex) != 0) {
+            WOLFSSL_MSG("Bad Lock Mutex rng");
+            return ret;
+        }
+
         rng = &globalRNG;
+        used_global = 1;
+    }
     else if(wc_InitRng(tmpRNG) == 0) {
         rng = tmpRNG;
@@ -28102,8 +31317,27 @@
     }
     if (rng) {
-        if (wc_RNG_GenerateBlock(rng, buf, num) != 0)
+        /* handles size grater than RNG_MAX_BLOCK_LEN */
+        blockCount = num / RNG_MAX_BLOCK_LEN;
+        
+        while(blockCount--) {
+            if((ret = wc_RNG_GenerateBlock(rng, buf, RNG_MAX_BLOCK_LEN) != 0)){
+                WOLFSSL_MSG("Bad wc_RNG_GenerateBlock");
+                break;
+            }
+            num -= RNG_MAX_BLOCK_LEN;
+            buf += RNG_MAX_BLOCK_LEN;
+        }
+        
+        if (ret == 0 && num)
+            ret = wc_RNG_GenerateBlock(rng, buf, num);
+        
+        if (ret != 0)
             WOLFSSL_MSG("Bad wc_RNG_GenerateBlock");
         else
             ret = WOLFSSL_SUCCESS;
+    }
+
+    if (used_global == 1) {
+        wc_UnLockMutex(&globalRNGMutex);
     }
 
@@ -28149,4 +31383,7 @@
     WOLFSSL_ASN1_INTEGER* a;
     int len;
+    const int extraTagSz = MAX_LENGTH_SZ + 1;
+    byte intTag[MAX_LENGTH_SZ + 1];
+    int idx = 0;
     WOLFSSL_ENTER("wolfSSL_BN_to_ASN1_INTEGER");
 
@@ -28173,7 +31410,8 @@
 
         /* allocate buffer */
-        if (len > (int)sizeof(a->intData)) {
+        if (len + extraTagSz > (int)sizeof(a->intData)) {
             /* create new data buffer and copy over */
-            a->data = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL);
+            a->data = (byte*)XMALLOC(len + extraTagSz, NULL,
+                    DYNAMIC_TYPE_OPENSSL);
             if (a->data == NULL) {
                 if (a != ai)
@@ -28187,5 +31425,4 @@
             a->data = a->intData;
         }
-        a->length = len;
 
         /* populate data */
@@ -28197,4 +31434,10 @@
         }
         a->length = len;
+
+        /* Write ASN tag */
+        idx = SetASNInt(a->length, a->data[0], intTag);
+        XMEMMOVE(a->data + idx, a->data, a->length);
+        XMEMCPY(a->data, intTag, idx);
+        a->dataMax = a->length += idx;
     }
 
@@ -28203,5 +31446,5 @@
 
 #ifdef OPENSSL_ALL
-void *wolfSSL_ASN1_item_new(const WOLFSSL_ASN1_ITEM *template)
+void *wolfSSL_ASN1_item_new(const WOLFSSL_ASN1_ITEM *tpl)
 {
     void *ret = NULL;
@@ -28209,12 +31452,12 @@
     size_t i;
     WOLFSSL_ENTER("wolfSSL_ASN1_item_new");
-    if (!template) {
+    if (!tpl) {
         return NULL;
     }
-    if (!(ret = XMALLOC(template->size, NULL, DYNAMIC_TYPE_OPENSSL))) {
+    if (!(ret = (void *)XMALLOC(tpl->size, NULL, DYNAMIC_TYPE_OPENSSL))) {
         return NULL;
     }
-    XMEMSET(ret, 0, template->size);
-    for (member = template->members, i = 0; i < template->mcount;
+    XMEMSET(ret, 0, tpl->size);
+    for (member = tpl->members, i = 0; i < tpl->mcount;
             member++, i++) {
         switch (member->type) {
@@ -28244,9 +31487,9 @@
     return ret;
 error:
-    wolfSSL_ASN1_item_free(ret, template);
+    wolfSSL_ASN1_item_free(ret, tpl);
     return NULL;
 }
 
-void wolfSSL_ASN1_item_free(void *val, const WOLFSSL_ASN1_ITEM *template)
+void wolfSSL_ASN1_item_free(void *val, const WOLFSSL_ASN1_ITEM *tpl)
 {
     const WOLFSSL_ASN1_TEMPLATE *member = NULL;
@@ -28254,5 +31497,5 @@
     WOLFSSL_ENTER("wolfSSL_ASN1_item_free");
     if (val) {
-        for (member = template->members, i = 0; i < template->mcount;
+        for (member = tpl->members, i = 0; i < tpl->mcount;
                 member++, i++) {
             switch (member->type) {
@@ -28342,5 +31585,5 @@
 
 int wolfSSL_ASN1_item_i2d(const void *src, byte **dest,
-                          const WOLFSSL_ASN1_ITEM *template)
+                          const WOLFSSL_ASN1_ITEM *tpl)
 {
     int len = 0;
@@ -28349,5 +31592,5 @@
     WOLFSSL_ENTER("wolfSSL_ASN1_item_i2d");
 
-    if (!src || !template) {
+    if (!src || !tpl) {
         WOLFSSL_LEAVE("wolfSSL_ASN1_item_i2d", WOLFSSL_FAILURE);
         return WOLFSSL_FAILURE;
@@ -28355,5 +31598,5 @@
 
     if (dest && !*dest) {
-        len = wolfSSL_ASN1_item_i2d(src, NULL, template);
+        len = wolfSSL_ASN1_item_i2d(src, NULL, tpl);
         if (!len) {
             goto error;
@@ -28366,9 +31609,9 @@
     }
 
-    switch (template->type) {
+    switch (tpl->type) {
         case ASN_SEQUENCE:
         {
-            int seq_len = i2dProcessMembers(src, NULL, template->members,
-                                         template->mcount);
+            int seq_len = i2dProcessMembers(src, NULL, tpl->members,
+                                         tpl->mcount);
             if (!seq_len) {
                 goto error;
@@ -28376,6 +31619,6 @@
             len += SetSequence(seq_len, bufLenOrNull(buf, len));
             if (buf &&
-                    i2dProcessMembers(src, bufLenOrNull(buf, len), template->members,
-                                   template->mcount) != seq_len) {
+                    i2dProcessMembers(src, bufLenOrNull(buf, len), tpl->members,
+                                   tpl->mcount) != seq_len) {
                 WOLFSSL_MSG("Inconsistent sequence length");
                 goto error;
@@ -28424,5 +31667,5 @@
     DhKey*     key;
 
-    WOLFSSL_MSG("wolfSSL_DH_new");
+    WOLFSSL_ENTER("wolfSSL_DH_new");
 
     key = (DhKey*) XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH);
@@ -28448,12 +31691,13 @@
     }
     external->internal = key;
+    external->priv_key = wolfSSL_BN_new();
+    external->pub_key = wolfSSL_BN_new();
 
     return external;
 }
 
-
 void wolfSSL_DH_free(WOLFSSL_DH* dh)
 {
-    WOLFSSL_MSG("wolfSSL_DH_free");
+    WOLFSSL_ENTER("wolfSSL_DH_free");
 
     if (dh) {
@@ -28479,5 +31723,5 @@
     int            pSz = 1024;
     int            gSz = 1024;
-#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+#ifdef WOLFSSL_DH_EXTRA
     int            privSz = 256; /* Up to 2048-bit */
     int            pubSz  = 256;
@@ -28486,5 +31730,5 @@
     unsigned char* p   = NULL;
     unsigned char* g   = NULL;
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+    #ifdef WOLFSSL_DH_EXTRA
         unsigned char* priv_key = NULL;
         unsigned char* pub_key = NULL;
@@ -28493,5 +31737,5 @@
     unsigned char  p[1024];
     unsigned char  g[1024];
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+    #ifdef WOLFSSL_DH_EXTRA
         unsigned char priv_key[256];
         unsigned char pub_key[256];
@@ -28507,19 +31751,20 @@
     else if (wolfSSL_BN_bn2bin(dh->g, NULL) > gSz)
         WOLFSSL_MSG("Bad g internal size");
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+#ifdef WOLFSSL_DH_EXTRA
     else if (wolfSSL_BN_bn2bin(dh->priv_key, NULL) > privSz)
         WOLFSSL_MSG("Bad private key internal size");
     else if (wolfSSL_BN_bn2bin(dh->pub_key, NULL) > privSz)
         WOLFSSL_MSG("Bad public key internal size");
-    #endif
+#endif
     else {
     #ifdef WOLFSSL_SMALL_STACK
         p = (unsigned char*)XMALLOC(pSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
         g = (unsigned char*)XMALLOC(gSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
-
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
-        priv_key = (unsigned char*)XMALLOC(privSz,NULL,DYNAMIC_TYPE_PRIVATE_KEY);
-        pub_key  = (unsigned char*)XMALLOC(pubSz,NULL,DYNAMIC_TYPE_PUBLIC_KEY);
-    #endif
+        #ifdef WOLFSSL_DH_EXTRA
+            priv_key = (unsigned char*)XMALLOC(privSz, NULL, 
+                DYNAMIC_TYPE_PRIVATE_KEY);
+            pub_key  = (unsigned char*)XMALLOC(pubSz, NULL, 
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        #endif
 
         if (p == NULL || g == NULL) {
@@ -28530,5 +31775,5 @@
     #endif /* WOLFSSL_SMALL_STACK */
 
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+    #ifdef WOLFSSL_DH_EXTRA
         privSz = wolfSSL_BN_bn2bin(dh->priv_key, priv_key);
         pubSz  = wolfSSL_BN_bn2bin(dh->pub_key,  pub_key);
@@ -28540,11 +31785,15 @@
         }
         if (privSz > 0 || pubSz > 0) {
-            ret = wc_DhSetFullKeys((DhKey*)dh->internal,priv_key,privSz,
-                                    pub_key,pubSz);
-            if (ret == WOLFSSL_FAILURE) {
+            ret = wc_DhImportKeyPair((DhKey*)dh->internal, priv_key, privSz,
+                                     pub_key, pubSz);
+            if (ret == 0) {
+                ret = WOLFSSL_SUCCESS;
+            }
+            else {
                 WOLFSSL_MSG("Failed setting private or public key.");
-            }
-        }
-    #endif /* WOLFSSL_QT || OPENSSL_ALL */
+                ret = WOLFSSL_FAILURE;
+            }
+        }
+    #endif /* WOLFSSL_DH_EXTRA */
 
         pSz = wolfSSL_BN_bn2bin(dh->p, p);
@@ -28563,5 +31812,5 @@
         XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
         XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
-        #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+        #ifdef WOLFSSL_DH_EXTRA
             XFREE(priv_key, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
             XFREE(pub_key,  NULL, DYNAMIC_TYPE_PUBLIC_KEY);
@@ -28570,9 +31819,49 @@
     }
 
-
     return ret;
 }
 
-#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH))
+#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL) \
+    || defined(WOLFSSL_OPENSSH))
+
+#ifdef WOLFSSL_DH_EXTRA
+WOLFSSL_DH* wolfSSL_DH_dup(WOLFSSL_DH* dh)
+{
+    WOLFSSL_DH* ret = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_DH_dup");
+
+    if (!dh) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    if (dh->inSet == 0 && SetDhInternal(dh) != WOLFSSL_SUCCESS){
+        WOLFSSL_MSG("Bad DH set internal");
+        return NULL;
+    }
+
+    if (!(ret = wolfSSL_DH_new())) {
+        WOLFSSL_MSG("wolfSSL_DH_new error");
+        return NULL;
+    }
+
+    if (wc_DhKeyCopy((DhKey*)dh->internal, (DhKey*)ret->internal) != MP_OKAY) {
+        WOLFSSL_MSG("wc_DhKeyCopy error");
+        wolfSSL_DH_free(ret);
+        return NULL;
+    }
+    ret->inSet = 1;
+
+    if (SetDhExternal(ret) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("SetDhExternal error");
+        wolfSSL_DH_free(ret);
+        return NULL;
+    }
+
+    return ret;
+}
+#endif /* WOLFSSL_DH_EXTRA */
+
 /* Set the members of DhKey into WOLFSSL_DH
  * DhKey was populated from wc_DhKeyDecode
@@ -28599,4 +31888,5 @@
     }
 
+#ifdef WOLFSSL_DH_EXTRA
     if (SetIndividualExternal(&dh->priv_key, &key->priv) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("No DH Private Key");
@@ -28608,4 +31898,5 @@
         return WOLFSSL_FATAL_ERROR;
     }
+#endif /* WOLFSSL_DH_EXTRA */
 
     dh->exSet = 1;
@@ -28648,5 +31939,5 @@
     WOLFSSL_ENTER("wolfSSL_DH_768_prime");
 
-    if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) {
+    if (wolfSSL_BN_hex2bn(&bn, prm) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("Error converting DH 768 prime to big number");
         return NULL;
@@ -28678,5 +31969,5 @@
     WOLFSSL_ENTER("wolfSSL_DH_1024_prime");
 
-    if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) {
+    if (wolfSSL_BN_hex2bn(&bn, prm) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("Error converting DH 1024 prime to big number");
         return NULL;
@@ -28712,5 +32003,5 @@
     WOLFSSL_ENTER("wolfSSL_DH_1536_prime");
 
-    if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) {
+    if (wolfSSL_BN_hex2bn(&bn, prm) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("Error converting DH 1536 prime to big number");
         return NULL;
@@ -28750,5 +32041,5 @@
     WOLFSSL_ENTER("wolfSSL_DH_2048_prime");
 
-    if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) {
+    if (wolfSSL_BN_hex2bn(&bn, prm) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("Error converting DH 2048 prime to big number");
         return NULL;
@@ -28796,5 +32087,5 @@
     WOLFSSL_ENTER("wolfSSL_DH_3072_prime");
 
-    if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) {
+    if (wolfSSL_BN_hex2bn(&bn, prm) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("Error converting DH 3072 prime to big number");
         return NULL;
@@ -28850,5 +32141,5 @@
     WOLFSSL_ENTER("wolfSSL_DH_4096_prime");
 
-    if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) {
+    if (wolfSSL_BN_hex2bn(&bn, prm) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("Error converting DH 4096 prime to big number");
         return NULL;
@@ -28920,5 +32211,5 @@
     WOLFSSL_ENTER("wolfSSL_DH_6144_prime");
 
-    if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) {
+    if (wolfSSL_BN_hex2bn(&bn, prm) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("Error converting DH 6144 prime to big number");
         return NULL;
@@ -29007,5 +32298,5 @@
     WOLFSSL_ENTER("wolfSSL_DH_8192_prime");
 
-    if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) {
+    if (wolfSSL_BN_hex2bn(&bn, prm) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("Error converting DH 8192 prime to big number");
         return NULL;
@@ -29015,4 +32306,5 @@
 }
 
+#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2))
 /* return code compliant with OpenSSL :
  *   1 if success, 0 if error
@@ -29066,6 +32358,12 @@
             privSz = pubSz;
         }
-        pub   = (unsigned char*)XMALLOC(pubSz,  NULL, DYNAMIC_TYPE_PUBLIC_KEY);
-        priv  = (unsigned char*)XMALLOC(privSz, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
+        if (pubSz > 0) {
+            pub = (unsigned char*)XMALLOC(pubSz,
+                    NULL, DYNAMIC_TYPE_PUBLIC_KEY);
+        }
+        if (privSz > 0) {
+            priv = (unsigned char*)XMALLOC(privSz,
+                    NULL, DYNAMIC_TYPE_PRIVATE_KEY);
+        }
         if (pub == NULL || priv == NULL) {
             WOLFSSL_MSG("Unable to malloc memory");
@@ -29158,6 +32456,6 @@
         privSz = wolfSSL_BN_bn2bin(dh->priv_key, priv);
         pubSz  = wolfSSL_BN_bn2bin(otherPub, pub);
-        if (dh->inSet == 0 && SetDhInternal(dh) != SSL_SUCCESS){
-                WOLFSSL_MSG("Bad DH set internal");
+        if (dh->inSet == 0 && SetDhInternal(dh) != WOLFSSL_SUCCESS){
+            WOLFSSL_MSG("Bad DH set internal");
         }
         if (privSz <= 0 || pubSz <= 0)
@@ -29174,4 +32472,6 @@
     XFREE(priv, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
 #endif
+
+    WOLFSSL_LEAVE("wolfSSL_DH_compute_key", ret);
 
     return ret;
@@ -29209,6 +32509,4 @@
     wolfSSL_BN_free(dh->q);
     wolfSSL_BN_free(dh->g);
-    wolfSSL_BN_free(dh->pub_key);
-    wolfSSL_BN_free(dh->priv_key);
 
     dh->p = p;
@@ -29229,9 +32527,11 @@
 }
 #endif /* v1.1.0 or later */
+#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
 
 #endif /* NO_DH */
-
-
-#ifndef NO_DSA
+#endif /* OPENSSL_EXTRA */
+
+#if !defined(NO_DSA) && \
+    (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL))
 static void InitwolfSSL_DSA(WOLFSSL_DSA* dsa)
 {
@@ -29306,10 +32606,4 @@
 }
 
-#endif /* NO_DSA */
-#endif /* OPENSSL_EXTRA */
-
-#ifdef OPENSSL_EXTRA
-
-#ifndef NO_DSA
 /* wolfSSL -> OpenSSL */
 int SetDsaExternal(WOLFSSL_DSA* dsa)
@@ -29354,5 +32648,8 @@
     return WOLFSSL_SUCCESS;
 }
-
+#endif /* !NO_DSA && (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */
+
+
+#if !defined(NO_DSA) && defined(OPENSSL_EXTRA)
 /* Openssl -> WolfSSL */
 int SetDsaInternal(WOLFSSL_DSA* dsa)
@@ -29410,10 +32707,66 @@
     return WOLFSSL_SUCCESS;
 }
-#endif /* NO_DSA */
-#endif /* OPENSSL_EXTRA */
+#endif /* !NO_DSA && OPENSSL_EXTRA */
 
 
 #ifdef OPENSSL_EXTRA
 #if !defined(NO_RSA)
+
+/* return wolfSSL native error codes. */
+static int wolfSSL_RSA_generate_key_native(WOLFSSL_RSA* rsa, int bits, WOLFSSL_BIGNUM* bn,
+                                void* cb)
+{
+    int ret;
+
+    (void)cb;
+    (void)bn;
+    (void)bits;
+
+    WOLFSSL_ENTER("wolfSSL_RSA_generate_key_native");
+
+    if (rsa == NULL || rsa->internal == NULL) {
+        /* bit size checked during make key call */
+        WOLFSSL_MSG("bad arguments");
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef WOLFSSL_KEY_GEN
+    {
+    #ifdef WOLFSSL_SMALL_STACK
+        WC_RNG* rng;
+    #else
+        WC_RNG  rng[1];
+    #endif
+
+    #ifdef WOLFSSL_SMALL_STACK
+        rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
+        if (rng == NULL)
+            return MEMORY_E;
+    #endif
+
+        if ((ret = wc_InitRng(rng)) < 0)
+            WOLFSSL_MSG("RNG init failed");
+        else if ((ret = wc_MakeRsaKey((RsaKey*)rsa->internal, bits,
+                    wolfSSL_BN_get_word(bn), rng)) != MP_OKAY)
+            WOLFSSL_MSG("wc_MakeRsaKey failed");
+        else if ((ret = SetRsaExternal(rsa)) != WOLFSSL_SUCCESS)
+            WOLFSSL_MSG("SetRsaExternal failed");
+        else {
+            rsa->inSet = 1;
+	    ret = WOLFSSL_ERROR_NONE;
+        }
+
+        wc_FreeRng(rng);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(rng, NULL, DYNAMIC_TYPE_RNG);
+    #endif
+    }
+#else
+    WOLFSSL_MSG("No Key Gen built in");
+    ret = NOT_COMPILED_IN;
+#endif
+    return ret;
+}
+
 /* Generates a RSA key of length len
  *
@@ -29450,5 +32803,5 @@
     }
 
-    if (wolfSSL_BN_set_word(bn, (WOLFSSL_BN_ULONG)e) != SSL_SUCCESS) {
+    if (wolfSSL_BN_set_word(bn, e) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("Error using e value");
         wolfSSL_BN_free(bn);
@@ -29461,7 +32814,17 @@
     }
     else {
-        if (wolfSSL_RSA_generate_key_ex(rsa, len, bn, NULL) != SSL_SUCCESS){
-            wolfSSL_RSA_free(rsa);
-            rsa = NULL;
+        for (;;) {
+            int gen_ret = wolfSSL_RSA_generate_key_native(rsa, len, bn, NULL);
+            if (gen_ret == WOLFSSL_ERROR_NONE)
+                break;
+#ifdef HAVE_FIPS
+            else if (gen_ret == PRIME_GEN_E)
+                continue;
+#endif
+            else {
+                wolfSSL_RSA_free(rsa);
+                rsa = NULL;
+                break;
+            }
         }
     }
@@ -29470,5 +32833,4 @@
     return rsa;
 }
-
 
 /* return compliant with OpenSSL
@@ -29478,53 +32840,15 @@
                                 void* cb)
 {
-    int ret = WOLFSSL_FAILURE;
-
-    (void)cb;
-    (void)bn;
-    (void)bits;
-
-    WOLFSSL_ENTER("wolfSSL_RSA_generate_key_ex");
-
-    if (rsa == NULL || rsa->internal == NULL) {
-        /* bit size checked during make key call */
-        WOLFSSL_MSG("bad arguments");
-        return WOLFSSL_FAILURE;
-    }
-
-#ifdef WOLFSSL_KEY_GEN
-    {
-    #ifdef WOLFSSL_SMALL_STACK
-        WC_RNG* rng;
-    #else
-        WC_RNG  rng[1];
-    #endif
-
-    #ifdef WOLFSSL_SMALL_STACK
-        rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
-        if (rng == NULL)
+    for (;;) {
+        int gen_ret = wolfSSL_RSA_generate_key_native(rsa, bits, bn, cb);
+        if (gen_ret == WOLFSSL_ERROR_NONE)
+            return WOLFSSL_SUCCESS;
+#ifdef HAVE_FIPS
+        else if (gen_ret == PRIME_GEN_E)
+            continue;
+#endif
+        else
             return WOLFSSL_FAILURE;
-    #endif
-
-        if (wc_InitRng(rng) < 0)
-            WOLFSSL_MSG("RNG init failed");
-        else if (wc_MakeRsaKey((RsaKey*)rsa->internal, bits,
-                    wolfSSL_BN_get_word(bn), rng) != MP_OKAY)
-            WOLFSSL_MSG("wc_MakeRsaKey failed");
-        else if (SetRsaExternal(rsa) != WOLFSSL_SUCCESS)
-            WOLFSSL_MSG("SetRsaExternal failed");
-        else {
-            rsa->inSet = 1;
-            ret = WOLFSSL_SUCCESS;
-        }
-
-        wc_FreeRng(rng);
-    #ifdef WOLFSSL_SMALL_STACK
-        XFREE(rng, NULL, DYNAMIC_TYPE_RNG);
-    #endif
-    }
-#else
-    WOLFSSL_MSG("No Key Gen built in");
-#endif
-    return ret;
+    }
 }
 #endif /* NO_RSA */
@@ -29622,5 +32946,5 @@
 
     if (wolfSSL_DSA_generate_parameters_ex(dsa, bits, seed, seedLen,
-                                  counterRet, hRet, NULL) != SSL_SUCCESS) {
+                                  counterRet, hRet, NULL) != WOLFSSL_SUCCESS) {
         wolfSSL_DSA_free(dsa);
         return NULL;
@@ -29863,4 +33187,14 @@
 }
 
+
+int wolfSSL_DSA_bits(const WOLFSSL_DSA *d)
+{
+    if (!d)
+        return WOLFSSL_FAILURE;
+    if (!d->exSet && SetDsaExternal((WOLFSSL_DSA*)d) != WOLFSSL_SUCCESS)
+        return WOLFSSL_FAILURE;
+    return wolfSSL_BN_num_bits(d->p);
+}
+
 #if !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS)
 int wolfSSL_DSA_do_verify_ex(const unsigned char* digest, int digest_len,
@@ -29924,5 +33258,5 @@
 
 #ifdef DEBUG_SIGN
-static void show(const char *title, const unsigned char *out, unsigned int outlen)
+static void DEBUG_SIGN_msg(const char *title, const unsigned char *out, unsigned int outlen)
 {
     const unsigned char *pt;
@@ -29934,40 +33268,8 @@
 }
 #else
-#define show(a,b,c)
-#endif
-
-/* return SSL_SUCCESS on ok, 0 otherwise */
-int wolfSSL_RSA_sign(int type, const unsigned char* m,
-                           unsigned int mLen, unsigned char* sigRet,
-                           unsigned int* sigLen, WOLFSSL_RSA* rsa)
-{
-    return wolfSSL_RSA_sign_ex(type, m, mLen, sigRet, sigLen, rsa, 1);
-}
-
-int wolfSSL_RSA_sign_ex(int type, const unsigned char* m,
-                           unsigned int mLen, unsigned char* sigRet,
-                           unsigned int* sigLen, WOLFSSL_RSA* rsa, int flag)
-{
-    word32  outLen;
-    word32  signSz;
-    int     initTmpRng = 0;
-    WC_RNG* rng        = NULL;
-    int     ret        = 0;
-#ifdef WOLFSSL_SMALL_STACK
-    WC_RNG* tmpRNG     = NULL;
-    byte*   encodedSig = NULL;
-#else
-    WC_RNG  tmpRNG[1];
-    byte    encodedSig[MAX_ENCODED_SIG_SZ];
-#endif
-
-    WOLFSSL_ENTER("wolfSSL_RSA_sign");
-
-    if (m == NULL || sigRet == NULL || sigLen == NULL || rsa == NULL) {
-        WOLFSSL_MSG("Bad function arguments");
-        return 0;
-    }
-    show("Message to Sign", m, mLen);
-
+#define DEBUG_SIGN_msg(a,b,c)
+#endif
+
+static int nid2HashSum(int type) {
     switch (type) {
     #ifdef WOLFSSL_MD2
@@ -30005,14 +33307,78 @@
             return 0;
     }
-
-    if (rsa->inSet == 0)
-    {
+    return type;
+}
+
+/* return WOLFSSL_SUCCESS on ok, 0 otherwise */
+int wolfSSL_RSA_sign(int type, const unsigned char* m,
+                           unsigned int mLen, unsigned char* sigRet,
+                           unsigned int* sigLen, WOLFSSL_RSA* rsa)
+{
+    return wolfSSL_RSA_sign_ex(type, m, mLen, sigRet, sigLen, rsa, 1);
+}
+
+int wolfSSL_RSA_sign_ex(int type, const unsigned char* m,
+                           unsigned int mLen, unsigned char* sigRet,
+                           unsigned int* sigLen, WOLFSSL_RSA* rsa, int flag)
+{
+    return wolfSSL_RSA_sign_generic_padding(type, m, mLen, sigRet, sigLen,
+            rsa, flag, RSA_PKCS1_PADDING);
+}
+
+/**
+ * Sign a message with the chosen message digest, padding, and RSA key.
+ * @param type      Hash NID
+ * @param m         Message to sign. Most likely this will be the digest of
+ *                  the message to sign
+ * @param mLen      Length of message to sign
+ * @param sigRet    Output buffer
+ * @param sigLen    On Input: length of sigRet buffer
+ *                  On Output: length of data written to sigRet
+ * @param rsa       RSA key used to sign the input
+ * @param flag      1: Output the signature
+ *                  0: Output the value that the unpadded signature should be
+ *                     compared to. Note: for RSA_PKCS1_PSS_PADDING the
+ *                     wc_RsaPSS_CheckPadding_ex function should be used to check
+ *                     the output of a *Verify* function.
+ * @param padding   Padding to use. Only RSA_PKCS1_PSS_PADDING and
+ *                  RSA_PKCS1_PADDING are currently supported for signing.
+ * @return          WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on error
+ */
+int wolfSSL_RSA_sign_generic_padding(int type, const unsigned char* m,
+                           unsigned int mLen, unsigned char* sigRet,
+                           unsigned int* sigLen, WOLFSSL_RSA* rsa, int flag,
+                           int padding)
+{
+    word32  outLen;
+    word32  signSz;
+    int     initTmpRng = 0;
+    WC_RNG* rng        = NULL;
+    int     ret        = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    WC_RNG* tmpRNG     = NULL;
+    byte*   encodedSig = NULL;
+#else
+    WC_RNG  tmpRNG[1];
+    byte    encodedSig[MAX_ENCODED_SIG_SZ];
+#endif
+
+    WOLFSSL_ENTER("wolfSSL_RSA_sign_generic_padding");
+
+    if (m == NULL || sigRet == NULL || sigLen == NULL || rsa == NULL) {
+        WOLFSSL_MSG("Bad function arguments");
+        return WOLFSSL_FAILURE;
+    }
+    DEBUG_SIGN_msg("Message to Sign", m, mLen);
+
+    if (rsa->inSet == 0) {
         WOLFSSL_MSG("No RSA internal set, do it");
 
         if (SetRsaInternal(rsa) != WOLFSSL_SUCCESS) {
             WOLFSSL_MSG("SetRsaInternal failed");
-            return 0;
-        }
-    }
+            return WOLFSSL_FAILURE;
+        }
+    }
+
+    type = nid2HashSum(type);
 
     outLen = (word32)wolfSSL_BN_num_bytes(rsa->n);
@@ -30021,5 +33387,5 @@
     tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
     if (tmpRNG == NULL)
-        return 0;
+        return WOLFSSL_FAILURE;
 
     encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
@@ -30027,10 +33393,11 @@
     if (encodedSig == NULL) {
         XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG);
-        return 0;
-    }
-#endif
-
-    if (outLen == 0)
+        return WOLFSSL_FAILURE;
+    }
+#endif
+
+    if (outLen == 0) {
         WOLFSSL_MSG("Bad RSA size");
+    }
     else if (wc_InitRng(tmpRNG) == 0) {
         rng = tmpRNG;
@@ -30047,30 +33414,83 @@
 
     if (rng) {
-
-        signSz = wc_EncodeSignature(encodedSig, m, mLen, type);
-        if (signSz == 0) {
-            WOLFSSL_MSG("Bad Encode Signature");
-        }
-        else {
-            show("Encoded Message", encodedSig, signSz);
-            if (flag != 0) {
+        if (flag != 0) {
+            switch (padding) {
+#ifdef WC_RSA_NO_PADDING
+            case RSA_NO_PADDING:
+                WOLFSSL_MSG("RSA_NO_PADDING not supported for signing");
+                ret = BAD_FUNC_ARG;
+                break;
+#endif
+#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && defined(WC_RSA_PSS)
+            case RSA_PKCS1_PSS_PADDING:
+            {
+                enum wc_HashType hType = wc_OidGetHash(type);
+#ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER
+                WOLFSSL_MSG("Using RSA-PSS with hash length salt. "
+                            "OpenSSL uses max length by default.");
+#endif
+                ret = wc_RsaPSS_Sign_ex(m, mLen, sigRet, outLen,
+                        hType, wc_hash2mgf(hType),
+#ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER
+                        RSA_PSS_SALT_LEN_DEFAULT,
+#else
+                        RSA_PSS_SALT_LEN_DISCOVER,
+#endif
+                        (RsaKey*)rsa->internal, rng);
+                break;
+            }
+#endif
+#ifndef WC_NO_RSA_OAEP
+            case RSA_PKCS1_OAEP_PADDING:
+            {
+                WOLFSSL_MSG("RSA_PKCS1_OAEP_PADDING not supported for signing");
+                ret = BAD_FUNC_ARG;
+                break;
+            }
+#endif
+            case RSA_PKCS1_PADDING:
+                signSz = wc_EncodeSignature(encodedSig, m, mLen, type);
+                if (signSz == 0) {
+                    WOLFSSL_MSG("Bad Encode Signature");
+                }
+                DEBUG_SIGN_msg("Encoded Message", encodedSig, signSz);
                 ret = wc_RsaSSL_Sign(encodedSig, signSz, sigRet, outLen,
                                 (RsaKey*)rsa->internal, rng);
-                if (ret <= 0) {
-                    WOLFSSL_MSG("Bad Rsa Sign");
-                    ret = 0;
+                break;
+            default:
+                WOLFSSL_MSG("Unsupported padding");
+                ret = BAD_FUNC_ARG;
+                break;
+            }
+            if (ret <= 0) {
+                WOLFSSL_MSG("Bad Rsa Sign");
+                ret = 0;
+            }
+            else {
+                *sigLen = (unsigned int)ret;
+                ret = WOLFSSL_SUCCESS;
+                DEBUG_SIGN_msg("Signature", sigRet, *sigLen);
+            }
+        } else {
+            switch (padding) {
+            case RSA_NO_PADDING:
+            case RSA_PKCS1_PSS_PADDING:
+            case RSA_PKCS1_OAEP_PADDING:
+                ret = WOLFSSL_SUCCESS;
+                XMEMCPY(sigRet, m, mLen);
+                *sigLen = mLen;
+                break;
+            case RSA_PKCS1_PADDING:
+            default:
+                signSz = wc_EncodeSignature(encodedSig, m, mLen, type);
+                if (signSz == 0) {
+                    WOLFSSL_MSG("Bad Encode Signature");
                 }
-                else {
-                    *sigLen = (unsigned int)ret;
-                    ret = SSL_SUCCESS;
-                    show("Signature", sigRet, *sigLen);
-                }
-            } else {
-                ret = SSL_SUCCESS;
+                ret = WOLFSSL_SUCCESS;
                 XMEMCPY(sigRet, encodedSig, signSz);
                 *sigLen = signSz;
-            }
-        }
-
+                break;
+            }
+        }
     }
 
@@ -30083,12 +33503,15 @@
 #endif
 
-    if (ret == WOLFSSL_SUCCESS)
-        WOLFSSL_MSG("wolfSSL_RSA_sign success");
+    if (ret == WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("wolfSSL_RSA_sign_generic_padding success");
+    }
     else {
-        WOLFSSL_MSG("wolfSSL_RSA_sign failed");
+        WOLFSSL_LEAVE("wolfSSL_RSA_sign_generic_padding", ret);
+        WOLFSSL_MSG("wolfSSL_RSA_sign_generic_padding failed. "
+                    "Returning WOLFSSL_FAILURE.");
+        ret = WOLFSSL_FAILURE;
     }
     return ret;
 }
-
 
 /* returns WOLFSSL_SUCCESS on successful verify and WOLFSSL_FAILURE on fail */
@@ -30097,8 +33520,21 @@
                                unsigned int sigLen, WOLFSSL_RSA* rsa)
 {
-    int     ret;
-    unsigned char *sigRet ;
-    unsigned char *sigDec ;
-    unsigned int   len;
+    return wolfSSL_RSA_verify_ex(type, m, mLen, sig, sigLen, rsa, RSA_PKCS1_PADDING);
+}
+
+/* returns WOLFSSL_SUCCESS on successful verify and WOLFSSL_FAILURE on fail */
+int wolfSSL_RSA_verify_ex(int type, const unsigned char* m,
+                               unsigned int mLen, const unsigned char* sig,
+                               unsigned int sigLen, WOLFSSL_RSA* rsa,
+                               int padding) {
+    int     ret = WOLFSSL_FAILURE;
+    unsigned char *sigRet = NULL;
+    unsigned char *sigDec = NULL;
+    unsigned int   len = 0;
+    int verLen;
+#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+    int hSum = nid2HashSum(type);
+    enum wc_HashType hType;
+#endif
 
     WOLFSSL_ENTER("wolfSSL_RSA_verify");
@@ -30107,48 +33543,68 @@
         return WOLFSSL_FAILURE;
     }
-
-    sigRet = (unsigned char *)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    if (sigRet == NULL) {
-        WOLFSSL_MSG("Memory failure");
-        return WOLFSSL_FAILURE;
-    }
     sigDec = (unsigned char *)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
     if (sigDec == NULL) {
         WOLFSSL_MSG("Memory failure");
+        goto cleanup;
+    }
+    if (padding != RSA_PKCS1_PSS_PADDING) {
+        sigRet = (unsigned char *)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (sigRet == NULL) {
+            WOLFSSL_MSG("Memory failure");
+            goto cleanup;
+        }
+        /* get non-encrypted signature to be compared with decrypted signature */
+        if (wolfSSL_RSA_sign_generic_padding(type, m, mLen, sigRet, &len, rsa,
+                0, padding) <= 0) {
+            WOLFSSL_MSG("Message Digest Error");
+            goto cleanup;
+        }
+        DEBUG_SIGN_msg("Encoded Message", sigRet, len);
+    }
+    else {
+        DEBUG_SIGN_msg("Encoded Message", m, mLen);
+    }
+    /* decrypt signature */
+#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+    hType = wc_OidGetHash(hSum);
+    if ((verLen = wc_RsaSSL_Verify_ex2(sig, sigLen, (unsigned char *)sigDec,
+            sigLen, (RsaKey*)rsa->internal, padding, hType)) <= 0) {
+        WOLFSSL_MSG("RSA Decrypt error");
+        goto cleanup;
+    }
+#else
+    verLen = wc_RsaSSL_Verify(sig, sigLen, (unsigned char *)sigDec, sigLen,
+        (RsaKey*)rsa->internal);
+#endif
+    DEBUG_SIGN_msg("Decrypted Signature", sigDec, ret);
+#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && defined(WC_RSA_PSS)
+    if (padding == RSA_PKCS1_PSS_PADDING) {
+        if (wc_RsaPSS_CheckPadding_ex(m, mLen, sigDec, verLen,
+                hType,
+#ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER
+                RSA_PSS_SALT_LEN_DEFAULT,
+#else
+                RSA_PSS_SALT_LEN_DISCOVER,
+#endif
+                mp_count_bits(&((RsaKey*)rsa->internal)->n)) != 0) {
+            WOLFSSL_MSG("wc_RsaPSS_CheckPadding_ex error");
+            goto cleanup;
+        }
+    }
+    else
+#endif /* !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) */
+    if ((int)len != verLen || XMEMCMP(sigRet, sigDec, verLen) != 0) {
+        WOLFSSL_MSG("wolfSSL_RSA_verify_ex failed");
+        goto cleanup;
+    }
+
+    WOLFSSL_MSG("wolfSSL_RSA_verify_ex success");
+    ret = WOLFSSL_SUCCESS;
+cleanup:
+    if (sigRet)
         XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        return WOLFSSL_FAILURE;
-    }
-    /* get non-encrypted signature to be compared with decrypted signature */
-    ret = wolfSSL_RSA_sign_ex(type, m, mLen, sigRet, &len, rsa, 0);
-    if (ret <= 0) {
-        WOLFSSL_MSG("Message Digest Error");
-        XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (sigDec)
         XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        return WOLFSSL_FAILURE;
-    }
-    show("Encoded Message", sigRet, len);
-    /* decrypt signature */
-    ret = wc_RsaSSL_Verify(sig, sigLen, (unsigned char *)sigDec, sigLen,
-        (RsaKey*)rsa->internal);
-    if (ret <= 0) {
-        WOLFSSL_MSG("RSA Decrypt error");
-        XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        return WOLFSSL_FAILURE;
-    }
-    show("Decrypted Signature", sigDec, ret);
-
-    if ((int)len == ret && XMEMCMP(sigRet, sigDec, ret) == 0) {
-        WOLFSSL_MSG("wolfSSL_RSA_verify success");
-        XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        return WOLFSSL_SUCCESS;
-    }
-    else {
-        WOLFSSL_MSG("wolfSSL_RSA_verify failed");
-        XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        return WOLFSSL_FAILURE;
-    }
+    return ret;
 }
 
@@ -30225,6 +33681,10 @@
 WOLFSSL_HMAC_CTX* wolfSSL_HMAC_CTX_new(void)
 {
-    return (WOLFSSL_HMAC_CTX*)XMALLOC(sizeof(WOLFSSL_HMAC_CTX), NULL,
-        DYNAMIC_TYPE_OPENSSL);
+    WOLFSSL_HMAC_CTX* hmac_ctx = (WOLFSSL_HMAC_CTX*)XMALLOC(
+        sizeof(WOLFSSL_HMAC_CTX), NULL, DYNAMIC_TYPE_OPENSSL);
+    if (hmac_ctx != NULL) {
+        XMEMSET(hmac_ctx, 0, sizeof(WOLFSSL_HMAC_CTX));
+    }
+    return hmac_ctx;
 }
 
@@ -30258,4 +33718,5 @@
 {
     void* heap;
+    int ret;
 
 #ifndef HAVE_FIPS
@@ -30272,5 +33733,5 @@
     #ifndef NO_MD5
         case WC_MD5:
-            wc_Md5Copy(&src->hash.md5, &des->hash.md5);
+            ret = wc_Md5Copy(&src->hash.md5, &des->hash.md5);
             break;
     #endif /* !NO_MD5 */
@@ -30278,5 +33739,5 @@
     #ifndef NO_SHA
         case WC_SHA:
-            wc_ShaCopy(&src->hash.sha, &des->hash.sha);
+            ret = wc_ShaCopy(&src->hash.sha, &des->hash.sha);
             break;
     #endif /* !NO_SHA */
@@ -30284,5 +33745,5 @@
     #ifdef WOLFSSL_SHA224
         case WC_SHA224:
-            wc_Sha224Copy(&src->hash.sha224, &des->hash.sha224);
+            ret = wc_Sha224Copy(&src->hash.sha224, &des->hash.sha224);
             break;
     #endif /* WOLFSSL_SHA224 */
@@ -30290,5 +33751,5 @@
     #ifndef NO_SHA256
         case WC_SHA256:
-            wc_Sha256Copy(&src->hash.sha256, &des->hash.sha256);
+            ret = wc_Sha256Copy(&src->hash.sha256, &des->hash.sha256);
             break;
     #endif /* !NO_SHA256 */
@@ -30296,16 +33757,41 @@
     #ifdef WOLFSSL_SHA384
         case WC_SHA384:
-            wc_Sha384Copy(&src->hash.sha384, &des->hash.sha384);
+            ret = wc_Sha384Copy(&src->hash.sha384, &des->hash.sha384);
             break;
     #endif /* WOLFSSL_SHA384 */
     #ifdef WOLFSSL_SHA512
         case WC_SHA512:
-            wc_Sha512Copy(&src->hash.sha512, &des->hash.sha512);
+            ret = wc_Sha512Copy(&src->hash.sha512, &des->hash.sha512);
             break;
     #endif /* WOLFSSL_SHA512 */
+#ifdef WOLFSSL_SHA3
+    #ifndef WOLFSSL_NOSHA3_224
+        case WC_SHA3_224:
+            ret = wc_Sha3_224_Copy(&src->hash.sha3, &des->hash.sha3);
+            break;
+    #endif /* WOLFSSL_NO_SHA3_224 */
+    #ifndef WOLFSSL_NOSHA3_256
+        case WC_SHA3_256:
+            ret = wc_Sha3_256_Copy(&src->hash.sha3, &des->hash.sha3);
+            break;
+    #endif /* WOLFSSL_NO_SHA3_256 */
+    #ifndef WOLFSSL_NOSHA3_384
+        case WC_SHA3_384:
+            ret = wc_Sha3_384_Copy(&src->hash.sha3, &des->hash.sha3);
+            break;
+    #endif /* WOLFSSL_NO_SHA3_384 */
+    #ifndef WOLFSSL_NOSHA3_512
+        case WC_SHA3_512:
+            ret = wc_Sha3_512_Copy(&src->hash.sha3, &des->hash.sha3);
+            break;
+    #endif /* WOLFSSL_NO_SHA3_512 */
+#endif /* WOLFSSL_SHA3 */
 
         default:
             return WOLFSSL_FAILURE;
     }
+
+    if (ret != 0)
+        return WOLFSSL_FAILURE;
 
     XMEMCPY((byte*)des->ipad, (byte*)src->ipad, WC_HMAC_BLOCK_SIZE);
@@ -30438,4 +33924,5 @@
     int hmac_error = 0;
     void* heap = NULL;
+    int inited;
 
     WOLFSSL_MSG("wolfSSL_HMAC_Init");
@@ -30487,4 +33974,32 @@
         }
         else
+#endif
+#ifdef WOLFSSL_SHA3
+    #ifndef WOLFSSL_NOSHA3_224
+        if (XSTRNCMP(type, "SHA3_224", 8) == 0) {
+            WOLFSSL_MSG("sha3_224 hmac");
+            ctx->type = WC_SHA3_224;
+        }
+        else
+    #endif
+    #ifndef WOLFSSL_NOSHA3_256
+        if (XSTRNCMP(type, "SHA3_256", 8) == 0) {
+            WOLFSSL_MSG("sha3_256 hmac");
+            ctx->type = WC_SHA3_256;
+        } 
+        else
+    #endif
+        if (XSTRNCMP(type, "SHA3_384", 8) == 0) {
+            WOLFSSL_MSG("sha3_384 hmac");
+            ctx->type = WC_SHA3_384;
+        }
+        else
+    #ifndef WOLFSSL_NOSHA3_512
+        if (XSTRNCMP(type, "SHA3_512", 8) == 0) {
+            WOLFSSL_MSG("sha3_512 hmac");
+            ctx->type = WC_SHA3_512;
+        }
+        else
+    #endif
 #endif
 
@@ -30503,5 +34018,11 @@
     }
 
-    if (key && keylen) {
+    /* Check if init has been called before */
+    inited = (ctx->hmac.macType != WC_HASH_TYPE_NONE);
+    /* Free if needed */
+    if (inited) {
+        wc_HmacFree(&ctx->hmac);
+    }
+    if (key != NULL) {
         WOLFSSL_MSG("keying hmac");
 
@@ -30519,7 +34040,10 @@
         }
         /* OpenSSL compat, no error */
-    } else if(ctx->type >= 0) { /* MD5 == 0 */
+    }
+    else if (!inited) {
+        return WOLFSSL_FAILURE;
+    }
+    else if (ctx->type >= 0) { /* MD5 == 0 */
         WOLFSSL_MSG("recover hmac");
-        wc_HmacFree(&ctx->hmac);
         if (wc_HmacInit(&ctx->hmac, NULL, INVALID_DEVID) == 0) {
             ctx->hmac.macType = (byte)ctx->type;
@@ -30626,4 +34150,27 @@
             #endif
 
+        #ifdef WOLFSSL_SHA3
+            #ifndef WOLFSSL_NOSHA3_224
+            case WC_SHA3_224:
+                *len = WC_SHA3_224_DIGEST_SIZE;
+                break;
+            #endif
+            #ifndef WOLFSSL_NOSHA3_256
+            case WC_SHA3_256:
+                *len = WC_SHA3_256_DIGEST_SIZE;
+                break;
+            #endif
+            #ifndef WOLFSSL_NOSHA3_384
+            case WC_SHA3_384:
+                *len = WC_SHA3_384_DIGEST_SIZE;
+                break;
+            #endif
+            #ifndef WOLFSSL_NOSHA3_512
+            case WC_SHA3_512:
+                *len = WC_SHA3_512_DIGEST_SIZE;
+                break;
+            #endif
+        #endif
+
             default:
                 WOLFSSL_MSG("bad hmac type");
@@ -30640,18 +34187,24 @@
     WOLFSSL_MSG("wolfSSL_HMAC_cleanup");
 
-    if (ctx)
+    if (ctx) {
         wc_HmacFree(&ctx->hmac);
-
-    return SSL_SUCCESS;
-}
-
+    }
+
+    return WOLFSSL_SUCCESS;
+}
+
+void wolfSSL_HMAC_CTX_cleanup(WOLFSSL_HMAC_CTX* ctx)
+{
+    if (ctx) {
+        wolfSSL_HMAC_cleanup(ctx);
+    }
+}
 
 void wolfSSL_HMAC_CTX_free(WOLFSSL_HMAC_CTX* ctx)
 {
-    if (!ctx) {
-        return;
-    }
-    wolfSSL_HMAC_cleanup(ctx);
-    XFREE(ctx, NULL, DYNAMIC_TYPE_OPENSSL);
+    if (ctx) {
+        wolfSSL_HMAC_CTX_cleanup(ctx);
+        XFREE(ctx, NULL, DYNAMIC_TYPE_OPENSSL);
+    }
 }
 
@@ -30724,5 +34277,19 @@
 void *wolfSSL_OPENSSL_malloc(size_t a)
 {
-  return XMALLOC(a, NULL, DYNAMIC_TYPE_OPENSSL);
+    return (void *)XMALLOC(a, NULL, DYNAMIC_TYPE_OPENSSL);
+}
+
+int wolfSSL_OPENSSL_init_ssl(word64 opts, const OPENSSL_INIT_SETTINGS *settings)
+{
+    (void)opts;
+    (void)settings;
+    return wolfSSL_library_init();
+}
+
+int wolfSSL_OPENSSL_init_crypto(word64 opts, const OPENSSL_INIT_SETTINGS* settings)
+{
+    (void)opts;
+    (void)settings;
+    return wolfSSL_library_init();
 }
 
@@ -30730,5 +34297,6 @@
 
 static int EncryptDerKey(byte *der, int *derSz, const EVP_CIPHER* cipher,
-                         unsigned char* passwd, int passwdSz, byte **cipherInfo)
+                         unsigned char* passwd, int passwdSz, byte **cipherInfo,
+                         int maxDerSz)
 {
     int ret, paddingSz;
@@ -30783,4 +34351,11 @@
     if (paddingSz == 0)
         paddingSz = info->ivSz;
+    if (maxDerSz < *derSz + paddingSz) {
+        WOLFSSL_MSG("not enough DER buffer allocated");
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO);
+#endif
+        return WOLFSSL_FAILURE;
+    }
     XMEMSET(der+(*derSz), (byte)paddingSz, paddingSz);
     (*derSz) += paddingSz;
@@ -30898,7 +34473,6 @@
 #endif
 
-#if defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN)
+#ifndef NO_BIO
 #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) && !defined(NO_RSA)
-
 /* Takes a WOLFSSL_RSA key and writes it out to a WOLFSSL_BIO
  *
@@ -30946,4 +34520,9 @@
         }
 
+        if (derBuf == NULL) {
+            WOLFSSL_MSG("wolfSSL_RSA_To_Der failed to get buffer");
+            return WOLFSSL_FAILURE;
+        }
+
         pkey->pkey.ptr = (char*)XMALLOC(derSz, bio->heap,
                 DYNAMIC_TYPE_TMP_BUFFER);
@@ -31001,4 +34580,9 @@
     }
 
+    if (derBuf == NULL) {
+        WOLFSSL_MSG("wolfSSL_RSA_To_Der failed to get buffer");
+        return WOLFSSL_FAILURE;
+    }
+
     pkey->pkey.ptr = (char*)XMALLOC(derSz, bio->heap,
             DYNAMIC_TYPE_TMP_BUFFER);
@@ -31183,5 +34767,5 @@
     return WOLFSSL_SUCCESS;
 }
-#endif /* defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN) */
+#endif /* !NO_BIO */
 
 #if (defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) && !defined(HAVE_USER_RSA)) && \
@@ -31228,7 +34812,18 @@
     if (passwd != NULL && passwdSz > 0 && cipher != NULL) {
         int ret;
+        int blockSz = wolfSSL_EVP_CIPHER_block_size(cipher);
+        byte *tmpBuf;
+
+        /* Add space for padding */
+        if (!(tmpBuf = (byte*)XREALLOC(derBuf, derSz + blockSz, NULL,
+                DYNAMIC_TYPE_TMP_BUFFER))) {
+            WOLFSSL_MSG("Extending DER buffer failed");
+            XFREE(derBuf, NULL, DYNAMIC_TYPE_DER);
+            return WOLFSSL_FAILURE;
+        }
+        derBuf = tmpBuf;
 
         ret = EncryptDerKey(derBuf, &derSz, cipher,
-                            passwd, passwdSz, &cipherInfo);
+                            passwd, passwdSz, &cipherInfo, derSz + blockSz);
         if (ret != WOLFSSL_SUCCESS) {
             WOLFSSL_MSG("EncryptDerKey failed");
@@ -31459,5 +35054,5 @@
     /* set group (OID, nid and idx) */
     eckey->group->curve_oid = ecc_sets[key->idx].oidSum;
-    eckey->group->curve_nid = ecc_sets[key->idx].id;
+    eckey->group->curve_nid = EccEnumToNID(ecc_sets[key->idx].id);
     eckey->group->curve_idx = key->idx;
 
@@ -31627,12 +35222,7 @@
     WOLFSSL_EC_KEY *key;
     int x;
-    int eccEnum;
+    int eccEnum = NIDToEccEnum(nid);
 
     WOLFSSL_ENTER("wolfSSL_EC_KEY_new_by_curve_name");
-
-    /* If NID passed in is OpenSSL type, convert it to ecc_curve_id enum */
-    eccEnum = NIDToEccEnum(nid);
-    if (eccEnum == -1)
-        eccEnum = nid;
 
     key = wolfSSL_EC_KEY_new();
@@ -31643,13 +35233,15 @@
 
     /* set the nid of the curve */
-    key->group->curve_nid = eccEnum;
-
-    /* search and set the corresponding internal curve idx */
-    for (x = 0; ecc_sets[x].size != 0; x++)
-        if (ecc_sets[x].id == key->group->curve_nid) {
-            key->group->curve_idx = x;
-            key->group->curve_oid = ecc_sets[x].oidSum;
-            break;
-        }
+    key->group->curve_nid = nid;
+
+    if (eccEnum != -1) {
+        /* search and set the corresponding internal curve idx */
+        for (x = 0; ecc_sets[x].size != 0; x++)
+            if (ecc_sets[x].id == eccEnum) {
+                key->group->curve_idx = x;
+                key->group->curve_oid = ecc_sets[x].oidSum;
+                break;
+            }
+    }
 
     return key;
@@ -31667,5 +35259,5 @@
 }
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)
 static int populate_groups(int* groups, int max_count, char *list)
 {
@@ -31723,6 +35315,5 @@
     }
 
-    return wolfSSL_CTX_set_groups(ctx, groups, count) == WOLFSSL_SUCCESS ?
-            WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
+    return wolfSSL_CTX_set1_groups(ctx, groups, count);
 }
 
@@ -31741,6 +35332,5 @@
     }
 
-    return wolfSSL_set_groups(ssl, groups, count) == WOLFSSL_SUCCESS ?
-            WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
+    return wolfSSL_set1_groups(ssl, groups, count);
 }
 #endif /* WOLFSSL_TLS13 */
@@ -31848,4 +35438,5 @@
 {
     int     initTmpRng = 0;
+    int     eccEnum;
     WC_RNG* rng = NULL;
 #ifdef WOLFSSL_SMALL_STACK
@@ -31889,6 +35480,9 @@
     }
 
-    if (wc_ecc_make_key_ex(rng, 0, (ecc_key*)key->internal,
-                                        key->group->curve_nid) != MP_OKAY) {
+    /* NIDToEccEnum returns -1 for invalid NID so if key->group->curve_nid
+     * is 0 then pass ECC_CURVE_DEF as arg */
+    eccEnum = key->group->curve_nid ?
+            NIDToEccEnum(key->group->curve_nid) : ECC_CURVE_DEF;
+    if (wc_ecc_make_key_ex(rng, 0, (ecc_key*)key->internal, eccEnum) != MP_OKAY) {
         WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key wc_ecc_make_key failed");
 #ifdef WOLFSSL_SMALL_STACK
@@ -32201,4 +35795,11 @@
 }
 
+WOLFSSL_EC_GROUP *wolfSSL_EC_GROUP_dup(const WOLFSSL_EC_GROUP *src)
+{
+    if (!src)
+        return NULL;
+    return wolfSSL_EC_GROUP_new_by_curve_name(src->curve_nid);
+}
+
 #endif /* HAVE_ECC */
 #endif /* OPENSSL_EXTRA */
@@ -32251,7 +35852,4 @@
     /* If NID passed in is OpenSSL type, convert it to ecc_curve_id enum */
     eccEnum = NIDToEccEnum(nid);
-    if (eccEnum == -1)
-        eccEnum = nid;
-
 
     /* curve group */
@@ -32265,10 +35863,10 @@
 
     /* set the nid of the curve */
-    g->curve_nid = eccEnum;
-
-    if (eccEnum > ECC_CURVE_DEF) {
+    g->curve_nid = nid;
+
+    if (eccEnum != -1) {
         /* search and set the corresponding internal curve idx */
         for (x = 0; ecc_sets[x].size != 0; x++)
-            if (ecc_sets[x].id == g->curve_nid) {
+            if (ecc_sets[x].id == eccEnum) {
                 g->curve_idx = x;
                 g->curve_oid = ecc_sets[x].oidSum;
@@ -32518,4 +36116,5 @@
 }
 
+#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2))
 /* return code compliant with OpenSSL :
  *   1 if success, 0 if error
@@ -32621,4 +36220,5 @@
 }
 
+
 int wolfSSL_EC_POINT_oct2point(const WOLFSSL_EC_GROUP *group,
                                WOLFSSL_EC_POINT *p, const unsigned char *buf,
@@ -32648,8 +36248,12 @@
     }
 
+#ifdef HAVE_COMP_KEY
     /* Default to compressed form if not set */
     form = in->form == POINT_CONVERSION_UNCOMPRESSED ?
             POINT_CONVERSION_UNCOMPRESSED:
             POINT_CONVERSION_COMPRESSED;
+#else
+    form = POINT_CONVERSION_UNCOMPRESSED;
+#endif
 
     len = wolfSSL_EC_POINT_point2oct(in->group, in->pub_key, form,
@@ -32684,9 +36288,102 @@
 }
 
+#ifdef HAVE_ECC_KEY_IMPORT
+WOLFSSL_EC_KEY *wolfSSL_d2i_ECPrivateKey(WOLFSSL_EC_KEY **key, const unsigned char **in,
+                                         long len)
+{
+    WOLFSSL_EC_KEY *eckey = NULL;
+    WOLFSSL_ENTER("wolfSSL_d2i_ECPrivateKey");
+
+    if (!in || !*in || len <= 0) {
+        WOLFSSL_MSG("wolfSSL_d2i_ECPrivateKey Bad arguments");
+        return NULL;
+    }
+
+    if (!(eckey = wolfSSL_EC_KEY_new())) {
+        WOLFSSL_MSG("wolfSSL_EC_KEY_new error");
+        return NULL;
+    }
+
+    if (wc_ecc_import_private_key(*in, (word32)len, NULL, 0,
+            (ecc_key*)eckey->internal) != MP_OKAY) {
+        WOLFSSL_MSG("wc_ecc_import_private_key error");
+        goto error;
+    }
+
+    eckey->inSet = 1;
+
+    if (SetECKeyExternal(eckey) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("SetECKeyExternal error");
+        goto error;
+    }
+
+    if (key) {
+        *key = eckey;
+    }
+
+    return eckey;
+
+error:
+    wolfSSL_EC_KEY_free(eckey);
+    return NULL;
+}
+#endif /* HAVE_ECC_KEY_IMPORT */
+
+int wolfSSL_i2d_ECPrivateKey(const WOLFSSL_EC_KEY *in, unsigned char **out)
+{
+    int len;
+    byte* buf = NULL;
+    WOLFSSL_ENTER("wolfSSL_i2d_ECPrivateKey");
+
+    if (!in) {
+        WOLFSSL_MSG("wolfSSL_i2d_ECPrivateKey Bad arguments");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (!in->inSet && SetECKeyInternal((WOLFSSL_EC_KEY*)in) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("SetECKeyInternal error");
+        return WOLFSSL_FAILURE;
+    }
+
+    if ((len = wc_ecc_size((ecc_key*)in->internal)) <= 0) {
+        WOLFSSL_MSG("wc_ecc_size error");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (out) {
+        if (!(buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER))) {
+            WOLFSSL_MSG("tmp buffer malloc error");
+            return WOLFSSL_FAILURE;
+        }
+
+        if (wc_ecc_export_private_only((ecc_key*)in->internal, buf,
+                (word32*)&len) != MP_OKAY) {
+            WOLFSSL_MSG("wc_ecc_export_private_only error");
+            XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return WOLFSSL_FAILURE;
+        }
+
+        if (*out) {
+            XMEMCPY(*out, buf, len);
+            XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        }
+        else {
+            *out = buf;
+        }
+    }
+
+    return len;
+}
+
 void wolfSSL_EC_KEY_set_conv_form(WOLFSSL_EC_KEY *eckey, char form)
 {
-    if (eckey && (form == POINT_CONVERSION_COMPRESSED ||
-                  form == POINT_CONVERSION_UNCOMPRESSED)) {
+    if (eckey && (form == POINT_CONVERSION_UNCOMPRESSED
+#ifdef HAVE_COMP_KEY
+                  || form == POINT_CONVERSION_COMPRESSED
+#endif
+                  )) {
         eckey->form = form;
+    } else {
+        WOLFSSL_MSG("Incorrect form or HAVE_COMP_KEY not compiled in");
     }
 }
@@ -32728,4 +36425,28 @@
     return ret;
 }
+#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
+
+#ifdef USE_ECC_B_PARAM
+int wolfSSL_EC_POINT_is_on_curve(const WOLFSSL_EC_GROUP *group,
+                                 const WOLFSSL_EC_POINT *point,
+                                 WOLFSSL_BN_CTX *ctx)
+{
+    (void)ctx;
+    WOLFSSL_ENTER("wolfSSL_EC_POINT_is_on_curve");
+
+    if (!group || !point) {
+        WOLFSSL_MSG("Invalid arguments");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (!point->inSet && SetECPointInternal((WOLFSSL_EC_POINT*)point)) {
+        WOLFSSL_MSG("SetECPointInternal error");
+        return WOLFSSL_FAILURE;
+    }
+
+    return wc_ecc_point_is_on_curve((ecc_point*)point->internal, group->curve_idx)
+            == MP_OKAY ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
+}
+#endif /* USE_ECC_B_PARAM */
 
 WOLFSSL_EC_POINT *wolfSSL_EC_POINT_new(const WOLFSSL_EC_GROUP *group)
@@ -32859,5 +36580,113 @@
 }
 
-#if !defined(WOLFSSL_ATECC508A) && !defined(HAVE_SELFTEST)
+#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
+    !defined(HAVE_SELFTEST)
+#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2))
+int wolfSSL_EC_POINT_add(const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *r,
+                         const WOLFSSL_EC_POINT *p1,
+                         const WOLFSSL_EC_POINT *p2, WOLFSSL_BN_CTX *ctx)
+{
+    mp_int a, prime, mu;
+    mp_digit mp = 0;
+    ecc_point* montP1 = NULL;
+    ecc_point* montP2 = NULL;
+    ecc_point* eccP1;
+    ecc_point* eccP2;
+    int ret = WOLFSSL_FAILURE;
+
+    (void)ctx;
+
+    if (!group || !r || !p1 || !p2) {
+        WOLFSSL_MSG("wolfSSL_EC_POINT_add error");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (setupPoint(r) != WOLFSSL_SUCCESS ||
+        setupPoint(p1) != WOLFSSL_SUCCESS ||
+        setupPoint(p2) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("setupPoint error");
+        return WOLFSSL_FAILURE;
+    }
+
+    /* read the curve prime and a */
+    if (mp_init_multi(&prime, &a, &mu, NULL, NULL, NULL) != MP_OKAY) {
+        WOLFSSL_MSG("mp_init_multi error");
+        goto cleanup;
+    }
+
+    if (mp_read_radix(&a, ecc_sets[group->curve_idx].Af, MP_RADIX_HEX)
+            != MP_OKAY) {
+        WOLFSSL_MSG("mp_read_radix a error");
+        goto cleanup;
+    }
+
+    if (mp_read_radix(&prime, ecc_sets[group->curve_idx].prime, MP_RADIX_HEX)
+            != MP_OKAY) {
+        WOLFSSL_MSG("mp_read_radix prime error");
+        goto cleanup;
+    }
+
+    if (mp_montgomery_setup(&prime, &mp) != MP_OKAY) {
+        WOLFSSL_MSG("mp_montgomery_setup nqm error");
+        goto cleanup;
+    }
+
+    eccP1 = (ecc_point*)p1->internal;
+    eccP2 = (ecc_point*)p2->internal;
+
+    if (!(montP1 = wc_ecc_new_point_h(NULL)) ||
+            !(montP2 = wc_ecc_new_point_h(NULL))) {
+        WOLFSSL_MSG("wc_ecc_new_point_h nqm error");
+        goto cleanup;
+    }
+
+    if ((mp_montgomery_calc_normalization(&mu, &prime)) != MP_OKAY) {
+        WOLFSSL_MSG("mp_montgomery_calc_normalization error");
+        goto cleanup;
+    }
+
+    /* Convert to Montgomery form */
+    if (mp_cmp_d(&mu, 1) == MP_EQ) {
+        if (wc_ecc_copy_point(eccP1, montP1) != MP_OKAY ||
+                wc_ecc_copy_point(eccP2, montP2) != MP_OKAY) {
+            WOLFSSL_MSG("wc_ecc_copy_point error");
+            goto cleanup;
+        }
+    } else {
+        if (mp_mulmod(eccP1->x, &mu, &prime, montP1->x) != MP_OKAY ||
+                mp_mulmod(eccP1->y, &mu, &prime, montP1->y) != MP_OKAY ||
+                mp_mulmod(eccP1->z, &mu, &prime, montP1->z) != MP_OKAY) {
+            WOLFSSL_MSG("mp_mulmod error");
+            goto cleanup;
+        }
+        if (mp_mulmod(eccP2->x, &mu, &prime, montP2->x) != MP_OKAY ||
+                mp_mulmod(eccP2->y, &mu, &prime, montP2->y) != MP_OKAY ||
+                mp_mulmod(eccP2->z, &mu, &prime, montP2->z) != MP_OKAY) {
+            WOLFSSL_MSG("mp_mulmod error");
+            goto cleanup;
+        }
+    }
+
+    if (ecc_projective_add_point(montP1, montP2, (ecc_point*)r->internal,
+            &a, &prime, mp) != MP_OKAY) {
+        WOLFSSL_MSG("ecc_projective_add_point error");
+        goto cleanup;
+    }
+
+    if (ecc_map((ecc_point*)r->internal, &prime, mp) != MP_OKAY) {
+        WOLFSSL_MSG("ecc_map error");
+        goto cleanup;
+    }
+
+    ret = WOLFSSL_SUCCESS;
+cleanup:
+    mp_clear(&a);
+    mp_clear(&prime);
+    mp_clear(&mu);
+    wc_ecc_del_point_h(montP1, NULL);
+    wc_ecc_del_point_h(montP2, NULL);
+    return ret;
+}
+
 /* Calculate the value: generator * n + q * m
  * return code compliant with OpenSSL :
@@ -32940,5 +36769,5 @@
         }
         /* r = generator * n */
-        if (wc_ecc_mulmod((mp_int*)n->internal, result, result, &a, &prime, 1)
+        if (wc_ecc_mulmod((mp_int*)n->internal, result, result, &a, &prime, 0)
                 != MP_OKAY) {
             WOLFSSL_MSG("wc_ecc_mulmod nqm error");
@@ -32947,5 +36776,5 @@
         /* tmp = q * m */
         if (wc_ecc_mulmod((mp_int*)m->internal, (ecc_point*)q->internal,
-                tmp, &a, &prime, 1) != MP_OKAY) {
+                tmp, &a, &prime, 0) != MP_OKAY) {
             WOLFSSL_MSG("wc_ecc_mulmod nqm error");
             goto cleanup;
@@ -32999,6 +36828,43 @@
     return ret;
 }
+#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
 #endif /* !defined(WOLFSSL_ATECC508A) && defined(ECC_SHAMIR) &&
         * !defined(HAVE_SELFTEST) */
+
+/* (x, y) -> (x, -y) */
+int wolfSSL_EC_POINT_invert(const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *a,
+                            WOLFSSL_BN_CTX *ctx)
+{
+    ecc_point* p;
+    mp_int prime;
+
+    (void)ctx;
+
+    WOLFSSL_ENTER("wolfSSL_EC_POINT_invert");
+
+    if (!group || !a || !a->internal || setupPoint(a) != WOLFSSL_SUCCESS) {
+        return WOLFSSL_FAILURE;
+    }
+
+    p = (ecc_point*)a->internal;
+
+    /* read the curve prime and a */
+    if (mp_init_multi(&prime, NULL, NULL, NULL, NULL, NULL) != MP_OKAY) {
+        WOLFSSL_MSG("mp_init_multi error");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (mp_sub(&prime, p->y, p->y) != MP_OKAY) {
+        WOLFSSL_MSG("mp_sub error");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (SetECPointExternal(a) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("SetECPointExternal error");
+        return WOLFSSL_FAILURE;
+    }
+
+    return WOLFSSL_SUCCESS;
+}
 
 void wolfSSL_EC_POINT_clear_free(WOLFSSL_EC_POINT *p)
@@ -33122,4 +36988,5 @@
 /* End EC_POINT */
 
+#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2))
 size_t wolfSSL_EC_get_builtin_curves(WOLFSSL_EC_BUILTIN_CURVE *r, size_t nitems)
 {
@@ -33141,6 +37008,7 @@
     }
 
-    return ecc_sets_count;
-}
+    return min_nitems;
+}
+#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
 
 /* Start ECDSA_SIG */
@@ -33392,6 +37260,10 @@
 {
     word32 len;
-    (void)KDF;
-
+    ecc_key* key;
+    int ret;
+#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) \
+    && !defined(HAVE_FIPS)
+    int setGlobalRNG = 0;
+#endif
     (void)KDF;
 
@@ -33416,8 +37288,25 @@
 
     len = (word32)outlen;
-
-    if (wc_ecc_shared_secret_ssh((ecc_key*)ecdh->internal,
-                                 (ecc_point*)pub_key->internal,
-                                 (byte *)out, &len) != MP_OKAY) {
+    key = (ecc_key*)ecdh->internal;
+
+#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) \
+    && !defined(HAVE_FIPS)
+    if (key->rng == NULL) {
+        if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("No RNG to use");
+            return WOLFSSL_FATAL_ERROR;
+        }
+        key->rng = &globalRNG;
+        setGlobalRNG = 1;
+    }
+#endif
+    ret = wc_ecc_shared_secret_ssh(key, (ecc_point*)pub_key->internal,
+            (byte *)out, &len);
+#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) \
+    && !defined(HAVE_FIPS)
+    if (setGlobalRNG)
+        key->rng = NULL;
+#endif
+    if (ret != MP_OKAY) {
         WOLFSSL_MSG("wc_ecc_shared_secret failed");
         return WOLFSSL_FATAL_ERROR;
@@ -33443,4 +37332,6 @@
 }
 #endif
+
+#ifndef NO_BIO
 
 /* Uses the same format of input as wolfSSL_PEM_read_bio_PrivateKey but expects
@@ -33512,7 +37403,9 @@
     return local;
 }
+#endif /* !NO_BIO */
 #endif /* NO_FILESYSTEM */
 
 #if defined(WOLFSSL_KEY_GEN)
+#ifndef NO_BIO
 /* Takes a public WOLFSSL_EC_KEY and writes it out to WOLFSSL_BIO
  * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE
@@ -33653,4 +37546,6 @@
 }
 
+#endif /* !NO_BIO */
+
 /* return code compliant with OpenSSL :
  *   1 if success, 0 if error
@@ -33709,5 +37604,5 @@
 
         ret = EncryptDerKey(derBuf, &derSz, cipher,
-                            passwd, passwdSz, &cipherInfo);
+                            passwd, passwdSz, &cipherInfo, der_max_len);
         if (ret != WOLFSSL_SUCCESS) {
             WOLFSSL_MSG("EncryptDerKey failed");
@@ -33823,4 +37718,5 @@
 
 #if defined(WOLFSSL_KEY_GEN)
+#ifndef NO_BIO
 
 /* Takes a DSA Privatekey and writes it out to a WOLFSSL_BIO
@@ -33962,4 +37858,5 @@
 }
 #endif /* HAVE_SELFTEST */
+#endif /* !NO_BIO */
 
 /* return code compliant with OpenSSL :
@@ -34019,5 +37916,5 @@
 
         ret = EncryptDerKey(derBuf, &derSz, cipher,
-                            passwd, passwdSz, &cipherInfo);
+                            passwd, passwdSz, &cipherInfo, der_max_len);
         if (ret != WOLFSSL_SUCCESS) {
             WOLFSSL_MSG("EncryptDerKey failed");
@@ -34145,4 +38042,6 @@
 
 #endif /* #ifndef NO_DSA */
+
+#ifndef NO_BIO
 
 static int pem_read_bio_key(WOLFSSL_BIO* bio, pem_password_cb* cb, void* pass,
@@ -34500,4 +38399,6 @@
 #endif /* HAVE_ECC */
 
+#endif /* !NO_BIO */
+
 #if !defined(NO_FILESYSTEM)
 WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PUBKEY(XFILE fp, EVP_PKEY **x,
@@ -34517,4 +38418,5 @@
 #ifndef NO_RSA
 
+#ifndef NO_BIO
 #if defined(XSNPRINTF) && !defined(HAVE_FAST_RSA)
 /* snprintf() must be available */
@@ -34537,5 +38439,6 @@
     int i = 0;
     mp_int *rsaElem = NULL;
-    char rsaStr[][20] = { "Modulus:",
+    const char *rsaStr[] = {
+                          "Modulus:",
                           "PublicExponent:",
                           "PrivateExponent:",
@@ -34688,4 +38591,5 @@
 
 #endif /* XSNPRINTF */
+#endif /* !NO_BIO */
 
 #if !defined(NO_FILESYSTEM)
@@ -34898,44 +38802,5 @@
 #if defined(WC_RSA_PSS) && (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \
         defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX))
-static int hash2mgf(enum wc_HashType hType)
-{
-    switch (hType) {
-#ifndef NO_SHA
-    case WC_HASH_TYPE_SHA:
-        return WC_MGF1SHA1;
-#endif
-#ifndef NO_SHA256
-#ifdef WOLFSSL_SHA224
-    case WC_HASH_TYPE_SHA224:
-        return WC_MGF1SHA224;
-#endif
-    case WC_HASH_TYPE_SHA256:
-        return WC_MGF1SHA256;
-#endif
-#ifdef WOLFSSL_SHA384
-    case WC_HASH_TYPE_SHA384:
-        return WC_MGF1SHA384;
-#endif
-#ifdef WOLFSSL_SHA512
-    case WC_HASH_TYPE_SHA512:
-        return WC_MGF1SHA512;
-#endif
-    case WC_HASH_TYPE_NONE:
-    case WC_HASH_TYPE_MD2:
-    case WC_HASH_TYPE_MD4:
-    case WC_HASH_TYPE_MD5:
-    case WC_HASH_TYPE_MD5_SHA:
-    case WC_HASH_TYPE_SHA3_224:
-    case WC_HASH_TYPE_SHA3_256:
-    case WC_HASH_TYPE_SHA3_384:
-    case WC_HASH_TYPE_SHA3_512:
-    case WC_HASH_TYPE_BLAKE2B:
-    case WC_HASH_TYPE_BLAKE2S:
-    default:
-        WOLFSSL_MSG("Unrecognized or unsupported hash function");
-        return WC_MGF1NONE;
-    }
-}
-
+#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2))
 /*
  *                                +-----------+
@@ -35003,6 +38868,6 @@
     }
 
-   if ((mgf = hash2mgf(hashType)) == WC_MGF1NONE) {
-       WOLFSSL_MSG("hash2mgf error");
+   if ((mgf = wc_hash2mgf(hashType)) == WC_MGF1NONE) {
+       WOLFSSL_MSG("wc_hash2mgf error");
        goto cleanup;
    }
@@ -35035,7 +38900,7 @@
     }
 
-    if (wc_RsaPad_ex(mHash, wolfSSL_EVP_MD_size(hashAlg), EM, emLen,
+    if (wc_RsaPad_ex(mHash, hashLen, EM, emLen,
                      RSA_BLOCK_TYPE_1, rng, WC_RSA_PSS_PAD,
-                     wolfSSL_EVP_md2macType(hashAlg), mgf, NULL, 0, saltLen,
+                     hashType, mgf, NULL, 0, saltLen,
                      wolfSSL_BN_num_bits(rsa->n), NULL) != MP_OKAY) {
         WOLFSSL_MSG("wc_RsaPad_ex error");
@@ -35110,6 +38975,6 @@
     }
 
-    if ((mgf = hash2mgf(hashType)) == WC_MGF1NONE) {
-        WOLFSSL_MSG("hash2mgf error");
+    if ((mgf = wc_hash2mgf(hashType)) == WC_MGF1NONE) {
+        WOLFSSL_MSG("wc_hash2mgf error");
         return WOLFSSL_FAILURE;
     }
@@ -35147,5 +39012,8 @@
     return WOLFSSL_SUCCESS;
 }
-#endif
+#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
+#endif /* WC_RSA_PSS && (OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY
+        *                || WOLFSSL_NGINX)
+        */
 
 #if defined(OPENSSL_EXTRA)
@@ -35256,5 +39124,5 @@
     if (wolfSSL_RSA_LoadDer_ex(local,
                 derBuf, derSz,
-                WOLFSSL_RSA_LOAD_PUBLIC) != SSL_SUCCESS) {
+                WOLFSSL_RSA_LOAD_PUBLIC) != WOLFSSL_SUCCESS) {
         wolfSSL_RSA_free(local);
         local = NULL;
@@ -35322,6 +39190,6 @@
 #endif /* NO_RSA */
 
-#ifdef OPENSSL_EXTRA
-#ifndef NO_DSA
+#if !defined(NO_DSA) && \
+    (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL))
 /* return WOLFSSL_SUCCESS if success, WOLFSSL_FATAL_ERROR if error */
 int wolfSSL_DSA_LoadDer(WOLFSSL_DSA* dsa, const unsigned char* derBuf, int derSz)
@@ -35393,6 +39261,7 @@
     return WOLFSSL_SUCCESS;
 }
-#endif /* !NO_DSA */
-
+#endif /* !NO_DSA && (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */
+
+#ifdef OPENSSL_EXTRA
 #ifdef HAVE_ECC
 /* return WOLFSSL_SUCCESS if success, WOLFSSL_FATAL_ERROR if error */
@@ -35448,4 +39317,5 @@
 #if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH))
 /* return WOLFSSL_SUCCESS if success, WOLFSSL_FATAL_ERROR if error */
+#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2))
 int wolfSSL_DH_LoadDer(WOLFSSL_DH* dh, const unsigned char* derBuf, int derSz)
 {
@@ -35463,4 +39333,5 @@
         return WOLFSSL_FATAL_ERROR;
     }
+    dh->inSet = 1;
 
     if (SetDhExternal(dh) != WOLFSSL_SUCCESS) {
@@ -35471,4 +39342,5 @@
     return WOLFSSL_SUCCESS;
 }
+#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
 #endif /* ! NO_DH && WOLFSSL_QT || OPENSSL_ALL */
 
@@ -35488,8 +39360,8 @@
         wc_UnLockMutex(&rsa->refMutex);
 
-        return 1;
-    }
-
-    return 0;
+        return WOLFSSL_SUCCESS;
+    }
+
+    return WOLFSSL_FAILURE;
 }
 
@@ -35504,8 +39376,8 @@
         wc_UnLockMutex(&x509->refMutex);
 
-        return 1;
-    }
-
-    return 0;
+        return WOLFSSL_SUCCESS;
+    }
+
+    return WOLFSSL_FAILURE;
 }
 
@@ -36124,10 +39996,11 @@
 #endif
 
-#ifdef OPENSSL_EXTRA
-    #ifndef NO_CERTS
+#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
+    !defined(WOLFCRYPT_ONLY)
+#ifndef NO_CERTS
     void wolfSSL_X509_NAME_free(WOLFSSL_X509_NAME *name)
     {
         WOLFSSL_ENTER("wolfSSL_X509_NAME_free");
-        FreeX509Name(name, NULL);
+        FreeX509Name(name);
         XFREE(name, NULL, DYNAMIC_TYPE_X509);
     }
@@ -36147,5 +40020,5 @@
                 DYNAMIC_TYPE_X509);
         if (name != NULL) {
-            InitX509Name(name, 1);
+            InitX509Name(name, 1, NULL);
         }
         return name;
@@ -36156,5 +40029,5 @@
     WOLFSSL_X509_NAME* wolfSSL_X509_NAME_dup(WOLFSSL_X509_NAME *name)
     {
-        WOLFSSL_X509_NAME* dup = NULL;
+        WOLFSSL_X509_NAME* copy = NULL;
 
         WOLFSSL_ENTER("wolfSSL_X509_NAME_dup");
@@ -36165,212 +40038,53 @@
         }
 
-        if (!(dup = wolfSSL_X509_NAME_new())) {
+        if (!(copy = wolfSSL_X509_NAME_new())) {
             return NULL;
         }
 
         /* copy contents */
-        XMEMCPY(dup, name, sizeof(WOLFSSL_X509_NAME));
-        InitX509Name(dup, 1);
-        dup->sz = name->sz;
-
-        /* handle dynamic portions */
-        if (name->dynamicName) {
-            if (!(dup->name = (char*)XMALLOC(name->sz, 0,
-                                             DYNAMIC_TYPE_OPENSSL))) {
-                goto err;
-            }
-        }
-        XMEMCPY(dup->name, name->name, name->sz);
-    #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
-        !defined(NO_ASN)
-        if (!(dup->fullName.fullName = (char*)XMALLOC(name->fullName.fullNameLen,
-                                                   0, DYNAMIC_TYPE_OPENSSL))) {
-            goto err;
-        }
-        XMEMCPY(dup->fullName.fullName, name->fullName.fullName,
-            name->fullName.fullNameLen);
-    #endif
-
-        return dup;
-
-    err:
-        if (dup) {
-            if (dup->dynamicName && dup->name) {
-                XFREE(dup->name, 0, DYNAMIC_TYPE_OPENSSL);
-                dup->name = NULL;
-            }
-        #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
-            !defined(NO_ASN)
-            if (dup->fullName.fullName &&
-                dup->fullName.fullName != name->fullName.fullName) {
-                XFREE(dup->fullName.fullName, 0, DYNAMIC_TYPE_OPENSSL);
-                dup->fullName.fullName = NULL;
-            }
-        #endif
-            wolfSSL_X509_NAME_free(dup);
-        }
-        return NULL;
-    }
-
-#if defined(WOLFSSL_CERT_GEN)
-    /* helper function for CopyX509NameToCertName()
-     *
-     * returns WOLFSSL_SUCCESS on success
-     */
-    static int CopyX509NameEntry(char* out, int mx, char* in, int inLen)
+        InitX509Name(copy, 1, name->heap);
+        if (wolfSSL_X509_NAME_copy(name, copy) != WOLFSSL_SUCCESS) {
+            wolfSSL_X509_NAME_free(copy);
+            return NULL;
+        }
+
+        return copy;
+    }
+
+#ifdef WOLFSSL_CERT_GEN
+
+#if defined(WOLFSSL_CERT_REQ) || defined(WOLFSSL_CERT_EXT) || defined(OPENSSL_EXTRA)
+    /* Helper function to copy cert name from a WOLFSSL_X509_NAME structure to
+    * a Cert structure.
+    *
+    * returns length of DER on success and a negative error value on failure
+    */
+    static int CopyX509NameToCert(WOLFSSL_X509_NAME* n, byte* out)
     {
-        if (inLen > mx) {
-            WOLFSSL_MSG("Name too long");
-            XMEMCPY(out, in, mx);
-        }
-        else {
-            XMEMCPY(out, in, inLen);
-            out[inLen] = '\0';
-        }
-
-        /* make sure is null terminated */
-        out[mx-1] = '\0';
-
-        return WOLFSSL_SUCCESS;
-    }
-
-
-    /* Helper function to copy cert name from a WOLFSSL_X509_NAME structure to
-     * a CertName structure.
-     *
-     * returns WOLFSSL_SUCCESS on success and a negative error value on failure
-     */
-    static int CopyX509NameToCertName(WOLFSSL_X509_NAME* n, CertName* cName)
-    {
-        DecodedName* dn = NULL;
-
-        if (n == NULL || cName == NULL) {
-            return BAD_FUNC_ARG;
-        }
-
-        dn = &(n->fullName);
-
-        /* initialize cert name */
-        cName->country[0] = '\0';
-        cName->countryEnc = CTC_PRINTABLE;
-        cName->state[0] = '\0';
-        cName->stateEnc = CTC_UTF8;
-        cName->locality[0] = '\0';
-        cName->localityEnc = CTC_UTF8;
-        cName->sur[0] = '\0';
-        cName->surEnc = CTC_UTF8;
-        cName->org[0] = '\0';
-        cName->orgEnc = CTC_UTF8;
-        cName->unit[0] = '\0';
-        cName->unitEnc = CTC_UTF8;
-        cName->commonName[0] = '\0';
-        cName->commonNameEnc = CTC_UTF8;
-        cName->serialDev[0] = '\0';
-        cName->serialDevEnc = CTC_PRINTABLE;
-    #ifdef WOLFSSL_CERT_EXT
-        cName->busCat[0] = '\0';
-        cName->busCatEnc = CTC_UTF8;
-        cName->joiC[0] = '\0';
-        cName->joiCEnc = CTC_PRINTABLE;
-        cName->joiSt[0] = '\0';
-        cName->joiStEnc = CTC_PRINTABLE;
-    #endif
-        cName->email[0] = '\0';
-
-
-        /* ASN_COUNTRY_NAME */
-        WOLFSSL_MSG("Copy Country Name");
-        if (CopyX509NameEntry(cName->country, CTC_NAME_SIZE, dn->fullName + dn->cIdx,
-                    dn->cLen) != SSL_SUCCESS) {
-            return BUFFER_E;
-        }
-
-        /* ASN_ORGUNIT_NAME */
-        WOLFSSL_MSG("Copy Org Unit Name");
-        if (CopyX509NameEntry(cName->unit, CTC_NAME_SIZE, dn->fullName + dn->ouIdx,
-                    dn->ouLen) != SSL_SUCCESS) {
-            return BUFFER_E;
-        }
-
-        /* ASN_ORG_NAME */
-        WOLFSSL_MSG("Copy Org Name");
-        if (CopyX509NameEntry(cName->org, CTC_NAME_SIZE, dn->fullName + dn->oIdx,
-                    dn->oLen) != SSL_SUCCESS) {
-            return BUFFER_E;
-        }
-
-        /* ASN_STATE_NAME */
-        WOLFSSL_MSG("Copy State Name");
-        if (CopyX509NameEntry(cName->state, CTC_NAME_SIZE, dn->fullName + dn->stIdx,
-                    dn->stLen) != SSL_SUCCESS) {
-            return BUFFER_E;
-        }
-
-        /* ASN_LOCALITY_NAME */
-        WOLFSSL_MSG("Copy Locality Name");
-        if (CopyX509NameEntry(cName->locality, CTC_NAME_SIZE,
-                    dn->fullName + dn->lIdx, dn->lLen)
-                    != SSL_SUCCESS) {
-            return BUFFER_E;
-        }
-
-        /* ASN_SUR_NAME */
-        WOLFSSL_MSG("Copy Sur Name");
-        if (CopyX509NameEntry(cName->sur, CTC_NAME_SIZE, dn->fullName + dn->snIdx,
-                    dn->snLen) != SSL_SUCCESS) {
-            return BUFFER_E;
-        }
-
-        /* ASN_COMMON_NAME */
-        WOLFSSL_MSG("Copy Common Name");
-        if (CopyX509NameEntry(cName->commonName, CTC_NAME_SIZE,
-                    dn->fullName + dn->cnIdx, dn->cnLen)
-                    != SSL_SUCCESS) {
-            return BUFFER_E;
-        }
-
-        /* ASN_SERIAL_NUMBER */
-        WOLFSSL_MSG("Copy Serial Number of Device");
-        if (CopyX509NameEntry(cName->serialDev, CTC_NAME_SIZE,
-                    dn->fullName + dn->serialIdx, dn->serialLen)
-                    != SSL_SUCCESS) {
-            return BUFFER_E;
-        }
-
-    #ifdef WOLFSSL_CERT_EXT
-        /* ASN_BUS_CAT */
-        WOLFSSL_MSG("Copy Business Category");
-        if (CopyX509NameEntry(cName->busCat, CTC_NAME_SIZE,
-                    dn->fullName + dn->bcIdx, dn->bcLen)
-                    != SSL_SUCCESS) {
-            return BUFFER_E;
-        }
-
-        /* JoI Country */
-        WOLFSSL_MSG("Copy Jurisdiction of Incorporation Country");
-        if (CopyX509NameEntry(cName->joiC, CTC_NAME_SIZE,
-                    dn->fullName + dn->jcIdx, dn->jcLen)
-                    != SSL_SUCCESS) {
-            return BUFFER_E;
-        }
-
-        /* JoI State */
-        WOLFSSL_MSG("Copy Jurisdiction of Incorporation State");
-        if (CopyX509NameEntry(cName->joiSt, CTC_NAME_SIZE,
-                    dn->fullName + dn->jsIdx, dn->jsLen)
-                    != SSL_SUCCESS) {
-            return BUFFER_E;
-        }
-    #endif
-
-        WOLFSSL_MSG("Copy Email");
-        if (CopyX509NameEntry(cName->email, CTC_NAME_SIZE,
-                    dn->fullName + dn->emailIdx, dn->emailLen)
-                    != SSL_SUCCESS) {
-            return BUFFER_E;
-        }
-
-        return WOLFSSL_SUCCESS;
-    }
+        unsigned char* der = NULL;
+        int length = BAD_FUNC_ARG, ret;
+        word32 idx = 0;
+
+        ret = wolfSSL_i2d_X509_NAME(n, &der);
+        if (ret > (int)sizeof(CertName) || ret < 0) {
+            WOLFSSL_MSG("Name conversion error");
+            ret = MEMORY_E;
+        }
+
+        if (ret > 0) {
+            /* strip off sequence, this gets added on certificate creation */
+            ret = GetSequence(der, &idx, &length, ret);
+        }
+
+        if (ret > 0) {
+            XMEMCPY(out, der + idx, length);
+        }
+
+        if (der != NULL)
+            XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
+
+        return length;
+    }
+#endif
 
 #ifdef WOLFSSL_CERT_REQ
@@ -36382,9 +40096,18 @@
             return WOLFSSL_FAILURE;
 
-        ret = CopyX509NameToCertName(&req->subject, &cert->subject);
+
+        ret = CopyX509NameToCert(&req->subject, cert->sbjRaw);
+        if (ret < 0) {
+            WOLFSSL_MSG("REQ subject conversion error");
+            ret = MEMORY_E;
+        }
+        else {
+            ret = WOLFSSL_SUCCESS;
+        }
+
         if (ret == WOLFSSL_SUCCESS) {
             cert->version = req->version;
             cert->isCA = req->isCa;
-#ifdef WOLFSSL_CERT_EXT
+    #ifdef WOLFSSL_CERT_EXT
             if (req->subjKeyIdSz != 0) {
                 XMEMCPY(cert->skid, req->subjKeyId, req->subjKeyIdSz);
@@ -36394,10 +40117,38 @@
                 cert->keyUsage = req->keyUsage;
             /* Extended Key Usage not supported. */
-#endif
+    #endif
+    #ifdef WOLFSSL_CERT_REQ
+            XMEMCPY(cert->challengePw, req->challengePw, CTC_NAME_SIZE);
+            cert->challengePwPrintableString = req->challengePw[0] != 0;
+    #endif
+    #ifdef WOLFSSL_ALT_NAMES
+            cert->altNamesSz = FlattenAltNames(cert->altNames,
+                    sizeof(cert->altNames), req->altNames);
+    #endif /* WOLFSSL_ALT_NAMES */
         }
 
         return ret;
     }
-#endif
+#endif /* WOLFSSL_CERT_REQ */
+
+#ifdef WOLFSSL_ALT_NAMES
+    /* converts WOLFSSL_AN1_TIME to Cert form, returns positive size on
+     * success */
+    static int CertDateFromX509(byte* out, int outSz, WOLFSSL_ASN1_TIME* t)
+    {
+        int sz, i;
+
+        if (t->length + 1 >= outSz) {
+            return BUFFER_E;
+        }
+
+        out[0] = t->type;
+        sz = SetLength(t->length, out + 1) + 1;  /* gen tag */
+        for (i = 0; i < t->length; i++) {
+            out[sz + i] = t->data[i];
+        }
+        return t->length + sz;
+    }
+#endif /* WOLFSSL_ALT_NAMES */
 
     /* convert a WOLFSSL_X509 to a Cert structure for writing out */
@@ -36421,13 +40172,8 @@
     #ifdef WOLFSSL_ALT_NAMES
         if (x509->notBefore.length > 0) {
-            if ((x509->notBefore.length + 2) < CTC_DATE_SIZE) {
-                cert->beforeDate[0] = x509->notBefore.type;
-                cert->beforeDate[1] = x509->notBefore.length;
-                XMEMCPY(&cert->beforeDate[2], x509->notBefore.data,
-                        x509->notBefore.length);
-                cert->beforeDateSz = x509->notBefore.length + 2;
-            }
-            else {
-                WOLFSSL_MSG("Not before date too large");
+            cert->beforeDateSz = CertDateFromX509(cert->beforeDate,
+                        CTC_DATE_SIZE, &x509->notBefore);
+            if (cert->beforeDateSz <= 0){
+                WOLFSSL_MSG("Not before date error");
                 return WOLFSSL_FAILURE;
             }
@@ -36436,14 +40182,10 @@
             cert->beforeDateSz = 0;
         }
+
         if (x509->notAfter.length > 0) {
-            if ((x509->notAfter.length + 2) < CTC_DATE_SIZE) {
-                cert->afterDate[0] = x509->notAfter.type;
-                cert->afterDate[1] = x509->notAfter.length;
-                XMEMCPY(&cert->afterDate[2], x509->notAfter.data,
-                        x509->notAfter.length);
-                cert->afterDateSz = x509->notAfter.length + 2;
-            }
-            else {
-                WOLFSSL_MSG("Not after date too large");
+            cert->afterDateSz = CertDateFromX509(cert->afterDate,
+                        CTC_DATE_SIZE, &x509->notAfter);
+            if (cert->afterDateSz <= 0){
+                WOLFSSL_MSG("Not after date error");
                 return WOLFSSL_FAILURE;
             }
@@ -36455,5 +40197,4 @@
         cert->altNamesSz = FlattenAltNames(cert->altNames,
                 sizeof(cert->altNames), x509->altNames);
-
     #endif /* WOLFSSL_ALT_NAMES */
 
@@ -36502,10 +40243,21 @@
     #endif
 
-        if (x509->serialSz <= CTC_SERIAL_SIZE) {
-            XMEMCPY(cert->serial, x509->serial, x509->serialSz);
-        }
-        else {
-            WOLFSSL_MSG("Serial size error");
+        /* set serial number */
+        if (x509->serialSz > 0) {
+        #if defined(OPENSSL_EXTRA)
+            byte serial[EXTERNAL_SERIAL_SIZE];
+            int  serialSz = EXTERNAL_SERIAL_SIZE;
+
+            ret = wolfSSL_X509_get_serial_number(x509, serial, &serialSz);
+            if (ret != WOLFSSL_SUCCESS) {
+                WOLFSSL_MSG("Serial size error");
+                return WOLFSSL_FAILURE;
+            }
+            XMEMCPY(cert->serial, serial, serialSz);
+            cert->serialSz = serialSz;
+        #else
+            WOLFSSL_MSG("Getting X509 serial number not supported");
             return WOLFSSL_FAILURE;
+        #endif
         }
 
@@ -36513,19 +40265,26 @@
         if (x509->issuerSet)
             cert->selfSigned = 0;
-        if ((ret = CopyX509NameToCertName(&(x509->issuer), &(cert->issuer)))
-            != WOLFSSL_SUCCESS) {
-            WOLFSSL_MSG("Error copying over issuer names");
-            WOLFSSL_LEAVE("wolfSSL_X509_to_Cert()", ret);
-            return WOLFSSL_FAILURE;
-        }
-        if ((ret = CopyX509NameToCertName(&(x509->subject), &(cert->subject)))
-            != WOLFSSL_SUCCESS) {
-            WOLFSSL_MSG("Error copying over subject names");
-            WOLFSSL_LEAVE("wolfSSL_X509_to_Cert()", ret);
-            return WOLFSSL_FAILURE;
-        }
+
+    #if defined(WOLFSSL_CERT_EXT) || defined(OPENSSL_EXTRA)
+        ret = CopyX509NameToCert(&x509->subject, cert->sbjRaw);
+        if (ret < 0) {
+            WOLFSSL_MSG("Subject conversion error");
+            return MEMORY_E;
+        }
+        if (cert->selfSigned) {
+            XMEMCPY(cert->issRaw, cert->sbjRaw, sizeof(CertName));
+        }
+        else {
+            ret = CopyX509NameToCert(&x509->issuer, cert->issRaw);
+            if (ret < 0) {
+                WOLFSSL_MSG("Issuer conversion error");
+                return MEMORY_E;
+            }
+        }
+    #endif
 
         cert->heap = x509->heap;
 
+        (void)ret;
         return WOLFSSL_SUCCESS;
     }
@@ -36540,7 +40299,14 @@
         int sigType = WOLFSSL_FAILURE;
 
+    #if !defined(NO_PWDBASED) && defined(OPENSSL_EXTRA)
         /* Convert key type and hash algorithm to a signature algorithm */
-        if (wolfSSL_EVP_get_hashinfo(md, &hashType, NULL) == WOLFSSL_FAILURE)
+        if (wolfSSL_EVP_get_hashinfo(md, &hashType, NULL) == WOLFSSL_FAILURE) {
             return WOLFSSL_FAILURE;
+        }
+    #else
+        (void)md;
+        WOLFSSL_MSG("Cannot get hashinfo when NO_PWDBASED is defined");
+        return WOLFSSL_FAILURE;
+    #endif /* !defined(NO_PWDBASED) */
 
 
@@ -36599,8 +40365,9 @@
      * return WOLFSSL_SUCCESS on success
      */
-    static int wolfSSL_X509_make_der(WOLFSSL_X509* x509, int req,
-            unsigned char* der, int* derSz)
+    static int wolfssl_x509_make_der(WOLFSSL_X509* x509, int req,
+            unsigned char* der, int* derSz, int includeSig)
     {
-        int ret;
+        int ret = WOLFSSL_FAILURE;
+        int totalLen;
         Cert cert;
         void* key = NULL;
@@ -36611,4 +40378,7 @@
     #ifdef HAVE_ECC
         ecc_key ecc;
+    #endif
+    #ifndef NO_DSA
+        DsaKey dsa;
     #endif
         WC_RNG rng;
@@ -36669,6 +40439,23 @@
         }
     #endif
-        if (key == NULL)
+    #ifndef NO_DSA
+        if (x509->pubKeyOID == DSAk) {
+            type = DSA_TYPE;
+            ret = wc_InitDsaKey(&dsa);
+            if (ret != 0)
+                return ret;
+            ret = wc_DsaPublicKeyDecode(x509->pubKey.buffer, &idx, &dsa,
+                                                           x509->pubKey.length);
+            if (ret != 0) {
+                wc_FreeDsaKey(&dsa);
+                return ret;
+            }
+            key = (void*)&dsa;
+        }
+    #endif
+        if (key == NULL) {
+            WOLFSSL_MSG("No public key found for certificate");
             return WOLFSSL_FAILURE;
+        }
 
         /* Make the body of the certificate request. */
@@ -36687,8 +40474,61 @@
             wc_FreeRng(&rng);
         }
-        if (ret < 0) {
-            return ret;
-        }
-
+        if (ret <= 0) {
+            ret = WOLFSSL_FAILURE;
+            goto cleanup;
+        }
+
+        if ((x509->serialSz == 0) &&
+                (cert.serialSz <= EXTERNAL_SERIAL_SIZE) &&
+                (cert.serialSz > 0)) {
+        #if defined(OPENSSL_EXTRA)
+            WOLFSSL_ASN1_INTEGER *i = wolfSSL_ASN1_INTEGER_new();
+
+            if (i == NULL) {
+                WOLFSSL_MSG("wolfSSL_ASN1_INTEGER_new error");
+                ret = WOLFSSL_FAILURE;
+                goto cleanup;
+            }
+            else {
+                i->length = cert.serialSz + 2;
+                i->data[0] = ASN_INTEGER;
+                i->data[1] = cert.serialSz;
+                XMEMCPY(i->data + 2, cert.serial, cert.serialSz);
+                if (wolfSSL_X509_set_serialNumber(x509, i) != WOLFSSL_SUCCESS) {
+                    WOLFSSL_MSG("Issue setting generated serial number");
+                    wolfSSL_ASN1_INTEGER_free(i);
+                    ret = WOLFSSL_FAILURE;
+                    goto cleanup;
+                }
+                wolfSSL_ASN1_INTEGER_free(i);
+            }
+        #else
+            WOLFSSL_MSG("ASN1_INTEGER API not in build");
+
+            ret = WOLFSSL_FAILURE;
+            goto cleanup;
+        #endif /* OPENSSL_EXTRA */
+        }
+
+        if (includeSig) {
+            if (!x509->sig.buffer) {
+                WOLFSSL_MSG("No signature buffer");
+                ret = WOLFSSL_FAILURE;
+                goto cleanup;
+            }
+            totalLen = AddSignature(NULL, ret, NULL, x509->sig.length,
+                                  x509->sigOID);
+            if (totalLen > *derSz) {
+                WOLFSSL_MSG("Output der buffer too short");
+                ret = WOLFSSL_FAILURE;
+                goto cleanup;
+            }
+            ret = AddSignature(der, ret, x509->sig.buffer,
+                               x509->sig.length, x509->sigOID);
+        }
+
+        *derSz = ret;
+        ret = WOLFSSL_SUCCESS;
+cleanup:
         /* Dispose of the public key object. */
     #ifndef NO_RSA
@@ -36700,7 +40540,6 @@
             wc_ecc_free(&ecc);
     #endif
-        *derSz = ret;
-
-        return WOLFSSL_SUCCESS;
+
+        return ret;
     }
 
@@ -36723,4 +40562,6 @@
         WC_RNG rng;
 
+        (void)req;
+
         sigType = wolfSSL_sigTypeFromPKEY(md, pkey);
         if (sigType == WOLFSSL_FAILURE)
@@ -36742,5 +40583,5 @@
     #endif
 
-        /* Sign the certificate request body. */
+        /* Sign the certificate (request) body. */
         ret = wc_InitRng(&rng);
         if (ret != 0)
@@ -36750,23 +40591,68 @@
         if (ret < 0)
             return ret;
+        derSz = ret;
+
+        /* Extract signature from buffer */
+        {
+            word32 idx = 0;
+            int    len = 0;
+
+            /* Read top level sequence */
+            if (GetSequence(der, &idx, &len, derSz) < 0) {
+                WOLFSSL_MSG("GetSequence error");
+                return WOLFSSL_FATAL_ERROR;
+            }
+            /* Move idx to signature */
+            idx += certBodySz;
+            /* Read signature algo sequence */
+            if (GetSequence(der, &idx, &len, derSz) < 0) {
+                WOLFSSL_MSG("GetSequence error");
+                return WOLFSSL_FATAL_ERROR;
+            }
+            idx += len;
+            /* Read signature bit string */
+            if (CheckBitString(der, &idx, &len, derSz, 0, NULL) != 0) {
+                WOLFSSL_MSG("CheckBitString error");
+                return WOLFSSL_FATAL_ERROR;
+            }
+            /* Sanity check */
+            if (idx + len != (word32)derSz) {
+                WOLFSSL_MSG("unexpected asn1 structure");
+                return WOLFSSL_FATAL_ERROR;
+            }
+            x509->sig.length = 0;
+            if (x509->sig.buffer)
+                XFREE(x509->sig.buffer, x509->heap, DYNAMIC_TYPE_SIGNATURE);
+            x509->sig.buffer = (byte*)XMALLOC(len, x509->heap,
+                                              DYNAMIC_TYPE_SIGNATURE);
+            if (!x509->sig.buffer) {
+                WOLFSSL_MSG("malloc error");
+                return WOLFSSL_FATAL_ERROR;
+            }
+            XMEMCPY(x509->sig.buffer, der + idx, len);
+            x509->sig.length = len;
+        }
 
         /* Put in the new certificate encoding into the x509 object. */
         FreeDer(&x509->derCert);
         type = CERT_TYPE;
-    #ifdef WOLFSSL_REQ_CERT
+    #ifdef WOLFSSL_CERT_REQ
         if (req) {
             type = CERTREQ_TYPE;
         }
     #endif
-
-        if (AllocDer(&x509->derCert, ret, type, NULL) != 0)
+        if (AllocDer(&x509->derCert, derSz, type, NULL) != 0)
             return WOLFSSL_FATAL_ERROR;
-        XMEMCPY(x509->derCert->buffer, der, ret);
-        x509->derCert->length = ret;
-
-        (void)req;
+        XMEMCPY(x509->derCert->buffer, der, derSz);
+        x509->derCert->length = derSz;
+
         return ret;
     }
 
+
+    #ifndef WC_MAX_X509_GEN
+        /* able to override max size until dynamic buffer created */
+        #define WC_MAX_X509_GEN 4096
+    #endif
 
     /* returns the size of signature on success */
@@ -36775,77 +40661,97 @@
     {
         int  ret;
-        byte der[4096]; /* @TODO dynamic set based on expected cert size */
-        int  derSz = sizeof(der);
+        /* @TODO dynamic set based on expected cert size */
+        byte *der = (byte *)XMALLOC(WC_MAX_X509_GEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        int  derSz = WC_MAX_X509_GEN;
 
         WOLFSSL_ENTER("wolfSSL_X509_sign");
 
-        if (x509 == NULL || pkey == NULL || md == NULL)
-            return WOLFSSL_FAILURE;
+        if (x509 == NULL || pkey == NULL || md == NULL) {
+            ret = WOLFSSL_FAILURE;
+            goto out;
+        }
 
         x509->sigOID = wolfSSL_sigTypeFromPKEY((WOLFSSL_EVP_MD*)md, pkey);
-        if ((ret = wolfSSL_X509_make_der(x509, 0, der, &derSz)) !=
+        if ((ret = wolfssl_x509_make_der(x509, 0, der, &derSz, 0)) !=
                 WOLFSSL_SUCCESS) {
             WOLFSSL_MSG("Unable to make DER for X509");
             WOLFSSL_LEAVE("wolfSSL_X509_sign", ret);
-            return WOLFSSL_FAILURE;
-        }
-
-        ret = wolfSSL_X509_resign_cert(x509, 0, der, sizeof(der), derSz,
+            (void)ret;
+            ret = WOLFSSL_FAILURE;
+            goto out;
+        }
+
+        ret = wolfSSL_X509_resign_cert(x509, 0, der, WC_MAX_X509_GEN, derSz,
                 (WOLFSSL_EVP_MD*)md, pkey);
         if (ret <= 0) {
             WOLFSSL_LEAVE("wolfSSL_X509_sign", ret);
+            ret = WOLFSSL_FAILURE;
+            goto out;
+        }
+
+    out:
+	if (der)
+            XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+        return ret;
+    }
+
+#if defined(OPENSSL_EXTRA)
+    int wolfSSL_X509_sign_ctx(WOLFSSL_X509 *x509, WOLFSSL_EVP_MD_CTX *ctx)
+    {
+        WOLFSSL_ENTER("wolfSSL_X509_sign_ctx");
+
+        if (!x509 || !ctx || !ctx->pctx || !ctx->pctx->pkey) {
+            WOLFSSL_MSG("Bad parameter");
             return WOLFSSL_FAILURE;
         }
 
-        return ret;
-    }
-
-
-    /* Converts the x509 name structure into DER format.
-     *
-     * out  pointer to either a pre setup buffer or a pointer to null for
-     *      creating a dynamic buffer. In the case that a pre-existing buffer is
-     *      used out will be incremented the size of the DER buffer on success.
-     *
-     * returns the size of the buffer on success, or negative value with failure
-     */
-    int wolfSSL_i2d_X509_NAME(WOLFSSL_X509_NAME* name, unsigned char** out)
+        return wolfSSL_X509_sign(x509, ctx->pctx->pkey, wolfSSL_EVP_MD_CTX_md(ctx));
+    }
+#endif /* OPENSSL_EXTRA */
+#endif /* WOLFSSL_CERT_GEN */
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)
+
+    WOLFSSL_X509_NAME *wolfSSL_d2i_X509_NAME(WOLFSSL_X509_NAME **name,
+                                             unsigned char **in, long length)
     {
-        CertName cName;
-        unsigned char buf[256]; /* ASN_MAX_NAME */
-        int sz;
-        WOLFSSL_ENTER("wolfSSL_i2d_X509_NAME");
-
-        if (out == NULL || name == NULL) {
-            return BAD_FUNC_ARG;
-        }
-        XMEMSET(&cName, 0, sizeof(CertName));
-
-        if (CopyX509NameToCertName(name, &cName) != SSL_SUCCESS) {
-            WOLFSSL_MSG("Error converting x509 name to internal CertName");
-            return SSL_FATAL_ERROR;
-        }
-
-        sz = SetName(buf, sizeof(buf), &cName);
-        if (sz < 0) {
-            return sz;
-        }
-
-        /* using buffer passed in */
-        if (*out != NULL) {
-            XMEMCPY(*out, buf, sz);
-            *out += sz;
-        }
-        else {
-            *out = (unsigned char*)XMALLOC(sz, NULL, DYNAMIC_TYPE_OPENSSL);
-            if (*out == NULL) {
-                return MEMORY_E;
-            }
-            XMEMCPY(*out, buf, sz);
-        }
-
-        return sz;
-    }
-#endif /* WOLFSSL_CERT_GEN */
+        WOLFSSL_X509_NAME* tmp = NULL;
+        DecodedCert cert;
+
+        WOLFSSL_ENTER("wolfSSL_d2i_X509_NAME");
+
+        if (!in || !*in || length <= 0) {
+            WOLFSSL_MSG("Bad argument");
+            return NULL;
+        }
+
+        /* Set the X509_NAME buffer as the input data for cert.
+         * in is NOT a full certificate. Just the name. */
+        InitDecodedCert(&cert, *in, (word32)length, NULL);
+
+        /* Parse the X509 subject name */
+        if (GetName(&cert, SUBJECT, (int)length) != 0) {
+            WOLFSSL_MSG("WOLFSSL_X509_NAME parse error");
+            goto cleanup;
+        }
+
+        if (!(tmp = wolfSSL_X509_NAME_new())) {
+            WOLFSSL_MSG("wolfSSL_X509_NAME_new error");
+            goto cleanup;
+        }
+
+        if (wolfSSL_X509_NAME_copy((WOLFSSL_X509_NAME*)cert.subjectName,
+                    tmp) != WOLFSSL_SUCCESS) {
+            wolfSSL_X509_NAME_free(tmp);
+            tmp = NULL;
+            goto cleanup;
+        }
+
+        if (name)
+            *name = tmp;
+cleanup:
+        FreeDecodedCert(&cert);
+        return tmp;
+    }
 
 
@@ -36888,7 +40794,8 @@
     }
 
-
-    WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509(WOLFSSL_BIO *bp, WOLFSSL_X509 **x,
-                                                 pem_password_cb *cb, void *u)
+#ifndef NO_BIO
+
+    static WOLFSSL_X509 *loadX509orX509REQFromPemBio(WOLFSSL_BIO *bp,
+            WOLFSSL_X509 **x, pem_password_cb *cb, void *u, int type)
     {
         WOLFSSL_X509* x509 = NULL;
@@ -36896,10 +40803,10 @@
         unsigned char* pem = NULL;
         int pemSz;
-        long  i = 0, l;
+        long  i = 0, l, footerSz;
         const char* footer = NULL;
 
-        WOLFSSL_ENTER("wolfSSL_PEM_read_bio_X509");
-
-        if (bp == NULL) {
+        WOLFSSL_ENTER("loadX509orX509REQFromPemBio");
+
+        if (bp == NULL || (type != CERT_TYPE && type != CERTREQ_TYPE)) {
             WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_X509", BAD_FUNC_ARG);
             return NULL;
@@ -36919,19 +40826,25 @@
 
         i = 0;
-        if (wc_PemGetHeaderFooter(CERT_TYPE, NULL, &footer) != 0) {
+        if (wc_PemGetHeaderFooter(type, NULL, &footer) != 0) {
             XFREE(pem, 0, DYNAMIC_TYPE_PEM);
             return NULL;
         }
+        footerSz = (long)XSTRLEN(footer);
 
         /* TODO: Inefficient
-         * reading in one byte at a time until see "END CERTIFICATE"
+         * reading in one byte at a time until see the footer
          */
         while ((l = wolfSSL_BIO_read(bp, (char *)&pem[i], 1)) == 1) {
             i++;
-            if (i > 26 && XMEMCMP((char *)&pem[i-26], footer, 25) == 0) {
-                if (pem[i-1] == '\r') {
-                    /* found \r , Windows line ending is \r\n so try to read one
-                     * more byte for \n, ignoring return value */
-                    (void)wolfSSL_BIO_read(bp, (char *)&pem[i++], 1);
+            if (i > footerSz && XMEMCMP((char *)&pem[i-footerSz], footer,
+                    footerSz) == 0) {
+                if (wolfSSL_BIO_read(bp, (char *)&pem[i], 1) == 1) {
+                    /* attempt to read newline following footer */
+                    i++;
+                    if (pem[i-1] == '\r') {
+                        /* found \r , Windows line ending is \r\n so try to read one
+                         * more byte for \n, ignoring return value */
+                        (void)wolfSSL_BIO_read(bp, (char *)&pem[i++], 1);
+                    }
                 }
                 break;
@@ -36943,6 +40856,12 @@
     #endif
         pemSz = (int)i;
-        x509 = wolfSSL_X509_load_certificate_buffer(pem, pemSz,
-                                                              WOLFSSL_FILETYPE_PEM);
+    #ifdef WOLFSSL_CERT_REQ
+        if (type == CERTREQ_TYPE)
+            x509 = wolfSSL_X509_REQ_load_certificate_buffer(pem, pemSz,
+                                                        WOLFSSL_FILETYPE_PEM);
+        else
+    #endif
+            x509 = wolfSSL_X509_load_certificate_buffer(pem, pemSz,
+                                                        WOLFSSL_FILETYPE_PEM);
 
         if (x != NULL) {
@@ -36960,4 +40879,19 @@
         return x509;
     }
+
+
+    WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509(WOLFSSL_BIO *bp, WOLFSSL_X509 **x,
+                                                 pem_password_cb *cb, void *u)
+    {
+        return loadX509orX509REQFromPemBio(bp, x, cb, u, CERT_TYPE);
+    }
+
+#ifdef WOLFSSL_CERT_REQ
+    WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509_REQ(WOLFSSL_BIO *bp, WOLFSSL_X509 **x,
+                                                 pem_password_cb *cb, void *u)
+    {
+        return loadX509orX509REQFromPemBio(bp, x, cb, u, CERTREQ_TYPE);
+    }
+#endif
 
     WOLFSSL_X509_CRL *wolfSSL_PEM_read_bio_X509_CRL(WOLFSSL_BIO *bp,
@@ -37013,4 +40947,6 @@
 #endif
     }
+
+#endif /* !NO_BIO */
 
 #if !defined(NO_FILESYSTEM)
@@ -37117,4 +41053,6 @@
 #endif
 
+#ifdef WOLFSSL_CERT_GEN
+#ifndef NO_BIO
     int wolfSSL_PEM_write_X509(XFILE fp, WOLFSSL_X509* x)
     {
@@ -37141,4 +41079,6 @@
         return ret;
     }
+#endif /* !NO_BIO */
+#endif /* WOLFSSL_CERT_GEN */
 #endif /* !NO_FILESYSTEM */
 
@@ -37152,4 +41092,6 @@
     #define PEM_HDR_FIN_EOL_NULL_TERM "-----\0"
     #define PEM_HDR_FIN_EOL_SZ     6
+
+#ifndef NO_BIO
 
     int wolfSSL_PEM_read_bio(WOLFSSL_BIO* bio, char **name, char **header,
@@ -37439,4 +41381,5 @@
     }
 #endif
+#endif /* !NO_BIO */
 
     int wolfSSL_PEM_get_EVP_CIPHER_INFO(char* header, EncryptedInfo* cipher)
@@ -37480,4 +41423,5 @@
     }
 
+#ifndef NO_BIO
     /*
      * bp : bio to read X509 from
@@ -37498,7 +41442,11 @@
         return wolfSSL_PEM_read_bio_X509(bp, x, cb, u);
     }
-
-
+#endif /* !NO_BIO */
+
+
+#endif /* OPENSSL_EXTRA || OPENSSL_ALL */
 #ifdef OPENSSL_ALL
+
+#ifndef NO_BIO
     /* create and return a new WOLFSSL_X509_PKEY structure or NULL on failure */
     static WOLFSSL_X509_PKEY* wolfSSL_X509_PKEY_new(void* heap)
@@ -37531,4 +41479,5 @@
         return WOLFSSL_SUCCESS;
     }
+#endif /* !NO_BIO */
 
 
@@ -37538,8 +41487,10 @@
         if (xPkey != NULL) {
             wolfSSL_EVP_PKEY_free(xPkey->dec_pkey);
-        }
-        XFREE(xPkey, xPkey->heap, DYNAMIC_TYPE_KEY);
-    }
-
+            XFREE(xPkey, xPkey->heap, DYNAMIC_TYPE_KEY);
+        }
+    }
+
+
+#ifndef NO_BIO
 
     /* Takes control of x509 on success
@@ -37581,4 +41532,159 @@
     }
 
+    /**
+     * This read one structure from bio and returns the read structure
+     * in the appropriate output parameter (x509, crl, x_pkey). The
+     * output parameters must be set to NULL.
+     * @param bio    Input for reading structures
+     * @param cb     Password callback
+     * @param x509   Output
+     * @param crl    Output
+     * @param x_pkey Output
+     * @return WOLFSSL_SUCCESSS on success and WOLFSSL_FAILURE otherwise
+     */
+    static int wolfSSL_PEM_X509_X509_CRL_X509_PKEY_read_bio(
+            WOLFSSL_BIO* bio, pem_password_cb* cb,
+            WOLFSSL_X509** x509, WOLFSSL_X509_CRL** crl, WOLFSSL_X509_PKEY** x_pkey)
+    {
+
+#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)
+        char* pem = NULL;
+        long  i = pem_struct_min_sz, l;
+        const char* header = NULL;
+        const char* headerEnd = NULL;
+        const char* footer = NULL;
+        const char* footerEnd = NULL;
+        DerBuffer* der = NULL;
+
+        (void)cb;
+
+        if (!bio || !x509 || *x509 || !crl || *crl || !x_pkey || *x_pkey) {
+            WOLFSSL_MSG("Bad input parameter or output parameters "
+                        "not set to a NULL value.");
+            return WOLFSSL_FAILURE;
+        }
+
+        if ((l = wolfSSL_BIO_get_len(bio)) <= 0) {
+    #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
+            /* No certificate in buffer */
+            WOLFSSL_ERROR(ASN_NO_PEM_HEADER);
+    #endif
+            return WOLFSSL_FAILURE;
+        }
+
+        pem = (char*)XMALLOC(l, 0, DYNAMIC_TYPE_PEM);
+        if (pem == NULL)
+            return WOLFSSL_FAILURE;
+
+        if (wolfSSL_BIO_read(bio, &pem[0], pem_struct_min_sz) !=
+                pem_struct_min_sz) {
+            goto err;
+        }
+
+        /* Read the header and footer */
+        while (wolfSSL_BIO_read(bio, &pem[i], 1) == 1) {
+            i++;
+            if (!header)
+                header = XSTRNSTR(pem, "-----BEGIN ", (unsigned int)i);
+            else if (header) {
+                if (!headerEnd) {
+                    headerEnd = XSTRNSTR(header + XSTR_SIZEOF("-----BEGIN "),
+                            "-----",
+                            (unsigned int)
+                            (i - (header + XSTR_SIZEOF("-----BEGIN ") - pem)));
+                    if (headerEnd) {
+                        headerEnd += XSTR_SIZEOF("-----");
+                        /* Read in the newline */
+                        (void)wolfSSL_BIO_read(bio, &pem[i], 1);
+                        i++;
+                        if (*headerEnd != '\n' && *headerEnd != '\r') {
+                            WOLFSSL_MSG("Missing newline after header");
+                            goto err;
+                        }
+                    }
+                }
+                else if (!footer) {
+                    footer = XSTRNSTR(headerEnd, "-----END ",
+                            (unsigned int)(i - (headerEnd - pem)));
+                }
+                else if (!footerEnd) {
+                    footerEnd = XSTRNSTR(footer + XSTR_SIZEOF("-----"),
+                            "-----", (unsigned int)(i -
+                                (footer + XSTR_SIZEOF("-----") - pem)));
+                    if (footerEnd) {
+                        footerEnd += XSTR_SIZEOF("-----");
+                        /* Now check that footer matches header */
+                        if (XMEMCMP(header + XSTR_SIZEOF("-----BEGIN "),
+                                    footer + XSTR_SIZEOF("-----END "),
+                            headerEnd - (header + XSTR_SIZEOF("-----BEGIN ")))
+                                != 0) {
+                            WOLFSSL_MSG("Header and footer don't match");
+                            goto err;
+                        }
+                        /* header and footer match */
+                        break;
+                    }
+                }
+                else {
+                    break;
+                }
+            }
+        }
+        if (!footerEnd) {
+            /* Only check footerEnd since it is set last */
+            WOLFSSL_ERROR(ASN_NO_PEM_HEADER);
+            goto err;
+        }
+        else {
+            if (headerEnd - header ==
+                    XSTR_SIZEOF("-----BEGIN CERTIFICATE-----") &&
+                    XMEMCMP(header, "-----BEGIN CERTIFICATE-----",
+                            XSTR_SIZEOF("-----BEGIN CERTIFICATE-----")) == 0) {
+                /* We have a certificate */
+                WOLFSSL_MSG("Parsing x509 cert");
+                *x509 = wolfSSL_X509_load_certificate_buffer(
+                        (const unsigned char*) header,
+                        (int)(footerEnd - header), WOLFSSL_FILETYPE_PEM);
+                if (!*x509) {
+                    WOLFSSL_MSG("wolfSSL_X509_load_certificate_buffer error");
+                    goto err;
+                }
+            }
+#ifdef HAVE_CRL
+            else if (headerEnd - header ==
+                    XSTR_SIZEOF("-----BEGIN X509 CRL-----") &&
+                    XMEMCMP(header, "-----BEGIN X509 CRL-----",
+                            XSTR_SIZEOF("-----BEGIN X509 CRL-----")) == 0) {
+                /* We have a crl */
+                WOLFSSL_MSG("Parsing crl");
+                if((PemToDer((const unsigned char*) header, footerEnd - header,
+                        CRL_TYPE, &der, NULL, NULL, NULL)) < 0) {
+                    WOLFSSL_MSG("PemToDer error");
+                    goto err;
+                }
+                *crl = wolfSSL_d2i_X509_CRL(NULL, der->buffer, der->length);
+                if (!*crl) {
+                    WOLFSSL_MSG("wolfSSL_d2i_X509_CRL error");
+                    goto err;
+                }
+            }
+#endif
+            else {
+                /* TODO support WOLFSSL_X509_PKEY as well */
+                WOLFSSL_MSG("Unsupported PEM structure");
+                goto err;
+            }
+        }
+
+        XFREE(pem, 0, DYNAMIC_TYPE_PEM);
+        return WOLFSSL_SUCCESS;
+err:
+        if (pem)
+            XFREE(pem, 0, DYNAMIC_TYPE_PEM);
+        if (der)
+            FreeDer(&der);
+        return WOLFSSL_FAILURE;
+#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */
+    }
 
     /*
@@ -37594,26 +41700,19 @@
         pem_password_cb* cb, void* u)
     {
-        WOLF_STACK_OF(WOLFSSL_X509_INFO)* localSk;
-        WOLFSSL_X509* x509 = NULL;
+        WOLF_STACK_OF(WOLFSSL_X509_INFO)* localSk = NULL;
         int ret = WOLFSSL_SUCCESS;
 
+        (void)u;
+
         WOLFSSL_ENTER("wolfSSL_PEM_X509_INFO_read_bio");
 
-        /* attempt to used passed in stack or create a new one */
-        if (sk != NULL) {
-            localSk = sk;
-        }
-        else {
-            localSk = wolfSSL_sk_X509_INFO_new_null();
-        }
-        if (localSk == NULL) {
-            WOLFSSL_LEAVE("wolfSSL_PEM_X509_INFO_read_bio", MEMORY_E);
-            return NULL;
-        }
-
         /* parse through BIO and push new info's found onto stack */
-        do {
-            x509 = wolfSSL_PEM_read_bio_X509(bio, NULL, cb, u);
-            if (x509 != NULL) {
+        while (1) {
+            WOLFSSL_X509      *x509 = NULL;
+            WOLFSSL_X509_CRL  *crl  = NULL;
+            WOLFSSL_X509_PKEY *x_pkey = NULL;
+
+            if (wolfSSL_PEM_X509_X509_CRL_X509_PKEY_read_bio(bio, cb,
+                    &x509, &crl, &x_pkey) == WOLFSSL_SUCCESS) {
                 WOLFSSL_X509_INFO* current;
 
@@ -37621,18 +41720,59 @@
                 if (current == NULL) {
                     WOLFSSL_LEAVE("wolfSSL_PEM_X509_INFO_read_bio", MEMORY_E);
+                    wolfSSL_sk_free(localSk);
                     return NULL;
                 }
-                ret = wolfSSL_X509_INFO_set(current, x509);
-                if (ret  != WOLFSSL_SUCCESS) {
-                    wolfSSL_X509_free(x509);
+                if (x509) {
+                    ret = wolfSSL_X509_INFO_set(current, x509);
+                }
+                else if (crl) {
+                    current->crl = crl;
+                    ret = WOLFSSL_SUCCESS;
+                }
+                else if (x_pkey) {
+                    current->x_pkey = x_pkey;
+                    ret = WOLFSSL_SUCCESS;
                 }
                 else {
+                    WOLFSSL_MSG("No output parameters set");
+                    WOLFSSL_LEAVE("wolfSSL_PEM_X509_INFO_read_bio", WOLFSSL_FAILURE);
+                    wolfSSL_sk_free(localSk);
+                    wolfSSL_X509_INFO_free(current);
+                    return NULL;
+                }
+                if (ret != WOLFSSL_SUCCESS) {
+                    wolfSSL_X509_free(x509);
+#ifdef HAVE_CRL
+                    wolfSSL_X509_CRL_free(crl);
+#endif
+                    wolfSSL_X509_PKEY_free(x_pkey);
+                }
+                else {
+                    if (!localSk) {
+                        /* attempt to used passed in stack
+                         * or create a new one */
+                        if (sk != NULL) {
+                            localSk = sk;
+                        }
+                        else {
+                            localSk = wolfSSL_sk_X509_INFO_new_null();
+                        }
+                        if (localSk == NULL) {
+                            WOLFSSL_LEAVE("wolfSSL_PEM_X509_INFO_read_bio",
+                                    MEMORY_E);
+                            return NULL;
+                        }
+                    }
                     wolfSSL_sk_X509_INFO_push(localSk, current);
                 }
             }
-        } while (x509 != NULL && ret == WOLFSSL_SUCCESS);
+            else {
+                break;
+            }
+        }
         WOLFSSL_LEAVE("wolfSSL_PEM_X509_INFO_read_bio", ret);
         return localSk;
     }
+#endif /* !NO_BIO */
 #endif /* OPENSSL_ALL */
 
@@ -37641,5 +41781,6 @@
         WOLFSSL_ENTER("wolfSSL_X509_NAME_ENTRY_free");
         if (ne != NULL) {
-            if (ne->value != NULL && ne->value != &(ne->data)) {
+            wolfSSL_ASN1_OBJECT_free(ne->object);
+            if (ne->value != NULL) {
                 wolfSSL_ASN1_STRING_free(ne->value);
             }
@@ -37657,5 +41798,4 @@
         if (ne != NULL) {
             XMEMSET(ne, 0, sizeof(WOLFSSL_X509_NAME_ENTRY));
-            ne->value = &(ne->data);
         }
 
@@ -37696,4 +41836,5 @@
             }
             ne->nid = nid;
+            ne->object = wolfSSL_OBJ_nid2obj_ex(nid, ne->object);
             ne->value = wolfSSL_ASN1_STRING_type_new(type);
             if (ne->value != NULL) {
@@ -37707,4 +41848,10 @@
 
 
+    /* Creates a new entry given the NID, type, and data
+     * "dataSz" is number of bytes in data, if set to -1 then XSTRLEN is used
+     * "out" can be used to store the new entry data in an existing structure
+     *       if NULL then a new WOLFSSL_X509_NAME_ENTRY structure is created
+     * returns a pointer to WOLFSSL_X509_NAME_ENTRY on success and NULL on fail
+     */
     WOLFSSL_X509_NAME_ENTRY* wolfSSL_X509_NAME_ENTRY_create_by_NID(
             WOLFSSL_X509_NAME_ENTRY** out, int nid, int type,
@@ -37715,16 +41862,28 @@
         WOLFSSL_ENTER("wolfSSL_X509_NAME_ENTRY_create_by_NID()");
 
-        ne = wolfSSL_X509_NAME_ENTRY_new();
-        if (ne == NULL) {
+        if (!data) {
+            WOLFSSL_MSG("Bad parameter");
             return NULL;
         }
 
+        if (out == NULL || *out == NULL) {
+            ne = wolfSSL_X509_NAME_ENTRY_new();
+            if (ne == NULL) {
+                return NULL;
+            }
+            if (out != NULL) {
+                *out = ne;
+            }
+        }
+        else {
+            ne = *out;
+        }
+
         ne->nid = nid;
+        ne->object = wolfSSL_OBJ_nid2obj_ex(nid, ne->object);
         ne->value = wolfSSL_ASN1_STRING_type_new(type);
-        wolfSSL_ASN1_STRING_set(ne->value, (const void*)data, dataSz);
-        ne->set = 1;
-
-        if (out != NULL) {
-            *out = ne;
+        if (ne->value != NULL) {
+            wolfSSL_ASN1_STRING_set(ne->value, (const void*)data, dataSz);
+            ne->set = 1;
         }
 
@@ -37732,188 +41891,93 @@
     }
 
-    static int RebuildFullNameAdd(DecodedName* dName, char* data)
+    /* add all entry of type "nid" to the buffer "fullName" and advance "idx"
+     * since number of entries is small, a brute force search is used here
+     * returns the number of entries added
+     */
+    static int AddAllEntry(WOLFSSL_X509_NAME* name, char* fullName,
+            int fullNameSz, int* idx)
     {
-        int totalLen = 0;
         int i;
+        int ret = 0;
+
+        for (i = 0; i < MAX_NAME_ENTRIES; i++) {
+            if (name->entry[i].set) {
+                WOLFSSL_X509_NAME_ENTRY* e;
+                WOLFSSL_ASN1_OBJECT* obj;
+
+                int sz;
+                unsigned char* data;
+
+                e = &name->entry[i];
+                obj = wolfSSL_X509_NAME_ENTRY_get_object(e);
+                if (obj == NULL) {
+                    return BAD_FUNC_ARG;
+                }
+
+                XMEMCPY(fullName + *idx, "/", 1); *idx = *idx + 1;
+                sz = (int)XSTRLEN(obj->sName);
+                XMEMCPY(fullName + *idx, obj->sName, sz);
+                *idx += sz;
+                XMEMCPY(fullName + *idx, "=", 1); *idx = *idx + 1;
+
+                data = wolfSSL_ASN1_STRING_data(e->value);
+                if (data != NULL) {
+                    sz = (int)XSTRLEN((const char*)data);
+                    XMEMCPY(fullName + *idx, data, sz);
+                    *idx += sz;
+                }
+
+                ret++;
+            }
+        }
+        (void)fullNameSz;
+        return ret;
+    }
+
+
+    /* Converts a list of entries in WOLFSSL_X509_NAME struct into a string
+     * returns 0 on success */
+    static int RebuildFullName(WOLFSSL_X509_NAME* name)
+    {
+        int totalLen = 0, i, idx, entryCount = 0;
         char* fullName;
-        int idx;
-
-        if (dName->cnLen != 0)
-            totalLen += dName->cnLen + 4;
-        if (dName->snLen != 0)
-            totalLen += dName->snLen + 4;
-        if (dName->cLen != 0)
-            totalLen += dName->cLen + 3;
-        if (dName->lLen != 0)
-            totalLen += dName->lLen + 3;
-        if (dName->stLen != 0)
-            totalLen += dName->stLen + 4;
-        if (dName->oLen != 0)
-            totalLen += dName->oLen + 3;
-        if (dName->ouLen != 0)
-            totalLen += dName->ouLen + 4;
-        if (dName->emailLen != 0)
-            totalLen += dName->emailLen + 14;
-        if (dName->uidLen != 0)
-            totalLen += dName->uidLen + 5;
-        if (dName->serialLen != 0)
-            totalLen += dName->serialLen + 14;
-        if (dName->dcNum != 0) {
-            for (i = 0; i < dName->dcNum; i++)
-                totalLen += dName->dcLen[i] + 4;
-        }
-
-        fullName = (char*)XMALLOC(totalLen + 1, NULL, DYNAMIC_TYPE_X509);
+
+        if (name == NULL)
+            return BAD_FUNC_ARG;
+
+        for (i = 0; i < MAX_NAME_ENTRIES; i++) {
+            if (name->entry[i].set) {
+                WOLFSSL_X509_NAME_ENTRY* e;
+                WOLFSSL_ASN1_OBJECT* obj;
+
+                e = &name->entry[i];
+                obj = wolfSSL_X509_NAME_ENTRY_get_object(e);
+                if (obj == NULL)
+                    return BAD_FUNC_ARG;
+
+                totalLen += (int)XSTRLEN(obj->sName) + 2;/*+2 for '/' and '=' */
+                totalLen += wolfSSL_ASN1_STRING_length(e->value);
+            }
+        }
+
+        fullName = (char*)XMALLOC(totalLen + 1, name->heap, DYNAMIC_TYPE_X509);
         if (fullName == NULL)
             return MEMORY_E;
 
         idx = 0;
-        dName->entryCount = 0;
-        if (dName->cnLen != 0) {
-            dName->entryCount++;
-            XMEMCPY(fullName + idx, WOLFSSL_COMMON_NAME, 4);
-            idx += 4;
-            if (dName->cnIdx == -1)
-                XMEMCPY(fullName + idx, data, dName->cnLen);
-            else {
-                XMEMCPY(fullName + idx, dName->fullName + dName->cnIdx,
-                                                                  dName->cnLen);
-            }
-            dName->cnIdx = idx;
-            idx += dName->cnLen;
-        }
-        if (dName->snLen != 0) {
-            dName->entryCount++;
-            XMEMCPY(fullName + idx, WOLFSSL_SUR_NAME, 4);
-            idx += 4;
-            if (dName->snIdx == -1)
-                XMEMCPY(fullName + idx, data, dName->snLen);
-            else {
-                XMEMCPY(fullName + idx, dName->fullName + dName->snIdx,
-                                                                  dName->snLen);
-            }
-            dName->snIdx = idx;
-            idx += dName->snLen;
-        }
-        if (dName->cLen != 0) {
-            dName->entryCount++;
-            XMEMCPY(fullName + idx, WOLFSSL_COUNTRY_NAME, 3);
-            idx += 3;
-            if (dName->cIdx == -1)
-                XMEMCPY(fullName + idx, data, dName->cLen);
-            else {
-                XMEMCPY(fullName + idx, dName->fullName + dName->cIdx,
-                                                                   dName->cLen);
-            }
-            dName->cIdx = idx;
-            idx += dName->cLen;
-        }
-        if (dName->lLen != 0) {
-            dName->entryCount++;
-            XMEMCPY(fullName + idx, WOLFSSL_LOCALITY_NAME, 3);
-            idx += 3;
-            if (dName->lIdx == -1)
-                XMEMCPY(fullName + idx, data, dName->lLen);
-            else {
-                XMEMCPY(fullName + idx, dName->fullName + dName->lIdx,
-                                                                   dName->lLen);
-            }
-            dName->lIdx = idx;
-            idx += dName->lLen;
-        }
-        if (dName->stLen != 0) {
-            dName->entryCount++;
-            XMEMCPY(fullName + idx, WOLFSSL_STATE_NAME, 4);
-            idx += 4;
-            if (dName->stIdx == -1)
-                XMEMCPY(fullName + idx, data, dName->stLen);
-            else {
-                XMEMCPY(fullName + idx, dName->fullName + dName->stIdx,
-                                                                  dName->stLen);
-            }
-            dName->stIdx = idx;
-            idx += dName->stLen;
-        }
-        if (dName->oLen != 0) {
-            dName->entryCount++;
-            XMEMCPY(fullName + idx, WOLFSSL_ORG_NAME, 3);
-            idx += 3;
-            if (dName->oIdx == -1)
-                XMEMCPY(fullName + idx, data, dName->oLen);
-            else {
-                XMEMCPY(fullName + idx, dName->fullName + dName->oIdx,
-                                                                   dName->oLen);
-            }
-            dName->oIdx = idx;
-            idx += dName->oLen;
-        }
-        if (dName->ouLen != 0) {
-            dName->entryCount++;
-            XMEMCPY(fullName + idx, WOLFSSL_ORGUNIT_NAME, 4);
-            idx += 4;
-            if (dName->ouIdx == -1)
-                XMEMCPY(fullName + idx, data, dName->ouLen);
-            else {
-                XMEMCPY(fullName + idx, dName->fullName + dName->ouIdx,
-                                                                  dName->ouLen);
-            }
-            dName->ouIdx = idx;
-            idx += dName->ouLen;
-        }
-        if (dName->emailLen != 0) {
-            dName->entryCount++;
-            XMEMCPY(fullName + idx, "/emailAddress=", 14);
-            idx += 14;
-            if (dName->emailIdx == -1)
-                XMEMCPY(fullName + idx, data, dName->emailLen);
-            else {
-                XMEMCPY(fullName + idx, dName->fullName + dName->emailIdx,
-                                                               dName->emailLen);
-            }
-            dName->emailIdx = idx;
-            idx += dName->emailLen;
-        }
-        if (dName->dcNum != 0) {
-            for (i = 0; i < dName->dcNum; i++) {
-                dName->entryCount++;
-                XMEMCPY(fullName + idx, WOLFSSL_DOMAIN_COMPONENT, 4);
-                idx += 4;
-                XMEMCPY(fullName + idx, dName->fullName + dName->dcIdx[i],
-                                                               dName->dcLen[i]);
-                dName->dcIdx[i] = idx;
-                idx += dName->dcLen[i];
-            }
-        }
-        if (dName->uidLen != 0) {
-            dName->entryCount++;
-            XMEMCPY(fullName + idx, "/UID=", 5);
-            idx += 5;
-            if (dName->uidIdx == -1)
-                XMEMCPY(fullName + idx, data, dName->uidLen);
-            else {
-                XMEMCPY(fullName + idx, dName->fullName + dName->uidIdx,
-                                                                 dName->uidLen);
-            }
-            dName->uidIdx = idx;
-            idx += dName->uidLen;
-        }
-        if (dName->serialLen != 0) {
-            dName->entryCount++;
-            XMEMCPY(fullName + idx, WOLFSSL_SERIAL_NUMBER, 14);
-            idx += 14;
-            if (dName->serialIdx == -1)
-                XMEMCPY(fullName + idx, data, dName->serialLen);
-            else {
-                XMEMCPY(fullName + idx, dName->fullName + dName->serialIdx,
-                                                              dName->serialLen);
-            }
-            dName->serialIdx = idx;
-            idx += dName->serialLen;
-        }
-
-        if (dName->fullName != NULL)
-            XFREE(dName->fullName, NULL, DYNAMIC_TYPE_X509);
-        dName->fullName = fullName;
-        dName->fullNameLen = idx + 1;
+        entryCount = AddAllEntry(name, fullName, totalLen, &idx);
+        if (entryCount < 0) {
+            XFREE(fullName, name->heap, DYNAMIC_TYPE_X509);
+            return entryCount;
+        }
+
+        if (name->dynamicName) {
+            XFREE(name->name, name->heap, DYNAMIC_TYPE_X509);
+        }
+        fullName[idx] = '\0';
+        name->name = fullName;
+        name->dynamicName = 1;
+        name->sz = idx + 1; /* size includes null terminator */
+        name->entrySz = entryCount;
 
         return 0;
@@ -37926,121 +41990,28 @@
             WOLFSSL_X509_NAME_ENTRY* entry, int idx, int set)
     {
+        WOLFSSL_X509_NAME_ENTRY* current = NULL;
         int i;
-        int fullName = 1;
 
         WOLFSSL_ENTER("wolfSSL_X509_NAME_add_entry()");
 
-        switch (entry->nid) {
-            case ASN_COMMON_NAME:
-                name->fullName.cnIdx = -1;
-                name->fullName.cnLen = entry->value->length;
-                name->fullName.cnNid = entry->nid;
-                break;
-            case ASN_SUR_NAME:
-                name->fullName.snIdx = -1;
-                name->fullName.snLen = entry->value->length;
-                name->fullName.snNid = entry->nid;
-                break;
-            case ASN_SERIAL_NUMBER:
-                name->fullName.serialIdx = -1;
-                name->fullName.serialLen = entry->value->length;
-                name->fullName.serialNid = entry->nid;
-                break;
-            case ASN_COUNTRY_NAME:
-                name->fullName.cIdx = -1;
-                name->fullName.cLen = entry->value->length;
-                name->fullName.cNid = entry->nid;
-                break;
-            case ASN_LOCALITY_NAME:
-                name->fullName.lIdx = -1;
-                name->fullName.lLen = entry->value->length;
-                name->fullName.lNid = entry->nid;
-                break;
-            case ASN_STATE_NAME:
-                name->fullName.stIdx = -1;
-                name->fullName.stLen = entry->value->length;
-                name->fullName.stNid = entry->nid;
-                break;
-            case ASN_ORG_NAME:
-                name->fullName.oIdx = -1;
-                name->fullName.oLen = entry->value->length;
-                name->fullName.oNid = entry->nid;
-                break;
-            case ASN_ORGUNIT_NAME:
-                name->fullName.ouIdx = -1;
-                name->fullName.ouLen = entry->value->length;
-                name->fullName.ouNid = entry->nid;
-                break;
-            case NID_emailAddress:
-                name->fullName.emailIdx = -1;
-                name->fullName.emailLen = entry->value->length;
-                name->fullName.emailNid = entry->nid;
-                break;
-            case ASN_USER_ID:
-                name->fullName.uidIdx = -1;
-                name->fullName.uidLen = entry->value->length;
-                name->fullName.uidNid = entry->nid;
-                break;
-            case ASN_DOMAIN_COMPONENT:
-                name->fullName.dcIdx[0] = -1;
-                name->fullName.dcLen[0] = entry->value->length;
-                break;
-            default:
-                fullName = 0;
-                break;
-        }
-
-        if (fullName) {
-            int nid = entry->nid;
-
-            if (nid == NID_emailAddress) {
-                nid = (int)ASN_EMAIL_NAME;
-            }
-
-            if (idx >= DN_NAMES_MAX + DOMAIN_COMPONENT_MAX) {
+        if (name == NULL || entry == NULL || entry->value == NULL) {
+            WOLFSSL_MSG("NULL argument passed in");
+            return WOLFSSL_FAILURE;
+        }
+
+        if (idx >= 0) {
+            /* place in specific index */
+
+            if (idx >= MAX_NAME_ENTRIES) {
+                WOLFSSL_MSG("Error index to insert entry is larger than array");
                 return WOLFSSL_FAILURE;
             }
-
-            if (idx >= 0) {
-                name->fullName.loc[idx] = nid;
-                if (idx == name->fullName.locSz) {
-                    name->fullName.locSz += 1;
-                }
-            }
-
-            /* place at end */
-            if (idx < 0 && name->fullName.locSz + 1
-                    < DN_NAMES_MAX + DOMAIN_COMPONENT_MAX) {
-                name->fullName.loc[name->fullName.locSz] = nid;
-                name->fullName.locSz += 1;
-            }
-
-            if (RebuildFullNameAdd(&name->fullName, entry->value->data) != 0)
-                return WOLFSSL_FAILURE;
+            i = idx;
         }
         else {
+            /* iterate through and find first open spot */
             for (i = 0; i < MAX_NAME_ENTRIES; i++) {
-                if (name->extra[i].set != 1) { /* not set so overwritten */
-                    WOLFSSL_X509_NAME_ENTRY* current = &(name->extra[i]);
-                    WOLFSSL_ASN1_STRING*     str;
-
+                if (name->entry[i].set != 1) { /* not set so overwritten */
                     WOLFSSL_MSG("Found place for name entry");
-
-                    XMEMCPY(current, entry, sizeof(WOLFSSL_X509_NAME_ENTRY));
-                    str = entry->value;
-                    XMEMCPY(&(current->data), str, sizeof(WOLFSSL_ASN1_STRING));
-                    current->value = &(current->data);
-                    current->data.data = (char*)XMALLOC(str->length,
-                           name->x509->heap, DYNAMIC_TYPE_OPENSSL);
-
-                    if (current->data.data == NULL) {
-                        return SSL_FAILURE;
-                    }
-                    XMEMCPY(current->data.data, str->data, str->length);
-
-                    /* make sure is null terminated */
-                    current->data.data[str->length - 1] = '\0';
-
-                    current->set = 1; /* make sure now listed as set */
                     break;
                 }
@@ -38049,11 +42020,28 @@
             if (i == MAX_NAME_ENTRIES) {
                 WOLFSSL_MSG("No spot found for name entry");
-                return SSL_FAILURE;
-            }
-        }
-
-        (void)idx;
+                return WOLFSSL_FAILURE;
+            }
+        }
+
+        current = &(name->entry[i]);
+        if (current->set == 0)
+            name->entrySz++;
+        if (wolfSSL_X509_NAME_ENTRY_create_by_NID(&current,
+                                entry->nid,
+                                wolfSSL_ASN1_STRING_type(entry->value),
+                                wolfSSL_ASN1_STRING_data(entry->value),
+                                wolfSSL_ASN1_STRING_length(entry->value))
+                                == NULL) {
+            WOLFSSL_MSG("Issue adding the name entry");
+            if (current->set == 0)
+                name->entrySz--;
+            return WOLFSSL_FAILURE;
+        }
+
+        if (RebuildFullName(name) != 0)
+            return WOLFSSL_FAILURE;
+
         (void)set;
-        return SSL_SUCCESS;
+        return WOLFSSL_SUCCESS;
     }
 
@@ -38073,6 +42061,8 @@
             return WOLFSSL_FAILURE;
 
-        if ((nid = wolfSSL_OBJ_txt2nid(field)) == NID_undef)
+        if ((nid = wolfSSL_OBJ_txt2nid(field)) == NID_undef) {
+            WOLFSSL_MSG("Unable convert text to NID");
             return WOLFSSL_FAILURE;
+        }
 
         entry = wolfSSL_X509_NAME_ENTRY_create_by_NID(NULL,
@@ -38093,5 +42083,7 @@
         int ret;
         WOLFSSL_X509_NAME_ENTRY* entry;
-        entry = wolfSSL_X509_NAME_ENTRY_create_by_NID(NULL, nid, type, bytes, len);
+        WOLFSSL_ENTER("wolfSSL_X509_NAME_add_entry_by_NID");
+        entry = wolfSSL_X509_NAME_ENTRY_create_by_NID(NULL, nid, type, bytes,
+                len);
         if (entry == NULL)
             return WOLFSSL_FAILURE;
@@ -38100,6 +42092,26 @@
         return ret;
     }
-    #endif /* !NO_CERTS */
-
+
+    WOLFSSL_X509_NAME_ENTRY *wolfSSL_X509_NAME_delete_entry(
+            WOLFSSL_X509_NAME *name, int loc)
+    {
+        WOLFSSL_X509_NAME_ENTRY* ret;
+        WOLFSSL_ENTER("wolfSSL_X509_NAME_delete_entry");
+
+        if (!name) {
+            WOLFSSL_MSG("Bad parameter");
+            return NULL;
+        }
+
+        ret = wolfSSL_X509_NAME_get_entry(name, loc);
+        if (!ret) {
+            WOLFSSL_MSG("loc entry not found");
+            return NULL;
+        }
+        name->entry[loc].set = 0;
+        return ret;
+    }
+
+#endif /* !NO_CERTS */
 
     /* NID variables are dependent on compatibility header files currently
@@ -38169,7 +42181,4 @@
                 return NULL;
             }
-            obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
-        } else {
-            obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC;
         }
         obj->type    = id;
@@ -38185,16 +42194,21 @@
         XMEMCPY(objBuf + objSz, oid, oidSz);
         objSz     += oidSz;
-        obj->objSz = objSz;
-        if(((obj->dynamic & WOLFSSL_ASN1_DYNAMIC_DATA) != 0) ||
+
+        if (obj->objSz == 0 || objSz != obj->objSz) {
+            obj->objSz = objSz;
+            if(((obj->dynamic & WOLFSSL_ASN1_DYNAMIC_DATA) != 0) ||
                                                            (obj->obj == NULL)) {
-            obj->obj = (byte*)XREALLOC((byte*)obj->obj, obj->objSz, NULL,
-                                                             DYNAMIC_TYPE_ASN1);
-            if (obj->obj == NULL) {
-                wolfSSL_ASN1_OBJECT_free(obj);
-                return NULL;
-            }
-            obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA ;
-        } else {
-            obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA ;
+                if (obj->obj != NULL)
+                    XFREE((byte*)obj->obj, NULL, DYNAMIC_TYPE_ASN1);
+                obj->obj = (byte*)XMALLOC(obj->objSz, NULL, DYNAMIC_TYPE_ASN1);
+                if (obj->obj == NULL) {
+                    wolfSSL_ASN1_OBJECT_free(obj);
+                    return NULL;
+                }
+                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA ;
+            }
+            else {
+                obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA ;
+            }
         }
         XMEMCPY((byte*)obj->obj, objBuf, obj->objSz);
@@ -38279,7 +42293,13 @@
 
         }
-        else { /* return short name */
-            if (XSTRLEN(a->sName) + 1 < (word32)bufLen - 1) {
-                bufSz = (int)XSTRLEN(a->sName);
+        else { /* return long name unless using x509small, then return short name */
+#if defined(OPENSSL_EXTRA_X509_SMALL) && !defined(OPENSSL_EXTRA)
+            const char* name = a->sName;
+#else
+            const char* name = wolfSSL_OBJ_nid2ln(wolfSSL_OBJ_obj2nid(a));
+#endif
+
+            if (XSTRLEN(name) + 1 < (word32)bufLen - 1) {
+                bufSz = (int)XSTRLEN(name);
             }
             else {
@@ -38287,5 +42307,5 @@
             }
             if (bufSz) {
-                XMEMCPY(buf, a->sName, bufSz);
+                XMEMCPY(buf, name, bufSz);
             }
             else if (wolfSSL_OBJ_obj2txt(buf, bufLen, a, 1)) {
@@ -38311,34 +42331,11 @@
         return bufSz;
     }
-#endif /* OPENSSL_EXTRA */
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
 
 #if defined(OPENSSL_EXTRA) && !defined(NO_ASN)
-    /* DN_Tags to strings */
-    static const struct DN_Tag_Strings {
-        enum DN_Tags tag;
-        const char* str;
-    } dn_tag_strings[] = {
-           { ASN_COMMON_NAME,      "CN" },
-           { ASN_SUR_NAME,         "SN" },
-           { ASN_SERIAL_NUMBER,    "serialNumber" },
-           { ASN_COUNTRY_NAME,     "C" },
-           { ASN_LOCALITY_NAME,    "L" },
-           { ASN_STATE_NAME,       "ST" },
-           { ASN_ORG_NAME,         "O"},
-           { ASN_ORGUNIT_NAME,     "OU"},
-           { ASN_BUS_CAT,          "businessCategory"},
-           { ASN_EMAIL_NAME,       "emailAddress"},
-           { ASN_USER_ID,          "UID"},
-           { ASN_DOMAIN_COMPONENT, "DC"},
-           { ASN_DN_NULL,          NULL }
-    };
-
     int wolfSSL_X509_NAME_get_index_by_OBJ(WOLFSSL_X509_NAME *name,
                                            const WOLFSSL_ASN1_OBJECT *obj,
                                            int idx) {
-        const struct DN_Tag_Strings* dn;
-        enum DN_Tags tag = ASN_DN_NULL;
-
-        if (!name || idx >= name->fullName.locSz ||
+        if (!name || idx >= MAX_NAME_ENTRIES ||
                 !obj || !obj->obj) {
             return -1;
@@ -38346,21 +42343,15 @@
 
         if (idx < 0) {
-            idx = 0;
-        }
-        for (dn = dn_tag_strings; dn->str != NULL; dn++) {
-            /* Find the DN_Tags number for the name */
-            if (XSTRNCMP((const char*) obj->sName, dn->str, obj->objSz - 1) == 0) {
-                tag = dn->tag;
-                break;
-            }
-        }
-        if (!tag) {
-            /* Unable to identify desired name */
-            return -1;
-        }
-        for (idx++; idx < name->fullName.locSz; idx++) {
+            idx = -1;
+        }
+
+        for (idx++; idx < MAX_NAME_ENTRIES; idx++) {
             /* Find index of desired name */
-            if ((enum DN_Tags)name->fullName.loc[idx] == tag) {
-                return idx;
+            if (name->entry[idx].set) {
+                if (XSTRLEN(obj->sName) == XSTRLEN(name->entry[idx].object->sName) &&
+                    XSTRNCMP((const char*) obj->sName,
+                        name->entry[idx].object->sName, obj->objSz - 1) == 0) {
+                    return idx;
+                }
             }
         }
@@ -38368,4 +42359,6 @@
     }
 #endif
+
+#endif /* !WOLFCRYPT_ONLY */
 
 #if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \
@@ -38390,4 +42383,5 @@
     {
         static byte dig[WC_SHA_DIGEST_SIZE];
+        byte* ret = md;
         wc_Sha sha;
 
@@ -38404,18 +42398,17 @@
         }
 
-        if (wc_ShaFinal(&sha, dig) != 0) {
+        if (md == NULL) {
+            WOLFSSL_MSG("STATIC BUFFER BEING USED. wolfSSL_SHA1 IS NOT "
+                        "THREAD SAFE WHEN md == NULL");
+            ret = dig;
+        }
+        if (wc_ShaFinal(&sha, ret) != 0) {
             WOLFSSL_MSG("SHA1 Final failed");
+            wc_ShaFree(&sha);
             return NULL;
         }
-
         wc_ShaFree(&sha);
 
-        if (md != NULL) {
-            XMEMCPY(md, dig, WC_SHA_DIGEST_SIZE);
-            return md;
-        }
-        else {
-            return (unsigned char*)dig;
-        }
+        return ret;
     }
 #endif /* ! NO_SHA */
@@ -38437,4 +42430,5 @@
     {
         static byte dig[WC_SHA256_DIGEST_SIZE];
+        byte* ret = md;
         wc_Sha256 sha;
 
@@ -38451,18 +42445,17 @@
         }
 
-        if (wc_Sha256Final(&sha, dig) != 0) {
+        if (md == NULL) {
+            WOLFSSL_MSG("STATIC BUFFER BEING USED. wolfSSL_SHA256 IS NOT "
+                        "THREAD SAFE WHEN md == NULL");
+            ret = dig;
+        }
+        if (wc_Sha256Final(&sha, ret) != 0) {
             WOLFSSL_MSG("SHA256 Final failed");
+            wc_Sha256Free(&sha);
             return NULL;
         }
-
         wc_Sha256Free(&sha);
 
-        if (md != NULL) {
-            XMEMCPY(md, dig, WC_SHA256_DIGEST_SIZE);
-            return md;
-        }
-        else {
-            return (unsigned char*)dig;
-        }
+        return ret;
     }
 #endif /* ! NO_SHA256 */
@@ -38484,4 +42477,5 @@
      {
          static byte dig[WC_SHA384_DIGEST_SIZE];
+         byte* ret = md;
          wc_Sha384 sha;
 
@@ -38498,18 +42492,17 @@
          }
 
-         if (wc_Sha384Final(&sha, dig) != 0) {
+         if (md == NULL) {
+             WOLFSSL_MSG("STATIC BUFFER BEING USED. wolfSSL_SHA384 IS NOT "
+                         "THREAD SAFE WHEN md == NULL");
+             ret = dig;
+         }
+         if (wc_Sha384Final(&sha, ret) != 0) {
              WOLFSSL_MSG("SHA384 Final failed");
+             wc_Sha384Free(&sha);
              return NULL;
          }
-
          wc_Sha384Free(&sha);
 
-         if (md != NULL) {
-             XMEMCPY(md, dig, WC_SHA384_DIGEST_SIZE);
-             return md;
-         }
-         else {
-             return (unsigned char*)dig;
-         }
+         return ret;
      }
 #endif /* WOLFSSL_SHA384  */
@@ -38532,4 +42525,5 @@
      {
          static byte dig[WC_SHA512_DIGEST_SIZE];
+         byte* ret = md;
          wc_Sha512 sha;
 
@@ -38546,20 +42540,19 @@
          }
 
-         if (wc_Sha512Final(&sha, dig) != 0) {
+         if (md == NULL) {
+             WOLFSSL_MSG("STATIC BUFFER BEING USED. wolfSSL_SHA512 IS NOT "
+                         "THREAD SAFE WHEN md == NULL");
+             ret = dig;
+         }
+         if (wc_Sha512Final(&sha, ret) != 0) {
              WOLFSSL_MSG("SHA512 Final failed");
+             wc_Sha512Free(&sha);
              return NULL;
          }
-
          wc_Sha512Free(&sha);
 
-         if (md != NULL) {
-             XMEMCPY(md, dig, WC_SHA512_DIGEST_SIZE);
-             return md;
-         }
-         else {
-             return (unsigned char*)dig;
-         }
+         return ret;
      }
-#endif /* defined(WOLFSSL_SHA512)  */
+#endif /* WOLFSSL_SHA512 */
 #endif /* OPENSSL_EXTRA */
 
@@ -38575,4 +42568,8 @@
 
         WOLFSSL_ENTER("wolfSSL_CTX_use_certificate");
+        if (!ctx || !x || !x->derCert) {
+            WOLFSSL_MSG("Bad parameter");
+            return WOLFSSL_FAILURE;
+        }
 
         FreeDer(&ctx->certificate); /* Make sure previous is free'd */
@@ -38580,5 +42577,5 @@
                        ctx->heap);
         if (ret != 0)
-            return 0;
+            return WOLFSSL_FAILURE;
 
         XMEMCPY(ctx->certificate->buffer, x->derCert->buffer,
@@ -38586,17 +42583,21 @@
 #ifdef KEEP_OUR_CERT
         if (ctx->ourCert != NULL && ctx->ownOurCert) {
-            FreeX509(ctx->ourCert);
-            XFREE(ctx->ourCert, ctx->heap, DYNAMIC_TYPE_X509);
+            wolfSSL_X509_free(ctx->ourCert);
         }
         #ifndef WOLFSSL_X509_STORE_CERTS
         ctx->ourCert = x;
+        if (wolfSSL_X509_up_ref(x) != 1) {
+            return WOLFSSL_FAILURE;
+        }
         #else
         ctx->ourCert = wolfSSL_X509_d2i(NULL, x->derCert->buffer,x->derCert->length);
         if(ctx->ourCert == NULL){
-            return 0;
+            return WOLFSSL_FAILURE;
         }
         #endif
 
-        ctx->ownOurCert = 0;
+        /* We own the cert because either we up its reference counter
+         * or we create our own copy of the cert object. */
+        ctx->ownOurCert = 1;
 #endif
 
@@ -38636,4 +42637,5 @@
     }
 
+#ifndef NO_BIO
     int wolfSSL_BIO_read_filename(WOLFSSL_BIO *b, const char *name) {
     #ifndef NO_FILESYSTEM
@@ -38647,5 +42649,5 @@
         }
 
-        fp = XFOPEN(name, "r");
+        fp = XFOPEN(name, "rb");
         if (fp == XBADFILE)
             return WOLFSSL_BAD_FILE;
@@ -38664,4 +42666,5 @@
     #endif
     }
+#endif
 
     /* Return the corresponding short name for the nid <n>.
@@ -38701,4 +42704,5 @@
         word32 oid = 0;
         word32 idx = 0;
+        int ret;
 
         WOLFSSL_ENTER("wolfSSL_OBJ_obj2nid");
@@ -38718,7 +42722,27 @@
         if (o->nid > 0)
             return o->nid;
-        if (GetObjectId(o->obj, &idx, &oid, o->grp, o->objSz) < 0) {
-            WOLFSSL_MSG("Issue getting OID of object");
-            return -1;
+        if ((ret = GetObjectId(o->obj, &idx, &oid, o->grp, o->objSz)) < 0) {
+            if (ret == ASN_OBJECT_ID_E) {
+                /* Put ASN object tag in front and try again */
+                int len = SetObjectId(o->objSz, NULL) + o->objSz;
+                byte* buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                if (!buf) {
+                    WOLFSSL_MSG("malloc error");
+                    return -1;
+                }
+                idx = SetObjectId(o->objSz, buf);
+                XMEMCPY(buf + idx, o->obj, o->objSz);
+                idx = 0;
+                ret = GetObjectId(buf, &idx, &oid, o->grp, len);
+                XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                if (ret < 0) {
+                    WOLFSSL_MSG("Issue getting OID of object");
+                    return -1;
+                }
+            }
+            else {
+                WOLFSSL_MSG("Issue getting OID of object");
+                return -1;
+            }
         }
 
@@ -38777,13 +42801,44 @@
         WOLFSSL_ENTER("wolfSSL_OBJ_cmp");
 
-        if (a != NULL && b != NULL &&
-            a->obj != NULL && b->obj != NULL &&
-            a->objSz == b->objSz) {
-            return XMEMCMP(a->obj, b->obj, a->objSz);
+        if (a && b && a->obj && b->obj) {
+            if (a->objSz == b->objSz) {
+                return XMEMCMP(a->obj, b->obj, a->objSz);
+            }
+            else if (a->type == EXT_KEY_USAGE_OID ||
+                     b->type == EXT_KEY_USAGE_OID) {
+                /* Special case for EXT_KEY_USAGE_OID so that
+                 * cmp will be treated as a substring search */
+                /* Used in libest to check for id-kp-cmcRA in
+                 * EXT_KEY_USAGE extension */
+                unsigned int idx;
+                const byte* s; /* shorter */
+                unsigned int sLen;
+                const byte* l; /* longer */
+                unsigned int lLen;
+                if (a->objSz > b->objSz) {
+                    s = b->obj; sLen = b->objSz;
+                    l = a->obj; lLen = a->objSz;
+                }
+                else {
+                    s = a->obj; sLen = a->objSz;
+                    l = b->obj; lLen = b->objSz;
+                }
+                for (idx = 0; idx <= lLen - sLen; idx++) {
+                    if (XMEMCMP(l + idx, s, sLen) == 0) {
+                        /* Found substring */
+                        return 0;
+                    }
+                }
+            }
         }
 
         return WOLFSSL_FATAL_ERROR;
     }
-
+#endif /* OPENSSL_EXTRA, HAVE_LIGHTY, WOLFSSL_MYSQL_COMPATIBLE, HAVE_STUNNEL,
+          WOLFSSL_NGINX, HAVE_POCO_LIB, WOLFSSL_HAPROXY */
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
+    defined(HAVE_LIGHTY) || defined(WOLFSSL_MYSQL_COMPATIBLE) || \
+    defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \
+    defined(HAVE_POCO_LIB) || defined(WOLFSSL_HAPROXY)
     /* Gets the NID value that is related to the OID string passed in. Example
      * string would be "2.5.29.14" for subject key ID.
@@ -38831,10 +42886,12 @@
             /* try as a short name */
             len = (int)XSTRLEN(s);
-            if (XSTRNCMP(wolfssl_object_info[i].sName, s, len) == 0) {
+            if ((int)XSTRLEN(wolfssl_object_info[i].sName) == len &&
+                XSTRNCMP(wolfssl_object_info[i].sName, s, len) == 0) {
                 return wolfssl_object_info[i].nid;
             }
 
             /* try as a long name */
-            if (XSTRNCMP(wolfssl_object_info[i].lName, s, len) == 0) {
+            if ((int)XSTRLEN(wolfssl_object_info[i].lName) == len &&
+                XSTRNCMP(wolfssl_object_info[i].lName, s, len) == 0) {
                 return wolfssl_object_info[i].nid;
             }
@@ -38843,4 +42900,9 @@
         return NID_undef;
     }
+#endif
+#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \
+    defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \
+    defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \
+    defined(WOLFSSL_HAPROXY)
 
     /* Creates new ASN1_OBJECT from short name, long name, or text
@@ -38858,5 +42920,5 @@
         unsigned int outSz = MAX_OID_SZ;
         unsigned char out[MAX_OID_SZ];
-        unsigned int sum = 0;
+        WOLFSSL_ASN1_OBJECT* obj;
 
         WOLFSSL_ENTER("wolfSSL_OBJ_txt2obj");
@@ -38867,8 +42929,25 @@
         /* If s is numerical value, try to sum oid */
         ret = EncodePolicyOID(out, &outSz, s, NULL);
-        if (ret == 0) {
-            for (i = 0; i < (int)outSz; i++) {
-                sum += out[i];
-            }
+        if (ret == 0 && outSz > 0) {
+            /* If numerical encode succeeded then just
+             * create object from that because sums are
+             * not unique and can cause confusion. */
+            obj = wolfSSL_ASN1_OBJECT_new();
+            if (obj == NULL) {
+                WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                return NULL;
+            }
+            obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
+            obj->obj = (byte*)XMALLOC(1 + MAX_LENGTH_SZ + outSz, NULL,
+                    DYNAMIC_TYPE_ASN1);
+            if (obj->obj == NULL) {
+                wolfSSL_ASN1_OBJECT_free(obj);
+                return NULL;
+            }
+            obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA ;
+            i = SetObjectId(outSz, (byte*)obj->obj);
+            XMEMCPY((byte*)obj->obj + i, out, outSz);
+            obj->objSz = i + outSz;
+            return obj;
         }
 
@@ -38880,9 +42959,5 @@
             /* Short name, long name, and numerical value are interpreted */
             if (no_name == 0 && ((XSTRNCMP(s, wolfssl_object_info[i].sName, len) == 0) ||
-                                 (XSTRNCMP(s, wolfssl_object_info[i].lName, len) == 0) ||
-                                 (wolfssl_object_info[i].id == (int)sum)))
-                    nid = wolfssl_object_info[i].nid;
-            /* Only numerical value is interpreted */
-            else if (no_name == 1 && wolfssl_object_info[i].id == (int)sum)
+                                 (XSTRNCMP(s, wolfssl_object_info[i].lName, len) == 0)))
                     nid = wolfssl_object_info[i].nid;
         }
@@ -38916,9 +42991,5 @@
     void wolfSSL_set_verify_depth(WOLFSSL *ssl, int depth)
     {
-    #if !defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_STUB)
-        (void)ssl;
-        (void)depth;
-        WOLFSSL_STUB("wolfSSL_set_verify_depth");
-    #else
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
         WOLFSSL_ENTER("wolfSSL_set_verify_depth");
         ssl->options.verifyDepth = (byte)depth;
@@ -38926,11 +42997,20 @@
     }
 
-
-    WOLFSSL_ASN1_OBJECT * wolfSSL_X509_NAME_ENTRY_get_object(WOLFSSL_X509_NAME_ENTRY *ne) {
+#endif /* OPENSSL_ALL || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE ||
+    HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
+    defined(HAVE_LIGHTY) || defined(WOLFSSL_MYSQL_COMPATIBLE) || \
+    defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \
+    defined(HAVE_POCO_LIB) || defined(WOLFSSL_HAPROXY)
+    WOLFSSL_ASN1_OBJECT * wolfSSL_X509_NAME_ENTRY_get_object(WOLFSSL_X509_NAME_ENTRY *ne)
+    {
+        WOLFSSL_ASN1_OBJECT* obj = NULL;
+
         WOLFSSL_ENTER("wolfSSL_X509_NAME_ENTRY_get_object");
         if (ne == NULL) return NULL;
-        if (wolfSSL_OBJ_nid2obj_ex(ne->nid, &ne->object) != NULL) {
-            ne->object.nid = ne->nid;
-            return &ne->object;
+        obj = wolfSSL_OBJ_nid2obj_ex(ne->nid, ne->object);
+        if (obj != NULL) {
+            obj->nid = ne->nid;
+            return obj;
         }
         return NULL;
@@ -38938,114 +43018,12 @@
 
 
-    /* looks up the DN given the location "loc". "loc" is the number indicating
-     * the order that the DN was parsed as, 0 is first DN parsed.
-     *
-     * returns the setup WOLFSSL_X509_NAME pointer on success and NULL on fail
-     */
-    static WOLFSSL_X509_NAME* wolfSSL_nameByLoc(WOLFSSL_X509_NAME *name, int loc)
-    {
-        char* pt = NULL;
-        int sz = 0;
-
-        switch (name->fullName.loc[loc])
-        {
-        case ASN_COMMON_NAME:
-            sz = name->fullName.cnLen;
-            pt = &name->fullName.fullName[name->fullName.cnIdx];
-            name->cnEntry.nid           = name->fullName.cnNid;
-            break;
-        case ASN_COUNTRY_NAME:
-            sz = name->fullName.cLen;
-            pt = &name->fullName.fullName[name->fullName.cIdx];
-            name->cnEntry.nid           = name->fullName.cNid;
-            break;
-        case ASN_LOCALITY_NAME:
-            sz = name->fullName.lLen;
-            pt = &name->fullName.fullName[name->fullName.lIdx];
-            name->cnEntry.nid           = name->fullName.lNid;
-            break;
-        case ASN_STATE_NAME:
-            sz = name->fullName.stLen;
-            pt = &name->fullName.fullName[name->fullName.stIdx];
-            name->cnEntry.nid           = name->fullName.stNid;
-            break;
-        case ASN_ORG_NAME:
-            sz = name->fullName.oLen;
-            pt = &name->fullName.fullName[name->fullName.oIdx];
-            name->cnEntry.nid           = name->fullName.oNid;
-            break;
-        case ASN_ORGUNIT_NAME:
-            sz = name->fullName.ouLen;
-            pt = &name->fullName.fullName[name->fullName.ouIdx];
-            name->cnEntry.nid           = name->fullName.ouNid;
-            break;
-        case ASN_EMAIL_NAME:
-            sz = name->fullName.emailLen;
-            pt = &name->fullName.fullName[name->fullName.emailIdx];
-            name->cnEntry.nid           = name->fullName.emailNid;
-            break;
-        case ASN_SUR_NAME:
-            sz = name->fullName.snLen;
-            pt = &name->fullName.fullName[name->fullName.snIdx];
-            name->cnEntry.nid           = name->fullName.snNid;
-            break;
-        case ASN_USER_ID:
-            sz = name->fullName.uidLen;
-            pt = &name->fullName.fullName[name->fullName.uidIdx];
-            name->cnEntry.nid           = name->fullName.uidNid;
-            break;
-        case ASN_SERIAL_NUMBER:
-            sz = name->fullName.serialLen;
-            pt = &name->fullName.fullName[name->fullName.serialIdx];
-            name->cnEntry.nid           = name->fullName.serialNid;
-            break;
-#ifdef WOLFSSL_CERT_EXT
-        case ASN_BUS_CAT:
-            sz = name->fullName.bcLen;
-            pt = &name->fullName.fullName[name->fullName.bcIdx];
-            break;
-#endif
-
-        case ASN_DOMAIN_COMPONENT:
-            /* get index of DC i.e. first or second or ... case */
-            {
-                int idx = 0, i;
-                for (i = 0; i < loc; i++) {
-                    if (name->fullName.loc[i] == ASN_DOMAIN_COMPONENT) {
-                        idx++;
-                    }
-                }
-
-                /* check that index is not larger than max buffer size or larger
-                 * than the number of domain components parsed */
-                if (idx >= DOMAIN_COMPONENT_MAX || idx > name->fullName.dcNum) {
-                    WOLFSSL_MSG("Index was larger then domain buffer");
-                    return NULL;
-                }
-                pt = &name->fullName.fullName[name->fullName.dcIdx[idx]],
-                sz = name->fullName.dcLen[idx];
-                name->cnEntry.nid         = ASN_DOMAIN_COMPONENT;
-                name->cnEntry.data.type   = CTC_UTF8;
-            }
-            break;
-
-        default:
-            return NULL;
-        }
-
-        /* -1 to leave room for trailing terminator 0 */
-        if (sz == 0 || sz >= CTC_NAME_SIZE - 1)
-            return NULL;
-        if (wolfSSL_ASN1_STRING_set(name->cnEntry.value, pt, sz) !=
-                WOLFSSL_SUCCESS) {
-            WOLFSSL_MSG("Error setting local ASN1 string data");
-            return NULL;
-        }
-        name->cnEntry.value->type   = CTC_UTF8;
-        name->cnEntry.set           = 1;
-        return name;
-    }
-
-
+#endif /* OPENSSL_ALL || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE ||
+    HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \
+    defined(OPENSSL_EXTRA_X509_SMALL)
+
+    /* returns a pointer to the internal entry at location 'loc' on success,
+     * a null pointer is returned in fail cases */
     WOLFSSL_X509_NAME_ENTRY *wolfSSL_X509_NAME_get_entry(
                                              WOLFSSL_X509_NAME *name, int loc)
@@ -39057,74 +43035,34 @@
         }
 
-        if (loc < 0) {
+        if (loc < 0 || loc >= MAX_NAME_ENTRIES) {
             WOLFSSL_MSG("Bad argument");
             return NULL;
         }
 
-        if (loc <= DN_NAMES_MAX + name->fullName.dcNum) {
-            if (wolfSSL_nameByLoc(name, loc) != NULL)
-                return &name->cnEntry;
-        }
-        /* DC component */
-        if (name->fullName.dcMode) {
-            if (name->fullName.fullName != NULL){
-                if (loc == name->fullName.dcNum){
-                    name->cnEntry.data.data
-                        = &name->fullName.fullName[name->fullName.cIdx];
-                    name->cnEntry.data.length = name->fullName.cLen;
-                    name->cnEntry.nid         = ASN_COUNTRY_NAME;
-                } else {
-                    name->cnEntry.data.data
-                        = &name->fullName.fullName[name->fullName.dcIdx[loc]];
-                    name->cnEntry.data.length = name->fullName.dcLen[loc];
-                    name->cnEntry.nid         = ASN_DOMAIN_COMPONENT;
-                }
-            }
-            name->cnEntry.data.type = CTC_UTF8;
-        /* common name index case */
-        } else if (loc == name->fullName.cnIdx && name->x509 != NULL) {
-            /* get CN shortcut from x509 since it has null terminator */
-            name->cnEntry.data.data   = name->x509->subjectCN;
-            name->cnEntry.data.length = name->fullName.cnLen;
-            name->cnEntry.data.type   = CTC_UTF8;
-            name->cnEntry.nid         = ASN_COMMON_NAME;
-            name->cnEntry.set         = 1;
-        } else {
-            WOLFSSL_MSG("loc passed in is not in range of parsed DN's");
+        if (name->entry[loc].set) {
+            return &name->entry[loc];
+        }
+        else {
             return NULL;
         }
-        return &name->cnEntry;
-    }
-
-    #ifndef NO_WOLFSSL_STUB
+    }
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#ifdef OPENSSL_EXTRA
+
     int wolfSSL_X509_check_private_key(WOLFSSL_X509 *x509, WOLFSSL_EVP_PKEY *key)
     {
-        (void) x509;
-        (void) key;
         WOLFSSL_ENTER("wolfSSL_X509_check_private_key");
-        WOLFSSL_STUB("X509_check_private_key");
-
-        return WOLFSSL_SUCCESS;
-    }
-
-    WOLF_STACK_OF(WOLFSSL_X509_NAME) *wolfSSL_dup_CA_list(
-        WOLF_STACK_OF(WOLFSSL_X509_NAME) *sk)
-    {
-        (void) sk;
-        WOLFSSL_ENTER("wolfSSL_dup_CA_list");
-        WOLFSSL_STUB("SSL_dup_CA_list");
-
-        return NULL;
-    }
-
-    #endif
-
-#endif /* OPENSSL_ALL || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE ||
-    HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */
-#endif /* OPENSSL_EXTRA */
-
-#ifndef WOLFCRYPT_ONLY
-
-#ifdef OPENSSL_EXTRA
+
+        if (!x509 || !key) {
+            WOLFSSL_MSG("Bad parameter");
+            return WOLFSSL_FAILURE;
+        }
+
+        return wc_CheckPrivateKey((byte*)key->pkey.ptr, key->pkey_sz,
+                x509->pubKey.buffer, x509->pubKey.length,
+                (enum Key_Sum)x509->pubKeyOID) == 1 ?
+                        WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
+    }
 
 /* wolfSSL uses negative values for error states. This function returns an
@@ -39179,17 +43117,20 @@
 #endif /* !NO_CERTS */
 
-
-#if defined(HAVE_EX_DATA) || defined(FORTRESS)
+#endif /* OPENSSL_EXTRA */
+
+#if ((defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && defined(HAVE_EX_DATA)) || \
+    defined(FORTRESS) || \
+    defined(WOLFSSL_WPAS_SMALL)
 void* wolfSSL_CTX_get_ex_data(const WOLFSSL_CTX* ctx, int idx)
 {
     WOLFSSL_ENTER("wolfSSL_CTX_get_ex_data");
-    #ifdef HAVE_EX_DATA
+#ifdef HAVE_EX_DATA
     if(ctx != NULL) {
         return wolfSSL_CRYPTO_get_ex_data(&ctx->ex_data, idx);
     }
-    #else
+#else
     (void)ctx;
     (void)idx;
-    #endif
+#endif
     return NULL;
 }
@@ -39247,6 +43188,8 @@
     return WOLFSSL_FAILURE;
 }
-#endif
-
+
+#endif /* ((OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) && HAVE_EX_DATA) || FORTRESS || WOLFSSL_WPAS_SMALL */
+
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
 
 /* Returns char* to app data stored in ex[0].
@@ -39268,5 +43211,5 @@
  * arg data to be stored
  *
- * Returns SSL_SUCCESS on success and SSL_FAILURE on failure
+ * Returns WOLFSSL_SUCCESS on success and SSL_FAILURE on failure
  */
 int wolfSSL_set_app_data(WOLFSSL *ssl, void* arg) {
@@ -39276,4 +43219,8 @@
 }
 
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
+
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
+    defined(WOLFSSL_WPAS_SMALL)
 
 int wolfSSL_set_ex_data(WOLFSSL* ssl, int idx, void* data)
@@ -39294,6 +43241,4 @@
 }
 
-
-
 void* wolfSSL_get_ex_data(const WOLFSSL* ssl, int idx)
 {
@@ -39311,5 +43256,10 @@
 }
 
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL || WOLFSSL_WPAS_SMALL */
+
+#ifdef OPENSSL_EXTRA
+
 #ifndef NO_DSA
+#ifndef NO_BIO
 WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSAparams(WOLFSSL_BIO *bp, WOLFSSL_DSA **x,
         pem_password_cb *cb, void *u)
@@ -39342,11 +43292,11 @@
     }
 
-    if ((ret = PemToDer(buf, (long)bufSz, DSA_PARAM_TYPE, &pDer, NULL, NULL,
-                    NULL)) < 0 ) {
+    if (PemToDer(buf, (long)bufSz, DSA_PARAM_TYPE, &pDer, NULL, NULL,
+                    NULL) < 0 ) {
         WOLFSSL_MSG("Issue converting from PEM to DER");
         return NULL;
     }
 
-    if ((ret = GetSequence(pDer->buffer, &idx, &length, pDer->length)) < 0) {
+    if (GetSequence(pDer->buffer, &idx, &length, pDer->length) < 0) {
         WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_DSAparams", ret);
         FreeDer(&pDer);
@@ -39406,7 +43356,7 @@
     return dsa;
 }
+#endif /* !NO_BIO */
 #endif /* NO_DSA */
 #endif /* OPENSSL_EXTRA */
-#endif /* WOLFCRYPT_ONLY */
 
 #if defined(OPENSSL_EXTRA)
@@ -39481,4 +43431,35 @@
 /* End Functions for openssl/buffer.h */
 
+size_t wolfSSL_strlcpy(char *dst, const char *src, size_t dstSize)
+{
+    size_t i;
+
+    if (!dstSize || !dst || !src)
+        return 0;
+
+    /* Always have to leave a space for NULL */
+    for (i = 0; i < (dstSize - 1) && *src != '\0'; i++) {
+        *dst++ = *src++;
+    }
+    *dst = '\0';
+
+    return i; /* return length without NULL */
+}
+
+size_t wolfSSL_strlcat(char *dst, const char *src, size_t dstSize)
+{
+    size_t dstLen;
+
+    if (!dstSize)
+        return 0;
+
+    dstLen = XSTRLEN(dst);
+
+    if (dstSize < dstLen)
+        return dstLen + XSTRLEN(src);
+
+    return dstLen + wolfSSL_strlcpy(dst + dstLen, src, dstSize - dstLen);
+
+}
 #endif /* OPENSSL_EXTRA */
 
@@ -39487,4 +43468,5 @@
     || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA)
 
+#ifndef NO_BIO
 WOLFSSL_BIO *wolfSSL_BIO_new_file(const char *filename, const char *mode)
 {
@@ -39541,7 +43523,9 @@
 }
 #endif
+#endif /* !NO_BIO */
 
 
 #ifndef NO_DH
+#ifndef NO_BIO
 WOLFSSL_DH *wolfSSL_PEM_read_bio_DHparams(WOLFSSL_BIO *bio, WOLFSSL_DH **x,
         pem_password_cb *cb, void *u)
@@ -39673,4 +43657,5 @@
 #endif
 }
+#endif /* !NO_BIO */
 
 #ifndef NO_FILESYSTEM
@@ -39758,4 +43743,5 @@
 }
 
+#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2))
 int wc_DhPubKeyToDer(DhKey*  key, byte* out, word32* outSz)
 {
@@ -40023,7 +44009,10 @@
     return WOLFSSL_SUCCESS;
 }
+#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
 #endif /* WOLFSSL_QT || OPENSSL_ALL */
 #endif /* !NO_FILESYSTEM */
 #endif /* !NO_DH */
+
+#ifndef NO_BIO
 
 #ifdef WOLFSSL_CERT_GEN
@@ -40126,12 +44115,16 @@
     return WOLFSSL_SUCCESS;
 }
-#endif /* WOLFSSL_CERT_GEN */
 
 int wolfSSL_PEM_write_bio_X509(WOLFSSL_BIO *bio, WOLFSSL_X509 *cert)
 {
-    byte* pem;
+    byte* pem = NULL;
     int   pemSz = 0;
-    const unsigned char* der;
-    int derSz;
+    /* Get large buffer to hold cert der */
+    int derSz = X509_BUFFER_SZ;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* der;
+#else
+    byte der[X509_BUFFER_SZ];
+#endif
     int ret;
 
@@ -40143,7 +44136,14 @@
     }
 
-    der = wolfSSL_X509_get_der(cert, &derSz);
-    if (der == NULL) {
+#ifdef WOLFSSL_SMALL_STACK
+    der = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (!der) {
+        WOLFSSL_MSG("malloc failed");
         return WOLFSSL_FAILURE;
+    }
+#endif
+
+    if (wolfssl_x509_make_der(cert, 0, der, &derSz, 1) != WOLFSSL_SUCCESS) {
+        goto error;
     }
 
@@ -40151,5 +44151,5 @@
     pemSz = wc_DerToPemEx(der, derSz, NULL, 0, NULL, CERT_TYPE);
     if (pemSz < 0) {
-        return WOLFSSL_FAILURE;
+        goto error;
     }
 
@@ -40157,9 +44157,8 @@
     pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
     if (pem == NULL) {
-        return WOLFSSL_FAILURE;
+        goto error;
     }
     if (wc_DerToPemEx(der, derSz, pem, pemSz, NULL, CERT_TYPE) < 0) {
-        XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        return WOLFSSL_FAILURE;
+        goto error;
     }
 
@@ -40170,6 +44169,16 @@
     if (ret <= 0) return WOLFSSL_FAILURE;
     return WOLFSSL_SUCCESS;
-}
-
+
+error:
+    #ifdef WOLFSSL_SMALL_STACK
+    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+    if (pem)
+        XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    return WOLFSSL_FAILURE;
+}
+#endif /* WOLFSSL_CERT_GEN */
+
+#endif /* !NO_BIO */
 
 #if defined(OPENSSL_EXTRA) && !defined(NO_DH)
@@ -40245,7 +44254,7 @@
     switch (cmd) {
         #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+        #ifdef HAVE_SNI
         case SSL_CTRL_SET_TLSEXT_HOSTNAME:
             WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TLSEXT_HOSTNAME.");
-        #ifdef HAVE_SNI
             if (pt == NULL) {
                 WOLFSSL_MSG("Passed in NULL Host Name.");
@@ -40253,7 +44262,4 @@
             }
             return wolfSSL_set_tlsext_host_name(ssl, (const char*) pt);
-        #else
-            WOLFSSL_MSG("SNI not enabled.");
-            break;
         #endif /* HAVE_SNI */
         #endif /* WOLFSSL_NGINX || WOLFSSL_QT || OPENSSL_ALL */
@@ -40314,8 +44320,8 @@
         wolfSSL_sk_X509_free(ctx->x509Chain);
         ctx->x509Chain = sk;
-        if (sk) {
+        if (sk && opt == 1) {
+            /* up all refs when opt == 1 */
             for (i = 0; i < wolfSSL_sk_X509_num(sk); i++) {
                 x509 = wolfSSL_sk_X509_value(sk, i);
-                /* On successful setting of new chain up all refs */
                 if (wolfSSL_X509_up_ref(x509) != 1) {
                     WOLFSSL_MSG("Error increasing reference count");
@@ -40428,4 +44434,6 @@
 }
 
+#ifndef NO_BIO
+
 /* Creates a new bio pair.
 Returns WOLFSSL_SUCCESS if no error, WOLFSSL_FAILURE otherwise.*/
@@ -40455,10 +44463,10 @@
     }
     if (ret && writebuf1) {
-        if (!(ret = wolfSSL_BIO_set_write_buf_size(bio1, writebuf1))) {
+        if (!(ret = wolfSSL_BIO_set_write_buf_size(bio1, (long)writebuf1))) {
             WOLFSSL_MSG("wolfSSL_BIO_set_write_buf() failure");
         }
     }
     if (ret && writebuf2) {
-        if (!(ret = wolfSSL_BIO_set_write_buf_size(bio2, writebuf2))) {
+        if (!(ret = wolfSSL_BIO_set_write_buf_size(bio2, (long)writebuf2))) {
             WOLFSSL_MSG("wolfSSL_BIO_set_write_buf() failure");
         }
@@ -40490,5 +44498,5 @@
     int bioMemSz = 0;
     WOLFSSL_RSA* key = NULL;
-    unsigned char maxKeyBuf[4096];
+    unsigned char *maxKeyBuf = NULL;
     unsigned char* bufPtr = NULL;
     unsigned char* extraBioMem = NULL;
@@ -40505,7 +44513,7 @@
     (void)out;
 
-    bioMemSz = wolfSSL_BIO_pending(bio);
+    bioMemSz = wolfSSL_BIO_get_len(bio);
     if (bioMemSz <= 0) {
-        WOLFSSL_MSG("wolfSSL_BIO_pending() failure");
+        WOLFSSL_MSG("wolfSSL_BIO_get_len() failure");
         return NULL;
     }
@@ -40517,4 +44525,10 @@
     }
 
+    maxKeyBuf = (unsigned char*)XMALLOC(4096, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (maxKeyBuf == NULL) {
+        WOLFSSL_MSG("Malloc failure");
+        XFREE((unsigned char*)bioMem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return NULL;
+    }
     bufPtr = maxKeyBuf;
     if (wolfSSL_BIO_read(bio, (unsigned char*)bioMem, (int)bioMemSz) == bioMemSz) {
@@ -40539,4 +44553,5 @@
                 XFREE((unsigned char*)bioMem, bio->heap,
                                                        DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE((unsigned char*)maxKeyBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
                 return NULL;
             }
@@ -40548,5 +44563,5 @@
 
             wolfSSL_BIO_write(bio, extraBioMem, extraBioMemSz);
-            if (wolfSSL_BIO_pending(bio) <= 0) {
+            if (wolfSSL_BIO_get_len(bio) <= 0) {
                 WOLFSSL_MSG("Failed to write memory to bio");
                 XFREE((unsigned char*)extraBioMem, bio->heap,
@@ -40554,4 +44569,5 @@
                 XFREE((unsigned char*)bioMem, bio->heap,
                                                        DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE((unsigned char*)maxKeyBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
                 return NULL;
             }
@@ -40565,7 +44581,10 @@
     }
     XFREE((unsigned char*)bioMem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE((unsigned char*)maxKeyBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
     return key;
 }
 #endif
+
+#endif /* !NO_BIO */
 
 
@@ -40595,5 +44614,5 @@
     int ret;
     int derSize;
-    unsigned char maxDerBuf[4096];
+    unsigned char *maxDerBuf;
     unsigned char* key = NULL;
 
@@ -40603,4 +44622,9 @@
         WOLFSSL_MSG("one or more inputs were NULL");
         return BAD_FUNC_ARG;
+    }
+    maxDerBuf = (unsigned char*)XMALLOC(4096, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (maxDerBuf == NULL) {
+        WOLFSSL_MSG("Malloc failure");
+        return MEMORY_E;
     }
     key = maxDerBuf;
@@ -40608,4 +44632,5 @@
     if ((derSize = wolfSSL_i2d_RSAPrivateKey(rsa, &key)) <= 0) {
         WOLFSSL_MSG("wolfSSL_i2d_RSAPrivateKey() failure");
+        XFREE(maxDerBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
         return WOLFSSL_FAILURE;
     }
@@ -40614,6 +44639,8 @@
     if (ret != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("wolfSSL_CTX_USE_PrivateKey_buffer() failure");
+        XFREE(maxDerBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
         return WOLFSSL_FAILURE;
     }
+    XFREE(maxDerBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
     return ret;
 }
@@ -40621,4 +44648,5 @@
 
 
+#ifndef NO_BIO
 /* Converts EVP_PKEY data from a bio buffer to a WOLFSSL_EVP_PKEY structure.
 Returns pointer to private EVP_PKEY struct upon success, NULL if there
@@ -40642,7 +44670,7 @@
     (void)out;
 
-    memSz = wolfSSL_BIO_pending(bio);
+    memSz = wolfSSL_BIO_get_len(bio);
     if (memSz <= 0) {
-        WOLFSSL_MSG("wolfSSL_BIO_pending() failure");
+        WOLFSSL_MSG("wolfSSL_BIO_get_len() failure");
         return NULL;
     }
@@ -40682,5 +44710,5 @@
 
             wolfSSL_BIO_write(bio, extraBioMem, extraBioMemSz);
-            if (wolfSSL_BIO_pending(bio) <= 0) {
+            if (wolfSSL_BIO_get_len(bio) <= 0) {
                 WOLFSSL_MSG("Failed to write memory to bio");
                 XFREE((unsigned char*)extraBioMem, bio->heap,
@@ -40700,4 +44728,5 @@
     return key;
 }
+#endif /* !NO_BIO */
 
 
@@ -40815,6 +44844,11 @@
     (void)fp;
 }
-#endif
-
+#endif /* !NO_FILESYSTEM */
+
+#endif /* OPENSSL_ALL || OPENSSL_EXTRA || HAVE_STUNNEL || WOLFSSL_NGINX ||
+    HAVE_LIGHTY || WOLFSSL_HAPROXY || WOLFSSL_OPENSSH */
+
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || defined(FORTRESS)
 int wolfSSL_SESSION_set_ex_data(WOLFSSL_SESSION* session, int idx, void* data)
 {
@@ -40831,4 +44865,23 @@
     return WOLFSSL_FAILURE;
 }
+
+void* wolfSSL_SESSION_get_ex_data(const WOLFSSL_SESSION* session, int idx)
+{
+    WOLFSSL_ENTER("wolfSSL_SESSION_get_ex_data");
+#ifdef HAVE_EX_DATA
+    if (session != NULL) {
+        return wolfSSL_CRYPTO_get_ex_data(&session->ex_data, idx);
+    }
+#else
+    (void)session;
+    (void)idx;
+#endif
+    return NULL;
+}
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL || FORTRESS */
+
+#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || \
+                             defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY) || \
+                             defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_OPENSSH)))
 
 
@@ -40848,19 +44901,4 @@
     }
     return WOLFSSL_FAILURE;
-}
-
-
-void* wolfSSL_SESSION_get_ex_data(const WOLFSSL_SESSION* session, int idx)
-{
-    WOLFSSL_ENTER("wolfSSL_SESSION_get_ex_data");
-#ifdef HAVE_EX_DATA
-    if (session != NULL) {
-        return wolfSSL_CRYPTO_get_ex_data(&session->ex_data, idx);
-    }
-#else
-    (void)session;
-    (void)idx;
-#endif
-    return NULL;
 }
 
@@ -41046,41 +45084,4 @@
 }
 
-
-/* copies over data of "in" to "out" */
-static void wolfSSL_CIPHER_copy(WOLFSSL_CIPHER* in, WOLFSSL_CIPHER* out)
-{
-    if (in == NULL || out == NULL)
-        return;
-
-    out->cipherSuite  = in->cipherSuite;
-    out->cipherSuite0 = in->cipherSuite0;
-}
-
-
-/* create duplicate of stack and return the new stack
- * returns null on failure */
-WOLF_STACK_OF(WOLFSSL_CIPHER)* wolfSSL_sk_SSL_CIPHER_dup(
-        WOLF_STACK_OF(WOLFSSL_CIPHER)* in)
-{
-    WOLFSSL_STACK* current;
-    WOLF_STACK_OF(WOLFSSL_CIPHER)* ret = NULL;
-    int i, sz;
-
-    sz = wolfSSL_sk_SSL_CIPHER_num(in);
-    current = in;
-    for (i = 0; i < sz && current != NULL; i++) {
-        WOLFSSL_STACK* add = wolfSSL_sk_new_node(in->heap);
-        if (add != NULL) {
-            add->type = STACK_TYPE_CIPHER;
-            wolfSSL_CIPHER_copy(&(current->data.cipher), &(add->data.cipher));
-            add->num = i+1;
-            add->next = ret;
-            ret = add;
-            current = current->next;
-        }
-    }
-    return ret;
-}
-
 /* nothing to do yet */
 static void wolfSSL_CIPHER_free(WOLFSSL_CIPHER* in)
@@ -41141,5 +45142,5 @@
         sk->data.info = node->data.info;
         sk->next = node->next;
-        XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL);
+        wolfSSL_sk_free_node(node);
     }
     else { /* last x509 in stack */
@@ -41254,4 +45255,36 @@
     return sk;
 }
+
+
+/* Creates a duplicate of WOLF_STACK_OF(WOLFSSL_X509_NAME).
+ * Returns a new WOLF_STACK_OF(WOLFSSL_X509_NAME) or NULL on failure */
+WOLF_STACK_OF(WOLFSSL_X509_NAME) *wolfSSL_dup_CA_list(
+    WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk)
+{
+    int i;
+    const int num = wolfSSL_sk_X509_NAME_num(sk);
+    WOLF_STACK_OF(WOLFSSL_X509_NAME) *copy;
+    WOLFSSL_X509_NAME *name;
+
+    WOLFSSL_ENTER("wolfSSL_dup_CA_list");
+
+    copy = wolfSSL_sk_X509_NAME_new(NULL);
+    if (copy == NULL) {
+        WOLFSSL_MSG("Memory error");
+        return NULL;
+    }
+
+    for (i = 0; i < num; i++) {
+        name = wolfSSL_X509_NAME_dup(wolfSSL_sk_X509_NAME_value(sk, i));
+        if (name == NULL || 0 != wolfSSL_sk_X509_NAME_push(copy, name)) {
+            WOLFSSL_MSG("Memory error");
+            wolfSSL_sk_X509_NAME_pop_free(copy, wolfSSL_X509_NAME_free);
+            return NULL;
+        }
+    }
+
+    return copy;
+}
+
 
 int wolfSSL_sk_X509_NAME_push(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk,
@@ -41450,4 +45483,6 @@
     XFREE(sk, sk->heap, DYNAMIC_TYPE_OPENSSL);
 }
+
+#ifndef NO_BIO
 
 #if defined(WOLFSSL_APACHE_HTTPD) || defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
@@ -41508,5 +45543,5 @@
 #if defined(WOLFSSL_APACHE_HTTPD) || defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
     int count = 0, len = 0, totalSz = 0, tmpSz = 0;
-    char tmp[ASN_NAME_MAX];
+    char tmp[ASN_NAME_MAX+1];
     char fullName[ASN_NAME_MAX];
     const char *buf = NULL;
@@ -41550,5 +45585,5 @@
                 /* tmpSz+1 for last null char */
                 XSNPRINTF(tmp, tmpSz+1, "%s=%s,", buf, str->data);
-                XSTRNCAT(fullName, tmp, tmpSz);
+                XSTRNCAT(fullName, tmp, tmpSz+1);
             }
             else {
@@ -41575,4 +45610,27 @@
     return WOLFSSL_SUCCESS;
 }
+#endif /* !NO_BIO */
+
+#ifndef NO_FILESYSTEM
+int wolfSSL_X509_NAME_print_ex_fp(XFILE file, WOLFSSL_X509_NAME* name,
+        int indent, unsigned long flags)
+{
+    WOLFSSL_BIO* bio;
+    int ret;
+
+    WOLFSSL_ENTER("wolfSSL_X509_NAME_print_ex_fp");
+
+    if (!(bio = wolfSSL_BIO_new_fp(file, BIO_NOCLOSE))) {
+        WOLFSSL_MSG("wolfSSL_BIO_new_fp error");
+        return WOLFSSL_FAILURE;
+    }
+
+    ret = wolfSSL_X509_NAME_print_ex(bio, name, indent, flags);
+
+    wolfSSL_BIO_free(bio);
+
+    return ret;
+}
+#endif
 
 #ifndef NO_WOLFSSL_STUB
@@ -41682,4 +45740,6 @@
 
 
+#ifdef HAVE_SNI
+
 void wolfSSL_CTX_set_servername_callback(WOLFSSL_CTX* ctx, CallbackSniRecv cb)
 {
@@ -41710,8 +45770,13 @@
 }
 
+#endif /* HAVE_SNI */
+
+
+#ifndef NO_BIO
 void wolfSSL_ERR_load_BIO_strings(void) {
     WOLFSSL_ENTER("ERR_load_BIO_strings");
     /* do nothing */
 }
+#endif
 
 #ifndef NO_WOLFSSL_STUB
@@ -41782,4 +45847,11 @@
 #if defined(OPENSSL_EXTRA)
 
+int wolfSSL_CRYPTO_memcmp(const void *a, const void *b, size_t size)
+{
+    if (!a || !b)
+        return 0;
+    return ConstantCompare((const byte*)a, (const byte*)b, (int)size);
+}
+
 int wolfSSL_sk_X509_num(const WOLF_STACK_OF(WOLFSSL_X509) *s)
 {
@@ -41837,4 +45909,6 @@
 #if (defined(HAVE_SESSION_TICKET) || defined(SESSION_CERTS)) && \
     !defined(NO_FILESYSTEM)
+
+#ifndef NO_BIO
 
 #if defined(SESSION_CERTS) || \
@@ -41996,4 +46070,6 @@
 #endif
 
+#if !defined(NO_SESSION_CACHE) && (defined(OPENSSL_EXTRA) || \
+        defined(HAVE_EXT_CACHE))
     if (wolfSSL_BIO_printf(bp, "    Start Time: %ld\n",
                 wolfSSL_SESSION_get_time(x)) <= 0)
@@ -42003,4 +46079,5 @@
             wolfSSL_SESSION_get_timeout(x)) <= 0)
         return WOLFSSL_FAILURE;
+#endif /* !NO_SESSION_CACHE && OPENSSL_EXTRA || HAVE_EXT_CACHE */
 
     /* @TODO verify return code print */
@@ -42012,4 +46089,6 @@
     return WOLFSSL_SUCCESS;
 }
+
+#endif /* !NO_BIO */
 #endif /* (HAVE_SESSION_TICKET || SESSION_CERTS) && !NO_FILESYSTEM */
 
@@ -42019,22 +46098,55 @@
     || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX)
 
-int wolfSSL_CTX_get_verify_mode(WOLFSSL_CTX* ctx)
+/* TODO: Doesn't currently track SSL_VERIFY_CLIENT_ONCE */
+int wolfSSL_get_verify_mode(const WOLFSSL* ssl) {
+    int mode = 0;
+    WOLFSSL_ENTER("wolfSSL_get_verify_mode");
+
+    if (!ssl) {
+        return WOLFSSL_FAILURE;
+    }
+
+    if (ssl->options.verifyNone) {
+        mode = WOLFSSL_VERIFY_NONE;
+    }
+    else {
+        if (ssl->options.verifyPeer) {
+            mode |= WOLFSSL_VERIFY_PEER;
+        }
+        if (ssl->options.failNoCert) {
+            mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+        }
+        if (ssl->options.failNoCertxPSK) {
+            mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK;
+        }
+    }
+
+    WOLFSSL_LEAVE("wolfSSL_get_verify_mode", mode);
+    return mode;
+}
+
+int wolfSSL_CTX_get_verify_mode(const WOLFSSL_CTX* ctx)
 {
     int mode = 0;
     WOLFSSL_ENTER("wolfSSL_CTX_get_verify_mode");
 
-    if(!ctx)
-        return WOLFSSL_FATAL_ERROR;
-
-    if (ctx->verifyPeer)
-        mode |= WOLFSSL_VERIFY_PEER;
-    else if (ctx->verifyNone)
-        mode |= WOLFSSL_VERIFY_NONE;
-
-    if (ctx->failNoCert)
-        mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-
-    if (ctx->failNoCertxPSK)
-        mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK;
+    if (!ctx) {
+        return WOLFSSL_FAILURE;
+    }
+
+    if (ctx->verifyNone) {
+        mode = WOLFSSL_VERIFY_NONE;
+    }
+    else {
+        if (ctx->verifyPeer) {
+            mode |= WOLFSSL_VERIFY_PEER;
+        }
+        if (ctx->failNoCert) {
+            mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+        }
+        if (ctx->failNoCertxPSK) {
+            mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK;
+        }
+    }
 
     WOLFSSL_LEAVE("wolfSSL_CTX_get_verify_mode", mode);
@@ -42641,5 +46753,5 @@
     }
 
-    if (wc_ed448_sign_msg(msg, msgSz, sig, sigSz, &key) != MP_OKAY)
+    if (wc_ed448_sign_msg(msg, msgSz, sig, sigSz, &key, NULL, 0) != MP_OKAY)
         WOLFSSL_MSG("wc_curve448_shared_secret_ex failed");
     else
@@ -42693,5 +46805,5 @@
 
     if ((ret = wc_ed448_verify_msg((byte*)sig, sigSz, msg, msgSz, &check,
-                                   &key)) != MP_OKAY) {
+                                   &key, NULL, 0)) != MP_OKAY) {
         WOLFSSL_MSG("wc_ed448_verify_msg failed");
     }
@@ -42788,5 +46900,6 @@
 
         while (1) {
-            if ((ret = wc_PeekErrorNode(-1, file, NULL, line)) < 0) {
+            ret = wc_PeekErrorNode(-1, file, NULL, line);
+            if (ret == BAD_MUTEX_E || ret == BAD_FUNC_ARG || ret == BAD_STATE_E) {
                 WOLFSSL_MSG("Issue peeking at error node in queue");
                 return 0;
@@ -42799,7 +46912,7 @@
             if (ret == -ASN_NO_PEM_HEADER)
                 return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE;
-            if (ret != WANT_READ && ret != WANT_WRITE &&
-                    ret != ZERO_RETURN && ret != WOLFSSL_ERROR_ZERO_RETURN &&
-                    ret != SOCKET_PEER_CLOSED_E && ret != SOCKET_ERROR_E)
+            if (ret != -WANT_READ && ret != -WANT_WRITE &&
+                    ret != -ZERO_RETURN && ret != -WOLFSSL_ERROR_ZERO_RETURN &&
+                    ret != -SOCKET_PEER_CLOSED_E && ret != -SOCKET_ERROR_E)
                 break;
 
@@ -42816,4 +46929,61 @@
 
 #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+
+
+/* Is the specified cipher suite a fake one used an an extension proxy? */
+static WC_INLINE int SCSV_Check(byte suite0, byte suite)
+{
+    (void)suite0;
+    (void)suite;
+#ifdef HAVE_RENEGOTIATION_INDICATION
+    if (suite0 == CIPHER_BYTE && suite == TLS_EMPTY_RENEGOTIATION_INFO_SCSV)
+        return 1;
+#endif
+#ifdef BUILD_TLS_QSH
+    /* This isn't defined as a SCSV, but it acts like one. */
+    if (suite0 == QSH_BYTE && suite == TLS_QSH)
+        return 1;
+#endif
+    return 0;
+}
+
+static WC_INLINE int sslCipherMinMaxCheck(const WOLFSSL *ssl, byte suite0,
+        byte suite)
+{
+    const CipherSuiteInfo* cipher_names = GetCipherNames();
+    int cipherSz = GetCipherNamesSize();
+    int i;
+    for (i = 0; i < cipherSz; i++)
+        if (cipher_names[i].cipherSuite0 == suite0 &&
+                cipher_names[i].cipherSuite == suite)
+            break;
+    if (i == cipherSz)
+        return 1;
+    /* Check min version */
+    if (cipher_names[i].minor < ssl->options.minDowngrade) {
+        if (ssl->options.minDowngrade <= TLSv1_2_MINOR &&
+                cipher_names[i].minor >= TLSv1_MINOR)
+            /* 1.0 ciphersuites are in general available in 1.1 and
+             * 1.1 ciphersuites are in general available in 1.2 */
+            return 0;
+        return 1;
+    }
+    /* Check max version */
+    switch (cipher_names[i].minor) {
+    case SSLv3_MINOR :
+        return ssl->options.mask & WOLFSSL_OP_NO_SSLv3;
+    case TLSv1_MINOR :
+        return ssl->options.mask & WOLFSSL_OP_NO_TLSv1;
+    case TLSv1_1_MINOR :
+        return ssl->options.mask & WOLFSSL_OP_NO_TLSv1_1;
+    case TLSv1_2_MINOR :
+        return ssl->options.mask & WOLFSSL_OP_NO_TLSv1_2;
+    case TLSv1_3_MINOR :
+        return ssl->options.mask & WOLFSSL_OP_NO_TLSv1_3;
+    default:
+        WOLFSSL_MSG("Unrecognized minor version");
+        return 1;
+    }
+}
 
 /* returns a pointer to internal cipher suite list. Should not be free'd by
@@ -42824,4 +46994,8 @@
     WOLF_STACK_OF(WOLFSSL_CIPHER)* ret = NULL;
     Suites* suites;
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
+    const CipherSuiteInfo* cipher_names = GetCipherNames();
+    int cipherSz = GetCipherNamesSize();
+#endif
 
     WOLFSSL_ENTER("wolfSSL_get_ciphers_compat");
@@ -42831,4 +47005,9 @@
 
     if (ssl->suites != NULL) {
+        if (ssl->suites->suiteSz == 0 &&
+                InitSSL_Suites((WOLFSSL*)ssl) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("Suite initialization failure");
+            return NULL;
+        }
         suites = ssl->suites;
     }
@@ -42840,13 +47019,38 @@
     if (suites->stack == NULL) {
         int i;
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
+        int j;
+#endif
         for (i = 0; i < suites->suiteSz; i+=2) {
-            WOLFSSL_STACK* add = wolfSSL_sk_new_node(ssl->heap);
+            WOLFSSL_STACK* add;
+
+            /* A couple of suites are placeholders for special options,
+             * skip those. */
+            if (SCSV_Check(suites->suites[i], suites->suites[i+1])
+                    || sslCipherMinMaxCheck(ssl, suites->suites[i],
+                                            suites->suites[i+1])) {
+                continue;
+            }
+
+            add = wolfSSL_sk_new_node(ssl->heap);
             if (add != NULL) {
                 add->type = STACK_TYPE_CIPHER;
                 add->data.cipher.cipherSuite0 = suites->suites[i];
                 add->data.cipher.cipherSuite  = suites->suites[i+1];
+                add->data.cipher.ssl          = ssl;
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
+                for (j = 0; j < cipherSz; j++) {
+                    if (cipher_names[j].cipherSuite0 ==
+                            add->data.cipher.cipherSuite0 &&
+                            cipher_names[j].cipherSuite ==
+                                    add->data.cipher.cipherSuite) {
+                        add->data.cipher.offset = j;
+                        break;
+                    }
+                }
+#endif
                 #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
                 /* in_stack is checked in wolfSSL_CIPHER_description */
-                add->data.cipher.in_stack = 1;
+                add->data.cipher.in_stack     = 1;
                 #endif
 
@@ -42877,4 +47081,5 @@
 #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \
     || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY)
+
 int wolfSSL_X509_get_ex_new_index(int idx, void *arg, void *a, void *b, void *c)
 {
@@ -42890,5 +47095,8 @@
     return x509_idx++;
 }
-
+#endif
+
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
+    defined(WOLFSSL_WPAS_SMALL)
 #if defined(HAVE_EX_DATA) || defined(FORTRESS)
 void* wolfSSL_CRYPTO_get_ex_data(const WOLFSSL_CRYPTO_EX_DATA* ex_data, int idx)
@@ -42921,17 +47129,17 @@
     return WOLFSSL_FAILURE;
 }
-#endif /* defined(HAVE_EX_DATA) || defined(FORTRESS) */
+#endif /* HAVE_EX_DATA || FORTRESS */
 
 void *wolfSSL_X509_get_ex_data(X509 *x509, int idx)
 {
     WOLFSSL_ENTER("wolfSSL_X509_get_ex_data");
-    #ifdef HAVE_EX_DATA
+#ifdef HAVE_EX_DATA
     if (x509 != NULL) {
         return wolfSSL_CRYPTO_get_ex_data(&x509->ex_data, idx);
     }
-    #else
+#else
     (void)x509;
     (void)idx;
-    #endif
+#endif
     return NULL;
 }
@@ -42940,16 +47148,99 @@
 {
     WOLFSSL_ENTER("wolfSSL_X509_set_ex_data");
-    #ifdef HAVE_EX_DATA
+#ifdef HAVE_EX_DATA
     if (x509 != NULL)
     {
         return wolfSSL_CRYPTO_set_ex_data(&x509->ex_data, idx, data);
     }
-    #else
+#else
     (void)x509;
     (void)idx;
     (void)data;
-    #endif
+#endif
     return WOLFSSL_FAILURE;
 }
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL || WOLFSSL_WPAS_SMALL */
+
+
+#ifndef NO_ASN
+int wolfSSL_X509_check_host(WOLFSSL_X509 *x, const char *chk, size_t chklen,
+                    unsigned int flags, char **peername)
+{
+    int         ret;
+    DecodedCert dCert;
+
+    WOLFSSL_ENTER("wolfSSL_X509_check_host");
+
+    /* flags and peername not needed for Nginx. */
+    (void)flags;
+    (void)peername;
+
+    if ((x == NULL) || (chk == NULL)) {
+        WOLFSSL_MSG("Invalid parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (flags == WOLFSSL_NO_WILDCARDS) {
+        WOLFSSL_MSG("X509_CHECK_FLAG_NO_WILDCARDS not yet implemented");
+        return WOLFSSL_FAILURE;
+    }
+
+    InitDecodedCert(&dCert, x->derCert->buffer, x->derCert->length, NULL);
+    ret = ParseCertRelative(&dCert, CERT_TYPE, 0, NULL);
+    if (ret != 0) {
+        FreeDecodedCert(&dCert);
+        return WOLFSSL_FAILURE;
+    }
+
+    ret = CheckHostName(&dCert, (char *)chk, chklen);
+    FreeDecodedCert(&dCert);
+    if (ret != 0)
+        return WOLFSSL_FAILURE;
+    return WOLFSSL_SUCCESS;
+}
+
+
+int wolfSSL_X509_check_ip_asc(WOLFSSL_X509 *x, const char *ipasc,
+        unsigned int flags)
+{
+    int ret = WOLFSSL_FAILURE;
+    DecodedCert dCert;
+
+    WOLFSSL_ENTER("wolfSSL_X509_check_ip_asc");
+
+    /* flags not yet implemented */
+    (void)flags;
+
+    if ((x == NULL) || (x->derCert == NULL) || (ipasc == NULL)) {
+        WOLFSSL_MSG("Invalid parameter");
+    }
+    else {
+        ret = WOLFSSL_SUCCESS;
+    }
+
+    if (ret == WOLFSSL_SUCCESS) {
+        InitDecodedCert(&dCert, x->derCert->buffer, x->derCert->length, NULL);
+        ret = ParseCertRelative(&dCert, CERT_TYPE, 0, NULL);
+        if (ret != 0) {
+            ret = WOLFSSL_FAILURE;
+        }
+        else {
+            ret = CheckIPAddr(&dCert, ipasc);
+            if (ret != 0) {
+                ret = WOLFSSL_FAILURE;
+            }
+            else {
+                ret = WOLFSSL_SUCCESS;
+            }
+        }
+        FreeDecodedCert(&dCert);
+    }
+
+    return ret;
+}
+#endif
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \
+    || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY)
 
 int wolfSSL_X509_NAME_digest(const WOLFSSL_X509_NAME *name,
@@ -42962,6 +47253,6 @@
 
 #if !defined(NO_FILESYSTEM) && !defined(NO_PWDBASED)
-    return wolfSSL_EVP_Digest((unsigned char*)name->fullName.fullName,
-                              name->fullName.fullNameLen, md, len, type, NULL);
+    return wolfSSL_EVP_Digest((unsigned char*)name->name,
+                              name->sz, md, len, type, NULL);
 #else
     (void)md;
@@ -43030,4 +47321,5 @@
 }
 
+#ifndef NO_BIO
 BIO *wolfSSL_SSL_get_rbio(const WOLFSSL *s)
 {
@@ -43130,32 +47422,93 @@
 #endif /* NO_SESSION_CACHE */
 
-int wolfSSL_X509_check_host(X509 *x, const char *chk, size_t chklen,
-                    unsigned int flags, char **peername)
-{
-    int         ret;
-    DecodedCert dCert;
-
-    WOLFSSL_ENTER("wolfSSL_X509_check_host");
-
-    /* flags and peername not needed for Nginx. */
-    (void)flags;
-    (void)peername;
-
-    if (flags == WOLFSSL_NO_WILDCARDS) {
-        WOLFSSL_MSG("X509_CHECK_FLAG_NO_WILDCARDS not yet implemented");
+int wolfSSL_a2i_ASN1_INTEGER(WOLFSSL_BIO *bio, WOLFSSL_ASN1_INTEGER *asn1,
+        char *buf, int size)
+{
+    int readNextLine;
+    int lineLen;
+    int len;
+    byte isNumCheck;
+    word32 outLen;
+    const int extraTagSz = MAX_LENGTH_SZ + 1;
+    byte intTag[MAX_LENGTH_SZ + 1];
+    int idx = 0;
+
+    WOLFSSL_ENTER("wolfSSL_a2i_ASN1_INTEGER");
+
+    if (!bio || !asn1 || !buf || size <= 0) {
+        WOLFSSL_MSG("Bad parameter");
         return WOLFSSL_FAILURE;
     }
 
-    InitDecodedCert(&dCert, x->derCert->buffer, x->derCert->length, NULL);
-    ret = ParseCertRelative(&dCert, CERT_TYPE, 0, NULL);
-    if (ret != 0) {
-        FreeDecodedCert(&dCert);
-        return WOLFSSL_FAILURE;
-    }
-
-    ret = CheckHostName(&dCert, (char *)chk, chklen);
-    FreeDecodedCert(&dCert);
-    if (ret != 0)
-        return WOLFSSL_FAILURE;
+    /* Reset asn1 */
+    if (asn1->isDynamic && asn1->data) {
+        XFREE(asn1->data, NULL, DYNAMIC_TYPE_OPENSSL);
+        asn1->isDynamic = 0;
+    }
+    XMEMSET(asn1->intData, 0, sizeof(WOLFSSL_ASN1_INTEGER));
+    asn1->data = asn1->intData;
+    asn1->length = 0;
+    asn1->negative = 0;
+    asn1->type = V_ASN1_INTEGER;
+
+    lineLen = wolfSSL_BIO_gets(bio, buf, size);
+    do {
+        readNextLine = 0;
+        if (lineLen <= 0) {
+            WOLFSSL_MSG("wolfSSL_BIO_gets error");
+            return WOLFSSL_FAILURE;
+        }
+        while (lineLen && (buf[lineLen-1] == '\n' || buf[lineLen-1] == '\r'))
+            lineLen--;
+        if (buf[lineLen-1] == '\\')
+            readNextLine = 1;
+        /* Ignore none-hex chars at the end of the line */
+        outLen = 1;
+        while (lineLen && Base16_Decode((byte*)buf + lineLen - 1, 1,
+                &isNumCheck, &outLen) == ASN_INPUT_E)
+            lineLen--;
+        if (!lineLen || lineLen % 2) {
+            WOLFSSL_MSG("Invalid line length");
+            return WOLFSSL_FAILURE;
+        }
+        len = asn1->length + (lineLen/2);
+        /* Check if it will fit in static memory and
+         * save space for the ASN tag in front */
+        if (len > (int)(sizeof(asn1->intData) - extraTagSz)) {
+            /* Allocate mem for data */
+            if (asn1->isDynamic) {
+                byte* tmp = (byte*)XREALLOC(asn1->data, len + extraTagSz, NULL,
+                        DYNAMIC_TYPE_OPENSSL);
+                if (!tmp) {
+                    WOLFSSL_MSG("realloc error");
+                    return WOLFSSL_FAILURE;
+                }
+                asn1->data = tmp;
+            }
+            else {
+                asn1->data = (byte*)XMALLOC(len + extraTagSz, NULL,
+                        DYNAMIC_TYPE_OPENSSL);
+                if (!asn1->data) {
+                    WOLFSSL_MSG("malloc error");
+                    return WOLFSSL_FAILURE;
+                }
+                XMEMCPY(asn1->data, asn1->intData, asn1->length);
+            }
+        }
+        len = lineLen/2;
+        if (Base16_Decode((byte*)buf, lineLen, asn1->data + asn1->length,
+                (word32*)&len) != 0) {
+            WOLFSSL_MSG("Base16_Decode error");
+            return WOLFSSL_FAILURE;
+        }
+        asn1->length += len;
+    } while (readNextLine);
+
+    /* Write ASN tag */
+    idx = SetASNInt(asn1->length, asn1->data[0], intTag);
+    XMEMMOVE(asn1->data + idx, asn1->data, asn1->length);
+    XMEMCPY(asn1->data, intTag, idx);
+    asn1->dataMax = asn1->length += idx;
+
     return WOLFSSL_SUCCESS;
 }
@@ -43163,9 +47516,8 @@
 int wolfSSL_i2a_ASN1_INTEGER(BIO *bp, const WOLFSSL_ASN1_INTEGER *a)
 {
-    static char num[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
-                            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-    int    i;
-    word32 j;
-    word32 len = 0;
+    word32 idx = 1;
+    int len = 0;
+    byte buf[512];
+    word32 bufLen = 512;
 
     WOLFSSL_ENTER("wolfSSL_i2a_ASN1_INTEGER");
@@ -43175,30 +47527,7 @@
 
     /* Skip ASN.1 INTEGER (type) byte. */
-    i = 1;
-    /* When indefinite length, can't determine length with data available. */
-    if (a->data[i] == 0x80)
+    if (a->data[idx] == 0x80 || /* Indefinite length, can't determine length */
+            GetLength(a->data, &idx, &len, a->length) < 0) {
         return 0;
-    /* One length byte if less than 0x80. */
-    if (a->data[i] < 0x80)
-        len = a->data[i++];
-    /* Multiple length byte if greater than 0x80. */
-    else if (a->data[i] > 0x80) {
-        switch (a->data[i++] - 0x80) {
-            case 4:
-                len |= a->data[i++] << 24;
-                FALL_THROUGH;
-            case 3:
-                len |= a->data[i++] << 16;
-                FALL_THROUGH;
-            case 2:
-                len |= a->data[i++] <<  8;
-                FALL_THROUGH;
-            case 1:
-                len |= a->data[i++];
-                break;
-            default:
-                /* Not supporting greater than 4 bytes of length. */
-                return 0;
-        }
     }
 
@@ -43209,13 +47538,12 @@
     }
 
-    /* Don't do negative - just write out every byte. */
-    for (j = 0; j < len; i++,j++) {
-        wolfSSL_BIO_write(bp, &num[a->data[i] >> 4], 1);
-        wolfSSL_BIO_write(bp, &num[a->data[i] & 0xf], 1);
-    }
-
-    /* Two nibbles written for each byte. */
-    return len * 2;
-}
+    if (Base16_Encode(a->data + idx, len, buf, &bufLen) != 0 ||
+            bufLen <= 0) {
+        return 0;
+    }
+
+    return wolfSSL_BIO_write(bp, buf, bufLen - 1); /* Don't write out NULL char */
+}
+#endif /* !NO_BIO */
 
 
@@ -43344,8 +47672,76 @@
     return WOLFSSL_SUCCESS;
 }
+
 #endif /* HAVE_SESSION_TICKET */
 
 #endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY ||
     OPENSSL_EXTRA || HAVE_LIGHTY */
+
+#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
+    !defined(NO_WOLFSSL_SERVER)
+/* Serialize the session ticket encryption keys.
+ *
+ * @param [in]  ctx     SSL/TLS context object.
+ * @param [in]  keys    Buffer to hold session ticket keys.
+ * @param [in]  keylen  Length of buffer.
+ * @return  WOLFSSL_SUCCESS on success.
+ * @return  WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the
+ *          correct length.
+ */
+long wolfSSL_CTX_get_tlsext_ticket_keys(WOLFSSL_CTX *ctx,
+     unsigned char *keys, int keylen)
+{
+    if (ctx == NULL || keys == NULL) {
+        return WOLFSSL_FAILURE;
+    }
+    if (keylen != WOLFSSL_TICKET_KEYS_SZ) {
+        return WOLFSSL_FAILURE;
+    }
+
+    XMEMCPY(keys, ctx->ticketKeyCtx.name, WOLFSSL_TICKET_NAME_SZ);
+    keys += WOLFSSL_TICKET_NAME_SZ;
+    XMEMCPY(keys, ctx->ticketKeyCtx.key[0], WOLFSSL_TICKET_KEY_SZ);
+    keys += WOLFSSL_TICKET_KEY_SZ;
+    XMEMCPY(keys, ctx->ticketKeyCtx.key[1], WOLFSSL_TICKET_KEY_SZ);
+    keys += WOLFSSL_TICKET_KEY_SZ;
+    c32toa(ctx->ticketKeyCtx.expirary[0], keys);
+    keys += OPAQUE32_LEN;
+    c32toa(ctx->ticketKeyCtx.expirary[1], keys);
+
+    return WOLFSSL_SUCCESS;
+}
+
+/* Deserialize the session ticket encryption keys.
+ *
+ * @param [in]  ctx     SSL/TLS context object.
+ * @param [in]  keys    Session ticket keys.
+ * @param [in]  keylen  Length of data.
+ * @return  WOLFSSL_SUCCESS on success.
+ * @return  WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the
+ *          correct length.
+ */
+long wolfSSL_CTX_set_tlsext_ticket_keys(WOLFSSL_CTX *ctx,
+     unsigned char *keys, int keylen)
+{
+    if (ctx == NULL || keys == NULL) {
+        return WOLFSSL_FAILURE;
+    }
+    if (keylen != WOLFSSL_TICKET_KEYS_SZ) {
+        return WOLFSSL_FAILURE;
+    }
+
+    XMEMCPY(ctx->ticketKeyCtx.name, keys, WOLFSSL_TICKET_NAME_SZ);
+    keys += WOLFSSL_TICKET_NAME_SZ;
+    XMEMCPY(ctx->ticketKeyCtx.key[0], keys, WOLFSSL_TICKET_KEY_SZ);
+    keys += WOLFSSL_TICKET_KEY_SZ;
+    XMEMCPY(ctx->ticketKeyCtx.key[1], keys, WOLFSSL_TICKET_KEY_SZ);
+    keys += WOLFSSL_TICKET_KEY_SZ;
+    ato32(keys, &ctx->ticketKeyCtx.expirary[0]);
+    keys += OPAQUE32_LEN;
+    ato32(keys, &ctx->ticketKeyCtx.expirary[1]);
+
+    return WOLFSSL_SUCCESS;
+}
+#endif
 
 #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
@@ -43374,5 +47770,46 @@
 }
 #endif /* OCSP */
-#endif /* OPENSSL_ALL / WOLFSSL_NGINX  / WOLFSSL_HAPROXY */
+#endif /* OPENSSL_ALL || WOLFSSL_NGINX  || WOLFSSL_HAPROXY */
+
+#if defined(HAVE_OCSP) && !defined(NO_ASN_TIME)
+int wolfSSL_get_ocsp_producedDate(
+    WOLFSSL *ssl,
+    byte *producedDate,
+    size_t producedDate_space,
+    int *producedDateFormat)
+{
+    if ((ssl->ocspProducedDateFormat != ASN_UTC_TIME) &&
+        (ssl->ocspProducedDateFormat != ASN_GENERALIZED_TIME))
+        return BAD_FUNC_ARG;
+
+    if ((producedDate == NULL) || (producedDateFormat == NULL))
+        return BAD_FUNC_ARG;
+
+    if (XSTRLEN((char *)ssl->ocspProducedDate) >= producedDate_space)
+        return BUFFER_E;
+
+    XSTRNCPY((char *)producedDate, (const char *)ssl->ocspProducedDate, producedDate_space);
+    *producedDateFormat = ssl->ocspProducedDateFormat;
+
+    return 0;
+}
+
+int wolfSSL_get_ocsp_producedDate_tm(WOLFSSL *ssl, struct tm *produced_tm) {
+    int idx = 0;
+
+    if ((ssl->ocspProducedDateFormat != ASN_UTC_TIME) &&
+        (ssl->ocspProducedDateFormat != ASN_GENERALIZED_TIME))
+        return BAD_FUNC_ARG;
+
+    if (produced_tm == NULL)
+        return BAD_FUNC_ARG;
+
+    if (ExtractDate(ssl->ocspProducedDate, ssl->ocspProducedDateFormat, produced_tm, &idx))
+        return 0;
+    else
+        return ASN_PARSE_E;
+}
+#endif
+
 
 #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \
@@ -43595,10 +48032,33 @@
 }
 
-WOLFSSL_X509* wolfSSL_X509_dup(WOLFSSL_X509 *x)
-{
-    return wolfSSL_X509_d2i(NULL, x->derCert->buffer, x->derCert->length);
-}
-
-char* wolfSSL_sk_WOLFSSL_STRING_value(WOLF_STACK_OF(WOLFSSL_STRING)* strings,
+WOLF_STACK_OF(WOLFSSL_STRING)* wolfSSL_sk_WOLFSSL_STRING_new(void)
+{
+    WOLF_STACK_OF(WOLFSSL_STRING)* ret = wolfSSL_sk_new_node(NULL);
+
+    if (ret) {
+        ret->type = STACK_TYPE_STRING;
+    }
+
+    return ret;
+}
+
+void wolfSSL_sk_WOLFSSL_STRING_free(WOLF_STACK_OF(WOLFSSL_STRING)* sk)
+{
+    WOLFSSL_STACK* tmp;
+    WOLFSSL_ENTER("wolfSSL_sk_WOLFSSL_STRING_free");
+
+    if (sk == NULL)
+        return;
+
+    /* parse through stack freeing each node */
+    while (sk) {
+        tmp = sk->next;
+        XFREE(sk->data.string, NULL, DYNAMIC_TYPE_OPENSSL);
+        XFREE(sk, NULL, DYNAMIC_TYPE_OPENSSL);
+        sk = tmp;
+    }
+}
+
+WOLFSSL_STRING wolfSSL_sk_WOLFSSL_STRING_value(WOLF_STACK_OF(WOLFSSL_STRING)* strings,
     int idx)
 {
@@ -43609,7 +48069,29 @@
     return strings->data.string;
 }
+
+int wolfSSL_sk_WOLFSSL_STRING_num(WOLF_STACK_OF(WOLFSSL_STRING)* strings)
+{
+    if (strings)
+        return (int)strings->num;
+    return 0;
+}
 #endif /* WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || OPENSSL_ALL */
 
-#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
+WOLFSSL_X509* wolfSSL_X509_dup(WOLFSSL_X509 *x)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_dup");
+
+    if (x == NULL) {
+        WOLFSSL_MSG("Error: NULL certificate passed in");
+        return NULL;
+    }
+
+    return wolfSSL_X509_d2i(NULL, x->derCert->buffer, x->derCert->length);
+}
+#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
+    defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY)
 #ifdef HAVE_ALPN
 void wolfSSL_get0_alpn_selected(const WOLFSSL *ssl, const unsigned char **data,
@@ -43822,5 +48304,5 @@
  * cb  callback to use
  *
- * return SSL_SUCCESS on success and SSL_FAILURE with error case
+ * return WOLFSSL_SUCCESS on success and SSL_FAILURE with error case
  */
 int wolfSSL_set_msg_callback(WOLFSSL *ssl, SSL_Msg_Cb cb)
@@ -43837,5 +48319,5 @@
 
     ssl->protoMsgCb = cb;
-    return SSL_SUCCESS;
+    return WOLFSSL_SUCCESS;
 }
 #ifndef NO_WOLFSSL_STUB
@@ -43873,4 +48355,10 @@
     }
     return XMEMCPY(ret, data, siz);
+}
+
+void wolfSSL_OPENSSL_cleanse(void *ptr, size_t len)
+{
+    if (ptr)
+        ForceZero(ptr, (word32)len);
 }
 
@@ -43890,9 +48378,10 @@
     ctx->alpn_cli_protos_len = p_len;
 
-    return SSL_SUCCESS;
+    return WOLFSSL_SUCCESS;
 }
 
 
 #ifdef HAVE_ALPN
+#ifndef NO_BIO
 /* Sets the ALPN extension protos
  *
@@ -43952,16 +48441,351 @@
     return WOLFSSL_SUCCESS;
 }
+#endif /* !NO_BIO */
 #endif /* HAVE_ALPN */
 #endif
 
-#endif /* WOLFCRYPT_ONLY */
-
 #if defined(OPENSSL_EXTRA)
 
+#ifndef NO_BIO
 #define WOLFSSL_BIO_INCLUDED
 #include "src/bio.c"
+#endif
+
+word32 nid2oid(int nid, int grp)
+{
+    /* get OID type */
+    switch (grp) {
+        /* oidHashType */
+        case oidHashType:
+            switch (nid) {
+            #ifdef WOLFSSL_MD2
+                case NID_md2:
+                    return MD2h;
+            #endif
+            #ifndef NO_MD5
+                case NID_md5:
+                    return MD5h;
+            #endif
+            #ifndef NO_SHA
+                case NID_sha1:
+                    return SHAh;
+            #endif
+                case NID_sha224:
+                    return SHA224h;
+            #ifndef NO_SHA256
+                case NID_sha256:
+                    return SHA256h;
+            #endif
+            #ifdef WOLFSSL_SHA384
+                case NID_sha384:
+                    return SHA384h;
+            #endif
+            #ifdef WOLFSSL_SHA512
+                case NID_sha512:
+                    return SHA512h;
+            #endif
+            }
+            break;
+
+        /*  oidSigType */
+        case oidSigType:
+            switch (nid) {
+            #ifndef NO_DSA
+                case CTC_SHAwDSA:
+                    return CTC_SHAwDSA;
+            #endif /* NO_DSA */
+            #ifndef NO_RSA
+                case CTC_MD2wRSA:
+                    return CTC_MD2wRSA;
+                case CTC_MD5wRSA:
+                    return CTC_MD5wRSA;
+                case CTC_SHAwRSA:
+                    return CTC_SHAwRSA;
+                case CTC_SHA224wRSA:
+                    return CTC_SHA224wRSA;
+                case CTC_SHA256wRSA:
+                    return CTC_SHA256wRSA;
+                case CTC_SHA384wRSA:
+                    return CTC_SHA384wRSA;
+                case CTC_SHA512wRSA:
+                    return CTC_SHA512wRSA;
+            #endif /* NO_RSA */
+            #ifdef HAVE_ECC
+                case CTC_SHAwECDSA:
+                    return CTC_SHAwECDSA;
+                case CTC_SHA224wECDSA:
+                    return CTC_SHA224wECDSA;
+                case CTC_SHA256wECDSA:
+                    return CTC_SHA256wECDSA;
+                case CTC_SHA384wECDSA:
+                    return CTC_SHA384wECDSA;
+                case CTC_SHA512wECDSA:
+                    return CTC_SHA512wECDSA;
+            #endif /* HAVE_ECC */
+            }
+            break;
+
+        /* oidKeyType */
+        case oidKeyType:
+            switch (nid) {
+            #ifndef NO_DSA
+                case DSAk:
+                    return DSAk;
+            #endif /* NO_DSA */
+            #ifndef NO_RSA
+                case RSAk:
+                    return RSAk;
+            #endif /* NO_RSA */
+            #ifdef HAVE_NTRU
+                case NTRUk:
+                    return NTRUk;
+            #endif /* HAVE_NTRU */
+            #ifdef HAVE_ECC
+                case ECDSAk:
+                    return ECDSAk;
+            #endif /* HAVE_ECC */
+            }
+            break;
+
+
+    #ifdef HAVE_ECC
+        case oidCurveType:
+            switch (nid) {
+            case NID_X9_62_prime192v1:
+                return ECC_SECP192R1_OID;
+            case NID_X9_62_prime192v2:
+                return ECC_PRIME192V2_OID;
+            case NID_X9_62_prime192v3:
+                return ECC_PRIME192V3_OID;
+            case NID_X9_62_prime239v1:
+                return ECC_PRIME239V1_OID;
+            case NID_X9_62_prime239v2:
+                return ECC_PRIME239V2_OID;
+            case NID_X9_62_prime239v3:
+                return ECC_PRIME239V3_OID;
+            case NID_X9_62_prime256v1:
+                return ECC_SECP256R1_OID;
+            case NID_secp112r1:
+                return ECC_SECP112R1_OID;
+            case NID_secp112r2:
+                return ECC_SECP112R2_OID;
+            case NID_secp128r1:
+                return ECC_SECP128R1_OID;
+            case NID_secp128r2:
+                return ECC_SECP128R2_OID;
+            case NID_secp160r1:
+                return ECC_SECP160R1_OID;
+            case NID_secp160r2:
+                return ECC_SECP160R2_OID;
+            case NID_secp224r1:
+                return ECC_SECP224R1_OID;
+            case NID_secp384r1:
+                return ECC_SECP384R1_OID;
+            case NID_secp521r1:
+                return ECC_SECP521R1_OID;
+            case NID_secp160k1:
+                return ECC_SECP160K1_OID;
+            case NID_secp192k1:
+                return ECC_SECP192K1_OID;
+            case NID_secp224k1:
+                return ECC_SECP224K1_OID;
+            case NID_secp256k1:
+                return ECC_SECP256K1_OID;
+            case NID_brainpoolP160r1:
+                return ECC_BRAINPOOLP160R1_OID;
+            case NID_brainpoolP192r1:
+                return ECC_BRAINPOOLP192R1_OID;
+            case NID_brainpoolP224r1:
+                return ECC_BRAINPOOLP224R1_OID;
+            case NID_brainpoolP256r1:
+                return ECC_BRAINPOOLP256R1_OID;
+            case NID_brainpoolP320r1:
+                return ECC_BRAINPOOLP320R1_OID;
+            case NID_brainpoolP384r1:
+                return ECC_BRAINPOOLP384R1_OID;
+            case NID_brainpoolP512r1:
+                return ECC_BRAINPOOLP512R1_OID;
+            }
+            break;
+    #endif /* HAVE_ECC */
+
+        /* oidBlkType */
+        case oidBlkType:
+            switch (nid) {
+            #ifdef WOLFSSL_AES_128
+                case AES128CBCb:
+                    return AES128CBCb;
+            #endif
+            #ifdef WOLFSSL_AES_192
+                case AES192CBCb:
+                    return AES192CBCb;
+            #endif
+            #ifdef WOLFSSL_AES_256
+                case AES256CBCb:
+                    return AES256CBCb;
+            #endif
+            #ifndef NO_DES3
+                case NID_des:
+                    return DESb;
+                case NID_des3:
+                    return DES3b;
+            #endif
+            }
+            break;
+
+    #ifdef HAVE_OCSP
+        case oidOcspType:
+            switch (nid) {
+                case NID_id_pkix_OCSP_basic:
+                    return OCSP_BASIC_OID;
+                case OCSP_NONCE_OID:
+                    return OCSP_NONCE_OID;
+            }
+            break;
+    #endif /* HAVE_OCSP */
+
+        /* oidCertExtType */
+        case oidCertExtType:
+            switch (nid) {
+                case BASIC_CA_OID:
+                    return BASIC_CA_OID;
+                case ALT_NAMES_OID:
+                    return ALT_NAMES_OID;
+                case CRL_DIST_OID:
+                    return CRL_DIST_OID;
+                case AUTH_INFO_OID:
+                    return AUTH_INFO_OID;
+                case AUTH_KEY_OID:
+                    return AUTH_KEY_OID;
+                case SUBJ_KEY_OID:
+                    return SUBJ_KEY_OID;
+                case INHIBIT_ANY_OID:
+                    return INHIBIT_ANY_OID;
+                case NID_key_usage:
+                    return KEY_USAGE_OID;
+                case NID_name_constraints:
+                    return NAME_CONS_OID;
+                case NID_certificate_policies:
+                    return CERT_POLICY_OID;
+            }
+            break;
+
+        /* oidCertAuthInfoType */
+        case oidCertAuthInfoType:
+            switch (nid) {
+                case AIA_OCSP_OID:
+                    return AIA_OCSP_OID;
+                case AIA_CA_ISSUER_OID:
+                    return AIA_CA_ISSUER_OID;
+            }
+            break;
+
+        /* oidCertPolicyType */
+        case oidCertPolicyType:
+            switch (nid) {
+                case NID_any_policy:
+                    return CP_ANY_OID;
+            }
+            break;
+
+        /* oidCertAltNameType */
+        case oidCertAltNameType:
+            switch (nid) {
+                case NID_hw_name_oid:
+                    return HW_NAME_OID;
+            }
+            break;
+
+        /* oidCertKeyUseType */
+        case oidCertKeyUseType:
+            switch (nid) {
+                case NID_anyExtendedKeyUsage:
+                    return EKU_ANY_OID;
+                case EKU_SERVER_AUTH_OID:
+                    return EKU_SERVER_AUTH_OID;
+                case EKU_CLIENT_AUTH_OID:
+                    return EKU_CLIENT_AUTH_OID;
+                case EKU_OCSP_SIGN_OID:
+                    return EKU_OCSP_SIGN_OID;
+            }
+            break;
+
+        /* oidKdfType */
+        case oidKdfType:
+            switch (nid) {
+                case PBKDF2_OID:
+                    return PBKDF2_OID;
+            }
+            break;
+
+        /* oidPBEType */
+        case oidPBEType:
+            switch (nid) {
+                case PBE_SHA1_RC4_128:
+                    return PBE_SHA1_RC4_128;
+                case PBE_SHA1_DES:
+                    return PBE_SHA1_DES;
+                case PBE_SHA1_DES3:
+                    return PBE_SHA1_DES3;
+            }
+            break;
+
+        /* oidKeyWrapType */
+        case oidKeyWrapType:
+            switch (nid) {
+            #ifdef WOLFSSL_AES_128
+                case AES128_WRAP:
+                    return AES128_WRAP;
+            #endif
+            #ifdef WOLFSSL_AES_192
+                case AES192_WRAP:
+                    return AES192_WRAP;
+            #endif
+            #ifdef WOLFSSL_AES_256
+                case AES256_WRAP:
+                    return AES256_WRAP;
+            #endif
+            }
+            break;
+
+        /* oidCmsKeyAgreeType */
+        case oidCmsKeyAgreeType:
+            switch (nid) {
+                #ifndef NO_SHA
+                case dhSinglePass_stdDH_sha1kdf_scheme:
+                    return dhSinglePass_stdDH_sha1kdf_scheme;
+                #endif
+                #ifdef WOLFSSL_SHA224
+                case dhSinglePass_stdDH_sha224kdf_scheme:
+                    return dhSinglePass_stdDH_sha224kdf_scheme;
+                #endif
+                #ifndef NO_SHA256
+                case dhSinglePass_stdDH_sha256kdf_scheme:
+                    return dhSinglePass_stdDH_sha256kdf_scheme;
+                #endif
+                #ifdef WOLFSSL_SHA384
+                case dhSinglePass_stdDH_sha384kdf_scheme:
+                    return dhSinglePass_stdDH_sha384kdf_scheme;
+                #endif
+                #ifdef WOLFSSL_SHA512
+                case dhSinglePass_stdDH_sha512kdf_scheme:
+                    return dhSinglePass_stdDH_sha512kdf_scheme;
+                #endif
+            }
+            break;
+
+        default:
+            WOLFSSL_MSG("NID not in table");
+            /* MSVC warns without the cast */
+            return (word32)-1;
+    }
+
+    /* MSVC warns without the cast */
+    return (word32)-1;
+}
 
 int oid2nid(word32 oid, int grp)
 {
+    size_t i;
     /* get OID type */
     switch (grp) {
@@ -44004,4 +48828,6 @@
                 case CTC_SHAwDSA:
                     return CTC_SHAwDSA;
+                case CTC_SHA256wDSA:
+                    return CTC_SHA256wDSA;
             #endif /* NO_DSA */
             #ifndef NO_RSA
@@ -44285,7 +49111,23 @@
             break;
 
+#ifdef WOLFSSL_CERT_REQ
+        case oidCsrAttrType:
+            switch (oid) {
+                case CHALLENGE_PASSWORD_OID:
+                    return NID_pkcs9_challengePassword;
+                case SERIAL_NUMBER_OID:
+                    return NID_serialNumber;
+            }
+            break;
+#endif
+
         default:
             WOLFSSL_MSG("NID not in table");
-            return -1;
+    }
+    /* If not found in above switch then try the table */
+    for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++) {
+        if (wolfssl_object_info[i].id == (int)oid) {
+            return wolfssl_object_info[i].nid;
+        }
     }
 
@@ -44307,5 +49149,5 @@
     }
 
-    if (mpi == NULL || (mp_init(mpi) != MP_OKAY)) {
+    if (mpi == NULL) {
         WOLFSSL_MSG("mpi NULL error");
         return WOLFSSL_FATAL_ERROR;
@@ -44338,5 +49180,8 @@
     if (ret != 0) {
     #ifdef WOLFSSL_QT
-        mp_init(&mpi); /* must init mpi */
+        ret = mp_init(&mpi); /* must init mpi */
+        if (ret != MP_OKAY) {
+            return NULL;
+        }
         /* Serial number in QT starts at index 0 of data */
         if (mp_read_unsigned_bin(&mpi, (byte*)ai->data, ai->length) != 0) {
@@ -44486,5 +49331,5 @@
 
 
-/* SSL_SUCCESS on ok */
+/* WOLFSSL_SUCCESS on ok */
 #ifndef NO_WOLFSSL_STUB
 int wolfSSL_RSA_blinding_on(WOLFSSL_RSA* rsa, WOLFSSL_BN_CTX* bn)
@@ -44550,5 +49395,5 @@
     if (rsa->inSet == 0)
     {
-        if (SetRsaInternal(rsa) != SSL_SUCCESS) {
+        if (SetRsaInternal(rsa) != WOLFSSL_SUCCESS) {
             WOLFSSL_MSG("SetRsaInternal failed");
             return 0;
@@ -44642,5 +49487,5 @@
     if (rsa->inSet == 0)
     {
-        if (SetRsaInternal(rsa) != SSL_SUCCESS) {
+        if (SetRsaInternal(rsa) != WOLFSSL_SUCCESS) {
             WOLFSSL_MSG("SetRsaInternal failed");
             return 0;
@@ -44676,5 +49521,6 @@
 }
 
-#if !defined(_WIN32) && !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \
+    (defined(HAVE_FIPS_VERSION) && HAVE_FIPS_VERSION > 2))
 int wolfSSL_RSA_public_decrypt(int flen, const unsigned char* from,
                           unsigned char* to, WOLFSSL_RSA* rsa, int padding)
@@ -44728,5 +49574,5 @@
     return tlen;
 }
-#endif /* !defined(_WIN32) && !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) */
+#endif /* !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) */
 
 /* RSA private encrypt calls wc_RsaSSL_Sign. Similar function set up as RSA
@@ -44765,5 +49611,5 @@
         WOLFSSL_MSG("Setting internal RSA structure");
 
-        if (SetRsaInternal(rsa) != SSL_SUCCESS) {
+        if (SetRsaInternal(rsa) != WOLFSSL_SUCCESS) {
             WOLFSSL_MSG("SetRsaInternal failed");
             return 0;
@@ -44921,5 +49767,5 @@
     if ((ret = mp_mulmod((mp_int*)a->internal,(mp_int*)p->internal,
                (mp_int*)m->internal, (mp_int*)r->internal)) == MP_OKAY) {
-        return SSL_SUCCESS;
+        return WOLFSSL_SUCCESS;
     }
 
@@ -44930,5 +49776,4 @@
 }
 
-#ifdef OPENSSL_EXTRA
 const WOLFSSL_BIGNUM* wolfSSL_BN_value_one(void)
 {
@@ -44948,5 +49793,4 @@
     return bn_one;
 }
-#endif
 
 /* return compliant with OpenSSL
@@ -45031,5 +49875,5 @@
 int wolfSSL_BN_is_word(const WOLFSSL_BIGNUM* bn, WOLFSSL_BN_ULONG w)
 {
-    WOLFSSL_ENTER("wolfSSL_BN_is_word");
+    WOLFSSL_MSG("wolfSSL_BN_is_word");
 
     if (bn == NULL || bn->internal == NULL) {
@@ -45038,6 +49882,19 @@
     }
 
-    if (mp_isword((mp_int*)bn->internal, w) == MP_YES) {
-         return WOLFSSL_SUCCESS;
+    if (w <= MP_MASK) {
+        if (mp_isword((mp_int*)bn->internal, (mp_digit)w) == MP_YES) {
+            return WOLFSSL_SUCCESS;
+        }
+    } else {
+        int ret;
+        mp_int w_mp;
+        if (mp_init(&w_mp) != MP_OKAY)
+            return WOLFSSL_FAILURE;
+        if (mp_set_int(&w_mp, w) != MP_OKAY)
+            return WOLFSSL_FAILURE;
+        ret = mp_cmp((mp_int *)bn->internal, &w_mp);
+        mp_free(&w_mp);
+        if (ret == MP_EQ)
+            return WOLFSSL_SUCCESS;
     }
 
@@ -45473,5 +50330,5 @@
  *   1 if success, 0 else
  */
-int wolfSSL_BN_set_word(WOLFSSL_BIGNUM* bn, WOLFSSL_BN_ULONG w)
+int wolfSSL_BN_set_word(WOLFSSL_BIGNUM* bn, unsigned long w)
 {
     WOLFSSL_MSG("wolfSSL_BN_set_word");
@@ -45490,4 +50347,19 @@
 }
 
+static WOLFSSL_BN_ULONG wolfSSL_BN_get_word_1(mp_int *mp) {
+#if DIGIT_BIT == (SIZEOF_LONG * 8)
+    return (WOLFSSL_BN_ULONG)mp->dp[0];
+#else
+    WOLFSSL_BN_ULONG ret = 0UL;
+    int digit_i;
+
+    for (digit_i = 0; digit_i < mp->used; ++digit_i) {
+        ret <<= (WOLFSSL_BN_ULONG)DIGIT_BIT;
+        ret |= (WOLFSSL_BN_ULONG)mp->dp[digit_i];
+    }
+
+    return ret;
+#endif
+}
 
 /* Returns the big number as an unsigned long if possible.
@@ -45497,8 +50369,6 @@
  * Returns value or 0xFFFFFFFFL if bigger than unsigned long.
  */
-unsigned long wolfSSL_BN_get_word(const WOLFSSL_BIGNUM* bn)
-{
-    mp_int* mp;
-
+WOLFSSL_BN_ULONG wolfSSL_BN_get_word(const WOLFSSL_BIGNUM* bn)
+{
     WOLFSSL_MSG("wolfSSL_BN_get_word");
 
@@ -45512,7 +50382,6 @@
         return 0xFFFFFFFFL;
     }
-    mp = (mp_int*)bn->internal;
-
-    return (unsigned long)(mp->dp[0]);
+
+    return wolfSSL_BN_get_word_1((mp_int*)bn->internal);
 }
 
@@ -45627,7 +50496,22 @@
     }
 
-    if (mp_add_d((mp_int*)bn->internal, w, (mp_int*)bn->internal) != MP_OKAY) {
-        WOLFSSL_MSG("mp_add_d error");
-        return WOLFSSL_FAILURE;
+    if (w <= MP_MASK) {
+        if (mp_add_d((mp_int*)bn->internal, (mp_digit)w, (mp_int*)bn->internal) != MP_OKAY) {
+            WOLFSSL_MSG("mp_add_d error");
+            return WOLFSSL_FAILURE;
+        }
+    } else {
+        int ret;
+        mp_int w_mp;
+        if (mp_init(&w_mp) != MP_OKAY)
+            return WOLFSSL_FAILURE;
+        if (mp_set_int(&w_mp, w) != MP_OKAY)
+            return WOLFSSL_FAILURE;
+        ret = mp_add((mp_int *)bn->internal, &w_mp, (mp_int *)bn->internal);
+        mp_free(&w_mp);
+        if (ret != MP_OKAY) {
+            WOLFSSL_MSG("mp_add error");
+            return WOLFSSL_FAILURE;
+        }
     }
 
@@ -45764,7 +50648,28 @@
     }
 
-    if (mp_mod_d((mp_int*)bn->internal, w, &ret) != MP_OKAY) {
-        WOLFSSL_MSG("mp_add_d error");
-        return (WOLFSSL_BN_ULONG)WOLFSSL_FATAL_ERROR;
+    if (w <= MP_MASK) {
+        mp_digit bn_ret;
+        if (mp_mod_d((mp_int*)bn->internal, (WOLFSSL_BN_ULONG)w, &bn_ret) != MP_OKAY) {
+            WOLFSSL_MSG("mp_add_d error");
+            return (WOLFSSL_BN_ULONG)WOLFSSL_FATAL_ERROR;
+        }
+        ret = (WOLFSSL_BN_ULONG)bn_ret;
+    } else {
+        int mp_ret;
+        mp_int w_mp, r_mp;
+        if (mp_init(&w_mp) != MP_OKAY)
+            return (unsigned long)WOLFSSL_FAILURE;
+        if (mp_init(&r_mp) != MP_OKAY)
+            return (unsigned long)WOLFSSL_FAILURE;
+        if (mp_set_int(&w_mp, w) != MP_OKAY)
+            return (unsigned long)WOLFSSL_FAILURE;
+        mp_ret = mp_mod((mp_int *)bn->internal, &w_mp, &r_mp);
+        ret = wolfSSL_BN_get_word_1(&r_mp);
+        mp_free(&r_mp);
+        mp_free(&w_mp);
+        if (mp_ret != MP_OKAY) {
+            WOLFSSL_MSG("mp_mod error");
+            return (WOLFSSL_BN_ULONG)WOLFSSL_FAILURE;
+        }
     }
 
@@ -45789,5 +50694,4 @@
         return NULL;
     }
-    len += 1; /* add one for null terminator */
 
     buf = (char*)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL);
@@ -45826,5 +50730,5 @@
     }
 
-    fprintf(fp, "%s", buf);
+    XFPRINTF(fp, "%s", buf);
     XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL);
 
@@ -45908,4 +50812,5 @@
 #endif  /* OPENSSL_EXTRA */
 #if (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) && !defined(NO_ASN)
+#ifndef NO_BIO
 static int unprintable_char(char c)
 {
@@ -45940,4 +50845,5 @@
     return str->length;
 }
+#endif /* !NO_BIO */
 #endif /* (WOLFSSL_QT || OPENSSL_ALL) && !NO_ASN */
 
@@ -45977,4 +50883,5 @@
 }
 
+#ifndef NO_BIO
 static int check_esc_char(char c, char *esc)
 {
@@ -46107,22 +51014,8 @@
     return WOLFSSL_FAILURE;
 }
+#endif /* !NO_BIO */
 
 #if !defined(NO_ASN_TIME) && !defined(USER_TIME) && !defined(TIME_OVERRIDES)
-WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_new(void)
-{
-    WOLFSSL_ASN1_TIME* ret = (WOLFSSL_ASN1_TIME*)
-            XMALLOC(sizeof(WOLFSSL_ASN1_TIME), NULL, DYNAMIC_TYPE_OPENSSL);
-    if (!ret)
-        return NULL;
-    XMEMSET(ret, 0, sizeof(WOLFSSL_ASN1_TIME));
-    return ret;
-}
-
-void wolfSSL_ASN1_TIME_free(WOLFSSL_ASN1_TIME* t)
-{
-    if (t) {
-        XFREE(t, NULL, DYNAMIC_TYPE_OPENSSL);
-    }
-}
+
 
 WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_adj(WOLFSSL_ASN1_TIME *s, time_t t,
@@ -46210,4 +51103,21 @@
 
 #ifndef NO_ASN_TIME
+
+WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_new(void)
+{
+    WOLFSSL_ASN1_TIME* ret = (WOLFSSL_ASN1_TIME*)
+            XMALLOC(sizeof(WOLFSSL_ASN1_TIME), NULL, DYNAMIC_TYPE_OPENSSL);
+    if (!ret)
+        return NULL;
+    XMEMSET(ret, 0, sizeof(WOLFSSL_ASN1_TIME));
+    return ret;
+}
+
+void wolfSSL_ASN1_TIME_free(WOLFSSL_ASN1_TIME* t)
+{
+    if (t) {
+        XFREE(t, NULL, DYNAMIC_TYPE_OPENSSL);
+    }
+}
 /* not a compatibility function - length getter for opaque type */
 int wolfSSL_ASN1_TIME_get_length(WOLFSSL_ASN1_TIME *t)
@@ -46388,5 +51298,7 @@
 }
 #endif /* !NO_CERTS */
-
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
 long wolfSSL_X509_get_version(const WOLFSSL_X509 *x509)
 {
@@ -46405,6 +51317,7 @@
     return 0L;
 }
-
-
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
+
+#if defined(OPENSSL_EXTRA)
 int wolfSSL_X509_get_signature_nid(const WOLFSSL_X509 *x)
 {
@@ -46428,5 +51341,5 @@
     if (rsa->inSet == 0)
     {
-        if (SetRsaInternal((WOLFSSL_RSA*)rsa) != SSL_SUCCESS) {
+        if (SetRsaInternal((WOLFSSL_RSA*)rsa) != WOLFSSL_SUCCESS) {
             WOLFSSL_MSG("SetRsaInternal failed");
             return 0;
@@ -46802,6 +51715,8 @@
     }
 
-    if (ret != 0 && pkcs7 != NULL)
+    if (ret != 0 && pkcs7 != NULL) {
         XFREE(pkcs7, NULL, DYNAMIC_TYPE_PKCS7);
+        pkcs7 = NULL;
+    }
 
     return (PKCS7*)pkcs7;
@@ -46838,7 +51753,10 @@
             XFREE(p7->data, NULL, DYNAMIC_TYPE_PKCS7);
         wc_PKCS7_Free(&p7->pkcs7);
+        if (p7->certs)
+            wolfSSL_sk_free(p7->certs);
         XFREE(p7, NULL, DYNAMIC_TYPE_PKCS7);
     }
 }
+
 void wolfSSL_PKCS7_SIGNED_free(PKCS7_SIGNED* p7)
 {
@@ -46846,10 +51764,30 @@
     return;
 }
+
 PKCS7* wolfSSL_d2i_PKCS7(PKCS7** p7, const unsigned char** in, int len)
+{
+    return wolfSSL_d2i_PKCS7_ex(p7, in, len, NULL, 0);
+}
+
+/*****************************************************************************
+* wolfSSL_d2i_PKCS7_ex - Converts the given unsigned char buffer of size len
+* into a PKCS7 object.  Optionally, accepts a byte buffer of content which
+* is stored as the PKCS7 object's content, to support detached signatures.
+* @param content The content which is signed, in case the signature is
+*                detached.  Ignored if NULL.
+* @param contentSz The size of the passed in content.
+*
+* RETURNS:
+* returns pointer to a PKCS7 structure on success, otherwise returns NULL
+*/
+PKCS7* wolfSSL_d2i_PKCS7_ex(PKCS7** p7, const unsigned char** in, int len,
+                            byte* content, word32 contentSz)
 {
     WOLFSSL_PKCS7* pkcs7 = NULL;
     word32 idx = 0;
 
-    if (in == NULL)
+    WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_ex");
+
+    if (in == NULL || *in == NULL)
         return NULL;
 
@@ -46869,14 +51807,28 @@
     }
     XMEMCPY(pkcs7->data, *in, pkcs7->len);
-    *in += pkcs7->len;
+
+    if (content != NULL) {
+        pkcs7->pkcs7.content = content;
+        pkcs7->pkcs7.contentSz = contentSz;
+    }
+    if (wc_PKCS7_VerifySignedData(&pkcs7->pkcs7, pkcs7->data, pkcs7->len) != 0) {
+        wolfSSL_PKCS7_free((PKCS7*)pkcs7);
+        return NULL;
+    }
 
     if (p7 != NULL)
         *p7 = (PKCS7*)pkcs7;
+    *in += pkcs7->len;
     return (PKCS7*)pkcs7;
 }
 
+#ifndef NO_BIO
+
 PKCS7* wolfSSL_d2i_PKCS7_bio(WOLFSSL_BIO* bio, PKCS7** p7)
 {
     WOLFSSL_PKCS7* pkcs7;
+    int ret;
+
+    WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_bio");
 
     if (bio == NULL)
@@ -46886,5 +51838,5 @@
         return NULL;
 
-    pkcs7->len = wolfSSL_BIO_pending(bio);
+    pkcs7->len = wolfSSL_BIO_get_len(bio);
     pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7);
     if (pkcs7->data == NULL) {
@@ -46893,6 +51845,12 @@
     }
 
-    if (wolfSSL_BIO_read(bio, pkcs7->data, pkcs7->len) != pkcs7->len) {
+    if ((ret = wolfSSL_BIO_read(bio, pkcs7->data, pkcs7->len)) <= 0) {
         wolfSSL_PKCS7_free((PKCS7*)pkcs7);
+        return NULL;
+    }
+    /* pkcs7->len may change if using b64 for example */
+    pkcs7->len = ret;
+
+    if (wc_PKCS7_VerifySignedData(&pkcs7->pkcs7, pkcs7->data, pkcs7->len) != 0) {
         return NULL;
     }
@@ -46901,4 +51859,58 @@
         *p7 = (PKCS7*)pkcs7;
     return (PKCS7*)pkcs7;
+}
+
+int wolfSSL_i2d_PKCS7_bio(WOLFSSL_BIO *bio, PKCS7 *p7)
+{
+    byte* output = NULL;
+    int len;
+    WC_RNG rng;
+    int ret = WOLFSSL_FAILURE;
+    WOLFSSL_ENTER("wolfSSL_i2d_PKCS7_bio");
+
+    if (!bio || !p7) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (!p7->rng) {
+        if (wc_InitRng(&rng) != 0) {
+            WOLFSSL_MSG("wc_InitRng error");
+            return WOLFSSL_FAILURE;
+        }
+        p7->rng = &rng;
+    }
+
+    if ((len = wc_PKCS7_EncodeSignedData(p7, NULL, 0)) < 0) {
+        WOLFSSL_MSG("wc_PKCS7_EncodeSignedData error");
+        goto cleanup;
+    }
+
+    output = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (!output) {
+        WOLFSSL_MSG("malloc error");
+        goto cleanup;
+    }
+
+    if ((len = wc_PKCS7_EncodeSignedData(p7, output, len)) < 0) {
+        WOLFSSL_MSG("wc_PKCS7_EncodeSignedData error");
+        goto cleanup;
+    }
+
+    if (wolfSSL_BIO_write(bio, output, len) <= 0) {
+        WOLFSSL_MSG("wolfSSL_BIO_write error");
+        goto cleanup;
+    }
+
+    ret = WOLFSSL_SUCCESS;
+cleanup:
+    if (p7->rng == &rng) {
+        wc_FreeRng(&rng);
+        p7->rng = NULL;
+    }
+    if (output) {
+        XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+    return ret;
 }
 
@@ -46911,4 +51923,6 @@
     int memSz = 0;
     WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7;
+
+    WOLFSSL_ENTER("wolfSSL_PKCS7_verify");
 
     if (pkcs7 == NULL)
@@ -46930,6 +51944,5 @@
     (void)store;
 
-    ret = wc_PKCS7_VerifySignedData_ex(&p7->pkcs7, NULL, 0, p7->data, p7->len,
-                                                                       NULL, 0);
+    ret = wc_PKCS7_VerifySignedData(&p7->pkcs7, p7->data, p7->len);
     if (ret != 0)
         return WOLFSSL_FAILURE;
@@ -46944,4 +51957,134 @@
 
     return WOLFSSL_SUCCESS;
+}
+
+/**
+ * This API was added as a helper function for libest. It
+ * encodes a stack of certificates to pkcs7 format.
+ * @param pkcs7 PKCS7 parameter object
+ * @param certs WOLFSSL_STACK_OF(WOLFSSL_X509)*
+ * @param out   Output bio
+ * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure
+ */
+int wolfSSL_PKCS7_encode_certs(PKCS7* pkcs7, WOLFSSL_STACK* certs,
+                               WOLFSSL_BIO* out)
+{
+    int ret;
+    WOLFSSL_PKCS7* p7;
+    WOLFSSL_ENTER("wolfSSL_PKCS7_encode_certs");
+
+    if (!pkcs7 || !certs || !out) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    p7 = (WOLFSSL_PKCS7*)pkcs7;
+
+    /* take ownership of certs */
+    p7->certs = certs;
+
+    if (pkcs7->certList) {
+        WOLFSSL_MSG("wolfSSL_PKCS7_encode_certs called multiple times on same "
+                    "struct");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (certs) {
+        /* Save some of the values */
+        int hashOID = pkcs7->hashOID;
+        byte version = pkcs7->version;
+
+        if (!certs->data.x509 || !certs->data.x509->derCert) {
+            WOLFSSL_MSG("Missing cert");
+            return WOLFSSL_FAILURE;
+        }
+
+        if (wc_PKCS7_InitWithCert(pkcs7, certs->data.x509->derCert->buffer,
+                certs->data.x509->derCert->length) != 0) {
+            WOLFSSL_MSG("wc_PKCS7_InitWithCert error");
+            return WOLFSSL_FAILURE;
+        }
+        certs = certs->next;
+
+        pkcs7->hashOID = hashOID;
+        pkcs7->version = version;
+    }
+
+    /* Add the certs to the PKCS7 struct */
+    while (certs) {
+        if (!certs->data.x509 || !certs->data.x509->derCert) {
+            WOLFSSL_MSG("Missing cert");
+            return WOLFSSL_FAILURE;
+        }
+        if (wc_PKCS7_AddCertificate(pkcs7, certs->data.x509->derCert->buffer,
+                certs->data.x509->derCert->length) != 0) {
+            WOLFSSL_MSG("wc_PKCS7_AddCertificate error");
+            return WOLFSSL_FAILURE;
+        }
+        certs = certs->next;
+    }
+
+    if (wc_PKCS7_SetSignerIdentifierType(pkcs7, DEGENERATE_SID) != 0) {
+        WOLFSSL_MSG("wc_PKCS7_SetSignerIdentifierType error");
+        return WOLFSSL_FAILURE;
+    }
+
+    ret = wolfSSL_i2d_PKCS7_bio(out, pkcs7);
+
+    return ret;
+}
+#endif /* !NO_BIO */
+
+/**
+ * This API was added as a helper function for libest. It
+ * extracts a stack of certificates from the pkcs7 object.
+ * @param pkcs7 PKCS7 parameter object
+ * @return WOLFSSL_STACK_OF(WOLFSSL_X509)*
+ */
+WOLFSSL_STACK* wolfSSL_PKCS7_to_stack(PKCS7* pkcs7)
+{
+    int i;
+    WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7;
+    WOLF_STACK_OF(WOLFSSL_X509)* ret = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_PKCS7_to_stack");
+
+    if (!p7) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    if (p7->certs)
+        return p7->certs;
+
+    for (i = 0; i < MAX_PKCS7_CERTS && p7->pkcs7.cert[i]; i++) {
+        WOLFSSL_X509* x509 = wolfSSL_X509_d2i(NULL, p7->pkcs7.cert[i],
+                                              p7->pkcs7.certSz[i]);
+        if (!ret)
+            ret = wolfSSL_sk_X509_new();
+        if (x509) {
+            if (wolfSSL_sk_X509_push(ret, x509) != WOLFSSL_SUCCESS) {
+                wolfSSL_X509_free(x509);
+                WOLFSSL_MSG("wolfSSL_sk_X509_push error");
+                goto error;
+            }
+        }
+        else {
+            WOLFSSL_MSG("wolfSSL_X509_d2i error");
+            goto error;
+        }
+    }
+
+    /* Save stack to free later */
+    if (p7->certs)
+        wolfSSL_sk_free(p7->certs);
+    p7->certs = ret;
+
+    return ret;
+error:
+    if (ret) {
+        wolfSSL_sk_free(ret);
+    }
+    return NULL;
 }
 
@@ -46985,4 +52128,5 @@
 }
 
+#ifndef NO_BIO
 /******************************************************************************
 * wolfSSL_PEM_write_bio_PKCS7 - writes the PKCS7 data to BIO
@@ -47107,4 +52251,295 @@
     return WOLFSSL_FAILURE;
 }
+
+#ifdef HAVE_SMIME
+/*****************************************************************************
+* wolfSSL_SMIME_read_PKCS7 - Reads the given S/MIME message and parses it into
+* a PKCS7 object. In case of a multipart message, stores the signed data in
+* bcont.
+*
+* RETURNS:
+* returns pointer to a PKCS7 structure on success, otherwise returns NULL
+*/
+WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in,
+                                            WOLFSSL_BIO** bcont)
+{
+    MimeHdr* allHdrs = NULL;
+    MimeHdr* curHdr = NULL;
+    MimeParam* curParam = NULL;
+    int inLen = 0;
+    byte* bcontMem = NULL;
+    int bcontMemSz = 0;
+    int sectionLen = 0;
+    int ret = -1;
+    char* section = NULL;
+    PKCS7* pkcs7 = NULL;
+    word32 outLen = 0;
+    byte* out = NULL;
+    byte* outHead = NULL;
+
+    int lineLen = 0;
+    int remainLen = 0;
+    byte isEnd = 0;
+    size_t boundLen = 0;
+    char* boundary = NULL;
+
+    static const char* kContType = "Content-Type";
+    static const char* kCTE = "Content-Transfer-Encoding";
+    static const char* kMultSigned = "multipart/signed";
+    static const char* kAppPkcsSign = "application/pkcs7-signature";
+    static const char* kAppXPkcsSign = "application/x-pkcs7-signature";
+    static const char* kAppPkcs7Mime = "application/pkcs7-mime";
+    static const char* kAppXPkcs7Mime = "application/x-pkcs7-mime";
+
+
+    if (in == NULL || bcont == NULL) {
+        goto error;
+    }
+    inLen = wolfSSL_BIO_get_len(in);
+    if (inLen <= 0) {
+        goto error;
+    }
+    remainLen = wolfSSL_BIO_get_len(in);
+    if (remainLen <= 0) {
+        goto error;
+    }
+
+    section = (char*)XMALLOC((remainLen+1)*sizeof(char), NULL,
+                             DYNAMIC_TYPE_PKCS7);
+    if (section == NULL) {
+        goto error;
+    }
+    lineLen = wolfSSL_BIO_gets(in, section, remainLen);
+    if (lineLen <= 0) {
+        goto error;
+    }
+    while(isEnd == 0 && remainLen > 0) {
+        sectionLen += lineLen;
+        remainLen -= lineLen;
+        lineLen = wolfSSL_BIO_gets(in, &section[sectionLen], remainLen);
+        if (lineLen <= 0) {
+            goto error;
+        }
+        /* Line with just newline signals end of headers. */
+        if ((lineLen==2 && !XSTRNCMP(&section[sectionLen],
+                                     "\r\n", 2)) ||
+            (lineLen==1 && (section[sectionLen] == '\r' ||
+                            section[sectionLen] == '\n'))) {
+            isEnd = 1;
+        }
+    }
+    section[sectionLen] = '\0';
+    ret = wc_MIME_parse_headers(section, sectionLen, &allHdrs);
+    if (ret < 0) {
+        WOLFSSL_MSG("Parsing MIME headers failed.\n");
+        goto error;
+    }
+    isEnd = 0;
+    section[0] = '\0';
+    sectionLen = 0;
+
+    curHdr = wc_MIME_find_header_name(kContType, allHdrs);
+    if (curHdr && !XSTRNCMP(curHdr->body, kMultSigned,
+                            XSTR_SIZEOF(kMultSigned))) {
+        curParam = wc_MIME_find_param_attr("protocol", curHdr->params);
+        if (curParam && (!XSTRNCMP(curParam->value, kAppPkcsSign,
+                                   XSTR_SIZEOF(kAppPkcsSign)) ||
+                         !XSTRNCMP(curParam->value, kAppXPkcsSign,
+                                   XSTR_SIZEOF(kAppXPkcsSign)))) {
+            curParam = wc_MIME_find_param_attr("boundary", curHdr->params);
+            if (curParam == NULL) {
+                goto error;
+            }
+
+            boundLen = XSTRLEN(curParam->value) + 2;
+            boundary = (char*)XMALLOC((boundLen+1)*sizeof(char), NULL,
+                                      DYNAMIC_TYPE_PKCS7);
+            if (boundary == NULL) {
+                goto error;
+            }
+            XMEMSET(boundary, 0, (word32)((boundLen+1)*sizeof(char)));
+            boundary[0] = boundary[1] = '-';
+            XSTRNCPY(&boundary[2], curParam->value, boundLen-2);
+
+            /* Parse up to first boundary, ignore everything here. */
+            lineLen = wolfSSL_BIO_gets(in, section, remainLen);
+            if (lineLen <= 0) {
+                goto error;
+            }
+            while(XSTRNCMP(&section[sectionLen], boundary, boundLen) &&
+                  remainLen > 0) {
+                sectionLen += lineLen;
+                remainLen -= lineLen;
+                lineLen = wolfSSL_BIO_gets(in, &section[sectionLen],
+                                           remainLen);
+                if (lineLen <= 0) {
+                    goto error;
+                }
+            }
+
+            section[0] = '\0';
+            sectionLen = 0;
+            lineLen = wolfSSL_BIO_gets(in, section, remainLen);
+            while(XSTRNCMP(&section[sectionLen], boundary, boundLen) &&
+                           remainLen > 0) {
+                sectionLen += lineLen;
+                remainLen -= lineLen;
+                lineLen = wolfSSL_BIO_gets(in, &section[sectionLen],
+                                           remainLen);
+                if (lineLen <= 0) {
+                    goto error;
+                }
+            }
+            sectionLen--;
+            /* Strip the final trailing newline.  Support \r, \n or \r\n. */
+            if (section[sectionLen] == '\n') {
+                sectionLen--;
+                if (section[sectionLen] == '\r') {
+                    sectionLen--;
+                }
+            }
+            else if (section[sectionLen] == '\r') {
+                sectionLen--;
+            }
+            section[sectionLen+1] = '\0';
+
+            *bcont = wolfSSL_BIO_new(wolfSSL_BIO_s_mem());
+            ret = wolfSSL_BIO_write(*bcont, section, (int)XSTRLEN(section));
+            if (ret != (int)XSTRLEN(section)) {
+                goto error;
+            }
+            if ((bcontMemSz = wolfSSL_BIO_get_mem_data(*bcont, &bcontMem)) < 0) {
+                goto error;
+            }
+
+
+            wc_MIME_free_hdrs(allHdrs);
+            section[0] = '\0';
+            sectionLen = 0;
+            lineLen = wolfSSL_BIO_gets(in, section, remainLen);
+            if (lineLen <= 0) {
+                goto error;
+            }
+            while(isEnd == 0 && remainLen > 0) {
+                sectionLen += lineLen;
+                remainLen -= lineLen;
+                lineLen = wolfSSL_BIO_gets(in, &section[sectionLen],
+                                           remainLen);
+                if (lineLen <= 0) {
+                    goto error;
+                }
+                /* Line with just newline signals end of headers. */
+                if ((lineLen==2 && !XSTRNCMP(&section[sectionLen],
+                                             "\r\n", 2)) ||
+                    (lineLen==1 && (section[sectionLen] == '\r' ||
+                                    section[sectionLen] == '\n'))) {
+                    isEnd = 1;
+                }
+            }
+            section[sectionLen] = '\0';
+            ret = wc_MIME_parse_headers(section, sectionLen, &allHdrs);
+            if (ret < 0) {
+                WOLFSSL_MSG("Parsing MIME headers failed.\n");
+                goto error;
+            }
+            curHdr = wc_MIME_find_header_name(kContType, allHdrs);
+            if (curHdr == NULL || (XSTRNCMP(curHdr->body, kAppPkcsSign,
+                                   XSTR_SIZEOF(kAppPkcsSign)) &&
+                                   XSTRNCMP(curHdr->body, kAppXPkcsSign,
+                                   XSTR_SIZEOF(kAppXPkcsSign)))) {
+                WOLFSSL_MSG("S/MIME headers not found inside "
+                            "multipart message.\n");
+                goto error;
+            }
+
+            section[0] = '\0';
+            sectionLen = 0;
+            lineLen = wolfSSL_BIO_gets(in, section, remainLen);
+            while(XSTRNCMP(&section[sectionLen], boundary, boundLen) &&
+                  remainLen > 0) {
+                sectionLen += lineLen;
+                remainLen -= lineLen;
+                lineLen = wolfSSL_BIO_gets(in, &section[sectionLen],
+                                           remainLen);
+                if (lineLen <= 0) {
+                    goto error;
+                }
+            }
+
+            XFREE(boundary, NULL, DYNAMIC_TYPE_PKCS7);
+        }
+    }
+    else if (curHdr && (!XSTRNCMP(curHdr->body, kAppPkcs7Mime,
+                                  XSTR_SIZEOF(kAppPkcs7Mime)) ||
+                        !XSTRNCMP(curHdr->body, kAppXPkcs7Mime,
+                                  XSTR_SIZEOF(kAppXPkcs7Mime)))) {
+        sectionLen = wolfSSL_BIO_get_len(in);
+        if (sectionLen <= 0) {
+            goto error;
+        }
+        ret = wolfSSL_BIO_read(in, section, sectionLen);
+        if (ret < 0 || ret != sectionLen) {
+            WOLFSSL_MSG("Error reading input BIO.\n");
+            goto error;
+        }
+    }
+    else {
+        WOLFSSL_MSG("S/MIME headers not found.\n");
+        goto error;
+    }
+
+    curHdr = wc_MIME_find_header_name(kCTE, allHdrs);
+    if (curHdr == NULL) {
+        WOLFSSL_MSG("Content-Transfer-Encoding header not found, "
+                    "assuming base64 encoding.");
+    }
+    else if (XSTRNCMP(curHdr->body, "base64", XSTRLEN("base64"))) {
+        WOLFSSL_MSG("S/MIME encodings other than base64 are not "
+                    "currently supported.\n");
+        goto error;
+    }
+
+    if (section == NULL || sectionLen <= 0) {
+        goto error;
+    }
+    outLen = ((sectionLen*3+3)/4)+1;
+    out = (byte*)XMALLOC(outLen*sizeof(byte), NULL, DYNAMIC_TYPE_PKCS7);
+    outHead = out;
+    if (outHead == NULL) {
+        goto error;
+    }
+    /* Strip trailing newlines. */
+    while ((section[sectionLen-1] == '\r' || section[sectionLen-1] == '\n') &&
+           sectionLen > 0) {
+        sectionLen--;
+    }
+    section[sectionLen] = '\0';
+    ret = Base64_Decode((const byte*)section, sectionLen, out, &outLen);
+    if (ret < 0) {
+        WOLFSSL_MSG("Error base64 decoding S/MIME message.\n");
+        goto error;
+    }
+    pkcs7 = wolfSSL_d2i_PKCS7_ex(NULL, (const unsigned char**)&out, outLen,
+                                 bcontMem, bcontMemSz);
+
+
+    wc_MIME_free_hdrs(allHdrs);
+    XFREE(outHead, NULL, DYNAMIC_TYPE_PKCS7);
+    XFREE(section, NULL, DYNAMIC_TYPE_PKCS7);
+
+
+    return pkcs7;
+
+error:
+    wc_MIME_free_hdrs(allHdrs);
+    XFREE(boundary, NULL, DYNAMIC_TYPE_PKCS7);
+    XFREE(outHead, NULL, DYNAMIC_TYPE_PKCS7);
+    XFREE(section, NULL, DYNAMIC_TYPE_PKCS7);
+    wolfSSL_BIO_free(*bcont);
+
+    return NULL;
+}
+#endif /* HAVE_SMIME */
+#endif /* !NO_BIO */
 #endif /* OPENSSL_ALL && HAVE_PKCS7 */
 
@@ -47124,4 +52559,5 @@
 
 #ifdef OPENSSL_ALL
+#ifndef NO_BIO
 int wolfSSL_PEM_write_bio_PKCS8PrivateKey(WOLFSSL_BIO* bio,
                                           WOLFSSL_EVP_PKEY* pkey,
@@ -47192,4 +52628,5 @@
     if (ret == 0 && enc == NULL) {
         type = PKCS8_PRIVATEKEY_TYPE;
+    #ifdef HAVE_ECC
         if (pkey->type == EVP_PKEY_EC) {
             algId = ECDSAk;
@@ -47197,5 +52634,7 @@
                                                                         &oidSz);
         }
-        else {
+        else
+    #endif
+        {
             algId = RSAk;
             curveOid = NULL;
@@ -47377,4 +52816,6 @@
     return key;
 }
+
+#endif /* !NO_BIO */
 
 /* Detect which type of key it is before decoding. */
@@ -47439,70 +52880,83 @@
 #endif
 
-#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
-    defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ)
-int wolfSSL_X509_set_subject_name(WOLFSSL_X509 *cert, WOLFSSL_X509_NAME *name)
+#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
+    !defined(WOLFCRYPT_ONLY)
+/* unlike wolfSSL_X509_NAME_dup this does not malloc a duplicate, only deep
+ * copy. "to" is expected to be a fresh blank name, if not pointers could be
+ * lost */
+int wolfSSL_X509_NAME_copy(WOLFSSL_X509_NAME* from, WOLFSSL_X509_NAME* to)
 {
     int i;
     WOLFSSL_X509_NAME_ENTRY* ne;
 
+    WOLFSSL_ENTER("wolfSSL_X509_NAME_copy");
+
+    if (from == NULL || to == NULL) {
+        WOLFSSL_MSG("NULL parameter");
+        return BAD_FUNC_ARG;
+    }
+
+    if (from->dynamicName) {
+        to->name = (char*)XMALLOC(from->sz, to->heap, DYNAMIC_TYPE_SUBJECT_CN);
+        if (to->name == NULL)
+            return WOLFSSL_FAILURE;
+        to->dynamicName = 1;
+    }
+    XMEMCPY(to->name, from->name, from->sz);
+    to->sz = from->sz;
+
+    for (i = 0; i < MAX_NAME_ENTRIES; i++) {
+        ne = wolfSSL_X509_NAME_get_entry(from, i);
+        if (ne != NULL)
+            wolfSSL_X509_NAME_add_entry(to, ne, i, 1);
+    }
+    to->entrySz = from->entrySz;
+    return WOLFSSL_SUCCESS;
+}
+
+
+/* copies over information from "name" to the "cert" subject name
+ * returns WOLFSSL_SUCCESS on success */
+int wolfSSL_X509_set_subject_name(WOLFSSL_X509 *cert, WOLFSSL_X509_NAME *name)
+{
     WOLFSSL_ENTER("X509_set_subject_name");
     if (cert == NULL || name == NULL)
         return WOLFSSL_FAILURE;
 
-    FreeX509Name(&cert->subject, cert->heap);
-    InitX509Name(&cert->subject, 0);
-    if (name->dynamicName) {
-        cert->subject.name = (char*)XMALLOC(name->sz, cert->heap,
-                                                       DYNAMIC_TYPE_SUBJECT_CN);
-        if (cert->subject.name == NULL)
-            return WOLFSSL_FAILURE;
-    }
-    XMEMCPY(cert->subject.name, name->name, name->sz);
-    cert->subject.sz = name->sz;
-
-    for (i = 0; i < 10; i++) {
-        ne = wolfSSL_X509_NAME_get_entry(name, i);
-        if (ne != NULL)
-            wolfSSL_X509_NAME_add_entry(&cert->subject, ne, i, 1);
-    }
+    FreeX509Name(&cert->subject);
+    InitX509Name(&cert->subject, 0, cert->heap);
+
+    if (wolfSSL_X509_NAME_copy(name, &cert->subject) != WOLFSSL_SUCCESS) {
+        FreeX509Name(&cert->subject);
+        return WOLFSSL_FAILURE;
+    }
+
     cert->subject.x509 = cert;
-    cert->subject.name = cert->subject.fullName.fullName;
-    cert->subject.sz = cert->subject.fullName.fullNameLen;
-
     return WOLFSSL_SUCCESS;
 }
 
+
+/* copies over information from "name" to the "cert" issuer name
+ * returns WOLFSSL_SUCCESS on success */
 int wolfSSL_X509_set_issuer_name(WOLFSSL_X509 *cert, WOLFSSL_X509_NAME *name)
 {
-    int i;
-    WOLFSSL_X509_NAME_ENTRY* ne;
-
     WOLFSSL_ENTER("X509_set_issuer_name");
     if (cert == NULL || name == NULL)
         return WOLFSSL_FAILURE;
 
-    FreeX509Name(&cert->issuer, cert->heap);
-    InitX509Name(&cert->issuer, 0);
-    if (name->dynamicName) {
-        cert->issuer.name = (char*)XMALLOC(name->sz, cert->heap,
-                                                       DYNAMIC_TYPE_SUBJECT_CN);
-        if (cert->issuer.name == NULL)
-            return WOLFSSL_FAILURE;
-    }
-    XMEMCPY(cert->issuer.name, name->name, name->sz);
-    cert->issuer.sz = name->sz;
-
-    for (i = 0; i < 10; i++) {
-        ne = wolfSSL_X509_NAME_get_entry(name, i);
-        if (ne != NULL)
-            wolfSSL_X509_NAME_add_entry(&cert->issuer, ne, i, 1);
-    }
+    FreeX509Name(&cert->issuer);
+    InitX509Name(&cert->issuer, 0, cert->heap);
+
+    if (wolfSSL_X509_NAME_copy(name, &cert->issuer) != WOLFSSL_SUCCESS) {
+        FreeX509Name(&cert->issuer);
+        return WOLFSSL_FAILURE;
+    }
+
     cert->issuer.x509 = cert;
-    cert->issuer.name = cert->issuer.fullName.fullName;
-    cert->issuer.sz = cert->issuer.fullName.fullNameLen;
     cert->issuerSet = 1;
 
     return WOLFSSL_SUCCESS;
 }
+
 
 int wolfSSL_X509_set_notAfter(WOLFSSL_X509* x509, const WOLFSSL_ASN1_TIME* t)
@@ -47512,5 +52966,8 @@
     }
 
-    XMEMCPY(&x509->notAfter, t, sizeof(WOLFSSL_ASN1_TIME));
+    x509->notAfter.type = t->type;
+    x509->notAfter.length = t->length;
+
+    XMEMCPY(x509->notAfter.data, t->data, CTC_DATE_SIZE);
 
     return WOLFSSL_SUCCESS;
@@ -47523,5 +52980,8 @@
     }
 
-    XMEMCPY(&x509->notBefore, t, sizeof(WOLFSSL_ASN1_TIME));
+    x509->notBefore.type = t->type;
+    x509->notBefore.length = t->length;
+
+    XMEMCPY(x509->notBefore.data, t->data, CTC_DATE_SIZE);
 
     return WOLFSSL_SUCCESS;
@@ -47531,14 +52991,14 @@
 {
     WOLFSSL_ENTER("wolfSSL_X509_set_serialNumber");
-    if (!x509 || !s || s->dataMax >= EXTERNAL_SERIAL_SIZE)
+    if (!x509 || !s || s->length >= EXTERNAL_SERIAL_SIZE)
         return WOLFSSL_FAILURE;
 
-    if (s->isDynamic)
-        XSTRNCPY((char*)x509->serial,(char*)s->data,s->dataMax);
-    else
-        XSTRNCPY((char*)x509->serial,(char*)s->intData,s->dataMax);
-
-    x509->serial[s->dataMax] = 0;
-    x509->serialSz = s->dataMax;
+    /* WOLFSSL_ASN1_INTEGER has type | size | data */
+    if (s->length < 3) {
+        return WOLFSSL_FAILURE;
+    }
+    XMEMCPY(x509->serial, s->data + 2, s->length - 2);
+    x509->serialSz = s->length - 2;
+    x509->serial[s->length] = 0;
 
     return WOLFSSL_SUCCESS;
@@ -47548,5 +53008,5 @@
 int wolfSSL_X509_set_pubkey(WOLFSSL_X509 *cert, WOLFSSL_EVP_PKEY *pkey)
 {
-    byte* p;
+    byte* p = NULL;
     WOLFSSL_ENTER("wolfSSL_X509_set_pubkey");
 
@@ -47554,20 +53014,54 @@
         return WOLFSSL_FAILURE;
 
-    if (pkey->type == EVP_PKEY_RSA)
-        cert->pubKeyOID = RSAk;
-    else if (pkey->type == EVP_PKEY_EC)
+    if (pkey->type == EVP_PKEY_RSA
+#ifndef NO_DSA
+            || pkey->type == EVP_PKEY_DSA
+#endif /* !NO_DSA */
+            ) {
+        p = (byte*)XMALLOC(pkey->pkey_sz, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+        if (p == NULL)
+            return WOLFSSL_FAILURE;
+
+        if (cert->pubKey.buffer != NULL)
+            XFREE(cert->pubKey.buffer, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+        cert->pubKey.buffer = p;
+        XMEMCPY(cert->pubKey.buffer, pkey->pkey.ptr, pkey->pkey_sz);
+        cert->pubKey.length = pkey->pkey_sz;
+#ifndef NO_DSA
+        if (pkey->type == EVP_PKEY_DSA)
+            cert->pubKeyOID = DSAk;
+        else
+#endif /* !NO_DSA */
+            cert->pubKeyOID = RSAk;
+    }
+#ifdef HAVE_ECC
+    else if (pkey->type == EVP_PKEY_EC) {
+        /* Generate since pkey->pkey.ptr may contain private key */
+        ecc_key* ecc;
+        int derSz;
+
+        if (pkey->ecc == NULL || pkey->ecc->internal == NULL)
+            return WOLFSSL_FAILURE;
+
+        ecc = (ecc_key*)pkey->ecc->internal;
+        derSz = wc_EccPublicKeyDerSize(ecc, 1);
+        if (derSz <= 0)
+            return WOLFSSL_FAILURE;
+
+        p = (byte*)XMALLOC(derSz, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+        if (p == NULL)
+            return WOLFSSL_FAILURE;
+
+        if ((derSz = wc_EccPublicKeyToDer(ecc, p, derSz, 1)) <= 0) {
+            XFREE(p, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+            return WOLFSSL_FAILURE;
+        }
+        cert->pubKey.buffer = p;
+        cert->pubKey.length = derSz;
         cert->pubKeyOID = ECDSAk;
+    }
+#endif /* HAVE_ECC */
     else
         return WOLFSSL_FAILURE;
-
-    p = (byte*)XMALLOC(pkey->pkey_sz, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
-    if (p == NULL)
-        return WOLFSSL_FAILURE;
-
-    if (cert->pubKey.buffer != NULL)
-        XFREE(cert->pubKey.buffer, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
-    cert->pubKey.buffer = p;
-    XMEMCPY(cert->pubKey.buffer, pkey->pkey.ptr, pkey->pkey_sz);
-    cert->pubKey.length = pkey->pkey_sz;
 
     return WOLFSSL_SUCCESS;
@@ -47585,7 +53079,7 @@
 }
 
-#endif /* OPENSSL_EXTRA && !NO_CERTS && WOLFSSL_CERT_GEN && WOLFSSL_CERT_REQ */
-
-#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
+#endif /* (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) && WOLFSSL_CERT_GEN */
+
+#if defined(OPENSSL_ALL) && !defined(NO_CERTS) && \
     defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ)
 
@@ -47599,4 +53093,10 @@
         return;
 
+    if (!ctx->x509) {
+        ctx->x509 = wolfSSL_X509_new();
+        if (!ctx->x509)
+            return;
+    }
+
     /* Set parameters in ctx as long as ret == WOLFSSL_SUCCESS */
     if (issuer)
@@ -47625,6 +53125,7 @@
 int wolfSSL_i2d_X509_REQ(WOLFSSL_X509* req, unsigned char** out)
 {
-    const unsigned char* der;
     int derSz = 0;
+    int ret = WOLFSSL_FAILURE;
+    WOLFSSL_BIO* bio = NULL;
     WOLFSSL_ENTER("wolfSSL_i2d_X509_REQ");
 
@@ -47633,19 +53134,34 @@
     }
 
-    der = wolfSSL_X509_get_der(req, &derSz);
-    if (der == NULL) {
-        return MEMORY_E;
-    }
+    if (!(bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()))) {
+        return WOLFSSL_FAILURE;
+    }
+
+    if (wolfSSL_i2d_X509_REQ_bio(bio, req) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("wolfSSL_i2d_X509_REQ_bio error");
+        goto cleanup;
+    }
+
+    derSz = wolfSSL_BIO_get_len(bio);
 
     if (*out == NULL) {
         *out = (unsigned char*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_OPENSSL);
-        if (*out == NULL) {
-            return MEMORY_E;
-        }
-    }
-
-    XMEMCPY(*out, der, derSz);
-
-    return derSz;
+        if (!*out) {
+            WOLFSSL_MSG("malloc error");
+            ret = MEMORY_E;
+            goto cleanup;
+        }
+    }
+
+    if (wolfSSL_BIO_read(bio, *out, derSz) != derSz) {
+        WOLFSSL_MSG("wolfSSL_BIO_read error");
+        goto cleanup;
+    }
+
+    ret = derSz;
+cleanup:
+    wolfSSL_BIO_free(bio);
+
+    return ret;
 }
 
@@ -47671,5 +53187,5 @@
     /* Create a Cert that has the certificate request fields. */
     req->sigOID = wolfSSL_sigTypeFromPKEY((WOLFSSL_EVP_MD*)md, pkey);
-    if (wolfSSL_X509_make_der(req, 1, der, &derSz) != WOLFSSL_SUCCESS) {
+    if (wolfssl_x509_make_der(req, 1, der, &derSz, 0) != WOLFSSL_SUCCESS) {
         return WOLFSSL_FAILURE;
     }
@@ -47682,14 +53198,283 @@
 }
 
-
-#ifndef NO_WOLFSSL_STUB
+int wolfSSL_X509_REQ_sign_ctx(WOLFSSL_X509 *req,
+                              WOLFSSL_EVP_MD_CTX* md_ctx)
+{
+    if (md_ctx && md_ctx->pctx)
+        return wolfSSL_X509_REQ_sign(req, md_ctx->pctx->pkey,
+                wolfSSL_EVP_MD_CTX_md(md_ctx));
+    else
+        return WOLFSSL_FAILURE;
+}
+
+static int regenX509REQDerBuffer(WOLFSSL_X509* x509)
+{
+    int derSz = X509_BUFFER_SZ;
+    int ret = WOLFSSL_FAILURE;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* der;
+    der = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (!der) {
+        WOLFSSL_MSG("malloc failed");
+        return WOLFSSL_FAILURE;
+    }
+#else
+    byte der[X509_BUFFER_SZ];
+#endif
+
+    if (wolfssl_x509_make_der(x509, 1, der, &derSz, 0) == WOLFSSL_SUCCESS) {
+        FreeDer(&x509->derCert);
+        if (AllocDer(&x509->derCert, derSz, CERT_TYPE, x509->heap) == 0) {
+            XMEMCPY(x509->derCert->buffer, der, derSz);
+            ret = WOLFSSL_SUCCESS;
+        }
+        else {
+            WOLFSSL_MSG("Failed to allocate DER buffer for X509");
+        }
+    }
+    else {
+        WOLFSSL_MSG("Unable to make DER for X509 REQ");
+    }
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+    return ret;
+}
+
 int wolfSSL_X509_REQ_add_extensions(WOLFSSL_X509* req,
-        WOLF_STACK_OF(WOLFSSL_X509_EXTENSION)* ext)
-{
+        WOLF_STACK_OF(WOLFSSL_X509_EXTENSION)* ext_sk)
+{
+    if (!req || !ext_sk) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    while (ext_sk) {
+        WOLFSSL_X509_EXTENSION* ext = ext_sk->data.ext;
+
+        if (wolfSSL_X509_add_ext(req, ext, -1) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("wolfSSL_X509_add_ext error");
+            return WOLFSSL_FAILURE;
+        }
+
+        ext_sk = ext_sk->next;
+    }
+
+    return regenX509REQDerBuffer(req);
+}
+
+int wolfSSL_X509_REQ_add1_attr_by_txt(WOLFSSL_X509 *req,
+                              const char *attrname, int type,
+                              const unsigned char *bytes, int len)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_REQ_add1_attr_by_txt");
+
+#ifdef HAVE_LIBEST
+    if (!req || !attrname || !bytes || type != MBSTRING_ASC) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    if (len < 0) {
+        len = (int)XSTRLEN((char*)bytes);
+    }
+
+    /* For now just pretend that we support this for libest testing */
+    if (len == XSTR_SIZEOF("1.3.6.1.1.1.1.22") &&
+            XMEMCMP("1.3.6.1.1.1.1.22", bytes, len) == 0) {
+        /* MAC Address */
+    }
+    else if (len == XSTR_SIZEOF("1.2.840.10045.2.1") &&
+            XMEMCMP("1.2.840.10045.2.1", bytes, len) == 0) {
+        /* ecPublicKey */
+    }
+    else if (len == XSTR_SIZEOF("1.2.840.10045.4.3.3") &&
+            XMEMCMP("1.2.840.10045.4.3.3", bytes, len) == 0) {
+        /* ecdsa-with-SHA384 */
+    }
+    else {
+        return WOLFSSL_FAILURE;
+    }
+
+    /* return error if not built for libest */
+    return WOLFSSL_SUCCESS;
+#else
     (void)req;
-    (void)ext;
-    return WOLFSSL_FATAL_ERROR;
-}
-#endif
+    (void)attrname;
+    (void)type;
+    (void)bytes;
+    (void)len;
+    return WOLFSSL_FAILURE;
+#endif
+}
+
+int wolfSSL_X509_REQ_add1_attr_by_NID(WOLFSSL_X509 *req,
+                                      int nid, int type,
+                                      const unsigned char *bytes,
+                                      int len)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_REQ_add1_attr_by_NID");
+
+    if (!req || !bytes || type != MBSTRING_ASC) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    switch (nid) {
+    case NID_pkcs9_challengePassword:
+        if (len < 0)
+            len = (int)XSTRLEN((char*)bytes);
+        if (len < CTC_NAME_SIZE) {
+            XMEMCPY(req->challengePw, bytes, len);
+            req->challengePw[len] = '\0';
+        }
+        else {
+            WOLFSSL_MSG("Challenge password too long");
+            return WOLFSSL_FAILURE;
+        }
+        if (req->challengePwAttr) {
+            wolfSSL_X509_ATTRIBUTE_free(req->challengePwAttr);
+        }
+        req->challengePwAttr = wolfSSL_X509_ATTRIBUTE_new();
+        if (req->challengePwAttr) {
+            req->challengePwAttr->value->value.asn1_string =
+                    wolfSSL_ASN1_STRING_new();
+            if (wolfSSL_ASN1_STRING_set(
+                    req->challengePwAttr->value->value.asn1_string,
+                    bytes, len) != WOLFSSL_SUCCESS) {
+                WOLFSSL_MSG("wolfSSL_ASN1_STRING_set error");
+                return WOLFSSL_FAILURE;
+            }
+            req->challengePwAttr->value->type = V_ASN1_PRINTABLESTRING;
+        }
+        else {
+            WOLFSSL_MSG("wolfSSL_X509_ATTRIBUTE_new error");
+            return WOLFSSL_FAILURE;
+        }
+        break;
+    case NID_serialNumber:
+        if (len < 0)
+            len = (int)XSTRLEN((char*)bytes);
+        if (len + 1 > EXTERNAL_SERIAL_SIZE) {
+            WOLFSSL_MSG("SerialNumber too long");
+            return WOLFSSL_FAILURE;
+        }
+        XMEMCPY(req->serial, bytes, len);
+        req->serialSz = len;
+        break;
+    default:
+        WOLFSSL_MSG("Unsupported attribute");
+        return WOLFSSL_FAILURE;
+    }
+    return WOLFSSL_SUCCESS;
+}
+
+
+/* Return NID as the attr index */
+int wolfSSL_X509_REQ_get_attr_by_NID(const WOLFSSL_X509 *req,
+        int nid, int lastpos)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_REQ_get_attr_by_NID");
+
+    /* Since we only support 1 attr per attr type then a lastpos of >= 0
+     * indicates that one was already returned */
+    if (!req || lastpos >= 0) {
+        WOLFSSL_MSG("Bad parameter");
+        return WOLFSSL_FATAL_ERROR;
+    }
+
+    switch (nid) {
+    case NID_pkcs9_challengePassword:
+        return req->challengePwAttr ? nid : WOLFSSL_FATAL_ERROR;
+    default:
+        WOLFSSL_MSG("Unsupported attribute");
+        return WOLFSSL_FATAL_ERROR;
+    }
+}
+
+/**
+ * @param req X509_REQ containing attribute
+ * @param loc NID of the attribute to return
+ */
+WOLFSSL_X509_ATTRIBUTE *wolfSSL_X509_REQ_get_attr(
+        const WOLFSSL_X509 *req, int loc)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_REQ_get_attr");
+
+    if (!req) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    switch (loc) {
+    case NID_pkcs9_challengePassword:
+        return req->challengePwAttr;
+    default:
+        WOLFSSL_MSG("Unsupported attribute");
+        return NULL;
+    }
+}
+
+WOLFSSL_X509_ATTRIBUTE* wolfSSL_X509_ATTRIBUTE_new(void)
+{
+    WOLFSSL_X509_ATTRIBUTE* ret;
+    WOLFSSL_ENTER("wolfSSL_X509_ATTRIBUTE_new");
+    ret = (WOLFSSL_X509_ATTRIBUTE*)XMALLOC(sizeof(WOLFSSL_X509_ATTRIBUTE),
+            NULL, DYNAMIC_TYPE_OPENSSL);
+    if (!ret) {
+        WOLFSSL_MSG("malloc error");
+        return NULL;
+    }
+    XMEMSET(ret, 0, sizeof(WOLFSSL_X509_ATTRIBUTE));
+    ret->object = wolfSSL_ASN1_OBJECT_new();
+    ret->value = wolfSSL_ASN1_TYPE_new();
+    /* Don't allocate ret->set since WOLFSSL_ASN1_TYPE
+     * is not supported as a stack type */
+    if (!ret->object || !ret->value) {
+        WOLFSSL_MSG("wolfSSL_ASN1_OBJECT_new or wolfSSL_ASN1_TYPE_new error");
+        wolfSSL_X509_ATTRIBUTE_free(ret);
+        return NULL;
+    }
+    return ret;
+}
+
+void wolfSSL_X509_ATTRIBUTE_free(WOLFSSL_X509_ATTRIBUTE* attr)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_ATTRIBUTE_free");
+    if (attr) {
+        if (attr->object) {
+            wolfSSL_ASN1_OBJECT_free(attr->object);
+        }
+        if (attr->value) {
+            wolfSSL_ASN1_TYPE_free(attr->value);
+        }
+        if (attr->set) {
+            wolfSSL_sk_free(attr->set);
+        }
+        XFREE(attr, NULL, DYNAMIC_TYPE_OPENSSL);
+    }
+}
+
+WOLFSSL_ASN1_TYPE *wolfSSL_X509_ATTRIBUTE_get0_type(
+        WOLFSSL_X509_ATTRIBUTE *attr, int idx)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_ATTRIBUTE_get0_type");
+
+    if (!attr || idx != 0) {
+        WOLFSSL_MSG("Bad parameter");
+        return NULL;
+    }
+
+    return attr->value;
+}
+
+WOLFSSL_X509 *wolfSSL_X509_to_X509_REQ(WOLFSSL_X509 *x,
+        WOLFSSL_EVP_PKEY *pkey, const WOLFSSL_EVP_MD *md)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_to_X509_REQ");
+    (void)pkey;
+    (void)md;
+    return wolfSSL_X509_dup(x);
+}
 
 int wolfSSL_X509_REQ_set_subject_name(WOLFSSL_X509 *req,
@@ -47703,5 +53488,134 @@
     return wolfSSL_X509_set_pubkey(req, pkey);
 }
-#endif /* OPENSSL_EXTRA && !NO_CERTS && WOLFSSL_CERT_GEN && WOLFSSL_CERT_REQ */
-
-
+#endif /* OPENSSL_ALL && !NO_CERTS && WOLFSSL_CERT_GEN && WOLFSSL_CERT_REQ */
+
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+static int SetStaticEphemeralKey(StaticKeyExchangeInfo_t* staticKE, int keyAlgo, 
+    const char* key, unsigned int keySz, int format, void* heap, WOLFSSL_CTX* ctx)
+{
+    int ret = 0;
+    DerBuffer* der = NULL;
+    byte* keyBuf = NULL;
+#ifndef NO_FILESYSTEM
+    const char* keyFile = NULL;
+#endif
+
+    /* allow empty key to free buffer */
+    if (staticKE == NULL || (key == NULL && keySz > 0)) {
+        return BAD_FUNC_ARG;
+    }
+
+    WOLFSSL_ENTER("SetStaticEphemeralKey");
+
+    /* if key is already set free it */
+#ifndef NO_DH
+    if (keyAlgo == WC_PK_TYPE_DH && staticKE->dhKey && 
+            (ctx == NULL || staticKE->dhKey != ctx->staticKE.dhKey))
+        FreeDer(&staticKE->dhKey);
+#endif
+#ifdef HAVE_ECC
+    if (keyAlgo == WC_PK_TYPE_ECDH && staticKE->ecKey && 
+            (ctx == NULL || staticKE->ecKey != ctx->staticKE.ecKey))
+        FreeDer(&staticKE->ecKey);
+#endif
+
+    /* check if just free'ing key */
+    if (key == NULL && keySz == 0) {
+        return 0;
+    }
+
+#ifndef NO_FILESYSTEM
+    /* load file from filesystem */
+    if (key && keySz == 0) {
+        size_t keyBufSz = 0;
+        keyFile = (const char*)key;
+        ret = wc_FileLoad(keyFile, &keyBuf, &keyBufSz, heap);
+        if (ret != 0) {
+            return ret;
+        }
+        keySz = (unsigned int)keyBufSz;
+    }
+    else
+#endif
+    {
+        /* use as key buffer directly */
+        keyBuf = (byte*)key;
+    }
+
+    if (format == WOLFSSL_FILETYPE_PEM) {
+    #ifdef WOLFSSL_PEM_TO_DER
+        int keyFormat = 0;
+        ret = PemToDer(keyBuf, keySz, PRIVATEKEY_TYPE, &der, 
+            heap, NULL, &keyFormat);
+        /* auto detect key type */
+        if (ret == 0 && keyAlgo == 0) {
+            if (keyFormat == ECDSAk)
+                keyAlgo = WC_PK_TYPE_ECDH;
+            else
+                keyAlgo = WC_PK_TYPE_DH;
+        }
+    #else
+        ret = NOT_COMPILED_IN;
+    #endif
+    }
+    else {
+        ret = AllocDer(&der, keySz, PRIVATEKEY_TYPE, heap);
+        if (ret == 0) {
+            XMEMCPY(der->buffer, keyBuf, keySz);
+        }
+    }
+
+    switch (keyAlgo) {
+    #ifndef NO_DH
+        case WC_PK_TYPE_DH:
+            staticKE->dhKey = der;
+            break;
+    #endif
+    #ifdef HAVE_ECC
+        case WC_PK_TYPE_ECDH:
+            staticKE->ecKey = der;
+            break;
+    #endif
+        default:
+            /* not supported */
+            ret = NOT_COMPILED_IN;
+            FreeDer(&der);
+            break;
+    }
+
+#ifndef NO_FILESYSTEM
+    if (keyFile && keyBuf) {
+        XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+#endif
+
+    WOLFSSL_LEAVE("SetStaticEphemeralKey", ret);
+
+    return ret;
+}
+
+int wolfSSL_CTX_set_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, 
+    const char* key, unsigned int keySz, int format)
+{
+    if (ctx == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    return SetStaticEphemeralKey(&ctx->staticKE, keyAlgo, key, keySz, format, 
+        ctx->heap, NULL);
+}
+
+int wolfSSL_set_ephemeral_key(WOLFSSL* ssl, int keyAlgo, 
+    const char* key, unsigned int keySz, int format)
+{
+    if (ssl == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    return SetStaticEphemeralKey(&ssl->staticKE, keyAlgo, key, keySz, format, 
+        ssl->heap, ssl->ctx);
+}
+
+#endif /* WOLFSSL_STATIC_EPHEMERAL */
+
+#endif /* !WOLFCRYPT_ONLY */
Index: azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/tls.c
===================================================================
--- azure_iot_hub_f767zi/trunk/wolfssl-4.4.0/src/tls.c	(revision 457)
+++ azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/tls.c	(revision 464)
@@ -60,17 +60,9 @@
 #endif /* HAVE_QSH */
 
-#if (!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
-        !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \
-    (defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES))
+#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)
 static int TLSX_KeyShare_IsSupported(int namedGroup);
 #endif
 
-#if ((!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
-        !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \
-    (defined(WOLFSSL_TLS13) && !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) \
-        && !defined(HAVE_CURVE448) && defined(HAVE_SUPPORTED_CURVES)) || \
-    ((defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
-        defined(HAVE_CURVE448)) && defined(HAVE_SUPPORTED_CURVES))) && \
-     defined(HAVE_TLS_EXTENSIONS)
+#ifdef HAVE_SUPPORTED_CURVES
 static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions);
 #endif
@@ -135,13 +127,34 @@
 
 #ifdef WOLFSSL_RENESAS_TSIP_TLS
+    
+    #if (WOLFSSL_RENESAS_TSIP_VER >=109)
+
+    int tsip_generateMasterSecretEx(
+            byte        cipherSuiteFirst,
+            byte        cipherSuite,
+            const byte* pr,                 /* pre-master    */
+            const byte* cr,                 /* client random */
+            const byte* sr,                 /* server random */
+            byte*       ms);
+
+    #elif (WOLFSSL_RENESAS_TSIP_VER >=106)
+    
+    int tsip_generateMasterSecret(
+            const byte* pre,
+            const byte* cr,
+            const byte* sr,
+            byte*       ms);
+    
+    #endif     
+
     int tsip_useable(const WOLFSSL *ssl);
-    int tsip_generateMasterSecret(const byte *pre,
-                                const byte *cr,const byte *sr,
-                                byte *ms/* out */);
     int tsip_generateSeesionKey(WOLFSSL *ssl);
-    int tsip_generateVerifyData(const byte *ms, const byte *side,
-                                const byte *handshake_hash,
-                                byte *hashes /* out */);
-#endif
+    int tsip_generateVerifyData(
+            const byte* ms,
+            const byte* side,
+            const byte* handshake_hash,
+            byte*       hashes);
+
+#endif /*WOLFSSL_RENESAS_TSIP_TLS*/
 
 int BuildTlsHandshakeHash(WOLFSSL* ssl, byte* hash, word32* hashLen)
@@ -535,4 +548,17 @@
     !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION)
         if (tsip_useable(ssl)) {
+            
+            #if (WOLFSSL_RENESAS_TSIP_VER>=109)
+
+            ret = tsip_generateMasterSecretEx(
+                            ssl->options.cipherSuite0,
+                            ssl->options.cipherSuite,                
+                            &ssl->arrays->preMasterSecret[VERSION_SZ],
+                            ssl->arrays->clientRandom,
+                            ssl->arrays->serverRandom,
+                            ssl->arrays->tsip_masterSecret);
+            
+            #elif (WOLFSSL_RENESAS_TSIP_VER>=106)
+
             ret = tsip_generateMasterSecret(
                             &ssl->arrays->preMasterSecret[VERSION_SZ],
@@ -540,4 +566,10 @@
                             ssl->arrays->serverRandom,
                             ssl->arrays->tsip_masterSecret);
+
+            #else
+
+            ret = NOT_COMPILED_IN;
+
+            #endif
         } else
 #endif
@@ -642,69 +674,4 @@
     return ret;
 }
-
-
-static WC_INLINE void GetSEQIncrement(WOLFSSL* ssl, int verify, word32 seq[2])
-{
-    if (verify) {
-        seq[0] = ssl->keys.peer_sequence_number_hi;
-        seq[1] = ssl->keys.peer_sequence_number_lo++;
-        if (seq[1] > ssl->keys.peer_sequence_number_lo) {
-            /* handle rollover */
-            ssl->keys.peer_sequence_number_hi++;
-        }
-    }
-    else {
-        seq[0] = ssl->keys.sequence_number_hi;
-        seq[1] = ssl->keys.sequence_number_lo++;
-        if (seq[1] > ssl->keys.sequence_number_lo) {
-            /* handle rollover */
-            ssl->keys.sequence_number_hi++;
-        }
-    }
-}
-
-
-#ifdef WOLFSSL_DTLS
-static WC_INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2])
-{
-    if (order == PREV_ORDER) {
-        /* Previous epoch case */
-        seq[0] = (((word32)ssl->keys.dtls_epoch - 1) << 16) |
-                 (ssl->keys.dtls_prev_sequence_number_hi & 0xFFFF);
-        seq[1] = ssl->keys.dtls_prev_sequence_number_lo;
-    }
-    else if (order == PEER_ORDER) {
-        seq[0] = ((word32)ssl->keys.curEpoch << 16) |
-                 (ssl->keys.curSeq_hi & 0xFFFF);
-        seq[1] = ssl->keys.curSeq_lo; /* explicit from peer */
-    }
-    else {
-        seq[0] = ((word32)ssl->keys.dtls_epoch << 16) |
-                 (ssl->keys.dtls_sequence_number_hi & 0xFFFF);
-        seq[1] = ssl->keys.dtls_sequence_number_lo;
-    }
-}
-#endif /* WOLFSSL_DTLS */
-
-
-static WC_INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
-{
-    word32 seq[2] = {0, 0};
-
-    if (!ssl->options.dtls) {
-        GetSEQIncrement(ssl, verifyOrder, seq);
-    }
-    else {
-#ifdef WOLFSSL_DTLS
-        DtlsGetSEQ(ssl, verifyOrder, seq);
-#endif
-    }
-
-    c32toa(seq[0], out);
-    c32toa(seq[1], out + OPAQUE32_LEN);
-}
-
-
-/*** end copy ***/
 
 
@@ -1170,18 +1137,21 @@
 
 int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz,
-             int content, int verify)
+             int content, int verify, int epochOrder)
 {
     Hmac   hmac;
     byte   myInner[WOLFSSL_TLS_HMAC_INNER_SZ];
     int    ret = 0;
+    const byte* macSecret = NULL;
+    word32 hashSz = 0;
+
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
 #ifdef HAVE_TRUNCATED_HMAC
-    word32 hashSz = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ
+    hashSz = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ
                                         : ssl->specs.hash_size;
 #else
-    word32 hashSz = ssl->specs.hash_size;
-#endif
-
-    if (ssl == NULL)
-        return BAD_FUNC_ARG;
+    hashSz = ssl->specs.hash_size;
+#endif
 
 #ifdef HAVE_FUZZER
@@ -1198,5 +1168,8 @@
 #endif
 
-    wolfSSL_SetTlsHmacInner(ssl, myInner, sz, content, verify);
+    if (!ssl->options.dtls)
+        wolfSSL_SetTlsHmacInner(ssl, myInner, sz, content, verify);
+    else
+        wolfSSL_SetTlsHmacInner(ssl, myInner, sz, content, epochOrder);
 #if defined(WOLFSSL_RENESAS_TSIP_TLS) && \
     !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION)
@@ -1218,7 +1191,17 @@
         return ret;
 
+
+#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
     ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl),
-                                              wolfSSL_GetMacSecret(ssl, verify),
+                                              macSecret,
                                               ssl->specs.hash_size);
+
     if (ret == 0) {
         /* Constant time verification required. */
@@ -1375,4 +1358,41 @@
 }
 
+#ifdef WOLFSSL_TLS13
+
+/**
+ * Creates a new extension and prepend it to the provided list.
+ * Checks for duplicate extensions, keeps the newest.
+ */
+static int TLSX_Prepend(TLSX** list, TLSX_Type type, void* data, void* heap)
+{
+    TLSX* extension = TLSX_New(type, data, heap);
+    TLSX* curr = *list;
+
+    if (extension == NULL)
+        return MEMORY_E;
+
+    /* remove duplicate extensions, there should be only one of each type. */
+    while (curr && curr->next) {
+        if (curr->next->type == type) {
+            TLSX *next = curr->next;
+
+            curr->next = next->next;
+            next->next = NULL;
+
+            TLSX_FreeAll(next, heap);
+        }
+        curr = curr->next;
+    }
+
+    if (curr)
+        curr->next = extension;
+    else
+        *list = extension;
+
+    return 0;
+}
+
+#endif /* WOLFSSL_TLS13 */
+
 #ifndef NO_WOLFSSL_CLIENT
 
@@ -2961,4 +2981,27 @@
 {
     int ret;
+#if !defined(NO_WOLFSSL_SERVER)
+    byte status_type;
+    word16 size = 0;
+#if defined(WOLFSSL_TLS13)
+    DecodedCert* cert;
+#endif
+#endif
+
+#if !defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER) \
+    && defined(WOLFSSL_TLS13)
+    OcspRequest* request;
+    TLSX* extension;
+    CertificateStatusRequest* csr;
+#endif
+
+#if !defined(NO_WOLFSSL_CLIENT) && defined(WOLFSSL_TLS13) \
+ || !defined(NO_WOLFSSL_SERVER) 
+    word32 offset = 0;
+#endif
+
+#if !defined(NO_WOLFSSL_CLIENT) && defined(WOLFSSL_TLS13)
+    word32 resp_length;
+#endif
 
     /* shut up compiler warnings */
@@ -2967,7 +3010,6 @@
     if (!isRequest) {
 #ifndef NO_WOLFSSL_CLIENT
-        TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
-        CertificateStatusRequest* csr = extension ?
-                              (CertificateStatusRequest*)extension->data : NULL;
+        extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
+        csr = extension ? (CertificateStatusRequest*)extension->data : NULL;
 
         if (!csr) {
@@ -2990,6 +3032,6 @@
                     /* propagate nonce */
                     if (csr->request.ocsp.nonceSz) {
-                        OcspRequest* request =
-                             (OcspRequest*)TLSX_CSR_GetRequest(ssl->extensions);
+                        request = 
+                            (OcspRequest*)TLSX_CSR_GetRequest(ssl->extensions);
 
                         if (request) {
@@ -3007,7 +3049,4 @@
     #ifdef WOLFSSL_TLS13
         if (ssl->options.tls1_3) {
-            word32       resp_length;
-            word32       offset = 0;
-
             /* Get the new extension potentially created above. */
             extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
@@ -3027,10 +3066,8 @@
                     ret = BUFFER_ERROR;
             }
-        #if !defined(NO_WOLFSSL_SERVER)
             if (ret == 0) {
                 csr->response.buffer = input + offset;
                 csr->response.length = resp_length;
             }
-        #endif
 
             return ret;
@@ -3046,12 +3083,6 @@
     else {
 #ifndef NO_WOLFSSL_SERVER
-        byte   status_type;
-        word16 offset = 0;
-        word16 size = 0;
-
         if (length == 0)
             return 0;
-        if (length < ENUM_LEN)
-            return BUFFER_ERROR;
 
         status_type = input[offset++];
@@ -3061,5 +3092,5 @@
 
                 /* skip responder_id_list */
-                if (length - offset < OPAQUE16_LEN)
+                if ((int)(length - offset) < OPAQUE16_LEN)
                     return BUFFER_ERROR;
 
@@ -3068,5 +3099,5 @@
 
                 /* skip request_extensions */
-                if (length - offset < OPAQUE16_LEN)
+                if ((int)(length - offset) < OPAQUE16_LEN)
                     return BUFFER_ERROR;
 
@@ -3100,9 +3131,27 @@
             return ret; /* throw error */
 
-    #if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+    #if defined(WOLFSSL_TLS13)
         if (ssl->options.tls1_3) {
-            OcspRequest* request;
-            TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
-            CertificateStatusRequest* csr = extension ?
+            cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap,
+                                         DYNAMIC_TYPE_DCERT);
+            if (cert == NULL) {
+                return MEMORY_E;
+            }
+            InitDecodedCert(cert, ssl->buffers.certificate->buffer,
+                            ssl->buffers.certificate->length, ssl->heap);
+            ret = ParseCert(cert, CERT_TYPE, 1, ssl->ctx->cm);
+            if (ret != 0 ) {
+                XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
+                return ret;
+            }
+            ret = TLSX_CSR_InitRequest(ssl->extensions, cert, ssl->heap);
+            if (ret != 0 ) {
+                XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
+                return ret;
+            }
+            XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
+
+            extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
+            csr = extension ?
                 (CertificateStatusRequest*)extension->data : NULL;
             if (csr == NULL)
@@ -3454,5 +3503,5 @@
 
         while (length > offset) {
-            if (length - offset < ENUM_LEN + OPAQUE16_LEN)
+            if ((int)(length - offset) < ENUM_LEN + OPAQUE16_LEN)
                 return BUFFER_ERROR;
 
@@ -3469,5 +3518,5 @@
                 case WOLFSSL_CSR2_OCSP_MULTI:
                     /* skip responder_id_list */
-                    if (length - offset < OPAQUE16_LEN)
+                    if ((int)(length - offset) < OPAQUE16_LEN)
                         return BUFFER_ERROR;
 
@@ -3478,5 +3527,5 @@
                     offset += OPAQUE16_LEN + size;
                     /* skip request_extensions */
-                    if (length - offset < OPAQUE16_LEN)
+                    if ((int)(length - offset) < OPAQUE16_LEN)
                         return BUFFER_ERROR;
 
@@ -3507,12 +3556,17 @@
             #endif
 
-            /* accept the first good status_type and return */
-            ret = TLSX_UseCertificateStatusRequestV2(&ssl->extensions,
+            /* TLS 1.3 servers MUST NOT act upon presence or information in
+             * this extension (RFC 8448 Section 4.4.2.1).
+             */
+            if (!IsAtLeastTLSv1_3(ssl->version)) {
+                /* accept the first good status_type and return */
+                ret = TLSX_UseCertificateStatusRequestV2(&ssl->extensions,
                                          status_type, 0, ssl->heap, ssl->devId);
-            if (ret != WOLFSSL_SUCCESS)
-                return ret; /* throw error */
-
-            TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST_V2);
-            ssl->status_request_v2 = status_type;
+                if (ret != WOLFSSL_SUCCESS)
+                    return ret; /* throw error */
+
+                TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST_V2);
+                ssl->status_request_v2 = status_type;
+            }
 
             return 0;
@@ -3708,5 +3762,5 @@
 #error Elliptic Curves Extension requires Elliptic Curve Cryptography. \
        Use --enable-ecc in the configure script or define HAVE_ECC. \
-       Alternatively use FFDHE for DH ciperhsuites.
+       Alternatively use FFDHE for DH ciphersuites.
 #endif
 
@@ -3854,16 +3908,13 @@
         #endif
         }
-        else {
-        #ifdef HAVE_FFDHE
-            return;
-        #endif
-        }
-    }
-
+    }
+ #ifdef HAVE_FFDHE
+        return;
+ #endif
     /* turns semaphore on to avoid sending this extension. */
     TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
 }
 
-#endif
+#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */
 
 #ifndef NO_WOLFSSL_SERVER
@@ -3897,5 +3948,6 @@
 }
 
-#endif
+#endif /* !NO_WOLFSSL_SERVER */
+
 #ifndef NO_WOLFSSL_CLIENT
 
@@ -4056,4 +4108,9 @@
 
     ext = TLSX_Find(priority, TLSX_SUPPORTED_GROUPS);
+    if (ext == NULL) {
+        WOLFSSL_MSG("Could not find supported groups extension");
+        return 0;
+    }
+
     curve = (SupportedCurve*)ext->data;
     name = curve->name;
@@ -4081,5 +4138,5 @@
 }
 
-#endif
+#endif /* WOLFSSL_TLS13 && !WOLFSSL_NO_SERVER_GROUPS_EXT */
 
 #if defined(HAVE_FFDHE) && !defined(WOLFSSL_NO_TLS12)
@@ -4130,6 +4187,8 @@
 
 
-    if ((ret = TLSX_PopulateSupportedGroups(ssl, &priority)) != WOLFSSL_SUCCESS)
+    if ((ret = TLSX_PopulateSupportedGroups(ssl, &priority)) != WOLFSSL_SUCCESS) {
+        TLSX_FreeAll(priority, ssl->heap);
         return ret;
+    }
     ret = 0;
 
@@ -4231,5 +4290,5 @@
 }
 
-#endif
+#endif /* HAVE_SUPPORTED_CURVES */
 
 #ifndef NO_WOLFSSL_SERVER
@@ -4262,5 +4321,9 @@
     SupportedCurve* curve     = NULL;
     word32          oid       = 0;
+#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_ED25519) || \
+                              defined(HAVE_CURVE448) || defined(HAVE_ED448) || \
+                                (!defined(NO_RSA) && defined(WOLFSSL_STATIC_DH))
     word32          pkOid     = 0;
+#endif /* HAVE_ECC || HAVE_ED25519 || HAVE_ED448 || (!NO_RSA && STATIC_DH) */
     word32          defOid    = 0;
     word32          defSz     = 80; /* Maximum known curve size is 66. */
@@ -4274,5 +4337,19 @@
 
     (void)oid;
-
+    (void)pkOid;
+
+    if (first == CHACHA_BYTE) {
+        switch (second) {
+            case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case TLS_PSK_WITH_CHACHA20_POLY1305_SHA256:
+            case TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+            case TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256:
+                return 1; /* no suite restriction */
+            case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256:
+            case TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+                break;
+        }
+    }
     if (first == ECC_BYTE || first == CHACHA_BYTE)
         extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
@@ -4296,5 +4373,5 @@
         switch (curve->name) {
 #ifdef HAVE_ECC
-    #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:
@@ -4315,6 +4392,6 @@
                 break;
         #endif /* HAVE_ECC_KOBLITZ */
-    #endif
-    #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)
+        #endif
+    #if (defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 192
         #ifndef NO_ECC_SECP
             case WOLFSSL_ECC_SECP192R1:
@@ -4330,5 +4407,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:
@@ -4344,5 +4421,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 WOLFSSL_ECC_SECP256R1:
@@ -4353,5 +4430,5 @@
     #endif /* !NO_ECC256 || HAVE_ALL_CURVES */
 #endif
-        #ifdef HAVE_CURVE25519
+        #if (defined(HAVE_CURVE25519) || defined(HAVE_ED25519)) && ECC_MIN_KEY_SZ <= 256
             case WOLFSSL_ECC_X25519:
                 oid = ECC_X25519_OID;
@@ -4365,5 +4442,5 @@
         #endif /* HAVE_CURVE25519 */
 #ifdef HAVE_ECC
-    #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+    #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256
         #ifdef HAVE_ECC_KOBLITZ
             case WOLFSSL_ECC_SECP256K1:
@@ -4379,6 +4456,20 @@
         #endif /* HAVE_ECC_BRAINPOOL */
     #endif
-#endif
-        #ifdef HAVE_CURVE448
+    #if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384
+        #ifndef NO_ECC_SECP
+            case WOLFSSL_ECC_SECP384R1:
+                pkOid = oid = ECC_SECP384R1_OID;
+                octets = 48;
+                break;
+        #endif /* !NO_ECC_SECP */
+        #ifdef HAVE_ECC_BRAINPOOL
+            case WOLFSSL_ECC_BRAINPOOLP384R1:
+                pkOid = oid = ECC_BRAINPOOLP384R1_OID;
+                octets = 48;
+                break;
+        #endif /* HAVE_ECC_BRAINPOOL */
+    #endif
+#endif
+        #if (defined(HAVE_CURVE448) || defined(HAVE_ED448)) && ECC_MIN_KEY_SZ <= 448
             case WOLFSSL_ECC_X448:
                 oid = ECC_X448_OID;
@@ -4392,19 +4483,5 @@
         #endif /* HAVE_CURVE448 */
 #ifdef HAVE_ECC
-    #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
-        #ifndef NO_ECC_SECP
-            case WOLFSSL_ECC_SECP384R1:
-                pkOid = oid = ECC_SECP384R1_OID;
-                octets = 48;
-                break;
-        #endif /* !NO_ECC_SECP */
-        #ifdef HAVE_ECC_BRAINPOOL
-            case WOLFSSL_ECC_BRAINPOOLP384R1:
-                pkOid = oid = ECC_BRAINPOOLP384R1_OID;
-                octets = 48;
-                break;
-        #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:
@@ -4414,5 +4491,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 WOLFSSL_ECC_SECP521R1:
@@ -4456,4 +4533,5 @@
         if (first == ECC_BYTE) {
             switch (second) {
+#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448)
                 /* ECDHE_ECDSA */
                 case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
@@ -4472,5 +4550,5 @@
                 break;
 
-#ifdef WOLFSSL_STATIC_DH
+    #ifdef WOLFSSL_STATIC_DH
                 /* ECDH_ECDSA */
                 case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
@@ -4493,5 +4571,6 @@
                     key |= ssl->pkCurveOID == oid;
                 break;
-#endif /* WOLFSSL_STATIC_DH */
+    #endif /* WOLFSSL_STATIC_DH */
+#endif /* HAVE_ECC || HAVE_ED25519 || HAVE_ED448 */
 #ifndef NO_RSA
                 /* ECDHE_RSA */
@@ -4509,5 +4588,5 @@
                 break;
 
-#ifdef WOLFSSL_STATIC_DH
+    #ifdef WOLFSSL_STATIC_DH
                 /* ECDH_RSA */
                 case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
@@ -4530,5 +4609,5 @@
                     key |= ssl->pkCurveOID == pkOid;
                 break;
-#endif /* WOLFSSL_STATIC_DH */
+    #endif /* WOLFSSL_STATIC_DH */
 #endif
                 default:
@@ -4552,4 +4631,5 @@
         if (first == CHACHA_BYTE) {
             switch (second) {
+#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448)
                 /* ECDHE_ECDSA */
                 case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 :
@@ -4559,4 +4639,5 @@
                     ephmSuite = 1;
                 break;
+#endif /* HAVE_ECC || HAVE_ED25519 || HAVE_ED448 */
 #ifndef NO_RSA
                 /* ECDHE_RSA */
@@ -4816,5 +4897,5 @@
         #endif
         }
-        else {
+        else if (ssl->secure_renegotiation != NULL) {
         #ifndef NO_WOLFSSL_CLIENT
             if (!ssl->secure_renegotiation->enabled) {
@@ -4982,10 +5063,19 @@
         }
 
-        if (length == 0) {
+        if (length > SESSION_TICKET_LEN) {
+            ret = BAD_TICKET_MSG_SZ;
+        } else if (IsAtLeastTLSv1_3(ssl->version)) {
+            WOLFSSL_MSG("Process client ticket rejected, TLS 1.3 no support");
+            ssl->options.rejectTicket = 1;
+            ret = 0;  /* not fatal */
+        } else if (ssl->options.noTicketTls12) {
+            /* ignore ticket request */
+        } else if (length == 0) {
             /* blank ticket */
             ret = TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap);
             if (ret == WOLFSSL_SUCCESS) {
                 ret = 0;
-                TLSX_SetResponse(ssl, TLSX_SESSION_TICKET);  /* send blank ticket */
+                /* send blank ticket */
+                TLSX_SetResponse(ssl, TLSX_SESSION_TICKET);
                 ssl->options.createTicket = 1;  /* will send ticket msg */
                 ssl->options.useTicket    = 1;
@@ -5015,4 +5105,8 @@
                 ssl->options.rejectTicket = 1;
                 ret = 0;  /* not fatal */
+            } else if (ret == VERSION_ERROR) {
+                WOLFSSL_MSG("Process client ticket rejected, bad TLS version");
+                ssl->options.rejectTicket = 1;
+                ret = 0;  /* not fatal */
             } else if (ret == WOLFSSL_TICKET_RET_FATAL || ret < 0) {
                 WOLFSSL_MSG("Process client ticket fatal error, not using");
@@ -5876,8 +5970,6 @@
         *pSz += (word16)(OPAQUE8_LEN + cnt * OPAQUE16_LEN);
     }
-#ifndef WOLFSSL_TLS13_DRAFT_18
     else if (msgType == server_hello || msgType == hello_retry_request)
         *pSz += OPAQUE16_LEN;
-#endif
     else
         return SANITY_MSG_E;
@@ -5957,22 +6049,10 @@
         *pSz += (word16)(OPAQUE8_LEN + *cnt);
     }
-#ifndef WOLFSSL_TLS13_DRAFT_18
     else if (msgType == server_hello || msgType == hello_retry_request) {
-    #ifdef WOLFSSL_TLS13_DRAFT
-        if (ssl->version.major == SSLv3_MAJOR &&
-                                          ssl->version.minor == TLSv1_3_MINOR) {
-            output[0] = TLS_DRAFT_MAJOR;
-            output[1] = TLS_DRAFT_MINOR;
-        }
-        else
-    #endif
-        {
-            output[0] = ssl->version.major;
-            output[1] = ssl->version.minor;
-        }
+        output[0] = ssl->version.major;
+        output[1] = ssl->version.minor;
 
         *pSz += OPAQUE16_LEN;
     }
-#endif
     else
         return SANITY_MSG_E;
@@ -5998,4 +6078,5 @@
     int newMinor = 0;
     int set = 0;
+    int ret;
 
     if (msgType == client_hello) {
@@ -6050,9 +6131,10 @@
                 if (!ssl->options.tls1_3) {
                     ssl->options.tls1_3 = 1;
-                    TLSX_Push(&ssl->extensions, TLSX_SUPPORTED_VERSIONS, ssl,
-                              ssl->heap);
-#ifndef WOLFSSL_TLS13_DRAFT_18
+                    ret = TLSX_Prepend(&ssl->extensions,
+                              TLSX_SUPPORTED_VERSIONS, ssl, ssl->heap);
+                    if (ret != 0) {
+                        return ret;
+                    }
                     TLSX_SetResponse(ssl, TLSX_SUPPORTED_VERSIONS);
-#endif
                 }
                 if (minor > newMinor) {
@@ -6075,5 +6157,4 @@
         }
     }
-#ifndef WOLFSSL_TLS13_DRAFT_18
     else if (msgType == server_hello || msgType == hello_retry_request) {
         /* Must contain one version. */
@@ -6084,11 +6165,4 @@
         minor = input[OPAQUE8_LEN];
 
-    #ifdef WOLFSSL_TLS13_DRAFT
-        if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) {
-            major = SSLv3_MAJOR;
-            minor = TLSv1_3_MINOR;
-        }
-    #endif
-
         if (major != pv.major)
             return VERSION_ERROR;
@@ -6120,5 +6194,4 @@
         }
     }
-#endif
     else
         return SANITY_MSG_E;
@@ -6155,5 +6228,5 @@
 #endif /* WOLFSSL_TLS13 */
 
-#if defined(WOLFSSL_TLS13)
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
 
 /******************************************************************************/
@@ -6302,4 +6375,7 @@
         XMEMCPY(&cookie->data + len, mac, macSz);
 
+    if (extension->data != NULL)
+        XFREE(extension->data, ssl->heap, DYNAMIC_TYPE_TLSX);
+
     extension->data = (void*)cookie;
     extension->resp = (byte)resp;
@@ -6321,5 +6397,5 @@
 
 #endif
-#if !defined(WOLFSSL_NO_SIGALG)
+#if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
 /******************************************************************************/
 /* Signature Algorithms                                                       */
@@ -6418,4 +6494,8 @@
         return BUFFER_ERROR;
 
+    /* Sig Algo list size must be even. */
+    if (suites->hashSigAlgoSz % 2 != 0)
+        return BUFFER_ERROR;
+
     /* truncate hashSigAlgo list if too long */
     suites->hashSigAlgoSz = len;
@@ -6453,6 +6533,5 @@
 /******************************************************************************/
 
-#ifdef WOLFSSL_TLS13
-#if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+#if defined(WOLFSSL_TLS13) && !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
 /* Return the size of the SignatureAlgorithms extension's data.
  *
@@ -6541,5 +6620,4 @@
 #define SAC_WRITE     TLSX_SignatureAlgorithmsCert_Write
 #define SAC_PARSE     TLSX_SignatureAlgorithmsCert_Parse
-#endif /* !WOLFSSL_TLS13_DRAFT_18 && !WOLFSSL_TLS13_DRAFT_22 */
 #endif /* WOLFSSL_TLS13 */
 
@@ -6549,5 +6627,5 @@
 /******************************************************************************/
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)
 /* Create a key share entry using named Diffie-Hellman parameters group.
  * Generates a key pair.
@@ -6623,5 +6701,5 @@
     }
 
-    /* Allocate space for the public key. */
+    /* Allocate space for the public key */
     dataSz = params->p_len;
     keyData = (byte*)XMALLOC(dataSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
@@ -6630,5 +6708,5 @@
         goto end;
     }
-    /* Allocate space for the private key. */
+    /* Allocate space for the private key */
     key = (byte*)XMALLOC(keySz, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
     if (key == NULL) {
@@ -6644,18 +6722,32 @@
         goto end;
 
-    /* Generate a new key pair. */
-    ret = wc_DhGenerateKeyPair(dhKey, ssl->rng, (byte*)key, &keySz, keyData,
-                               &dataSz);
-#ifdef WOLFSSL_ASYNC_CRYPT
-    /* TODO: Make this function non-blocking */
-    if (ret == WC_PENDING_E) {
-        ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
-    }
-#endif
+#if defined(WOLFSSL_STATIC_EPHEMERAL) && defined(WOLFSSL_DH_EXTRA)
+    if (ssl->staticKE.dhKey) {
+        DerBuffer* keyDer = ssl->staticKE.dhKey;
+        word32 idx = 0;
+        WOLFSSL_MSG("Using static DH key");
+        ret = wc_DhKeyDecode(keyDer->buffer, &idx, dhKey, keyDer->length);
+        if (ret == 0) {
+            ret = wc_DhExportKeyPair(dhKey, (byte*)key, &keySz, keyData, &dataSz);
+        }
+    }
+    else
+#endif
+    {
+        /* Generate a new key pair */
+        ret = wc_DhGenerateKeyPair(dhKey, ssl->rng, (byte*)key, &keySz, keyData,
+                                &dataSz);
+    #ifdef WOLFSSL_ASYNC_CRYPT
+        /* TODO: Make this function non-blocking */
+        if (ret == WC_PENDING_E) {
+            ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
+        }
+    #endif
+    }
     if (ret != 0)
         goto end;
 
     if (params->p_len != dataSz) {
-        /* Pad the front of the key data with zeros. */
+        /* Zero pad the front of the public key to match prime "p" size */
         XMEMMOVE(keyData + params->p_len - dataSz, keyData, dataSz);
         XMEMSET(keyData, 0, params->p_len - dataSz);
@@ -6865,5 +6957,5 @@
     /* Translate named group to a curve id. */
     switch (kse->group) {
-    #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:
@@ -6874,5 +6966,5 @@
         #endif /* !NO_ECC_SECP */
     #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:
@@ -6883,5 +6975,5 @@
         #endif /* !NO_ECC_SECP */
     #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:
@@ -6892,5 +6984,5 @@
         #endif /* !NO_ECC_SECP */
     #endif
-    #ifdef HAVE_X448
+    #if defined(HAVE_X448) && ECC_MIN_KEY_SZ <= 448
         case WOLFSSL_ECC_X448:
             curveId = ECC_X448;
@@ -6915,11 +7007,24 @@
     if (ret != 0)
         goto end;
-    ret = wc_ecc_make_key_ex(ssl->rng, keySize, eccKey, curveId);
-#ifdef WOLFSSL_ASYNC_CRYPT
-    /* TODO: Make this function non-blocking */
-    if (ret == WC_PENDING_E) {
-        ret = wc_AsyncWait(ret, &eccKey->asyncDev, WC_ASYNC_FLAG_NONE);
-    }
-#endif
+
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+    if (ssl->staticKE.ecKey) {
+        DerBuffer* keyDer = ssl->staticKE.ecKey;
+        word32 idx = 0;
+        WOLFSSL_MSG("Using static ECDH key");
+        ret = wc_EccPrivateKeyDecode(keyDer->buffer, &idx, eccKey, keyDer->length);
+    }
+    else
+#endif
+    {
+        /* Generate ephemeral ECC key */
+        ret = wc_ecc_make_key_ex(ssl->rng, keySize, eccKey, curveId);
+    #ifdef WOLFSSL_ASYNC_CRYPT
+        /* TODO: Make this function non-blocking */
+        if (ret == WC_PENDING_E) {
+            ret = wc_AsyncWait(ret, &eccKey->asyncDev, WC_ASYNC_FLAG_NONE);
+        }
+    #endif
+    }
     if (ret != 0)
         goto end;
@@ -7410,5 +7515,5 @@
     /* find supported curve */
     switch (keyShareEntry->group) {
-    #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:
@@ -7417,5 +7522,5 @@
         #endif /* !NO_ECC_SECP */
     #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:
@@ -7424,5 +7529,5 @@
         #endif /* !NO_ECC_SECP */
     #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:
@@ -7431,5 +7536,5 @@
         #endif /* !NO_ECC_SECP */
     #endif
-    #ifdef HAVE_X448
+    #if defined(HAVE_X448) && ECC_MIN_KEY_SZ <= 448
         case WOLFSSL_ECC_X448:
             curveId = ECC_X448;
@@ -7452,4 +7557,13 @@
     }
     ssl->ecdhCurveOID = ssl->peerEccKey->dp->oidSum;
+
+#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
+    !defined(HAVE_SELFTEST)
+    ret = wc_ecc_set_rng(keyShareKey, ssl->rng);
+    if (ret != 0) {
+        return ret;
+    }
+#endif
 
     do {
@@ -7897,5 +8011,5 @@
             break;
     #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:
@@ -7903,13 +8017,13 @@
         #endif /* !NO_ECC_SECP */
     #endif
-    #ifdef HAVE_CURVE25519
+    #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
         case WOLFSSL_ECC_X25519:
             break;
     #endif
-    #ifdef HAVE_CURVE448
+    #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
         case WOLFSSL_ECC_X448:
             break;
     #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:
@@ -7917,5 +8031,5 @@
         #endif /* !NO_ECC_SECP */
     #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:
@@ -7944,5 +8058,5 @@
     if (ssl->numGroups == 0) {
 #if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
-    #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
             ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP256R1;
@@ -7951,20 +8065,20 @@
 #endif
     #ifndef HAVE_FIPS
-        #if defined(HAVE_CURVE25519)
+        #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
             ssl->group[ssl->numGroups++] = WOLFSSL_ECC_X25519;
         #endif
     #endif
     #ifndef HAVE_FIPS
-        #if defined(HAVE_CURVE448)
+        #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
             ssl->group[ssl->numGroups++] = WOLFSSL_ECC_X448;
         #endif
     #endif
 #if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
-    #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
             ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP384R1;
         #endif
     #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
             ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP521R1;
@@ -8091,11 +8205,15 @@
             return BAD_KEY_SHARE_DATA;
 
-    #ifdef OPENSSL_EXTRA
         if ((clientKSE->group & NAMED_DH_MASK) == 0) {
+            /* Check max value supported. */
+            if (clientKSE->group > WOLFSSL_ECC_MAX) {
+                continue;
+            }
+        #ifdef OPENSSL_EXTRA
             /* Check if server supports group. */
-            if (ssl->ctx->disabledCurves & (1 << clientKSE->group))
+            if (ssl->ctx->disabledCurves & ((word32)1 << clientKSE->group))
                 continue;
-        }
-    #endif
+        #endif
+        }
         if (!TLSX_KeyShare_IsSupported(clientKSE->group))
             continue;
@@ -8405,5 +8523,5 @@
 
         /* Length of identities and of binders. */
-        if (length - idx < OPAQUE16_LEN + OPAQUE16_LEN)
+        if ((int)(length - idx) < OPAQUE16_LEN + OPAQUE16_LEN)
             return BUFFER_E;
 
@@ -8955,10 +9073,10 @@
  * In messages: ClientHello, EncryptedExtensions and NewSessionTicket.
  *
- * max      The maximum early data size.
+ * maxSz    The maximum early data size.
  * output   The buffer to write into.
  * msgType  The type of the message this extension is being written into.
  * returns the number of bytes written into the buffer.
  */
-static int TLSX_EarlyData_Write(word32 max, byte* output, byte msgType,
+static int TLSX_EarlyData_Write(word32 maxSz, byte* output, byte msgType,
                                 word16* pSz)
 {
@@ -8966,5 +9084,5 @@
         return 0;
     else if (msgType == session_ticket) {
-        c32toa(max, output);
+        c32toa(maxSz, output);
         *pSz += OPAQUE32_LEN;
         return 0;
@@ -9023,9 +9141,9 @@
 /* Use the data to create a new Early Data object in the extensions.
  *
- * ssl  The SSL/TLS object.
- * max  The maximum early data size.
+ * ssl    The SSL/TLS object.
+ * maxSz  The maximum early data size.
  * returns 0 on success and other values indicate failure.
  */
-int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 max)
+int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 maxSz)
 {
     int   ret = 0;
@@ -9046,5 +9164,5 @@
 
     extension->resp = 1;
-    extension->val  = max;
+    extension->val  = maxSz;
 
     return 0;
@@ -9106,7 +9224,9 @@
         switch (extension->type) {
 
+#ifdef HAVE_SNI
             case TLSX_SERVER_NAME:
                 SNI_FREE_ALL((SNI*)extension->data, heap);
                 break;
+#endif
 
             case TLSX_TRUSTED_CA_KEYS:
@@ -9118,4 +9238,5 @@
                 break;
 
+            case TLSX_EXTENDED_MASTER_SECRET:
             case TLSX_TRUNCATED_HMAC:
                 /* Nothing to do. */
@@ -9154,5 +9275,5 @@
                 ALPN_FREE_ALL((ALPN*)extension->data, heap);
                 break;
-#if !defined(WOLFSSL_NO_SIGALG)
+#if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
             case TLSX_SIGNATURE_ALGORITHMS:
                 break;
@@ -9166,7 +9287,9 @@
                 break;
 
+    #ifdef WOLFSSL_SEND_HRR_COOKIE
             case TLSX_COOKIE:
                 CKE_FREE_ALL((Cookie*)extension->data, heap);
                 break;
+    #endif
 
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
@@ -9189,5 +9312,5 @@
     #endif
 
-    #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+    #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
             case TLSX_SIGNATURE_ALGORITHMS_CERT:
                 break;
@@ -9235,7 +9358,7 @@
         length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
 
-
         switch (extension->type) {
 
+#ifdef HAVE_SNI
             case TLSX_SERVER_NAME:
                 /* SNI only sends the name on the request. */
@@ -9243,4 +9366,5 @@
                     length += SNI_GET_SIZE((SNI*)extension->data);
                 break;
+#endif
 
             case TLSX_TRUSTED_CA_KEYS:
@@ -9254,4 +9378,5 @@
                 break;
 
+            case TLSX_EXTENDED_MASTER_SECRET:
             case TLSX_TRUNCATED_HMAC:
                 /* always empty. */
@@ -9294,5 +9419,5 @@
                 length += ALPN_GET_SIZE((ALPN*)extension->data);
                 break;
-#if !defined(WOLFSSL_NO_SIGALG)
+#if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
             case TLSX_SIGNATURE_ALGORITHMS:
                 length += SA_GET_SIZE(extension->data);
@@ -9309,7 +9434,9 @@
                 break;
 
+    #ifdef WOLFSSL_SEND_HRR_COOKIE
             case TLSX_COOKIE:
                 ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &length);
                 break;
+    #endif
 
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
@@ -9336,5 +9463,5 @@
     #endif
 
-    #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+    #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
             case TLSX_SIGNATURE_ALGORITHMS_CERT:
                 length += SAC_GET_SIZE(extension->data);
@@ -9387,4 +9514,5 @@
         /* extension data should be written internally. */
         switch (extension->type) {
+#ifdef HAVE_SNI
             case TLSX_SERVER_NAME:
                 if (isRequest) {
@@ -9393,4 +9521,5 @@
                 }
                 break;
+#endif
 
             case TLSX_TRUSTED_CA_KEYS:
@@ -9404,4 +9533,9 @@
                 WOLFSSL_MSG("Max Fragment Length extension to write");
                 offset += MFL_WRITE((byte*)extension->data, output + offset);
+                break;
+
+            case TLSX_EXTENDED_MASTER_SECRET:
+                WOLFSSL_MSG("Extended Master Secret");
+                /* always empty. */
                 break;
 
@@ -9461,5 +9595,5 @@
                 offset += ALPN_WRITE((ALPN*)extension->data, output + offset);
                 break;
-#if !defined(WOLFSSL_NO_SIGALG)
+#if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
             case TLSX_SIGNATURE_ALGORITHMS:
                 WOLFSSL_MSG("Signature Algorithms extension to write");
@@ -9479,4 +9613,5 @@
                 break;
 
+    #ifdef WOLFSSL_SEND_HRR_COOKIE
             case TLSX_COOKIE:
                 WOLFSSL_MSG("Cookie extension to write");
@@ -9484,4 +9619,5 @@
                                 msgType, &offset);
                 break;
+    #endif
 
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
@@ -9514,5 +9650,5 @@
     #endif
 
-    #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+    #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
             case TLSX_SIGNATURE_ALGORITHMS_CERT:
                 WOLFSSL_MSG("Signature Algorithms extension to write");
@@ -9733,10 +9869,5 @@
 #endif /* HAVE_QSH */
 
-#if (!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
-        !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \
-    (defined(WOLFSSL_TLS13) && !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) \
-        && !defined(HAVE_CURVE448) && defined(HAVE_SUPPORTED_CURVES)) || \
-    ((defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
-        defined(HAVE_CURVE448)) && defined(HAVE_SUPPORTED_CURVES))
+#ifdef HAVE_SUPPORTED_CURVES
 
 /* Populates the default supported groups / curves */
@@ -9745,6 +9876,4 @@
     int ret = WOLFSSL_SUCCESS;
 #ifdef WOLFSSL_TLS13
-    int i;
-
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
     if (ssl->options.resuming && ssl->session.namedGroup != 0) {
@@ -9755,4 +9884,5 @@
 
     if (ssl->numGroups != 0) {
+        int i;
         for (i = 0; i < ssl->numGroups; i++) {
             ret = TLSX_UseSupportedCurve(extensions, ssl->group[i], ssl->heap);
@@ -9764,7 +9894,7 @@
 #endif /* WOLFSSL_TLS13 */
 
-#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+#if defined(HAVE_ECC)
         /* list in order by strength, since not all servers choose by strength */
-        #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
                 ret = TLSX_UseSupportedCurve(extensions,
@@ -9773,5 +9903,5 @@
             #endif
         #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
                 ret = TLSX_UseSupportedCurve(extensions,
@@ -9780,5 +9910,5 @@
             #endif
         #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
                 ret = TLSX_UseSupportedCurve(extensions,
@@ -9792,8 +9922,8 @@
             #endif
         #endif
-#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */
+#endif /* HAVE_ECC */
 
         #ifndef HAVE_FIPS
-            #if defined(HAVE_CURVE448)
+            #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
                 ret = TLSX_UseSupportedCurve(extensions,
                                                    WOLFSSL_ECC_X448, ssl->heap);
@@ -9803,5 +9933,5 @@
 
 #if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
-        #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
                 ret = TLSX_UseSupportedCurve(extensions,
@@ -9820,8 +9950,8 @@
             #endif
         #endif
-#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */
+#endif /* HAVE_ECC */
 
         #ifndef HAVE_FIPS
-            #if defined(HAVE_CURVE25519)
+            #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
                 ret = TLSX_UseSupportedCurve(extensions,
                                                  WOLFSSL_ECC_X25519, ssl->heap);
@@ -9831,5 +9961,5 @@
 
 #if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
-        #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
                 ret = TLSX_UseSupportedCurve(extensions,
@@ -9845,5 +9975,5 @@
 
     #ifndef HAVE_FIPS
-        #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
                 ret = TLSX_UseSupportedCurve(extensions,
@@ -9857,5 +9987,5 @@
             #endif
         #endif
-        #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
                 ret = TLSX_UseSupportedCurve(extensions,
@@ -9875,7 +10005,7 @@
         #endif
     #endif /* HAVE_FIPS */
-#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */
-
-                /* Add FFDHE supported groups. */
+#endif /* HAVE_ECC */
+
+            /* Add FFDHE supported groups. */
         #ifdef HAVE_FFDHE_8192
             if (8192/8 >= ssl->options.minDhKeySz &&
@@ -9930,5 +10060,46 @@
 }
 
-#endif
+#endif /* HAVE_SUPPORTED_CURVES */
+
+#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)
+
+static const word16 preferredGroup[] = {
+#if defined(HAVE_ECC) && (!defined(NO_ECC256) || \
+    defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) && ECC_MIN_KEY_SZ <= 256
+    WOLFSSL_ECC_SECP256R1,
+#endif
+#if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
+    WOLFSSL_ECC_X25519,
+#endif
+#if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
+    WOLFSSL_ECC_X448,
+#endif
+#if defined(HAVE_ECC) && (!defined(NO_ECC384) || \
+    defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) && ECC_MIN_KEY_SZ <= 384
+    WOLFSSL_ECC_SECP384R1,
+#endif
+#if defined(HAVE_ECC) && (!defined(NO_ECC521) || \
+    defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) && ECC_MIN_KEY_SZ <= 521
+    WOLFSSL_ECC_SECP521R1,
+#endif
+#if defined(HAVE_FFDHE_2048)
+    WOLFSSL_FFDHE_2048,
+#endif
+#if defined(HAVE_FFDHE_3072)
+    WOLFSSL_FFDHE_3072,
+#endif
+#if defined(HAVE_FFDHE_4096)
+    WOLFSSL_FFDHE_4096,
+#endif
+#if defined(HAVE_FFDHE_6144)
+    WOLFSSL_FFDHE_6144,
+#endif
+#if defined(HAVE_FFDHE_8192)
+    WOLFSSL_FFDHE_8192,
+#endif
+};
+#define PREFERRED_GROUP_SZ (sizeof(preferredGroup) / sizeof(*preferredGroup))
+
+#endif /* WOLFSSL_TLS13 && HAVE_SUPPORTED_CURVES */
 
 int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
@@ -10052,5 +10223,5 @@
     } /* is not server */
 
-#if !defined(WOLFSSL_NO_SIGALG)
+#if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
     WOLFSSL_MSG("Adding signature algorithms extension");
     if ((ret = TLSX_SetSignatureAlgorithms(&ssl->extensions, ssl, ssl->heap))
@@ -10061,5 +10232,5 @@
     ret = 0;
 #endif
-    #ifdef WOLFSSL_TLS13
+#ifdef WOLFSSL_TLS13
         if (!isServer && IsAtLeastTLSv1_3(ssl->version)) {
             /* Add mandatory TLS v1.3 extension: supported version */
@@ -10079,7 +10250,7 @@
             ret = 0;
         }
-    #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && HAVE_SUPPORTED_CURVES */
-
-        #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+    #endif /* !(HAVE_ECC || CURVE25519 || CURVE448) && HAVE_SUPPORTED_CURVES */
+ 
+        #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
             if (ssl->certHashSigAlgoSz > 0) {
                 WOLFSSL_MSG("Adding signature algorithms cert extension");
@@ -10089,41 +10260,40 @@
                 }
             }
-        #endif /* !WOLFSSL_TLS13_DRAFT_18 && !WOLFSSL_TLS13_DRAFT_22 */
-
+        #endif
+
+        #if defined(HAVE_SUPPORTED_CURVES)
             if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) {
                 word16 namedGroup;
 
-        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+            #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
                 if (ssl->options.resuming && ssl->session.namedGroup != 0)
                     namedGroup = ssl->session.namedGroup;
                 else
-        #endif
-                {
-        #if defined(HAVE_ECC) && (!defined(NO_ECC256) || \
-                              defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP)
-                    namedGroup = WOLFSSL_ECC_SECP256R1;
-        #elif defined(HAVE_CURVE25519)
-                    namedGroup = WOLFSSL_ECC_X25519;
-        #elif defined(HAVE_CURVE448)
-                    namedGroup = WOLFSSL_ECC_X448;
-        #elif defined(HAVE_ECC) && (!defined(NO_ECC384) || \
-                              defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP)
-                    namedGroup = WOLFSSL_ECC_SECP384R1;
-        #elif defined(HAVE_ECC) && (!defined(NO_ECC521) || \
-                              defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP)
-                    namedGroup = WOLFSSL_ECC_SECP521R1;
-        #elif defined(HAVE_FFDHE_2048)
-                    namedGroup = WOLFSSL_FFDHE_2048;
-        #elif defined(HAVE_FFDHE_3072)
-                    namedGroup = WOLFSSL_FFDHE_3072;
-        #elif defined(HAVE_FFDHE_4096)
-                    namedGroup = WOLFSSL_FFDHE_4096;
-        #elif defined(HAVE_FFDHE_6144)
-                    namedGroup = WOLFSSL_FFDHE_6144;
-        #elif defined(HAVE_FFDHE_8192)
-                    namedGroup = WOLFSSL_FFDHE_8192;
-        #else
+            #endif
+                if (PREFERRED_GROUP_SZ == 0) {
+                    WOLFSSL_MSG("No groups in preference list");
                     return KEY_SHARE_ERROR;
-        #endif
+                }
+                else if (ssl->numGroups > 0) {
+                    int set = 0;
+                    int i, j;
+
+                    /* Default to first group in supported list. */
+                    namedGroup = ssl->group[0];
+                    /* Try to find preferred in supported list. */
+                    for (i = 0; i < (int)PREFERRED_GROUP_SZ && !set; i++) {
+                        for (j = 0; j < ssl->numGroups; j++) {
+                            if (preferredGroup[i] == ssl->group[j]) {
+                                /* Most preferred that is supported. */
+                                namedGroup = ssl->group[j];
+                                set = 1;
+                                break;
+                            }
+                        }
+                    }
+                }
+                else {
+                    /* Choose the most preferred group. */
+                    namedGroup = preferredGroup[0];
                 }
                 ret = TLSX_KeyShare_Use(ssl, namedGroup, 0, NULL, NULL);
@@ -10131,4 +10301,5 @@
                     return ret;
             }
+        #endif
 
         #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
@@ -10171,4 +10342,5 @@
                 byte cipherSuite0 = TLS13_BYTE;
                 byte cipherSuite = WOLFSSL_DEF_PSK_CIPHER;
+                int cipherSuiteFlags = WOLFSSL_CIPHER_SUITE_FLAG_NONE;
                 const char* cipherName = NULL;
 
@@ -10179,5 +10351,5 @@
                         ssl->arrays->psk_key, MAX_PSK_KEY_LEN, &cipherName);
                     if (GetCipherSuiteFromName(cipherName, &cipherSuite0,
-                                                           &cipherSuite) != 0) {
+                                               &cipherSuite, &cipherSuiteFlags) != 0) {
                         return PSK_KEY_ERROR;
                     }
@@ -10193,7 +10365,7 @@
                 }
                 ssl->arrays->client_identity[MAX_PSK_ID_LEN] = '\0';
-                /* TODO: Callback should be able to change ciphersuite. */
                 ssl->options.cipherSuite0 = cipherSuite0;
                 ssl->options.cipherSuite  = cipherSuite;
+                (void)cipherSuiteFlags;
                 ret = SetCipherSpecs(ssl);
                 if (ret != 0)
@@ -10237,5 +10409,5 @@
         }
 
-    #endif
+#endif
 
     (void)isServer;
@@ -10264,5 +10436,5 @@
         QSH_VALIDATE_REQUEST(ssl, semaphore);
         WOLF_STK_VALIDATE_REQUEST(ssl);
-#if !defined(WOLFSSL_NO_SIGALG)
+#if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
         if (ssl->suites->hashSigAlgoSz == 0)
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
@@ -10271,18 +10443,22 @@
         if (!IsAtLeastTLSv1_2(ssl))
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+    #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS)
         if (!IsAtLeastTLSv1_3(ssl->version)) {
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
-    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES));
+        #endif
+        #ifdef WOLFSSL_EARLY_DATA
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
+        #endif
+        #ifdef WOLFSSL_SEND_HRR_COOKIE
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
+        #endif
+        #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_POST_HANDSHAKE_AUTH));
+        #endif
+        }
     #endif
-    #ifdef WOLFSSL_EARLY_DATA
-            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
-    #endif
-            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
-    #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
-            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_POST_HANDSHAKE_AUTH));
-    #endif
-        }
 #endif
     #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
@@ -10299,6 +10475,7 @@
     #ifndef NO_CERTS
     else if (msgType == certificate_request) {
+        /* Don't send out any extension except those that are turned off. */
         XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-#if !defined(WOLFSSL_NO_SIGALG)
+#if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
 #endif
@@ -10353,5 +10530,5 @@
         WOLF_STK_VALIDATE_REQUEST(ssl);
         QSH_VALIDATE_REQUEST(ssl, semaphore);
-#if !defined(WOLFSSL_NO_SIGALG)
+#if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
         if (ssl->suites->hashSigAlgoSz == 0)
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
@@ -10360,17 +10537,21 @@
         if (!IsAtLeastTLSv1_2(ssl))
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+    #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS)
         if (!IsAtLeastTLSv1_3(ssl->version)) {
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
-    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES));
+        #endif
+        #ifdef WOLFSSL_EARLY_DATA
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
+        #endif
+        #ifdef WOLFSSL_SEND_HRR_COOKIE
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
+        #endif
+        #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_POST_HANDSHAKE_AUTH));
+        #endif
+        }
     #endif
-    #ifdef WOLFSSL_EARLY_DATA
-            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
-    #endif
-            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
-    #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
-            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_POST_HANDSHAKE_AUTH));
-    #endif
-        }
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
         /* Must write Pre-shared Key extension at the end in TLS v1.3.
@@ -10393,6 +10574,7 @@
     #ifndef NO_CERTS
     else if (msgType == certificate_request) {
+        /* Don't send out any extension except those that are turned off. */
         XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-#if !defined(WOLFSSL_NO_SIGALG)
+#if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
 #endif
@@ -10467,20 +10649,24 @@
                 if (IsAtLeastTLSv1_3(ssl->version)) {
                     XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-        #ifndef WOLFSSL_TLS13_DRAFT_18
                     TURN_OFF(semaphore,
                                      TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
-        #endif
+            #ifdef HAVE_SUPPORTED_CURVES
                     if (!ssl->options.noPskDheKe)
                         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+            #endif
         #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
                     TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
         #endif
                 }
+        #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS)
                 else {
+            #ifdef HAVE_SUPPORTED_CURVES
                     TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
-        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+            #endif
+            #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
                     TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+            #endif
+                }
         #endif
-                }
     #endif
             break;
@@ -10489,10 +10675,12 @@
         case hello_retry_request:
             XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-        #ifndef WOLFSSL_TLS13_DRAFT_18
                 TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
-        #endif
+        #ifdef HAVE_SUPPORTED_CURVES
             if (!ssl->options.noPskDheKe)
                 TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #endif
+        #ifdef WOLFSSL_SEND_HRR_COOKIE
             TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
+        #endif
             break;
     #endif
@@ -10500,8 +10688,15 @@
     #ifdef WOLFSSL_TLS13
         case encrypted_extensions:
+            /* Send out all extension except those that are turned on. */
+        #ifdef HAVE_ECC
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
+        #endif
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+        #ifdef HAVE_SESSION_TICKET
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
+        #endif
+        #ifdef HAVE_SUPPORTED_CURVES
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #endif
         #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
@@ -10509,4 +10704,7 @@
         #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+        #endif
+        #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST_V2));
         #endif
         #if defined(HAVE_SECURE_RENEGOTIATION)
@@ -10529,4 +10727,5 @@
     #ifndef NO_CERTS
         case certificate:
+            /* Don't send out any extension except those that are turned off. */
             XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
             TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
@@ -10587,20 +10786,24 @@
                 if (IsAtLeastTLSv1_3(ssl->version)) {
                     XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-        #ifndef WOLFSSL_TLS13_DRAFT_18
                     TURN_OFF(semaphore,
                                      TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
-        #endif
+            #ifdef HAVE_SUPPORTED_CURVES
                     if (!ssl->options.noPskDheKe)
                         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
-        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+            #endif
+            #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
                     TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+            #endif
+                }
+        #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS)
+                else {
+            #ifdef HAVE_SUPPORTED_CURVES
+                    TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+            #endif
+            #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+                    TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+            #endif
+                }
         #endif
-                }
-                else {
-                    TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
-        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
-                    TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
-        #endif
-                }
     #endif
                 break;
@@ -10609,9 +10812,9 @@
             case hello_retry_request:
                 XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-        #ifndef WOLFSSL_TLS13_DRAFT_18
                 TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
-        #endif
+        #ifdef HAVE_SUPPORTED_CURVES
                 if (!ssl->options.noPskDheKe)
                     TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #endif
                 /* Cookie is written below as last extension. */
                 break;
@@ -10620,8 +10823,15 @@
     #ifdef WOLFSSL_TLS13
             case encrypted_extensions:
+                /* Send out all extension except those that are turned on. */
+        #ifdef HAVE_ECC
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
+        #endif
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+        #ifdef HAVE_SESSION_TICKET
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
+        #endif
+        #ifdef HAVE_SUPPORTED_CURVES
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #endif
         #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
@@ -10630,4 +10840,7 @@
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
         #endif
+        #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST_V2));
+        #endif
         #if defined(HAVE_SECURE_RENEGOTIATION)
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_RENEGOTIATION_INFO));
@@ -10649,4 +10862,6 @@
         #ifndef NO_CERTS
             case certificate:
+                /* Don't send out any extension except those that are turned
+                 * off. */
                 XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
                 TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
@@ -10666,5 +10881,5 @@
             return ret;
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
         if (msgType == hello_retry_request) {
             XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
@@ -10785,4 +11000,5 @@
 
         switch (type) {
+#ifdef HAVE_SNI
             case TLSX_SERVER_NAME:
                 WOLFSSL_MSG("SNI extension received");
@@ -10791,5 +11007,5 @@
             #endif
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_SNI)
                 if (IsAtLeastTLSv1_3(ssl->version) &&
                         msgType != client_hello &&
@@ -10805,4 +11021,5 @@
                 ret = SNI_PARSE(ssl, input + offset, size, isRequest);
                 break;
+#endif
 
             case TLSX_TRUSTED_CA_KEYS:
@@ -10812,5 +11029,5 @@
             #endif
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_TRUSTED_CA)
                 if (IsAtLeastTLSv1_3(ssl->version) &&
                         msgType != client_hello &&
@@ -10828,5 +11045,5 @@
             #endif
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_MAX_FRAGMENT)
                 if (IsAtLeastTLSv1_3(ssl->version) &&
                         msgType != client_hello &&
@@ -10848,5 +11065,5 @@
             #endif
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_TRUNCATED_HMAC)
                 if (IsAtLeastTLSv1_3(ssl->version))
                     break;
@@ -10861,5 +11078,5 @@
             #endif
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)
                 if (IsAtLeastTLSv1_3(ssl->version) &&
                         msgType != client_hello &&
@@ -10882,5 +11099,5 @@
             #endif
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)
                 if (IsAtLeastTLSv1_3(ssl->version))
                     break;
@@ -10895,5 +11112,5 @@
             #endif
 
- #ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_CERTIFICATE_STATUS_REQUEST)
                 if (IsAtLeastTLSv1_3(ssl->version) &&
                         msgType != client_hello &&
@@ -10912,5 +11129,5 @@
             #endif
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
                 if (IsAtLeastTLSv1_3(ssl->version) &&
                         msgType != client_hello &&
@@ -10930,5 +11147,5 @@
             #endif
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13)
                 if (IsAtLeastTLSv1_3(ssl->version))
                     break;
@@ -10951,5 +11168,5 @@
             #endif
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_SECURE_RENEGOTIATION)
                 if (IsAtLeastTLSv1_3(ssl->version))
                     break;
@@ -10964,5 +11181,5 @@
             #endif
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
                 if (IsAtLeastTLSv1_3(ssl->version) &&
                         msgType != client_hello) {
@@ -10979,5 +11196,5 @@
             #endif
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_QSH)
                 if (IsAtLeastTLSv1_3(ssl->version))
                     break;
@@ -10993,5 +11210,5 @@
             #endif
 
-#ifdef WOLFSSL_TLS13
+#if defined(WOLFSSL_TLS13) && defined(HAVE_ALPN)
                 if (IsAtLeastTLSv1_3(ssl->version) &&
                         msgType != client_hello &&
@@ -11007,5 +11224,5 @@
                 ret = ALPN_PARSE(ssl, input + offset, size, isRequest);
                 break;
-#if !defined(WOLFSSL_NO_SIGALG)
+#if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
             case TLSX_SIGNATURE_ALGORITHMS:
                 WOLFSSL_MSG("Signature Algorithms extension received");
@@ -11016,5 +11233,5 @@
                 if (!IsAtLeastTLSv1_2(ssl))
                     break;
-#ifdef WOLFSSL_TLS13
+            #ifdef WOLFSSL_TLS13
                 if (IsAtLeastTLSv1_3(ssl->version) &&
                         msgType != client_hello &&
@@ -11022,5 +11239,5 @@
                     return EXT_NOT_ALLOWED;
                 }
-#endif
+            #endif
                 ret = SA_PARSE(ssl, input + offset, size, isRequest, suites);
                 break;
@@ -11048,4 +11265,5 @@
                 break;
 
+    #ifdef WOLFSSL_SEND_HRR_COOKIE
             case TLSX_COOKIE:
                 WOLFSSL_MSG("Cookie extension received");
@@ -11064,4 +11282,5 @@
                 ret = CKE_PARSE(ssl, input + offset, size, msgType);
                 break;
+    #endif
 
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
@@ -11138,5 +11357,5 @@
     #endif
 
-    #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+    #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG)
             case TLSX_SIGNATURE_ALGORITHMS_CERT:
                 WOLFSSL_MSG("Signature Algorithms extension received");
@@ -11167,4 +11386,5 @@
             #endif
 
+    #ifdef HAVE_SUPPORTED_CURVES
                 if (!IsAtLeastTLSv1_3(ssl->version))
                     break;
@@ -11174,4 +11394,6 @@
                     return EXT_NOT_ALLOWED;
                 }
+    #endif
+
                 ret = KS_PARSE(ssl, input + offset, size, msgType);
                 break;
@@ -11632,4 +11854,5 @@
 
 #ifndef WOLFSSL_NO_TLS12
+    WOLFSSL_ABI
     WOLFSSL_METHOD* wolfTLSv1_2_server_method(void)
     {
@@ -11656,4 +11879,5 @@
      * returns the method data for a TLS v1.3 server.
      */
+    WOLFSSL_ABI
     WOLFSSL_METHOD* wolfTLSv1_3_server_method(void)
     {
Index: azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/tls13.c
===================================================================
--- azure_iot_hub_f767zi/trunk/wolfssl-4.4.0/src/tls13.c	(revision 457)
+++ azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/tls13.c	(revision 464)
@@ -30,7 +30,6 @@
  * NO_PSK
  *    Do not enable Pre-Shared Keys.
- * TLS13_SUPPORTS_EXPORTERS
- *    Guard to compile out any code for exporter keys.
- *    Feature not supported yet.
+ * HAVE_KEYING_MATERIAL
+ *    Enables exporting keying material based on section 7.5 of RFC 8446.
  * WOLFSSL_ASYNC_CRYPT
  *    Enables the use of asynchronous cryptographic operations.
@@ -56,10 +55,4 @@
  * WOLFSSL_TLS13
  *    Enable TLS 1.3 protocol implementation.
- * WOLFSSL_TLS13_DRAFT_18
- *    Conform with Draft 18 of the TLS v1.3 specification.
- * WOLFSSL_TLS13_DRAFT_22
- *    Conform with Draft 22 of the TLS v1.3 specification.
- * WOLFSSL_TLS13_DRAFT_23
- *    Conform with Draft 23 of the TLS v1.3 specification.
  * WOLFSSL_TLS13_MIDDLEBOX_COMPAT
  *    Enable middlebox compatibility in the TLS 1.3 handshake.
@@ -119,5 +112,9 @@
 
 #ifndef HAVE_HKDF
-    #error The build option HAVE_HKDF is required for TLS 1.3
+    #ifndef _MSC_VER
+        #error "The build option HAVE_HKDF is required for TLS 1.3"
+    #else
+        #pragma message("error: The build option HAVE_HKDF is required for TLS 1.3")
+    #endif
 #endif
 
@@ -264,18 +261,9 @@
 }
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* Size of the TLS v1.3 label use when deriving keys. */
-#define TLS13_PROTOCOL_LABEL_SZ    9
-/* The protocol label for TLS v1.3. */
-static const byte tls13ProtocolLabel[TLS13_PROTOCOL_LABEL_SZ + 1] = "TLS 1.3, ";
-#else
 /* Size of the TLS v1.3 label use when deriving keys. */
 #define TLS13_PROTOCOL_LABEL_SZ    6
 /* The protocol label for TLS v1.3. */
 static const byte tls13ProtocolLabel[TLS13_PROTOCOL_LABEL_SZ + 1] = "tls13 ";
-#endif
-
-#if !defined(WOLFSSL_TLS13_DRAFT_18) || defined(HAVE_SESSION_TICKET) || \
-                                        !defined(NO_PSK)
+
 /* Derive a key from a message.
  *
@@ -370,5 +358,4 @@
                              hash, hashSz, digestAlg);
 }
-#endif
 
 /* Derive a key.
@@ -442,11 +429,4 @@
 
 #ifndef NO_PSK
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* The length of the binder key label. */
-#define BINDER_KEY_LABEL_SZ         23
-/* The binder key label. */
-static const byte binderKeyLabel[BINDER_KEY_LABEL_SZ + 1] =
-    "external psk binder key";
-#else
 /* The length of the binder key label. */
 #define BINDER_KEY_LABEL_SZ         10
@@ -454,5 +434,5 @@
 static const byte binderKeyLabel[BINDER_KEY_LABEL_SZ + 1] =
     "ext binder";
-#endif
+
 /* Derive the binder key.
  *
@@ -464,4 +444,7 @@
 {
     WOLFSSL_MSG("Derive Binder Key");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     return DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret,
                         binderKeyLabel, BINDER_KEY_LABEL_SZ,
@@ -471,11 +454,5 @@
 
 #ifdef HAVE_SESSION_TICKET
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* The length of the binder key resume label. */
-#define BINDER_KEY_RESUME_LABEL_SZ  25
-/* The binder key resume label. */
-static const byte binderKeyResumeLabel[BINDER_KEY_RESUME_LABEL_SZ + 1] =
-    "resumption psk binder key";
-#else
+
 /* The length of the binder key resume label. */
 #define BINDER_KEY_RESUME_LABEL_SZ  10
@@ -483,5 +460,5 @@
 static const byte binderKeyResumeLabel[BINDER_KEY_RESUME_LABEL_SZ + 1] =
     "res binder";
-#endif
+
 /* Derive the binder resumption key.
  *
@@ -493,4 +470,7 @@
 {
     WOLFSSL_MSG("Derive Binder Key - Resumption");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     return DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret,
                         binderKeyResumeLabel, BINDER_KEY_RESUME_LABEL_SZ,
@@ -500,11 +480,5 @@
 
 #ifdef WOLFSSL_EARLY_DATA
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* The length of the early traffic label. */
-#define EARLY_TRAFFIC_LABEL_SZ      27
-/* The early traffic label. */
-static const byte earlyTrafficLabel[EARLY_TRAFFIC_LABEL_SZ + 1] =
-    "client early traffic secret";
-#else
+
 /* The length of the early traffic label. */
 #define EARLY_TRAFFIC_LABEL_SZ      11
@@ -512,5 +486,5 @@
 static const byte earlyTrafficLabel[EARLY_TRAFFIC_LABEL_SZ + 1] =
     "c e traffic";
-#endif
+
 /* Derive the early traffic key.
  *
@@ -523,4 +497,7 @@
     int ret;
     WOLFSSL_MSG("Derive Early Traffic Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->secret,
                     earlyTrafficLabel, EARLY_TRAFFIC_LABEL_SZ,
@@ -538,12 +515,5 @@
 }
 
-#ifdef TLS13_SUPPORTS_EXPORTERS
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* The length of the early exporter label. */
-#define EARLY_EXPORTER_LABEL_SZ     28
-/* The early exporter label. */
-static const byte earlyExporterLabel[EARLY_EXPORTER_LABEL_SZ + 1] =
-    "early exporter master secret";
-#else
+#ifdef HAVE_KEYING_MATERIAL
 /* The length of the early exporter label. */
 #define EARLY_EXPORTER_LABEL_SZ     12
@@ -551,5 +521,5 @@
 static const byte earlyExporterLabel[EARLY_EXPORTER_LABEL_SZ + 1] =
     "e exp master";
-#endif
+
 /* Derive the early exporter key.
  *
@@ -562,4 +532,7 @@
     int ret;
     WOLFSSL_MSG("Derive Early Exporter Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->secret,
                     earlyExporterLabel, EARLY_EXPORTER_LABEL_SZ,
@@ -579,11 +552,4 @@
 #endif
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* The length of the client handshake label. */
-#define CLIENT_HANDSHAKE_LABEL_SZ   31
-/* The client handshake label. */
-static const byte clientHandshakeLabel[CLIENT_HANDSHAKE_LABEL_SZ + 1] =
-    "client handshake traffic secret";
-#else
 /* The length of the client handshake label. */
 #define CLIENT_HANDSHAKE_LABEL_SZ   12
@@ -591,5 +557,5 @@
 static const byte clientHandshakeLabel[CLIENT_HANDSHAKE_LABEL_SZ + 1] =
     "c hs traffic";
-#endif
+
 /* Derive the client handshake key.
  *
@@ -602,4 +568,7 @@
     int ret;
     WOLFSSL_MSG("Derive Client Handshake Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret,
                     clientHandshakeLabel, CLIENT_HANDSHAKE_LABEL_SZ,
@@ -617,11 +586,4 @@
 }
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* The length of the server handshake label. */
-#define SERVER_HANDSHAKE_LABEL_SZ   31
-/* The server handshake label. */
-static const byte serverHandshakeLabel[SERVER_HANDSHAKE_LABEL_SZ + 1] =
-    "server handshake traffic secret";
-#else
 /* The length of the server handshake label. */
 #define SERVER_HANDSHAKE_LABEL_SZ   12
@@ -629,5 +591,5 @@
 static const byte serverHandshakeLabel[SERVER_HANDSHAKE_LABEL_SZ + 1] =
     "s hs traffic";
-#endif
+
 /* Derive the server handshake key.
  *
@@ -640,4 +602,7 @@
     int ret;
     WOLFSSL_MSG("Derive Server Handshake Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret,
                     serverHandshakeLabel, SERVER_HANDSHAKE_LABEL_SZ,
@@ -655,11 +620,4 @@
 }
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* The length of the client application traffic label. */
-#define CLIENT_APP_LABEL_SZ         33
-/* The client application traffic label. */
-static const byte clientAppLabel[CLIENT_APP_LABEL_SZ + 1] =
-    "client application traffic secret";
-#else
 /* The length of the client application traffic label. */
 #define CLIENT_APP_LABEL_SZ         12
@@ -667,5 +625,5 @@
 static const byte clientAppLabel[CLIENT_APP_LABEL_SZ + 1] =
     "c ap traffic";
-#endif
+
 /* Derive the client application traffic key.
  *
@@ -678,4 +636,7 @@
     int ret;
     WOLFSSL_MSG("Derive Client Traffic Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret,
                     clientAppLabel, CLIENT_APP_LABEL_SZ,
@@ -693,11 +654,4 @@
 }
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* The length of the server application traffic label. */
-#define SERVER_APP_LABEL_SZ         33
-/* The  server application traffic label. */
-static const byte serverAppLabel[SERVER_APP_LABEL_SZ + 1] =
-    "server application traffic secret";
-#else
 /* The length of the server application traffic label. */
 #define SERVER_APP_LABEL_SZ         12
@@ -705,5 +659,5 @@
 static const byte serverAppLabel[SERVER_APP_LABEL_SZ + 1] =
     "s ap traffic";
-#endif
+
 /* Derive the server application traffic key.
  *
@@ -716,4 +670,7 @@
     int ret;
     WOLFSSL_MSG("Derive Server Traffic Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret,
                     serverAppLabel, SERVER_APP_LABEL_SZ,
@@ -731,12 +688,5 @@
 }
 
-#ifdef TLS13_SUPPORTS_EXPORTERS
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* The length of the exporter master secret label. */
-#define EXPORTER_MASTER_LABEL_SZ    22
-/* The exporter master secret label. */
-static const byte exporterMasterLabel[EXPORTER_MASTER_LABEL_SZ + 1] =
-    "exporter master secret";
-#else
+#ifdef HAVE_KEYING_MATERIAL
 /* The length of the exporter master secret label. */
 #define EXPORTER_MASTER_LABEL_SZ    10
@@ -744,5 +694,5 @@
 static const byte exporterMasterLabel[EXPORTER_MASTER_LABEL_SZ + 1] =
     "exp master";
-#endif
+
 /* Derive the exporter secret.
  *
@@ -754,5 +704,8 @@
 {
     int ret;
-    WOLFSSL_MSG("Derive Exporter Secret");
+    WOLFSSL_ENTER("Derive Exporter Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret,
                     exporterMasterLabel, EXPORTER_MASTER_LABEL_SZ,
@@ -769,14 +722,105 @@
     return ret;
 }
+
+/* The length of the exporter label. */
+#define EXPORTER_LABEL_SZ    8
+/* The exporter label. */
+static const byte exporterLabel[EXPORTER_LABEL_SZ + 1] =
+    "exporter";
+/* Hash("") */
+#ifndef NO_SHA256
+static const byte emptySHA256Hash[] = {
+    0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8,
+    0x99, 0x6F, 0xB9, 0x24, 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C,
+    0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55
+};
+#endif
+#ifdef WOLFSSL_SHA384
+static const byte emptySHA384Hash[] = {
+    0x38, 0xB0, 0x60, 0xA7, 0x51, 0xAC, 0x96, 0x38, 0x4C, 0xD9, 0x32, 0x7E,
+    0xB1, 0xB1, 0xE3, 0x6A, 0x21, 0xFD, 0xB7, 0x11, 0x14, 0xBE, 0x07, 0x43,
+    0x4C, 0x0C, 0xC7, 0xBF, 0x63, 0xF6, 0xE1, 0xDA, 0x27, 0x4E, 0xDE, 0xBF,
+    0xE7, 0x6F, 0x65, 0xFB, 0xD5, 0x1A, 0xD2, 0xF1, 0x48, 0x98, 0xB9, 0x5B
+};
+#endif
+#ifdef WOLFSSL_TLS13_SHA512
+static const byte emptySHA512Hash[] = {
+    0xCF, 0x83, 0xE1, 0x35, 0x7E, 0xEF, 0xB8, 0xBD, 0xF1, 0x54, 0x28, 0x50,
+    0xD6, 0x6D, 0x80, 0x07, 0xD6, 0x20, 0xE4, 0x05, 0x0B, 0x57, 0x15, 0xDC,
+    0x83, 0xF4, 0xA9, 0x21, 0xD3, 0x6C, 0xE9, 0xCE, 0x47, 0xD0, 0xD1, 0x3C,
+    0x5D, 0x85, 0xF2, 0xB0, 0xFF, 0x83, 0x18, 0xD2, 0x87, 0x7E, 0xEC, 0x2F,
+    0x63, 0xB9, 0x31, 0xBD, 0x47, 0x41, 0x7A, 0x81, 0xA5, 0x38, 0x32, 0x7A,
+    0xF9, 0x27, 0xDA, 0x3E
+};
+#endif
+/**
+ * Implement section 7.5 of RFC 8446
+ * @return  0 on success
+ *         <0 on failure
+ */
+int Tls13_Exporter(WOLFSSL* ssl, unsigned char *out, size_t outLen,
+        const char *label, size_t labelLen,
+        const unsigned char *context, size_t contextLen)
+{
+    int                 ret;
+    enum wc_HashType    hashType = WC_HASH_TYPE_NONE;
+    int                 hashLen = 0;
+    byte                hashOut[WC_MAX_DIGEST_SIZE];
+    const byte*         emptyHash = NULL;
+    byte                firstExpand[WC_MAX_DIGEST_SIZE];
+    const byte*         protocol = tls13ProtocolLabel;
+    word32              protocolLen = TLS13_PROTOCOL_LABEL_SZ;
+
+    if (ssl->version.minor != TLSv1_3_MINOR)
+        return VERSION_ERROR;
+
+    switch (ssl->specs.mac_algorithm) {
+        #ifndef NO_SHA256
+        case sha256_mac:
+            hashType  = WC_HASH_TYPE_SHA256;
+            hashLen   = WC_SHA256_DIGEST_SIZE;
+            emptyHash = emptySHA256Hash;
+            break;
+        #endif
+
+        #ifdef WOLFSSL_SHA384
+        case sha384_mac:
+            hashType  = WC_HASH_TYPE_SHA384;
+            hashLen   = WC_SHA384_DIGEST_SIZE;
+            emptyHash = emptySHA384Hash;
+            break;
+        #endif
+
+        #ifdef WOLFSSL_TLS13_SHA512
+        case sha512_mac:
+            hashType  = WC_HASH_TYPE_SHA512;
+            hashLen   = WC_SHA512_DIGEST_SIZE;
+            emptyHash = emptySHA512Hash;
+            break;
+        #endif
+    }
+
+    /* Derive-Secret(Secret, label, "") */
+    ret = HKDF_Expand_Label(firstExpand, hashLen,
+            ssl->arrays->exporterSecret, hashLen,
+            protocol, protocolLen, (byte*)label, (word32)labelLen,
+            emptyHash, hashLen, hashType);
+    if (ret != 0)
+        return ret;
+
+    /* Hash(context_value) */
+    ret = wc_Hash(hashType, context, (word32)contextLen, hashOut, WC_MAX_DIGEST_SIZE);
+    if (ret != 0)
+        return ret;
+
+    ret = HKDF_Expand_Label(out, (word32)outLen, firstExpand, hashLen,
+            protocol, protocolLen, exporterLabel, EXPORTER_LABEL_SZ,
+            hashOut, hashLen, hashType);
+
+    return ret;
+}
 #endif
 
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* The length of the resumption master secret label. */
-#define RESUME_MASTER_LABEL_SZ      24
-/* The resumption master secret label. */
-static const byte resumeMasterLabel[RESUME_MASTER_LABEL_SZ + 1] =
-    "resumption master secret";
-#else
 /* The length of the resumption master secret label. */
 #define RESUME_MASTER_LABEL_SZ      10
@@ -784,5 +828,5 @@
 static const byte resumeMasterLabel[RESUME_MASTER_LABEL_SZ + 1] =
     "res master";
-#endif
+
 /* Derive the resumption secret.
  *
@@ -791,10 +835,20 @@
  * returns 0 on success, otherwise failure.
  */
-static int DeriveResumptionSecret(WOLFSSL* ssl, byte* key)
-{
+int DeriveResumptionSecret(WOLFSSL* ssl, byte* key)
+{
+    byte* masterSecret;
+
     WOLFSSL_MSG("Derive Resumption Secret");
-    return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret,
-                     resumeMasterLabel, RESUME_MASTER_LABEL_SZ,
-                     ssl->specs.mac_algorithm, 1);
+    if (ssl == NULL) {
+        return BAD_FUNC_ARG;
+    }
+    if (ssl->arrays != NULL) {
+        masterSecret = ssl->arrays->masterSecret;
+    }
+    else {
+        masterSecret = ssl->session.masterSecret;
+    }
+    return DeriveKey(ssl, key, -1, masterSecret, resumeMasterLabel,
+                     RESUME_MASTER_LABEL_SZ, ssl->specs.mac_algorithm, 1);
 }
 #endif
@@ -818,11 +872,4 @@
 }
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* The length of the application traffic label. */
-#define APP_TRAFFIC_LABEL_SZ        26
-/* The application traffic label. */
-static const byte appTrafficLabel[APP_TRAFFIC_LABEL_SZ + 1] =
-    "application traffic secret";
-#else
 /* The length of the application traffic label. */
 #define APP_TRAFFIC_LABEL_SZ        11
@@ -830,5 +877,5 @@
 static const byte appTrafficLabel[APP_TRAFFIC_LABEL_SZ + 1] =
     "traffic upd";
-#endif
+
 /* Update the traffic secret.
  *
@@ -849,7 +896,10 @@
  * ssl  The SSL/TLS object.
  */
-static int DeriveEarlySecret(WOLFSSL* ssl)
+int DeriveEarlySecret(WOLFSSL* ssl)
 {
     WOLFSSL_MSG("Derive Early Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
     return Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0,
@@ -862,5 +912,4 @@
 }
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
 /* The length of the derived label. */
 #define DERIVED_LABEL_SZ        7
@@ -868,23 +917,17 @@
 static const byte derivedLabel[DERIVED_LABEL_SZ + 1] =
     "derived";
-#endif
+
 /* Derive the handshake secret using HKDF Extract.
  *
  * ssl  The SSL/TLS object.
  */
-static int DeriveHandshakeSecret(WOLFSSL* ssl)
-{
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    WOLFSSL_MSG("Derive Handshake Secret");
-    return Tls13_HKDF_Extract(ssl->arrays->preMasterSecret,
-            ssl->arrays->secret, ssl->specs.hash_size,
-            ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz,
-            ssl->specs.mac_algorithm);
-#else
+int DeriveHandshakeSecret(WOLFSSL* ssl)
+{
     byte key[WC_MAX_DIGEST_SIZE];
     int ret;
-
     WOLFSSL_MSG("Derive Handshake Secret");
-
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret,
                         derivedLabel, DERIVED_LABEL_SZ,
@@ -897,5 +940,4 @@
             ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz,
             ssl->specs.mac_algorithm);
-#endif
 }
 
@@ -904,17 +946,12 @@
  * ssl  The SSL/TLS object.
  */
-static int DeriveMasterSecret(WOLFSSL* ssl)
-{
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    WOLFSSL_MSG("Derive Master Secret");
-    return Tls13_HKDF_Extract(ssl->arrays->masterSecret,
-            ssl->arrays->preMasterSecret, ssl->specs.hash_size,
-            ssl->arrays->masterSecret, 0, ssl->specs.mac_algorithm);
-#else
+int DeriveMasterSecret(WOLFSSL* ssl)
+{
     byte key[WC_MAX_DIGEST_SIZE];
     int ret;
-
     WOLFSSL_MSG("Derive Master Secret");
-
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKeyMsg(ssl, key, -1, ssl->arrays->preMasterSecret,
                         derivedLabel, DERIVED_LABEL_SZ,
@@ -923,11 +960,19 @@
         return ret;
 
-    return Tls13_HKDF_Extract(ssl->arrays->masterSecret,
+    ret = Tls13_HKDF_Extract(ssl->arrays->masterSecret,
             key, ssl->specs.hash_size,
             ssl->arrays->masterSecret, 0, ssl->specs.mac_algorithm);
-#endif
-}
-
-#ifndef WOLFSSL_TLS13_DRAFT_18
+
+#ifdef HAVE_KEYING_MATERIAL
+    if (ret != 0)
+        return ret;
+    /* Calculate exporter secret only when saving arrays */
+    if (ssl->options.saveArrays)
+        ret = DeriveExporterSecret(ssl, ssl->arrays->exporterSecret);
+#endif
+
+    return ret;
+}
+
 #if defined(HAVE_SESSION_TICKET)
 /* Length of the resumption label. */
@@ -943,6 +988,5 @@
  * returns 0 on success, otherwise failure.
  */
-static int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen,
-                               byte* secret)
+int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, byte* secret)
 {
     int         digestAlg;
@@ -982,5 +1026,4 @@
 }
 #endif /* HAVE_SESSION_TICKET */
-#endif /* WOLFSSL_TLS13_DRAFT_18 */
 
 
@@ -999,4 +1042,8 @@
     int  hashSz = WC_SHA256_DIGEST_SIZE;
     int  ret = BAD_FUNC_ARG;
+
+    if (ssl == NULL || key == NULL || hash == NULL) {
+        return BAD_FUNC_ARG;
+    }
 
     /* Get the hash of the previous handshake messages. */
@@ -1071,5 +1118,5 @@
  * returns 0 on success, otherwise failure.
  */
-static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store)
+int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store)
 {
     int   ret = BAD_FUNC_ARG; /* Assume failure */
@@ -1282,6 +1329,6 @@
     word32 TimeNowInMilliseconds(void)
     {
-        const uint32_t systemTickTimeInHz = 1000000 / systemTickInMicroseconds();
-        uint32_t *systemTickPtr = systemTickPointer();
+        const word32 systemTickTimeInHz = 1000000 / systemTickInMicroseconds();
+        word32 *systemTickPtr = systemTickPointer();
 
         return (word32) (*systemTickPtr/systemTickTimeInHz) * 1000;
@@ -1407,4 +1454,36 @@
         return (word32)(uTaskerSystemTick / (TICK_RESOLUTION / 1000));
     }
+#elif defined(WOLFSSL_LINUXKM)
+    /* The time in milliseconds.
+     * Used for tickets to represent difference between when first seen and when
+     * sending.
+     *
+     * returns the time in milliseconds as a 32-bit value.
+     */
+    word32 TimeNowInMilliseconds(void)
+    {
+    #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
+        return (word32)(ktime_get_real_ns() / (s64)1000000);
+    #else
+        return (word32)(ktime_get_real_ns() / (ktime_t)1000000);
+    #endif
+    }
+#elif defined(FUSION_RTOS)
+    /* The time in milliseconds.
+     * Used for tickets to represent difference between when first seen and when
+     * sending.
+     *
+     * returns the time in milliseconds as a 32-bit value.
+     */
+    word32 TimeNowInMilliseconds(void)
+    {
+        struct timeval now;
+        if (FCL_GETTIMEOFDAY(&now, 0) < 0)
+            return (word32)GETTIME_ERROR; /* TODO: return 0 for failure */
+
+        /* Convert to milliseconds number. */
+        return (word32)(now.tv_sec * 1000 + now.tv_usec / 1000);
+    }
+
 #else
     /* The time in milliseconds.
@@ -1419,5 +1498,6 @@
 
         if (gettimeofday(&now, 0) < 0)
-            return GETTIME_ERROR;
+            return (word32)GETTIME_ERROR; /* TODO: return 0 for failure */
+
         /* Convert to milliseconds number. */
         return (word32)(now.tv_sec * 1000 + now.tv_usec / 1000);
@@ -1426,37 +1506,4 @@
 #endif /* HAVE_SESSION_TICKET || !NO_PSK */
 
-
-#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_SESSION_TICKET) || \
-                                    !defined(NO_PSK))
-/* Add input to all handshake hashes.
- *
- * ssl    The SSL/TLS object.
- * input  The data to hash.
- * sz     The size of the data to hash.
- * returns 0 on success, otherwise failure.
- */
-static int HashInputRaw(WOLFSSL* ssl, const byte* input, int sz)
-{
-    int ret = BAD_FUNC_ARG;
-
-#ifndef NO_SHA256
-    ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, input, sz);
-    if (ret != 0)
-        return ret;
-#endif
-#ifdef WOLFSSL_SHA384
-    ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, input, sz);
-    if (ret != 0)
-        return ret;
-#endif
-#ifdef WOLFSSL_TLS13_SHA512
-    ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, input, sz);
-    if (ret != 0)
-        return ret;
-#endif
-
-    return ret;
-}
-#endif
 
 /* Extract the handshake header information.
@@ -1502,10 +1549,6 @@
     rl->type    = type;
     rl->pvMajor = ssl->version.major;
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    rl->pvMinor = TLSv1_MINOR;
-#else
     /* NOTE: May be TLSv1_MINOR when sending first ClientHello. */
     rl->pvMinor = TLSv1_2_MINOR;
-#endif
     c16toa((word16)length, rl->length);
 }
@@ -1584,5 +1627,5 @@
  * out          The buffer to write into.
  */
-static WC_INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
+static WC_INLINE void WriteSEQTls13(WOLFSSL* ssl, int verifyOrder, byte* out)
 {
     word32 seq[2] = {0, 0};
@@ -1620,5 +1663,5 @@
 
     /* The nonce is the IV with the sequence XORed into the last bytes. */
-    WriteSEQ(ssl, order, nonce + AEAD_NONCE_SZ - SEQ_SZ);
+    WriteSEQTls13(ssl, order, nonce + AEAD_NONCE_SZ - SEQ_SZ);
     for (i = 0; i < AEAD_NONCE_SZ - SEQ_SZ; i++)
         nonce[i] = iv[i];
@@ -1628,5 +1671,5 @@
 
 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
-/* Encrypt with ChaCha20 and create authenication tag with Poly1305.
+/* Encrypt with ChaCha20 and create authentication tag with Poly1305.
  *
  * ssl     The SSL/TLS object.
@@ -1683,5 +1726,5 @@
 
 #ifdef HAVE_NULL_CIPHER
-/* Create authenication tag and copy data over input.
+/* Create authentication tag and copy data over input.
  *
  * ssl     The SSL/TLS object.
@@ -1765,9 +1808,6 @@
             WOLFSSL_MSG("Data to encrypt");
             WOLFSSL_BUFFER(input, dataSz);
-#if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) && \
-                                        !defined(WOLFSSL_TLS13_DRAFT_23)
             WOLFSSL_MSG("Additional Authentication Data");
             WOLFSSL_BUFFER(aad, aadSz);
-#endif
         #endif
 
@@ -1912,5 +1952,5 @@
 
 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
-/* Decrypt with ChaCha20 and check authenication tag with Poly1305.
+/* Decrypt with ChaCha20 and check authentication tag with Poly1305.
  *
  * ssl     The SSL/TLS object.
@@ -2068,9 +2108,6 @@
             WOLFSSL_MSG("Data to decrypt");
             WOLFSSL_BUFFER(input, dataSz);
-#if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) && \
-                                        !defined(WOLFSSL_TLS13_DRAFT_23)
             WOLFSSL_MSG("Additional Authentication Data");
             WOLFSSL_BUFFER(aad, aadSz);
-#endif
             WOLFSSL_MSG("Authentication tag");
             WOLFSSL_BUFFER(input + dataSz, macSz);
@@ -2351,15 +2388,8 @@
         #endif
             {
-#if defined(WOLFSSL_TLS13_DRAFT_18) || defined(WOLFSSL_TLS13_DRAFT_22) || \
-                                       defined(WOLFSSL_TLS13_DRAFT_23)
-                output += args->headerSz;
-                ret = EncryptTls13(ssl, output, output, args->size, NULL, 0,
-                                                                     asyncOkay);
-#else
                 const byte* aad = output;
                 output += args->headerSz;
                 ret = EncryptTls13(ssl, output, output, args->size, aad,
                                    RECORD_HEADER_SZ, asyncOkay);
-#endif
             }
             break;
@@ -2415,5 +2445,4 @@
 #endif
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
 #if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER)
 /* Create Cookie extension using the hash of the first ClientHello.
@@ -2462,5 +2491,5 @@
  * returns 0 on success, otherwise failure.
  */
-static int RestartHandshakeHash(WOLFSSL* ssl)
+int RestartHandshakeHash(WOLFSSL* ssl)
 {
     int    ret;
@@ -2526,8 +2555,8 @@
     if (ret != 0)
         return ret;
-    ret = HashOutputRaw(ssl, header, sizeof(header));
+    ret = HashRaw(ssl, header, sizeof(header));
     if (ret != 0)
         return ret;
-    return HashOutputRaw(ssl, hash, hashSz);
+    return HashRaw(ssl, hash, hashSz);
 }
 
@@ -2541,5 +2570,5 @@
     0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C
 };
-#endif /* WOLFSSL_TLS13_DRAFT_18 */
+
 
 #ifndef NO_WOLFSSL_CLIENT
@@ -2578,13 +2607,8 @@
         /* Resumption PSK is master secret. */
         ssl->arrays->psk_keySz = ssl->specs.hash_size;
-#ifdef WOLFSSL_TLS13_DRAFT_18
-        XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret,
-                ssl->arrays->psk_keySz);
-#else
         if ((ret = DeriveResumptionPSK(ssl, ssl->session.ticketNonce.data,
                     ssl->session.ticketNonce.len, ssl->arrays->psk_key)) != 0) {
             return ret;
         }
-#endif
     }
 #endif
@@ -2594,4 +2618,5 @@
         const char* cipherName = NULL;
         byte cipherSuite0 = TLS13_BYTE, cipherSuite = WOLFSSL_DEF_PSK_CIPHER;
+        int cipherSuiteFlags = WOLFSSL_CIPHER_SUITE_FLAG_NONE;
 
         /* Get the pre-shared key. */
@@ -2602,5 +2627,5 @@
                     &cipherName);
             if (GetCipherSuiteFromName(cipherName, &cipherSuite0,
-                                                           &cipherSuite) != 0) {
+                                       &cipherSuite, &cipherSuiteFlags) != 0) {
                 return PSK_KEY_ERROR;
             }
@@ -2620,4 +2645,5 @@
             return PSK_KEY_ERROR;
         }
+        (void)cipherSuiteFlags;
     #else
         /* PSK information loaded during setting of default TLS extensions. */
@@ -2626,6 +2652,7 @@
 #endif
 
-    if (ssl->options.noPskDheKe)
+    if (ssl->options.noPskDheKe) {
         ssl->arrays->preMasterSz = 0;
+    }
 
     /* Derive the early secret using the PSK. */
@@ -2707,5 +2734,5 @@
 
     /* Hash binders to complete the hash of the ClientHello. */
-    ret = HashOutputRaw(ssl, output + idx, len);
+    ret = HashRaw(ssl, output + idx, len);
     if (ret < 0)
         return ret;
@@ -2778,5 +2805,4 @@
     length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->suites->suiteSz +
              SUITE_LEN + COMP_LEN + ENUM_LEN;
-#ifndef WOLFSSL_TLS13_DRAFT_18
     #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
     length += ID_LEN;
@@ -2785,5 +2811,4 @@
         length += ssl->session.sessionIDSz;
     #endif
-#endif
 
     /* Auto populate extensions supported unless user defined. */
@@ -2846,8 +2871,4 @@
     idx += RAN_LEN;
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    /* TLS v1.3 does not use session id - 0 length. */
-    output[idx++] = 0;
-#else
     if (ssl->session.sessionIDSz > 0) {
         /* Session resumption for old versions of protocol. */
@@ -2866,5 +2887,4 @@
     #endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */
     }
-#endif /* WOLFSSL_TLS13_DRAFT_18 */
 
     /* Cipher suites */
@@ -2921,73 +2941,4 @@
 }
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* handle rocessing of TLS 1.3 hello_retry_request (6) */
-/* Parse and handle a HelloRetryRequest message.
- * Only a client will receive this message.
- *
- * ssl       The SSL/TLS object.
- * input     The message buffer.
- * inOutIdx  On entry, the index into the message buffer of
- *           HelloRetryRequest.
- *           On exit, the index of byte after the HelloRetryRequest message.
- * totalSz   The length of the current handshake message.
- * returns 0 on success and otherwise failure.
- */
-static int DoTls13HelloRetryRequest(WOLFSSL* ssl, const byte* input,
-                                    word32* inOutIdx, word32 totalSz)
-{
-    int             ret;
-    word32          begin = *inOutIdx;
-    word32          i = begin;
-    word16          totalExtSz;
-    ProtocolVersion pv;
-
-    WOLFSSL_ENTER("DoTls13HelloRetryRequest");
-
-#ifdef WOLFSSL_CALLBACKS
-    if (ssl->hsInfoOn) AddPacketName(ssl, "HelloRetryRequest");
-    if (ssl->toInfoOn) AddLateName("HelloRetryRequest", &ssl->timeoutInfo);
-#endif
-
-    /* Version info and length field of extension data. */
-    if (totalSz < i - begin + OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN)
-        return BUFFER_ERROR;
-
-    /* Protocol version. */
-    XMEMCPY(&pv, input + i, OPAQUE16_LEN);
-    i += OPAQUE16_LEN;
-    ret = CheckVersion(ssl, pv);
-    if (ret != 0)
-        return ret;
-
-    /* Length of extension data. */
-    ato16(&input[i], &totalExtSz);
-    i += OPAQUE16_LEN;
-    if (totalExtSz == 0) {
-        WOLFSSL_MSG("HelloRetryRequest must contain extensions");
-        return MISSING_HANDSHAKE_DATA;
-    }
-
-    /* Extension data. */
-    if (i - begin + totalExtSz > totalSz)
-        return BUFFER_ERROR;
-    if ((ret = TLSX_Parse(ssl, (byte *)(input + i), totalExtSz,
-                          hello_retry_request, NULL)) != 0)
-        return ret;
-    /* The KeyShare extension parsing fails when not valid. */
-
-    /* Move index to byte after message. */
-    *inOutIdx = i + totalExtSz;
-
-    ssl->options.tls1_3 = 1;
-    ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE;
-
-    WOLFSSL_LEAVE("DoTls13HelloRetryRequest", ret);
-
-    return ret;
-}
-#endif
-
-
 /* handle processing of TLS 1.3 server_hello (2) and hello_retry_request (6) */
 /* Handle the ServerHello message from the server.
@@ -3008,10 +2959,8 @@
     word32          begin = i;
     int             ret;
-#ifndef WOLFSSL_TLS13_DRAFT_18
     byte            sessIdSz;
     const byte*     sessId;
     byte            b;
     int             foundVersion;
-#endif
     word16          totalExtSz;
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
@@ -3023,4 +2972,7 @@
     WOLFSSL_ENTER("DoTls13ServerHello");
 
+    if (ssl->arrays == NULL)
+        return BAD_FUNC_ARG;
+
 #ifdef WOLFSSL_CALLBACKS
     if (ssl->hsInfoOn) AddPacketName(ssl, "ServerHello");
@@ -3028,4 +2980,7 @@
 #endif
 
+    if (ssl == NULL || ssl->arrays == NULL)
+        return BAD_FUNC_ARG;
+
     /* Protocol version length check. */
     if (OPAQUE16_LEN > helloSz)
@@ -3035,20 +2990,5 @@
     XMEMCPY(&pv, input + i, OPAQUE16_LEN);
     i += OPAQUE16_LEN;
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    ret = CheckVersion(ssl, pv);
-    if (ret != 0)
-        return ret;
-    if (!IsAtLeastTLSv1_3(pv) && pv.major != TLS_DRAFT_MAJOR) {
-#ifndef WOLFSSL_NO_TLS12
-        if (ssl->options.downgrade) {
-            ssl->version = pv;
-            return DoServerHello(ssl, input, inOutIdx, helloSz);
-        }
-#endif
-
-        WOLFSSL_MSG("Client using higher version, fatal error");
-        return VERSION_ERROR;
-    }
-#else
+
 #ifndef WOLFSSL_NO_TLS12
     if (pv.major == ssl->version.major  && pv.minor < TLSv1_2_MINOR &&
@@ -3062,18 +3002,22 @@
     if (pv.major != ssl->version.major || pv.minor != TLSv1_2_MINOR)
         return VERSION_ERROR;
-#endif
-
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    /* Random length check */
-    if ((i - begin) + RAN_LEN > helloSz)
-        return BUFFER_ERROR;
-#else
+
     /* Random and session id length check */
     if ((i - begin) + RAN_LEN + ENUM_LEN > helloSz)
         return BUFFER_ERROR;
 
-    if (XMEMCMP(input + i, helloRetryRequestRandom, RAN_LEN) == 0)
+    if (XMEMCMP(input + i, helloRetryRequestRandom, RAN_LEN) == 0) {
         *extMsgType = hello_retry_request;
-#endif
+        /* A HelloRetryRequest comes in as an ServerHello for MiddleBox compat.
+         * Found message to be a HelloRetryRequest.
+         * Don't allow more than one HelloRetryRequest or ServerHello.
+         */
+        if (ssl->msgsReceived.got_hello_retry_request == 1) {
+            return DUPLICATE_MSG_E;
+        }
+        /* Update counts to reflect change of message type. */
+        ssl->msgsReceived.got_hello_retry_request++;
+        ssl->msgsReceived.got_server_hello--;
+    }
 
     /* Server random - keep for debugging. */
@@ -3081,5 +3025,4 @@
     i += RAN_LEN;
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
     /* Session id */
     sessIdSz = input[i++];
@@ -3088,16 +3031,10 @@
     sessId = input + i;
     i += sessIdSz;
-#endif /* WOLFSSL_TLS13_DRAFT_18 */
+
     ssl->options.haveSessionId = 1;
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    /* Ciphersuite check */
-    if ((i - begin) + OPAQUE16_LEN + OPAQUE16_LEN > helloSz)
-        return BUFFER_ERROR;
-#else
     /* Ciphersuite and compression check */
     if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz)
         return BUFFER_ERROR;
-#endif
 
     /* Set the cipher suite from the message. */
@@ -3105,5 +3042,4 @@
     ssl->options.cipherSuite  = input[i++];
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
     /* Compression */
     b = input[i++];
@@ -3112,7 +3048,5 @@
         return INVALID_PARAMETER;
     }
-#endif
-
-#ifndef WOLFSSL_TLS13_DRAFT_18
+
     if ((i - begin) + OPAQUE16_LEN > helloSz) {
         if (!ssl->options.downgrade)
@@ -3123,7 +3057,5 @@
         ssl->options.haveEMS = 0;
     }
-    if ((i - begin) < helloSz)
-#endif
-    {
+    if ((i - begin) < helloSz) {
         /* Get extension length and length check. */
         if ((i - begin) + OPAQUE16_LEN > helloSz)
@@ -3134,5 +3066,4 @@
             return BUFFER_ERROR;
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
         /* Need to negotiate version first. */
         if ((ret = TLSX_ParseVersion(ssl, (byte*)input + i, totalExtSz,
@@ -3151,5 +3082,4 @@
             ssl->version.minor = pv.minor;
         }
-#endif
 
         /* Parse and handle extensions. */
@@ -3176,5 +3106,4 @@
 #endif /* HAVE_SECRET_CALLBACK */
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
     /* Version only negotiated in extensions for TLS v1.3.
      * Only now do we know how to deal with session id.
@@ -3208,5 +3137,5 @@
     }
 
-    #ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
+#ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
     if (sessIdSz == 0)
         return INVALID_PARAMETER;
@@ -3219,5 +3148,5 @@
     else if (XMEMCMP(ssl->arrays->clientRandom, sessId, sessIdSz) != 0)
         return INVALID_PARAMETER;
-    #else
+#else
     if (sessIdSz != ssl->session.sessionIDSz || (sessIdSz > 0 &&
                   XMEMCMP(ssl->session.sessionID, sessId, sessIdSz) != 0)) {
@@ -3225,6 +3154,5 @@
         return INVALID_PARAMETER;
     }
-    #endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */
-#endif
+#endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */
 
     ret = SetCipherSpecs(ssl);
@@ -3246,8 +3174,5 @@
 
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
-#ifndef WOLFSSL_TLS13_DRAFT_18
-    if (*extMsgType == server_hello)
-#endif
-    {
+    if (*extMsgType == server_hello) {
         ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
         if (ext != NULL)
@@ -3265,7 +3190,4 @@
 #endif
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    ssl->keys.encryptionOn = 1;
-#else
     if (*extMsgType == server_hello) {
         ssl->keys.encryptionOn = 1;
@@ -3278,5 +3200,4 @@
         ret = RestartHandshakeHash(ssl);
     }
-#endif
 
     WOLFSSL_LEAVE("DoTls13ServerHello", ret);
@@ -3358,4 +3279,5 @@
 }
 
+#ifndef NO_CERTS
 /* handle processing TLS v1.3 certificate_request (13) */
 /* Handle a TLS v1.3 CertificateRequest message.
@@ -3376,7 +3298,5 @@
     word32      begin = *inOutIdx;
     int         ret = 0;
-#ifndef WOLFSSL_TLS13_DRAFT_18
     Suites      peerSuites;
-#endif
 #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
     CertReqCtx* certReqCtx;
@@ -3386,7 +3306,6 @@
     WOLFSSL_ENTER("DoTls13CertificateRequest");
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
     XMEMSET(&peerSuites, 0, sizeof(Suites));
-#endif
+
 #ifdef WOLFSSL_CALLBACKS
     if (ssl->hsInfoOn) AddPacketName(ssl, "CertificateRequest");
@@ -3420,53 +3339,4 @@
     *inOutIdx += len;
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    /* Signature and hash algorithms. */
-    if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
-        return BUFFER_ERROR;
-    ato16(input + *inOutIdx, &len);
-    *inOutIdx += OPAQUE16_LEN;
-    if ((*inOutIdx - begin) + len > size)
-        return BUFFER_ERROR;
-    if (PickHashSigAlgo(ssl, input + *inOutIdx, len) != 0 &&
-                 ssl->buffers.certificate && ssl->buffers.certificate->buffer &&
-                 ssl->buffers.key && ssl->buffers.key->buffer) {
-        return INVALID_PARAMETER;
-    }
-    *inOutIdx += len;
-
-    /* Length of certificate authority data. */
-    if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
-        return BUFFER_ERROR;
-    ato16(input + *inOutIdx, &len);
-    *inOutIdx += OPAQUE16_LEN;
-    if ((*inOutIdx - begin) + len > size)
-        return BUFFER_ERROR;
-
-    /* Certificate authorities. */
-    while (len) {
-        word16 dnSz;
-
-        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
-            return BUFFER_ERROR;
-
-        ato16(input + *inOutIdx, &dnSz);
-        *inOutIdx += OPAQUE16_LEN;
-
-        if ((*inOutIdx - begin) + dnSz > size)
-            return BUFFER_ERROR;
-
-        *inOutIdx += dnSz;
-        len -= OPAQUE16_LEN + dnSz;
-    }
-
-    /* Certificate extensions */
-    if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
-        return BUFFER_ERROR;
-    ato16(input + *inOutIdx, &len);
-    *inOutIdx += OPAQUE16_LEN;
-    if ((*inOutIdx - begin) + len > size)
-        return BUFFER_ERROR;
-    *inOutIdx += len;
-#else
     /* TODO: Add support for more extensions:
      *   signed_certificate_timestamp, certificate_authorities, oid_filters.
@@ -3486,5 +3356,4 @@
     }
     *inOutIdx += len;
-#endif
 
     if (ssl->buffers.certificate && ssl->buffers.certificate->buffer &&
@@ -3494,14 +3363,18 @@
         #endif
     )) {
-#ifndef WOLFSSL_TLS13_DRAFT_18
         if (PickHashSigAlgo(ssl, peerSuites.hashSigAlgo,
                                                peerSuites.hashSigAlgoSz) != 0) {
             return INVALID_PARAMETER;
         }
-#endif
         ssl->options.sendVerify = SEND_CERT;
     }
     else {
+#ifndef WOLFSSL_NO_CLIENT_CERT_ERROR
         ssl->options.sendVerify = SEND_BLANK_CERT;
+#else
+        WOLFSSL_MSG("Certificate required but none set on client");
+        SendAlert(ssl, alert_fatal, illegal_parameter);
+        return NO_CERT_ERROR;
+#endif
     }
 
@@ -3514,5 +3387,5 @@
     return ret;
 }
-
+#endif /* !NO_CERTS */
 #endif /* !NO_WOLFSSL_CLIENT */
 
@@ -3576,4 +3449,5 @@
     byte          cipherSuite0 = TLS13_BYTE;
     byte          cipherSuite  = WOLFSSL_DEF_PSK_CIPHER;
+    int           cipherSuiteFlags = WOLFSSL_CIPHER_SUITE_FLAG_NONE;
 #endif
 
@@ -3625,5 +3499,5 @@
     #ifdef HAVE_SESSION_TICKET
         /* Decode the identity. */
-        if ((ret = DoClientTicket(ssl, current->identity, current->identityLen))
+        if (DoClientTicket(ssl, current->identity, current->identityLen)
                                                      == WOLFSSL_TICKET_RET_OK) {
             word32 now;
@@ -3642,5 +3516,6 @@
                 /* Invalid difference, fallback to full handshake. */
                 ssl->options.resuming = 0;
-                break;
+                /* Hash the rest of the ClientHello. */
+                return HashRaw(ssl, input + helloSz - bindersLen, bindersLen);
             }
 
@@ -3667,13 +3542,8 @@
             /* Resumption PSK is resumption master secret. */
             ssl->arrays->psk_keySz = ssl->specs.hash_size;
-        #ifdef WOLFSSL_TLS13_DRAFT_18
-            XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret,
-                    ssl->arrays->psk_keySz);
-        #else
             if ((ret = DeriveResumptionPSK(ssl, ssl->session.ticketNonce.data,
                     ssl->session.ticketNonce.len, ssl->arrays->psk_key)) != 0) {
                 return ret;
             }
-        #endif
 
             /* Derive the early secret using the PSK. */
@@ -3694,5 +3564,5 @@
                              MAX_PSK_KEY_LEN, &cipherName)) != 0 &&
              GetCipherSuiteFromName(cipherName, &cipherSuite0,
-                                                          &cipherSuite) == 0) ||
+                                    &cipherSuite, &cipherSuiteFlags) == 0) ||
             (ssl->options.server_psk_cb != NULL &&
              (ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl,
@@ -3705,4 +3575,5 @@
             suite[0] = cipherSuite0;
             suite[1] = cipherSuite;
+            (void)cipherSuiteFlags;
             if (!FindSuiteSSL(ssl, suite)) {
                 current = current->next;
@@ -3712,4 +3583,6 @@
             /* Default to ciphersuite if cb doesn't specify. */
             ssl->options.resuming = 0;
+            /* Don't send certificate request when using PSK. */
+            ssl->options.verifyPeer = 0;
 
             /* PSK age is always zero. */
@@ -3765,5 +3638,5 @@
 
     /* Hash the rest of the ClientHello. */
-    ret = HashInputRaw(ssl, input + helloSz - bindersLen, bindersLen);
+    ret = HashRaw(ssl, input + helloSz - bindersLen, bindersLen);
     if (ret != 0)
         return ret;
@@ -3807,4 +3680,5 @@
     modes = ext->val;
 
+#ifdef HAVE_SUPPORTED_CURVES
     ext = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
     /* Use (EC)DHE for forward-security if possible. */
@@ -3826,5 +3700,7 @@
         ext->resp = 1;
     }
-    else {
+    else
+#endif
+    {
         if ((modes & (1 << PSK_KE)) == 0)
             return PSK_KEY_ERROR;
@@ -3841,5 +3717,5 @@
 #endif
 
-#if !defined(WOLFSSL_TLS13_DRAFT_18) && defined(WOLFSSL_SEND_HRR_COOKIE)
+#if defined(WOLFSSL_SEND_HRR_COOKIE)
 /* Check that the Cookie data's integrity.
  *
@@ -3892,13 +3768,4 @@
 /* Length of the Cookie Extension excluding cookie data */
 #define HRR_COOKIE_HDR_SZ  (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN)
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* PV | CipherSuite | Ext Len */
-#define HRR_BODY_SZ        (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN)
-/* HH | PV | CipherSuite | Ext Len | Key Share | Cookie */
-#define MAX_HRR_SZ   (HANDSHAKE_HEADER_SZ   + \
-                        HRR_BODY_SZ         + \
-                          HRR_KEY_SHARE_SZ  + \
-                          HRR_COOKIE_HDR_SZ)
-#else
 /* PV | Random | Session Id | CipherSuite | Compression | Ext Len */
 #define HRR_BODY_SZ        (VERSION_SZ + RAN_LEN + ENUM_LEN + ID_LEN + \
@@ -3910,5 +3777,5 @@
                           HRR_VERSIONS_SZ   + \
                           HRR_COOKIE_HDR_SZ)
-#endif
+
 
 /* Restart the handshake hash from the cookie value.
@@ -3942,38 +3809,18 @@
     if ((ret = InitHandshakeHashes(ssl)) != 0)
         return ret;
-    if ((ret = HashOutputRaw(ssl, header, sizeof(header))) != 0)
-        return ret;
-    if ((ret = HashOutputRaw(ssl, cookieData + idx, hashSz)) != 0)
+    if ((ret = HashRaw(ssl, header, sizeof(header))) != 0)
+        return ret;
+    if ((ret = HashRaw(ssl, cookieData + idx, hashSz)) != 0)
         return ret;
 
     /* Reconstruct the HelloRetryMessage for handshake hash. */
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    length = HRR_BODY_SZ + HRR_COOKIE_HDR_SZ + cookie->len;
-#else
     length = HRR_BODY_SZ - ID_LEN + ssl->session.sessionIDSz +
              HRR_COOKIE_HDR_SZ + cookie->len;
     length += HRR_VERSIONS_SZ;
-#endif
     if (cookieDataSz > hashSz + OPAQUE16_LEN) {
         keyShareExt = 1;
         length += HRR_KEY_SHARE_SZ;
     }
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    AddTls13HandShakeHeader(hrr, length, 0, 0, hello_retry_request, ssl);
-
-    idx += hashSz;
-    hrrIdx = HANDSHAKE_HEADER_SZ;
-    /* The negotiated protocol version. */
-    hrr[hrrIdx++] = TLS_DRAFT_MAJOR;
-    hrr[hrrIdx++] = TLS_DRAFT_MINOR;
-    /* Cipher Suite */
-    hrr[hrrIdx++] = cookieData[idx++];
-    hrr[hrrIdx++] = cookieData[idx++];
-
-    /* Extensions' length */
-    length -= HRR_BODY_SZ;
-    c16toa(length, hrr + hrrIdx);
-    hrrIdx += 2;
-#else
+
     AddTls13HandShakeHeader(hrr, length, 0, 0, server_hello, ssl);
 
@@ -4007,5 +3854,4 @@
     hrrIdx += 2;
 
-#endif
     /* Optional KeyShare Extension */
     if (keyShareExt) {
@@ -4017,5 +3863,4 @@
         hrr[hrrIdx++] = cookieData[idx++];
     }
-#ifndef WOLFSSL_TLS13_DRAFT_18
     c16toa(TLSX_SUPPORTED_VERSIONS, hrr + hrrIdx);
     hrrIdx += 2;
@@ -4029,5 +3874,5 @@
         hrr[hrrIdx++] = ssl->version.minor;
     #endif
-#endif
+
     /* Mandatory Cookie Extension */
     c16toa(TLSX_COOKIE, hrr + hrrIdx);
@@ -4045,7 +3890,7 @@
 #endif
 
-    if ((ret = HashOutputRaw(ssl, hrr, hrrIdx)) != 0)
-        return ret;
-    return HashOutputRaw(ssl, cookieData, cookie->len);
+    if ((ret = HashRaw(ssl, hrr, hrrIdx)) != 0)
+        return ret;
+    return HashRaw(ssl, cookieData, cookie->len);
 }
 #endif
@@ -4205,4 +4050,6 @@
     }
 
+    /* From here on we are a TLS 1.3 ClientHello. */
+
     /* Client random */
     XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN);
@@ -4214,16 +4061,7 @@
 #endif
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    /* Session id - empty in TLS v1.3 */
-    sessIdSz = input[i++];
-    if (sessIdSz > 0 && !ssl->options.downgrade) {
-        WOLFSSL_MSG("Client sent session id - not supported");
-        return BUFFER_ERROR;
-    }
-#else
     sessIdSz = input[i++];
     if (sessIdSz != ID_LEN && sessIdSz != 0)
         return INVALID_PARAMETER;
-#endif
 
     if (sessIdSz + i > helloSz) {
@@ -4251,24 +4089,4 @@
     clSuites.hashSigAlgoSz = 0;
 
-#ifdef HAVE_SERVER_RENEGOTIATION_INFO
-    ret = FindSuite(&clSuites, 0, TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
-    if (ret == SUITES_ERROR)
-        return BUFFER_ERROR;
-    if (ret >= 0) {
-        TLSX* extension;
-
-        /* check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV suite */
-        ret = TLSX_AddEmptyRenegotiationInfo(&ssl->extensions, ssl->heap);
-        if (ret != WOLFSSL_SUCCESS)
-            return ret;
-
-        extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO);
-        if (extension) {
-            ssl->secure_renegotiation = (SecureRenegotiation*)extension->data;
-            ssl->secure_renegotiation->enabled = 1;
-        }
-    }
-#endif /* HAVE_SERVER_RENEGOTIATION_INFO */
-
     /* Compression */
     b = input[i++];
@@ -4306,10 +4124,9 @@
     }
 
-#if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \
-                                                        defined(WOLFSSL_HAPROXY)
+#ifdef HAVE_SNI
         if ((ret = SNI_Callback(ssl)) != 0)
             return ret;
         ssl->options.side = WOLFSSL_SERVER_END;
-#endif /* OPENSSL_ALL || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */
+#endif
 
     i += totalExtSz;
@@ -4321,5 +4138,5 @@
     ssl->options.haveSessionId = 1;
 
-#if !defined(WOLFSSL_TLS13_DRAFT_18) && defined(WOLFSSL_SEND_HRR_COOKIE)
+#if defined(WOLFSSL_SEND_HRR_COOKIE)
     if (ssl->options.sendCookie &&
               ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
@@ -4340,5 +4157,5 @@
 
 #if (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \
-     defined(HAVE_TLS_EXTENSIONS)
+                                                    defined(HAVE_TLS_EXTENSIONS)
     if (TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY) != NULL) {
         /* Refine list for PSK processing. */
@@ -4362,4 +4179,5 @@
 
     if (!usingPSK) {
+#ifndef NO_CERTS
         if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) {
             WOLFSSL_MSG("Client did not send a KeyShare extension");
@@ -4379,5 +4197,5 @@
         }
 
-#ifdef HAVE_NULL_CIPHER
+    #ifdef HAVE_NULL_CIPHER
         if (ssl->options.cipherSuite0 == ECC_BYTE &&
                               (ssl->options.cipherSuite == TLS_SHA256_SHA256 ||
@@ -4386,5 +4204,5 @@
         }
         else
-#endif
+    #endif
         /* Check that the negotiated ciphersuite matches protocol version. */
         if (ssl->options.cipherSuite0 != TLS13_BYTE) {
@@ -4395,14 +4213,17 @@
         }
 
-#ifdef HAVE_SESSION_TICKET
+    #ifdef HAVE_SESSION_TICKET
         if (ssl->options.resuming) {
             ssl->options.resuming = 0;
             XMEMSET(ssl->arrays->psk_key, 0, ssl->specs.hash_size);
         }
-#endif
+    #endif
 
         /* Derive early secret for handshake secret. */
         if ((ret = DeriveEarlySecret(ssl)) != 0)
             return ret;
+#else
+        ret = INVALID_PARAMETER;
+#endif
     }
 
@@ -4413,8 +4234,5 @@
 }
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-/* handle generation of TLS 1.3 hello_retry_request (6) */
-/* Send the HelloRetryRequest message to indicate the negotiated protocol
- * version and security parameters the server is willing to use.
+/* Send TLS v1.3 ServerHello message to client.
  * Only a server will send this message.
  *
@@ -4422,77 +4240,4 @@
  * returns 0 on success, otherwise failure.
  */
-int SendTls13HelloRetryRequest(WOLFSSL* ssl)
-{
-    int    ret;
-    byte*  output;
-    word32 length;
-    word16 len;
-    word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
-    int    sendSz;
-
-    WOLFSSL_ENTER("SendTls13HelloRetryRequest");
-
-    /* Get the length of the extensions that will be written. */
-    len = 0;
-    ret = TLSX_GetResponseSize(ssl, hello_retry_request, &len);
-    /* There must be extensions sent to indicate what client needs to do. */
-    if (ret != 0)
-        return MISSING_HANDSHAKE_DATA;
-
-    /* Protocol version + Extensions */
-    length = OPAQUE16_LEN + len;
-    sendSz = idx + length;
-
-    /* Check buffers are big enough and grow if needed. */
-    if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
-        return ret;
-
-    /* Get position in output buffer to write new message to. */
-    output = ssl->buffers.outputBuffer.buffer +
-             ssl->buffers.outputBuffer.length;
-    /* Add record and handshake headers. */
-    AddTls13Headers(output, length, hello_retry_request, ssl);
-
-    /* The negotiated protocol version. */
-    output[idx++] = TLS_DRAFT_MAJOR;
-    output[idx++] = TLS_DRAFT_MINOR;
-
-    /* Add TLS extensions. */
-    ret = TLSX_WriteResponse(ssl, output + idx, hello_retry_request, NULL);
-    if (ret != 0)
-        return ret;
-    idx += len;
-
-#ifdef WOLFSSL_CALLBACKS
-    if (ssl->hsInfoOn)
-        AddPacketName(ssl, "HelloRetryRequest");
-    if (ssl->toInfoOn) {
-        AddPacketInfo(ssl, "HelloRetryRequest", handshake, output, sendSz,
-                      WRITE_PROTO, ssl->heap);
-    }
-#endif
-    if ((ret = HashOutput(ssl, output, idx, 0)) != 0)
-        return ret;
-
-    ssl->buffers.outputBuffer.length += sendSz;
-
-    if (!ssl->options.groupMessages)
-        ret = SendBuffered(ssl);
-
-    WOLFSSL_LEAVE("SendTls13HelloRetryRequest", ret);
-
-    return ret;
-}
-#endif /* WOLFSSL_TLS13_DRAFT_18 */
-
-/* Send TLS v1.3 ServerHello message to client.
- * Only a server will send this message.
- *
- * ssl  The SSL/TLS object.
- * returns 0 on success, otherwise failure.
- */
-#ifdef WOLFSSL_TLS13_DRAFT_18
-static
-#endif
 /* handle generation of TLS 1.3 server_hello (2) */
 int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
@@ -4507,5 +4252,4 @@
     WOLFSSL_ENTER("SendTls13ServerHello");
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
     if (extMsgType == hello_retry_request) {
         WOLFSSL_MSG("wolfSSL Doing HelloRetryRequest");
@@ -4513,13 +4257,5 @@
             return ret;
     }
-#endif
-
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    /* Protocol version, server random, cipher suite and extensions. */
-    length = VERSION_SZ + RAN_LEN + SUITE_LEN;
-    ret = TLSX_GetResponseSize(ssl, server_hello, &length);
-    if (ret != 0)
-        return ret;
-#else
+
     /* Protocol version, server random, session id, cipher suite, compression
      * and extensions.
@@ -4530,5 +4266,4 @@
     if (ret != 0)
         return ret;
-#endif
     sendSz = idx + length;
 
@@ -4544,13 +4279,7 @@
     AddTls13Headers(output, length, server_hello, ssl);
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    /* The negotiated protocol version. */
-    output[idx++] = TLS_DRAFT_MAJOR;
-    output[idx++] = TLS_DRAFT_MINOR;
-#else
     /* The protocol version must be TLS v1.2 for middleboxes. */
     output[idx++] = ssl->version.major;
     output[idx++] = TLSv1_2_MINOR;
-#endif
 
     if (extMsgType == server_hello) {
@@ -4559,10 +4288,9 @@
             return ret;
     }
-#ifndef WOLFSSL_TLS13_DRAFT_18
     else {
         /* HelloRetryRequest message has fixed value for random. */
         XMEMCPY(output + idx, helloRetryRequestRandom, RAN_LEN);
     }
-#endif
+
     /* Store in SSL for debugging. */
     XMEMCPY(ssl->arrays->serverRandom, output + idx, RAN_LEN);
@@ -4574,5 +4302,4 @@
 #endif
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
     output[idx++] = ssl->session.sessionIDSz;
     if (ssl->session.sessionIDSz > 0) {
@@ -4580,5 +4307,4 @@
         idx += ssl->session.sessionIDSz;
     }
-#endif
 
     /* Chosen cipher suite */
@@ -4586,8 +4312,6 @@
     output[idx++] = ssl->options.cipherSuite;
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
     /* Compression not supported in TLS v1.3. */
     output[idx++] = 0;
-#endif
 
     /* Extensions */
@@ -4610,16 +4334,9 @@
     #endif
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    ssl->options.serverState = SERVER_HELLO_COMPLETE;
-#else
     if (extMsgType == server_hello)
         ssl->options.serverState = SERVER_HELLO_COMPLETE;
-#endif
-
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    if (!ssl->options.groupMessages)
-#else
+
     if (!ssl->options.groupMessages || extMsgType != server_hello)
-#endif
+
         ret = SendBuffered(ssl);
 
@@ -4651,5 +4368,5 @@
     ssl->keys.encryptionOn = 1;
 
-#ifndef WOLFSSL_NO_SERVER_GROUPS_EXT
+#if defined(HAVE_SUPPORTED_CURVES) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)
     if ((ret = TLSX_SupportedCurve_CheckPriority(ssl)) != 0)
         return ret;
@@ -4750,7 +4467,5 @@
     word32 i;
     word16 reqSz;
-#ifndef WOLFSSL_TLS13_DRAFT_18
     TLSX*  ext;
-#endif
 
     WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_SEND);
@@ -4760,46 +4475,4 @@
         InitSuitesHashSigAlgo(ssl->suites, 1, 1, 0, 1, ssl->buffers.keySz);
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
-    reqSz = OPAQUE8_LEN + reqCtxLen + REQ_HEADER_SZ + REQ_HEADER_SZ;
-    reqSz += LENGTH_SZ + ssl->suites->hashSigAlgoSz;
-
-    sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz;
-    /* Always encrypted and make room for padding. */
-    sendSz += MAX_MSG_EXTRA;
-
-    /* Check buffers are big enough and grow if needed. */
-    if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
-        return ret;
-
-    /* Get position in output buffer to write new message to. */
-    output = ssl->buffers.outputBuffer.buffer +
-             ssl->buffers.outputBuffer.length;
-
-    /* Put the record and handshake headers on. */
-    AddTls13Headers(output, reqSz, certificate_request, ssl);
-
-    /* Certificate request context. */
-    output[i++] = reqCtxLen;
-    if (reqCtxLen != 0) {
-        XMEMCPY(output + i, reqCtx, reqCtxLen);
-        i += reqCtxLen;
-    }
-
-    /* supported hash/sig */
-    c16toa(ssl->suites->hashSigAlgoSz, &output[i]);
-    i += LENGTH_SZ;
-
-    XMEMCPY(&output[i], ssl->suites->hashSigAlgo, ssl->suites->hashSigAlgoSz);
-    i += ssl->suites->hashSigAlgoSz;
-
-    /* Certificate authorities not supported yet - empty buffer. */
-    c16toa(0, &output[i]);
-    i += REQ_HEADER_SZ;
-
-    /* Certificate extensions. */
-    c16toa(0, &output[i]);  /* auth's */
-    i += REQ_HEADER_SZ;
-#else
     ext = TLSX_Find(ssl->extensions, TLSX_SIGNATURE_ALGORITHMS);
     if (ext == NULL)
@@ -4841,5 +4514,4 @@
         return ret;
     i += reqSz;
-#endif
 
     /* Always encrypted. */
@@ -5181,5 +4853,5 @@
 #endif /* HAVE_ECC */
 
-#ifndef NO_RSA
+#if !defined(NO_RSA) && defined(WC_RSA_PSS)
 /* Check that the decrypted signature matches the encoded signature
  * based on the digest of the signature data.
@@ -5224,5 +4896,5 @@
     return ret;
 }
-#endif /* !NO_RSA */
+#endif /* !NO_RSA && WC_RSA_PSS */
 #endif /* !NO_RSA || HAVE_ECC */
 
@@ -5534,4 +5206,7 @@
 }
 
+#if (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \
+     defined(HAVE_ED448)) && \
+    (!defined(NO_WOLFSSL_SERVER) || !defined(WOLFSSL_NO_CLIENT_AUTH))
 typedef struct Scv13Args {
     byte*  output; /* not allocated */
@@ -5650,5 +5325,5 @@
             }
 
-            if (args->length <= 0) {
+            if (args->length == 0) {
                 ERROR_OUT(NO_PRIVATE_KEY, exit_scv);
             }
@@ -5657,6 +5332,8 @@
             if (ssl->hsType == DYNAMIC_TYPE_RSA)
                 args->sigAlgo = rsa_pss_sa_algo;
+        #ifdef HAVE_ECC
             else if (ssl->hsType == DYNAMIC_TYPE_ECC)
                 args->sigAlgo = ecc_dsa_sa_algo;
+        #endif
         #ifdef HAVE_ED25519
             else if (ssl->hsType == DYNAMIC_TYPE_ED25519)
@@ -5667,4 +5344,7 @@
                 args->sigAlgo = ed448_sa_algo;
         #endif
+            else {
+                ERROR_OUT(ALGO_ID_E, exit_scv);
+            }
             EncodeSigAlg(ssl->suites->hashAlgo, args->sigAlgo, args->verify);
 
@@ -5913,5 +5593,7 @@
     return ret;
 }
-
+#endif
+
+#if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH)
 /* handle processing TLS v1.3 certificate (11) */
 /* Parse and handle a TLS v1.3 Certificate message.
@@ -5954,4 +5636,5 @@
     return ret;
 }
+#endif
 
 #if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \
@@ -6078,10 +5761,14 @@
             if (args->sigAlgo == ed25519_sa_algo &&
                                                   !ssl->peerEd25519KeyPresent) {
-                WOLFSSL_MSG("Oops, peer sent ED25519 key but not in verify");
+                WOLFSSL_MSG("Peer sent ED22519 sig but not ED22519 cert");
+                ret = SIG_VERIFY_E;
+                goto exit_dcv;
             }
         #endif
         #ifdef HAVE_ED448
             if (args->sigAlgo == ed448_sa_algo && !ssl->peerEd448KeyPresent) {
-                WOLFSSL_MSG("Oops, peer sent ED448 key but not in verify");
+                WOLFSSL_MSG("Peer sent ED448 sig but not ED448 cert");
+                ret = SIG_VERIFY_E;
+                goto exit_dcv;
             }
         #endif
@@ -6089,15 +5776,19 @@
             if (args->sigAlgo == ecc_dsa_sa_algo &&
                                                    !ssl->peerEccDsaKeyPresent) {
-                WOLFSSL_MSG("Oops, peer sent ECC key but not in verify");
+                WOLFSSL_MSG("Peer sent ECC sig but not ECC cert");
+                ret = SIG_VERIFY_E;
+                goto exit_dcv;
             }
         #endif
         #ifndef NO_RSA
             if (args->sigAlgo == rsa_sa_algo) {
-                WOLFSSL_MSG("Oops, peer sent PKCS#1.5 signature");
+                WOLFSSL_MSG("Peer sent PKCS#1.5 algo but not in certificate");
                 ERROR_OUT(INVALID_PARAMETER, exit_dcv);
             }
             if (args->sigAlgo == rsa_pss_sa_algo &&
                          (ssl->peerRsaKey == NULL || !ssl->peerRsaKeyPresent)) {
-                WOLFSSL_MSG("Oops, peer sent RSA key but not in verify");
+                WOLFSSL_MSG("Peer sent RSA sig but not RSA cert");
+                ret = SIG_VERIFY_E;
+                goto exit_dcv;
             }
         #endif
@@ -6261,5 +5952,5 @@
         case TLS_ASYNC_VERIFY:
         {
-        #ifndef NO_RSA
+        #if !defined(NO_RSA) && defined(WC_RSA_PSS)
             if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) {
                 ret = CheckRSASignature(ssl, args->sigAlgo, args->hashAlgo,
@@ -6271,5 +5962,5 @@
                 ssl->peerRsaKeyPresent = 0;
             }
-        #endif /* !NO_RSA */
+        #endif /* !NO_RSA && WC_RSA_PSS */
 
             /* Advance state and proceed */
@@ -6291,4 +5982,9 @@
             /* Advance state and proceed */
             ssl->options.asyncState = TLS_ASYNC_END;
+
+        #if !defined(NO_WOLFSSL_CLIENT)
+            if (ssl->options.side == WOLFSSL_CLIENT_END)
+                ssl->options.serverState = SERVER_CERT_VERIFY_COMPLETE;
+        #endif
         } /* case TLS_ASYNC_FINALIZE */
 
@@ -6326,4 +6022,5 @@
 }
 #endif /* !NO_RSA || HAVE_ECC */
+#endif /* !NO_CERTS */
 
 /* Parse and handle a TLS v1.3 Finished message.
@@ -6338,5 +6035,5 @@
  * returns 0 on success and otherwise failure.
  */
-static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
+int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
                            word32 size, word32 totalSz, int sniff)
 {
@@ -6377,17 +6074,20 @@
         secret = ssl->keys.server_write_MAC_secret;
     }
-    else
+    else {
         secret = ssl->keys.client_write_MAC_secret;
-
-    ret = BuildTls13HandshakeHmac(ssl, secret, mac, &finishedSz);
-    if (ret != 0)
-        return ret;
-    if (size != finishedSz)
-        return BUFFER_ERROR;
-
-    #ifdef WOLFSSL_CALLBACKS
-        if (ssl->hsInfoOn) AddPacketName(ssl, "Finished");
-        if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo);
-    #endif
+    }
+
+    if (sniff == NO_SNIFF) {
+        ret = BuildTls13HandshakeHmac(ssl, secret, mac, &finishedSz);
+        if (ret != 0)
+            return ret;
+        if (size != finishedSz)
+            return BUFFER_ERROR;
+    }
+
+#ifdef WOLFSSL_CALLBACKS
+    if (ssl->hsInfoOn) AddPacketName(ssl, "Finished");
+    if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo);
+#endif
 
     if (sniff == NO_SNIFF) {
@@ -6433,5 +6133,4 @@
     return 0;
 }
-#endif /* NO_CERTS */
 
 /* Send the TLS v1.3 Finished message.
@@ -6502,11 +6201,4 @@
     if (sendSz < 0)
         return BUILD_MSG_ERROR;
-
-#ifndef NO_SESSION_CACHE
-    if (!ssl->options.resuming && (ssl->options.side == WOLFSSL_SERVER_END ||
-            (ssl->options.side == WOLFSSL_SERVER_END && ssl->arrays != NULL))) {
-        AddSession(ssl);    /* just try */
-    }
-#endif
 
     #ifdef WOLFSSL_CALLBACKS
@@ -6839,8 +6531,6 @@
     word16 length;
     word32 now;
-#ifndef WOLFSSL_TLS13_DRAFT_18
-    const byte*  nonce;
-    byte         nonceLength;
-#endif
+    const byte* nonce;
+    byte        nonceLength;
 
     WOLFSSL_START(WC_FUNC_NEW_SESSION_TICKET_DO);
@@ -6861,5 +6551,4 @@
     *inOutIdx += SESSION_ADD_SZ;
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
     /* Ticket nonce. */
     if ((*inOutIdx - begin) + 1 > size)
@@ -6875,5 +6564,4 @@
     nonce = input + *inOutIdx;
     *inOutIdx += nonceLength;
-#endif
 
     /* Ticket length. */
@@ -6902,9 +6590,7 @@
     ssl->session.maxEarlyDataSz = ssl->options.maxEarlyDataSz;
     #endif
-#ifndef WOLFSSL_TLS13_DRAFT_18
     ssl->session.ticketNonce.len = nonceLength;
     if (nonceLength > 0)
         XMEMCPY(&ssl->session.ticketNonce.data, nonce, nonceLength);
-#endif
     ssl->session.namedGroup     = ssl->namedGroup;
 
@@ -7002,12 +6688,12 @@
     if (ssl->earlyData != no_early_data) {
         static byte endOfEarlyData[] = { 0x05, 0x00, 0x00, 0x00 };
-        ret = HashInputRaw(ssl, endOfEarlyData, sizeof(endOfEarlyData));
+        ret = HashRaw(ssl, endOfEarlyData, sizeof(endOfEarlyData));
         if (ret != 0)
             return ret;
     }
 #endif
-    if ((ret = HashInputRaw(ssl, header, sizeof(header))) != 0)
-        return ret;
-    if ((ret = HashInputRaw(ssl, mac, finishedSz)) != 0)
+    if ((ret = HashRaw(ssl, header, sizeof(header))) != 0)
+        return ret;
+    if ((ret = HashRaw(ssl, mac, finishedSz)) != 0)
         return ret;
 
@@ -7069,5 +6755,4 @@
 #endif
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
     /* Start ticket nonce at 0 and go up to 255. */
     if (ssl->session.ticketNonce.len == 0) {
@@ -7077,5 +6762,4 @@
     else
         ssl->session.ticketNonce.data[0]++;
-#endif
 
     if (!ssl->options.noTicketTls13) {
@@ -7099,8 +6783,6 @@
     length = SESSION_HINT_SZ + SESSION_ADD_SZ + LENGTH_SZ +
              ssl->session.ticketLen + extSz;
-#ifndef WOLFSSL_TLS13_DRAFT_18
     /* Nonce */
     length += TICKET_NONCE_LEN_SZ + DEF_TICKET_NONCE_SZ;
-#endif
     sendSz = idx + length + MAX_MSG_EXTRA;
 
@@ -7123,8 +6805,6 @@
     idx += SESSION_ADD_SZ;
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
     output[idx++] = ssl->session.ticketNonce.len;
     output[idx++] = ssl->session.ticketNonce.data[0];
-#endif
 
     /* length */
@@ -7161,6 +6841,8 @@
     ssl->buffers.outputBuffer.length += sendSz;
 
-    if (!ssl->options.groupMessages)
-        ret = SendBuffered(ssl);
+    /* Always send as this is either directly after server's Finished or only
+     * message after client's Finished.
+     */
+    ret = SendBuffered(ssl);
 
     WOLFSSL_LEAVE("SendTls13NewSessionTicket", 0);
@@ -7212,17 +6894,9 @@
             }
         #endif
-        #ifdef WOLFSSL_TLS13_DRAFT_18
-            if (ssl->msgsReceived.got_server_hello) {
+            if (ssl->msgsReceived.got_server_hello == 1) {
                 WOLFSSL_MSG("Duplicate ServerHello received");
                 return DUPLICATE_MSG_E;
             }
-            ssl->msgsReceived.got_server_hello = 1;
-        #else
-            if (ssl->msgsReceived.got_server_hello == 2) {
-                WOLFSSL_MSG("Duplicate ServerHello received");
-                return DUPLICATE_MSG_E;
-            }
             ssl->msgsReceived.got_server_hello++;
-        #endif
 
             break;
@@ -7273,27 +6947,4 @@
 #endif
 
-#ifdef WOLFSSL_TLS13_DRAFT_18
-    #ifndef NO_WOLFSSL_CLIENT
-        case hello_retry_request:
-        #ifndef NO_WOLFSSL_SERVER
-            if (ssl->options.side == WOLFSSL_SERVER_END) {
-                WOLFSSL_MSG("HelloRetryRequest received by server");
-                return OUT_OF_ORDER_E;
-            }
-        #endif
-            if (ssl->options.clientState > CLIENT_FINISHED_COMPLETE) {
-                WOLFSSL_MSG("HelloRetryRequest received out of order");
-                return OUT_OF_ORDER_E;
-            }
-            if (ssl->msgsReceived.got_hello_retry_request) {
-                WOLFSSL_MSG("Duplicate HelloRetryRequest received");
-                return DUPLICATE_MSG_E;
-            }
-            ssl->msgsReceived.got_hello_retry_request = 1;
-
-            break;
-    #endif
-#endif
-
 #ifndef NO_WOLFSSL_CLIENT
         case encrypted_extensions:
@@ -7377,4 +7028,5 @@
             if (ssl->options.serverState ==
                                          SERVER_ENCRYPTED_EXTENSIONS_COMPLETE &&
+                                                  ssl->arrays != NULL &&
                                                   ssl->arrays->psk_keySz != 0) {
                 WOLFSSL_MSG("CertificateRequset received while using PSK");
@@ -7403,4 +7055,5 @@
                 /* Server's authenticating with PSK must not send this. */
                 if (ssl->options.serverState == SERVER_CERT_COMPLETE &&
+                                                  ssl->arrays != NULL &&
                                                   ssl->arrays->psk_keySz != 0) {
                     WOLFSSL_MSG("CertificateVerify received while using PSK");
@@ -7441,6 +7094,17 @@
                     return OUT_OF_ORDER_E;
                 }
-                if (ssl->options.serverState <
+                /* Must have seen certificate and verify from server except when
+                 * using PSK. */
+            #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+                if (ssl->arrays != NULL && ssl->arrays->psk_keySz != 0) {
+                    if (ssl->options.serverState !=
                                          SERVER_ENCRYPTED_EXTENSIONS_COMPLETE) {
+                        WOLFSSL_MSG("Finished received out of order");
+                        return OUT_OF_ORDER_E;
+                    }
+                }
+                else
+            #endif
+                if (ssl->options.serverState != SERVER_CERT_VERIFY_COMPLETE) {
                     WOLFSSL_MSG("Finished received out of order");
                     return OUT_OF_ORDER_E;
@@ -7450,5 +7114,5 @@
         #ifndef NO_WOLFSSL_SERVER
             if (ssl->options.side == WOLFSSL_SERVER_END) {
-                if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) {
+                if (ssl->options.serverState != SERVER_FINISHED_COMPLETE) {
                     WOLFSSL_MSG("Finished received out of order");
                     return OUT_OF_ORDER_E;
@@ -7531,5 +7195,5 @@
     if (ssl->options.handShakeState == HANDSHAKE_DONE &&
             type != session_ticket && type != certificate_request &&
-            type != certificate && type != key_update) {
+            type != certificate && type != key_update && type != finished) {
         WOLFSSL_MSG("HandShake message after handshake complete");
         SendAlert(ssl, alert_fatal, unexpected_message);
@@ -7556,11 +7220,4 @@
 #ifndef NO_WOLFSSL_CLIENT
     /* Messages only received by client. */
-    #ifdef WOLFSSL_TLS13_DRAFT_18
-    case hello_retry_request:
-        WOLFSSL_MSG("processing hello retry request");
-        ret = DoTls13HelloRetryRequest(ssl, input, inOutIdx, size);
-        break;
-    #endif
-
     case server_hello:
         WOLFSSL_MSG("processing server hello");
@@ -7572,5 +7229,5 @@
                                                IsAtLeastTLSv1_3(ssl->version)) {
             ssl->options.cacheMessages = 0;
-            if (ssl->hsHashes->messages != NULL) {
+            if ((ssl->hsHashes != NULL) && (ssl->hsHashes->messages != NULL)) {
                 XFREE(ssl->hsHashes->messages, ssl->heap, DYNAMIC_TYPE_HASHES);
                 ssl->hsHashes->messages = NULL;
@@ -7614,5 +7271,6 @@
 
     /* Messages received by both client and server. */
-#ifndef NO_CERTS
+#if !defined(NO_CERTS) && (!defined(NO_WOLFSSL_CLIENT) || \
+                           !defined(WOLFSSL_NO_CLIENT_AUTH))
     case certificate:
         WOLFSSL_MSG("processing certificate");
@@ -7676,14 +7334,16 @@
 
                 if ((ret = DeriveTls13Keys(ssl, handshake_key,
-                                           ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) {
+                                        ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) {
                     return ret;
                 }
         #ifdef WOLFSSL_EARLY_DATA
-                if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0)
-                    return ret;
-        #else
+                if (ssl->earlyData != no_early_data) {
+                    if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0)
+                        return ret;
+                }
+                else
+        #endif
                 if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0)
                     return ret;
-        #endif
             }
 
@@ -7693,11 +7353,11 @@
         #ifdef WOLFSSL_EARLY_DATA
                 if ((ret = DeriveTls13Keys(ssl, traffic_key,
-                                       ENCRYPT_AND_DECRYPT_SIDE,
-                                       ssl->earlyData == no_early_data)) != 0) {
+                                    ENCRYPT_AND_DECRYPT_SIDE,
+                                    ssl->earlyData == no_early_data)) != 0) {
                     return ret;
                 }
         #else
                 if ((ret = DeriveTls13Keys(ssl, traffic_key,
-                                           ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) {
+                                        ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) {
                     return ret;
                 }
@@ -7711,7 +7371,11 @@
                 ssl->options.connectState  = FIRST_REPLY_DONE;
                 ssl->options.handShakeState = CLIENT_HELLO_COMPLETE;
-
-                if (wolfSSL_connect_TLSv13(ssl) != SSL_SUCCESS)
-                    ret = POST_HAND_AUTH_ERROR;
+                ssl->options.processReply = 0; /* doProcessInit */
+
+                if (wolfSSL_connect_TLSv13(ssl) != WOLFSSL_SUCCESS) {
+                    ret = ssl->error;
+                    if (ret != WC_PENDING_E)
+                        ret = POST_HAND_AUTH_ERROR;
+                }
             }
         #endif
@@ -7756,10 +7420,11 @@
     int    ret = 0;
     word32 inputLength;
+    byte   type;
+    word32 size = 0;
 
     WOLFSSL_ENTER("DoTls13HandShakeMsg()");
 
     if (ssl->arrays == NULL) {
-        byte   type;
-        word32 size;
+
 
         if (GetHandshakeHeader(ssl, input, inOutIdx, &type, &size,
@@ -7778,6 +7443,4 @@
      * pending message size will be non-zero. */
     if (ssl->arrays->pendingMsgSz == 0) {
-        byte   type;
-        word32 size;
 
         if (GetHandshakeHeader(ssl,input, inOutIdx, &type, &size, totalSz) != 0)
@@ -7879,5 +7542,5 @@
     if (ssl->buffers.outputBuffer.length > 0
     #ifdef WOLFSSL_ASYNC_CRYPT
-        /* do not send buffered or advance state if last error was an 
+        /* do not send buffered or advance state if last error was an
             async pending operation */
         && ssl->error != WC_PENDING_E
@@ -7917,6 +7580,5 @@
     #ifdef WOLFSSL_EARLY_DATA
             if (ssl->earlyData != no_early_data) {
-        #if !defined(WOLFSSL_TLS13_DRAFT_18) && \
-                                         defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
+        #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
                 if ((ssl->error = SendChangeCipher(ssl)) != 0) {
                     WOLFSSL_ERROR(ssl->error);
@@ -7941,12 +7603,4 @@
             }
 
-            ssl->options.connectState = HELLO_AGAIN;
-            WOLFSSL_MSG("connect state: HELLO_AGAIN");
-            FALL_THROUGH;
-
-        case HELLO_AGAIN:
-            if (ssl->options.certOnly)
-                return WOLFSSL_SUCCESS;
-
             if (!ssl->options.tls1_3) {
     #ifndef WOLFSSL_NO_TLS12
@@ -7954,13 +7608,19 @@
                     return wolfSSL_connect(ssl);
     #endif
-
                 WOLFSSL_MSG("Client using higher version, fatal error");
                 return VERSION_ERROR;
             }
 
+            ssl->options.connectState = HELLO_AGAIN;
+            WOLFSSL_MSG("connect state: HELLO_AGAIN");
+            FALL_THROUGH;
+
+        case HELLO_AGAIN:
+            if (ssl->options.certOnly)
+                return WOLFSSL_SUCCESS;
+
             if (ssl->options.serverState ==
                                           SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
-        #if !defined(WOLFSSL_TLS13_DRAFT_18) && \
-                                         defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
+        #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
                 if (!ssl->options.sentChangeCipher) {
                     if ((ssl->error = SendChangeCipher(ssl)) != 0) {
@@ -8011,6 +7671,5 @@
 
         case FIRST_REPLY_FIRST:
-        #if !defined(WOLFSSL_TLS13_DRAFT_18) && \
-                                         defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
+        #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
             if (!ssl->options.sentChangeCipher) {
                 if ((ssl->error = SendChangeCipher(ssl)) != 0) {
@@ -8043,5 +7702,7 @@
 
         case FIRST_REPLY_THIRD:
-        #ifndef NO_CERTS
+        #if (!defined(NO_CERTS) && (!defined(NO_RSA) || defined(HAVE_ECC) || \
+             defined(HAVE_ED25519) || defined(HAVE_ED448))) && \
+             (!defined(NO_WOLFSSL_SERVER) || !defined(WOLFSSL_NO_CLIENT_AUTH))
             if (!ssl->options.resuming && ssl->options.sendVerify) {
                 ssl->error = SendTls13CertificateVerify(ssl);
@@ -8172,4 +7833,5 @@
 #endif
 
+#ifdef HAVE_SUPPORTED_CURVES
 /* Create a key share entry from group.
  * Generates a key pair.
@@ -8213,4 +7875,5 @@
     return WOLFSSL_SUCCESS;
 }
+#endif
 
 /* Do not send a ticket after TLS v1.3 handshake for resumption.
@@ -8414,7 +8077,11 @@
         return NOT_READY_ERROR;
 
+#ifdef HAVE_SUPPORTED_CURVES
     /* Return supported groups only. */
     return TLSX_SupportedCurve_Preferred(ssl, 1);
 #else
+    return 0;
+#endif
+#else
     return SIDE_ERROR;
 #endif
@@ -8422,4 +8089,5 @@
 #endif
 
+#if defined(HAVE_SUPPORTED_CURVES)
 /* Sets the key exchange groups in rank order on a context.
  *
@@ -8432,6 +8100,7 @@
 int wolfSSL_CTX_set_groups(WOLFSSL_CTX* ctx, int* groups, int count)
 {
-    int i;
-
+    int ret, i;
+
+    WOLFSSL_ENTER("wolfSSL_CTX_set_groups");
     if (ctx == NULL || groups == NULL || count > WOLFSSL_MAX_GROUP_COUNT)
         return BAD_FUNC_ARG;
@@ -8439,6 +8108,16 @@
         return BAD_FUNC_ARG;
 
-    for (i = 0; i < count; i++)
-        ctx->group[i] = (word16)groups[i];
+    ctx->numGroups = 0;
+    TLSX_Remove(&ctx->extensions, TLSX_SUPPORTED_GROUPS, ctx->heap);
+    for (i = 0; i < count; i++) {
+        /* Call to wolfSSL_CTX_UseSupportedCurve also checks if input groups
+         * are valid */
+        if ((ret = wolfSSL_CTX_UseSupportedCurve(ctx, groups[i]))
+                != WOLFSSL_SUCCESS) {
+            TLSX_Remove(&ctx->extensions, TLSX_SUPPORTED_GROUPS, ctx->heap);
+            return ret;
+        }
+        ctx->group[i] = groups[i];
+    }
     ctx->numGroups = (byte)count;
 
@@ -8456,6 +8135,7 @@
 int wolfSSL_set_groups(WOLFSSL* ssl, int* groups, int count)
 {
-    int i;
-
+    int ret, i;
+
+    WOLFSSL_ENTER("wolfSSL_set_groups");
     if (ssl == NULL || groups == NULL || count > WOLFSSL_MAX_GROUP_COUNT)
         return BAD_FUNC_ARG;
@@ -8463,10 +8143,21 @@
         return BAD_FUNC_ARG;
 
-    for (i = 0; i < count; i++)
-        ssl->group[i] = (word16)groups[i];
+    ssl->numGroups = 0;
+    TLSX_Remove(&ssl->extensions, TLSX_SUPPORTED_GROUPS, ssl->heap);
+    for (i = 0; i < count; i++) {
+        /* Call to wolfSSL_UseSupportedCurve also checks if input groups
+                 * are valid */
+        if ((ret = wolfSSL_UseSupportedCurve(ssl, groups[i]))
+                != WOLFSSL_SUCCESS) {
+            TLSX_Remove(&ssl->extensions, TLSX_SUPPORTED_GROUPS, ssl->heap);
+            return ret;
+        }
+        ssl->group[i] = groups[i];
+    }
     ssl->numGroups = (byte)count;
 
     return WOLFSSL_SUCCESS;
 }
+#endif /* HAVE_SUPPORTED_CURVES */
 
 #ifndef NO_PSK
@@ -8607,5 +8298,5 @@
     if (ssl->buffers.outputBuffer.length > 0
     #ifdef WOLFSSL_ASYNC_CRYPT
-        /* do not send buffered or advance state if last error was an 
+        /* do not send buffered or advance state if last error was an
             async pending operation */
         && ssl->error != WC_PENDING_E
@@ -8653,19 +8344,4 @@
 
         case TLS13_ACCEPT_CLIENT_HELLO_DONE :
-#ifdef WOLFSSL_TLS13_DRAFT_18
-            if (ssl->options.serverState ==
-                                          SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
-                if ((ssl->error = SendTls13HelloRetryRequest(ssl)) != 0) {
-                    WOLFSSL_ERROR(ssl->error);
-                    return WOLFSSL_FATAL_ERROR;
-                }
-            }
-
-            ssl->options.acceptState = TLS13_ACCEPT_FIRST_REPLY_DONE;
-            WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE");
-            FALL_THROUGH;
-
-        case TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE :
-#else
             if (ssl->options.serverState ==
                                           SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
@@ -8696,5 +8372,4 @@
             WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE");
             FALL_THROUGH;
-#endif
 
         case TLS13_ACCEPT_FIRST_REPLY_DONE :
@@ -8724,6 +8399,5 @@
 
         case TLS13_SERVER_HELLO_SENT :
-    #if !defined(WOLFSSL_TLS13_DRAFT_18) && \
-                                         defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
+    #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
             if (!ssl->options.sentChangeCipher) {
                 if ((ssl->error = SendChangeCipher(ssl)) != 0) {
@@ -8740,4 +8414,5 @@
 
         case TLS13_ACCEPT_THIRD_REPLY_DONE :
+#ifdef HAVE_SUPPORTED_CURVES
             if (!ssl->options.noPskDheKe) {
                 ssl->error = TLSX_KeyShare_DeriveSecret(ssl);
@@ -8745,4 +8420,5 @@
                     return WOLFSSL_FATAL_ERROR;
             }
+#endif
 
             if ((ssl->error = SendTls13EncryptedExtensions(ssl)) != 0) {
@@ -8784,5 +8460,6 @@
 
         case TLS13_CERT_SENT :
-#ifndef NO_CERTS
+#if !defined(NO_CERTS) && (!defined(NO_RSA) || defined(HAVE_ECC) || \
+     defined(HAVE_ED25519) || defined(HAVE_ED448))
             if (!ssl->options.resuming && ssl->options.sendVerify) {
                 if ((ssl->error = SendTls13CertificateVerify(ssl)) != 0) {
Index: azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/wolfio.c
===================================================================
--- azure_iot_hub_f767zi/trunk/wolfssl-4.4.0/src/wolfio.c	(revision 457)
+++ azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/wolfio.c	(revision 464)
@@ -89,10 +89,17 @@
 }
 
-static WC_INLINE int wolfSSL_LastError(void)
-{
+static WC_INLINE int wolfSSL_LastError(int err)
+{
+    (void)err; /* Suppress unused arg */
+
 #ifdef USE_WINDOWS_API
     return WSAGetLastError();
 #elif defined(EBSNET)
     return xn_getlasterror();
+#elif defined(WOLFSSL_LINUXKM)
+    return err; /* Return provided error value */
+#elif defined(FUSION_RTOS)
+    #include <fclerrno.h>
+    return FCL_GET_ERRNO;
 #else
     return errno;
@@ -104,4 +111,5 @@
 
 #ifdef OPENSSL_EXTRA
+#ifndef NO_BIO
 /* Use the WOLFSSL read BIO for receiving data. This is set by the function
  * wolfSSL_set_bio and can also be set by wolfSSL_CTX_SetIORecv.
@@ -182,5 +190,5 @@
         WOLFSSL_MSG("Calling custom biowr");
         sent = ssl->biowr->method->writeCb(ssl->biowr, buf, sz);
-        if (sent < 0) {
+        if ((sent < 0) && (sent != WOLFSSL_CBIO_ERR_WANT_WRITE)) {
             return WOLFSSL_CBIO_ERR_GENERAL;
         }
@@ -205,5 +213,6 @@
     return sent;
 }
-#endif
+#endif /* !NO_BIO */
+#endif /* OPENSSL_EXTRA */
 
 
@@ -215,10 +224,14 @@
 int EmbedReceive(WOLFSSL *ssl, char *buf, int sz, void *ctx)
 {
+    int recvd;
+#ifndef WOLFSSL_LINUXKM
     int sd = *(int*)ctx;
-    int recvd;
+#else
+    struct socket *sd = (struct socket*)ctx;
+#endif
 
     recvd = wolfIO_Recv(sd, buf, sz, ssl->rflags);
     if (recvd < 0) {
-        int err = wolfSSL_LastError();
+        int err = wolfSSL_LastError(recvd);
         WOLFSSL_MSG("Embed Receive error");
 
@@ -257,6 +270,10 @@
 int EmbedSend(WOLFSSL* ssl, char *buf, int sz, void *ctx)
 {
+    int sent;
+#ifndef WOLFSSL_LINUXKM
     int sd = *(int*)ctx;
-    int sent;
+#else
+    struct socket *sd = (struct socket*)ctx;
+#endif
 
 #ifdef WOLFSSL_MAX_SEND_SZ
@@ -267,5 +284,5 @@
     sent = wolfIO_Send(sd, buf, sz, ssl->wflags);
     if (sent < 0) {
-        int err = wolfSSL_LastError();
+        int err = wolfSSL_LastError(sent);
         WOLFSSL_MSG("Embed Send error");
 
@@ -319,5 +336,7 @@
     WOLFSSL_ENTER("EmbedReceiveFrom()");
 
-    if (ssl->options.handShakeDone)
+    /* Don't use ssl->options.handShakeDone since it is true even if
+     * we are in the process of renegotiation */
+    if (ssl->options.handShakeState == HANDSHAKE_DONE)
         dtls_timeout = 0;
 
@@ -335,4 +354,16 @@
         }
     }
+#ifndef NO_ASN_TIME
+    else if(IsSCR(ssl)) {
+        if (ssl->dtls_start_timeout &&
+                LowResTimer() - ssl->dtls_start_timeout > (word32)dtls_timeout) {
+            ssl->dtls_start_timeout = 0;
+            return WOLFSSL_CBIO_ERR_TIMEOUT;
+        }
+        else if (!ssl->dtls_start_timeout) {
+            ssl->dtls_start_timeout = LowResTimer();
+        }
+    }
+#endif /* !NO_ASN_TIME */
 
     recvd = (int)RECVFROM_FUNCTION(sd, buf, sz, ssl->rflags,
@@ -342,5 +373,5 @@
 
     if (recvd < 0) {
-        err = wolfSSL_LastError();
+        err = wolfSSL_LastError(recvd);
         WOLFSSL_MSG("Embed Receive From error");
 
@@ -380,4 +411,7 @@
         }
     }
+#ifndef NO_ASN_TIME
+    ssl->dtls_start_timeout = 0;
+#endif /* !NO_ASN_TIME */
 
     return recvd;
@@ -404,5 +438,5 @@
 
     if (sent < 0) {
-        err = wolfSSL_LastError();
+        err = wolfSSL_LastError(sent);
         WOLFSSL_MSG("Embed Send To error");
 
@@ -452,5 +486,5 @@
 
     if (recvd < 0) {
-        err = wolfSSL_LastError();
+        err = wolfSSL_LastError(recvd);
         WOLFSSL_MSG("Embed Receive From error");
 
@@ -636,4 +670,26 @@
 #endif /* WOLFSSL_SESSION_EXPORT */
 #endif /* WOLFSSL_DTLS */
+
+#ifdef WOLFSSL_LINUXKM
+static int linuxkm_send(struct socket *socket, void *buf, int size,
+    unsigned int flags)
+{
+    int ret;
+    struct kvec vec = { .iov_base = buf, .iov_len = size };
+    struct msghdr msg = { .msg_flags = flags };
+    ret = kernel_sendmsg(socket, &msg, &vec, 1, size);
+    return ret;
+}
+
+static int linuxkm_recv(struct socket *socket, void *buf, int size,
+    unsigned int flags)
+{
+    int ret;
+    struct kvec vec = { .iov_base = buf, .iov_len = size };
+    struct msghdr msg = { .msg_flags = flags };
+    ret = kernel_recvmsg(socket, &msg, &vec, 1, size, msg.msg_flags);
+    return ret;
+}
+#endif /* WOLFSSL_LINUXKM */
 
 
@@ -733,4 +789,6 @@
             }
         }
+
+        WOLFSSL_MSG("Select error");
         return SOCKET_ERROR_E;
     }
@@ -780,4 +838,8 @@
 #endif
 
+    if (sockfd == NULL || ip == NULL) {
+        return -1;
+    }
+
     XMEMSET(&addr, 0, sizeof(addr));
 
@@ -822,16 +884,13 @@
 
     *sockfd = (SOCKET_T)socket(addr.ss_family, SOCK_STREAM, 0);
-
 #ifdef USE_WINDOWS_API
-    if (*sockfd == INVALID_SOCKET) {
+    if (*sockfd == SOCKET_INVALID)
+#else
+    if (*sockfd <= SOCKET_INVALID)
+#endif
+    {
         WOLFSSL_MSG("bad socket fd, out of fds?");
         return -1;
     }
-#else
-     if (*sockfd < 0) {
-         WOLFSSL_MSG("bad socket fd, out of fds?");
-         return -1;
-     }
-#endif
 
 #ifdef HAVE_IO_TIMEOUT
@@ -858,4 +917,6 @@
     if (ret != 0) {
         WOLFSSL_MSG("Responder tcp connect failed");
+        CloseSocket(*sockfd);
+        *sockfd = SOCKET_INVALID;
         return -1;
     }
@@ -1074,4 +1135,10 @@
             }
             else {
+                result = TranslateReturnCode(result, sfd);
+                result = wolfSSL_LastError(result);
+                if (result == SOCKET_EWOULDBLOCK || result == SOCKET_EAGAIN) {
+                    return OCSP_WANT_READ;
+                }
+
                 WOLFSSL_MSG("wolfIO_HttpProcessResponse recv http from peer failed");
                 return -1;
@@ -1339,5 +1406,5 @@
                         byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
 {
-    SOCKET_T sfd = 0;
+    SOCKET_T sfd = SOCKET_INVALID;
     word16   port;
     int      ret = -1;
@@ -1386,5 +1453,5 @@
 
             ret = wolfIO_TcpConnect(&sfd, domainName, port, io_timeout_sec);
-            if ((ret != 0) || ((int)sfd < 0)) {
+            if (ret != 0) {
                 WOLFSSL_MSG("OCSP Responder connection failed");
             }
@@ -1401,6 +1468,6 @@
                                                  HTTP_SCRATCH_BUFFER_SIZE, ctx);
             }
-
-            CloseSocket(sfd);
+            if (sfd != SOCKET_INVALID)
+                CloseSocket(sfd);
             XFREE(httpBuf, ctx, DYNAMIC_TYPE_OCSP);
         }
@@ -1460,5 +1527,5 @@
 int EmbedCrlLookup(WOLFSSL_CRL* crl, const char* url, int urlSz)
 {
-    SOCKET_T sfd = 0;
+    SOCKET_T sfd = SOCKET_INVALID;
     word16   port;
     int      ret = -1;
@@ -1492,5 +1559,5 @@
 
             ret = wolfIO_TcpConnect(&sfd, domainName, port, io_timeout_sec);
-            if ((ret != 0) || (sfd < 0)) {
+            if (ret != 0) {
                 WOLFSSL_MSG("CRL connection failed");
             }
@@ -1503,6 +1570,6 @@
                                                       HTTP_SCRATCH_BUFFER_SIZE);
             }
-
-            CloseSocket(sfd);
+            if (sfd != SOCKET_INVALID)
+                CloseSocket(sfd);
             XFREE(httpBuf, crl->heap, DYNAMIC_TYPE_CRL);
         }
@@ -2031,5 +2098,5 @@
 
     XMEMSET(mynewt_ctx, 0, sizeof(Mynewt_Ctx));
-    mynewt_ctx->mnMemBuffer = XMALLOC(mempool_bytes, 0, 0);
+    mynewt_ctx->mnMemBuffer = (void *)XMALLOC(mempool_bytes, 0, 0);
     if(!mynewt_ctx->mnMemBuffer) {
         mynewt_ctx_clear((void*)mynewt_ctx);
@@ -2082,5 +2149,5 @@
     struct os_mbuf *m;
     int read_sz = 0;
-    uint16_t total;
+    word16 total;
 
     if (mynewt_ctx == NULL || mynewt_ctx->mnSocket == NULL) {
@@ -2325,5 +2392,5 @@
     sock_udp_ep_t ep;
     int ret;
-    uint32_t timeout = wolfSSL_dtls_get_current_timeout(ssl) * 1000000;
+    word32 timeout = wolfSSL_dtls_get_current_timeout(ssl) * 1000000;
     sock_tls_t *ctx = (sock_tls_t *)_ctx;
     if (!ctx)
