/* ssl_load.c
 *
 * Copyright (C) 2006-2026 wolfSSL Inc.
 *
 * This file is part of wolfSSL.
 *
 * wolfSSL is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * wolfSSL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
 */

#include <wolfssl/wolfcrypt/libwolfssl_sources.h>

/*
 * WOLFSSL_SYS_CA_CERTS
 *     Enables ability to load system CA certs from the OS via
 *     wolfSSL_CTX_load_system_CA_certs.
 */

#ifdef WOLFSSL_SYS_CA_CERTS
/* Will be turned off automatically when NO_FILESYSTEM is defined
 * for non Mac/Windows systems */

#ifdef _WIN32
    #define _WINSOCKAPI_ /* block inclusion of winsock.h header file */
    #include <windows.h>
    #include <wincrypt.h>
    #undef _WINSOCKAPI_ /* undefine it for MINGW winsock2.h header file */

    /* mingw gcc does not support pragma comment, and the
     * linking with crypt32 is handled in configure.ac */
    #if !defined(__MINGW32__) && !defined(__MINGW64__)
        #pragma comment(lib, "crypt32")
    #endif
#endif

#if defined(__APPLE__)
#if defined(HAVE_SECURITY_SECTRUSTSETTINGS_H)
#include <Security/SecTrustSettings.h>
#endif /* HAVE_SECURITY_SECTRUSTSETTINGS_H */
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
#include <CoreFoundation/CoreFoundation.h>
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
#endif /* __APPLE__ */

#endif /* WOLFSSL_SYS_CA_CERTS */

#if !defined(WOLFSSL_SSL_LOAD_INCLUDED)
    #ifndef WOLFSSL_IGNORE_FILE_WARN
        #warning ssl_load.c does not need to be compiled separately from ssl.c
    #endif
#else

#include <wolfssl/wolfcrypt/logging.h>

#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
    /* PSK field of context when it exists. */
    #define CTX_HAVE_PSK(ctx)   (ctx)->havePSK
    /* PSK field of ssl when it exists. */
    #define SSL_HAVE_PSK(ssl)   (ssl)->options.havePSK
#else
    /* Have PSK value when no field. */
    #define CTX_HAVE_PSK(ctx)   0
    /* Have PSK value when no field. */
    #define SSL_HAVE_PSK(ssl)   0
#endif
#ifdef NO_RSA
    /* Boolean for RSA available. */
    #define WOLFSSL_HAVE_RSA    0
#else
    /* Boolean for RSA available. */
    #define WOLFSSL_HAVE_RSA    1
#endif
#ifndef NO_CERTS
    /* Private key size from ssl. */
    #define SSL_KEY_SZ(ssl)     (ssl)->buffers.keySz
#else
    /* Private key size not available. */
    #define SSL_KEY_SZ(ssl)     0
#endif
#ifdef HAVE_ANON
    /* Anonymous ciphersuite allowed field in context. */
    #define CTX_USE_ANON(ctx)   (ctx)->useAnon
#else
    /* Anonymous ciphersuite allowed field not in context. */
    #define CTX_USE_ANON(ctx)   0
#endif

#ifdef HAVE_PK_CALLBACKS
    #define WOLFSSL_IS_PRIV_PK_SET(ctx, ssl)                            \
        wolfSSL_CTX_IsPrivatePkSet(((ssl) == NULL) ? (ctx) : (ssl)->ctx)
#else
    #define WOLFSSL_IS_PRIV_PK_SET(ctx, ssl)    0
#endif

/* Get the heap from the context or the ssl depending on which is available. */
#define WOLFSSL_HEAP(ctx, ssl)                                              \
    (((ctx) != NULL) ? (ctx)->heap : (((ssl) != NULL) ? (ssl)->heap : NULL))


#ifndef NO_CERTS

/* Get DER encoding from data in a buffer as a DerBuffer.
 *
 * @param [in]      buff    Buffer containing data.
 * @param [in]      len     Length of data in buffer.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @param [in]      type    Type of data:
 *                            CERT_TYPE, CA_TYPE, TRUSTED_PEER_TYPE,
 *                            PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE.
 * @param [in, out] info    Info for encryption.
 * @param [in]      heap    Dynamic memory allocation hint.
 * @param [out]     der     Holds DER encoded data.
 * @param [out]     algId   Algorithm identifier for private keys.
 * @return  0 on success.
 * @return  NOT_COMPILED_IN when format is PEM and PEM not supported.
 * @return  ASN_PARSE_E when format is ASN.1 and invalid DER encoding.
 * @return  MEMORY_E when dynamic memory allocation fails.
 */
static int DataToDerBuffer(const unsigned char* buff, word32 len, int format,
    int type, EncryptedInfo* info, void* heap, DerBuffer** der, int* algId)
{
    int ret;

    info->consumed = 0;

    /* Data in buffer has PEM format - extract DER data. */
    if (format == WOLFSSL_FILETYPE_PEM) {
    #ifdef WOLFSSL_PEM_TO_DER
        ret = PemToDer(buff, (long)(len), type, der, heap, info, algId);
        if (ret != 0) {
            FreeDer(der);
        }
    #else
        (void)algId;
        ret = NOT_COMPILED_IN;
    #endif
    }
    /* Data in buffer is ASN.1 format - get first SEQ or OCT into der. */
    else {
        /* Get length of SEQ including header. */
        if ((info->consumed = wolfssl_der_length(buff, (int)len)) > 0) {
            ret = 0;
        }
        else {
            ret = ASN_PARSE_E;
        }

        if (info->consumed > (int)len) {
            ret = ASN_PARSE_E;
        }
        if (ret == 0) {
            ret = AllocCopyDer(der, buff, (word32)info->consumed, type, heap);
        }
    }

    return ret;
}

/* Process a user's certificate.
 *
 * Puts the 3-byte length before certificate data as required for TLS.
 * CA certificates are added to the certificate manager.
 *
 * @param [in]      cm           Certificate manager.
 * @param [in, out] pDer         DER encoded data.
 * @param [in]      type         Type of data. Valid values:
 *                                 CERT_TYPE, CA_TYPE or TRUSTED_PEER_TYPE.
 * @param [in]      verify       How to verify certificate.
 * @param [out]     chainBuffer  Buffer to hold chain of certificates.
 * @param [in, out] pIdx         On in, current index into chainBuffer.
 *                               On out, index after certificate added.
 * @param [in]      bufferSz     Size of buffer in bytes.
 * @return  0 on success.
 * @return  BUFFER_E if chain buffer not big enough to hold certificate.
 */
static int ProcessUserCert(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer,
    int type, int verify, byte* chainBuffer, word32* pIdx, word32 bufferSz)
{
    int ret = 0;
    word32 idx = *pIdx;
    DerBuffer* der = *pDer;

    /* Check there is space for certificate in chainBuffer. */
    if ((ret == 0) && ((idx + der->length + CERT_HEADER_SZ) > bufferSz)) {
        WOLFSSL_MSG("   Cert Chain bigger than buffer. "
                    "Consider increasing MAX_CHAIN_DEPTH");
        ret = BUFFER_E;
    }
    if (ret == 0) {
        /* 3-byte length. */
        c32to24(der->length, &chainBuffer[idx]);
        idx += CERT_HEADER_SZ;
        /* Add complete DER encoded certificate. */
        XMEMCPY(&chainBuffer[idx], der->buffer, der->length);
        idx += der->length;

        if (type == CA_TYPE) {
            /* Add CA to certificate manager */
            ret = AddCA(cm, pDer, WOLFSSL_USER_CA, verify);
            if (ret == 1) {
                ret = 0;
            }
        }
    }

    /* Update the index into chainBuffer. */
    *pIdx = idx;
    return ret;
}

/* Store the certificate chain buffer aganst WOLFSSL_CTX or WOLFSSL object.
 *
 * @param [in, out] ctx          SSL context object.
 * @param [in, out] ssl          SSL object.
 * @param [in]      chainBuffer  Buffer containing chain of certificates.
 * @param [in]      len          Length, in bytes, of data in buffer.
 * @param [in]      cnt          Number of certificates in chain.
 * @param [in]      type         Type of data. Valid values:
 *                                 CERT_TYPE, CA_TYPE or CHAIN_CERT_TYPE.
 * @param [in]      heap         Dynamic memory allocation hint.
 * @return  0 on success.
 * @return  MEMORY_E when dynamic memory allocation fails.
 */
static int ProcessUserChainRetain(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    const byte* chainBuffer, word32 len, int cnt, int type, void* heap)
{
    int ret = 0;

    (void)cnt;

    /* Store in SSL object if available. */
    if (ssl != NULL) {
        /* Dispose of old chain if not reference to context's. */
        if (ssl->buffers.weOwnCertChain) {
            FreeDer(&ssl->buffers.certChain);
        }
        /* Allocate and copy the buffer into SSL object. */
        ret = AllocCopyDer(&ssl->buffers.certChain, chainBuffer, len, type,
            heap);
        ssl->buffers.weOwnCertChain = (ret == 0);
        /* Update count of certificates in chain. */
        ssl->buffers.certChainCnt = cnt;
    }
    /* Store in SSL context object if available. */
    else if (ctx != NULL) {
        /* Dispose of old chain and allocate and copy in new chain. */
        FreeDer(&ctx->certChain);
        /* Allocate and copy the buffer into SSL context object. */
        ret = AllocCopyDer(&ctx->certChain, chainBuffer, len, type, heap);
        /* Update count of certificates in chain. */
        ctx->certChainCnt = cnt;
    }

    return ret;
}

/* Process user cert chain to pass during the TLS handshake.
 *
 * If not a certificate type then data is ignored.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in, out] ssl     SSL object.
 * @param [in]      buff    Buffer holding certificates.
 * @param [in]      sz      Length of data in buffer.
 * @param [in]      format  Format of the certificate:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1
 * @param [in]      type    Type of certificate:
 *                            CA_TYPE, CERT_TYPE or CHAIN_CERT_TYPE
 * @param [out]     used    Number of bytes from buff used.
 * @param [in, out] info    Encryption information.
 * @param [in]      verify  How to verify certificate.
 * @return  0 on success.
 * @return  BAD_FUNC_ARG when type is CA_TYPE and ctx is NULL.
 * @return  MEMORY_E when dynamic memory allocation fails.
 */
static int ProcessUserChain(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    const unsigned char* buff, long sz, int format, int type, long* used,
    EncryptedInfo* info, int verify)
{
    int ret = 0;
    void* heap = WOLFSSL_HEAP(ctx, ssl);

    WOLFSSL_ENTER("ProcessUserChain");

    /* Check we haven't consumed all the data. */
    if (info->consumed >= sz) {
        WOLFSSL_MSG("Already consumed data");
    }
    else {
    #ifndef WOLFSSL_SMALL_STACK
        byte stackBuffer[FILE_BUFFER_SIZE];
    #endif
        StaticBuffer chain;
        long   consumed = info->consumed;
        word32 idx = 0;
        int    gotOne = 0;
        int    cnt = 0;
        /* Calculate max possible size, including max headers */
        long   maxSz = (sz - consumed) + (CERT_HEADER_SZ * MAX_CHAIN_DEPTH);

        /* Setup buffer to hold chain. */
    #ifdef WOLFSSL_SMALL_STACK
        static_buffer_init(&chain);
    #else
        static_buffer_init(&chain, stackBuffer, FILE_BUFFER_SIZE);
    #endif
        /* Make buffer big enough to support maximum size. */
        ret = static_buffer_set_size(&chain, (word32)maxSz, heap,
            DYNAMIC_TYPE_FILE);

        WOLFSSL_MSG("Processing Cert Chain");
        /* Keep parsing certificates will data available. */
        while ((ret == 0) && (consumed < sz)) {
            DerBuffer* part = NULL;

            /* Get a certificate as DER. */
            ret = DataToDerBuffer(buff + consumed, (word32)(sz - consumed),
                format, type, info, heap, &part, NULL);
            if (ret == 0) {
                /* Process the user certificate. */
                ret = ProcessUserCert(ctx->cm, &part, type, verify,
                   chain.buffer, &idx, (word32)maxSz);
            }
            /* PEM may have trailing data that can be ignored. */
            if ((ret == WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER)) && gotOne) {
                WOLFSSL_MSG("We got one good cert, so stuff at end ok");
                ret = 0;
                break;
            }
            /* Certificate data handled. */
            FreeDer(&part);

            if (ret == 0) {
                /* Update consumed length. */
                consumed += info->consumed;
                WOLFSSL_MSG("   Consumed another Cert in Chain");
                /* Update whether we got a user certificate. */
                gotOne |= (type != CA_TYPE);
                /* Update count of certificates added to chain. */
                cnt++;
            }
        }
        if (used != NULL) {
            /* Return the total consumed length. */
            *used = consumed;
        }

        /* Check whether there is data in the chain buffer. */
        if ((ret == 0) && (idx > 0)) {
            /* Put the chain buffer against the SSL or SSL context object. */
            ret = ProcessUserChainRetain(ctx, ssl, chain.buffer, idx, cnt, type,
                heap);
        }

        /* Dispose of chain buffer. */
        static_buffer_free(&chain, heap, DYNAMIC_TYPE_FILE);
    }

    WOLFSSL_LEAVE("ProcessUserChain", ret);
    return ret;
}

#ifndef NO_RSA
#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
    (HAVE_FIPS_VERSION > 2))
/* See if DER data is an RSA private key.
 *
 * Checks size meets minimum RSA key size.
 * This implementation uses less dynamic memory.
 *
 * @param [in, out] ctx        SSL context object.
 * @param [in, out] ssl        SSL object.
 * @param [in]      der        DER encoding.
 * @param [in, out] keyFormat  On in, expected format. 0 means unknown.
 * @param [in]      devId      Device identifier.
 * @param [out]     keyType    Type of key.
 * @param [out]     keySize    Size of key.
 * @return  0 on success or not an RSA key and format unknown.
 * @return  RSA_KEY_SIZE_E when key size doesn't meet minimum required.
 */
