Index: asp3_tinet_ecnl_arm/trunk/wolfssl-3.12.2/wolfcrypt/src/asn.c
===================================================================
--- asp3_tinet_ecnl_arm/trunk/wolfssl-3.12.2/wolfcrypt/src/asn.c	(revision 352)
+++ asp3_tinet_ecnl_arm/trunk/wolfssl-3.12.2/wolfcrypt/src/asn.c	(revision 372)
@@ -35,4 +35,6 @@
  * RSA_DECODE_EXTRA: Decodes extra information in RSA public key.
  * WOLFSSL_CERT_GEN: Cert generation. Saves extra certificate info in GetName.
+ * WOLFSSL_NO_ASN_STRICT: Disable strict RFC compliance checks to
+    restore 3.13.0 behavior.
  * WOLFSSL_NO_OCSP_OPTIONAL_CERTS: Skip optional OCSP certs (responder issuer
     must still be trusted)
@@ -45,12 +47,10 @@
  * WOLFSSL_ALT_CERT_CHAINS: Allows matching multiple CA's to validate
     chain based on issuer and public key (includes signature confirmation)
+ * WOLFSSL_SMALL_CERT_VERIFY: Verify the certificate signature without using
+    DecodedCert. Doubles up on some code but allows smaller dynamic memory
+    usage.
 */
 
 #ifndef NO_ASN
-
-#ifdef HAVE_RTP_SYS
-    #include "os.h"           /* dc_rtc_api needs    */
-    #include "dc_rtc_api.h"   /* to get current time */
-#endif
 
 #include <wolfssl/wolfcrypt/asn.h>
@@ -61,4 +61,6 @@
 #include <wolfssl/wolfcrypt/pwdbased.h>
 #include <wolfssl/wolfcrypt/des3.h>
+#include <wolfssl/wolfcrypt/aes.h>
+#include <wolfssl/wolfcrypt/wc_encrypt.h>
 #include <wolfssl/wolfcrypt/logging.h>
 
@@ -72,4 +74,7 @@
 #endif
 
+#ifndef NO_PWDBASED
+    #include <wolfssl/wolfcrypt/aes.h>
+#endif
 #ifndef NO_RC4
     #include <wolfssl/wolfcrypt/arc4.h>
@@ -112,4 +117,5 @@
 #endif
 
+
 #ifdef _MSC_VER
     /* 4996 warning to use MS extensions e.g., strcpy_s instead of XSTRNCPY */
@@ -119,381 +125,25 @@
 #define ERROR_OUT(err, eLabel) { ret = (err); goto eLabel; }
 
-#ifndef NO_ASN_TIME
-#if defined(USER_TIME)
-    /* Use our gmtime and time_t/struct tm types.
-       Only needs seconds since EPOCH using XTIME function.
-       time_t XTIME(time_t * timer) {}
-    */
-    #define WOLFSSL_GMTIME
-    #define USE_WOLF_TM
-    #define USE_WOLF_TIME_T
-
-#elif defined(TIME_OVERRIDES)
-    /* Override XTIME() and XGMTIME() functionality.
-       Requires user to provide these functions:
-        time_t XTIME(time_t * timer) {}
-        struct tm* XGMTIME(const time_t* timer, struct tm* tmp) {}
-    */
-    #ifndef HAVE_TIME_T_TYPE
-        #define USE_WOLF_TIME_T
-    #endif
-    #ifndef HAVE_TM_TYPE
-        #define USE_WOLF_TM
-    #endif
-    #define NEED_TMP_TIME
-
-#elif defined(HAVE_RTP_SYS)
-    /* uses parital <time.h> structures */
-    #define XTIME(tl)       (0)
-    #define XGMTIME(c, t)   rtpsys_gmtime((c))
-
-#elif defined(MICRIUM)
-    #include <clk.h>
-    #include <time.h>
-    #define XTIME(t1)       micrium_time((t1))
-    #define WOLFSSL_GMTIME
-
-#elif defined(MICROCHIP_TCPIP_V5) || defined(MICROCHIP_TCPIP)
-    #include <time.h>
-    #define XTIME(t1)       pic32_time((t1))
-    #define XGMTIME(c, t)   gmtime((c))
-
-#elif defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX)
-    #define XTIME(t1)       mqx_time((t1))
-    #define HAVE_GMTIME_R
-
-#elif defined(FREESCALE_KSDK_BM) || defined(FREESCALE_FREE_RTOS) || \
-        defined(FREESCALE_KSDK_FREERTOS)
-    #include <time.h>
-    #ifndef XTIME
-        /*extern time_t ksdk_time(time_t* timer);*/
-        #define XTIME(t1)   ksdk_time((t1))
-    #endif
-    #define XGMTIME(c, t)   gmtime((c))
-
-#elif defined(WOLFSSL_ATMEL)
-    #define XTIME(t1)       atmel_get_curr_time_and_date((t1))
-    #define WOLFSSL_GMTIME
-    #define USE_WOLF_TM
-    #define USE_WOLF_TIME_T
-
-#elif defined(IDIRECT_DEV_TIME)
-    /*Gets the timestamp from cloak software owned by VT iDirect
-    in place of time() from <time.h> */
-    #include <time.h>
-    #define XTIME(t1)       idirect_time((t1))
-    #define XGMTIME(c, t)   gmtime((c))
-
-#elif defined(_WIN32_WCE)
-    #include <windows.h>
-    #define XTIME(t1)       windows_time((t1))
-    #define WOLFSSL_GMTIME
-#else
-
-    /* default */
-    /* uses complete <time.h> facility */
-    #include <time.h>
-#endif
-
-
-/* Map default time functions */
-#if !defined(XTIME) && !defined(TIME_OVERRIDES) && !defined(USER_TIME)
-    #define XTIME(tl)       time((tl))
-#endif
-#if !defined(XGMTIME) && !defined(TIME_OVERRIDES)
-    #if defined(WOLFSSL_GMTIME) || !defined(HAVE_GMTIME_R)
-        #define XGMTIME(c, t)   gmtime((c))
-    #else
-        #define XGMTIME(c, t)   gmtime_r((c), (t))
-        #define NEED_TMP_TIME
-    #endif
-#endif
-#if !defined(XVALIDATE_DATE) && !defined(HAVE_VALIDATE_DATE)
-    #define USE_WOLF_VALIDDATE
-    #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t))
-#endif
-
-/* wolf struct tm and time_t */
-#if defined(USE_WOLF_TM)
-    struct tm {
-        int  tm_sec;     /* seconds after the minute [0-60] */
-        int  tm_min;     /* minutes after the hour [0-59] */
-        int  tm_hour;    /* hours since midnight [0-23] */
-        int  tm_mday;    /* day of the month [1-31] */
-        int  tm_mon;     /* months since January [0-11] */
-        int  tm_year;    /* years since 1900 */
-        int  tm_wday;    /* days since Sunday [0-6] */
-        int  tm_yday;    /* days since January 1 [0-365] */
-        int  tm_isdst;   /* Daylight Savings Time flag */
-        long tm_gmtoff;  /* offset from CUT in seconds */
-        char *tm_zone;   /* timezone abbreviation */
+#ifdef HAVE_SELFTEST
+    #ifndef WOLFSSL_AES_KEY_SIZE_ENUM
+    enum Asn_Misc {
+        AES_IV_SIZE         = 16,
+        AES_128_KEY_SIZE    = 16,
+        AES_192_KEY_SIZE    = 24,
+        AES_256_KEY_SIZE    = 32
     };
-#endif /* USE_WOLF_TM */
-#if defined(USE_WOLF_TIME_T)
-    typedef long time_t;
-#endif
-
-/* forward declarations */
-#if defined(USER_TIME)
-    struct tm* gmtime(const time_t* timer);
-    extern time_t XTIME(time_t * timer);
-
-    #ifdef STACK_TRAP
-        /* for stack trap tracking, don't call os gmtime on OS X/linux,
-           uses a lot of stack spce */
-        extern time_t time(time_t * timer);
-        #define XTIME(tl)  time((tl))
-    #endif /* STACK_TRAP */
-
-#elif defined(TIME_OVERRIDES)
-    extern time_t XTIME(time_t * timer);
-    extern struct tm* XGMTIME(const time_t* timer, struct tm* tmp);
-#elif defined(WOLFSSL_GMTIME)
-    struct tm* gmtime(const time_t* timer);
-#endif
-
-
-#if defined(_WIN32_WCE)
-time_t windows_time(time_t* timer)
-{
-    SYSTEMTIME     sysTime;
-    FILETIME       fTime;
-    ULARGE_INTEGER intTime;
-    time_t         localTime;
-
-    if (timer == NULL)
-        timer = &localTime;
-
-    GetSystemTime(&sysTime);
-    SystemTimeToFileTime(&sysTime, &fTime);
-
-    XMEMCPY(&intTime, &fTime, sizeof(FILETIME));
-    /* subtract EPOCH */
-    intTime.QuadPart -= 0x19db1ded53e8000;
-    /* to secs */
-    intTime.QuadPart /= 10000000;
-    *timer = (time_t)intTime.QuadPart;
-
-    return *timer;
-}
-#endif /*  _WIN32_WCE */
-
-#if defined(WOLFSSL_GMTIME)
-struct tm* gmtime(const time_t* timer)
-{
-    #define YEAR0          1900
-    #define EPOCH_YEAR     1970
-    #define SECS_DAY       (24L * 60L * 60L)
-    #define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) %400)))
-    #define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365)
-
-    static const int _ytab[2][12] =
-    {
-        {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
-        {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
-    };
-
-    static struct tm st_time;
-    struct tm* ret = &st_time;
-    time_t secs = *timer;
-    unsigned long dayclock, dayno;
-    int year = EPOCH_YEAR;
-
-    dayclock = (unsigned long)secs % SECS_DAY;
-    dayno    = (unsigned long)secs / SECS_DAY;
-
-    ret->tm_sec  = (int) dayclock % 60;
-    ret->tm_min  = (int)(dayclock % 3600) / 60;
-    ret->tm_hour = (int) dayclock / 3600;
-    ret->tm_wday = (int) (dayno + 4) % 7;        /* day 0 a Thursday */
-
-    while(dayno >= (unsigned long)YEARSIZE(year)) {
-        dayno -= YEARSIZE(year);
-        year++;
-    }
-
-    ret->tm_year = year - YEAR0;
-    ret->tm_yday = (int)dayno;
-    ret->tm_mon  = 0;
-
-    while(dayno >= (unsigned long)_ytab[LEAPYEAR(year)][ret->tm_mon]) {
-        dayno -= _ytab[LEAPYEAR(year)][ret->tm_mon];
-        ret->tm_mon++;
-    }
-
-    ret->tm_mday  = (int)++dayno;
-    ret->tm_isdst = 0;
-
-    return ret;
-}
-#endif /* WOLFSSL_GMTIME */
-
-
-#if defined(HAVE_RTP_SYS)
-#define YEAR0          1900
-
-struct tm* rtpsys_gmtime(const time_t* timer)       /* has a gmtime() but hangs */
-{
-    static struct tm st_time;
-    struct tm* ret = &st_time;
-
-    DC_RTC_CALENDAR cal;
-    dc_rtc_time_get(&cal, TRUE);
-
-    ret->tm_year  = cal.year - YEAR0;       /* gm starts at 1900 */
-    ret->tm_mon   = cal.month - 1;          /* gm starts at 0 */
-    ret->tm_mday  = cal.day;
-    ret->tm_hour  = cal.hour;
-    ret->tm_min   = cal.minute;
-    ret->tm_sec   = cal.second;
-
-    return ret;
-}
-
-#endif /* HAVE_RTP_SYS */
-
-
-#if defined(MICROCHIP_TCPIP_V5) || defined(MICROCHIP_TCPIP)
-
-/*
- * time() is just a stub in Microchip libraries. We need our own
- * implementation. Use SNTP client to get seconds since epoch.
- */
-time_t pic32_time(time_t* timer)
-{
-#ifdef MICROCHIP_TCPIP_V5
-    DWORD sec = 0;
-#else
-    uint32_t sec = 0;
-#endif
-    time_t localTime;
-
-    if (timer == NULL)
-        timer = &localTime;
-
-#ifdef MICROCHIP_MPLAB_HARMONY
-    sec = TCPIP_SNTP_UTCSecondsGet();
-#else
-    sec = SNTPGetUTCSeconds();
-#endif
-    *timer = (time_t) sec;
-
-    return *timer;
-}
-
-#endif /* MICROCHIP_TCPIP || MICROCHIP_TCPIP_V5 */
-
-
-#if defined(MICRIUM)
-
-time_t micrium_time(time_t* timer)
-{
-    CLK_TS_SEC sec;
-
-    Clk_GetTS_Unix(&sec);
-
-    return (time_t) sec;
-}
-
-#endif /* MICRIUM */
-
-
-#if defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX)
-
-time_t mqx_time(time_t* timer)
-{
-    time_t localTime;
-    TIME_STRUCT time_s;
-
-    if (timer == NULL)
-        timer = &localTime;
-
-    _time_get(&time_s);
-    *timer = (time_t) time_s.SECONDS;
-
-    return *timer;
-}
-
-#endif /* FREESCALE_MQX || FREESCALE_KSDK_MQX */
-
-
-#if defined(WOLFSSL_TIRTOS)
-
-time_t XTIME(time_t * timer)
-{
-    time_t sec = 0;
-
-    sec = (time_t) Seconds_get();
-
-    if (timer != NULL)
-        *timer = sec;
-
-    return sec;
-}
-
-#endif /* WOLFSSL_TIRTOS */
-
-
-#if defined(WOLFSSL_XILINX)
-#include "xrtcpsu.h"
-
-time_t XTIME(time_t * timer)
-{
-    time_t sec = 0;
-    XRtcPsu_Config* con;
-    XRtcPsu         rtc;
-
-    con = XRtcPsu_LookupConfig(XPAR_XRTCPSU_0_DEVICE_ID);
-    if (con != NULL) {
-        if (XRtcPsu_CfgInitialize(&rtc, con, con->BaseAddr) == XST_SUCCESS) {
-            sec = (time_t)XRtcPsu_GetCurrentTime(&rtc);
-        }
-        else {
-            WOLFSSL_MSG("Unable to initialize RTC");
-        }
-    }
-
-    if (timer != NULL)
-        *timer = sec;
-
-    return sec;
-}
-
-#endif /* WOLFSSL_TIRTOS */
-
-
-/* two byte date/time, add to value */
-static INLINE void GetTime(int* value, const byte* date, int* idx)
-{
-    int i = *idx;
-
-    *value += btoi(date[i++]) * 10;
-    *value += btoi(date[i++]);
-
-    *idx = i;
-}
-
-
-#if defined(IDIRECT_DEV_TIME)
-
-extern time_t getTimestamp();
-
-time_t idirect_time(time_t * timer)
-{
-    time_t sec = getTimestamp();
-
-    if (timer != NULL)
-        *timer = sec;
-
-    return sec;
-}
-
-#endif /* IDIRECT_DEV_TIME */
-
-#endif /* !NO_ASN_TIME */
-
+#endif
+#endif
 
 WOLFSSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len,
                            word32 maxIdx)
+{
+    return GetLength_ex(input, inOutIdx, len, maxIdx, 1);
+}
+
+
+/* give option to check length value found against index. 1 to check 0 to not */
+WOLFSSL_LOCAL int GetLength_ex(const byte* input, word32* inOutIdx, int* len,
+                           word32 maxIdx, int check)
 {
     int     length = 0;
@@ -525,5 +175,5 @@
         length = b;
 
-    if ((idx + length) > maxIdx) {   /* for user of length */
+    if (check && (idx + length) > maxIdx) {   /* for user of length */
         WOLFSSL_MSG("GetLength value exceeds buffer length");
         return BUFFER_E;
@@ -534,4 +184,27 @@
         *len = length;
 
+    return length;
+}
+
+
+static int GetASNHeader_ex(const byte* input, byte tag, word32* inOutIdx, int* len,
+                        word32 maxIdx, int check)
+{
+    word32 idx = *inOutIdx;
+    byte   b;
+    int    length;
+
+    if ((idx + 1) > maxIdx)
+        return BUFFER_E;
+
+    b = input[idx++];
+    if (b != tag)
+        return ASN_PARSE_E;
+
+    if (GetLength_ex(input, &idx, &length, maxIdx, check) < 0)
+        return ASN_PARSE_E;
+
+    *len      = length;
+    *inOutIdx = idx;
     return length;
 }
@@ -552,22 +225,7 @@
                         word32 maxIdx)
 {
-    word32 idx = *inOutIdx;
-    byte   b;
-    int    length;
-
-    if ((idx + 1) > maxIdx)
-        return BUFFER_E;
-
-    b = input[idx++];
-    if (b != tag)
-        return ASN_PARSE_E;
-
-    if (GetLength(input, &idx, &length, maxIdx) < 0)
-        return ASN_PARSE_E;
-
-    *len      = length;
-    *inOutIdx = idx;
-    return length;
-}
+    return GetASNHeader_ex(input, tag, inOutIdx, len, maxIdx, 1);
+}
+
 
 WOLFSSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len,
@@ -576,4 +234,12 @@
     return GetASNHeader(input, ASN_SEQUENCE | ASN_CONSTRUCTED, inOutIdx, len,
                         maxIdx);
+}
+
+
+WOLFSSL_LOCAL int GetSequence_ex(const byte* input, word32* inOutIdx, int* len,
+                           word32 maxIdx, int check)
+{
+    return GetASNHeader_ex(input, ASN_SEQUENCE | ASN_CONSTRUCTED, inOutIdx, len,
+                        maxIdx, check);
 }
 
@@ -724,6 +390,4 @@
                 return ASN_PARSE_E;
         }
-        else if ((input[*inOutIdx] & 0x80) == 0x80)
-            return ASN_PARSE_E;
     }
 
@@ -759,8 +423,123 @@
 }
 
+
+#if !defined(NO_DSA) && !defined(NO_SHA)
+static char sigSha1wDsaName[] = "SHAwDSA";
+#endif /* NO_DSA */
+#ifndef NO_RSA
+#ifdef WOLFSSL_MD2
+    static char sigMd2wRsaName[] = "MD2wRSA";
+#endif
+#ifndef NO_MD5
+    static char sigMd5wRsaName[] = "MD5wRSA";
+#endif
+#ifndef NO_SHA
+    static char sigSha1wRsaName[] = "SHAwRSA";
+#endif
+#ifdef WOLFSSL_SHA224
+    static char sigSha224wRsaName[] = "SHA224wRSA";
+#endif
+#ifndef NO_SHA256
+    static char sigSha256wRsaName[] = "SHA256wRSA";
+#endif
+#ifdef WOLFSSL_SHA384
+    static char sigSha384wRsaName[] = "SHA384wRSA";
+#endif
+#ifdef WOLFSSL_SHA512
+    static char sigSha512wRsaName[] = "SHA512wRSA";
+#endif
+#endif /* NO_RSA */
+#ifdef HAVE_ECC
+#ifndef NO_SHA
+    static char sigSha1wEcdsaName[] = "SHAwECDSA";
+#endif
+#ifdef WOLFSSL_SHA224
+    static char sigSha224wEcdsaName[] = "SHA224wECDSA";
+#endif
+#ifndef NO_SHA256
+    static char sigSha256wEcdsaName[] = "SHA256wECDSA";
+#endif
+#ifdef WOLFSSL_SHA384
+    static char sigSha384wEcdsaName[] = "SHA384wECDSA";
+#endif
+#ifdef WOLFSSL_SHA512
+    static char sigSha512wEcdsaName[] = "SHA512wECDSA";
+#endif
+#endif /* HAVE_ECC */
+static char sigUnknownName[] = "Unknown";
+
+
+/* Get the human readable string for a signature type
+ *
+ * oid  Oid value for signature
+ */
+char* GetSigName(int oid) {
+    switch (oid) {
+    #if !defined(NO_DSA) && !defined(NO_SHA)
+        case CTC_SHAwDSA:
+            return sigSha1wDsaName;
+    #endif /* NO_DSA && NO_SHA */
+    #ifndef NO_RSA
+        #ifdef WOLFSSL_MD2
+        case CTC_MD2wRSA:
+            return sigMd2wRsaName;
+        #endif
+        #ifndef NO_MD5
+        case CTC_MD5wRSA:
+            return sigMd5wRsaName;
+        #endif
+        #ifndef NO_SHA
+        case CTC_SHAwRSA:
+            return sigSha1wRsaName;
+        #endif
+        #ifdef WOLFSSL_SHA224
+        case CTC_SHA224wRSA:
+            return sigSha224wRsaName;
+        #endif
+        #ifndef NO_SHA256
+        case CTC_SHA256wRSA:
+            return sigSha256wRsaName;
+        #endif
+        #ifdef WOLFSSL_SHA384
+        case CTC_SHA384wRSA:
+            return sigSha384wRsaName;
+        #endif
+        #ifdef WOLFSSL_SHA512
+        case CTC_SHA512wRSA:
+            return sigSha512wRsaName;
+        #endif
+    #endif /* NO_RSA */
+    #ifdef HAVE_ECC
+        #ifndef NO_SHA
+        case CTC_SHAwECDSA:
+            return sigSha1wEcdsaName;
+        #endif
+        #ifdef WOLFSSL_SHA224
+        case CTC_SHA224wECDSA:
+            return sigSha224wEcdsaName;
+        #endif
+        #ifndef NO_SHA256
+        case CTC_SHA256wECDSA:
+            return sigSha256wEcdsaName;
+        #endif
+        #ifdef WOLFSSL_SHA384
+        case CTC_SHA384wECDSA:
+            return sigSha384wEcdsaName;
+        #endif
+        #ifdef WOLFSSL_SHA512
+        case CTC_SHA512wECDSA:
+            return sigSha512wEcdsaName;
+        #endif
+    #endif /* HAVE_ECC */
+        default:
+            return sigUnknownName;
+    }
+}
+
+
 #if !defined(NO_DSA) || defined(HAVE_ECC) || \
    (!defined(NO_RSA) && \
         (defined(WOLFSSL_CERT_GEN) || \
-        (defined(WOLFSSL_KEY_GEN) && !defined(HAVE_USER_RSA))))
+        ((defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA)) && !defined(HAVE_USER_RSA))))
 /* Set the DER/BER encoding of the ASN.1 INTEGER header.
  *
@@ -786,5 +565,5 @@
 
 #if !defined(NO_DSA) || defined(HAVE_ECC) || defined(WOLFSSL_CERT_GEN) || \
-    (defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) && !defined(HAVE_USER_RSA))
+    ((defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA)) && !defined(NO_RSA) && !defined(HAVE_USER_RSA))
 /* Set the DER/BER encoding of the ASN.1 INTEGER element with an mp_int.
  * The number is assumed to be positive.
@@ -906,4 +685,50 @@
     return *number;
 }
+
+
+/* Set small integer, 32 bits or less. DER encoding with no leading 0s
+ * returns total amount written including ASN tag and length byte on success */
+static int SetShortInt(byte* input, word32* inOutIdx, word32 number,
+                              word32 maxIdx)
+{
+    word32 idx = *inOutIdx;
+    word32 len = 0;
+    int    i;
+    byte ar[MAX_LENGTH_SZ];
+
+    /* check for room for type and length bytes */
+    if ((idx + 2) > maxIdx)
+        return BUFFER_E;
+
+    input[idx++] = ASN_INTEGER;
+    idx++; /* place holder for length byte */
+    if (MAX_LENGTH_SZ + idx > maxIdx)
+        return ASN_PARSE_E;
+
+    /* find first non zero byte */
+    XMEMSET(ar, 0, MAX_LENGTH_SZ);
+    c32toa(number, ar);
+    for (i = 0; i < MAX_LENGTH_SZ; i++) {
+        if (ar[i] != 0) {
+            break;
+        }
+    }
+
+    /* handle case of 0 */
+    if (i == MAX_LENGTH_SZ) {
+        input[idx++] = 0; len++;
+    }
+
+    for (; i < MAX_LENGTH_SZ && idx < maxIdx; i++) {
+        input[idx++] = ar[i]; len++;
+    }
+
+    /* jump back to beginning of input buffer using unaltered inOutIdx value
+     * and set number of bytes for integer, then update the index value */
+    input[*inOutIdx + 1] = (byte)len;
+    *inOutIdx = idx;
+
+    return len + 2; /* size of integer bytes plus ASN TAG and length byte */
+}
 #endif /* !NO_PWDBASED */
 
@@ -959,4 +784,24 @@
     return 0;
 }
+
+#if (!defined(WOLFSSL_KEY_GEN) && !defined(OPENSSL_EXTRA) && defined(RSA_LOW_MEM)) \
+    || defined(WOLFSSL_RSA_PUBLIC_ONLY)
+#if !defined(NO_RSA) && !defined(HAVE_USER_RSA)
+static int SkipInt(const byte* input, word32* inOutIdx, word32 maxIdx)
+{
+    word32 idx = *inOutIdx;
+    int    ret;
+    int    length;
+
+    ret = GetASNInt(input, &idx, &length, maxIdx);
+    if (ret != 0)
+        return ret;
+
+    *inOutIdx = idx + length;
+
+    return 0;
+}
+#endif
+#endif
 
 static int CheckBitString(const byte* input, word32* inOutIdx, int* len,
@@ -1008,9 +853,11 @@
 }
 
-#if (!defined(NO_RSA) && (defined(WOLFSSL_CERT_GEN) || \
-                          (defined(WOLFSSL_KEY_GEN) && \
-                           !defined(HAVE_USER_RSA)))) || \
-    (defined(HAVE_ECC) && (defined(WOLFSSL_CERT_GEN) || \
-                           defined(WOLFSSL_KEY_GEN)))
+/* RSA (with CertGen or KeyGen) OR ECC OR ED25519 (with CertGen or KeyGen) */
+#if (!defined(NO_RSA) && !defined(HAVE_USER_RSA) && \
+        (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA))) || \
+    (defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT)) || \
+    (defined(HAVE_ED25519) && \
+        (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA)))
+
 /* Set the DER/BER encoding of the ASN.1 BIT_STRING header.
  *
@@ -1032,4 +879,216 @@
     return idx;
 }
+#endif /* !NO_RSA || HAVE_ECC || HAVE_ED25519 */
+
+#ifdef ASN_BER_TO_DER
+/* Convert a BER encoding with indefinite length items to DER.
+ *
+ * ber    BER encoded data.
+ * berSz  Length of BER encoded data.
+ * der    Buffer to hold DER encoded version of data.
+ *        NULL indicates only the length is required.
+ * derSz  The size of the buffer to hold the DER encoded data.
+ *        Will be set if der is NULL, otherwise the value is checked as der is
+ *        filled.
+ * returns ASN_PARSE_E if the BER data is invalid and BAD_FUNC_ARG if ber or
+ * derSz are NULL.
+ */
+int wc_BerToDer(const byte* ber, word32 berSz, byte* der, word32* derSz)
+{
+    int ret;
+    word32 i, j, k;
+    int len, l;
+    int indef;
+    int depth = 0;
+    byte type;
+    word32 cnt, sz;
+    word32 outSz = 0;
+    byte lenBytes[4];
+
+    if (ber == NULL || derSz == NULL)
+        return BAD_FUNC_ARG;
+
+    sz = 0;
+    outSz = *derSz;
+
+    for (i = 0, j = 0; i < berSz; ) {
+        /* Check that there is data for an ASN item to parse. */
+        if (i + 2 > berSz)
+            return ASN_PARSE_E;
+
+        /* End Of Content (EOC) mark end of indefinite length items.
+         * EOCs are not encoded in DER.
+         * Keep track of no. indefinite length items that have not been
+         * terminated in depth.
+         */
+        if (ber[i] == 0 && ber[i+1] == 0) {
+            if (depth == 0)
+                break;
+            if (--depth == 0)
+                break;
+
+            i += 2;
+            continue;
+        }
+
+        /* Indefinite length is encoded as: 0x80 */
+        type = ber[i];
+        indef = ber[i+1] == ASN_INDEF_LENGTH;
+        if (indef && (type & 0xC0) == 0 &&
+                                   ber[i] != (ASN_SEQUENCE | ASN_CONSTRUCTED) &&
+                                   ber[i] != (ASN_SET      | ASN_CONSTRUCTED)) {
+            /* Indefinite length OCTET STRING or other simple type.
+             * Put all the data into one entry.
+             */
+
+            /* Type no longer constructed. */
+            type &= ~ASN_CONSTRUCTED;
+            if (der != NULL) {
+                /* Ensure space for type. */
+                if (j + 1 >= outSz)
+                    return BUFFER_E;
+                der[j] = type;
+            }
+            i++; j++;
+            /* Skip indefinite length. */
+            i++;
+
+            /* There must be further ASN1 items to combine. */
+            if (i + 2 > berSz)
+                return ASN_PARSE_E;
+
+            /* Calculate length of combined data. */
+            len = 0;
+            k = i;
+            while (ber[k] != 0x00) {
+                /* Each ASN item must be the same type as the constructed. */
+                if (ber[k] != type)
+                    return ASN_PARSE_E;
+                k++;
+
+                ret = GetLength(ber, &k, &l, berSz);
+                if (ret < 0)
+                    return ASN_PARSE_E;
+                k += l;
+                len += l;
+
+                /* Must at least have terminating EOC. */
+                if (k + 2 > berSz)
+                    return ASN_PARSE_E;
+            }
+            /* Ensure a valid EOC ASN item. */
+            if (ber[k+1] != 0x00)
+                return ASN_PARSE_E;
+
+            if (der == NULL) {
+                /* Add length of ASN item length encoding and data. */
+                j += SetLength(len, lenBytes);
+                j += len;
+            }
+            else {
+                /* Check space for encoded length. */
+                if (SetLength(len, lenBytes) > outSz - j)
+                    return BUFFER_E;
+                /* Encode new length. */
+                j += SetLength(len, der + j);
+
+                /* Encode data in single item. */
+                k = i;
+                while (ber[k] != 0x00) {
+                    /* Skip ASN type. */
+                    k++;
+
+                    /* Find length of data in ASN item. */
+                    ret = GetLength(ber, &k, &l, berSz);
+                    if (ret < 0)
+                        return ASN_PARSE_E;
+
+                    /* Ensure space for data and copy in. */
+                    if (j + l > outSz)
+                        return BUFFER_E;
+                    XMEMCPY(der + j, ber + k, l);
+                    k += l; j += l;
+                }
+            }
+            /* Continue conversion after EOC. */
+            i = k + 2;
+
+            continue;
+        }
+
+        if (der != NULL) {
+            /* Ensure space for type and at least one byte of length. */
+            if (j + 1 >= outSz)
+                return BUFFER_E;
+            /* Put in type. */
+            der[j] = ber[i];
+        }
+        i++; j++;
+
+        if (indef) {
+            /* Skip indefinite length. */
+            i++;
+            /* Calculate the size of the data inside constructed. */
+            ret = wc_BerToDer(ber + i, berSz - i, NULL, &sz);
+            if (ret != LENGTH_ONLY_E)
+                return ret;
+
+            if (der != NULL) {
+                /* Ensure space for encoded length. */
+                if (SetLength(sz, lenBytes) > outSz - j)
+                    return BUFFER_E;
+                /* Encode real length. */
+                j += SetLength(sz, der + j);
+            }
+            else {
+                /* Add size of encoded length. */
+                j += SetLength(sz, lenBytes);
+            }
+
+            /* Another EOC to find. */
+            depth++;
+        }
+        else {
+            /* Get the size of the encode length and length value. */
+            cnt = i;
+            ret = GetLength(ber, &cnt, &len, berSz);
+            if (ret < 0)
+                return ASN_PARSE_E;
+            cnt -= i;
+
+            /* Check there is enough data to copy out. */
+            if (i + cnt + len > berSz)
+                return ASN_PARSE_E;
+
+            if (der != NULL) {
+                /* Ensure space in DER buffer. */
+                if (j + cnt + len > outSz)
+                    return BUFFER_E;
+                /* Copy length and data into DER buffer. */
+                XMEMCPY(der + j, ber + i, cnt + len);
+            }
+            /* Continue conversion after this ASN item. */
+            i += cnt + len;
+            j += cnt + len;
+        }
+    }
+
+    if (depth >= 1)
+        return ASN_PARSE_E;
+
+    /* Return length if no buffer to write to. */
+    if (der == NULL) {
+        *derSz = j;
+        return LENGTH_ONLY_E;
+    }
+
+    return 0;
+}
+#endif
+
+#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN)
+
+#if (!defined(NO_RSA) && !defined(HAVE_USER_RSA)) || \
+    defined(HAVE_ECC) || defined(HAVE_ED25519)
 
 #ifdef WOLFSSL_CERT_EXT
@@ -1067,37 +1126,91 @@
 }
 #endif /* WOLFSSL_CERT_EXT */
-#endif /* !NO_RSA && (WOLFSSL_CERT_GEN || (WOLFSSL_KEY_GEN &&
-                                           !HAVE_USER_RSA)) */
+#endif /* !NO_RSA || HAVE_ECC || HAVE_ED25519 */
+#endif /* WOLFSSL_CERT_GEN || WOLFSSL_KEY_GEN */
 
 
 
 /* hashType */
+#ifdef WOLFSSL_MD2
 static const byte hashMd2hOid[] = {42, 134, 72, 134, 247, 13, 2, 2};
+#endif
+#ifndef NO_MD5
 static const byte hashMd5hOid[] = {42, 134, 72, 134, 247, 13, 2, 5};
+#endif
+#ifndef NO_SHA
 static const byte hashSha1hOid[] = {43, 14, 3, 2, 26};
+#endif
+#ifdef WOLFSSL_SHA224
 static const byte hashSha224hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 4};
+#endif
+#ifndef NO_SHA256
 static const byte hashSha256hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 1};
+#endif
+#ifdef WOLFSSL_SHA384
 static const byte hashSha384hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 2};
+#endif
+#ifdef WOLFSSL_SHA512
 static const byte hashSha512hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 3};
+#endif
+
+/* hmacType */
+#ifndef NO_HMAC
+    #ifdef WOLFSSL_SHA224
+    static const byte hmacSha224Oid[] = {42, 134, 72, 134, 247, 13, 2, 8};
+    #endif
+    #ifndef NO_SHA256
+    static const byte hmacSha256Oid[] = {42, 134, 72, 134, 247, 13, 2, 9};
+    #endif
+    #ifdef WOLFSSL_SHA384
+    static const byte hmacSha384Oid[] = {42, 134, 72, 134, 247, 13, 2, 10};
+    #endif
+    #ifdef WOLFSSL_SHA512
+    static const byte hmacSha512Oid[] = {42, 134, 72, 134, 247, 13, 2, 11};
+    #endif
+#endif
 
 /* sigType */
-#ifndef NO_DSA
+#if !defined(NO_DSA) && !defined(NO_SHA)
     static const byte sigSha1wDsaOid[] = {42, 134, 72, 206, 56, 4, 3};
 #endif /* NO_DSA */
 #ifndef NO_RSA
+    #ifdef WOLFSSL_MD2
     static const byte sigMd2wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1, 2};
+    #endif
+    #ifndef NO_MD5
     static const byte sigMd5wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1, 4};
+    #endif
+    #ifndef NO_SHA
     static const byte sigSha1wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1, 5};
+    #endif
+    #ifdef WOLFSSL_SHA224
     static const byte sigSha224wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1,14};
+    #endif
+    #ifndef NO_SHA256
     static const byte sigSha256wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1,11};
+    #endif
+    #ifdef WOLFSSL_SHA384
     static const byte sigSha384wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1,12};
+    #endif
+    #ifdef WOLFSSL_SHA512
     static const byte sigSha512wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1,13};
+    #endif
 #endif /* NO_RSA */
 #ifdef HAVE_ECC
+    #ifndef NO_SHA
     static const byte sigSha1wEcdsaOid[] = {42, 134, 72, 206, 61, 4, 1};
+    #endif
+    #ifdef WOLFSSL_SHA224
     static const byte sigSha224wEcdsaOid[] = {42, 134, 72, 206, 61, 4, 3, 1};
+    #endif
+    #ifndef NO_SHA256
     static const byte sigSha256wEcdsaOid[] = {42, 134, 72, 206, 61, 4, 3, 2};
+    #endif
+    #ifdef WOLFSSL_SHA384
     static const byte sigSha384wEcdsaOid[] = {42, 134, 72, 206, 61, 4, 3, 3};
+    #endif
+    #ifdef WOLFSSL_SHA512
     static const byte sigSha512wEcdsaOid[] = {42, 134, 72, 206, 61, 4, 3, 4};
+    #endif
 #endif /* HAVE_ECC */
 #ifdef HAVE_ED25519
@@ -1127,23 +1240,76 @@
 #endif /* HAVE_ECC */
 
+#ifdef HAVE_AES_CBC
 /* blkType */
+    #ifdef WOLFSSL_AES_128
 static const byte blkAes128CbcOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 2};
+    #endif
+    #ifdef WOLFSSL_AES_192
 static const byte blkAes192CbcOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 22};
+    #endif
+    #ifdef WOLFSSL_AES_256
 static const byte blkAes256CbcOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 42};
+    #endif
+#endif /* HAVE_AES_CBC */
+#ifdef HAVE_AESGCM
+    #ifdef WOLFSSL_AES_128
+    static const byte blkAes128GcmOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 6};
+    #endif
+    #ifdef WOLFSSL_AES_192
+    static const byte blkAes192GcmOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 26};
+    #endif
+    #ifdef WOLFSSL_AES_256
+    static const byte blkAes256GcmOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 46};
+    #endif
+#endif /* HAVE_AESGCM */
+#ifdef HAVE_AESCCM
+    #ifdef WOLFSSL_AES_128
+    static const byte blkAes128CcmOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 7};
+    #endif
+    #ifdef WOLFSSL_AES_192
+    static const byte blkAes192CcmOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 27};
+    #endif
+    #ifdef WOLFSSL_AES_256
+    static const byte blkAes256CcmOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 47};
+    #endif
+#endif /* HAVE_AESCCM */
+
+#ifndef NO_DES3
 static const byte blkDesCbcOid[]  = {43, 14, 3, 2, 7};
 static const byte blkDes3CbcOid[] = {42, 134, 72, 134, 247, 13, 3, 7};
