int PemToDer(const unsigned char* buff, long longSz, int type,
              DerBuffer** pDer, void* heap, EncryptedInfo* info, int* keyFormat)
{
    const char* header      = NULL;
    const char* footer      = NULL;
    const char* headerEnd;
    const char* footerEnd;
    const char* consumedEnd;
    const char* bufferEnd   = (const char*)(buff + longSz);
    long        neededSz;
    int         ret         = 0;
    int         sz          = (int)longSz;
    int         encrypted_key = 0;
    DerBuffer*  der;
#if defined(HAVE_PKCS8) || defined(WOLFSSL_ENCRYPTED_KEYS)
    word32      algId = 0;
    #if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_DES3) && !defined(NO_WOLFSSL_SKIP_TRAILING_PAD)
        int     padVal = 0;
    #endif
#endif
#ifdef OPENSSL_EXTRA
    char        beginBuf[PEM_LINE_LEN + 1]; /* add 1 for null terminator */
    char        endBuf[PEM_LINE_LEN + 1];   /* add 1 for null terminator */
#endif

    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) {
            break;
        } else
        if (type == PRIVATEKEY_TYPE) {
            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
    #if defined(HAVE_ED25519) || defined(HAVE_ED448)
        #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
            {
                break;
            }
        } else
#ifdef HAVE_CRL
        if ((type == CRL_TYPE) && (header != BEGIN_X509_CRL)) {
            header =  BEGIN_X509_CRL;           footer = END_X509_CRL;
        } else