static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DerBuffer* der, int* keyFormat, int devId, byte* keyType, int* keySize)
{
    int ret;
    word32 idx;
    int keySz = 0;

    (void)devId;

    /* Validate we have an RSA private key and get key size. */
    idx = 0;
    ret = wc_RsaPrivateKeyValidate(der->buffer, &idx, &keySz, der->length);
#ifdef WOLF_PRIVATE_KEY_ID
    /* If that didn't work then maybe a public key if device ID or callback. */
    if ((ret != 0) && ((devId != INVALID_DEVID) ||
            WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
        word32 nSz;

        /* Decode as an RSA public key. */
        idx = 0;
        ret = wc_RsaPublicKeyDecode_ex(der->buffer, &idx, der->length, NULL,
            &nSz, NULL, NULL);
        if (ret == 0) {
            keySz = (int)nSz;
        }
    }
#endif
    if (ret == 0) {
        /* Get the minimum RSA key size from SSL or SSL context object. */
        int minRsaSz = ssl ? ssl->options.minRsaKeySz : ctx->minRsaKeySz;

        /* Format, type and size are known. */
        *keyFormat = RSAk;
        *keyType = rsa_sa_algo;
        *keySize = keySz;

        /* Check that the size of the RSA key is enough. */
        if (keySz < minRsaSz) {
            WOLFSSL_MSG("Private Key size too small");
            ret = RSA_KEY_SIZE_E;
        }
         /* No static ECC key possible. */
        if ((ssl != NULL) && (ssl->options.side == WOLFSSL_SERVER_END)) {
             ssl->options.haveStaticECC = 0;
        }
    }
    /* Not an RSA key but check whether we know what it is. */
    else if (*keyFormat == 0) {
        WOLFSSL_MSG("Not an RSA key");
        /* Format unknown so keep trying. */
        ret = 0;
    }

    return ret;
}
#else
/* See if DER data is an RSA private key.
 *
 * Checks size meets minimum RSA key size.
 * This implementation uses more dynamic memory but supports older FIPS.
 *
 * @param [in, out] ctx        SSL context object.
 * @param [in, out] ssl        SSL object.
 * @param [in]      der        DER encoding.
 * @param [in, out] keyFormat  On in, expected format. 0 means unknown.
 * @param [in]      heap       Dynamic memory allocation hint.
 * @param [in]      devId      Device identifier.
 * @param [out]     keyType    Type of key.
 * @param [out]     keySize    Size of key.
 * @return  0 on success or not an RSA key and format unknown.
 * @return  RSA_KEY_SIZE_E when key size doesn't meet minimum required.
 */
static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType,
    int* keySize)
{
    int ret;
    word32 idx;
    /* make sure RSA key can be used */
    WC_DECLARE_VAR(key, RsaKey, 1, 0);

    /* Allocate an RSA key to parse into so we can get size. */
    WC_ALLOC_VAR_EX(key, RsaKey, 1, heap, DYNAMIC_TYPE_RSA,
        return MEMORY_E);

    /* Initialize the RSA key. */
    ret = wc_InitRsaKey_ex(key, heap, devId);
    if (ret == 0) {
        /* Check we have an RSA private key. */
        idx = 0;
        ret = wc_RsaPrivateKeyDecode(der->buffer, &idx, key, der->length);
    #ifdef WOLF_PRIVATE_KEY_ID
        /* If that didn't work then maybe a public key if device ID or callback.
         */
        if ((ret != 0) && ((devId != INVALID_DEVID) ||
                WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
            /* If that didn't work then maybe a public key if device ID or
             * callback. */
            idx = 0;
            ret = wc_RsaPublicKeyDecode(der->buffer, &idx, key, der->length);
        }
    #endif
        if (ret == 0) {
            /* Get the minimum RSA key size from SSL or SSL context object. */
            int minRsaSz = ssl ? ssl->options.minRsaKeySz : ctx->minRsaKeySz;
            int keySz = wc_RsaEncryptSize((RsaKey*)key);

            /* Format is known. */
            *keyFormat = RSAk;
            *keyType = rsa_sa_algo;
            *keySize = keySz;

            /* Check that the size of the RSA key is enough. */
            if (keySz < minRsaSz) {
                WOLFSSL_MSG("Private Key size too small");
                ret = RSA_KEY_SIZE_E;
            }
            /* No static ECC key possible. */
            if ((ssl != NULL) && (ssl->options.side == WOLFSSL_SERVER_END)) {
                 ssl->options.haveStaticECC = 0;
            }
        }
        /* Not an RSA key but check whether we know what it is. */
        else if (*keyFormat == 0) {
            WOLFSSL_MSG("Not an RSA key");
            /* Format unknown so keep trying. */
            ret = 0;
        }

        /* Free dynamically allocated data in key. */
        wc_FreeRsaKey(key);
    }

    WC_FREE_VAR_EX(key, heap, DYNAMIC_TYPE_RSA);

    return ret;
}
#endif
#endif /* !NO_RSA */

#ifdef HAVE_ECC
/* See if DER data is an ECC private key.
 *
 * Checks size meets minimum ECC key size.
 *
 * @param [in, out] ctx        SSL context object.
 * @param [in, out] ssl        SSL object.
 * @param [in]      der        DER encoding.
 * @param [in, out] keyFormat  On in, expected format. 0 means unknown.
 * @param [in]      heap       Dynamic memory allocation hint.
 * @param [in]      devId      Device identifier.
 * @param [out]     keyType    Type of key.
 * @param [out]     keySize    Size of key.
 * @return  0 on success or not an ECC key and format unknown.
 * @return  ECC_KEY_SIZE_E when ECC key size doesn't meet minimum required.
 */
static int ProcessBufferTryDecodeEcc(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType,
    int* keySize)
{
    int ret = 0;
    word32 idx;
    /* make sure ECC key can be used */
    WC_DECLARE_VAR(key, ecc_key, 1, 0);

    /* Allocate an ECC key to parse into. */
    WC_ALLOC_VAR_EX(key, ecc_key, 1, heap, DYNAMIC_TYPE_ECC,
        return MEMORY_E);

    /* Initialize ECC key. */
    if (wc_ecc_init_ex(key, heap, devId) == 0) {
        /* Decode as an ECC private key. */
        idx = 0;
        ret = wc_EccPrivateKeyDecode(der->buffer, &idx, key, der->length);
    #ifdef WOLF_PRIVATE_KEY_ID
        /* If that didn't work then maybe a public key if device ID or callback.
         */
        if ((ret != 0) && ((devId != INVALID_DEVID) ||
                WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
            /* Decode as an ECC public key. */
            idx = 0;
            ret = wc_EccPublicKeyDecode(der->buffer, &idx, key, der->length);
        }
    #endif
    #ifdef WOLFSSL_SM2
        if (*keyFormat == SM2k) {
            ret = wc_ecc_set_curve(key, WOLFSSL_SM2_KEY_BITS / 8,
                ECC_SM2P256V1);
        }
    #endif
        if (ret == 0) {
            /* Get the minimum ECC key size from SSL or SSL context object. */
            int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz;
            int keySz = wc_ecc_size(key);

            /* Format is known. */
            *keyFormat = ECDSAk;
        #ifdef WOLFSSL_SM2
            if (key->dp->id == ECC_SM2P256V1) {
                *keyType = sm2_sa_algo;
            }
            else
        #endif
            {
                *keyType = ecc_dsa_sa_algo;
            }
            *keySize = keySz;

            /* Check that the size of the ECC key is enough. */
            if (keySz < minKeySz) {
                WOLFSSL_MSG("ECC private key too small");
                ret = ECC_KEY_SIZE_E;
            }
            /* Static ECC key possible. */
            if (ssl) {
                ssl->options.haveStaticECC = 1;
            }
            else {
                ctx->haveStaticECC = 1;
            }
        }
        /* Not an ECC key but check whether we know what it is. */
        else if (*keyFormat == 0) {
            WOLFSSL_MSG("Not an ECC key");
            /* Format unknown so keep trying. */
            ret = 0;
        }

        /* Free dynamically allocated data in key. */
        wc_ecc_free(key);
    }

    WC_FREE_VAR_EX(key, heap, DYNAMIC_TYPE_ECC);
    return ret;
}
#endif /* HAVE_ECC */

#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT)
/* See if DER data is an Ed25519 private key.
 *
 * Checks size meets minimum ECC key size.
 *
 * @param [in, out] ctx        SSL context object.
 * @param [in, out] ssl        SSL object.
 * @param [in]      der        DER encoding.
 * @param [in, out] keyFormat  On in, expected format. 0 means unknown.
 * @param [in]      heap       Dynamic memory allocation hint.
 * @param [in]      devId      Device identifier.
 * @param [out]     keyType    Type of key.
 * @param [out]     keySize    Size of key.
 * @return  0 on success or not an Ed25519 key and format unknown.
 * @return  ECC_KEY_SIZE_E when key size doesn't meet minimum required.
 */
static int ProcessBufferTryDecodeEd25519(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType,
    int* keySize)
{
    int ret;
    word32 idx;
    /* make sure Ed25519 key can be used */
    WC_DECLARE_VAR(key, ed25519_key, 1, 0);

    /* Allocate an Ed25519 key to parse into. */
    WC_ALLOC_VAR_EX(key, ed25519_key, 1, heap, DYNAMIC_TYPE_ED25519,
        return MEMORY_E);

    /* Initialize Ed25519 key. */
    ret = wc_ed25519_init_ex(key, heap, devId);
    if (ret == 0) {
        /* Decode as an Ed25519 private key. */
        idx = 0;
        ret = wc_Ed25519PrivateKeyDecode(der->buffer, &idx, key, der->length);
    #ifdef WOLF_PRIVATE_KEY_ID
        /* If that didn't work then maybe a public key if device ID or callback.
         */
        if ((ret != 0) && ((devId != INVALID_DEVID) ||
                WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
            /* Decode as an Ed25519 public key. */
            idx = 0;
            ret = wc_Ed25519PublicKeyDecode(der->buffer, &idx, key,
                der->length);
        }
    #endif
        if (ret == 0) {
            /* Get the minimum ECC key size from SSL or SSL context object. */
            int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz;

            /* Format is known. */
            *keyFormat = ED25519k;
            *keyType = ed25519_sa_algo;
            *keySize = ED25519_KEY_SIZE;

            /* Check that the size of the ECC key is enough. */
            if (ED25519_KEY_SIZE < minKeySz) {
                WOLFSSL_MSG("ED25519 private key too small");
                ret = ECC_KEY_SIZE_E;
            }
            if (ssl != NULL) {
#if !defined(WOLFSSL_NO_CLIENT_AUTH) && !defined(NO_ED25519_CLIENT_AUTH)
                /* Ed25519 requires caching enabled for tracking message
                 * hash used in EdDSA_Update for signing */
                ssl->options.cacheMessages = 1;
#endif
            }
        }
        /* Not an Ed25519 key but check whether we know what it is. */
        else if (*keyFormat == 0) {
            WOLFSSL_MSG("Not an Ed25519 key");
            /* Format unknown so keep trying. */
            ret = 0;
        }

        /* Free dynamically allocated data in key. */
        wc_ed25519_free(key);
    }

    WC_FREE_VAR_EX(key, heap, DYNAMIC_TYPE_ED25519);
    return ret;
}
#endif /* HAVE_ED25519 && HAVE_ED25519_KEY_IMPORT */

#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
/* See if DER data is an Ed448 private key.
 *
 * Checks size meets minimum ECC key size.
 *
 * @param [in, out] ctx        SSL context object.
 * @param [in, out] ssl        SSL object.
 * @param [in]      der        DER encoding.
 * @param [in, out] keyFormat  On in, expected format. 0 means unknown.
 * @param [in]      heap       Dynamic memory allocation hint.
 * @param [in]      devId      Device identifier.
 * @param [out]     keyType    Type of key.
 * @param [out]     keySize    Size of key.
 * @return  0 on success or not an Ed448 key and format unknown.
 * @return  ECC_KEY_SIZE_E when key size doesn't meet minimum required.
 */
static int ProcessBufferTryDecodeEd448(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType,
    int* keySize)
{
    int ret;
    word32 idx;
    /* make sure Ed448 key can be used */
    WC_DECLARE_VAR(key, ed448_key, 1, 0);

    /* Allocate an Ed448 key to parse into. */
    WC_ALLOC_VAR_EX(key, ed448_key, 1, heap, DYNAMIC_TYPE_ED448,
        return MEMORY_E);

    /* Initialize Ed448 key. */
    ret = wc_ed448_init_ex(key, heap, devId);
    if (ret == 0) {
        /* Decode as an Ed448 private key. */
        idx = 0;
        ret = wc_Ed448PrivateKeyDecode(der->buffer, &idx, key, der->length);
    #ifdef WOLF_PRIVATE_KEY_ID
        /* If that didn't work then maybe a public key if device ID or callback.
         */
        if ((ret != 0) && ((devId != INVALID_DEVID) ||
                WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
            /* Decode as an Ed448 public key. */
            idx = 0;
            ret = wc_Ed448PublicKeyDecode(der->buffer, &idx, key, der->length);
        }
    #endif
        if (ret == 0) {
            /* Get the minimum ECC key size from SSL or SSL context object. */
            int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz;

            /* Format is known. */
            *keyFormat = ED448k;
            *keyType = ed448_sa_algo;
            *keySize = ED448_KEY_SIZE;

            /* Check that the size of the ECC key is enough. */
            if (ED448_KEY_SIZE < minKeySz) {
                WOLFSSL_MSG("ED448 private key too small");
                ret = ECC_KEY_SIZE_E;
            }
        #if !defined(WOLFSSL_NO_CLIENT_AUTH) && !defined(NO_ED448_CLIENT_AUTH)
            if (ssl != NULL) {
                /* Ed448 requires caching enabled for tracking message
                 * hash used in EdDSA_Update for signing */
                ssl->options.cacheMessages = 1;
            }
        #endif
        }
        /* Not an Ed448 key but check whether we know what it is. */
        else if (*keyFormat == 0) {
            WOLFSSL_MSG("Not an Ed448 key");
            /* Format unknown so keep trying. */
            ret = 0;
        }

        /* Free dynamically allocated data in key. */
        wc_ed448_free(key);
    }

    WC_FREE_VAR_EX(key, heap, DYNAMIC_TYPE_ED448);
    return ret;
}
#endif /* HAVE_ED448 && HAVE_ED448_KEY_IMPORT */

#if defined(HAVE_FALCON)
/* See if DER data is an Falcon private key.
 *
 * Checks size meets minimum Falcon key size.
 *
 * @param [in, out] ctx        SSL context object.
 * @param [in, out] ssl        SSL object.
 * @param [in]      der        DER encoding.
 * @param [in, out] keyFormat  On in, expected format. 0 means unknown.
 * @param [in]      heap       Dynamic memory allocation hint.
 * @param [in]      devId      Device identifier.
 * @param [out]     keyType    Type of key.
 * @param [out]     keySize    Size of key.
 * @return  0 on success or not an Falcon key and format unknown.
 * @return  FALCON_KEY_SIZE_E when key size doesn't meet minimum required.
 */
static int ProcessBufferTryDecodeFalcon(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DerBuffer* der, int* keyFormat, void* heap, byte* keyType, int* keySize)
{
    int ret;
    falcon_key* key;

    /* Allocate a Falcon key to parse into. */
    key = (falcon_key*)XMALLOC(sizeof(falcon_key), heap, DYNAMIC_TYPE_FALCON);
    if (key == NULL) {
        return MEMORY_E;
    }

    /* Initialize Falcon key. */
    ret = wc_falcon_init(key);
    if (ret == 0) {
        byte level = 0;
        word32 idx;

        if (*keyFormat == FALCON_LEVEL1k) {
            level = 1;
        }
        else if (*keyFormat == FALCON_LEVEL5k) {
            level = 5;
        }

        if (level != 0) {
            /* Caller told us the level via the OID sum. */
            ret = wc_falcon_set_level(key, level);
            if (ret == 0) {
                idx = 0;
                ret = wc_Falcon_PrivateKeyDecode(der->buffer, &idx, key,
                                                  der->length);
            }
        }
        else if (*keyFormat == 0) {
            /* Key format unknown. Try both levels; the expected OID inside
             * wc_Falcon_PrivateKeyDecode rejects non-matching DER. Re-init
             * between attempts so a partial first decode can't leave stale
             * bytes in key->k / key->p. */
            idx = 0;
            if (wc_falcon_set_level(key, 1) == 0 &&
                wc_Falcon_PrivateKeyDecode(der->buffer, &idx, key,
                                           der->length) == 0) {
                level = 1;
            }
            else {
                wc_falcon_free(key);
                if (wc_falcon_init(key) != 0) {
                    XFREE(key, heap, DYNAMIC_TYPE_FALCON);
                    return MEMORY_E;
                }
                idx = 0;
                if (wc_falcon_set_level(key, 5) == 0 &&
                    wc_Falcon_PrivateKeyDecode(der->buffer, &idx, key,
                                               der->length) == 0) {
                    level = 5;
                }
            }
            if (level == 0) {
                /* Not a Falcon key; let caller try another algorithm. */
                WOLFSSL_MSG("Not a Falcon key");
                wc_falcon_free(key);
                XFREE(key, heap, DYNAMIC_TYPE_FALCON);
                return 0;
            }
            ret = 0;
        }
        else {
            wc_falcon_free(key);
            ret = ALGO_ID_E;
        }
    }

    if (ret == 0) {
        /* Get the minimum Falcon key size from SSL or SSL context object. */
        int minKeySz = ssl ? ssl->options.minFalconKeySz :
                             ctx->minFalconKeySz;

        if (key->level == 1) {
            *keyFormat = FALCON_LEVEL1k;
            *keyType = falcon_level1_sa_algo;
            *keySize = FALCON_LEVEL1_KEY_SIZE;
        }
        else {
            *keyFormat = FALCON_LEVEL5k;
            *keyType = falcon_level5_sa_algo;
            *keySize = FALCON_LEVEL5_KEY_SIZE;
        }

        /* Check that the size of the Falcon key is enough. */
        if (*keySize < minKeySz) {
            WOLFSSL_MSG("Falcon private key too small");
            ret = FALCON_KEY_SIZE_E;
        }

        wc_falcon_free(key);
    }
    else if ((ret == WC_NO_ERR_TRACE(ALGO_ID_E)) && (*keyFormat == 0)) {
        WOLFSSL_MSG("Not a Falcon key");
        /* Format unknown so keep trying. */
        ret = 0;
    }

    /* Dispose of allocated key. */
    XFREE(key, heap, DYNAMIC_TYPE_FALCON);
    return ret;
}
#endif

#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_MLDSA_NO_SIGN) && \
    !defined(WOLFSSL_MLDSA_NO_ASN1)
/* See if DER data is an Dilithium private key.
 *
 * Checks size meets minimum Falcon key size.
 *
 * @param [in, out] ctx        SSL context object.
 * @param [in, out] ssl        SSL object.
 * @param [in]      der        DER encoding.
 * @param [in, out] keyFormat  On in, expected format. 0 means unknown.
 * @param [in]      heap       Dynamic memory allocation hint.
 * @param [in]      devId      Device identifier.
 * @param [out]     keyType    Type of key.
 * @param [out]     keySize    Size of key.
 * @return  0 on success or not a Dilithium key and format unknown.
 * @return  MLDSA_KEY_SIZE_E when key size doesn't meet minimum required.
 */
static int ProcessBufferTryDecodeMlDsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DerBuffer* der, int* keyFormat, void* heap, byte* keyType, int* keySize)
{
    int ret;
    word32 idx;
    wc_MlDsaKey* key;
    int keyFormatTemp = 0;
    int keyTypeTemp = 0;
    int keySizeTemp = 0;

    /* Allocate a Dilithium key to parse into. */
    key = (wc_MlDsaKey*)XMALLOC(sizeof(wc_MlDsaKey), heap,
        DYNAMIC_TYPE_MLDSA);
    if (key == NULL) {
        return MEMORY_E;
    }

    /* Initialize ML-DSA key. */
    ret = wc_MlDsaKey_Init(key, NULL, INVALID_DEVID);
    if (ret == 0) {
        /* Decode as an ML-DSA private key. The FIPS wrapper for
         * wc_MlDsaKey_ImportPrivRaw gates on the per-thread
         * privateKeyReadEnable flag, which is unset by default in any
         * thread that hasn't called PRIVATE_KEY_UNLOCK(). Without the
         * bracket, loading an ML-DSA private key from a worker thread
         * fails with FIPS_PRIVATE_KEY_LOCKED_E. */
        idx = 0;
        PRIVATE_KEY_UNLOCK();
        ret = wc_MlDsaKey_PrivateKeyDecode(key, der->buffer,
            der->length, &idx);
        PRIVATE_KEY_LOCK();
        if (ret == 0) {
            ret = mldsa_get_oid_sum(key, &keyFormatTemp);
            if (ret == 0) {
                /* Format is known. */
                #if defined(WOLFSSL_MLDSA_FIPS204_DRAFT)
                if (keyFormatTemp == DILITHIUM_LEVEL2k) {
                    keyTypeTemp = mldsa_44_sa_algo;
                    keySizeTemp = WC_MLDSA_44_KEY_SIZE;
                }
                else if (keyFormatTemp == DILITHIUM_LEVEL3k) {
                    keyTypeTemp = mldsa_65_sa_algo;
                    keySizeTemp = WC_MLDSA_65_KEY_SIZE;
                }
                else if (keyFormatTemp == DILITHIUM_LEVEL5k) {
                    keyTypeTemp = mldsa_87_sa_algo;
                    keySizeTemp = WC_MLDSA_87_KEY_SIZE;
                }
                else
                #endif /* WOLFSSL_MLDSA_FIPS204_DRAFT */
                if (keyFormatTemp == ML_DSA_44k) {
                    keyTypeTemp = mldsa_44_sa_algo;
                    keySizeTemp = WC_MLDSA_44_KEY_SIZE;
                }
                else if (keyFormatTemp == ML_DSA_65k) {
                    keyTypeTemp = mldsa_65_sa_algo;
                    keySizeTemp = WC_MLDSA_65_KEY_SIZE;
                }
                else if (keyFormatTemp == ML_DSA_87k) {
                    keyTypeTemp = mldsa_87_sa_algo;
                    keySizeTemp = WC_MLDSA_87_KEY_SIZE;
                }
                else {
                    ret = ALGO_ID_E;
                }
            }

            if (ret == 0) {
                /* Get the minimum Dilithium key size from SSL or SSL context
                 * object. */
                int minKeySz = ssl ? ssl->options.minMlDsaKeySz :
                                     ctx->minMlDsaKeySz;

                /* Check that the size of the Dilithium key is enough. */
                if (keySizeTemp < minKeySz) {
                    WOLFSSL_MSG("ML-DSA private key too small");
                    ret = MLDSA_KEY_SIZE_E;
                }
            }

            if (ret == 0) {
                *keyFormat = keyFormatTemp;
                *keyType = keyTypeTemp;
                *keySize = keySizeTemp;
            }
        }
        else if (*keyFormat == 0) {
            WOLFSSL_MSG("Not an ML-DSA key");
            /* Unknown format wasn't dilithium, so keep trying other formats. */
            ret = 0;
        }

        /* Free dynamically allocated data in key. */
        wc_MlDsaKey_Free(key);
    }

    /* Dispose of allocated key. */
    XFREE(key, heap, DYNAMIC_TYPE_MLDSA);
    return ret;
}
#endif /* WOLFSSL_HAVE_MLDSA */

/* Try to decode DER data is a known private key.
 *
 * Checks size meets minimum for key type.
 *
 * @param [in, out] ctx        SSL context object.
 * @param [in, out] ssl        SSL object.
 * @param [in]      der        DER encoding.
 * @param [in, out] keyFormat  On in, expected format. 0 means unknown.
 * @param [in]      heap       Dynamic memory allocation hint.
 * @param [out]     type       Type of key:
 *                               PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE.
 * @return  0 on success.
 * @return  BAD_FUNC_ARG when der or keyFormat is NULL.
 * @return  BAD_FUNC_ARG when ctx and ssl are NULL.
 * @return  WOLFSSL_BAD_FILE when unable to identify the key format.
 */
static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DerBuffer* der, int* keyFormat, void* heap, int type)
{
    int ret = 0;
    int devId = wolfSSL_CTX_GetDevId(ctx, ssl);
    byte* keyType = NULL;
    int* keySz = NULL;
    int matchAnyKey = 0;

    (void)heap;
    (void)devId;
    (void)type;

    /* Validate parameters. */
    if ((der == NULL) || (keyFormat == NULL)) {
        ret = BAD_FUNC_ARG;
    }
    /* Must have an SSL context or SSL object to use. */
    if ((ret == 0) && (ctx == NULL) && (ssl == NULL)) {
        ret = BAD_FUNC_ARG;
    }

    if (ret == 0) {
        /* Determine where to put key type and size in SSL or context object. */
    #ifdef WOLFSSL_DUAL_ALG_CERTS
        if (type == ALT_PRIVATEKEY_TYPE) {
            if (ssl != NULL) {
                keyType = &ssl->buffers.altKeyType;
                keySz = &ssl->buffers.altKeySz;
            }
            else {
                keyType = &ctx->altPrivateKeyType;
                keySz = &ctx->altPrivateKeySz;
            }
        }
        else
    #endif
        /* Type is PRIVATEKEY_TYPE. */
        if (ssl != NULL) {
            keyType = &ssl->buffers.keyType;
            keySz = &ssl->buffers.keySz;
        }
        else {
            keyType = &ctx->privateKeyType;
            keySz = &ctx->privateKeySz;
        }
    }

#ifndef NO_RSA
    /* Try RSA if key format is RSA or yet unknown. */
    if ((ret == 0) && ((*keyFormat == 0) || (*keyFormat == RSAk))) {
#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
    (HAVE_FIPS_VERSION > 2))
        ret = ProcessBufferTryDecodeRsa(ctx, ssl, der, keyFormat, devId,
            keyType, keySz);
#else
        ret = ProcessBufferTryDecodeRsa(ctx, ssl, der, keyFormat, heap, devId,
            keyType, keySz);
#endif
        matchAnyKey = 1;
    }
#ifdef WC_RSA_PSS
    if((ret == 0) && (*keyFormat == RSAPSSk)) {
        /* Require logic to verify that the der is RSAPSSk
         * (when *keyFormat == RSAPSSK), and to detect that the der is RSAPSSk
         * (when *keyFormat == 0). */
        matchAnyKey = 1;
    }
#endif /* WC_RSA_PSS */
#endif /* NO_RSA */
#ifdef HAVE_ECC
    /* Try ECC if key format is ECDSA or SM2, or yet unknown. */
    if ((ret == 0) && ((*keyFormat == 0) || (*keyFormat == ECDSAk)
    #ifdef WOLFSSL_SM2
        || (*keyFormat == SM2k)
    #endif
        )) {
        ret = ProcessBufferTryDecodeEcc(ctx, ssl, der, keyFormat, heap, devId,
            keyType, keySz);
        matchAnyKey = 1;
    }
#endif /* HAVE_ECC */
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT)
    /* Try Ed25519 if key format is Ed25519 or yet unknown. */
    if ((ret == 0) && ((*keyFormat == 0 || *keyFormat == ED25519k))) {
        ret = ProcessBufferTryDecodeEd25519(ctx, ssl, der, keyFormat, heap,
            devId, keyType, keySz);
        matchAnyKey = 1;
    }
#endif /* HAVE_ED25519 && HAVE_ED25519_KEY_IMPORT */
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
    /* Try Ed448 if key format is Ed448 or yet unknown. */
    if ((ret == 0) && ((*keyFormat == 0 || *keyFormat == ED448k))) {
        ret = ProcessBufferTryDecodeEd448(ctx, ssl, der, keyFormat, heap, devId,
            keyType, keySz);
        matchAnyKey = 1;
    }
#endif /* HAVE_ED448 && HAVE_ED448_KEY_IMPORT */
#if defined(HAVE_FALCON)
    /* Try Falcon if key format is Falcon level 1k or 5k or yet unknown. */
    if ((ret == 0) && ((*keyFormat == 0) || (*keyFormat == FALCON_LEVEL1k) ||
            (*keyFormat == FALCON_LEVEL5k))) {
        ret = ProcessBufferTryDecodeFalcon(ctx, ssl, der, keyFormat, heap,
            keyType, keySz);
        matchAnyKey = 1;
    }
#endif /* HAVE_FALCON */
#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_MLDSA_NO_SIGN) && \
    !defined(WOLFSSL_MLDSA_NO_ASN1)
    /* Try Falcon if key format is Dilithium level 2k, 3k or 5k or yet unknown.
     */
    if ((ret == 0) &&
        ((*keyFormat == 0) ||
        (*keyFormat == ML_DSA_44k) ||
        (*keyFormat == ML_DSA_65k) ||
        (*keyFormat == ML_DSA_87k)
    #ifdef WOLFSSL_MLDSA_FIPS204_DRAFT
     || (*keyFormat == DILITHIUM_LEVEL2k)
     || (*keyFormat == DILITHIUM_LEVEL3k)
     || (*keyFormat == DILITHIUM_LEVEL5k)
    #endif
        )) {
        ret = ProcessBufferTryDecodeMlDsa(ctx, ssl, der, keyFormat, heap,
            keyType, keySz);
        matchAnyKey = 1;
    }
#endif /* WOLFSSL_HAVE_MLDSA */

    /* Check we know the format. */
    if ((ret == 0) &&
        ((*keyFormat == 0) || ((*keyFormat != 0) && (matchAnyKey == 0)))) {
        WOLFSSL_MSG("Not a supported key type");
        /* Not supported key format. */
        ret = WOLFSSL_BAD_FILE;
    }

    return ret;
}

#if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED)
/* Decrypt PKCS#8 private key.
 *
 * @param [in] info   Encryption information.
 * @param [in] der    DER encoded data.
 * @param [in] heap   Dynamic memory allocation hint.
 * @return  0 on success.
 * @return  MEMORY_E when dynamic memory allocation fails.
 */
static int ProcessBufferPrivPkcs8Dec(EncryptedInfo* info, DerBuffer* der,
    void* heap)
{
    int ret = 0;
    word32 algId;
    int   passwordSz = NAME_SZ;
    WC_DECLARE_VAR(password, char, NAME_SZ, 0);

    (void)heap;
#ifdef WOLFSSL_SMALL_STACK
    /* Allocate memory for password. */
    password = (char*)XMALLOC(passwordSz, heap, DYNAMIC_TYPE_STRING);
    if (password == NULL) {
        ret = MEMORY_E;
    }
#endif

    if (ret == 0) {
        /* Get password. */
        ret = info->passwd_cb(password, passwordSz, PEM_PASS_READ,
            info->passwd_userdata);
    }
    if (ret >= 0) {
        /* Returned value is password size. */
        passwordSz = ret;
    #ifdef WOLFSSL_CHECK_MEM_ZERO
        wc_MemZero_Add("ProcessBuffer password", password, passwordSz);
    #endif

        /* Decrypt PKCS#8 private key inline and get algorithm id. */
        ret = ToTraditionalEnc(der->buffer, der->length, password, passwordSz,
            &algId);
    }
    if (ret >= 0) {
        /* Zero out encrypted data not overwritten. */
        ForceZero(der->buffer + ret, der->length - (word32)ret);
        /* Set decrypted data length. */
        der->length = (word32)ret;
    }

#ifdef WOLFSSL_SMALL_STACK
    if (password != NULL)
#endif
    {
        /* Ensure password is zeroized. */
        ForceZero(password, (word32)passwordSz);
    }
#ifdef WOLFSSL_SMALL_STACK
    /* Dispose of password memory. */
    XFREE(password, heap, DYNAMIC_TYPE_STRING);
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
    wc_MemZero_Check(password, NAME_SZ);
#endif
    return ret;
}
#endif /* WOLFSSL_ENCRYPTED_KEYS && !NO_PWDBASED */

/* Put the DER into the SSL or SSL context object.
 *
 * Precondition: ctx or ssl is not NULL.
 * Precondition: Must be a private key type.
 *
 * @param [in, out] ctx  SSL context object.
 * @param [in, out] ssl  SSL object.
 * @param [in]      der  DER encoding.
 * @return  0 on success.
 */
static int ProcessBufferPrivKeyHandleDer(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DerBuffer** der, int type)
{
    int ret = 0;

    (void)type;

#ifdef WOLFSSL_DUAL_ALG_CERTS
    if (type == ALT_PRIVATEKEY_TYPE) {
        /* Put in alternate private key fields of objects. */
        if (ssl != NULL) {
            /* Dispose of previous key if not context's. */
            if (ssl->buffers.weOwnAltKey) {
                FreeDer(&ssl->buffers.altKey);
            #ifdef WOLFSSL_BLIND_PRIVATE_KEY
                FreeDer(&ssl->buffers.altKeyMask);
            #endif
            }
            ssl->buffers.altKeyId = 0;
            ssl->buffers.altKeyLabel = 0;
            ssl->buffers.altKeyDevId = INVALID_DEVID;
            /* Store key by reference and own it. */
            ssl->buffers.altKey = *der;
        #ifdef WOLFSSL_CHECK_MEM_ZERO
            wc_MemZero_Add("SSL Buffers key", (*der)->buffer, (*der)->length);
        #endif
            ssl->buffers.weOwnAltKey = 1;
        }
        else if (ctx != NULL) {
            /* Dispose of previous key. */
            FreeDer(&ctx->altPrivateKey);
            ctx->altPrivateKeyId = 0;
            ctx->altPrivateKeyLabel = 0;
            ctx->altPrivateKeyDevId = INVALID_DEVID;
            /* Store key by reference. */
            ctx->altPrivateKey = *der;
        #ifdef WOLFSSL_CHECK_MEM_ZERO
            wc_MemZero_Add("CTX private key", (*der)->buffer, (*der)->length);
        #endif
        }
    }
    else
#endif /* WOLFSSL_DUAL_ALG_CERTS */
    if (ssl != NULL) {
        /* Dispose of previous key if not context's. */
        if (ssl->buffers.weOwnKey) {
            FreeDer(&ssl->buffers.key);
        #ifdef WOLFSSL_BLIND_PRIVATE_KEY
            FreeDer(&ssl->buffers.keyMask);
        #endif
        }
        ssl->buffers.keyId = 0;
        ssl->buffers.keyLabel = 0;
        ssl->buffers.keyDevId = INVALID_DEVID;
        /* Store key by reference and own it. */
        ssl->buffers.key = *der;
    #ifdef WOLFSSL_CHECK_MEM_ZERO
        wc_MemZero_Add("SSL Buffers key", (*der)->buffer, (*der)->length);
    #endif
        ssl->buffers.weOwnKey = 1;
    }
    else if (ctx != NULL) {
        /* Dispose of previous key. */
        FreeDer(&ctx->privateKey);
        ctx->privateKeyId = 0;
        ctx->privateKeyLabel = 0;
        ctx->privateKeyDevId = INVALID_DEVID;
        /* Store key by reference. */
        ctx->privateKey = *der;
    #ifdef WOLFSSL_CHECK_MEM_ZERO
        wc_MemZero_Add("CTX private key", (*der)->buffer, (*der)->length);
    #endif
    }

    return ret;
}

/* Decode private key.
 *
 * Precondition: ctx or ssl is not NULL.
 * Precondition: Must be a private key type.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in, out] ssl     SSL object.
 * @param [in]      der     DER encoding.
 * @param [in]      format  Original format of data.
 * @param [in]      info    Encryption information.
 * @param [in]      heap    Dynamic memory allocation hint.
 * @param [in]      type    Type of data:
 *                            PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE.
 * @param [in]      algId   Algorithm id of key.
 * @return  0 on success.
 * @return  WOLFSSL_BAD_FILE when not able to decode.
 */
static int ProcessBufferPrivateKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DerBuffer* der, int format, EncryptedInfo* info, void* heap, int type,
    int algId)
{
    int ret;

    (void)info;
    (void)format;

    /* Put the data into the SSL or SSL context object. */
    ret = ProcessBufferPrivKeyHandleDer(ctx, ssl, &der, type);
    if (ret == 0) {
        /* Try to decode the DER data. */
        ret = ProcessBufferTryDecode(ctx, ssl, der, &algId, heap, type);
    }

#if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED)
    /* If private key type PKCS8 header wasn't already removed (algId == 0). */
    if (((ret != 0) || (algId == 0)) && (format != WOLFSSL_FILETYPE_PEM) &&
            (info->passwd_cb != NULL) && (algId == 0)) {
        /* Try to decrypt DER data as a PKCS#8 private key. */
        ret = ProcessBufferPrivPkcs8Dec(info, der, heap);
        if (ret >= 0) {
            /* Try to decode decrypted data.  */
            ret = ProcessBufferTryDecode(ctx, ssl, der, &algId, heap, type);
        }
    }
#endif /* WOLFSSL_ENCRYPTED_KEYS && !NO_PWDBASED */

#ifdef WOLFSSL_BLIND_PRIVATE_KEY
    {
        int blindRet = 0;
#ifdef WOLFSSL_DUAL_ALG_CERTS
        if (type == ALT_PRIVATEKEY_TYPE) {
            if (ssl != NULL) {
                blindRet = wolfssl_priv_der_blind(ssl->rng, ssl->buffers.altKey,
                    &ssl->buffers.altKeyMask);
            }
            else {
                blindRet = wolfssl_priv_der_blind(NULL, ctx->altPrivateKey,
                    &ctx->altPrivateKeyMask);
            }
        }
        else
#endif
        if (ssl != NULL) {
            blindRet = wolfssl_priv_der_blind(ssl->rng, ssl->buffers.key,
                &ssl->buffers.keyMask);
        }
        else {
            blindRet = wolfssl_priv_der_blind(NULL, ctx->privateKey,
                &ctx->privateKeyMask);
        }
        if (ret == 0 && blindRet != 0)
            ret = blindRet;
    }
#endif

    /* Check if we were able to determine algorithm id. */
    if ((ret == 0) && (algId == 0)) {
    #ifdef OPENSSL_EXTRA
        /* Decryption password is probably wrong. */
        if (info->passwd_cb) {
            WOLFSSL_EVPerr(0, -WOLFSSL_EVP_R_BAD_DECRYPT_E);
        }
    #endif
        WOLFSSL_ERROR(WOLFSSL_BAD_FILE);
        /* Unable to decode DER data. */
        ret = WOLFSSL_BAD_FILE;
    }

    return ret;
}