+#endif
 
 /* keyWrapType */
+#ifdef WOLFSSL_AES_128
 static const byte wrapAes128Oid[] = {96, 134, 72, 1, 101, 3, 4, 1, 5};
+#endif
+#ifdef WOLFSSL_AES_192
 static const byte wrapAes192Oid[] = {96, 134, 72, 1, 101, 3, 4, 1, 25};
+#endif
+#ifdef WOLFSSL_AES_256
 static const byte wrapAes256Oid[] = {96, 134, 72, 1, 101, 3, 4, 1, 45};
+#endif
+#ifdef HAVE_PKCS7
+/* From RFC 3211 */
+static const byte wrapPwriKekOid[] = {42, 134, 72, 134, 247, 13, 1, 9, 16, 3,9};
+#endif
 
 /* cmsKeyAgreeType */
+#ifndef NO_SHA
 static const byte dhSinglePass_stdDH_sha1kdf_Oid[]   =
                                           {43, 129, 5, 16, 134, 72, 63, 0, 2};
+#endif
+#ifdef WOLFSSL_SHA224
 static const byte dhSinglePass_stdDH_sha224kdf_Oid[] = {43, 129, 4, 1, 11, 0};
+#endif
+#ifndef NO_SHA256
 static const byte dhSinglePass_stdDH_sha256kdf_Oid[] = {43, 129, 4, 1, 11, 1};
+#endif
+#ifdef WOLFSSL_SHA384
 static const byte dhSinglePass_stdDH_sha384kdf_Oid[] = {43, 129, 4, 1, 11, 2};
+#endif
+#ifdef WOLFSSL_SHA512
 static const byte dhSinglePass_stdDH_sha512kdf_Oid[] = {43, 129, 4, 1, 11, 3};
+#endif
 
 /* ocspType */
@@ -1164,8 +1330,12 @@
 static const byte extInhibitAnyOid[] = {85, 29, 54};
 static const byte extExtKeyUsageOid[] = {85, 29, 37};
+#ifndef IGNORE_NAME_CONSTRAINTS
 static const byte extNameConsOid[] = {85, 29, 30};
+#endif
 
 /* certAuthInfoType */
+#ifdef HAVE_OCSP
 static const byte extAuthInfoOcspOid[] = {43, 6, 1, 5, 5, 7, 48, 1};
+#endif
 static const byte extAuthInfoCaIssuerOid[] = {43, 6, 1, 5, 5, 7, 48, 2};
 
@@ -1188,5 +1358,26 @@
 static const byte pbkdf2Oid[] = {42, 134, 72, 134, 247, 13, 1, 5, 12};
 