#endif
        {
            break;
        }
    }

    if (!headerEnd) {
#ifdef OPENSSL_EXTRA
        if (type == PRIVATEKEY_TYPE) {
            const char* beginEnd;
            int endLen;
            /* see if there is a -----BEGIN * PRIVATE KEY----- header */
            headerEnd = XSTRNSTR((char*)buff, PRIV_KEY_SUFFIX, sz);
            if (headerEnd) {
                beginEnd = headerEnd + XSTR_SIZEOF(PRIV_KEY_SUFFIX);
                if (beginEnd >= (char*)buff + sz) {
                    return BUFFER_E;
                }

                /* back up to BEGIN_PRIV_KEY_PREFIX */
                while (headerEnd > (char*)buff &&
                        XSTRNCMP(headerEnd, BEGIN_PRIV_KEY_PREFIX,
                                XSTR_SIZEOF(BEGIN_PRIV_KEY_PREFIX)) != 0 &&
                        *headerEnd != '\n') {
                    headerEnd--;
                }
                if (headerEnd <= (char*)buff ||
                        XSTRNCMP(headerEnd, BEGIN_PRIV_KEY_PREFIX,
                        XSTR_SIZEOF(BEGIN_PRIV_KEY_PREFIX)) != 0 ||
                        beginEnd - headerEnd > PEM_LINE_LEN) {
                    WOLFSSL_MSG("Couldn't find PEM header");
                    WOLFSSL_ERROR(ASN_NO_PEM_HEADER);
                    return ASN_NO_PEM_HEADER;
                }

                /* headerEnd now points to beginning of header */
                XMEMCPY(beginBuf, headerEnd, beginEnd - headerEnd);
                beginBuf[beginEnd - headerEnd] = '\0';
                /* look for matching footer */
                footer = XSTRNSTR(beginEnd,
                                beginBuf + XSTR_SIZEOF(BEGIN_PRIV_KEY_PREFIX),
                                (unsigned int)((char*)buff + sz - beginEnd));
                if (!footer) {
                    WOLFSSL_MSG("Couldn't find PEM footer");
                    WOLFSSL_ERROR(ASN_NO_PEM_HEADER);
                    return ASN_NO_PEM_HEADER;
                }

                footer -= XSTR_SIZEOF(END_PRIV_KEY_PREFIX);
                if (footer > (char*)buff + sz - XSTR_SIZEOF(END_PRIV_KEY_PREFIX)
                        || XSTRNCMP(footer, END_PRIV_KEY_PREFIX,
                            XSTR_SIZEOF(END_PRIV_KEY_PREFIX)) != 0) {
                    WOLFSSL_MSG("Unexpected footer for PEM");
                    return BUFFER_E;
                }

                endLen = (unsigned int)(beginEnd - headerEnd -
                            (XSTR_SIZEOF(BEGIN_PRIV_KEY_PREFIX) -
                                    XSTR_SIZEOF(END_PRIV_KEY_PREFIX)));
                XMEMCPY(endBuf, footer, endLen);
                endBuf[endLen] = '\0';

                header = beginBuf;
                footer = endBuf;
                headerEnd = beginEnd;
            }
        }

        if (!headerEnd) {
            WOLFSSL_MSG("Couldn't find PEM header");
            WOLFSSL_ERROR(ASN_NO_PEM_HEADER);
            return ASN_NO_PEM_HEADER;
        }
#else
        WOLFSSL_MSG("Couldn't find PEM header");
        return ASN_NO_PEM_HEADER;
#endif
    } else {
        headerEnd += XSTRLEN(header);
    }

    /* eat end of line characters */
    headerEnd = SkipEndOfLineChars(headerEnd, bufferEnd);

    if (type == PRIVATEKEY_TYPE) {
        /* keyFormat is Key_Sum enum */
        if (keyFormat) {
        #ifdef HAVE_ECC
            if (header == BEGIN_EC_PRIV)
                *keyFormat = ECDSAk;
        #endif
        #if !defined(NO_DSA)
            if (header == BEGIN_DSA_PRIV)
                *keyFormat = DSAk;
        #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(headerEnd, footer, (unsigned int)((char*)buff + sz - headerEnd));
    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 - (const 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 OPENSSL_EXTRA
         || header == beginBuf
#endif
#ifdef HAVE_ECC
         || header == BEGIN_EC_PRIV
#endif
        ) && !encrypted_key)
    {
    #ifdef HAVE_PKCS8
        /* pkcs8 key, convert and adjust length */
        if ((ret = ToTraditional_ex(der->buffer, der->length, &algId)) > 0) {
            der->length = ret;
            if (keyFormat) {
                *keyFormat = algId;
            }
        }
        else {
            /* ignore failure here and assume key is not pkcs8 wrapped */
        }
    #endif

        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 (keyFormat) {
                        *keyFormat = algId;
                    }
                    ret = 0;
                }
            #else
                ret = NOT_COMPILED_IN;
            #endif
            }
            /* decrypt the key */
            else {
                if (passwordSz == 0) {
                    /* The key is encrypted but does not have a password */
                    WOLFSSL_MSG("No password for encrypted key");
                    ret = NO_PASSWORD;
                }
                else {
                    ret = wc_BufferKeyDecrypt(info, der->buffer, der->length,
                        (byte*)password, passwordSz, WC_MD5);

#ifndef NO_WOLFSSL_SKIP_TRAILING_PAD
                #ifndef NO_DES3
                    if (info->cipherType == WC_CIPHER_DES3) {
                        /* Assuming there is padding:
                         *      (der->length > 0 && der->length > DES_BLOCK_SIZE &&
                         *       (der->length % DES_BLOCK_SIZE) != 0)
                         * and assuming the last value signifies the number of
                         * padded bytes IE if last value is 0x08 then there are
                         * 8 bytes of padding:
                         *      padVal = der->buffer[der->length-1];
                         * then strip this padding before proceeding:
                         * der->length -= padVal;
                         */
                        if (der->length > DES_BLOCK_SIZE &&
                            (der->length % DES_BLOCK_SIZE) != 0) {
                            padVal = der->buffer[der->length-1];
                            if (padVal < DES_BLOCK_SIZE) {
                                der->length -= padVal;
                            }
                        }
                    }
                #endif /* !NO_DES3 */
#endif /* !NO_WOLFSSL_SKIP_TRAILING_PAD */
                }
            }
#ifdef OPENSSL_EXTRA
            if (ret) {
                PEMerr(0, PEM_R_BAD_DECRYPT);
            }
#endif
            ForceZero(password, passwordSz);
        }
#ifdef OPENSSL_EXTRA
        else {
            PEMerr(0, PEM_R_BAD_PASSWORD_READ);
        }
#endif

    #ifdef WOLFSSL_SMALL_STACK
        XFREE(password, heap, DYNAMIC_TYPE_STRING);
    #endif
    }
#endif /* WOLFSSL_ENCRYPTED_KEYS */

    return ret;
}