/* Use the key OID to determine have options.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in, out] ssl     SSL object.
 * @param [in]      keyOID  OID for public/private key.
 */
static void wolfssl_set_have_from_key_oid(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    int keyOID)
{
    /* Set which private key algorithm available based on key OID. */
    switch (keyOID) {
        case ECDSAk:
    #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
        case SM2k:
    #endif
    #ifdef HAVE_ED25519
        case ED25519k:
    #endif
    #ifdef HAVE_ED448
        case ED448k:
    #endif
            if (ssl != NULL) {
                ssl->options.haveECC = 1;
            }
            else {
                ctx->haveECC = 1;
            }
            break;
    #ifndef NO_RSA
        case RSAk:
        #ifdef WC_RSA_PSS
        case RSAPSSk:
        #endif
            if (ssl != NULL) {
                ssl->options.haveRSA = 1;
            }
            else {
                ctx->haveRSA = 1;
            }
            break;
    #endif
    #ifdef HAVE_FALCON
        case FALCON_LEVEL1k:
        case FALCON_LEVEL5k:
            if (ssl != NULL) {
                ssl->options.haveFalconSig = 1;
            }
            else {
                ctx->haveFalconSig = 1;
            }
            break;
    #endif /* HAVE_FALCON */
    #ifdef WOLFSSL_HAVE_MLDSA
        case ML_DSA_44k:
        case ML_DSA_65k:
        case ML_DSA_87k:
        #ifdef WOLFSSL_MLDSA_FIPS204_DRAFT
        case DILITHIUM_LEVEL2k:
        case DILITHIUM_LEVEL3k:
        case DILITHIUM_LEVEL5k:
        #endif
            if (ssl != NULL) {
                ssl->options.haveMlDsaSig = 1;
            }
            else {
                ctx->haveMlDsaSig = 1;
            }
            break;
    #endif /* WOLFSSL_HAVE_MLDSA */
        default:
            WOLFSSL_MSG("Cert key not supported");
            break;
        }
}

/* Set which private key algorithm we have against SSL or SSL context object.
 *
 * Precondition: ctx or ssl is not NULL.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in, out] ssl     SSL object.
 * @param [in]      cert    Decode certificate.
 */
static void ProcessBufferCertSetHave(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DecodedCert* cert)
{
    if (ssl != NULL) {
        /* Reset signatures we have in SSL. */
        ssl->options.haveECDSAsig = 0;
        ssl->options.haveFalconSig = 0;
        ssl->options.haveMlDsaSig = 0;
    }

    /* Set which signature we have based on the type in the cert. */
    switch (cert->signatureOID) {
        case CTC_SHAwECDSA:
        case CTC_SHA256wECDSA:
        case CTC_SHA384wECDSA:
        case CTC_SHA512wECDSA:
    #ifdef HAVE_ED25519
        case CTC_ED25519:
    #endif
    #ifdef HAVE_ED448
        case CTC_ED448:
    #endif
    #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
        case CTC_SM3wSM2:
    #endif
            WOLFSSL_MSG("ECDSA/ED25519/ED448 cert signature");
            if (ssl) {
                ssl->options.haveECDSAsig = 1;
            }
            else if (ctx) {
                ctx->haveECDSAsig = 1;
            }
            break;
    #ifdef HAVE_FALCON
        case CTC_FALCON_LEVEL1:
        case CTC_FALCON_LEVEL5:
            WOLFSSL_MSG("Falcon cert signature");
            if (ssl) {
                ssl->options.haveFalconSig = 1;
            }
            else if (ctx) {
                ctx->haveFalconSig = 1;
            }
            break;
    #endif
    #ifdef WOLFSSL_HAVE_MLDSA
        case CTC_ML_DSA_44:
        case CTC_ML_DSA_65:
        case CTC_ML_DSA_87:
        #ifdef WOLFSSL_MLDSA_FIPS204_DRAFT
        case CTC_DILITHIUM_LEVEL2:
        case CTC_DILITHIUM_LEVEL3:
        case CTC_DILITHIUM_LEVEL5:
        #endif /* WOLFSSL_MLDSA_FIPS204_DRAFT */
            WOLFSSL_MSG("ML-DSA cert signature");
            if (ssl) {
                ssl->options.haveMlDsaSig = 1;
            }
            else if (ctx) {
                ctx->haveMlDsaSig = 1;
            }
            break;
    #endif
        default:
            WOLFSSL_MSG("Cert signature not supported");
            break;
    }

#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \
    defined(HAVE_FALCON) || defined(WOLFSSL_HAVE_MLDSA) || !defined(NO_RSA)
    #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448)
    /* Set the private key curve OID. */
    if (ssl != NULL) {
        ssl->pkCurveOID = cert->pkCurveOID;
    }
    else if (ctx) {
        ctx->pkCurveOID = cert->pkCurveOID;
    }
    #endif
#ifndef WC_STRICT_SIG
    if ((ctx != NULL) || (ssl != NULL)) {
        wolfssl_set_have_from_key_oid(ctx, ssl, (int)cert->keyOID);
    }
#else
    /* Set whether ECC is available based on signature available. */
    if (ssl != NULL) {
        ssl->options.haveECC = ssl->options.haveECDSAsig;
    }
    else if (ctx) {
        ctx->haveECC = ctx->haveECDSAsig;
    }
#endif /* !WC_STRICT_SIG */
#endif
}

/* Check key size is valid.
 *
 * Precondition: ctx or ssl is not NULL.
 *
 * @param [in] min    Minimum key size.
 * @param [in] max    Maximum key size.
 * @param [in] keySz  Key size.
 * @param [in] err    Error value to return when key size is invalid.
 * @return  0 on success.
 * @return  err when verifying and min is less than 0 or key size is invalid.
 */
#define CHECK_KEY_SZ(min, max, keySz, err)                                     \
    (((min) < 0) || ((keySz) < (min)) || ((keySz) > (max))) ? (err) : 0

/* Check public key in certificate.
 *
 * @param [in, out] ctx   SSL context object.
 * @param [in, out] ssl   SSL object.
 * @param [in]      cert  Certificate object.
 * @return  0 on success.
 * @return  Non-zero when an error occurred.
 */
static int ProcessBufferCertPublicKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DecodedCert* cert, int checkKeySz)
{
    int ret = 0;
    byte keyType = 0;
    int keySz = 0;
#ifndef NO_RSA
    word32 idx;
#endif
    if (ctx == NULL && ssl == NULL) {
        return BAD_FUNC_ARG;
    }

    /* Get key size and check unless not verifying. */
    switch (cert->keyOID) {
#ifndef NO_RSA
    #ifdef WC_RSA_PSS
        case RSAPSSk:
    #endif
        case RSAk:
            keyType = rsa_sa_algo;
            /* Determine RSA key size by parsing public key */
            idx = 0;
            ret = wc_RsaPublicKeyDecode_ex(cert->publicKey, &idx,
                cert->pubKeySize, NULL, (word32*)&keySz, NULL, NULL);
            if ((ret == 0) && checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minRsaKeySz :
                    ctx->minRsaKeySz, RSA_MAX_SIZE / 8, keySz, RSA_KEY_SIZE_E);
            }
    #ifdef WC_RSA_PSS
            if (ssl) {
                ssl->useRsaPss = cert->keyOID == RSAPSSk;
            }
            if (ctx) {
                ctx->useRsaPss = cert->keyOID == RSAPSSk;
            }
    #endif
            break;
#endif /* !NO_RSA */
    #ifdef HAVE_ECC
        case ECDSAk:
            keyType = ecc_dsa_sa_algo;
            /* Determine ECC key size based on curve */
        #ifdef WOLFSSL_CUSTOM_CURVES
            if ((cert->pkCurveOID == 0) && (cert->pkCurveSize != 0)) {
                keySz = cert->pkCurveSize;
            }
            else
        #endif
            {
                keySz = wc_ecc_get_curve_size_from_id(wc_ecc_get_oid(
                    cert->pkCurveOID, NULL, NULL));
            }

            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
                     ctx->minEccKeySz, (MAX_ECC_BITS + 7) / 8, keySz,
                     ECC_KEY_SIZE_E);
            }
            break;
    #endif /* HAVE_ECC */
    #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
        case SM2k:
            keyType = sm2_sa_algo;
            /* Determine ECC key size based on curve */
            keySz = WOLFSSL_SM2_KEY_BITS / 8;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
                    ctx->minEccKeySz, (MAX_ECC_BITS + 7) / 8, keySz,
                    ECC_KEY_SIZE_E);
            }
            break;
    #endif /* WOLFSSL_SM2 && WOLFSSL_SM3 */
    #ifdef HAVE_ED25519
        case ED25519k:
            keyType = ed25519_sa_algo;
            /* ED25519 is fixed key size */
            keySz = ED25519_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
                    ctx->minEccKeySz, ED25519_KEY_SIZE, keySz, ECC_KEY_SIZE_E);
            }
            break;
    #endif /* HAVE_ED25519 */
    #ifdef HAVE_ED448
        case ED448k:
            keyType = ed448_sa_algo;
            /* ED448 is fixed key size */
            keySz = ED448_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
                    ctx->minEccKeySz, ED448_KEY_SIZE, keySz, ECC_KEY_SIZE_E);
            }
            break;
    #endif /* HAVE_ED448 */
    #if defined(HAVE_FALCON)
        case FALCON_LEVEL1k:
            keyType = falcon_level1_sa_algo;
            /* Falcon is fixed key size */
            keySz = FALCON_LEVEL1_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minFalconKeySz :
                    ctx->minFalconKeySz, FALCON_MAX_KEY_SIZE, keySz,
                    FALCON_KEY_SIZE_E);
            }
            break;
        case FALCON_LEVEL5k:
            keyType = falcon_level5_sa_algo;
            /* Falcon is fixed key size */
            keySz = FALCON_LEVEL5_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minFalconKeySz :
                    ctx->minFalconKeySz, FALCON_MAX_KEY_SIZE, keySz,
                    FALCON_KEY_SIZE_E);
            }
            break;
    #endif /* HAVE_FALCON */
    #if defined(WOLFSSL_HAVE_MLDSA)
        #ifdef WOLFSSL_MLDSA_FIPS204_DRAFT
        case DILITHIUM_LEVEL2k:
            keyType = mldsa_44_sa_algo;
            /* Dilithium is fixed key size */
            keySz = WC_MLDSA_44_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minMlDsaKeySz :
                    ctx->minMlDsaKeySz, MLDSA_MAX_KEY_SIZE, keySz,
                    MLDSA_KEY_SIZE_E);
            }
            break;
        case DILITHIUM_LEVEL3k:
            keyType = mldsa_65_sa_algo;
            /* Dilithium is fixed key size */
            keySz = WC_MLDSA_65_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minMlDsaKeySz :
                    ctx->minMlDsaKeySz, MLDSA_MAX_KEY_SIZE, keySz,
                    MLDSA_KEY_SIZE_E);
            }
            break;
        case DILITHIUM_LEVEL5k:
            keyType = mldsa_87_sa_algo;
            /* Dilithium is fixed key size */
            keySz = WC_MLDSA_87_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minMlDsaKeySz :
                    ctx->minMlDsaKeySz, MLDSA_MAX_KEY_SIZE, keySz,
                    MLDSA_KEY_SIZE_E);
            }
            break;
        #endif /* WOLFSSL_MLDSA_FIPS204_DRAFT */
        case ML_DSA_44k:
            keyType = mldsa_44_sa_algo;
            /* Dilithium is fixed key size */
            keySz = WC_MLDSA_44_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minMlDsaKeySz :
                    ctx->minMlDsaKeySz, MLDSA_MAX_KEY_SIZE, keySz,
                    MLDSA_KEY_SIZE_E);
            }
            break;
        case ML_DSA_65k:
            keyType = mldsa_65_sa_algo;
            /* Dilithium is fixed key size */
            keySz = WC_MLDSA_65_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minMlDsaKeySz :
                    ctx->minMlDsaKeySz, MLDSA_MAX_KEY_SIZE, keySz,
                    MLDSA_KEY_SIZE_E);
            }
            break;
        case ML_DSA_87k:
            keyType = mldsa_87_sa_algo;
            /* Dilithium is fixed key size */
            keySz = WC_MLDSA_87_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minMlDsaKeySz :
                    ctx->minMlDsaKeySz, MLDSA_MAX_KEY_SIZE, keySz,
                    MLDSA_KEY_SIZE_E);
            }
            break;
    #endif /* WOLFSSL_HAVE_MLDSA */

        default:
            WOLFSSL_MSG("No key size check done on public key in certificate");
            break;
    }

    /* Store the type and key size as there may not be a private key set. */
    if (ssl != NULL) {
        ssl->buffers.keyType = keyType;
        ssl->buffers.keySz = keySz;
    }
    else {
        ctx->privateKeyType = keyType;
        ctx->privateKeySz = keySz;
    }

    return ret;
}

#ifdef WOLFSSL_DUAL_ALG_CERTS
static int ProcessBufferCertAltPublicKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DecodedCert* cert, int checkKeySz)
{
    int ret = 0;
    void* heap = WOLFSSL_HEAP(ctx, ssl);
    byte keyType = 0;
    int keySz = 0;
#ifndef NO_RSA
    word32 idx;
#endif

    /* Check alternative key size of cert. */
    switch (cert->sapkiOID) {
        /* No OID set. */
        case 0:
            if (cert->sapkiLen != 0) {
                /* Have the alternative key data but no OID. */
                ret = NOT_COMPILED_IN;
            }
            break;

#ifndef NO_RSA
    #ifdef WC_RSA_PSS
        case RSAPSSk:
    #endif
        case RSAk:
            keyType = rsa_sa_algo;
            /* Determine RSA key size by parsing public key */
            idx = 0;
            ret = wc_RsaPublicKeyDecode_ex(cert->sapkiDer, &idx,
                cert->sapkiLen, NULL, (word32*)&keySz, NULL, NULL);
            if ((ret == 0) && checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minRsaKeySz :
                    ctx->minRsaKeySz, RSA_MAX_SIZE / 8, keySz, RSA_KEY_SIZE_E);
            }
            break;
#endif /* !NO_RSA */
    #ifdef HAVE_ECC
        case ECDSAk:
        {
            WC_DECLARE_VAR(temp_key, ecc_key, 1, 0);
            keyType = ecc_dsa_sa_algo;

            WC_ALLOC_VAR_EX(temp_key, ecc_key, 1, heap, DYNAMIC_TYPE_ECC,
                ret=MEMORY_E);

            /* Determine ECC key size. We have to decode the sapki for
             * that. */
            if (ret == 0) {
                ret = wc_ecc_init_ex(temp_key, heap, INVALID_DEVID);
                if (ret == 0) {
                    idx = 0;
                    ret = wc_EccPublicKeyDecode(cert->sapkiDer, &idx, temp_key,
                        cert->sapkiLen);
                    if (ret == 0) {
                        keySz = wc_ecc_size(temp_key);
                    }
                    wc_ecc_free(temp_key);
                }
            }
            WC_FREE_VAR_EX(temp_key, heap, DYNAMIC_TYPE_ECC);

            if ((ret == 0) && checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
                     ctx->minEccKeySz, (MAX_ECC_BITS + 7) / 8, keySz,
                     ECC_KEY_SIZE_E);
            }
            break;
        }
    #endif /* HAVE_ECC */
    #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
        case SM2k:
            keyType = sm2_sa_algo;
            /* Determine ECC key size based on curve */
            keySz = WOLFSSL_SM2_KEY_BITS / 8;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
                    ctx->minEccKeySz, (MAX_ECC_BITS + 7) / 8, keySz,
                    ECC_KEY_SIZE_E);
            }
            break;
    #endif /* WOLFSSL_SM2 && WOLFSSL_SM3 */
    #ifdef HAVE_ED25519
        case ED25519k:
            keyType = ed25519_sa_algo;
            /* ED25519 is fixed key size */
            keySz = ED25519_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
                    ctx->minEccKeySz, ED25519_KEY_SIZE, keySz, ECC_KEY_SIZE_E);
            }
            break;
    #endif /* HAVE_ED25519 */
    #ifdef HAVE_ED448
        case ED448k:
            keyType = ed448_sa_algo;
            /* ED448 is fixed key size */
            keySz = ED448_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
                    ctx->minEccKeySz, ED448_KEY_SIZE, keySz, ECC_KEY_SIZE_E);
            }
            break;
    #endif /* HAVE_ED448 */
    #if defined(HAVE_FALCON)
        case FALCON_LEVEL1k:
            keyType = falcon_level1_sa_algo;
            /* Falcon is fixed key size */
            keySz = FALCON_LEVEL1_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minFalconKeySz :
                    ctx->minFalconKeySz, FALCON_MAX_KEY_SIZE, keySz,
                    FALCON_KEY_SIZE_E);
            }
            break;
        case FALCON_LEVEL5k:
            keyType = falcon_level5_sa_algo;
            /* Falcon is fixed key size */
            keySz = FALCON_LEVEL5_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minFalconKeySz :
                    ctx->minFalconKeySz, FALCON_MAX_KEY_SIZE, keySz,
                    FALCON_KEY_SIZE_E);
            }
            break;
    #endif /* HAVE_FALCON */
    #if defined(WOLFSSL_HAVE_MLDSA)
        #ifdef WOLFSSL_MLDSA_FIPS204_DRAFT
        case DILITHIUM_LEVEL2k:
            keyType = mldsa_44_sa_algo;
            /* Dilithium is fixed key size */
            keySz = WC_MLDSA_44_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minMlDsaKeySz :
                    ctx->minMlDsaKeySz, MLDSA_MAX_KEY_SIZE, keySz,
                    MLDSA_KEY_SIZE_E);
            }
            break;
        case DILITHIUM_LEVEL3k:
            keyType = mldsa_65_sa_algo;
            /* Dilithium is fixed key size */
            keySz = WC_MLDSA_65_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minMlDsaKeySz :
                    ctx->minMlDsaKeySz, MLDSA_MAX_KEY_SIZE, keySz,
                    MLDSA_KEY_SIZE_E);
            }
            break;
        case DILITHIUM_LEVEL5k:
            keyType = mldsa_87_sa_algo;
            /* Dilithium is fixed key size */
            keySz = WC_MLDSA_87_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minMlDsaKeySz :
                    ctx->minMlDsaKeySz, MLDSA_MAX_KEY_SIZE, keySz,
                    MLDSA_KEY_SIZE_E);
            }
            break;
        #endif /* WOLFSSL_MLDSA_FIPS204_DRAFT */
        case ML_DSA_44k:
            keyType = mldsa_44_sa_algo;
            /* Dilithium is fixed key size */
            keySz = WC_MLDSA_44_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minMlDsaKeySz :
                    ctx->minMlDsaKeySz, MLDSA_MAX_KEY_SIZE, keySz,
                    MLDSA_KEY_SIZE_E);
            }
            break;
        case ML_DSA_65k:
            keyType = mldsa_65_sa_algo;
            /* Dilithium is fixed key size */
            keySz = WC_MLDSA_65_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minMlDsaKeySz :
                    ctx->minMlDsaKeySz, MLDSA_MAX_KEY_SIZE, keySz,
                    MLDSA_KEY_SIZE_E);
            }
            break;
        case ML_DSA_87k:
            keyType = mldsa_87_sa_algo;
            /* Dilithium is fixed key size */
            keySz = WC_MLDSA_87_KEY_SIZE;
            if (checkKeySz) {
                ret = CHECK_KEY_SZ(ssl ? ssl->options.minMlDsaKeySz :
                    ctx->minMlDsaKeySz, MLDSA_MAX_KEY_SIZE, keySz,
                    MLDSA_KEY_SIZE_E);
            }
            break;
    #endif /* WOLFSSL_HAVE_MLDSA */

        default:
            /* In this case, there was an OID that we didn't recognize.
             * This is an error. Use not compiled in because likely the
             * given algorithm was not enabled. */
            ret = NOT_COMPILED_IN;
            WOLFSSL_MSG("No alt key size check done on certificate");
            break;
    }

    if (ssl != NULL) {
        ssl->buffers.altKeyType = (byte)keyType;
        ssl->buffers.altKeySz = keySz;
    }
    else if (ctx != NULL) {
        ctx->altPrivateKeyType = (byte)keyType;
        ctx->altPrivateKeySz = keySz;
    }

    return ret;
}
#endif /* WOLFSSL_DUAL_ALG_CERTS */

/* Parse the certificate and pull out information for TLS handshake.
 *
 * @param [in, out] ctx   SSL context object.
 * @param [in, out] ssl   SSL object.
 * @param [in]      der   DER encoded X509 certificate.
 * @return  0 on success.
 * @return  MEMORY_E when dynamic memory allocation fails.
 * @return  WOLFSSL_BAD_FILE when decoding certificate fails.
 */
static int ProcessBufferCert(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der)
{
    int ret = 0;
    void* heap = WOLFSSL_HEAP(ctx, ssl);
#if defined(HAVE_RPK)
    RpkState* rpkState = ssl ? &ssl->options.rpkState : &ctx->rpkState;
#endif
    WC_DECLARE_VAR(cert, DecodedCert, 1, 0);

    /* Allocate memory for certificate to be decoded into. */
    WC_ALLOC_VAR_EX(cert, DecodedCert, 1, heap, DYNAMIC_TYPE_DCERT,
        ret=MEMORY_E);
    if (WC_VAR_OK(cert))
    {
        /* Get device id from SSL context or SSL object. */
        int devId = wolfSSL_CTX_GetDevId(ctx, ssl);

        WOLFSSL_MSG("Checking cert signature type");
        /* Initialize certificate object. */
        InitDecodedCert_ex(cert, der->buffer, der->length, heap, devId);

        /* Decode up to and including public key. */
        if (DecodeToKey(cert, 0) < 0) {
            WOLFSSL_MSG("Decode to key failed");
            ret = WOLFSSL_BAD_FILE;
        }
        if (ret == 0) {
            int checkKeySz = 1;

        #if defined(HAVE_RPK)
            /* Store whether the crtificate is a raw public key. */
            rpkState->isRPKLoaded = cert->isRPK;
        #endif /* HAVE_RPK */

            /* Set which private key algorithm we have. */
            ProcessBufferCertSetHave(ctx, ssl, cert);

            /* Don't check if verification is disabled for SSL. */
            if ((ssl != NULL) && ssl->options.verifyNone) {
                checkKeySz = 0;
            }
            /* Don't check if no SSL object verification is disabled for SSL
             * context. */
            else if ((ssl == NULL) && (ctx != NULL) && ctx->verifyNone) {
                checkKeySz = 0;
            }

            /* Check public key size. */
            ret = ProcessBufferCertPublicKey(ctx, ssl, cert, checkKeySz);
        #ifdef WOLFSSL_DUAL_ALG_CERTS
            if (ret == 0) {
                ret = ProcessBufferCertAltPublicKey(ctx, ssl, cert, checkKeySz);
            }
        #endif
        }
    }

    /* Dispose of dynamic memory in certificate object. */
    FreeDecodedCert(cert);
    WC_FREE_VAR_EX(cert, heap, DYNAMIC_TYPE_DCERT);
    return ret;
}

/* Handle storing the DER encoding of the certificate.
 *
 * Do not free der outside of this function.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in, out] ssl     SSL object.
 * @param [in]      der     DER encoded certificate.
 * @param [in]      type    Type of data:
 *                            CERT_TYPE, CA_TYPE or TRUSTED_PEER_TYPE.
 * @param [in]      verify  What verification to do.
 * @return  0 on success.
 * @return  BAD_FUNC_ARG when type is CA_TYPE and ctx is NULL.
 * @return  WOLFSSL_BAD_CERTTYPE when data type is not supported.
 */