-static const byte* OidFromId(word32 id, word32 type, word32* oidSz)
+/* PKCS5 */
+#if !defined(NO_DES3) && !defined(NO_SHA)
+static const byte pbeSha1Des[] = {42, 134, 72, 134, 247, 13, 1, 5, 10};
+#endif
+static const byte pbes2[] = {42, 134, 72, 134, 247, 13, 1, 5, 13};
+
+/* PKCS12 */
+#if !defined(NO_RC4) && !defined(NO_SHA)
+static const byte pbeSha1RC4128[] = {42, 134, 72, 134, 247, 13, 1, 12, 1, 1};
+#endif
+#if !defined(NO_DES3) && !defined(NO_SHA)
+static const byte pbeSha1Des3[] = {42, 134, 72, 134, 247, 13, 1, 12, 1, 3};
+#endif
+
+#ifdef HAVE_LIBZ
+/* zlib compression */
+static const byte zlibCompress[] = {42, 134, 72, 134, 247, 13, 1, 9, 16, 3, 8};
+#endif
+
+
+/* returns a pointer to the OID string on success and NULL on fail */
+const byte* OidFromId(word32 id, word32 type, word32* oidSz)
 {
     const byte* oid = NULL;
@@ -1198,32 +1389,46 @@
         case oidHashType:
             switch (id) {
+            #ifdef WOLFSSL_MD2
                 case MD2h:
                     oid = hashMd2hOid;
                     *oidSz = sizeof(hashMd2hOid);
                     break;
+            #endif
+            #ifndef NO_MD5
                 case MD5h:
                     oid = hashMd5hOid;
                     *oidSz = sizeof(hashMd5hOid);
                     break;
+            #endif
+            #ifndef NO_SHA
                 case SHAh:
                     oid = hashSha1hOid;
                     *oidSz = sizeof(hashSha1hOid);
                     break;
+            #endif
+            #ifdef WOLFSSL_SHA224
                 case SHA224h:
                     oid = hashSha224hOid;
                     *oidSz = sizeof(hashSha224hOid);
                     break;
+            #endif
+            #ifndef NO_SHA256
                 case SHA256h:
                     oid = hashSha256hOid;
                     *oidSz = sizeof(hashSha256hOid);
                     break;
+            #endif
+            #ifdef WOLFSSL_SHA384
                 case SHA384h:
                     oid = hashSha384hOid;
                     *oidSz = sizeof(hashSha384hOid);
                     break;
+            #endif
+            #ifdef WOLFSSL_SHA512
                 case SHA512h:
                     oid = hashSha512hOid;
                     *oidSz = sizeof(hashSha512hOid);
                     break;
+            #endif
             }
             break;
@@ -1231,5 +1436,5 @@
         case oidSigType:
             switch (id) {
-                #ifndef NO_DSA
+                #if !defined(NO_DSA) && !defined(NO_SHA)
                 case CTC_SHAwDSA:
                     oid = sigSha1wDsaOid;
@@ -1238,54 +1443,78 @@
                 #endif /* NO_DSA */
                 #ifndef NO_RSA
+                #ifdef WOLFSSL_MD2
                 case CTC_MD2wRSA:
                     oid = sigMd2wRsaOid;
                     *oidSz = sizeof(sigMd2wRsaOid);
                     break;
+                #endif
+                #ifndef NO_MD5
                 case CTC_MD5wRSA:
                     oid = sigMd5wRsaOid;
                     *oidSz = sizeof(sigMd5wRsaOid);
                     break;
+                #endif
+                #ifndef NO_SHA
                 case CTC_SHAwRSA:
                     oid = sigSha1wRsaOid;
                     *oidSz = sizeof(sigSha1wRsaOid);
                     break;
+                #endif
+                #ifdef WOLFSSL_SHA224
                 case CTC_SHA224wRSA:
                     oid = sigSha224wRsaOid;
                     *oidSz = sizeof(sigSha224wRsaOid);
                     break;
+                #endif
+                #ifndef NO_SHA256
                 case CTC_SHA256wRSA:
                     oid = sigSha256wRsaOid;
                     *oidSz = sizeof(sigSha256wRsaOid);
                     break;
+                #endif
+                #ifdef WOLFSSL_SHA384
                 case CTC_SHA384wRSA:
                     oid = sigSha384wRsaOid;
                     *oidSz = sizeof(sigSha384wRsaOid);
                     break;
+                #endif
+                #ifdef WOLFSSL_SHA512
                 case CTC_SHA512wRSA:
                     oid = sigSha512wRsaOid;
                     *oidSz = sizeof(sigSha512wRsaOid);
                     break;
+                #endif /* WOLFSSL_SHA512 */
                 #endif /* NO_RSA */
                 #ifdef HAVE_ECC
+                #ifndef NO_SHA
                 case CTC_SHAwECDSA:
                     oid = sigSha1wEcdsaOid;
                     *oidSz = sizeof(sigSha1wEcdsaOid);
                     break;
+                #endif
+                #ifdef WOLFSSL_SHA224
                 case CTC_SHA224wECDSA:
                     oid = sigSha224wEcdsaOid;
                     *oidSz = sizeof(sigSha224wEcdsaOid);
                     break;
+                #endif
+                #ifndef NO_SHA256
                 case CTC_SHA256wECDSA:
                     oid = sigSha256wEcdsaOid;
                     *oidSz = sizeof(sigSha256wEcdsaOid);
                     break;
+                #endif
+                #ifdef WOLFSSL_SHA384
                 case CTC_SHA384wECDSA:
                     oid = sigSha384wEcdsaOid;
                     *oidSz = sizeof(sigSha384wEcdsaOid);
                     break;
+                #endif
+                #ifdef WOLFSSL_SHA512
                 case CTC_SHA512wECDSA:
                     oid = sigSha512wEcdsaOid;
                     *oidSz = sizeof(sigSha512wEcdsaOid);
                     break;
+                #endif
                 #endif /* HAVE_ECC */
                 #ifdef HAVE_ED25519
@@ -1347,16 +1576,65 @@
         case oidBlkType:
             switch (id) {
+    #ifdef HAVE_AES_CBC
+        #ifdef WOLFSSL_AES_128
                 case AES128CBCb:
                     oid = blkAes128CbcOid;
                     *oidSz = sizeof(blkAes128CbcOid);
                     break;
+        #endif
+        #ifdef WOLFSSL_AES_192
                 case AES192CBCb:
                     oid = blkAes192CbcOid;
                     *oidSz = sizeof(blkAes192CbcOid);
                     break;
+        #endif
+        #ifdef WOLFSSL_AES_256
                 case AES256CBCb:
                     oid = blkAes256CbcOid;
                     *oidSz = sizeof(blkAes256CbcOid);
                     break;
+        #endif
+    #endif /* HAVE_AES_CBC */
+    #ifdef HAVE_AESGCM
+        #ifdef WOLFSSL_AES_128
+                case AES128GCMb:
+                    oid = blkAes128GcmOid;
+                    *oidSz = sizeof(blkAes128GcmOid);
+                    break;
+        #endif
+        #ifdef WOLFSSL_AES_192
+                case AES192GCMb:
+                    oid = blkAes192GcmOid;
+                    *oidSz = sizeof(blkAes192GcmOid);
+                    break;
+        #endif
+        #ifdef WOLFSSL_AES_256
+                case AES256GCMb:
+                    oid = blkAes256GcmOid;
+                    *oidSz = sizeof(blkAes256GcmOid);
+                    break;
+        #endif
+    #endif /* HAVE_AESGCM */
+    #ifdef HAVE_AESCCM
+        #ifdef WOLFSSL_AES_128
+                case AES128CCMb:
+                    oid = blkAes128CcmOid;
+                    *oidSz = sizeof(blkAes128CcmOid);
+                    break;
+        #endif
+        #ifdef WOLFSSL_AES_192
+                case AES192CCMb:
+                    oid = blkAes192CcmOid;
+                    *oidSz = sizeof(blkAes192CcmOid);
+                    break;
+        #endif
+        #ifdef WOLFSSL_AES_256
+                case AES256CCMb:
+                    oid = blkAes256CcmOid;
+                    *oidSz = sizeof(blkAes256CcmOid);
+                    break;
+        #endif
+    #endif /* HAVE_AESCCM */
+    #ifndef NO_DES3
                 case DESb:
                     oid = blkDesCbcOid;
@@ -1367,4 +1645,5 @@
                     *oidSz = sizeof(blkDes3CbcOid);
                     break;
+    #endif /* !NO_DES3 */
             }
             break;
@@ -1427,8 +1706,10 @@
                     *oidSz = sizeof(extExtKeyUsageOid);
                     break;
+            #ifndef IGNORE_NAME_CONSTRAINTS
                 case NAME_CONS_OID:
                     oid = extNameConsOid;
                     *oidSz = sizeof(extNameConsOid);
                     break;
+            #endif
             }
             break;
@@ -1436,8 +1717,10 @@
         case oidCertAuthInfoType:
             switch (id) {
+            #ifdef HAVE_OCSP
                 case AIA_OCSP_OID:
                     oid = extAuthInfoOcspOid;
                     *oidSz = sizeof(extAuthInfoOcspOid);
                     break;
+            #endif
                 case AIA_CA_ISSUER_OID:
                     oid = extAuthInfoCaIssuerOid;
@@ -1507,18 +1790,58 @@
             break;
 
+        case oidPBEType:
+            switch (id) {
+        #if !defined(NO_SHA) && !defined(NO_RC4)
+                case PBE_SHA1_RC4_128:
+                    oid = pbeSha1RC4128;
+                    *oidSz = sizeof(pbeSha1RC4128);
+                    break;
+        #endif
+        #if !defined(NO_SHA) && !defined(NO_DES3)
+                case PBE_SHA1_DES:
+                    oid = pbeSha1Des;
+                    *oidSz = sizeof(pbeSha1Des);
+                    break;
+
+        #endif
+        #if !defined(NO_SHA) && !defined(NO_DES3)
+                case PBE_SHA1_DES3:
+                    oid = pbeSha1Des3;
+                    *oidSz = sizeof(pbeSha1Des3);
+                    break;
+        #endif
+                case PBES2:
+                    oid = pbes2;
+                    *oidSz = sizeof(pbes2);
+                    break;
+            }
+            break;
+
         case oidKeyWrapType:
             switch (id) {
+            #ifdef WOLFSSL_AES_128
                 case AES128_WRAP:
                     oid = wrapAes128Oid;
                     *oidSz = sizeof(wrapAes128Oid);
                     break;
+            #endif
+            #ifdef WOLFSSL_AES_192
                 case AES192_WRAP:
                     oid = wrapAes192Oid;
                     *oidSz = sizeof(wrapAes192Oid);
                     break;
+            #endif
+            #ifdef WOLFSSL_AES_256
                 case AES256_WRAP:
                     oid = wrapAes256Oid;
                     *oidSz = sizeof(wrapAes256Oid);
                     break;
+            #endif
+            #ifdef HAVE_PKCS7
+                case PWRI_KEK_WRAP:
+                    oid = wrapPwriKekOid;
+                    *oidSz = sizeof(wrapPwriKekOid);
+                    break;
+            #endif
             }
             break;
@@ -1526,26 +1849,78 @@
         case oidCmsKeyAgreeType:
             switch (id) {
+            #ifndef NO_SHA
                 case dhSinglePass_stdDH_sha1kdf_scheme:
                     oid = dhSinglePass_stdDH_sha1kdf_Oid;
                     *oidSz = sizeof(dhSinglePass_stdDH_sha1kdf_Oid);
                     break;
+            #endif
+            #ifdef WOLFSSL_SHA224
                 case dhSinglePass_stdDH_sha224kdf_scheme:
                     oid = dhSinglePass_stdDH_sha224kdf_Oid;
                     *oidSz = sizeof(dhSinglePass_stdDH_sha224kdf_Oid);
                     break;
+            #endif
+            #ifndef NO_SHA256
                 case dhSinglePass_stdDH_sha256kdf_scheme:
                     oid = dhSinglePass_stdDH_sha256kdf_Oid;
                     *oidSz = sizeof(dhSinglePass_stdDH_sha256kdf_Oid);
                     break;
+            #endif
+            #ifdef WOLFSSL_SHA384
                 case dhSinglePass_stdDH_sha384kdf_scheme:
                     oid = dhSinglePass_stdDH_sha384kdf_Oid;
                     *oidSz = sizeof(dhSinglePass_stdDH_sha384kdf_Oid);
                     break;
+            #endif
+            #ifdef WOLFSSL_SHA512
                 case dhSinglePass_stdDH_sha512kdf_scheme:
                     oid = dhSinglePass_stdDH_sha512kdf_Oid;
                     *oidSz = sizeof(dhSinglePass_stdDH_sha512kdf_Oid);
                     break;
+            #endif
             }
             break;
+
+#ifndef NO_HMAC
+        case oidHmacType:
+            switch (id) {
+        #ifdef WOLFSSL_SHA224
+                case HMAC_SHA224_OID:
+                    oid = hmacSha224Oid;
+                    *oidSz = sizeof(hmacSha224Oid);
+                    break;
+        #endif
+        #ifndef NO_SHA256
+                case HMAC_SHA256_OID:
+                    oid = hmacSha256Oid;
+                    *oidSz = sizeof(hmacSha256Oid);
+                    break;
+        #endif
+        #ifdef WOLFSSL_SHA384
+                case HMAC_SHA384_OID:
+                    oid = hmacSha384Oid;
+                    *oidSz = sizeof(hmacSha384Oid);
+                    break;
+        #endif
+        #ifdef WOLFSSL_SHA512
+                case HMAC_SHA512_OID:
+                    oid = hmacSha512Oid;
+                    *oidSz = sizeof(hmacSha512Oid);
+                    break;
+        #endif
+            }
+            break;
+#endif /* !NO_HMAC */
+
+#ifdef HAVE_LIBZ
+        case oidCompressType:
+            switch (id) {
+                case ZLIBc:
+                    oid = zlibCompress;
+                    *oidSz = sizeof(zlibCompress);
+                    break;
+            }
+            break;
+#endif /* HAVE_LIBZ */
 
         case oidIgnoreType:
@@ -1682,5 +2057,5 @@
  *         Otherwise, 0 to indicate success.
  */
-static int GetASNObjectId(const byte* input, word32* inOutIdx, int* len,
+int GetASNObjectId(const byte* input, word32* inOutIdx, int* len,
                           word32 maxIdx)
 {
@@ -1710,5 +2085,5 @@
  * returns the number of bytes added to the buffer.
  */
-static int SetObjectId(int len, byte* output)
+int SetObjectId(int len, byte* output)
 {
     int idx = 0;
@@ -1758,5 +2133,5 @@
         word32 checkOidSz;
     #ifdef ASN_DUMP_OID
-        int i;
+        word32 i;
     #endif
 
@@ -1836,5 +2211,5 @@
 
     /* could have NULL tag and 0 terminator, but may not */
-    if (input[idx] == ASN_TAG_NULL) {
+    if (idx < maxIdx && input[idx] == ASN_TAG_NULL) {
         ret = GetASNNull(input, &idx, maxIdx);
         if (ret != 0)
@@ -1868,10 +2243,25 @@
     if (GetInt(&key->n,  input, inOutIdx, inSz) < 0 ||
         GetInt(&key->e,  input, inOutIdx, inSz) < 0 ||
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
         GetInt(&key->d,  input, inOutIdx, inSz) < 0 ||
         GetInt(&key->p,  input, inOutIdx, inSz) < 0 ||
-        GetInt(&key->q,  input, inOutIdx, inSz) < 0 ||
-        GetInt(&key->dP, input, inOutIdx, inSz) < 0 ||
+        GetInt(&key->q,  input, inOutIdx, inSz) < 0)
+#else
+        SkipInt(input, inOutIdx, inSz) < 0 ||
+        SkipInt(input, inOutIdx, inSz) < 0 ||
+        SkipInt(input, inOutIdx, inSz) < 0 )
+
+#endif
+            return ASN_RSA_KEY_E;
+#if (defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || !defined(RSA_LOW_MEM)) \
+    && !defined(WOLFSSL_RSA_PUBLIC_ONLY)
+    if (GetInt(&key->dP, input, inOutIdx, inSz) < 0 ||
         GetInt(&key->dQ, input, inOutIdx, inSz) < 0 ||
         GetInt(&key->u,  input, inOutIdx, inSz) < 0 )  return ASN_RSA_KEY_E;
+#else
+    if (SkipInt(input, inOutIdx, inSz) < 0 ||
+        SkipInt(input, inOutIdx, inSz) < 0 ||
+        SkipInt(input, inOutIdx, inSz) < 0 )  return ASN_RSA_KEY_E;
+#endif
 
 #ifdef WOLFSSL_XILINX_CRYPT
@@ -1888,7 +2278,8 @@
 /* Remove PKCS8 header, place inOutIdx at beginning of traditional,
  * return traditional length on success, negative on error */
-int ToTraditionalInline(const byte* input, word32* inOutIdx, word32 sz)
-{
-    word32 idx, oid;
+int ToTraditionalInline_ex(const byte* input, word32* inOutIdx, word32 sz,
+                           word32* algId)
+{
+    word32 idx;
     int    version, length;
     int    ret;
@@ -1905,5 +2296,5 @@
         return ASN_PARSE_E;
 
-    if (GetAlgoId(input, &idx, &oid, oidKeyType, sz) < 0)
+    if (GetAlgoId(input, &idx, algId, oidKeyType, sz) < 0)
         return ASN_PARSE_E;
 
@@ -1922,6 +2313,13 @@
 }
 
+int ToTraditionalInline(const byte* input, word32* inOutIdx, word32 sz)
+{
+    word32 oid;
+
+    return ToTraditionalInline_ex(input, inOutIdx, sz, &oid);
+}
+
 /* Remove PKCS8 header, move beginning of traditional to beginning of input */
-int ToTraditional(byte* input, word32 sz)
+int ToTraditional_ex(byte* input, word32 sz, word32* algId)
 {
     word32 inOutIdx = 0;
@@ -1931,5 +2329,5 @@
         return BAD_FUNC_ARG;
 
-    length = ToTraditionalInline(input, &inOutIdx, sz);
+    length = ToTraditionalInline_ex(input, &inOutIdx, sz, algId);
     if (length < 0)
         return length;
@@ -1940,4 +2338,10 @@
 }
 
+int ToTraditional(byte* input, word32 sz)
+{
+    word32 oid;
+
+    return ToTraditional_ex(input, sz, &oid);
+}
 
 /* find beginning of traditional key inside PKCS#8 unencrypted buffer
@@ -1948,9 +2352,10 @@
 {
     int length;
+    word32 algId;
 
     if (input == NULL || inOutIdx == NULL || (*inOutIdx > sz))
         return BAD_FUNC_ARG;
 
-    length = ToTraditionalInline(input, inOutIdx, sz);
+    length = ToTraditionalInline_ex(input, inOutIdx, sz, &algId);
 
     return length;
@@ -2079,4 +2484,5 @@
 {
     int ret;
+    (void)keySz;
 
     if (key == NULL || der == NULL) {
@@ -2084,21 +2490,46 @@
     }
 
-    #if !defined(NO_RSA)
+    #if !defined(NO_RSA) && !defined(NO_ASN_CRYPT)
     /* test if RSA key */
     if (der->keyOID == RSAk) {
-        RsaKey a, b;
+    #ifdef WOLFSSL_SMALL_STACK
+        RsaKey* a = NULL;
+        RsaKey* b = NULL;
+    #else
+        RsaKey a[1], b[1];
+    #endif
         word32 keyIdx = 0;
 
-        if ((ret = wc_InitRsaKey(&a, NULL)) < 0)
+    #ifdef WOLFSSL_SMALL_STACK
+        a = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA);
+        if (a == NULL)
+            return MEMORY_E;
+        b = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA);
+        if (b == NULL) {
+            XFREE(a, NULL, DYNAMIC_TYPE_RSA);
+            return MEMORY_E;
+        }
+    #endif
+
+        if ((ret = wc_InitRsaKey(a, NULL)) < 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+            XFREE(b, NULL, DYNAMIC_TYPE_RSA);
+            XFREE(a, NULL, DYNAMIC_TYPE_RSA);
+    #endif
             return ret;
-        if ((ret = wc_InitRsaKey(&b, NULL)) < 0) {
-            wc_FreeRsaKey(&a);
+        }
+        if ((ret = wc_InitRsaKey(b, NULL)) < 0) {
+            wc_FreeRsaKey(a);
+    #ifdef WOLFSSL_SMALL_STACK
+            XFREE(b, NULL, DYNAMIC_TYPE_RSA);
+            XFREE(a, NULL, DYNAMIC_TYPE_RSA);
+    #endif
             return ret;
         }
-        if ((ret = wc_RsaPrivateKeyDecode(key, &keyIdx, &a, keySz)) == 0) {
+        if ((ret = wc_RsaPrivateKeyDecode(key, &keyIdx, a, keySz)) == 0) {
             WOLFSSL_MSG("Checking RSA key pair");
             keyIdx = 0; /* reset to 0 for parsing public key */
 
-            if ((ret = wc_RsaPublicKeyDecode(der->publicKey, &keyIdx, &b,
+            if ((ret = wc_RsaPublicKeyDecode(der->publicKey, &keyIdx, b,
                                                        der->pubKeySize)) == 0) {
                 /* limit for user RSA crypto because of RsaKey
@@ -2110,6 +2541,6 @@
                 /* both keys extracted successfully now check n and e
                  * values are the same. This is dereferencing RsaKey */
-                if (mp_cmp(&(a.n), &(b.n)) != MP_EQ ||
-                    mp_cmp(&(a.e), &(b.e)) != MP_EQ) {
+                if (mp_cmp(&(a->n), &(b->n)) != MP_EQ ||
+                    mp_cmp(&(a->e), &(b->e)) != MP_EQ) {
                     ret = MP_CMP_E;
                 }
@@ -2119,63 +2550,127 @@
             }
         }
-        wc_FreeRsaKey(&b);
-        wc_FreeRsaKey(&a);
+        wc_FreeRsaKey(b);
+        wc_FreeRsaKey(a);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(b, NULL, DYNAMIC_TYPE_RSA);
+        XFREE(a, NULL, DYNAMIC_TYPE_RSA);
+    #endif
     }
     else
-    #endif /* NO_RSA */
-
-    #ifdef HAVE_ECC
+    #endif /* !NO_RSA && !NO_ASN_CRYPT */
+
+    #if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(NO_ASN_CRYPT)
     if (der->keyOID == ECDSAk) {
+    #ifdef WOLFSSL_SMALL_STACK
+        ecc_key* key_pair = NULL;
+        byte*    privDer;
+    #else
+        ecc_key  key_pair[1];
+        byte     privDer[MAX_ECC_BYTES];
+    #endif
+        word32   privSz = MAX_ECC_BYTES;
         word32  keyIdx = 0;
-        ecc_key key_pair;
-
-        if ((ret = wc_ecc_init(&key_pair)) < 0)
+
+    #ifdef WOLFSSL_SMALL_STACK
+        key_pair = (ecc_key*)XMALLOC(sizeof(ecc_key), NULL, DYNAMIC_TYPE_ECC);
+        if (key_pair == NULL)
+            return MEMORY_E;
+        privDer = (byte*)XMALLOC(MAX_ECC_BYTES, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (privDer == NULL) {
+            XFREE(key_pair, NULL, DYNAMIC_TYPE_ECC);
+            return MEMORY_E;
+        }
+    #endif
+
+        if ((ret = wc_ecc_init(key_pair)) < 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+            XFREE(privDer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(key_pair, NULL, DYNAMIC_TYPE_ECC);
+    #endif
             return ret;
-        if ((ret = wc_EccPrivateKeyDecode(key, &keyIdx, &key_pair,
+        }
+
+        if ((ret = wc_EccPrivateKeyDecode(key, &keyIdx, key_pair,
                                                                  keySz)) == 0) {
             WOLFSSL_MSG("Checking ECC key pair");
-            keyIdx = 0;
-            if ((ret = wc_ecc_import_x963(der->publicKey, der->pubKeySize,
-                                                             &key_pair)) == 0) {
-                /* public and private extracted successfuly no check if is
+
+            if ((ret = wc_ecc_export_private_only(key_pair, privDer, &privSz))
+                                                                         == 0) {
+                wc_ecc_free(key_pair);
+                ret = wc_ecc_init(key_pair);
+                if (ret == 0) {
+                    ret = wc_ecc_import_private_key((const byte*)privDer,
+                                            privSz, (const byte*)der->publicKey,
+                                            der->pubKeySize, key_pair);
+                }
+
+                /* public and private extracted successfuly now check if is
                  * a pair and also do sanity checks on key. wc_ecc_check_key
                  * checks that private * base generator equals pubkey */
-                if ((ret = wc_ecc_check_key(&key_pair)) == 0)
+                if (ret == 0) {
+                    if ((ret = wc_ecc_check_key(key_pair)) == 0) {
                     ret = 1;
             }
         }
-        wc_ecc_free(&key_pair);
+                ForceZero(privDer, privSz);
+            }
+        }
+        wc_ecc_free(key_pair);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(privDer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(key_pair, NULL, DYNAMIC_TYPE_ECC);
+    #endif
     }
     else
-    #endif /* HAVE_ECC */
-
-    #ifdef HAVE_ED25519
+    #endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT && !NO_ASN_CRYPT */
+
+    #if defined(HAVE_ED25519) && !defined(NO_ASN_CRYPT)
     if (der->keyOID == ED25519k) {
+    #ifdef WOLFSSL_SMALL_STACK
+        ed25519_key* key_pair = NULL;
+    #else
+        ed25519_key  key_pair[1];
+    #endif
         word32  keyIdx = 0;
-        ed25519_key key_pair;
-
-        if ((ret = wc_ed25519_init(&key_pair)) < 0)
+
+    #ifdef WOLFSSL_SMALL_STACK
+        key_pair = (ed25519_key*)XMALLOC(sizeof(ed25519_key), NULL,
+                                                          DYNAMIC_TYPE_ED25519);
+        if (key_pair == NULL)
+            return MEMORY_E;
+    #endif
+
+        if ((ret = wc_ed25519_init(key_pair)) < 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+            XFREE(key_pair, NULL, DYNAMIC_TYPE_ED25519);
+    #endif
             return ret;
-        if ((ret = wc_Ed25519PrivateKeyDecode(key, &keyIdx, &key_pair,
+        }
+        if ((ret = wc_Ed25519PrivateKeyDecode(key, &keyIdx, key_pair,
                                                                  keySz)) == 0) {
             WOLFSSL_MSG("Checking ED25519 key pair");
             keyIdx = 0;
             if ((ret = wc_ed25519_import_public(der->publicKey, der->pubKeySize,
-                                                             &key_pair)) == 0) {
+                                                              key_pair)) == 0) {
                 /* public and private extracted successfuly no check if is
                  * a pair and also do sanity checks on key. wc_ecc_check_key
                  * checks that private * base generator equals pubkey */
-                if ((ret = wc_ed25519_check_key(&key_pair)) == 0)
+                if ((ret = wc_ed25519_check_key(key_pair)) == 0)
                     ret = 1;
             }
         }
-        wc_ed25519_free(&key_pair);
+        wc_ed25519_free(key_pair);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(key_pair, NULL, DYNAMIC_TYPE_ED25519);
+    #endif
     }
     else
-    #endif
+    #endif /* HAVE_ED25519 && !NO_ASN_CRYPT */
     {
         ret = 0;
     }
 
+    (void)keySz;
+
     return ret;
 }
@@ -2185,19 +2680,27 @@
 /* Check To see if PKCS version algo is supported, set id if it is return 0
    < 0 on error */
-static int CheckAlgo(int first, int second, int* id, int* version)
+static int CheckAlgo(int first, int second, int* id, int* version, int* blockSz)
 {
     *id      = ALGO_ID_E;
     *version = PKCS5;   /* default */
+    if (blockSz) *blockSz = 8; /* default */
 
     if (first == 1) {
         switch (second) {
-        case 1:
+#if !defined(NO_SHA)
+    #ifndef NO_RC4
+        case PBE_SHA1_RC4_128:
             *id = PBE_SHA1_RC4_128;
             *version = PKCS12v1;
             return 0;
-        case 3:
+    #endif
+    #ifndef NO_DES3
+        case PBE_SHA1_DES3:
             *id = PBE_SHA1_DES3;
             *version = PKCS12v1;
+            if (blockSz) *blockSz = DES_BLOCK_SIZE;
             return 0;
+    #endif
+#endif /* !NO_SHA */
         default:
             return ALGO_ID_E;
@@ -2214,10 +2717,18 @@
 
     switch (second) {
+#ifndef NO_DES3
+    #ifndef NO_MD5
     case 3:                   /* see RFC 2898 for ids */
         *id = PBE_MD5_DES;
+        if (blockSz) *blockSz = DES_BLOCK_SIZE;
         return 0;
+    #endif
+    #ifndef NO_SHA
     case 10:
         *id = PBE_SHA1_DES;
+        if (blockSz) *blockSz = DES_BLOCK_SIZE;
         return 0;
+    #endif
+#endif /* !NO_DES3 */
     default:
         return ALGO_ID_E;
@@ -2229,13 +2740,25 @@
 /* Check To see if PKCS v2 algo is supported, set id if it is return 0
    < 0 on error */
-static int CheckAlgoV2(int oid, int* id)
-{
+static int CheckAlgoV2(int oid, int* id, int* blockSz)
+{
+    if (blockSz) *blockSz = 8; /* default */
+    (void)id; /* not used if AES and DES3 disabled */
     switch (oid) {
-    case 69:
+#if !defined(NO_DES3) && !defined(NO_SHA)
+    case DESb:
         *id = PBE_SHA1_DES;
+        if (blockSz) *blockSz = DES_BLOCK_SIZE;
         return 0;
-    case 652:
+    case DES3b:
         *id = PBE_SHA1_DES3;
+        if (blockSz) *blockSz = DES_BLOCK_SIZE;
         return 0;
+#endif
+#ifdef WOLFSSL_AES_256
+    case AES256CBCb:
+        *id = PBE_AES256_CBC;
+        if (blockSz) *blockSz = AES_BLOCK_SIZE;
+        return 0;
+#endif
     default:
         return ALGO_ID_E;
@@ -2245,208 +2768,22 @@
 
 
-/* Decrypt input in place from parameters based on id */
-static int DecryptKey(const char* password, int passwordSz, byte* salt,
-                      int saltSz, int iterations, int id, byte* input,
-                      int length, int version, byte* cbcIv)
-{
-    int typeH;
-    int derivedLen;
-    int decryptionType;
-    int ret = 0;
-#ifdef WOLFSSL_SMALL_STACK
-    byte* key;
-#else
-    byte key[MAX_KEY_SIZE];
-#endif
-
-    (void)input;
-    (void)length;
-
-    switch (id) {
-        case PBE_MD5_DES:
-            typeH = WC_MD5;
-            derivedLen = 16;           /* may need iv for v1.5 */
-            decryptionType = DES_TYPE;
-            break;
-
-        case PBE_SHA1_DES:
-            typeH = WC_SHA;
-            derivedLen = 16;           /* may need iv for v1.5 */
-            decryptionType = DES_TYPE;
-            break;
-
-        case PBE_SHA1_DES3:
-            typeH = WC_SHA;
-            derivedLen = 32;           /* may need iv for v1.5 */
-            decryptionType = DES3_TYPE;
-            break;
-
-        case PBE_SHA1_RC4_128:
-            typeH = WC_SHA;
-            derivedLen = 16;
-            decryptionType = RC4_TYPE;
-            break;
-
-        default:
-            return ALGO_ID_E;
-    }
-
-#ifdef WOLFSSL_SMALL_STACK
-    key = (byte*)XMALLOC(MAX_KEY_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    if (key == NULL)
-        return MEMORY_E;
-#endif
-
-    if (version == PKCS5v2)
-        ret = wc_PBKDF2(key, (byte*)password, passwordSz,
-                        salt, saltSz, iterations, derivedLen, typeH);
-#ifndef NO_SHA
-    else if (version == PKCS5)
-        ret = wc_PBKDF1(key, (byte*)password, passwordSz,
-                        salt, saltSz, iterations, derivedLen, typeH);
-#endif
-    else if (version == PKCS12v1) {
-        int  i, idx = 0;
-        byte unicodePasswd[MAX_UNICODE_SZ];
-
-        if ( (passwordSz * 2 + 2) > (int)sizeof(unicodePasswd)) {
-#ifdef WOLFSSL_SMALL_STACK
-            XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-            return UNICODE_SIZE_E;
-        }
-
-        for (i = 0; i < passwordSz; i++) {
-            unicodePasswd[idx++] = 0x00;
-            unicodePasswd[idx++] = (byte)password[i];
-        }
-        /* add trailing NULL */
-        unicodePasswd[idx++] = 0x00;
-        unicodePasswd[idx++] = 0x00;
-
-        ret =  wc_PKCS12_PBKDF(key, unicodePasswd, idx, salt, saltSz,
-                            iterations, derivedLen, typeH, 1);
-        if (decryptionType != RC4_TYPE)
-            ret += wc_PKCS12_PBKDF(cbcIv, unicodePasswd, idx, salt, saltSz,
-                                iterations, 8, typeH, 2);
-    }
-    else {
-#ifdef WOLFSSL_SMALL_STACK
-        XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-        return ALGO_ID_E;
-    }
-
-    if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-        XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-        return ret;
-    }
-
-    switch (decryptionType) {
-#ifndef NO_DES3
-        case DES_TYPE:
-        {
-            Des    dec;
-            byte*  desIv = key + 8;
-
-            if (version == PKCS5v2 || version == PKCS12v1)
-                desIv = cbcIv;
-
-            ret = wc_Des_SetKey(&dec, key, desIv, DES_DECRYPTION);
-            if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-                XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-                return ret;
-            }
-
-            wc_Des_CbcDecrypt(&dec, input, input, length);
-            break;
-        }
-
-        case DES3_TYPE:
-        {
-            Des3   dec;
-            byte*  desIv = key + 24;
-
-            if (version == PKCS5v2 || version == PKCS12v1)
-                desIv = cbcIv;
-
-            ret = wc_Des3Init(&dec, NULL, INVALID_DEVID);
-            if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-                XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-                return ret;
-            }
-            ret = wc_Des3_SetKey(&dec, key, desIv, DES_DECRYPTION);
-            if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-                XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-                return ret;
-            }
-            ret = wc_Des3_CbcDecrypt(&dec, input, input, length);
-            if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-                XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-                return ret;
-            }
-            break;
-        }
-#endif
-#ifndef NO_RC4
-        case RC4_TYPE:
-        {
-            Arc4    dec;
-
-            wc_Arc4SetKey(&dec, key, derivedLen);
-            wc_Arc4Process(&dec, input, input, length);
-            break;
-        }
-#endif
-
-        default:
-#ifdef WOLFSSL_SMALL_STACK
-            XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-            return ALGO_ID_E;
-    }
-
-#ifdef WOLFSSL_SMALL_STACK
-    XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-
-    return 0;
-}
-
-
 int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID, word32* oidSz,
         int* algoID, void* heap)
 {
     word32 tmpIdx = 0;
-#ifdef HAVE_ECC
-    ecc_key ecc;
-#endif
-#ifndef NO_RSA
-    RsaKey rsa;
-#endif
-#ifdef HAVE_ED25519
-    ed25519_key ed25519;
-#endif
-
-    if (algoID == NULL) {
+
+    if (key == NULL || algoID == NULL)
         return BAD_FUNC_ARG;
-    }
+
     *algoID = 0;
 
-#ifndef NO_RSA
-    if (wc_InitRsaKey(&rsa, heap) == 0) {
+    #if !defined(NO_RSA) && !defined(NO_ASN_CRYPT)
+    {
+        RsaKey rsa;
+
+        wc_InitRsaKey(&rsa, heap);
         if (wc_RsaPrivateKeyDecode(key, &tmpIdx, &rsa, keySz) == 0) {
             *algoID = RSAk;
-        }
+    }
         else {
             WOLFSSL_MSG("Not RSA DER key");
@@ -2454,56 +2791,47 @@
         wc_FreeRsaKey(&rsa);
     }
-    else {
-        WOLFSSL_MSG("GetKeyOID wc_InitRsaKey failed");
-    }
-#endif /* NO_RSA */
-#ifdef HAVE_ECC
-    if (*algoID != RSAk) {
+    #endif /* !NO_RSA && !NO_ASN_CRYPT */
+    #if defined(HAVE_ECC) && !defined(NO_ASN_CRYPT)
+    if (*algoID == 0) {
+        ecc_key ecc;
+
         tmpIdx = 0;
-        if (wc_ecc_init_ex(&ecc, heap, INVALID_DEVID) == 0) {
-            if (wc_EccPrivateKeyDecode(key, &tmpIdx, &ecc, keySz) == 0) {
-                *algoID = ECDSAk;
-
-                /* sanity check on arguments */
-                if (curveOID == NULL || oidSz == NULL) {
-                    WOLFSSL_MSG("Error getting ECC curve OID");
-                    wc_ecc_free(&ecc);
-                    return BAD_FUNC_ARG;
-                }
-
-                /* now find oid */
-                if (wc_ecc_get_oid(ecc.dp->oidSum, curveOID, oidSz) < 0) {
-                    WOLFSSL_MSG("Error getting ECC curve OID");
-                    wc_ecc_free(&ecc);
-                    return BAD_FUNC_ARG;
-                }
-            }
-            else {
-                WOLFSSL_MSG("Not ECC DER key either");
-            }
-            wc_ecc_free(&ecc);
+        wc_ecc_init_ex(&ecc, heap, INVALID_DEVID);
+        if (wc_EccPrivateKeyDecode(key, &tmpIdx, &ecc, keySz) == 0) {
+            *algoID = ECDSAk;
+
+            /* now find oid */
+            if (wc_ecc_get_oid(ecc.dp->oidSum, curveOID, oidSz) < 0) {
+                WOLFSSL_MSG("Error getting ECC curve OID");
+                wc_ecc_free(&ecc);
+                return BAD_FUNC_ARG;
+        }
         }
         else {
-            WOLFSSL_MSG("GetKeyOID wc_ecc_init_ex failed");
-        }
-    }
-#endif /* HAVE_ECC */
-#ifdef HAVE_ED25519
+            WOLFSSL_MSG("Not ECC DER key either");
+        }
+        wc_ecc_free(&ecc);
+    }
+#endif /* HAVE_ECC && !NO_ASN_CRYPT */
+#if defined(HAVE_ED25519) && !defined(NO_ASN_CRYPT)
     if (*algoID != RSAk && *algoID != ECDSAk) {
+        ed25519_key ed25519;
+
+        tmpIdx = 0;
         if (wc_ed25519_init(&ed25519) == 0) {
             if (wc_Ed25519PrivateKeyDecode(key, &tmpIdx, &ed25519, keySz)
                                                                          == 0) {
                 *algoID = ED25519k;
-            }
-            else {
+    }
+    else {
                 WOLFSSL_MSG("Not ED25519 DER key");
-            }
+    }
             wc_ed25519_free(&ed25519);
-        }
+    }
         else {
             WOLFSSL_MSG("GetKeyOID wc_ed25519_init failed");
         }
     }
-#endif
+#endif /* HAVE_ED25519 && !NO_ASN_CRYPT */
 
     /* if flag is not set then is neither RSA or ECC key that could be
@@ -2514,18 +2842,480 @@
     }
 
+    (void)tmpIdx;
     (void)curveOID;
     (void)oidSz;
+    (void)keySz;
+    (void)heap;
 
     return 1;
 }
 
+#define PKCS8_MIN_BLOCK_SIZE 8
+static int Pkcs8Pad(byte* buf, int sz, int blockSz)
+        {
+    int i, padSz;
+
+    /* calculate pad size */
+    padSz = blockSz - (sz & (blockSz - 1));
+
+    /* pad with padSz value */
+    if (buf) {
+        for (i = 0; i < padSz; i++) {
+            buf[sz+i] = (byte)(padSz & 0xFF);
+        }
+            }
+
+    /* return adjusted length */
+    return sz + padSz;
+        }
+
+/*
+ * Used when creating PKCS12 shrouded key bags
+ * vPKCS is the version of PKCS to use
+ * vAlgo is the algorithm version to use
+ *
+ * if salt is NULL a random number is generated
+ *
+ * returns the size of encrypted data on success
+ */
+int UnTraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz,
+        const char* password, int passwordSz, int vPKCS, int vAlgo,
+        byte* salt, word32 saltSz, int itt, WC_RNG* rng, void* heap)
+        {
+    int algoID = 0;
+    byte*  tmp;
+    word32 tmpSz = 0;
+    word32 sz;
+    word32 seqSz;
+    word32 inOutIdx = 0;
+    word32 totalSz = 0;
+    int    version, id;
+    int    ret;
+    int    blockSz = 0;
+
+    const byte* curveOID = NULL;
+    word32 oidSz   = 0;
+
+#ifdef WOLFSSL_SMALL_STACK
+    byte*  saltTmp = NULL;
+    byte*  cbcIv   = NULL;
+#else
+    byte   saltTmp[MAX_IV_SIZE];
+    byte   cbcIv[MAX_IV_SIZE];
+#endif
+
+    WOLFSSL_ENTER("UnTraditionalEnc()");
+
+    if (saltSz > MAX_SALT_SIZE)
+        return ASN_PARSE_E;
+
+
+    inOutIdx += MAX_SEQ_SZ; /* leave room for size of finished shroud */
+    if (CheckAlgo(vPKCS, vAlgo, &id, &version, &blockSz) < 0) {
+        WOLFSSL_MSG("Bad/Unsupported algorithm ID");
+        return ASN_INPUT_E;  /* Algo ID error */
+            }
+
+    if (out != NULL) {
+        if (*outSz < inOutIdx + MAX_ALGO_SZ + MAX_SALT_SIZE + MAX_SEQ_SZ + 1 +
+                MAX_LENGTH_SZ + MAX_SHORT_SZ + 1)
+                return BUFFER_E;
+
+        if (version == PKCS5v2) {
+            WOLFSSL_MSG("PKCS5v2 Not supported yet\n");
+            return ASN_VERSION_E;
+        }
+
+        if (salt == NULL || saltSz <= 0) {
+            saltSz = 8;
+        #ifdef WOLFSSL_SMALL_STACK
+            saltTmp = (byte*)XMALLOC(saltSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
+            if (saltTmp == NULL)
+                return MEMORY_E;
+        #endif
+            salt = saltTmp;
+
+            if ((ret = wc_RNG_GenerateBlock(rng, saltTmp, saltSz)) != 0) {
+                WOLFSSL_MSG("Error generating random salt");
+#ifdef WOLFSSL_SMALL_STACK
+                if (saltTmp != NULL)
+                    XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                return ret;
+            }
+        }
+
+
+        /* leave room for a sequence (contains salt and iterations int) */
+        inOutIdx += MAX_SEQ_SZ; sz = 0;
+        inOutIdx += MAX_ALGO_SZ;
+
+        /* place salt in buffer */
+        out[inOutIdx++] = ASN_OCTET_STRING; sz++;
+        tmpSz = SetLength(saltSz, out + inOutIdx);
+        inOutIdx += tmpSz; sz += tmpSz;
+        XMEMCPY(out + inOutIdx, salt, saltSz);
+        inOutIdx += saltSz; sz += saltSz;
+
+        /* place iteration count in buffer */
+        ret = SetShortInt(out, &inOutIdx, itt, *outSz);
+        if (ret < 0) {
+            return ret;
+        }
+        sz += (word32)ret;
+
+        /* wind back index and set sequence then clean up buffer */
+        inOutIdx -= (sz + MAX_SEQ_SZ);
+        tmpSz = SetSequence(sz, out + inOutIdx);
+        XMEMMOVE(out + inOutIdx + tmpSz, out + inOutIdx + MAX_SEQ_SZ, sz);
+        totalSz += tmpSz + sz; sz += tmpSz;
+
+        /* add in algo ID */
+        inOutIdx -= MAX_ALGO_SZ;
+        tmpSz =  SetAlgoID(id, out + inOutIdx, oidPBEType, sz);
+        XMEMMOVE(out + inOutIdx + tmpSz, out + inOutIdx + MAX_ALGO_SZ, sz);
+        totalSz += tmpSz; inOutIdx += tmpSz + sz;
+
+        /* octet string containing encrypted key */
+        out[inOutIdx++] = ASN_OCTET_STRING; totalSz++;
+    }
+
+    /* check key type and get OID if ECC */
+    if ((ret = wc_GetKeyOID(key, keySz, &curveOID, &oidSz, &algoID, heap))< 0) {
+            return ret;
+    }
+
+    /* PKCS#8 wrapping around key */
+    if (wc_CreatePKCS8Key(NULL, &tmpSz, key, keySz, algoID, curveOID, oidSz)
+            != LENGTH_ONLY_E) {
+#ifdef WOLFSSL_SMALL_STACK
+        if (saltTmp != NULL)
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return MEMORY_E;
+            }
+
+    /* check if should return max size */
+    if (out == NULL) {
+        /* account for salt size */
+        if (salt == NULL || saltSz <= 0) {
+            tmpSz += MAX_SALT_SIZE;
+        }
+        else {
+            tmpSz += saltSz;
+        }
+
+        /* plus 3 for tags */
+        *outSz = tmpSz + MAX_ALGO_SZ + MAX_LENGTH_SZ +MAX_LENGTH_SZ + MAX_SEQ_SZ
+            + MAX_LENGTH_SZ + MAX_SEQ_SZ + 3;
+        return LENGTH_ONLY_E;
+        }
+
+    /* reserve buffer for crypto and make sure it supports full blocks */
+    tmp = (byte*)XMALLOC(tmpSz + (blockSz-1), heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (tmp == NULL) {
+    #ifdef WOLFSSL_SMALL_STACK
+        if (saltTmp != NULL)
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return MEMORY_E;
+    }
+
+    if ((ret = wc_CreatePKCS8Key(tmp, &tmpSz, key, keySz, algoID, curveOID,
+                    oidSz)) < 0) {
+        XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        WOLFSSL_MSG("Error wrapping key with PKCS#8");
+    #ifdef WOLFSSL_SMALL_STACK
+        if (saltTmp != NULL)
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+        return ret;
+    }
+    tmpSz = ret;
+
+    /* adjust size to pad */
+    tmpSz = Pkcs8Pad(tmp, tmpSz, blockSz);
+
+#ifdef WOLFSSL_SMALL_STACK
+    cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (cbcIv == NULL) {
+        if (saltTmp != NULL)
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(salt, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+        }
+#endif
+
+    /* encrypt PKCS#8 wrapped key */
+    if ((ret = wc_CryptKey(password, passwordSz, salt, saltSz, itt, id,
+               tmp, tmpSz, version, cbcIv, 1)) < 0) {
+        XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        WOLFSSL_MSG("Error encrypting key");
+#ifdef WOLFSSL_SMALL_STACK
+        if (saltTmp != NULL)
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (cbcIv != NULL)
+            XFREE(cbcIv, heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ret;  /* encryption failure */
+    }
+    totalSz += tmpSz;
+
+#ifdef WOLFSSL_SMALL_STACK
+    if (saltTmp != NULL)
+        XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (cbcIv != NULL)
+        XFREE(cbcIv, heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    if (*outSz < inOutIdx + tmpSz + MAX_LENGTH_SZ) {
+        XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return BUFFER_E;
+}
+
+    /* set length of key and copy over encrypted key */
+    seqSz = SetLength(tmpSz, out + inOutIdx);
+    inOutIdx += seqSz; totalSz += seqSz;
+    XMEMCPY(out + inOutIdx, tmp, tmpSz);
+    XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+
+    /* set total size at beginning */
+    sz = SetSequence(totalSz, out);
+    XMEMMOVE(out + sz, out + MAX_SEQ_SZ, totalSz);
+
+    (void)rng;
+
+    return totalSz + sz;
+}
+
+static int GetAlgoV2(int encAlgId, const byte** oid, int *len, int* id,
+                     int *blkSz)
+{
+    int ret = 0;
+
+    switch (encAlgId) {
+#if !defined(NO_DES3) && !defined(NO_SHA)
+    case DESb:
+        *len = sizeof(blkDesCbcOid);
+        *oid = blkDesCbcOid;
+        *id = PBE_SHA1_DES;
+        *blkSz = 8;
+        break;
+    case DES3b:
+        *len = sizeof(blkDes3CbcOid);
+        *oid = blkDes3CbcOid;
+        *id = PBE_SHA1_DES3;
+        *blkSz = 8;
+        break;
+#endif
+#if defined(WOLFSSL_AES_256) && defined(HAVE_AES_CBC)
+    case AES256CBCb:
+        *len = sizeof(blkAes256CbcOid);
+        *oid = blkAes256CbcOid;
+        *id = PBE_AES256_CBC;
+        *blkSz = 16;
+        break;
+#endif
+    default:
+        (void)len;
+        (void)oid;
+        (void)id;
+        (void)blkSz;
+        ret = ALGO_ID_E;
+    }
+
+    return ret;
+        }
+
+/* Converts Encrypted PKCS#8 to 'traditional' (i.e. PKCS#8 removed from
+ * decrypted key.)
+ */
+int TraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz,
+        const char* password, int passwordSz, int vPKCS, int vAlgo,
+        int encAlgId, byte* salt, word32 saltSz, int itt, WC_RNG* rng,
+        void* heap)
+{
+    int ret = 0;
+    int version, blockSz, id;
+    word32 idx = 0, encIdx;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* saltTmp = NULL;
+#else
+    byte saltTmp[MAX_SALT_SIZE];
+#endif
+    byte cbcIv[MAX_IV_SIZE];
+    byte *pkcs8Key = NULL;
+    word32 pkcs8KeySz, padSz = 0;
+    int algId;
+    const byte* curveOid = NULL;
+    word32 curveOidSz = 0;
+    const byte* pbeOid = NULL;
+    word32 pbeOidSz;
+    const byte* encOid = NULL;
+    int encOidSz = 0;
+    word32 pbeLen = 0, kdfLen = 0, encLen = 0;
+    word32 innerLen = 0, outerLen;
+
+    ret = CheckAlgo(vPKCS, vAlgo, &id, &version, &blockSz);
+    /* create random salt if one not provided */
+    if (ret == 0 && (salt == NULL || saltSz <= 0)) {
+        saltSz = 8;
+    #ifdef WOLFSSL_SMALL_STACK
+        saltTmp = (byte*)XMALLOC(saltSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (saltTmp == NULL)
+            return MEMORY_E;
+    #endif
+        salt = saltTmp;
+
+        if ((ret = wc_RNG_GenerateBlock(rng, saltTmp, saltSz)) != 0) {
+            WOLFSSL_MSG("Error generating random salt");
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+            return ret;
+    }
+    }
+
+    if (ret == 0) {
+        /* check key type and get OID if ECC */
+        ret = wc_GetKeyOID(key, keySz, &curveOid, &curveOidSz, &algId, heap);
+        if (ret == 1)
+            ret = 0;
+                }
+    if (ret == 0) {
+        ret = wc_CreatePKCS8Key(NULL, &pkcs8KeySz, key, keySz, algId, curveOid,
+                                                                    curveOidSz);
+        if (ret == LENGTH_ONLY_E)
+            ret = 0;
+                }
+    if (ret == 0) {
+        pkcs8Key = (byte*)XMALLOC(pkcs8KeySz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (pkcs8Key == NULL)
+            ret = MEMORY_E;
+            }
+    if (ret == 0) {
+        ret = wc_CreatePKCS8Key(pkcs8Key, &pkcs8KeySz, key, keySz, algId,
+                                                          curveOid, curveOidSz);
+        if (ret >= 0) {
+            pkcs8KeySz = ret;
+            ret = 0;
+            }
+        }
+
+    if (ret == 0 && version == PKCS5v2)
+        ret = GetAlgoV2(encAlgId, &encOid, &encOidSz, &id, &blockSz);
+
+    if (ret == 0) {
+        padSz = (blockSz - (pkcs8KeySz & (blockSz - 1))) & (blockSz - 1);
+        /* inner = OCT salt INT itt */
+        innerLen = 2 + saltSz + 2 + (itt < 256 ? 1 : 2);
+
+        if (version != PKCS5v2) {
+            pbeOid = OidFromId(id, oidPBEType, &pbeOidSz);
+            /* pbe = OBJ pbse1 SEQ [ inner ] */
+            pbeLen = 2 + pbeOidSz + 2 + innerLen;
+        }
+        else {
+            pbeOid = pbes2;
+            pbeOidSz = sizeof(pbes2);
+            /* kdf = OBJ pbkdf2 [ SEQ innerLen ] */
+            kdfLen = 2 + sizeof(pbkdf2Oid) + 2 + innerLen;
+            /* enc = OBJ enc_alg OCT iv */
+            encLen = 2 + encOidSz + 2 + blockSz;
+            /* pbe = OBJ pbse2 SEQ [ SEQ [ kdf ] SEQ [ enc ] ] */
+            pbeLen = 2 + sizeof(pbes2) + 2 + 2 + kdfLen + 2 + encLen;
+
+            ret = wc_RNG_GenerateBlock(rng, cbcIv, blockSz);
+        }
+    }
+    if (ret == 0) {
+        /* outer = SEQ [ pbe ] OCT encrypted_PKCS#8_key */
+        outerLen = 2 + pbeLen;
+        outerLen += SetOctetString(pkcs8KeySz + padSz, out);
+        outerLen += pkcs8KeySz + padSz;
+
+        idx += SetSequence(outerLen, out + idx);
+
+        encIdx = idx + outerLen - pkcs8KeySz - padSz;
+        /* Put Encrypted content in place. */
+        XMEMCPY(out + encIdx, pkcs8Key, pkcs8KeySz);
+        if (padSz > 0) {
+            XMEMSET(out + encIdx + pkcs8KeySz, padSz, padSz);
+            pkcs8KeySz += padSz;
+            }
+        ret = wc_CryptKey(password, passwordSz, salt, saltSz, itt, id,
+                                   out + encIdx, pkcs8KeySz, version, cbcIv, 1);
+            }
+    if (ret == 0) {
+        if (version != PKCS5v2) {
+            /* PBE algorithm */
+            idx += SetSequence(pbeLen, out + idx);
+            idx += SetObjectId(pbeOidSz, out + idx);
+            XMEMCPY(out + idx, pbeOid, pbeOidSz);
+            idx += pbeOidSz;
+        }
+        else {
+            /* PBES2 algorithm identifier */
+            idx += SetSequence(pbeLen, out + idx);
+            idx += SetObjectId(pbeOidSz, out + idx);
+            XMEMCPY(out + idx, pbeOid, pbeOidSz);
+            idx += pbeOidSz;
+            /* PBES2 Parameters: SEQ [ kdf ] SEQ [ enc ] */
+            idx += SetSequence(2 + kdfLen + 2 + encLen, out + idx);
+            /* KDF Algorithm Identifier */
+            idx += SetSequence(kdfLen, out + idx);
+            idx += SetObjectId(sizeof(pbkdf2Oid), out + idx);
+            XMEMCPY(out + idx, pbkdf2Oid, sizeof(pbkdf2Oid));
+            idx += sizeof(pbkdf2Oid);
+        }
+        idx += SetSequence(innerLen, out + idx);
+        idx += SetOctetString(saltSz, out + idx);
+        XMEMCPY(out + idx, salt, saltSz); idx += saltSz;
+        ret = SetShortInt(out, &idx, itt, *outSz);
+        if (ret > 0)
+            ret = 0;
+        }
+    if (ret == 0) {
+        if (version == PKCS5v2) {
+            /* Encryption Algorithm Identifier */
+            idx += SetSequence(encLen, out + idx);
+            idx += SetObjectId(encOidSz, out + idx);
+            XMEMCPY(out + idx, encOid, encOidSz);
+            idx += encOidSz;
+            /* Encryption Algorithm Parameter: CBC IV */
+            idx += SetOctetString(blockSz, out + idx);
+            XMEMCPY(out + idx, cbcIv, blockSz);
+            idx += blockSz;
+        }
+        idx += SetOctetString(pkcs8KeySz, out + idx);
+        /* Default PRF - no need to write out OID */
+        idx += pkcs8KeySz;
+
+        ret = idx;
+    }
+
+    if (pkcs8Key != NULL) {
+        ForceZero(pkcs8Key, pkcs8KeySz);
+        XFREE(pkcs8Key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        }
+#ifdef WOLFSSL_SMALL_STACK
+    if (saltTmp != NULL) {
+        XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+#endif
+
+    (void)rng;
+
+    return ret;
+}
 
 /* Remove Encrypted PKCS8 header, move beginning of traditional to beginning
    of input */
-int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
-{
-    word32 inOutIdx = 0, oid;
+int ToTraditionalEnc(byte* input, word32 sz,const char* password,
+                     int passwordSz, word32* algId)
+{
+    word32 inOutIdx = 0, seqEnd, oid;
     int    ret = 0, first, second, length = 0, version, saltSz, id;
-    int    iterations = 0;
+    int    iterations = 0, keySz = 0;
 #ifdef WOLFSSL_SMALL_STACK
     byte*  salt = NULL;
@@ -2536,9 +3326,14 @@
 #endif
 
+    if (passwordSz < 0) {
+        WOLFSSL_MSG("Bad password size");
+        return BAD_FUNC_ARG;
+    }
+
     if (GetSequence(input, &inOutIdx, &length, sz) < 0) {
         ERROR_OUT(ASN_PARSE_E, exit_tte);
     }
 
-    if (GetAlgoId(input, &inOutIdx, &oid, oidSigType, sz) < 0) {
+    if (GetAlgoId(input, &inOutIdx, &oid, oidIgnoreType, sz) < 0) {
         ERROR_OUT(ASN_PARSE_E, exit_tte);
     }
@@ -2547,5 +3342,5 @@
     second = input[inOutIdx - 1];   /* version.algo, algo id last byte */
 
-    if (CheckAlgo(first, second, &id, &version) < 0) {
+    if (CheckAlgo(first, second, &id, &version, NULL) < 0) {
         ERROR_OUT(ASN_INPUT_E, exit_tte); /* Algo ID error */
     }
@@ -2568,4 +3363,7 @@
         ERROR_OUT(ASN_PARSE_E, exit_tte);
     }
+    /* Find the end of this SEQUENCE so we can check for the OPTIONAL and
+     * DEFAULT items. */
+    seqEnd = inOutIdx + length;
 
     ret = GetOctetString(input, &inOutIdx, &saltSz, sz);
@@ -2591,4 +3389,18 @@
     }
 
+    /* OPTIONAL key length */
+    if (seqEnd > inOutIdx && input[inOutIdx] == ASN_INTEGER) {
+        if (GetShortInt(input, &inOutIdx, &keySz, sz) < 0) {
+            ERROR_OUT(ASN_PARSE_E, exit_tte);
+        }
+    }
+
+    /* DEFAULT HMAC is SHA-1 */
+    if (seqEnd > inOutIdx) {
+        if (GetAlgoId(input, &inOutIdx, &oid, oidHmacType, sz) < 0) {
+            ERROR_OUT(ASN_PARSE_E, exit_tte);
+        }
+    }
+
 #ifdef WOLFSSL_SMALL_STACK
     cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@@ -2600,10 +3412,9 @@
     if (version == PKCS5v2) {
         /* get encryption algo */
-        /* JOHN: New type. Need a little more research. */
         if (GetAlgoId(input, &inOutIdx, &oid, oidBlkType, sz) < 0) {
             ERROR_OUT(ASN_PARSE_E, exit_tte);
         }
 
-        if (CheckAlgoV2(oid, &id) < 0) {
+        if (CheckAlgoV2(oid, &id, NULL) < 0) {
             ERROR_OUT(ASN_PARSE_E, exit_tte); /* PKCS v2 algo id error */
         }
@@ -2625,6 +3436,6 @@
         goto exit_tte;
 
-    ret = DecryptKey(password, passwordSz, salt, saltSz, iterations, id,
-                                   input + inOutIdx, length, version, cbcIv);
+    ret = wc_CryptKey(password, passwordSz, salt, saltSz, iterations, id,
+                   input + inOutIdx, length, version, cbcIv, 0);
 
 exit_tte:
@@ -2636,5 +3447,5 @@
     if (ret == 0) {
         XMEMMOVE(input, input + inOutIdx, length);
-        ret = ToTraditional(input, length);
+        ret = ToTraditional_ex(input, length, algId);
     }
 
@@ -2642,11 +3453,229 @@
 }
 
-/* decrypt PKCS */
-int DecryptContent(byte* input, word32 sz,const char* password,int passwordSz)
-{
-    word32 inOutIdx = 0, oid;
+
+/* encrypt PKCS 12 content
+ *
+ * NOTE: if out is NULL then outSz is set with the total buffer size needed and
+ *       the error value LENGTH_ONLY_E is returned.
+ *
+ * input      data to encrypt
+ * inputSz    size of input buffer
+ * out        buffer to hold the result
+ * outSz      size of out buffer
+ * password   password if used. Can be NULL for no password
+ * passwordSz size of password buffer
+ * vPKCS      version of PKCS i.e. PKCS5v2
+ * vAlgo      algorithm version
+ * salt       buffer holding salt if used. If NULL then a random salt is created
+ * saltSz     size of salt buffer if it is not NULL
+ * itt        number of iterations used
+ * rng        random number generator to use
+ * heap       possible heap hint for mallocs/frees
+ *
+ * returns the total size of encrypted content on success.
+ */
+int EncryptContent(byte* input, word32 inputSz, byte* out, word32* outSz,
+        const char* password, int passwordSz, int vPKCS, int vAlgo,
+        byte* salt, word32 saltSz, int itt, WC_RNG* rng, void* heap)
+{
+    word32 sz;
+    word32 inOutIdx = 0;
+    word32 tmpIdx   = 0;
+    word32 totalSz  = 0;
+    word32 seqSz;
+    int    ret;
+    int    version, id, blockSz = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    byte*  saltTmp = NULL;
+    byte*  cbcIv = NULL;
+#else
+    byte   saltTmp[MAX_SALT_SIZE];
+    byte   cbcIv[MAX_IV_SIZE];
+#endif
+
+    (void)heap;
+
+    WOLFSSL_ENTER("EncryptContent()");
+
+    if (CheckAlgo(vPKCS, vAlgo, &id, &version, &blockSz) < 0)
+        return ASN_INPUT_E;  /* Algo ID error */
+
+    if (version == PKCS5v2) {
+        WOLFSSL_MSG("PKCS#5 version 2 not supported yet");
+        return BAD_FUNC_ARG;
+        }
+
+    if (saltSz > MAX_SALT_SIZE)
+        return ASN_PARSE_E;
+
+    if (outSz == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (out == NULL) {
+        sz = inputSz;
+        switch (id) {
+        #if !defined(NO_DES3) && (!defined(NO_MD5) || !defined(NO_SHA))
+            case PBE_MD5_DES:
+            case PBE_SHA1_DES:
+            case PBE_SHA1_DES3:
+                /* set to block size of 8 for DES operations. This rounds up
+                 * to the nearest multiple of 8 */
+                sz &= 0xfffffff8;
+                sz += 8;
+                break;
+        #endif /* !NO_DES3 && (!NO_MD5 || !NO_SHA) */
+        #if !defined(NO_RC4) && !defined(NO_SHA)
+            case PBE_SHA1_RC4_128:
+                break;
+        #endif
+            case -1:
+                break;
+
+            default:
+                return ALGO_ID_E;
+        }
+
+        if (saltSz <= 0) {
+            sz += MAX_SALT_SIZE;
+        }
+        else {
+            sz += saltSz;
+        }
+
+        /* add 2 for tags */
+        totalSz = sz + MAX_ALGO_SZ + MAX_SEQ_SZ + MAX_LENGTH_SZ +
+            MAX_LENGTH_SZ + MAX_LENGTH_SZ + MAX_SHORT_SZ + 2;
+
+        /* adjust size to pad */
+        totalSz = Pkcs8Pad(NULL, totalSz, blockSz);
+
+        /* return result */
+        *outSz = totalSz;
+
+        return LENGTH_ONLY_E;
+    }
+
+    if (inOutIdx + MAX_ALGO_SZ + MAX_SEQ_SZ + 1 > *outSz)
+        return BUFFER_E;
+
+    sz = SetAlgoID(id, out + inOutIdx, oidPBEType, 0);
+    inOutIdx += sz; totalSz += sz;
+    tmpIdx = inOutIdx;
+    tmpIdx += MAX_SEQ_SZ; /* save room for salt and itter sequence */
+    out[tmpIdx++] = ASN_OCTET_STRING;
+
+    /* create random salt if one not provided */
+    if (salt == NULL || saltSz <= 0) {
+        saltSz = 8;
+    #ifdef WOLFSSL_SMALL_STACK
+        saltTmp = (byte*)XMALLOC(saltSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (saltTmp == NULL)
+            return MEMORY_E;
+    #endif
+        salt = saltTmp;
+
+        if ((ret = wc_RNG_GenerateBlock(rng, saltTmp, saltSz)) != 0) {
+            WOLFSSL_MSG("Error generating random salt");
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+            return ret;
+        }
+    }
+
+    if (tmpIdx + MAX_LENGTH_SZ + saltSz + MAX_SHORT_SZ > *outSz) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+        return BUFFER_E;
+    }
+
+    sz = SetLength(saltSz, out + tmpIdx);
+    tmpIdx += sz;
+
+    XMEMCPY(out + tmpIdx, salt, saltSz);
+    tmpIdx += saltSz;
+
+    /* place iteration setting in buffer */
+    ret = SetShortInt(out, &tmpIdx, itt, *outSz);
+    if (ret < 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+        return ret;
+    }
+
+    /* rewind and place sequence */
+    sz = tmpIdx - inOutIdx - MAX_SEQ_SZ;
+    seqSz = SetSequence(sz, out + inOutIdx);
+    XMEMMOVE(out + inOutIdx + seqSz, out + inOutIdx + MAX_SEQ_SZ, sz);
+    inOutIdx += seqSz; totalSz += seqSz;
+    inOutIdx += sz; totalSz += sz;
+
+#ifdef WOLFSSL_SMALL_STACK
+    cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (cbcIv == NULL) {
+        XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    if (inOutIdx + 1 + MAX_LENGTH_SZ + inputSz > *outSz)
+        return BUFFER_E;
+
+    out[inOutIdx++] = ASN_CONTEXT_SPECIFIC | 0; totalSz++;
+    sz = SetLength(inputSz, out + inOutIdx);
+    inOutIdx += sz; totalSz += sz;
+
+    /* get pad size and verify buffer room */
+    sz = Pkcs8Pad(NULL, inputSz, blockSz);
+    if (sz + inOutIdx > *outSz)
+        return BUFFER_E;
+
+    /* copy input to output buffer and pad end */
+    XMEMCPY(out + inOutIdx, input, inputSz);
+    sz = Pkcs8Pad(out + inOutIdx, inputSz, blockSz);
+    totalSz += sz;
+
+    /* encrypt */
+    if ((ret = wc_CryptKey(password, passwordSz, salt, saltSz, itt, id,
+                   out + inOutIdx, sz, version, cbcIv, 1)) < 0) {
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(cbcIv,   heap, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+        return ret;  /* encrypt failure */
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(cbcIv,   heap, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    (void)rng;
+
+    return totalSz;
+}
+
+
+/* decrypt PKCS
+ *
+ * NOTE: input buffer is overwritten with decrypted data!
+ *
+ * input[in/out] data to decrypt and results are written to
+ * sz            size of input buffer
+ * password      password if used. Can be NULL for no password
+ * passwordSz    size of password buffer
+ *
+ * returns the total size of decrypted content on success.
+ */
+int DecryptContent(byte* input, word32 sz,const char* password, int passwordSz)
+{
+    word32 inOutIdx = 0, seqEnd, oid;
     int    ret = 0;
     int    first, second, length = 0, version, saltSz, id;
-    int    iterations = 0;
+    int    iterations = 0, keySz = 0;
 #ifdef WOLFSSL_SMALL_STACK
     byte*  salt = NULL;
@@ -2657,5 +3686,5 @@
 #endif
 
-    if (GetAlgoId(input, &inOutIdx, &oid, oidSigType, sz) < 0) {
+    if (GetAlgoId(input, &inOutIdx, &oid, oidIgnoreType, sz) < 0) {
         ERROR_OUT(ASN_PARSE_E, exit_dc);
     }
@@ -2664,5 +3693,5 @@
     second = input[inOutIdx - 1];   /* version.algo, algo id last byte */
 
-    if (CheckAlgo(first, second, &id, &version) < 0) {
+    if (CheckAlgo(first, second, &id, &version, NULL) < 0) {
         ERROR_OUT(ASN_INPUT_E, exit_dc); /* Algo ID error */
     }
@@ -2685,4 +3714,7 @@
         ERROR_OUT(ASN_PARSE_E, exit_dc);
     }
+    /* Find the end of this SEQUENCE so we can check for the OPTIONAL and
+     * DEFAULT items. */
+    seqEnd = inOutIdx + length;
 
     ret = GetOctetString(input, &inOutIdx, &saltSz, sz);
@@ -2708,4 +3740,18 @@
     }
 
+    /* OPTIONAL key length */
+    if (seqEnd > inOutIdx && input[inOutIdx] == ASN_INTEGER) {
+        if (GetShortInt(input, &inOutIdx, &keySz, sz) < 0) {
+            ERROR_OUT(ASN_PARSE_E, exit_dc);
+        }
+    }
+
+    /* DEFAULT HMAC is SHA-1 */
+    if (seqEnd > inOutIdx) {
+        if (GetAlgoId(input, &inOutIdx, &oid, oidHmacType, sz) < 0) {
+            ERROR_OUT(ASN_PARSE_E, exit_dc);
+        }
+    }
+
 #ifdef WOLFSSL_SMALL_STACK
     cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@@ -2717,10 +3763,9 @@
     if (version == PKCS5v2) {
         /* get encryption algo */
-        /* JOHN: New type. Need a little more research. */
         if (GetAlgoId(input, &inOutIdx, &oid, oidBlkType, sz) < 0) {
             ERROR_OUT(ASN_PARSE_E, exit_dc);
         }
 
-        if (CheckAlgoV2(oid, &id) < 0) {
+        if (CheckAlgoV2(oid, &id, NULL) < 0) {
             ERROR_OUT(ASN_PARSE_E, exit_dc); /* PKCS v2 algo id error */
         }
@@ -2730,4 +3775,8 @@
             goto exit_dc;
 
+        if (length > MAX_IV_SIZE) {
+            ERROR_OUT(ASN_PARSE_E, exit_dc);
+        }
+
         XMEMCPY(cbcIv, &input[inOutIdx], length);
         inOutIdx += length;
@@ -2742,6 +3791,6 @@
     }
 
-    ret = DecryptKey(password, passwordSz, salt, saltSz, iterations, id,
-                                   input + inOutIdx, length, version, cbcIv);
+    ret = wc_CryptKey(password, passwordSz, salt, saltSz, iterations, id,
+                   input + inOutIdx, length, version, cbcIv, 0);
 
 exit_dc:
@@ -2764,20 +3813,18 @@
 
 #ifndef HAVE_USER_RSA
-int wc_RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
-                       word32 inSz)
-{
+int wc_RsaPublicKeyDecode_ex(const byte* input, word32* inOutIdx, word32 inSz,
+    const byte** n, word32* nSz, const byte** e, word32* eSz)
+{
+    int ret = 0;
     int  length;
 #if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
     byte b;
 #endif
-    int ret;
-
-    if (input == NULL || inOutIdx == NULL || key == NULL)
+
+    if (input == NULL || inOutIdx == NULL)
         return BAD_FUNC_ARG;
 
     if (GetSequence(input, inOutIdx, &length, inSz) < 0)
         return ASN_PARSE_E;
-
-    key->type = RSA_PUBLIC;
 
 #if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
@@ -2795,4 +3842,7 @@
 
         /* Option NULL ASN.1 tag */
+        if (*inOutIdx  >= inSz) {
+            return BUFFER_E;
+        }
         if (input[*inOutIdx] == ASN_TAG_NULL) {
             ret = GetASNNull(input, inOutIdx, inSz);
@@ -2811,18 +3861,45 @@
 #endif /* OPENSSL_EXTRA */
 
-    if (GetInt(&key->n,  input, inOutIdx, inSz) < 0)
+    /* Get modulus */
+    ret = GetASNInt(input, inOutIdx, &length, inSz);
+    if (ret < 0) {
         return ASN_RSA_KEY_E;
-    if (GetInt(&key->e,  input, inOutIdx, inSz) < 0) {
-        mp_clear(&key->n);
+    }
+    if (nSz)
+        *nSz = length;
+    if (n)
+        *n = &input[*inOutIdx];
+    *inOutIdx += length;
+
+    /* Get exponent */
+    ret = GetASNInt(input, inOutIdx, &length, inSz);
+    if (ret < 0) {
         return ASN_RSA_KEY_E;
     }
-
-#ifdef WOLFSSL_XILINX_CRYPT
-    if (wc_InitRsaHw(key) != 0) {
-        return BAD_STATE_E;
-    }
-#endif
-
-    return 0;
+    if (eSz)
+        *eSz = length;
+    if (e)
+        *e = &input[*inOutIdx];
+    *inOutIdx += length;
+
+    return ret;
+    }
+
+int wc_RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
+                       word32 inSz)
+{
+    int ret;
+    const byte *n = NULL, *e = NULL;
+    word32 nSz = 0, eSz = 0;
+
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    ret = wc_RsaPublicKeyDecode_ex(input, inOutIdx, inSz, &n, &nSz, &e, &eSz);
+    if (ret == 0) {
+        ret = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz, key);
+    }
+
+    return ret;
 }
 
@@ -2843,4 +3920,10 @@
         return ASN_GETINT_E;
     }
+#ifdef HAVE_WOLF_BIGINT
+    if ((int)nSz > 0 && wc_bigint_from_unsigned_bin(&key->n.raw, n, nSz) != 0) {
+        mp_clear(&key->n);
+        return ASN_GETINT_E;
+    }
+#endif /* HAVE_WOLF_BIGINT */
 
     if (mp_init(&key->e) != MP_OKAY) {
@@ -2854,4 +3937,11 @@
         return ASN_GETINT_E;
     }
+#ifdef HAVE_WOLF_BIGINT
+    if ((int)eSz > 0 && wc_bigint_from_unsigned_bin(&key->e.raw, e, eSz) != 0) {
+        mp_clear(&key->n);
+        mp_clear(&key->e);
+        return ASN_GETINT_E;
+    }
+#endif /* HAVE_WOLF_BIGINT */
 
 #ifdef WOLFSSL_XILINX_CRYPT
@@ -2864,5 +3954,5 @@
 }
 #endif /* HAVE_USER_RSA */
-#endif
+#endif /* !NO_RSA */
 
 #ifndef NO_DH
@@ -2994,5 +4084,5 @@
 
 /* Release Tmp DSA resources */
-static INLINE void FreeTmpDsas(byte** tmps, void* heap)
+static WC_INLINE void FreeTmpDsas(byte** tmps, void* heap)
 {
     int i;
@@ -3076,5 +4166,6 @@
 
 
-void InitDecodedCert(DecodedCert* cert, byte* source, word32 inSz, void* heap)
+void InitDecodedCert(DecodedCert* cert,
+                     const byte* source, word32 inSz, void* heap)
 {
     if (cert != NULL) {
@@ -3136,5 +4227,5 @@
         XFREE(cert->subjectCN, cert->heap, DYNAMIC_TYPE_SUBJECT_CN);
     if (cert->pubKeyStored == 1)
-        XFREE(cert->publicKey, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+        XFREE((void*)cert->publicKey, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
     if (cert->weOwnAltNames && cert->altNames)
         FreeAltNames(cert->altNames, cert->heap);
@@ -3152,5 +4243,5 @@
     XFREE(cert->hwSerialNum, cert->heap, DYNAMIC_TYPE_X509_EXT);
 #endif /* WOLFSSL_SEP */
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     if (cert->issuerName.fullName != NULL)
         XFREE(cert->issuerName.fullName, cert->heap, DYNAMIC_TYPE_X509);
@@ -3231,5 +4322,5 @@
 {
     int length;
-#ifdef HAVE_NTRU
+#if defined(HAVE_ECC) || defined(HAVE_NTRU)
     int tmpIdx = cert->srcIdx;
 #endif
@@ -3264,4 +4355,5 @@
             word32      rc;
             word32      remaining = cert->maxIdx - cert->srcIdx;
+            byte*       publicKey;
 #ifdef WOLFSSL_SMALL_STACK
             byte*       keyBlob = NULL;
@@ -3277,5 +4369,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-            keyBlob = (byte*)XMALLOC(MAX_NTRU_KEY_SZ, NULL,
+            keyBlob = (byte*)XMALLOC(MAX_NTRU_KEY_SZ, cert->heap,
                                      DYNAMIC_TYPE_TMP_BUFFER);
             if (keyBlob == NULL)
@@ -3287,5 +4379,5 @@
             if (rc != NTRU_OK) {
 #ifdef WOLFSSL_SMALL_STACK
-                XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(keyBlob, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
                 return ASN_NTRU_KEY_E;
@@ -3294,5 +4386,5 @@
             if ( (next - key) < 0) {
 #ifdef WOLFSSL_SMALL_STACK
-                XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(keyBlob, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
                 return ASN_NTRU_KEY_E;
@@ -3301,18 +4393,19 @@
             cert->srcIdx = tmpIdx + (int)(next - key);
 
-            cert->publicKey = (byte*) XMALLOC(keyLen, cert->heap,
+            publicKey = (byte*)XMALLOC(keyLen, cert->heap,
                                               DYNAMIC_TYPE_PUBLIC_KEY);
-            if (cert->publicKey == NULL) {
+            if (publicKey == NULL) {
 #ifdef WOLFSSL_SMALL_STACK
-                XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(keyBlob, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
                 return MEMORY_E;
             }
-            XMEMCPY(cert->publicKey, keyBlob, keyLen);
+            XMEMCPY(publicKey, keyBlob, keyLen);
+            cert->publicKey = publicKey;
             cert->pubKeyStored = 1;
             cert->pubKeySize   = keyLen;
 
 #ifdef WOLFSSL_SMALL_STACK
-            XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(keyBlob, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -3324,5 +4417,10 @@
         {
             int ret;
-
+            byte seq[5];
+            int pubLen = length + 1 + SetLength(length, seq);
+            byte* publicKey;
+
+            if (cert->source[cert->srcIdx] !=
+                                             (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
             if (GetObjectId(cert->source, &cert->srcIdx,
                             &cert->pkCurveOID, oidCurveType, cert->maxIdx) < 0)
@@ -3337,14 +4435,16 @@
             if (ret != 0)
                 return ret;
-
-            cert->publicKey = (byte*)XMALLOC(length, cert->heap,
+            }
+
+            publicKey = (byte*)XMALLOC(pubLen, cert->heap,
                                              DYNAMIC_TYPE_PUBLIC_KEY);
-            if (cert->publicKey == NULL)
+            if (publicKey == NULL)
                 return MEMORY_E;
-            XMEMCPY(cert->publicKey, &cert->source[cert->srcIdx], length);
+            XMEMCPY(publicKey, &cert->source[tmpIdx], pubLen);
+            cert->publicKey = publicKey;
             cert->pubKeyStored = 1;
-            cert->pubKeySize   = length;
-
-            cert->srcIdx += length;
+            cert->pubKeySize   = pubLen;
+
+            cert->srcIdx = tmpIdx + pubLen;
 
             return 0;
@@ -3354,4 +4454,5 @@
         case ED25519k:
         {
+            byte* publicKey;
             int ret;
 
@@ -3363,9 +4464,10 @@
                 return ret;
 
-            cert->publicKey = (byte*) XMALLOC(length, cert->heap,
+            publicKey = (byte*) XMALLOC(length, cert->heap,
                                               DYNAMIC_TYPE_PUBLIC_KEY);
-            if (cert->publicKey == NULL)
+            if (publicKey == NULL)
                 return MEMORY_E;
-            XMEMCPY(cert->publicKey, &cert->source[cert->srcIdx], length);
+            XMEMCPY(publicKey, &cert->source[cert->srcIdx], length);
+            cert->publicKey = publicKey;
             cert->pubKeyStored = 1;
             cert->pubKeySize   = length;
@@ -3380,4 +4482,46 @@
     }
 }
+
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+WOLFSSL_LOCAL int OBJ_sn2nid(const char *sn)
+{
+    static const struct {
+        const char *sn;
+        int  nid;
+    } sn2nid[] = {
+        {WOLFSSL_COMMON_NAME, NID_commonName},
+        {WOLFSSL_COUNTRY_NAME, NID_countryName},
+        {WOLFSSL_LOCALITY_NAME, NID_localityName},
+        {WOLFSSL_STATE_NAME, NID_stateOrProvinceName},
+        {WOLFSSL_ORG_NAME, NID_organizationName},
+        {WOLFSSL_ORGUNIT_NAME, NID_organizationalUnitName},
+        {WOLFSSL_EMAIL_ADDR, NID_emailAddress},
+        {NULL, -1}};
+
+    int i;
+    WOLFSSL_ENTER("OBJ_osn2nid");
+    #ifdef HAVE_ECC
+    /* Nginx uses this OpenSSL string. */
+    if (XSTRNCMP(sn, "prime256v1", 10) == 0)
+        sn = "SECP256R1";
+    if (XSTRNCMP(sn, "secp384r1", 10) == 0)
+        sn = "SECP384R1";
+    /* find based on name and return NID */
+    for (i = 0; i < ecc_sets[i].size; i++) {
+        if (XSTRNCMP(sn, ecc_sets[i].name, ECC_MAXNAME) == 0) {
+            return ecc_sets[i].id;
+        }
+    }
+    #endif
+
+    for(i=0; sn2nid[i].sn != NULL; i++) {
+        if(XSTRNCMP(sn, sn2nid[i].sn, XSTRLEN(sn2nid[i].sn)) == 0) {
+            return sn2nid[i].nid;
+        }
+    }
+
+    return NID_undef;
+}
+#endif
 
 /* process NAME, either issuer or subject */
@@ -3390,7 +4534,8 @@
     byte*  hash;
     word32 idx;
-    #ifdef OPENSSL_EXTRA
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
         DecodedName* dName =
                   (nameType == ISSUER) ? &cert->issuerName : &cert->subjectName;
+        int dcnum = 0;
     #endif /* OPENSSL_EXTRA */
 
@@ -3404,4 +4549,8 @@
         full = cert->subject;
         hash = cert->subjectHash;
+    }
+
+    if (cert->srcIdx >= cert->maxIdx) {
+        return BUFFER_E;
     }
 
@@ -3421,9 +4570,5 @@
         return ASN_PARSE_E;
 
-#ifdef NO_SHA
-    ret = wc_Sha256Hash(&cert->source[idx], length + cert->srcIdx - idx, hash);
-#else
-    ret = wc_ShaHash(&cert->source[idx], length + cert->srcIdx - idx, hash);
-#endif
+    ret = CalcHashId(&cert->source[idx], length + cert->srcIdx - idx, hash);
     if (ret != 0)
         return ret;
@@ -3432,5 +4577,5 @@
     idx = 0;
 
-#ifdef HAVE_PKCS7
+#if defined(HAVE_PKCS7) || defined(WOLFSSL_CERT_EXT)
     /* store pointer to raw issuer */
     if (nameType == ISSUER) {
@@ -3471,7 +4616,7 @@
         /* v1 name types */
         if (joint[0] == 0x55 && joint[1] == 0x04) {
+            const char*  copy = NULL;
+            int    strLen;
             byte   id;
-            byte   copy = FALSE;
-            int    strLen;
 
             cert->srcIdx += 2;
@@ -3496,10 +4641,6 @@
                 }
 
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/CN=", 4);
-                    idx += 4;
-                    copy = TRUE;
-                }
-                #ifdef OPENSSL_EXTRA
+                copy = WOLFSSL_COMMON_NAME;
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->cnIdx = cert->srcIdx;
                     dName->cnLen = strLen;
@@ -3507,9 +4648,5 @@
             }
             else if (id == ASN_SUR_NAME) {
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/SN=", 4);
-                    idx += 4;
-                    copy = TRUE;
-                }
+                copy = WOLFSSL_SUR_NAME;
                 #ifdef WOLFSSL_CERT_GEN
                     if (nameType == SUBJECT) {
@@ -3519,5 +4656,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->snIdx = cert->srcIdx;
                     dName->snLen = strLen;
@@ -3525,9 +4662,5 @@
             }
             else if (id == ASN_COUNTRY_NAME) {
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/C=", 3);
-                    idx += 3;
-                    copy = TRUE;
-                }
+                copy = WOLFSSL_COUNTRY_NAME;
                 #ifdef WOLFSSL_CERT_GEN
                     if (nameType == SUBJECT) {
@@ -3537,5 +4670,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->cIdx = cert->srcIdx;
                     dName->cLen = strLen;
@@ -3543,9 +4676,5 @@
             }
             else if (id == ASN_LOCALITY_NAME) {
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/L=", 3);
-                    idx += 3;
-                    copy = TRUE;
-                }
+                copy = WOLFSSL_LOCALITY_NAME;
                 #ifdef WOLFSSL_CERT_GEN
                     if (nameType == SUBJECT) {
@@ -3555,5 +4684,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->lIdx = cert->srcIdx;
                     dName->lLen = strLen;
@@ -3561,9 +4690,5 @@
             }
             else if (id == ASN_STATE_NAME) {
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/ST=", 4);
-                    idx += 4;
-                    copy = TRUE;
-                }
+                copy = WOLFSSL_STATE_NAME;
                 #ifdef WOLFSSL_CERT_GEN
                     if (nameType == SUBJECT) {
@@ -3573,5 +4698,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->stIdx = cert->srcIdx;
                     dName->stLen = strLen;
@@ -3579,9 +4704,5 @@
             }
             else if (id == ASN_ORG_NAME) {
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/O=", 3);
-                    idx += 3;
-                    copy = TRUE;
-                }
+                copy = WOLFSSL_ORG_NAME;
                 #ifdef WOLFSSL_CERT_GEN
                     if (nameType == SUBJECT) {
@@ -3591,5 +4712,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->oIdx = cert->srcIdx;
                     dName->oLen = strLen;
@@ -3597,9 +4718,5 @@
             }
             else if (id == ASN_ORGUNIT_NAME) {
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/OU=", 4);
-                    idx += 4;
-                    copy = TRUE;
-                }
+                copy = WOLFSSL_ORGUNIT_NAME;
                 #ifdef WOLFSSL_CERT_GEN
                     if (nameType == SUBJECT) {
@@ -3609,5 +4726,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->ouIdx = cert->srcIdx;
                     dName->ouLen = strLen;
@@ -3615,16 +4732,40 @@
             }
             else if (id == ASN_SERIAL_NUMBER) {
-                if (!tooBig) {
-                   XMEMCPY(&full[idx], "/serialNumber=", 14);
-                   idx += 14;
-                   copy = TRUE;
+                copy = WOLFSSL_SERIAL_NUMBER;
+                #ifdef WOLFSSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectSND = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectSNDLen = strLen;
+                        cert->subjectSNDEnc = b;
                 }
-                #ifdef OPENSSL_EXTRA
+                #endif /* WOLFSSL_CERT_GEN */
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->snIdx = cert->srcIdx;
                     dName->snLen = strLen;
                 #endif /* OPENSSL_EXTRA */
             }
-
+        #ifdef WOLFSSL_CERT_EXT
+            else if (id == ASN_BUS_CAT) {
+                copy = WOLFSSL_BUS_CAT;
+            #ifdef WOLFSSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectBC = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectBCLen = strLen;
+                    cert->subjectBCEnc = b;
+                }
+            #endif /* WOLFSSL_CERT_GEN */
+            #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+                dName->bcIdx = cert->srcIdx;
+                dName->bcLen = strLen;
+            #endif /* OPENSSL_EXTRA */
+            }
+        #endif /* WOLFSSL_CERT_EXT */
             if (copy && !tooBig) {
+                XMEMCPY(&full[idx], copy, XSTRLEN(copy));
+                idx += (word32)XSTRLEN(copy);
+            #ifdef WOLFSSL_WPAS
+                full[idx] = '=';
+                idx++;
+            #endif
                 XMEMCPY(&full[idx], &cert->source[cert->srcIdx], strLen);
                 idx += strLen;
@@ -3633,8 +4774,80 @@
             cert->srcIdx += strLen;
         }
+    #ifdef WOLFSSL_CERT_EXT
+        else if ((0 == XMEMCMP(&cert->source[cert->srcIdx], ASN_JOI_PREFIX,
+                               XSTRLEN(ASN_JOI_PREFIX))) &&
+                 ((cert->source[cert->srcIdx + XSTRLEN(ASN_JOI_PREFIX)] ==
+                         ASN_JOI_C) ||
+                  (cert->source[cert->srcIdx + XSTRLEN(ASN_JOI_PREFIX)] ==
+                          ASN_JOI_ST)))
+        {
+            int strLen;
+            byte id;
+            const char* copy = NULL;
+
+            cert->srcIdx += 10;
+            id = cert->source[cert->srcIdx++];
+            b = cert->source[cert->srcIdx++]; /* encoding */
+
+            if (GetLength(cert->source, &cert->srcIdx, &strLen,
+                          cert->maxIdx) < 0)
+                return ASN_PARSE_E;
+
+            if ((strLen + strlen(WOLFSSL_JOI_ST)) > (ASN_NAME_MAX - idx)) {
+                WOLFSSL_MSG("ASN Name too big, skipping");
+                tooBig = TRUE;
+            }
+
+            /* Check for jurisdiction of incorporation country name */
+            if (id == ASN_JOI_C) {
+                copy = WOLFSSL_JOI_C;
+                #ifdef WOLFSSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectJC = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectJCLen = strLen;
+                        cert->subjectJCEnc = b;
+                    }
+                #endif /* WOLFSSL_CERT_GEN */
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+                    dName->jcIdx = cert->srcIdx;
+                    dName->jcLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+
+            /* Check for jurisdiction of incorporation state name */
+            else if (id == ASN_JOI_ST) {
+                copy = WOLFSSL_JOI_ST;
+                #ifdef WOLFSSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectJS = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectJSLen = strLen;
+                        cert->subjectJSEnc = b;
+                    }
+                #endif /* WOLFSSL_CERT_GEN */
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+                    dName->jsIdx = cert->srcIdx;
+                    dName->jsLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+
+            if ((copy != NULL) && (tooBig != 1)) {
+                XMEMCPY(&full[idx], copy, XSTRLEN(copy));
+                idx += (word32)XSTRLEN(copy);
+            #ifdef WOLFSSL_WPAS
+                full[idx] = '=';
+                idx++;
+            #endif
+                XMEMCPY(&full[idx], &cert->source[cert->srcIdx], strLen);
+                idx += strLen;
+            }
+
+            cert->srcIdx += strLen;
+        }
+    #endif /* WOLFSSL_CERT_EXT */
         else {
             /* skip */
             byte email = FALSE;
-            byte uid   = FALSE;
+            byte pilot = FALSE;
+            byte id    = 0;
             int  adv;
 
@@ -3642,6 +4855,9 @@
                 email = TRUE;
 
-            if (joint[0] == 0x9  && joint[1] == 0x92)  /* uid id hdr */
-                uid = TRUE;
+            if (joint[0] == 0x9  && joint[1] == 0x92) { /* uid id hdr */
+                /* last value of OID is the type of pilot attribute */
+                id    = cert->source[cert->srcIdx + oidSz - 1];
+                pilot = TRUE;
+            }
 
             cert->srcIdx += oidSz + 1;
@@ -3671,5 +4887,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->emailIdx = cert->srcIdx;
                     dName->emailLen = adv;
@@ -3685,4 +4901,5 @@
                             return MEMORY_E;
                         }
+                        emailName->type = 0;
                         emailName->name = (char*)XMALLOC(adv + 1,
                                               cert->heap, DYNAMIC_TYPE_ALTNAME);
@@ -3692,7 +4909,8 @@
                             return MEMORY_E;
                         }
+                        emailName->len = adv;
                         XMEMCPY(emailName->name,
                                               &cert->source[cert->srcIdx], adv);
-                        emailName->name[adv] = 0;
+                        emailName->name[adv] = '\0';
 
                         emailName->next = cert->altEmailNames;
@@ -3706,5 +4924,5 @@
             }
 
-            if (uid) {
+            if (pilot) {
                 if ( (5 + adv) > (int)(ASN_NAME_MAX - idx)) {
                     WOLFSSL_MSG("ASN name too big, skipping");
@@ -3712,14 +4930,34 @@
                 }
                 if (!tooBig) {
+                    switch (id) {
+                        case ASN_USER_ID:
                     XMEMCPY(&full[idx], "/UID=", 5);
                     idx += 5;
-
+                        #if defined(OPENSSL_EXTRA) || \
+                            defined(OPENSSL_EXTRA_X509_SMALL)
+                            dName->uidIdx = cert->srcIdx;
+                            dName->uidLen = adv;
+                        #endif /* OPENSSL_EXTRA */
+                            break;
+
+                        case ASN_DOMAIN_COMPONENT:
+                            XMEMCPY(&full[idx], "/DC=", 4);
+                            idx += 4;
+                        #if defined(OPENSSL_EXTRA) || \
+                            defined(OPENSSL_EXTRA_X509_SMALL)
+                            dName->dcIdx[dcnum] = cert->srcIdx;
+                            dName->dcLen[dcnum] = adv;
+                            dName->dcNum = dcnum + 1;
+                            dcnum++;
+                        #endif /* OPENSSL_EXTRA */
+                            break;
+
+                        default:
+                            WOLFSSL_MSG("Unknown pilot attribute type");
+                            return ASN_PARSE_E;
+                    }
                     XMEMCPY(&full[idx], &cert->source[cert->srcIdx], adv);
                     idx += adv;
                 }
-                #ifdef OPENSSL_EXTRA
-                    dName->uidIdx = cert->srcIdx;
-                    dName->uidLen = adv;
-                #endif /* OPENSSL_EXTRA */
             }
 
@@ -3729,7 +4967,8 @@
     full[idx++] = 0;
 
-    #ifdef OPENSSL_EXTRA
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     {
         int totalLen = 0;
+        int i = 0;
 
         if (dName->cnLen != 0)
@@ -3753,4 +4992,8 @@
         if (dName->serialLen != 0)
             totalLen += dName->serialLen + 14;
+        if (dName->dcNum != 0){
+            for (i = 0;i < dName->dcNum;i++)
+                totalLen += dName->dcLen[i] + 4;
+        }
 
         dName->fullName = (char*)XMALLOC(totalLen + 1, cert->heap,
@@ -3761,5 +5004,6 @@
             if (dName->cnLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/CN=", 4);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_COMMON_NAME, 4);
+                dName->cnNid = OBJ_sn2nid((const char *)WOLFSSL_COMMON_NAME);
                 idx += 4;
                 XMEMCPY(&dName->fullName[idx],
@@ -3770,5 +5014,6 @@
             if (dName->snLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/SN=", 4);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_SUR_NAME, 4);
+                dName->snNid = OBJ_sn2nid((const char *)WOLFSSL_SUR_NAME);
                 idx += 4;
                 XMEMCPY(&dName->fullName[idx],
@@ -3779,5 +5024,6 @@
             if (dName->cLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/C=", 3);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_COUNTRY_NAME, 3);
+                dName->cNid = OBJ_sn2nid((const char *)WOLFSSL_COUNTRY_NAME);
                 idx += 3;
                 XMEMCPY(&dName->fullName[idx],
@@ -3788,5 +5034,6 @@
             if (dName->lLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/L=", 3);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_LOCALITY_NAME, 3);
+                dName->lNid = OBJ_sn2nid((const char *)WOLFSSL_LOCALITY_NAME);
                 idx += 3;
                 XMEMCPY(&dName->fullName[idx],
@@ -3797,5 +5044,6 @@
             if (dName->stLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/ST=", 4);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_STATE_NAME, 4);
+                dName->stNid = OBJ_sn2nid((const char *)WOLFSSL_STATE_NAME);
                 idx += 4;
                 XMEMCPY(&dName->fullName[idx],
@@ -3806,5 +5054,6 @@
             if (dName->oLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/O=", 3);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_ORG_NAME, 3);
+                dName->oNid = OBJ_sn2nid((const char *)WOLFSSL_ORG_NAME);
                 idx += 3;
                 XMEMCPY(&dName->fullName[idx],
@@ -3815,5 +5064,6 @@
             if (dName->ouLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/OU=", 4);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_ORGUNIT_NAME, 4);
+                dName->ouNid = OBJ_sn2nid((const char *)WOLFSSL_ORGUNIT_NAME);
                 idx += 4;
                 XMEMCPY(&dName->fullName[idx],
@@ -3825,4 +5075,5 @@
                 dName->entryCount++;
                 XMEMCPY(&dName->fullName[idx], "/emailAddress=", 14);
+                dName->emailNid = OBJ_sn2nid((const char *)"/emailAddress=");
                 idx += 14;
                 XMEMCPY(&dName->fullName[idx],
@@ -3831,7 +5082,19 @@
                 idx += dName->emailLen;
             }
+            for (i = 0;i < dName->dcNum;i++){
+                if (dName->dcLen[i] != 0) {
+                    dName->entryCount++;
+                    XMEMCPY(&dName->fullName[idx], WOLFSSL_DOMAIN_COMPONENT, 4);
+                    idx += 4;
+                    XMEMCPY(&dName->fullName[idx],
+                                    &cert->source[dName->dcIdx[i]], dName->dcLen[i]);
+                    dName->dcIdx[i] = idx;
+                    idx += dName->dcLen[i];
+                }
+            }
             if (dName->uidLen != 0) {
                 dName->entryCount++;
                 XMEMCPY(&dName->fullName[idx], "/UID=", 5);
+                dName->uidNid = OBJ_sn2nid((const char *)"/UID=");
                 idx += 5;
                 XMEMCPY(&dName->fullName[idx],
@@ -3842,5 +5105,6 @@
             if (dName->serialLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/serialNumber=", 14);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_SERIAL_NUMBER, 14);
+                dName->serialNid = OBJ_sn2nid((const char *)WOLFSSL_SERIAL_NUMBER);
                 idx += 14;
                 XMEMCPY(&dName->fullName[idx],
@@ -3860,86 +5124,15 @@
 
 #ifndef NO_ASN_TIME
-#if !defined(NO_TIME_H) && defined(USE_WOLF_VALIDDATE)
-
-/* to the second */
-static int DateGreaterThan(const struct tm* a, const struct tm* b)
-{
-    if (a->tm_year > b->tm_year)
-        return 1;
-
-    if (a->tm_year == b->tm_year && a->tm_mon > b->tm_mon)
-        return 1;
-
-    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
-           a->tm_mday > b->tm_mday)
-        return 1;
-
-    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
-        a->tm_mday == b->tm_mday && a->tm_hour > b->tm_hour)
-        return 1;
-
-    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
-        a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour &&
-        a->tm_min > b->tm_min)
-        return 1;
-
-    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
-        a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour &&
-        a->tm_min  == b->tm_min  && a->tm_sec > b->tm_sec)
-        return 1;
-
-    return 0; /* false */
-}
-
-
-static INLINE int DateLessThan(const struct tm* a, const struct tm* b)
-{
-    return DateGreaterThan(b,a);
-}
-
-
-#if defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
-int GetTimeString(byte* date, int format, char* buf, int len)
-{
-    struct tm t;
-    int idx = 0;
-
-    if (!ExtractDate(date, format, &t, &idx)) {
-        return 0;
-    }
-
-    if (date[idx] != 'Z') {
-        WOLFSSL_MSG("UTCtime, not Zulu") ;
-        return 0;
-    }
-
-    /* place month in buffer */
-    buf[0] = '\0';
-    switch(t.tm_mon) {
-        case 0:  XSTRNCAT(buf, "Jan ", 4); break;
-        case 1:  XSTRNCAT(buf, "Feb ", 4); break;
-        case 2:  XSTRNCAT(buf, "Mar ", 4); break;
-        case 3:  XSTRNCAT(buf, "Apr ", 4); break;
-        case 4:  XSTRNCAT(buf, "May ", 4); break;
-        case 5:  XSTRNCAT(buf, "Jun ", 4); break;
-        case 6:  XSTRNCAT(buf, "Jul ", 4); break;
-        case 7:  XSTRNCAT(buf, "Aug ", 4); break;
-        case 8:  XSTRNCAT(buf, "Sep ", 4); break;
-        case 9:  XSTRNCAT(buf, "Oct ", 4); break;
-        case 10: XSTRNCAT(buf, "Nov ", 4); break;
-        case 11: XSTRNCAT(buf, "Dec ", 4); break;
-        default:
-            return 0;
-
-    }
-    idx = 4; /* use idx now for char buffer */
-    buf[idx] = ' ';
-
-    XSNPRINTF(buf + idx, len - idx, "%2d %02d:%02d:%02d %d GMT",
-              t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, t.tm_year + 1900);
-
-    return 1;
-}
-#endif /* WOLFSSL_MYSQL_COMPATIBLE */
+
+/* two byte date/time, add to value */
+static WC_INLINE void GetTime(int* value, const byte* date, int* idx)
+{
+    int i = *idx;
+
+    *value += btoi(date[i++]) * 10;
+    *value += btoi(date[i++]);
+
+    *idx = i;
+}
 
 int ExtractDate(const unsigned char* date, unsigned char format,
@@ -3957,5 +5150,5 @@
         certTime->tm_year += btoi(date[*idx]) * 1000; *idx = *idx + 1;
         certTime->tm_year += btoi(date[*idx]) * 100;  *idx = *idx + 1;
-    }
+}
 
     /* adjust tm_year, tm_mon */
@@ -3970,4 +5163,178 @@
 }
 
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_MYSQL_COMPATIBLE) || \
+    defined(OPENSSL_EXTRA) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+int GetTimeString(byte* date, int format, char* buf, int len)
+{
+    struct tm t;
+    int idx = 0;
+
+    if (!ExtractDate(date, (unsigned char)format, &t, &idx)) {
+        return 0;
+    }
+
+    if (date[idx] != 'Z') {
+        WOLFSSL_MSG("UTCtime, not Zulu") ;
+        return 0;
+    }
+
+    /* place month in buffer */
+    buf[0] = '\0';
+    switch(t.tm_mon) {
+        case 0:  XSTRNCAT(buf, "Jan ", 5); break;
+        case 1:  XSTRNCAT(buf, "Feb ", 5); break;
+        case 2:  XSTRNCAT(buf, "Mar ", 5); break;
+        case 3:  XSTRNCAT(buf, "Apr ", 5); break;
+        case 4:  XSTRNCAT(buf, "May ", 5); break;
+        case 5:  XSTRNCAT(buf, "Jun ", 5); break;
+        case 6:  XSTRNCAT(buf, "Jul ", 5); break;
+        case 7:  XSTRNCAT(buf, "Aug ", 5); break;
+        case 8:  XSTRNCAT(buf, "Sep ", 5); break;
+        case 9:  XSTRNCAT(buf, "Oct ", 5); break;
+        case 10: XSTRNCAT(buf, "Nov ", 5); break;
+        case 11: XSTRNCAT(buf, "Dec ", 5); break;
+        default:
+            return 0;
+
+    }
+    idx = 4; /* use idx now for char buffer */
+
+    XSNPRINTF(buf + idx, len - idx, "%2d %02d:%02d:%02d %d GMT",
+              t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, t.tm_year + 1900);
+
+    return 1;
+}
+#endif /* OPENSSL_ALL || WOLFSSL_MYSQL_COMPATIBLE || WOLFSSL_NGINX || WOLFSSL_HAPROXY */
+
+
+#if !defined(NO_ASN_TIME) && defined(HAVE_PKCS7)
+
+/* Set current time string, either UTC or GeneralizedTime.
+ * (void*) tm should be a pointer to time_t, output is placed in buf.
+ *
+ * Return time string length placed in buf on success, negative on error */
+int GetAsnTimeString(void* currTime, byte* buf, word32 len)
+{
+    struct tm* ts      = NULL;
+    struct tm* tmpTime = NULL;
+#if defined(NEED_TMP_TIME)
+    struct tm tmpTimeStorage;
+    tmpTime = &tmpTimeStorage;
+#else
+    (void)tmpTime;
+#endif
+    byte* data_ptr  = buf;
+    word32 data_len = 0;
+    int year, mon, day, hour, mini, sec;
+
+    WOLFSSL_ENTER("SetAsnTimeString");
+
+    if (buf == NULL || len == 0)
+        return BAD_FUNC_ARG;
+
+    ts = (struct tm *)XGMTIME((time_t*)currTime, tmpTime);
+    if (ts == NULL){
+        WOLFSSL_MSG("failed to get time data.");
+        return ASN_TIME_E;
+    }
+
+    /* Note ASN_UTC_TIME_SIZE and ASN_GENERALIZED_TIME_SIZE include space for
+     * the null terminator. ASN encoded values leave off the terminator. */
+
+    if (ts->tm_year >= 50 && ts->tm_year < 150) {
+        /* UTC Time */
+        char utc_str[ASN_UTC_TIME_SIZE];
+        data_len = ASN_UTC_TIME_SIZE - 1 + 2;
+
+        if (len < data_len)
+            return BUFFER_E;
+
+        if (ts->tm_year >= 50 && ts->tm_year < 100) {
+            year = ts->tm_year;
+        } else if (ts->tm_year >= 100 && ts->tm_year < 150) {
+            year = ts->tm_year - 100;
+        }
+        else {
+            WOLFSSL_MSG("unsupported year range");
+            return BAD_FUNC_ARG;
+    }
+        mon  = ts->tm_mon + 1;
+        day  = ts->tm_mday;
+        hour = ts->tm_hour;
+        mini = ts->tm_min;
+        sec  = ts->tm_sec;
+        XSNPRINTF((char *)utc_str, ASN_UTC_TIME_SIZE,
+                  "%02d%02d%02d%02d%02d%02dZ", year, mon, day, hour, mini, sec);
+        *data_ptr = (byte) ASN_UTC_TIME; data_ptr++;
+        /* -1 below excludes null terminator */
+        *data_ptr = (byte) ASN_UTC_TIME_SIZE - 1; data_ptr++;
+        XMEMCPY(data_ptr,(byte *)utc_str, ASN_UTC_TIME_SIZE - 1);
+
+    } else {
+        /* GeneralizedTime */
+        char gt_str[ASN_GENERALIZED_TIME_SIZE];
+        data_len = ASN_GENERALIZED_TIME_SIZE - 1 + 2;
+
+        if (len < data_len)
+            return BUFFER_E;
+
+        year = ts->tm_year + 1900;
+        mon  = ts->tm_mon + 1;
+        day  = ts->tm_mday;
+        hour = ts->tm_hour;
+        mini = ts->tm_min;
+        sec  = ts->tm_sec;
+        XSNPRINTF((char *)gt_str, ASN_GENERALIZED_TIME_SIZE,
+                  "%4d%02d%02d%02d%02d%02dZ", year, mon, day, hour, mini, sec);
+        *data_ptr = (byte) ASN_GENERALIZED_TIME; data_ptr++;
+        /* -1 below excludes null terminator */
+        *data_ptr = (byte) ASN_GENERALIZED_TIME_SIZE - 1; data_ptr++;
+        XMEMCPY(data_ptr,(byte *)gt_str, ASN_GENERALIZED_TIME_SIZE - 1);
+    }
+
+    return data_len;
+}
+
+#endif /* !NO_ASN_TIME && HAVE_PKCS7 */
+
+
+#if defined(USE_WOLF_VALIDDATE)
+
+/* to the second */
+static int DateGreaterThan(const struct tm* a, const struct tm* b)
+{
+    if (a->tm_year > b->tm_year)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon > b->tm_mon)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+           a->tm_mday > b->tm_mday)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+        a->tm_mday == b->tm_mday && a->tm_hour > b->tm_hour)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+        a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour &&
+        a->tm_min > b->tm_min)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+        a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour &&
+        a->tm_min  == b->tm_min  && a->tm_sec > b->tm_sec)
+    return 1;
+
+    return 0; /* false */
+}
+
+
+static WC_INLINE int DateLessThan(const struct tm* a, const struct tm* b)
+{
+    return DateGreaterThan(b,a);
+}
 
 /* like atoi but only use first byte */
@@ -4046,5 +5413,5 @@
     return 1;
 }
-#endif /* !NO_TIME_H && USE_WOLF_VALIDDATE */
+#endif /* USE_WOLF_VALIDDATE */
 
 int wc_GetTime(void* timePtr, word32 timeSize)
@@ -4067,12 +5434,49 @@
 #endif /* !NO_ASN_TIME */
 
-static int GetDate(DecodedCert* cert, int dateType)
+
+/* Get date buffer, format and length. Returns 0=success or error */
+static int GetDateInfo(const byte* source, word32* idx, const byte** pDate,
+                        byte* pFormat, int* pLength, word32 maxIdx)
 {
     int    length;
+    byte format;
+
+    if (source == NULL || idx == NULL)
+        return BAD_FUNC_ARG;
+
+    /* get ASN format header */
+    if (*idx+1 > maxIdx)
+        return BUFFER_E;
+    format = source[*idx];
+    *idx += 1;
+    if (format != ASN_UTC_TIME && format != ASN_GENERALIZED_TIME)
+        return ASN_TIME_E;
+
+    /* get length */
+    if (GetLength(source, idx, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+    if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE)
+        return ASN_DATE_SZ_E;
+
+    /* return format, date and length */
+    if (pFormat)
+        *pFormat = format;
+    if (pDate)
+        *pDate = &source[*idx];
+    if (pLength)
+        *pLength = length;
+
+    *idx += length;
+
+    return 0;
+}
+
+static int GetDate(DecodedCert* cert, int dateType, int verify)
+{
+    int    ret, length;
+    const byte *datePtr = NULL;
     byte   date[MAX_DATE_SIZE];
-    byte   b;
+    byte   format;
     word32 startIdx = 0;
-
-    XMEMSET(date, 0, MAX_DATE_SIZE);
 
     if (dateType == BEFORE)
@@ -4082,16 +5486,11 @@
     startIdx = cert->srcIdx;
 
-    b = cert->source[cert->srcIdx++];
-    if (b != ASN_UTC_TIME && b != ASN_GENERALIZED_TIME)
-        return ASN_TIME_E;
-
-    if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
-        return ASN_PARSE_E;
-
-    if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE)
-        return ASN_DATE_SZ_E;
-
-    XMEMCPY(date, &cert->source[cert->srcIdx], length);
-    cert->srcIdx += length;
+    ret = GetDateInfo(cert->source, &cert->srcIdx, &datePtr, &format,
+                      &length, cert->maxIdx);
+    if (ret < 0)
+        return ret;
+
+    XMEMSET(date, 0, MAX_DATE_SIZE);
+    XMEMCPY(date, datePtr, length);
 
     if (dateType == BEFORE)
@@ -4101,5 +5500,5 @@
 
 #ifndef NO_ASN_TIME
-    if (!XVALIDATE_DATE(date, b, dateType)) {
+    if (verify != NO_VERIFY && !XVALIDATE_DATE(date, format, dateType)) {
         if (dateType == BEFORE)
             return ASN_BEFORE_DATE_E;
@@ -4107,4 +5506,6 @@
             return ASN_AFTER_DATE_E;
     }
+#else
+    (void)verify;
 #endif
 
@@ -4120,8 +5521,8 @@
         return ASN_PARSE_E;
 
-    if (GetDate(cert, BEFORE) < 0 && verify != NO_VERIFY)
+    if (GetDate(cert, BEFORE, verify) < 0)
         badDate = ASN_BEFORE_DATE_E;           /* continue parsing */
 
-    if (GetDate(cert, AFTER) < 0 && verify != NO_VERIFY)
+    if (GetDate(cert, AFTER, verify) < 0)
         return ASN_AFTER_DATE_E;
 
@@ -4131,4 +5532,58 @@
     return 0;
 }
+
+
+int wc_GetDateInfo(const byte* certDate, int certDateSz, const byte** date,
+    byte* format, int* length)
+{
+    int ret;
+    word32 idx = 0;
+
+    ret = GetDateInfo(certDate, &idx, date, format, length, certDateSz);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+#ifndef NO_ASN_TIME
+int wc_GetDateAsCalendarTime(const byte* date, int length, byte format,
+    struct tm* timearg)
+{
+    int idx = 0;
+    (void)length;
+    if (!ExtractDate(date, format, timearg, &idx))
+        return ASN_TIME_E;
+    return 0;
+}
+
+#if defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_ALT_NAMES)
+int wc_GetCertDates(Cert* cert, struct tm* before, struct tm* after)
+{
+    int ret = 0;
+    const byte* date;
+    byte format;
+    int length;
+
+    if (cert == NULL)
+        return BAD_FUNC_ARG;
+
+    if (before && cert->beforeDateSz > 0) {
+        ret = wc_GetDateInfo(cert->beforeDate, cert->beforeDateSz, &date,
+                             &format, &length);
+        if (ret == 0)
+            ret = wc_GetDateAsCalendarTime(date, length, format, before);
+    }
+    if (after && cert->afterDateSz > 0) {
+        ret = wc_GetDateInfo(cert->afterDate, cert->afterDateSz, &date,
+                             &format, &length);
+        if (ret == 0)
+            ret = wc_GetDateAsCalendarTime(date, length, format, after);
+    }
+
+    return ret;
+}
+#endif /* WOLFSSL_CERT_GEN && WOLFSSL_ALT_NAMES */
+#endif /* !NO_ASN_TIME */
 
 
@@ -4267,5 +5722,5 @@
 
 
-#if defined(HAVE_ECC) && (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN))
+#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT)
 
 static int SetCurve(ecc_key* key, byte* output)
@@ -4306,8 +5761,9 @@
 }
 
-#endif /* HAVE_ECC && (WOLFSSL_CERT_GEN || WOLFSSL_KEY_GEN) */
-
-
-static INLINE int IsSigAlgoECDSA(int algoOID)
+#endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT */
+
+
+#ifdef HAVE_ECC
+static WC_INLINE int IsSigAlgoECDSA(int algoOID)
 {
     /* ECDSA sigAlgo must not have ASN1 NULL parameters */
@@ -4319,4 +5775,5 @@
     return 0;
 }
+#endif
 
 WOLFSSL_LOCAL word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz)
@@ -4328,6 +5785,12 @@
 
     tagSz = (type == oidHashType ||
-             (type == oidSigType && !IsSigAlgoECDSA(algoOID) &&
-                                         algoOID != ED25519k) ||
+             (type == oidSigType
+        #ifdef HAVE_ECC
+              && !IsSigAlgoECDSA(algoOID)
+        #endif
+        #ifdef HAVE_ED25519
+              && algoOID != ED25519k
+        #endif
+              ) ||
              (type == oidKeyType && algoOID == RSAk)) ? 2 : 0;
 
@@ -4375,36 +5838,13 @@
 int wc_GetCTC_HashOID(int type)
 {
-    switch (type) {
-#ifdef WOLFSSL_MD2
-        case MD2:
-            return MD2h;
-#endif
-#ifndef NO_MD5
-        case WC_MD5:
-            return MD5h;
-#endif
-#ifndef NO_SHA
-        case WC_SHA:
-            return SHAh;
-#endif
-#ifdef WOLFSSL_SHA224
-        case WC_SHA224:
-            return SHA224h;
-#endif
-#ifndef NO_SHA256
-        case WC_SHA256:
-            return SHA256h;
-#endif
-#ifdef WOLFSSL_SHA384
-        case WC_SHA384:
-            return SHA384h;
-#endif
-#ifdef WOLFSSL_SHA512
-        case WC_SHA512:
-            return SHA512h;
-#endif
-        default:
-            return 0;
-    };
+    int ret;
+    enum wc_HashType hType;
+
+    hType = wc_HashTypeConvert(type);
+    ret = wc_HashGetOID(hType);
+    if (ret < 0)
+        ret = 0; /* backwards compatibility */
+
+    return ret;
 }
 
@@ -4433,4 +5873,5 @@
     }
 #endif
+#ifndef NO_ASN_CRYPT
     if (sigCtx->key.ptr) {
         switch (sigCtx->keyOID) {
@@ -4458,4 +5899,5 @@
         sigCtx->key.ptr = NULL;
     }
+#endif
 
     /* reset state, we are done */
@@ -4463,4 +5905,5 @@
 }
 
+#ifndef NO_ASN_CRYPT
 static int HashForSignature(const byte* buf, word32 bufSz, word32 sigOID,
                             byte* digest, int* typeH, int* digestSz, int verify)
@@ -4549,4 +5992,5 @@
     return ret;
 }
+#endif /* !NO_ASN_CRYPT */
 
 /* Return codes: 0=Success, Negative (see error-crypt.h), ASN_SIG_CONFIRM_E */
@@ -4570,7 +6014,10 @@
     WOLFSSL_ENTER("ConfirmSignature");
 
+#ifndef NO_ASN_CRYPT
     switch (sigCtx->state) {
         case SIG_STATE_BEGIN:
         {
+            sigCtx->keyOID = keyOID; /* must set early for cleanup */
+
             sigCtx->digest = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, sigCtx->heap,
                                                     DYNAMIC_TYPE_DIGEST);
@@ -4597,6 +6044,4 @@
         case SIG_STATE_KEY:
         {
-            sigCtx->keyOID = keyOID;
-
             switch (keyOID) {
             #ifndef NO_RSA
@@ -4637,4 +6082,6 @@
                 case ECDSAk:
                 {
+                    word32 idx = 0;
+
                     sigCtx->verify = 0;
                     sigCtx->key.ecc = (ecc_key*)XMALLOC(sizeof(ecc_key),
@@ -4647,6 +6094,7 @@
                         goto exit_cs;
                     }
-                    if ((ret = wc_ecc_import_x963(key, keySz,
-                                                        sigCtx->key.ecc)) < 0) {
+                    ret = wc_EccPublicKeyDecode(key, &idx, sigCtx->key.ecc,
+                                                                         keySz);
+                    if (ret < 0) {
                         WOLFSSL_MSG("ASN Key import error ECC");
                         goto exit_cs;
@@ -4696,5 +6144,5 @@
         #ifdef WOLFSSL_ASYNC_CRYPT
             if (sigCtx->devId != INVALID_DEVID && sigCtx->asyncDev && sigCtx->asyncCtx) {
-                /* make sure event is intialized */
+                /* make sure event is initialized */
                 WOLF_EVENT* event = &sigCtx->asyncDev->event;
                 ret = wolfAsync_EventInit(event, WOLF_EVENT_TYPE_ASYNC_WOLFSSL,
@@ -4711,6 +6159,17 @@
                 case RSAk:
                 {
+                #ifdef HAVE_PK_CALLBACKS
+                    if (sigCtx->pkCbRsa) {
+                        ret = sigCtx->pkCbRsa(
+                                sigCtx->plain, sigSz, &sigCtx->out,
+                                key, keySz,
+                                sigCtx->pkCtxRsa);
+                    }
+                    else
+                #endif /* HAVE_PK_CALLBACKS */
+                    {
                     ret = wc_RsaSSL_VerifyInline(sigCtx->plain, sigSz,
                                                 &sigCtx->out, sigCtx->key.rsa);
+                    }
                     break;
                 }
@@ -4719,6 +6178,19 @@
                 case ECDSAk:
                 {
+                #ifdef HAVE_PK_CALLBACKS
+                    if (sigCtx->pkCbEcc) {
+                        ret = sigCtx->pkCbEcc(
+                                sig, sigSz,
+                                sigCtx->digest, sigCtx->digestSz,
+                                key, keySz, &sigCtx->verify,
+                                sigCtx->pkCtxEcc);
+                    }
+                    else
+                #endif /* HAVE_PK_CALLBACKS */
+                    {
                     ret = wc_ecc_verify_hash(sig, sigSz, sigCtx->digest,
-                        sigCtx->digestSz, &sigCtx->verify, sigCtx->key.ecc);
+                                            sigCtx->digestSz, &sigCtx->verify,
+                                            sigCtx->key.ecc);
+                    }
                     break;
                 }
@@ -4769,5 +6241,5 @@
                     encodedSigSz = wc_EncodeSignature(encodedSig,
                             sigCtx->digest, sigCtx->digestSz, sigCtx->typeH);
-                    if (encodedSigSz == verifySz &&
+                    if (encodedSigSz == verifySz && sigCtx->out != NULL &&
                         XMEMCMP(sigCtx->out, encodedSig, encodedSigSz) == 0) {
                         ret = 0;
@@ -4820,4 +6292,9 @@
 exit_cs:
 
+#endif /* !NO_ASN_CRYPT */
+
+    (void)keyOID;
+    (void)sigOID;
+
     WOLFSSL_LEAVE("ConfirmSignature", ret);
 
@@ -4911,5 +6388,5 @@
                     while (name != NULL) {
                         if (MatchBaseName(ASN_DNS_TYPE,
-                                          name->name, (int)XSTRLEN(name->name),
+                                          name->name, name->len,
                                           base->name, base->nameSz)) {
                             return 0;
@@ -4924,5 +6401,5 @@
                     while (name != NULL) {
                         if (MatchBaseName(ASN_RFC822_TYPE,
-                                          name->name, (int)XSTRLEN(name->name),
+                                          name->name, name->len,
                                           base->name, base->nameSz)) {
                             return 0;
@@ -4968,5 +6445,5 @@
                     while (name != NULL) {
                         matchDns = MatchBaseName(ASN_DNS_TYPE,
-                                          name->name, (int)XSTRLEN(name->name),
+                                          name->name, name->len,
                                           base->name, base->nameSz);
                         name = name->next;
@@ -4983,5 +6460,5 @@
                     while (name != NULL) {
                         matchEmail = MatchBaseName(ASN_DNS_TYPE,
-                                          name->name, (int)XSTRLEN(name->name),
+                                          name->name, name->len,
                                           base->name, base->nameSz);
                         name = name->next;
@@ -5017,5 +6494,5 @@
 #endif /* IGNORE_NAME_CONSTRAINTS */
 
-static int DecodeAltNames(byte* input, int sz, DecodedCert* cert)
+static int DecodeAltNames(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5056,4 +6533,5 @@
             }
 
+            dnsEntry->type = ASN_DNS_TYPE;
             dnsEntry->name = (char*)XMALLOC(strLen + 1, cert->heap,
                                          DYNAMIC_TYPE_ALTNAME);
@@ -5063,5 +6541,5 @@
                 return MEMORY_E;
             }
-
+            dnsEntry->len = strLen;
             XMEMCPY(dnsEntry->name, &input[idx], strLen);
             dnsEntry->name[strLen] = '\0';
@@ -5092,4 +6570,5 @@
             }
 
+            emailEntry->type = ASN_RFC822_TYPE;
             emailEntry->name = (char*)XMALLOC(strLen + 1, cert->heap,
                                          DYNAMIC_TYPE_ALTNAME);
@@ -5099,5 +6578,5 @@
                 return MEMORY_E;
             }
-
+            emailEntry->len = strLen;
             XMEMCPY(emailEntry->name, &input[idx], strLen);
             emailEntry->name[strLen] = '\0';
@@ -5105,4 +6584,75 @@
             emailEntry->next = cert->altEmailNames;
             cert->altEmailNames = emailEntry;
+
+            length -= strLen;
+            idx    += strLen;
+        }
+        else if (b == (ASN_CONTEXT_SPECIFIC | ASN_URI_TYPE)) {
+            DNS_entry* uriEntry;
+            int strLen;
+            word32 lenStartIdx = idx;
+
+            WOLFSSL_MSG("\tPutting URI into list but not using");
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                WOLFSSL_MSG("\tfail: str length");
+                return ASN_PARSE_E;
+            }
+            length -= (idx - lenStartIdx);
+
+            /* check that strLen at index is not past input buffer */
+            if (strLen + (int)idx > sz) {
+                return BUFFER_E;
+            }
+
+        #ifndef WOLFSSL_NO_ASN_STRICT
+            /* Verify RFC 5280 Sec 4.2.1.6 rule:
+                "The name MUST NOT be a relative URI" */
+
+            {
+                int i;
+
+                /* skip past scheme (i.e http,ftp,...) finding first ':' char */
+                for (i = 0; i < strLen; i++) {
+                    if (input[idx + i] == ':') {
+                        break;
+                    }
+                    if (input[idx + i] == '/') {
+                        i = strLen; /* error, found relative path since '/' was
+                                     * encountered before ':'. Returning error
+                                     * value in next if statement. */
+                    }
+                }
+
+                /* test if no ':' char was found and test that the next two
+                 * chars are // to match the pattern "://" */
+                if (i >= strLen - 2 || (input[idx + i + 1] != '/' ||
+                                        input[idx + i + 2] != '/')) {
+                    WOLFSSL_MSG("\tAlt Name must be absolute URI");
+                    return ASN_ALT_NAME_E;
+                }
+            }
+        #endif
+
+            uriEntry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), cert->heap,
+                                        DYNAMIC_TYPE_ALTNAME);
+            if (uriEntry == NULL) {
+                WOLFSSL_MSG("\tOut of Memory");
+                return MEMORY_E;
+            }
+
+            uriEntry->type = ASN_URI_TYPE;
+            uriEntry->name = (char*)XMALLOC(strLen + 1, cert->heap,
+                                         DYNAMIC_TYPE_ALTNAME);
+            if (uriEntry->name == NULL) {
+                WOLFSSL_MSG("\tOut of Memory");
+                XFREE(uriEntry, cert->heap, DYNAMIC_TYPE_ALTNAME);
+                return MEMORY_E;
+            }
+            uriEntry->len = strLen;
+            XMEMCPY(uriEntry->name, &input[idx], strLen);
+            uriEntry->name[strLen] = '\0';
+
+            uriEntry->next = cert->altNames;
+            cert->altNames = uriEntry;
 
             length -= strLen;
@@ -5201,5 +6751,5 @@
 }
 
-static int DecodeBasicCaConstraint(byte* input, int sz, DecodedCert* cert)
+static int DecodeBasicCaConstraint(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5248,5 +6798,5 @@
     /* From RFC3280 SS4.2.1.7, GeneralName */
 
-static int DecodeCrlDist(byte* input, int sz, DecodedCert* cert)
+static int DecodeCrlDist(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5329,5 +6879,5 @@
 
 
-static int DecodeAuthInfo(byte* input, int sz, DecodedCert* cert)
+static int DecodeAuthInfo(const byte* input, int sz, DecodedCert* cert)
 /*
  *  Read the first of the Authority Information Access records. If there are
@@ -5375,5 +6925,5 @@
 
 
-static int DecodeAuthKeyId(byte* input, int sz, DecodedCert* cert)
+static int DecodeAuthKeyId(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5397,5 +6947,5 @@
     }
 
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     cert->extAuthKeyIdSrc = &input[idx];
     cert->extAuthKeyIdSz = length;
@@ -5405,11 +6955,6 @@
         XMEMCPY(cert->extAuthKeyId, input + idx, length);
     }
-    else {
-    #ifdef NO_SHA
-        ret = wc_Sha256Hash(input + idx, length, cert->extAuthKeyId);
-    #else
-        ret = wc_ShaHash(input + idx, length, cert->extAuthKeyId);
-    #endif
-    }
+    else
+        ret = CalcHashId(input + idx, length, cert->extAuthKeyId);
 
     return ret;
@@ -5417,5 +6962,5 @@
 
 
-static int DecodeSubjKeyId(byte* input, int sz, DecodedCert* cert)
+static int DecodeSubjKeyId(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5431,19 +6976,14 @@
         return ret;
 
-    #ifdef OPENSSL_EXTRA
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
         cert->extSubjKeyIdSrc = &input[idx];
         cert->extSubjKeyIdSz = length;
     #endif /* OPENSSL_EXTRA */
 
-    if (length == SIGNER_DIGEST_SIZE) {
+    if (length == KEYID_SIZE) {
         XMEMCPY(cert->extSubjKeyId, input + idx, length);
     }
-    else {
-    #ifdef NO_SHA
-        ret = wc_Sha256Hash(input + idx, length, cert->extSubjKeyId);
-    #else
-        ret = wc_ShaHash(input + idx, length, cert->extSubjKeyId);
-    #endif
-    }
+    else
+        ret = CalcHashId(input + idx, length, cert->extSubjKeyId);
 
     return ret;
@@ -5451,5 +6991,5 @@
 
 
-static int DecodeKeyUsage(byte* input, int sz, DecodedCert* cert)
+static int DecodeKeyUsage(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5470,10 +7010,10 @@
 
 
-static int DecodeExtKeyUsage(byte* input, int sz, DecodedCert* cert)
+static int DecodeExtKeyUsage(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0, oid;
-    int length;
-
-    WOLFSSL_ENTER("DecodeExtKeyUsage");
+    int length, ret;
+
+    WOLFSSL_MSG("DecodeExtKeyUsage");
 
     if (GetSequence(input, &idx, &length, sz) < 0) {
@@ -5482,5 +7022,5 @@
     }
 
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     cert->extExtKeyUsageSrc = input + idx;
     cert->extExtKeyUsageSz = length;
@@ -5488,6 +7028,9 @@
 
     while (idx < (word32)sz) {
-        if (GetObjectId(input, &idx, &oid, oidCertKeyUseType, sz) < 0)
-            return ASN_PARSE_E;
+        ret = GetObjectId(input, &idx, &oid, oidCertKeyUseType, sz);
+        if (ret == ASN_UNKNOWN_OID_E)
+            continue;
+        else if (ret < 0)
+            return ret;
 
         switch (oid) {
@@ -5515,5 +7058,5 @@
         }
 
-    #ifdef OPENSSL_EXTRA
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
         cert->extExtKeyUsageCount++;
     #endif
@@ -5526,5 +7069,6 @@
 #ifndef IGNORE_NAME_CONSTRAINTS
 #define ASN_TYPE_MASK 0xF
-static int DecodeSubtree(byte* input, int sz, Base_entry** head, void* heap)
+static int DecodeSubtree(const byte* input, int sz,
+                         Base_entry** head, void* heap)
 {
     word32 idx = 0;
@@ -5593,5 +7137,5 @@
 
 
-static int DecodeNameConstraints(byte* input, int sz, DecodedCert* cert)
+static int DecodeNameConstraints(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5632,6 +7176,5 @@
 #endif /* IGNORE_NAME_CONSTRAINTS */
 
-
-#if defined(WOLFSSL_CERT_EXT) && !defined(WOLFSSL_SEP)
+#if (defined(WOLFSSL_CERT_EXT) && !defined(WOLFSSL_SEP)) || defined(OPENSSL_EXTRA)
 
 static int Word32ToString(char* d, word32 number)
@@ -5669,5 +7212,5 @@
 /* Decode ITU-T X.690 OID format to a string representation
  * return string length */
-static int DecodePolicyOID(char *out, word32 outSz, byte *in, word32 inSz)
+int DecodePolicyOID(char *out, word32 outSz, const byte *in, word32 inSz)
 {
     word32 val, idx = 0, nb_bytes;
@@ -5716,5 +7259,5 @@
     }
 
-    return 0;
+    return (int)w_bytes;
 }
 #endif /* WOLFSSL_CERT_EXT && !WOLFSSL_SEP */
@@ -5722,5 +7265,5 @@
 #if defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)
     /* Reference: https://tools.ietf.org/html/rfc5280#section-4.2.1.4 */
-    static int DecodeCertPolicy(byte* input, int sz, DecodedCert* cert)
+    static int DecodeCertPolicy(const byte* input, int sz, DecodedCert* cert)
     {
         word32 idx = 0;
@@ -5778,6 +7321,6 @@
         #elif defined(WOLFSSL_CERT_EXT)
                 /* decode cert policy */
-                if (DecodePolicyOID(cert->extCertPolicies[cert->extCertPoliciesNb],
-                                    MAX_CERTPOL_SZ, input + idx, length) != 0) {
+                if (DecodePolicyOID(cert->extCertPolicies[cert->extCertPoliciesNb], MAX_CERTPOL_SZ,
+                                    input + idx, length) <= 0) {
                     WOLFSSL_MSG("\tCouldn't decode CertPolicy");
                     return ASN_PARSE_E;
@@ -5817,4 +7360,18 @@
 #endif /* WOLFSSL_SEP */
 
+/* Macro to check if bit is set, if not sets and return success.
+    Otherwise returns failure */
+/* Macro required here because bit-field operation */
+#ifndef WOLFSSL_NO_ASN_STRICT
+    #define VERIFY_AND_SET_OID(bit) \
+        if (bit == 0) \
+            bit = 1; \
+        else \
+            return ASN_OBJECT_ID_E;
+#else
+    /* With no strict defined, the verify is skipped */
+#define VERIFY_AND_SET_OID(bit) bit = 1;
+#endif
+
 static int DecodeCertExtensions(DecodedCert* cert)
 /*
@@ -5823,8 +7380,8 @@
  */
 {
-    int ret;
+    int ret = 0;
     word32 idx = 0;
     int sz = cert->extensionsSz;
-    byte* input = cert->extensions;
+    const byte* input = cert->extensions;
     int length;
     word32 oid;
@@ -5885,6 +7442,6 @@
         switch (oid) {
             case BASIC_CA_OID:
-                #ifdef OPENSSL_EXTRA
-                    cert->extBasicConstSet = 1;
+                VERIFY_AND_SET_OID(cert->extBasicConstSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extBasicConstCrit = critical;
                 #endif
@@ -5894,6 +7451,6 @@
 
             case CRL_DIST_OID:
-                #ifdef OPENSSL_EXTRA
-                    cert->extCRLdistSet  = 1;
+                VERIFY_AND_SET_OID(cert->extCRLdistSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extCRLdistCrit = critical;
                 #endif
@@ -5903,6 +7460,6 @@
 
             case AUTH_INFO_OID:
-                #ifdef OPENSSL_EXTRA
-                    cert->extAuthInfoSet  = 1;
+                VERIFY_AND_SET_OID(cert->extAuthInfoSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extAuthInfoCrit = critical;
                 #endif
@@ -5912,16 +7469,28 @@
 
             case ALT_NAMES_OID:
-                #ifdef OPENSSL_EXTRA
-                    cert->extSubjAltNameSet = 1;
+                VERIFY_AND_SET_OID(cert->extSubjAltNameSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extSubjAltNameCrit = critical;
                 #endif
-                if (DecodeAltNames(&input[idx], length, cert) < 0)
-                    return ASN_PARSE_E;
+                ret = DecodeAltNames(&input[idx], length, cert);
+                if (ret < 0)
+                    return ret;
                 break;
 
             case AUTH_KEY_OID:
-                cert->extAuthKeyIdSet = 1;
-                #ifdef OPENSSL_EXTRA
+                VERIFY_AND_SET_OID(cert->extAuthKeyIdSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extAuthKeyIdCrit = critical;
+                #endif
+                #ifndef WOLFSSL_ALLOW_CRIT_SKID
+                    /* This check is added due to RFC 5280 section 4.2.1.1
+                     * stating that conforming CA's must mark this extension
+                     * as non-critical. When parsing extensions check that
+                     * certificate was made in compliance with this. */
+                    if (critical) {
+                        WOLFSSL_MSG("Critical Auth Key ID is not allowed");
+                        WOLFSSL_MSG("Use macro WOLFSSL_ALLOW_CRIT_SKID if wanted");
+                        return ASN_CRIT_EXT_E;
+                    }
                 #endif
                 if (DecodeAuthKeyId(&input[idx], length, cert) < 0)
@@ -5930,6 +7499,6 @@
 
             case SUBJ_KEY_OID:
-                cert->extSubjKeyIdSet = 1;
-                #ifdef OPENSSL_EXTRA
+                VERIFY_AND_SET_OID(cert->extSubjKeyIdSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extSubjKeyIdCrit = critical;
                 #endif
@@ -5952,6 +7521,7 @@
             case CERT_POLICY_OID:
                 #ifdef WOLFSSL_SEP
-                    #ifdef OPENSSL_EXTRA
-                        cert->extCertPolicySet = 1;
+                    VERIFY_AND_SET_OID(cert->extCertPolicySet);
+                    #if defined(OPENSSL_EXTRA) || \
+                        defined(OPENSSL_EXTRA_X509_SMALL)
                         cert->extCertPolicyCrit = critical;
                     #endif
@@ -5967,6 +7537,6 @@
 
             case KEY_USAGE_OID:
-                cert->extKeyUsageSet = 1;
-                #ifdef OPENSSL_EXTRA
+                VERIFY_AND_SET_OID(cert->extKeyUsageSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extKeyUsageCrit = critical;
                 #endif
@@ -5976,6 +7546,6 @@
 
             case EXT_KEY_USAGE_OID:
-                cert->extExtKeyUsageSet = 1;
-                #ifdef OPENSSL_EXTRA
+                VERIFY_AND_SET_OID(cert->extExtKeyUsageSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extExtKeyUsageCrit = critical;
                 #endif
@@ -5986,6 +7556,15 @@
             #ifndef IGNORE_NAME_CONSTRAINTS
             case NAME_CONS_OID:
-                cert->extNameConstraintSet = 1;
-                #ifdef OPENSSL_EXTRA
+            #ifndef WOLFSSL_NO_ASN_STRICT
+                /* Verify RFC 5280 Sec 4.2.1.10 rule:
+                    "The name constraints extension,
+                    which MUST be used only in a CA certificate" */
+                if (!cert->isCA) {
+                    WOLFSSL_MSG("Name constraints allowed only for CA certs");
+                    return ASN_NAME_INVALID_E;
+                }
+            #endif
+                VERIFY_AND_SET_OID(cert->extNameConstraintSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extNameConstraintCrit = critical;
                 #endif
@@ -5996,8 +7575,10 @@
 
             case INHIBIT_ANY_OID:
+                VERIFY_AND_SET_OID(cert->inhibitAnyOidSet);
                 WOLFSSL_MSG("Inhibit anyPolicy extension not supported yet.");
                 break;
 
             default:
+            #ifndef WOLFSSL_NO_ASN_STRICT
                 /* While it is a failure to not support critical extensions,
                  * still parse the certificate ignoring the unsupported
@@ -6006,4 +7587,5 @@
                 if (critical)
                     criticalFail = 1;
+            #endif
                 break;
         }
@@ -6048,4 +7630,5 @@
 }
 
+
 /* from SSL proper, for locking can't do find here anymore */
 #ifdef __cplusplus
@@ -6101,4 +7684,270 @@
 #endif
 
+#ifdef WOLFSSL_SMALL_CERT_VERIFY
+/* Only quick step through the certificate to find fields that are then used
+ * in certificate signature verification.
+ * Must use the signature OID from the signed part of the certificate.
+ *
+ * This is only for minimizing dynamic memory usage during TLS certificate
+ * chain processing.
+ * Doesn't support:
+ *   OCSP Only: alt lookup using subject and pub key w/o sig check
+ */
+int CheckCertSignature(const byte* cert, word32 certSz, void* heap, void* cm)
+{
+#ifndef WOLFSSL_SMALL_STACK
+    SignatureCtx  sigCtx[1];
+#else
+    SignatureCtx* sigCtx;
+#endif
+    byte          hash[KEYID_SIZE];
+    Signer*       ca = NULL;
+    word32        idx = 0;
+    int           len;
+    word32        tbsCertIdx;
+    word32        sigIndex;
+    word32        signatureOID;
+    word32        oid;
+    word32        issuerIdx;
+    word32        issuerSz;
+#ifndef NO_SKID
+    int           extLen;
+    word32        extIdx;
+    word32        extEndIdx;
+    int           extAuthKeyIdSet = 0;
+#endif
+    int    ret = 0;
+
+    if (cert == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    sigCtx = XMALLOC(sizeof(*sigCtx), heap, DYNAMIC_TYPE_SIGNATURE);
+    if (sigCtx == NULL)
+        return MEMORY_E;
+#endif
+    InitSignatureCtx(sigCtx, heap, INVALID_DEVID);
+
+    /* Certificate SEQUENCE */
+    if (GetSequence(cert, &idx, &len, certSz) < 0)
+        ret = ASN_PARSE_E;
+    if (ret == 0) {
+        tbsCertIdx = idx;
+
+        /* TBSCertificate SEQUENCE */
+        if (GetSequence(cert, &idx, &len, certSz) < 0)
+            ret = ASN_PARSE_E;
+            }
+    if (ret == 0) {
+        sigIndex = len + idx;
+
+        if ((idx + 1) > certSz)
+            ret = BUFFER_E;
+    }
+    if (ret == 0) {
+        /* version - optional */
+        if (cert[idx] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) {
+            idx++;
+            if (GetLength(cert, &idx, &len, certSz) < 0)
+                ret = ASN_PARSE_E;
+            idx += len;
+        }
+            }
+
+    if (ret == 0) {
+        /* serialNumber */
+        if (GetASNHeader(cert, ASN_INTEGER, &idx, &len, certSz) < 0)
+            ret = ASN_PARSE_E;
+        }
+    if (ret == 0) {
+        idx += len;
+
+        /* signature */
+        if (GetAlgoId(cert, &idx, &signatureOID, oidSigType, certSz) < 0)
+            ret = ASN_PARSE_E;
+    }
+
+    if (ret == 0) {
+        issuerIdx = idx;
+        /* issuer */
+        if (GetSequence(cert, &idx, &len, certSz) < 0)
+            ret = ASN_PARSE_E;
+    }
+    if (ret == 0) {
+        issuerSz = len + idx - issuerIdx;
+    }
+#ifndef NO_SKID
+    if (ret == 0) {
+        idx += len;
+
+        /* validity */
+        if (GetSequence(cert, &idx, &len, certSz) < 0)
+            ret = ASN_PARSE_E;
+    }
+    if (ret == 0) {
+        idx += len;
+
+        /* subject */
+        if (GetSequence(cert, &idx, &len, certSz) < 0)
+            ret = ASN_PARSE_E;
+    }
+    if (ret == 0) {
+        idx += len;
+
+        /* subjectPublicKeyInfo */
+        if (GetSequence(cert, &idx, &len, certSz) < 0)
+            ret = ASN_PARSE_E;
+    }
+    if (ret == 0) {
+        idx += len;
+
+        if ((idx + 1) > certSz)
+            ret = BUFFER_E;
+    }
+    if (ret == 0) {
+        /* issuerUniqueID - optional */
+        if (cert[idx] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) {
+            idx++;
+            if (GetLength(cert, &idx, &len, certSz) < 0)
+                ret = ASN_PARSE_E;
+            idx += len;
+        }
+    }
+    if (ret == 0) {
+        if ((idx + 1) > certSz)
+            ret = BUFFER_E;
+    }
+    if (ret == 0) {
+        /* subjectUniqueID - optional */
+        if (cert[idx] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 2)) {
+            idx++;
+            if (GetLength(cert, &idx, &len, certSz) < 0)
+                ret = ASN_PARSE_E;
+            idx += len;
+        }
+    }
+
+    if (ret == 0) {
+        if ((idx + 1) > certSz)
+            ret = BUFFER_E;
+    }
+    /* extensions - optional */
+    if (ret == 0 && cert[idx] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 3)) {
+        idx++;
+        if (GetLength(cert, &idx, &extLen, certSz) < 0)
+            ret = ASN_PARSE_E;
+        if (ret == 0) {
+            if (GetSequence(cert, &idx, &extLen, certSz) < 0)
+                ret = ASN_PARSE_E;
+        }
+        if (ret == 0) {
+            extEndIdx = idx + extLen;
+
+            /* Check each extension for the ones we want. */
+            while (ret == 0 && idx < extEndIdx) {
+                if (GetSequence(cert, &idx, &len, certSz) < 0)
+                    ret = ASN_PARSE_E;
+                if (ret == 0) {
+                    extIdx = idx;
+                    if (GetObjectId(cert, &extIdx, &oid, oidCertExtType,
+                                                                  certSz) < 0) {
+                        ret = ASN_PARSE_E;
+                    }
+                }
+                if (ret == 0) {
+                    if (cert[extIdx] == ASN_BOOLEAN) {
+                        if (GetBoolean(cert, &extIdx, certSz) < 0)
+                            ret = ASN_PARSE_E;
+                    }
+                }
+                if (ret == 0) {
+                    if (GetOctetString(cert, &extIdx, &extLen, certSz) < 0)
+                        ret = ASN_PARSE_E;
+                }
+
+                if (ret == 0) {
+                    switch (oid) {
+                    case AUTH_KEY_OID:
+                        extAuthKeyIdSet = 1;
+                        if (GetSequence(cert, &extIdx, &extLen, certSz) < 0)
+                            ret = ASN_PARSE_E;
+
+                        if (ret == 0 &&
+                                 cert[extIdx++] == (ASN_CONTEXT_SPECIFIC | 0)) {
+                            if (GetLength(cert, &extIdx, &extLen, certSz) <= 0)
+                                ret = ASN_PARSE_E;
+                            if (ret == 0) {
+                                if (extLen == KEYID_SIZE)
+                                    XMEMCPY(hash, cert + extIdx, extLen);
+                                else {
+                                    ret = CalcHashId(cert + extIdx, extLen,
+                                                                          hash);
+                                }
+                            }
+                        }
+                        break;
+
+                    default:
+                        break;
+                    }
+                }
+                idx += len;
+            }
+        }
+    }
+
+    if (ret == 0) {
+        if (extAuthKeyIdSet)
+            ca = GetCA(cm, hash);
+        if (ca == NULL) {
+            ret = CalcHashId(cert + issuerIdx, issuerSz, hash);
+            if (ret == 0)
+                ca = GetCAByName(cm, hash);
+        }
+    }
+#else
+    if (ret == 0) {
+        ret = CalcHashId(cert + issuerIdx, issuerSz, hash);
+        if (ret == 0)
+            ca = GetCA(cm, hash);
+    }
+#endif /* !NO_SKID */
+    if (ca == NULL)
+        ret = ASN_NO_SIGNER_E;
+
+    if (ret == 0) {
+        idx = sigIndex;
+        /* signatureAlgorithm */
+        if (GetAlgoId(cert, &idx, &oid, oidSigType, certSz) < 0)
+            ret = ASN_PARSE_E;
+    }
+    if (ret == 0) {
+        if (oid != signatureOID)
+            ret = ASN_SIG_OID_E;
+    }
+    if (ret == 0) {
+        /* signatureValue */
+        if (CheckBitString(cert, &idx, &len, certSz, 1, NULL) < 0)
+            ret = ASN_PARSE_E;
+    }
+
+    if (ret == 0) {
+        ret = ConfirmSignature(sigCtx, cert + tbsCertIdx, sigIndex - tbsCertIdx,
+                               ca->publicKey, ca->pubKeySize, ca->keyOID,
+                               cert + idx, len, signatureOID);
+        if (ret != WC_PENDING_E) {
+            WOLFSSL_MSG("Confirm signature failed");
+        }
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    if (sigCtx != NULL)
+        XFREE(sigCtx, heap, DYNAMIC_TYPE_SIGNATURE);
+#endif
+    return ret;
+}
+#endif /* WOLFSSL_SMALL_CERT_VERIFY */
+
 int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm)
 {
@@ -6107,4 +7956,5 @@
     int    criticalExt = 0;
     word32 confirmOID;
+    int    selfSigned = 0;
 
     if (cert == NULL) {
@@ -6159,11 +8009,6 @@
         if (cert->extSubjKeyIdSet == 0 && cert->publicKey != NULL &&
                                                         cert->pubKeySize > 0) {
-        #ifdef NO_SHA
-            ret = wc_Sha256Hash(cert->publicKey, cert->pubKeySize,
+            ret = CalcHashId(cert->publicKey, cert->pubKeySize,
                                                             cert->extSubjKeyId);
-        #else
-            ret = wc_ShaHash(cert->publicKey, cert->pubKeySize,
-                                                            cert->extSubjKeyId);
-        #endif /* NO_SHA */
             if (ret != 0)
                 return ret;
@@ -6197,16 +8042,23 @@
     #else
             cert->ca = GetCA(cm, cert->issuerHash);
+            if (XMEMCMP(cert->issuerHash, cert->subjectHash, KEYID_SIZE) == 0)
+                selfSigned = 1;
     #endif /* !NO_SKID */
 
             WOLFSSL_MSG("About to verify certificate signature");
             if (cert->ca) {
-                if (cert->isCA) {
-                    if (cert->ca->pathLengthSet) {
+                if (cert->isCA && cert->ca->pathLengthSet) {
+                    if (selfSigned) {
+                        if (cert->ca->pathLength != 0) {
+                           WOLFSSL_MSG("Root CA with path length > 0");
+                           return ASN_PATHLEN_INV_E;
+                        }
+                    }
+                    else {
                         if (cert->ca->pathLength == 0) {
                             WOLFSSL_MSG("CA with path length 0 signing a CA");
                             return ASN_PATHLEN_INV_E;
                         }
-                        if (cert->pathLengthSet &&
-                            cert->pathLength >= cert->ca->pathLength) {
+                        else if (cert->pathLength >= cert->ca->pathLength) {
 
                             WOLFSSL_MSG("CA signing CA with longer path length");
@@ -6218,11 +8070,6 @@
         #ifdef HAVE_OCSP
                 /* Need the CA's public key hash for OCSP */
-            #ifdef NO_SHA
-                ret = wc_Sha256Hash(cert->ca->publicKey, cert->ca->pubKeySize,
+            ret = CalcHashId(cert->ca->publicKey, cert->ca->pubKeySize,
                                                            cert->issuerKeyHash);
-            #else
-                ret = wc_ShaHash(cert->ca->publicKey, cert->ca->pubKeySize,
-                                                           cert->issuerKeyHash);
-            #endif /* NO_SHA */
                 if (ret != 0)
                     return ret;
@@ -6247,5 +8094,8 @@
                     return ret;
                 }
+            }
             #ifndef IGNORE_NAME_CONSTRAINTS
+            if (verify == VERIFY || verify == VERIFY_OCSP ||
+                                                        verify == VERIFY_NAME) {
                 /* check that this cert's name is permitted by the signer's
                  * name constraints */
@@ -6254,6 +8104,6 @@
                     return ASN_NAME_INVALID_E;
                 }
-            #endif /* IGNORE_NAME_CONSTRAINTS */
-            }
+            }
+        #endif /* IGNORE_NAME_CONSTRAINTS */
         }
         else {
@@ -6294,4 +8144,7 @@
         signer->pathLengthSet = 0;
         signer->pathLength = 0;
+    #ifdef WOLFSSL_SIGNER_DER_CERT
+        signer->derCert    = NULL;
+    #endif
         signer->next       = NULL;
     }
@@ -6306,5 +8159,5 @@
 {
     XFREE(signer->name, heap, DYNAMIC_TYPE_SUBJECT_CN);
-    XFREE(signer->publicKey, heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    XFREE((void*)signer->publicKey, heap, DYNAMIC_TYPE_PUBLIC_KEY);
 #ifndef IGNORE_NAME_CONSTRAINTS
     if (signer->permittedNames)
@@ -6312,4 +8165,7 @@
     if (signer->excludedNames)
         FreeNameSubtrees(signer->excludedNames, heap);
+#endif
+#ifdef WOLFSSL_SIGNER_DER_CERT
+    FreeDer(&signer->derCert);
 #endif
     XFREE(signer, heap, DYNAMIC_TYPE_SIGNER);
@@ -6476,31 +8332,414 @@
 
 
-
-const char* BEGIN_CERT         = "-----BEGIN CERTIFICATE-----";
-const char* END_CERT           = "-----END CERTIFICATE-----";
-const char* BEGIN_CERT_REQ     = "-----BEGIN CERTIFICATE REQUEST-----";
-const char* END_CERT_REQ       = "-----END CERTIFICATE REQUEST-----";
-const char* BEGIN_DH_PARAM     = "-----BEGIN DH PARAMETERS-----";
-const char* END_DH_PARAM       = "-----END DH PARAMETERS-----";
-const char* BEGIN_DSA_PARAM    = "-----BEGIN DSA PARAMETERS-----";
-const char* END_DSA_PARAM      = "-----END DSA PARAMETERS-----";
-const char* BEGIN_X509_CRL     = "-----BEGIN X509 CRL-----";
-const char* END_X509_CRL       = "-----END X509 CRL-----";
-const char* BEGIN_RSA_PRIV     = "-----BEGIN RSA PRIVATE KEY-----";
-const char* END_RSA_PRIV       = "-----END RSA PRIVATE KEY-----";
-const char* BEGIN_PRIV_KEY     = "-----BEGIN PRIVATE KEY-----";
-const char* END_PRIV_KEY       = "-----END PRIVATE KEY-----";
-const char* BEGIN_ENC_PRIV_KEY = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
-const char* END_ENC_PRIV_KEY   = "-----END ENCRYPTED PRIVATE KEY-----";
-const char* BEGIN_EC_PRIV      = "-----BEGIN EC PRIVATE KEY-----";
-const char* END_EC_PRIV        = "-----END EC PRIVATE KEY-----";
-const char* BEGIN_DSA_PRIV     = "-----BEGIN DSA PRIVATE KEY-----";
-const char* END_DSA_PRIV       = "-----END DSA PRIVATE KEY-----";
-const char* BEGIN_PUB_KEY      = "-----BEGIN PUBLIC KEY-----";
-const char* END_PUB_KEY        = "-----END PUBLIC KEY-----";
-const char* BEGIN_EDDSA_PRIV   = "-----BEGIN EDDSA PRIVATE KEY-----";
-const char* END_EDDSA_PRIV     = "-----END EDDSA PRIVATE KEY-----";
-
-#if defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN) || defined(OPENSSL_EXTRA)
+int AllocDer(DerBuffer** pDer, word32 length, int type, void* heap)
+{
+    int ret = BAD_FUNC_ARG;
+    if (pDer) {
+        int dynType = 0;
+        DerBuffer* der;
+
+        /* Determine dynamic type */
+        switch (type) {
+            case CA_TYPE:   dynType = DYNAMIC_TYPE_CA;   break;
+            case CERT_TYPE: dynType = DYNAMIC_TYPE_CERT; break;
+            case CRL_TYPE:  dynType = DYNAMIC_TYPE_CRL;  break;
+            case DSA_TYPE:  dynType = DYNAMIC_TYPE_DSA;  break;
+            case ECC_TYPE:  dynType = DYNAMIC_TYPE_ECC;  break;
+            case RSA_TYPE:  dynType = DYNAMIC_TYPE_RSA;  break;
+            default:        dynType = DYNAMIC_TYPE_KEY;  break;
+        }
+
+        /* Setup new buffer */
+        *pDer = (DerBuffer*)XMALLOC(sizeof(DerBuffer) + length, heap, dynType);
+        if (*pDer == NULL) {
+            return MEMORY_E;
+        }
+        XMEMSET(*pDer, 0, sizeof(DerBuffer) + length);
+
+        der = *pDer;
+        der->type = type;
+        der->dynType = dynType; /* Cache this for FreeDer */
+        der->heap = heap;
+        der->buffer = (byte*)der + sizeof(DerBuffer);
+        der->length = length;
+        ret = 0; /* Success */
+    }
+    return ret;
+}
+
+void FreeDer(DerBuffer** pDer)
+{
+    if (pDer && *pDer)
+    {
+        DerBuffer* der = (DerBuffer*)*pDer;
+
+        /* ForceZero private keys */
+        if (der->type == PRIVATEKEY_TYPE) {
+            ForceZero(der->buffer, der->length);
+}
+        der->buffer = NULL;
+        der->length = 0;
+        XFREE(der, der->heap, der->dynType);
+
+        *pDer = NULL;
+    }
+}
+
+int wc_AllocDer(DerBuffer** pDer, word32 length, int type, void* heap)
+{
+    return AllocDer(pDer, length, type, heap);
+}
+void wc_FreeDer(DerBuffer** pDer)
+{
+    FreeDer(pDer);
+}
+
+
+#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)
+
+/* Max X509 header length indicates the max length + 2 ('\n', '\0') */
+#define MAX_X509_HEADER_SZ  (37 + 2)
+
+const char* const BEGIN_CERT           = "-----BEGIN CERTIFICATE-----";
+const char* const END_CERT             = "-----END CERTIFICATE-----";
+#ifdef WOLFSSL_CERT_REQ
+    const char* const BEGIN_CERT_REQ   = "-----BEGIN CERTIFICATE REQUEST-----";
+    const char* const END_CERT_REQ     = "-----END CERTIFICATE REQUEST-----";
+#endif
+#ifndef NO_DH
+    const char* const BEGIN_DH_PARAM   = "-----BEGIN DH PARAMETERS-----";
+    const char* const END_DH_PARAM     = "-----END DH PARAMETERS-----";
+#endif
+#ifndef NO_DSA
+    const char* const BEGIN_DSA_PARAM  = "-----BEGIN DSA PARAMETERS-----";
+    const char* const END_DSA_PARAM    = "-----END DSA PARAMETERS-----";
+#endif
+const char* const BEGIN_X509_CRL       = "-----BEGIN X509 CRL-----";
+const char* const END_X509_CRL         = "-----END X509 CRL-----";
+const char* const BEGIN_RSA_PRIV       = "-----BEGIN RSA PRIVATE KEY-----";
+const char* const END_RSA_PRIV         = "-----END RSA PRIVATE KEY-----";
+const char* const BEGIN_PRIV_KEY       = "-----BEGIN PRIVATE KEY-----";
+const char* const END_PRIV_KEY         = "-----END PRIVATE KEY-----";
+const char* const BEGIN_ENC_PRIV_KEY   = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
+const char* const END_ENC_PRIV_KEY     = "-----END ENCRYPTED PRIVATE KEY-----";
+#ifdef HAVE_ECC
+    const char* const BEGIN_EC_PRIV    = "-----BEGIN EC PRIVATE KEY-----";
+    const char* const END_EC_PRIV      = "-----END EC PRIVATE KEY-----";
+#endif
+#if defined(HAVE_ECC) || defined(HAVE_ED25519) || !defined(NO_DSA)
+    const char* const BEGIN_DSA_PRIV   = "-----BEGIN DSA PRIVATE KEY-----";
+    const char* const END_DSA_PRIV     = "-----END DSA PRIVATE KEY-----";
+#endif
+const char* const BEGIN_PUB_KEY        = "-----BEGIN PUBLIC KEY-----";
+const char* const END_PUB_KEY          = "-----END PUBLIC KEY-----";
+#ifdef HAVE_ED25519
+    const char* const BEGIN_EDDSA_PRIV = "-----BEGIN EDDSA PRIVATE KEY-----";
+    const char* const END_EDDSA_PRIV   = "-----END EDDSA PRIVATE KEY-----";
+#endif
+#ifdef HAVE_CRL
+    const char *const BEGIN_CRL = "-----BEGIN X509 CRL-----";
+    const char* const END_CRL   = "-----END X509 CRL-----";
+#endif
+
+
+static WC_INLINE char* SkipEndOfLineChars(char* line, const char* endOfLine)
+{
+    /* eat end of line characters */
+    while (line < endOfLine &&
+              (line[0] == '\r' || line[0] == '\n')) {
+        line++;
+    }
+    return line;
+    }
+
+int wc_PemGetHeaderFooter(int type, const char** header, const char** footer)
+{
+    int ret = BAD_FUNC_ARG;
+
+    switch (type) {
+        case CA_TYPE:       /* same as below */
+        case TRUSTED_PEER_TYPE:
+        case CERT_TYPE:
+            if (header) *header = BEGIN_CERT;
+            if (footer) *footer = END_CERT;
+            ret = 0;
+            break;
+
+        case CRL_TYPE:
+            if (header) *header = BEGIN_X509_CRL;
+            if (footer) *footer = END_X509_CRL;
+            ret = 0;
+            break;
+    #ifndef NO_DH
+        case DH_PARAM_TYPE:
+            if (header) *header = BEGIN_DH_PARAM;
+            if (footer) *footer = END_DH_PARAM;
+            ret = 0;
+            break;
+    #endif
+    #ifndef NO_DSA
+        case DSA_PARAM_TYPE:
+            if (header) *header = BEGIN_DSA_PARAM;
+            if (footer) *footer = END_DSA_PARAM;
+            ret = 0;
+            break;
+    #endif
+    #ifdef WOLFSSL_CERT_REQ
+        case CERTREQ_TYPE:
+            if (header) *header = BEGIN_CERT_REQ;
+            if (footer) *footer = END_CERT_REQ;
+            ret = 0;
+            break;
+    #endif
+    #ifndef NO_DSA
+        case DSA_TYPE:
+        case DSA_PRIVATEKEY_TYPE:
+            if (header) *header = BEGIN_DSA_PRIV;
+            if (footer) *footer = END_DSA_PRIV;
+            ret = 0;
+            break;
+    #endif
+    #ifdef HAVE_ECC
+        case ECC_TYPE:
+        case ECC_PRIVATEKEY_TYPE:
+            if (header) *header = BEGIN_EC_PRIV;
+            if (footer) *footer = END_EC_PRIV;
+            ret = 0;
+            break;
+    #endif
+        case RSA_TYPE:
+        case PRIVATEKEY_TYPE:
+            if (header) *header = BEGIN_RSA_PRIV;
+            if (footer) *footer = END_RSA_PRIV;
+            ret = 0;
+            break;
+    #ifdef HAVE_ED25519
+        case ED25519_TYPE:
+        case EDDSA_PRIVATEKEY_TYPE:
+            if (header) *header = BEGIN_EDDSA_PRIV;
+            if (footer) *footer = END_EDDSA_PRIV;
+            ret = 0;
+            break;
+    #endif
+        case PUBLICKEY_TYPE:
+            if (header) *header = BEGIN_PUB_KEY;
+            if (footer) *footer = END_PUB_KEY;
+            ret = 0;
+            break;
+        case PKCS8_PRIVATEKEY_TYPE:
+            if (header) *header = BEGIN_PRIV_KEY;
+            if (footer) *footer = END_PRIV_KEY;
+            ret = 0;
+            break;
+        case PKCS8_ENC_PRIVATEKEY_TYPE:
+            if (header) *header = BEGIN_ENC_PRIV_KEY;
+            if (footer) *footer = END_ENC_PRIV_KEY;
+            ret = 0;
+            break;
+        default:
+            break;
+    }
+    return ret;
+}
+
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+
+static const char* const kProcTypeHeader = "Proc-Type";
+static const char* const kDecInfoHeader = "DEK-Info";
+
+#ifdef WOLFSSL_PEM_TO_DER
+#ifndef NO_DES3
+    static const char* const kEncTypeDes = "DES-CBC";
+    static const char* const kEncTypeDes3 = "DES-EDE3-CBC";
+#endif
+#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128)
+    static const char* const kEncTypeAesCbc128 = "AES-128-CBC";
+#endif
+#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_192)
+    static const char* const kEncTypeAesCbc192 = "AES-192-CBC";
+#endif
+#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
+    static const char* const kEncTypeAesCbc256 = "AES-256-CBC";
+#endif
+
+int wc_EncryptedInfoGet(EncryptedInfo* info, const char* cipherInfo)
+{
+    int ret = 0;
+
+    if (info == NULL || cipherInfo == NULL)
+        return BAD_FUNC_ARG;
+
+    /* determine cipher information */
+#ifndef NO_DES3
+    if (XSTRNCMP(cipherInfo, kEncTypeDes, XSTRLEN(kEncTypeDes)) == 0) {
+        info->cipherType = WC_CIPHER_DES;
+        info->keySz = DES_KEY_SIZE;
+        if (info->ivSz == 0) info->ivSz  = DES_IV_SIZE;
+    }
+    else if (XSTRNCMP(cipherInfo, kEncTypeDes3, XSTRLEN(kEncTypeDes3)) == 0) {
+        info->cipherType = WC_CIPHER_DES3;
+        info->keySz = DES3_KEY_SIZE;
+        if (info->ivSz == 0) info->ivSz  = DES_IV_SIZE;
+    }
+    else
+#endif /* !NO_DES3 */
+#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128)
+    if (XSTRNCMP(cipherInfo, kEncTypeAesCbc128, XSTRLEN(kEncTypeAesCbc128)) == 0) {
+        info->cipherType = WC_CIPHER_AES_CBC;
+        info->keySz = AES_128_KEY_SIZE;
+        if (info->ivSz == 0) info->ivSz  = AES_IV_SIZE;
+    }
+    else
+#endif
+#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_192)
+    if (XSTRNCMP(cipherInfo, kEncTypeAesCbc192, XSTRLEN(kEncTypeAesCbc192)) == 0) {
+        info->cipherType = WC_CIPHER_AES_CBC;
+        info->keySz = AES_192_KEY_SIZE;
+        if (info->ivSz == 0) info->ivSz  = AES_IV_SIZE;
+    }
+    else
+#endif
+#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
+    if (XSTRNCMP(cipherInfo, kEncTypeAesCbc256, XSTRLEN(kEncTypeAesCbc256)) == 0) {
+        info->cipherType = WC_CIPHER_AES_CBC;
+        info->keySz = AES_256_KEY_SIZE;
+        if (info->ivSz == 0) info->ivSz  = AES_IV_SIZE;
+    }
+    else
+#endif
+    {
+        ret = NOT_COMPILED_IN;
+    }
+    return ret;
+}
+
+int wc_EncryptedInfoParse(EncryptedInfo* info, char** pBuffer, size_t bufSz)
+{
+    int err = 0;
+    char*  bufferStart;
+    char*  bufferEnd;
+    char*  line;
+    word32 lineSz;
+    char*  finish;
+    word32 finishSz;
+    char*  start = NULL;
+    word32 startSz;
+    char*  newline = NULL;
+
+    if (info == NULL || pBuffer == NULL || bufSz == 0)
+        return BAD_FUNC_ARG;
+
+    bufferStart = *pBuffer;
+    bufferEnd = bufferStart + bufSz;
+
+    /* find encrypted info marker */
+    line = XSTRNSTR(bufferStart, kProcTypeHeader,
+                    min((word32)bufSz, PEM_LINE_LEN));
+    if (line != NULL) {
+        if (line >= bufferEnd) {
+            return BUFFER_E;
+        }
+
+        lineSz = (word32)(bufferEnd - line);
+
+        /* find DEC-Info marker */
+        start = XSTRNSTR(line, kDecInfoHeader, min(lineSz, PEM_LINE_LEN));
+
+        if (start == NULL)
+            return BUFFER_E;
+
+        /* skip dec-info and ": " */
+        start += XSTRLEN(kDecInfoHeader);
+        if (start >= bufferEnd)
+            return BUFFER_E;
+
+        if (start[0] == ':') {
+            start++;
+            if (start >= bufferEnd)
+                return BUFFER_E;
+        }
+        if (start[0] == ' ')
+            start++;
+
+        startSz = (word32)(bufferEnd - start);
+        finish = XSTRNSTR(start, ",", min(startSz, PEM_LINE_LEN));
+
+        if ((start != NULL) && (finish != NULL) && (start < finish)) {
+            if (finish >= bufferEnd) {
+                return BUFFER_E;
+            }
+
+            finishSz = (word32)(bufferEnd - finish);
+            newline = XSTRNSTR(finish, "\r", min(finishSz, PEM_LINE_LEN));
+
+            /* get cipher name */
+            if (NAME_SZ < (finish - start)) /* buffer size of info->name */
+                return BUFFER_E;
+            if (XMEMCPY(info->name, start, finish - start) == NULL)
+                return BUFFER_E;
+            info->name[finish - start] = '\0'; /* null term */
+
+            /* populate info */
+            err = wc_EncryptedInfoGet(info, info->name);
+            if (err != 0)
+                return err;
+
+            /* get IV */
+            if (finishSz < info->ivSz + 1)
+                return BUFFER_E;
+
+            if (newline == NULL) {
+                newline = XSTRNSTR(finish, "\n", min(finishSz,
+                                                     PEM_LINE_LEN));
+            }
+            if ((newline != NULL) && (newline > finish)) {
+                info->ivSz = (word32)(newline - (finish + 1));
+                if (XMEMCPY(info->iv, finish + 1, info->ivSz) == NULL)
+                    return BUFFER_E;
+                info->set = 1;
+            }
+            else
+                return BUFFER_E;
+        }
+        else
+            return BUFFER_E;
+
+        /* eat end of line characters */
+        newline = SkipEndOfLineChars(newline, bufferEnd);
+
+        /* return new headerEnd */
+        if (pBuffer)
+            *pBuffer = newline;
+    }
+
+    return err;
+}
+#endif /* WOLFSSL_PEM_TO_DER */
+
+#ifdef WOLFSSL_DER_TO_PEM
+static int wc_EncryptedInfoAppend(char* dest, int destSz, char* cipherInfo)
+{
+    if (cipherInfo != NULL) {
+        int cipherInfoStrLen = (int)XSTRLEN((char*)cipherInfo);
+
+        if (cipherInfoStrLen > HEADER_ENCRYPTED_KEY_SIZE - (9+14+10+3))
+            cipherInfoStrLen = HEADER_ENCRYPTED_KEY_SIZE - (9+14+10+3);
+
+        if (destSz - (int)XSTRLEN(dest) >= cipherInfoStrLen + (9+14+8+2+2+1)) {
+            /* strncat's src length needs to include the NULL */
+            XSTRNCAT(dest, kProcTypeHeader, 10);
+            XSTRNCAT(dest, ": 4,ENCRYPTED\n", 15);
+            XSTRNCAT(dest, kDecInfoHeader, 9);
+            XSTRNCAT(dest, ": ", 3);
+            XSTRNCAT(dest, cipherInfo, destSz - (int)XSTRLEN(dest) - 1);
+            XSTRNCAT(dest, "\n\n", 4);
+        }
+    }
+    return 0;
+}
+#endif /* WOLFSSL_DER_TO_PEM */
+#endif /* WOLFSSL_ENCRYPTED_KEYS */
+
+#ifdef WOLFSSL_DER_TO_PEM
 
 /* Used for compatibility API */
@@ -6516,20 +8755,27 @@
              byte *cipher_info, int type)
 {
+    const char* headerStr = NULL;
+    const char* footerStr = NULL;
 #ifdef WOLFSSL_SMALL_STACK
     char* header = NULL;
     char* footer = NULL;
 #else
-    char header[40 + HEADER_ENCRYPTED_KEY_SIZE];
-    char footer[40];
-#endif
-
-    int headerLen = 40 + HEADER_ENCRYPTED_KEY_SIZE;
-    int footerLen = 40;
+    char header[MAX_X509_HEADER_SZ + HEADER_ENCRYPTED_KEY_SIZE];
+    char footer[MAX_X509_HEADER_SZ];
+#endif
+    int headerLen = MAX_X509_HEADER_SZ + HEADER_ENCRYPTED_KEY_SIZE;
+    int footerLen = MAX_X509_HEADER_SZ;
     int i;
     int err;
     int outLen;   /* return length or error */
 
+    (void)cipher_info;
+
     if (der == output)      /* no in place conversion */
         return BAD_FUNC_ARG;
+
+    err = wc_PemGetHeaderFooter(type, &headerStr, &footerStr);
+    if (err != 0)
+        return err;
 
 #ifdef WOLFSSL_SMALL_STACK
@@ -6544,84 +8790,25 @@
     }
 #endif
-    if (type == CERT_TYPE) {
-        XSTRNCPY(header, BEGIN_CERT, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_CERT, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-    else if (type == PRIVATEKEY_TYPE) {
-        XSTRNCPY(header, BEGIN_RSA_PRIV, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_RSA_PRIV, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-#ifndef NO_DSA
-    else if (type == DSA_PRIVATEKEY_TYPE) {
-        XSTRNCPY(header, BEGIN_DSA_PRIV, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_DSA_PRIV, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-#endif
-#ifdef HAVE_ECC
-    else if (type == ECC_PRIVATEKEY_TYPE) {
-        XSTRNCPY(header, BEGIN_EC_PRIV, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_EC_PRIV, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-#endif
-#ifdef HAVE_ED25519
-    else if (type == EDDSA_PRIVATEKEY_TYPE) {
-        XSTRNCPY(header, BEGIN_EDDSA_PRIV, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_EDDSA_PRIV, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-#endif
-#ifdef WOLFSSL_CERT_REQ
-    else if (type == CERTREQ_TYPE)
-    {
-        XSTRNCPY(header, BEGIN_CERT_REQ, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_CERT_REQ, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-#endif
-#ifdef HAVE_CRL
-    else if (type == CRL_TYPE)
-    {
-        XSTRNCPY(header, BEGIN_X509_CRL, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_X509_CRL, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-#endif
-    else {
-#ifdef WOLFSSL_SMALL_STACK
+
+    /* build header and footer based on type */
+    XSTRNCPY(header, headerStr, headerLen - 1);
+    header[headerLen - 1] = 0;
+    XSTRNCPY(footer, footerStr, footerLen - 1);
+    footer[footerLen - 1] = 0;
+
+    /* add new line to end */
+    XSTRNCAT(header, "\n", 2);
+    XSTRNCAT(footer, "\n", 2);
+
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+    err = wc_EncryptedInfoAppend(header, headerLen, (char*)cipher_info);
+    if (err != 0) {
+    #ifdef WOLFSSL_SMALL_STACK
         XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER);
         XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-        return BAD_FUNC_ARG;
-    }
-
-    /* extra header information for encrypted key */
-    if (cipher_info != NULL) {
-        size_t cipherInfoStrLen = XSTRLEN((char*)cipher_info);
-        if (cipherInfoStrLen > HEADER_ENCRYPTED_KEY_SIZE - (23+10+2))
-            cipherInfoStrLen = HEADER_ENCRYPTED_KEY_SIZE - (23+10+2);
-
-        XSTRNCAT(header, "Proc-Type: 4,ENCRYPTED\n", 23);
-        XSTRNCAT(header, "DEK-Info: ", 10);
-        XSTRNCAT(header, (char*)cipher_info, cipherInfoStrLen);
-        XSTRNCAT(header, "\n\n", 2);
-    }
+    #endif
+        return err;
+    }
+#endif
 
     headerLen = (int)XSTRLEN(header);
@@ -6693,8 +8880,541 @@
 }
 
-#endif /* WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN || OPENSSL_EXTRA */
+#endif /* WOLFSSL_DER_TO_PEM */
+
+#ifdef WOLFSSL_PEM_TO_DER
+
+/* Remove PEM header/footer, convert to ASN1, store any encrypted data
+   info->consumed tracks of PEM bytes consumed in case multiple parts */
+int PemToDer(const unsigned char* buff, long longSz, int type,
+              DerBuffer** pDer, void* heap, EncryptedInfo* info, int* eccKey)
+{
+    const char* header      = NULL;
+    const char* footer      = NULL;
+    char*       headerEnd;
+    char*       footerEnd;
+    char*       consumedEnd;
+    char*       bufferEnd   = (char*)(buff + longSz);
+    long        neededSz;
+    int         ret         = 0;
+    int         sz          = (int)longSz;
+    int         encrypted_key = 0;
+    DerBuffer*  der;
+    word32      algId = 0;
+
+    WOLFSSL_ENTER("PemToDer");
+
+    /* get PEM header and footer based on type */
+    ret = wc_PemGetHeaderFooter(type, &header, &footer);
+    if (ret != 0)
+        return ret;
+
+    /* map header if not found for type */
+    for (;;) {
+        headerEnd = XSTRNSTR((char*)buff, header, sz);
+
+        if (headerEnd || type != PRIVATEKEY_TYPE) {
+            break;
+        } else
+        if (header == BEGIN_RSA_PRIV) {
+            header =  BEGIN_PRIV_KEY;       footer = END_PRIV_KEY;
+        } else
+        if (header == BEGIN_PRIV_KEY) {
+            header =  BEGIN_ENC_PRIV_KEY;   footer = END_ENC_PRIV_KEY;
+        } else
+#ifdef HAVE_ECC
+        if (header == BEGIN_ENC_PRIV_KEY) {
+            header =  BEGIN_EC_PRIV;        footer = END_EC_PRIV;
+        } else
+        if (header == BEGIN_EC_PRIV) {
+            header =  BEGIN_DSA_PRIV;       footer = END_DSA_PRIV;
+        } else
+#endif
+#ifdef HAVE_ED25519
+    #ifdef HAVE_ECC
+        if (header == BEGIN_DSA_PRIV)
+    #else
+        if (header == BEGIN_ENC_PRIV_KEY)
+    #endif
+        {
+            header =  BEGIN_EDDSA_PRIV;     footer = END_EDDSA_PRIV;
+        } else
+#endif
+#ifdef HAVE_CRL
+        if (type == CRL_TYPE) {
+            header =  BEGIN_CRL;        footer = END_CRL;
+        } else
+#endif
+        {
+            break;
+        }
+    }
+
+    if (!headerEnd) {
+        WOLFSSL_MSG("Couldn't find PEM header");
+        return ASN_NO_PEM_HEADER;
+    }
+
+    headerEnd += XSTRLEN(header);
+
+    /* eat end of line characters */
+    headerEnd = SkipEndOfLineChars(headerEnd, bufferEnd);
+
+    if (type == PRIVATEKEY_TYPE) {
+        if (eccKey) {
+        #ifdef HAVE_ECC
+            *eccKey = (header == BEGIN_EC_PRIV) ? 1 : 0;
+        #else
+            *eccKey = 0;
+        #endif
+        }
+    }
+
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+    if (info) {
+        ret = wc_EncryptedInfoParse(info, &headerEnd, bufferEnd - headerEnd);
+        if (ret < 0)
+            return ret;
+        if (info->set)
+            encrypted_key = 1;
+    }
+#endif /* WOLFSSL_ENCRYPTED_KEYS */
+
+    /* find footer */
+    footerEnd = XSTRNSTR((char*)buff, footer, sz);
+    if (!footerEnd) {
+        if (info)
+            info->consumed = longSz; /* No more certs if no footer */
+        return BUFFER_E;
+    }
+
+    consumedEnd = footerEnd + XSTRLEN(footer);
+
+    if (consumedEnd < bufferEnd) { /* handle no end of line on last line */
+        /* eat end of line characters */
+        consumedEnd = SkipEndOfLineChars(consumedEnd, bufferEnd);
+        /* skip possible null term */
+        if (consumedEnd < bufferEnd && consumedEnd[0] == '\0')
+            consumedEnd++;
+    }
+
+    if (info)
+        info->consumed = (long)(consumedEnd - (char*)buff);
+
+    /* set up der buffer */
+    neededSz = (long)(footerEnd - headerEnd);
+    if (neededSz > sz || neededSz <= 0)
+        return BUFFER_E;
+
+    ret = AllocDer(pDer, (word32)neededSz, type, heap);
+    if (ret < 0) {
+        return ret;
+    }
+    der = *pDer;
+
+    if (Base64_Decode((byte*)headerEnd, (word32)neededSz,
+                      der->buffer, &der->length) < 0)
+        return BUFFER_E;
+
+    if ((header == BEGIN_PRIV_KEY
+#ifdef HAVE_ECC
+         || header == BEGIN_EC_PRIV
+#endif
+        ) && !encrypted_key)
+    {
+        /* pkcs8 key, convert and adjust length */
+        if ((ret = ToTraditional_ex(der->buffer, der->length, &algId)) > 0) {
+            der->length = ret;
+        }
+        else {
+            /* ignore failure here and assume key is not pkcs8 wrapped */
+        }
+
+        return 0;
+    }
+
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+    if (encrypted_key || header == BEGIN_ENC_PRIV_KEY) {
+        int   passwordSz = NAME_SZ;
+    #ifdef WOLFSSL_SMALL_STACK
+        char* password = NULL;
+    #else
+        char  password[NAME_SZ];
+    #endif
+
+        if (!info || !info->passwd_cb) {
+            WOLFSSL_MSG("No password callback set");
+            return NO_PASSWORD;
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
+        password = (char*)XMALLOC(passwordSz, heap, DYNAMIC_TYPE_STRING);
+        if (password == NULL)
+            return MEMORY_E;
+    #endif
+
+        /* get password */
+        ret = info->passwd_cb(password, passwordSz, PEM_PASS_READ,
+            info->passwd_userdata);
+        if (ret >= 0) {
+            passwordSz = ret;
+
+            /* convert and adjust length */
+            if (header == BEGIN_ENC_PRIV_KEY) {
+            #ifndef NO_PWDBASED
+                ret = ToTraditionalEnc(der->buffer, der->length,
+                                       password, passwordSz, &algId);
+
+                if (ret >= 0) {
+                    der->length = ret;
+                    if ((algId == ECDSAk) && (eccKey != NULL)) {
+                        *eccKey = 1;
+                    }
+                    ret = 0;
+                }
+            #else
+                ret = NOT_COMPILED_IN;
+            #endif
+            }
+            /* decrypt the key */
+            else {
+                ret = wc_BufferKeyDecrypt(info, der->buffer, der->length,
+                    (byte*)password, passwordSz, WC_MD5);
+            }
+            ForceZero(password, passwordSz);
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(password, heap, DYNAMIC_TYPE_STRING);
+    #endif
+    }
+#endif /* WOLFSSL_ENCRYPTED_KEYS */
+
+    return ret;
+}
+
+int wc_PemToDer(const unsigned char* buff, long longSz, int type,
+              DerBuffer** pDer, void* heap, EncryptedInfo* info, int* eccKey)
+{
+    return PemToDer(buff, longSz, type, pDer, heap, info, eccKey);
+}
+
+
+/* our KeyPemToDer password callback, password in userData */
+static WC_INLINE int OurPasswordCb(char* passwd, int sz, int rw, void* userdata)
+{
+    (void)rw;
+
+    if (userdata == NULL)
+        return 0;
+
+    XSTRNCPY(passwd, (char*)userdata, sz);
+    return min((word32)sz, (word32)XSTRLEN((char*)userdata));
+}
+
+/* Return bytes written to buff or < 0 for error */
+int wc_KeyPemToDer(const unsigned char* pem, int pemSz,
+                        unsigned char* buff, int buffSz, const char* pass)
+{
+    int            eccKey = 0;
+    int            ret;
+    DerBuffer*     der = NULL;
+#ifdef WOLFSSL_SMALL_STACK
+    EncryptedInfo* info = NULL;
+#else
+    EncryptedInfo  info[1];
+#endif
+
+    WOLFSSL_ENTER("wc_KeyPemToDer");
+
+    if (pem == NULL || buff == NULL || buffSz <= 0) {
+        WOLFSSL_MSG("Bad pem der args");
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL,
+                                   DYNAMIC_TYPE_ENCRYPTEDINFO);
+    if (info == NULL)
+        return MEMORY_E;
+#endif
+
+    XMEMSET(info, 0, sizeof(EncryptedInfo));
+    info->passwd_cb = OurPasswordCb;
+    info->passwd_userdata = (void*)pass;
+
+    ret = PemToDer(pem, pemSz, PRIVATEKEY_TYPE, &der, NULL, info, &eccKey);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO);
+#endif
+
+    if (ret < 0) {
+        WOLFSSL_MSG("Bad Pem To Der");
+    }
+    else {
+        if (der->length <= (word32)buffSz) {
+            XMEMCPY(buff, der->buffer, der->length);
+            ret = der->length;
+        }
+        else {
+            WOLFSSL_MSG("Bad der length");
+            ret = BAD_FUNC_ARG;
+        }
+    }
+
+    FreeDer(&der);
+    return ret;
+}
+
+
+/* Return bytes written to buff or < 0 for error */
+int wc_CertPemToDer(const unsigned char* pem, int pemSz,
+                        unsigned char* buff, int buffSz, int type)
+{
+    int            eccKey = 0;
+    int            ret;
+    DerBuffer*     der = NULL;
+
+    WOLFSSL_ENTER("wc_CertPemToDer");
+
+    if (pem == NULL || buff == NULL || buffSz <= 0) {
+        WOLFSSL_MSG("Bad pem der args");
+        return BAD_FUNC_ARG;
+    }
+
+    if (type != CERT_TYPE && type != CA_TYPE && type != CERTREQ_TYPE) {
+        WOLFSSL_MSG("Bad cert type");
+        return BAD_FUNC_ARG;
+    }
+
+
+    ret = PemToDer(pem, pemSz, type, &der, NULL, NULL, &eccKey);
+    if (ret < 0) {
+        WOLFSSL_MSG("Bad Pem To Der");
+    }
+    else {
+        if (der->length <= (word32)buffSz) {
+            XMEMCPY(buff, der->buffer, der->length);
+            ret = der->length;
+        }
+        else {
+            WOLFSSL_MSG("Bad der length");
+            ret = BAD_FUNC_ARG;
+        }
+    }
+
+    FreeDer(&der);
+    return ret;
+}
+
+#endif /* WOLFSSL_PEM_TO_DER */
+#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */
+
+
+#ifdef WOLFSSL_PEM_TO_DER
+#if defined(WOLFSSL_CERT_EXT) || defined(WOLFSSL_PUB_PEM_TO_DER)
+/* Return bytes written to buff or < 0 for error */
+int wc_PubKeyPemToDer(const unsigned char* pem, int pemSz,
+                           unsigned char* buff, int buffSz)
+{
+    int ret;
+    DerBuffer* der = NULL;
+
+    WOLFSSL_ENTER("wc_PubKeyPemToDer");
+
+    if (pem == NULL || buff == NULL || buffSz <= 0) {
+        WOLFSSL_MSG("Bad pem der args");
+        return BAD_FUNC_ARG;
+    }
+
+    ret = PemToDer(pem, pemSz, PUBLICKEY_TYPE, &der, NULL, NULL, NULL);
+    if (ret < 0) {
+        WOLFSSL_MSG("Bad Pem To Der");
+    }
+    else {
+        if (der->length <= (word32)buffSz) {
+            XMEMCPY(buff, der->buffer, der->length);
+            ret = der->length;
+        }
+        else {
+            WOLFSSL_MSG("Bad der length");
+            ret = BAD_FUNC_ARG;
+        }
+    }
+
+    FreeDer(&der);
+    return ret;
+}
+#endif /* WOLFSSL_CERT_EXT || WOLFSSL_PUB_PEM_TO_DER */
+#endif /* WOLFSSL_PEM_TO_DER */
+
+#ifndef NO_FILESYSTEM
+
+#ifdef WOLFSSL_CERT_GEN
+/* load pem cert from file into der buffer, return der size or error */
+int wc_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    byte   staticBuffer[1]; /* force XMALLOC */
+#else
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+#endif
+    byte*  fileBuf = staticBuffer;
+    int    dynamic = 0;
+    int    ret     = 0;
+    long   sz      = 0;
+    XFILE  file;
+    DerBuffer* converted = NULL;
+
+    WOLFSSL_ENTER("wc_PemCertToDer");
+
+    if (fileName == NULL) {
+        ret = BAD_FUNC_ARG;
+    }
+    else {
+        file = XFOPEN(fileName, "rb");
+        if (file == XBADFILE) {
+            ret = BUFFER_E;
+        }
+    }
+
+    if (ret == 0) {
+        if(XFSEEK(file, 0, XSEEK_END) != 0)
+            ret = BUFFER_E;
+        sz = XFTELL(file);
+        XREWIND(file);
+
+        if (sz <= 0) {
+            ret = BUFFER_E;
+        }
+        else if (sz > (long)sizeof(staticBuffer)) {
+        #ifdef WOLFSSL_STATIC_MEMORY
+            WOLFSSL_MSG("File was larger then static buffer");
+            return MEMORY_E;
+        #endif
+            fileBuf = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE);
+            if (fileBuf == NULL)
+                ret = MEMORY_E;
+            else
+                dynamic = 1;
+        }
+
+        if (ret == 0) {
+            if ( (ret = (int)XFREAD(fileBuf, 1, sz, file)) != sz) {
+                ret = BUFFER_E;
+            }
+        #ifdef WOLFSSL_PEM_TO_DER
+            else {
+                ret = PemToDer(fileBuf, sz, CA_TYPE, &converted,  0, NULL,NULL);
+            }
+        #endif
+
+            if (ret == 0) {
+                if (converted->length < (word32)derSz) {
+                    XMEMCPY(derBuf, converted->buffer, converted->length);
+                    ret = converted->length;
+                }
+                else
+                    ret = BUFFER_E;
+            }
+
+            FreeDer(&converted);
+        }
+
+        XFCLOSE(file);
+        if (dynamic)
+            XFREE(fileBuf, NULL, DYNAMIC_TYPE_FILE);
+    }
+
+    return ret;
+}
+#endif /* WOLFSSL_CERT_GEN */
+
+#if defined(WOLFSSL_CERT_EXT) || defined(WOLFSSL_PUB_PEM_TO_DER)
+/* load pem public key from file into der buffer, return der size or error */
+int wc_PemPubKeyToDer(const char* fileName,
+                           unsigned char* derBuf, int derSz)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    byte   staticBuffer[1]; /* force XMALLOC */
+#else
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+#endif
+    byte*  fileBuf = staticBuffer;
+    int    dynamic = 0;
+    int    ret     = 0;
+    long   sz      = 0;
+    XFILE  file;
+    DerBuffer* converted = NULL;
+
+    WOLFSSL_ENTER("wc_PemPubKeyToDer");
+
+    if (fileName == NULL) {
+        ret = BAD_FUNC_ARG;
+    }
+    else {
+        file = XFOPEN(fileName, "rb");
+        if (file == XBADFILE) {
+            ret = BUFFER_E;
+        }
+    }
+
+    if (ret == 0) {
+        if(XFSEEK(file, 0, XSEEK_END) != 0)
+            ret = BUFFER_E;
+        sz = XFTELL(file);
+        XREWIND(file);
+
+        if (sz <= 0) {
+            ret = BUFFER_E;
+        }
+        else if (sz > (long)sizeof(staticBuffer)) {
+        #ifdef WOLFSSL_STATIC_MEMORY
+            WOLFSSL_MSG("File was larger then static buffer");
+            return MEMORY_E;
+        #endif
+            fileBuf = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE);
+            if (fileBuf == NULL)
+                ret = MEMORY_E;
+            else
+                dynamic = 1;
+        }
+        if (ret == 0) {
+            if ( (ret = (int)XFREAD(fileBuf, 1, sz, file)) != sz) {
+                ret = BUFFER_E;
+            }
+        #ifdef WOLFSSL_PEM_TO_DER
+            else {
+                ret = PemToDer(fileBuf, sz, PUBLICKEY_TYPE, &converted,
+                               0, NULL, NULL);
+            }
+        #endif
+
+            if (ret == 0) {
+                if (converted->length < (word32)derSz) {
+                    XMEMCPY(derBuf, converted->buffer, converted->length);
+                    ret = converted->length;
+                }
+                else
+                    ret = BUFFER_E;
+    }
+
+            FreeDer(&converted);
+    }
+
+        XFCLOSE(file);
+        if (dynamic)
+            XFREE(fileBuf, NULL, DYNAMIC_TYPE_FILE);
+    }
+
+    return ret;
+}
+#endif /* WOLFSSL_CERT_EXT || WOLFSSL_PUB_PEM_TO_DER */
+
+#endif /* !NO_FILESYSTEM */
+
 
 #if !defined(NO_RSA) && (defined(WOLFSSL_CERT_GEN) || \
-        (defined(WOLFSSL_KEY_GEN) && !defined(HAVE_USER_RSA)))
+    ((defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA)) && !defined(HAVE_USER_RSA)))
 /* USER RSA ifdef portions used instead of refactor in consideration for
    possible fips build */
@@ -6723,5 +9443,5 @@
     /* n */
 #ifdef WOLFSSL_SMALL_STACK
-    n = (byte*)XMALLOC(MAX_RSA_INT_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    n = (byte*)XMALLOC(MAX_RSA_INT_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (n == NULL)
         return MEMORY_E;
@@ -6735,5 +9455,5 @@
     if (nSz < 0) {
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(n, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
         return nSz;
@@ -6742,8 +9462,8 @@
     /* e */
 #ifdef WOLFSSL_SMALL_STACK
-    e = (byte*)XMALLOC(MAX_RSA_E_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    e = (byte*)XMALLOC(MAX_RSA_E_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (e == NULL) {
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(n, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
         return MEMORY_E;
@@ -6758,6 +9478,6 @@
     if (eSz < 0) {
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(n, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(e, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
         return eSz;
@@ -6769,6 +9489,6 @@
     if ( (seqSz + nSz + eSz) > outLen) {
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(n,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        XFREE(e,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(n,    key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(e,    key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
         return BUFFER_E;
@@ -6781,8 +9501,8 @@
         byte* algo = NULL;
 
-        algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        algo = (byte*)XMALLOC(MAX_ALGO_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
         if (algo == NULL) {
-            XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-            XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(n, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(e, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
             return MEMORY_E;
         }
@@ -6798,7 +9518,7 @@
         if ( (idx + algoSz + bitStringSz + seqSz + nSz + eSz) > outLen) {
             #ifdef WOLFSSL_SMALL_STACK
-                XFREE(n,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
-                XFREE(e,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
-                XFREE(algo, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(n,    key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(e,    key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(algo, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
             #endif
 
@@ -6813,5 +9533,5 @@
         idx += bitStringSz;
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(algo, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(algo, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
     }
@@ -6830,7 +9550,86 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(n,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    XFREE(e,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
+    XFREE(n,    key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(e,    key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return idx;
+}
+
+int RsaPublicKeyDerSize(RsaKey* key, int with_header)
+{
+    byte* dummy = NULL;
+    byte seq[MAX_SEQ_SZ];
+    byte bitString[1 + MAX_LENGTH_SZ + 1];
+    int  nSz;
+    int  eSz;
+    int  seqSz;
+    int  bitStringSz;
+    int  idx;
+
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    /* n */
+    dummy = (byte*)XMALLOC(MAX_RSA_INT_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (dummy == NULL)
+        return MEMORY_E;
+
+#ifdef HAVE_USER_RSA
+    nSz = SetASNIntRSA(key->n, dummy);
+#else
+    nSz = SetASNIntMP(&key->n, MAX_RSA_INT_SZ, dummy);
+#endif
+    XFREE(dummy, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (nSz < 0) {
+        return nSz;
+    }
+
+    /* e */
+    dummy = (byte*)XMALLOC(MAX_RSA_E_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (dummy == NULL) {
+        XFREE(dummy, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+
+#ifdef HAVE_USER_RSA
+    eSz = SetASNIntRSA(key->e, dummy);
+#else
+    eSz = SetASNIntMP(&key->e, MAX_RSA_INT_SZ, dummy);
+#endif
+    XFREE(dummy, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (eSz < 0) {
+        return eSz;
+    }
+
+    seqSz  = SetSequence(nSz + eSz, seq);
+
+    /* headers */
+    if (with_header) {
+        int  algoSz;
+        dummy = (byte*)XMALLOC(MAX_RSA_INT_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (dummy == NULL)
+            return MEMORY_E;
+
+        algoSz = SetAlgoID(RSAk, dummy, oidKeyType, 0);
+        bitStringSz  = SetBitString(seqSz + nSz + eSz, 0, bitString);
+
+        idx = SetSequence(nSz + eSz + seqSz + bitStringSz + algoSz, dummy);
+        XFREE(dummy, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+
+        /* algo */
+        idx += algoSz;
+        /* bit string */
+        idx += bitStringSz;
+    }
+    else
+        idx = 0;
+
+    /* seq */
+    idx += seqSz;
+    /* n */
+    idx += nSz;
+    /* e */
+    idx += eSz;
 
     return idx;
@@ -6841,5 +9640,4 @@
 
 #if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) && !defined(HAVE_USER_RSA)
-
 
 static mp_int* GetRsaInt(RsaKey* key, int idx)
@@ -6867,5 +9665,5 @@
 
 /* Release Tmp RSA resources */
-static INLINE void FreeTmpRsas(byte** tmps, void* heap)
+static WC_INLINE void FreeTmpRsas(byte** tmps, void* heap)
 {
     int i;
@@ -6929,6 +9727,8 @@
 
     outLen = seqSz + verSz + intTotalLen;
-    if (outLen > (int)inLen)
+    if (outLen > (int)inLen) {
+        FreeTmpRsas(tmps, key->heap);
         return BAD_FUNC_ARG;
+    }
 
     /* write to output */
@@ -6946,6 +9746,7 @@
     return outLen;
 }
-
-
+#endif
+
+#if (defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA)) && !defined(NO_RSA) && !defined(HAVE_USER_RSA)
 /* Convert Rsa Public key to DER format, write to output (inLen), return bytes
    written */
@@ -6955,5 +9756,5 @@
 }
 
-#endif /* WOLFSSL_KEY_GEN && !NO_RSA && !HAVE_USER_RSA */
+#endif /* (WOLFSSL_KEY_GEN || OPENSSL_EXTRA) && !NO_RSA && !HAVE_USER_RSA */
 
 
@@ -6971,72 +9772,50 @@
 int wc_InitCert(Cert* cert)
 {
+#ifdef WOLFSSL_MULTI_ATTRIB
+    int i = 0;
+#endif
     if (cert == NULL) {
         return BAD_FUNC_ARG;
     }
 
+    XMEMSET(cert, 0, sizeof(Cert));
+
     cert->version    = 2;   /* version 3 is hex 2 */
+#ifndef NO_SHA
     cert->sigType    = CTC_SHAwRSA;
+#elif !defined(NO_SHA256)
+    cert->sigType    = CTC_SHA256wRSA;
+#else
+    cert->sigType    = 0;
+#endif
     cert->daysValid  = 500;
     cert->selfSigned = 1;
-    cert->isCA       = 0;
-    cert->bodySz     = 0;
-#ifdef WOLFSSL_ALT_NAMES
-    cert->altNamesSz   = 0;
-    cert->beforeDateSz = 0;
-    cert->afterDateSz  = 0;
-#endif
-#ifdef WOLFSSL_CERT_EXT
-    cert->skidSz = 0;
-    cert->akidSz = 0;
-    cert->keyUsage = 0;
-    cert->extKeyUsage = 0;
-    cert->certPoliciesNb = 0;
-    XMEMSET(cert->akid, 0, CTC_MAX_AKID_SIZE);
-    XMEMSET(cert->skid, 0, CTC_MAX_SKID_SIZE);
-    XMEMSET(cert->certPolicies, 0, CTC_MAX_CERTPOL_NB*CTC_MAX_CERTPOL_SZ);
-#endif
     cert->keyType    = RSA_KEY;
-    XMEMSET(cert->serial, 0, CTC_SERIAL_SIZE);
-    cert->serialSz = 0;
-
-    cert->issuer.country[0] = '\0';
+
     cert->issuer.countryEnc = CTC_PRINTABLE;
-    cert->issuer.state[0] = '\0';
     cert->issuer.stateEnc = CTC_UTF8;
-    cert->issuer.locality[0] = '\0';
     cert->issuer.localityEnc = CTC_UTF8;
-    cert->issuer.sur[0] = '\0';
     cert->issuer.surEnc = CTC_UTF8;
-    cert->issuer.org[0] = '\0';
     cert->issuer.orgEnc = CTC_UTF8;
-    cert->issuer.unit[0] = '\0';
     cert->issuer.unitEnc = CTC_UTF8;
-    cert->issuer.commonName[0] = '\0';
     cert->issuer.commonNameEnc = CTC_UTF8;
-    cert->issuer.email[0] = '\0';
-
-    cert->subject.country[0] = '\0';
+
     cert->subject.countryEnc = CTC_PRINTABLE;
-    cert->subject.state[0] = '\0';
     cert->subject.stateEnc = CTC_UTF8;
-    cert->subject.locality[0] = '\0';
     cert->subject.localityEnc = CTC_UTF8;
-    cert->subject.sur[0] = '\0';
     cert->subject.surEnc = CTC_UTF8;
-    cert->subject.org[0] = '\0';
     cert->subject.orgEnc = CTC_UTF8;
-    cert->subject.unit[0] = '\0';
     cert->subject.unitEnc = CTC_UTF8;
-    cert->subject.commonName[0] = '\0';
     cert->subject.commonNameEnc = CTC_UTF8;
-    cert->subject.email[0] = '\0';
-
-#ifdef WOLFSSL_CERT_REQ
-    cert->challengePw[0] ='\0';
-#endif
+
+#ifdef WOLFSSL_MULTI_ATTRIB
+    for (i = 0; i < CTC_MAX_ATTRIB; i++) {
+        cert->issuer.name[i].type   = CTC_UTF8;
+        cert->subject.name[i].type  = CTC_UTF8;
+    }
+#endif /* WOLFSSL_MULTI_ATTRIB */
+
 #ifdef WOLFSSL_HEAP_TEST
     cert->heap = (void*)WOLFSSL_HEAP_TEST;
-#else
-    cert->heap = NULL;
 #endif
 
@@ -7049,5 +9828,5 @@
     byte size[MAX_LENGTH_SZ];          /* length encoded */
     byte version[MAX_VERSION_SZ];      /* version encoded */
-    byte serial[CTC_SERIAL_SIZE + MAX_LENGTH_SZ]; /* serial number encoded */
+    byte serial[(int)CTC_SERIAL_SIZE + (int)MAX_LENGTH_SZ]; /* serial number encoded */
     byte sigAlgo[MAX_ALGO_SZ];         /* signature algo encoded */
     byte issuer[ASN_NAME_MAX];         /* issuer  encoded */
@@ -7110,5 +9889,6 @@
 #endif /*WOLFSSL_CERT_GEN */
 
-#if defined(HAVE_ECC) && (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN))
+
+#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT)
 
 /* Write a public ECC key to output */
@@ -7130,15 +9910,16 @@
     byte pub[ECC_BUFSIZE];
 #endif
+    int ret;
 
 #ifdef WOLFSSL_SMALL_STACK
-    pub = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    pub = (byte*)XMALLOC(ECC_BUFSIZE, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (pub == NULL)
         return MEMORY_E;
 #endif
 
-    int ret = wc_ecc_export_x963(key, pub, &pubSz);
+    ret = wc_ecc_export_x963(key, pub, &pubSz);
     if (ret != 0) {
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(pub, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
         return ret;
@@ -7148,7 +9929,7 @@
     if (with_header) {
 #ifdef WOLFSSL_SMALL_STACK
-        curve = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        curve = (byte*)XMALLOC(MAX_ALGO_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
         if (curve == NULL) {
-            XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(pub, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
             return MEMORY_E;
         }
@@ -7157,6 +9938,6 @@
         if (curveSz <= 0) {
 #ifdef WOLFSSL_SMALL_STACK
-            XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-            XFREE(pub,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(curve, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(pub,   key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
             return curveSz;
@@ -7164,8 +9945,8 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-        algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        algo = (byte*)XMALLOC(MAX_ALGO_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
         if (algo == NULL) {
-            XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-            XFREE(pub,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(curve, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(pub,   key->heap, DYNAMIC_TYPE_TMP_BUFFER);
             return MEMORY_E;
         }
@@ -7195,8 +9976,8 @@
 #ifdef WOLFSSL_SMALL_STACK
     if (with_header) {
-        XFREE(algo,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    }
-    XFREE(pub,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(algo,  key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(curve, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+    XFREE(pub,   key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -7241,5 +10022,5 @@
     return SetEccPublicKey(output, key, with_AlgCurve);
 }
-#endif /* HAVE_ECC && (WOLFSSL_CERT_GEN || WOLFSSL_KEY_GEN) */
+#endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT */
 
 #if defined(HAVE_ED25519) && (defined(WOLFSSL_CERT_GEN) || \
@@ -7271,5 +10052,5 @@
     if (ret != 0) {
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(pub, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
         return ret;
@@ -7281,5 +10062,5 @@
         algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
         if (algo == NULL) {
-            XFREE(pub,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(pub,   key->heap, DYNAMIC_TYPE_TMP_BUFFER);
             return MEMORY_E;
         }
@@ -7351,5 +10132,5 @@
 #ifdef WOLFSSL_CERT_GEN
 
-static INLINE byte itob(int number)
+static WC_INLINE byte itob(int number)
 {
     return (byte)number + 0x30;
@@ -7406,16 +10187,4 @@
 
 
-/* for systems where mktime() doesn't normalize fully */
-static void RebuildTime(time_t* in, struct tm* out)
-{
-    #if defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX)
-        out = localtime_r(in, out);
-    #else
-        (void)in;
-        (void)out;
-    #endif
-}
-
-
 /* Set Date validity from now until now + daysValid
  * return size in bytes written to output, 0 on error */
@@ -7429,9 +10198,9 @@
     int seqSz;
 
-    time_t     ticks;
-    time_t     normalTime;
-    struct tm* now;
+    time_t now;
+    time_t then;
     struct tm* tmpTime = NULL;
-    struct tm  local;
+    struct tm* expandedTime;
+    struct tm localTime;
 
 #if defined(NEED_TMP_TIME)
@@ -7443,44 +10212,43 @@
 #endif
 
-    ticks = XTIME(0);
-    now   = XGMTIME(&ticks, tmpTime);
-
-    if (now == NULL) {
+    now = XTIME(0);
+
+    /* before now */
+    before[0] = ASN_GENERALIZED_TIME;
+    beforeSz  = SetLength(ASN_GEN_TIME_SZ, before + 1) + 1;  /* gen tag */
+
+    /* subtract 1 day of seconds for more compliance */
+    then = now - 86400;
+    expandedTime = XGMTIME(&then, tmpTime);
+    if (expandedTime == NULL) {
         WOLFSSL_MSG("XGMTIME failed");
         return 0;   /* error */
     }
-
-    /* before now */
-    local = *now;
-    before[0] = ASN_GENERALIZED_TIME;
-    beforeSz  = SetLength(ASN_GEN_TIME_SZ, before + 1) + 1;  /* gen tag */
-
-    /* subtract 1 day for more compliance */
-    local.tm_mday -= 1;
-    normalTime = mktime(&local);
-    RebuildTime(&normalTime, &local);
+    localTime = *expandedTime;
 
     /* adjust */
-    local.tm_year += 1900;
-    local.tm_mon  +=    1;
-
-    SetTime(&local, before + beforeSz);
+    localTime.tm_year += 1900;
+    localTime.tm_mon +=    1;
+
+    SetTime(&localTime, before + beforeSz);
     beforeSz += ASN_GEN_TIME_SZ;
 
-    /* after now + daysValid */
-    local = *now;
     after[0] = ASN_GENERALIZED_TIME;
     afterSz  = SetLength(ASN_GEN_TIME_SZ, after + 1) + 1;  /* gen tag */
 
-    /* add daysValid */
-    local.tm_mday += daysValid;
-    normalTime = mktime(&local);
-    RebuildTime(&normalTime, &local);
+    /* add daysValid of seconds */
+    then = now + (daysValid * 86400);
+    expandedTime = XGMTIME(&then, tmpTime);
+    if (expandedTime == NULL) {
+        WOLFSSL_MSG("XGMTIME failed");
+        return 0;   /* error */
+    }
+    localTime = *expandedTime;
 
     /* adjust */
-    local.tm_year += 1900;
-    local.tm_mon  +=    1;
-
-    SetTime(&local, after + afterSz);
+    localTime.tm_year += 1900;
+    localTime.tm_mon  +=    1;
+
+    SetTime(&localTime, after + afterSz);
     afterSz += ASN_GEN_TIME_SZ;
 
@@ -7530,4 +10298,14 @@
 
     case 7:
+       return name->serialDev;
+
+#ifdef WOLFSSL_CERT_EXT
+    case 8:
+       return name->busCat;
+
+    case 9:
+#else
+    case 8:
+#endif
        return name->email;
 
@@ -7563,4 +10341,18 @@
        return name->commonNameEnc;
 
+    case 7:
+       return name->serialDevEnc;
+
+#ifdef WOLFSSL_CERT_EXT
+    case 8:
+       return name->busCatEnc;
+
+    case 9:
+#else
+    case 8:
+#endif
+        /* FALL THROUGH */
+        /* The last index, email name, does not have encoding type.
+           The empty case here is to keep track of it for future reference. */
     default:
        return 0;
@@ -7595,6 +10387,15 @@
 
     case 7:
-       /* email uses different id type */
-       return 0;
+       return ASN_SERIAL_NUMBER;
+
+#ifdef WOLFSSL_CERT_EXT
+    case 8:
+        return ASN_BUS_CAT;
+
+    case 9:
+#else
+    case 8:
+#endif
+        return ASN_EMAIL_NAME;
 
     default:
@@ -7814,5 +10615,5 @@
 
 /* encode Extended Key Usage (RFC 5280 4.2.1.12), return total bytes written */
-static int SetExtKeyUsage(byte* output, word32 outSz, byte input)
+static int SetExtKeyUsage(Cert* cert, byte* output, word32 outSz, byte input)
 {
     int idx = 0, oidListSz = 0, totalSz, ret = 0;
@@ -7851,4 +10652,17 @@
             ret |= SetOjectIdValue(output, outSz, &idx,
                 extExtKeyUsageOcspSignOid, sizeof(extExtKeyUsageOcspSignOid));
+    #ifdef WOLFSSL_EKU_OID
+        /* iterate through OID values */
+        if (input & EXTKEYUSE_USER) {
+            int i, sz;
+            for (i = 0; i < CTC_MAX_EKU_NB; i++) {
+                sz = cert->extKeyUsageOIDSz[i];
+                if (sz > 0) {
+                    ret |= SetOjectIdValue(output, outSz, &idx,
+                        cert->extKeyUsageOID[i], sz);
+                }
+            }
+        }
+    #endif /* WOLFSSL_EKU_OID */
     }
     if (ret != 0)
@@ -7875,4 +10689,5 @@
     idx += oidListSz;
 
+    (void)cert;
     return idx;
 }
@@ -7894,6 +10709,5 @@
         return MEMORY_E;
 
-    XSTRNCPY(str, in, len);
-    str[len] = 0x00;
+    XSTRNCPY(str, in, len+1);
 
     nb_val = 0;
@@ -8033,4 +10847,132 @@
 #endif /* WOLFSL_ALT_NAMES */
 
+/* Encodes one attribute of the name (issuer/subject)
+ *
+ * name     structure to hold result of encoding
+ * nameStr  value to be encoded
+ * nameType type of encoding i.e CTC_UTF8
+ * type     id of attribute i.e ASN_COMMON_NAME
+ *
+ * returns length on success
+ */
+static int wc_EncodeName(EncodedName* name, const char* nameStr, char nameType,
+        byte type)
+{
+    word32 idx = 0;
+
+    if (nameStr) {
+        /* bottom up */
+        byte firstLen[1 + MAX_LENGTH_SZ];
+        byte secondLen[MAX_LENGTH_SZ];
+        byte sequence[MAX_SEQ_SZ];
+        byte set[MAX_SET_SZ];
+
+        int strLen  = (int)XSTRLEN(nameStr);
+        int thisLen = strLen;
+        int firstSz, secondSz, seqSz, setSz;
+
+        if (strLen == 0) { /* no user data for this item */
+            name->used = 0;
+            return 0;
+        }
+
+        /* Restrict country code size */
+        if (ASN_COUNTRY_NAME == type && strLen != CTC_COUNTRY_SIZE) {
+            return ASN_COUNTRY_SIZE_E;
+        }
+
+        secondSz = SetLength(strLen, secondLen);
+        thisLen += secondSz;
+        switch (type) {
+            case ASN_EMAIL_NAME: /* email */
+                thisLen += EMAIL_JOINT_LEN;
+                firstSz  = EMAIL_JOINT_LEN;
+                break;
+
+            case ASN_DOMAIN_COMPONENT:
+                thisLen += PILOT_JOINT_LEN;
+                firstSz  = PILOT_JOINT_LEN;
+                break;
+
+            default:
+                thisLen++;                                 /* str type */
+                thisLen += JOINT_LEN;
+                firstSz  = JOINT_LEN + 1;
+        }
+        thisLen++; /* id  type */
+        firstSz  = SetObjectId(firstSz, firstLen);
+        thisLen += firstSz;
+
+        seqSz = SetSequence(thisLen, sequence);
+        thisLen += seqSz;
+        setSz = SetSet(thisLen, set);
+        thisLen += setSz;
+
+        if (thisLen > (int)sizeof(name->encoded)) {
+            return BUFFER_E;
+        }
+
+        /* store it */
+        idx = 0;
+        /* set */
+        XMEMCPY(name->encoded, set, setSz);
+        idx += setSz;
+        /* seq */
+        XMEMCPY(name->encoded + idx, sequence, seqSz);
+        idx += seqSz;
+        /* asn object id */
+        XMEMCPY(name->encoded + idx, firstLen, firstSz);
+        idx += firstSz;
+        switch (type) {
+            case ASN_EMAIL_NAME:
+                {
+                    const byte EMAIL_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                       0x01, 0x09, 0x01, 0x16 };
+                    /* email joint id */
+                    XMEMCPY(name->encoded + idx, EMAIL_OID, sizeof(EMAIL_OID));
+                    idx += (int)sizeof(EMAIL_OID);
+                }
+                break;
+
+            case ASN_DOMAIN_COMPONENT:
+                {
+                    const byte PILOT_OID[] = { 0x09, 0x92, 0x26, 0x89,
+                                    0x93, 0xF2, 0x2C, 0x64, 0x01
+                    };
+
+                    XMEMCPY(name->encoded + idx, PILOT_OID,
+                                                     sizeof(PILOT_OID));
+                    idx += (int)sizeof(PILOT_OID);
+                    /* id type */
+                    name->encoded[idx++] = type;
+                    /* str type */
+                    name->encoded[idx++] = nameType;
+                }
+                break;
+
+            default:
+                name->encoded[idx++] = 0x55;
+                name->encoded[idx++] = 0x04;
+                /* id type */
+                name->encoded[idx++] = type;
+                /* str type */
+                name->encoded[idx++] = nameType;
+        }
+        /* second length */
+        XMEMCPY(name->encoded + idx, secondLen, secondSz);
+        idx += secondSz;
+        /* str value */
+        XMEMCPY(name->encoded + idx, nameStr, strLen);
+        idx += strLen;
+
+        name->type = type;
+        name->totalLen = idx;
+        name->used = 1;
+    }
+    else
+        name->used = 0;
+
+    return idx;
+}
 
 /* encode CertName into output, return total bytes written */
@@ -8043,4 +10985,8 @@
     EncodedName  names[NAME_ENTRIES];
 #endif
+#ifdef WOLFSSL_MULTI_ATTRIB
+    EncodedName addNames[CTC_MAX_ATTRIB];
+    int j, type;
+#endif
 
     if (output == NULL || name == NULL)
@@ -8058,51 +11004,24 @@
 
     for (i = 0; i < NAME_ENTRIES; i++) {
+        int ret;
         const char* nameStr = GetOneName(name, i);
-        if (nameStr) {
-            /* bottom up */
-            byte firstLen[1 + MAX_LENGTH_SZ];
-            byte secondLen[MAX_LENGTH_SZ];
-            byte sequence[MAX_SEQ_SZ];
-            byte set[MAX_SET_SZ];
-
-            int email = i == (NAME_ENTRIES - 1) ? 1 : 0;
-            int strLen  = (int)XSTRLEN(nameStr);
-            int thisLen = strLen;
-            int firstSz, secondSz, seqSz, setSz;
-
-            if (strLen == 0) { /* no user data for this item */
-                names[i].used = 0;
-                continue;
-            }
-
-            /* Restrict country code size */
-            if (i == 0 && strLen != CTC_COUNTRY_SIZE) {
+
+        ret = wc_EncodeName(&names[i], nameStr, GetNameType(name, i),
+                          GetNameId(i));
+        if (ret < 0) {
 #ifdef WOLFSSL_SMALL_STACK
                 XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
-                return ASN_COUNTRY_SIZE_E;
-            }
-
-            secondSz = SetLength(strLen, secondLen);
-            thisLen += secondSz;
-            if (email) {
-                thisLen += EMAIL_JOINT_LEN;
-                thisLen ++;                               /* id type */
-                firstSz  = SetObjectId(EMAIL_JOINT_LEN, firstLen);
-            }
-            else {
-                thisLen++;                                 /* str type */
-                thisLen++;                                 /* id  type */
-                thisLen += JOINT_LEN;
-                firstSz  = SetObjectId(JOINT_LEN + 1, firstLen);
-            }
-            thisLen += firstSz;
-
-            seqSz = SetSequence(thisLen, sequence);
-            thisLen += seqSz;
-            setSz = SetSet(thisLen, set);
-            thisLen += setSz;
-
-            if (thisLen > (int)sizeof(names[i].encoded)) {
+                return BUFFER_E;
+            }
+        totalBytes += ret;
+            }
+#ifdef WOLFSSL_MULTI_ATTRIB
+    for (i = 0; i < CTC_MAX_ATTRIB; i++) {
+        if (name->name[i].sz > 0) {
+            int ret;
+            ret = wc_EncodeName(&addNames[i], name->name[i].value,
+                        name->name[i].type, name->name[i].id);
+            if (ret < 0) {
 #ifdef WOLFSSL_SMALL_STACK
                 XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@@ -8110,47 +11029,11 @@
                 return BUFFER_E;
             }
-
-            /* store it */
-            idx = 0;
-            /* set */
-            XMEMCPY(names[i].encoded, set, setSz);
-            idx += setSz;
-            /* seq */
-            XMEMCPY(names[i].encoded + idx, sequence, seqSz);
-            idx += seqSz;
-            /* asn object id */
-            XMEMCPY(names[i].encoded + idx, firstLen, firstSz);
-            idx += firstSz;
-            if (email) {
-                const byte EMAIL_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-                                           0x01, 0x09, 0x01, 0x16 };
-                /* email joint id */
-                XMEMCPY(names[i].encoded + idx, EMAIL_OID, sizeof(EMAIL_OID));
-                idx += (int)sizeof(EMAIL_OID);
+            totalBytes += ret;
             }
             else {
-                /* joint id */
-                byte bType = GetNameId(i);
-                names[i].encoded[idx++] = 0x55;
-                names[i].encoded[idx++] = 0x04;
-                /* id type */
-                names[i].encoded[idx++] = bType;
-                /* str type */
-                names[i].encoded[idx++] = GetNameType(name, i);
-            }
-            /* second length */
-            XMEMCPY(names[i].encoded + idx, secondLen, secondSz);
-            idx += secondSz;
-            /* str value */
-            XMEMCPY(names[i].encoded + idx, nameStr, strLen);
-            idx += strLen;
-
-            totalBytes += idx;
-            names[i].totalLen = idx;
-            names[i].used = 1;
-        }
-        else
-            names[i].used = 0;
-    }
+            addNames[i].used = 0;
+        }
+    }
+#endif /* WOLFSSL_MULTI_ATTRIB */
 
     /* header */
@@ -8165,4 +11048,44 @@
 
     for (i = 0; i < NAME_ENTRIES; i++) {
+    #ifdef WOLFSSL_MULTI_ATTRIB
+        type = GetNameId(i);
+
+        /* list all DC values before OUs */
+        if (type == ASN_ORGUNIT_NAME) {
+            type = ASN_DOMAIN_COMPONENT;
+            for (j = 0; j < CTC_MAX_ATTRIB; j++) {
+                if (name->name[j].sz > 0 && type == name->name[j].id) {
+                    if (outputSz < (word32)(idx+addNames[j].totalLen)) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return BUFFER_E;
+                    }
+
+                    XMEMCPY(output + idx, addNames[j].encoded,
+                            addNames[j].totalLen);
+                    idx += addNames[j].totalLen;
+                }
+            }
+            type = ASN_ORGUNIT_NAME;
+        }
+
+        /* write all similar types to the buffer */
+        for (j = 0; j < CTC_MAX_ATTRIB; j++) {
+            if (name->name[j].sz > 0 && type == name->name[j].id) {
+                if (outputSz < (word32)(idx+addNames[j].totalLen)) {
+                #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                #endif
+                    return BUFFER_E;
+                }
+
+                XMEMCPY(output + idx, addNames[j].encoded,
+                        addNames[j].totalLen);
+                idx += addNames[j].totalLen;
+            }
+        }
+    #endif /* WOLFSSL_MULTI_ATTRIB */
+
         if (names[i].used) {
             if (outputSz < (word32)(idx+names[i].totalLen)) {
@@ -8296,11 +11219,56 @@
 
     /* subject name */
-    der->subjectSz = SetName(der->subject, sizeof(der->subject), &cert->subject);
+#ifdef WOLFSSL_CERT_EXT
+    if (XSTRLEN((const char*)cert->sbjRaw) > 0) {
+        /* Use the raw subject */
+        int idx;
+
+        der->subjectSz = min(sizeof(der->subject),
+                (word32)XSTRLEN((const char*)cert->sbjRaw));
+        /* header */
+        idx = SetSequence(der->subjectSz, der->subject);
+        if (der->subjectSz + idx > (int)sizeof(der->subject)) {
+            return SUBJECT_E;
+        }
+
+        XMEMCPY((char*)der->subject + idx, (const char*)cert->sbjRaw,
+                der->subjectSz);
+        der->subjectSz += idx;
+    }
+    else
+#endif
+    {
+        /* Use the name structure */
+        der->subjectSz = SetName(der->subject, sizeof(der->subject),
+                &cert->subject);
+    }
     if (der->subjectSz <= 0)
         return SUBJECT_E;
 
     /* issuer name */
-    der->issuerSz = SetName(der->issuer, sizeof(der->issuer), cert->selfSigned ?
-             &cert->subject : &cert->issuer);
+#ifdef WOLFSSL_CERT_EXT
+    if (XSTRLEN((const char*)cert->issRaw) > 0) {
+        /* Use the raw issuer */
+        int idx;
+
+        der->issuerSz = min(sizeof(der->issuer),
+                (word32)XSTRLEN((const char*)cert->issRaw));
+        /* header */
+        idx = SetSequence(der->issuerSz, der->issuer);
+        if (der->issuerSz + idx > (int)sizeof(der->issuer)) {
+            return ISSUER_E;
+        }
+
+        XMEMCPY((char*)der->issuer + idx, (const char*)cert->issRaw,
+                der->issuerSz);
+        der->issuerSz += idx;
+    }
+    else
+#endif
+    {
+        /* Use the name structure */
+        der->issuerSz = SetName(der->issuer, sizeof(der->issuer),
+                cert->selfSigned ? &cert->subject : &cert->issuer);
+    }
     if (der->issuerSz <= 0)
         return ISSUER_E;
@@ -8338,5 +11306,5 @@
     if (cert->skidSz) {
         /* check the provided SKID size */
-        if (cert->skidSz > (int)sizeof(der->skid))
+        if (cert->skidSz > (int)min(CTC_MAX_SKID_SIZE, sizeof(der->skid)))
             return SKID_E;
 
@@ -8356,5 +11324,5 @@
     if (cert->akidSz) {
         /* check the provided AKID size */
-        if (cert->akidSz > (int)sizeof(der->akid))
+        if (cert->akidSz > (int)min(CTC_MAX_AKID_SIZE, sizeof(der->akid)))
             return AKID_E;
 
@@ -8383,5 +11351,5 @@
     /* Extended Key Usage */
     if (cert->extKeyUsage != 0){
-        der->extKeyUsageSz = SetExtKeyUsage(der->extKeyUsage,
+        der->extKeyUsageSz = SetExtKeyUsage(cert, der->extKeyUsage,
                                 sizeof(der->extKeyUsage), cert->extKeyUsage);
         if (der->extKeyUsageSz <= 0)
@@ -8687,5 +11655,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    der = (DerCert*)XMALLOC(sizeof(DerCert), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    der = (DerCert*)XMALLOC(sizeof(DerCert), cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (der == NULL)
         return MEMORY_E;
@@ -8702,5 +11670,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(der, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -8741,5 +11709,5 @@
                   const byte* ntruKey, word16 keySz, WC_RNG* rng)
 {
-    return MakeAnyCert(cert, derBuffer, derSz, NULL, NULL, rng, ntruKey, keySz);
+    return MakeAnyCert(cert, derBuffer, derSz, NULL, NULL, rng, ntruKey, keySz, NULL);
 }
 
@@ -8889,5 +11857,5 @@
     if (cert->skidSz) {
         /* check the provided SKID size */
-        if (cert->skidSz > (int)sizeof(der->skid))
+        if (cert->skidSz > (int)min(CTC_MAX_SKID_SIZE, sizeof(der->skid)))
             return SKID_E;
 
@@ -8916,5 +11884,5 @@
     /* Extended Key Usage */
     if (cert->extKeyUsage != 0){
-        der->extKeyUsageSz = SetExtKeyUsage(der->extKeyUsage,
+        der->extKeyUsageSz = SetExtKeyUsage(cert, der->extKeyUsage,
                                 sizeof(der->extKeyUsage), cert->extKeyUsage);
         if (der->extKeyUsageSz <= 0)
@@ -9041,5 +12009,6 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    der = (DerCert*)XMALLOC(sizeof(DerCert), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    der = (DerCert*)XMALLOC(sizeof(DerCert), cert->heap,
+                                                    DYNAMIC_TYPE_TMP_BUFFER);
     if (der == NULL)
         return MEMORY_E;
@@ -9056,5 +12025,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(der, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -9140,6 +12109,9 @@
     sigSz = MakeSignature(certSignCtx, buffer, requestSz, certSignCtx->sig,
         MAX_ENCODED_SIG_SZ, rsaKey, eccKey, ed25519Key, rng, sType, heap);
-    if (sigSz == WC_PENDING_E)
+    if (sigSz == WC_PENDING_E) {
+        /* Not free'ing certSignCtx->sig here because it could still be in use
+         * with async operations. */
         return sigSz;
+    }
 
     if (sigSz >= 0) {
@@ -9147,5 +12119,6 @@
             sigSz = BUFFER_E;
         else
-            sigSz = AddSignature(buffer, requestSz, certSignCtx->sig, sigSz, sType);
+            sigSz = AddSignature(buffer, requestSz, certSignCtx->sig, sigSz,
+                                 sType);
     }
 
@@ -9196,4 +12169,16 @@
 
 #ifdef WOLFSSL_CERT_EXT
+
+/* Get raw subject from cert, which may contain OIDs not parsed by Decode.
+   The raw subject pointer will only be valid while "cert" is valid. */
+int wc_GetSubjectRaw(byte **subjectRaw, Cert *cert)
+{
+    int rc = BAD_FUNC_ARG;
+    if ((subjectRaw != NULL) && (cert != NULL)) {
+        *subjectRaw = cert->sbjRaw;
+        rc = 0;
+    }
+    return rc;
+}
 
 /* Set KID from public key */
@@ -9252,27 +12237,14 @@
 
     /* Compute SKID by hashing public key */
-#ifdef NO_SHA
     if (kid_type == SKID_TYPE) {
-        ret = wc_Sha256Hash(buffer, bufferSz, cert->skid);
-        cert->skidSz = WC_SHA256_DIGEST_SIZE;
+        ret = CalcHashId(buffer, bufferSz, cert->skid);
+        cert->skidSz = KEYID_SIZE;
     }
     else if (kid_type == AKID_TYPE) {
-        ret = wc_Sha256Hash(buffer, bufferSz, cert->akid);
-        cert->akidSz = WC_SHA256_DIGEST_SIZE;
+        ret = CalcHashId(buffer, bufferSz, cert->akid);
+        cert->akidSz = KEYID_SIZE;
     }
     else
         ret = BAD_FUNC_ARG;
-#else /* NO_SHA */
-    if (kid_type == SKID_TYPE) {
-        ret = wc_ShaHash(buffer, bufferSz, cert->skid);
-        cert->skidSz = WC_SHA_DIGEST_SIZE;
-    }
-    else if (kid_type == AKID_TYPE) {
-        ret = wc_ShaHash(buffer, bufferSz, cert->akid);
-        cert->akidSz = WC_SHA_DIGEST_SIZE;
-    }
-    else
-        ret = BAD_FUNC_ARG;
-#endif /* NO_SHA */
 
     XFREE(buffer, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
@@ -9337,5 +12309,5 @@
 
 
-#ifndef NO_FILESYSTEM
+#if !defined(NO_FILESYSTEM) && !defined(NO_ASN_CRYPT)
 
 /* Set SKID from public key file in PEM */
@@ -9357,5 +12329,5 @@
     }
 
-    derSz = wolfSSL_PemPubKeyToDer(file, der, MAX_PUBLIC_KEY_SZ);
+    derSz = wc_PemPubKeyToDer(file, der, MAX_PUBLIC_KEY_SZ);
     if (derSz <= 0)
     {
@@ -9413,4 +12385,5 @@
             XFREE(der, cert->heap, DYNAMIC_TYPE_CERT);
             wc_ecc_free(eckey);
+            XFREE(eckey, cert->heap, DYNAMIC_TYPE_ECC);
             return PUBLIC_KEY_E;
         }
@@ -9436,5 +12409,5 @@
 }
 
-#endif /* NO_FILESYSTEM */
+#endif /* !NO_FILESYSTEM && !NO_ASN_CRYPT */
 
 /* Set AKID from certificate contains in buffer (DER encoded) */
@@ -9454,5 +12427,5 @@
 #ifdef WOLFSSL_SMALL_STACK
     decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert),
-                                    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                                    cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (decoded == NULL)
         return MEMORY_E;
@@ -9460,10 +12433,10 @@
 
     /* decode certificate and get SKID that will be AKID of current cert */
-    InitDecodedCert(decoded, (byte*)der, derSz, NULL);
+    InitDecodedCert(decoded, der, derSz, NULL);
     ret = ParseCert(decoded, CERT_TYPE, NO_VERIFY, 0);
     if (ret != 0) {
         FreeDecodedCert(decoded);
         #ifdef WOLFSSL_SMALL_STACK
-            XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(decoded, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
         #endif
         return ret;
@@ -9474,5 +12447,5 @@
         FreeDecodedCert(decoded);
         #ifdef WOLFSSL_SMALL_STACK
-            XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(decoded, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
         #endif
         return ASN_NO_SKID;
@@ -9483,5 +12456,5 @@
         FreeDecodedCert(decoded);
         #ifdef WOLFSSL_SMALL_STACK
-            XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(decoded, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
         #endif
         return MEMORY_E;
@@ -9494,5 +12467,5 @@
     FreeDecodedCert(decoded);
     #ifdef WOLFSSL_SMALL_STACK
-        XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(decoded, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
     #endif
 
@@ -9519,5 +12492,5 @@
     }
 
-    derSz = wolfSSL_PemCertToDer(file, der, EIGHTK_BUF);
+    derSz = wc_PemCertToDer(file, der, EIGHTK_BUF);
     if (derSz <= 0)
     {
@@ -9532,5 +12505,5 @@
 }
 
-#endif /* NO_FILESYSTEM */
+#endif /* !NO_FILESYSTEM */
 
 /* Set KeyUsage from human readable string */
@@ -9546,10 +12519,10 @@
     cert->keyUsage = 0;
 
-    str = (char*)XMALLOC(XSTRLEN(value)+1, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    len = (word32)XSTRLEN(value);
+    str = (char*)XMALLOC(len+1, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (str == NULL)
         return MEMORY_E;
 
-    XMEMSET(str, 0, XSTRLEN(value)+1);
-    XSTRNCPY(str, value, XSTRLEN(value));
+    XSTRNCPY(str, value, len+1);
 
     /* parse value, and set corresponding Key Usage value */
@@ -9605,10 +12578,10 @@
     cert->extKeyUsage = 0;
 
-    str = (char*)XMALLOC(XSTRLEN(value)+1, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    len = (word32)XSTRLEN(value);
+    str = (char*)XMALLOC(len+1, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (str == NULL)
         return MEMORY_E;
 
-    XMEMSET(str, 0, XSTRLEN(value)+1);
-    XSTRNCPY(str, value, XSTRLEN(value));
+    XSTRNCPY(str, value, len+1);
 
     /* parse value, and set corresponding Key Usage value */
@@ -9647,4 +12620,36 @@
     return ret;
 }
+
+#ifdef WOLFSSL_EKU_OID
+/*
+ * cert structure to set EKU oid in
+ * oid  the oid in byte representation
+ * sz   size of oid buffer
+ * idx  index of array to place oid
+ *
+ * returns 0 on success
+ */
+int wc_SetExtKeyUsageOID(Cert *cert, const char *in, word32 sz, byte idx,
+        void* heap)
+{
+    byte oid[MAX_OID_SZ];
+    word32 oidSz = MAX_OID_SZ;
+
+    if (idx >= CTC_MAX_EKU_NB || sz >= CTC_MAX_EKU_OID_SZ) {
+        WOLFSSL_MSG("Either idx or sz was too large");
+        return BAD_FUNC_ARG;
+    }
+
+    if (EncodePolicyOID(oid, &oidSz, in, heap) != 0) {
+        return BUFFER_E;
+    }
+
+    XMEMCPY(cert->extKeyUsageOID[idx], oid, oidSz);
+    cert->extKeyUsageOIDSz[idx] = oidSz;
+    cert->extKeyUsage |= EXTKEYUSE_USER;
+
+    return 0;
+}
+#endif /* WOLFSSL_EKU_OID */
 #endif /* WOLFSSL_CERT_EXT */
 
@@ -9666,5 +12671,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cert->heap,
                                                        DYNAMIC_TYPE_TMP_BUFFER);
     if (decoded == NULL)
@@ -9672,5 +12677,5 @@
 #endif
 
-    InitDecodedCert(decoded, (byte*)der, derSz, NULL);
+    InitDecodedCert(decoded, der, derSz, NULL);
     ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0);
 
@@ -9740,5 +12745,5 @@
     FreeDecodedCert(decoded);
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(decoded, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -9762,5 +12767,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cert->heap,
                                                        DYNAMIC_TYPE_TMP_BUFFER);
     if (decoded == NULL)
@@ -9768,5 +12773,5 @@
 #endif
 
-    InitDecodedCert(decoded, (byte*)der, derSz, NULL);
+    InitDecodedCert(decoded, der, derSz, NULL);
     ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0);
 
@@ -9794,5 +12799,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(decoded, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -9822,5 +12827,5 @@
 #endif
 
-    InitDecodedCert(decoded, (byte*)der, derSz, NULL);
+    InitDecodedCert(decoded, der, derSz, NULL);
     ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0);
 
@@ -9833,5 +12838,5 @@
                                                          : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->commonName, decoded->subjectCN, CTC_NAME_SIZE);
-            cn->commonName[sz] = 0;
+            cn->commonName[sz] = '\0';
             cn->commonNameEnc = decoded->subjectCNEnc;
         }
@@ -9840,5 +12845,5 @@
                                                         : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->country, decoded->subjectC, CTC_NAME_SIZE);
-            cn->country[sz] = 0;
+            cn->country[sz] = '\0';
             cn->countryEnc = decoded->subjectCEnc;
         }
@@ -9847,5 +12852,5 @@
                                                          : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->state, decoded->subjectST, CTC_NAME_SIZE);
-            cn->state[sz] = 0;
+            cn->state[sz] = '\0';
             cn->stateEnc = decoded->subjectSTEnc;
         }
@@ -9854,5 +12859,5 @@
                                                         : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->locality, decoded->subjectL, CTC_NAME_SIZE);
-            cn->locality[sz] = 0;
+            cn->locality[sz] = '\0';
             cn->localityEnc = decoded->subjectLEnc;
         }
@@ -9861,5 +12866,5 @@
                                                         : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->org, decoded->subjectO, CTC_NAME_SIZE);
-            cn->org[sz] = 0;
+            cn->org[sz] = '\0';
             cn->orgEnc = decoded->subjectOEnc;
         }
@@ -9868,5 +12873,5 @@
                                                          : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->unit, decoded->subjectOU, CTC_NAME_SIZE);
-            cn->unit[sz] = 0;
+            cn->unit[sz] = '\0';
             cn->unitEnc = decoded->subjectOUEnc;
         }
@@ -9875,12 +12880,42 @@
                                                          : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->sur, decoded->subjectSN, CTC_NAME_SIZE);
-            cn->sur[sz] = 0;
+            cn->sur[sz] = '\0';
             cn->surEnc = decoded->subjectSNEnc;
         }
+        if (decoded->subjectSND) {
+            sz = (decoded->subjectSNDLen < CTC_NAME_SIZE) ? decoded->subjectSNDLen
+                                                         : CTC_NAME_SIZE - 1;
+            XSTRNCPY(cn->serialDev, decoded->subjectSND, CTC_NAME_SIZE);
+            cn->serialDev[sz] = '\0';
+            cn->serialDevEnc = decoded->subjectSNDEnc;
+        }
+    #ifdef WOLFSSL_CERT_EXT
+        if (decoded->subjectBC) {
+            sz = (decoded->subjectBCLen < CTC_NAME_SIZE) ? decoded->subjectBCLen
+                                                         : CTC_NAME_SIZE - 1;
+            XSTRNCPY(cn->busCat, decoded->subjectBC, CTC_NAME_SIZE);
+            cn->busCat[sz] = '\0';
+            cn->busCatEnc = decoded->subjectBCEnc;
+        }
+        if (decoded->subjectJC) {
+            sz = (decoded->subjectJCLen < CTC_NAME_SIZE) ? decoded->subjectJCLen
+                                                         : CTC_NAME_SIZE - 1;
+            XSTRNCPY(cn->joiC, decoded->subjectJC, CTC_NAME_SIZE);
+            cn->joiC[sz] = '\0';
+            cn->joiCEnc = decoded->subjectJCEnc;
+        }
+        if (decoded->subjectJS) {
+            sz = (decoded->subjectJSLen < CTC_NAME_SIZE) ? decoded->subjectJSLen
+                                                         : CTC_NAME_SIZE - 1;
+            XSTRNCPY(cn->joiSt, decoded->subjectJS, CTC_NAME_SIZE);
+            cn->joiSt[sz] = '\0';
+            cn->joiStEnc = decoded->subjectJSEnc;
+        }
+    #endif
         if (decoded->subjectEmail) {
             sz = (decoded->subjectEmailLen < CTC_NAME_SIZE)
                ?  decoded->subjectEmailLen : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->email, decoded->subjectEmail, CTC_NAME_SIZE);
-            cn->email[sz] = 0;
+            cn->email[sz] = '\0';
         }
     }
@@ -9895,4 +12930,109 @@
 }
 
+#ifdef WOLFSSL_CERT_EXT
+/* Set raw subject from der buffer, return 0 on success */
+static int SetSubjectRawFromCert(byte* sbjRaw, const byte* der, int derSz)
+{
+    int ret;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* decoded;
+#else
+    DecodedCert decoded[1];
+#endif
+
+    if ((derSz < 0) || (sbjRaw == NULL)) {
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (decoded == NULL) {
+        return MEMORY_E;
+    }
+#endif
+
+    InitDecodedCert(decoded, der, derSz, NULL);
+    ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0);
+
+    if (ret < 0) {
+        WOLFSSL_MSG("ParseCertRelative error");
+    }
+#ifndef IGNORE_NAME_CONSTRAINT
+    else {
+        if ((decoded->subjectRaw) &&
+            (decoded->subjectRawLen <= (int)sizeof(CertName))) {
+            XMEMCPY(sbjRaw, decoded->subjectRaw, decoded->subjectRawLen);
+        }
+        }
+#else
+    else {
+        /* Fields are not accessible */
+        ret = -1;
+        WOLFSSL_MSG("IGNORE_NAME_CONSTRAINT excludes raw subject");
+    }
+#endif
+
+    FreeDecodedCert(decoded);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret < 0 ? ret : 0;
+}
+
+/* Set raw issuer from der buffer, return 0 on success */
+static int SetIssuerRawFromCert(byte* issuerRaw, const byte* der, int derSz)
+{
+    int ret;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* decoded;
+#else
+    DecodedCert decoded[1];
+#endif
+
+    if ((derSz < 0) || (issuerRaw == NULL)) {
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (decoded == NULL) {
+        return MEMORY_E;
+    }
+#endif
+
+    InitDecodedCert(decoded, der, derSz, NULL);
+    ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0);
+
+    if (ret < 0) {
+        WOLFSSL_MSG("ParseCertRelative error");
+    }
+#ifndef IGNORE_NAME_CONSTRAINT
+    else {
+        if ((decoded->issuerRaw) &&
+            (decoded->issuerRawLen <= (int)sizeof(CertName))) {
+            XMEMCPY(issuerRaw, decoded->issuerRaw, decoded->issuerRawLen);
+        }
+    }
+#else
+    else {
+        /* Fields are not accessible */
+        ret = -1;
+        WOLFSSL_MSG("IGNORE_NAME_CONSTRAINT excludes raw issuer");
+    }
+#endif
+
+    FreeDecodedCert(decoded);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret < 0 ? ret : 0;
+}
+#endif /* WOLFSSL_CERT_EXT */
 
 #ifndef NO_FILESYSTEM
@@ -9903,11 +13043,16 @@
     int         ret;
     int         derSz;
-    byte*       der = (byte*)XMALLOC(EIGHTK_BUF, cert->heap, DYNAMIC_TYPE_CERT);
-
+    byte*       der;
+
+    if (cert == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    der = (byte*)XMALLOC(EIGHTK_BUF, cert->heap, DYNAMIC_TYPE_CERT);
     if (der == NULL) {
         WOLFSSL_MSG("wc_SetIssuer OOF Problem");
         return MEMORY_E;
     }
-    derSz = wolfSSL_PemCertToDer(issuerFile, der, EIGHTK_BUF);
+    derSz = wc_PemCertToDer(issuerFile, der, EIGHTK_BUF);
     cert->selfSigned = 0;
     ret = SetNameFromCert(&cert->issuer, der, derSz);
@@ -9923,11 +13068,17 @@
     int         ret;
     int         derSz;
-    byte*       der = (byte*)XMALLOC(EIGHTK_BUF, cert->heap, DYNAMIC_TYPE_CERT);
-
+    byte*       der;
+
+    if (cert == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    der = (byte*)XMALLOC(EIGHTK_BUF, cert->heap, DYNAMIC_TYPE_CERT);
     if (der == NULL) {
         WOLFSSL_MSG("wc_SetSubject OOF Problem");
         return MEMORY_E;
     }
-    derSz = wolfSSL_PemCertToDer(subjectFile, der, EIGHTK_BUF);
+
+    derSz = wc_PemCertToDer(subjectFile, der, EIGHTK_BUF);
     ret = SetNameFromCert(&cert->subject, der, derSz);
     XFREE(der, cert->heap, DYNAMIC_TYPE_CERT);
@@ -9936,19 +13087,23 @@
 }
 
-
 #ifdef WOLFSSL_ALT_NAMES
 
-/* Set atl names from file in PEM */
+/* Set alt names from file in PEM */
 int wc_SetAltNames(Cert* cert, const char* file)
 {
     int         ret;
     int         derSz;
-    byte*       der = (byte*)XMALLOC(EIGHTK_BUF, cert->heap, DYNAMIC_TYPE_CERT);
-
+    byte*       der;
+
+    if (cert == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    der = (byte*)XMALLOC(EIGHTK_BUF, cert->heap, DYNAMIC_TYPE_CERT);
     if (der == NULL) {
         WOLFSSL_MSG("wc_SetAltNames OOF Problem");
         return MEMORY_E;
     }
-    derSz = wolfSSL_PemCertToDer(file, der, EIGHTK_BUF);
+    derSz = wc_PemCertToDer(file, der, EIGHTK_BUF);
     ret = SetAltNamesFromCert(cert, der, derSz);
     XFREE(der, cert->heap, DYNAMIC_TYPE_CERT);
@@ -9959,20 +13114,55 @@
 #endif /* WOLFSSL_ALT_NAMES */
 
-#endif /* NO_FILESYSTEM */
+#endif /* !NO_FILESYSTEM */
 
 /* Set cert issuer from DER buffer */
 int wc_SetIssuerBuffer(Cert* cert, const byte* der, int derSz)
 {
+    if (cert == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
     cert->selfSigned = 0;
     return SetNameFromCert(&cert->issuer, der, derSz);
 }
 
-
 /* Set cert subject from DER buffer */
 int wc_SetSubjectBuffer(Cert* cert, const byte* der, int derSz)
 {
+    if (cert == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
     return SetNameFromCert(&cert->subject, der, derSz);
 }
-
+#ifdef WOLFSSL_CERT_EXT
+/* Set cert raw subject from DER buffer */
+int wc_SetSubjectRaw(Cert* cert, const byte* der, int derSz)
+{
+    int ret;
+
+    if (cert == NULL) {
+        ret = BAD_FUNC_ARG;
+    }
+    else {
+        ret = SetSubjectRawFromCert(cert->sbjRaw, der, derSz);
+    }
+    return ret;
+}
+
+/* Set cert raw issuer from DER buffer */
+int wc_SetIssuerRaw(Cert* cert, const byte* der, int derSz)
+{
+    int ret;
+
+    if (cert == NULL) {
+        ret = BAD_FUNC_ARG;
+    }
+    else {
+        ret = SetIssuerRawFromCert(cert->issRaw, der, derSz);
+    }
+    return ret;
+}
+#endif
 
 #ifdef WOLFSSL_ALT_NAMES
@@ -10088,4 +13278,7 @@
         return ASN_PARSE_E;
 
+    if (*inOutIdx >= inSz)
+        return ASN_PARSE_E;
+
     b = input[*inOutIdx];
     *inOutIdx += 1;
@@ -10102,11 +13295,11 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    priv = (byte*)XMALLOC(ECC_MAXSIZE+1, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    priv = (byte*)XMALLOC(ECC_MAXSIZE+1, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (priv == NULL)
         return MEMORY_E;
 
-    pub = (byte*)XMALLOC(2*(ECC_MAXSIZE+1), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    pub = (byte*)XMALLOC(2*(ECC_MAXSIZE+1), key->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (pub == NULL) {
-        XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(priv, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
         return MEMORY_E;
     }
@@ -10175,6 +13368,6 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    XFREE(pub,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(priv, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(pub,  key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -10182,4 +13375,47 @@
 }
 
+
+#ifdef WOLFSSL_CUSTOM_CURVES
+static void ByteToHex(byte n, char* str)
+{
+    static const char hexChar[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+                                    '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+    str[0] = hexChar[n >> 4];
+    str[1] = hexChar[n & 0xf];
+}
+
+/* returns 0 on success */
+static int ASNToHexString(const byte* input, word32* inOutIdx, char** out,
+                          word32 inSz, void* heap, int heapType)
+{
+    int len;
+    int i;
+    char* str;
+
+    if (*inOutIdx >= inSz) {
+        return BUFFER_E;
+    }
+
+    if (input[*inOutIdx] == ASN_INTEGER) {
+        if (GetASNInt(input, inOutIdx, &len, inSz) < 0)
+            return ASN_PARSE_E;
+    }
+    else {
+        if (GetOctetString(input, inOutIdx, &len, inSz) < 0)
+            return ASN_PARSE_E;
+    }
+
+    str = (char*)XMALLOC(len * 2 + 1, heap, heapType);
+    for (i=0; i<len; i++)
+        ByteToHex(input[*inOutIdx + i], str + i*2);
+    str[len*2] = '\0';
+
+    *inOutIdx += len;
+    *out = str;
+
+    return 0;
+}
+#endif /* WOLFSSL_CUSTOM_CURVES */
 
 int wc_EccPublicKeyDecode(const byte* input, word32* inOutIdx,
@@ -10188,7 +13424,6 @@
     int    length;
     int    ret;
-#ifdef ECC_CHECK_PUBLIC_KEY_OID
+    int    curve_id = ECC_CURVE_DEF;
     word32 oidSum;
-#endif
 
     if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0)
@@ -10205,32 +13440,144 @@
         return ret;
 
+    if (*inOutIdx >= inSz) {
+        return BUFFER_E;
+    }
+
+    if (input[*inOutIdx] == (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
+#ifdef WOLFSSL_CUSTOM_CURVES
+        ecc_set_type* curve;
+        int len;
+        char* point;
+
+        ret = 0;
+
+        curve = (ecc_set_type*)XMALLOC(sizeof(*curve), key->heap,
+                                                       DYNAMIC_TYPE_ECC_BUFFER);
+        if (curve == NULL)
+            ret = MEMORY_E;
+
+        if (ret == 0) {
+            XMEMSET(curve, 0, sizeof(*curve));
+            curve->name = "Custom";
+            curve->id = ECC_CURVE_CUSTOM;
+
+            if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+                ret = ASN_PARSE_E;
+        }
+
+        if (ret == 0) {
+            GetInteger7Bit(input, inOutIdx, inSz);
+            if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+                ret = ASN_PARSE_E;
+        }
+        if (ret == 0) {
+            SkipObjectId(input, inOutIdx, inSz);
+            ret = ASNToHexString(input, inOutIdx, (char**)&curve->prime, inSz,
+                                            key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+        }
+        if (ret == 0) {
+            curve->size = (int)XSTRLEN(curve->prime) / 2;
+
+            if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+                ret = ASN_PARSE_E;
+        }
+        if (ret == 0) {
+            ret = ASNToHexString(input, inOutIdx, (char**)&curve->Af, inSz,
+                                            key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+        }
+        if (ret == 0) {
+            ret = ASNToHexString(input, inOutIdx, (char**)&curve->Bf, inSz,
+                                            key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+        }
+        if (ret == 0) {
+            if (*inOutIdx < inSz && input[*inOutIdx] == ASN_BIT_STRING) {
+                len = 0;
+                ret = GetASNHeader(input, ASN_BIT_STRING, inOutIdx, &len, inSz);
+                *inOutIdx += len;
+            }
+        }
+        if (ret == 0) {
+            ret = ASNToHexString(input, inOutIdx, (char**)&point, inSz,
+                                            key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+
+            /* sanity check that point buffer is not smaller than the expected
+             * size to hold ( 0 4 || Gx || Gy )
+             * where Gx and Gy are each the size of curve->size * 2 */
+            if (ret == 0 && (int)XSTRLEN(point) < (curve->size * 4) + 2) {
+                XFREE(point, key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+                ret = BUFFER_E;
+            }
+        }
+        if (ret == 0) {
+            curve->Gx = (const char*)XMALLOC(curve->size * 2 + 2, key->heap,
+                                                       DYNAMIC_TYPE_ECC_BUFFER);
+            curve->Gy = (const char*)XMALLOC(curve->size * 2 + 2, key->heap,
+                                                       DYNAMIC_TYPE_ECC_BUFFER);
+            if (curve->Gx == NULL || curve->Gy == NULL) {
+                XFREE(point, key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+                ret = MEMORY_E;
+            }
+        }
+        if (ret == 0) {
+            XMEMCPY((char*)curve->Gx, point + 2, curve->size * 2);
+            XMEMCPY((char*)curve->Gy, point + curve->size * 2 + 2,
+                                                               curve->size * 2);
+            ((char*)curve->Gx)[curve->size * 2] = '\0';
+            ((char*)curve->Gy)[curve->size * 2] = '\0';
+            XFREE(point, key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+            ret = ASNToHexString(input, inOutIdx, (char**)&curve->order, inSz,
+                                            key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+        }
+        if (ret == 0) {
+            curve->cofactor = GetInteger7Bit(input, inOutIdx, inSz);
+
+            curve->oid = NULL;
+            curve->oidSz = 0;
+            curve->oidSum = 0;
+
+            if (wc_ecc_set_custom_curve(key, curve) < 0) {
+                ret = ASN_PARSE_E;
+            }
+            key->deallocSet = 1;
+            curve = NULL;
+        }
+        if (curve != NULL)
+            wc_ecc_free_curve(curve, key->heap);
+
+        if (ret < 0)
+            return ret;
+#else
+        return ASN_PARSE_E;
+#endif /* WOLFSSL_CUSTOM_CURVES */
+    }
+    else {
     /* ecc params information */
-#ifdef ECC_CHECK_PUBLIC_KEY_OID
     ret = GetObjectId(input, inOutIdx, &oidSum, oidIgnoreType, inSz);
     if (ret != 0)
         return ret;
-    if (CheckCurve(oidSum) < 0)
+
+        /* get curve id */
+        curve_id = wc_ecc_get_oid(oidSum, NULL, 0);
+        if (curve_id < 0)
         return ECC_CURVE_OID_E;
-#else
-    ret = SkipObjectId(input, inOutIdx, inSz);
+    }
+
+    /* key header */
+    ret = CheckBitString(input, inOutIdx, &length, inSz, 1, NULL);
     if (ret != 0)
         return ret;
-#endif
-
-    /* key header */
-    ret = CheckBitString(input, inOutIdx, NULL, inSz, 1, NULL);
-    if (ret != 0)
-        return ret;
 
     /* This is the raw point data compressed or uncompressed. */
-    if (wc_ecc_import_x963(input + *inOutIdx, inSz - *inOutIdx, key) != 0)
+    if (wc_ecc_import_x963_ex(input + *inOutIdx, inSz - *inOutIdx, key,
+                                                            curve_id) != 0) {
         return ASN_ECC_KEY_E;
+}
+
+    *inOutIdx += length;
 
     return 0;
 }
 
-
-#ifdef WOLFSSL_KEY_GEN
-
+#if defined(HAVE_ECC_KEY_EXPORT) && !defined(NO_ASN_CRYPT)
 /* build DER formatted ECC key, include optional public key if requested,
  * return length on success, negative on error */
@@ -10350,5 +13697,4 @@
 }
 
-
 /* Write a Private ecc key, including public to DER format,
  * length on success else < 0 */
@@ -10366,6 +13712,74 @@
 }
 
-#endif /* WOLFSSL_KEY_GEN */
-
+/* Write only private ecc key to unencrypted PKCS#8 format.
+ *
+ * If output is NULL, places required PKCS#8 buffer size in outLen and
+ * returns LENGTH_ONLY_E.
+ *
+ * return length on success else < 0 */
+int wc_EccPrivateKeyToPKCS8(ecc_key* key, byte* output, word32* outLen)
+{
+    int ret, tmpDerSz;
+    int algoID = 0;
+    word32 oidSz = 0;
+    word32 pkcs8Sz = 0;
+    const byte* curveOID = NULL;
+    byte* tmpDer = NULL;
+
+    if (key == NULL || outLen == NULL)
+        return BAD_FUNC_ARG;
+
+    /* set algoID, get curve OID */
+    algoID = ECDSAk;
+    ret = wc_ecc_get_oid(key->dp->oidSum, &curveOID, &oidSz);
+    if (ret < 0)
+        return ret;
+
+    /* temp buffer for plain DER key */
+    tmpDer = (byte*)XMALLOC(ECC_BUFSIZE, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (tmpDer == NULL)
+        return MEMORY_E;
+
+    XMEMSET(tmpDer, 0, ECC_BUFSIZE);
+
+    tmpDerSz = wc_BuildEccKeyDer(key, tmpDer, ECC_BUFSIZE, 0);
+    if (tmpDerSz < 0) {
+        XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return tmpDerSz;
+    }
+
+    /* get pkcs8 expected output size */
+    ret = wc_CreatePKCS8Key(NULL, &pkcs8Sz, tmpDer, tmpDerSz, algoID,
+                            curveOID, oidSz);
+    if (ret != LENGTH_ONLY_E) {
+        XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return ret;
+    }
+
+    if (output == NULL) {
+        XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        *outLen = pkcs8Sz;
+        return LENGTH_ONLY_E;
+
+    } else if (*outLen < pkcs8Sz) {
+        XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        WOLFSSL_MSG("Input buffer too small for ECC PKCS#8 key");
+        return BUFFER_E;
+    }
+
+    ret = wc_CreatePKCS8Key(output, &pkcs8Sz, tmpDer, tmpDerSz,
+                            algoID, curveOID, oidSz);
+    if (ret < 0) {
+        XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return ret;
+    }
+
+    XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+
+    *outLen = ret;
+    return ret;
+}
+
+#endif /* HAVE_ECC_KEY_EXPORT && !NO_ASN_CRYPT */
 #endif  /* HAVE_ECC */
 
@@ -10384,6 +13798,5 @@
         return BAD_FUNC_ARG;
 
-    if (GetSequence(input, inOutIdx, &length, inSz) < 0)
-        return ASN_PARSE_E;
+    if (GetSequence(input, inOutIdx, &length, inSz) >= 0) {
     endKeyIdx = *inOutIdx + length;
 
@@ -10405,6 +13818,16 @@
     if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0)
         return ASN_PARSE_E;
+
+        priv = input + *inOutIdx;
+        *inOutIdx += privSz;
+    }
+    else {
+        if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0)
+            return ASN_PARSE_E;
+
     priv = input + *inOutIdx;
     *inOutIdx += privSz;
+        endKeyIdx = *inOutIdx;
+    }
 
     if (endKeyIdx == (int)*inOutIdx) {
@@ -10435,7 +13858,4 @@
     int    length;
     int    ret;
-#ifdef ECC_CHECK_PUBLIC_KEY_OID
-    word32 oidSum;
-#endif
 
     if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0)
@@ -10548,26 +13968,19 @@
                         byte* format, int maxIdx)
 {
-    int    length;
+    int    ret, length;
+    const byte *datePtr = NULL;
 
     WOLFSSL_ENTER("GetBasicDate");
 
-    *format = source[*idx];
-    *idx += 1;
-    if (*format != ASN_UTC_TIME && *format != ASN_GENERALIZED_TIME)
-        return ASN_TIME_E;
-
-    if (GetLength(source, idx, &length, maxIdx) < 0)
-        return ASN_PARSE_E;
-
-    if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE)
-        return ASN_DATE_SZ_E;
-
-    XMEMCPY(date, &source[*idx], length);
-    *idx += length;
+    ret = GetDateInfo(source, idx, &datePtr, format, &length, maxIdx);
+    if (ret < 0)
+        return ret;
+
+    XMEMCPY(date, datePtr, length);
 
     return 0;
 }
 
-#endif
+#endif /* HAVE_OCSP || HAVE_CRL */
 
 
@@ -10667,5 +14080,5 @@
     }
 
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
     cs->thisDateAsn = source + idx;
 #endif
@@ -10688,5 +14101,5 @@
         if (GetLength(source, &idx, &length, size) < 0)
             return ASN_PARSE_E;
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
         cs->nextDateAsn = source + idx;
 #endif
@@ -10937,7 +14350,10 @@
             else {
                 WOLFSSL_MSG("\tOCSP Responder key usage check failed");
-
+    #ifdef OPENSSL_EXTRA
+                resp->verifyError = OCSP_BAD_ISSUER;
+    #else
                 FreeDecodedCert(&cert);
                 return BAD_OCSP_RESPONDER;
+    #endif
             }
         }
@@ -11207,5 +14623,5 @@
 
         if (cert->extAuthInfoSz != 0 && cert->extAuthInfo != NULL) {
-            req->url = (byte*)XMALLOC(cert->extAuthInfoSz, req->heap,
+            req->url = (byte*)XMALLOC(cert->extAuthInfoSz + 1, req->heap,
                                                      DYNAMIC_TYPE_OCSP_REQUEST);
             if (req->url == NULL) {
@@ -11216,4 +14632,5 @@
             XMEMCPY(req->url, cert->extAuthInfo, cert->extAuthInfoSz);
             req->urlSz = cert->extAuthInfoSz;
+            req->url[req->urlSz] = 0;
         }
     }
@@ -11249,7 +14666,9 @@
         if (req->serial)
             XFREE(req->serial, req->heap, DYNAMIC_TYPE_OCSP_REQUEST);
+        req->serial = NULL;
 
         if (req->url)
             XFREE(req->url, req->heap, DYNAMIC_TYPE_OCSP_REQUEST);
+        req->url = NULL;
     }
 }
@@ -11323,5 +14742,5 @@
 }
 
-#endif
+#endif /* HAVE_OCSP */
 
 
@@ -11353,9 +14772,5 @@
         return ASN_PARSE_E;
 
-#ifdef NO_SHA
-    ret = wc_Sha256Hash(source + dummy, length + *idx - dummy, hash);
-#else
-    ret = wc_ShaHash(source + dummy, length + *idx - dummy, hash);
-#endif
+    ret = CalcHashId(source + dummy, length + *idx - dummy, hash);
 
     *idx += length;
@@ -11404,5 +14819,5 @@
                       int maxIdx)
 {
-    int    len;
+    int    ret, len;
     word32 end;
     byte   b;
@@ -11434,19 +14849,10 @@
     dcrl->totalCerts++;
 
-
     /* get date */
-    b = buff[*idx];
-    *idx += 1;
-
-    if (b != ASN_UTC_TIME && b != ASN_GENERALIZED_TIME) {
+    ret = GetDateInfo(buff, idx, NULL, &b, NULL, maxIdx);
+    if (ret < 0) {
         WOLFSSL_MSG("Expecting Date");
-        return ASN_PARSE_E;
-    }
-
-    if (GetLength(buff, idx, &len, maxIdx) < 0)
-        return ASN_PARSE_E;
-
-    /* skip for now */
-    *idx += len;
+        return ret;
+    }
 
     if (*idx != end)  /* skip extensions */
@@ -11610,4 +15016,89 @@
 #endif /* HAVE_CRL */
 
+
+
+#ifdef WOLFSSL_CERT_PIV
+
+int wc_ParseCertPIV(wc_CertPIV* piv, const byte* buf, word32 totalSz)
+{
+    int length = 0;
+    word32 idx = 0;
+
+    WOLFSSL_ENTER("wc_ParseCertPIV");
+
+    if (piv == NULL || buf == NULL || totalSz == 0)
+        return BAD_FUNC_ARG;
+
+    XMEMSET(piv, 0, sizeof(wc_CertPIV));
+
+    /* Detect Identiv PIV (with 0x0A, 0x0B and 0x0C sections) */
+    /* Certificate (0A 82 05FA) */
+    if (GetASNHeader(buf, ASN_PIV_CERT, &idx, &length, totalSz) >= 0) {
+        /* Identiv Type PIV card */
+        piv->isIdentiv = 1;
+
+        piv->cert =   &buf[idx];
+        piv->certSz = length;
+        idx += length;
+
+        /* Nonce (0B 14) */
+        if (GetASNHeader(buf, ASN_PIV_NONCE, &idx, &length, totalSz) >= 0) {
+            piv->nonce =   &buf[idx];
+            piv->nonceSz = length;
+            idx += length;
+        }
+
+        /* Signed Nonce (0C 82 0100) */
+        if (GetASNHeader(buf, ASN_PIV_SIGNED_NONCE, &idx, &length, totalSz) >= 0) {
+            piv->signedNonce =   &buf[idx];
+            piv->signedNonceSz = length;
+            idx += length;
+        }
+
+        idx = 0;
+        buf = piv->cert;
+        totalSz = piv->certSz;
+    }
+
+    /* Certificate Buffer Total Size (53 82 05F6) */
+    if (GetASNHeader(buf, ASN_APPLICATION | ASN_PRINTABLE_STRING, &idx,
+                                                   &length, totalSz) < 0) {
+        return ASN_PARSE_E;
+    }
+    /* PIV Certificate (70 82 05ED) */
+    if (GetASNHeader(buf, ASN_PIV_TAG_CERT, &idx, &length,
+                                                         totalSz) < 0) {
+        return ASN_PARSE_E;
+    }
+
+    /* Capture certificate buffer pointer and length */
+    piv->cert =   &buf[idx];
+    piv->certSz = length;
+    idx += length;
+
+    /* PIV Certificate Info (71 01 00) */
+    if (GetASNHeader(buf, ASN_PIV_TAG_CERT_INFO, &idx, &length,
+                                                        totalSz) >= 0) {
+        if (length >= 1) {
+            piv->compression = (buf[idx] & ASN_PIV_CERT_INFO_COMPRESSED);
+            piv->isX509 =      (buf[idx] & ASN_PIV_CERT_INFO_ISX509);
+        }
+        idx += length;
+    }
+
+    /* PIV Error Detection (FE 00) */
+    if (GetASNHeader(buf, ASN_PIV_TAG_ERR_DET, &idx, &length,
+                                                        totalSz) >= 0) {
+        piv->certErrDet =   &buf[idx];
+        piv->certErrDetSz = length;
+        idx += length;
+    }
+
+    return 0;
+}
+
+#endif /* WOLFSSL_CERT_PIV */
+
+
 #undef ERROR_OUT
 
