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 */