static int ProcessBufferCertHandleDer(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    DerBuffer* der, int type, int verify)
{
    int ret = 0;

    /* CA certificate to verify with. */
    if (type == CA_TYPE) {
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
        /* TEST ONLY CODE:
         * Store the DER encoding of the CA certificate so we can append it to
         * the list of trusted CA certificates if the subsequent call to AddCA
         * is successful */
        word32 derLen;
        byte* derBuf;
        if (ctx->doAppleNativeCertValidationFlag == 1) {
            WOLFSSL_MSG("ANCV Test: copy DER CA cert");
            derLen = der->length;
            derBuf = (byte*)XMALLOC(derLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
            if (derBuf == NULL) {
                return MEMORY_E;
            }
            XMEMCPY(derBuf, der->buffer, derLen);
        }
        else {
            (void)derLen;
            (void)derBuf;
        }
#endif
        /* verify CA unless user set to no verify */
        ret = AddCA(ctx->cm, &der, WOLFSSL_USER_CA, verify);

#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
        /* TEST ONLY CODE:
         * Append the DER encoded CA certificate to the list of trusted CA
         * certificates so we can inject them at verification time */
        if (ret == 1 && ctx->doAppleNativeCertValidationFlag == 1) {
            WOLFSSL_MSG("ANCV Test: Appending CA to cert list");
            ret = wolfSSL_TestAppleNativeCertValidation_AppendCA(ctx, derBuf,
                (int)derLen);
            if (ret == WOLFSSL_SUCCESS) {
                WOLFSSL_MSG("ANCV Test: Clearing CA table");
                /* Clear the CA table so we can ensure they won't be used for
                 * verification */
                ret = wolfSSL_CertManagerUnloadCAs(ctx->cm);
                if (ret == WOLFSSL_SUCCESS) {
                    ret = 0;
                }
            }
            XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        }
#endif /* !WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */

        if (ret == 1) {
            ret = 0;
        }
    }
#ifdef WOLFSSL_TRUST_PEER_CERT
    /* Trusted certificate to verify peer with. */
    else if (type == TRUSTED_PEER_TYPE) {
        WOLFSSL_CERT_MANAGER* cm;

        /* Get certificate manager to add certificate to. */
        if (ctx != NULL) {
            cm = ctx->cm;
        }
        else {
            SSL_CM_WARNING(ssl);
            cm = SSL_CM(ssl);
        }
        /* Add certificate as a trusted peer. */
        ret = AddTrustedPeer(cm, &der, verify);
        if (ret != 1) {
            WOLFSSL_MSG("Error adding trusted peer");
        }
    }
#endif /* WOLFSSL_TRUST_PEER_CERT */
    /* Leaf certificate - our certificate. */
    else if (type == CERT_TYPE) {
        if (ssl != NULL) {
            /* Free previous certificate if we own it. */
            if (ssl->buffers.weOwnCert) {
                FreeDer(&ssl->buffers.certificate);
            #ifdef KEEP_OUR_CERT
                /* Dispose of X509 version of certificate. */
                wolfSSL_X509_free(ssl->ourCert);
                ssl->ourCert = NULL;
            #endif
            }
            /* Store certificate as ours. */
            ssl->buffers.certificate = der;
        #ifdef KEEP_OUR_CERT
            ssl->keepCert = 1; /* hold cert for ssl lifetime */
        #endif
            /* We have to free the certificate buffer. */
            ssl->buffers.weOwnCert = 1;
            /* ourCert is created on demand. */
        }
        else if (ctx != NULL) {
            /* Free previous certificate. */
            FreeDer(&ctx->certificate); /* Make sure previous is free'd */
        #ifdef KEEP_OUR_CERT
            /* Dispose of X509 version of certificate if we own it. */
            if (ctx->ownOurCert) {
                wolfSSL_X509_free(ctx->ourCert);
            }
            ctx->ourCert = NULL;
        #endif
            /* Store certificate as ours. */
            ctx->certificate = der;
            /* ourCert is created on demand. */
        }
    }
    else {
        /* Dispose of DER buffer. */
        FreeDer(&der);
        /* Not a certificate type supported. */
        ret = WOLFSSL_BAD_CERTTYPE;
    }

    return ret;
}

/* Process certificate based on type.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in, out] ssl     SSL object.
 * @param [in]      buff    Buffer holding original data.
 * @param [in]      sz      Size of data in buffer.
 * @param [in]      der     DER encoding of certificate.
 * @param [in]      format  Format of data.
 * @param [in]      type    Type of data:
 *                            CERT_TYPE, CA_TYPE or TRUSTED_PEER_TYPE.
 * @param [in]      verify  What verification to do.
 * @return  0 on success.
 * @return  WOLFSSL_FATAL_ERROR on failure.
 */
static int ProcessBufferCertTypes(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    const unsigned char* buff, long sz, DerBuffer* der, int format, int type,
    int verify)
{
    int ret;

    (void)buff;
    (void)sz;
    (void)format;

    ret = ProcessBufferCertHandleDer(ctx, ssl, der, type, verify);
    if ((ret == 0) && (type == CERT_TYPE)) {
        /* Process leaf certificate. */
        ret = ProcessBufferCert(ctx, ssl, der);
    }
#if !defined(NO_WOLFSSL_CM_VERIFY) && (!defined(NO_WOLFSSL_CLIENT) || \
    !defined(WOLFSSL_NO_CLIENT_AUTH))
    /* Hand bad CA or user certificate to callback. */
    if ((ret < 0) && ((type == CA_TYPE) || (type == CERT_TYPE))) {
        /* Check for verification callback that may override error. */
        if ((ctx != NULL) && (ctx->cm != NULL) &&
                (ctx->cm->verifyCallback != NULL)) {
            /* Verify and use callback. */
            ret = CM_VerifyBuffer_ex(ctx->cm, buff, sz, format, ret);
            /* Convert error. */
            if (ret == 0) {
                ret = WOLFSSL_FATAL_ERROR;
            }
            if (ret == 1) {
                ret = 0;
            }
        }
    }
#endif /* NO_WOLFSSL_CM_VERIFY */

    return ret;
}

/* Reset the cipher suites based on updated private key or certificate.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in, out] ssl     SSL object.
 * @param [in]      type    Type of certificate.
 * @return  0 on success.
 * @return  WOLFSSL_FATAL_ERROR when allocation fails.
 */
static int ProcessBufferResetSuites(WOLFSSL_CTX* ctx, WOLFSSL* ssl, int type)
{
    int ret = 0;

    /* Reset suites of SSL object. */
    if (ssl != NULL) {
        if (ssl->options.side == WOLFSSL_SERVER_END) {
            /* Allocate memory for suites. */
            if (AllocateSuites(ssl) != 0) {
                ret = WOLFSSL_FATAL_ERROR;
            }
            else {
                /* Determine cipher suites based on what we have. */
                InitSuites(ssl->suites, ssl->version, ssl->buffers.keySz,
                    WOLFSSL_HAVE_RSA, SSL_HAVE_PSK(ssl), ssl->options.haveDH,
                    ssl->options.haveECDSAsig, ssl->options.haveECC, TRUE,
                    ssl->options.haveStaticECC,
                    ssl->options.useAnon, TRUE,
                    TRUE, TRUE, TRUE, ssl->options.side);
            }
        }
    }
    /* Reset suites of SSL context object. */
    else if ((type == CERT_TYPE) && (ctx->method->side == WOLFSSL_SERVER_END)) {
        /* Allocate memory for suites. */
        if (AllocateCtxSuites(ctx) != 0) {
            ret = WOLFSSL_FATAL_ERROR;
        }
        else {
            /* Determine cipher suites based on what we have. */
            InitSuites(ctx->suites, ctx->method->version, ctx->privateKeySz,
                WOLFSSL_HAVE_RSA, CTX_HAVE_PSK(ctx), ctx->haveDH,
                ctx->haveECDSAsig, ctx->haveECC, TRUE, ctx->haveStaticECC,
                CTX_USE_ANON(ctx),
                TRUE, TRUE, TRUE, TRUE, ctx->method->side);
        }
    }

    return ret;
}

#ifndef WOLFSSL_DUAL_ALG_CERTS
    /* Determine whether the type is for a private key. */
    #define IS_PRIVKEY_TYPE(type) ((type) == PRIVATEKEY_TYPE)
#else
    /* Determine whether the type is for a private key. */
    #define IS_PRIVKEY_TYPE(type) (((type) == PRIVATEKEY_TYPE) ||   \
                                   ((type) == ALT_PRIVATEKEY_TYPE))
#endif

/* Process a buffer of data.
 *
 * Data type is a private key or a certificate.
 * The format can be ASN.1 (DER) or PEM.
 *
 * @param [in, out] ctx        SSL context object.
 * @param [in]      buff       Buffer holding data.
 * @param [in]      sz         Size of data in buffer.
 * @param [in]      format     Format of data:
 *                               WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @param [in]      type       Type of data:
 *                               CERT_TYPE, CA_TYPE, TRUSTED_PEER_TYPE,
 *                               PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE.
 * @param [in, out] ssl        SSL object.
 * @param [out]     used       Number of bytes consumed.
 * @param [in[      userChain  Whether this certificate is for user's chain.
 * @param [in]      verify     How to verify certificate.
 * @param [in]      source_name Associated filename or other source ID.
 * @return  1 on success.
 * @return  Less than 1 on failure.
 */
int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, long sz,
    int format, int type, WOLFSSL* ssl, long* used, int userChain, int verify,
    const char *source_name)
{
    DerBuffer*    der = NULL;
    int           ret = 0;
    void*         heap = WOLFSSL_HEAP(ctx, ssl);
    WC_DECLARE_VAR(info, EncryptedInfo, 1, 0);
    int           algId = 0;
#ifdef WOLFSSL_DEBUG_CERTIFICATE_LOADS
    long usedAtStart = used ? *used : 0L;
#else
    (void)source_name;
#endif

    WOLFSSL_ENTER("ProcessBuffer");

    /* Check data format is supported. */
    if ((format != WOLFSSL_FILETYPE_ASN1) && (format != WOLFSSL_FILETYPE_PEM)) {
        ret = WOLFSSL_BAD_FILETYPE;
    }
    /* Need an object to store certificate into. */
    if ((ret == 0) && (ctx == NULL) && (ssl == NULL)) {
        ret = BAD_FUNC_ARG;
    }
    /* CA certificates go into the SSL context object. */
    if ((ret == 0) && (ctx == NULL) && (type == CA_TYPE)) {
        ret = BAD_FUNC_ARG;
    }
    /* This API does not handle CHAIN_CERT_TYPE */
    if ((ret == 0) && (type == CHAIN_CERT_TYPE)) {
        ret = BAD_FUNC_ARG;
    }
    /* Reject negative size - would wrap to huge word32. */
    if ((ret == 0) && (sz < 0)) {
        ret = BAD_FUNC_ARG;
    }

#ifdef WOLFSSL_SMALL_STACK
    if (ret == 0) {
        /* Allocate memory for encryption information. */
        info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), heap,
            DYNAMIC_TYPE_ENCRYPTEDINFO);
        if (info == NULL) {
            ret = MEMORY_E;
        }
    }
#endif
    if (ret == 0) {
        /* Initialize encryption information. */
        XMEMSET(info, 0, sizeof(EncryptedInfo));
    #if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED)
        if (ctx != NULL) {
            info->passwd_cb       = ctx->passwd_cb;
            info->passwd_userdata = ctx->passwd_userdata;
        }
    #endif

        /* Get the DER data for a private key or certificate. */
        ret = DataToDerBuffer(buff, (word32)sz, format, type, info, heap, &der,
            &algId);
        if (used != NULL) {
            /* Update to amount used/consumed. */
            *used = info->consumed;
        }
    #ifdef WOLFSSL_SMALL_STACK
        if (ret != 0) {
             /* Info no longer needed as loading failed. */
             XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO);
        }
    #endif
    }

    if ((ret == 0) && IS_PRIVKEY_TYPE(type)) {
        /* Process the private key. */
        ret = ProcessBufferPrivateKey(ctx, ssl, der, format, info, heap, type,
            algId);
        WC_FREE_VAR_EX(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO);
    }
    else if (ret == 0) {
        /* Processing a certificate. */
        if (userChain) {
            /* Take original buffer and add to user chain to send in TLS
             * handshake. */
            ret = ProcessUserChain(ctx, ssl, buff, sz, format, type, used, info,
                verify);
            /* Additional chain is optional */
            if (ret == WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER)) {
                unsigned long pemErr = 0;
                CLEAR_ASN_NO_PEM_HEADER_ERROR(pemErr);
                ret = 0;
            }
#ifdef WOLFSSL_DEBUG_CERTIFICATE_LOADS
            if (ret < 0) {
#ifdef NO_ERROR_STRINGS
                WOLFSSL_DEBUG_PRINTF(
                    "ERROR: ProcessUserChain: certificate from %s at offset %ld"
                    " rejected with code %d\n",
                    source_name, usedAtStart, ret);
#else
                WOLFSSL_DEBUG_PRINTF(
                    "ERROR: ProcessUserChain: certificate from %s at offset %ld"
                    " rejected with code %d: %s\n",
                    source_name, usedAtStart, ret,
                    wolfSSL_ERR_reason_error_string(ret));
#endif
            }
#endif /* WOLFSSL_DEBUG_CERTIFICATE_LOADS */
        }

        WC_FREE_VAR_EX(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO);

        if (ret == 0) {
            /* Process the different types of certificates. */
            ret = ProcessBufferCertTypes(ctx, ssl, buff, sz, der, format, type,
                verify);
#ifdef WOLFSSL_DEBUG_CERTIFICATE_LOADS
            if (ret < 0) {
#ifdef NO_ERROR_STRINGS
                WOLFSSL_DEBUG_PRINTF(
                    "ERROR: ProcessBufferCertTypes: certificate from %s at"
                    " offset %ld rejected with code %d\n",
                    source_name, usedAtStart, ret);
#else
                WOLFSSL_DEBUG_PRINTF(
                    "ERROR: ProcessBufferCertTypes: certificate from %s at"
                    " offset %ld rejected with code %d: %s\n",
                    source_name, usedAtStart, ret,
                    wolfSSL_ERR_reason_error_string(ret));
#endif
            }
#endif /* WOLFSSL_DEBUG_CERTIFICATE_LOADS */
        }
        else {
            FreeDer(&der);
        }
    }

    /* Reset suites if this is a private key or user certificate. */
    if ((ret == 0) && ((type == PRIVATEKEY_TYPE) || (type == CERT_TYPE))) {
        ret = ProcessBufferResetSuites(ctx, ssl, type);
    }

    /* Convert return code. */
    if (ret == 0) {
        ret = 1;
    }
    else if (ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) {
        ret = 0;
    }
    WOLFSSL_LEAVE("ProcessBuffer", ret);
    return ret;
}

#if defined(WOLFSSL_WPAS) && defined(HAVE_CRL)
/* Try to parse data as a PEM CRL.
 *
 * @param [in]  ctx       SSL context object.
 * @param [in]  buff      Buffer containing potential CRL in PEM format.
 * @param [in]  sz        Amount of data in buffer remaining.
 * @param [out] consumed  Number of bytes in buffer was the CRL.
 * @return  0 on success.
 */
static int ProcessChainBufferCRL(WOLFSSL_CTX* ctx, const unsigned char* buff,
    long sz, long* consumed)
{
    int           ret;
    DerBuffer*    der = NULL;
    EncryptedInfo info;

    WOLFSSL_MSG("Trying a CRL");
    ret = PemToDer(buff, sz, CRL_TYPE, &der, NULL, &info, NULL);
    if (ret == 0) {
        WOLFSSL_MSG("   Processed a CRL");
        wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, der->buffer, der->length,
            WOLFSSL_FILETYPE_ASN1);
        FreeDer(&der);
        *consumed = info.consumed;
    }

    return ret;
}
#endif

/* Process all chain certificates (and CRLs) in the PEM data.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in, out] ssl     SSL object.
 * @param [in]      buff    Buffer containing PEM data.
 * @param [in]      sz      Size of data in buffer.
 * @param [in]      type    Type of data.
 * @param [in]      verify  How to verify certificate.
 * @param [in]      source_name   Associated filename or other source ID.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  MEMORY_E when dynamic memory allocation fails.
 */
static int ProcessChainBuffer(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    const unsigned char* buff, long sz, int type, int verify,
    const char *source_name)
{
    int  ret    = 0;
    long used   = 0;
    int  gotOne = 0;

    WOLFSSL_MSG("Processing CA PEM file");
    /* Keep processing file while no errors and data to parse. */
    while ((ret >= 0) && (used < sz)) {
        long consumed = used;

        /* Process the buffer. */
        ret = ProcessBuffer(ctx, buff + used, sz - used, WOLFSSL_FILETYPE_PEM,
            type, ssl, &consumed, 0, verify, source_name);
        /* Memory allocation failure is fatal. */
        if (ret == WC_NO_ERR_TRACE(MEMORY_E)) {
            gotOne = 0;
        }
        /* Other error parsing. */
        else if (ret < 0) {
#if defined(WOLFSSL_WPAS) && defined(HAVE_CRL)
            /* Try parsing a CRL. */
            if (ProcessChainBufferCRL(ctx, buff + used, sz - used,
                    &consumed) == 0) {
                ret = 0;
            }
            else
#endif
            /* Check whether we made progress. */
            if (consumed > 0) {
                WOLFSSL_ERROR(ret);
                WOLFSSL_MSG("CA Parse failed, with progress in file.");
                WOLFSSL_MSG("Search for other certs in file");
                /* Check if we have more data to parse to recover. */
                if (used + consumed < sz) {
                    ret = 0;
                }
            }
            else {
                /* No progress in parsing being made - stop here. */
                WOLFSSL_MSG("CA Parse failed, no progress in file.");
                WOLFSSL_MSG("Do not continue search for other certs in file");
            }
        }
        else {
            /* Got a certificate out. */
            WOLFSSL_MSG("   Processed a CA");
            gotOne = 1;
        }
        /* Update used count. */
        used += consumed;
    }

    /* May have other unparsable data but did we get a certificate? */
    if (gotOne) {
        WOLFSSL_MSG("Processed at least one valid CA. Other stuff OK");
        ret = 1;
    }
    return ret;
}


/* Get verify settings for AddCA from SSL context. */
#define GET_VERIFY_SETTING_CTX(ctx) \
    ((ctx) && (ctx)->verifyNone ? NO_VERIFY : VERIFY)
/* Get verify settings for AddCA from SSL. */
#define GET_VERIFY_SETTING_SSL(ssl) \
    ((ssl)->options.verifyNone ? NO_VERIFY : VERIFY)

#ifndef NO_FILESYSTEM

/* Process data from a file as private keys, CRL or certificates.
 *
 * @param [in, out] ctx        SSL context object.
 * @param [in]      fname      Name of file to read.
 * @param [in]      format     Format of data:
 *                               WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @param [in]      type       Type of data:
 *                               CERT_TYPE, CA_TYPE, TRUSTED_PEER_TYPE,
 *                               PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE.
 * @param [in, out] ssl        SSL object.
 * @param [in]      userChain  Whether file contains chain of certificates.
 * @param [in, out] crl        CRL object to load data into.
 * @param [in]      verify     How to verify certificates.
 * @return  1 on success.
 * @return  WOLFSSL_BAD_FILE when reading the file fails.
 * @return  WOLFSSL_BAD_CERTTYPE when unable to detect certificate type.
 */
int ProcessFile(WOLFSSL_CTX* ctx, const char* fname, int format, int type,
    WOLFSSL* ssl, int userChain, WOLFSSL_CRL* crl, int verify)
{
    int    ret = 0;
#ifndef WOLFSSL_SMALL_STACK
    byte   stackBuffer[FILE_BUFFER_SIZE];
#endif
    StaticBuffer content;
    long   sz = 0;
    void*  heap = WOLFSSL_HEAP(ctx, ssl);

    (void)crl;
    (void)heap;

#ifdef WOLFSSL_SMALL_STACK
    static_buffer_init(&content);
#else
    static_buffer_init(&content, stackBuffer, FILE_BUFFER_SIZE);
#endif

    /* Read file into static buffer. */
    ret = wolfssl_read_file_static(fname, &content, heap, DYNAMIC_TYPE_FILE,
        &sz);
    if ((ret == 0) && (type == DETECT_CERT_TYPE) &&
            (format != WOLFSSL_FILETYPE_PEM)) {
        WOLFSSL_MSG_CERT_LOG("Cannot detect certificate type when not PEM");
        ret = WOLFSSL_BAD_CERTTYPE;
    }
    /* Try to detect type by parsing cert header and footer. */
    if ((ret == 0) && (type == DETECT_CERT_TYPE)) {
#if !defined(NO_CODING) && !defined(WOLFSSL_NO_PEM)
        const char* header = NULL;
        const char* footer = NULL;
#ifdef HAVE_CRL
        WOLFSSL_MSG_CERT("Detecting cert type... (including CRL_TYPE)");
#else
        WOLFSSL_MSG_CERT("Detecting cert type... (HAVE_CRL not defined)");
#endif

        /* Look for CA header and footer - same as CERT_TYPE. */
        if (wc_PemGetHeaderFooter(CA_TYPE, &header, &footer) == 0 &&
                (XSTRNSTR((char*)content.buffer, header, sz) != NULL)) {
            type = CA_TYPE;
            WOLFSSL_MSG_CERT_LOG_EX("Detected cert type CA_TYPE = %d:", type);
        }
#ifdef HAVE_CRL
        /* Look for CRL header and footer. */
        else if (wc_PemGetHeaderFooter(CRL_TYPE, &header, &footer) == 0 &&
                (XSTRNSTR((char*)content.buffer, header, sz) != NULL)) {
            type = CRL_TYPE;
            WOLFSSL_MSG_CERT_LOG_EX("Detected cert type CRL_TYPE = %d:", type);
        }
#endif
        /* Look for cert header and footer - same as CA_TYPE. */
        else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 &&
                (XSTRNSTR((char*)content.buffer, header, sz) !=
                    NULL)) {
            type = CERT_TYPE;
            WOLFSSL_MSG_CERT_LOG_EX("Detected cert type CERT_TYPE = %d:", type);
        }
        else
#endif /* !NO_CODING && !WOLFSSL_NO_PEM */
        {
            /* Not a header that we support. */
            WOLFSSL_MSG_CERT_LOG("Failed to detect certificate type");
#ifdef WOLFSSL_DEBUG_CERTIFICATE_LOADS
            WOLFSSL_DEBUG_PRINTF(
                "ERROR: ProcessFile: Failed to detect certificate type"
                " of \"%s\"\n",
                fname);
#endif
            ret = WOLFSSL_BAD_CERTTYPE;
        }
    } /* (ret == 0) && (type == DETECT_CERT_TYPE) */

    if (ret == 0) {
        /* When CA or trusted peer and PEM - process as a chain buffer. */
        if (((type == CA_TYPE) || (type == TRUSTED_PEER_TYPE)) &&
                (format == WOLFSSL_FILETYPE_PEM)) {
            WOLFSSL_MSG_CERT("Processing cert chain buffer...");
            ret = ProcessChainBuffer(ctx, ssl, content.buffer, sz, type,
                verify, fname);
        }
#ifdef HAVE_CRL
        else if (type == CRL_TYPE) {
            WOLFSSL_MSG_CERT("Loading CRL...");
            ret = BufferLoadCRL(crl, content.buffer, sz, format, verify);
        }
#endif
#ifdef WOLFSSL_DUAL_ALG_CERTS
        else if (type == PRIVATEKEY_TYPE) {
            /* When support for dual algorithm certificates is enabled, the
             * private key file may contain both the primary and the
             * alternative private key. Hence, we have to parse both of them.
             */
            long consumed = 0;

            ret = ProcessBuffer(ctx, content.buffer, sz, format, type, ssl,
                &consumed, userChain, verify, fname);
            if ((ret == 1) && (consumed < sz)) {
                ret = ProcessBuffer(ctx, content.buffer + consumed,
                    sz - consumed, format, ALT_PRIVATEKEY_TYPE, ssl, NULL, 0,
                    verify, fname);
            }
        }
#endif
        else {
            /* Load all other certificate types. */
            ret = ProcessBuffer(ctx, content.buffer, sz, format, type, ssl,
                NULL, userChain, verify, fname);
        }
    }

    /* Dispose of dynamically allocated data. */
    static_buffer_free(&content, heap, DYNAMIC_TYPE_FILE);
    return ret;
}

#ifndef NO_WOLFSSL_DIR
/* Load file when filename is in the path.
 *
 * @param [in, out] ctx           SSL context object.
 * @param [in]      name          Name of file.
 * @param [in]      verify        How to verify a certificate.
 * @param [in]      flags         Flags representing options for loading.
 * @param [in, out] failCount     Number of files that failed to load.
 * @param [in, out] successCount  Number of files successfully loaded.
 * @return  1 on success.
 * @return  Not 1 when loading PEM certificate failed.
 */
static int wolfssl_ctx_load_path_file(WOLFSSL_CTX* ctx, const char* name,
    int verify, int flags, int* failCount, int* successCount)
{
    int ret;

    /* Attempt to load file as a CA. */
    ret = ProcessFile(ctx, name, WOLFSSL_FILETYPE_PEM, CA_TYPE, NULL, 0, NULL,
        verify);
    if (ret != 1) {
        /* When ignoring errors or loading PEM only and no PEM. don't fail. */
        if ((flags & WOLFSSL_LOAD_FLAG_IGNORE_ERR) ||
                ((flags & WOLFSSL_LOAD_FLAG_PEM_CA_ONLY) &&
                 (ret == WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER)))) {
            unsigned long err = 0;
            CLEAR_ASN_NO_PEM_HEADER_ERROR(err);
        #if defined(WOLFSSL_QT)
            ret = 1;
        #endif
        }
        else {
            WOLFSSL_ERROR(ret);
            WOLFSSL_MSG("Load CA file failed, continuing");
            /* Add to fail count. */
            (*failCount)++;
        }
    }
    else {
    #if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS)
        /* Try loading as a trusted peer certificate. */
        ret = wolfSSL_CTX_trust_peer_cert(ctx, name, WOLFSSL_FILETYPE_PEM);
        if (ret != 1) {
            WOLFSSL_MSG("wolfSSL_CTX_trust_peer_cert error. "
                        "Ignoring this error.");
        }
    #endif
        /* Add to success count. */
        (*successCount)++;
    }

    return ret;
}

/* Load PEM formatted CA files from a path.
 *
 * @param [in, out] ctx           SSL context object.
 * @param [in]      path          Path to directory to read.
 * @param [in]      flags         Flags representing options for loading.
 * @param [in]      verify        How to verify a certificate.
 * @param [in]      successCount  Number of files successfully loaded.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  MEMORY_E when dynamic memory allocation fails.
 */
static int wolfssl_ctx_load_path(WOLFSSL_CTX* ctx, const char* path,
    word32 flags, int verify, int successCount)
{
    int ret = 1;
    char* name = NULL;
    int fileRet;
    int failCount = 0;
    WC_DECLARE_VAR(readCtx, ReadDirCtx, 1, 0);

    /* Allocate memory for directory reading context. */
    WC_ALLOC_VAR_EX(readCtx, ReadDirCtx, 1, ctx->heap, DYNAMIC_TYPE_DIRCTX,
        ret=MEMORY_E);

    if (ret == 1) {
        /* Get name of first file in path. */
        fileRet = wc_ReadDirFirst(readCtx, path, &name);
        /* While getting filename doesn't fail and name returned, process file.
         */
        while ((fileRet == 0) && (name != NULL)) {
            WOLFSSL_MSG(name);
            /* Load file. */
            ret = wolfssl_ctx_load_path_file(ctx, name, verify, (int)flags,
                &failCount, &successCount);
            /* Get next filename. */
            fileRet = wc_ReadDirNext(readCtx, path, &name);
        }
        /* Cleanup directory reading context. */
        wc_ReadDirClose(readCtx);

        /* When not WOLFSSL_QT, ret is always overwritten. */
        (void)ret;

        /* Return real directory read failure error codes. */
        if (fileRet != WC_READDIR_NOFILE) {
            ret = fileRet;
        #if defined(WOLFSSL_QT) || defined(WOLFSSL_IGNORE_BAD_CERT_PATH)
            /* Ignore bad path error when flag set. */
            if ((ret == WC_NO_ERR_TRACE(BAD_PATH_ERROR)) &&
                    (flags & WOLFSSL_LOAD_FLAG_IGNORE_BAD_PATH_ERR)) {
               /* QSslSocket always loads certs in system folder
                * when it is initialized.
                * Compliant with OpenSSL when flag set.
                */
                ret = 1;
            }
            else {
                /* qssl socket wants to know errors. */
                WOLFSSL_ERROR(ret);
            }
        #endif
        }
        /* Report failure if no files successfully loaded or there were
         * failures. */
        else if ((successCount == 0) || (failCount > 0)) {
            /* Use existing error code if exists. */
        #if defined(WOLFSSL_QT)
            /* Compliant with OpenSSL when flag set. */
            if (!(flags & WOLFSSL_LOAD_FLAG_IGNORE_ZEROFILE))
        #endif
            {
                /* Return 0 when no files loaded. */
                ret = 0;
            }
        }
        else {
            /* We loaded something so it is a success. */
            ret = 1;
        }

        WC_FREE_VAR_EX(readCtx, ctx->heap, DYNAMIC_TYPE_DIRCTX);
    }

    return ret;
}
#endif

/* Load a file and/or files in path
 *
 * No c_rehash.
 *
 * @param [in, out] ctx    SSL context object.
 * @param [in]      file   Name of file to load. May be NULL.
 * @param [in]      path   Path to directory containing PEM CA files.
 *                         May be NULL.
 * @param [in]      flags  Flags representing options for loading.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  NOT_COMPILED_IN when directory reading not supported and path is
 *          not NULL.
 * @return  Other negative on error.
 */
int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file,
    const char* path, word32 flags)
{
    int ret = 1;
#ifndef NO_WOLFSSL_DIR
    int successCount = 0;
#endif
    int verify = WOLFSSL_VERIFY_DEFAULT;

    WOLFSSL_MSG("wolfSSL_CTX_load_verify_locations_ex");

    /* Validate parameters. */
    if ((ctx == NULL) || ((file == NULL) && (path == NULL))) {
        ret = 0;
    }

#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
    if (ret == 1) {
    /* TEST ONLY CODE: force native cert validation on */
        WOLFSSL_MSG("ANCV Test: Loading system CA certs");
        wolfSSL_CTX_load_system_CA_certs(ctx);
    }
#endif

    if (ret == 1) {
        /* Get setting on how to verify certificates. */
        verify = GET_VERIFY_SETTING_CTX(ctx);
        /* Overwrite setting when flag set. */
        if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) {
            verify = VERIFY_SKIP_DATE;
        }

        if (file != NULL) {
#ifdef WOLFSSL_PEM_TO_DER
            /* Load the PEM formatted CA file */
            ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CA_TYPE, NULL, 0,
                NULL, verify);
#else
            /* Load the DER formatted CA file */
            ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_ASN1, CA_TYPE, NULL,
                0, NULL, verify);
#endif
#ifndef NO_WOLFSSL_DIR
            if (ret == 1) {
                /* Include success in overall count. */
                successCount++;
            }
#endif
#if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS)
            /* Load CA as a trusted peer certificate. */
#ifdef WOLFSSL_PEM_TO_DER
            ret = wolfSSL_CTX_trust_peer_cert(ctx, file, WOLFSSL_FILETYPE_PEM);
#else
            ret = wolfSSL_CTX_trust_peer_cert(ctx, file, WOLFSSL_FILETYPE_ASN1);
#endif
            if (ret != 1) {
                WOLFSSL_MSG("wolfSSL_CTX_trust_peer_cert error");
            }
#endif
        }
    }

    if ((ret == 1) && (path != NULL)) {
#ifndef NO_WOLFSSL_DIR
        /* Load CA files form path. */
        ret = wolfssl_ctx_load_path(ctx, path, flags, verify, successCount);
#else
        /* Loading a path not supported. */
        ret = NOT_COMPILED_IN;
        (void)flags;
#endif
    }

    return ret;
}

/* Load a file and/or files in path
 *
 * No c_rehash.
 *
 * @param [in, out] ctx    SSL context object.
 * @param [in]      file   Name of file to load. May be NULL.
 * @param [in]      path   Path to directory containing PEM CA files.
 *                         May be NULL.
 * @return  1 on success.
 * @return  0 on failure.
 */
WOLFSSL_ABI
int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
                                     const char* path)
{
    /* Load using default flags/options. */
    int ret = wolfSSL_CTX_load_verify_locations_ex(ctx, file, path,
        WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS);

    /* Return 1 on success or 0 on failure. */
    return WS_RETURN_CODE(ret, 0);
}

/* Load a file and/or files in path, with OpenSSL-compatible semantics.
 *
 * No c_rehash.
 *
 * @param [in, out] ctx    SSL context object.
 * @param [in]      file   Name of file to load. May be NULL.
 * @param [in]      path   Path to directory containing PEM CA files.
 *                         May be NULL.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_load_verify_locations_compat(WOLFSSL_CTX* ctx, const char* file,
                                     const char* path)
{
    /* We want to keep trying to load more CA certs even if one cert in the
     * directory is bad and can't be used (e.g. if one is expired), and we
     * want to return success if any were successfully loaded (mimicking
     * OpenSSL SSL_CTX_load_verify_locations() semantics), so we use
     * WOLFSSL_LOAD_FLAG_IGNORE_ERR.  OpenSSL (as of v3.3.2) actually
     * returns success even if no certs are loaded (e.g. because the
     * supplied "path" doesn't exist or access is prohibited), and only
     * returns failure if the "file" is non-null and fails to load.
     *
     * Note that if a file is supplied and can't be successfully loaded, the
     * overall call fails and the path is never even evaluated.  This is
     * consistent with OpenSSL behavior.
     */

    int ret = wolfSSL_CTX_load_verify_locations_ex(ctx, file, path,
        WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS | WOLFSSL_LOAD_FLAG_IGNORE_ERR);

    /* Return 1 on success or 0 on failure. */
    return WS_RETURN_CODE(ret, 0);
}

#ifdef WOLFSSL_TRUST_PEER_CERT
/* Load a trusted peer certificate into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      file    Name of peer certificate file.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 when ctx or file is NULL.
 */
int wolfSSL_CTX_trust_peer_cert(WOLFSSL_CTX* ctx, const char* file, int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_CTX_trust_peer_cert");

    /* Validate parameters. */
    if ((ctx == NULL) || (file == NULL)) {
        ret = 0;
    }
    else {
        ret = ProcessFile(ctx, file, format, TRUSTED_PEER_TYPE, NULL, 0, NULL,
            GET_VERIFY_SETTING_CTX(ctx));
    }

    return ret;
}

/* Load a trusted peer certificate into SSL.
 *
 * @param [in, out] ssl     SSL object.
 * @param [in]      file    Name of peer certificate file.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 when ssl or file is NULL.
 */
int wolfSSL_trust_peer_cert(WOLFSSL* ssl, const char* file, int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_trust_peer_cert");

    /* Validate parameters. */
    if ((ssl == NULL) || (file == NULL)) {
        ret = 0;
    }
    else {
        ret = ProcessFile(NULL, file, format, TRUSTED_PEER_TYPE, ssl, 0, NULL,
            GET_VERIFY_SETTING_SSL(ssl));
    }

    return ret;
}
#endif /* WOLFSSL_TRUST_PEER_CERT */


#ifdef WOLFSSL_DER_LOAD

/* Load a CA certificate into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      file    Name of peer certificate file.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_der_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
    int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_CTX_der_load_verify_locations");

    /* Validate parameters. */
    if ((ctx == NULL) || (file == NULL)) {
        ret = 0;
    }
    else {
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
        /* TEST ONLY CODE: force native cert validation on */
        WOLFSSL_MSG("ANCV Test: loading system CA certs");
        wolfSSL_CTX_load_system_CA_certs(ctx);
#endif
        ret = ProcessFile(ctx, file, format, CA_TYPE, NULL, 0, NULL,
            GET_VERIFY_SETTING_CTX(ctx));
    }

    /* Return 1 on success or 0 on failure. */
    return WS_RC(ret);
}

#endif /* WOLFSSL_DER_LOAD */


/* Load a user certificate into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      file    Name of user certificate file.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 */
WOLFSSL_ABI
int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX* ctx, const char* file,
    int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_file");

    ret = ProcessFile(ctx, file, format, CERT_TYPE, NULL, 0, NULL,
        GET_VERIFY_SETTING_CTX(ctx));

    /* Return 1 on success or 0 on failure. */
    return WS_RC(ret);
}


/* Load a private key into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      file    Name of private key file.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 */
WOLFSSL_ABI
int wolfSSL_CTX_use_PrivateKey_file(WOLFSSL_CTX* ctx, const char* file,
    int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_file");

    ret = ProcessFile(ctx, file, format, PRIVATEKEY_TYPE, NULL, 0, NULL,
        GET_VERIFY_SETTING_CTX(ctx));

    /* Return 1 on success or 0 on failure. */
    return WS_RC(ret);
}

#ifdef WOLFSSL_DUAL_ALG_CERTS
/* Load an alternative private key into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      file    Name of private key file.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_use_AltPrivateKey_file(WOLFSSL_CTX* ctx, const char* file,
    int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_file");

    ret = ProcessFile(ctx, file, format, ALT_PRIVATEKEY_TYPE, NULL, 0, NULL,
        GET_VERIFY_SETTING_CTX(ctx));

    /* Return 1 on success or 0 on failure. */
    return WS_RC(ret);
}
#endif /* WOLFSSL_DUAL_ALG_CERTS */


/* Load a PEM certificate chain into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      file    Name of PEM certificate chain file.
 * @return  1 on success.
 * @return  0 on failure.
 */
WOLFSSL_ABI
int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX* ctx, const char* file)
{
    int ret;

    /* process up to MAX_CHAIN_DEPTH plus subject cert */
    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file");

#ifdef WOLFSSL_PEM_TO_DER
    ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, NULL, 1, NULL,
        GET_VERIFY_SETTING_CTX(ctx));
#else
    ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, NULL, 1,
        NULL, GET_VERIFY_SETTING_CTX(ctx));
#endif

    /* Return 1 on success or 0 on failure. */
    return WS_RC(ret);
}

/* Load certificate chain into SSL context.
 *
 * Processes up to MAX_CHAIN_DEPTH plus subject cert.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      file    Name of private key file.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_use_certificate_chain_file_format(WOLFSSL_CTX* ctx,
     const char* file, int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file_format");

    ret = ProcessFile(ctx, file, format, CERT_TYPE, NULL, 1, NULL,
        GET_VERIFY_SETTING_CTX(ctx));

    /* Return 1 on success or 0 on failure. */
    return WS_RC(ret);
}

#endif /* NO_FILESYSTEM */

#ifdef WOLFSSL_SYS_CA_CERTS

#ifdef USE_WINDOWS_API

/* Load CA certificate from Windows store.
 *
 * Assumes loaded is 0.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [out]     loaded  Whether CA certificates were loaded.
 * @return  1 on success.
 * @return  0 on failure.
 */
static int LoadSystemCaCertsWindows(WOLFSSL_CTX* ctx, byte* loaded)
{
    int ret = 1;
    word32 i;
    HANDLE handle = NULL;
    PCCERT_CONTEXT certCtx = NULL;
    LPCSTR storeNames[2] = {"ROOT", "CA"};
    HCRYPTPROV_LEGACY hProv = (HCRYPTPROV_LEGACY)NULL;

    if ((ctx == NULL) || (loaded == NULL)) {
        ret = 0;
    }

    for (i = 0; (ret == 1) && (i < sizeof(storeNames)/sizeof(*storeNames));
         ++i) {
        handle = CertOpenSystemStoreA(hProv, storeNames[i]);
        if (handle != NULL) {
            while ((certCtx = CertEnumCertificatesInStore(handle, certCtx))
                   != NULL) {
                if (certCtx->dwCertEncodingType == X509_ASN_ENCODING) {
                    if (ProcessBuffer(ctx, certCtx->pbCertEncoded,
                          certCtx->cbCertEncoded, WOLFSSL_FILETYPE_ASN1,
                          CA_TYPE, NULL, NULL, 0,
                          GET_VERIFY_SETTING_CTX(ctx),
                          storeNames[i]) == 1) {
                        /*
                         * Set "loaded" as long as we've loaded one CA
                         * cert.
                         */
                        *loaded = 1;
                    }
                }
            }
        }
        else {
            WOLFSSL_MSG_EX("Failed to open cert store %s.", storeNames[i]);
        }

        if (handle != NULL && !CertCloseStore(handle, 0)) {
            WOLFSSL_MSG_EX("Failed to close cert store %s.", storeNames[i]);
            ret = 0;
        }
    }

    return ret;
}

#elif defined(__APPLE__)

#if defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) \
  && !defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION)
/* Manually obtains certificates from the system trust store and loads them
 * directly into wolfSSL "the old way".
 *
 * As of MacOS 14.0 we are still able to use this method to access system
 * certificates. Accessibility of this API is indicated by the presence of the
 * Security/SecTrustSettings.h header. In the likely event that Apple removes
 * access to this API on Macs, this function should be removed and the
 * DoAppleNativeCertValidation() routine should be used for all devices.
 *
 * Assumes loaded is 0.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [out]     loaded  Whether CA certificates were loaded.
 * @return  1 on success.
 * @return  0 on failure.
 */
static int LoadSystemCaCertsMac(WOLFSSL_CTX* ctx, byte* loaded)
{
    int ret = 1;
    word32 i;
    const unsigned int trustDomains[] = {
        kSecTrustSettingsDomainUser,
        kSecTrustSettingsDomainAdmin,
        kSecTrustSettingsDomainSystem
    };
    CFArrayRef certs;
    OSStatus stat;
    CFIndex numCerts;
    CFDataRef der;
    CFIndex j;

    if ((ctx == NULL) || (loaded == NULL)) {
        ret = 0;
    }

    for (i = 0; (ret == 1) && (i < sizeof(trustDomains)/sizeof(*trustDomains));
         ++i) {
        stat = SecTrustSettingsCopyCertificates(
            (SecTrustSettingsDomain)trustDomains[i], &certs);
        if (stat == errSecSuccess) {
            numCerts = CFArrayGetCount(certs);
            for (j = 0; j < numCerts; ++j) {
                der = SecCertificateCopyData((SecCertificateRef)
                          CFArrayGetValueAtIndex(certs, j));
                if (der != NULL) {
                    if (ProcessBuffer(ctx, CFDataGetBytePtr(der),
                          CFDataGetLength(der), WOLFSSL_FILETYPE_ASN1,
                          CA_TYPE, NULL, NULL, 0,
                          GET_VERIFY_SETTING_CTX(ctx),
                          "MacOSX trustDomains") == 1) {
                        /*
                         * Set "loaded" as long as we've loaded one CA
                         * cert.
                         */
                        *loaded = 1;
                    }

                    CFRelease(der);
                }
            }

            CFRelease(certs);
        }
        else if (stat == errSecNoTrustSettings) {
            WOLFSSL_MSG_EX("No trust settings for domain %d, moving to next "
                "domain.", trustDomains[i]);
        }
        else {
            WOLFSSL_MSG_EX("SecTrustSettingsCopyCertificates failed with"
                " status %d.", stat);
            ret = 0;
            break;
        }
    }

    return ret;
}
#endif /* defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) */

#elif !defined(NO_FILESYSTEM)

/* Potential system CA certs directories on Linux/Unix distros. */
static const char* systemCaDirs[] = {
#if defined(__ANDROID__) || defined(ANDROID)
    "/system/etc/security/cacerts"      /* Android */
#else
    "/etc/ssl/certs",                   /* Debian, Ubuntu, Gentoo, others */
    "/etc/pki/ca-trust/source/anchors", /* Fedora, RHEL */
    "/etc/pki/tls/certs"                /* Older RHEL */
#endif
};

/* Get CA directory list.
 *
 * @param [out] num  Number of CA directories.
 * @return  CA directory list.
 * @return  NULL when num is NULL.
 */
const char** wolfSSL_get_system_CA_dirs(word32* num)
{
    const char** ret;

    /* Validate parameters. */
    if (num == NULL) {
        ret = NULL;
    }
    else {
        ret = systemCaDirs;
        *num = sizeof(systemCaDirs)/sizeof(*systemCaDirs);
    }

    return ret;
}

/* Load CA certificate from default system directories.
 *
 * Assumes loaded is 0.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [out]     loaded  Whether CA certificates were loaded.
 * @return  1 on success.
 * @return  0 on failure.
 */
static int LoadSystemCaCertsNix(WOLFSSL_CTX* ctx, byte* loaded) {
    int ret = 1;
    word32 i;

    if ((ctx == NULL) || (loaded == NULL)) {
        ret = 0;
    }

    for (i = 0; (ret == 1) && (i < sizeof(systemCaDirs)/sizeof(*systemCaDirs));
         ++i) {
        WOLFSSL_MSG_EX("Attempting to load system CA certs from %s.",
            systemCaDirs[i]);
        /*
         * We want to keep trying to load more CA certs even if one cert in
         * the directory is bad and can't be used (e.g. if one is expired),
         * so we use WOLFSSL_LOAD_FLAG_IGNORE_ERR.
         */
        if (wolfSSL_CTX_load_verify_locations_ex(ctx, NULL, systemCaDirs[i],
                WOLFSSL_LOAD_FLAG_IGNORE_ERR) != 1) {
            WOLFSSL_MSG_EX("Failed to load CA certs from %s, trying "
                "next possible location.", systemCaDirs[i]);
        }
        else {
            WOLFSSL_MSG_EX("Loaded CA certs from %s.",
                systemCaDirs[i]);
            *loaded = 1;
            /* Stop searching after we've loaded one directory. */
            break;
        }
    }

    return ret;
}

#endif

/* Load CA certificates from system defined locations.
 *
 * @param [in, out] ctx  SSL context object.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  WOLFSSL_BAD_PATH when no error but no certificates loaded.
 */
int wolfSSL_CTX_load_system_CA_certs(WOLFSSL_CTX* ctx)
{
    int ret;
    byte loaded = 0;

    WOLFSSL_ENTER("wolfSSL_CTX_load_system_CA_certs");

#ifdef USE_WINDOWS_API

    ret = LoadSystemCaCertsWindows(ctx, &loaded);

#elif defined(__APPLE__)

#if defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) \
  && !defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION)
    /* As of MacOS 14.0 we are still able to access system certificates and
     * load them manually into wolfSSL "the old way". Accessibility of this API
     * is indicated by the presence of the Security/SecTrustSettings.h header */
    ret = LoadSystemCaCertsMac(ctx, &loaded);
#elif defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION)
    /* For other Apple devices, Apple has removed the ability to obtain
     * certificates from the trust store, so we can't use wolfSSL's built-in
     * certificate validation mechanisms anymore. We instead must call into the
     * Security Framework APIs to authenticate peer certificates when received.
     * (see src/internal.c:DoAppleNativeCertValidation()).
     * Thus, there is no CA "loading" required, but to keep behavior consistent
     * with the current API (not using system CA certs unless this function has
     * been called), we simply set a flag indicating that the new apple trust
     * verification routine should be used later */
    ctx->doAppleNativeCertValidationFlag = 1;
    ret = 1;
    loaded = 1;

#if FIPS_VERSION_GE(2,0) /* Gate back to cert 3389 FIPS modules */
#warning "Cryptographic operations may occur outside the FIPS module boundary" \
         "Please review FIPS claims for cryptography on this Apple device"
#endif /* FIPS_VERSION_GE(2,0) */

#else
/* HAVE_SECURITY_SECXXX_H macros are set by autotools or CMake when searching
 * system for the required SDK headers. If building with user_settings.h, you
 * will need to manually define WOLFSSL_APPLE_NATIVE_CERT_VALIDATION
 * and ensure the appropriate Security.framework headers and libraries are
 * visible to your compiler */
#error "WOLFSSL_SYS_CA_CERTS on Apple devices requires Security.framework" \
       " header files to be detected, or a manual override with" \
       " WOLFSSL_APPLE_NATIVE_CERT_VALIDATION"
#endif

#else

    ret = LoadSystemCaCertsNix(ctx, &loaded);

#endif

    /* If we didn't fail but didn't load then we error out. */
    if ((ret == 1) && (!loaded)) {
        ret = WOLFSSL_BAD_PATH;
    }

    WOLFSSL_LEAVE("wolfSSL_CTX_load_system_CA_certs", ret);

    return ret;
}

#endif /* WOLFSSL_SYS_CA_CERTS */

#ifdef OPENSSL_EXTRA

/* Load a private key into SSL.
 *
 * @param [in, out] ssl   SSL object.
 * @param [in]      pkey  EVP private key.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_use_PrivateKey(WOLFSSL* ssl, WOLFSSL_EVP_PKEY* pkey)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_use_PrivateKey");

    /* Validate parameters. */
    if ((ssl == NULL) || (pkey == NULL)) {
        ret = 0;
    }
    else {
        /* Get DER encoded key data from EVP private key. */
        ret = wolfSSL_use_PrivateKey_buffer(ssl, (unsigned char*)pkey->pkey.ptr,
            pkey->pkey_sz, WOLFSSL_FILETYPE_ASN1);
    }

    return ret;
}

/* Load a DER encoded private key in a buffer into SSL.
 *
 * @param [in]      pri    Indicates type of private key. Ignored.
 * @param [in, out] ssl    SSL object.
 * @param [in]      der    Buffer holding DER encoded private key.
 * @param [in]      derSz  Size of data in bytes.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_use_PrivateKey_ASN1(int pri, WOLFSSL* ssl, const unsigned char* der,
    long derSz)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_use_PrivateKey_ASN1");

    (void)pri;

    /* Validate parameters. */
    if ((ssl == NULL) || (der == NULL)) {
        ret = 0;
    }
    else {
        ret = wolfSSL_use_PrivateKey_buffer(ssl, der, derSz,
            WOLFSSL_FILETYPE_ASN1);
    }

    return ret;
}

/* Load a DER encoded private key in a buffer into SSL context.
 *
 * @param [in]      pri    Indicates type of private key. Ignored.
 * @param [in, out] ctx    SSL context object.
 * @param [in]      der    Buffer holding DER encoded private key.
 * @param [in]      derSz  Size of data in bytes.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_use_PrivateKey_ASN1(int pri, WOLFSSL_CTX* ctx,
    unsigned char* der, long derSz)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_ASN1");

    (void)pri;

    /* Validate parameters. */
    if ((ctx == NULL) || (der == NULL)) {
        ret = 0;
    }
    else {
        ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, derSz,
            WOLFSSL_FILETYPE_ASN1);
    }

    return ret;
}


#ifndef NO_RSA
/* Load a DER encoded RSA private key in a buffer into SSL.
 *
 * @param [in, out] ssl    SSL object.
 * @param [in]      der    Buffer holding DER encoded RSA private key.
 * @param [in]      derSz  Size of data in bytes.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_use_RSAPrivateKey_ASN1(WOLFSSL* ssl, unsigned char* der, long derSz)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_ASN1");

    /* Validate parameters. */
    if ((ssl == NULL) || (der == NULL)) {
        ret = 0;
    }
    else {
        ret = wolfSSL_use_PrivateKey_buffer(ssl, der, derSz,
            WOLFSSL_FILETYPE_ASN1);
    }

    return ret;
}
#endif

/* Load a certificate into SSL.
 *
 * @param [in, out] ssl   SSL object.
 * @param [in]      x509  X509 certificate object.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_use_certificate(WOLFSSL* ssl, WOLFSSL_X509* x509)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_use_certificate");

    /* Validate parameters. */
    if ((ssl == NULL) || (x509 == NULL) || (x509->derCert == NULL)) {
        ret = 0;
    }
    else {
        long idx = 0;

        /* Get DER encoded certificate data from X509 object. */
        ret = ProcessBuffer(NULL, x509->derCert->buffer, x509->derCert->length,
            WOLFSSL_FILETYPE_ASN1, CERT_TYPE, ssl, &idx, 0,
            GET_VERIFY_SETTING_SSL(ssl),
            "x509 buffer");
    }

    /* Return 1 on success or 0 on failure. */
    return WS_RC(ret);
}

#endif /* OPENSSL_EXTRA */

/* Load a DER encoded certificate in a buffer into SSL.
 *
 * @param [in, out] ssl    SSL object.
 * @param [in]      der    Buffer holding DER encoded certificate.
 * @param [in]      derSz  Size of data in bytes.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_use_certificate_ASN1(WOLFSSL* ssl, const unsigned char* der,
    int derSz)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_use_certificate_ASN1");

    /* Validate parameters. */
    if ((ssl == NULL) || (der == NULL)) {
        ret = 0;
    }
    else {
        long idx = 0;

        ret = ProcessBuffer(NULL, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE,
            ssl, &idx, 0, GET_VERIFY_SETTING_SSL(ssl),
            "asn1 buffer");
    }

    /* Return 1 on success or 0 on failure. */
    return WS_RC(ret);
}

#ifndef NO_FILESYSTEM

/* Load a certificate from a file into SSL.
 *
 * @param [in, out] ssl     SSL object.
 * @param [in]      file    Name of file.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  BAD_FUNC_ARG when ssl is NULL.
 */
WOLFSSL_ABI
int wolfSSL_use_certificate_file(WOLFSSL* ssl, const char* file, int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_use_certificate_file");

    /* Validate parameters. */
    if (ssl == NULL) {
        ret = BAD_FUNC_ARG;
    }
    else {
        ret = ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 0, NULL,
            GET_VERIFY_SETTING_SSL(ssl));
        /* Return 1 on success or 0 on failure. */
        ret = WS_RC(ret);
    }

    return ret;
}


/* Load a private key from a file into SSL.
 *
 * @param [in, out] ssl     SSL object.
 * @param [in]      file    Name of file.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  BAD_FUNC_ARG when ssl is NULL.
 */
WOLFSSL_ABI
int wolfSSL_use_PrivateKey_file(WOLFSSL* ssl, const char* file, int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_use_PrivateKey_file");

    /* Validate parameters. */
    if (ssl == NULL) {
        ret = BAD_FUNC_ARG;
    }
    else {
        ret = ProcessFile(ssl->ctx, file, format, PRIVATEKEY_TYPE, ssl, 0, NULL,
            GET_VERIFY_SETTING_SSL(ssl));
        /* Return 1 on success or 0 on failure. */
        ret = WS_RC(ret);
    }

    return ret;
}


/* Load a PEM encoded certificate chain from a file into SSL.
 *
 * Process up to MAX_CHAIN_DEPTH plus subject cert.
 *
 * @param [in, out] ssl     SSL object.
 * @param [in]      file    Name of file.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  BAD_FUNC_ARG when ssl is NULL.
 */
WOLFSSL_ABI
int wolfSSL_use_certificate_chain_file(WOLFSSL* ssl, const char* file)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file");

    /* Validate parameters. */
    if (ssl == NULL) {
        ret = BAD_FUNC_ARG;
    }
    else {
#ifdef WOLFSSL_PEM_TO_DER
        ret = ProcessFile(ssl->ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, ssl,
            1, NULL, GET_VERIFY_SETTING_SSL(ssl));
#else
        ret = ProcessFile(ssl->ctx, file, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, ssl,
            1, NULL, GET_VERIFY_SETTING_SSL(ssl));
#endif
        /* Return 1 on success or 0 on failure. */
        ret = WS_RC(ret);
    }

   return ret;
}

/* Load a certificate chain from a file into SSL.
 *
 * @param [in, out] ssl     SSL object.
 * @param [in]      file    Name of file.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  BAD_FUNC_ARG when ssl is NULL.
 */
int wolfSSL_use_certificate_chain_file_format(WOLFSSL* ssl, const char* file,
    int format)
{
    int ret;

    /* process up to MAX_CHAIN_DEPTH plus subject cert */
    WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file_format");

    /* Validate parameters. */
    if (ssl == NULL) {
        ret = BAD_FUNC_ARG;
    }
    else {
        ret = ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 1, NULL,
            GET_VERIFY_SETTING_SSL(ssl));
        /* Return 1 on success or 0 on failure. */
        ret = WS_RC(ret);
    }

    return ret;
}

#endif /* !NO_FILESYSTEM */

#ifdef OPENSSL_EXTRA

#ifndef NO_FILESYSTEM
/* Load an RSA private key from a file into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      file    Name of file.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_use_RSAPrivateKey_file(WOLFSSL_CTX* ctx,const char* file,
    int format)
{
    WOLFSSL_ENTER("wolfSSL_CTX_use_RSAPrivateKey_file");

    return wolfSSL_CTX_use_PrivateKey_file(ctx, file, format);
}

/* Load an RSA private key from a file into SSL.
 *
 * @param [in, out] ssl     SSL object.
 * @param [in]      file    Name of file.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  BAD_FUNC_ARG when ssl is NULL.
 */
int wolfSSL_use_RSAPrivateKey_file(WOLFSSL* ssl, const char* file, int format)
{
    WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_file");

    return wolfSSL_use_PrivateKey_file(ssl, file, format);
}
#endif /* NO_FILESYSTEM */

#endif /* OPENSSL_EXTRA */

/* Load a buffer of certificate/s into SSL context.
 *
 * @param [in, out] ctx        SSL context object.
 * @param [in]      in         Buffer holding certificate or private key.
 * @param [in]      sz         Length of data in buffer in bytes.
 * @param [in]      format     Format of data:
 *                               WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @param [in]      userChain  Whether file contains chain of certificates.
 * @param [in]      flags      Flags representing options for loading.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  Negative on error.
 */
int wolfSSL_CTX_load_verify_buffer_ex(WOLFSSL_CTX* ctx, const unsigned char* in,
    long sz, int format, int userChain, word32 flags)
{
    int ret;
    int verify;

    WOLFSSL_ENTER("wolfSSL_CTX_load_verify_buffer_ex");

#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
    /* TEST ONLY CODE: force native cert validation on */
    if (ctx != NULL) {
        WOLFSSL_MSG("ANCV Test: loading system CA certs");
        wolfSSL_CTX_load_system_CA_certs(ctx);
    }
#endif

    /* Get setting on how to verify certificates. */
    verify = GET_VERIFY_SETTING_CTX(ctx);
    /* Overwrite setting when flag set. */
    if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) {
        verify = VERIFY_SKIP_DATE;
    }

    /* When PEM, treat as certificate chain of CA certificates. */
    if (format == WOLFSSL_FILETYPE_PEM) {
        ret = ProcessChainBuffer(ctx, NULL, in, sz, CA_TYPE, verify,
                                 "PEM buffer");
    }
    /* When DER, load the CA certificate. */
    else {
        ret = ProcessBuffer(ctx, in, sz, format, CA_TYPE, NULL, NULL,
            userChain, verify, "buffer");
    }
#if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS)
    if (ret == 1) {
        /* Load certificate/s as trusted peer certificate. */
        ret = wolfSSL_CTX_trust_peer_buffer(ctx, in, sz, format);
    }
#endif

    WOLFSSL_LEAVE("wolfSSL_CTX_load_verify_buffer_ex", ret);
    return ret;
}

/* Load a buffer of certificate/s into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      in      Buffer holding certificate or private key.
 * @param [in]      sz      Length of data in buffer in bytes.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  Negative on error.
 */
int wolfSSL_CTX_load_verify_buffer(WOLFSSL_CTX* ctx, const unsigned char* in,
    long sz, int format)
{
    return wolfSSL_CTX_load_verify_buffer_ex(ctx, in, sz, format, 0,
        WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS);
}

/* Load a buffer of certificate chain into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      in      Buffer holding certificate chain.
 * @param [in]      sz      Length of data in buffer in bytes.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  Negative on error.
 */
int wolfSSL_CTX_load_verify_chain_buffer_format(WOLFSSL_CTX* ctx,
    const unsigned char* in, long sz, int format)
{
    return wolfSSL_CTX_load_verify_buffer_ex(ctx, in, sz, format, 1,
        WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS);
}


#ifdef WOLFSSL_TRUST_PEER_CERT
/* Load a buffer of certificate/s into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      in      Buffer holding certificate/s.
 * @param [in]      sz      Length of data in buffer in bytes.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  BAD_FUNC_ARG when ctx or in is NULL, or sz is less than zero.
 */
int wolfSSL_CTX_trust_peer_buffer(WOLFSSL_CTX* ctx, const unsigned char* in,
    long sz, int format)
{
    int ret;
    int verify;

    WOLFSSL_ENTER("wolfSSL_CTX_trust_peer_buffer");

    /* Validate parameters. */
    if ((ctx == NULL) || (in == NULL) || (sz < 0)) {
        ret = BAD_FUNC_ARG;
    }
    else {
    #if WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY
        verify = VERIFY_SKIP_DATE;
    #else
        verify = GET_VERIFY_SETTING_CTX(ctx);
    #endif

        /* When PEM, treat as certificate chain of trusted peer certificates. */
        if (format == WOLFSSL_FILETYPE_PEM) {
            ret = ProcessChainBuffer(ctx, NULL, in, sz, TRUSTED_PEER_TYPE,
                verify, "peer");
        }
        /* When DER, load the trusted peer certificate. */
        else {
            ret = ProcessBuffer(ctx, in, sz, format, TRUSTED_PEER_TYPE, NULL,
                NULL, 0, verify, "peer");
        }
    }

    return ret;
}
#endif /* WOLFSSL_TRUST_PEER_CERT */

/* Load a certificate in a buffer into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      in      Buffer holding certificate.
 * @param [in]      sz      Size of data in bytes.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  Negative on error.
 */
int wolfSSL_CTX_use_certificate_buffer(WOLFSSL_CTX* ctx,
    const unsigned char* in, long sz, int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_buffer");
    ret = ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 0,
        GET_VERIFY_SETTING_CTX(ctx), "buffer");
    WOLFSSL_LEAVE("wolfSSL_CTX_use_certificate_buffer", ret);

    return ret;
}

/* Load a private key in a buffer into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      in      Buffer holding private key.
 * @param [in]      sz      Size of data in bytes.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  Negative on error.
 */
int wolfSSL_CTX_use_PrivateKey_buffer(WOLFSSL_CTX* ctx, const unsigned char* in,
    long sz, int format)
{
    int ret;
    long consumed = 0;

    WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_buffer");

    ret = ProcessBuffer(ctx, in, sz, format, PRIVATEKEY_TYPE, NULL, &consumed,
        0, GET_VERIFY_SETTING_CTX(ctx), "key buffer");
#ifdef WOLFSSL_DUAL_ALG_CERTS
    if ((ret == 1) && (consumed < sz)) {
        /* When support for dual algorithm certificates is enabled, the
         * buffer may contain both the primary and the alternative
         * private key. Hence, we have to parse both of them.
         */
        ret = ProcessBuffer(ctx, in + consumed, sz - consumed, format,
            ALT_PRIVATEKEY_TYPE, NULL, NULL, 0, GET_VERIFY_SETTING_CTX(ctx),
            "key buffer");
    }
#endif

    (void)consumed;

    WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_buffer", ret);
    return ret;
}

#ifdef WOLFSSL_DUAL_ALG_CERTS
int wolfSSL_CTX_use_AltPrivateKey_buffer(WOLFSSL_CTX* ctx,
    const unsigned char* in, long sz, int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_buffer");
    ret = ProcessBuffer(ctx, in, sz, format, ALT_PRIVATEKEY_TYPE, NULL,
        NULL, 0, GET_VERIFY_SETTING_CTX(ctx), "alt key buffer");
    WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_buffer", ret);

    return ret;
}
#endif /* WOLFSSL_DUAL_ALG_CERTS */

#ifdef WOLF_PRIVATE_KEY_ID
/* Load the id of a private key into SSL context.
 *
 * @param [in, out] ctx    SSL context object.
 * @param [in]      id     Buffer holding id.
 * @param [in]      sz     Size of data in bytes.
 * @param [in]      devId  Device identifier.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_use_PrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id,
    long sz, int devId)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_Id");

    if (ctx == NULL || id == NULL || sz < 0) {
        return 0;
    }

    /* Dispose of old private key and allocate and copy in id. */
    FreeDer(&ctx->privateKey);
    if (AllocCopyDer(&ctx->privateKey, id, (word32)sz, PRIVATEKEY_TYPE,
            ctx->heap) != 0) {
        ret = 0;
    }
    if (ret == 1) {
        /* Private key is an id. */
        ctx->privateKeyId = 1;
        ctx->privateKeyLabel = 0;
        /* Set private key device id to be one passed in or for SSL context. */
        if (devId != INVALID_DEVID) {
            ctx->privateKeyDevId = devId;
        }
        else {
            ctx->privateKeyDevId = ctx->devId;
        }

    #ifdef WOLFSSL_DUAL_ALG_CERTS
        /* Set the ID for the alternative key, too. User can still override that
         * afterwards. */
        ret = wolfSSL_CTX_use_AltPrivateKey_Id(ctx, id, sz, devId);
    #endif
    }

    WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_Id", ret);
    return ret;
}

/* Load the id of a private key into SSL context and set key size.
 *
 * @param [in, out] ctx    SSL context object.
 * @param [in]      id     Buffer holding id.
 * @param [in]      sz     Size of data in bytes.
 * @param [in]      devId  Device identifier.
 * @param [in]      keySz  Size of key.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_use_PrivateKey_Id_ex(WOLFSSL_CTX* ctx, const unsigned char* id,
    long sz, int devId, long keySz)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_Id_ex");

    ret = wolfSSL_CTX_use_PrivateKey_Id(ctx, id, sz, devId);
    if (ret == 1) {
        /* Set the key size which normally is calculated during decoding. */
        ctx->privateKeySz = (int)keySz;
    }

    WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_Id_ex", ret);
    return ret;
}

/* Load the label name of a private key into SSL context.
 *
 * @param [in, out] ctx    SSL context object.
 * @param [in]      label  Buffer holding label.
 * @param [in]      devId  Device identifier.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_use_PrivateKey_Label(WOLFSSL_CTX* ctx, const char* label,
    int devId)
{
    int ret = 1;
    word32 sz;

    WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_Label");

    if (ctx == NULL || label == NULL) {
        return 0;
    }

    sz = (word32)XSTRLEN(label) + 1;

    /* Dispose of old private key and allocate and copy in label. */
    FreeDer(&ctx->privateKey);
    if (AllocCopyDer(&ctx->privateKey, (const byte*)label, (word32)sz,
            PRIVATEKEY_TYPE, ctx->heap) != 0) {
        ret = 0;
    }
    if (ret == 1) {
        /* Private key is a label. */
        ctx->privateKeyId = 0;
        ctx->privateKeyLabel = 1;
        /* Set private key device id to be one passed in or for SSL context. */
        if (devId != INVALID_DEVID) {
            ctx->privateKeyDevId = devId;
        }
        else {
            ctx->privateKeyDevId = ctx->devId;
        }

    #ifdef WOLFSSL_DUAL_ALG_CERTS
        /* Set the ID for the alternative key, too. User can still override that
         * afterwards. */
        ret = wolfSSL_CTX_use_AltPrivateKey_Label(ctx, label, devId);
    #endif
    }

    WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_Label", ret);
    return ret;
}

#ifdef WOLFSSL_DUAL_ALG_CERTS
int wolfSSL_CTX_use_AltPrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id,
    long sz, int devId)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_Id");

    if ((ctx == NULL) || (id == NULL) || (sz < 0)) {
        ret = 0;
    }

    if (ret == 1) {
        FreeDer(&ctx->altPrivateKey);
        if (AllocDer(&ctx->altPrivateKey, (word32)sz, ALT_PRIVATEKEY_TYPE,
                ctx->heap) != 0) {
            ret = 0;
        }
    }
    if (ret == 1) {
        XMEMCPY(ctx->altPrivateKey->buffer, id, (word32)sz);
        ctx->altPrivateKeyId = 1;
        if (devId != INVALID_DEVID) {
            ctx->altPrivateKeyDevId = devId;
        }
        else {
            ctx->altPrivateKeyDevId = ctx->devId;
        }
    }

    WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_Id", ret);
    return ret;
}

int wolfSSL_CTX_use_AltPrivateKey_Id_ex(WOLFSSL_CTX* ctx,
    const unsigned char* id, long sz, int devId, long keySz)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_Id_ex");

    ret = wolfSSL_CTX_use_AltPrivateKey_Id(ctx, id, sz, devId);
    if (ret == 1) {
        ctx->altPrivateKeySz = (word32)keySz;
    }

    WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_Id_ex", ret);
    return ret;
}

int wolfSSL_CTX_use_AltPrivateKey_Label(WOLFSSL_CTX* ctx, const char* label,
    int devId)
{
    int ret = 1;
    word32 sz;

    WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_Label");

    if ((ctx == NULL) || (label == NULL)) {
        ret = 0;
    }

    if (ret == 1) {
        sz = (word32)XSTRLEN(label) + 1;
        FreeDer(&ctx->altPrivateKey);
        if (AllocDer(&ctx->altPrivateKey, (word32)sz, ALT_PRIVATEKEY_TYPE,
                ctx->heap) != 0) {
            ret = 0;
        }
    }
    if (ret == 1) {
        XMEMCPY(ctx->altPrivateKey->buffer, label, sz);
        ctx->altPrivateKeyLabel = 1;
        if (devId != INVALID_DEVID) {
            ctx->altPrivateKeyDevId = devId;
        }
        else {
            ctx->altPrivateKeyDevId = ctx->devId;
        }
    }

    WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_Label", ret);
    return ret;
}
#endif /* WOLFSSL_DUAL_ALG_CERTS */
#endif /* WOLF_PRIVATE_KEY_ID */

#if defined(WOLF_CRYPTO_CB) && !defined(NO_CERTS)

static int wolfSSL_CTX_use_certificate_ex(WOLFSSL_CTX* ctx,
    const char *label, const unsigned char *id, int idLen, int devId)
{
    int ret;
    byte *certData = NULL;
    word32 certDataLen = 0;
    word32 labelLen = 0;
    int certFormat = 0;

    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_ex");

    if (label != NULL) {
        labelLen = (word32)XSTRLEN(label);
    }

    ret = wc_CryptoCb_GetCert(devId, label, labelLen, id, idLen,
        &certData, &certDataLen, &certFormat, ctx->heap);
    if (ret != 0) {
        ret = WOLFSSL_FAILURE;
        goto exit;
    }

    ret = ProcessBuffer(ctx, certData, certDataLen, certFormat,
        CERT_TYPE, NULL, NULL, 0, GET_VERIFY_SETTING_CTX(ctx),
        label ? label : "cert buffer");

exit:
    XFREE(certData, ctx->heap, DYNAMIC_TYPE_CERT);
    return ret;
}

/* Load the label name of a certificate into the SSL context.
 *
 * @param [in, out] ctx    SSL context object.
 * @param [in]      label  Buffer holding label.
 * @param [in]      devId  Device identifier.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_use_certificate_label(WOLFSSL_CTX* ctx,
    const char *label, int devId)
{
    if ((ctx == NULL) || (label == NULL)) {
        return WOLFSSL_FAILURE;
    }

    return wolfSSL_CTX_use_certificate_ex(ctx, label, NULL, 0, devId);
}

/* Load the id of a certificate into SSL context.
 *
 * @param [in, out] ctx    SSL context object.
 * @param [in]      id     Buffer holding id.
 * @param [in]      idLen  Size of data in bytes.
 * @param [in]      devId  Device identifier.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_use_certificate_id(WOLFSSL_CTX* ctx,
    const unsigned char *id, int idLen, int devId)
{
    if ((ctx == NULL) || (id == NULL) || (idLen <= 0)) {
        return WOLFSSL_FAILURE;
    }

    return wolfSSL_CTX_use_certificate_ex(ctx, NULL, id, idLen, devId);
}

#endif /* if defined(WOLF_CRYPTO_CB) && !defined(NO_CERTS) */

/* Load a certificate chain in a buffer into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      in      Buffer holding DER encoded certificate chain.
 * @param [in]      sz      Size of data in bytes.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  Negative on error.
 */
int wolfSSL_CTX_use_certificate_chain_buffer_format(WOLFSSL_CTX* ctx,
    const unsigned char* in, long sz, int format)
{
    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_buffer_format");
    return ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 1,
        GET_VERIFY_SETTING_CTX(ctx), "cert chain buffer");
}

/* Load a PEM encoded certificate chain in a buffer into SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      in      Buffer holding DER encoded certificate chain.
 * @param [in]      sz      Size of data in bytes.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  Negative on error.
 */
int wolfSSL_CTX_use_certificate_chain_buffer(WOLFSSL_CTX* ctx,
    const unsigned char* in, long sz)
{
#ifdef WOLFSSL_PEM_TO_DER
    return wolfSSL_CTX_use_certificate_chain_buffer_format(ctx, in, sz,
        WOLFSSL_FILETYPE_PEM);
#else
    return wolfSSL_CTX_use_certificate_chain_buffer_format(ctx, in, sz,
        WOLFSSL_FILETYPE_ASN1);
#endif
}

/* Load a user certificate in a buffer into SSL.
 *
 * @param [in, out] ssl     SSL object.
 * @param [in]      in      Buffer holding user certificate.
 * @param [in]      sz      Size of data in bytes.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  BAD_FUNC_ARG when ssl is NULL.
 */
int wolfSSL_use_certificate_buffer(WOLFSSL* ssl, const unsigned char* in,
    long sz, int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_use_certificate_buffer");

    /* Validate parameters. */
    if (ssl == NULL) {
        ret = BAD_FUNC_ARG;
    }
    else {
        ret = ProcessBuffer(ssl->ctx, in, sz, format, CERT_TYPE, ssl, NULL, 0,
            GET_VERIFY_SETTING_SSL(ssl), "cert buffer");
    }

    return ret;
}

/* Load a private key in a buffer into SSL.
 *
 * @param [in, out] ssl     SSL object.
 * @param [in]      in      Buffer holding private key.
 * @param [in]      sz      Size of data in bytes.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  BAD_FUNC_ARG when ssl is NULL.
 */
int wolfSSL_use_PrivateKey_buffer(WOLFSSL* ssl, const unsigned char* in,
    long sz, int format)
{
    int ret;
    long consumed = 0;

    WOLFSSL_ENTER("wolfSSL_use_PrivateKey_buffer");

    /* Validate parameters. */
    if (ssl == NULL) {
        ret = BAD_FUNC_ARG;
    }
    else {
        ret = ProcessBuffer(ssl->ctx, in, sz, format, PRIVATEKEY_TYPE, ssl,
            &consumed, 0, GET_VERIFY_SETTING_SSL(ssl), "key buffer");
    #ifdef WOLFSSL_DUAL_ALG_CERTS
        if ((ret == 1) && (consumed < sz)) {
            /* When support for dual algorithm certificates is enabled, the
             * buffer may contain both the primary and the alternative
             * private key. Hence, we have to parse both of them.
             */
            ret = ProcessBuffer(ssl->ctx, in + consumed, sz - consumed, format,
                ALT_PRIVATEKEY_TYPE, ssl, NULL, 0, GET_VERIFY_SETTING_SSL(ssl),
                "key buffer");
        }
    #endif
    }

    return ret;
}

#ifdef WOLFSSL_DUAL_ALG_CERTS
int wolfSSL_use_AltPrivateKey_buffer(WOLFSSL* ssl, const unsigned char* in,
    long sz, int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_use_AltPrivateKey_buffer");
    ret = ProcessBuffer(ssl->ctx, in, sz, format, ALT_PRIVATEKEY_TYPE, ssl,
        NULL, 0, GET_VERIFY_SETTING_SSL(ssl), "alt key buffer");
    WOLFSSL_LEAVE("wolfSSL_use_AltPrivateKey_buffer", ret);

    return ret;
}
#endif /* WOLFSSL_DUAL_ALG_CERTS */

#ifdef WOLF_PRIVATE_KEY_ID
/* Load the id of a private key into SSL.
 *
 * @param [in, out] ssl    SSL object.
 * @param [in]      id     Buffer holding id.
 * @param [in]      sz     Size of data in bytes.
 * @param [in]      devId  Device identifier.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_use_PrivateKey_Id(WOLFSSL* ssl, const unsigned char* id,
                              long sz, int devId)
{
    int ret = 1;

    if (ssl == NULL || id == NULL || sz < 0) {
        return 0;
    }

    /* Dispose of old private key if owned and allocate and copy in id. */
    if (ssl->buffers.weOwnKey) {
        FreeDer(&ssl->buffers.key);
    #ifdef WOLFSSL_BLIND_PRIVATE_KEY
        FreeDer(&ssl->buffers.keyMask);
    #endif
    }
    if (AllocCopyDer(&ssl->buffers.key, id, (word32)sz, PRIVATEKEY_TYPE,
            ssl->heap) != 0) {
        ret = 0;
    }
    if (ret == 1) {
        /* Buffer now ours. */
        ssl->buffers.weOwnKey = 1;
        /* Private key is an id. */
        ssl->buffers.keyId = 1;
        ssl->buffers.keyLabel = 0;
        /* Set private key device id to be one passed in or for SSL. */
        if (devId != INVALID_DEVID) {
            ssl->buffers.keyDevId = devId;
        }
        else {
            ssl->buffers.keyDevId = ssl->devId;
        }

    #ifdef WOLFSSL_DUAL_ALG_CERTS
        /* Set the ID for the alternative key, too. User can still override that
         * afterwards. */
        ret = wolfSSL_use_AltPrivateKey_Id(ssl, id, sz, devId);
    #endif
    }

    return ret;
}

/* Load the id of a private key into SSL and set key size.
 *
 * @param [in, out] ssl    SSL object.
 * @param [in]      id     Buffer holding id.
 * @param [in]      sz     Size of data in bytes.
 * @param [in]      devId  Device identifier.
 * @param [in]      keySz  Size of key.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_use_PrivateKey_Id_ex(WOLFSSL* ssl, const unsigned char* id,
    long sz, int devId, long keySz)
{
    int ret = wolfSSL_use_PrivateKey_Id(ssl, id, sz, devId);
    if (ret == 1) {
        /* Set the key size which normally is calculated during decoding. */
        ssl->buffers.keySz = (int)keySz;
    }

    return ret;
}

/* Load the label name of a private key into SSL.
 *
 * @param [in, out] ssl    SSL object.
 * @param [in]      label  Buffer holding label.
 * @param [in]      devId  Device identifier.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_use_PrivateKey_Label(WOLFSSL* ssl, const char* label, int devId)
{
    int ret = 1;
    word32 sz;

    if (ssl == NULL || label == NULL) {
        return 0;
    }

    sz = (word32)XSTRLEN(label) + 1;

    /* Dispose of old private key if owned and allocate and copy in label. */
    if (ssl->buffers.weOwnKey) {
        FreeDer(&ssl->buffers.key);
    #ifdef WOLFSSL_BLIND_PRIVATE_KEY
        FreeDer(&ssl->buffers.keyMask);
    #endif
    }
    if (AllocCopyDer(&ssl->buffers.key, (const byte*)label, (word32)sz,
            PRIVATEKEY_TYPE, ssl->heap) != 0) {
        ret = 0;
    }
    if (ret == 1) {
        /* Buffer now ours. */
        ssl->buffers.weOwnKey = 1;
        /* Private key is a label. */
        ssl->buffers.keyId = 0;
        ssl->buffers.keyLabel = 1;
        /* Set private key device id to be one passed in or for SSL. */
        if (devId != INVALID_DEVID) {
            ssl->buffers.keyDevId = devId;
        }
        else {
            ssl->buffers.keyDevId = ssl->devId;
        }

    #ifdef WOLFSSL_DUAL_ALG_CERTS
        /* Set the label for the alternative key, too. User can still override
         * that afterwards. */
        ret = wolfSSL_use_AltPrivateKey_Label(ssl, label, devId);
    #endif
    }

    return ret;
}

#ifdef WOLFSSL_DUAL_ALG_CERTS
int wolfSSL_use_AltPrivateKey_Id(WOLFSSL* ssl, const unsigned char* id, long sz,
    int devId)
{
    int ret = 1;

    if ((ssl == NULL) || (id == NULL) || (sz < 0)) {
        ret = 0;
    }

    if (ret == 1) {
        if (ssl->buffers.weOwnAltKey) {
            FreeDer(&ssl->buffers.altKey);
        #ifdef WOLFSSL_BLIND_PRIVATE_KEY
            FreeDer(&ssl->buffers.altKeyMask);
        #endif
        }
        if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE,
                ssl->heap) != 0) {
            ret = 0;
        }
    }
    if (ret == 1) {
        XMEMCPY(ssl->buffers.altKey->buffer, id, (word32)sz);
        ssl->buffers.weOwnAltKey = 1;
        ssl->buffers.altKeyId = 1;
        if (devId != INVALID_DEVID) {
            ssl->buffers.altKeyDevId = devId;
        }
        else {
            ssl->buffers.altKeyDevId = ssl->devId;
        }
    }

    return ret;
}

int wolfSSL_use_AltPrivateKey_Id_ex(WOLFSSL* ssl, const unsigned char* id,
    long sz, int devId, long keySz)
{
    int ret = wolfSSL_use_AltPrivateKey_Id(ssl, id, sz, devId);
    if (ret == 1) {
        ssl->buffers.altKeySz = (word32)keySz;
    }

    return ret;
}

int wolfSSL_use_AltPrivateKey_Label(WOLFSSL* ssl, const char* label, int devId)
{
    int ret = 1;
    word32 sz;

    if ((ssl == NULL) || (label == NULL)) {
        ret = 0;
    }

    if (ret == 1) {
        sz = (word32)XSTRLEN(label) + 1;
        if (ssl->buffers.weOwnAltKey) {
            FreeDer(&ssl->buffers.altKey);
        #ifdef WOLFSSL_BLIND_PRIVATE_KEY
            FreeDer(&ssl->buffers.altKeyMask);
        #endif
        }
        if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE,
                ssl->heap) != 0) {
            ret = 0;
        }
    }
    if (ret == 1) {
        XMEMCPY(ssl->buffers.altKey->buffer, label, sz);
        ssl->buffers.weOwnAltKey = 1;
        ssl->buffers.altKeyLabel = 1;
        if (devId != INVALID_DEVID) {
            ssl->buffers.altKeyDevId = devId;
        }
        else {
            ssl->buffers.altKeyDevId = ssl->devId;
        }
    }

    return ret;
}
#endif /* WOLFSSL_DUAL_ALG_CERTS */
#endif /* WOLF_PRIVATE_KEY_ID */

/* Load a certificate chain in a buffer into SSL.
 *
 * @param [in, out] ssl     SSL object.
 * @param [in]      in      Buffer holding DER encoded certificate chain.
 * @param [in]      sz      Size of data in bytes.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  BAD_FUNC_ARG when ssl is NULL.
 */
int wolfSSL_use_certificate_chain_buffer_format(WOLFSSL* ssl,
    const unsigned char* in, long sz, int format)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_use_certificate_chain_buffer_format");

    /* Validate parameters. */
    if (ssl == NULL) {
        ret = BAD_FUNC_ARG;
    }
    else {
        ret = ProcessBuffer(ssl->ctx, in, sz, format, CERT_TYPE, ssl, NULL, 1,
            GET_VERIFY_SETTING_SSL(ssl), "cert chain buffer");
    }

    return ret;
}

/* Load a PEM encoded certificate chain in a buffer into SSL.
 *
 * @param [in, out] ssl     SSL object.
 * @param [in]      in      Buffer holding DER encoded certificate chain.
 * @param [in]      sz      Size of data in bytes.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  Negative on error.
 */
int wolfSSL_use_certificate_chain_buffer(WOLFSSL* ssl, const unsigned char* in,
    long sz)
{
#ifdef WOLFSSL_PEM_TO_DER
    return wolfSSL_use_certificate_chain_buffer_format(ssl, in, sz,
        WOLFSSL_FILETYPE_PEM);
#else
    return wolfSSL_use_certificate_chain_buffer_format(ssl, in, sz,
        WOLFSSL_FILETYPE_ASN1);
#endif
}

#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \
    defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \
    defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \
    defined(WOLFSSL_HAPROXY)
/* Add certificate to chain.
 *
 * @param [in, out] chain   Buffer holding encoded certificate for TLS.
 * @param [in]      weOwn   Indicates we need to free chain if repleced.
 * @param [in]      cert    Buffer holding DER encoded certificate.
 * @param [in]      certSz  Size of DER encoded certificate in bytes.
 * @param [in]      heap    Dynamic memory allocation hint.
 * @return  1 on success.
 * @return  0 on failure.
 */
static int wolfssl_add_to_chain(DerBuffer** chain, int weOwn, const byte* cert,
    word32 certSz, void* heap)
{
    int res = 1;
    int ret;
    DerBuffer* oldChain = *chain;
    DerBuffer* newChain = NULL;
    word32 len = 0;

    if (oldChain != NULL) {
        /* Get length of previous chain. */
        len = oldChain->length;
    }
    /* Check for integer overflow in size calculation. */
    if ((len > WOLFSSL_MAX_32BIT - CERT_HEADER_SZ) ||
            (certSz > WOLFSSL_MAX_32BIT - CERT_HEADER_SZ - len)) {
        WOLFSSL_MSG("wolfssl_add_to_chain overflow");
        res = 0;
    }
    if (res == 1) {
        /* Allocate DER buffer big enough to hold old and new certificates. */
        ret = AllocDer(&newChain, len + CERT_HEADER_SZ + certSz, CERT_TYPE,
            heap);
        if (ret != 0) {
            WOLFSSL_MSG("AllocDer error");
            res = 0;
        }
    }

    if (res == 1) {
        if (oldChain != NULL) {
            /* Place old chain in new buffer. */
            XMEMCPY(newChain->buffer, oldChain->buffer, len);
        }
        /* Append length and DER encoded certificate. */
        c32to24(certSz, newChain->buffer + len);
        XMEMCPY(newChain->buffer + len + CERT_HEADER_SZ, cert, certSz);

        /* Dispose of old chain if we own it. */
        if (weOwn) {
            FreeDer(chain);
        }
        /* Replace chain. */
        *chain = newChain;
    }

    return res;
}
#endif

#ifdef OPENSSL_EXTRA

/* Add a certificate to end of chain sent in TLS handshake.
 *
 * @param [in, out] ctx    SSL context.
 * @param [in]      der    Buffer holding DER encoded certificate.
 * @param [in]      derSz  Size of data in buffer.
 * @return  1 on success.
 * @return  0 on failure.
 */
static int wolfssl_ctx_add_to_chain(WOLFSSL_CTX* ctx, const byte* der,
    int derSz)
{
    int res = 1;
    int ret;
    DerBuffer* derBuffer = NULL;

    /* Create a DER buffer from DER encoding. */
    ret = AllocCopyDer(&derBuffer, der, (word32)derSz, CERT_TYPE, ctx->heap);
    if (ret != 0) {
        WOLFSSL_MSG("Memory Error");
        res = 0;
    }
    if (res == 1) {
        /* Add a user CA certificate to the certificate manager. */
        res = AddCA(ctx->cm, &derBuffer, WOLFSSL_USER_CA,
            GET_VERIFY_SETTING_CTX(ctx));
        if (res != 1) {
            res = 0;
        }
    }

    if (res == 1) {
         /* Add chain to DER buffer. */
         res = wolfssl_add_to_chain(&ctx->certChain, 1, der, (word32)derSz,
             ctx->heap);
    #ifdef WOLFSSL_TLS13
        /* Update count of certificates. */
        ctx->certChainCnt++;
    #endif
    }

    return res;
}

/* Add a certificate to chain sent in TLS handshake.
 *
 * @param [in, out] ctx   SSL context.
 * @param [in]      x509  X509 certificate object.
 * @return  1 on success.
 * @return  0 on failure.
 */
long wolfSSL_CTX_add_extra_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509)
{
    int   ret = 1;
    int   derSz = 0;
    const byte* der = NULL;

    WOLFSSL_ENTER("wolfSSL_CTX_add_extra_chain_cert");

    /* Validate parameters. */
    if ((ctx == NULL) || (x509 == NULL)) {
        WOLFSSL_MSG("Bad Argument");
        ret = 0;
    }

    if (ret == 1) {
        /* Get the DER encoding of the certificate from the X509 object. */
        der = wolfSSL_X509_get_der(x509, &derSz);
        /* Validate buffer. */
        if ((der == NULL) || (derSz <= 0)) {
            WOLFSSL_MSG("Error getting X509 DER");
            ret = 0;
        }
    }

    if ((ret == 1) && (ctx->certificate == NULL)) {
        WOLFSSL_ENTER("wolfSSL_use_certificate_chain_buffer_format");

        /* Process buffer makes first certificate the leaf. */
        ret = ProcessBuffer(ctx, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE,
            NULL, NULL, 1, GET_VERIFY_SETTING_CTX(ctx), "extra chain buffer");
        if (ret != 1) {
            ret = 0;
        }
    }
    else if (ret == 1) {
        /* Add certificate to existing chain. */
        ret = wolfssl_ctx_add_to_chain(ctx, der, derSz);
    }

    if (ret == 1) {
        /* On success WOLFSSL_X509 memory is responsibility of SSL context. */
        wolfSSL_X509_free(x509);
        x509 = NULL;
    }

    WOLFSSL_LEAVE("wolfSSL_CTX_add_extra_chain_cert", ret);
    return ret;
}

#endif /* OPENSSL_EXTRA */

#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \
    defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \
    defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \
    defined(WOLFSSL_HAPROXY)
/* Load a certificate into SSL context.
 *
 * @param [in, out] ctx   SSL context object.
 * @param [in]      x509  X509 certificate object.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_use_certificate(WOLFSSL_CTX *ctx, WOLFSSL_X509 *x)
{
    int res = 1;
    int ret;

    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate");

    /* Validate parameters. */
    if ((ctx == NULL) || (x == NULL) || (x->derCert == NULL)) {
        WOLFSSL_MSG("Bad parameter");
        res = 0;
    }

    if (res == 1) {
        /* Replace certificate buffer with one holding the new certificate. */
        FreeDer(&ctx->certificate);
        ret = AllocCopyDer(&ctx->certificate, x->derCert->buffer,
            x->derCert->length, CERT_TYPE, ctx->heap);
        if (ret != 0) {
            res = 0;
        }
    }

#ifdef KEEP_OUR_CERT
    if (res == 1) {
        /* Dispose of our certificate if it is ours. */
        if ((ctx->ourCert != NULL) && ctx->ownOurCert) {
            wolfSSL_X509_free(ctx->ourCert);
        }
    #ifndef WOLFSSL_X509_STORE_CERTS
        /* Keep a reference to the new certificate. */
        ctx->ourCert = x;
        if (wolfSSL_X509_up_ref(x) != 1) {
            res = 0;
        }
    #else
        /* Keep a copy of the new certificate. */
        ctx->ourCert = wolfSSL_X509_d2i_ex(NULL, x->derCert->buffer,
            x->derCert->length, ctx->heap);
        if (ctx->ourCert == NULL) {
            res = 0;
        }
    #endif
        /* Now own our certificate. */
        ctx->ownOurCert = 1;
    }
#endif

    if (res == 1) {
        /* Set have options based on public key OID. */
        wolfssl_set_have_from_key_oid(ctx, NULL, x->pubKeyOID);
    }

    return res;
}

/* Add the certificate to the chain in the SSL context and own the X509 object.
 *
 * @param [in, out] ctx   SSL context object.
 * @param [in]      x509  X509 certificate object.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_add0_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_CTX_add0_chain_cert");

    /* Add certificate to chain and copy or up reference it. */
    ret = wolfSSL_CTX_add1_chain_cert(ctx, x509);
    if (ret == 1) {
        /* Down reference or free original now as we own certificate. */
        wolfSSL_X509_free(x509);
        x509 = NULL;
    }

    return ret;
}

/* Add the certificate to the chain in the SSL context.
 *
 * X509 object copied or up referenced.
 *
 * @param [in, out] ctx   SSL context object.
 * @param [in]      x509  X509 certificate object.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_add1_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_CTX_add1_chain_cert");

    /* Validate parameters. */
    if ((ctx == NULL) || (x509 == NULL) || (x509->derCert == NULL)) {
        ret = 0;
    }

    /* Check if we already have set a certificate. */
    if ((ret == 1) && (ctx->certificate == NULL)) {
        /* Use the certificate. */
        ret = wolfSSL_CTX_use_certificate(ctx, x509);
    }
    /* Increase reference count as we will store it. */
    else if ((ret == 1) && ((ret = wolfSSL_X509_up_ref(x509)) == 1)) {
        /* Load the DER encoding. */
        ret = wolfSSL_CTX_load_verify_buffer(ctx, x509->derCert->buffer,
            x509->derCert->length, WOLFSSL_FILETYPE_ASN1);
        if (ret == 1) {
            /* Add DER encoding to chain. */
            ret = wolfssl_add_to_chain(&ctx->certChain, 1,
                x509->derCert->buffer, x509->derCert->length, ctx->heap);
        }
        /* Store cert in stack to free it later. */
        if ((ret == 1) && (ctx->x509Chain == NULL)) {
            /* Create a stack for certificates. */
            ctx->x509Chain = wolfSSL_sk_X509_new_null();
            if (ctx->x509Chain == NULL) {
                WOLFSSL_MSG("wolfSSL_sk_X509_new_null error");
                ret = 0;
            }
        }
        if (ret == 1) {
            /* Push the X509 object onto stack. */
            ret = wolfSSL_sk_X509_push(ctx->x509Chain, x509) > 0
                    ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
        }

        if (ret != 1) {
            /* Decrease reference count on error as we didn't store it. */
            wolfSSL_X509_free(x509);
            x509 = NULL;
        }
    }

    return WS_RC(ret);
}

#ifdef KEEP_OUR_CERT
/* Add the certificate to the chain in the SSL and own the X509 object.
 *
 * @param [in, out] ssl   SSL object.
 * @param [in]      x509  X509 certificate object.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_add0_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_add0_chain_cert");

    /* Validate parameters. */
    if ((ssl == NULL) || (x509 == NULL) || (x509->derCert == NULL)) {
        ret = 0;
    }

    /* Check if we already have set a certificate. */
    if ((ret == 1) && (ssl->buffers.certificate == NULL)) {
        /* Use the certificate. */
        ret = wolfSSL_use_certificate(ssl, x509);
        if (ret == 1) {
            /* Dispose of old certificate if we own it. */
            if (ssl->buffers.weOwnCert) {
                wolfSSL_X509_free(ssl->ourCert);
            }
            /* Store cert to free it later. */
            ssl->ourCert = x509;
            ssl->buffers.weOwnCert = 1;
        }
    }
    else if (ret == 1) {
        /* Add DER encoding to chain. */
        ret = wolfssl_add_to_chain(&ssl->buffers.certChain,
            ssl->buffers.weOwnCertChain, x509->derCert->buffer,
            x509->derCert->length, ssl->heap);
        if (ret == 1) {
            /* We now own cert chain. */
            ssl->buffers.weOwnCertChain = 1;
            /* Create a stack to put certificate into. */
            if (ssl->ourCertChain == NULL) {
                ssl->ourCertChain = wolfSSL_sk_X509_new_null();
                if (ssl->ourCertChain == NULL) {
                    WOLFSSL_MSG("wolfSSL_sk_X509_new_null error");
                    ret = 0;
                }
            }
        }
        if (ret == 1) {
            /* Push X509 object onto stack to be freed. */
            ret = wolfSSL_sk_X509_push(ssl->ourCertChain, x509) > 0
                    ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
        }
    }
    return WS_RC(ret);
}

/* Add the certificate to the chain in the SSL.
 *
 * X509 object is up referenced.
 *
 * @param [in, out] ssl   SSL object.
 * @param [in]      x509  X509 certificate object.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_add1_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_add1_chain_cert");

    /* Validate parameters. */
    if ((ssl == NULL) || (x509 == NULL) || (x509->derCert == NULL)) {
        ret = 0;
    }

    /* Increase reference count on X509 object before adding. */
    if ((ret == 1) && ((ret = wolfSSL_X509_up_ref(x509)) == 1)) {
        /* Add this to the chain. */
        if ((ret = wolfSSL_add0_chain_cert(ssl, x509)) != 1) {
            /* Decrease reference count on error as not stored. */
            wolfSSL_X509_free(x509);
            x509 = NULL;
        }
    }

    return ret;
}
#endif /* KEEP_OUR_CERT */
#endif /* OPENSSL_EXTRA, HAVE_LIGHTY, WOLFSSL_MYSQL_COMPATIBLE, HAVE_STUNNEL,
          WOLFSSL_NGINX, HAVE_POCO_LIB, WOLFSSL_HAPROXY */

#ifdef OPENSSL_EXTRA

/* Load a private key into SSL context.
 *
 * @param [in, out] ctx   SSL context object.
 * @param [in]      pkey  EVP private key.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_use_PrivateKey(WOLFSSL_CTX *ctx, WOLFSSL_EVP_PKEY *pkey)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey");

    /* Validate parameters. */
    if ((ctx == NULL) || (pkey == NULL) || (pkey->pkey.ptr == NULL)) {
        ret = 0;
    }

    if (ret == 1) {
        switch (pkey->type) {
    #if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA)
        case WC_EVP_PKEY_RSA:
            WOLFSSL_MSG("populating RSA key");
            ret = PopulateRSAEvpPkeyDer(pkey);
            break;
    #endif /* (WOLFSSL_KEY_GEN || OPENSSL_EXTRA) && !NO_RSA */
    #if !defined(HAVE_SELFTEST) && (defined(WOLFSSL_KEY_GEN) || \
            defined(WOLFSSL_CERT_GEN)) && !defined(NO_DSA)
        case WC_EVP_PKEY_DSA:
            break;
    #endif /* !HAVE_SELFTEST && (WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN) &&
            * !NO_DSA */
    #ifdef HAVE_ECC
        case WC_EVP_PKEY_EC:
            WOLFSSL_MSG("populating ECC key");
            ret = ECC_populate_EVP_PKEY(pkey, pkey->ecc);
            break;
    #endif
    #ifdef HAVE_ED25519
        case WC_EVP_PKEY_ED25519:
            /* DER is already stored in pkey->pkey.ptr by d2i_evp_pkey. */
            WOLFSSL_MSG("populating Ed25519 key");
            break;
    #endif
    #ifdef HAVE_ED448
        case WC_EVP_PKEY_ED448:
            /* DER is already stored in pkey->pkey.ptr by d2i_evp_pkey. */
            WOLFSSL_MSG("populating Ed448 key");
            break;
    #endif
        default:
            ret = 0;
        }
    }

    if (ret == 1) {
        /* ptr for WOLFSSL_EVP_PKEY struct is expected to be DER format */
        ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx,
            (const unsigned char*)pkey->pkey.ptr, pkey->pkey_sz,
            WOLFSSL_FILETYPE_ASN1);
    }

    return ret;
}

#endif /* OPENSSL_EXTRA */

#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \
    defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT)
/* Load a DER encoded certificate in a buffer into SSL context.
 *
 * @param [in, out] ctx    SSL context object.
 * @param [in]      der    Buffer holding DER encoded certificate.
 * @param [in]      derSz  Size of data in bytes.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_CTX_use_certificate_ASN1(WOLFSSL_CTX *ctx, int derSz,
    const unsigned char *der)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_ASN1");

    /* Validate parameters. */
    if ((ctx == NULL) || (der == NULL)) {
        ret = 0;
    }
    /* Load DER encoded certificate into SSL context. */
    if ((ret == 1) && (wolfSSL_CTX_use_certificate_buffer(ctx, der, derSz,
            WOLFSSL_FILETYPE_ASN1) != 1)) {
        ret = 0;
    }

    return ret;
}

#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA)
/* Load an RSA private key into SSL context.
 *
 * @param [in, out] ctx   SSL context object.
 * @param [in]      rsa   RSA private key.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  BAD_FUNC_ARG when ctx or rsa is NULL.
 * @return  MEMORY_E when dynamic memory allocation fails.
 */
int wolfSSL_CTX_use_RSAPrivateKey(WOLFSSL_CTX* ctx, WOLFSSL_RSA* rsa)
{
    int ret = 1;
    int derSize = 0;
    unsigned char* der = NULL;
    unsigned char* p;

    WOLFSSL_ENTER("wolfSSL_CTX_use_RSAPrivateKey");

    /* Validate parameters. */
    if ((ctx == NULL) || (rsa == NULL)) {
        WOLFSSL_MSG("one or more inputs were NULL");
        ret = BAD_FUNC_ARG;
    }

    /* Get DER encoding size. */
    if ((ret == 1) && ((derSize = wolfSSL_i2d_RSAPrivateKey(rsa, NULL)) <= 0)) {
        ret = 0;
    }

    if (ret == 1) {
        /* Allocate memory to hold DER encoding.. */
        der = (unsigned char*)XMALLOC((size_t)derSize, NULL,
                                            DYNAMIC_TYPE_TMP_BUFFER);
        if (der == NULL) {
            WOLFSSL_MSG("Malloc failure");
            ret = MEMORY_E;
        }
    }

    if (ret == 1) {
        /* Pointer passed in is modified.. */
        p = der;
        /* Encode the RSA key as DER into buffer and get size. */
        if ((derSize = wolfSSL_i2d_RSAPrivateKey(rsa, &p)) <= 0) {
            WOLFSSL_MSG("wolfSSL_i2d_RSAPrivateKey() failure");
            ret = 0;
        }
    }

    if (ret == 1) {
        /* Load DER encoded certificate into SSL context. */
        ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, derSize,
            SSL_FILETYPE_ASN1);
        if (ret != WOLFSSL_SUCCESS) {
            WOLFSSL_MSG("wolfSSL_CTX_USE_PrivateKey_buffer() failure");
            ret = 0;
        }
    }

    /* Dispos of dynamically allocated data. */
    if (der != NULL) {
        ForceZero(der, (word32)derSize);
    }
    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    return ret;
}
#endif /* WOLFSSL_KEY_GEN && !NO_RSA */

#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */

#endif /* !NO_CERTS */

#ifdef OPENSSL_EXTRA

/* Use the default paths to look for CA certificate.
 *
 * This is an OpenSSL compatibility layer function, but it doesn't mirror
 * the exact functionality of its OpenSSL counterpart. We don't support the
 * notion of an "OpenSSL directory". This function will attempt to load the
 * environment variables SSL_CERT_DIR and SSL_CERT_FILE, if either are
 * found, they will be loaded. Otherwise, it will act as a wrapper around
 * our native wolfSSL_CTX_load_system_CA_certs function. This function does
 * conform to OpenSSL's return value conventions.
 *
 * @param [in] ctx  SSL context object.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  WOLFSSL_FATAL_ERROR when using a filesystem is not supported.
 */
int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx)
{
    int ret;
#if defined(XGETENV) && !defined(NO_GETENV)
    char* certDir = NULL;
    char* certFile = NULL;
    word32 flags = 0;
#elif !defined(WOLFSSL_SYS_CA_CERTS)
    (void)ctx;
#endif

    WOLFSSL_ENTER("wolfSSL_CTX_set_default_verify_paths");

#if defined(XGETENV) && !defined(NO_GETENV)
    /* // NOLINTBEGIN(concurrency-mt-unsafe) */
    certDir = wc_strdup_ex(XGETENV("SSL_CERT_DIR"), DYNAMIC_TYPE_TMP_BUFFER);
    certFile = wc_strdup_ex(XGETENV("SSL_CERT_FILE"), DYNAMIC_TYPE_TMP_BUFFER);
    flags = WOLFSSL_LOAD_FLAG_PEM_CA_ONLY;

    if ((certDir != NULL) || (certFile != NULL)) {
        if (certDir != NULL) {
           /* We want to keep trying to load more CA certs even if one cert in
            * the directory is bad and can't be used (e.g. if one is
            * expired), so we use WOLFSSL_LOAD_FLAG_IGNORE_ERR.
            */
            flags |= WOLFSSL_LOAD_FLAG_IGNORE_ERR;
        }

        /* Load CA certificates from environment variable locations. */
        ret = wolfSSL_CTX_load_verify_locations_ex(ctx, certFile, certDir,
            flags);
        if (ret != 1) {
            WOLFSSL_MSG_EX("Failed to load CA certs from SSL_CERT_FILE: %s"
                            " SSL_CERT_DIR: %s. Error: %d", certFile,
                            certDir, ret);
            ret = 0;
        }
    }
    /* // NOLINTEND(concurrency-mt-unsafe) */
    else
#endif

    {
    #ifdef NO_FILESYSTEM
        WOLFSSL_MSG("wolfSSL_CTX_set_default_verify_paths not supported"
                    " with NO_FILESYSTEM enabled");
        ret = WOLFSSL_FATAL_ERROR;
    #elif defined(WOLFSSL_SYS_CA_CERTS)
        /* Load the system CA certificates. */
        ret = wolfSSL_CTX_load_system_CA_certs(ctx);
        if (ret == WC_NO_ERR_TRACE(WOLFSSL_BAD_PATH)) {
            /* OpenSSL doesn't treat the lack of a system CA cert directory as a
             * failure. We do the same here.
             */
            ret = 1;
        }
    #else
        /* No source available: SSL_CERT_DIR/SSL_CERT_FILE not set and
         * WOLFSSL_SYS_CA_CERTS not compiled in. Returning success would be
         * fail-open since no trust anchors were loaded. */
        WOLFSSL_MSG("wolfSSL_CTX_set_default_verify_paths: no CA source "
                    "available (build without WOLFSSL_SYS_CA_CERTS and no "
                    "SSL_CERT_DIR/SSL_CERT_FILE env)");
        ret = WOLFSSL_FAILURE;
    #endif
    }

#if defined(XGETENV) && !defined(NO_GETENV)
    XFREE(certFile, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(certDir, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
    WOLFSSL_LEAVE("wolfSSL_CTX_set_default_verify_paths", ret);

    return ret;
}

#endif /* OPENSSL_EXTRA */

#ifndef NO_DH

/* Set the temporary DH parameters against the SSL.
 *
 * @param [in, out] ssl   SSL object.
 * @param [in]      p     Buffer holding prime.
 * @param [in]      pSz   Length of prime in bytes.
 * @param [in]      g     Buffer holding generator.
 * @param [in]      gSz   Length of generator in bytes.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  DH_KEY_SIZE_E when the prime is too short or long.
 * @return  SIDE_ERROR when the SSL is for a client.
 */
static int wolfssl_set_tmp_dh(WOLFSSL* ssl, unsigned char* p, int pSz,
    unsigned char* g, int gSz)
{
    int ret = 1;

    /* Check the size of the prime meets the requirements of the SSL. */
    if (((word16)pSz < ssl->options.minDhKeySz) ||
            ((word16)pSz > ssl->options.maxDhKeySz)) {
        ret = DH_KEY_SIZE_E;
    }
    /* Only able to set DH parameters on server. */
    if ((ret == 1) && (ssl->options.side == WOLFSSL_CLIENT_END)) {
        ret = SIDE_ERROR;
    }

    if (ret == 1) {
    #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
        !defined(HAVE_SELFTEST)
        /* New DH parameters not tested for validity. */
        ssl->options.dhKeyTested = 0;
        /* New DH parameters must be tested for validity before use. */
        ssl->options.dhDoKeyTest = 1;
    #endif

        /* Dispose of old DH parameters if we own it. */
        if (ssl->buffers.weOwnDH) {
            XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
                DYNAMIC_TYPE_PUBLIC_KEY);
            XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap,
                DYNAMIC_TYPE_PUBLIC_KEY);
        }

        /* Assign the buffers and lengths to SSL. */
        ssl->buffers.serverDH_P.buffer = p;
        ssl->buffers.serverDH_G.buffer = g;
        ssl->buffers.serverDH_P.length = (unsigned int)pSz;
        ssl->buffers.serverDH_G.length = (unsigned int)gSz;
        /* We own the buffers. */
        ssl->buffers.weOwnDH = 1;
        /* We have a DH parameters to use. */
        ssl->options.haveDH = 1;
    }

    /* Allocate space for cipher suites. */
    if ((ret == 1) && (AllocateSuites(ssl) != 0)) {
        ssl->buffers.serverDH_P.buffer = NULL;
        ssl->buffers.serverDH_G.buffer = NULL;
        ret = 0;
    }
    if (ret == 1) {
        /* Reset the cipher suites based on having a DH parameters now. */
        InitSuites(ssl->suites, ssl->version, SSL_KEY_SZ(ssl),
            WOLFSSL_HAVE_RSA, SSL_HAVE_PSK(ssl), ssl->options.haveDH,
            ssl->options.haveECDSAsig, ssl->options.haveECC, TRUE,
            ssl->options.haveStaticECC,
            ssl->options.useAnon, TRUE,
            TRUE, TRUE, TRUE, ssl->options.side);
    }

    return ret;
}

/* Set the temporary DH parameters against the SSL.
 *
 * @param [in, out] ssl   SSL object.
 * @param [in]      p     Buffer holding prime.
 * @param [in]      pSz   Length of prime in bytes.
 * @param [in]      g     Buffer holding generator.
 * @param [in]      gSz   Length of generator in bytes.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  DH_KEY_SIZE_E when the prime is too short or long.
 * @return  SIDE_ERROR when the SSL is for a client.
 * @return  MEMORY_E when dynamic memory allocation fails.
 */
int wolfSSL_SetTmpDH(WOLFSSL* ssl, const unsigned char* p, int pSz,
    const unsigned char* g, int gSz)
{
    int ret = 1;
    byte* pAlloc = NULL;
    byte* gAlloc = NULL;

    WOLFSSL_ENTER("wolfSSL_SetTmpDH");

    /* Validate parameters. */
    if ((ssl == NULL) || (p == NULL) || (g == NULL)) {
        ret = 0;
    }

    if (ret == 1) {
        /* Allocate buffers for p and g to be assigned into SSL. */
        pAlloc = (byte*)XMALLOC((size_t)pSz, ssl->heap,
            DYNAMIC_TYPE_PUBLIC_KEY);
        gAlloc = (byte*)XMALLOC((size_t)gSz, ssl->heap,
            DYNAMIC_TYPE_PUBLIC_KEY);
        if ((pAlloc == NULL) || (gAlloc == NULL)) {
            /* Memory will be freed below in the (ret != 1) block */
            ret = MEMORY_E;
        }
    }
    if (ret == 1) {
        /* Copy p and g into allocated buffers. */
        XMEMCPY(pAlloc, p, (size_t)pSz);
        XMEMCPY(gAlloc, g, (size_t)gSz);
        /* Set the buffers into SSL. */
        ret = wolfssl_set_tmp_dh(ssl, pAlloc, pSz, gAlloc, gSz);
    }

    if (ret != 1 && ssl != NULL) {
        /* Free the allocated buffers if not assigned into SSL. */
        XFREE(pAlloc, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
        XFREE(gAlloc, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
    }

    WOLFSSL_LEAVE("wolfSSL_SetTmpDH", ret);
    return ret;
}

#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
    !defined(HAVE_SELFTEST)
/* Check the DH parameters is valid.
 *
 * @param [in]      p     Buffer holding prime.
 * @param [in]      pSz   Length of prime in bytes.
 * @param [in]      g     Buffer holding generator.
 * @param [in]      gSz   Length of generator in bytes.
 * @return  1 on success.
 * @return  DH_CHECK_PUB_E when p is not a prime.
 * @return  BAD_FUNC_ARG when p or g is NULL, or pSz or gSz is 0.
 * @return  MEMORY_E when dynamic memory allocation fails.
 */
static int wolfssl_check_dh_key(unsigned char* p, int pSz, unsigned char* g,
    int gSz)
{
    WC_RNG rng;
    int ret = 0;
    WC_DECLARE_VAR(checkKey, DhKey, 1, 0);

    WC_ALLOC_VAR_EX(checkKey, DhKey, 1, NULL, DYNAMIC_TYPE_DH,
        ret=MEMORY_E);
    /* Initialize a new random number generator. */
    if ((ret == 0) && ((ret = wc_InitRng(&rng)) == 0)) {
        /* Initialize a DH object. */
        if ((ret = wc_InitDhKey(checkKey)) == 0) {
            /* Check DH parameters. */
            ret = wc_DhSetCheckKey(checkKey, p, (word32)pSz, g, (word32)gSz,
                NULL, 0, 0, &rng);
            /* Dispose of DH object. */
            wc_FreeDhKey(checkKey);
        }
        /* Dispose of random number generator. */
        wc_FreeRng(&rng);
    }

    WC_FREE_VAR_EX(checkKey, NULL, DYNAMIC_TYPE_DH);
    /* Convert wolfCrypt return code to 1 on success and ret on failure. */
    return WC_TO_WS_RC(ret);
}
#endif

/* Set the temporary DH parameters against the SSL context.
 *
 * @param [in, out] ctx   SSL context object.
 * @param [in]      p     Buffer holding prime.
 * @param [in]      pSz   Length of prime in bytes.
 * @param [in]      g     Buffer holding generator.
 * @param [in]      gSz   Length of generator in bytes.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  DH_KEY_SIZE_E when the prime is too short or long.
 * @return  SIDE_ERROR when the SSL is for a client.
 * @return  BAD_FUNC_ARG when ctx, p or g is NULL.
 * @return  DH_CHECK_PUB_E when p is not a prime.
 * @return  MEMORY_E when dynamic memory allocation fails.
 */
static int wolfssl_ctx_set_tmp_dh(WOLFSSL_CTX* ctx, unsigned char* p, int pSz,
    unsigned char* g, int gSz)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_CTX_SetTmpDH");

    if ((ctx == NULL) || (p == NULL) || (g == NULL))
        ret = BAD_FUNC_ARG;

    /* Check the size of the prime meets the requirements of the SSL context. */
    if (ret == 1) {
        if (((word16)pSz < ctx->minDhKeySz) || ((word16)pSz > ctx->maxDhKeySz)) {
            ret = DH_KEY_SIZE_E;
        }
    }

#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
    !defined(HAVE_SELFTEST)
    if (ret == 1) {
        /* Test DH parameters for validity. */
        ret = wolfssl_check_dh_key(p, pSz, g, gSz);
        /* Record as whether tested based on result of validity test. */
        ctx->dhKeyTested = (ret == 1);
    }
#endif

    if (ret == 1) {
        /* Dispose of old DH parameters. */
        XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
        XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
        /* Assign the buffers and lengths to SSL context. */
        ctx->serverDH_P.buffer = p;
        ctx->serverDH_G.buffer = g;
        ctx->serverDH_P.length = (unsigned int)pSz;
        ctx->serverDH_G.length = (unsigned int)gSz;
        /* We have a DH parameters to use. */
        ctx->haveDH = 1;
    }

    WOLFSSL_LEAVE("wolfSSL_CTX_SetTmpDH", 0);
    return ret;
}

/* Set the temporary DH parameters against the SSL context.
 *
 * @param [in, out] ctx   SSL context object.
 * @param [in]      p     Buffer holding prime.
 * @param [in]      pSz   Length of prime in bytes.
 * @param [in]      g     Buffer holding generator.
 * @param [in]      gSz   Length of generator in bytes.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  DH_KEY_SIZE_E when the prime is too short or long.
 * @return  SIDE_ERROR when the SSL is for a client.
 * @return  BAD_FUNC_ARG when ctx, p or g is NULL.
 * @return  DH_CHECK_PUB_E when p is not a prime.
 */
int wolfSSL_CTX_SetTmpDH(WOLFSSL_CTX* ctx, const unsigned char* p, int pSz,
                         const unsigned char* g, int gSz)
{
    int ret = 1;
    byte* pAlloc = NULL;
    byte* gAlloc = NULL;

    /* Validate parameters. */
    if ((ctx == NULL) || (p == NULL) || (g == NULL)) {
        ret = BAD_FUNC_ARG;
    }

    if (ret == 1) {
        /* Allocate buffers for p and g to be assigned into SSL context. */
        pAlloc = (byte*)XMALLOC((size_t)pSz, ctx->heap,
            DYNAMIC_TYPE_PUBLIC_KEY);
        gAlloc = (byte*)XMALLOC((size_t)gSz, ctx->heap,
            DYNAMIC_TYPE_PUBLIC_KEY);
        if ((pAlloc == NULL) || (gAlloc == NULL)) {
            ret = MEMORY_E;
        }
    }

    if (ret == 1) {
        /* Copy p and g into allocated buffers. */
        XMEMCPY(pAlloc, p, (size_t)pSz);
        XMEMCPY(gAlloc, g, (size_t)gSz);
        /* Set the buffers into SSL context. */
        ret = wolfssl_ctx_set_tmp_dh(ctx, pAlloc, pSz, gAlloc, gSz);
    }

    if ((ret != 1) && (ctx != NULL)) {
        /* Free the allocated buffers if not assigned into SSL context. */
        XFREE(pAlloc, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
        XFREE(gAlloc, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
    }
    return ret;
}

#ifdef OPENSSL_EXTRA
/* Set the temporary DH parameters against the SSL.
 *
 * @param [in, out] ssl  SSL object.
 * @param [in]      dh   DH object.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  WOLFSSL_FATAL_ERROR on failure.
 * @return  BAD_FUNC_ARG when ssl or dh is NULL.
 * @return  DH_KEY_SIZE_E when the prime is too short or long.
 * @return  SIDE_ERROR when the SSL is for a client.
 */
long wolfSSL_set_tmp_dh(WOLFSSL *ssl, WOLFSSL_DH *dh)
{
    int ret = 1;
    byte* p = NULL;
    byte* g = NULL;
    int pSz = 0;
    int gSz = 0;

    WOLFSSL_ENTER("wolfSSL_set_tmp_dh");

    /* Validate parameters. */
    if ((ssl == NULL) || (dh == NULL)) {
        ret = BAD_FUNC_ARG;
    }

    if (ret == 1) {
        /* Get sizes of p and g. */
        pSz = wolfSSL_BN_bn2bin(dh->p, NULL);
        gSz = wolfSSL_BN_bn2bin(dh->g, NULL);
        /* Validate p and g size. */
        if ((pSz <= 0) || (gSz <= 0)) {
            ret = WOLFSSL_FATAL_ERROR;
        }
    }

    if (ret == 1) {
        /* Allocate buffers for p and g to be assigned into SSL. */
        p = (byte*)XMALLOC((size_t)pSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
        g = (byte*)XMALLOC((size_t)gSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
        if ((p == NULL) || (g == NULL)) {
            ret = MEMORY_E;
        }
    }
    if (ret == 1) {
        /* Encode p and g and get sizes. */
        pSz = wolfSSL_BN_bn2bin(dh->p, p);
        gSz = wolfSSL_BN_bn2bin(dh->g, g);
        /* Check encoding worked. */
        if ((pSz <= 0) || (gSz <= 0)) {
            ret = WOLFSSL_FATAL_ERROR;
        }
    }
    if (ret == 1) {
        /* Set the buffers into SSL. */
        ret = wolfssl_set_tmp_dh(ssl, p, pSz, g, gSz);
    }

    if ((ret != 1) && (ssl != NULL)) {
        /* Free the allocated buffers if not assigned into SSL. */
        XFREE(p, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
        XFREE(g, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
    }
    return ret;
}

/* Set the temporary DH parameters object against the SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      dh      DH object.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  DH_KEY_SIZE_E when the prime is too short or long.
 * @return  SIDE_ERROR when the SSL is for a client.
 * @return  BAD_FUNC_ARG when ctx, p or g is NULL.
 * @return  DH_CHECK_PUB_E when p is not a prime.
 */
long wolfSSL_CTX_set_tmp_dh(WOLFSSL_CTX* ctx, WOLFSSL_DH* dh)
{
    int ret = 1;
    int pSz = 0;
    int gSz = 0;
    byte* p = NULL;
    byte* g = NULL;

    WOLFSSL_ENTER("wolfSSL_CTX_set_tmp_dh");

    /* Validate parameters. */
    if ((ctx == NULL) || (dh == NULL)) {
        ret = BAD_FUNC_ARG;
    }

    if (ret == 1) {
        /* Get sizes of p and g. */
        pSz = wolfSSL_BN_bn2bin(dh->p, NULL);
        gSz = wolfSSL_BN_bn2bin(dh->g, NULL);
        /* Validate p and g size. */
        if ((pSz <= 0) || (gSz <= 0)) {
            ret = WOLFSSL_FATAL_ERROR;
        }
    }

    if (ret == 1) {
        /* Allocate buffers for p and g to be assigned into SSL. */
        p = (byte*)XMALLOC((size_t)pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
        g = (byte*)XMALLOC((size_t)gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
        if ((p == NULL) || (g == NULL)) {
            ret = MEMORY_E;
        }
    }

    if (ret == 1) {
        /* Encode p and g and get sizes. */
        pSz = wolfSSL_BN_bn2bin(dh->p, p);
        gSz = wolfSSL_BN_bn2bin(dh->g, g);
        /* Check encoding worked. */
        if ((pSz <= 0) || (gSz <= 0)) {
            ret = WOLFSSL_FATAL_ERROR;
        }
    }
    if (ret == 1) {
        /* Set the buffers into SSL context. */
        ret = wolfssl_ctx_set_tmp_dh(ctx, p, pSz, g, gSz);
    }

    if ((ret != 1) && (ctx != NULL)) {
        /* Free the allocated buffers if not assigned into SSL. */
        XFREE(p, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
        XFREE(g, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
    }
    return ret;
}

#endif /* OPENSSL_EXTRA */

#ifndef NO_CERTS

/* Set the temporary DH parameters against the SSL context or SSL.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in, out] ssl     SSL object.
 * @param [in]      buf     Buffer holding encoded DH parameters.
 * @param [in]      sz      Size of encoded DH parameters.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  0 on failure.
 * @return  BAD_FUNC_ARG when ctx and ssl NULL or buf is NULL.
 * @return  NOT_COMPLED_IN when format is PEM but PEM is not supported.
 * @return  WOLFSSL_BAD_FILETYPE if format is not supported.
 */
static int ws_ctx_ssl_set_tmp_dh(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    const unsigned char* buf, long sz, int format)
{
    DerBuffer* der = NULL;
    int res = 1;
    int ret;
    /* p and g size to allocate set to maximum valid size. */
    word32 pSz = MAX_DH_SIZE;
    word32 gSz = MAX_DH_SIZE;
    byte* p = NULL;
    byte* g = NULL;
    void* heap = WOLFSSL_HEAP(ctx, ssl);

    /* Validate parameters. */
    if (((ctx == NULL) && (ssl == NULL)) || (buf == NULL)) {
        res = BAD_FUNC_ARG;
    }
    /* Check format is supported. */
    if ((res == 1) && (format != WOLFSSL_FILETYPE_ASN1)) {
        if (format != WOLFSSL_FILETYPE_PEM) {
            res = WOLFSSL_BAD_FILETYPE;
        }
    #ifndef WOLFSSL_PEM_TO_DER
        else {
            res = NOT_COMPILED_IN;
        }
    #endif
    }

    /* PemToDer allocates its own DER buffer. */
    if ((res == 1) && (format != WOLFSSL_FILETYPE_PEM)) {
        /* Create a DER buffer and copy in the encoded DH parameters. */
        ret = AllocDer(&der, (word32)sz, DH_PARAM_TYPE, heap);
        if (ret == 0) {
            XMEMCPY(der->buffer, buf, (word32)sz);
        }
        else {
            res = ret;
        }
    }

    if (res == 1) {
        /* Allocate enough memory to p and g to support valid use cases. */
        p = (byte*)XMALLOC(pSz, heap, DYNAMIC_TYPE_PUBLIC_KEY);
        g = (byte*)XMALLOC(gSz, heap, DYNAMIC_TYPE_PUBLIC_KEY);
        if ((p == NULL) || (g == NULL)) {
            res = MEMORY_E;
        }
    }

#ifdef WOLFSSL_PEM_TO_DER
    if ((res == 1) && (format == WOLFSSL_FILETYPE_PEM)) {
        /* Convert from PEM to DER. */
        /* Try converting DH parameters from PEM to DER. */
        ret = PemToDer(buf, sz, DH_PARAM_TYPE, &der, heap, NULL, NULL);
        if (ret < 0) {
            /* Otherwise, try converting X9.43 format DH parameters. */
            ret = PemToDer(buf, sz, X942_PARAM_TYPE, &der, heap, NULL, NULL);
        }
    #if defined(WOLFSSL_WPAS) && !defined(NO_DSA)
        if (ret < 0) {
            /* Otherwise, try converting DSA parameters. */
            ret = PemToDer(buf, sz, DSA_PARAM_TYPE, &der, heap, NULL, NULL);
        }
    #endif /* WOLFSSL_WPAS && !NO_DSA */
       if (ret < 0) {
           /* Return error from conversion. */
           res = ret;
       }
    }
#endif /* WOLFSSL_PEM_TO_DER */

    if (res == 1) {
        /* Get the p and g from the DER encoded parameters. */
        if (wc_DhParamsLoad(der->buffer, der->length, p, &pSz, g, &gSz) < 0) {
            res = WOLFSSL_BAD_FILETYPE;
        }
        else if (ssl != NULL) {
            /* Set p and g into SSL. */
            res = wolfssl_set_tmp_dh(ssl, p, (int)pSz, g, (int)gSz);
        }
        else {
            /* Set p and g into SSL context. */
            res = wolfssl_ctx_set_tmp_dh(ctx, p, (int)pSz, g, (int)gSz);
        }
    }

    /* Dispose of the DER buffer. */
    FreeDer(&der);
    if (res != 1) {
        /* Free the allocated buffers if not assigned into SSL or context. */
        XFREE(p, heap, DYNAMIC_TYPE_PUBLIC_KEY);
        XFREE(g, heap, DYNAMIC_TYPE_PUBLIC_KEY);
    }
    return res;
}


/* Set the temporary DH parameters against the SSL.
 *
 * @param [in, out] ssl     SSL object.
 * @param [in]      buf     Buffer holding encoded DH parameters.
 * @param [in]      sz      Size of encoded DH parameters.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  BAD_FUNC_ARG when ssl or buf is NULL.
 * @return  NOT_COMPLED_IN when format is PEM but PEM is not supported.
 * @return  WOLFSSL_BAD_FILETYPE if format is not supported.
 */
int wolfSSL_SetTmpDH_buffer(WOLFSSL* ssl, const unsigned char* buf, long sz,
    int format)
{
    return ws_ctx_ssl_set_tmp_dh(NULL, ssl, buf, sz, format);
}


/* Set the temporary DH parameters against the SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      buf     Buffer holding encoded DH parameters.
 * @param [in]      sz      Size of encoded DH parameters.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  BAD_FUNC_ARG when ctx or buf is NULL.
 * @return  NOT_COMPLED_IN when format is PEM but PEM is not supported.
 * @return  WOLFSSL_BAD_FILETYPE if format is not supported.
 */
int wolfSSL_CTX_SetTmpDH_buffer(WOLFSSL_CTX* ctx, const unsigned char* buf,
    long sz, int format)
{
    return ws_ctx_ssl_set_tmp_dh(ctx, NULL, buf, sz, format);
}

#ifndef NO_FILESYSTEM

/* Set the temporary DH parameters file against the SSL context or SSL.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in, out] ssl     SSL object.
 * @param [in]      fname   Name of file to load.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  BAD_FUNC_ARG when ctx and ssl NULL or fname is NULL.
 * @return  NOT_COMPLED_IN when format is PEM but PEM is not supported.
 * @return  WOLFSSL_BAD_FILETYPE if format is not supported.
 */
static int ws_ctx_ssl_set_tmp_dh_file(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
    const char* fname, int format)
{
    int    res = 1;
    int    ret;
#ifndef WOLFSSL_SMALL_STACK
    byte   stackBuffer[FILE_BUFFER_SIZE];
#endif
    StaticBuffer dhFile;
    long   sz = 0;
    void*  heap = WOLFSSL_HEAP(ctx, ssl);

    /* Setup buffer to hold file contents. */
#ifdef WOLFSSL_SMALL_STACK
    static_buffer_init(&dhFile);
#else
    static_buffer_init(&dhFile, stackBuffer, FILE_BUFFER_SIZE);
#endif

    /* Validate parameters. */
    if (((ctx == NULL) && (ssl == NULL)) || (fname == NULL)) {
        res = BAD_FUNC_ARG;
    }

    if (res == 1) {
        /* Read file into static buffer. */
        ret = wolfssl_read_file_static(fname, &dhFile, heap, DYNAMIC_TYPE_FILE,
            &sz);
        if (ret != 0) {
            res = ret;
        }
    }
    if (res == 1) {
        if (ssl != NULL) {
            /* Set encoded DH parameters into SSL. */
            res = wolfSSL_SetTmpDH_buffer(ssl, dhFile.buffer, sz, format);
        }
        else {
            /* Set encoded DH parameters into SSL context. */
            res = wolfSSL_CTX_SetTmpDH_buffer(ctx, dhFile.buffer, sz, format);
        }
    }

    /* Dispose of any dynamically allocated data. */
    static_buffer_free(&dhFile, heap, DYNAMIC_TYPE_FILE);
    return res;
}

/* Set the temporary DH parameters file against the SSL.
 *
 * @param [in, out] ssl     SSL object.
 * @param [in]      fname   Name of file to load.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  BAD_FUNC_ARG when ssl or fname is NULL.
 * @return  NOT_COMPLED_IN when format is PEM but PEM is not supported.
 * @return  WOLFSSL_BAD_FILETYPE if format is not supported.
 */
int wolfSSL_SetTmpDH_file(WOLFSSL* ssl, const char* fname, int format)
{
    return ws_ctx_ssl_set_tmp_dh_file(NULL, ssl, fname, format);
}


/* Set the temporary DH parameters file against the SSL context.
 *
 * @param [in, out] ctx     SSL context object.
 * @param [in]      fname   Name of file to load.
 * @param [in]      format  Format of data:
 *                            WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
 * @return  1 on success.
 * @return  BAD_FUNC_ARG when ctx or fname is NULL.
 * @return  NOT_COMPLED_IN when format is PEM but PEM is not supported.
 * @return  WOLFSSL_BAD_FILETYPE if format is not supported.
 */
int wolfSSL_CTX_SetTmpDH_file(WOLFSSL_CTX* ctx, const char* fname, int format)
{
    return ws_ctx_ssl_set_tmp_dh_file(ctx, NULL, fname, format);
}

#endif /* NO_FILESYSTEM */

#endif /* NO_CERTS */

#endif /* !NO_DH */

#endif /* !WOLFSSL_SSL_LOAD_INCLUDED */

