/* api.c API unit tests
 *
 * 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
 */

/* For AES-CBC, input lengths can optionally be validated to be a
 * multiple of the block size, by defining WOLFSSL_AES_CBC_LENGTH_CHECKS,
 * also available via the configure option --enable-aescbc-length-checks.
 */


/*----------------------------------------------------------------------------*
 | Includes
 *----------------------------------------------------------------------------*/

#include <tests/unit.h>

#include <wolfssl/wolfcrypt/logging.h>
#include <wolfssl/wolfcrypt/hash.h>

#if defined(WOLFSSL_STATIC_MEMORY)
    #include <wolfssl/wolfcrypt/memory.h>
#endif
#ifdef WOLFSSL_ASYNC_CRYPT
    #include <wolfssl/wolfcrypt/async.h>
#endif
#ifdef HAVE_ECC
    #include <wolfssl/wolfcrypt/ecc.h>   /* wc_ecc_fp_free */
    #ifdef WOLFSSL_SM2
        #include <wolfssl/wolfcrypt/sm2.h>
    #endif
#endif
#ifndef NO_ASN
    #include <wolfssl/wolfcrypt/asn_public.h>
#endif

#include <stdlib.h>

#if defined(__linux__) || defined(__FreeBSD__)
#include <unistd.h>
#include <sys/wait.h>
#endif

#include <wolfssl/ssl.h>  /* compatibility layer */
#include <wolfssl/error-ssl.h>
#include <wolfssl/wolfcrypt/error-crypt.h>

#include <wolfssl/test.h>
#include <tests/utils.h>
#include <testsuite/utils.h>

#ifdef WOLFSSL_SWDEV
#include "swdev/swdev_loader.h"
#endif

/* for testing compatibility layer callbacks */
#include "examples/server/server.h"

#ifndef NO_SIG_WRAPPER
    #include <wolfssl/wolfcrypt/signature.h>
#endif

#ifdef WOLFSSL_SMALL_CERT_VERIFY
    #include <wolfssl/wolfcrypt/asn.h>
#endif

#ifndef NO_DSA
    #include <wolfssl/wolfcrypt/dsa.h>
#endif

#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
    defined(OPENSSL_ALL)
    #include <wolfssl/openssl/ssl.h>
    #ifndef NO_ASN
        /* for ASN_COMMON_NAME DN_tags enum */
        #include <wolfssl/wolfcrypt/asn.h>
    #endif
    #ifdef HAVE_OCSP
        #include <wolfssl/openssl/ocsp.h>
    #endif
#endif
#ifdef OPENSSL_EXTRA
    #include <wolfssl/openssl/cmac.h>
    #include <wolfssl/openssl/x509v3.h>
    #include <wolfssl/openssl/asn1.h>
    #include <wolfssl/openssl/crypto.h>
    #include <wolfssl/openssl/pkcs12.h>
    #include <wolfssl/openssl/evp.h>
    #include <wolfssl/openssl/dh.h>
    #include <wolfssl/openssl/bn.h>
    #include <wolfssl/openssl/buffer.h>
    #include <wolfssl/openssl/pem.h>
    #include <wolfssl/openssl/ec.h>
    #include <wolfssl/openssl/ecdh.h>
    #include <wolfssl/openssl/engine.h>
    #include <wolfssl/openssl/hmac.h>
    #include <wolfssl/openssl/objects.h>
    #include <wolfssl/openssl/rand.h>
    #include <wolfssl/openssl/modes.h>
    #include <wolfssl/openssl/fips_rand.h>
    #include <wolfssl/openssl/kdf.h>
    #include <wolfssl/openssl/x509_vfy.h>
#ifdef OPENSSL_ALL
    #include <wolfssl/openssl/txt_db.h>
    #include <wolfssl/openssl/lhash.h>
#endif
#ifndef NO_AES
    #include <wolfssl/openssl/aes.h>
#endif
#ifndef NO_DES3
    #include <wolfssl/openssl/des.h>
#endif
#ifndef NO_RC4
    #include <wolfssl/openssl/rc4.h>
#endif
#ifdef HAVE_ECC
    #include <wolfssl/openssl/ecdsa.h>
#endif
#ifdef HAVE_CURVE25519
    #include <wolfssl/openssl/ec25519.h>
#endif
#ifdef HAVE_ED25519
    #include <wolfssl/openssl/ed25519.h>
#endif
#ifdef HAVE_CURVE448
    #include <wolfssl/openssl/ec448.h>
#endif
#ifdef HAVE_ED448
    #include <wolfssl/openssl/ed448.h>
#endif
#endif /* OPENSSL_EXTRA */

#if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) && \
    !defined(NO_SHA256) && !defined(RC_NO_RNG)
        #include <wolfssl/wolfcrypt/srp.h>
#endif

#if (defined(SESSION_CERTS) && defined(TEST_PEER_CERT_CHAIN)) || \
    defined(HAVE_SESSION_TICKET) || (defined(OPENSSL_EXTRA) && \
    defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN)) || \
    defined(WOLFSSL_TEST_STATIC_BUILD) || defined(WOLFSSL_DTLS) || \
    defined(HAVE_ECH) || defined(HAVE_EX_DATA) || !defined(NO_SESSION_CACHE) \
    || !defined(WOLFSSL_NO_TLS12) || defined(WOLFSSL_TLS13)
    /* for testing SSL_get_peer_cert_chain, or SESSION_TICKET_HINT_DEFAULT,
     * for setting authKeyIdSrc in WOLFSSL_X509, or testing DTLS sequence
     * number tracking */
    #include "wolfssl/internal.h"
#endif

#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_CHAIN_INPUT)
    #include <wolfssl/sniffer.h>
    #include <wolfssl/sniffer_error.h>
    #include <sys/uio.h>
#endif

#ifdef WOLFSSL_HAVE_MLDSA
    #include <wolfssl/wolfcrypt/wc_mldsa.h>
#endif
#if defined(WOLFSSL_HAVE_MLKEM)
    #include <wolfssl/wolfcrypt/wc_mlkem.h>
#endif
#if defined(HAVE_PKCS7)
    #include <wolfssl/wolfcrypt/pkcs7.h>
#endif
#if !defined(NO_BIG_INT)
    #include <wolfssl/wolfcrypt/sp_int.h>
#endif

/* include misc.c here regardless of NO_INLINE, because misc.c implementations
 * have default (hidden) visibility, and in the absence of visibility, it's
 * benign to mask out the library implementation.
 */
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>

#include <tests/api/api.h>
#include <tests/api/api_decl.h>

/* Gather test declarations to include them in the testCases array */
#include <tests/api/test_md2.h>
#include <tests/api/test_md4.h>
#include <tests/api/test_md5.h>
#include <tests/api/test_sha.h>
#include <tests/api/test_sha256.h>
#include <tests/api/test_sha512.h>
#include <tests/api/test_sha3.h>
#include <tests/api/test_blake2.h>
#include <tests/api/test_sm3.h>
#include <tests/api/test_ripemd.h>
#include <tests/api/test_hash.h>
#include <tests/api/test_hmac.h>
#include <tests/api/test_cmac.h>
#include <tests/api/test_she.h>
#include <tests/api/test_des3.h>
#include <tests/api/test_chacha.h>
#include <tests/api/test_poly1305.h>
#include <tests/api/test_chacha20_poly1305.h>
#include <tests/api/test_camellia.h>
#include <tests/api/test_arc4.h>
#include <tests/api/test_rc2.h>
#include <tests/api/test_aes.h>
#include <tests/api/test_ascon.h>
#include <tests/api/test_sm4.h>
#include <tests/api/test_wc_encrypt.h>
#include <tests/api/test_random.h>
#include <tests/api/test_wolfmath.h>
#include <tests/api/test_rsa.h>
#include <tests/api/test_dsa.h>
#include <tests/api/test_dh.h>
#include <tests/api/test_ecc.h>
#include <tests/api/test_sm2.h>
#include <tests/api/test_curve25519.h>
#include <tests/api/test_ed25519.h>
#include <tests/api/test_curve448.h>
#include <tests/api/test_ed448.h>
#include <tests/api/test_mlkem.h>
#include <tests/api/test_mldsa.h>
#include <tests/api/test_slhdsa.h>
#include <tests/api/test_signature.h>
#include <tests/api/test_dtls.h>
#include <tests/api/test_ocsp.h>
#include <tests/api/test_evp.h>
#include <tests/api/test_tls_ext.h>
#include <tests/api/test_tls.h>
#include <tests/api/test_x509.h>
#include <tests/api/test_asn.h>
#include <tests/api/test_pkcs7.h>
#include <tests/api/test_pkcs12.h>
#include <tests/api/test_pwdbased.h>
#include <tests/api/test_ossl_asn1.h>
#include <tests/api/test_ossl_bn.h>
#include <tests/api/test_ossl_bio.h>
#include <tests/api/test_ossl_dgst.h>
#include <tests/api/test_ossl_mac.h>
#include <tests/api/test_ossl_cipher.h>
#include <tests/api/test_ossl_rsa.h>
#include <tests/api/test_ossl_dh.h>
#include <tests/api/test_ossl_ec.h>
#include <tests/api/test_ossl_ecx.h>
#include <tests/api/test_ossl_dsa.h>
#include <tests/api/test_ossl_sk.h>
#include <tests/api/test_ossl_x509.h>
#include <tests/api/test_ossl_x509_ext.h>
#include <tests/api/test_ossl_x509_name.h>
#include <tests/api/test_ossl_x509_pk.h>
#include <tests/api/test_ossl_x509_vp.h>
#include <tests/api/test_ossl_x509_io.h>
#include <tests/api/test_ossl_x509_crypto.h>
#include <tests/api/test_ossl_x509_acert.h>
#include <tests/api/test_ossl_x509_info.h>
#include <tests/api/test_ossl_x509_str.h>
#include <tests/api/test_ossl_x509_lu.h>
#include <tests/api/test_ossl_pem.h>
#include <tests/api/test_ossl_rand.h>
#include <tests/api/test_ossl_obj.h>
#include <tests/api/test_ossl_p7p12.h>
#include <tests/api/test_evp_digest.h>
#include <tests/api/test_evp_cipher.h>
#include <tests/api/test_evp_pkey.h>
#include <tests/api/test_certman.h>
#include <tests/api/test_tls13.h>

#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_RSA) && \
    !defined(NO_WOLFSSL_SERVER) && !defined(NO_WOLFSSL_CLIENT) && \
    !defined(WOLFSSL_TIRTOS)
    #define HAVE_SSL_MEMIO_TESTS_DEPENDENCIES
#endif

#if defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFCRYPT_ONLY)
    #if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) || \
        defined(SESSION_CERTS) || defined(WOLFSSL_HAVE_MLKEM)
        #ifdef OPENSSL_EXTRA
            #define TEST_TLS_STATIC_MEMSZ (400000)
        #else
            #define TEST_TLS_STATIC_MEMSZ (320000)
        #endif
    #else
            #define TEST_TLS_STATIC_MEMSZ (80000)
    #endif
#endif

#ifdef WOLFSSL_DUMP_MEMIO_STREAM
const char* currentTestName = NULL;
char tmpDirName[16];
int tmpDirNameSet = 0;
#endif

/*----------------------------------------------------------------------------*
 | Constants
 *----------------------------------------------------------------------------*/

#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT))
    static const char* bogusFile  =
    #ifdef _WIN32
        "NUL"
    #else
        "/dev/null"
    #endif
    ;
#endif /* !NO_FILESYSTEM && !NO_CERTS && (!NO_WOLFSSL_SERVER || !NO_WOLFSSL_CLIENT) */

enum {
    TESTING_RSA = 1,
    TESTING_ECC = 2
};

#ifdef WOLFSSL_QNX_CAAM
#include <wolfssl/wolfcrypt/port/caam/wolfcaam.h>
int testDevId = WOLFSSL_CAAM_DEVID;
#else
int testDevId = INVALID_DEVID;
#endif

#ifdef USE_WINDOWS_API
    #define MESSAGE_TYPE_CAST char*
#else
    #define MESSAGE_TYPE_CAST void*
#endif

/*----------------------------------------------------------------------------*
 | BIO with fixed read/write size
 *----------------------------------------------------------------------------*/

#if defined(OPENSSL_EXTRA) && !defined(NO_BIO)

static int wolfssl_bio_s_fixed_mem_write(WOLFSSL_BIO* bio, const char* data,
    int len)
{
    if ((bio == NULL) || (bio->ptr.mem_buf_data == NULL) || (data == NULL)) {
        len = 0;
    }
    else {
        if (bio->wrSz - bio->wrIdx < len) {
            len = bio->wrSz - bio->wrIdx;
        }
        XMEMCPY(bio->ptr.mem_buf_data + bio->wrIdx, data, (size_t)len);
        bio->wrIdx += len;
    }

    return len;
}

static int wolfssl_bio_s_fixed_mem_read(WOLFSSL_BIO* bio, char* data, int len)
{
    if ((bio == NULL) || (bio->ptr.mem_buf_data == NULL) || (data == NULL)) {
        len = 0;
    }
    else {
        if (bio->wrSz - bio->rdIdx < len) {
            len = bio->wrSz - bio->rdIdx;
        }
        XMEMCPY(data, bio->ptr.mem_buf_data + bio->rdIdx, (size_t)len);
        bio->rdIdx += len;
    }

    return len;
}

WOLFSSL_BIO_METHOD* wolfSSL_BIO_s_fixed_mem(void)
{
    static WOLFSSL_BIO_METHOD meth;

    meth.type = WOLFSSL_BIO_BIO;
    XMEMCPY(meth.name, "Fixed Memory Size", 18);
    meth.writeCb = wolfssl_bio_s_fixed_mem_write;
    meth.readCb = wolfssl_bio_s_fixed_mem_read;

    return &meth;
}

#endif

/*----------------------------------------------------------------------------*
 | Setup
 *----------------------------------------------------------------------------*/

static int test_wolfSSL_Init(void)
{
    EXPECT_DECLS;
    ExpectIntEQ(wolfSSL_Init(), WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}


static int test_wolfSSL_Cleanup(void)
{
    EXPECT_DECLS;
    ExpectIntEQ(wolfSSL_Cleanup(), WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}


/*  Initialize the wolfCrypt state.
 *  POST: 0 success.
 */
static int test_wolfCrypt_Init(void)
{
    EXPECT_DECLS;
    ExpectIntEQ(wolfCrypt_Init(), 0);
    return EXPECT_RESULT();

} /* END test_wolfCrypt_Init */

static int test_wolfCrypt_Cleanup(void)
{
    EXPECT_DECLS;
    ExpectIntEQ(wolfCrypt_Cleanup(), 0);
    return EXPECT_RESULT();
}


#ifdef WOLFSSL_STATIC_MEMORY
    #define TEST_LSM_STATIC_SIZE 440000
    /* Create new bucket list, using the default list, adding
     * one dang large buffer size. */
    #define TEST_LSM_DEF_BUCKETS (WOLFMEM_DEF_BUCKETS+1)
    #define TEST_LSM_BUCKETS WOLFMEM_BUCKETS,(LARGEST_MEM_BUCKET*2)
    #define TEST_LSM_DIST WOLFMEM_DIST,1
#endif

static int test_wc_LoadStaticMemory_ex(void)
{
    EXPECT_DECLS;
#ifdef WOLFSSL_STATIC_MEMORY
    byte staticMemory[TEST_LSM_STATIC_SIZE];
    word32 sizeList[TEST_LSM_DEF_BUCKETS] = { TEST_LSM_BUCKETS };
    word32 distList[TEST_LSM_DEF_BUCKETS] = { TEST_LSM_DIST };
    WOLFSSL_HEAP_HINT* heap;

    /* For this test, the size and dist lists will be the ones configured
     * for the build, or default. The value of WOLFMEM_DEF_BUCKETS is 9,
     * so these lists are 10 long. For most tests, the value of
     * WOLFMEM_DEF_BUCKETS is used. There's a test case where one is added
     * to that, to make sure the list size is larger than
     * WOLFMEM_MAX_BUCKETS. */

    /* Pass in zero everything. */
    ExpectIntEQ(wc_LoadStaticMemory_ex(NULL, 0, NULL, NULL, NULL, 0, 0, 0),
            WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Set the heap pointer to NULL. */
    ExpectIntEQ(wc_LoadStaticMemory_ex(NULL,
                WOLFMEM_DEF_BUCKETS, sizeList, distList,
                staticMemory, (word32)sizeof(staticMemory),
                0, 1),
            WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Set other pointer values to NULL one at a time. */
    heap = NULL;
    ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
                WOLFMEM_DEF_BUCKETS, NULL, distList,
                staticMemory, (word32)sizeof(staticMemory),
                0, 1),
            WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    heap = NULL;
    ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
                WOLFMEM_DEF_BUCKETS, sizeList, NULL,
                staticMemory, (word32)sizeof(staticMemory),
                0, 1),
            WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    heap = NULL;
    ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
                WOLFMEM_DEF_BUCKETS, sizeList, distList,
                NULL, (word32)sizeof(staticMemory),
                0, 1),
            WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Set the size of the static buffer to 0. */
    heap = NULL;
    ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
                WOLFMEM_DEF_BUCKETS, sizeList, distList,
                staticMemory, 0,
                0, 1),
            WC_NO_ERR_TRACE(BUFFER_E));

    /* Set the size of the static buffer to one less than minimum allowed. */
    heap = NULL;
    ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
                WOLFMEM_DEF_BUCKETS, sizeList, distList,
                staticMemory,
                (word32)(sizeof(WOLFSSL_HEAP) + sizeof(WOLFSSL_HEAP_HINT)) - 1,
                0, 1),
            WC_NO_ERR_TRACE(BUFFER_E));

    /* Set the size of the static buffer to exactly the minimum size. */
    heap = NULL;
    ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
                WOLFMEM_DEF_BUCKETS, sizeList, distList,
                staticMemory,
                (word32)(sizeof(WOLFSSL_HEAP) + sizeof(WOLFSSL_HEAP_HINT)),
                0, 1),
            0);
    wc_UnloadStaticMemory(heap);

    /* Use more buckets than able. Success case. */
    heap = NULL;
    ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
                WOLFMEM_DEF_BUCKETS*2, sizeList, distList,
                staticMemory, (word32)sizeof(staticMemory),
                0, 1),
            0);
    wc_UnloadStaticMemory(heap);

    /* Success case. */
    heap = NULL;
    ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
                WOLFMEM_DEF_BUCKETS, sizeList, distList,
                staticMemory, (word32)sizeof(staticMemory),
                0, 1),
            0);
    wc_UnloadStaticMemory(heap);
#endif /* WOLFSSL_STATIC_MEMORY */
    return EXPECT_RESULT();
}


static int test_wc_LoadStaticMemory_CTX(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_STATIC_MEMORY) && !defined(NO_WOLFSSL_CLIENT)
    byte staticMemory[TEST_LSM_STATIC_SIZE];
    word32 sizeList[TEST_LSM_DEF_BUCKETS] = { TEST_LSM_BUCKETS };
    word32 distList[TEST_LSM_DEF_BUCKETS] = { TEST_LSM_DIST };
    WOLFSSL_HEAP_HINT* heap;
    WOLFSSL_CTX *ctx1 = NULL, *ctx2 = NULL;


    /* Set the size of the static buffer to exactly the minimum size. */
    heap = NULL;
    ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
                WOLFMEM_DEF_BUCKETS, sizeList, distList,
                staticMemory, sizeof(staticMemory), 0, 1),
            0);

    /* Creating two WOLFSSL_CTX objects from the same heap hint and free'ing
     * them should not cause issues. */
    ExpectNotNull((ctx1 = wolfSSL_CTX_new_ex(wolfSSLv23_client_method_ex(heap),
        heap)));
    wolfSSL_CTX_free(ctx1);
    ExpectNotNull((ctx2 = wolfSSL_CTX_new_ex(wolfSSLv23_client_method_ex(heap),
        heap)));
    wolfSSL_CTX_free(ctx2);

    /* two CTX's at once */
    ExpectNotNull((ctx1 = wolfSSL_CTX_new_ex(wolfSSLv23_client_method_ex(heap),
        heap)));
    ExpectNotNull((ctx2 = wolfSSL_CTX_new_ex(wolfSSLv23_client_method_ex(heap),
        heap)));
    wolfSSL_CTX_free(ctx1);
    wolfSSL_CTX_free(ctx2);

    wc_UnloadStaticMemory(heap);
#endif /* WOLFSSL_STATIC_MEMORY */
    return EXPECT_RESULT();
}


/*----------------------------------------------------------------------------*
 | Platform dependent function test
 *----------------------------------------------------------------------------*/
static int test_fileAccess(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_TEST_PLATFORMDEPEND) && !defined(NO_FILESYSTEM)
    const char *fname[] = {
        svrCertFile, svrKeyFile, caCertFile,
        eccCertFile, eccKeyFile, eccRsaCertFile,
        cliCertFile, cliCertDerFile, cliKeyFile,
        dhParamFile,
        cliEccKeyFile, cliEccCertFile, caEccCertFile, edCertFile, edKeyFile,
        cliEdCertFile, cliEdKeyFile, caEdCertFile,
        NULL
    };
    const char derfile[] = "./certs/server-cert.der";
    XFILE f = XBADFILE;
    size_t sz;
    byte *buff = NULL;
    int i;

    ExpectTrue(XFOPEN("badfilename", "rb") == XBADFILE);
    for (i=0; EXPECT_SUCCESS() && fname[i] != NULL ; i++) {
        ExpectTrue((f = XFOPEN(fname[i], "rb")) != XBADFILE);
        XFCLOSE(f);
    }

    ExpectTrue((f = XFOPEN(derfile, "rb")) != XBADFILE);
    ExpectTrue(XFSEEK(f, 0, XSEEK_END) == 0);
    ExpectIntGE(sz = (size_t) XFTELL(f), sizeof_server_cert_der_2048);
    ExpectTrue(XFSEEK(f, 0, XSEEK_SET) == 0);
    ExpectTrue((buff = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)) != NULL);
    ExpectTrue(XFREAD(buff, 1, sz, f) == sz);
    ExpectIntEQ(XMEMCMP(server_cert_der_2048, buff, sz), 0);
    XFREE(buff, NULL, DYNAMIC_TYPE_FILE);
    XFCLOSE(f);
#endif
    return EXPECT_RESULT();
}
static int test_wc_FreeCertList(void)
{
    EXPECT_DECLS;
#if defined(HAVE_PKCS12) && !defined(NO_ASN) && \
!defined(NO_PWDBASED) && !defined(NO_HMAC) && !defined(NO_CERTS) && \
defined(USE_CERT_BUFFERS_2048)
    WC_DerCertList* list = NULL;
    void* heap = NULL;
    /* Test freeing a list with a single node */
    list = (WC_DerCertList*)XMALLOC(sizeof(WC_DerCertList),
            heap, DYNAMIC_TYPE_PKCS);
    ExpectNotNull(list);
    if (list != NULL) {
        list->buffer = (byte*)XMALLOC(10, heap, DYNAMIC_TYPE_PKCS);
        ExpectNotNull(list->buffer);
        if (list->buffer != NULL) {
            list->bufferSz = 10;
            list->next = NULL;
            wc_FreeCertList(list, heap);
        }
        else {
            XFREE(list, heap, DYNAMIC_TYPE_PKCS);
            list = NULL;
        }
    }
#endif
    return EXPECT_RESULT();
}

/*----------------------------------------------------------------------------*
 | Method Allocators
 *----------------------------------------------------------------------------*/

static int test_wolfSSL_Method_Allocators(void)
{
    EXPECT_DECLS;

    #define TEST_METHOD_ALLOCATOR(allocator, condition) \
        do {                                            \
            WOLFSSL_METHOD *method = NULL;              \
            condition(method = allocator());            \
            XFREE(method, 0, DYNAMIC_TYPE_METHOD);      \
        } while (0)

    #define TEST_VALID_METHOD_ALLOCATOR(a) \
            TEST_METHOD_ALLOCATOR(a, ExpectNotNull)

    #define TEST_INVALID_METHOD_ALLOCATOR(a) \
            TEST_METHOD_ALLOCATOR(a, ExpectNull)

#ifndef NO_TLS
#ifndef NO_OLD_TLS
    #ifdef WOLFSSL_ALLOW_SSLV3
        #ifndef NO_WOLFSSL_SERVER
        TEST_VALID_METHOD_ALLOCATOR(wolfSSLv3_server_method);
        #endif
        #ifndef NO_WOLFSSL_CLIENT
        TEST_VALID_METHOD_ALLOCATOR(wolfSSLv3_client_method);
        #endif
    #endif
    #ifdef WOLFSSL_ALLOW_TLSV10
        #ifndef NO_WOLFSSL_SERVER
        TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_server_method);
        #endif
        #ifndef NO_WOLFSSL_CLIENT
        TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_client_method);
        #endif
    #endif
    #ifndef NO_WOLFSSL_SERVER
        TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_1_server_method);
    #endif
    #ifndef NO_WOLFSSL_CLIENT
        TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_1_client_method);
    #endif
#endif /* !NO_OLD_TLS */

#ifndef WOLFSSL_NO_TLS12
    #ifndef NO_WOLFSSL_SERVER
        TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_2_server_method);
    #endif
    #ifndef NO_WOLFSSL_CLIENT
        TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_2_client_method);
    #endif
#endif /* !WOLFSSL_NO_TLS12 */

#ifdef WOLFSSL_TLS13
    #ifndef NO_WOLFSSL_SERVER
        TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_3_server_method);
    #endif
    #ifndef NO_WOLFSSL_CLIENT
        TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_3_client_method);
    #endif
#endif /* WOLFSSL_TLS13 */

#ifndef NO_WOLFSSL_SERVER
    TEST_VALID_METHOD_ALLOCATOR(wolfSSLv23_server_method);
#endif
#ifndef NO_WOLFSSL_CLIENT
    TEST_VALID_METHOD_ALLOCATOR(wolfSSLv23_client_method);
#endif

#ifdef WOLFSSL_DTLS
    #ifndef NO_OLD_TLS
        #ifndef NO_WOLFSSL_SERVER
        TEST_VALID_METHOD_ALLOCATOR(wolfDTLSv1_server_method);
        #endif
        #ifndef NO_WOLFSSL_CLIENT
        TEST_VALID_METHOD_ALLOCATOR(wolfDTLSv1_client_method);
        #endif
    #endif
    #ifndef WOLFSSL_NO_TLS12
        #ifndef NO_WOLFSSL_SERVER
        TEST_VALID_METHOD_ALLOCATOR(wolfDTLSv1_2_server_method);
        #endif
        #ifndef NO_WOLFSSL_CLIENT
        TEST_VALID_METHOD_ALLOCATOR(wolfDTLSv1_2_client_method);
        #endif
    #endif
#endif /* WOLFSSL_DTLS */

#if !defined(NO_OLD_TLS) && defined(OPENSSL_EXTRA)
    /* Stubs */
    #ifndef NO_WOLFSSL_SERVER
        TEST_INVALID_METHOD_ALLOCATOR(wolfSSLv2_server_method);
    #endif
    #ifndef NO_WOLFSSL_CLIENT
        TEST_INVALID_METHOD_ALLOCATOR(wolfSSLv2_client_method);
    #endif
#endif

    /* Test Either Method (client or server) */
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    TEST_VALID_METHOD_ALLOCATOR(wolfSSLv23_method);
    #ifndef NO_OLD_TLS
        #ifdef WOLFSSL_ALLOW_TLSV10
            TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_method);
        #endif
        TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_1_method);
    #endif /* !NO_OLD_TLS */
    #ifndef WOLFSSL_NO_TLS12
        TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_2_method);
    #endif /* !WOLFSSL_NO_TLS12 */
    #ifdef WOLFSSL_TLS13
        TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_3_method);
    #endif /* WOLFSSL_TLS13 */
    #ifdef WOLFSSL_DTLS
        TEST_VALID_METHOD_ALLOCATOR(wolfDTLS_method);
        #ifndef NO_OLD_TLS
            TEST_VALID_METHOD_ALLOCATOR(wolfDTLSv1_method);
        #endif /* !NO_OLD_TLS */
        #ifndef WOLFSSL_NO_TLS12
            TEST_VALID_METHOD_ALLOCATOR(wolfDTLSv1_2_method);
        #endif /* !WOLFSSL_NO_TLS12 */
        #ifdef WOLFSSL_DTLS13
            TEST_VALID_METHOD_ALLOCATOR(wolfDTLSv1_3_method);
        #endif /* WOLFSSL_DTLS13 */
    #endif /* WOLFSSL_DTLS */
#endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */
#endif /* !NO_TLS */
    return EXPECT_RESULT();
}

#if defined(WOLFSSL_DUAL_ALG_CERTS) && !defined(NO_FILESYSTEM)
/*----------------------------------------------------------------------------*
 | Dual algorithm Certificate Tests
 *----------------------------------------------------------------------------*/
#define LARGE_TEMP_SZ 4096

/* To better understand this, please see the X9.146 example in wolfssl-examples
 * repo. */
static int do_dual_alg_root_certgen(byte **out, char *caKeyFile,
                                    char *sapkiFile, char *altPrivFile)
{
    EXPECT_DECLS;
    FILE* file = NULL;
    Cert newCert;
    DecodedCert preTBS;

    byte caKeyBuf[LARGE_TEMP_SZ];
    word32 caKeySz = LARGE_TEMP_SZ;
    byte sapkiBuf[LARGE_TEMP_SZ];
    word32 sapkiSz = LARGE_TEMP_SZ;
    byte altPrivBuf[LARGE_TEMP_SZ];
    word32 altPrivSz = LARGE_TEMP_SZ;
    byte altSigAlgBuf[LARGE_TEMP_SZ];
    word32 altSigAlgSz = LARGE_TEMP_SZ;
    byte scratchBuf[LARGE_TEMP_SZ];
    word32 scratchSz = LARGE_TEMP_SZ;
    byte preTbsBuf[LARGE_TEMP_SZ];
    word32 preTbsSz = LARGE_TEMP_SZ;
    byte altSigValBuf[LARGE_TEMP_SZ];
    word32 altSigValSz = LARGE_TEMP_SZ;
    byte *outBuf = NULL;
    word32 outSz = LARGE_TEMP_SZ;
    WC_RNG rng;
    RsaKey caKey;
    ecc_key altCaKey;
    word32 idx = 0;

    XMEMSET(&rng, 0, sizeof(WC_RNG));
    XMEMSET(&caKey, 0, sizeof(RsaKey));
    XMEMSET(&altCaKey, 0, sizeof(ecc_key));

    ExpectNotNull(outBuf = (byte*)XMALLOC(outSz, NULL,
                  DYNAMIC_TYPE_TMP_BUFFER));
    ExpectIntEQ(wc_InitRng(&rng), 0);
    XMEMSET(caKeyBuf, 0, caKeySz);
    ExpectNotNull(file = fopen(caKeyFile, "rb"));
    ExpectIntGT(caKeySz = (word32)fread(caKeyBuf, 1, caKeySz, file), 0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    ExpectIntEQ(wc_InitRsaKey_ex(&caKey, NULL, INVALID_DEVID), 0);
    idx = 0;
    ExpectIntEQ(wc_RsaPrivateKeyDecode(caKeyBuf, &idx, &caKey, caKeySz),
                0);
    XMEMSET(sapkiBuf, 0, sapkiSz);
    ExpectNotNull(file = fopen(sapkiFile, "rb"));
    ExpectIntGT(sapkiSz = (word32)fread(sapkiBuf, 1, sapkiSz, file), 0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    XMEMSET(altPrivBuf, 0, altPrivSz);
    ExpectNotNull(file = fopen(altPrivFile, "rb"));
    ExpectIntGT(altPrivSz = (word32)fread(altPrivBuf, 1, altPrivSz, file), 0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    wc_ecc_init(&altCaKey);
    idx = 0;
    ExpectIntEQ(wc_EccPrivateKeyDecode(altPrivBuf, &idx, &altCaKey,
                                       (word32)altPrivSz), 0);
    XMEMSET(altSigAlgBuf, 0, altSigAlgSz);
    ExpectIntGT(altSigAlgSz = SetAlgoID(CTC_SHA256wECDSA, altSigAlgBuf,
                                         oidSigType, 0), 0);
    wc_InitCert(&newCert);
    strncpy(newCert.subject.country, "US", CTC_NAME_SIZE);
    strncpy(newCert.subject.state, "MT", CTC_NAME_SIZE);
    strncpy(newCert.subject.locality, "Bozeman", CTC_NAME_SIZE);
    strncpy(newCert.subject.org, "wolfSSL", CTC_NAME_SIZE);
    strncpy(newCert.subject.unit, "Engineering", CTC_NAME_SIZE);
    strncpy(newCert.subject.commonName, "www.wolfssl.com", CTC_NAME_SIZE);
    strncpy(newCert.subject.email, "root@wolfssl.com", CTC_NAME_SIZE);
    strncpy((char*)newCert.beforeDate, "\x18\x0f""20250101000000Z",
        CTC_DATE_SIZE);
    newCert.beforeDateSz = 17;
    strncpy((char*)newCert.afterDate, "\x18\x0f""20493112115959Z",
        CTC_DATE_SIZE);
    newCert.afterDateSz = 17;
    newCert.sigType = CTC_SHA256wRSA;
    newCert.isCA    = 1;

    ExpectIntEQ(wc_SetCustomExtension(&newCert, 0, "1.2.3.4.5",
                (const byte *)"This is NOT a critical extension", 32), 0);
    ExpectIntEQ(wc_SetCustomExtension(&newCert, 0, "2.5.29.72", sapkiBuf,
                sapkiSz), 0);
    ExpectIntEQ(wc_SetCustomExtension(&newCert, 0, "2.5.29.73", altSigAlgBuf,
                                altSigAlgSz), 0);

    XMEMSET(scratchBuf, 0, scratchSz);
    ExpectIntGT(scratchSz = wc_MakeSelfCert(&newCert, scratchBuf, scratchSz,
                &caKey, &rng), 0);

    wc_InitDecodedCert(&preTBS, scratchBuf, scratchSz, 0);
    ExpectIntEQ(wc_ParseCert(&preTBS, CERT_TYPE, NO_VERIFY, NULL), 0);

    XMEMSET(preTbsBuf, 0, preTbsSz);
    ExpectIntGT(preTbsSz = wc_GeneratePreTBS(&preTBS, preTbsBuf, preTbsSz), 0);
    XMEMSET(altSigValBuf, 0, altSigValSz);
    ExpectIntGT(altSigValSz = wc_MakeSigWithBitStr(altSigValBuf, altSigValSz,
                CTC_SHA256wECDSA, preTbsBuf, preTbsSz, ECC_TYPE, &altCaKey,
                &rng), 0);
    ExpectIntEQ(wc_SetCustomExtension(&newCert, 0, "2.5.29.74", altSigValBuf,
                altSigValSz), 0);

    /* Finally, generate the new certificate. */
    if (outBuf != NULL) {
        XMEMSET(outBuf, 0, outSz);
    }
    ExpectIntGT(outSz = wc_MakeSelfCert(&newCert, outBuf, outSz, &caKey, &rng),
                0);
    *out = outBuf;

    wc_FreeRsaKey(&caKey);
    wc_FreeRng(&rng);
    wc_FreeDecodedCert(&preTBS);
    return outSz;
}

static int do_dual_alg_server_certgen(byte **out, char *caKeyFile,
                                      char *sapkiFile, char *altPrivFile,
                                      char *serverKeyFile,
                                      byte *caCertBuf, int caCertSz)
{
    EXPECT_DECLS;
    FILE* file = NULL;
    Cert newCert;
    DecodedCert preTBS;

    byte serverKeyBuf[LARGE_TEMP_SZ];
    word32 serverKeySz = LARGE_TEMP_SZ;
    byte caKeyBuf[LARGE_TEMP_SZ];
    word32 caKeySz = LARGE_TEMP_SZ;
    byte sapkiBuf[LARGE_TEMP_SZ];
    word32 sapkiSz = LARGE_TEMP_SZ;
    byte altPrivBuf[LARGE_TEMP_SZ];
    word32 altPrivSz = LARGE_TEMP_SZ;
    byte altSigAlgBuf[LARGE_TEMP_SZ];
    word32 altSigAlgSz = LARGE_TEMP_SZ;
    byte scratchBuf[LARGE_TEMP_SZ];
    word32 scratchSz = LARGE_TEMP_SZ;
    byte preTbsBuf[LARGE_TEMP_SZ];
    word32 preTbsSz = LARGE_TEMP_SZ;
    byte altSigValBuf[LARGE_TEMP_SZ];
    word32 altSigValSz = LARGE_TEMP_SZ;
    byte *outBuf = NULL;
    word32 outSz = LARGE_TEMP_SZ;
    WC_RNG rng;
    RsaKey caKey;
    RsaKey serverKey;
    ecc_key altCaKey;
    word32 idx = 0;

    XMEMSET(&rng, 0, sizeof(WC_RNG));
    XMEMSET(&caKey, 0, sizeof(RsaKey));
    XMEMSET(&serverKey, 0, sizeof(RsaKey));
    XMEMSET(&altCaKey, 0, sizeof(ecc_key));

    ExpectNotNull(outBuf = (byte*)XMALLOC(outSz, NULL,
                  DYNAMIC_TYPE_TMP_BUFFER));
    ExpectIntEQ(wc_InitRng(&rng), 0);
    XMEMSET(serverKeyBuf, 0, serverKeySz);
    ExpectNotNull(file = fopen(serverKeyFile, "rb"));
    ExpectIntGT(serverKeySz = (word32)fread(serverKeyBuf, 1, serverKeySz, file),
                0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    ExpectIntEQ(wc_InitRsaKey_ex(&serverKey, NULL, INVALID_DEVID), 0);
    idx = 0;
    ExpectIntEQ(wc_RsaPrivateKeyDecode(serverKeyBuf, &idx, &serverKey,
                (word32)serverKeySz), 0);
    XMEMSET(caKeyBuf, 0, caKeySz);
    ExpectNotNull(file = fopen(caKeyFile, "rb"));
    ExpectIntGT(caKeySz = (word32)fread(caKeyBuf, 1, caKeySz, file), 0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    ExpectIntEQ(wc_InitRsaKey_ex(&caKey, NULL, INVALID_DEVID), 0);
    idx = 0;
    ExpectIntEQ(wc_RsaPrivateKeyDecode(caKeyBuf, &idx, &caKey,
                (word32)caKeySz), 0);
    XMEMSET(sapkiBuf, 0, sapkiSz);
    ExpectNotNull(file = fopen(sapkiFile, "rb"));
    ExpectIntGT(sapkiSz = (word32)fread(sapkiBuf, 1, sapkiSz, file), 0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    XMEMSET(altPrivBuf, 0, altPrivSz);
    ExpectNotNull(file = fopen(altPrivFile, "rb"));
    ExpectIntGT(altPrivSz = (word32)fread(altPrivBuf, 1, altPrivSz, file), 0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    wc_ecc_init(&altCaKey);
    idx = 0;
    ExpectIntEQ(wc_EccPrivateKeyDecode(altPrivBuf, &idx, &altCaKey,
                (word32)altPrivSz), 0);
    XMEMSET(altSigAlgBuf, 0, altSigAlgSz);
    ExpectIntGT(altSigAlgSz = SetAlgoID(CTC_SHA256wECDSA, altSigAlgBuf,
                oidSigType, 0), 0);
    wc_InitCert(&newCert);
    strncpy(newCert.subject.country, "US", CTC_NAME_SIZE);
    strncpy(newCert.subject.state, "MT", CTC_NAME_SIZE);
    strncpy(newCert.subject.locality, "Bozeman", CTC_NAME_SIZE);
    strncpy(newCert.subject.org, "wolfSSL", CTC_NAME_SIZE);
    strncpy(newCert.subject.unit, "Engineering", CTC_NAME_SIZE);
    strncpy(newCert.subject.commonName, "www.wolfssl.com", CTC_NAME_SIZE);
    strncpy(newCert.subject.email, "server@wolfssl.com", CTC_NAME_SIZE);
    strncpy((char*)newCert.beforeDate, "\x18\x0f""20250101000000Z",
        CTC_DATE_SIZE);
    newCert.beforeDateSz = 17;
    strncpy((char*)newCert.afterDate, "\x18\x0f""20493112115959Z",
        CTC_DATE_SIZE);
    newCert.afterDateSz = 17;

    newCert.sigType = CTC_SHA256wRSA;
    newCert.isCA    = 0;
    ExpectIntEQ(wc_SetIssuerBuffer(&newCert, caCertBuf, caCertSz), 0);
    ExpectIntEQ(wc_SetCustomExtension(&newCert, 0, "2.5.29.72", sapkiBuf,
                sapkiSz), 0);
    ExpectIntEQ(wc_SetCustomExtension(&newCert, 0, "2.5.29.73", altSigAlgBuf,
                altSigAlgSz), 0);
    XMEMSET(scratchBuf, 0, scratchSz);
    ExpectIntGT(wc_MakeCert(&newCert, scratchBuf, scratchSz, &serverKey, NULL,
                &rng), 0);
    ExpectIntGT(scratchSz = wc_SignCert(newCert.bodySz, newCert.sigType,
                scratchBuf, scratchSz, &caKey, NULL, &rng), 0);
    wc_InitDecodedCert(&preTBS, scratchBuf, scratchSz, 0);
    ExpectIntEQ(wc_ParseCert(&preTBS, CERT_TYPE, NO_VERIFY, NULL), 0);
    XMEMSET(preTbsBuf, 0, preTbsSz);
    ExpectIntGT(preTbsSz = wc_GeneratePreTBS(&preTBS, preTbsBuf, preTbsSz), 0);
    XMEMSET(altSigValBuf, 0, altSigValSz);
    ExpectIntGT(altSigValSz = wc_MakeSigWithBitStr(altSigValBuf, altSigValSz,
                CTC_SHA256wECDSA, preTbsBuf, preTbsSz, ECC_TYPE, &altCaKey,
                &rng), 0);
    ExpectIntEQ(wc_SetCustomExtension(&newCert, 0, "2.5.29.74",
                 altSigValBuf, altSigValSz), 0);
    /* Finally, generate the new certificate. */
    if (outBuf != NULL) {
        XMEMSET(outBuf, 0, outSz);
    }
    ExpectIntGT(wc_MakeCert(&newCert, outBuf, outSz, &serverKey, NULL, &rng),
                0);
    ExpectIntGT(outSz = wc_SignCert(newCert.bodySz, newCert.sigType, outBuf,
                outSz, &caKey, NULL, &rng), 0);
    *out = outBuf;
    wc_FreeRsaKey(&caKey);
    wc_FreeRsaKey(&serverKey);
    wc_FreeRng(&rng);
    wc_FreeDecodedCert(&preTBS);
    return outSz;
}

static int do_dual_alg_tls13_connection(byte *caCert, word32 caCertSz,
                                        byte *serverCert, word32 serverCertSz,
                                        byte *serverKey, word32 serverKeySz,
                                        int negative_test)
{
    EXPECT_DECLS;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup_ex(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
                wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
                caCert, caCertSz, serverCert, serverCertSz,
                serverKey, serverKeySz), 0);
    if (negative_test) {
        ExpectTrue(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL) != 0);
    }
    else {
        ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
    }
    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
    return EXPECT_RESULT();
}

/**
 * Function to generate a root certificate with dual algorithm support and
 * configurable criticality for extensions and path length constraints.
 *
 * @param out         [out] Pointer to store the generated certificate
 * @param caKeyFile   [in]  Path to the CA key file
 * @param sapkiFile   [in]  Path to the subject alternative public key info file
 * @param altPrivFile [in]  Path to the alternative private key file
 * @param setCrit     [in]  Flag to set criticality of extensions (1=critical, 0=non-critical)
 * @param setPathLen  [in]  Flag to set path length constraint (1=set, 0=don't set)
 * @param pathLen     [in]  Path length value (only used if setPathLen=1)
 * @return            Size of the generated certificate or negative on error
 */
static int do_dual_alg_root_certgen_crit(byte **out, char *caKeyFile,
                                      char *sapkiFile, char *altPrivFile,
                                      int setCrit, int setPathLen, int pathLen)
{
    EXPECT_DECLS;
    FILE* file = NULL;
    Cert newCert;
    DecodedCert preTBS;

    byte caKeyBuf[LARGE_TEMP_SZ];
    word32 caKeySz = LARGE_TEMP_SZ;
    byte sapkiBuf[LARGE_TEMP_SZ];
    word32 sapkiSz = LARGE_TEMP_SZ;
    byte altPrivBuf[LARGE_TEMP_SZ];
    word32 altPrivSz = LARGE_TEMP_SZ;
    byte altSigAlgBuf[LARGE_TEMP_SZ];
    word32 altSigAlgSz = LARGE_TEMP_SZ;
    byte scratchBuf[LARGE_TEMP_SZ];
    word32 scratchSz = LARGE_TEMP_SZ;
    byte preTbsBuf[LARGE_TEMP_SZ];
    word32 preTbsSz = LARGE_TEMP_SZ;
    byte altSigValBuf[LARGE_TEMP_SZ];
    word32 altSigValSz = LARGE_TEMP_SZ;
    byte *outBuf = NULL;
    word32 outSz = LARGE_TEMP_SZ;
    WC_RNG rng;
    RsaKey caKey;
    ecc_key altCaKey;
    word32 idx = 0;

    XMEMSET(&rng, 0, sizeof(WC_RNG));
    XMEMSET(&caKey, 0, sizeof(RsaKey));
    XMEMSET(&altCaKey, 0, sizeof(ecc_key));

    ExpectNotNull(outBuf = (byte*)XMALLOC(outSz, NULL,
                  DYNAMIC_TYPE_TMP_BUFFER));
    ExpectIntEQ(wc_InitRng(&rng), 0);
    XMEMSET(caKeyBuf, 0, caKeySz);
    ExpectNotNull(file = fopen(caKeyFile, "rb"));
    ExpectIntGT(caKeySz = (word32)fread(caKeyBuf, 1, caKeySz, file), 0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    ExpectIntEQ(wc_InitRsaKey_ex(&caKey, NULL, INVALID_DEVID), 0);
    idx = 0;
    ExpectIntEQ(wc_RsaPrivateKeyDecode(caKeyBuf, &idx, &caKey, caKeySz),
                0);
    XMEMSET(sapkiBuf, 0, sapkiSz);
    ExpectNotNull(file = fopen(sapkiFile, "rb"));
    ExpectIntGT(sapkiSz = (word32)fread(sapkiBuf, 1, sapkiSz, file), 0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    XMEMSET(altPrivBuf, 0, altPrivSz);
    ExpectNotNull(file = fopen(altPrivFile, "rb"));
    ExpectIntGT(altPrivSz = (word32)fread(altPrivBuf, 1, altPrivSz, file), 0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    wc_ecc_init(&altCaKey);
    idx = 0;
    ExpectIntEQ(wc_EccPrivateKeyDecode(altPrivBuf, &idx, &altCaKey,
                                       (word32)altPrivSz), 0);
    XMEMSET(altSigAlgBuf, 0, altSigAlgSz);
    ExpectIntGT(altSigAlgSz = SetAlgoID(CTC_SHA256wECDSA, altSigAlgBuf,
                                         oidSigType, 0), 0);
    wc_InitCert(&newCert);
    strncpy(newCert.subject.country, "US", CTC_NAME_SIZE);
    strncpy(newCert.subject.state, "MT", CTC_NAME_SIZE);
    strncpy(newCert.subject.locality, "Bozeman", CTC_NAME_SIZE);
    strncpy(newCert.subject.org, "wolfSSL", CTC_NAME_SIZE);
    strncpy(newCert.subject.unit, "Engineering", CTC_NAME_SIZE);
    strncpy(newCert.subject.commonName, "www.wolfssl.com", CTC_NAME_SIZE);
    strncpy(newCert.subject.email, "root@wolfssl.com", CTC_NAME_SIZE);
    strncpy((char*)newCert.beforeDate, "\x18\x0f""20250101000000Z",
        CTC_DATE_SIZE);
    newCert.beforeDateSz = 17;
    strncpy((char*)newCert.afterDate, "\x18\x0f""20493112115959Z",
        CTC_DATE_SIZE);
    newCert.afterDateSz = 17;
    newCert.sigType = CTC_SHA256wRSA;
    newCert.isCA    = 1;

    /* Set criticality of basic constraint extension if requested */
    if (setCrit) {
        newCert.basicConstCrit = 1;
    }

    /* Set pathlen if requested */
    if (setPathLen) {
        newCert.pathLen = pathLen;
        newCert.pathLenSet = 1;
    }

    ExpectIntEQ(wc_SetCustomExtension(&newCert, 0, "1.2.3.4.5",
                (const byte *)"This is NOT a critical extension", 32), 0);
    ExpectIntEQ(wc_SetCustomExtension(&newCert, setCrit, "2.5.29.72", sapkiBuf,
                sapkiSz), 0);
    ExpectIntEQ(wc_SetCustomExtension(&newCert, setCrit, "2.5.29.73",
                                      altSigAlgBuf, altSigAlgSz), 0);

    XMEMSET(scratchBuf, 0, scratchSz);
    ExpectIntGT(scratchSz = wc_MakeSelfCert(&newCert, scratchBuf, scratchSz,
                &caKey, &rng), 0);

    wc_InitDecodedCert(&preTBS, scratchBuf, scratchSz, 0);
    ExpectIntEQ(wc_ParseCert(&preTBS, CERT_TYPE, NO_VERIFY, NULL), 0);

    XMEMSET(preTbsBuf, 0, preTbsSz);
    ExpectIntGT(preTbsSz = wc_GeneratePreTBS(&preTBS, preTbsBuf, preTbsSz), 0);
    XMEMSET(altSigValBuf, 0, altSigValSz);
    ExpectIntGT(altSigValSz = wc_MakeSigWithBitStr(altSigValBuf, altSigValSz,
                CTC_SHA256wECDSA, preTbsBuf, preTbsSz, ECC_TYPE, &altCaKey,
                &rng), 0);
    ExpectIntEQ(wc_SetCustomExtension(&newCert, setCrit, "2.5.29.74",
                                      altSigValBuf, altSigValSz), 0);

    /* Finally, generate the new certificate. */
    if (outBuf != NULL) {
        XMEMSET(outBuf, 0, outSz);
        ExpectIntGT(outSz = wc_MakeSelfCert(&newCert, outBuf, outSz, &caKey,
                    &rng), 0);
        *out = outBuf;
    }
    else {
        outSz = 0;
    }

    wc_FreeDecodedCert(&preTBS);
    wc_ecc_free(&altCaKey);
    wc_FreeRsaKey(&caKey);
    wc_FreeRng(&rng);

    return (int)outSz;
}

/**
 * Function to generate a server certificate with dual algorithm support and
 * configurable criticality for extensions and path length constraints.
 *
 * @param out           [out] Pointer to store the generated certificate
 * @param caKeyFile     [in]  Path to the CA key file
 * @param sapkiFile     [in]  Path to the subject alternative public key info file
 * @param altPrivFile   [in]  Path to the alternative private key file
 * @param serverKeyFile [in]  Path to the server key file
 * @param caCertBuf     [in]  Buffer containing the CA certificate
 * @param caCertSz      [in]  Size of the CA certificate buffer
 * @param setCrit       [in]  Flag to set criticality of extensions (1=critical, 0=non-critical)
 * @param setPathLen    [in]  Flag to set path length constraint (1=set, 0=don't set)
 * @param pathLen       [in]  Path length value (only used if setPathLen=1)
 * @return              Size of the generated certificate or negative on error
 */
static int do_dual_alg_server_certgen_crit(byte **out, char *caKeyFile,
                                        char *sapkiFile, char *altPrivFile,
                                        char *serverKeyFile,
                                        byte *caCertBuf, int caCertSz,
                                        int setCrit)
{
    EXPECT_DECLS;
    FILE* file = NULL;
    Cert newCert;
    DecodedCert preTBS;

    byte serverKeyBuf[LARGE_TEMP_SZ];
    word32 serverKeySz = LARGE_TEMP_SZ;
    byte caKeyBuf[LARGE_TEMP_SZ];
    word32 caKeySz = LARGE_TEMP_SZ;
    byte sapkiBuf[LARGE_TEMP_SZ];
    word32 sapkiSz = LARGE_TEMP_SZ;
    byte altPrivBuf[LARGE_TEMP_SZ];
    word32 altPrivSz = LARGE_TEMP_SZ;
    byte altSigAlgBuf[LARGE_TEMP_SZ];
    word32 altSigAlgSz = LARGE_TEMP_SZ;
    byte scratchBuf[LARGE_TEMP_SZ];
    word32 scratchSz = LARGE_TEMP_SZ;
    byte preTbsBuf[LARGE_TEMP_SZ];
    word32 preTbsSz = LARGE_TEMP_SZ;
    byte altSigValBuf[LARGE_TEMP_SZ];
    word32 altSigValSz = LARGE_TEMP_SZ;
    byte *outBuf = NULL;
    word32 outSz = LARGE_TEMP_SZ;
    WC_RNG rng;
    RsaKey caKey;
    RsaKey serverKey;
    ecc_key altCaKey;
    word32 idx = 0;

    XMEMSET(&rng, 0, sizeof(WC_RNG));
    XMEMSET(&caKey, 0, sizeof(RsaKey));
    XMEMSET(&serverKey, 0, sizeof(RsaKey));
    XMEMSET(&altCaKey, 0, sizeof(ecc_key));

    ExpectNotNull(outBuf = (byte*)XMALLOC(outSz, NULL,
                  DYNAMIC_TYPE_TMP_BUFFER));
    ExpectIntEQ(wc_InitRng(&rng), 0);
    XMEMSET(serverKeyBuf, 0, serverKeySz);
    ExpectNotNull(file = fopen(serverKeyFile, "rb"));
    ExpectIntGT(serverKeySz = (word32)fread(serverKeyBuf, 1, serverKeySz, file),
                0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    ExpectIntEQ(wc_InitRsaKey_ex(&serverKey, NULL, INVALID_DEVID), 0);
    idx = 0;
    ExpectIntEQ(wc_RsaPrivateKeyDecode(serverKeyBuf, &idx, &serverKey,
                                       serverKeySz), 0);
    XMEMSET(caKeyBuf, 0, caKeySz);
    ExpectNotNull(file = fopen(caKeyFile, "rb"));
    ExpectIntGT(caKeySz = (word32)fread(caKeyBuf, 1, caKeySz, file), 0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    ExpectIntEQ(wc_InitRsaKey_ex(&caKey, NULL, INVALID_DEVID), 0);
    idx = 0;
    ExpectIntEQ(wc_RsaPrivateKeyDecode(caKeyBuf, &idx, &caKey, caKeySz), 0);
    XMEMSET(sapkiBuf, 0, sapkiSz);
    ExpectNotNull(file = fopen(sapkiFile, "rb"));
    ExpectIntGT(sapkiSz = (word32)fread(sapkiBuf, 1, sapkiSz, file), 0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    XMEMSET(altPrivBuf, 0, altPrivSz);
    ExpectNotNull(file = fopen(altPrivFile, "rb"));
    ExpectIntGT(altPrivSz = (word32)fread(altPrivBuf, 1, altPrivSz, file), 0);
    if (file) {
        fclose(file);
        file = NULL;
    }
    wc_ecc_init(&altCaKey);
    idx = 0;
    ExpectIntEQ(wc_EccPrivateKeyDecode(altPrivBuf, &idx, &altCaKey,
                                       (word32)altPrivSz), 0);
    XMEMSET(altSigAlgBuf, 0, altSigAlgSz);
    ExpectIntGT(altSigAlgSz = SetAlgoID(CTC_SHA256wECDSA, altSigAlgBuf,
                                         oidSigType, 0), 0);
    wc_InitCert(&newCert);
    strncpy(newCert.subject.country, "US", CTC_NAME_SIZE);
    strncpy(newCert.subject.state, "MT", CTC_NAME_SIZE);
    strncpy(newCert.subject.locality, "Bozeman", CTC_NAME_SIZE);
    strncpy(newCert.subject.org, "wolfSSL", CTC_NAME_SIZE);
    strncpy(newCert.subject.unit, "Engineering", CTC_NAME_SIZE);
    strncpy(newCert.subject.commonName, "www.wolfssl.com", CTC_NAME_SIZE);
    strncpy(newCert.subject.email, "server@wolfssl.com", CTC_NAME_SIZE);
    strncpy((char*)newCert.beforeDate, "\x18\x0f""20250101000000Z",
        CTC_DATE_SIZE);
    newCert.beforeDateSz = 17;
    strncpy((char*)newCert.afterDate, "\x18\x0f""20493112115959Z",
        CTC_DATE_SIZE);
    newCert.afterDateSz = 17;

    newCert.sigType = CTC_SHA256wRSA;
    newCert.isCA    = 0;
    ExpectIntEQ(wc_SetIssuerBuffer(&newCert, caCertBuf, caCertSz), 0);
    ExpectIntEQ(wc_SetCustomExtension(&newCert, setCrit, "2.5.29.72", sapkiBuf,
                                      sapkiSz), 0);
    ExpectIntEQ(wc_SetCustomExtension(&newCert, setCrit, "2.5.29.73",
                                      altSigAlgBuf, altSigAlgSz), 0);
    XMEMSET(scratchBuf, 0, scratchSz);
    ExpectIntGT(wc_MakeCert(&newCert, scratchBuf, scratchSz, &serverKey, NULL,
                &rng), 0);
    ExpectIntGT(scratchSz = wc_SignCert(newCert.bodySz, newCert.sigType,
                scratchBuf, scratchSz, &caKey, NULL, &rng), 0);
    wc_InitDecodedCert(&preTBS, scratchBuf, scratchSz, 0);
    ExpectIntEQ(wc_ParseCert(&preTBS, CERT_TYPE, NO_VERIFY, NULL), 0);
    XMEMSET(preTbsBuf, 0, preTbsSz);
    ExpectIntGT(preTbsSz = wc_GeneratePreTBS(&preTBS, preTbsBuf, preTbsSz), 0);
    XMEMSET(altSigValBuf, 0, altSigValSz);
    ExpectIntGT(altSigValSz = wc_MakeSigWithBitStr(altSigValBuf, altSigValSz,
                CTC_SHA256wECDSA, preTbsBuf, preTbsSz, ECC_TYPE, &altCaKey,
                &rng), 0);
    ExpectIntEQ(wc_SetCustomExtension(&newCert, setCrit, "2.5.29.74",
                                      altSigValBuf, altSigValSz), 0);

    /* Finally, generate the new certificate. */
    if (outBuf != NULL) {
        XMEMSET(outBuf, 0, outSz);
        ExpectIntGT(outSz = wc_SignCert(newCert.bodySz, newCert.sigType, scratchBuf,
                    outSz, &caKey, NULL, &rng), 0);
        *out = outBuf;
    }
    else {
        outSz = 0;
    }

    wc_FreeDecodedCert(&preTBS);
    wc_ecc_free(&altCaKey);
    wc_FreeRsaKey(&serverKey);
    wc_FreeRsaKey(&caKey);
    wc_FreeRng(&rng);

    return (int)outSz;
}

/**
 * Test dual-alg ECDSA + ML-DSA with critical extensions and path length
 * constraints:
 *  - keygen + certgen
 *
 * TLS tests not designed to pass with these extensions marked critical. No
 * TLS connection.
 * */
static int test_dual_alg_crit_ext_support(void)
{
    EXPECT_DECLS;
    /* Root CA and server keys will be the same. This is only appropriate for
     * testing. */
    char keyFile[] = "./certs/ca-key.der";
    char sapkiFile[] = "./certs/ecc-keyPub.der";
    char altPrivFile[] = "./certs/ecc-key.der";
    byte *serverKey = NULL;
    size_t serverKeySz = 0;
    byte *root = NULL;
    int rootSz = 0;
    byte *server = NULL;
    int serverSz = 0;

    ExpectIntEQ(load_file(keyFile, &serverKey, &serverKeySz), 0);

    /* Test with critical extensions and pathlen set to 1 */
    if (EXPECT_SUCCESS()) {
        rootSz = do_dual_alg_root_certgen_crit(&root, keyFile, sapkiFile,
            altPrivFile, 1, 1, 1);
    }
    ExpectNotNull(root);
    ExpectIntGT(rootSz, 0);
    if (EXPECT_SUCCESS()) {
        serverSz = do_dual_alg_server_certgen_crit(&server, keyFile, sapkiFile,
            altPrivFile, keyFile, root, rootSz, 1);
    }
    ExpectNotNull(server);
    ExpectIntGT(serverSz, 0);
    XFREE(root, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    root = NULL;
    XFREE(server, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    server = NULL;

    /* Test with critical extensions and pathlen set to 0 */
    if (EXPECT_SUCCESS()) {
        rootSz = do_dual_alg_root_certgen_crit(&root, keyFile, sapkiFile,
            altPrivFile, 1, 1, 0);
    }
    ExpectNotNull(root);
    ExpectIntGT(rootSz, 0);
    if (EXPECT_SUCCESS()) {
        serverSz = do_dual_alg_server_certgen_crit(&server, keyFile, sapkiFile,
            altPrivFile, keyFile, root, rootSz, 1);
    }
    ExpectNotNull(server);
    ExpectIntGT(serverSz, 0);
    XFREE(root, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    root = NULL;
    XFREE(server, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    server = NULL;

    /* Test with critical alt extensions and no pathlen set */
    if (EXPECT_SUCCESS()) {
        rootSz = do_dual_alg_root_certgen_crit(&root, keyFile, sapkiFile,
            altPrivFile, 1, 0, 0);
    }
    ExpectNotNull(root);
    ExpectIntGT(rootSz, 0);
    if (EXPECT_SUCCESS()) {
        serverSz = do_dual_alg_server_certgen_crit(&server, keyFile, sapkiFile,
            altPrivFile, keyFile, root, rootSz, 0);
    }
    ExpectNotNull(server);
    ExpectIntGT(serverSz, 0);
    XFREE(root, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(server, NULL, DYNAMIC_TYPE_TMP_BUFFER);

    XFREE(serverKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);

    return EXPECT_RESULT();
}

static int test_dual_alg_support(void)
{
    EXPECT_DECLS;
    /* Root CA and server keys will be the same. This is only appropriate for
     * testing. */
    char keyFile[] = "./certs/ca-key.der";
    char sapkiFile[] = "./certs/ecc-keyPub.der";
    char altPrivFile[] = "./certs/ecc-key.der";
    char wrongPrivFile[] = "./certs/ecc-client-key.der";
    byte *serverKey = NULL;
    size_t serverKeySz = 0;
    byte *root = NULL;
    int rootSz = 0;
    byte *server = NULL;
    int serverSz = 0;

    ExpectIntEQ(load_file(keyFile, &serverKey, &serverKeySz), 0);

    /* Base normal case. */
    if (EXPECT_SUCCESS()) {
        rootSz = do_dual_alg_root_certgen(&root, keyFile, sapkiFile,
            altPrivFile);
    }
    ExpectNotNull(root);
    ExpectIntGT(rootSz, 0);
    if (EXPECT_SUCCESS()) {
        serverSz = do_dual_alg_server_certgen(&server, keyFile, sapkiFile,
            altPrivFile, keyFile, root, rootSz);
    }
    ExpectNotNull(server);
    ExpectIntGT(serverSz, 0);
    ExpectIntEQ(do_dual_alg_tls13_connection(root, rootSz,
                server, serverSz, serverKey, (word32)serverKeySz, 0),
                TEST_SUCCESS);
    XFREE(root, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    root = NULL;
    XFREE(server, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    server = NULL;

    /* Now we try a negative case. Note that we use wrongPrivFile to generate
     * the alternative signature and then set negative_test to true for the
     * call to do_dual_alg_tls13_connection(). Its expecting a failed connection
     * because the signature won't verify. The exception is if
     * WOLFSSL_TRUST_PEER_CERT is defined. In that case, no verification happens
     * and this is no longer a negative test. */
    if (EXPECT_SUCCESS()) {
        rootSz = do_dual_alg_root_certgen(&root, keyFile, sapkiFile,
            wrongPrivFile);
    }
    ExpectNotNull(root);
    ExpectIntGT(rootSz, 0);
    if (EXPECT_SUCCESS()) {
        serverSz = do_dual_alg_server_certgen(&server, keyFile, sapkiFile,
            wrongPrivFile, keyFile, root, rootSz);
    }
    ExpectNotNull(server);
    ExpectIntGT(serverSz, 0);
#ifdef WOLFSSL_TRUST_PEER_CERT
    ExpectIntEQ(do_dual_alg_tls13_connection(root, rootSz,
                server, serverSz, serverKey, (word32)serverKeySz, 0),
                TEST_SUCCESS);
#else
    ExpectIntEQ(do_dual_alg_tls13_connection(root, rootSz,
                server, serverSz, serverKey, (word32)serverKeySz, 1),
                TEST_SUCCESS);
#endif

    XFREE(root, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(server, NULL, DYNAMIC_TYPE_TMP_BUFFER);

    XFREE(serverKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);

    return EXPECT_RESULT();
}
#else
static int test_dual_alg_support(void)
{
    return TEST_SKIPPED;
}

static int test_dual_alg_crit_ext_support(void)
{
    return TEST_SKIPPED;
}

#endif /* WOLFSSL_DUAL_ALG_CERTS && !NO_FILESYSTEM */

/**
 * Test dual-alg ECDSA + ML-DSA:
 *  - keygen + certgen + cert manager load
 * */
static int test_dual_alg_ecdsa_mldsa(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_DUAL_ALG_CERTS) && defined(WOLFSSL_HAVE_MLDSA) && \
    defined(HAVE_ECC) && !defined(WC_NO_RNG) && \
    !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \
    !defined(WOLFSSL_MLDSA_NO_SIGN) && \
    !defined(WOLFSSL_MLDSA_NO_VERIFY) && !defined(WOLFSSL_SMALL_STACK)
    WOLFSSL_CERT_MANAGER * cm = NULL;
    wc_MlDsaKey alt_ca_key;
    ecc_key     ca_key;
    WC_RNG      rng;
    int         ret = 0;
    DecodedCert d_cert;
    Cert        new_cert;
    /* various tmp buffs.  */
    byte        alt_pub_der[LARGE_TEMP_SZ];
    word32      alt_pub_sz = LARGE_TEMP_SZ;
    byte        alt_sig_alg[LARGE_TEMP_SZ];
    word32      alt_sig_alg_sz = LARGE_TEMP_SZ;
    byte        tbs_der[LARGE_TEMP_SZ];
    word32      tbs_der_sz = LARGE_TEMP_SZ;
    byte        alt_sig[LARGE_TEMP_SZ];
    word32      alt_sig_sz = LARGE_TEMP_SZ;
    /* Intermediate der. */
    byte        der[LARGE_TEMP_SZ];
    word32      der_sz = LARGE_TEMP_SZ;
    /* The final der will be large because of ML-DSA signature. */
    byte        final_der[2 * LARGE_TEMP_SZ];
    word32      final_der_sz = 2 * LARGE_TEMP_SZ;

    XMEMSET(alt_pub_der, 0, alt_pub_sz);
    XMEMSET(alt_sig_alg, 0, alt_sig_alg_sz);
    XMEMSET(tbs_der, 0, tbs_der_sz);
    XMEMSET(alt_sig, 0, alt_sig_sz);
    XMEMSET(der, 0, der_sz);
    XMEMSET(final_der, 0, final_der_sz);

    ExpectIntEQ(wc_InitRng(&rng), 0);

    /**
     * ML-DSA key gen.
     * */
    ret = wc_MlDsaKey_Init(&alt_ca_key, NULL, INVALID_DEVID);
    ExpectIntEQ(ret, 0);
    ret = wc_MlDsaKey_SetParams(&alt_ca_key, WC_ML_DSA_44);
    ExpectIntEQ(ret, 0);
    ret = wc_MlDsaKey_MakeKey(&alt_ca_key, &rng);
    ExpectIntEQ(ret, 0);
    alt_pub_sz = wc_MlDsaKey_PublicKeyToDer(&alt_ca_key, alt_pub_der,
                                            alt_pub_sz, 1);
    ExpectIntGT(alt_pub_sz, 0);

    alt_sig_alg_sz = SetAlgoID(CTC_SHA256wECDSA, alt_sig_alg, oidSigType, 0);
    ExpectIntGT(alt_sig_alg_sz, 0);

    /**
     * ECC key gen.
     * */
    ret = wc_ecc_init(&ca_key);
    ExpectIntEQ(ret, 0);
    ret = wc_ecc_make_key(&rng, KEY32, &ca_key);
    ExpectIntEQ(ret, 0);

    /**
     * Cert gen.
     * */
    wc_InitCert(&new_cert);
    strncpy(new_cert.subject.country, "US", CTC_NAME_SIZE);
    strncpy(new_cert.subject.state, "MT", CTC_NAME_SIZE);
    strncpy(new_cert.subject.locality, "Bozeman", CTC_NAME_SIZE);
    strncpy(new_cert.subject.org, "wolfSSL", CTC_NAME_SIZE);
    strncpy(new_cert.subject.unit, "Engineering", CTC_NAME_SIZE);
    strncpy(new_cert.subject.commonName, "www.wolfssl.com", CTC_NAME_SIZE);
    strncpy(new_cert.subject.email, "root@wolfssl.com", CTC_NAME_SIZE);
    new_cert.sigType = CTC_SHA256wECDSA;
    new_cert.isCA    = 1;

    ret = wc_SetCustomExtension(&new_cert, 0, "1.2.3.4.5",
                         (const byte *)"This is NOT a critical extension", 32);
    ExpectIntEQ(ret, 0);

    ExpectIntEQ(wc_SetCustomExtension(&new_cert, 0, "2.5.29.72", alt_pub_der,
                alt_pub_sz), 0);
    ExpectIntEQ(wc_SetCustomExtension(&new_cert, 0, "2.5.29.73", alt_sig_alg,
                alt_sig_alg_sz), 0);

    ret = wc_MakeCert_ex(&new_cert, der, der_sz, ECC_TYPE, &ca_key, &rng);
    ExpectIntGT(ret, 0);

    der_sz = wc_SignCert_ex(new_cert.bodySz, new_cert.sigType, der, der_sz,
                            ECC_TYPE, &ca_key, &rng);
    ExpectIntGT(der_sz, 0);

    wc_InitDecodedCert(&d_cert, der, der_sz, 0);
    ret = wc_ParseCert(&d_cert, CERT_TYPE, NO_VERIFY, NULL);
    ExpectIntEQ(ret, 0);

    tbs_der_sz = wc_GeneratePreTBS(&d_cert, tbs_der, tbs_der_sz);
    ExpectIntGT(tbs_der_sz, 0);

    alt_sig_sz = wc_MakeSigWithBitStr(alt_sig, alt_sig_sz,
                                      CTC_ML_DSA_44, tbs_der, tbs_der_sz,
                                      ML_DSA_44_TYPE, &alt_ca_key, &rng);
    ExpectIntGT(alt_sig_sz, 0);

    ret = wc_SetCustomExtension(&new_cert, 0, "2.5.29.74", alt_sig, alt_sig_sz);
    ExpectIntEQ(ret, 0);

    /* Finally generate the new certificate. */
    ret = wc_MakeCert_ex(&new_cert, final_der, final_der_sz, ECC_TYPE, &ca_key,
                         &rng);
    ExpectIntGT(ret, 0);

    final_der_sz = wc_SignCert_ex(new_cert.bodySz, new_cert.sigType, final_der,
                                  final_der_sz, ECC_TYPE, &ca_key, &rng);
    ExpectIntGT(final_der_sz, 0);

    cm = wolfSSL_CertManagerNew();
    ExpectNotNull(cm);

    /* Load the certificate into CertManager. */
    if (cm != NULL && final_der_sz > 0) {
        ret = wolfSSL_CertManagerLoadCABuffer(cm, final_der, final_der_sz,
                                              WOLFSSL_FILETYPE_ASN1);
        ExpectIntEQ(ret, WOLFSSL_SUCCESS);
    }

    if (cm != NULL) {
        wolfSSL_CertManagerFree(cm);
        cm = NULL;
    }

    wc_FreeDecodedCert(&d_cert);
    wc_ecc_free(&ca_key);
    wc_MlDsaKey_Free(&alt_ca_key);
    wc_FreeRng(&rng);

#endif /* WOLFSSL_DUAL_ALG_CERTS && DILITHIUM and more */
    return EXPECT_RESULT();
}

/* Test wolfSSL_use_AltPrivateKey_Id.
 * Verify that a valid key ID can be set successfully. Guards against an
 * inverted AllocDer return check (== 0 vs != 0) that would treat successful
 * allocation as failure. */
static int test_wolfSSL_use_AltPrivateKey_Id(void)
{
    EXPECT_DECLS;
#if defined(WOLF_PRIVATE_KEY_ID) && defined(WOLFSSL_DUAL_ALG_CERTS) && \
    !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL*     ssl = NULL;
    const unsigned char id[] = { 0x01, 0x02, 0x03, 0x04 };

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* Negative tests. */
    ExpectIntEQ(wolfSSL_use_AltPrivateKey_Id(NULL, id, sizeof(id),
        INVALID_DEVID), 0);
    ExpectIntEQ(wolfSSL_use_AltPrivateKey_Id(ssl, NULL, sizeof(id),
        INVALID_DEVID), 0);

    /* Positive test - valid ID should succeed. */
    ExpectIntEQ(wolfSSL_use_AltPrivateKey_Id(ssl, id, sizeof(id),
        INVALID_DEVID), 1);

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif /* WOLF_PRIVATE_KEY_ID && WOLFSSL_DUAL_ALG_CERTS && !NO_TLS && */
       /* !NO_WOLFSSL_CLIENT                                          */
    return EXPECT_RESULT();
}

/* Test wolfSSL_use_AltPrivateKey_Label.
 * Verify that a valid key label can be set successfully. Guards against an
 * inverted AllocDer return check (== 0 vs != 0) that would treat successful
 * allocation as failure. */
static int test_wolfSSL_use_AltPrivateKey_Label(void)
{
    EXPECT_DECLS;
#if defined(WOLF_PRIVATE_KEY_ID) && defined(WOLFSSL_DUAL_ALG_CERTS) && \
    !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL*     ssl = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* Negative tests. */
    ExpectIntEQ(wolfSSL_use_AltPrivateKey_Label(NULL, "label", INVALID_DEVID),
        0);
    ExpectIntEQ(wolfSSL_use_AltPrivateKey_Label(ssl, NULL, INVALID_DEVID), 0);

    /* Positive test - valid label should succeed. */
    ExpectIntEQ(wolfSSL_use_AltPrivateKey_Label(ssl, "test_label",
        INVALID_DEVID), 1);

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif /* WOLF_PRIVATE_KEY_ID && WOLFSSL_DUAL_ALG_CERTS && !NO_TLS && */
       /* !NO_WOLFSSL_CLIENT                                          */
    return EXPECT_RESULT();
}


/*----------------------------------------------------------------------------*
 | Context
 *----------------------------------------------------------------------------*/
#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS)
static int test_wolfSSL_CTX_new(void)
{
    EXPECT_DECLS;
    WOLFSSL_CTX *ctx;
    WOLFSSL_METHOD* method = NULL;

    ExpectNull(ctx = wolfSSL_CTX_new(NULL));
    ExpectNotNull(method = wolfSSLv23_server_method());
    if (method != NULL)
        ExpectNotNull(ctx = wolfSSL_CTX_new(method));

    wolfSSL_CTX_free(ctx);

    return EXPECT_RESULT();
}
#endif

#if (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)) && \
    !defined(NO_TLS) && \
    (!defined(NO_RSA) || defined(HAVE_ECC)) && !defined(NO_FILESYSTEM)
static int test_for_double_Free(void)
{
    EXPECT_DECLS;
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL*     ssl = NULL;
    int skipTest = 0;
    const char* testCertFile;
    const char* testKeyFile;
    char optionsCiphers[] = "RC4-SHA:RC4-MD5:DES-CBC3-SHA:AES128-SHA:AES256-SHA"
":NULL-SHA:NULL-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-PSK-AES256-GCM"
"-SHA384:DHE-PSK-AES128-GCM-SHA256:PSK-AES256-GCM-SHA384:PSK-AES128-GCM-SHA256:"
"DHE-PSK-AES256-CBC-SHA384:DHE-PSK-AES128-CBC-SHA256:PSK-AES256-CBC-SHA384:PSK-"
"AES128-CBC-SHA256:PSK-AES128-CBC-SHA:PSK-AES256-CBC-SHA:DHE-PSK-AES128-CCM:DHE"
"-PSK-AES256-CCM:PSK-AES128-CCM:PSK-AES256-CCM:PSK-AES128-CCM-8:PSK-AES256-CCM-"
"8:DHE-PSK-NULL-SHA384:DHE-PSK-NULL-SHA256:PSK-NULL-SHA384:PSK-NULL-SHA256:PSK-"
"NULL-SHA:AES128-CCM-8:AES256-CCM-8:ECDHE-ECDSA-"
"AES128-CCM:ECDHE-ECDSA-AES128-CCM-8:ECDHE-ECDSA-AES256-CCM-8:ECDHE-RSA-AES128-"
"SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-R"
"SA-RC4-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-RC4-SHA:ECDHE-ECDSA-DES-CBC3-SHA"
":AES128-SHA256:AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:ECDH-"
"RSA-AES128-SHA:ECDH-RSA-AES256-SHA:ECDH-ECDSA-AES128-SHA:ECDH-ECDSA-AES256-SHA"
":ECDH-RSA-RC4-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-ECDSA-RC4-SHA:ECDH-ECDSA-DES-CBC3"
"-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES"
"256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-E"
"CDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDH-RSA-AES128-GCM-SHA25"
"6:ECDH-RSA-AES256-GCM-SHA384:ECDH-ECDSA-AES128-GCM-SHA256:ECDH-ECDSA-AES256-GC"
"M-SHA384:CAMELLIA128-SHA:DHE-RSA-CAMELLIA128-SHA:CAMELLIA256-SHA:DHE-RSA-CAMEL"
"LIA256-SHA:CAMELLIA128-SHA256:DHE-RSA-CAMELLIA128-SHA256:CAMELLIA256-SHA256:DH"
"E-RSA-CAMELLIA256-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECD"
"H-RSA-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-ECD"
"SA-AES256-SHA384:ECDH-RSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDHE-RSA-CHA"
"CHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-R"
"SA-CHACHA20-POLY1305-OLD:ECDHE-ECDSA-CHACHA20-POLY1305-OLD:DHE-RSA-CHACHA20-PO"
"LY1305-OLD:ECDHE-ECDSA-NULL-SHA:ECDHE-PSK-NULL-SHA256:ECDHE-PSK-A"
"ES128-CBC-SHA256:PSK-CHACHA20-POLY1305:ECDHE-PSK-CHACHA20-POLY1305:DHE-PSK-CHA"
"CHA20-POLY1305:EDH-RSA-DES-CBC3-SHA:TLS13-AES128-GCM-SHA256:TLS13-AES256-GCM-S"
"HA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES128-CCM-SHA256:TLS13-AES128-CCM-"
"8-SHA256:TLS13-SHA256-SHA256:TLS13-SHA384-SHA384";
    /* OpenVPN uses a "blacklist" method to specify which ciphers NOT to use */
#ifdef OPENSSL_EXTRA
    char openvpnCiphers[] = "DEFAULT:!EXP:!LOW:!MEDIUM:!kDH:!kECDH:!DSS:!PSK:"
                            "!SRP:!kRSA:!aNULL:!eNULL";
#endif

#ifndef NO_RSA
    testCertFile = svrCertFile;
    testKeyFile = svrKeyFile;
#elif defined(HAVE_ECC)
    testCertFile = eccCertFile;
    testKeyFile = eccKeyFile;
#else
    skipTest = 1;
#endif

    if (skipTest != 1) {
#ifndef NO_WOLFSSL_SERVER
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#endif
        ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, testCertFile,
            CERT_FILETYPE));
        ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, testKeyFile,
            CERT_FILETYPE));
        ExpectNotNull(ssl = wolfSSL_new(ctx));

        /* First test freeing SSL, then CTX */
        wolfSSL_free(ssl);
        ssl = NULL;
        wolfSSL_CTX_free(ctx);
        ctx = NULL;

#ifndef NO_WOLFSSL_CLIENT
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#endif
        ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, testCertFile,
            CERT_FILETYPE));
        ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, testKeyFile,
            CERT_FILETYPE));
        ExpectNotNull(ssl = wolfSSL_new(ctx));

        /* Next test freeing CTX then SSL */
        wolfSSL_CTX_free(ctx);
        ctx = NULL;
        wolfSSL_free(ssl);
        ssl = NULL;

#ifndef NO_WOLFSSL_SERVER
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#endif
        /* Test setting ciphers at ctx level */
        ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, testCertFile,
            CERT_FILETYPE));
        ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, testKeyFile,
            CERT_FILETYPE));
        ExpectTrue(wolfSSL_CTX_set_cipher_list(ctx, optionsCiphers));
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_TLS13) && defined(HAVE_AESGCM) && \
        defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256)
        /* only update TLSv13 suites */
        ExpectTrue(wolfSSL_CTX_set_cipher_list(ctx, "TLS13-AES256-GCM-SHA384"));
#endif
#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) && defined(HAVE_AESGCM) && \
    !defined(NO_SHA256) && !defined(WOLFSSL_NO_TLS12) && \
    defined(WOLFSSL_AES_128) && !defined(NO_RSA)
        /* only update pre-TLSv13 suites */
        ExpectTrue(wolfSSL_CTX_set_cipher_list(ctx,
            "ECDHE-RSA-AES128-GCM-SHA256"));
#endif
#ifdef OPENSSL_EXTRA
        ExpectTrue(wolfSSL_CTX_set_cipher_list(ctx, openvpnCiphers));
#endif
        ExpectNotNull(ssl = wolfSSL_new(ctx));
        wolfSSL_CTX_free(ctx);
        ctx = NULL;
        wolfSSL_free(ssl);
        ssl = NULL;

#ifndef NO_WOLFSSL_CLIENT
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#endif
        ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, testCertFile,
            CERT_FILETYPE));
        ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, testKeyFile,
            CERT_FILETYPE));
        ExpectNotNull(ssl = wolfSSL_new(ctx));
        /* test setting ciphers at SSL level */
        ExpectTrue(wolfSSL_set_cipher_list(ssl, optionsCiphers));
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_TLS13) && defined(HAVE_AESGCM) && \
        defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256)
        /* only update TLSv13 suites */
        ExpectTrue(wolfSSL_set_cipher_list(ssl, "TLS13-AES256-GCM-SHA384"));
#endif
#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) && defined(HAVE_AESGCM) && \
    !defined(NO_SHA256) && !defined(WOLFSSL_NO_TLS12) && \
    defined(WOLFSSL_AES_128) && !defined(NO_RSA)
        /* only update pre-TLSv13 suites */
        ExpectTrue(wolfSSL_set_cipher_list(ssl, "ECDHE-RSA-AES128-GCM-SHA256"));
#endif
        wolfSSL_CTX_free(ctx);
        ctx = NULL;
        wolfSSL_free(ssl);
        ssl = NULL;
    }

    return EXPECT_RESULT();
}
#endif


static int test_wolfSSL_CTX_set_cipher_list_bytes(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_SET_CIPHER_BYTES)) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)) && \
    (!defined(NO_RSA) || defined(HAVE_ECC)) && !defined(NO_FILESYSTEM) && \
    !defined(NO_TLS)
    const char* testCertFile;
    const char* testKeyFile;
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;

    const byte cipherList[] =
    {
        /* TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA */ 0x00, 0x16,
        /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA  */ 0x00, 0x39,
        /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA  */ 0x00, 0x33,
        /* TLS_DH_anon_WITH_AES_128_CBC_SHA  */ 0x00, 0x34,
        /* TLS_RSA_WITH_AES_256_CBC_SHA      */ 0x00, 0x35,
        /* TLS_RSA_WITH_AES_128_CBC_SHA      */ 0x00, 0x2F,
        /* TLS_RSA_WITH_NULL_MD5             */ 0x00, 0x01,
        /* TLS_RSA_WITH_NULL_SHA             */ 0x00, 0x02,
        /* TLS_PSK_WITH_AES_256_CBC_SHA      */ 0x00, 0x8d,
        /* TLS_PSK_WITH_AES_128_CBC_SHA256   */ 0x00, 0xae,
        /* TLS_PSK_WITH_AES_256_CBC_SHA384   */ 0x00, 0xaf,
        /* TLS_PSK_WITH_AES_128_CBC_SHA      */ 0x00, 0x8c,
        /* TLS_PSK_WITH_NULL_SHA256          */ 0x00, 0xb0,
        /* TLS_PSK_WITH_NULL_SHA384          */ 0x00, 0xb1,
        /* TLS_PSK_WITH_NULL_SHA             */ 0x00, 0x2c,
        /* SSL_RSA_WITH_RC4_128_SHA          */ 0x00, 0x05,
        /* SSL_RSA_WITH_RC4_128_MD5          */ 0x00, 0x04,
        /* SSL_RSA_WITH_3DES_EDE_CBC_SHA     */ 0x00, 0x0A,

        /* ECC suites, first byte is 0xC0 (ECC_BYTE) */
        /* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA     */ 0xC0, 0x14,
        /* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA     */ 0xC0, 0x13,
        /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA   */ 0xC0, 0x0A,
        /* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA   */ 0xC0, 0x09,
        /* TLS_ECDHE_RSA_WITH_RC4_128_SHA         */ 0xC0, 0x11,
        /* TLS_ECDHE_ECDSA_WITH_RC4_128_SHA       */ 0xC0, 0x07,
        /* TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA    */ 0xC0, 0x12,
        /* TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA  */ 0xC0, 0x08,
        /* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256  */ 0xC0, 0x27,
        /* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256*/ 0xC0, 0x23,
        /* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384  */ 0xC0, 0x28,
        /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384*/ 0xC0, 0x24,
        /* TLS_ECDHE_ECDSA_WITH_NULL_SHA          */ 0xC0, 0x06,
        /* TLS_ECDHE_PSK_WITH_NULL_SHA256         */ 0xC0, 0x3a,
        /* TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256  */ 0xC0, 0x37,

        /* static ECDH, first byte is 0xC0 (ECC_BYTE) */
        /* TLS_ECDH_RSA_WITH_AES_256_CBC_SHA      */ 0xC0, 0x0F,
        /* TLS_ECDH_RSA_WITH_AES_128_CBC_SHA      */ 0xC0, 0x0E,
        /* TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA    */ 0xC0, 0x05,
        /* TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA    */ 0xC0, 0x04,
        /* TLS_ECDH_RSA_WITH_RC4_128_SHA          */ 0xC0, 0x0C,
        /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA        */ 0xC0, 0x02,
        /* TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA     */ 0xC0, 0x0D,
        /* TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA   */ 0xC0, 0x03,
        /* TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256   */ 0xC0, 0x29,
        /* TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 */ 0xC0, 0x25,
        /* TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384   */ 0xC0, 0x2A,
        /* TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 */ 0xC0, 0x26,

        /* WDM_WITH_NULL_SHA256 */ 0x00, 0xFE, /* wolfSSL DTLS Multicast */

        /* SHA256 */
        /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 */ 0x00, 0x6b,
        /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 */ 0x00, 0x67,
        /* TLS_RSA_WITH_AES_256_CBC_SHA256     */ 0x00, 0x3d,
        /* TLS_RSA_WITH_AES_128_CBC_SHA256     */ 0x00, 0x3c,
        /* TLS_RSA_WITH_NULL_SHA256            */ 0x00, 0x3b,
        /* TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 */ 0x00, 0xb2,
        /* TLS_DHE_PSK_WITH_NULL_SHA256        */ 0x00, 0xb4,

        /* SHA384 */
        /* TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 */ 0x00, 0xb3,
        /* TLS_DHE_PSK_WITH_NULL_SHA384        */ 0x00, 0xb5,

        /* AES-GCM */
        /* TLS_RSA_WITH_AES_128_GCM_SHA256      */ 0x00, 0x9c,
        /* TLS_RSA_WITH_AES_256_GCM_SHA384      */ 0x00, 0x9d,
        /* TLS_DHE_RSA_WITH_AES_128_GCM_SHA256  */ 0x00, 0x9e,
        /* TLS_DHE_RSA_WITH_AES_256_GCM_SHA384  */ 0x00, 0x9f,
        /* TLS_DH_anon_WITH_AES_256_GCM_SHA384  */ 0x00, 0xa7,
        /* TLS_PSK_WITH_AES_128_GCM_SHA256      */ 0x00, 0xa8,
        /* TLS_PSK_WITH_AES_256_GCM_SHA384      */ 0x00, 0xa9,
        /* TLS_DHE_PSK_WITH_AES_128_GCM_SHA256  */ 0x00, 0xaa,
        /* TLS_DHE_PSK_WITH_AES_256_GCM_SHA384  */ 0x00, 0xab,

        /* ECC AES-GCM, first byte is 0xC0 (ECC_BYTE) */
        /* TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 */ 0xC0, 0x2b,
        /* TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 */ 0xC0, 0x2c,
        /* TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256  */ 0xC0, 0x2d,
        /* TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384  */ 0xC0, 0x2e,
        /* TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256   */ 0xC0, 0x2f,
        /* TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384   */ 0xC0, 0x30,
        /* TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256    */ 0xC0, 0x31,
        /* TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384    */ 0xC0, 0x32,

        /* AES-CCM, first byte is 0xC0 but isn't ECC,
         * also, in some of the other AES-CCM suites
         * there will be second byte number conflicts
         * with non-ECC AES-GCM */
        /* TLS_RSA_WITH_AES_128_CCM_8         */ 0xC0, 0xa0,
        /* TLS_RSA_WITH_AES_256_CCM_8         */ 0xC0, 0xa1,
        /* TLS_ECDHE_ECDSA_WITH_AES_128_CCM   */ 0xC0, 0xac,
        /* TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */ 0xC0, 0xae,
        /* TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 */ 0xC0, 0xaf,
        /* TLS_PSK_WITH_AES_128_CCM           */ 0xC0, 0xa4,
        /* TLS_PSK_WITH_AES_256_CCM           */ 0xC0, 0xa5,
        /* TLS_PSK_WITH_AES_128_CCM_8         */ 0xC0, 0xa8,
        /* TLS_PSK_WITH_AES_256_CCM_8         */ 0xC0, 0xa9,
        /* TLS_DHE_PSK_WITH_AES_128_CCM       */ 0xC0, 0xa6,
        /* TLS_DHE_PSK_WITH_AES_256_CCM       */ 0xC0, 0xa7,

        /* Camellia */
        /* TLS_RSA_WITH_CAMELLIA_128_CBC_SHA        */ 0x00, 0x41,
        /* TLS_RSA_WITH_CAMELLIA_256_CBC_SHA        */ 0x00, 0x84,
        /* TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256     */ 0x00, 0xba,
        /* TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256     */ 0x00, 0xc0,
        /* TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA    */ 0x00, 0x45,
        /* TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA    */ 0x00, 0x88,
        /* TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 */ 0x00, 0xbe,
        /* TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 */ 0x00, 0xc4,

        /* chacha20-poly1305 suites first byte is 0xCC (CHACHA_BYTE) */
        /* TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256   */ 0xCC, 0xa8,
        /* TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 */ 0xCC, 0xa9,
        /* TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256     */ 0xCC, 0xaa,
        /* TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256   */ 0xCC, 0xac,
        /* TLS_PSK_WITH_CHACHA20_POLY1305_SHA256         */ 0xCC, 0xab,
        /* TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256     */ 0xCC, 0xad,

        /* chacha20-poly1305 earlier version of nonce and padding (CHACHA_BYTE) */
        /* TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256   */ 0xCC, 0x13,
        /* TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 */ 0xCC, 0x14,
        /* TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256     */ 0xCC, 0x15,

        /* ECDHE_PSK RFC8442, first byte is 0xD0 (ECDHE_PSK_BYTE) */
        /* TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 */ 0xD0, 0x01,

        /* TLS v1.3 cipher suites */
        /* TLS_AES_128_GCM_SHA256       */ 0x13, 0x01,
        /* TLS_AES_256_GCM_SHA384       */ 0x13, 0x02,
        /* TLS_CHACHA20_POLY1305_SHA256 */ 0x13, 0x03,
        /* TLS_AES_128_CCM_SHA256       */ 0x13, 0x04,
        /* TLS_AES_128_CCM_8_SHA256     */ 0x13, 0x05,

        /* TLS v1.3 Integrity only cipher suites - 0xC0 (ECC) first byte */
        /* TLS_SHA256_SHA256 */ 0xC0, 0xB4,
        /* TLS_SHA384_SHA384 */ 0xC0, 0xB5
    };

#ifndef NO_RSA
    testCertFile = svrCertFile;
    testKeyFile = svrKeyFile;
#elif defined(HAVE_ECC)
    testCertFile = eccCertFile;
    testKeyFile = eccKeyFile;
#endif

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#endif

    ExpectTrue(wolfSSL_CTX_set_cipher_list_bytes(ctx, &cipherList[0U],
                                                           sizeof(cipherList)));

    wolfSSL_CTX_free(ctx);
    ctx = NULL;

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#endif

    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, testCertFile,
                                                         CERT_FILETYPE));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, testKeyFile,
                                                         CERT_FILETYPE));

    ExpectNotNull(ssl = wolfSSL_new(ctx));

    ExpectTrue(wolfSSL_set_cipher_list_bytes(ssl, &cipherList[0U],
                                                           sizeof(cipherList)));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif /* (OPENSSL_EXTRA || WOLFSSL_SET_CIPHER_BYTES) &&
    (!NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER) && (!NO_RSA || HAVE_ECC) */

    return EXPECT_RESULT();
}

#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_TLS13) && \
    !defined(WOLFSSL_NO_TLS12) && \
    !defined(NO_WOLFSSL_CLIENT) && \
    !defined(HAVE_RENEGOTIATION_INDICATION) && \
    defined(HAVE_AESGCM) && \
    ((!defined(NO_RSA) && defined(HAVE_ECC)) || !defined(NO_ERROR_STRINGS))
/* Helper function to check if TLS 1.3 suites exist in the suites list */
static int suites_has_tls13(const byte* suites, word16 suiteSz)
{
    word16 i;
    for (i = 0; i < suiteSz; i += 2) {
        if (suites[i] == 0x13) { /* TLS13_BYTE */
            return 1;
        }
    }
    return 0;
}

/* Helper function to check if TLS 1.2 (non-1.3) suites exist in the suites list */
static int suites_has_tls12(const byte* suites, word16 suiteSz)
{
    word16 i;
    for (i = 0; i < suiteSz; i += 2) {
        if (suites[i] != 0x13) { /* Not TLS13_BYTE */
            return 1;
        }
    }
    return 0;
}
#endif

/* Test 1: SSLv23 + set TLS 1.2 cipher -> TLS 1.3 suites should still be there */
static int test_wolfSSL_set_cipher_list_tls12_keeps_tls13(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_TLS13) && \
    !defined(WOLFSSL_NO_TLS12) && \
    !defined(NO_WOLFSSL_CLIENT) && \
    !defined(HAVE_RENEGOTIATION_INDICATION) && \
    defined(HAVE_AESGCM) && defined(HAVE_ECC) && !defined(NO_RSA)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* Set only a TLS 1.2 cipher suite */
    ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "ECDHE-RSA-AES128-GCM-SHA256"),
                WOLFSSL_SUCCESS);

    /* TLS 1.3 suites should still be present (downgrade is enabled) */
    ExpectNotNull(ssl->suites);
    ExpectTrue(suites_has_tls13(ssl->suites->suites, ssl->suites->suiteSz));
    /* The TLS 1.2 suite we set should also be there */
    ExpectTrue(suites_has_tls12(ssl->suites->suites, ssl->suites->suiteSz));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

/* Test 2: SSLv23 + set TLS 1.3 cipher -> TLS 1.2 suites should still be there */
static int test_wolfSSL_set_cipher_list_tls13_keeps_tls12(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_TLS13) && \
    !defined(WOLFSSL_NO_TLS12) && \
    !defined(NO_WOLFSSL_CLIENT) && \
    !defined(HAVE_RENEGOTIATION_INDICATION) && \
    defined(HAVE_AESGCM) && !defined(NO_ERROR_STRINGS)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* Set only a TLS 1.3 cipher suite */
    ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "TLS_AES_128_GCM_SHA256"),
                WOLFSSL_SUCCESS);

    /* TLS 1.2 suites should still be present (downgrade is enabled) */
    ExpectNotNull(ssl->suites);
    ExpectTrue(suites_has_tls12(ssl->suites->suites, ssl->suites->suiteSz));
    /* The TLS 1.3 suite we set should also be there */
    ExpectTrue(suites_has_tls13(ssl->suites->suites, ssl->suites->suiteSz));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

/* Test 3: SSLv23 + SetVersion(TLS 1.2) + set TLS 1.2 cipher -> only that cipher */
static int test_wolfSSL_set_cipher_list_tls12_with_version(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_TLS13) && \
    !defined(WOLFSSL_NO_TLS12) && \
    !defined(NO_WOLFSSL_CLIENT) && \
    !defined(HAVE_RENEGOTIATION_INDICATION) && \
    defined(HAVE_AESGCM) && defined(HAVE_ECC) && !defined(NO_RSA)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* Set protocol version to TLS 1.2 (this disables downgrade) */
    ExpectIntEQ(wolfSSL_SetVersion(ssl, WOLFSSL_TLSV1_2), WOLFSSL_SUCCESS);

    /* Set only a TLS 1.2 cipher suite */
    ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "ECDHE-RSA-AES128-GCM-SHA256"),
                WOLFSSL_SUCCESS);

    /* Should have only TLS 1.2 suites (no TLS 1.3) since downgrade is disabled */
    ExpectNotNull(ssl->suites);
    ExpectFalse(suites_has_tls13(ssl->suites->suites, ssl->suites->suiteSz));
    /* Should have the TLS 1.2 suite we set */
    ExpectTrue(suites_has_tls12(ssl->suites->suites, ssl->suites->suiteSz));
    /* Should have exactly one cipher suite (2 bytes) */
    ExpectIntEQ(ssl->suites->suiteSz, 2);

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

/* Test 4: SSLv23 + SetVersion(TLS 1.3) + set TLS 1.3 cipher -> only that cipher */
static int test_wolfSSL_set_cipher_list_tls13_with_version(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_TLS13) && \
    !defined(WOLFSSL_NO_TLS12) && \
    !defined(NO_WOLFSSL_CLIENT) && \
    !defined(HAVE_RENEGOTIATION_INDICATION) && \
    defined(HAVE_AESGCM) && !defined(NO_ERROR_STRINGS)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* Set protocol version to TLS 1.3 (this disables downgrade) */
    ExpectIntEQ(wolfSSL_SetVersion(ssl, WOLFSSL_TLSV1_3), WOLFSSL_SUCCESS);

    /* Set only a TLS 1.3 cipher suite */
    ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "TLS_AES_128_GCM_SHA256"),
                WOLFSSL_SUCCESS);

    /* Should have only TLS 1.3 suites (no TLS 1.2) since downgrade is disabled */
    ExpectNotNull(ssl->suites);
    ExpectFalse(suites_has_tls12(ssl->suites->suites, ssl->suites->suiteSz));
    /* Should have the TLS 1.3 suite we set */
    ExpectTrue(suites_has_tls13(ssl->suites->suites, ssl->suites->suiteSz));
    /* Should have exactly one cipher suite (2 bytes) */
    ExpectIntEQ(ssl->suites->suiteSz, 2);

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_set_alpn_protos_default_fails(void)
{
    EXPECT_DECLS;
#if defined(HAVE_ALPN) && defined(OPENSSL_EXTRA) && !defined(NO_BIO) && \
    !defined(NO_WOLFSSL_CLIENT)
    {
        WOLFSSL_CTX* ctx = NULL;
        WOLFSSL* ssl = NULL;
        unsigned char p[] = { 6, 's', 'p', 'd', 'y', '/', '3' };
        TLSX* ext = NULL;
        ALPN* alpn = NULL;

        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
        ExpectNotNull(ssl = wolfSSL_new(ctx));
#ifdef WOLFSSL_ERROR_CODE_OPENSSL
        ExpectIntEQ(wolfSSL_set_alpn_protos(ssl, p, sizeof(p)), 0);
#else
        ExpectIntEQ(wolfSSL_set_alpn_protos(ssl, p, sizeof(p)),
            WOLFSSL_SUCCESS);
#endif
        if (ssl != NULL) {
            ext = TLSX_Find(ssl->extensions,
                TLSX_APPLICATION_LAYER_PROTOCOL);
            ExpectNotNull(ext);
            if (ext != NULL) {
                alpn = (ALPN*)ext->data;
                ExpectNotNull(alpn);
                if (alpn != NULL) {
                    ExpectTrue((alpn->options
                        & WOLFSSL_ALPN_FAILED_ON_MISMATCH) != 0);
                    ExpectIntEQ(alpn->options
                        & WOLFSSL_ALPN_CONTINUE_ON_MISMATCH, 0);
                }
            }
        }
        wolfSSL_free(ssl);
        wolfSSL_CTX_free(ctx);
    }
#if !defined(NO_WOLFSSL_SERVER) && !defined(WOLFSSL_NO_TLS12) && \
    !defined(SINGLE_THREADED) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
    {
        struct test_memio_ctx test_ctx;
        WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
        WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
        unsigned char client_protos[] = { 6, 's', 'p', 'd', 'y', '/', '3' };
        const char* server_protos = "http/2";
        WOLFSSL_ALERT_HISTORY h;

        XMEMSET(&test_ctx, 0, sizeof(test_ctx));
        ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
            wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);

#ifdef WOLFSSL_ERROR_CODE_OPENSSL
        ExpectIntEQ(wolfSSL_set_alpn_protos(ssl_c, client_protos,
            sizeof(client_protos)), 0);
#else
        ExpectIntEQ(wolfSSL_set_alpn_protos(ssl_c, client_protos,
            sizeof(client_protos)), WOLFSSL_SUCCESS);
#endif
        ExpectIntEQ(wolfSSL_UseALPN(ssl_s, (char*)server_protos,
            (word32)XSTRLEN(server_protos),
            WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS);

        ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
        ExpectIntEQ(wolfSSL_get_alert_history(ssl_s, &h), WOLFSSL_SUCCESS);
        ExpectIntEQ(h.last_tx.code, no_application_protocol);
        ExpectIntEQ(h.last_tx.level, alert_fatal);

        wolfSSL_free(ssl_c);
        wolfSSL_free(ssl_s);
        wolfSSL_CTX_free(ctx_c);
        wolfSSL_CTX_free(ctx_s);
    }
#endif
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_use_certificate(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \
    defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \
    defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \
    defined(WOLFSSL_HAPROXY)
#if !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    WOLFSSL_CTX* ctx = NULL;
    X509* x509 = NULL;

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#endif

    ExpectNotNull(x509 = wolfSSL_X509_new());

    /* Negative tests. */
    ExpectIntEQ(SSL_CTX_use_certificate(NULL, NULL), 0);
    ExpectIntEQ(SSL_CTX_use_certificate(ctx, NULL), 0);
    ExpectIntEQ(SSL_CTX_use_certificate(NULL, x509), 0);
    /* Empty certificate */
    ExpectIntEQ(SSL_CTX_use_certificate(ctx, x509), 0);

    wolfSSL_X509_free(x509);
    wolfSSL_CTX_free(ctx);
#endif /* !NO_TLS && (!NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER) */
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_use_certificate_file(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_SERVER)
    WOLFSSL_CTX *ctx = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));

    /* invalid context */
    ExpectFalse(wolfSSL_CTX_use_certificate_file(NULL, svrCertFile,
                                                         CERT_FILETYPE));
    /* invalid cert file */
    ExpectFalse(wolfSSL_CTX_use_certificate_file(ctx, bogusFile,
                                                         CERT_FILETYPE));
    /* invalid cert type */
    ExpectFalse(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, 9999));

#ifdef NO_RSA
    /* rsa needed */
    ExpectFalse(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
                                                         CERT_FILETYPE));
#else
    /* success */
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
                                                         CERT_FILETYPE));
#endif

    wolfSSL_CTX_free(ctx);
#endif

    return EXPECT_RESULT();
}

#if (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO)) && !defined(NO_RSA)
static int test_wolfSSL_CTX_use_certificate_ASN1(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_WOLFSSL_SERVER) && !defined(NO_ASN) && \
    !defined(NO_TLS)
    WOLFSSL_CTX* ctx = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));

    /* Failure cases. */
    ExpectIntEQ(SSL_CTX_use_certificate_ASN1(NULL, 0, NULL                ),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_CTX_use_certificate_ASN1(ctx , 0, NULL                ),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_CTX_use_certificate_ASN1(NULL, 0, server_cert_der_2048),
       WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_CTX_use_certificate_ASN1(ctx , 0, server_cert_der_2048),
       WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    ExpectIntEQ(SSL_CTX_use_certificate_ASN1(ctx, sizeof_server_cert_der_2048,
        server_cert_der_2048), WOLFSSL_SUCCESS);

    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}
#endif /* (OPENSSL_ALL || WOLFSSL_ASIO) && !NO_RSA */

/*  Test function for wolfSSL_CTX_use_certificate_buffer. Load cert into
 *  context using buffer.
 *  PRE: NO_CERTS not defined; USE_CERT_BUFFERS_2048 defined; compile with
 *  --enable-testcert flag.
 */
static int test_wolfSSL_CTX_use_certificate_buffer(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_TLS) && !defined(NO_WOLFSSL_SERVER) && \
    defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA)
    WOLFSSL_CTX* ctx = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));

    /* Invalid parameters. */
    ExpectIntEQ(wolfSSL_CTX_use_certificate_buffer(NULL, NULL, 0,
        WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_use_certificate_buffer(ctx, NULL, 0,
        WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(ASN_PARSE_E));
    ExpectIntEQ(wolfSSL_CTX_use_certificate_buffer(NULL, server_cert_der_2048,
        0, WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_use_certificate_buffer(ctx, server_cert_der_2048, 0,
        WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(ASN_PARSE_E));

    ExpectIntEQ(wolfSSL_CTX_use_certificate_buffer(ctx,
        server_cert_der_2048, sizeof_server_cert_der_2048,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();

} /* END test_wolfSSL_CTX_use_certificate_buffer */

static int test_wolfSSL_use_certificate_buffer(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) && \
    defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL*     ssl = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* Invalid parameters. */
    ExpectIntEQ(wolfSSL_use_certificate_buffer(NULL, NULL, 0,
        WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_use_certificate_buffer(ssl, NULL, 0,
        WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(ASN_PARSE_E));
    ExpectIntEQ(wolfSSL_use_certificate_buffer(NULL, client_cert_der_2048, 0,
        WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_use_certificate_buffer(ssl, client_cert_der_2048, 0,
        WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(ASN_PARSE_E));

    ExpectIntEQ(wolfSSL_use_certificate_buffer(ssl,
        client_cert_der_2048, sizeof_client_cert_der_2048,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_use_PrivateKey_file(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_SERVER)
    WOLFSSL_CTX *ctx = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));

    /* invalid context */
    ExpectFalse(wolfSSL_CTX_use_PrivateKey_file(NULL, svrKeyFile,
                                                         CERT_FILETYPE));
    /* invalid key file */
    ExpectFalse(wolfSSL_CTX_use_PrivateKey_file(ctx, bogusFile,
                                                         CERT_FILETYPE));
    /* invalid key type */
    ExpectFalse(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, 9999));

    /* invalid key format */
#ifdef WOLFSSL_PEM_TO_DER
    ExpectFalse(wolfSSL_CTX_use_PrivateKey_file(ctx, "./certs/dh-priv-2048.pem",
                                                         WOLFSSL_FILETYPE_PEM));
#else
    ExpectFalse(wolfSSL_CTX_use_PrivateKey_file(ctx, "./certs/dh-priv-2048.der",
                                                         WOLFSSL_FILETYPE_ASN1));
#endif

    /* success */
#ifdef NO_RSA
    /* rsa needed */
    ExpectFalse(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
                                                         CERT_FILETYPE));
#else
    /* success */
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
                                                         CERT_FILETYPE));
#endif

    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_use_RSAPrivateKey_file(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_SERVER) && defined(OPENSSL_EXTRA)
    WOLFSSL_CTX *ctx = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));

    /* invalid context */
    ExpectIntEQ(wolfSSL_CTX_use_RSAPrivateKey_file(NULL, svrKeyFile,
        WOLFSSL_FILETYPE_PEM), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    /* invalid key file */
    ExpectIntEQ(wolfSSL_CTX_use_RSAPrivateKey_file(ctx, bogusFile,
        WOLFSSL_FILETYPE_PEM), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    /* invalid key type */
    ExpectIntEQ(wolfSSL_CTX_use_RSAPrivateKey_file(ctx, svrKeyFile, 9999),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    /* success */
#ifdef NO_RSA
    /* rsa needed */
    ExpectIntEQ(wolfSSL_CTX_use_RSAPrivateKey_file(ctx, svrKeyFile,
        WOLFSSL_FILETYPE_PEM), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#else
    /* success */
    ExpectIntEQ(wolfSSL_CTX_use_RSAPrivateKey_file(ctx, svrKeyFile,
        WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
#endif

    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_use_RSAPrivateKey_file(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_CLIENT) && defined(OPENSSL_EXTRA)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL*     ssl = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = SSL_new(ctx));

    /* invalid context */
    ExpectIntEQ(wolfSSL_use_RSAPrivateKey_file(NULL, svrKeyFile,
        WOLFSSL_FILETYPE_PEM), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* invalid key file */
    ExpectIntEQ(wolfSSL_use_RSAPrivateKey_file(ssl, bogusFile,
        WOLFSSL_FILETYPE_PEM), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    /* invalid key type */
    ExpectIntEQ(wolfSSL_use_RSAPrivateKey_file(ssl, svrKeyFile, 9999),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    /* success */
#ifdef NO_RSA
    /* rsa needed */
    ExpectIntEQ(wolfSSL_use_RSAPrivateKey_file(ssl, svrKeyFile,
        WOLFSSL_FILETYPE_PEM), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#else
    /* success */
    ExpectIntEQ(wolfSSL_use_RSAPrivateKey_file(ssl, svrKeyFile,
        WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
#endif

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_use_PrivateKey(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_SERVER) && defined(OPENSSL_EXTRA)
    WOLFSSL_CTX *ctx = NULL;
    WOLFSSL_EVP_PKEY* pkey = NULL;
    const unsigned char* p;

    (void)p;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));

    ExpectNotNull(pkey = wolfSSL_EVP_PKEY_new());
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(NULL, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(ctx, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(NULL, pkey), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    /* No data. */
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(ctx, pkey), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    wolfSSL_EVP_PKEY_free(pkey);
    pkey = NULL;

#if defined(USE_CERT_BUFFERS_2048)
#if !defined(NO_RSA)
    p = client_key_der_2048;
    ExpectNotNull(pkey = d2i_PrivateKey(EVP_PKEY_RSA, NULL, &p,
        sizeof_client_key_der_2048));
#if defined(WOLFSSL_KEY_GEN)
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(ctx, pkey), WOLFSSL_SUCCESS);
#else
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(ctx, pkey), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif
    wolfSSL_EVP_PKEY_free(pkey);
    pkey = NULL;
#endif
#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH)
#ifndef NO_DSA
    p = dsa_key_der_2048;
    ExpectNotNull(pkey = d2i_PrivateKey(EVP_PKEY_DSA, NULL, &p,
        sizeof_dsa_key_der_2048));
#if !defined(HAVE_SELFTEST) && (defined(WOLFSSL_KEY_GEN) || \
    defined(WOLFSSL_CERT_GEN))
    /* Not supported in ProcessBuffer. */
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(ctx, pkey), WC_NO_ERR_TRACE(WOLFSSL_BAD_FILE));
#else
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(ctx, pkey), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif
    wolfSSL_EVP_PKEY_free(pkey);
    pkey = NULL;
#endif
#endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH */
#if !defined(NO_DH) && defined(OPENSSL_ALL) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
    p = dh_ffdhe_statickey_der_2048;
    ExpectNotNull(pkey = d2i_PrivateKey(EVP_PKEY_DH, NULL, &p,
        sizeof_dh_ffdhe_statickey_der_2048));
    /* Not supported. */
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(ctx, pkey), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    wolfSSL_EVP_PKEY_free(pkey);
    pkey = NULL;
#endif
#endif /* USE_CERT_BUFFERS_2048 */
#if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256)
    p = ecc_clikey_der_256;
    ExpectNotNull(pkey = d2i_PrivateKey(EVP_PKEY_EC, NULL, &p,
        sizeof_ecc_clikey_der_256));
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(ctx, pkey), WOLFSSL_SUCCESS);
    wolfSSL_EVP_PKEY_free(pkey);
    pkey = NULL;
#endif
    ExpectNotNull(pkey = wolfSSL_EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL,
        (unsigned char*)"01234567012345670123456701234567", 32));
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(ctx, pkey), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    wolfSSL_EVP_PKEY_free(pkey);
    pkey = NULL;

    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

/* test both file and buffer versions along with unloading trusted peer certs */
static int test_wolfSSL_CTX_trust_peer_cert(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && defined(WOLFSSL_TRUST_PEER_CERT) && \
    !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_RSA)
    WOLFSSL_CTX *ctx = NULL;
    WOLFSSL* ssl = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

#if !defined(NO_FILESYSTEM)
    /* invalid file */
    ExpectIntNE(wolfSSL_CTX_trust_peer_cert(ctx, NULL,
                                     WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    ExpectIntNE(wolfSSL_CTX_trust_peer_cert(ctx, bogusFile,
                                     WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    ExpectIntNE(wolfSSL_CTX_trust_peer_cert(ctx, cliCertFile,
                                     WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    /* success */
    ExpectIntEQ(wolfSSL_CTX_trust_peer_cert(ctx, cliCertFile,
                                     WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);

    /* unload cert */
    ExpectIntNE(wolfSSL_CTX_Unload_trust_peers(NULL), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_Unload_trust_peers(ctx), WOLFSSL_SUCCESS);

    /* invalid file */
    ExpectIntNE(wolfSSL_trust_peer_cert(ssl, NULL,
                                     WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    ExpectIntNE(wolfSSL_trust_peer_cert(ssl, bogusFile,
                                     WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    ExpectIntNE(wolfSSL_trust_peer_cert(ssl, cliCertFile,
                                     WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    /* success */
    ExpectIntEQ(wolfSSL_trust_peer_cert(ssl, cliCertFile,
                                     WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);

    #ifdef WOLFSSL_LOCAL_X509_STORE
    /* unload cert */
    ExpectIntNE(wolfSSL_Unload_trust_peers(NULL), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_Unload_trust_peers(ssl), WOLFSSL_SUCCESS);
    #endif
#endif

    /* Test of loading certs from buffers */

    /* invalid buffer */
    ExpectIntNE(wolfSSL_CTX_trust_peer_buffer(ctx, NULL, -1,
                                     WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    /* success */
#ifdef USE_CERT_BUFFERS_1024
    ExpectIntEQ(wolfSSL_CTX_trust_peer_buffer(ctx, client_cert_der_1024,
          sizeof_client_cert_der_1024, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
#endif
#ifdef USE_CERT_BUFFERS_2048
    ExpectIntEQ(wolfSSL_CTX_trust_peer_buffer(ctx, client_cert_der_2048,
          sizeof_client_cert_der_2048, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
#endif

    /* unload cert */
    ExpectIntNE(wolfSSL_CTX_Unload_trust_peers(NULL), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_Unload_trust_peers(ctx), WOLFSSL_SUCCESS);

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif

    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_load_verify_locations(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL_CTX *ctx = NULL;
#ifndef NO_RSA
    WOLFSSL_CERT_MANAGER* cm = NULL;
#ifdef PERSIST_CERT_CACHE
    int cacheSz = 0;
    unsigned char* cache = NULL;
    int used = 0;
#ifndef NO_FILESYSTEM
    const char* cacheFile = "./tests/cert_cache.tmp";
#endif
    int i;
    int t;
    int* p;
#endif
#endif
#if !defined(NO_WOLFSSL_DIR) && !defined(WOLFSSL_TIRTOS) && \
    defined(WOLFSSL_PEM_TO_DER)
    const char* load_certs_path = "./certs/external";
    const char* load_no_certs_path = "./examples";
    const char* load_expired_path = "./certs/test/expired";
#endif

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));

    /* invalid arguments */
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations(NULL, caCertFile, NULL),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx, NULL, NULL),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    /* invalid ca file */
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx, bogusFile, NULL),
        WS_RETURN_CODE(WC_NO_ERR_TRACE(WOLFSSL_BAD_FILE),
                       WC_NO_ERR_TRACE(WOLFSSL_FAILURE)));


#if !defined(NO_WOLFSSL_DIR) && !defined(WOLFSSL_TIRTOS) && \
  ((defined(WOLFSSL_QT) || defined(WOLFSSL_IGNORE_BAD_CERT_PATH)) && \
  !(WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS & WOLFSSL_LOAD_FLAG_IGNORE_BAD_PATH_ERR))
    /* invalid path */
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx, NULL, bogusFile),
        WS_RETURN_CODE(WC_NO_ERR_TRACE(BAD_PATH_ERROR),WC_NO_ERR_TRACE(WOLFSSL_FAILURE)));
#endif
#if defined(WOLFSSL_QT) || defined(WOLFSSL_IGNORE_BAD_CERT_PATH)
    /* test ignoring the invalid path */
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx, NULL, bogusFile,
        WOLFSSL_LOAD_FLAG_IGNORE_BAD_PATH_ERR), WOLFSSL_SUCCESS);
#endif

    /* load ca cert */
#ifdef NO_RSA
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx, caCertFile, NULL),
        WS_RETURN_CODE(WC_NO_ERR_TRACE(ASN_UNKNOWN_OID_E),WC_NO_ERR_TRACE(WOLFSSL_FAILURE)));
#else /* Skip the following test without RSA certs. */
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx, caCertFile, NULL),
        WOLFSSL_SUCCESS);

#ifdef PERSIST_CERT_CACHE
    /* Get cert cache size */
    ExpectIntGT(cacheSz = wolfSSL_CTX_get_cert_cache_memsize(ctx), 0);

    ExpectNotNull(cache = (byte*)XMALLOC((size_t)cacheSz, NULL,
                            DYNAMIC_TYPE_TMP_BUFFER));

    ExpectIntEQ(wolfSSL_CTX_memsave_cert_cache(NULL, NULL, -1, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memsave_cert_cache(ctx, NULL, -1, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memsave_cert_cache(NULL, cache, -1, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memsave_cert_cache(NULL, NULL, cacheSz, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memsave_cert_cache(NULL, NULL, -1, &used),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memsave_cert_cache(NULL, cache, cacheSz, &used),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memsave_cert_cache(ctx, NULL, cacheSz, &used),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memsave_cert_cache(ctx, cache, -1, &used),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memsave_cert_cache(ctx, cache, cacheSz, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memsave_cert_cache(ctx, cache, cacheSz - 10, &used),
        WC_NO_ERR_TRACE(BUFFER_E));
    ExpectIntEQ(wolfSSL_CTX_memsave_cert_cache(ctx, cache, cacheSz, &used), 1);
    ExpectIntEQ(cacheSz, used);

    ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(NULL, NULL, -1),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(ctx, NULL, -1),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(NULL, cache, -1),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(NULL, NULL, cacheSz),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(NULL, cache, cacheSz),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(ctx, NULL, cacheSz),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(ctx, cache, -1),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* Smaller than header. */
    ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(ctx, cache, 1), WC_NO_ERR_TRACE(BUFFER_E));
    for (i = 1; i < cacheSz; i++) {
        ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(ctx, cache, cacheSz - i),
            WC_NO_ERR_TRACE(BUFFER_E));
    }
    if (EXPECT_SUCCESS()) {
        /* Modify header for bad results! */
        p = (int*)cache;
        /* version */
        t = p[0]; p[0] = 0xff;
        ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(ctx, cache, cacheSz),
            WC_NO_ERR_TRACE(CACHE_MATCH_ERROR));
        p[0] = t; p++;
        /* rows */
        t = p[0]; p[0] = 0xff;
        ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(ctx, cache, cacheSz),
            WC_NO_ERR_TRACE(CACHE_MATCH_ERROR));
        p[0] = t; p++;
        /* columns[0] */
        t = p[0]; p[0] = -1;
        ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(ctx, cache, cacheSz),
            WC_NO_ERR_TRACE(PARSE_ERROR));
        p[0] = t; p += CA_TABLE_SIZE;
        /* signerSz*/
        t = p[0]; p[0] = 0xff;
        ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(ctx, cache, cacheSz),
            WC_NO_ERR_TRACE(CACHE_MATCH_ERROR));
        p[0] = t;
    }

    ExpectIntEQ(wolfSSL_CTX_memrestore_cert_cache(ctx, cache, cacheSz), 1);
    ExpectIntEQ(cacheSz = wolfSSL_CTX_get_cert_cache_memsize(ctx), used);

#ifndef NO_FILESYSTEM
    ExpectIntEQ(wolfSSL_CTX_save_cert_cache(NULL, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_save_cert_cache(ctx, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_save_cert_cache(NULL, cacheFile), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_save_cert_cache(ctx, cacheFile), 1);

    ExpectIntEQ(wolfSSL_CTX_restore_cert_cache(NULL, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_restore_cert_cache(ctx, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_restore_cert_cache(NULL, cacheFile), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_restore_cert_cache(ctx, "no-file"),
        WC_NO_ERR_TRACE(WOLFSSL_BAD_FILE));
    ExpectIntEQ(wolfSSL_CTX_restore_cert_cache(ctx, cacheFile), 1);
    /* File contents is not a cache. */
    ExpectIntEQ(wolfSSL_CTX_restore_cert_cache(ctx, "./certs/ca-cert.pem"),
        WC_NO_ERR_TRACE(CACHE_MATCH_ERROR));
#endif

    XFREE(cache, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
    /* Test unloading CA's */
    ExpectIntEQ(wolfSSL_CTX_UnloadCAs(ctx), WOLFSSL_SUCCESS);

#ifdef PERSIST_CERT_CACHE
    /* Verify no certs (result is less than cacheSz) */
    ExpectIntGT(cacheSz, wolfSSL_CTX_get_cert_cache_memsize(ctx));
#endif

    /* load ca cert again */
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx, caCertFile, NULL),
        WOLFSSL_SUCCESS);

    /* Test getting CERT_MANAGER */
    ExpectNotNull(cm = wolfSSL_CTX_GetCertManager(ctx));

    /* Test unloading CA's using CM */
    ExpectIntEQ(wolfSSL_CertManagerUnloadCAs(cm), WOLFSSL_SUCCESS);

#ifdef PERSIST_CERT_CACHE
    /* Verify no certs (result is less than cacheSz) */
    ExpectIntGT(cacheSz, wolfSSL_CTX_get_cert_cache_memsize(ctx));
#endif
#endif

#if !defined(NO_WOLFSSL_DIR) && !defined(WOLFSSL_TIRTOS) && \
    defined(WOLFSSL_PEM_TO_DER)
    /* Test loading CA certificates using a path */
    #ifdef NO_RSA
    /* failure here okay since certs in external directory are RSA */
    ExpectIntNE(wolfSSL_CTX_load_verify_locations_ex(ctx, NULL, load_certs_path,
        WOLFSSL_LOAD_FLAG_PEM_CA_ONLY), WOLFSSL_SUCCESS);
    #else
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx, NULL, load_certs_path,
        WOLFSSL_LOAD_FLAG_PEM_CA_ONLY), WOLFSSL_SUCCESS);
    #endif

    /* Test loading path with no files */
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx, NULL,
        load_no_certs_path, WOLFSSL_LOAD_FLAG_PEM_CA_ONLY),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    /* Test loading expired CA certificates */
    #ifdef NO_RSA
    ExpectIntNE(wolfSSL_CTX_load_verify_locations_ex(ctx, NULL,
        load_expired_path,
        WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY | WOLFSSL_LOAD_FLAG_PEM_CA_ONLY),
        WOLFSSL_SUCCESS);
    #else
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx, NULL,
        load_expired_path,
        WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY | WOLFSSL_LOAD_FLAG_PEM_CA_ONLY),
        WOLFSSL_SUCCESS);
    #endif

    /* Test loading CA certificates and ignoring all errors */
    #ifdef NO_RSA
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx, NULL, load_certs_path,
        WOLFSSL_LOAD_FLAG_IGNORE_ERR), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    #else
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx, NULL, load_certs_path,
        WOLFSSL_LOAD_FLAG_IGNORE_ERR), WOLFSSL_SUCCESS);
    #endif
#endif

    wolfSSL_CTX_free(ctx);
#endif

    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_load_system_CA_certs(void)
{
    int res = TEST_SKIPPED;
#if defined(WOLFSSL_SYS_CA_CERTS) && !defined(NO_WOLFSSL_CLIENT) && \
    !defined(NO_TLS) && (!defined(NO_RSA) || defined(HAVE_ECC)) && \
    defined(WOLFSSL_PEM_TO_DER)
    WOLFSSL_CTX* ctx;
    byte dirValid = 0;
    int ret = 0;

    ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
    if (ctx == NULL) {
        fprintf(stderr, "wolfSSL_CTX_new failed.\n");
        ret = -1;
    }
    if (ret == 0) {
    #if defined(USE_WINDOWS_API) || defined(__APPLE__) || \
        defined(NO_WOLFSSL_DIR)
        dirValid = 1;
    #else
        word32 numDirs;
        const char** caDirs = wolfSSL_get_system_CA_dirs(&numDirs);

        if (caDirs == NULL || numDirs == 0) {
            fprintf(stderr, "wolfSSL_get_system_CA_dirs failed.\n");
            ret = -1;
        }
        else {
            ReadDirCtx dirCtx;
            word32 i;

            for (i = 0; i < numDirs; ++i) {
                if (wc_ReadDirFirst(&dirCtx, caDirs[i], NULL) == 0) {
                    /* Directory isn't empty. */
                    dirValid = 1;
                    wc_ReadDirClose(&dirCtx);
                    break;
                }
            }
        }
    #endif
    }
    /*
     * If the directory isn't empty, we should be able to load CA
     * certs from it. On Windows/Mac, we assume the CA cert stores are
     * usable.
     */
    if (ret == 0 && dirValid && wolfSSL_CTX_load_system_CA_certs(ctx) !=
        WOLFSSL_SUCCESS) {
        fprintf(stderr, "wolfSSL_CTX_load_system_CA_certs failed.\n");
        ret = -1;
    }
#ifdef OPENSSL_EXTRA
    if (ret == 0 &&
        wolfSSL_CTX_set_default_verify_paths(ctx) != WOLFSSL_SUCCESS) {
        fprintf(stderr, "wolfSSL_CTX_set_default_verify_paths failed.\n");
        ret = -1;
    }
#endif /* OPENSSL_EXTRA */

    wolfSSL_CTX_free(ctx);

    res = TEST_RES_CHECK(ret == 0);
#endif /* WOLFSSL_SYS_CA_CERTS && !NO_WOLFSSL_CLIENT */

    return res;
}

static int test_wolfSSL_CheckOCSPResponse(void)
{
    EXPECT_DECLS;
#if defined(HAVE_OCSP) && defined(OPENSSL_EXTRA) && \
    !defined(NO_RSA) && !defined(NO_SHA)
    const char* responseFile = "./certs/ocsp/test-response.der";
    const char* responseMultiFile = "./certs/ocsp/test-multi-response.der";
    const char* responseNoInternFile =
        "./certs/ocsp/test-response-nointern.der";
    const char* caFile = "./certs/ocsp/root-ca-cert.pem";
    OcspResponse* res = NULL;
    byte data[4096];
    const unsigned char* pt;
    int  dataSz = 0; /* initialize to mitigate spurious maybe-uninitialized from
                      * gcc sanitizer with --enable-heapmath.
                      */
    XFILE f = XBADFILE;
    WOLFSSL_OCSP_BASICRESP* bs = NULL;
    WOLFSSL_X509_STORE* st = NULL;
    WOLFSSL_X509* issuer = NULL;


    ExpectTrue((f = XFOPEN(responseFile, "rb")) != XBADFILE);
    ExpectIntGT(dataSz = (word32)XFREAD(data, 1, sizeof(data), f), 0);
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }

    pt = data;
    ExpectNotNull(res = wolfSSL_d2i_OCSP_RESPONSE(NULL, &pt, dataSz));
    ExpectPtrEq(pt, data + dataSz);
    ExpectNotNull(issuer = wolfSSL_X509_load_certificate_file(caFile,
        SSL_FILETYPE_PEM));
    ExpectNotNull(st = wolfSSL_X509_STORE_new());
    ExpectIntEQ(wolfSSL_X509_STORE_add_cert(st, issuer), WOLFSSL_SUCCESS);
    ExpectNotNull(bs = wolfSSL_OCSP_response_get1_basic(res));
    ExpectIntEQ(wolfSSL_OCSP_basic_verify(bs, NULL, st, 0), WOLFSSL_SUCCESS);
    wolfSSL_OCSP_BASICRESP_free(bs);
    bs = NULL;
    wolfSSL_OCSP_RESPONSE_free(res);
    res = NULL;
    wolfSSL_X509_STORE_free(st);
    st = NULL;
    wolfSSL_X509_free(issuer);
    issuer = NULL;

    /* check loading a response with optional certs */
    ExpectTrue((f = XFOPEN(responseNoInternFile, "rb")) != XBADFILE);
    ExpectIntGT(dataSz = (word32)XFREAD(data, 1, sizeof(data), f), 0);
    if (f != XBADFILE)
        XFCLOSE(f);
    f = XBADFILE;

    pt = data;
    ExpectNotNull(res = wolfSSL_d2i_OCSP_RESPONSE(NULL, &pt, dataSz));
    ExpectPtrEq(pt, data + dataSz);
    wolfSSL_OCSP_RESPONSE_free(res);
    res = NULL;

    /* check loading a response with multiple certs */
    {
        WOLFSSL_CERT_MANAGER* cm = NULL;
        OcspEntry *entry = NULL;
        CertStatus* status = NULL;
        OcspRequest* request = NULL;

        byte serial1[] = {0x01};
        byte serial[] = {0x02};

        byte issuerHash[] = {
            0x44, 0xA8, 0xDB, 0xD1, 0xBC, 0x97, 0x0A, 0x83,
            0x3B, 0x5B, 0x31, 0x9A, 0x4C, 0xB8, 0xD2, 0x52,
            0x37, 0x15, 0x8A, 0x88
        };
        byte issuerKeyHash[] = {
            0x73, 0xB0, 0x1C, 0xA4, 0x2F, 0x82, 0xCB, 0xCF,
            0x47, 0xA5, 0x38, 0xD7, 0xB0, 0x04, 0x82, 0x3A,
            0x7E, 0x72, 0x15, 0x21
        };

        ExpectNotNull(entry = (OcspEntry*)XMALLOC(sizeof(OcspEntry), NULL,
             DYNAMIC_TYPE_OPENSSL));

        ExpectNotNull(status = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL,
             DYNAMIC_TYPE_OPENSSL));

        if (entry != NULL)
            XMEMSET(entry, 0, sizeof(OcspEntry));
        if (status != NULL)
            XMEMSET(status, 0, sizeof(CertStatus));

        ExpectNotNull(request = wolfSSL_OCSP_REQUEST_new());
        ExpectNotNull(request->serial = (byte*)XMALLOC(sizeof(serial), NULL,
                                                    DYNAMIC_TYPE_OCSP_REQUEST));

        if (request != NULL && request->serial != NULL) {
             request->serialSz = sizeof(serial);
             XMEMCPY(request->serial, serial, sizeof(serial));
             XMEMCPY(request->issuerHash, issuerHash, sizeof(issuerHash));
             XMEMCPY(request->issuerKeyHash, issuerKeyHash,
                 sizeof(issuerKeyHash));
        }

        ExpectNotNull(cm = wolfSSL_CertManagerNew_ex(NULL));
        ExpectIntEQ(wolfSSL_CertManagerEnableOCSP(cm, 0), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, caFile, NULL),
            WOLFSSL_SUCCESS);

        ExpectTrue((f = XFOPEN(responseMultiFile, "rb")) != XBADFILE);
        ExpectIntGT(dataSz = (word32)XFREAD(data, 1, sizeof(data), f), 0);
        if (f != XBADFILE)
            XFCLOSE(f);
        f = XBADFILE;

        ExpectIntEQ(wolfSSL_CertManagerCheckOCSPResponse(cm, data,
            dataSz, NULL, status, entry, request), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CertManagerCheckOCSPResponse(cm, data,
            dataSz, NULL, entry->status, entry, request), WOLFSSL_SUCCESS);
        ExpectNotNull(entry->status);

        if (request != NULL && request->serial != NULL)
            XMEMCPY(request->serial, serial1, sizeof(serial1));
        ExpectIntEQ(wolfSSL_CertManagerCheckOCSPResponse(cm, data,
            dataSz, NULL, status, entry, request), WOLFSSL_SUCCESS);

        /* store both status's in the entry to check that "next" is not
         * overwritten */
        if (EXPECT_SUCCESS() && status != NULL && entry != NULL) {
            status->next  = entry->status;
            entry->status = status;
        }

        if (request != NULL && request->serial != NULL)
            XMEMCPY(request->serial, serial, sizeof(serial));
        ExpectIntEQ(wolfSSL_CertManagerCheckOCSPResponse(cm, data,
            dataSz, NULL, entry->status, entry, request), WOLFSSL_SUCCESS);
        ExpectNotNull(entry->status->next);

        /* compare the status found */
        ExpectIntEQ(status->serialSz, entry->status->serialSz);
        ExpectIntEQ(XMEMCMP(status->serial, entry->status->serial,
            status->serialSz), 0);

        if (status != NULL && entry != NULL && entry->status != status) {
            XFREE(status, NULL, DYNAMIC_TYPE_OPENSSL);
        }
        wolfSSL_OCSP_CERTID_free(entry);
        wolfSSL_OCSP_REQUEST_free(request);
        wolfSSL_CertManagerFree(cm);
    }

/* FIPS v2 and below don't support long salts. */
#if defined(WC_RSA_PSS) && \
    (!defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
     (HAVE_FIPS_VERSION > 2))) && (!defined(HAVE_SELFTEST) || \
     (defined(HAVE_SELFTEST_VERSION) && (HAVE_SELFTEST_VERSION > 2)))
    {
        const char* responsePssFile = "./certs/ocsp/test-response-rsapss.der";

        /* check loading a response with RSA-PSS signature */
        ExpectTrue((f = XFOPEN(responsePssFile, "rb")) != XBADFILE);
        ExpectIntGT(dataSz = (word32)XFREAD(data, 1, sizeof(data), f), 0);
        if (f != XBADFILE)
            XFCLOSE(f);

        pt = data;
        ExpectNotNull(res = wolfSSL_d2i_OCSP_RESPONSE(NULL, &pt, dataSz));
        ExpectPtrEq(pt, data + dataSz);

        /* try to verify the response */
        ExpectNotNull(issuer = wolfSSL_X509_load_certificate_file(caFile,
            SSL_FILETYPE_PEM));
        ExpectNotNull(st = wolfSSL_X509_STORE_new());
        ExpectIntEQ(wolfSSL_X509_STORE_add_cert(st, issuer), WOLFSSL_SUCCESS);
        ExpectNotNull(bs = wolfSSL_OCSP_response_get1_basic(res));
        ExpectIntEQ(wolfSSL_OCSP_basic_verify(bs, NULL, st, 0),
            WOLFSSL_SUCCESS);
        wolfSSL_OCSP_BASICRESP_free(bs);
        wolfSSL_OCSP_RESPONSE_free(res);
        wolfSSL_X509_STORE_free(st);
        wolfSSL_X509_free(issuer);
    }
#endif
#endif /* HAVE_OCSP */
    return EXPECT_RESULT();
}

static int test_wolfSSL_FPKI(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_FPKI) && !defined(NO_RSA) && !defined(NO_FILESYSTEM)
    XFILE f = XBADFILE;
    const char* fpkiCert = "./certs/fpki-cert.der";
    const char* fpkiCertPolCert = "./certs/fpki-certpol-cert.der";
    DecodedCert cert;
    byte buf[4096];
    byte* uuid = NULL;
    byte* fascn = NULL;
    word32 fascnSz;
    word32 uuidSz;
    int bytes = 0;

    ExpectTrue((f = XFOPEN(fpkiCert, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buf, 1, sizeof(buf), f), 0);
    if (f != XBADFILE)
        XFCLOSE(f);

    wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL);
    ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, 0, NULL), 0);
    ExpectIntEQ(wc_GetFASCNFromCert(&cert, NULL, &fascnSz), WC_NO_ERR_TRACE(LENGTH_ONLY_E));
    ExpectNotNull(fascn = (byte*)XMALLOC(fascnSz, NULL,
        DYNAMIC_TYPE_TMP_BUFFER));
    ExpectIntEQ(wc_GetFASCNFromCert(&cert, fascn, &fascnSz), 0);
    XFREE(fascn, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    fascn = NULL;

    ExpectIntEQ(wc_GetUUIDFromCert(&cert, NULL, &uuidSz), WC_NO_ERR_TRACE(LENGTH_ONLY_E));
    ExpectNotNull(uuid = (byte*)XMALLOC(uuidSz, NULL, DYNAMIC_TYPE_TMP_BUFFER));
    ExpectIntEQ(wc_GetUUIDFromCert(&cert, uuid, &uuidSz), 0);
    XFREE(uuid, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    uuid = NULL;
    wc_FreeDecodedCert(&cert);

    XMEMSET(buf, 0, 4096);
    fascnSz = uuidSz = bytes = 0;
    f = XBADFILE;

    ExpectTrue((f = XFOPEN(fpkiCertPolCert, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buf, 1, sizeof(buf), f), 0);
    if (f != XBADFILE)
        XFCLOSE(f);

    wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL);
    ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, 0, NULL), 0);
    ExpectIntEQ(wc_GetFASCNFromCert(&cert, NULL, &fascnSz), WC_NO_ERR_TRACE(LENGTH_ONLY_E));
    ExpectNotNull(fascn = (byte*)XMALLOC(fascnSz, NULL,
        DYNAMIC_TYPE_TMP_BUFFER));
    ExpectIntEQ(wc_GetFASCNFromCert(&cert, fascn, &fascnSz), 0);
    XFREE(fascn, NULL, DYNAMIC_TYPE_TMP_BUFFER);

    ExpectIntEQ(wc_GetUUIDFromCert(&cert, NULL, &uuidSz), WC_NO_ERR_TRACE(LENGTH_ONLY_E));
    ExpectNotNull(uuid = (byte*)XMALLOC(uuidSz, NULL, DYNAMIC_TYPE_TMP_BUFFER));
    ExpectIntEQ(wc_GetUUIDFromCert(&cert, uuid, &uuidSz), 0);
    XFREE(uuid, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    wc_FreeDecodedCert(&cert);
#endif

    return EXPECT_RESULT();
}

/* use RID in confuncture with other names to test parsing of unknown other
 * names */
static int test_wolfSSL_OtherName(void)
{
    EXPECT_DECLS;
#if !defined(NO_RSA) && !defined(NO_FILESYSTEM)
    XFILE f = XBADFILE;
    const char* ridCert = "./certs/rid-cert.der";
    DecodedCert cert;
    byte buf[4096];
    int bytes = 0;

    ExpectTrue((f = XFOPEN(ridCert, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buf, 1, sizeof(buf), f), 0);
    if (f != XBADFILE)
        XFCLOSE(f);

    wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL);
    ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, 0, NULL), 0);
    wc_FreeDecodedCert(&cert);
#endif

    return EXPECT_RESULT();
}

#ifdef HAVE_CERT_CHAIN_VALIDATION
#ifndef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
static int test_wolfSSL_CertRsaPss(void)
{
    EXPECT_DECLS;
/* FIPS v2 and below don't support long salts. */
#if !defined(NO_RSA) && defined(WC_RSA_PSS) && !defined(NO_FILESYSTEM) && \
    (!defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
     (HAVE_FIPS_VERSION > 2))) && (!defined(HAVE_SELFTEST) || \
     (defined(HAVE_SELFTEST_VERSION) && (HAVE_SELFTEST_VERSION > 2)))
    XFILE f = XBADFILE;
#ifndef NO_SHA256
    const char* rsaPssSha256Cert = "./certs/rsapss/ca-rsapss.der";
#ifdef WOLFSSL_PEM_TO_DER
    const char* rsaPssRootSha256Cert = "./certs/rsapss/root-rsapss.pem";
#else
    const char* rsaPssRootSha256Cert = "./certs/rsapss/root-rsapss.der";
#endif
#endif
#if defined(WOLFSSL_SHA384) && defined(WOLFSSL_PSS_LONG_SALT) && \
    RSA_MAX_SIZE >= 3072
    const char* rsaPssSha384Cert = "./certs/rsapss/ca-3072-rsapss.der";
#endif
#if defined(WOLFSSL_SHA384) && RSA_MAX_SIZE >= 3072
#ifdef WOLFSSL_PEM_TO_DER
    const char* rsaPssRootSha384Cert = "./certs/rsapss/root-3072-rsapss.pem";
#else
    const char* rsaPssRootSha384Cert = "./certs/rsapss/root-3072-rsapss.der";
#endif
#endif
    DecodedCert cert;
    byte buf[4096];
    int bytes = 0;
    WOLFSSL_CERT_MANAGER* cm = NULL;

    ExpectNotNull(cm = wolfSSL_CertManagerNew());
#ifndef NO_SHA256
    ExpectIntEQ(WOLFSSL_SUCCESS,
        wolfSSL_CertManagerLoadCA(cm, rsaPssRootSha256Cert, NULL));
#endif
#if defined(WOLFSSL_SHA384) && RSA_MAX_SIZE >= 3072
    ExpectIntEQ(WOLFSSL_SUCCESS,
        wolfSSL_CertManagerLoadCA(cm, rsaPssRootSha384Cert, NULL));
#endif

#ifndef NO_SHA256
    ExpectTrue((f = XFOPEN(rsaPssSha256Cert, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buf, 1, sizeof(buf), f), 0);
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }
    wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL);
    ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, VERIFY, cm), 0);
    wc_FreeDecodedCert(&cert);
#endif

#if defined(WOLFSSL_SHA384) && defined(WOLFSSL_PSS_LONG_SALT) && \
    RSA_MAX_SIZE >= 3072
    ExpectTrue((f = XFOPEN(rsaPssSha384Cert, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buf, 1, sizeof(buf), f), 0);
    if (f != XBADFILE)
        XFCLOSE(f);
    wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL);
    ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, VERIFY, cm), 0);
    wc_FreeDecodedCert(&cert);
#endif

    wolfSSL_CertManagerFree(cm);

    (void)buf;
    (void)bytes;
#endif

    return EXPECT_RESULT();
}
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
#endif /* HAVE_CERT_CHAIN_VALIDATION */


static int test_wolfSSL_CTX_load_verify_locations_ex(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_RSA)
    WOLFSSL_CTX* ctx = NULL;
#ifdef WOLFSSL_PEM_TO_DER
    const char* ca_cert = "./certs/ca-cert.pem";
    const char* ca_expired_cert = "./certs/test/expired/expired-ca.pem";
#else
    const char* ca_cert = "./certs/ca-cert.der";
    const char* ca_expired_cert = "./certs/test/expired/expired-ca.der";
#endif

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));

    /* test good CA */
    ExpectTrue(WOLFSSL_SUCCESS ==
        wolfSSL_CTX_load_verify_locations_ex(ctx, ca_cert, NULL,
            WOLFSSL_LOAD_FLAG_NONE));

    /* test expired CA */
#if !defined(OPENSSL_COMPATIBLE_DEFAULTS) && !defined(NO_ASN_TIME)
    ExpectIntNE(wolfSSL_CTX_load_verify_locations_ex(ctx, ca_expired_cert, NULL,
            WOLFSSL_LOAD_FLAG_NONE), WOLFSSL_SUCCESS);
#else
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx, ca_expired_cert, NULL,
            WOLFSSL_LOAD_FLAG_NONE), WOLFSSL_SUCCESS);
#endif
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx, ca_expired_cert, NULL,
            WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY), WOLFSSL_SUCCESS);

    wolfSSL_CTX_free(ctx);
#endif

    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_load_verify_buffer_ex(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_RSA) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    WOLFSSL_CTX* ctx;
    const char* ca_expired_cert_file = "./certs/test/expired/expired-ca.der";
    byte ca_expired_cert[TWOK_BUF];
    word32 sizeof_ca_expired_cert = 0;
    XFILE fp = XBADFILE;

#ifndef NO_WOLFSSL_CLIENT
    ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
#else
    ctx = wolfSSL_CTX_new(wolfSSLv23_server_method());
#endif
    ExpectNotNull(ctx);

#if defined(USE_CERT_BUFFERS_2048)
    /* test good CA */
    ExpectTrue(WOLFSSL_SUCCESS ==
        wolfSSL_CTX_load_verify_buffer_ex(ctx, ca_cert_der_2048,
            sizeof_ca_cert_der_2048, WOLFSSL_FILETYPE_ASN1, 0,
            WOLFSSL_LOAD_FLAG_NONE));
#endif

    /* load expired CA */
    XMEMSET(ca_expired_cert, 0, sizeof(ca_expired_cert));
    ExpectTrue((fp = XFOPEN(ca_expired_cert_file, "rb")) != XBADFILE);
    ExpectIntGT(sizeof_ca_expired_cert = (word32)XFREAD(ca_expired_cert, 1,
        sizeof(ca_expired_cert), fp), 0);
    if (fp != XBADFILE)
        XFCLOSE(fp);

    /* test expired CA failure */


#if !defined(OPENSSL_COMPATIBLE_DEFAULTS) && !defined(NO_ASN_TIME)
    ExpectIntNE(wolfSSL_CTX_load_verify_buffer_ex(ctx, ca_expired_cert,
            sizeof_ca_expired_cert, WOLFSSL_FILETYPE_ASN1, 0,
            WOLFSSL_LOAD_FLAG_NONE), WOLFSSL_SUCCESS);
#else
    ExpectIntEQ(wolfSSL_CTX_load_verify_buffer_ex(ctx, ca_expired_cert,
            sizeof_ca_expired_cert, WOLFSSL_FILETYPE_ASN1, 0,
            WOLFSSL_LOAD_FLAG_NONE), WOLFSSL_SUCCESS);
#endif
    /* test expired CA success */
    ExpectIntEQ(wolfSSL_CTX_load_verify_buffer_ex(ctx, ca_expired_cert,
            sizeof_ca_expired_cert, WOLFSSL_FILETYPE_ASN1, 0,
            WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY), WOLFSSL_SUCCESS);

    /* Fail when ctx is NULL. */
    ExpectIntEQ(wolfSSL_CTX_load_verify_buffer_ex(NULL, ca_expired_cert,
            sizeof_ca_expired_cert, WOLFSSL_FILETYPE_ASN1, 0,
            WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* Load as modified cert - bad initial length. */
    ca_expired_cert[2] = 0x7f;
    ExpectIntEQ(wolfSSL_CTX_load_verify_buffer_ex(ctx, ca_expired_cert,
            sizeof_ca_expired_cert, WOLFSSL_FILETYPE_ASN1, 1,
            WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY), WC_NO_ERR_TRACE(ASN_PARSE_E));

    wolfSSL_CTX_free(ctx);
#endif

    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_load_verify_chain_buffer_format(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_RSA) && defined(OPENSSL_EXTRA) && \
    defined(USE_CERT_BUFFERS_2048) && (WOLFSSL_MIN_RSA_BITS <= 1024) && \
    !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    WOLFSSL_CTX* ctx = NULL;

  #ifndef NO_WOLFSSL_CLIENT
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
  #else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
  #endif

    /* Public key 140 bytes??? */
    ExpectIntEQ(wolfSSL_CTX_load_verify_chain_buffer_format(ctx,
        ca_cert_chain_der, sizeof_ca_cert_chain_der, WOLFSSL_FILETYPE_ASN1),
        WOLFSSL_SUCCESS);

    wolfSSL_CTX_free(ctx);
#endif

    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_add1_chain_cert(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && defined(OPENSSL_EXTRA) && \
    defined(KEEP_OUR_CERT) && !defined(NO_RSA) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL_CTX*        ctx;
    WOLFSSL*            ssl = NULL;
    const char *certChain[] = {
            "./certs/intermediate/client-int-cert.pem",
            "./certs/intermediate/ca-int2-cert.pem",
            "./certs/intermediate/ca-int-cert.pem",
            "./certs/ca-cert.pem",
            NULL
    };
    const char** cert;
    WOLFSSL_X509* x509 = NULL;
    WOLF_STACK_OF(X509)* chain = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    ExpectNotNull(x509 = wolfSSL_X509_new());
    ExpectIntEQ(SSL_CTX_add1_chain_cert(ctx, x509), 0);
    ExpectIntEQ(SSL_CTX_add0_chain_cert(ctx, x509), 0);
    ExpectIntEQ(SSL_add1_chain_cert(ssl, x509), 0);
    ExpectIntEQ(SSL_add0_chain_cert(ssl, x509), 0);
    wolfSSL_X509_free(x509);
    x509 = NULL;

    for (cert = certChain; EXPECT_SUCCESS() && *cert != NULL; cert++) {
        ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(*cert,
            WOLFSSL_FILETYPE_PEM));

        /* Do negative tests once */
        if (cert == certChain) {
            /* Negative tests. */
            ExpectIntEQ(SSL_CTX_add1_chain_cert(NULL, NULL), 0);
            ExpectIntEQ(SSL_CTX_add1_chain_cert(ctx, NULL), 0);
            ExpectIntEQ(SSL_CTX_add1_chain_cert(NULL, x509), 0);
            ExpectIntEQ(SSL_CTX_add0_chain_cert(NULL, NULL), 0);
            ExpectIntEQ(SSL_CTX_add0_chain_cert(ctx, NULL), 0);
            ExpectIntEQ(SSL_CTX_add0_chain_cert(NULL, x509), 0);
        }

        ExpectIntEQ(SSL_CTX_add1_chain_cert(ctx, x509), 1);
        /* add1 must increment ref count (was 1, now 2). Verifies the
         * up_ref return value is assigned, not just compared. */
        if (EXPECT_SUCCESS() && x509 != NULL) {
            ExpectIntEQ(wolfSSL_RefCur(x509->ref), 2);
        }
        X509_free(x509);
        x509 = NULL;
    }
    for (cert = certChain; EXPECT_SUCCESS() && *cert != NULL; cert++) {
        ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(*cert,
            WOLFSSL_FILETYPE_PEM));

        /* Do negative tests once */
        if (cert == certChain) {
            /* Negative tests. */
            ExpectIntEQ(SSL_add1_chain_cert(NULL, NULL), 0);
            ExpectIntEQ(SSL_add1_chain_cert(ssl, NULL), 0);
            ExpectIntEQ(SSL_add1_chain_cert(NULL, x509), 0);
            ExpectIntEQ(SSL_add0_chain_cert(NULL, NULL), 0);
            ExpectIntEQ(SSL_add0_chain_cert(ssl, NULL), 0);
            ExpectIntEQ(SSL_add0_chain_cert(NULL, x509), 0);
        }

        ExpectIntEQ(SSL_add1_chain_cert(ssl, x509), 1);
        /* add1 must increment ref count (was 1, now 2) */
        if (EXPECT_SUCCESS() && x509 != NULL) {
            ExpectIntEQ(wolfSSL_RefCur(x509->ref), 2);
        }
        X509_free(x509);
        x509 = NULL;
    }

    ExpectIntEQ(SSL_CTX_get0_chain_certs(ctx, &chain), 1);
    ExpectIntEQ(sk_X509_num(chain), 3);
    ExpectIntEQ(SSL_get0_chain_certs(ssl, &chain), 1);
    ExpectIntEQ(sk_X509_num(chain), 3);

    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

/* Test that wolfssl_add_to_chain rejects sizes that would overflow word32.
 * ZD #21241 */
static int test_wolfSSL_add_to_chain_overflow(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && defined(OPENSSL_EXTRA) && \
    defined(KEEP_OUR_CERT) && !defined(NO_RSA) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_FILESYSTEM)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL_X509* x509 = NULL;
    DerBuffer* fakeChain = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));

    /* Load a real cert so ctx->certificate is set (first add goes there). */
    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(
        "./certs/intermediate/client-int-cert.pem", WOLFSSL_FILETYPE_PEM));
    ExpectIntEQ(SSL_CTX_add1_chain_cert(ctx, x509), 1);
    wolfSSL_X509_free(x509);
    x509 = NULL;

    /* Now ctx->certificate is set, next add goes to certChain via
     * wolfssl_add_to_chain.  Fake a chain whose length is near UINT32_MAX
     * so the size calculation (len + CERT_HEADER_SZ + certSz) overflows. */
    fakeChain = (DerBuffer*)XMALLOC(sizeof(DerBuffer) + 16, ctx->heap,
        DYNAMIC_TYPE_CERT);
    ExpectNotNull(fakeChain);
    if (EXPECT_SUCCESS()) {
        XMEMSET(fakeChain, 0, sizeof(DerBuffer) + 16);
        fakeChain->buffer = (byte*)(fakeChain + 1);
        fakeChain->length = WOLFSSL_MAX_32BIT - 2; /* will overflow with any cert */
        fakeChain->type = CERT_TYPE;
        fakeChain->dynType = DYNAMIC_TYPE_CERT;
        /* Replace the real chain with our fake one. */
        if (ctx->certChain != NULL) {
            XFREE(ctx->certChain, ctx->heap, DYNAMIC_TYPE_CERT);
        }
        ctx->certChain = fakeChain;
    }
    else {
        XFREE(fakeChain, ctx ? ctx->heap : NULL, DYNAMIC_TYPE_CERT);
    }

    /* Try to add another cert - this MUST fail due to overflow guard. */
    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(
        "./certs/intermediate/ca-int2-cert.pem", WOLFSSL_FILETYPE_PEM));
    ExpectIntEQ(SSL_CTX_add1_chain_cert(ctx, x509), 0);
    wolfSSL_X509_free(x509);

    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_use_certificate_chain_buffer_format(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_RSA) && \
    (!defined(NO_FILESYSTEM) || defined(USE_CERT_BUFFERS_2048))
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;
#ifndef NO_FILESYSTEM
    const char* cert = svrCertFile;
    unsigned char* buf = NULL;
    size_t len = 0;

    ExpectIntEQ(load_file(cert, &buf, &len), 0);
#endif

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* Invalid parameters. */
#ifndef NO_FILESYSTEM
    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer_format(NULL,
        NULL, 0, WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer_format(ctx,
        NULL, 0, WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(ASN_PARSE_E));
    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer(NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifdef WOLFSSL_PEM_TO_DER
    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer(ctx, NULL, 0),
        WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER));
#endif
    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer(NULL, buf,
        (sword32)len), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_use_certificate_chain_buffer(NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifdef WOLFSSL_PEM_TO_DER
    ExpectIntEQ(wolfSSL_use_certificate_chain_buffer(ssl, NULL, 0),
        WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER));
#endif
    ExpectIntEQ(wolfSSL_use_certificate_chain_buffer(NULL, buf, (sword32)len),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer_format(ctx, buf,
        (sword32)len, CERT_FILETYPE), WOLFSSL_SUCCESS);

    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer(ctx, buf, (sword32)len),
        WOLFSSL_SUCCESS);

    ExpectIntEQ(wolfSSL_use_certificate_chain_buffer(ssl, buf, (sword32)len),
        WOLFSSL_SUCCESS);
#endif /* !NO_FILESYSTEM */

    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer_format(NULL,
        server_cert_der_2048, sizeof_server_cert_der_2048,
        WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer_format(ctx,
        server_cert_der_2048, sizeof_server_cert_der_2048,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

#ifdef WOLFSSL_PEM_TO_DER
    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer(ctx,
        server_cert_der_2048, sizeof_server_cert_der_2048),
        WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER));

    ExpectIntEQ(wolfSSL_use_certificate_chain_buffer(ssl, server_cert_der_2048,
        sizeof_server_cert_der_2048), WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER));
#endif

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#ifndef NO_FILESYSTEM
    if (buf != NULL) {
        XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    }
#endif
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_use_certificate_chain_file_format(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_RSA) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    const char* server_chain_der = "./certs/server-cert-chain.der";
    const char* client_single_pem = cliCertFile;
    WOLFSSL_CTX* ctx = NULL;

    (void)server_chain_der;
    (void)client_single_pem;
    (void)ctx;

  #ifndef NO_WOLFSSL_CLIENT
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
  #else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
  #endif

    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_file_format(ctx,
        server_chain_der, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_file_format(ctx,
        client_single_pem, CERT_FILETYPE), WOLFSSL_SUCCESS);

    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_use_certificate_chain_file(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_RSA)
    const char* server_chain_der = "./certs/server-cert-chain.der";
    const char* client_single_pem = cliCertFile;
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;

    (void)server_chain_der;
    (void)client_single_pem;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* Invalid parameters. */
    ExpectIntEQ(wolfSSL_use_certificate_chain_file_format(NULL, NULL,
        WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_use_certificate_chain_file_format(ssl, NULL,
        WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_use_certificate_chain_file_format(NULL,
       server_chain_der, WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_use_certificate_chain_file(NULL, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_use_certificate_chain_file(ssl, NULL),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_use_certificate_chain_file(NULL, client_single_pem),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifdef WOLFSSL_PEM_TO_DER
    ExpectIntEQ(wolfSSL_use_certificate_chain_file(ssl, server_chain_der),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif

    ExpectIntEQ(wolfSSL_use_certificate_chain_file_format(ssl,
        server_chain_der, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_use_certificate_chain_file_format(ssl,
        client_single_pem, CERT_FILETYPE), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_use_certificate_chain_file(ssl, client_single_pem),
        WOLFSSL_SUCCESS);

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_SetTmpDH_file(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_DH) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    WOLFSSL_CTX *ctx = NULL;
#if defined(WOLFSSL_WPAS) && !defined(NO_DSA)
#if defined(WOLFSSL_PEM_TO_DER)
    const char* dsaParamFile = "./certs/dsaparams.pem";
#else
    const char* dsaParamFile = "./certs/dsaparams.der";
#endif
#endif

    (void)ctx;

  #ifndef NO_WOLFSSL_CLIENT
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
  #else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
  #endif

    /* invalid context */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_file(NULL,
                dhParamFile, CERT_FILETYPE));

    /* invalid dhParamFile file */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_file(ctx,
                NULL, CERT_FILETYPE));

    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_file(ctx,
                bogusFile, CERT_FILETYPE));

    /* success */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_file(ctx, dhParamFile,
                CERT_FILETYPE));
#if defined(WOLFSSL_WPAS) && !defined(NO_DSA)
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_file(ctx, dsaParamFile,
                CERT_FILETYPE));
#endif

    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_SetTmpDH_buffer(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_TLS) && !defined(NO_DH) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    WOLFSSL_CTX *ctx = NULL;

  #ifndef NO_WOLFSSL_CLIENT
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
  #else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
  #endif

    /* invalid context */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_buffer(NULL,
                dh_key_der_2048, sizeof_dh_key_der_2048,
                WOLFSSL_FILETYPE_ASN1));

    /* invalid dhParamFile file */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_buffer(NULL, NULL,
                0, WOLFSSL_FILETYPE_ASN1));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_buffer(ctx, NULL,
                0, WOLFSSL_FILETYPE_ASN1));

    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_buffer(ctx,
                dsa_key_der_2048, sizeof_dsa_key_der_2048,
                WOLFSSL_FILETYPE_ASN1));

    /* invalid file format */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_buffer(ctx,
                dh_key_der_2048, sizeof_dh_key_der_2048, -1));

    /* success */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_buffer(ctx,
                dh_key_der_2048, sizeof_dh_key_der_2048,
                WOLFSSL_FILETYPE_ASN1));

    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wc_DhSetNamedKey(void)
{
    EXPECT_DECLS;
#if !defined(HAVE_SELFTEST) && !defined(NO_DH) && \
    !defined(WOLFSSL_NO_MALLOC) && defined(HAVE_FFDHE) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
    DhKey *key = NULL;
    key = (DhKey*)XMALLOC(sizeof(DhKey), HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    ExpectNotNull(key);
    if (key != NULL){
        #ifdef HAVE_FFDHE_2048
        if (wc_InitDhKey_ex(key, HEAP_HINT, INVALID_DEVID) == 0){
            ExpectIntEQ(wc_DhSetNamedKey(key, WC_FFDHE_2048), 0);
            ExpectIntEQ(wc_DhGetNamedKeyMinSize(WC_FFDHE_2048), 29);
            wc_FreeDhKey(key);
        }
        #endif
        #ifdef HAVE_FFDHE_3072
        if (wc_InitDhKey_ex(key, HEAP_HINT, INVALID_DEVID) == 0){
            ExpectIntEQ(wc_DhSetNamedKey(key, WC_FFDHE_3072), 0);
            ExpectIntEQ(wc_DhGetNamedKeyMinSize(WC_FFDHE_3072), 34);
            wc_FreeDhKey(key);
        }
        #endif
        #ifdef HAVE_FFDHE_4096
        if (wc_InitDhKey_ex(key, HEAP_HINT, INVALID_DEVID) == 0){
            ExpectIntEQ(wc_DhSetNamedKey(key, WC_FFDHE_4096), 0);
            ExpectIntEQ(wc_DhGetNamedKeyMinSize(WC_FFDHE_4096), 39);
            wc_FreeDhKey(key);
        }
        #endif
        #ifdef HAVE_FFDHE_6144
        if (wc_InitDhKey_ex(key, HEAP_HINT, INVALID_DEVID) == 0){
            ExpectIntEQ(wc_DhSetNamedKey(key, WC_FFDHE_6144), 0);
            ExpectIntEQ(wc_DhGetNamedKeyMinSize(WC_FFDHE_6144), 46);
            wc_FreeDhKey(key);
        }
        #endif
        #ifdef HAVE_FFDHE_8192
        if (wc_InitDhKey_ex(key, HEAP_HINT, INVALID_DEVID) == 0){
            ExpectIntEQ(wc_DhSetNamedKey(key, WC_FFDHE_8192), 0);
            ExpectIntEQ(wc_DhGetNamedKeyMinSize(WC_FFDHE_8192), 52);
            wc_FreeDhKey(key);
        }
        #endif
        XFREE(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    }
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_SetMinMaxDhKey_Sz(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_TLS) && !defined(NO_DH) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    WOLFSSL_CTX *ctx;

    (void)ctx;

  #ifndef NO_WOLFSSL_CLIENT
    ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
  #else
    ctx = wolfSSL_CTX_new(wolfSSLv23_server_method());
  #endif
    ExpectNotNull(ctx);

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetMinDhKey_Sz(ctx, 3072));

    ExpectIntEQ(WC_NO_ERR_TRACE(DH_KEY_SIZE_E), wolfSSL_CTX_SetTmpDH_buffer(ctx, dh_key_der_2048,
                sizeof_dh_key_der_2048, WOLFSSL_FILETYPE_ASN1));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetMinDhKey_Sz(ctx, 2048));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_buffer(ctx,
                dh_key_der_2048, sizeof_dh_key_der_2048,
                WOLFSSL_FILETYPE_ASN1));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetMaxDhKey_Sz(ctx, 1024));

    ExpectIntEQ(WC_NO_ERR_TRACE(DH_KEY_SIZE_E), wolfSSL_CTX_SetTmpDH_buffer(ctx,
                dh_key_der_2048, sizeof_dh_key_der_2048,
                WOLFSSL_FILETYPE_ASN1));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetMaxDhKey_Sz(ctx, 2048));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_buffer(ctx,
                dh_key_der_2048, sizeof_dh_key_der_2048,
                WOLFSSL_FILETYPE_ASN1));

    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_der_load_verify_locations(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_DER_LOAD) && \
    !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    WOLFSSL_CTX* ctx = NULL;
    const char* derCert = "./certs/server-cert.der";
    const char* nullPath = NULL;
    const char* invalidPath = "./certs/this-cert-does-not-exist.der";
    const char* emptyPath = "";

    /* der load Case 1 ctx NULL */
    ExpectIntEQ(wolfSSL_CTX_der_load_verify_locations(ctx, derCert,
                WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

  #ifndef NO_WOLFSSL_CLIENT
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
  #else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
  #endif

    /* Case 2 filePath NULL */
    ExpectIntEQ(wolfSSL_CTX_der_load_verify_locations(ctx, nullPath,
                WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    /* Case 3 invalid format */
    ExpectIntEQ(wolfSSL_CTX_der_load_verify_locations(ctx, derCert,
                WOLFSSL_FILETYPE_PEM), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    /* Case 4 filePath not valid */
    ExpectIntEQ(wolfSSL_CTX_der_load_verify_locations(ctx, invalidPath,
                WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    /* Case 5 filePath empty */
    ExpectIntEQ(wolfSSL_CTX_der_load_verify_locations(ctx, emptyPath,
                WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#ifndef NO_RSA
    /* Case 6 success case */
    ExpectIntEQ(wolfSSL_CTX_der_load_verify_locations(ctx, derCert,
                WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
#endif

    wolfSSL_CTX_free(ctx);
#endif

    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_enable_disable(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_TLS)
    WOLFSSL_CTX* ctx = NULL;

  #ifdef HAVE_CRL
    ExpectIntEQ(wolfSSL_CTX_DisableCRL(ctx), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_EnableCRL(ctx, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
  #endif

  #ifdef HAVE_OCSP
    ExpectIntEQ(wolfSSL_CTX_DisableOCSP(ctx), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_EnableOCSP(ctx, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
  #endif

  #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
      defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
    ExpectIntEQ(wolfSSL_CTX_DisableOCSPStapling(ctx), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(ctx), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_DisableOCSPMustStaple(ctx), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_EnableOCSPMustStaple(ctx), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
  #endif

  #ifndef NO_WOLFSSL_CLIENT

    #ifdef HAVE_EXTENDED_MASTER
    ExpectIntEQ(wolfSSL_CTX_DisableExtendedMasterSecret(ctx), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    #endif
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));

    #ifdef HAVE_EXTENDED_MASTER
    ExpectIntEQ(wolfSSL_CTX_DisableExtendedMasterSecret(ctx), WOLFSSL_SUCCESS);
    #endif

  #elif !defined(NO_WOLFSSL_SERVER)
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
  #endif

  #if !defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)

    #ifdef HAVE_CRL
        ExpectIntEQ(wolfSSL_CTX_DisableCRL(ctx), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CTX_EnableCRL(ctx, 0), WOLFSSL_SUCCESS);
    #endif

    #ifdef HAVE_OCSP
        ExpectIntEQ(wolfSSL_CTX_DisableOCSP(ctx), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CTX_EnableOCSP(ctx, WOLFSSL_OCSP_URL_OVERRIDE),
                    WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CTX_EnableOCSP(ctx, WOLFSSL_OCSP_NO_NONCE),
                    WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CTX_EnableOCSP(ctx, WOLFSSL_OCSP_CHECKALL),
                    WOLFSSL_SUCCESS);
    #endif

    #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
        defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
        ExpectIntEQ(wolfSSL_CTX_DisableOCSPStapling(ctx), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(ctx), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CTX_DisableOCSPMustStaple(ctx), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CTX_DisableOCSPMustStaple(ctx), WOLFSSL_SUCCESS);
    #endif
        wolfSSL_CTX_free(ctx);
  #endif /* !NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER */
#endif /* !NO_CERTS && !NO_CERTS */

    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_ticket_API(void)
{
    EXPECT_DECLS;
#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) && \
    !defined(NO_TLS)
    WOLFSSL_CTX* ctx = NULL;
    void *userCtx = (void*)"this is my ctx";

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_set_TicketEncCtx(ctx, userCtx));
    ExpectTrue(userCtx == wolfSSL_CTX_get_TicketEncCtx(ctx));

    wolfSSL_CTX_free(ctx);

    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_set_TicketEncCtx(NULL, userCtx));
    ExpectNull(wolfSSL_CTX_get_TicketEncCtx(NULL));
#endif /* HAVE_SESSION_TICKET && !NO_WOLFSSL_SERVER && !NO_TLS */
    return EXPECT_RESULT();
}

static int test_wolfSSL_set_minmax_proto_version(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_TLS)
    WOLFSSL_CTX *ctx = NULL;
    WOLFSSL *ssl = NULL;

    (void)ssl;

#ifndef NO_WOLFSSL_CLIENT
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, 0), SSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, 0), SSL_SUCCESS);

    ExpectIntEQ(wolfSSL_set_min_proto_version(NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_set_min_proto_version(ssl, 0), SSL_SUCCESS);
    ExpectIntEQ(wolfSSL_set_max_proto_version(NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, 0), SSL_SUCCESS);

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
    ctx = NULL;
#endif
#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));

    ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, 0), SSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, 0), SSL_SUCCESS);

    wolfSSL_CTX_free(ctx);
#endif
#endif

    return EXPECT_RESULT();
}

#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_TLS12) && \
    defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
static int test_wolfSSL_CTX_set_max_proto_version_on_result(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    ExpectStrEQ(wolfSSL_get_version(ssl), "TLSv1.2");
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_set_max_proto_version_ctx_ready(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    /* Set TLS 1.2 */
    ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION),
            WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}

/* Test using wolfSSL_CTX_set_max_proto_version to limit the version below
 * what was set at ctx creation. */
static int test_wolfSSL_CTX_set_max_proto_version(void)
{
    EXPECT_DECLS;
    test_ssl_cbf client_cbs;
    test_ssl_cbf server_cbs;

    XMEMSET(&client_cbs, 0, sizeof(client_cbs));
    XMEMSET(&server_cbs, 0, sizeof(server_cbs));

    client_cbs.method = wolfTLS_client_method;
    server_cbs.method = wolfTLS_server_method;

    server_cbs.ctx_ready = test_wolfSSL_CTX_set_max_proto_version_ctx_ready;

    client_cbs.on_result = test_wolfSSL_CTX_set_max_proto_version_on_result;
    server_cbs.on_result = test_wolfSSL_CTX_set_max_proto_version_on_result;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbs,
        &server_cbs, NULL), TEST_SUCCESS);

    return EXPECT_RESULT();
}
#else
static int test_wolfSSL_CTX_set_max_proto_version(void)
{
    return TEST_SKIPPED;
}
#endif

/*----------------------------------------------------------------------------*
 | SSL
 *----------------------------------------------------------------------------*/

static int test_server_wolfSSL_new(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_SERVER) && !defined(NO_RSA)

    WOLFSSL_CTX *ctx = NULL;
    WOLFSSL_CTX *ctx_nocert = NULL;
    WOLFSSL *ssl = NULL;

    ExpectNotNull(ctx_nocert = wolfSSL_CTX_new(wolfSSLv23_server_method()));
    ExpectNotNull(ctx        = wolfSSL_CTX_new(wolfSSLv23_server_method()));

    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
        CERT_FILETYPE));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
        CERT_FILETYPE));

    /* invalid context */
    ExpectNull(ssl = wolfSSL_new(NULL));
#if !defined(WOLFSSL_SESSION_EXPORT) && !defined(WOLFSSL_QT) && \
        !defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_INIT_CTX_KEY)
    ExpectNull(ssl = wolfSSL_new(ctx_nocert));
#endif

    /* success */
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
    wolfSSL_CTX_free(ctx_nocert);
#endif

    return EXPECT_RESULT();
}


static int test_client_wolfSSL_new(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_RSA)

    WOLFSSL_CTX *ctx = NULL;
    WOLFSSL_CTX *ctx_nocert = NULL;
    WOLFSSL *ssl = NULL;

    ExpectNotNull(ctx_nocert = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ctx        = wolfSSL_CTX_new(wolfSSLv23_client_method()));

    ExpectTrue(wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0));

    /* invalid context */
    ExpectNull(ssl = wolfSSL_new(NULL));

    /* success */
    ExpectNotNull(ssl = wolfSSL_new(ctx_nocert));
    wolfSSL_free(ssl);
    ssl = NULL;

    /* success */
    ExpectNotNull(ssl = wolfSSL_new(ctx));
    wolfSSL_free(ssl);

    wolfSSL_CTX_free(ctx);
    wolfSSL_CTX_free(ctx_nocert);
#endif

    return EXPECT_RESULT();
}

static int test_wolfSSL_SetTmpDH_file(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_SERVER) && !defined(NO_DH)

    WOLFSSL_CTX *ctx = NULL;
    WOLFSSL *ssl = NULL;
#ifdef WOLFSSL_PEM_TO_DER
    const char* dhX942ParamFile = "./certs/x942dh2048.pem";
#if defined(WOLFSSL_WPAS) && !defined(NO_DSA)
    const char* dsaParamFile = "./certs/dsaparams.pem";
#endif
#else
    const char* dhX942ParamFile = "./certs/x942dh2048.der";
#if defined(WOLFSSL_WPAS) && !defined(NO_DSA)
    const char* dsaParamFile = "./certs/dsaparams.der";
#endif
#endif

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#ifndef NO_RSA
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
               CERT_FILETYPE));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
               CERT_FILETYPE));
#elif defined(HAVE_ECC)
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, eccCertFile,
               CERT_FILETYPE));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, eccKeyFile,
               CERT_FILETYPE));
#elif defined(HAVE_ED25519)
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, edCertFile,
               CERT_FILETYPE));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, edKeyFile,
               CERT_FILETYPE));
#elif defined(HAVE_ED448)
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, ed448CertFile,
               CERT_FILETYPE));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, ed448KeyFile,
               CERT_FILETYPE));
#endif
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* invalid ssl */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_file(NULL,
                dhParamFile, CERT_FILETYPE));

    /* invalid dhParamFile file */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_file(ssl,
                NULL, CERT_FILETYPE));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_file(ssl,
                bogusFile, CERT_FILETYPE));

    /* success */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_file(ssl, dhParamFile,
                CERT_FILETYPE));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_file(ssl, dhX942ParamFile,
                CERT_FILETYPE));
#if defined(WOLFSSL_WPAS) && !defined(NO_DSA)
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_file(ctx, dsaParamFile,
                CERT_FILETYPE));
#endif

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif

    return EXPECT_RESULT();
}

static int test_wolfSSL_SetTmpDH_buffer(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_TLS) && !defined(NO_WOLFSSL_SERVER) && \
    !defined(NO_DH)
    WOLFSSL_CTX *ctx = NULL;
    WOLFSSL *ssl = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
    ExpectTrue(wolfSSL_CTX_use_certificate_buffer(ctx, server_cert_der_2048,
               sizeof_server_cert_der_2048, WOLFSSL_FILETYPE_ASN1));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_buffer(ctx, server_key_der_2048,
               sizeof_server_key_der_2048, WOLFSSL_FILETYPE_ASN1));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* invalid ssl */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_buffer(NULL, dh_key_der_2048,
                sizeof_dh_key_der_2048, WOLFSSL_FILETYPE_ASN1));

    /* invalid dhParamFile file */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_buffer(NULL, NULL,
                0, WOLFSSL_FILETYPE_ASN1));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_buffer(ssl, NULL, 0,
                WOLFSSL_FILETYPE_ASN1));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_buffer(ssl, dsa_key_der_2048,
                sizeof_dsa_key_der_2048, WOLFSSL_FILETYPE_ASN1));

    /* success */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_buffer(ssl, dh_key_der_2048,
                sizeof_dh_key_der_2048, WOLFSSL_FILETYPE_ASN1));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif

    return EXPECT_RESULT();
}

static int test_wolfSSL_SetMinMaxDhKey_Sz(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_TLS) && !defined(NO_WOLFSSL_SERVER) && \
    !defined(NO_DH)
    WOLFSSL_CTX *ctx = NULL;
    WOLFSSL_CTX *ctx2 = NULL;
    WOLFSSL *ssl = NULL;
    WOLFSSL *ssl2 = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
    ExpectTrue(wolfSSL_CTX_use_certificate_buffer(ctx, server_cert_der_2048,
                sizeof_server_cert_der_2048, WOLFSSL_FILETYPE_ASN1));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_buffer(ctx, server_key_der_2048,
                sizeof_server_key_der_2048, WOLFSSL_FILETYPE_ASN1));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetMinDhKey_Sz(ctx, 3072));
    ExpectNotNull(ssl = wolfSSL_new(ctx));
    ExpectNotNull(ctx2 = wolfSSL_CTX_new(wolfSSLv23_server_method()));
    ExpectTrue(wolfSSL_CTX_use_certificate_buffer(ctx2, server_cert_der_2048,
                sizeof_server_cert_der_2048, WOLFSSL_FILETYPE_ASN1));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_buffer(ctx2, server_key_der_2048,
                sizeof_server_key_der_2048, WOLFSSL_FILETYPE_ASN1));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetMaxDhKey_Sz(ctx, 1024));
    ExpectNotNull(ssl2 = wolfSSL_new(ctx2));

    ExpectIntEQ(WC_NO_ERR_TRACE(DH_KEY_SIZE_E), wolfSSL_SetTmpDH_buffer(ssl, dh_key_der_2048,
                sizeof_dh_key_der_2048, WOLFSSL_FILETYPE_ASN1));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetMinDhKey_Sz(ssl, 2048));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_buffer(ssl, dh_key_der_2048,
                sizeof_dh_key_der_2048, WOLFSSL_FILETYPE_ASN1));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetMinDhKey_Sz(ssl, 3072));
    ExpectIntEQ(WC_NO_ERR_TRACE(DH_KEY_SIZE_E), wolfSSL_SetTmpDH_buffer(ssl, dh_key_der_2048,
                sizeof_dh_key_der_2048, WOLFSSL_FILETYPE_ASN1));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_buffer(ssl2, dh_key_der_2048,
                sizeof_dh_key_der_2048, WOLFSSL_FILETYPE_ASN1));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetMaxDhKey_Sz(ssl2, 2048));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_buffer(ssl2, dh_key_der_2048,
                sizeof_dh_key_der_2048, WOLFSSL_FILETYPE_ASN1));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetMaxDhKey_Sz(ssl2, 1024));
    ExpectIntEQ(WC_NO_ERR_TRACE(DH_KEY_SIZE_E), wolfSSL_SetTmpDH_buffer(ssl, dh_key_der_2048,
                sizeof_dh_key_der_2048, WOLFSSL_FILETYPE_ASN1));

    wolfSSL_free(ssl2);
    wolfSSL_CTX_free(ctx2);
    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}


/* Test function for wolfSSL_SetMinVersion. Sets the minimum downgrade version
 * allowed.
 * POST: return 1 on success.
 */
static int test_wolfSSL_SetMinVersion(void)
{
    int                 res = TEST_SKIPPED;
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS)
    int                 failFlag = WOLFSSL_SUCCESS;
    WOLFSSL_CTX*        ctx = NULL;
    WOLFSSL*            ssl = NULL;
    int                 itr;

    #ifndef NO_OLD_TLS
        const int versions[]  =  {
                            #ifdef WOLFSSL_ALLOW_TLSV10
                                   WOLFSSL_TLSV1,
                            #endif
                                   WOLFSSL_TLSV1_1,
                                   WOLFSSL_TLSV1_2};
    #elif !defined(WOLFSSL_NO_TLS12)
        const int versions[]  =  { WOLFSSL_TLSV1_2 };
    #else
        const int versions[]  =  { WOLFSSL_TLSV1_3 };
    #endif

    ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
    ssl = wolfSSL_new(ctx);

    for (itr = 0; itr < (int)(sizeof(versions)/sizeof(int)); itr++) {
       if (wolfSSL_SetMinVersion(ssl, *(versions + itr)) != WOLFSSL_SUCCESS) {
            failFlag = WOLFSSL_FAILURE;
        }
    }

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);

    res = TEST_RES_CHECK(failFlag == WOLFSSL_SUCCESS);
#endif
    return res;

} /* END test_wolfSSL_SetMinVersion */


#include <wolfssl/openssl/pem.h>

/*----------------------------------------------------------------------------*
 | IO
 *----------------------------------------------------------------------------*/

#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) || \
    defined(HAVE_IO_TESTS_DEPENDENCIES)
#ifdef WOLFSSL_HAVE_TLS_UNIQUE
    byte server_side_msg1[WC_MAX_DIGEST_SIZE]; /* msg sent by server */
    byte server_side_msg2[WC_MAX_DIGEST_SIZE]; /* msg received from client */
    byte client_side_msg1[WC_MAX_DIGEST_SIZE]; /* msg sent by client */
    byte client_side_msg2[WC_MAX_DIGEST_SIZE]; /* msg received from server */
#endif /* WOLFSSL_HAVE_TLS_UNIQUE */

/* TODO: Expand and enable this when EVP_chacha20_poly1305 is supported */
#if defined(HAVE_SESSION_TICKET) && defined(OPENSSL_EXTRA) && \
    defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)

    typedef struct openssl_key_ctx {
        byte name[WOLFSSL_TICKET_NAME_SZ]; /* server name */
        byte key[WOLFSSL_TICKET_KEY_SZ]; /* cipher key */
        byte hmacKey[WOLFSSL_TICKET_NAME_SZ]; /* hmac key */
        byte iv[WOLFSSL_TICKET_IV_SZ]; /* cipher iv */
    } openssl_key_ctx;

    static THREAD_LS_T openssl_key_ctx myOpenSSLKey_ctx;
    static THREAD_LS_T WC_RNG myOpenSSLKey_rng;

    static WC_INLINE int OpenSSLTicketInit(void)
    {
        int ret = wc_InitRng(&myOpenSSLKey_rng);
        if (ret != 0) return ret;

        ret = wc_RNG_GenerateBlock(&myOpenSSLKey_rng, myOpenSSLKey_ctx.name,
                sizeof(myOpenSSLKey_ctx.name));
        if (ret != 0) return ret;

        ret = wc_RNG_GenerateBlock(&myOpenSSLKey_rng, myOpenSSLKey_ctx.key,
                sizeof(myOpenSSLKey_ctx.key));
        if (ret != 0) return ret;

        ret = wc_RNG_GenerateBlock(&myOpenSSLKey_rng, myOpenSSLKey_ctx.hmacKey,
                sizeof(myOpenSSLKey_ctx.hmacKey));
        if (ret != 0) return ret;

        ret = wc_RNG_GenerateBlock(&myOpenSSLKey_rng, myOpenSSLKey_ctx.iv,
                sizeof(myOpenSSLKey_ctx.iv));
        if (ret != 0) return ret;

        return 0;
    }

    static int myTicketEncCbOpenSSL(WOLFSSL* ssl,
                             byte name[WOLFSSL_TICKET_NAME_SZ],
                             byte iv[WOLFSSL_TICKET_IV_SZ],
                             WOLFSSL_EVP_CIPHER_CTX *ectx,
                             WOLFSSL_HMAC_CTX *hctx, int enc) {
        (void)ssl;
        if (enc) {
            XMEMCPY(name, myOpenSSLKey_ctx.name, sizeof(myOpenSSLKey_ctx.name));
            XMEMCPY(iv, myOpenSSLKey_ctx.iv, sizeof(myOpenSSLKey_ctx.iv));
        }
        else if (XMEMCMP(name, myOpenSSLKey_ctx.name,
                            sizeof(myOpenSSLKey_ctx.name)) != 0 ||
                 XMEMCMP(iv, myOpenSSLKey_ctx.iv,
                            sizeof(myOpenSSLKey_ctx.iv)) != 0) {
            return 0;
        }
        HMAC_Init_ex(hctx, myOpenSSLKey_ctx.hmacKey, WOLFSSL_TICKET_NAME_SZ, EVP_sha256(), NULL);
        if (enc)
            EVP_EncryptInit_ex(ectx, EVP_aes_256_cbc(), NULL, myOpenSSLKey_ctx.key, iv);
        else
            EVP_DecryptInit_ex(ectx, EVP_aes_256_cbc(), NULL, myOpenSSLKey_ctx.key, iv);
        return 1;
    }

    static WC_INLINE void OpenSSLTicketCleanup(void)
    {
        wc_FreeRng(&myOpenSSLKey_rng);
    }
#endif
#endif

/* helper functions */
#ifdef HAVE_SSL_MEMIO_TESTS_DEPENDENCIES
static WC_INLINE int test_ssl_memio_write_cb(WOLFSSL *ssl, char *data, int sz,
    void *ctx)
{
    struct test_ssl_memio_ctx *test_ctx;
    byte *buf;
    int *len;
    int *msg_sizes;
    int *msg_count;

    test_ctx = (struct test_ssl_memio_ctx*)ctx;

    if (wolfSSL_GetSide(ssl) == WOLFSSL_SERVER_END) {
        buf = test_ctx->c_buff;
        len = &test_ctx->c_len;
        msg_sizes = test_ctx->c_msg_sizes;
        msg_count = &test_ctx->c_msg_count;
    }
    else {
        buf = test_ctx->s_buff;
        len = &test_ctx->s_len;
        msg_sizes = test_ctx->s_msg_sizes;
        msg_count = &test_ctx->s_msg_count;
    }

    if ((unsigned)(*len + sz) > TEST_SSL_MEMIO_BUF_SZ)
        return WOLFSSL_CBIO_ERR_WANT_WRITE;

    if (*msg_count >= TEST_MEMIO_MAX_MSGS)
        return WOLFSSL_CBIO_ERR_WANT_WRITE;

    XMEMCPY(buf + *len, data, sz);
    msg_sizes[*msg_count] = sz;
    (*msg_count)++;
    *len += sz;

#ifdef WOLFSSL_DUMP_MEMIO_STREAM
    {
        /* This can be imported into Wireshark by transforming the file with
         *   od -Ax -tx1 -v test_output.dump > test_output.dump.hex
         * And then loading test_output.dump.hex into Wireshark using the
         * "Import from Hex Dump..." option ion and selecting the TCP
         * encapsulation option. */
        char dump_file_name[64];
        XFILE dump_file;
        sprintf(dump_file_name, "%s/%s.dump", tmpDirName, currentTestName);
        dump_file = XFOPEN(dump_file_name, "ab");
        if (dump_file != XBADFILE) {
            (void)XFWRITE(data, 1, (size_t)sz, dump_file);
            XFCLOSE(dump_file);
        }
    }
#endif

    return sz;
}

static WC_INLINE int test_ssl_memio_read_cb(WOLFSSL *ssl, char *data, int sz,
    void *ctx)
{
    struct test_ssl_memio_ctx *test_ctx;
    int read_sz;
    byte *buf;
    int *len;
    int *msg_sizes;
    int *msg_count;
    int *msg_pos;
    int is_dtls;

    test_ctx = (struct test_ssl_memio_ctx*)ctx;
    is_dtls = wolfSSL_dtls(ssl);

    if (wolfSSL_GetSide(ssl) == WOLFSSL_SERVER_END) {
        buf = test_ctx->s_buff;
        len = &test_ctx->s_len;
        msg_sizes = test_ctx->s_msg_sizes;
        msg_count = &test_ctx->s_msg_count;
        msg_pos = &test_ctx->s_msg_pos;
    }
    else {
        buf = test_ctx->c_buff;
        len = &test_ctx->c_len;
        msg_sizes = test_ctx->c_msg_sizes;
        msg_count = &test_ctx->c_msg_count;
        msg_pos = &test_ctx->c_msg_pos;
    }

    if (*len == 0 || *msg_pos >= *msg_count)
        return WOLFSSL_CBIO_ERR_WANT_READ;

    /* Calculate how much we can read from current message */
    read_sz = msg_sizes[*msg_pos];
    if (read_sz > sz)
        read_sz = sz;

    if (read_sz > *len)
        return WOLFSSL_CBIO_ERR_GENERAL;

    /* Copy data from current message */
    XMEMCPY(data, buf, (size_t)read_sz);
    /* remove the read data from the buffer */
    XMEMMOVE(buf, buf + read_sz, (size_t)(*len - read_sz));
    *len -= read_sz;
    msg_sizes[*msg_pos] -= read_sz;

    /* if we are on dtls, discard the rest of the message */
    if (is_dtls && msg_sizes[*msg_pos] > 0) {
        XMEMMOVE(buf, buf + msg_sizes[*msg_pos], (size_t)(*len - msg_sizes[*msg_pos]));
        *len -= msg_sizes[*msg_pos];
        msg_sizes[*msg_pos] = 0;
    }

    /* If we've read the entire message */
    if (msg_sizes[*msg_pos] == 0) {
        /* Move to next message */
        (*msg_pos)++;
        if (*msg_pos >= *msg_count) {
            *msg_pos = 0;
            *msg_count = 0;
        }
    }

    return read_sz;
}

int test_ssl_memio_setup(test_ssl_memio_ctx *ctx)
{
    EXPECT_DECLS_NO_MSGS(-2000);
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    int c_sharedCtx = 0;
    int s_sharedCtx = 0;
#endif
    const char* clientCertFile = cliCertFile;
    const char* clientKeyFile = cliKeyFile;
    const char* serverCertFile = svrCertFile;
    const char* serverKeyFile = svrKeyFile;

    /********************************
     * Create WOLFSSL_CTX for client.
     ********************************/
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (ctx->c_ctx != NULL) {
        c_sharedCtx = ctx->c_cb.isSharedCtx;
    }
    else
#endif
    {
        WOLFSSL_METHOD* method  = NULL;
        if (ctx->c_cb.method != NULL) {
            method = ctx->c_cb.method();
        }
        else {
            method = wolfSSLv23_client_method();
        }
        ExpectNotNull(ctx->c_ctx = wolfSSL_CTX_new(method));
    }
    wolfSSL_SetIORecv(ctx->c_ctx, test_ssl_memio_read_cb);
    wolfSSL_SetIOSend(ctx->c_ctx, test_ssl_memio_write_cb);
#ifdef WOLFSSL_ENCRYPTED_KEYS
    wolfSSL_CTX_set_default_passwd_cb(ctx->c_ctx, PasswordCallBack);
#endif
    if (ctx->c_cb.caPemFile == NULL)
        ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx->c_ctx,
                caCertFile, 0), WOLFSSL_SUCCESS);
    else if (*ctx->c_cb.caPemFile != '\0')
        ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx->c_ctx,
                ctx->c_cb.caPemFile, 0), WOLFSSL_SUCCESS);
    if (ctx->c_cb.certPemFile != NULL) {
        clientCertFile = ctx->c_cb.certPemFile;
    }
    if (ctx->c_cb.keyPemFile != NULL) {
        clientKeyFile = ctx->c_cb.keyPemFile;
    }
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (!c_sharedCtx)
#endif
    {
        if (*clientCertFile != '\0') {
            ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_file(ctx->c_ctx,
                clientCertFile), WOLFSSL_SUCCESS);
        }
        if (*clientKeyFile != '\0') {
            ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx->c_ctx, clientKeyFile,
                CERT_FILETYPE), WOLFSSL_SUCCESS);
        }
    }
#ifdef HAVE_CRL
    if (ctx->c_cb.crlPemFile != NULL) {
        ExpectIntEQ(wolfSSL_CTX_EnableCRL(ctx->c_ctx, WOLFSSL_CRL_CHECKALL),
            WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CTX_LoadCRLFile(ctx->c_ctx, ctx->c_cb.crlPemFile,
            CERT_FILETYPE), WOLFSSL_SUCCESS);
    }
#endif
    if (ctx->c_ciphers != NULL) {
        ExpectIntEQ(wolfSSL_CTX_set_cipher_list(ctx->c_ctx, ctx->c_ciphers),
            WOLFSSL_SUCCESS);
    }
    if (ctx->c_cb.ctx_ready != NULL) {
        ExpectIntEQ(ctx->c_cb.ctx_ready(ctx->c_ctx), TEST_SUCCESS);
    }


    /********************************
     * Create WOLFSSL_CTX for server.
     ********************************/
    if (ctx->s_ctx != NULL) {
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
        s_sharedCtx = 1;
#endif
        ctx->s_cb.isSharedCtx = 1;
    }
    else
    {
        WOLFSSL_METHOD* method  = NULL;
        if (ctx->s_cb.method != NULL) {
            method = ctx->s_cb.method();
        }
        else {
            method = wolfSSLv23_server_method();
        }
        ExpectNotNull(ctx->s_ctx = wolfSSL_CTX_new(method));
        ctx->s_cb.isSharedCtx = 0;
    }
    if (!ctx->s_cb.ticNoInit && (ctx->s_ctx != NULL)) {
#if defined(HAVE_SESSION_TICKET) && \
    ((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))
#if defined(OPENSSL_EXTRA) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
        OpenSSLTicketInit();
        wolfSSL_CTX_set_tlsext_ticket_key_cb(ctx->s_ctx, myTicketEncCbOpenSSL);
#elif defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
        TicketInit();
        wolfSSL_CTX_set_TicketEncCb(ctx->s_ctx, myTicketEncCb);
#endif
#endif
    }
    wolfSSL_SetIORecv(ctx->s_ctx, test_ssl_memio_read_cb);
    wolfSSL_SetIOSend(ctx->s_ctx, test_ssl_memio_write_cb);
    wolfSSL_CTX_set_verify(ctx->s_ctx, WOLFSSL_VERIFY_PEER |
        WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
    if (ctx->s_cb.caPemFile == NULL)
        ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx->s_ctx,
                cliCertFile, 0), WOLFSSL_SUCCESS);
    else if (*ctx->s_cb.caPemFile != '\0')
        ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx->s_ctx,
                ctx->s_cb.caPemFile, 0), WOLFSSL_SUCCESS);
#ifdef WOLFSSL_ENCRYPTED_KEYS
    wolfSSL_CTX_set_default_passwd_cb(ctx->s_ctx, PasswordCallBack);
#endif
    if (ctx->s_cb.certPemFile != NULL) {
        serverCertFile = ctx->s_cb.certPemFile;
    }
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (!s_sharedCtx)
#endif
    {
        if (*serverCertFile != '\0') {
            ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_file(ctx->s_ctx,
                serverCertFile), WOLFSSL_SUCCESS);
        }
    }
    if (ctx->s_cb.keyPemFile != NULL) {
        serverKeyFile = ctx->s_cb.keyPemFile;
    }
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (!s_sharedCtx)
#endif
    {
        if (*serverKeyFile != '\0') {
            ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx->s_ctx, serverKeyFile,
                CERT_FILETYPE), WOLFSSL_SUCCESS);
        }
    }
    if (ctx->s_ciphers != NULL) {
        ExpectIntEQ(wolfSSL_CTX_set_cipher_list(ctx->s_ctx, ctx->s_ciphers),
            WOLFSSL_SUCCESS);
    }
    if (ctx->s_cb.ctx_ready != NULL) {
        ExpectIntEQ(ctx->s_cb.ctx_ready(ctx->s_ctx), TEST_SUCCESS);
    }


    /****************************
     * Create WOLFSSL for client.
     ****************************/
    ExpectNotNull(ctx->c_ssl = wolfSSL_new(ctx->c_ctx));
    wolfSSL_SetIOWriteCtx(ctx->c_ssl, ctx);
    wolfSSL_SetIOReadCtx(ctx->c_ssl, ctx);
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (c_sharedCtx) {
        if (*clientCertFile != '\0') {
            ExpectIntEQ(wolfSSL_use_certificate_chain_file(ctx->c_ssl,
                    clientCertFile), WOLFSSL_SUCCESS);
        }
        if (*clientKeyFile != '\0') {
            ExpectIntEQ(wolfSSL_use_PrivateKey_file(ctx->c_ssl, clientKeyFile,
                CERT_FILETYPE), WOLFSSL_SUCCESS);
        }
    }
#endif
    if (ctx->c_cb.ssl_ready != NULL) {
        ExpectIntEQ(ctx->c_cb.ssl_ready(ctx->c_ssl), TEST_SUCCESS);
    }

    /****************************
     * Create WOLFSSL for server.
     ****************************/
    ExpectNotNull(ctx->s_ssl = wolfSSL_new(ctx->s_ctx));
    wolfSSL_SetIOWriteCtx(ctx->s_ssl, ctx);
    wolfSSL_SetIOReadCtx(ctx->s_ssl, ctx);
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (s_sharedCtx) {
        if (*serverCertFile != '\0') {
            ExpectIntEQ(wolfSSL_use_certificate_chain_file(ctx->s_ssl,
                    serverCertFile), WOLFSSL_SUCCESS);
        }
        if (*serverKeyFile != '\0') {
            ExpectIntEQ(wolfSSL_use_PrivateKey_file(ctx->s_ssl, serverKeyFile,
                CERT_FILETYPE), WOLFSSL_SUCCESS);
        }
    }
#endif
#if !defined(NO_FILESYSTEM) && !defined(NO_DH)
    wolfSSL_SetTmpDH_file(ctx->s_ssl, dhParamFile, CERT_FILETYPE);
#elif !defined(NO_DH)
    /* will repick suites with DHE, higher priority than PSK */
    SetDH(ctx->s_ssl);
#endif
    if (ctx->s_cb.ssl_ready != NULL) {
        ExpectIntEQ(ctx->s_cb.ssl_ready(ctx->s_ssl), TEST_SUCCESS);
    }

    return EXPECT_RESULT();
}

int test_ssl_memio_do_handshake(test_ssl_memio_ctx* ctx, int max_rounds,
    int* rounds)
{
    int handshake_complete = 0;
    int hs_c = 0;
    int hs_s = 0;
    int failing_s = 0;
    int failing_c = 0;
    int ret;
    int err;

    if (rounds != NULL) {
        *rounds = 0;
    }
    while ((!handshake_complete) && (max_rounds > 0)) {
        if (!hs_c) {
            wolfSSL_SetLoggingPrefix("client");
            ret = wolfSSL_connect(ctx->c_ssl);
            wolfSSL_SetLoggingPrefix(NULL);
            if (ret == WOLFSSL_SUCCESS) {
                hs_c = 1;
            }
            else {
                err = wolfSSL_get_error(ctx->c_ssl, ret);
                if (err == WC_NO_ERR_TRACE(MP_WOULDBLOCK)) {
                    /* retry non-blocking math */
                }
                else if (err != WOLFSSL_ERROR_WANT_READ &&
                         err != WOLFSSL_ERROR_WANT_WRITE &&
                         err != WC_NO_ERR_TRACE(OCSP_WANT_READ)) {
                    char buff[WOLFSSL_MAX_ERROR_SZ];
                    fprintf(stderr, "error = %d, %s\n", err,
                        wolfSSL_ERR_error_string((word32)err, buff));
                    failing_c = 1;
                    hs_c = 1;
                    if (failing_c && failing_s) {
                        break;
                    }
                }
            }
        }
        if (!hs_s) {
            wolfSSL_SetLoggingPrefix("server");
            ret = wolfSSL_accept(ctx->s_ssl);
            wolfSSL_SetLoggingPrefix(NULL);
            if (ret == WOLFSSL_SUCCESS) {
                hs_s = 1;
            }
            else {
                err = wolfSSL_get_error(ctx->s_ssl, ret);
                if (err == WC_NO_ERR_TRACE(MP_WOULDBLOCK)) {
                    /* retry non-blocking math */
                }
                else if (err != WOLFSSL_ERROR_WANT_READ &&
                         err != WOLFSSL_ERROR_WANT_WRITE &&
                         err != WC_NO_ERR_TRACE(OCSP_WANT_READ)) {
                    char buff[WOLFSSL_MAX_ERROR_SZ];
                    fprintf(stderr, "error = %d, %s\n", err,
                        wolfSSL_ERR_error_string((word32)err, buff));
                    failing_s = 1;
                    hs_s = 1;
                    if (failing_c && failing_s) {
                        break;
                    }
                }
            }
        }
        handshake_complete = hs_c && hs_s;
        max_rounds--;
        if (rounds != NULL) {
            *rounds += 1;
        }
    }

    if (!handshake_complete || failing_c || failing_s) {
        return TEST_FAIL;
    }

    return TEST_SUCCESS;
}

static int test_ssl_memio_read_write(test_ssl_memio_ctx* ctx)
{
    EXPECT_DECLS_NO_MSGS(-3000);
    char input[1024];
    int idx = 0;
    const char* msg_c = "hello wolfssl!";
    int msglen_c = (int)XSTRLEN(msg_c);
    const char* msg_s = "I hear you fa shizzle!";
    int msglen_s = (int)XSTRLEN(msg_s);

    if (ctx->c_msg != NULL) {
        msg_c = ctx->c_msg;
        msglen_c = ctx->c_msglen;
    }
    if (ctx->s_msg != NULL) {
        msg_s = ctx->s_msg;
        msglen_s = ctx->s_msglen;
    }

    wolfSSL_SetLoggingPrefix("client");
    ExpectIntEQ(wolfSSL_write(ctx->c_ssl, msg_c, msglen_c), msglen_c);
    wolfSSL_SetLoggingPrefix("server");
    ExpectIntGT(idx = wolfSSL_read(ctx->s_ssl, input, sizeof(input) - 1), 0);
    if (idx >= 0) {
        input[idx] = '\0';
    }
    ExpectIntGT(fprintf(stderr, "Client message: %s\n", input), 0);
    ExpectIntEQ(wolfSSL_write(ctx->s_ssl, msg_s, msglen_s), msglen_s);
    ctx->s_cb.return_code = EXPECT_RESULT();
    wolfSSL_SetLoggingPrefix("client");
    ExpectIntGT(idx = wolfSSL_read(ctx->c_ssl, input, sizeof(input) - 1), 0);
    wolfSSL_SetLoggingPrefix(NULL);
    if (idx >= 0) {
        input[idx] = '\0';
    }
    ExpectIntGT(fprintf(stderr, "Server response: %s\n", input), 0);
    ctx->c_cb.return_code = EXPECT_RESULT();
    if (ctx->c_cb.on_result != NULL) {
        ExpectIntEQ(ctx->c_cb.on_result(ctx->c_ssl), TEST_SUCCESS);
    }
    if (ctx->s_cb.on_result != NULL) {
        ExpectIntEQ(ctx->s_cb.on_result(ctx->s_ssl), TEST_SUCCESS);
    }

    return EXPECT_RESULT();
}

void test_ssl_memio_cleanup(test_ssl_memio_ctx* ctx)
{
    ctx->c_cb.last_err = wolfSSL_get_error(ctx->c_ssl, 0);
    ctx->s_cb.last_err = wolfSSL_get_error(ctx->s_ssl, 0);
    if (ctx->c_cb.on_cleanup != NULL) {
        ctx->c_cb.on_cleanup(ctx->c_ssl);
    }
    if (ctx->s_cb.on_cleanup != NULL) {
        ctx->s_cb.on_cleanup(ctx->s_ssl);
    }
    wolfSSL_shutdown(ctx->s_ssl);
    wolfSSL_shutdown(ctx->c_ssl);
    wolfSSL_free(ctx->s_ssl);
    wolfSSL_free(ctx->c_ssl);
    if (ctx->c_cb.on_ctx_cleanup != NULL) {
        ctx->c_cb.on_ctx_cleanup(ctx->c_ctx);
    }
    if (!ctx->c_cb.isSharedCtx) {
        wolfSSL_CTX_free(ctx->c_ctx);
        ctx->c_ctx = NULL;
    }
    if (ctx->s_cb.on_ctx_cleanup != NULL) {
        ctx->s_cb.on_ctx_cleanup(ctx->s_ctx);
    }
    if (!ctx->s_cb.isSharedCtx) {
        wolfSSL_CTX_free(ctx->s_ctx);
        ctx->s_ctx = NULL;
    }

    if (!ctx->s_cb.ticNoInit) {
#if defined(HAVE_SESSION_TICKET) && \
    ((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))
#if defined(OPENSSL_EXTRA) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
        OpenSSLTicketCleanup();
#elif defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
        TicketCleanup();
#endif
#endif
    }
}

static int test_wolfSSL_client_server_nofail_memio_ex(test_ssl_cbf* client_cb,
    test_ssl_cbf* server_cb, cbType client_on_handshake,
    cbType server_on_handshake)
{
    /* We use EXPECT_DECLS_NO_MSGS() here because this helper routine is used
     * for numerous but varied expected-to-fail scenarios that should not emit
     * error messages on the expected failures.  Instead, we return a distinct
     * code for each failure point, allowing the caller to assert on a
     * particular mode of expected failure.  On success, the usual TEST_SUCCESS
     * is returned.
     */
    EXPECT_DECLS_NO_MSGS(-1000);
    struct test_ssl_memio_ctx test_ctx;
#ifdef WOLFSSL_HAVE_TLS_UNIQUE
    size_t msg_len;
#endif /* WOLFSSL_HAVE_TLS_UNIQUE */

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    XMEMCPY(&test_ctx.c_cb, client_cb, sizeof(test_ssl_cbf));
    XMEMCPY(&test_ctx.s_cb, server_cb, sizeof(test_ssl_cbf));

    test_ctx.c_ctx = client_cb->ctx;
    test_ctx.s_ctx = server_cb->ctx;
    test_ctx.c_cb.return_code = EXPECT_FAILURE_CODEPOINT_ID;
    test_ctx.s_cb.return_code = EXPECT_FAILURE_CODEPOINT_ID;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
    ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);

    if (client_on_handshake != NULL) {
        ExpectIntEQ(client_on_handshake(test_ctx.c_ctx, test_ctx.c_ssl),
            TEST_SUCCESS);
    }
    if (server_on_handshake != NULL) {
        ExpectIntEQ(server_on_handshake(test_ctx.s_ctx, test_ctx.s_ssl),
            TEST_SUCCESS);
    }
    if (client_cb->on_handshake != NULL) {
        ExpectIntEQ(client_cb->on_handshake(&test_ctx.c_ctx, &test_ctx.c_ssl),
            TEST_SUCCESS);
    }
    if (server_cb->on_handshake != NULL) {
        ExpectIntEQ(server_cb->on_handshake(&test_ctx.s_ctx, &test_ctx.s_ssl),
            TEST_SUCCESS);
    }
#ifdef WOLFSSL_HAVE_TLS_UNIQUE
    XMEMSET(server_side_msg2, 0, WC_MAX_DIGEST_SIZE);
    msg_len = wolfSSL_get_peer_finished(test_ctx.s_ssl, server_side_msg2,
        WC_MAX_DIGEST_SIZE);
    ExpectIntGE(msg_len, 0);

    XMEMSET(server_side_msg1, 0, WC_MAX_DIGEST_SIZE);
    msg_len = wolfSSL_get_finished(test_ctx.s_ssl, server_side_msg1,
        WC_MAX_DIGEST_SIZE);
    ExpectIntGE(msg_len, 0);
#endif /* WOLFSSL_HAVE_TLS_UNIQUE */

    ExpectIntEQ(test_ssl_memio_read_write(&test_ctx), TEST_SUCCESS);
    test_ssl_memio_cleanup(&test_ctx);

    client_cb->return_code = test_ctx.c_cb.return_code;
    client_cb->last_err = test_ctx.c_cb.last_err;
    server_cb->return_code = test_ctx.s_cb.return_code;
    server_cb->last_err = test_ctx.s_cb.last_err;

    return EXPECT_RESULT();
}

int test_wolfSSL_client_server_nofail_memio(test_ssl_cbf* client_cb,
    test_ssl_cbf* server_cb, cbType client_on_handshake)
{
    return (test_wolfSSL_client_server_nofail_memio_ex(client_cb, server_cb,
        client_on_handshake, NULL));
}
#endif

#ifdef HAVE_IO_TESTS_DEPENDENCIES

#ifdef WOLFSSL_SESSION_EXPORT
#ifdef WOLFSSL_DTLS
/* set up function for sending session information */
static int test_export(WOLFSSL* inSsl, byte* buf, word32 sz, void* userCtx)
{
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL*     ssl = NULL;

    AssertNotNull(inSsl);
    AssertNotNull(buf);
    AssertIntNE(0, sz);

    /* Set ctx to DTLS 1.2 */
    ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method());
    AssertNotNull(ctx);

    ssl = wolfSSL_new(ctx);
    AssertNotNull(ssl);

    AssertIntGE(wolfSSL_dtls_import(ssl, buf, sz), 0);

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
    (void)userCtx;
    return 0;
}
#endif

/* returns negative value on fail and positive (including 0) on success */
static int nonblocking_accept_read(void* args, WOLFSSL* ssl, SOCKET_T* sockfd)
{
    int ret, err, loop_count, count, timeout = 10;
    char msg[] = "I hear you fa shizzle!";
    char input[1024];

    loop_count = ((func_args*)args)->argc;

    #ifdef WOLFSSL_ASYNC_CRYPT
    err = 0; /* Reset error */
    #endif
    do {
    #ifdef WOLFSSL_ASYNC_CRYPT
        if (err == WC_NO_ERR_TRACE(WC_PENDING_E)) {
            ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
            if (ret < 0) { break; } else if (ret == 0) { continue; }
        }
    #endif
        ret = wolfSSL_accept(ssl);
        err = wolfSSL_get_error(ssl, 0);

        if (err == WOLFSSL_ERROR_WANT_READ ||
            err == WOLFSSL_ERROR_WANT_WRITE) {
            int select_ret;

            err = WC_PENDING_E;
            select_ret = tcp_select(*sockfd, timeout);
            if (select_ret == TEST_TIMEOUT) {
                return WOLFSSL_FATAL_ERROR;
            }
        }
    } while (err == WC_NO_ERR_TRACE(WC_PENDING_E));
    if (ret != WOLFSSL_SUCCESS) {
        char buff[WOLFSSL_MAX_ERROR_SZ];
        fprintf(stderr, "error = %d, %s\n", err,
            wolfSSL_ERR_error_string(err, buff));
        return ret;
    }

    for (count = 0; count < loop_count; count++) {
        int select_ret;

        select_ret = tcp_select(*sockfd, timeout);
        if (select_ret == TEST_TIMEOUT) {
            ret = WOLFSSL_FATAL_ERROR;
            break;
        }

        do {
            ret = wolfSSL_read(ssl, input, sizeof(input)-1);
            if (ret > 0) {
                input[ret] = '\0';
                fprintf(stderr, "Client message: %s\n", input);
            }
        } while (err == WOLFSSL_ERROR_WANT_READ && ret != WOLFSSL_SUCCESS);

        do {
            if ((ret = wolfSSL_write(ssl, msg, sizeof(msg))) != sizeof(msg)) {
                return WOLFSSL_FATAL_ERROR;
            }
            err = wolfSSL_get_error(ssl, ret);
        } while (err == WOLFSSL_ERROR_WANT_READ && ret != WOLFSSL_SUCCESS);
    }
    return ret;
}
#endif /* WOLFSSL_SESSION_EXPORT */

THREAD_RETURN WOLFSSL_THREAD test_server_nofail(void* args)
{
    SOCKET_T sockfd = 0;
    SOCKET_T clientfd = 0;
    word16 port;

    callback_functions* cbf;
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;
    func_args* opts = (func_args*)args;

    char msg[] = "I hear you fa shizzle!";
    char input[1024];
    int idx;
    int ret, err = 0;
    int sharedCtx = 0;
    int doUdp = 0;
    SOCKADDR_IN_T cliAddr;
    socklen_t     cliLen;
    const char* certFile = svrCertFile;
    const char* keyFile = svrKeyFile;

#ifdef WOLFSSL_HAVE_TLS_UNIQUE
    size_t msg_len = 0;
#endif

    wolfSSL_SetLoggingPrefix("server");

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    opts->return_code = TEST_FAIL;
    cbf = opts->callbacks;

    if (cbf != NULL && cbf->ctx) {
        ctx = cbf->ctx;
        sharedCtx = 1;
    }
    else
    {
        WOLFSSL_METHOD* method = NULL;
        if (cbf != NULL && cbf->method != NULL) {
            method = cbf->method();

        }
        else {
            method = wolfSSLv23_server_method();
        }
        ctx = wolfSSL_CTX_new(method);
    }
    if (ctx == NULL) {
        /* Release the wait for TCP ready. */
        signal_ready(opts->signal);
        goto done;
    }

    if (cbf == NULL || !cbf->ticNoInit) {
#if defined(HAVE_SESSION_TICKET) && \
    ((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))
#if defined(OPENSSL_EXTRA) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
        OpenSSLTicketInit();
        wolfSSL_CTX_set_tlsext_ticket_key_cb(ctx, myTicketEncCbOpenSSL);
#elif defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
        TicketInit();
        wolfSSL_CTX_set_TicketEncCb(ctx, myTicketEncCb);
#endif
#endif
    }

#if defined(USE_WINDOWS_API)
    port = opts->signal->port;
#elif defined(NO_MAIN_DRIVER) && !defined(WOLFSSL_SNIFFER) && \
     !defined(WOLFSSL_MDK_SHELL) && !defined(WOLFSSL_TIRTOS)
    /* Let tcp_listen assign port */
    port = 0;
#else
    /* Use default port */
    port = wolfSSLPort;
#endif

    if (cbf != NULL)
        doUdp = cbf->doUdp;

    /* do it here to detect failure */
    tcp_accept(
        &sockfd, &clientfd, opts, port, 0, doUdp, 0, 0, 1, 0, 0);

    if (doUdp) {
        cliLen = sizeof(cliAddr);

        idx = (int)recvfrom(sockfd, input, sizeof(input), MSG_PEEK,
                  (struct sockaddr*)&cliAddr, &cliLen);

        AssertIntGT(idx, 0);
    }
    else {
        CloseSocket(sockfd);
    }

    wolfSSL_CTX_set_verify(ctx,
                  WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);

#ifdef WOLFSSL_ENCRYPTED_KEYS
    wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
#endif

    if (wolfSSL_CTX_load_verify_locations(ctx, cliCertFile, 0)
                                                           != WOLFSSL_SUCCESS) {
        /*err_sys("can't load ca file, Please run from wolfSSL home dir");*/
        goto done;
    }

    if (cbf != NULL && cbf->certPemFile != NULL)
        certFile = cbf->certPemFile;
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (!sharedCtx && wolfSSL_CTX_use_certificate_file(ctx, certFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#else
    if (wolfSSL_CTX_use_certificate_file(ctx, certFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#endif
        /*err_sys("can't load server cert chain file, "
                "Please run from wolfSSL home dir");*/
        goto done;
    }

    if (cbf != NULL && cbf->keyPemFile != NULL)
        keyFile = cbf->keyPemFile;
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (!sharedCtx && wolfSSL_CTX_use_PrivateKey_file(ctx, keyFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#else
    if (wolfSSL_CTX_use_PrivateKey_file(ctx, keyFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#endif
        /*err_sys("can't load server key file, "
                "Please run from wolfSSL home dir");*/
        goto done;
    }

#ifdef HAVE_CRL
    if (cbf != NULL && cbf->crlPemFile != NULL) {
        if (wolfSSL_CTX_EnableCRL(ctx, WOLFSSL_CRL_CHECKALL) != WOLFSSL_SUCCESS)
            goto done;
        if (wolfSSL_CTX_LoadCRLFile(ctx, cbf->crlPemFile, CERT_FILETYPE)
                != WOLFSSL_SUCCESS)
            goto done;
    }
#endif

    /* call ctx setup callback */
    if (cbf != NULL && cbf->ctx_ready != NULL) {
        cbf->ctx_ready(ctx);
    }

    ssl = wolfSSL_new(ctx);
    if (ssl == NULL) {
        goto done;
    }

    if (doUdp) {
        err = wolfSSL_dtls_set_peer(ssl, &cliAddr, cliLen);
        if (err != WOLFSSL_SUCCESS)
            goto done;
    }

#ifdef WOLFSSL_SESSION_EXPORT
    /* only add in more complex nonblocking case with session export tests */
    if (args && opts->argc > 0) {
        /* set as nonblock and time out for waiting on read/write */
        tcp_set_nonblocking(&clientfd);
        wolfSSL_dtls_set_using_nonblock(ssl, 1);
    }
#endif
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (sharedCtx && wolfSSL_use_certificate_file(ssl, certFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#else
    if (wolfSSL_use_certificate_file(ssl, certFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#endif
        /*err_sys("can't load server cert chain file, "
                "Please run from wolfSSL home dir");*/
        goto done;
    }
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (sharedCtx && wolfSSL_use_PrivateKey_file(ssl, keyFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#else
    if (wolfSSL_use_PrivateKey_file(ssl, keyFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#endif
        /*err_sys("can't load server key file, "
                "Please run from wolfSSL home dir");*/
        goto done;
    }

    if (wolfSSL_set_fd(ssl, clientfd) != WOLFSSL_SUCCESS) {
        /*err_sys("SSL_set_fd failed");*/
        goto done;
    }

#if !defined(NO_FILESYSTEM) && !defined(NO_DH)
    wolfSSL_SetTmpDH_file(ssl, dhParamFile, CERT_FILETYPE);
#elif !defined(NO_DH)
    SetDH(ssl);  /* will repick suites with DHE, higher priority than PSK */
#endif

    /* call ssl setup callback */
    if (cbf != NULL && cbf->ssl_ready != NULL) {
        cbf->ssl_ready(ssl);
    }

#ifdef WOLFSSL_SESSION_EXPORT
    /* only add in more complex nonblocking case with session export tests */
    if (opts->argc > 0) {
        ret = nonblocking_accept_read(args, ssl, &clientfd);
        if (ret >= 0) {
            opts->return_code = TEST_SUCCESS;
        }
    #ifdef WOLFSSL_TIRTOS
        Task_yield();
    #endif
        goto done;
    }
#endif

    WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_negotiate(ssl),
                                ret != WOLFSSL_SUCCESS);
    if (ret != WOLFSSL_SUCCESS) {
        char buff[WOLFSSL_MAX_ERROR_SZ];
        fprintf(stderr, "error = %d, %s\n", err,
            wolfSSL_ERR_error_string((word32)err, buff));
        /*err_sys("SSL_accept failed");*/
        goto done;
    }

#ifdef WOLFSSL_HAVE_TLS_UNIQUE
    XMEMSET(server_side_msg2, 0, WC_MAX_DIGEST_SIZE);
    msg_len = wolfSSL_get_peer_finished(ssl, server_side_msg2, WC_MAX_DIGEST_SIZE);
    AssertIntGE(msg_len, 0);

    XMEMSET(server_side_msg1, 0, WC_MAX_DIGEST_SIZE);
    msg_len = wolfSSL_get_finished(ssl, server_side_msg1, WC_MAX_DIGEST_SIZE);
    AssertIntGE(msg_len, 0);
#endif /* WOLFSSL_HAVE_TLS_UNIQUE */

    idx = wolfSSL_read(ssl, input, sizeof(input)-1);
    if (idx > 0) {
        input[idx] = '\0';
        fprintf(stderr, "Client message: %s\n", input);
    }
    else if (idx < 0) {
        goto done;
    }

    if (wolfSSL_write(ssl, msg, sizeof(msg)) != sizeof(msg)) {
        /*err_sys("SSL_write failed");*/
        goto done;
    }

    if (cbf != NULL && cbf->on_result != NULL)
        cbf->on_result(ssl);

#ifdef WOLFSSL_TIRTOS
    Task_yield();
#endif

    opts->return_code = TEST_SUCCESS;

done:
    if (cbf != NULL)
        cbf->last_err = err;
    if (cbf != NULL && cbf->on_cleanup != NULL)
        cbf->on_cleanup(ssl);

    wolfSSL_shutdown(ssl);
    wolfSSL_free(ssl);
    if (!sharedCtx)
        wolfSSL_CTX_free(ctx);

    CloseSocket(clientfd);

#ifdef WOLFSSL_TIRTOS
    fdCloseSession(Task_self());
#endif

#if defined(NO_MAIN_DRIVER) && defined(HAVE_ECC) && defined(FP_ECC) \
                            && defined(HAVE_THREAD_LS)
    wc_ecc_fp_free();  /* free per thread cache */
#endif

    if (cbf == NULL || !cbf->ticNoInit) {
#if defined(HAVE_SESSION_TICKET) && \
    ((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))
#if defined(OPENSSL_EXTRA) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
        OpenSSLTicketCleanup();
#elif defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
        TicketCleanup();
#endif
#endif
    }

    wolfSSL_SetLoggingPrefix(NULL);

    WOLFSSL_RETURN_FROM_THREAD(0);
}

#if defined(OPENSSL_EXTRA) && !defined(NO_SESSION_CACHE) && \
    !defined(WOLFSSL_NO_TLS12)
static THREAD_RETURN WOLFSSL_THREAD test_server_loop(void* args)
{
    SOCKET_T sockfd;
    SOCKET_T clientfd = -1;
    word16 port;

    callback_functions* cbf;
    WOLFSSL_CTX* ctx = 0;
    WOLFSSL* ssl = 0;

    char msg[] = "I hear you fa shizzle!";
    char input[1024];
    int idx;
    int ret, err = 0;
    int sharedCtx = 0;
    func_args* opts = (func_args*)args;
    int loop_count = opts->argc;
    int count = 0;

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    opts->return_code = TEST_FAIL;
    cbf = opts->callbacks;

#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (cbf != NULL && cbf->ctx) {
        ctx = cbf->ctx;
        sharedCtx = 1;
    }
    else
#endif
    {
        WOLFSSL_METHOD* method = NULL;
        if (cbf != NULL && cbf->method != NULL) {
            method = cbf->method();
        }
        else {
            method = wolfSSLv23_server_method();
        }
        ctx = wolfSSL_CTX_new(method);
    }

#if defined(USE_WINDOWS_API)
    port = opts->signal->port;
#elif defined(NO_MAIN_DRIVER) && !defined(WOLFSSL_SNIFFER) && \
     !defined(WOLFSSL_MDK_SHELL) && !defined(WOLFSSL_TIRTOS)
    /* Let tcp_listen assign port */
    port = 0;
#else
    /* Use default port */
    port = wolfSSLPort;
#endif

    wolfSSL_CTX_set_verify(ctx,
                  WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);

#ifdef WOLFSSL_ENCRYPTED_KEYS
    wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
#endif

    if (wolfSSL_CTX_load_verify_locations(ctx, cliCertFile, 0)
                                                           != WOLFSSL_SUCCESS) {
        /*err_sys("can't load ca file, Please run from wolfSSL home dir");*/
        /* Release the wait for TCP ready. */
        signal_ready(opts->signal);
        goto done;
    }
    if (!sharedCtx && wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
        /*err_sys("can't load server cert chain file, "
                "Please run from wolfSSL home dir");*/
        /* Release the wait for TCP ready. */
        signal_ready(opts->signal);
        goto done;
    }
    if (!sharedCtx && wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
        /*err_sys("can't load server key file, "
                "Please run from wolfSSL home dir");*/
        /* Release the wait for TCP ready. */
        signal_ready(opts->signal);
        goto done;
    }
    /* call ctx setup callback */
    if (cbf != NULL && cbf->ctx_ready != NULL) {
        cbf->ctx_ready(ctx);
    }

    while (count != loop_count) {
        ssl = wolfSSL_new(ctx);
        if (ssl == NULL) {
            signal_ready(opts->signal);
            goto done;
        }
        if (sharedCtx && wolfSSL_use_certificate_file(ssl, svrCertFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
            /*err_sys("can't load server cert chain file, "
                    "Please run from wolfSSL home dir");*/
            /* Release the wait for TCP ready. */
            signal_ready(opts->signal);
            goto done;
        }
        if (sharedCtx && wolfSSL_use_PrivateKey_file(ssl, svrKeyFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
            /*err_sys("can't load server key file, "
                    "Please run from wolfSSL home dir");*/
            /* Release the wait for TCP ready. */
            signal_ready(opts->signal);
            goto done;
        }

#if !defined(NO_FILESYSTEM) && !defined(NO_DH)
        wolfSSL_SetTmpDH_file(ssl, dhParamFile, CERT_FILETYPE);
#elif !defined(NO_DH)
        SetDH(ssl);  /* will repick suites with DHE, higher priority than PSK */
#endif
        /* call ssl setup callback */
        if (cbf != NULL && cbf->ssl_ready != NULL) {
            cbf->ssl_ready(ssl);
        }
        /* do it here to detect failure */
        tcp_accept(&sockfd, &clientfd, (func_args*)args, port, 0, 0, 0, 0, 1, 0,
            0);
        CloseSocket(sockfd);
        if (wolfSSL_set_fd(ssl, clientfd) != WOLFSSL_SUCCESS) {
            /*err_sys("SSL_set_fd failed");*/
            goto done;
        }

        WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_accept(ssl),
                                    ret != WOLFSSL_SUCCESS);
        if (ret != WOLFSSL_SUCCESS) {
            char buff[WOLFSSL_MAX_ERROR_SZ];
            fprintf(stderr, "error = %d, %s\n", err,
                wolfSSL_ERR_error_string(err, buff));
            /*err_sys("SSL_accept failed");*/
            goto done;
        }

        idx = wolfSSL_read(ssl, input, sizeof(input)-1);
        if (idx > 0) {
            input[idx] = '\0';
            fprintf(stderr, "Client message: %s\n", input);
        }

        if (wolfSSL_write(ssl, msg, sizeof(msg)) != sizeof(msg)) {
            /*err_sys("SSL_write failed");*/
            goto done;
        }
        /* free ssl for this connection */
        wolfSSL_shutdown(ssl);
        wolfSSL_free(ssl); ssl = NULL;
        CloseSocket(clientfd);
        clientfd = -1;

        count++;
    }
#ifdef WOLFSSL_TIRTOS
    Task_yield();
#endif

    opts->return_code = TEST_SUCCESS;

done:
    if (ssl != NULL) {
        wolfSSL_shutdown(ssl);
        wolfSSL_free(ssl);
    }
    if (!sharedCtx)
        wolfSSL_CTX_free(ctx);

    if (clientfd != SOCKET_INVALID)
        CloseSocket(clientfd);

#ifdef WOLFSSL_TIRTOS
    fdCloseSession(Task_self());
#endif

#if defined(NO_MAIN_DRIVER) && defined(HAVE_ECC) && defined(FP_ECC) \
                            && defined(HAVE_THREAD_LS)
    wc_ecc_fp_free();  /* free per thread cache */
#endif

    WOLFSSL_RETURN_FROM_THREAD(0);
}
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_SESSION_CACHE) && !defined(WOLFSSL_TLS13) */

int test_client_nofail(void* args, cbType cb)
{
#if !defined(NO_WOLFSSL_CLIENT)
    SOCKET_T sockfd = 0;
    callback_functions* cbf;

    WOLFSSL_CTX*     ctx     = 0;
    WOLFSSL*         ssl     = 0;
    WOLFSSL_CIPHER*  cipher;

    char msg[64] = "hello wolfssl!";
    char reply[1024];
    int  input;
    int  msgSz = (int)XSTRLEN(msg);
    int  ret, err = 0;
    int  cipherSuite;
    int  sharedCtx = 0;
    int  doUdp = 0;
    const char* cipherName1, *cipherName2;

    wolfSSL_SetLoggingPrefix("client");

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    ((func_args*)args)->return_code = TEST_FAIL;
    cbf = ((func_args*)args)->callbacks;

#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (cbf != NULL && cbf->ctx) {
        ctx = cbf->ctx;
        sharedCtx = cbf->isSharedCtx;
    }
    else
#endif
    {
        WOLFSSL_METHOD* method  = NULL;
        if (cbf != NULL && cbf->method != NULL) {
            method = cbf->method();
        }
        else {
            method = wolfSSLv23_client_method();
        }
        ctx = wolfSSL_CTX_new(method);
    }

    if (cbf != NULL)
        doUdp = cbf->doUdp;

#ifdef WOLFSSL_ENCRYPTED_KEYS
    wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
#endif

    /* Do connect here so server detects failures */
    tcp_connect(&sockfd, wolfSSLIP, ((func_args*)args)->signal->port,
                doUdp, 0, NULL);
    /* Connect the socket so that we don't have to set the peer later on */
    if (doUdp)
        udp_connect(&sockfd, wolfSSLIP, ((func_args*)args)->signal->port);

    if (wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0) != WOLFSSL_SUCCESS)
    {
        /* err_sys("can't load ca file, Please run from wolfSSL home dir");*/
        goto done;
    }
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (!sharedCtx && wolfSSL_CTX_use_certificate_file(ctx, cliCertFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#else
    if (wolfSSL_CTX_use_certificate_file(ctx, cliCertFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#endif
        /*err_sys("can't load client cert file, "
                "Please run from wolfSSL home dir");*/
        goto done;
    }
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (!sharedCtx && wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#else
    if (wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#endif

        /*err_sys("can't load client key file, "
                "Please run from wolfSSL home dir");*/
        goto done;
    }

#ifdef WOLFSSL_SRTP
    /* make sure that NULL (error condition) returns 1 */
    if (wolfSSL_CTX_set_tlsext_use_srtp(ctx, NULL) != 1) {
         goto done;
    }
#endif

#ifdef HAVE_CRL
    if (cbf != NULL && cbf->crlPemFile != NULL) {
        if (wolfSSL_CTX_EnableCRL(ctx, WOLFSSL_CRL_CHECKALL) != WOLFSSL_SUCCESS)
            goto done;
        if (wolfSSL_CTX_LoadCRLFile(ctx, cbf->crlPemFile, CERT_FILETYPE)
                != WOLFSSL_SUCCESS)
            goto done;
    }
#endif

    /* call ctx setup callback */
    if (cbf != NULL && cbf->ctx_ready != NULL) {
        cbf->ctx_ready(ctx);
    }

    ssl = wolfSSL_new(ctx);
    if (ssl == NULL) {
        goto done;
    }
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (sharedCtx && wolfSSL_use_certificate_file(ssl, cliCertFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#else
    if (wolfSSL_use_certificate_file(ssl, cliCertFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#endif
        /*err_sys("can't load client cert file, "
                "Please run from wolfSSL home dir");*/
        goto done;
    }
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (sharedCtx && wolfSSL_use_PrivateKey_file(ssl, cliKeyFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#else
    if (wolfSSL_use_PrivateKey_file(ssl, cliKeyFile,
                                     CERT_FILETYPE) != WOLFSSL_SUCCESS) {
#endif
        /*err_sys("can't load client key file, "
                "Please run from wolfSSL home dir");*/
        goto done;
    }

#ifdef WOLFSSL_SRTP
    /* make sure that NULL (error condition) returns 1 */
    if (wolfSSL_set_tlsext_use_srtp(ssl, NULL) != 1) {
         goto done;
    }
#endif

    if (!doUdp) {
        if (wolfSSL_set_fd(ssl, sockfd) != WOLFSSL_SUCCESS) {
            /*err_sys("SSL_set_fd failed");*/
            goto done;
        }
    }
    else {
#ifdef WOLFSSL_DTLS
        if (wolfSSL_set_dtls_fd_connected(ssl, sockfd) != WOLFSSL_SUCCESS) {
            /*err_sys("SSL_set_fd failed");*/
            goto done;
        }
#else
        goto done;
#endif
    }

    /* call ssl setup callback */
    if (cbf != NULL && cbf->ssl_ready != NULL) {
        cbf->ssl_ready(ssl);
    }

    WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_negotiate(ssl),
                                ret != WOLFSSL_SUCCESS);
    if (ret != WOLFSSL_SUCCESS) {
        char buff[WOLFSSL_MAX_ERROR_SZ];
        fprintf(stderr, "error = %d, %s\n", err,
            wolfSSL_ERR_error_string((word32)err, buff));
        /*err_sys("SSL_connect failed");*/
        goto done;
    }

    /* test the various get cipher methods */
    /* Internal cipher suite names */
    cipherSuite = wolfSSL_get_current_cipher_suite(ssl);
    cipherName1 = wolfSSL_get_cipher_name(ssl);
    cipherName2 = wolfSSL_get_cipher_name_from_suite(
        (byte)(cipherSuite >> 8), cipherSuite & 0xFF);
    AssertStrEQ(cipherName1, cipherName2);

    /* IANA Cipher Suites Names */
    /* Unless WOLFSSL_CIPHER_INTERNALNAME or NO_ERROR_STRINGS,
        then it's the internal cipher suite name */
    cipher = wolfSSL_get_current_cipher(ssl);
    cipherName1 = wolfSSL_CIPHER_get_name(cipher);
    cipherName2 = wolfSSL_get_cipher(ssl);
    AssertStrEQ(cipherName1, cipherName2);
#if !defined(WOLFSSL_CIPHER_INTERNALNAME) && !defined(NO_ERROR_STRINGS) && \
    !defined(WOLFSSL_QT)
    cipherName1 = wolfSSL_get_cipher_name_iana_from_suite(
            (byte)(cipherSuite >> 8), cipherSuite & 0xFF);
    AssertStrEQ(cipherName1, cipherName2);
#endif

    if (cb != NULL)
        (cb)(ctx, ssl);

    if (wolfSSL_write(ssl, msg, msgSz) != msgSz) {
        /*err_sys("SSL_write failed");*/
        goto done;
    }

    input = wolfSSL_read(ssl, reply, sizeof(reply)-1);
    if (input > 0) {
        reply[input] = '\0';
        fprintf(stderr, "Server response: %s\n", reply);
    }

    if (cbf != NULL && cbf->on_result != NULL)
        cbf->on_result(ssl);

    ((func_args*)args)->return_code = TEST_SUCCESS;

done:
    if (cbf != NULL)
        cbf->last_err = err;
    if (cbf != NULL && cbf->on_cleanup != NULL)
        cbf->on_cleanup(ssl);

    wolfSSL_free(ssl);
    if (!sharedCtx)
        wolfSSL_CTX_free(ctx);

    CloseSocket(sockfd);

#ifdef WOLFSSL_TIRTOS
    fdCloseSession(Task_self());
#endif

#if defined(NO_MAIN_DRIVER) && defined(HAVE_ECC) && defined(FP_ECC) \
                            && defined(HAVE_THREAD_LS)
    wc_ecc_fp_free();  /* free per thread cache */
#endif

#else
    (void)args;
    (void)cb;
#endif /* !NO_WOLFSSL_CLIENT */

    wolfSSL_SetLoggingPrefix(NULL);

    return 0;
}

void test_wolfSSL_client_server_nofail_ex(callback_functions* client_cb,
    callback_functions* server_cb, cbType client_on_handshake)
{
    func_args client_args;
    func_args server_args;
    tcp_ready ready;
    THREAD_TYPE serverThread;

    XMEMSET(&client_args, 0, sizeof(func_args));
    XMEMSET(&server_args, 0, sizeof(func_args));

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    StartTCP();
    InitTcpReady(&ready);

    server_args.signal = &ready;
    server_args.callbacks = server_cb;
    client_args.signal = &ready;
    client_args.callbacks = client_cb;

    start_thread(test_server_nofail, &server_args, &serverThread);
    wait_tcp_ready(&server_args);
    test_client_nofail(&client_args, client_on_handshake);
    join_thread(serverThread);

    client_cb->return_code = client_args.return_code;
    server_cb->return_code = server_args.return_code;

    FreeTcpReady(&ready);

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif
}

void test_wolfSSL_client_server_nofail(callback_functions* client_cb,
    callback_functions* server_cb)
{
    test_wolfSSL_client_server_nofail_ex(client_cb, server_cb, NULL);
}


#if defined(OPENSSL_EXTRA) && !defined(NO_SESSION_CACHE) && \
   !defined(WOLFSSL_NO_TLS12) && !defined(NO_WOLFSSL_CLIENT)
static void test_client_reuse_WOLFSSLobj(void* args, cbType cb,
                                         void* server_args)
{
    SOCKET_T sockfd = 0;
    callback_functions* cbf;

    WOLFSSL_CTX*     ctx     = 0;
    WOLFSSL*         ssl     = 0;
    WOLFSSL_SESSION* session = NULL;

    char msg[64] = "hello wolfssl!";
    char reply[1024];
    int  input;
    int  msgSz = (int)XSTRLEN(msg);
    int  ret, err = 0;
    int  sharedCtx = 0;

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    ((func_args*)args)->return_code = TEST_FAIL;
    cbf = ((func_args*)args)->callbacks;

#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
    if (cbf != NULL && cbf->ctx) {
        ctx = cbf->ctx;
        sharedCtx = 1;
    }
    else
#endif
    {
        WOLFSSL_METHOD* method  = NULL;
        if (cbf != NULL && cbf->method != NULL) {
            method = cbf->method();
        }
        else {
            method = wolfSSLv23_client_method();
        }
        ctx = wolfSSL_CTX_new(method);
    }

#ifdef WOLFSSL_ENCRYPTED_KEYS
    wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
#endif

    /* Do connect here so server detects failures */
    tcp_connect(&sockfd, wolfSSLIP, ((func_args*)args)->signal->port,
                0, 0, NULL);

    if (wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0) !=
                                                              WOLFSSL_SUCCESS) {
        /* err_sys("can't load ca file, Please run from wolfSSL home dir");*/
        goto done;
    }
    if (!sharedCtx && wolfSSL_CTX_use_certificate_file(ctx, cliCertFile,
                                     WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS) {
        /*err_sys("can't load client cert file, "
                "Please run from wolfSSL home dir");*/
        goto done;
    }
    if (!sharedCtx && wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile,
                                     WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS) {
        /*err_sys("can't load client key file, "
                "Please run from wolfSSL home dir");*/
        goto done;
    }

    /* call ctx setup callback */
    if (cbf != NULL && cbf->ctx_ready != NULL) {
        cbf->ctx_ready(ctx);
    }

    ssl = wolfSSL_new(ctx);
    if (ssl == NULL) {
        goto done;
    }
    /* keep handshake resources for reusing WOLFSSL obj */
    wolfSSL_KeepArrays(ssl);
    if (wolfSSL_KeepHandshakeResources(ssl)) {
        /* err_sys("SSL_KeepHandshakeResources failed"); */
        goto done;
    }
    if (sharedCtx && wolfSSL_use_certificate_file(ssl, cliCertFile,
                                     WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS) {
        /*err_sys("can't load client cert file, "
                "Please run from wolfSSL home dir");*/
        goto done;
    }
    if (sharedCtx && wolfSSL_use_PrivateKey_file(ssl, cliKeyFile,
                                     WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS) {
        /*err_sys("can't load client key file, "
                "Please run from wolfSSL home dir");*/
        goto done;
    }

    if (wolfSSL_set_fd(ssl, sockfd) != WOLFSSL_SUCCESS) {
        /*err_sys("SSL_set_fd failed");*/
        goto done;
    }

    /* call ssl setup callback */
    if (cbf != NULL && cbf->ssl_ready != NULL) {
        cbf->ssl_ready(ssl);
    }

    WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_connect(ssl),
                                ret != WOLFSSL_SUCCESS);
    if (ret != WOLFSSL_SUCCESS) {
        char buff[WOLFSSL_MAX_ERROR_SZ];
        fprintf(stderr, "error = %d, %s\n", err,
            wolfSSL_ERR_error_string(err, buff));
        /*err_sys("SSL_connect failed");*/
        goto done;
    }
    /* Build first session */
    if (cb != NULL)
        cb(ctx, ssl);

    if (wolfSSL_write(ssl, msg, msgSz) != msgSz) {
        /*err_sys("SSL_write failed");*/
        goto done;
    }

    input = wolfSSL_read(ssl, reply, sizeof(reply)-1);
    if (input > 0) {
        reply[input] = '\0';
        fprintf(stderr, "Server response: %s\n", reply);
    }

    /* Session Resumption by reusing WOLFSSL object */
    wolfSSL_set_quiet_shutdown(ssl, 1);
    if (wolfSSL_shutdown(ssl) != WOLFSSL_SUCCESS) {
        /* err_sys ("SSL shutdown failed"); */
        goto done;
    }
    session = wolfSSL_get1_session(ssl);
    if (wolfSSL_clear(ssl) != WOLFSSL_SUCCESS) {
        wolfSSL_SESSION_free(session);
        /* err_sys ("SSL_clear failed"); */
        goto done;
    }
    wolfSSL_set_session(ssl, session);
    wolfSSL_SESSION_free(session);
    session = NULL;
    /* close socket once */
    CloseSocket(sockfd);
    sockfd = 0;
    /* wait until server ready */
    wait_tcp_ready((func_args*)server_args);
    fprintf(stderr, "session resumption\n");
    /* Do re-connect  */
    tcp_connect(&sockfd, wolfSSLIP, ((func_args*)args)->signal->port,
                0, 0, NULL);
    if (wolfSSL_set_fd(ssl, sockfd) != WOLFSSL_SUCCESS) {
        /*err_sys("SSL_set_fd failed");*/
        goto done;
    }

    WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_connect(ssl),
                                ret != WOLFSSL_SUCCESS);
    if (ret != WOLFSSL_SUCCESS) {
        char buff[WOLFSSL_MAX_ERROR_SZ];
        fprintf(stderr, "error = %d, %s\n", err,
            wolfSSL_ERR_error_string(err, buff));
        /*err_sys("SSL_connect failed");*/
        goto done;
    }
    /* Build first session */
    if (cb != NULL)
        cb(ctx, ssl);

    if (wolfSSL_write(ssl, msg, msgSz) != msgSz) {
        /*err_sys("SSL_write failed");*/
        goto done;
    }

    input = wolfSSL_read(ssl, reply, sizeof(reply)-1);
    if (input > 0) {
        reply[input] = '\0';
        fprintf(stderr, "Server response: %s\n", reply);
    }

    ((func_args*)args)->return_code = TEST_SUCCESS;

done:
    wolfSSL_free(ssl);
    if (!sharedCtx)
        wolfSSL_CTX_free(ctx);

    CloseSocket(sockfd);

#ifdef WOLFSSL_TIRTOS
    fdCloseSession(Task_self());
#endif

    return;
}
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_SESSION_CACHE) &&
         !defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT) */

#if (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
     defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY)) && \
    defined(HAVE_ALPN) && defined(HAVE_SNI) && \
    defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(NO_BIO)
    #define HAVE_ALPN_PROTOS_SUPPORT
#endif

/* Generic TLS client / server with callbacks for API unit tests
 * Used by SNI / ALPN / crypto callback helper functions */
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && \
    (defined(HAVE_SNI) || defined(HAVE_ALPN) || \
     (defined(WOLF_CRYPTO_CB) && \
      !defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \
      !defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES)) || \
     defined(HAVE_ALPN_PROTOS_SUPPORT)) || defined(WOLFSSL_STATIC_MEMORY)
    #define ENABLE_TLS_CALLBACK_TEST
#endif

#if defined(ENABLE_TLS_CALLBACK_TEST) || \
    (defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT))
/* TLS server for API unit testing - generic */
static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args)
{
    callback_functions* callbacks = ((func_args*)args)->callbacks;

    WOLFSSL_CTX*    ctx = NULL;
    WOLFSSL*        ssl = NULL;
    SOCKET_T        sfd = 0;
    SOCKET_T        cfd = 0;
    word16          port;

    char msg[] = "I hear you fa shizzle!";
    int  len   = (int) XSTRLEN(msg);
    char input[1024];
    int  idx;
    int  ret, err = 0;

    ((func_args*)args)->return_code = TEST_FAIL;

#if defined(USE_WINDOWS_API)
    port = ((func_args*)args)->signal->port;
#elif defined(NO_MAIN_DRIVER) && !defined(WOLFSSL_SNIFFER) && \
     !defined(WOLFSSL_MDK_SHELL) && !defined(WOLFSSL_TIRTOS)
    /* Let tcp_listen assign port */
    port = 0;
#else
    /* Use default port */
    port = wolfSSLPort;
#endif

#ifdef WOLFSSL_DTLS
    if (callbacks->method == wolfDTLS_server_method
#ifdef WOLFSSL_STATIC_MEMORY
     || callbacks->method_ex == wolfDTLS_server_method_ex
#endif
#ifndef NO_OLD_TLS
     || callbacks->method == wolfDTLSv1_server_method
#ifdef WOLFSSL_STATIC_MEMORY
     || callbacks->method_ex == wolfDTLSv1_server_method_ex
#endif
#endif
#ifndef WOLFSSL_NO_TLS12
     || callbacks->method == wolfDTLSv1_2_server_method
#ifdef WOLFSSL_STATIC_MEMORY
     || callbacks->method_ex == wolfDTLSv1_2_server_method_ex
#endif
#endif
#ifdef WOLFSSL_DTLS13
     || callbacks->method == wolfDTLSv1_3_server_method
#ifdef WOLFSSL_STATIC_MEMORY
     || callbacks->method_ex == wolfDTLSv1_3_server_method_ex
#endif
#endif
        ) {
        tcp_accept(&sfd, &cfd, (func_args*)args, port, 0, 1, 0, 0, 0, 0, 0);
    }
    else
#endif
    {
        tcp_accept(&sfd, &cfd, (func_args*)args, port, 0, 0, 0, 0, 1, 0, 0);
    }

#ifdef WOLFSSL_STATIC_MEMORY
    if (callbacks->method_ex != NULL && callbacks->mem != NULL &&
        callbacks->memSz > 0) {
        ret = wolfSSL_CTX_load_static_memory(&ctx, callbacks->method_ex,
            callbacks->mem, callbacks->memSz, 0, 1);
        if (ret != WOLFSSL_SUCCESS) {
            fprintf(stderr, "CTX static new failed %d\n", ret);
            goto cleanup;
        }
    }
#else
    ctx = wolfSSL_CTX_new(callbacks->method());
#endif
    if (ctx == NULL) {
        fprintf(stderr, "CTX new failed\n");
        goto cleanup;
    }

    /* set defaults */
    if (callbacks->caPemFile == NULL)
        callbacks->caPemFile = cliCertFile;
    if (callbacks->certPemFile == NULL)
        callbacks->certPemFile = svrCertFile;
    if (callbacks->keyPemFile == NULL)
        callbacks->keyPemFile = svrKeyFile;

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    wolfSSL_CTX_SetDevId(ctx, callbacks->devId);

    wolfSSL_CTX_set_verify(ctx,
                  WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);

#ifdef WOLFSSL_ENCRYPTED_KEYS
    wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
#endif
#if defined(WOLFSSL_SESSION_EXPORT) && defined(WOLFSSL_DTLS)
    if (callbacks->method == wolfDTLSv1_2_server_method) {
        if (wolfSSL_CTX_dtls_set_export(ctx, test_export) != WOLFSSL_SUCCESS)
            goto cleanup;
    }
#endif


    if (wolfSSL_CTX_load_verify_locations(ctx, callbacks->caPemFile, 0) !=
            WOLFSSL_SUCCESS) {
        goto cleanup;
    }

    if (wolfSSL_CTX_use_certificate_file(ctx, callbacks->certPemFile,
            CERT_FILETYPE) != WOLFSSL_SUCCESS) {
        goto cleanup;
    }

    if (wolfSSL_CTX_use_PrivateKey_file(ctx, callbacks->keyPemFile,
            CERT_FILETYPE) != WOLFSSL_SUCCESS) {
        goto cleanup;
    }

#ifdef HAVE_CRL
    if (callbacks->crlPemFile != NULL) {
        if (wolfSSL_CTX_LoadCRLFile(ctx, callbacks->crlPemFile,
                CERT_FILETYPE) != WOLFSSL_SUCCESS) {
            goto cleanup;
        }
    }
#endif

    if (callbacks->ctx_ready)
        callbacks->ctx_ready(ctx);

    ssl = wolfSSL_new(ctx);
    if (ssl == NULL) {
        fprintf(stderr, "SSL new failed\n");
        goto cleanup;
    }
    if (wolfSSL_dtls(ssl)) {
        SOCKADDR_IN_T cliAddr;
        socklen_t     cliLen;

        cliLen = sizeof(cliAddr);
        idx = (int)recvfrom(sfd, input, sizeof(input), MSG_PEEK,
                (struct sockaddr*)&cliAddr, &cliLen);
        if (idx <= 0) {
            goto cleanup;
        }
        wolfSSL_dtls_set_peer(ssl, &cliAddr, cliLen);
    }
    else {
        CloseSocket(sfd);
    }

    if (wolfSSL_set_fd(ssl, cfd) != WOLFSSL_SUCCESS) {
        goto cleanup;
    }

    if (callbacks->loadToSSL) {
        wolfSSL_SetDevId(ssl, callbacks->devId);

        if (wolfSSL_use_certificate_file(ssl, callbacks->certPemFile,
                CERT_FILETYPE) != WOLFSSL_SUCCESS) {
            goto cleanup;
        }

        if (wolfSSL_use_PrivateKey_file(ssl, callbacks->keyPemFile,
                CERT_FILETYPE) != WOLFSSL_SUCCESS) {
            goto cleanup;
        }
    }

#ifdef NO_PSK
    #if !defined(NO_FILESYSTEM) && !defined(NO_DH)
        wolfSSL_SetTmpDH_file(ssl, dhParamFile, CERT_FILETYPE);
    #elif !defined(NO_DH)
        SetDH(ssl);  /* will repick suites with DHE, higher priority than PSK */
    #endif
#endif

    if (callbacks->ssl_ready)
        callbacks->ssl_ready(ssl);

    WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_accept(ssl),
                                ret != WOLFSSL_SUCCESS);
    if (ret != WOLFSSL_SUCCESS) {
        char buff[WOLFSSL_MAX_ERROR_SZ];
        fprintf(stderr, "accept error = %d, %s\n", err,
            wolfSSL_ERR_error_string((word32)err, buff));
        /*err_sys("SSL_accept failed");*/
    }
    else {
        WOLFSSL_ASYNC_WHILE_PENDING(idx = wolfSSL_read(ssl, input, sizeof(input)-1),
                                    idx <= 0);
        if (idx > 0) {
            input[idx] = 0;
            fprintf(stderr, "Client message: %s\n", input);
        }

        WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_write(ssl, msg, len),
                                    len != ret);
        if (len != ret) {
            goto cleanup;
        }

#if defined(WOLFSSL_SESSION_EXPORT) && !defined(HAVE_IO_POOL) && \
        defined(WOLFSSL_DTLS)
        if (wolfSSL_dtls(ssl)) {
            byte*  import;
            word32 sz;

            wolfSSL_dtls_export(ssl, NULL, &sz);
            import = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
            if (import == NULL) {
                goto cleanup;
            }
            idx = wolfSSL_dtls_export(ssl, import, &sz);
            if (idx < 0) {
                goto cleanup;
            }
            if (wolfSSL_dtls_import(ssl, import, idx) < 0) {
                goto cleanup;
            }
            XFREE(import, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        }
#endif
#ifdef WOLFSSL_TIRTOS
        Task_yield();
#endif
        ((func_args*)args)->return_code = TEST_SUCCESS;
    }

    if (callbacks->on_result)
        callbacks->on_result(ssl);

    wolfSSL_shutdown(ssl);

cleanup:
    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
    CloseSocket(cfd);


#ifdef WOLFSSL_TIRTOS
    fdCloseSession(Task_self());
#endif

#if defined(NO_MAIN_DRIVER) && defined(HAVE_ECC) && defined(FP_ECC) \
                            && defined(HAVE_THREAD_LS)
    wc_ecc_fp_free();  /* free per thread cache */
#endif

    WOLFSSL_RETURN_FROM_THREAD(0);
}

/* TLS Client for API unit testing - generic */
static void run_wolfssl_client(void* args)
{
    callback_functions* callbacks = ((func_args*)args)->callbacks;

    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL*     ssl = NULL;
    SOCKET_T    sfd = 0;

    char msg[] = "hello wolfssl server!";
    int  len   = (int) XSTRLEN(msg);
    char input[1024];
    int  ret, err = 0;

    ((func_args*)args)->return_code = TEST_FAIL;

    /* set defaults */
    if (callbacks->caPemFile == NULL)
        callbacks->caPemFile = caCertFile;
    if (callbacks->certPemFile == NULL)
        callbacks->certPemFile = cliCertFile;
    if (callbacks->keyPemFile == NULL)
        callbacks->keyPemFile = cliKeyFile;

#ifdef WOLFSSL_STATIC_MEMORY
    if (callbacks->method_ex != NULL && callbacks->mem != NULL &&
        callbacks->memSz > 0) {
        ret = wolfSSL_CTX_load_static_memory(&ctx, callbacks->method_ex,
            callbacks->mem, callbacks->memSz, 0, 1);
        if (ret != WOLFSSL_SUCCESS) {
            fprintf(stderr, "CTX static new failed %d\n", ret);
            goto cleanup;
        }
    }
#else
    ctx = wolfSSL_CTX_new(callbacks->method());
#endif
    if (ctx == NULL) {
        fprintf(stderr, "CTX new failed\n");
        goto cleanup;
    }

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    if (!callbacks->loadToSSL) {
        wolfSSL_CTX_SetDevId(ctx, callbacks->devId);
    }

#ifdef WOLFSSL_ENCRYPTED_KEYS
    wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
#endif

    if (wolfSSL_CTX_load_verify_locations(ctx, callbacks->caPemFile, 0) !=
            WOLFSSL_SUCCESS) {
        goto cleanup;
    }

    if (!callbacks->loadToSSL) {
        if (wolfSSL_CTX_use_certificate_file(ctx, callbacks->certPemFile,
                CERT_FILETYPE) != WOLFSSL_SUCCESS) {
            goto cleanup;
        }

        if (wolfSSL_CTX_use_PrivateKey_file(ctx, callbacks->keyPemFile,
                CERT_FILETYPE) != WOLFSSL_SUCCESS) {
            goto cleanup;
        }
    }

#ifdef HAVE_CRL
    if (callbacks->crlPemFile != NULL) {
        if (wolfSSL_CTX_LoadCRLFile(ctx, callbacks->crlPemFile,
                CERT_FILETYPE) != WOLFSSL_SUCCESS) {
            goto cleanup;
        }
    }
#endif

    if (callbacks->ctx_ready)
        callbacks->ctx_ready(ctx);

    ssl = wolfSSL_new(ctx);
    if (wolfSSL_dtls(ssl)) {
        tcp_connect(&sfd, wolfSSLIP, ((func_args*)args)->signal->port,
                    1, 0, ssl);
    }
    else {
        tcp_connect(&sfd, wolfSSLIP, ((func_args*)args)->signal->port,
                    0, 0, ssl);
    }
    if (wolfSSL_set_fd(ssl, sfd) != WOLFSSL_SUCCESS) {
        goto cleanup;
    }

    if (callbacks->loadToSSL) {
        wolfSSL_SetDevId(ssl, callbacks->devId);

        if (wolfSSL_use_certificate_file(ssl, callbacks->certPemFile,
                CERT_FILETYPE) != WOLFSSL_SUCCESS) {
            goto cleanup;
        }

        if (wolfSSL_use_PrivateKey_file(ssl, callbacks->keyPemFile,
                CERT_FILETYPE) != WOLFSSL_SUCCESS) {
            goto cleanup;
        }
    }

    if (callbacks->ssl_ready)
        callbacks->ssl_ready(ssl);

    WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_connect(ssl),
                                ret != WOLFSSL_SUCCESS);
    if (ret != WOLFSSL_SUCCESS) {
        char buff[WOLFSSL_MAX_ERROR_SZ];
        fprintf(stderr, "error = %d, %s\n", err,
            wolfSSL_ERR_error_string((word32)err, buff));
        /*err_sys("SSL_connect failed");*/
    }
    else {
        WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_write(ssl, msg, len),
                                    ret != len);
        if (len != ret)
            goto cleanup;

        WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_read(ssl, input, sizeof(input)-1),
                                    ret <= 0);
        if (ret > 0) {
            input[ret] = '\0'; /* null term */
            fprintf(stderr, "Server response: %s\n", input);
        }
        ((func_args*)args)->return_code = TEST_SUCCESS;
    }

    if (callbacks->on_result)
        callbacks->on_result(ssl);

cleanup:
    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
    CloseSocket(sfd);

#ifdef WOLFSSL_TIRTOS
    fdCloseSession(Task_self());
#endif
}

#endif /* ENABLE_TLS_CALLBACK_TEST */


static int test_wolfSSL_read_write(void)
{
    EXPECT_DECLS;
#ifndef NO_SHA256
    /* The unit testing for read and write shall happen simultaneously, since
     * one can't do anything with one without the other. (Except for a failure
     * test case.) This function will call all the others that will set up,
     * execute, and report their test findings.
     *
     * Set up the success case first. This function will become the template
     * for the other tests. This should eventually be renamed
     *
     * The success case isn't interesting, how can this fail?
     * - Do not give the client context a CA certificate. The connect should
     *   fail. Do not need server for this?
     * - Using NULL for the ssl object on server. Do not need client for this.
     * - Using NULL for the ssl object on client. Do not need server for this.
     * - Good ssl objects for client and server. Client write() without server
     *   read().
     * - Good ssl objects for client and server. Server write() without client
     *   read().
     * - Forgetting the password callback?
    */
    tcp_ready ready;
    func_args client_args;
    func_args server_args;
    THREAD_TYPE serverThread;

    XMEMSET(&client_args, 0, sizeof(func_args));
    XMEMSET(&server_args, 0, sizeof(func_args));
#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    StartTCP();
    InitTcpReady(&ready);

    server_args.signal = &ready;
    client_args.signal = &ready;

    start_thread(test_server_nofail, &server_args, &serverThread);
    wait_tcp_ready(&server_args);
    test_client_nofail(&client_args, NULL);
    join_thread(serverThread);

    ExpectTrue(client_args.return_code);
    ExpectTrue(server_args.return_code);

    FreeTcpReady(&ready);

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_read_write_ex(void)
{
    EXPECT_DECLS;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    const char *test_str = "test";
    int test_str_size;
    size_t count;
    byte buf[255];

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfSSLv23_client_method, wolfSSLv23_server_method), 0);
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
    test_str_size = XSTRLEN("test") + 1;
    ExpectIntEQ(wolfSSL_write_ex(ssl_c, test_str, test_str_size, &count),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(count, test_str_size);
    count = 0;
    ExpectIntEQ(wolfSSL_read_ex(ssl_s, buf, sizeof(buf), &count), WOLFSSL_SUCCESS);
    ExpectIntEQ(count, test_str_size);
    ExpectIntEQ(XSTRCMP((char*)buf, test_str), 0);


    ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SHUTDOWN_NOT_DONE);
    ExpectIntEQ(wolfSSL_shutdown(ssl_s), WOLFSSL_SHUTDOWN_NOT_DONE);
    ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_shutdown(ssl_s), WOLFSSL_SUCCESS);

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);

    /* XXX this should be return EXPECT_RESULT(); */
    return TEST_SUCCESS;
}

static int test_wolfSSL_reuse_WOLFSSLobj(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_SESSION_CACHE) && \
    !defined(WOLFSSL_NO_TLS12)
    /* The unit test for session resumption by reusing WOLFSSL object.
     * WOLFSSL object is not cleared after first session. It reuse the object
     * for second connection.
    */
    tcp_ready ready;
    func_args client_args;
    func_args server_args;
    THREAD_TYPE serverThread;
    callback_functions client_cbf;
    callback_functions server_cbf;

    XMEMSET(&client_args, 0, sizeof(func_args));
    XMEMSET(&server_args, 0, sizeof(func_args));
    XMEMSET(&client_cbf, 0, sizeof(callback_functions));
    XMEMSET(&server_cbf, 0, sizeof(callback_functions));
#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    StartTCP();
    InitTcpReady(&ready);

    client_cbf.method = wolfTLSv1_2_client_method;
    server_cbf.method = wolfTLSv1_2_server_method;
    client_args.callbacks = &client_cbf;
    server_args.callbacks = &server_cbf;

    server_args.signal = &ready;
    client_args.signal = &ready;
    /* the var is used for loop number */
    server_args.argc = 2;

    start_thread(test_server_loop, &server_args, &serverThread);
    wait_tcp_ready(&server_args);
    test_client_reuse_WOLFSSLobj(&client_args, NULL, &server_args);
    join_thread(serverThread);

    ExpectTrue(client_args.return_code);
    ExpectTrue(server_args.return_code);

    FreeTcpReady(&ready);

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_SESSION_CACHE) &&
        * !defined(WOLFSSL_TLS13) */
    return EXPECT_RESULT();
}

#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
static int test_wolfSSL_CTX_verifyDepth_ServerClient_1_ctx_ready(
    WOLFSSL_CTX* ctx)
{
    wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, myVerify);
    myVerifyAction = VERIFY_USE_PREVERIFY;
    wolfSSL_CTX_set_verify_depth(ctx, 2);
    return TEST_SUCCESS;
}
#endif

static int test_wolfSSL_CTX_verifyDepth_ServerClient_1(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
    test_ssl_cbf client_cbf;
    test_ssl_cbf server_cbf;

    XMEMSET(&client_cbf, 0, sizeof(client_cbf));
    XMEMSET(&server_cbf, 0, sizeof(server_cbf));

#ifdef WOLFSSL_TLS13
    client_cbf.method = wolfTLSv1_3_client_method;
#endif /* WOLFSSL_TLS13 */
    client_cbf.ctx_ready =
        test_wolfSSL_CTX_verifyDepth_ServerClient_1_ctx_ready;

    /* test case 1 verify depth is equal to peer chain */
    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
        &server_cbf, NULL), TEST_SUCCESS);

    ExpectIntEQ(client_cbf.return_code, TEST_SUCCESS);
    ExpectIntEQ(server_cbf.return_code, TEST_SUCCESS);
#endif /* OPENSSL_EXTRA && HAVE_SSL_MEMIO_TESTS_DEPENDENCIES */

    return EXPECT_RESULT();
}

#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
static int test_wolfSSL_CTX_verifyDepth_ServerClient_2_ctx_ready(
    WOLFSSL_CTX* ctx)
{
    wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, myVerify);
    myVerifyAction = VERIFY_OVERRIDE_ERROR;
    wolfSSL_CTX_set_verify_depth(ctx, 0);
    return TEST_SUCCESS;
}
#endif

static int test_wolfSSL_CTX_verifyDepth_ServerClient_2(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
    test_ssl_cbf client_cbf;
    test_ssl_cbf server_cbf;

    XMEMSET(&client_cbf, 0, sizeof(client_cbf));
    XMEMSET(&server_cbf, 0, sizeof(server_cbf));

#ifdef WOLFSSL_TLS13
    client_cbf.method = wolfTLSv1_3_client_method;
#endif /* WOLFSSL_TLS13 */
    client_cbf.ctx_ready =
        test_wolfSSL_CTX_verifyDepth_ServerClient_2_ctx_ready;

    /* test case 2
     * verify depth is zero, number of peer's chain is 2.
     * verify result becomes MAX_CHAIN_ERROR, but it is overridden in
     * callback.
     */
    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
        &server_cbf, NULL), TEST_SUCCESS);

    ExpectIntEQ(client_cbf.return_code, TEST_SUCCESS);
    ExpectIntEQ(server_cbf.return_code, TEST_SUCCESS);
#endif /* OPENSSL_EXTRA && HAVE_SSL_MEMIO_TESTS_DEPENDENCIES */

    return EXPECT_RESULT();
}

#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
static int test_wolfSSL_CTX_verifyDepth_ServerClient_3_ctx_ready(
    WOLFSSL_CTX* ctx)
{
    wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, myVerify);
    myVerifyAction = VERIFY_USE_PREVERIFY;
    wolfSSL_CTX_set_verify_depth(ctx, 0);
    return TEST_SUCCESS;
}
#endif

static int test_wolfSSL_CTX_verifyDepth_ServerClient_3(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
    test_ssl_cbf client_cbf;
    test_ssl_cbf server_cbf;

    XMEMSET(&client_cbf, 0, sizeof(client_cbf));
    XMEMSET(&server_cbf, 0, sizeof(server_cbf));

#ifdef WOLFSSL_TLS13
    client_cbf.method = wolfTLSv1_3_client_method;
#endif /* WOLFSSL_TLS13 */
    client_cbf.ctx_ready =
        test_wolfSSL_CTX_verifyDepth_ServerClient_3_ctx_ready;

    /* test case 3
     * verify depth is zero, number of peer's chain is 2
     * verify result becomes MAX_CHAIN_ERRO. call-back returns failure.
     * therefore, handshake becomes failure.
     */
    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
        &server_cbf, NULL), -1001);

    ExpectIntEQ(client_cbf.return_code, -1000);
    ExpectIntEQ(server_cbf.return_code, -1000);
    ExpectIntEQ(client_cbf.last_err, WC_NO_ERR_TRACE(MAX_CHAIN_ERROR));
    ExpectIntEQ(server_cbf.last_err, WC_NO_ERR_TRACE(FATAL_ERROR));
#endif /* OPENSSL_EXTRA && HAVE_SSL_MEMIO_TESTS_DEPENDENCIES */

    return EXPECT_RESULT();
}

#if defined(OPENSSL_ALL) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(WOLFSSL_NO_TLS12) && \
    defined(HAVE_ECC) && !defined(NO_AES) && !defined(NO_SHA256)
static int test_wolfSSL_CTX_set_cipher_list_server_ctx_ready(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    ExpectTrue(wolfSSL_CTX_set_cipher_list(ctx, "DEFAULT:!NULL"));
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_set_cipher_list_client_ctx_ready(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    ExpectTrue(wolfSSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES128-SHA256"));
    return EXPECT_RESULT();
}
#endif

static int test_wolfSSL_CTX_set_cipher_list(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    defined(HAVE_ECC) && !defined(NO_AES) && !defined(NO_SHA256)

    #if !defined(WOLFSSL_NO_TLS12)
    WOLFSSL_CTX* ctxClient = NULL;
    WOLFSSL*     sslClient = NULL;
    test_ssl_cbf client_cbf;
    test_ssl_cbf server_cbf;

    XMEMSET(&client_cbf, 0, sizeof(client_cbf));
    XMEMSET(&server_cbf, 0, sizeof(server_cbf));

    server_cbf.method = wolfTLSv1_2_server_method;
    server_cbf.ctx_ready = test_wolfSSL_CTX_set_cipher_list_server_ctx_ready;
    client_cbf.method = wolfTLSv1_2_client_method;
    client_cbf.ctx_ready = test_wolfSSL_CTX_set_cipher_list_client_ctx_ready;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
        &server_cbf, NULL), TEST_SUCCESS);

    ExpectIntEQ(client_cbf.return_code, TEST_SUCCESS);
    ExpectIntEQ(server_cbf.return_code, TEST_SUCCESS);

    /* check with cipher string that has '+' */
    ExpectNotNull((ctxClient = wolfSSL_CTX_new(wolfTLSv1_2_client_method())));
    /* Use trailing : with nothing to test for ASAN */
    ExpectTrue(wolfSSL_CTX_set_cipher_list(ctxClient, "ECDHE+AESGCM:"));
    ExpectNotNull((sslClient = wolfSSL_new(ctxClient)));

    /* check for the existence of an ECDHE ECDSA cipher suite */
    if (EXPECT_SUCCESS()) {
        int i = 0;
        int found = 0;
        const char* suite;

        WOLF_STACK_OF(WOLFSSL_CIPHER)* sk = NULL;
        WOLFSSL_CIPHER* current;

        ExpectNotNull((sk = wolfSSL_get_ciphers_compat(sslClient)));
        do {
            current = wolfSSL_sk_SSL_CIPHER_value(sk, i++);
            if (current) {
                suite = wolfSSL_CIPHER_get_name(current);
                if (suite && XSTRSTR(suite, "ECDSA")) {
                    found = 1;
                    break;
                }
            }
        } while (current);
        ExpectIntEQ(found, 1);
    }

    wolfSSL_free(sslClient);
    wolfSSL_CTX_free(ctxClient);

    #endif /* !WOLFSSL_NO_TLS12 */
#endif
    return EXPECT_RESULT();
}

#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    defined(WOLFSSL_HAVE_TLS_UNIQUE)
static int test_wolfSSL_get_finished_client_on_handshake(WOLFSSL_CTX* ctx,
    WOLFSSL* ssl)
{
    EXPECT_DECLS;
    size_t msg_len;

    (void)ctx;

    /* get_finished test */
    /* 1. get own sent message */
    XMEMSET(client_side_msg1, 0, WC_MAX_DIGEST_SIZE);
    msg_len = wolfSSL_get_finished(ssl, client_side_msg1, WC_MAX_DIGEST_SIZE);
    ExpectIntGE(msg_len, 0);
    /* 2. get peer message */
    XMEMSET(client_side_msg2, 0, WC_MAX_DIGEST_SIZE);
    msg_len = wolfSSL_get_peer_finished(ssl, client_side_msg2, WC_MAX_DIGEST_SIZE);
    ExpectIntGE(msg_len, 0);

    return EXPECT_RESULT();
}
#endif

static int test_wolfSSL_get_finished(void)
{
    EXPECT_DECLS;
#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    defined(WOLFSSL_HAVE_TLS_UNIQUE)
    test_ssl_cbf client_cbf;
    test_ssl_cbf server_cbf;

    XMEMSET(&client_cbf, 0, sizeof(client_cbf));
    XMEMSET(&server_cbf, 0, sizeof(server_cbf));

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
        &server_cbf, test_wolfSSL_get_finished_client_on_handshake),
        TEST_SUCCESS);

    /* test received msg vs sent msg */
    ExpectIntEQ(0, XMEMCMP(client_side_msg1, server_side_msg2, WC_MAX_DIGEST_SIZE));
    ExpectIntEQ(0, XMEMCMP(client_side_msg2, server_side_msg1, WC_MAX_DIGEST_SIZE));
#endif /* HAVE_SSL_MEMIO_TESTS_DEPENDENCIES && WOLFSSL_HAVE_TLS_UNIQUE */

    return EXPECT_RESULT();
}

#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
    !defined(SINGLE_THREADED) && defined(WOLFSSL_TLS13) && \
    !defined(NO_SESSION_CACHE)

/* Sessions to restore/store */
static WOLFSSL_SESSION* test_wolfSSL_CTX_add_session_client_sess;
static WOLFSSL_SESSION* test_wolfSSL_CTX_add_session_server_sess;
static WOLFSSL_CTX*     test_wolfSSL_CTX_add_session_server_ctx;

static void test_wolfSSL_CTX_add_session_ctx_ready(WOLFSSL_CTX* ctx)
{
    /* Don't store sessions. Lookup is still enabled. */
    AssertIntEQ(wolfSSL_CTX_set_session_cache_mode(ctx,
            WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE), WOLFSSL_SUCCESS);
#ifdef OPENSSL_EXTRA
    AssertIntEQ(wolfSSL_CTX_get_session_cache_mode(ctx) &
            WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE,
            WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE);
#endif
    /* Require both peers to provide certs */
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
}

static void test_wolfSSL_CTX_add_session_on_result(WOLFSSL* ssl)
{
    WOLFSSL_SESSION** sess;
#ifdef WOLFSSL_MUTEX_INITIALIZER
    static wolfSSL_Mutex m = WOLFSSL_MUTEX_INITIALIZER(m);

    (void)wc_LockMutex(&m);
#endif
    if (wolfSSL_is_server(ssl))
        sess = &test_wolfSSL_CTX_add_session_server_sess;
    else
        sess = &test_wolfSSL_CTX_add_session_client_sess;
    if (*sess == NULL) {
#ifdef NO_SESSION_CACHE_REF
        *sess = wolfSSL_get1_session(ssl);
        AssertNotNull(*sess);
#else
        /* Test for backwards compatibility */
        if (wolfSSL_is_server(ssl)) {
            *sess = wolfSSL_get1_session(ssl);
            AssertNotNull(*sess);
        }
        else {
            *sess = wolfSSL_get_session(ssl);
            AssertNotNull(*sess);
        }
#endif
        /* Now save the session in the internal store to make it available
         * for lookup. For TLS 1.3, we can't save the session without
         * WOLFSSL_TICKET_HAVE_ID because there is no way to retrieve the
         * session from cache. */
        if (wolfSSL_is_server(ssl)
#ifndef WOLFSSL_TICKET_HAVE_ID
                && wolfSSL_version(ssl) != TLS1_3_VERSION
#endif
                )
            AssertIntEQ(wolfSSL_CTX_add_session(wolfSSL_get_SSL_CTX(ssl),
                    *sess), WOLFSSL_SUCCESS);
    }
    else {
        /* If we have a session retrieved then remaining connections should be
         * resuming on that session */
        AssertIntEQ(wolfSSL_session_reused(ssl), 1);
    }
#ifdef WOLFSSL_MUTEX_INITIALIZER
    wc_UnLockMutex(&m);
#endif

    /* Save CTX to be able to decrypt tickets */
    if (wolfSSL_is_server(ssl) &&
            test_wolfSSL_CTX_add_session_server_ctx == NULL) {
        test_wolfSSL_CTX_add_session_server_ctx = wolfSSL_get_SSL_CTX(ssl);
        AssertNotNull(test_wolfSSL_CTX_add_session_server_ctx);
        AssertIntEQ(wolfSSL_CTX_up_ref(wolfSSL_get_SSL_CTX(ssl)),
                WOLFSSL_SUCCESS);
    }
#if defined(SESSION_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH)
#ifndef WOLFSSL_TICKET_HAVE_ID
    if (wolfSSL_version(ssl) != TLS1_3_VERSION &&
            wolfSSL_session_reused(ssl))
#endif
    {
        /* With WOLFSSL_TICKET_HAVE_ID the peer certs should be available
         * for all connections. TLS 1.3 only has tickets so if we don't
         * include the session id in the ticket then the certificates
         * will not be available on resumption. */
    #ifdef KEEP_PEER_CERT
        WOLFSSL_X509* peer = wolfSSL_get_peer_certificate(ssl);
        AssertNotNull(peer);
        wolfSSL_X509_free(peer);
    #endif
        AssertNotNull(wolfSSL_SESSION_get_peer_chain(*sess));
    #ifdef OPENSSL_EXTRA
        AssertNotNull(SSL_SESSION_get0_peer(*sess));
    #endif
    }
#endif /* SESSION_CERTS && !WOLFSSL_NO_CLIENT_AUTH */
}

static void test_wolfSSL_CTX_add_session_ssl_ready(WOLFSSL* ssl)
{
    /* Set the session to reuse for the client */
    AssertIntEQ(wolfSSL_set_session(ssl,
            test_wolfSSL_CTX_add_session_client_sess), WOLFSSL_SUCCESS);
}
#endif

static int test_wolfSSL_CTX_add_session(void)
{
    EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
    !defined(SINGLE_THREADED) && defined(WOLFSSL_TLS13) && \
    !defined(NO_SESSION_CACHE)
    tcp_ready ready;
    func_args client_args;
    func_args server_args;
    THREAD_TYPE serverThread;
    callback_functions client_cb;
    callback_functions server_cb;
    method_provider methods[][2] = {
#if !defined(NO_OLD_TLS) && ((!defined(NO_AES) && !defined(NO_AES_CBC)) || \
        !defined(NO_DES3))
        /* Without AES there are almost no ciphersuites available. This leads
         * to no ciphersuites being available and an error. */
        { wolfTLSv1_1_client_method, wolfTLSv1_1_server_method },
#endif
#ifndef WOLFSSL_NO_TLS12
        { wolfTLSv1_2_client_method, wolfTLSv1_2_server_method },
#endif
        /* Needs the default ticket callback since it is tied to the
         * connection context and this makes it easy to carry over the ticket
         * crypto context between connections */
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
    defined(HAVE_SESSION_TICKET)
        { wolfTLSv1_3_client_method, wolfTLSv1_3_server_method },
#endif
    };
    const size_t methodsLen = sizeof(methods)/sizeof(*methods);
    size_t i, j;

    for (i = 0; i < methodsLen; i++) {
        /* First run creates a connection while the second+ run will attempt
         * to resume the connection. The trick is that the internal cache
         * is turned off. wolfSSL_CTX_add_session should put the session in
         * the cache anyway. */
        test_wolfSSL_CTX_add_session_client_sess = NULL;
        test_wolfSSL_CTX_add_session_server_sess = NULL;
        test_wolfSSL_CTX_add_session_server_ctx = NULL;

#ifdef NO_SESSION_CACHE_REF
        for (j = 0; j < 4; j++) {
#else
        /* The session may be overwritten in this case. Do only one resumption
         * to stop this test from failing intermittently. */
        for (j = 0; j < 2; j++) {
#endif
#ifdef WOLFSSL_TIRTOS
            fdOpenSession(Task_self());
#endif

            StartTCP();
            InitTcpReady(&ready);

            XMEMSET(&client_args, 0, sizeof(func_args));
            XMEMSET(&server_args, 0, sizeof(func_args));

            XMEMSET(&client_cb, 0, sizeof(callback_functions));
            XMEMSET(&server_cb, 0, sizeof(callback_functions));
            client_cb.method  = methods[i][0];
            server_cb.method  = methods[i][1];

            server_args.signal    = &ready;
            server_args.callbacks = &server_cb;
            client_args.signal    = &ready;
            client_args.callbacks = &client_cb;

            if (test_wolfSSL_CTX_add_session_server_ctx != NULL) {
                server_cb.ctx = test_wolfSSL_CTX_add_session_server_ctx;
                server_cb.isSharedCtx = 1;
            }
            server_cb.ctx_ready = test_wolfSSL_CTX_add_session_ctx_ready;
            client_cb.ctx_ready = test_wolfSSL_CTX_add_session_ctx_ready;
            if (j != 0)
                client_cb.ssl_ready = test_wolfSSL_CTX_add_session_ssl_ready;
            server_cb.on_result = test_wolfSSL_CTX_add_session_on_result;
            client_cb.on_result = test_wolfSSL_CTX_add_session_on_result;
            server_cb.ticNoInit = 1; /* Use default builtin */

            start_thread(test_server_nofail, &server_args, &serverThread);
            wait_tcp_ready(&server_args);
            test_client_nofail(&client_args, NULL);
            join_thread(serverThread);

            ExpectTrue(client_args.return_code);
            ExpectTrue(server_args.return_code);

            FreeTcpReady(&ready);

            if (EXPECT_FAIL())
                break;
        }
        wolfSSL_SESSION_free(test_wolfSSL_CTX_add_session_client_sess);
        wolfSSL_SESSION_free(test_wolfSSL_CTX_add_session_server_sess);
        wolfSSL_CTX_free(test_wolfSSL_CTX_add_session_server_ctx);

        if (EXPECT_FAIL())
            break;
    }
#endif

    return EXPECT_RESULT();
}
#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
     defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
     defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
     defined(HAVE_SESSION_TICKET) && \
    !defined(TITAN_SESSION_CACHE) && \
    !defined(HUGE_SESSION_CACHE) && \
    !defined(BIG_SESSION_CACHE) && \
    !defined(MEDIUM_SESSION_CACHE)

/* twcase - prefix for test_wolfSSL_CTX_add_session_ext */
/* Sessions to restore/store */
static WOLFSSL_SESSION* twcase_server_first_session_ptr;
static WOLFSSL_SESSION* twcase_client_first_session_ptr;
static WOLFSSL_CTX*     twcase_server_current_ctx_ptr;
static int twcase_new_session_called    = 0;
static int twcase_remove_session_called = 0;
static int twcase_get_session_called    = 0;

/* Test default, SESSIONS_PER_ROW*SESSION_ROWS = 3*11, see ssl.c */
#define SESSION_CACHE_SIZE 33

typedef struct {
    const byte* key;  /* key, altSessionID, session ID, NULL if empty */
    WOLFSSL_SESSION* value;
} hashTable_entry;

typedef struct {
    hashTable_entry entries[SESSION_CACHE_SIZE];  /* hash slots */
    size_t capacity;                     /* size of entries */
    size_t length;                       /* number of items in the hash table */
    wolfSSL_Mutex htLock;                /* lock */
}hashTable;

static hashTable server_sessionCache;

static int twcase_new_sessionCb(WOLFSSL *ssl, WOLFSSL_SESSION *sess)
{
    int i;
    unsigned int len;
    (void)ssl;

    /*
     * This example uses a hash table.
     * Steps you should take for a non-demo code:
     * - acquire a lock for the file named according to the session id
     * - open the file
     * - encrypt and write the SSL_SESSION object to the file
     * - release the lock
     *
     * Return:
     *  0: The callback does not wish to hold a reference of the sess
     *  1: The callback wants to hold a reference of the sess. The callback is
     *     now also responsible for calling wolfSSL_SESSION_free() on sess.
     */
    if (sess == NULL)
        return 0;

    if (wc_LockMutex(&server_sessionCache.htLock) != 0) {
        return 0;
    }
    for (i = 0; i < SESSION_CACHE_SIZE; i++) {
        if (server_sessionCache.entries[i].value == NULL) {
            server_sessionCache.entries[i].key = SSL_SESSION_get_id(sess, &len);
            server_sessionCache.entries[i].value = sess;
            server_sessionCache.length++;
            break;
        }
    }
    ++twcase_new_session_called;
    wc_UnLockMutex(&server_sessionCache.htLock);
    fprintf(stderr, "\t\ttwcase_new_session_called %d\n",
            twcase_new_session_called);
    return 1;
}

static void twcase_remove_sessionCb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess)
{
    int i;
    (void)ctx;
    (void)sess;

    if (sess == NULL)
        return;
    /*
     * This example uses a hash table.
     * Steps you should take for a non-demo code:
     * - acquire a lock for the file named according to the session id
     * - remove the file
     * - release the lock
     */
    if (wc_LockMutex(&server_sessionCache.htLock) != 0) {
        return;
    }
    for (i = 0; i < SESSION_CACHE_SIZE; i++) {
        if (server_sessionCache.entries[i].key != NULL &&
           XMEMCMP(server_sessionCache.entries[i].key,
                   sess->sessionID, SSL_MAX_SSL_SESSION_ID_LENGTH) == 0) {
            wolfSSL_SESSION_free(server_sessionCache.entries[i].value);
            server_sessionCache.entries[i].value = NULL;
            server_sessionCache.entries[i].key = NULL;
            server_sessionCache.length--;
            break;
        }
    }
    ++twcase_remove_session_called;
    wc_UnLockMutex(&server_sessionCache.htLock);
    fprintf(stderr, "\t\ttwcase_remove_session_called %d\n",
            twcase_remove_session_called);
}

static WOLFSSL_SESSION *twcase_get_sessionCb(WOLFSSL *ssl,
                                  const unsigned char *id, int len, int *ref)
{
    int i;
    (void)ssl;
    (void)id;
    (void)len;

    /*
     * This example uses a hash table.
     * Steps you should take for a non-demo code:
     * - acquire a lock for the file named according to the session id in the
     *   2nd arg
     * - read and decrypt contents of file and create a new SSL_SESSION
     * - object release the lock
     * - return the new session object
     */
    fprintf(stderr, "\t\ttwcase_get_session_called %d\n",
            ++twcase_get_session_called);
    /* This callback want to retain a copy of the object. If we want wolfSSL to
     * be responsible for the pointer then set to 0. */
    *ref = 1;

    for (i = 0; i < SESSION_CACHE_SIZE; i++) {
        if (server_sessionCache.entries[i].key != NULL &&
           XMEMCMP(server_sessionCache.entries[i].key, id,
                   SSL_MAX_SSL_SESSION_ID_LENGTH) == 0) {
           return server_sessionCache.entries[i].value;
        }
    }
    return NULL;
}
static int twcase_get_sessionCb_cleanup(void)
{
    int i;
    int cnt = 0;

    /* If  twcase_get_sessionCb sets *ref = 1, the application is responsible
     * for freeing sessions */

    for (i = 0; i < SESSION_CACHE_SIZE; i++) {
        if (server_sessionCache.entries[i].value != NULL) {
            wolfSSL_SESSION_free(server_sessionCache.entries[i].value);
            cnt++;
        }
    }

    fprintf(stderr, "\t\ttwcase_get_sessionCb_cleanup freed %d sessions\n",
            cnt);

    return TEST_SUCCESS;
}

static int twcase_cache_intOff_extOff(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    /* off - Disable internal cache */
    ExpectIntEQ(wolfSSL_CTX_set_session_cache_mode(ctx,
            WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE), WOLFSSL_SUCCESS);
#ifdef OPENSSL_EXTRA
    ExpectIntEQ(wolfSSL_CTX_get_session_cache_mode(ctx) &
            WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE,
            WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE);
#endif
    /* off - Do not setup external cache */

    /* Require both peers to provide certs */
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
    return EXPECT_RESULT();
}

static int twcase_cache_intOn_extOff(WOLFSSL_CTX* ctx)
{
    /* on - internal cache is on by default */
    /* off - Do not setup external cache */
    /* Require both peers to provide certs */
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
    return TEST_SUCCESS;
}

static int twcase_cache_intOff_extOn(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    /* off - Disable internal cache */
    ExpectIntEQ(wolfSSL_CTX_set_session_cache_mode(ctx,
            WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE), WOLFSSL_SUCCESS);
#ifdef OPENSSL_EXTRA
    ExpectIntEQ(wolfSSL_CTX_get_session_cache_mode(ctx) &
            WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE,
            WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE);
#endif
    /* on - Enable external cache */
    wolfSSL_CTX_sess_set_new_cb(ctx, twcase_new_sessionCb);
    wolfSSL_CTX_sess_set_remove_cb(ctx, twcase_remove_sessionCb);
    wolfSSL_CTX_sess_set_get_cb(ctx, twcase_get_sessionCb);

    /* Require both peers to provide certs */
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
    return EXPECT_RESULT();
}

static int twcase_cache_intOn_extOn(WOLFSSL_CTX* ctx)
{
    /* on - internal cache is on by default */
    /* on - Enable external cache */
    wolfSSL_CTX_sess_set_new_cb(ctx, twcase_new_sessionCb);
    wolfSSL_CTX_sess_set_remove_cb(ctx, twcase_remove_sessionCb);
    wolfSSL_CTX_sess_set_get_cb(ctx, twcase_get_sessionCb);

    /* Require both peers to provide certs */
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
    return TEST_SUCCESS;
}
static int twcase_cache_intOn_extOn_noTicket(WOLFSSL_CTX* ctx)
{
    /* on - internal cache is on by default */
    /* on - Enable external cache */
    wolfSSL_CTX_sess_set_new_cb(ctx, twcase_new_sessionCb);
    wolfSSL_CTX_sess_set_remove_cb(ctx, twcase_remove_sessionCb);
    wolfSSL_CTX_sess_set_get_cb(ctx, twcase_get_sessionCb);

    wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TICKET);
    /* Require both peers to provide certs */
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
    return TEST_SUCCESS;
}
static int twcase_server_sess_ctx_pre_shutdown(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    WOLFSSL_SESSION** sess;
    if (wolfSSL_is_server(ssl))
        sess = &twcase_server_first_session_ptr;
    else
        return TEST_SUCCESS;

    if (*sess == NULL) {
        ExpectNotNull(*sess = wolfSSL_get1_session(ssl));
        /* Now save the session in the internal store to make it available
         * for lookup. For TLS 1.3, we can't save the session without
         * WOLFSSL_TICKET_HAVE_ID because there is no way to retrieve the
         * session from cache. */
        if (wolfSSL_is_server(ssl)
#ifndef WOLFSSL_TICKET_HAVE_ID
                && wolfSSL_version(ssl) != TLS1_3_VERSION
                && wolfSSL_version(ssl) != DTLS1_3_VERSION
#endif
                ) {
            ExpectIntEQ(wolfSSL_CTX_add_session(wolfSSL_get_SSL_CTX(ssl),
                    *sess), WOLFSSL_SUCCESS);
        }
    }
    /* Save CTX to be able to decrypt tickets */
    if (twcase_server_current_ctx_ptr == NULL) {
        ExpectNotNull(twcase_server_current_ctx_ptr = wolfSSL_get_SSL_CTX(ssl));
        ExpectIntEQ(wolfSSL_CTX_up_ref(wolfSSL_get_SSL_CTX(ssl)),
                    WOLFSSL_SUCCESS);
    }
#if defined(SESSION_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH)
#ifndef WOLFSSL_TICKET_HAVE_ID
    if (wolfSSL_version(ssl) != TLS1_3_VERSION &&
            wolfSSL_session_reused(ssl))
#endif
    {
        /* With WOLFSSL_TICKET_HAVE_ID the peer certs should be available
         * for all connections. TLS 1.3 only has tickets so if we don't
         * include the session id in the ticket then the certificates
         * will not be available on resumption. */
    #ifdef KEEP_PEER_CERT
        WOLFSSL_X509* peer = NULL;
        ExpectNotNull(peer = wolfSSL_get_peer_certificate(ssl));
        wolfSSL_X509_free(peer);
    #endif
        ExpectNotNull(wolfSSL_SESSION_get_peer_chain(*sess));
    }
#endif
    return EXPECT_RESULT();
}

static int twcase_client_sess_ctx_pre_shutdown(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    WOLFSSL_SESSION** sess;
    sess = &twcase_client_first_session_ptr;
    if (*sess == NULL) {
        ExpectNotNull(*sess = wolfSSL_get1_session(ssl));
    }
    else {
        /* If we have a session retrieved then remaining connections should be
         * resuming on that session */
        ExpectIntEQ(wolfSSL_session_reused(ssl), 1);
    }

#if defined(SESSION_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH)
#ifndef WOLFSSL_TICKET_HAVE_ID
    if (wolfSSL_version(ssl) != TLS1_3_VERSION &&
            wolfSSL_session_reused(ssl))
#endif
    {
    #ifdef KEEP_PEER_CERT
        WOLFSSL_X509* peer = wolfSSL_get_peer_certificate(ssl);
        ExpectNotNull(peer);
        wolfSSL_X509_free(peer);
    #endif
        ExpectNotNull(wolfSSL_SESSION_get_peer_chain(*sess));
#ifdef OPENSSL_EXTRA
        ExpectNotNull(wolfSSL_SESSION_get0_peer(*sess));
#endif
    }
#endif
    return EXPECT_RESULT();
}
static int twcase_client_set_sess_ssl_ready(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    /* Set the session to reuse for the client */
    ExpectNotNull(ssl);
    ExpectNotNull(twcase_client_first_session_ptr);
    ExpectIntEQ(wolfSSL_set_session(ssl,twcase_client_first_session_ptr),
                WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}

struct test_add_session_ext_params {
    method_provider client_meth;
    method_provider server_meth;
    const char* tls_version;
};

static int test_wolfSSL_CTX_add_session_ext(
    struct test_add_session_ext_params* param)
{
    EXPECT_DECLS;
    /* Test the default 33 sessions */
    int j;

    /* Clear cache before starting */
    wolfSSL_CTX_flush_sessions(NULL, -1);

    XMEMSET(&server_sessionCache, 0, sizeof(hashTable));
    if (wc_InitMutex(&server_sessionCache.htLock) != 0)
        return BAD_MUTEX_E;
    server_sessionCache.capacity = SESSION_CACHE_SIZE;

    fprintf(stderr, "\tBegin %s\n", param->tls_version);
    for (j = 0; j < 5; j++) {
        int tls13 = XSTRSTR(param->tls_version, "TLSv1_3") != NULL;
        int dtls = XSTRSTR(param->tls_version, "DTLS") != NULL;
        test_ssl_cbf client_cb;
        test_ssl_cbf server_cb;

        (void)dtls;

        /* Test five cache configurations */
        twcase_client_first_session_ptr = NULL;
        twcase_server_first_session_ptr = NULL;
        twcase_server_current_ctx_ptr = NULL;
        twcase_new_session_called    = 0;
        twcase_remove_session_called = 0;
        twcase_get_session_called    = 0;

        /* connection 1 - first connection */
        fprintf(stderr, "\tconnect: %s: j=%d\n", param->tls_version, j);

        XMEMSET(&client_cb, 0, sizeof(client_cb));
        XMEMSET(&server_cb, 0, sizeof(server_cb));
        client_cb.method  = param->client_meth;
        server_cb.method  = param->server_meth;

        if (dtls)
            client_cb.doUdp = server_cb.doUdp = 1;

        /* Setup internal and external cache */
        switch (j) {
            case 0:
                /* SSL_OP_NO_TICKET stateful ticket case */
                server_cb.ctx_ready = twcase_cache_intOn_extOn_noTicket;
                break;
            case 1:
                server_cb.ctx_ready = twcase_cache_intOn_extOn;
                break;
            case 2:
                server_cb.ctx_ready = twcase_cache_intOff_extOn;
                break;
            case 3:
                server_cb.ctx_ready = twcase_cache_intOn_extOff;
                break;
            case 4:
                server_cb.ctx_ready = twcase_cache_intOff_extOff;
                break;
        }
        client_cb.ctx_ready = twcase_cache_intOff_extOff;

        /* Add session to internal cache and save SSL session for testing */
        server_cb.on_result = twcase_server_sess_ctx_pre_shutdown;
        /* Save client SSL session for testing */
        client_cb.on_result = twcase_client_sess_ctx_pre_shutdown;
        server_cb.ticNoInit = 1; /* Use default builtin */
        /* Don't free/release ctx */
        server_cb.ctx = twcase_server_current_ctx_ptr;
        server_cb.isSharedCtx = 1;

        ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cb,
            &server_cb, NULL), TEST_SUCCESS);

        ExpectIntEQ(twcase_get_session_called, 0);
        if (EXPECT_FAIL()) {
            wolfSSL_SESSION_free(twcase_client_first_session_ptr);
            wolfSSL_SESSION_free(twcase_server_first_session_ptr);
            wolfSSL_CTX_free(twcase_server_current_ctx_ptr);
            break;
        }

        switch (j) {
            case 0:
            case 1:
            case 2:
                /* cache cannot be searched with out a connection */
                /* Add a new session */
                ExpectIntEQ(twcase_new_session_called, 1);
                /* In twcase_server_sess_ctx_pre_shutdown
                 * wolfSSL_CTX_add_session which evicts the existing session
                 * in cache and adds it back in */
                ExpectIntLE(twcase_remove_session_called, 1);
                break;
            case 3:
            case 4:
                /* no external cache  */
                ExpectIntEQ(twcase_new_session_called, 0);
                ExpectIntEQ(twcase_remove_session_called, 0);
                break;
        }

        /* connection 2 - session resume */
        fprintf(stderr, "\tresume: %s: j=%d\n", param->tls_version, j);
        twcase_new_session_called    = 0;
        twcase_remove_session_called = 0;
        twcase_get_session_called    = 0;
        server_cb.on_result = 0;
        client_cb.on_result = 0;
        server_cb.ticNoInit = 1; /* Use default builtin */

        server_cb.ctx = twcase_server_current_ctx_ptr;

        /* try session resumption */
        client_cb.ssl_ready = twcase_client_set_sess_ssl_ready;

        ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cb,
            &server_cb, NULL), TEST_SUCCESS);

        /* Clear cache before checking */
        wolfSSL_CTX_flush_sessions(NULL, -1);

        switch (j) {
            case 0:
                if (tls13) {
                    /* (D)TLSv1.3 stateful case */
                    /* cache hit */
                    /* DTLS accesses cache once for stateless parsing and
                     * once for stateful parsing */
                    ExpectIntEQ(twcase_get_session_called, !dtls ? 1 : 2);

                    /* (D)TLSv1.3 creates a new ticket,
                     * updates both internal and external cache */
                    ExpectIntEQ(twcase_new_session_called, 1);
                    /* A new session ID is created for a new ticket */
                    ExpectIntEQ(twcase_remove_session_called, 2);

                }
                else {
                    /* non (D)TLSv1.3 case, no update */
                    /* DTLS accesses cache once for stateless parsing and
                     * once for stateful parsing */
#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME
                    ExpectIntEQ(twcase_get_session_called, !dtls ? 1 : 2);
#else
                    ExpectIntEQ(twcase_get_session_called, 1);
#endif
                    ExpectIntEQ(twcase_new_session_called, 0);
                    /* Called on session added in
                     * twcase_server_sess_ctx_pre_shutdown */
                    ExpectIntEQ(twcase_remove_session_called, 1);
                }
                break;
            case 1:
                if (tls13) {
                    /* (D)TLSv1.3 case */
                    /* cache hit */
                    ExpectIntEQ(twcase_get_session_called, 1);
                    /* (D)TLSv1.3 creates a new ticket,
                     * updates both internal and external cache */
                    ExpectIntEQ(twcase_new_session_called, 1);
                    /* Called on session added in
                     * twcase_server_sess_ctx_pre_shutdown and by wolfSSL */
                    ExpectIntEQ(twcase_remove_session_called, 1);
                }
                else {
                    /* non (D)TLSv1.3 case */
                    /* cache hit */
                    /* DTLS accesses cache once for stateless parsing and
                     * once for stateful parsing */
#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME
                    ExpectIntEQ(twcase_get_session_called, !dtls ? 1 : 2);
#else
                    ExpectIntEQ(twcase_get_session_called, 1);
#endif
                    ExpectIntEQ(twcase_new_session_called, 0);
                    /* Called on session added in
                     * twcase_server_sess_ctx_pre_shutdown */
                    ExpectIntEQ(twcase_remove_session_called, 1);
                }
                break;
            case 2:
                if (tls13) {
                    /* (D)TLSv1.3 case */
                    /* cache hit */
                    ExpectIntEQ(twcase_get_session_called, 1);
                    /* (D)TLSv1.3 creates a new ticket,
                     * updates both internal and external cache */
                    ExpectIntEQ(twcase_new_session_called, 1);
                    /* Called on session added in
                     * twcase_server_sess_ctx_pre_shutdown and by wolfSSL */
                    ExpectIntEQ(twcase_remove_session_called, 1);
                }
                else {
                    /* non (D)TLSv1.3 case */
                    /* cache hit */
                    /* DTLS accesses cache once for stateless parsing and
                     * once for stateful parsing */
#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME
                    ExpectIntEQ(twcase_get_session_called, !dtls ? 1 : 2);
#else
                    ExpectIntEQ(twcase_get_session_called, 1);
#endif
                    ExpectIntEQ(twcase_new_session_called, 0);
                    /* Called on session added in
                     * twcase_server_sess_ctx_pre_shutdown */
                    ExpectIntEQ(twcase_remove_session_called, 1);
                }
                break;
            case 3:
            case 4:
                /* no external cache */
                ExpectIntEQ(twcase_get_session_called, 0);
                ExpectIntEQ(twcase_new_session_called, 0);
                ExpectIntEQ(twcase_remove_session_called, 0);
                break;
        }
        wolfSSL_SESSION_free(twcase_client_first_session_ptr);
        wolfSSL_SESSION_free(twcase_server_first_session_ptr);
        wolfSSL_CTX_free(twcase_server_current_ctx_ptr);

        if (EXPECT_FAIL())
            break;
    }
    twcase_get_sessionCb_cleanup();
    XMEMSET(&server_sessionCache.entries, 0,
            sizeof(server_sessionCache.entries));
    fprintf(stderr, "\tEnd %s\n", param->tls_version);

    wc_FreeMutex(&server_sessionCache.htLock);

    return EXPECT_RESULT();
}
#endif

static int test_wolfSSL_CTX_add_session_ext_tls13(void)
{
    EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
     defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
     defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
     defined(HAVE_SESSION_TICKET) && \
    !defined(TITAN_SESSION_CACHE) && \
    !defined(HUGE_SESSION_CACHE) && \
    !defined(BIG_SESSION_CACHE) && \
    !defined(MEDIUM_SESSION_CACHE)
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
    defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TICKET_HAVE_ID)
    struct test_add_session_ext_params param[1] =  {
        { wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLSv1_3" }
    };
    ExpectIntEQ(test_wolfSSL_CTX_add_session_ext(param), TEST_SUCCESS);
#endif
#endif
    return EXPECT_RESULT();
}
static int test_wolfSSL_CTX_add_session_ext_dtls13(void)
{
    EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
     defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
     defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
     defined(HAVE_SESSION_TICKET) && \
    !defined(TITAN_SESSION_CACHE) && \
    !defined(HUGE_SESSION_CACHE) && \
    !defined(BIG_SESSION_CACHE) && \
    !defined(MEDIUM_SESSION_CACHE)
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
    defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TICKET_HAVE_ID)
#ifdef WOLFSSL_DTLS13
    struct test_add_session_ext_params param[1] =  {
        { wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLSv1_3" }
    };
    ExpectIntEQ(test_wolfSSL_CTX_add_session_ext(param), TEST_SUCCESS);
#endif
#endif
#endif
    return EXPECT_RESULT();
}
static int test_wolfSSL_CTX_add_session_ext_tls12(void)
{
    EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
     defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
     defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
     defined(HAVE_SESSION_TICKET) && \
    !defined(TITAN_SESSION_CACHE) && \
    !defined(HUGE_SESSION_CACHE) && \
    !defined(BIG_SESSION_CACHE) && \
    !defined(MEDIUM_SESSION_CACHE)
#ifndef WOLFSSL_NO_TLS12
    struct test_add_session_ext_params param[1] =  {
        { wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLSv1_2" }
    };
    ExpectIntEQ(test_wolfSSL_CTX_add_session_ext(param), TEST_SUCCESS);
#endif
#endif
    return EXPECT_RESULT();
}
static int test_wolfSSL_CTX_add_session_ext_dtls12(void)
{
    EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
     defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
     defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
     defined(HAVE_SESSION_TICKET) && \
    !defined(TITAN_SESSION_CACHE) && \
    !defined(HUGE_SESSION_CACHE) && \
    !defined(BIG_SESSION_CACHE) && \
    !defined(MEDIUM_SESSION_CACHE)
#ifndef WOLFSSL_NO_TLS12
#ifdef WOLFSSL_DTLS
    struct test_add_session_ext_params param[1] =  {
        { wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "DTLSv1_2" }
    };
    ExpectIntEQ(test_wolfSSL_CTX_add_session_ext(param), TEST_SUCCESS);
#endif
#endif
#endif
    return EXPECT_RESULT();
}
static int test_wolfSSL_CTX_add_session_ext_tls11(void)
{
    EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
     defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
     defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
     defined(HAVE_SESSION_TICKET) && \
    !defined(TITAN_SESSION_CACHE) && \
    !defined(HUGE_SESSION_CACHE) && \
    !defined(BIG_SESSION_CACHE) && \
    !defined(MEDIUM_SESSION_CACHE)
#if !defined(NO_OLD_TLS) && ((!defined(NO_AES) && !defined(NO_AES_CBC)) || \
        !defined(NO_DES3))
    struct test_add_session_ext_params param[1] =  {
        { wolfTLSv1_1_client_method, wolfTLSv1_1_server_method, "TLSv1_1" }
    };
    ExpectIntEQ(test_wolfSSL_CTX_add_session_ext(param), TEST_SUCCESS);
#endif
#endif
    return EXPECT_RESULT();
}
static int test_wolfSSL_CTX_add_session_ext_dtls1(void)
{
    EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
     defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
     defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
     defined(HAVE_SESSION_TICKET) && \
    !defined(TITAN_SESSION_CACHE) && \
    !defined(HUGE_SESSION_CACHE) && \
    !defined(BIG_SESSION_CACHE) && \
    !defined(MEDIUM_SESSION_CACHE)
#if !defined(NO_OLD_TLS) && ((!defined(NO_AES) && !defined(NO_AES_CBC)) || \
        !defined(NO_DES3))
#ifdef WOLFSSL_DTLS
    struct test_add_session_ext_params param[1] =  {
        { wolfDTLSv1_client_method, wolfDTLSv1_server_method, "DTLSv1_0" }
    };
    ExpectIntEQ(test_wolfSSL_CTX_add_session_ext(param), TEST_SUCCESS);
#endif
#endif
#endif
    return EXPECT_RESULT();
}

#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT)
/* canned export of a session using older version 3 */
static unsigned char version_3[] = {
    0xA5, 0xA3, 0x01, 0x88, 0x00, 0x3c, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x80, 0x0C, 0x00, 0x00, 0x00,
    0x00, 0x80, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x30,
    0x05, 0x09, 0x0A, 0x01, 0x01, 0x00, 0x0D, 0x05,
    0xFE, 0xFD, 0x01, 0x25, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00,
    0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01,
    0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3F,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x05,
    0x12, 0xCF, 0x22, 0xA1, 0x9F, 0x1C, 0x39, 0x1D,
    0x31, 0x11, 0x12, 0x1D, 0x11, 0x18, 0x0D, 0x0B,
    0xF3, 0xE1, 0x4D, 0xDC, 0xB1, 0xF1, 0x39, 0x98,
    0x91, 0x6C, 0x48, 0xE5, 0xED, 0x11, 0x12, 0xA0,
    0x00, 0xF2, 0x25, 0x4C, 0x09, 0x26, 0xD1, 0x74,
    0xDF, 0x23, 0x40, 0x15, 0x6A, 0x42, 0x2A, 0x26,
    0xA5, 0xAC, 0x56, 0xD5, 0x4A, 0x20, 0xB7, 0xE9,
    0xEF, 0xEB, 0xAF, 0xA8, 0x1E, 0x23, 0x7C, 0x04,
    0xAA, 0xA1, 0x6D, 0x92, 0x79, 0x7B, 0xFA, 0x80,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x0C, 0x79, 0x7B, 0xFA, 0x80, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA1, 0x6D,
    0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x04, 0x00,
    0x10, 0x00, 0x10, 0x08, 0x02, 0x05, 0x08, 0x01,
    0x30, 0x28, 0x00, 0x00, 0x0F, 0x00, 0x02, 0x00,
    0x09, 0x31, 0x32, 0x37, 0x2E, 0x30, 0x2E, 0x30,
    0x2E, 0x31, 0xED, 0x4F
};
#endif /* defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) */

static int test_wolfSSL_dtls_export(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT)
    tcp_ready ready;
    func_args client_args;
    func_args server_args;
    THREAD_TYPE serverThread;
    callback_functions server_cbf;
    callback_functions client_cbf;
#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    InitTcpReady(&ready);

    /* set using dtls */
    XMEMSET(&client_args, 0, sizeof(func_args));
    XMEMSET(&server_args, 0, sizeof(func_args));
    XMEMSET(&server_cbf, 0, sizeof(callback_functions));
    XMEMSET(&client_cbf, 0, sizeof(callback_functions));
    server_cbf.method = wolfDTLSv1_2_server_method;
    client_cbf.method = wolfDTLSv1_2_client_method;
    server_args.callbacks = &server_cbf;
    client_args.callbacks = &client_cbf;

    server_args.signal = &ready;
    client_args.signal = &ready;

    start_thread(run_wolfssl_server, &server_args, &serverThread);
    wait_tcp_ready(&server_args);
    run_wolfssl_client(&client_args);
    join_thread(serverThread);

    ExpectTrue(client_args.return_code);
    ExpectTrue(server_args.return_code);

    FreeTcpReady(&ready);

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    if (EXPECT_SUCCESS()) {
        SOCKET_T sockfd = 0;
        WOLFSSL_CTX* ctx = NULL;
        WOLFSSL*     ssl = NULL;
        char msg[64] = "hello wolfssl!";
        char reply[1024];
        int  msgSz = (int)XSTRLEN(msg);
        byte *session, *window;
        unsigned int sessionSz = 0;
        unsigned int windowSz = 0;

#ifndef TEST_IPV6
        struct sockaddr_in peerAddr;
#else
        struct sockaddr_in6 peerAddr;
#endif /* TEST_IPV6 */

        int i;


        /* Set ctx to DTLS 1.2 */
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method()));
        ExpectNotNull(ssl = wolfSSL_new(ctx));

        /* test importing version 3 */
        ExpectIntGE(wolfSSL_dtls_import(ssl, version_3, sizeof(version_3)), 0);

        /* test importing bad length and bad version */
        version_3[2]++;
        ExpectIntLT(wolfSSL_dtls_import(ssl, version_3, sizeof(version_3)), 0);
        version_3[2]--; version_3[1] = 0XA0;
        ExpectIntLT(wolfSSL_dtls_import(ssl, version_3, sizeof(version_3)), 0);
        wolfSSL_free(ssl);
        wolfSSL_CTX_free(ctx);


    /* check storing client state after connection and storing window only */
#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    InitTcpReady(&ready);

    /* set using dtls */
    XMEMSET(&server_args, 0, sizeof(func_args));
    XMEMSET(&server_cbf, 0, sizeof(callback_functions));
    server_cbf.method = wolfDTLSv1_2_server_method;
    server_cbf.doUdp = 1;
    server_args.callbacks = &server_cbf;
    server_args.argc = 3; /* set loop_count to 3 */


    server_args.signal = &ready;
    start_thread(test_server_nofail, &server_args, &serverThread);
    wait_tcp_ready(&server_args);

    /* create and connect with client */
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method()));
    ExpectIntEQ(WOLFSSL_SUCCESS,
            wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0));
    ExpectIntEQ(WOLFSSL_SUCCESS,
          wolfSSL_CTX_use_certificate_file(ctx, cliCertFile, SSL_FILETYPE_PEM));
    ExpectIntEQ(WOLFSSL_SUCCESS,
            wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile, SSL_FILETYPE_PEM));
    tcp_connect(&sockfd, wolfSSLIP, server_args.signal->port, 1, 0, NULL);
    ExpectNotNull(ssl = wolfSSL_new(ctx));
    ExpectIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS);

    /* store server information connected too */
    XMEMSET(&peerAddr, 0, sizeof(peerAddr));
#ifndef TEST_IPV6
    peerAddr.sin_family = AF_INET;
    ExpectIntEQ(XINET_PTON(AF_INET, wolfSSLIP, &peerAddr.sin_addr),1);
    peerAddr.sin_port = XHTONS(server_args.signal->port);
#else
    peerAddr.sin6_family = AF_INET6;
    ExpectIntEQ(
        XINET_PTON(AF_INET6, wolfSSLIP, &peerAddr.sin6_addr),1);
    peerAddr.sin6_port = XHTONS(server_args.signal->port);
#endif

    ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, &peerAddr, sizeof(peerAddr)),
                    WOLFSSL_SUCCESS);

    ExpectIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_dtls_export(ssl, NULL, &sessionSz), 0);
    session = (byte*)XMALLOC(sessionSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    ExpectIntGT(wolfSSL_dtls_export(ssl, session, &sessionSz), 0);
    ExpectIntEQ(wolfSSL_write(ssl, msg, msgSz), msgSz);
    ExpectIntGT(wolfSSL_read(ssl, reply, sizeof(reply)), 0);
    ExpectIntEQ(wolfSSL_dtls_export_state_only(ssl, NULL, &windowSz), 0);
    window = (byte*)XMALLOC(windowSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    ExpectIntGT(wolfSSL_dtls_export_state_only(ssl, window, &windowSz), 0);
    wolfSSL_free(ssl);

    for (i = 1; EXPECT_SUCCESS() && i < server_args.argc; i++) {
        /* restore state */
        ExpectNotNull(ssl = wolfSSL_new(ctx));
        ExpectIntGT(wolfSSL_dtls_import(ssl, session, sessionSz), 0);
        ExpectIntGT(wolfSSL_dtls_import(ssl, window, windowSz), 0);
        ExpectIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, &peerAddr, sizeof(peerAddr)),
                    WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_write(ssl, msg, msgSz), msgSz);
        ExpectIntGE(wolfSSL_read(ssl, reply, sizeof(reply)), 0);
        ExpectIntGT(wolfSSL_dtls_export_state_only(ssl, window, &windowSz), 0);
        wolfSSL_free(ssl);
    }
    XFREE(session, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(window, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    wolfSSL_CTX_free(ctx);

    fprintf(stderr, "done and waiting for server\n");
    join_thread(serverThread);
    ExpectIntEQ(server_args.return_code, TEST_SUCCESS);

    FreeTcpReady(&ready);

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif
    }
#endif

    return EXPECT_RESULT();
}

#if defined(WOLFSSL_SESSION_EXPORT) && !defined(WOLFSSL_NO_TLS12)
#ifdef WOLFSSL_TLS13
static const byte canned_client_tls13_session_v4[] = {
    0xA7, 0xA4, 0x01, 0x18, 0x00, 0x41, 0x00, 0x00,
    0x01, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x00,
    0x00, 0x80, 0x00, 0x1C, 0x01, 0x00, 0x00, 0x01,
    0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
    0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13,
    0x01, 0x0A, 0x0F, 0x10, 0x01, 0x02, 0x09, 0x00,
    0x05, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x00,
    0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
    0x11, 0x01, 0x01, 0x00, 0x20, 0x84, 0x4F, 0x18,
    0xD8, 0xC1, 0x24, 0xD8, 0xBB, 0x17, 0x9E, 0x31,
    0xA3, 0xF8, 0xA7, 0x3C, 0xBA, 0xEC, 0xFA, 0xB4,
    0x7F, 0xC5, 0x78, 0xEB, 0x6D, 0xE3, 0x2B, 0x7B,
    0x94, 0xBE, 0x20, 0x11, 0x7E, 0x17, 0x10, 0xA7,
    0x10, 0x19, 0xEC, 0x62, 0xCC, 0xBE, 0xF5, 0x01,
    0x35, 0x3C, 0xEA, 0xEF, 0x44, 0x3C, 0x40, 0xA2,
    0xBC, 0x18, 0x43, 0xA1, 0xA1, 0x65, 0x5C, 0x48,
    0xE2, 0xF9, 0x38, 0xEB, 0x11, 0x10, 0x72, 0x7C,
    0x78, 0x22, 0x13, 0x3B, 0x19, 0x40, 0xF0, 0x73,
    0xBE, 0x96, 0x14, 0x78, 0x26, 0xB9, 0x6B, 0x2E,
    0x72, 0x22, 0x0D, 0x90, 0x94, 0xDD, 0x78, 0x77,
    0xFC, 0x0C, 0x2E, 0x63, 0x6E, 0xF0, 0x0C, 0x35,
    0x41, 0xCD, 0xF3, 0x49, 0x31, 0x08, 0xD0, 0x6F,
    0x02, 0x3D, 0xC1, 0xD3, 0xB7, 0xEE, 0x3A, 0xA0,
    0x8E, 0xA1, 0x4D, 0xC3, 0x2E, 0x5E, 0x06, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C,
    0x35, 0x41, 0xCD, 0xF3, 0x49, 0x31, 0x08, 0xD0,
    0x6F, 0x02, 0x3D, 0xC1, 0xD3, 0xB7, 0xEE, 0x3A,
    0xA0, 0x8E, 0xA1, 0x4D, 0xC3, 0x2E, 0x5E, 0x06,
    0x00, 0x10, 0x00, 0x10, 0x00, 0x0C, 0x00, 0x10,
    0x00, 0x10, 0x07, 0x02, 0x04, 0x00, 0x00, 0x20,
    0x28, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x03
};

static const byte canned_client_tls13_session_v5[] = {
    0xa7, 0xa5, 0x01, 0x19, 0x00, 0x42, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80,
    0x04, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x01,
    0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x01, 0x0a, 0x0f, 0x10,
    0x01, 0x02, 0x09, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x04,
    0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00,
    0x00, 0x11, 0x01, 0x01, 0x00, 0x20, 0x84, 0x4f, 0x18, 0xd8, 0xc1, 0x24,
    0xd8, 0xbb, 0x17, 0x9e, 0x31, 0xa3, 0xf8, 0xa7, 0x3c, 0xba, 0xec, 0xfa,
    0xb4, 0x7f, 0xc5, 0x78, 0xeb, 0x6d, 0xe3, 0x2b, 0x7b, 0x94, 0xbe, 0x20,
    0x11, 0x7e, 0x17, 0x10, 0xa7, 0x10, 0x19, 0xec, 0x62, 0xcc, 0xbe, 0xf5,
    0x01, 0x35, 0x3c, 0xea, 0xef, 0x44, 0x3c, 0x40, 0xa2, 0xbc, 0x18, 0x43,
    0xa1, 0xa1, 0x65, 0x5c, 0x48, 0xe2, 0xf9, 0x38, 0xeb, 0x11, 0x10, 0x72,
    0x7c, 0x78, 0x22, 0x13, 0x3b, 0x19, 0x40, 0xf0, 0x73, 0xbe, 0x96, 0x14,
    0x78, 0x26, 0xb9, 0x6b, 0x2e, 0x72, 0x22, 0x0d, 0x90, 0x94, 0xdd, 0x78,
    0x77, 0xfc, 0x0c, 0x2e, 0x63, 0x6e, 0xf0, 0x0c, 0x35, 0x41, 0xcd, 0xf3,
    0x49, 0x31, 0x08, 0xd0, 0x6f, 0x02, 0x3d, 0xc1, 0xd3, 0xb7, 0xee, 0x3a,
    0xa0, 0x8e, 0xa1, 0x4d, 0xc3, 0x2e, 0x5e, 0x06, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x0c, 0x35, 0x41, 0xcd, 0xf3, 0x49, 0x31, 0x08,
    0xd0, 0x6f, 0x02, 0x3d, 0xc1, 0xd3, 0xb7, 0xee, 0x3a, 0xa0, 0x8e, 0xa1,
    0x4d, 0xc3, 0x2e, 0x5e, 0x06, 0x00, 0x10, 0x00, 0x10, 0x00, 0x0c, 0x00,
    0x10, 0x00, 0x10, 0x07, 0x02, 0x04, 0x00, 0x00, 0x20, 0x28, 0x00, 0x00,
    0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03
};

static const byte canned_server_tls13_session[] = {
    0xA7, 0xA4, 0x01, 0x18, 0x00, 0x41, 0x01, 0x00,
    0x01, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x00,
    0x00, 0x80, 0x00, 0x1C, 0x01, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13,
    0x01, 0x0A, 0x0F, 0x10, 0x01, 0x02, 0x00, 0x0F,
    0x05, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x00,
    0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
    0x11, 0x01, 0x01, 0x00, 0x20, 0x84, 0x4F, 0x18,
    0xD8, 0xC1, 0x24, 0xD8, 0xBB, 0x17, 0x9E, 0x31,
    0xA3, 0xF8, 0xA7, 0x3C, 0xBA, 0xEC, 0xFA, 0xB4,
    0x7F, 0xC5, 0x78, 0xEB, 0x6D, 0xE3, 0x2B, 0x7B,
    0x94, 0xBE, 0x20, 0x11, 0x7E, 0x17, 0x10, 0xA7,
    0x10, 0x19, 0xEC, 0x62, 0xCC, 0xBE, 0xF5, 0x01,
    0x35, 0x3C, 0xEA, 0xEF, 0x44, 0x3C, 0x40, 0xA2,
    0xBC, 0x18, 0x43, 0xA1, 0xA1, 0x65, 0x5C, 0x48,
    0xE2, 0xF9, 0x38, 0xEB, 0x11, 0x10, 0x72, 0x7C,
    0x78, 0x22, 0x13, 0x3B, 0x19, 0x40, 0xF0, 0x73,
    0xBE, 0x96, 0x14, 0x78, 0x26, 0xB9, 0x6B, 0x2E,
    0x72, 0x22, 0x0D, 0x90, 0x94, 0xDD, 0x78, 0x77,
    0xFC, 0x0C, 0x2E, 0x63, 0x6E, 0xF0, 0x0C, 0x35,
    0x41, 0xCD, 0xF3, 0x49, 0x31, 0x08, 0xD0, 0x6F,
    0x02, 0x3D, 0xC1, 0xD3, 0xB7, 0xEE, 0x3A, 0xA0,
    0x8E, 0xA1, 0x4D, 0xC3, 0x2E, 0x5E, 0x06, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C,
    0xD3, 0xB7, 0xEE, 0x3A, 0xA0, 0x8E, 0xA1, 0x4D,
    0xC3, 0x2E, 0x5E, 0x06, 0x35, 0x41, 0xCD, 0xF3,
    0x49, 0x31, 0x08, 0xD0, 0x6F, 0x02, 0x3D, 0xC1,
    0x00, 0x10, 0x00, 0x10, 0x00, 0x0C, 0x00, 0x10,
    0x00, 0x10, 0x07, 0x02, 0x04, 0x00, 0x00, 0x20,
    0x28, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x04
};
#endif /* WOLFSSL_TLS13 */

static const byte canned_client_session_v4[] = {
    0xA7, 0xA4, 0x01, 0x40, 0x00, 0x41, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00,
    0x00, 0x80, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
    0x27, 0x0A, 0x0D, 0x10, 0x01, 0x01, 0x0A, 0x00,
    0x05, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03, 0x00,
    0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
    0x0A, 0x01, 0x01, 0x00, 0x20, 0x69, 0x11, 0x6D,
    0x97, 0x15, 0x6E, 0x52, 0x27, 0xD6, 0x1D, 0x1D,
    0xF5, 0x0D, 0x59, 0xA5, 0xAC, 0x2E, 0x8C, 0x0E,
    0xCB, 0x26, 0x1E, 0xE2, 0xCE, 0xBB, 0xCE, 0xE1,
    0x7D, 0xD7, 0xEF, 0xA5, 0x44, 0x80, 0x2A, 0xDE,
    0xBB, 0x75, 0xB0, 0x1D, 0x75, 0x17, 0x20, 0x4C,
    0x08, 0x05, 0x1B, 0xBA, 0x60, 0x1F, 0x6C, 0x91,
    0x8C, 0xAA, 0xBB, 0xE5, 0xA3, 0x0B, 0x12, 0x3E,
    0xC0, 0x35, 0x43, 0x1D, 0xE2, 0x10, 0xE2, 0x02,
    0x92, 0x4B, 0x8F, 0x05, 0xA9, 0x4B, 0xCC, 0x90,
    0xC3, 0x0E, 0xC2, 0x0F, 0xE9, 0x33, 0x85, 0x9B,
    0x3C, 0x19, 0x21, 0xD5, 0x62, 0xE5, 0xE1, 0x17,
    0x8F, 0x8C, 0x19, 0x52, 0xD8, 0x59, 0x10, 0x2D,
    0x20, 0x6F, 0xBA, 0xC1, 0x1C, 0xD1, 0x82, 0xC7,
    0x32, 0x1B, 0xBB, 0xCC, 0x30, 0x03, 0xD7, 0x3A,
    0xC8, 0x18, 0xED, 0x58, 0xC8, 0x11, 0xFE, 0x71,
    0x9C, 0x71, 0xD8, 0x6B, 0xE0, 0x25, 0x64, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10,
    0x00, 0x00, 0x06, 0x01, 0x04, 0x08, 0x01, 0x20,
    0x28, 0x00, 0x09, 0xE1, 0x50, 0x70, 0x02, 0x2F,
    0x7E, 0xDA, 0xBD, 0x40, 0xC5, 0x58, 0x87, 0xCE,
    0x43, 0xF3, 0xC5, 0x8F, 0xA1, 0x59, 0x93, 0xEF,
    0x7E, 0xD3, 0xD0, 0xB5, 0x87, 0x1D, 0x81, 0x54,
    0x14, 0x63, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x03
};

static const byte canned_client_session_v5[] = {
    0xa7, 0xa5, 0x01, 0x41, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
    0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x27, 0x0a, 0x0d, 0x10,
    0x01, 0x01, 0x0a, 0x00, 0x05, 0x00, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03,
    0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00,
    0x00, 0x0a, 0x01, 0x01, 0x00, 0x20, 0x69, 0x11, 0x6d, 0x97, 0x15, 0x6e,
    0x52, 0x27, 0xd6, 0x1d, 0x1d, 0xf5, 0x0d, 0x59, 0xa5, 0xac, 0x2e, 0x8c,
    0x0e, 0xcb, 0x26, 0x1e, 0xe2, 0xce, 0xbb, 0xce, 0xe1, 0x7d, 0xd7, 0xef,
    0xa5, 0x44, 0x80, 0x2a, 0xde, 0xbb, 0x75, 0xb0, 0x1d, 0x75, 0x17, 0x20,
    0x4c, 0x08, 0x05, 0x1b, 0xba, 0x60, 0x1f, 0x6c, 0x91, 0x8c, 0xaa, 0xbb,
    0xe5, 0xa3, 0x0b, 0x12, 0x3e, 0xc0, 0x35, 0x43, 0x1d, 0xe2, 0x10, 0xe2,
    0x02, 0x92, 0x4b, 0x8f, 0x05, 0xa9, 0x4b, 0xcc, 0x90, 0xc3, 0x0e, 0xc2,
    0x0f, 0xe9, 0x33, 0x85, 0x9b, 0x3c, 0x19, 0x21, 0xd5, 0x62, 0xe5, 0xe1,
    0x17, 0x8f, 0x8c, 0x19, 0x52, 0xd8, 0x59, 0x10, 0x2d, 0x20, 0x6f, 0xba,
    0xc1, 0x1c, 0xd1, 0x82, 0xc7, 0x32, 0x1b, 0xbb, 0xcc, 0x30, 0x03, 0xd7,
    0x3a, 0xc8, 0x18, 0xed, 0x58, 0xc8, 0x11, 0xfe, 0x71, 0x9c, 0x71, 0xd8,
    0x6b, 0xe0, 0x25, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x06,
    0x01, 0x04, 0x08, 0x01, 0x20, 0x28, 0x00, 0x09, 0xe1, 0x50, 0x70, 0x02,
    0x2f, 0x7e, 0xda, 0xbd, 0x40, 0xc5, 0x58, 0x87, 0xce, 0x43, 0xf3, 0xc5,
    0x8f, 0xa1, 0x59, 0x93, 0xef, 0x7e, 0xd3, 0xd0, 0xb5, 0x87, 0x1d, 0x81,
    0x54, 0x14, 0x63, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03
};


static const byte canned_server_session[] = {
    0xA7, 0xA4, 0x01, 0x40, 0x00, 0x41, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00,
    0x00, 0x80, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
    0x27, 0x08, 0x0F, 0x10, 0x01, 0x01, 0x00, 0x11,
    0x05, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03, 0x00,
    0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
    0x0A, 0x01, 0x01, 0x00, 0x20, 0x69, 0x11, 0x6D,
    0x97, 0x15, 0x6E, 0x52, 0x27, 0xD6, 0x1D, 0x1D,
    0xF5, 0x0D, 0x59, 0xA5, 0xAC, 0x2E, 0x8C, 0x0E,
    0xCB, 0x26, 0x1E, 0xE2, 0xCE, 0xBB, 0xCE, 0xE1,
    0x7D, 0xD7, 0xEF, 0xA5, 0x44, 0x80, 0x2A, 0xDE,
    0xBB, 0x75, 0xB0, 0x1D, 0x75, 0x17, 0x20, 0x4C,
    0x08, 0x05, 0x1B, 0xBA, 0x60, 0x1F, 0x6C, 0x91,
    0x8C, 0xAA, 0xBB, 0xE5, 0xA3, 0x0B, 0x12, 0x3E,
    0xC0, 0x35, 0x43, 0x1D, 0xE2, 0x10, 0xE2, 0x02,
    0x92, 0x4B, 0x8F, 0x05, 0xA9, 0x4B, 0xCC, 0x90,
    0xC3, 0x0E, 0xC2, 0x0F, 0xE9, 0x33, 0x85, 0x9B,
    0x3C, 0x19, 0x21, 0xD5, 0x62, 0xE5, 0xE1, 0x17,
    0x8F, 0x8C, 0x19, 0x52, 0xD8, 0x59, 0x10, 0x2D,
    0x20, 0x6F, 0xBA, 0xC1, 0x1C, 0xD1, 0x82, 0xC7,
    0x32, 0x1B, 0xBB, 0xCC, 0x30, 0x03, 0xD7, 0x3A,
    0xC8, 0x18, 0xED, 0x58, 0xC8, 0x11, 0xFE, 0x71,
    0x9C, 0x71, 0xD8, 0x6B, 0xE0, 0x25, 0x64, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10,
    0x00, 0x00, 0x06, 0x01, 0x04, 0x08, 0x01, 0x20,
    0x28, 0x00, 0xC5, 0x8F, 0xA1, 0x59, 0x93, 0xEF,
    0x7E, 0xD3, 0xD0, 0xB5, 0x87, 0x1D, 0x81, 0x54,
    0x14, 0x63, 0x09, 0xE1, 0x50, 0x70, 0x02, 0x2F,
    0x7E, 0xDA, 0xBD, 0x40, 0xC5, 0x58, 0x87, 0xCE,
    0x43, 0xF3, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x04
};

static THREAD_RETURN WOLFSSL_THREAD tls_export_server(void* args)
{
    SOCKET_T sockfd = 0;
    SOCKET_T clientfd = 0;
    word16 port;

    callback_functions* cbf;
    WOLFSSL_CTX* ctx = 0;
    WOLFSSL* ssl = 0;

    char msg[] = "I hear you fa shizzle!";
    char input[1024];
    int idx;

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    ((func_args*)args)->return_code = TEST_FAIL;
    cbf = ((func_args*)args)->callbacks;

#if defined(USE_WINDOWS_API)
    port = ((func_args*)args)->signal->port;
#elif defined(NO_MAIN_DRIVER) && !defined(WOLFSSL_SNIFFER) && \
     !defined(WOLFSSL_MDK_SHELL) && !defined(WOLFSSL_TIRTOS)
    /* Let tcp_listen assign port */
    port = 0;
#else
    /* Use default port */
    port = wolfSSLPort;
#endif

    /* do it here to detect failure */
    tcp_accept(&sockfd, &clientfd, (func_args*)args, port, 0, 0, 0, 0, 1, 0, 0);
    CloseSocket(sockfd);

    {
        WOLFSSL_METHOD* method = NULL;
        if (cbf != NULL && cbf->method != NULL) {
            method = cbf->method();
        }
        else {
            method = wolfTLSv1_2_server_method();
        }
        ctx = wolfSSL_CTX_new(method);
    }
    if (ctx == NULL) {
        goto done;
    }
    wolfSSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES128-SHA256");

    /* call ctx setup callback */
    if (cbf != NULL && cbf->ctx_ready != NULL) {
        cbf->ctx_ready(ctx);
    }

    ssl = wolfSSL_new(ctx);
    if (ssl == NULL) {
        goto done;
    }
    wolfSSL_set_fd(ssl, clientfd);

    /* call ssl setup callback */
    if (cbf != NULL && cbf->ssl_ready != NULL) {
        cbf->ssl_ready(ssl);
    }
    idx = wolfSSL_read(ssl, input, sizeof(input)-1);
    if (idx > 0) {
        input[idx] = '\0';
        fprintf(stderr, "Client message export/import: %s\n", input);
    }
    else {
        fprintf(stderr, "ret = %d error = %d\n", idx,
            wolfSSL_get_error(ssl, idx));
        goto done;
    }

    if (wolfSSL_write(ssl, msg, sizeof(msg)) != sizeof(msg)) {
        /*err_sys("SSL_write failed");*/
        WOLFSSL_RETURN_FROM_THREAD(0);
    }

#ifdef WOLFSSL_TIRTOS
    Task_yield();
#endif

    ((func_args*)args)->return_code = TEST_SUCCESS;

done:
    wolfSSL_shutdown(ssl);
    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);

    CloseSocket(clientfd);

#ifdef WOLFSSL_TIRTOS
    fdCloseSession(Task_self());
#endif

#if defined(NO_MAIN_DRIVER) && defined(HAVE_ECC) && defined(FP_ECC) \
                            && defined(HAVE_THREAD_LS)
    wc_ecc_fp_free();  /* free per thread cache */
#endif

#if defined(HAVE_SESSION_TICKET) && \
    ((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))
#if defined(OPENSSL_EXTRA) && defined(HAVE_AESGCM)
    OpenSSLTicketCleanup();
#elif defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
    TicketCleanup();
#endif
#endif

    WOLFSSL_RETURN_FROM_THREAD(0);
}


static void load_tls12_canned_server(WOLFSSL* ssl)
{
    int clientfd = wolfSSL_get_fd(ssl);
    AssertIntEQ(wolfSSL_tls_import(ssl, canned_server_session,
                sizeof(canned_server_session)), sizeof(canned_server_session));
    wolfSSL_set_fd(ssl, clientfd);
}


#ifdef WOLFSSL_TLS13
static void load_tls13_canned_server(WOLFSSL* ssl)
{
    int clientfd = wolfSSL_get_fd(ssl);
    AssertIntEQ(wolfSSL_tls_import(ssl, canned_server_tls13_session,
            sizeof(canned_server_tls13_session)),
            sizeof(canned_server_tls13_session));
    wolfSSL_set_fd(ssl, clientfd);
}
#endif


/* v is for version WOLFSSL_TLSV1_2 or WOLFSSL_TLSV1_3 */
static int test_wolfSSL_tls_export_run(method_provider server_method,
        method_provider client_method, ssl_callback ssl_ready,
        const byte* clientSession, int clientSessionSz, int cmpSess)
{
    EXPECT_DECLS;
    SOCKET_T sockfd = 0;
    WOLFSSL_CTX*     ctx     = 0;
    WOLFSSL*         ssl     = 0;
    char msg[64] = "hello wolfssl!";
    char reply[1024];
    word32 replySz;
    int  msgSz = (int)XSTRLEN(msg);

    tcp_ready ready;
    func_args server_args;
    THREAD_TYPE serverThread;
    callback_functions server_cbf;

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    (void)cmpSess;

    InitTcpReady(&ready);

    XMEMSET(&server_args, 0, sizeof(func_args));
    XMEMSET(&server_cbf, 0, sizeof(callback_functions));
    server_cbf.method = server_method;
    server_cbf.ssl_ready = ssl_ready;
    ExpectNotNull(ctx = wolfSSL_CTX_new(client_method()));
    server_args.callbacks = &server_cbf;
    server_args.signal    = &ready;

    start_thread(tls_export_server, &server_args, &serverThread);
    wait_tcp_ready(&server_args);


#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    ExpectNotNull(ssl = wolfSSL_new(ctx));
    tcp_connect(&sockfd, wolfSSLIP, ready.port, 0, 0, ssl);
    ExpectIntEQ(wolfSSL_tls_import(ssl, clientSession, clientSessionSz),
                clientSessionSz);
    replySz = sizeof(reply);
    ExpectIntGT(wolfSSL_tls_export(ssl, (byte*)reply, &replySz), 0);
#if !defined(NO_PSK) && defined(HAVE_ANON)
    if (cmpSess) {
        /* index 20 has is setting if PSK was on and 49 is if anon is allowed */
        ExpectIntEQ(replySz, clientSessionSz);
        ExpectBufEQ(reply, clientSession, replySz);
    }
#endif
    wolfSSL_set_fd(ssl, sockfd);

    ExpectIntEQ(wolfSSL_write(ssl, msg, msgSz), msgSz);
    ExpectIntGT(wolfSSL_read(ssl, reply, sizeof(reply)-1), 0);

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);

    CloseSocket(sockfd);

#ifdef WOLFSSL_TIRTOS
    fdCloseSession(Task_self());
#endif

#if defined(NO_MAIN_DRIVER) && defined(HAVE_ECC) && defined(FP_ECC) \
                            && defined(HAVE_THREAD_LS)
    wc_ecc_fp_free();  /* free per thread cache */
#endif

    join_thread(serverThread);

    ExpectIntEQ(server_args.return_code, TEST_SUCCESS);
    FreeTcpReady(&ready);

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    return EXPECT_RESULT();
}
#endif

static int test_wolfSSL_tls_export(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_SESSION_EXPORT) && !defined(WOLFSSL_NO_TLS12)
    EXPECT_TEST(test_wolfSSL_tls_export_run(wolfTLSv1_2_server_method,
        wolfTLSv1_2_client_method, load_tls12_canned_server,
        canned_client_session_v4, sizeof(canned_client_session_v4), 0));
    EXPECT_TEST(test_wolfSSL_tls_export_run(wolfTLSv1_2_server_method,
        wolfTLSv1_2_client_method, load_tls12_canned_server,
        canned_client_session_v5, sizeof(canned_client_session_v5), 1));
    #ifdef WOLFSSL_TLS13
    EXPECT_TEST(test_wolfSSL_tls_export_run(wolfTLSv1_3_server_method,
        wolfTLSv1_3_client_method, load_tls13_canned_server,
        canned_client_tls13_session_v4, sizeof(canned_client_tls13_session_v4),
        0));
    EXPECT_TEST(test_wolfSSL_tls_export_run(wolfTLSv1_3_server_method,
        wolfTLSv1_3_client_method, load_tls13_canned_server,
        canned_client_tls13_session_v5, sizeof(canned_client_tls13_session_v5),
        1));
    #endif
#endif

    return EXPECT_RESULT();
}

/*----------------------------------------------------------------------------*
 | TLS extensions tests
 *----------------------------------------------------------------------------*/

#ifdef ENABLE_TLS_CALLBACK_TEST
/* Connection test runner - generic */
static void test_wolfSSL_client_server(callback_functions* client_callbacks,
                                       callback_functions* server_callbacks)
{
    tcp_ready ready;
    func_args client_args;
    func_args server_args;
    THREAD_TYPE serverThread;

    XMEMSET(&client_args, 0, sizeof(func_args));
    XMEMSET(&server_args, 0, sizeof(func_args));

    StartTCP();

    client_args.callbacks = client_callbacks;
    server_args.callbacks = server_callbacks;

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    /* RUN Server side */
    InitTcpReady(&ready);

    server_args.signal = &ready;
    client_args.signal = &ready;
    start_thread(run_wolfssl_server, &server_args, &serverThread);
    wait_tcp_ready(&server_args);

    /* RUN Client side */
    run_wolfssl_client(&client_args);
    join_thread(serverThread);

    FreeTcpReady(&ready);
#ifdef WOLFSSL_TIRTOS
    fdCloseSession(Task_self());
#endif

    client_callbacks->return_code = client_args.return_code;
    server_callbacks->return_code = server_args.return_code;
}
#endif /* ENABLE_TLS_CALLBACK_TEST */


#ifdef HAVE_SNI
static int test_wolfSSL_UseSNI_params(void)
{
    EXPECT_DECLS;
#if !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
    WOLFSSL     *ssl = wolfSSL_new(ctx);

    ExpectNotNull(ctx);
    ExpectNotNull(ssl);

    /* invalid [ctx|ssl] */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_UseSNI(NULL, 0, "ctx", 3));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseSNI(    NULL, 0, "ssl", 3));
    /* invalid type */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_UseSNI(ctx, (byte)-1, "ctx", 3));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseSNI(    ssl, (byte)-1, "ssl", 3));
    /* invalid data */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_UseSNI(ctx,  0, NULL,  3));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseSNI(    ssl,  0, NULL,  3));
    /* success case */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_UseSNI(ctx,  0, "ctx", 3));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSNI(    ssl,  0, "ssl", 3));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif /* !NO_WOLFSSL_CLIENT */

    return EXPECT_RESULT();
}

/* BEGIN of connection tests callbacks */
static void use_SNI_at_ctx(WOLFSSL_CTX* ctx)
{
    AssertIntEQ(WOLFSSL_SUCCESS,
        wolfSSL_CTX_UseSNI(ctx, WOLFSSL_SNI_HOST_NAME, "www.wolfssl.com", 15));
}

static void use_SNI_at_ssl(WOLFSSL* ssl)
{
    AssertIntEQ(WOLFSSL_SUCCESS,
             wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, "www.wolfssl.com", 15));
}

static void different_SNI_at_ssl(WOLFSSL* ssl)
{
    AssertIntEQ(WOLFSSL_SUCCESS,
             wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, "ww2.wolfssl.com", 15));
}

static void use_SNI_WITH_CONTINUE_at_ssl(WOLFSSL* ssl)
{
    use_SNI_at_ssl(ssl);
    wolfSSL_SNI_SetOptions(ssl, WOLFSSL_SNI_HOST_NAME,
                                              WOLFSSL_SNI_CONTINUE_ON_MISMATCH);
}

static void use_SNI_WITH_FAKE_ANSWER_at_ssl(WOLFSSL* ssl)
{
    use_SNI_at_ssl(ssl);
    wolfSSL_SNI_SetOptions(ssl, WOLFSSL_SNI_HOST_NAME,
                                                WOLFSSL_SNI_ANSWER_ON_MISMATCH);
}

static void use_MANDATORY_SNI_at_ctx(WOLFSSL_CTX* ctx)
{
    use_SNI_at_ctx(ctx);
    wolfSSL_CTX_SNI_SetOptions(ctx, WOLFSSL_SNI_HOST_NAME,
                                                  WOLFSSL_SNI_ABORT_ON_ABSENCE);
}

static void use_MANDATORY_SNI_at_ssl(WOLFSSL* ssl)
{
    use_SNI_at_ssl(ssl);
    wolfSSL_SNI_SetOptions(ssl, WOLFSSL_SNI_HOST_NAME,
                                                  WOLFSSL_SNI_ABORT_ON_ABSENCE);
}

static void use_PSEUDO_MANDATORY_SNI_at_ctx(WOLFSSL_CTX* ctx)
{
    use_SNI_at_ctx(ctx);
    wolfSSL_CTX_SNI_SetOptions(ctx, WOLFSSL_SNI_HOST_NAME,
                 WOLFSSL_SNI_ANSWER_ON_MISMATCH | WOLFSSL_SNI_ABORT_ON_ABSENCE);
}

static void verify_UNKNOWN_SNI_on_server(WOLFSSL* ssl)
{
    AssertIntEQ(WC_NO_ERR_TRACE(UNKNOWN_SNI_HOST_NAME_E),
                wolfSSL_get_error(ssl, 0));
}

static void verify_SNI_ABSENT_on_server(WOLFSSL* ssl)
{
    AssertIntEQ(WC_NO_ERR_TRACE(SNI_ABSENT_ERROR), wolfSSL_get_error(ssl, 0));
}

static void verify_SNI_no_matching(WOLFSSL* ssl)
{
    byte type = WOLFSSL_SNI_HOST_NAME;
    void* request = (void*) &type; /* to be overwritten */

    AssertIntEQ(WOLFSSL_SNI_NO_MATCH, wolfSSL_SNI_Status(ssl, type));
    AssertNotNull(request);
    AssertIntEQ(0, wolfSSL_SNI_GetRequest(ssl, type, &request));
    AssertNull(request);
}

static void verify_SNI_real_matching(WOLFSSL* ssl)
{
    byte type = WOLFSSL_SNI_HOST_NAME;
    void* request = NULL;

    AssertIntEQ(WOLFSSL_SNI_REAL_MATCH, wolfSSL_SNI_Status(ssl, type));
    AssertIntEQ(15, wolfSSL_SNI_GetRequest(ssl, type, &request));
    AssertNotNull(request);
    AssertStrEQ("www.wolfssl.com", (char*)request);
}

static void verify_SNI_fake_matching(WOLFSSL* ssl)
{
    byte type = WOLFSSL_SNI_HOST_NAME;
    void* request = NULL;

    AssertIntEQ(WOLFSSL_SNI_FAKE_MATCH, wolfSSL_SNI_Status(ssl, type));
    AssertIntEQ(15, wolfSSL_SNI_GetRequest(ssl, type, &request));
    AssertNotNull(request);
    AssertStrEQ("ww2.wolfssl.com", (char*)request);
}

static void verify_FATAL_ERROR_on_client(WOLFSSL* ssl)
{
    AssertIntEQ(WC_NO_ERR_TRACE(FATAL_ERROR), wolfSSL_get_error(ssl, 0));
}
/* END of connection tests callbacks */

static int test_wolfSSL_UseSNI_connection(void)
{
    int res = TEST_SKIPPED;
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
    callback_functions client_cb;
    callback_functions server_cb;
    size_t i;
#ifdef WOLFSSL_STATIC_MEMORY
    byte cliMem[TEST_TLS_STATIC_MEMSZ];
    byte svrMem[TEST_TLS_STATIC_MEMSZ];
#endif
    struct {
        method_provider client_meth;
        method_provider server_meth;
    #ifdef WOLFSSL_STATIC_MEMORY
        wolfSSL_method_func client_meth_ex;
        wolfSSL_method_func server_meth_ex;
    #endif
    } methods[] = {
#if defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_TLS13)
        {wolfSSLv23_client_method, wolfSSLv23_server_method
        #ifdef WOLFSSL_STATIC_MEMORY
            ,wolfSSLv23_client_method_ex, wolfSSLv23_server_method_ex
        #endif
        },
#endif
#ifndef WOLFSSL_NO_TLS12
        {wolfTLSv1_2_client_method, wolfTLSv1_2_server_method
        #ifdef WOLFSSL_STATIC_MEMORY
            ,wolfTLSv1_2_client_method_ex, wolfTLSv1_2_server_method_ex
        #endif
        },
#endif
#ifdef WOLFSSL_TLS13
        {wolfTLSv1_3_client_method, wolfTLSv1_3_server_method
        #ifdef WOLFSSL_STATIC_MEMORY
            ,wolfTLSv1_3_client_method_ex, wolfTLSv1_3_server_method_ex
        #endif
        },
#endif
    };
    size_t methodsSz = sizeof(methods) / sizeof(*methods);

    for (i = 0; i < methodsSz; i++) {
        XMEMSET(&client_cb, 0, sizeof(callback_functions));
        XMEMSET(&server_cb, 0, sizeof(callback_functions));
        client_cb.method = methods[i].client_meth;
        server_cb.method = methods[i].server_meth;
        client_cb.devId = testDevId;
        server_cb.devId = testDevId;
    #ifdef WOLFSSL_STATIC_MEMORY
        client_cb.method_ex = methods[i].client_meth_ex;
        server_cb.method_ex = methods[i].server_meth_ex;
        client_cb.mem = cliMem;
        client_cb.memSz = (word32)sizeof(cliMem);
        server_cb.mem = svrMem;
        server_cb.memSz = (word32)sizeof(svrMem);;
    #endif

        /* success case at ctx */
        fprintf(stderr, "\n\tsuccess case at ctx\n");
        client_cb.ctx_ready = use_SNI_at_ctx; client_cb.ssl_ready = NULL; client_cb.on_result = NULL;
        server_cb.ctx_ready = use_SNI_at_ctx; server_cb.ssl_ready = NULL; server_cb.on_result = verify_SNI_real_matching;
        test_wolfSSL_client_server(&client_cb, &server_cb);

        /* success case at ssl */
        fprintf(stderr, "\tsuccess case at ssl\n");
        client_cb.ctx_ready = NULL; client_cb.ssl_ready = use_SNI_at_ssl; client_cb.on_result = verify_SNI_real_matching;
        server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_SNI_at_ssl; server_cb.on_result = verify_SNI_real_matching;
        test_wolfSSL_client_server(&client_cb, &server_cb);

        /* default mismatch behavior */
        fprintf(stderr, "\tdefault mismatch behavior\n");
        client_cb.ctx_ready = NULL; client_cb.ssl_ready = different_SNI_at_ssl; client_cb.on_result = verify_FATAL_ERROR_on_client;
        server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_SNI_at_ssl;       server_cb.on_result = verify_UNKNOWN_SNI_on_server;
        test_wolfSSL_client_server(&client_cb, &server_cb);

        /* continue on mismatch */
        fprintf(stderr, "\tcontinue on mismatch\n");
        client_cb.ctx_ready = NULL; client_cb.ssl_ready = different_SNI_at_ssl;         client_cb.on_result = NULL;
        server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_SNI_WITH_CONTINUE_at_ssl; server_cb.on_result = verify_SNI_no_matching;
        test_wolfSSL_client_server(&client_cb, &server_cb);

        /* fake answer on mismatch */
        fprintf(stderr, "\tfake answer on mismatch\n");
        client_cb.ctx_ready = NULL; client_cb.ssl_ready = different_SNI_at_ssl;            client_cb.on_result = NULL;
        server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_SNI_WITH_FAKE_ANSWER_at_ssl; server_cb.on_result = verify_SNI_fake_matching;
        test_wolfSSL_client_server(&client_cb, &server_cb);

        /* sni abort - success */
        fprintf(stderr, "\tsni abort - success\n");
        client_cb.ctx_ready = use_SNI_at_ctx;           client_cb.ssl_ready = NULL; client_cb.on_result = NULL;
        server_cb.ctx_ready = use_MANDATORY_SNI_at_ctx; server_cb.ssl_ready = NULL; server_cb.on_result = verify_SNI_real_matching;
        test_wolfSSL_client_server(&client_cb, &server_cb);

        /* sni abort - abort when absent (ctx) */
        fprintf(stderr, "\tsni abort - abort when absent (ctx)\n");
        client_cb.ctx_ready = NULL;                     client_cb.ssl_ready = NULL; client_cb.on_result = verify_FATAL_ERROR_on_client;
        server_cb.ctx_ready = use_MANDATORY_SNI_at_ctx; server_cb.ssl_ready = NULL; server_cb.on_result = verify_SNI_ABSENT_on_server;
        test_wolfSSL_client_server(&client_cb, &server_cb);

        /* sni abort - abort when absent (ssl) */
        fprintf(stderr, "\tsni abort - abort when absent (ssl)\n");
        client_cb.ctx_ready = NULL; client_cb.ssl_ready = NULL;                     client_cb.on_result = verify_FATAL_ERROR_on_client;
        server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_MANDATORY_SNI_at_ssl; server_cb.on_result = verify_SNI_ABSENT_on_server;
        test_wolfSSL_client_server(&client_cb, &server_cb);

        /* sni abort - success when overwritten */
        fprintf(stderr, "\tsni abort - success when overwritten\n");
        client_cb.ctx_ready = NULL;                     client_cb.ssl_ready = NULL;           client_cb.on_result = NULL;
        server_cb.ctx_ready = use_MANDATORY_SNI_at_ctx; server_cb.ssl_ready = use_SNI_at_ssl; server_cb.on_result = verify_SNI_no_matching;
        test_wolfSSL_client_server(&client_cb, &server_cb);

        /* sni abort - success when allowing mismatches */
        fprintf(stderr, "\tsni abort - success when allowing mismatches\n");
        client_cb.ctx_ready = NULL;                            client_cb.ssl_ready = different_SNI_at_ssl; client_cb.on_result = NULL;
        server_cb.ctx_ready = use_PSEUDO_MANDATORY_SNI_at_ctx; server_cb.ssl_ready = NULL;                 server_cb.on_result = verify_SNI_fake_matching;
        test_wolfSSL_client_server(&client_cb, &server_cb);
    }

    res = TEST_RES_CHECK(1);
#endif /* !NO_WOLFSSL_CLIENT && !NO_WOLFSSL_SERVER */

    return res;
}

static int test_wolfSSL_SNI_GetFromBuffer(void)
{
    EXPECT_DECLS;
    byte buff[] = { /* www.paypal.com */
        0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x60, 0x03, 0x03, 0x5c,
        0xc4, 0xb3, 0x8c, 0x87, 0xef, 0xa4, 0x09, 0xe0, 0x02, 0xab, 0x86, 0xca,
        0x76, 0xf0, 0x9e, 0x01, 0x65, 0xf6, 0xa6, 0x06, 0x13, 0x1d, 0x0f, 0xa5,
        0x79, 0xb0, 0xd4, 0x77, 0x22, 0xeb, 0x1a, 0x00, 0x00, 0x16, 0x00, 0x6b,
        0x00, 0x67, 0x00, 0x39, 0x00, 0x33, 0x00, 0x3d, 0x00, 0x3c, 0x00, 0x35,
        0x00, 0x2f, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x21,
        0x00, 0x00, 0x00, 0x13, 0x00, 0x11, 0x00, 0x00, 0x0e, 0x77, 0x77, 0x77,
        0x2e, 0x70, 0x61, 0x79, 0x70, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x00,
        0x0d, 0x00, 0x06, 0x00, 0x04, 0x04, 0x01, 0x02, 0x01
    };

    byte buff2[] = { /* api.textmate.org */
        0x16, 0x03, 0x01, 0x00, 0xc6, 0x01, 0x00, 0x00, 0xc2, 0x03, 0x03, 0x52,
        0x8b, 0x7b, 0xca, 0x69, 0xec, 0x97, 0xd5, 0x08, 0x03, 0x50, 0xfe, 0x3b,
        0x99, 0xc3, 0x20, 0xce, 0xa5, 0xf6, 0x99, 0xa5, 0x71, 0xf9, 0x57, 0x7f,
        0x04, 0x38, 0xf6, 0x11, 0x0b, 0xb8, 0xd3, 0x00, 0x00, 0x5e, 0x00, 0xff,
        0xc0, 0x24, 0xc0, 0x23, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x07, 0xc0, 0x08,
        0xc0, 0x28, 0xc0, 0x27, 0xc0, 0x14, 0xc0, 0x13, 0xc0, 0x11, 0xc0, 0x12,
        0xc0, 0x26, 0xc0, 0x25, 0xc0, 0x2a, 0xc0, 0x29, 0xc0, 0x05, 0xc0, 0x04,
        0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x0f, 0xc0, 0x0e, 0xc0, 0x0c, 0xc0, 0x0d,
        0x00, 0x3d, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x05, 0x00, 0x04, 0x00, 0x35,
        0x00, 0x0a, 0x00, 0x67, 0x00, 0x6b, 0x00, 0x33, 0x00, 0x39, 0x00, 0x16,
        0x00, 0xaf, 0x00, 0xae, 0x00, 0x8d, 0x00, 0x8c, 0x00, 0x8a, 0x00, 0x8b,
        0x00, 0xb1, 0x00, 0xb0, 0x00, 0x2c, 0x00, 0x3b, 0x01, 0x00, 0x00, 0x3b,
        0x00, 0x00, 0x00, 0x15, 0x00, 0x13, 0x00, 0x00, 0x10, 0x61, 0x70, 0x69,
        0x2e, 0x74, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x74, 0x65, 0x2e, 0x6f, 0x72,
        0x67, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
        0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x0c, 0x00,
        0x0a, 0x05, 0x01, 0x04, 0x01, 0x02, 0x01, 0x04, 0x03, 0x02, 0x03
    };

    byte buff3[] = { /* no sni extension */
        0x16, 0x03, 0x03, 0x00, 0x4d, 0x01, 0x00, 0x00, 0x49, 0x03, 0x03, 0xea,
        0xa1, 0x9f, 0x60, 0xdd, 0x52, 0x12, 0x13, 0xbd, 0x84, 0x34, 0xd5, 0x1c,
        0x38, 0x25, 0xa8, 0x97, 0xd2, 0xd5, 0xc6, 0x45, 0xaf, 0x1b, 0x08, 0xe4,
        0x1e, 0xbb, 0xdf, 0x9d, 0x39, 0xf0, 0x65, 0x00, 0x00, 0x16, 0x00, 0x6b,
        0x00, 0x67, 0x00, 0x39, 0x00, 0x33, 0x00, 0x3d, 0x00, 0x3c, 0x00, 0x35,
        0x00, 0x2f, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x0a,
        0x00, 0x0d, 0x00, 0x06, 0x00, 0x04, 0x04, 0x01, 0x02, 0x01
    };

    byte buff4[] = { /* last extension has zero size */
        0x16, 0x03, 0x01, 0x00, 0xba, 0x01, 0x00, 0x00,
        0xb6, 0x03, 0x03, 0x83, 0xa3, 0xe6, 0xdc, 0x16, 0xa1, 0x43, 0xe9, 0x45,
        0x15, 0xbd, 0x64, 0xa9, 0xb6, 0x07, 0xb4, 0x50, 0xc6, 0xdd, 0xff, 0xc2,
        0xd3, 0x0d, 0x4f, 0x36, 0xb4, 0x41, 0x51, 0x61, 0xc1, 0xa5, 0x9e, 0x00,
        0x00, 0x28, 0xcc, 0x14, 0xcc, 0x13, 0xc0, 0x2b, 0xc0, 0x2f, 0x00, 0x9e,
        0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x14, 0xc0, 0x07, 0xc0, 0x11,
        0x00, 0x33, 0x00, 0x32, 0x00, 0x39, 0x00, 0x9c, 0x00, 0x2f, 0x00, 0x35,
        0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00, 0x00, 0x65, 0xff, 0x01,
        0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x17, 0x00,
        0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00,
        0x00, 0x33, 0x74, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x19, 0x06,
        0x73, 0x70, 0x64, 0x79, 0x2f, 0x33, 0x08, 0x73, 0x70, 0x64, 0x79, 0x2f,
        0x33, 0x2e, 0x31, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31,
        0x75, 0x50, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x0d, 0x00, 0x12, 0x00, 0x10, 0x04, 0x01, 0x05, 0x01, 0x02,
        0x01, 0x04, 0x03, 0x05, 0x03, 0x02, 0x03, 0x04, 0x02, 0x02, 0x02, 0x00,
        0x12, 0x00, 0x00
    };

    byte buff5[] = { /* SSL v2.0 client hello */
        0x00, 0x2b, 0x01, 0x03, 0x01, 0x00, 0x09, 0x00, 0x00,
        /* dummy bytes below, just to pass size check */
        0xb6, 0x03, 0x03, 0x83, 0xa3, 0xe6, 0xdc, 0x16, 0xa1, 0x43, 0xe9, 0x45,
        0x15, 0xbd, 0x64, 0xa9, 0xb6, 0x07, 0xb4, 0x50, 0xc6, 0xdd, 0xff, 0xc2,
        0xd3, 0x0d, 0x4f, 0x36, 0xb4, 0x41, 0x51, 0x61, 0xc1, 0xa5, 0x9e, 0x00,
    };

    byte result[32] = {0};
    word32 length   = 32;

    ExpectIntEQ(0, wolfSSL_SNI_GetFromBuffer(buff4, sizeof(buff4),
                                                           0, result, &length));

    ExpectIntEQ(0, wolfSSL_SNI_GetFromBuffer(buff3, sizeof(buff3),
                                                           0, result, &length));

    ExpectIntEQ(0, wolfSSL_SNI_GetFromBuffer(buff2, sizeof(buff2),
                                                           1, result, &length));

    ExpectIntEQ(WC_NO_ERR_TRACE(BUFFER_ERROR), wolfSSL_SNI_GetFromBuffer(buff, sizeof(buff),
                                                           0, result, &length));
    buff[0] = 0x16;

    ExpectIntEQ(WC_NO_ERR_TRACE(BUFFER_ERROR), wolfSSL_SNI_GetFromBuffer(buff, sizeof(buff),
                                                           0, result, &length));
    buff[1] = 0x03;

    ExpectIntEQ(WC_NO_ERR_TRACE(SNI_UNSUPPORTED), wolfSSL_SNI_GetFromBuffer(buff,
                                           sizeof(buff), 0, result, &length));
    buff[2] = 0x03;

    ExpectIntEQ(WC_NO_ERR_TRACE(INCOMPLETE_DATA), wolfSSL_SNI_GetFromBuffer(buff,
                                           sizeof(buff), 0, result, &length));
    buff[4] = 0x64;

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SNI_GetFromBuffer(buff, sizeof(buff),
                                                           0, result, &length));
    if (EXPECT_SUCCESS())
        result[length] = 0;
    ExpectStrEQ("www.paypal.com", (const char*) result);

    length = 32;

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SNI_GetFromBuffer(buff2, sizeof(buff2),
                                                           0, result, &length));
    if (EXPECT_SUCCESS())
        result[length] = 0;
    ExpectStrEQ("api.textmate.org", (const char*) result);

    /* SSL v2.0 tests */
    ExpectIntEQ(WC_NO_ERR_TRACE(SNI_UNSUPPORTED), wolfSSL_SNI_GetFromBuffer(buff5,
                                          sizeof(buff5), 0, result, &length));

    buff5[2] = 0x02;
    ExpectIntEQ(WC_NO_ERR_TRACE(BUFFER_ERROR), wolfSSL_SNI_GetFromBuffer(buff5,
                                          sizeof(buff5), 0, result, &length));

    buff5[2] = 0x01; buff5[6] = 0x08;
    ExpectIntEQ(WC_NO_ERR_TRACE(BUFFER_ERROR), wolfSSL_SNI_GetFromBuffer(buff5,
                                          sizeof(buff5), 0, result, &length));

    buff5[6] = 0x09; buff5[8] = 0x01;
    ExpectIntEQ(WC_NO_ERR_TRACE(BUFFER_ERROR), wolfSSL_SNI_GetFromBuffer(buff5,
                                          sizeof(buff5), 0, result, &length));

    return EXPECT_RESULT();
}

#endif /* HAVE_SNI */

#endif /* HAVE_IO_TESTS_DEPENDENCIES */


#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) && \
    defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
/* Dummy peer functions to satisfy the exporter/importer */
static int test_wolfSSL_dtls_export_peers_get_peer(WOLFSSL* ssl, char* ip,
        int* ipSz, unsigned short* port, int* fam)
{
    (void)ssl;
    ip[0] = -1;
    *ipSz = 1;
    *port = 1;
    *fam = 2;
    return 1;
}

static int test_wolfSSL_dtls_export_peers_set_peer(WOLFSSL* ssl, char* ip,
        int ipSz, unsigned short port, int fam)
{
    (void)ssl;
    if (ip[0] != -1 || ipSz != 1 || port != 1 || fam != 2)
        return 0;
    return 1;
}

static int test_wolfSSL_dtls_export_peers_on_handshake(WOLFSSL_CTX **ctx,
        WOLFSSL **ssl)
{
    EXPECT_DECLS;
    unsigned char* sessionBuf = NULL;
    unsigned int sessionSz = 0;
    void* ioWriteCtx = wolfSSL_GetIOWriteCtx(*ssl);
    void* ioReadCtx = wolfSSL_GetIOReadCtx(*ssl);

    wolfSSL_CTX_SetIOGetPeer(*ctx, test_wolfSSL_dtls_export_peers_get_peer);
    wolfSSL_CTX_SetIOSetPeer(*ctx, test_wolfSSL_dtls_export_peers_set_peer);
    ExpectIntGE(wolfSSL_dtls_export(*ssl, NULL, &sessionSz), 0);
    ExpectNotNull(sessionBuf =
        (unsigned char*)XMALLOC(sessionSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER));
    ExpectIntGE(wolfSSL_dtls_export(*ssl, sessionBuf, &sessionSz), 0);
    wolfSSL_free(*ssl);
    *ssl = NULL;
    ExpectNotNull(*ssl = wolfSSL_new(*ctx));
    ExpectIntGE(wolfSSL_dtls_import(*ssl, sessionBuf, sessionSz), 0);
    wolfSSL_SetIOWriteCtx(*ssl, ioWriteCtx);
    wolfSSL_SetIOReadCtx(*ssl, ioReadCtx);

    XFREE(sessionBuf, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    return EXPECT_RESULT();
}
#endif

static int test_wolfSSL_dtls_export_peers(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) && \
    defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
    test_ssl_cbf client_cbf;
    test_ssl_cbf server_cbf;
    size_t i, j;
    struct test_params {
        method_provider client_meth;
        method_provider server_meth;
        const char* dtls_version;
    } params[] = {
#ifndef NO_OLD_TLS
        {wolfDTLSv1_client_method, wolfDTLSv1_server_method, "1.0"},
#endif
        {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "1.2"},
        /* TODO DTLS 1.3 exporting not supported
#ifdef WOLFSSL_DTLS13
        {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "1.3"},
#endif
         */
    };

    for (i = 0; i < sizeof(params)/sizeof(*params); i++) {
        for (j = 0; j <= 3; j++) {
            XMEMSET(&client_cbf, 0, sizeof(client_cbf));
            XMEMSET(&server_cbf, 0, sizeof(server_cbf));

            printf("\n\tTesting DTLS %s connection;", params[i].dtls_version);

            client_cbf.method = params[i].client_meth;
            server_cbf.method = params[i].server_meth;

            if (j & 0x1) {
                client_cbf.on_handshake =
                        test_wolfSSL_dtls_export_peers_on_handshake;
                printf(" With client export;");
            }
            if (j & 0x2) {
                server_cbf.on_handshake =
                        test_wolfSSL_dtls_export_peers_on_handshake;
                printf(" With server export;");
            }

            printf("\n");

            ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
                &server_cbf, NULL), TEST_SUCCESS);
            if (!EXPECT_SUCCESS())
                break;
        }
    }
#endif
    return EXPECT_RESULT();
}

/* Test that ImportKeyState correctly skips extra window words when importing
 * state from a peer compiled with a larger WOLFSSL_DTLS_WINDOW_WORDS. */
static int test_wolfSSL_dtls_import_state_extra_window_words(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL*     ssl = NULL;
    unsigned int stateSz = 0;
    byte*        state = NULL;
    byte*        modified = NULL;
    unsigned int modifiedSz;
    word16       origKeyLen;
    word16       origTotalLen;
    /* Offset from start of key state data to the first wordCount field.
     * Layout: 4 sequence numbers (16 bytes) + DTLS-specific fields (42 bytes) +
     * encryptSz(4) + padSz(4) + encryptionOn(1) + decryptedCur(1) = 68 */
    const int keyStateWindowOffset = 68;
    /* Buffer header: 2 proto + 2 total_len + 2 key_len = 6 */
    const int headerSz = 6;
    int idx, modIdx;
    int extraPerWindow = 2 * (int)sizeof(word32); /* 8 bytes extra per window */
    int totalExtra = extraPerWindow * 2; /* 16 bytes extra total */

    /* Create DTLS context and SSL object */
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* Get required buffer size and export state-only */
    ExpectIntEQ(wolfSSL_dtls_export_state_only(ssl, NULL, &stateSz), 0);
    ExpectIntGT((int)stateSz, 0);
    state = (byte*)XMALLOC(stateSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    ExpectNotNull(state);
    ExpectIntGT(wolfSSL_dtls_export_state_only(ssl, state, &stateSz), 0);

    /* Build a modified buffer that simulates a peer with
     * WOLFSSL_DTLS_WINDOW_WORDS = WOLFSSL_DTLS_WINDOW_WORDS + 2.
     * Each window section gets 2 extra word32 values (8 bytes).
     * Two windows => 16 extra bytes total. */
    modifiedSz = stateSz + totalExtra;
    modified = (byte*)XMALLOC(modifiedSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    ExpectNotNull(modified);

    if (EXPECT_SUCCESS()) {
        int windowWords = WOLFSSL_DTLS_WINDOW_WORDS;
        int windowDataSz = windowWords * (int)sizeof(word32);

        XMEMSET(modified, 0, modifiedSz);

        /* Copy protocol/version bytes (first 2 bytes) */
        XMEMCPY(modified, state, 2);

        /* Read original total length and key state length */
        ato16(state + 2, &origTotalLen);
        ato16(state + 4, &origKeyLen);

        /* Write updated total length and key state length */
        c16toa((word16)(origTotalLen + totalExtra), modified + 2);
        c16toa((word16)(origKeyLen + totalExtra), modified + 4);

        /* Copy key state data up to first window section */
        idx = headerSz;
        modIdx = headerSz;
        XMEMCPY(modified + modIdx, state + idx, keyStateWindowOffset);
        idx += keyStateWindowOffset;
        modIdx += keyStateWindowOffset;

        /* First window: write increased wordCount */
        c16toa((word16)(windowWords + 2), modified + modIdx);
        idx += OPAQUE16_LEN;
        modIdx += OPAQUE16_LEN;

        /* Copy original window data */
        XMEMCPY(modified + modIdx, state + idx, windowDataSz);
        idx += windowDataSz;
        modIdx += windowDataSz;

        /* Insert 2 extra word32 padding values */
        XMEMSET(modified + modIdx, 0, extraPerWindow);
        modIdx += extraPerWindow;

        /* Second window (prevWindow): same transformation */
        c16toa((word16)(windowWords + 2), modified + modIdx);
        idx += OPAQUE16_LEN;
        modIdx += OPAQUE16_LEN;

        XMEMCPY(modified + modIdx, state + idx, windowDataSz);
        idx += windowDataSz;
        modIdx += windowDataSz;

        XMEMSET(modified + modIdx, 0, extraPerWindow);
        modIdx += extraPerWindow;

        /* Copy remainder of key state (after both windows) */
        XMEMCPY(modified + modIdx, state + idx, stateSz - idx);
    }

    /* Import the modified state - should succeed with the fix */
    wolfSSL_free(ssl);
    ssl = NULL;
    ExpectNotNull(ssl = wolfSSL_new(ctx));
    ExpectIntGT(wolfSSL_dtls_import(ssl, modified, modifiedSz), 0);

    XFREE(state, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(modified, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_UseTrustedCA(void)
{
    EXPECT_DECLS;
#if defined(HAVE_TRUSTED_CA) && !defined(NO_CERTS) && !defined(NO_FILESYSTEM) \
    && !defined(NO_RSA)
#if !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    WOLFSSL_CTX *ctx = NULL;
    WOLFSSL     *ssl = NULL;
    byte        id[20];

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull((ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())));
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, WOLFSSL_FILETYPE_PEM));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, WOLFSSL_FILETYPE_PEM));
#else
    ExpectNotNull((ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())));
#endif
    ExpectNotNull((ssl = wolfSSL_new(ctx)));
    XMEMSET(id, 0, sizeof(id));

    /* error cases */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(NULL, 0, NULL, 0));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl,
                WOLFSSL_TRUSTED_CA_CERT_SHA1+1, NULL, 0));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl,
                WOLFSSL_TRUSTED_CA_CERT_SHA1, NULL, 0));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl,
                WOLFSSL_TRUSTED_CA_CERT_SHA1, id, 5));
#ifdef NO_SHA
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl,
                WOLFSSL_TRUSTED_CA_KEY_SHA1, id, sizeof(id)));
#endif
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl,
                WOLFSSL_TRUSTED_CA_X509_NAME, id, 0));

    /* success cases */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl,
                WOLFSSL_TRUSTED_CA_PRE_AGREED, NULL, 0));
#ifndef NO_SHA
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl,
                WOLFSSL_TRUSTED_CA_KEY_SHA1, id, sizeof(id)));
#endif
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl,
                WOLFSSL_TRUSTED_CA_X509_NAME, id, 5));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif /* !NO_TLS && (!NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER) */
#endif /* HAVE_TRUSTED_CA */
    return EXPECT_RESULT();
}

static int test_wolfSSL_UseMaxFragment(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MAX_FRAGMENT) && !defined(NO_CERTS) && \
    !defined(NO_FILESYSTEM) && !defined(NO_RSA) && !defined(NO_WOLFSSL_CLIENT)

#if !defined(NO_TLS)
  #ifndef NO_WOLFSSL_SERVER
    WOLFSSL_CTX* ctx = wolfSSL_CTX_new(wolfSSLv23_server_method());
  #else
    WOLFSSL_CTX* ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
  #endif
    WOLFSSL     *ssl = NULL;
  #ifdef OPENSSL_EXTRA
    int (*UseMaxFragment)(SSL *s, unsigned char mode);
    int (*CTX_UseMaxFragment)(SSL_CTX *c, unsigned char mode);
  #else
    int (*UseMaxFragment)(WOLFSSL *s, unsigned char mode);
    int (*CTX_UseMaxFragment)(WOLFSSL_CTX *c, unsigned char mode);
  #endif

  #ifndef NO_WOLFSSL_SERVER
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, WOLFSSL_FILETYPE_PEM));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, WOLFSSL_FILETYPE_PEM));
  #endif

    ExpectNotNull(ctx);

    ExpectNotNull(ssl = wolfSSL_new(ctx));

  #ifdef OPENSSL_EXTRA
    CTX_UseMaxFragment = SSL_CTX_set_tlsext_max_fragment_length;
    UseMaxFragment = SSL_set_tlsext_max_fragment_length;
  #else
    UseMaxFragment = wolfSSL_UseMaxFragment;
    CTX_UseMaxFragment = wolfSSL_CTX_UseMaxFragment;
  #endif

    /* error cases */
    ExpectIntNE(WOLFSSL_SUCCESS, CTX_UseMaxFragment(NULL, WOLFSSL_MFL_2_9));
    ExpectIntNE(WOLFSSL_SUCCESS, UseMaxFragment(    NULL, WOLFSSL_MFL_2_9));
    ExpectIntNE(WOLFSSL_SUCCESS, CTX_UseMaxFragment(ctx, WOLFSSL_MFL_MIN-1));
    ExpectIntNE(WOLFSSL_SUCCESS, CTX_UseMaxFragment(ctx, WOLFSSL_MFL_MAX+1));
    ExpectIntNE(WOLFSSL_SUCCESS, UseMaxFragment(ssl, WOLFSSL_MFL_MIN-1));
    ExpectIntNE(WOLFSSL_SUCCESS, UseMaxFragment(ssl, WOLFSSL_MFL_MAX+1));

    /* success case */
  #ifdef OPENSSL_EXTRA
    ExpectIntEQ(WC_NO_ERR_TRACE(BAD_FUNC_ARG), CTX_UseMaxFragment(ctx,  WOLFSSL_MFL_2_8));
  #else
    ExpectIntEQ(WOLFSSL_SUCCESS, CTX_UseMaxFragment(ctx,  WOLFSSL_MFL_2_8));
  #endif
    ExpectIntEQ(WOLFSSL_SUCCESS, CTX_UseMaxFragment(ctx,  WOLFSSL_MFL_2_9));
    ExpectIntEQ(WOLFSSL_SUCCESS, CTX_UseMaxFragment(ctx,  WOLFSSL_MFL_2_10));
    ExpectIntEQ(WOLFSSL_SUCCESS, CTX_UseMaxFragment(ctx,  WOLFSSL_MFL_2_11));
    ExpectIntEQ(WOLFSSL_SUCCESS, CTX_UseMaxFragment(ctx,  WOLFSSL_MFL_2_12));
  #ifdef OPENSSL_EXTRA
    ExpectIntEQ(WC_NO_ERR_TRACE(BAD_FUNC_ARG), CTX_UseMaxFragment(ctx, WOLFSSL_MFL_2_13));

    ExpectIntEQ(WC_NO_ERR_TRACE(BAD_FUNC_ARG), UseMaxFragment(    ssl,  WOLFSSL_MFL_2_8));
  #else
    ExpectIntEQ(WOLFSSL_SUCCESS, CTX_UseMaxFragment(ctx,  WOLFSSL_MFL_2_13));

    ExpectIntEQ(WOLFSSL_SUCCESS, UseMaxFragment(    ssl,  WOLFSSL_MFL_2_8));
  #endif
    ExpectIntEQ(WOLFSSL_SUCCESS, UseMaxFragment(    ssl,  WOLFSSL_MFL_2_9));
    ExpectIntEQ(WOLFSSL_SUCCESS, UseMaxFragment(    ssl,  WOLFSSL_MFL_2_10));
    ExpectIntEQ(WOLFSSL_SUCCESS, UseMaxFragment(    ssl,  WOLFSSL_MFL_2_11));
    ExpectIntEQ(WOLFSSL_SUCCESS, UseMaxFragment(    ssl,  WOLFSSL_MFL_2_12));

  #ifdef OPENSSL_EXTRA
    ExpectIntEQ(WC_NO_ERR_TRACE(BAD_FUNC_ARG), UseMaxFragment(    ssl,  WOLFSSL_MFL_2_13));
  #else
    ExpectIntEQ(WOLFSSL_SUCCESS, UseMaxFragment(    ssl,  WOLFSSL_MFL_2_13));
  #endif

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);

#if defined(OPENSSL_EXTRA) && defined(HAVE_MAX_FRAGMENT) && \
    defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
    /* check negotiated max fragment size */
    {
        WOLFSSL *ssl_c = NULL;
        WOLFSSL *ssl_s = NULL;
        struct test_memio_ctx test_ctx;
        WOLFSSL_CTX *ctx_c = NULL;
        WOLFSSL_CTX *ctx_s = NULL;

        XMEMSET(&test_ctx, 0, sizeof(test_ctx));
        ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
            wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
        ExpectIntEQ(wolfSSL_UseMaxFragment(ssl_c, WOLFSSL_MFL_2_8),
            WOLFSSL_SUCCESS);
        ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
#ifndef NO_SESSION_CACHE
        ExpectIntEQ(SSL_SESSION_get_max_fragment_length(
            wolfSSL_get_session(ssl_c)), WOLFSSL_MFL_2_8);
#endif

        wolfSSL_free(ssl_c);
        wolfSSL_free(ssl_s);
        wolfSSL_CTX_free(ctx_c);
        wolfSSL_CTX_free(ctx_s);
    }
#endif
#endif /* !NO_TLS && (!NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER) */
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_UseTruncatedHMAC(void)
{
    EXPECT_DECLS;
#if defined(HAVE_TRUNCATED_HMAC) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_FILESYSTEM) && !defined(NO_RSA)
#if !defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)
  #ifndef NO_WOLFSSL_SERVER
    WOLFSSL_CTX* ctx = wolfSSL_CTX_new(wolfSSLv23_server_method());
  #else
    WOLFSSL_CTX* ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
  #endif
    WOLFSSL     *ssl = NULL;

    ExpectNotNull(ctx);

  #ifndef NO_WOLFSSL_SERVER
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, WOLFSSL_FILETYPE_PEM));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, WOLFSSL_FILETYPE_PEM));
  #endif

    ExpectNotNull(ssl = wolfSSL_new(ctx));

#ifndef NO_WOLFSSL_CLIENT
    /* error cases */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_UseTruncatedHMAC(NULL));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTruncatedHMAC(NULL));

    /* success case */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_UseTruncatedHMAC(ctx));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseTruncatedHMAC(ssl));
#endif

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif /* !NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER */
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_UseSupportedCurve(void)
{
    EXPECT_DECLS;
#if defined(HAVE_SUPPORTED_CURVES) && !defined(NO_WOLFSSL_CLIENT) && \
    !defined(NO_TLS)
    WOLFSSL_CTX* ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
    WOLFSSL     *ssl = wolfSSL_new(ctx);

    ExpectNotNull(ctx);
    ExpectNotNull(ssl);

    /* error cases */
    ExpectIntNE(WOLFSSL_SUCCESS,
                    wolfSSL_CTX_UseSupportedCurve(NULL, WOLFSSL_ECC_SECP256R1));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_UseSupportedCurve(ctx,  0));

    ExpectIntNE(WOLFSSL_SUCCESS,
                        wolfSSL_UseSupportedCurve(NULL, WOLFSSL_ECC_SECP256R1));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseSupportedCurve(ssl,  0));

    /* success case */
    ExpectIntEQ(WOLFSSL_SUCCESS,
                     wolfSSL_CTX_UseSupportedCurve(ctx, WOLFSSL_ECC_SECP256R1));
    ExpectIntEQ(WOLFSSL_SUCCESS,
                         wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP256R1));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif

    return EXPECT_RESULT();
}

#if defined(HAVE_ALPN) && defined(HAVE_IO_TESTS_DEPENDENCIES)

static void verify_ALPN_FATAL_ERROR_on_client(WOLFSSL* ssl)
{
    AssertIntEQ(WC_NO_ERR_TRACE(UNKNOWN_ALPN_PROTOCOL_NAME_E), wolfSSL_get_error(ssl, 0));
}

static void use_ALPN_all(WOLFSSL* ssl)
{
    /* http/1.1,spdy/1,spdy/2,spdy/3 */
    char alpn_list[] = {0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x2c,
                        0x73, 0x70, 0x64, 0x79, 0x2f, 0x31, 0x2c,
                        0x73, 0x70, 0x64, 0x79, 0x2f, 0x32, 0x2c,
                        0x73, 0x70, 0x64, 0x79, 0x2f, 0x33};
    AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseALPN(ssl, alpn_list, sizeof(alpn_list),
                                             WOLFSSL_ALPN_FAILED_ON_MISMATCH));
}

static void use_ALPN_all_continue(WOLFSSL* ssl)
{
    /* http/1.1,spdy/1,spdy/2,spdy/3 */
    char alpn_list[] = {0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x2c,
        0x73, 0x70, 0x64, 0x79, 0x2f, 0x31, 0x2c,
        0x73, 0x70, 0x64, 0x79, 0x2f, 0x32, 0x2c,
        0x73, 0x70, 0x64, 0x79, 0x2f, 0x33};
    AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseALPN(ssl, alpn_list, sizeof(alpn_list),
                                             WOLFSSL_ALPN_CONTINUE_ON_MISMATCH));
}

static void use_ALPN_one(WOLFSSL* ssl)
{
    /* spdy/2 */
    char proto[] = {0x73, 0x70, 0x64, 0x79, 0x2f, 0x32};

    AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseALPN(ssl, proto, sizeof(proto),
                                             WOLFSSL_ALPN_FAILED_ON_MISMATCH));
}

static void use_ALPN_unknown(WOLFSSL* ssl)
{
    /* http/2.0 */
    char proto[] = {0x68, 0x74, 0x74, 0x70, 0x2f, 0x32, 0x2e, 0x30};

    AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseALPN(ssl, proto, sizeof(proto),
                                             WOLFSSL_ALPN_FAILED_ON_MISMATCH));
}

static void use_ALPN_unknown_continue(WOLFSSL* ssl)
{
    /* http/2.0 */
    char proto[] = {0x68, 0x74, 0x74, 0x70, 0x2f, 0x32, 0x2e, 0x30};

    AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseALPN(ssl, proto, sizeof(proto),
                                             WOLFSSL_ALPN_CONTINUE_ON_MISMATCH));
}

static void verify_ALPN_not_matching_spdy3(WOLFSSL* ssl)
{
    /* spdy/3 */
    char nego_proto[] = {0x73, 0x70, 0x64, 0x79, 0x2f, 0x33};

    char *proto = NULL;
    word16 protoSz = 0;

    AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_ALPN_GetProtocol(ssl, &proto, &protoSz));

    /* check value */
    AssertIntNE(1, sizeof(nego_proto) == protoSz);
    if (proto) {
        AssertIntNE(0, XMEMCMP(nego_proto, proto, sizeof(nego_proto)));
    }
}

static void verify_ALPN_not_matching_continue(WOLFSSL* ssl)
{
    char *proto = NULL;
    word16 protoSz = 0;

    AssertIntEQ(WC_NO_ERR_TRACE(WOLFSSL_ALPN_NOT_FOUND),
                wolfSSL_ALPN_GetProtocol(ssl, &proto, &protoSz));

    /* check value */
    AssertIntEQ(1, (0 == protoSz));
    AssertIntEQ(1, (NULL == proto));
}

static void verify_ALPN_matching_http1(WOLFSSL* ssl)
{
    /* http/1.1 */
    char nego_proto[] = {0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31};
    char *proto;
    word16 protoSz = 0;

    AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_ALPN_GetProtocol(ssl, &proto, &protoSz));

    /* check value */
    AssertIntEQ(1, sizeof(nego_proto) == protoSz);
    AssertIntEQ(0, XMEMCMP(nego_proto, proto, protoSz));
}

static void verify_ALPN_matching_spdy2(WOLFSSL* ssl)
{
    /* spdy/2 */
    char nego_proto[] = {0x73, 0x70, 0x64, 0x79, 0x2f, 0x32};
    char *proto;
    word16 protoSz = 0;

    AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_ALPN_GetProtocol(ssl, &proto, &protoSz));

    /* check value */
    AssertIntEQ(1, sizeof(nego_proto) == protoSz);
    AssertIntEQ(0, XMEMCMP(nego_proto, proto, protoSz));
}

static void verify_ALPN_client_list(WOLFSSL* ssl)
{
    /* http/1.1,spdy/1,spdy/2,spdy/3 */
    char alpn_list[] = {0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x2c,
                        0x73, 0x70, 0x64, 0x79, 0x2f, 0x31, 0x2c,
                        0x73, 0x70, 0x64, 0x79, 0x2f, 0x32, 0x2c,
                        0x73, 0x70, 0x64, 0x79, 0x2f, 0x33};
    char    *clist = NULL;
    word16  clistSz = 0;

    AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_ALPN_GetPeerProtocol(ssl, &clist,
                                                          &clistSz));

    /* check value */
    AssertIntEQ(1, sizeof(alpn_list) == clistSz);
    AssertIntEQ(0, XMEMCMP(alpn_list, clist, clistSz));

    AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_ALPN_FreePeerProtocol(ssl, &clist));
}

#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
    defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY)

/* ALPN select callback, success with spdy/2 */
static int select_ALPN_spdy2(WOLFSSL *ssl, const unsigned char **out,
    unsigned char *outlen, const unsigned char *in,
    unsigned int inlen, void *arg)
{
    /* spdy/2 */
    const char proto[] = {0x73, 0x70, 0x64, 0x79, 0x2f, 0x32};

    (void)ssl;
    (void)arg;

    /* adding +1 since LEN byte comes first */
    if (inlen < sizeof(proto) + 1) {
        return SSL_TLSEXT_ERR_ALERT_FATAL;
    }

    if (XMEMCMP(in + 1, proto, sizeof(proto)) == 0) {
        *out = in + 1;
        *outlen = (unsigned char)sizeof(proto);
        return SSL_TLSEXT_ERR_OK;
    }

    return SSL_TLSEXT_ERR_ALERT_FATAL;
}

/* ALPN select callback, force failure */
static int select_ALPN_failure(WOLFSSL *ssl, const unsigned char **out,
    unsigned char *outlen, const unsigned char *in,
    unsigned int inlen, void *arg)
{
    (void)ssl;
    (void)out;
    (void)outlen;
    (void)in;
    (void)inlen;
    (void)arg;

    return SSL_TLSEXT_ERR_ALERT_FATAL;
}

static void use_ALPN_spdy2_callback(WOLFSSL* ssl)
{
    wolfSSL_set_alpn_select_cb(ssl, select_ALPN_spdy2, NULL);
}

static void use_ALPN_failure_callback(WOLFSSL* ssl)
{
    wolfSSL_set_alpn_select_cb(ssl, select_ALPN_failure, NULL);
}
#endif /* OPENSSL_ALL | NGINX | HAPROXY | LIGHTY | QUIC */

static int test_wolfSSL_UseALPN_connection(void)
{
    int res = TEST_SKIPPED;
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
    callback_functions client_cb;
    callback_functions server_cb;

    XMEMSET(&client_cb, 0, sizeof(callback_functions));
    XMEMSET(&server_cb, 0, sizeof(callback_functions));
    client_cb.method = wolfSSLv23_client_method;
    server_cb.method = wolfSSLv23_server_method;
    client_cb.devId = testDevId;
    server_cb.devId = testDevId;

    /* success case same list */
    client_cb.ctx_ready = NULL; client_cb.ssl_ready = use_ALPN_all; client_cb.on_result = NULL;
    server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_ALPN_all; server_cb.on_result = verify_ALPN_matching_http1;
    test_wolfSSL_client_server(&client_cb, &server_cb);

    /* success case only one for server */
    client_cb.ctx_ready = NULL; client_cb.ssl_ready = use_ALPN_all; client_cb.on_result = NULL;
    server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_ALPN_one; server_cb.on_result = verify_ALPN_matching_spdy2;
    test_wolfSSL_client_server(&client_cb, &server_cb);

    /* success case only one for client */
    client_cb.ctx_ready = NULL; client_cb.ssl_ready = use_ALPN_one; client_cb.on_result = NULL;
    server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_ALPN_all; server_cb.on_result = verify_ALPN_matching_spdy2;
    test_wolfSSL_client_server(&client_cb, &server_cb);

    /* success case none for client */
    client_cb.ctx_ready = NULL; client_cb.ssl_ready = NULL;         client_cb.on_result = NULL;
    server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_ALPN_all; server_cb.on_result = NULL;
    test_wolfSSL_client_server(&client_cb, &server_cb);

    /* success case mismatch behavior but option 'continue' set */
    client_cb.ctx_ready = NULL; client_cb.ssl_ready = use_ALPN_all_continue;     client_cb.on_result = verify_ALPN_not_matching_continue;
    server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_ALPN_unknown_continue; server_cb.on_result = NULL;
    test_wolfSSL_client_server(&client_cb, &server_cb);

    /* success case read protocol send by client */
    client_cb.ctx_ready = NULL; client_cb.ssl_ready = use_ALPN_all; client_cb.on_result = NULL;
    server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_ALPN_one; server_cb.on_result = verify_ALPN_client_list;
    test_wolfSSL_client_server(&client_cb, &server_cb);

    /* mismatch behavior with same list
        * the first and only this one must be taken */
    client_cb.ctx_ready = NULL; client_cb.ssl_ready = use_ALPN_all; client_cb.on_result = NULL;
    server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_ALPN_all; server_cb.on_result = verify_ALPN_not_matching_spdy3;
    test_wolfSSL_client_server(&client_cb, &server_cb);

    /* default mismatch behavior */
    client_cb.ctx_ready = NULL; client_cb.ssl_ready = use_ALPN_all;     client_cb.on_result = NULL;
    server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_ALPN_unknown; server_cb.on_result = verify_ALPN_FATAL_ERROR_on_client;
    test_wolfSSL_client_server(&client_cb, &server_cb);

#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
    defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY)

    /* WOLFSSL-level ALPN select callback tests */
    /* Callback: success (one protocol, spdy/2) */
    client_cb.ctx_ready = NULL;
    client_cb.ssl_ready = use_ALPN_one;
    client_cb.on_result = verify_ALPN_matching_spdy2;
    server_cb.ctx_ready = NULL;
    server_cb.ssl_ready = use_ALPN_spdy2_callback;
    server_cb.on_result = verify_ALPN_matching_spdy2;
    test_wolfSSL_client_server(&client_cb, &server_cb);

    /* Callback: failure (one client protocol, spdy/2) */
    client_cb.ctx_ready = NULL;
    client_cb.ssl_ready = use_ALPN_one;
    client_cb.on_result = NULL;
    server_cb.ctx_ready = NULL;
    server_cb.ssl_ready = use_ALPN_failure_callback;
    server_cb.on_result = verify_ALPN_FATAL_ERROR_on_client;
    test_wolfSSL_client_server(&client_cb, &server_cb);

#endif /* OPENSSL_ALL | NGINX | HAPROXY | LIGHTY */

    res = TEST_RES_CHECK(1);
#endif /* !NO_WOLFSSL_CLIENT && !NO_WOLFSSL_SERVER */
    return res;
}

static int test_wolfSSL_UseALPN_params(void)
{
    EXPECT_DECLS;
#ifndef NO_WOLFSSL_CLIENT
    /* "http/1.1" */
    char http1[] = {0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31};
    /* "spdy/1" */
    char spdy1[] = {0x73, 0x70, 0x64, 0x79, 0x2f, 0x31};
    /* "spdy/2" */
    char spdy2[] = {0x73, 0x70, 0x64, 0x79, 0x2f, 0x32};
    /* "spdy/3" */
    char spdy3[] = {0x73, 0x70, 0x64, 0x79, 0x2f, 0x33};
    char buff[256];
    word32 idx;

    WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
    WOLFSSL     *ssl = wolfSSL_new(ctx);

    ExpectNotNull(ctx);
    ExpectNotNull(ssl);

    /* error cases */
    ExpectIntNE(WOLFSSL_SUCCESS,
                wolfSSL_UseALPN(NULL, http1, sizeof(http1),
                                WOLFSSL_ALPN_FAILED_ON_MISMATCH));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseALPN(ssl, NULL, 0,
                                              WOLFSSL_ALPN_FAILED_ON_MISMATCH));

    /* success case */
    /* http1 only */
    ExpectIntEQ(WOLFSSL_SUCCESS,
                wolfSSL_UseALPN(ssl, http1, sizeof(http1),
                                WOLFSSL_ALPN_FAILED_ON_MISMATCH));

    /* http1, spdy1 */
    XMEMCPY(buff, http1, sizeof(http1));
    idx = sizeof(http1);
    buff[idx++] = ',';
    XMEMCPY(buff+idx, spdy1, sizeof(spdy1));
    idx += sizeof(spdy1);
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseALPN(ssl, buff, idx,
                                              WOLFSSL_ALPN_FAILED_ON_MISMATCH));

    /* http1, spdy2, spdy1 */
    XMEMCPY(buff, http1, sizeof(http1));
    idx = sizeof(http1);
    buff[idx++] = ',';
    XMEMCPY(buff+idx, spdy2, sizeof(spdy2));
    idx += sizeof(spdy2);
    buff[idx++] = ',';
    XMEMCPY(buff+idx, spdy1, sizeof(spdy1));
    idx += sizeof(spdy1);
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseALPN(ssl, buff, idx,
                                              WOLFSSL_ALPN_FAILED_ON_MISMATCH));

    /* spdy3, http1, spdy2, spdy1 */
    XMEMCPY(buff, spdy3, sizeof(spdy3));
    idx = sizeof(spdy3);
    buff[idx++] = ',';
    XMEMCPY(buff+idx, http1, sizeof(http1));
    idx += sizeof(http1);
    buff[idx++] = ',';
    XMEMCPY(buff+idx, spdy2, sizeof(spdy2));
    idx += sizeof(spdy2);
    buff[idx++] = ',';
    XMEMCPY(buff+idx, spdy1, sizeof(spdy1));
    idx += sizeof(spdy1);
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseALPN(ssl, buff, idx,
                                            WOLFSSL_ALPN_CONTINUE_ON_MISMATCH));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}
#endif /* HAVE_ALPN  */

#ifdef HAVE_ALPN_PROTOS_SUPPORT
static void CTX_set_alpn_protos(SSL_CTX *ctx)
{
    unsigned char p[] = {
       8, 'h', 't', 't', 'p', '/', '1', '.', '1',
       6, 's', 'p', 'd', 'y', '/', '2',
       6, 's', 'p', 'd', 'y', '/', '1',
    };

    unsigned char p_len = sizeof(p);
    int ret;

    ret = SSL_CTX_set_alpn_protos(ctx, p, p_len);

#ifdef WOLFSSL_ERROR_CODE_OPENSSL
    AssertIntEQ(ret, 0);
#else
    AssertIntEQ(ret, SSL_SUCCESS);
#endif
}

static void set_alpn_protos(SSL* ssl)
{
    unsigned char p[] = {
       6, 's', 'p', 'd', 'y', '/', '3',
       8, 'h', 't', 't', 'p', '/', '1', '.', '1',
       6, 's', 'p', 'd', 'y', '/', '2',
       6, 's', 'p', 'd', 'y', '/', '1',
    };

    unsigned char p_len = sizeof(p);
    int ret;

    ret = SSL_set_alpn_protos(ssl, p, p_len);

#ifdef WOLFSSL_ERROR_CODE_OPENSSL
    AssertIntEQ(ret, 0);
#else
    AssertIntEQ(ret, SSL_SUCCESS);
#endif

}

static void verify_alpn_matching_spdy3(WOLFSSL* ssl)
{
    /* "spdy/3" */
    char nego_proto[] = {0x73, 0x70, 0x64, 0x79, 0x2f, 0x33};
    const unsigned char *proto;
    unsigned int protoSz = 0;

    SSL_get0_alpn_selected(ssl, &proto, &protoSz);

    /* check value */
    AssertIntEQ(1, sizeof(nego_proto) == protoSz);
    AssertIntEQ(0, XMEMCMP(nego_proto, proto, protoSz));
}

static void verify_alpn_matching_http1(WOLFSSL* ssl)
{
    /* "http/1.1" */
    char nego_proto[] = {0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31};
    const unsigned char *proto;
    unsigned int protoSz = 0;

    SSL_get0_alpn_selected(ssl, &proto, &protoSz);

    /* check value */
    AssertIntEQ(1, sizeof(nego_proto) == protoSz);
    AssertIntEQ(0, XMEMCMP(nego_proto, proto, protoSz));
}

static int test_wolfSSL_set_alpn_protos(void)
{
    int res = TEST_SKIPPED;
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
    callback_functions client_cb;
    callback_functions server_cb;

    XMEMSET(&client_cb, 0, sizeof(callback_functions));
    XMEMSET(&server_cb, 0, sizeof(callback_functions));
    client_cb.method = wolfSSLv23_client_method;
    server_cb.method = wolfSSLv23_server_method;
    client_cb.devId = testDevId;
    server_cb.devId = testDevId;

    /* use CTX_alpn_protos */
    client_cb.ctx_ready = CTX_set_alpn_protos;
    client_cb.ssl_ready = NULL;
    client_cb.on_result = NULL;
    server_cb.ctx_ready = CTX_set_alpn_protos;
    server_cb.ssl_ready = NULL;
    server_cb.on_result = verify_alpn_matching_http1;
    test_wolfSSL_client_server(&client_cb, &server_cb);

    /* use set_alpn_protos */
    client_cb.ctx_ready = NULL;
    client_cb.ssl_ready = set_alpn_protos;
    client_cb.on_result = NULL;
    server_cb.ctx_ready = NULL;
    server_cb.ssl_ready = set_alpn_protos;
    server_cb.on_result = verify_alpn_matching_spdy3;
    test_wolfSSL_client_server(&client_cb, &server_cb);

    res = TEST_SUCCESS;
#endif /* !NO_WOLFSSL_CLIENT && !NO_WOLFSSL_SERVER */
    return res;
}

static int test_wolfSSL_select_next_proto(void)
{
    EXPECT_DECLS;
    unsigned char *out = NULL;
    unsigned char outLen = 0;
    int ret;

    /* Wire format: length-prefixed protocol names */
    unsigned char serverList[] = {
        8, 'h','t','t','p','/','1','.','1',
        6, 's','p','d','y','/','2'
    };
    unsigned int serverLen = sizeof(serverList);

    unsigned char clientList[] = {
        6, 's','p','d','y','/','2'
    };
    unsigned int clientLen = sizeof(clientList);

    unsigned char clientListHttp[] = {
        8, 'h','t','t','p','/','1','.','1'
    };
    unsigned int clientListHttpLen = sizeof(clientListHttp);

    unsigned char clientListNoMatch[] = {
        6, 's','p','d','y','/','3'
    };
    unsigned int clientListNoMatchLen = sizeof(clientListNoMatch);

    /* Test 1: NULL parameters return UNSUPPORTED */
    ExpectIntEQ(wolfSSL_select_next_proto(NULL, &outLen, serverList,
        serverLen, clientList, clientLen), WOLFSSL_NPN_UNSUPPORTED);
    ExpectIntEQ(wolfSSL_select_next_proto(&out, NULL, serverList,
        serverLen, clientList, clientLen), WOLFSSL_NPN_UNSUPPORTED);
    ExpectIntEQ(wolfSSL_select_next_proto(&out, &outLen, NULL,
        serverLen, clientList, clientLen), WOLFSSL_NPN_UNSUPPORTED);
    ExpectIntEQ(wolfSSL_select_next_proto(&out, &outLen, serverList,
        serverLen, NULL, clientLen), WOLFSSL_NPN_UNSUPPORTED);

    /* Test 2: Normal match - client wants "spdy/2", server offers it */
    out = NULL;
    outLen = 0;
    ret = wolfSSL_select_next_proto(&out, &outLen, serverList, serverLen,
        clientList, clientLen);
    ExpectIntEQ(ret, WOLFSSL_NPN_NEGOTIATED);
    ExpectIntEQ(outLen, 6);
    ExpectNotNull(out);
    ExpectIntEQ(XMEMCMP(out, "spdy/2", 6), 0);

    /* Test 3: No overlap - server offers "http/1.1,spdy/2", client wants
     * "spdy/3". Falls back to first client protocol. */
    out = NULL;
    outLen = 0;
    ret = wolfSSL_select_next_proto(&out, &outLen, serverList, serverLen,
        clientListNoMatch, clientListNoMatchLen);
    ExpectIntEQ(ret, WOLFSSL_NPN_NO_OVERLAP);
    ExpectIntEQ(outLen, 6);
    ExpectNotNull(out);
    ExpectIntEQ(XMEMCMP(out, "spdy/3", 6), 0);

    /* Test 4: Malformed server list - length byte overruns buffer.
     * Must NOT crash (heap over-read). */
    {
        unsigned char malformedServer[] = { 200, 'h','t','t','p' };
        out = NULL;
        outLen = 0;
        ret = wolfSSL_select_next_proto(&out, &outLen, malformedServer,
            sizeof(malformedServer), clientList, clientLen);
        ExpectIntEQ(ret, WOLFSSL_NPN_NO_OVERLAP);
    }

    /* Test 5: Malformed client list - length byte overruns buffer.
     * Must NOT crash. */
    {
        unsigned char malformedClient[] = { 200, 's','p','d','y' };
        out = NULL;
        outLen = 0;
        ret = wolfSSL_select_next_proto(&out, &outLen, serverList, serverLen,
            malformedClient, sizeof(malformedClient));
        ExpectIntEQ(ret, WOLFSSL_NPN_NO_OVERLAP);
    }

    /* Test 6: Zero-length entry in server list - must NOT infinite loop */
    {
        unsigned char zeroLenServer[] = { 0, 6, 's','p','d','y','/','2' };
        out = NULL;
        outLen = 0;
        ret = wolfSSL_select_next_proto(&out, &outLen, zeroLenServer,
            sizeof(zeroLenServer), clientList, clientLen);
        /* Zero-length entry causes break, so no match found */
        ExpectIntEQ(ret, WOLFSSL_NPN_NO_OVERLAP);
    }

    /* Test 7: Empty client list (clientLen == 0) - must NOT dereference
     * clientNames[0]. */
    {
        unsigned char emptyClient[] = { 0 };
        out = NULL;
        outLen = 0;
        ret = wolfSSL_select_next_proto(&out, &outLen, serverList, serverLen,
            emptyClient, 0);
        ExpectIntEQ(ret, WOLFSSL_NPN_NO_OVERLAP);
        ExpectIntEQ(outLen, 0);
    }

    /* Test 8: First protocol match - both start with "http/1.1" */
    out = NULL;
    outLen = 0;
    ret = wolfSSL_select_next_proto(&out, &outLen, serverList, serverLen,
        clientListHttp, clientListHttpLen);
    ExpectIntEQ(ret, WOLFSSL_NPN_NEGOTIATED);
    ExpectIntEQ(outLen, 8);
    ExpectNotNull(out);
    ExpectIntEQ(XMEMCMP(out, "http/1.1", 8), 0);

    return EXPECT_RESULT();
}

#endif /* HAVE_ALPN_PROTOS_SUPPORT */

static int test_wolfSSL_wolfSSL_UseSecureRenegotiation(void)
{
    EXPECT_DECLS;
#if defined(HAVE_SECURE_RENEGOTIATION) && !defined(NO_WOLFSSL_CLIENT) && \
    !defined(NO_TLS)
    WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
    WOLFSSL     *ssl = wolfSSL_new(ctx);

    ExpectNotNull(ctx);
    ExpectNotNull(ssl);

    /* error cases */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_UseSecureRenegotiation(NULL));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseSecureRenegotiation(NULL));

    /* success cases */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_UseSecureRenegotiation(ctx));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSecureRenegotiation(ssl));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

/* TLSX_FreeAll frees the SecureRenegotiation struct but the cached pointer
 * ssl->secure_renegotiation was not cleared, causing a use-after-free when
 * queried after wolfSSL_clear(). */
static int test_wolfSSL_clear_secure_renegotiation(void)
{
    EXPECT_DECLS;
#if (defined(HAVE_SECURE_RENEGOTIATION) || \
     defined(HAVE_SERVER_RENEGOTIATION_INFO)) && \
    (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS)
    WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
    WOLFSSL     *ssl = wolfSSL_new(ctx);
    long         support;

    ExpectNotNull(ctx);
    ExpectNotNull(ssl);

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSecureRenegotiation(ssl));
    ExpectNotNull(ssl->secure_renegotiation);
    if (EXPECT_SUCCESS()) {
        if (ssl->secure_renegotiation != NULL)
            ssl->secure_renegotiation->enabled = 1;
    }

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_clear(ssl));
    if (EXPECT_SUCCESS()) {
        support = wolfSSL_SSL_get_secure_renegotiation_support(ssl);
        ExpectNull(ssl->secure_renegotiation);
        ExpectIntEQ(WOLFSSL_FAILURE, support);
    }

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

/* Test reconnecting with a different ciphersuite after a renegotiation. */
static int test_wolfSSL_SCR_Reconnect(void)
{
    EXPECT_DECLS;
#if defined(HAVE_SECURE_RENEGOTIATION) && \
    defined(BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) && \
    defined(BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) && \
    defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
    struct test_memio_ctx test_ctx;
    WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
    byte data;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    test_ctx.c_ciphers = "ECDHE-RSA-AES256-GCM-SHA384";
    test_ctx.s_ciphers =
        "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305";
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_UseSecureRenegotiation(ctx_c));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_UseSecureRenegotiation(ctx_s));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSecureRenegotiation(ssl_c));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSecureRenegotiation(ssl_s));
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
    /* WOLFSSL_FATAL_ERROR since it will block */
    ExpectIntEQ(wolfSSL_Rehandshake(ssl_s), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
    ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
                WOLFSSL_ERROR_WANT_READ);
    ExpectIntEQ(wolfSSL_read(ssl_c, &data, 1), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
    ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
                WOLFSSL_ERROR_WANT_READ);
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
    wolfSSL_free(ssl_c);
    ssl_c = NULL;
    wolfSSL_free(ssl_s);
    ssl_s = NULL;
    wolfSSL_CTX_free(ctx_c);
    ctx_c = NULL;
    test_ctx.c_ciphers = "ECDHE-RSA-CHACHA20-POLY1305";
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
    wolfSSL_free(ssl_s);
    wolfSSL_free(ssl_c);
    wolfSSL_CTX_free(ctx_s);
    wolfSSL_CTX_free(ctx_c);
#endif
    return EXPECT_RESULT();
}

/* Test SCR check when server doesn't reply to secure_renegotiation. */
#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \
    defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK) && \
    defined(HAVE_SECURE_RENEGOTIATION) && \
    defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
/* IO callback to remove secure renegotiation extension from ServerHello */
static int test_SCR_check_remove_ext_io_cb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
{
    static int sentServerHello = FALSE;

    if (!sentServerHello) {
        /* Look for secure renegotiation extension: 0xFF 0x01 (extension type) */
        byte renegExt[] = { 0xFF, 0x01 };
        size_t i;

        if (sz < (int)sizeof(renegExt))
            return test_memio_write_cb(ssl, buf, sz, ctx);

        /* Search for the extension in the buffer */
        for (i = 0; i < (size_t)sz - sizeof(renegExt); i++) {
            if (XMEMCMP(buf + i, renegExt, sizeof(renegExt)) == 0) {
                /* Found the extension. Remove it by changing the type to something
                 * unrecognized so it won't be parsed as secure renegotiation. */
                buf[i+1] = 0x11;
                break;
            }
        }
        sentServerHello = TRUE;
    }

    /* Call the original test_memio_write_cb */
    return test_memio_write_cb(ssl, buf, sz, ctx);
}
#endif

static int test_wolfSSL_SCR_check_enabled(void)
{
    EXPECT_DECLS;
#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \
    defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK) && \
    defined(HAVE_SECURE_RENEGOTIATION) && \
    defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
    struct test_memio_ctx test_ctx;
    WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
    int ret;
    int enabled;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    /* Set up client and server */
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);

    /* Enable secure renegotiation on client (so it sends the extension) */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_UseSecureRenegotiation(ctx_c));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSecureRenegotiation(ssl_c));

    /* Set up IO callback on server to remove the extension from ServerHello */
    wolfSSL_SSLSetIOSend(ssl_s, test_SCR_check_remove_ext_io_cb);

    /* Try to connect - should fail with SECURE_RENEGOTIATION_E */
    ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL);
    ExpectIntNE(0, ret); /* Handshake should fail */
    ret = wolfSSL_get_error(ssl_c, 0);
    ExpectIntEQ(WC_NO_ERR_TRACE(SECURE_RENEGOTIATION_E), ret);

    /* Clean up for next attempt */
    wolfSSL_free(ssl_c);
    ssl_c = NULL;
    wolfSSL_free(ssl_s);
    ssl_s = NULL;
    test_memio_clear_buffer(&test_ctx, 1);
    test_memio_clear_buffer(&test_ctx, 0);

    /* Set up new client and server */
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);

    /* Enable secure renegotiation on client */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_UseSecureRenegotiation(ctx_c));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSecureRenegotiation(ssl_c));

    /* Set up IO callback on server to remove the extension from ServerHello */
    wolfSSL_SSLSetIOSend(ssl_s, test_SCR_check_remove_ext_io_cb);

    /* Disable the SCR check */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_set_scr_check_enabled(ssl_c, 0));

    /* Verify the state is 0 */
    enabled = wolfSSL_get_scr_check_enabled(ssl_c);
    ExpectIntEQ(0, enabled);

    /* Now connection should succeed */
    ExpectIntEQ(0, test_memio_do_handshake(ssl_c, ssl_s, 10, NULL));

    /* Cleanup */
    wolfSSL_free(ssl_c);
    ssl_c = NULL;
    wolfSSL_free(ssl_s);
    ssl_s = NULL;
    wolfSSL_CTX_free(ctx_c);
    ctx_c = NULL;
    wolfSSL_CTX_free(ctx_s);
    ctx_s = NULL;
#endif
    return EXPECT_RESULT();
}

/* F-2922: wolfSSL_TicketKeyCb must reject a session ticket whose HMAC
 * does not match its encrypted contents. */
static int test_wolfSSL_ticket_keycb_bad_hmac(void)
{
    EXPECT_DECLS;
#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_TLS12) && \
        defined(OPENSSL_EXTRA) && defined(HAVE_AES_CBC) && \
        defined(WOLFSSL_AES_256) && \
        defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
        !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
    struct test_memio_ctx test_ctx;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    WOLFSSL_SESSION *session = NULL;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
            wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);

    ExpectIntEQ(OpenSSLTicketInit(), 0);
    ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_key_cb(ctx_s,
            myTicketEncCbOpenSSL), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_UseSessionTicket(ssl_c), WOLFSSL_SUCCESS);

    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
    ExpectNotNull(session = wolfSSL_get1_session(ssl_c));
    ExpectIntGT(session->ticketLen, 0);

    /* Corrupt a byte of the ticket HMAC so the server's HMAC
     * verification rejects it. */
    if (session != NULL && session->ticket != NULL && session->ticketLen > 0)
        session->ticket[session->ticketLen - 1] ^= 0xFF;

    wolfSSL_free(ssl_c);
    ssl_c = NULL;
    wolfSSL_free(ssl_s);
    ssl_s = NULL;
    test_memio_clear_buffer(&test_ctx, 0);
    test_memio_clear_buffer(&test_ctx, 1);

    ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
    ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
    wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
    wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
    wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
    wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
    ExpectIntEQ(wolfSSL_set_session(ssl_c, session), WOLFSSL_SUCCESS);
    /* Disable the process-global session cache lookup on the server so that
     * the ticket is the only resumption path - with WOLFSSL_TICKET_HAVE_ID
     * the server could otherwise resume by session ID. */
    if (ssl_s != NULL)
        ssl_s->options.sessionCacheOff = 1;

    /* Corrupted ticket bytes fail the HMAC check in
     * wolfSSL_TicketKeyCb; the session must not resume. */
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
    ExpectIntEQ(wolfSSL_session_reused(ssl_c), 0);

    wolfSSL_SESSION_free(session);
    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
    OpenSSLTicketCleanup();
#endif
    return EXPECT_RESULT();
}


#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) && \
    !defined(NO_FILESYSTEM) && (!defined(NO_RSA) || defined(HAVE_ECC))
/* Called when writing. */
static int DummySend(WOLFSSL* ssl, char* buf, int sz, void* ctx)
{
    (void)ssl;
    (void)buf;
    (void)sz;
    (void)ctx;

    /* Force error return from wolfSSL_accept_TLSv13(). */
    return WANT_WRITE;
}
/* Called when reading. */
static int BufferInfoRecv(WOLFSSL* ssl, char* buf, int sz, void* ctx)
{
    WOLFSSL_BUFFER_INFO* msg = (WOLFSSL_BUFFER_INFO*)ctx;
    int len = (int)msg->length;

    (void)ssl;
    (void)sz;

    /* Pass back as much of message as will fit in buffer. */
    if (len > sz)
        len = sz;
    XMEMCPY(buf, msg->buffer, len);
    /* Move over returned data. */
    msg->buffer += len;
    msg->length -= (word32)len;

    /* Amount actually copied. */
    return len;
}
#endif

/* Test the detection of duplicate known TLS extensions.
 * Specifically in a ClientHello.
 */
static int test_tls_ext_duplicate(void)
{
    EXPECT_DECLS;
#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) && \
    !defined(NO_FILESYSTEM) && (!defined(NO_RSA) || defined(HAVE_ECC))
    const unsigned char clientHelloDupTlsExt[] = {
        0x16, 0x03, 0x03, 0x00, 0x6a, 0x01, 0x00, 0x00,
        0x66, 0x03, 0x03, 0xf4, 0x65, 0xbd, 0x22, 0xfe,
        0x6e, 0xab, 0x66, 0xdd, 0xcf, 0xe9, 0x65, 0x55,
        0xe8, 0xdf, 0xc3, 0x8e, 0x4b, 0x00, 0xbc, 0xf8,
        0x23, 0x57, 0x1b, 0xa0, 0xc8, 0xa9, 0xe2, 0x8c,
        0x91, 0x6e, 0xf9, 0x20, 0xf7, 0x5c, 0xc5, 0x5b,
        0x75, 0x8c, 0x47, 0x0a, 0x0e, 0xc4, 0x1a, 0xda,
        0xef, 0x75, 0xe5, 0x21, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x13, 0x01,
        0x00, 0x9e, 0x01, 0x00,
        /* Extensions - duplicate signature algorithms. */
                                0x00, 0x19, 0x00, 0x0d,
        0x00, 0x04, 0x00, 0x02, 0x04, 0x01, 0x00, 0x0d,
        0x00, 0x04, 0x00, 0x02, 0x04, 0x01,
        /* Supported Versions extension for TLS 1.3. */
                                            0x00, 0x2b,
        0x00, 0x05, 0x04, 0x03, 0x04, 0x03, 0x03
    };
    WOLFSSL_BUFFER_INFO msg;
    const char* testCertFile;
    const char* testKeyFile;
    WOLFSSL_CTX *ctx = NULL;
    WOLFSSL     *ssl = NULL;

#ifndef NO_RSA
    testCertFile = svrCertFile;
    testKeyFile = svrKeyFile;
#elif defined(HAVE_ECC)
    testCertFile = eccCertFile;
    testKeyFile = eccKeyFile;
#endif

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));

    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, testCertFile,
        CERT_FILETYPE));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, testKeyFile,
        CERT_FILETYPE));

    /* Read from 'msg'. */
    wolfSSL_SetIORecv(ctx, BufferInfoRecv);
    /* No where to send to - dummy sender. */
    wolfSSL_SetIOSend(ctx, DummySend);

    ssl = wolfSSL_new(ctx);
    ExpectNotNull(ssl);

    msg.buffer = (unsigned char*)clientHelloDupTlsExt;
    msg.length = (unsigned int)sizeof(clientHelloDupTlsExt);
    wolfSSL_SetIOReadCtx(ssl, &msg);

    ExpectIntNE(wolfSSL_accept(ssl), WOLFSSL_SUCCESS);
    /* can return duplicate ext error or socket error if the peer closed down
     * while sending alert */
    if (wolfSSL_get_error(ssl, 0) != WC_NO_ERR_TRACE(SOCKET_ERROR_E)) {
        ExpectIntEQ(wolfSSL_get_error(ssl, 0), WC_NO_ERR_TRACE(DUPLICATE_TLS_EXT_E));
    }

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

/* Regression test: TLSX extension size accumulation must not silently wrap
 * the internal word16 accumulator. Prior to the fix, a single extension
 * whose size (plus the 4-byte header) pushes the running total past 0xFFFF
 * caused TLSX_GetSize / TLSX_Write to return a truncated length, which
 * in turn led to undersized buffer writes. The on-wire extensions block
 * length is a 2-byte field per RFC 8446 Section 4.2, so the correct
 * behavior is to return BUFFER_E rather than wrap. */
static int test_tls_ext_word16_overflow(void)
{
    EXPECT_DECLS;
#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_CLIENT) && \
    !defined(NO_TLS)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL*     ssl = NULL;
    SessionTicket* ticket = NULL;
    byte*        big = NULL;
    /* Size chosen so that 4 (ext header) + size > 0xFFFF. */
    const word16 bigSz = 0xFFFE;
    word32 length = 0;

    big = (byte*)XMALLOC(bigSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    ExpectNotNull(big);
    if (big != NULL)
        XMEMSET(big, 0xA5, bigSz);

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* Build an oversized SessionTicket extension directly on the ssl
     * extension list. Going via the public API is not enough here because
     * wolfSSL_set_SessionTicket clamps to word16 without creating the
     * TLSX entry; the TLSX path is what exercises the accumulator. */
    if (EXPECT_SUCCESS()) {
        ticket = TLSX_SessionTicket_Create(0, big, bigSz, ssl->heap);
        ExpectNotNull(ticket);
    }
    if (EXPECT_SUCCESS()) {
        ExpectIntEQ(TLSX_UseSessionTicket(&ssl->extensions, ticket, ssl->heap),
            WOLFSSL_SUCCESS);
        /* TLSX_UseSessionTicket takes ownership on success. */
        if (EXPECT_SUCCESS())
            ticket = NULL;
    }

    /* TLSX_GetRequestSize must refuse to encode: 4-byte ext header +
     * 0xFFFE payload + 2-byte block length prefix = 0x10004, which does
     * not fit in a word16 wire length. Expect BUFFER_E, not a silently
     * wrapped small value. */
    if (EXPECT_SUCCESS()) {
        int ret = TLSX_GetRequestSize(ssl, client_hello, &length);
        ExpectIntEQ(ret, BUFFER_E);
    }

    if (ticket != NULL)
        TLSX_SessionTicket_Free(ticket, ssl->heap);
    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
    XFREE(big, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    ssl = NULL;
    ctx = NULL;
    big = NULL;

    /* Boundary case: construct a SessionTicket extension sized so that the
     * total extensions length in TLSX_GetRequestSize is exactly
     * WOLFSSL_MAX_16BIT - OPAQUE16_LEN (0xFFFD) *before* the OPAQUE16_LEN
     * block-prefix adjustment, which must succeed. This pins the `>`
     * comparison in the overflow check -- mutating it to `>=` would
     * incorrectly reject this valid case and fail this test. */
    {
        WOLFSSL_CTX* ctx2 = NULL;
        WOLFSSL*     ssl2 = NULL;
        SessionTicket* ticket2 = NULL;
        byte* buf = NULL;
        word32 baseLen = 0;
        word32 baseInternal = 0;
        word32 tickSz = 0;
        /* TLSX_GetRequestSize rejects when internal sum > 0xFFFD. */
        const word32 target = (word32)WOLFSSL_MAX_16BIT - (word32)OPAQUE16_LEN;
        /* Session ticket extension contributes: type (2) + len (2) + size. */
        const word32 extHdr = (word32)HELLO_EXT_TYPE_SZ
                            + (word32)OPAQUE16_LEN;
        int ret;

        ExpectNotNull(ctx2 = wolfSSL_CTX_new(wolfSSLv23_client_method()));
        ExpectNotNull(ssl2 = wolfSSL_new(ctx2));

        /* Measure baseline length with no session ticket extension. The
         * returned value already includes the 2-byte block-length prefix
         * when nonzero; strip it to get the raw internal sum. */
        if (EXPECT_SUCCESS()) {
            baseLen = 0;
            ret = TLSX_GetRequestSize(ssl2, client_hello, &baseLen);
            ExpectIntEQ(ret, 0);
            baseInternal = (baseLen > 0)
                           ? baseLen - (word32)OPAQUE16_LEN : 0;
        }

        /* Target: baseInternal + extHdr + tickSz == 0xFFFD. */
        if (EXPECT_SUCCESS() && baseInternal + extHdr < target) {
            tickSz = target - baseInternal - extHdr;
        }

        if (EXPECT_SUCCESS() && tickSz > 0 && tickSz <= WOLFSSL_MAX_16BIT) {
            buf = (byte*)XMALLOC(tickSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
            ExpectNotNull(buf);
            if (buf != NULL)
                XMEMSET(buf, 0x5A, tickSz);
        }

        if (EXPECT_SUCCESS() && buf != NULL) {
            ticket2 = TLSX_SessionTicket_Create(0, buf, (word16)tickSz,
                                                ssl2->heap);
            ExpectNotNull(ticket2);
        }
        if (EXPECT_SUCCESS() && ticket2 != NULL) {
            ExpectIntEQ(TLSX_UseSessionTicket(&ssl2->extensions, ticket2,
                                              ssl2->heap), WOLFSSL_SUCCESS);
            if (EXPECT_SUCCESS())
                ticket2 = NULL;
        }

        /* Exact boundary: internal sum == 0xFFFD must succeed, and the
         * final returned length is 0xFFFD + OPAQUE16_LEN == 0xFFFF. */
        if (EXPECT_SUCCESS()) {
            word32 lenBoundary = 0;
            ret = TLSX_GetRequestSize(ssl2, client_hello, &lenBoundary);
            ExpectIntEQ(ret, 0);
            ExpectIntEQ(lenBoundary, (word32)WOLFSSL_MAX_16BIT);
        }

        if (ticket2 != NULL)
            TLSX_SessionTicket_Free(ticket2, ssl2->heap);
        wolfSSL_free(ssl2);
        wolfSSL_CTX_free(ctx2);
        XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    }
#endif
    return EXPECT_RESULT();
}


/* Test TLS connection abort when legacy version field indicates TLS 1.3 or
 * higher. Based on test_tls_ext_duplicate() but with legacy version modified
 * to 0x0304.
 */
static int test_tls_bad_legacy_version(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_ALLOW_BAD_TLS_LEGACY_VERSION)
#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) && \
    !defined(NO_FILESYSTEM) && (!defined(NO_RSA) || defined(HAVE_ECC))
    /* This buffer (prior to Extensions) is exactly the same as the buffer in
     * test_tls_ext_duplicate() except the 11th byte is set to 0x04. That
     * change means the legacy protocol version field is invalid. That will be
     * caught before the dulplicate signature algorithms extension. */
    const unsigned char clientHelloBadLegacyVersion[] = {
        0x16, 0x03, 0x03, 0x00, 0x6a, 0x01, 0x00, 0x00,
        0x66, 0x03, 0x04, 0xf4, 0x65, 0xbd, 0x22, 0xfe,
        0x6e, 0xab, 0x66, 0xdd, 0xcf, 0xe9, 0x65, 0x55,
        0xe8, 0xdf, 0xc3, 0x8e, 0x4b, 0x00, 0xbc, 0xf8,
        0x23, 0x57, 0x1b, 0xa0, 0xc8, 0xa9, 0xe2, 0x8c,
        0x91, 0x6e, 0xf9, 0x20, 0xf7, 0x5c, 0xc5, 0x5b,
        0x75, 0x8c, 0x47, 0x0a, 0x0e, 0xc4, 0x1a, 0xda,
        0xef, 0x75, 0xe5, 0x21, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x13, 0x01,
        0x00, 0x9e, 0x01, 0x00,
        /* Extensions */
                                0x00, 0x19, 0x00, 0x0d,
        0x00, 0x04, 0x00, 0x02, 0x04, 0x01, 0x00, 0x15,
        0x00, 0x04, 0x00, 0x02, 0x04, 0x01,
        /* Supported Versions extension for TLS 1.3. */
                                            0x00, 0x2b,
        0x00, 0x05, 0x04, 0x03, 0x04, 0x03, 0x03
    };

    WOLFSSL_BUFFER_INFO msg;
    const char* testCertFile;
    const char* testKeyFile;
    WOLFSSL_CTX *ctx = NULL;
    WOLFSSL     *ssl = NULL;

#ifndef NO_RSA
    testCertFile = svrCertFile;
    testKeyFile = svrKeyFile;
#elif defined(HAVE_ECC)
    testCertFile = eccCertFile;
    testKeyFile = eccKeyFile;
#endif

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));

    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, testCertFile,
        CERT_FILETYPE));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, testKeyFile,
        CERT_FILETYPE));

    /* Read from 'msg'. */
    wolfSSL_SetIORecv(ctx, BufferInfoRecv);
    /* No where to send to - dummy sender. */
    wolfSSL_SetIOSend(ctx, DummySend);

    ssl = wolfSSL_new(ctx);
    ExpectNotNull(ssl);

    msg.buffer = (unsigned char*)clientHelloBadLegacyVersion;
    msg.length = (unsigned int)sizeof(clientHelloBadLegacyVersion);
    wolfSSL_SetIOReadCtx(ssl, &msg);

    ExpectIntNE(wolfSSL_accept(ssl), WOLFSSL_SUCCESS);
    /* Connection should fail due to bad legacy version field. When that
     * happens the return code is VERSION_ERROR but that gets transformed into
     * SOCKET_ERROR_E. */
    ExpectIntEQ(wolfSSL_get_error(ssl, 0), WC_NO_ERR_TRACE(SOCKET_ERROR_E));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
#endif
    return EXPECT_RESULT();
}
/*----------------------------------------------------------------------------*
 | X509 Tests
 *----------------------------------------------------------------------------*/

#if !defined(NO_FILESYSTEM) && !defined(NO_ASN) && defined(HAVE_PKCS8) && \
    defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_DES3) && !defined(NO_PWDBASED) && \
    (!defined(NO_RSA) || defined(HAVE_ECC)) && !defined(NO_MD5)
    #define TEST_PKCS8_ENC
#endif

#if !defined(NO_FILESYSTEM) && !defined(NO_ASN) && defined(HAVE_PKCS8) && \
    defined(HAVE_ECC) && defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_TLS)

/* used to keep track if FailTestCallback was called */
static int failTestCallbackCalled = 0;

static WC_INLINE int FailTestCallBack(char* passwd, int sz, int rw, void* userdata)
{
    (void)passwd;
    (void)sz;
    (void)rw;
    (void)userdata;

    /* mark called, test_wolfSSL_no_password_cb() will check and fail if set */
    failTestCallbackCalled = 1;

    return -1;
}
#endif

static int test_wolfSSL_no_password_cb(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_ASN) && defined(HAVE_PKCS8) && \
    defined(HAVE_ECC) && defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_TLS)
    WOLFSSL_CTX* ctx = NULL;
    byte buff[FOURK_BUF];
    const char eccPkcs8PrivKeyDerFile[] = "./certs/ecc-privkeyPkcs8.der";
    const char eccPkcs8PrivKeyPemFile[] = "./certs/ecc-privkeyPkcs8.pem";
    XFILE f = XBADFILE;
    int bytes = 0;

#ifndef NO_WOLFSSL_CLIENT
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLS_client_method()));
#else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLS_server_method()));
#endif
    wolfSSL_CTX_set_default_passwd_cb(ctx, FailTestCallBack);

    ExpectTrue((f = XFOPEN(eccPkcs8PrivKeyDerFile, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buff, 1, sizeof(buff), f), 0);
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }
    ExpectIntLE(bytes, sizeof(buff));
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    ExpectTrue((f = XFOPEN(eccPkcs8PrivKeyPemFile, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buff, 1, sizeof(buff), f), 0);
    if (f != XBADFILE)
        XFCLOSE(f);
    ExpectIntLE(bytes, sizeof(buff));
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);

    wolfSSL_CTX_free(ctx);

    /* Password callback should not be called by default */
    ExpectIntEQ(failTestCallbackCalled, 0);
#endif
    return EXPECT_RESULT();
}

#if defined(TEST_PKCS8_ENC) && !defined(NO_TLS)
/* for PKCS8 test case */
static int PKCS8TestCallBack(char* passwd, int sz, int rw, void* userdata)
{
    int flag = 0;

    (void)rw;
    if (userdata != NULL) {
        flag = *((int*)userdata); /* user set data */
    }

    switch (flag) {
        case 1: /* flag set for specific WOLFSSL_CTX structure, note userdata
                 * can be anything the user wishes to be passed to the callback
                 * associated with the WOLFSSL_CTX */
            XSTRNCPY(passwd, "yassl123", sz);
            return 8;

        default:
            return BAD_FUNC_ARG;
    }
}
#endif /* TEST_PKCS8_ENC && !NO_TLS */

/* Testing functions dealing with PKCS8 */
static int test_wolfSSL_PKCS8(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_ASN) && defined(HAVE_PKCS8) && \
    !defined(WOLFCRYPT_ONLY) && !defined(NO_TLS) && \
    (!defined(WOLFSSL_NO_TLS12) || defined(WOLFSSL_TLS13))
#if !defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)
    byte buff[FOURK_BUF];
    byte der[FOURK_BUF];
    #ifndef NO_RSA
#ifdef WOLFSSL_PEM_TO_DER
        const char serverKeyPkcs8PemFile[] = "./certs/server-keyPkcs8.pem";
#endif
        const char serverKeyPkcs8DerFile[] = "./certs/server-keyPkcs8.der";
    #endif
#ifdef WOLFSSL_PEM_TO_DER
    const char eccPkcs8PrivKeyPemFile[] = "./certs/ecc-privkeyPkcs8.pem";
#endif
    #ifdef HAVE_ECC
        const char eccPkcs8PrivKeyDerFile[] = "./certs/ecc-privkeyPkcs8.der";
    #endif
    XFILE f = XBADFILE;
    int bytes = 0;
    WOLFSSL_CTX* ctx = NULL;
#if defined(HAVE_ECC) && !defined(NO_CODING) && !defined(WOLFSSL_NO_PEM)
    int ret;
    ecc_key key;
    word32 x = 0;
#endif
#ifdef TEST_PKCS8_ENC
    #if !defined(NO_RSA) && !defined(NO_SHA)
        const char serverKeyPkcs8EncPemFile[] = "./certs/server-keyPkcs8Enc.pem";
        const char serverKeyPkcs8EncDerFile[] = "./certs/server-keyPkcs8Enc.der";
    #endif
    #if defined(HAVE_ECC) && !defined(NO_SHA)
        const char eccPkcs8EncPrivKeyPemFile[] = "./certs/ecc-keyPkcs8Enc.pem";
        const char eccPkcs8EncPrivKeyDerFile[] = "./certs/ecc-keyPkcs8Enc.der";
    #endif
    int flag;
#endif

    (void)der;

#ifndef NO_WOLFSSL_CLIENT
    #ifndef WOLFSSL_NO_TLS12
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
    #else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
    #endif
#else
    #ifndef WOLFSSL_NO_TLS12
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()));
    #else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
    #endif
#endif

#ifdef TEST_PKCS8_ENC
    wolfSSL_CTX_set_default_passwd_cb(ctx, PKCS8TestCallBack);
    wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, (void*)&flag);
    flag = 1; /* used by password callback as return code */

    #if !defined(NO_RSA) && !defined(NO_SHA)
    #if defined(WOLFSSL_PEM_TO_DER)
    /* test loading PEM PKCS8 encrypted file */
    ExpectTrue((f = XFOPEN(serverKeyPkcs8EncPemFile, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buff, 1, sizeof(buff), f), 0);
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);

    /* this next case should fail because of password callback return code */
    flag = 0; /* used by password callback as return code */
    ExpectIntNE(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);

    /* decrypt PKCS8 PEM to key in DER format with not using WOLFSSL_CTX */
    ExpectIntGT(wc_KeyPemToDer(buff, bytes, der, (word32)sizeof(der),
        "yassl123"), 0);

    /* test that error value is returned with a bad password */
    ExpectIntLT(wc_KeyPemToDer(buff, bytes, der, (word32)sizeof(der),
        "bad"), 0);
    #endif

    /* test loading PEM PKCS8 encrypted file */
    ExpectTrue((f = XFOPEN(serverKeyPkcs8EncDerFile, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buff, 1, sizeof(buff), f), 0);
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }
    flag = 1; /* used by password callback as return code */
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    /* this next case should fail because of password callback return code */
    flag = 0; /* used by password callback as return code */
    ExpectIntNE(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
    #endif /* !NO_RSA && !NO_SHA */

    #if defined(HAVE_ECC) && !defined(NO_SHA)
    #if defined(WOLFSSL_PEM_TO_DER)
    /* test loading PEM PKCS8 encrypted ECC Key file */
    ExpectTrue((f = XFOPEN(eccPkcs8EncPrivKeyPemFile, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buff, 1, sizeof(buff), f), 0);
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }
    flag = 1; /* used by password callback as return code */
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);

    /* this next case should fail because of password callback return code */
    flag = 0; /* used by password callback as return code */
    ExpectIntNE(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);

    /* decrypt PKCS8 PEM to key in DER format with not using WOLFSSL_CTX */
    ExpectIntGT(wc_KeyPemToDer(buff, bytes, der, (word32)sizeof(der),
        "yassl123"), 0);

    /* test that error value is returned with a bad password */
    ExpectIntLT(wc_KeyPemToDer(buff, bytes, der, (word32)sizeof(der),
        "bad"), 0);
    #endif

    /* test loading DER PKCS8 encrypted ECC Key file */
    ExpectTrue((f = XFOPEN(eccPkcs8EncPrivKeyDerFile, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buff, 1, sizeof(buff), f), 0);
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }
    flag = 1; /* used by password callback as return code */
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    /* this next case should fail because of password callback return code */
    flag = 0; /* used by password callback as return code */
    ExpectIntNE(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    /* leave flag as "okay" */
    flag = 1;
    #endif /* HAVE_ECC && !NO_SHA */
#endif /* TEST_PKCS8_ENC */


#ifndef NO_RSA
    /* test loading ASN.1 (DER) PKCS8 private key file (not encrypted) */
    ExpectTrue((f = XFOPEN(serverKeyPkcs8DerFile, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buff, 1, sizeof(buff), f), 0);
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    #ifdef WOLFSSL_PEM_TO_DER
    /* test loading PEM PKCS8 private key file (not encrypted) */
    ExpectTrue((f = XFOPEN(serverKeyPkcs8PemFile, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buff, 1, sizeof(buff), f), 0);
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    #endif
#endif /* !NO_RSA */

#ifdef WOLFSSL_PEM_TO_DER
    /* Test PKCS8 PEM ECC key no crypt */
    ExpectTrue((f = XFOPEN(eccPkcs8PrivKeyPemFile, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buff, 1, sizeof(buff), f), 0);
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }
#endif
#ifdef HAVE_ECC
#ifdef WOLFSSL_PEM_TO_DER
    /* Test PKCS8 PEM ECC key no crypt */
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);

    /* decrypt PKCS8 PEM to key in DER format */
    ExpectIntGT((bytes = wc_KeyPemToDer(buff, bytes, der,
        (word32)sizeof(der), NULL)), 0);
    ret = wc_ecc_init(&key);
    if (ret == 0) {
        ret = wc_EccPrivateKeyDecode(der, &x, &key, (word32)bytes);
        wc_ecc_free(&key);
    }
    ExpectIntEQ(ret, 0);
#endif

    /* Test PKCS8 DER ECC key no crypt */
    ExpectTrue((f = XFOPEN(eccPkcs8PrivKeyDerFile, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buff, 1, sizeof(buff), f), 0);
    if (f != XBADFILE)
        XFCLOSE(f);

    /* Test using a PKCS8 ECC PEM */
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, bytes,
                WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
#else
#ifdef WOLFSSL_PEM_TO_DER
    /* if HAVE_ECC is not defined then BEGIN EC PRIVATE KEY is not found */
    ExpectIntEQ((bytes = wc_KeyPemToDer(buff, bytes, der,
        (word32)sizeof(der), NULL)), WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER));
#endif
#endif /* HAVE_ECC */

    wolfSSL_CTX_free(ctx);
#endif /* !NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER */
#endif /* !NO_FILESYSTEM && !NO_ASN && HAVE_PKCS8 */
    return EXPECT_RESULT();
}

static int test_wolfSSL_PKCS8_ED25519(void)
{
    EXPECT_DECLS;
#if !defined(NO_ASN) && defined(HAVE_PKCS8) && defined(HAVE_AES_CBC) && \
    defined(WOLFSSL_AES_256) && \
    defined(WOLFSSL_ENCRYPTED_KEYS) && defined(HAVE_ED25519) && \
    defined(HAVE_ED25519_KEY_IMPORT)
    const byte encPrivKey[] = \
    "-----BEGIN ENCRYPTED PRIVATE KEY-----\n"
    "MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAheCGLmWGh7+AICCAAw\n"
    "DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEC4L5P6GappsTyhOOoQfvh8EQJMX\n"
    "OAdlsYKCOcFo4djg6AI1lRdeBRwVFWkha7gBdoCJOzS8wDvTbYcJMPvANu5ft3nl\n"
    "2L9W4v7swXkV+X+a1ww=\n"
    "-----END ENCRYPTED PRIVATE KEY-----\n";
    const char password[] = "abcdefghijklmnopqrstuvwxyz";
    byte der[FOURK_BUF];
#if !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    WOLFSSL_CTX* ctx = NULL;
#endif
    int bytes;

    XMEMSET(der, 0, sizeof(der));
    ExpectIntGT((bytes = wc_KeyPemToDer(encPrivKey, sizeof(encPrivKey), der,
        (word32)sizeof(der), password)), 0);
#if !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#endif
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, bytes,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    wolfSSL_CTX_free(ctx);
#endif /* !NO_TLS && (!NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER) */
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_PKCS8_ED448(void)
{
    EXPECT_DECLS;
#if !defined(NO_ASN) && defined(HAVE_PKCS8) && defined(HAVE_AES_CBC) && \
    defined(WOLFSSL_AES_256) && \
    defined(WOLFSSL_ENCRYPTED_KEYS) && defined(HAVE_ED448) && \
    defined(HAVE_ED448_KEY_IMPORT)
    const byte encPrivKey[] = \
    "-----BEGIN ENCRYPTED PRIVATE KEY-----\n"
    "MIGrMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAjSbZKnG4EPggICCAAw\n"
    "DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEFvCFWBBHBlJBsYleBJlJWcEUNC7\n"
    "Tf5pZviT5Btar4D/MNg6BsQHSDf5KW4ix871EsgDY2Zz+euaoWspiMntz7gU+PQu\n"
    "T/JJcbD2Ly8BbE3l5WHMifAQqNLxJBfXrHkfYtAo\n"
    "-----END ENCRYPTED PRIVATE KEY-----\n";
    const char password[] = "abcdefghijklmnopqrstuvwxyz";
    byte der[FOURK_BUF];
#if !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    WOLFSSL_CTX* ctx = NULL;
#endif
    int bytes;

    XMEMSET(der, 0, sizeof(der));
    ExpectIntGT((bytes = wc_KeyPemToDer(encPrivKey, sizeof(encPrivKey), der,
        (word32)sizeof(der), password)), 0);
#if !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#endif
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, bytes,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    wolfSSL_CTX_free(ctx);
#endif /* !NO_TLS && (!NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER) */
#endif
    return EXPECT_RESULT();
}

/* Testing functions dealing with PKCS5 */
static int test_wolfSSL_PKCS5(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_SHA) && !defined(NO_PWDBASED)
#ifdef HAVE_FIPS /* Password minimum length is 14 (112-bit) in FIPS MODE */
    const char* passwd = "myfipsPa$$W0rd";
#else
    const char *passwd = "pass1234";
#endif
    const unsigned char *salt = (unsigned char *)"salt1234";
    unsigned char *out = (unsigned char *)XMALLOC(WC_SHA_DIGEST_SIZE, NULL,
                                                  DYNAMIC_TYPE_TMP_BUFFER);
    int ret = 0;

    ExpectNotNull(out);
    ExpectIntEQ(ret = PKCS5_PBKDF2_HMAC_SHA1(passwd,(int)XSTRLEN(passwd), salt,
        (int)XSTRLEN((const char *) salt), 10, WC_SHA_DIGEST_SIZE,out),
        WOLFSSL_SUCCESS);

#ifdef WOLFSSL_SHA512
    ExpectIntEQ(ret = PKCS5_PBKDF2_HMAC(passwd,(int)XSTRLEN(passwd), salt,
        (int)XSTRLEN((const char *) salt), 10, wolfSSL_EVP_sha512(),
        WC_SHA_DIGEST_SIZE, out), SSL_SUCCESS);
#endif

    XFREE(out, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_SHA) */
    return EXPECT_RESULT();
}

/* test parsing URI from certificate */
static int test_wolfSSL_URI(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) \
    && (defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) || \
    defined(OPENSSL_EXTRA))
    WOLFSSL_X509* x509 = NULL;
    const char uri[] = "./certs/client-uri-cert.pem";
    const char urn[] = "./certs/client-absolute-urn.pem";
    const char badUri[] = "./certs/client-relative-uri.pem";

    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(uri,
        WOLFSSL_FILETYPE_PEM));
    wolfSSL_FreeX509(x509);
    x509 = NULL;

    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(urn,
        WOLFSSL_FILETYPE_PEM));
    wolfSSL_FreeX509(x509);
    x509 = NULL;

#if !defined(IGNORE_NAME_CONSTRAINTS) && !defined(WOLFSSL_NO_ASN_STRICT) \
    && !defined(WOLFSSL_FPKI)
    ExpectNull(x509 = wolfSSL_X509_load_certificate_file(badUri,
        WOLFSSL_FILETYPE_PEM));
#else
    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(badUri,
        WOLFSSL_FILETYPE_PEM));
#endif
    wolfSSL_FreeX509(x509);
#endif
    return EXPECT_RESULT();
}


#if !defined(NO_DH) && !defined(NO_AES) && defined(WOLFSSL_CERT_GEN) && \
         defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
         defined(OPENSSL_EXTRA) && !defined(NO_ASN_TIME)
/* create certificate with version 2 */
static int test_set_x509_badversion(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    WOLFSSL_X509 *x509 = NULL, *x509v2 = NULL;
    WOLFSSL_EVP_PKEY *priv = NULL, *pub = NULL;
    unsigned char *der = NULL, *key = NULL, *pt;
    char *header = NULL, *name = NULL;
    int derSz;
    long keySz;
    XFILE fp = XBADFILE;
    WOLFSSL_ASN1_TIME *notBefore = NULL, *notAfter = NULL;
    time_t t;

    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(cliCertFile,
                WOLFSSL_FILETYPE_PEM));

    ExpectTrue((fp = XFOPEN(cliKeyFile, "rb")) != XBADFILE);
    ExpectIntEQ(wolfSSL_PEM_read(fp, &name, &header, &key, &keySz),
            WOLFSSL_SUCCESS);
    if (fp != XBADFILE)
        XFCLOSE(fp);
    pt = key;
    ExpectNotNull(priv = wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, NULL,
                (const unsigned char**)&pt, keySz));


    /* create the version 2 certificate */
    ExpectNotNull(x509v2 = X509_new());
    ExpectIntEQ(wolfSSL_X509_set_version(x509v2, 1), WOLFSSL_SUCCESS);

    ExpectIntEQ(wolfSSL_X509_set_subject_name(x509v2,
                wolfSSL_X509_get_subject_name(x509)), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_X509_set_issuer_name(x509v2,
                wolfSSL_X509_get_issuer_name(x509)), WOLFSSL_SUCCESS);
    ExpectNotNull(pub = wolfSSL_X509_get_pubkey(x509));
    ExpectIntEQ(X509_set_pubkey(x509v2, pub), WOLFSSL_SUCCESS);

    t = time(NULL);
    ExpectNotNull(notBefore = wolfSSL_ASN1_TIME_adj(NULL, t, 0, 0));
    ExpectNotNull(notAfter = wolfSSL_ASN1_TIME_adj(NULL, t, 365, 0));
    ExpectTrue(wolfSSL_X509_set_notBefore(x509v2, notBefore));
    ExpectTrue(wolfSSL_X509_set_notAfter(x509v2, notAfter));

    ExpectIntGT(wolfSSL_X509_sign(x509v2, priv, EVP_sha256()), 0);
    derSz = wolfSSL_i2d_X509(x509v2, &der);
    ExpectIntGT(derSz, 0);
    ExpectIntEQ(wolfSSL_CTX_use_certificate_buffer(ctx, der, derSz,
                                     WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
    /* TODO: Replace with API call */
    XFREE(der, HEAP_HINT, DYNAMIC_TYPE_OPENSSL);
    XFREE(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(name, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(header, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    wolfSSL_X509_free(x509);
    wolfSSL_X509_free(x509v2);
    wolfSSL_EVP_PKEY_free(priv);
    wolfSSL_EVP_PKEY_free(pub);
    wolfSSL_ASN1_TIME_free(notBefore);
    wolfSSL_ASN1_TIME_free(notAfter);

    return EXPECT_RESULT();
}


/* override certificate version error */
static int test_override_x509(int preverify, WOLFSSL_X509_STORE_CTX* store)
{
    EXPECT_DECLS;
#ifndef OPENSSL_COMPATIBLE_DEFAULTS
    ExpectIntEQ(store->error, WC_NO_ERR_TRACE(ASN_VERSION_E));
#else
    ExpectIntEQ(store->error, 0);
#endif
    ExpectIntEQ((int)wolfSSL_X509_get_version(store->current_cert), 1);
    (void)preverify;
    return EXPECT_RESULT() == TEST_SUCCESS;
}


/* set verify callback that will override bad certificate version */
static int test_set_override_x509(WOLFSSL_CTX* ctx)
{
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, test_override_x509);
    return TEST_SUCCESS;
}
#endif


static int test_wolfSSL_X509_TLS_version_test_1(void)
{
    EXPECT_DECLS;
#if !defined(NO_DH) && !defined(NO_AES) && defined(WOLFSSL_CERT_GEN) && \
         defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
         defined(OPENSSL_EXTRA) && !defined(NO_ASN_TIME)
    test_ssl_cbf func_cb_client;
    test_ssl_cbf func_cb_server;

    /* test server rejects a client certificate that is not version 3 */
    XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
    XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));

    func_cb_client.ctx_ready = &test_set_x509_badversion;
#ifndef WOLFSSL_NO_TLS12
    func_cb_client.method = wolfTLSv1_2_client_method;
#else
    func_cb_client.method = wolfTLSv1_3_client_method;
#endif

#ifndef WOLFSSL_NO_TLS12
    func_cb_server.method = wolfTLSv1_2_server_method;
#else
    func_cb_server.method = wolfTLSv1_3_server_method;
#endif

#ifndef OPENSSL_COMPATIBLE_DEFAULTS
    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
        &func_cb_server, NULL), -1001);
#else
    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
        &func_cb_server, NULL), TEST_SUCCESS);
#endif
#endif

    return EXPECT_RESULT();
}

static int test_wolfSSL_X509_TLS_version_test_2(void)
{
    EXPECT_DECLS;
#if !defined(NO_DH) && !defined(NO_AES) && defined(WOLFSSL_CERT_GEN) && \
         defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
         defined(OPENSSL_EXTRA) && !defined(NO_ASN_TIME)
    test_ssl_cbf func_cb_client;
    test_ssl_cbf func_cb_server;

    XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
    XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));

    func_cb_client.ctx_ready = &test_set_x509_badversion;
    func_cb_server.ctx_ready = &test_set_override_x509;
#ifndef WOLFSSL_NO_TLS12
    func_cb_client.method = wolfTLSv1_2_client_method;
#else
    func_cb_client.method = wolfTLSv1_3_client_method;
#endif

#ifndef WOLFSSL_NO_TLS12
    func_cb_server.method = wolfTLSv1_2_server_method;
#else
    func_cb_server.method = wolfTLSv1_3_server_method;
#endif

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
        &func_cb_server, NULL), TEST_SUCCESS);
#endif

    return EXPECT_RESULT();
}

/* Testing function  wolfSSL_CTX_SetMinVersion; sets the minimum downgrade
 * version allowed.
 * POST: 1 on success.
 */
static int test_wolfSSL_CTX_SetMinVersion(void)
{
    int                     res = TEST_SKIPPED;
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS)
    int                     failFlag = WOLFSSL_SUCCESS;
    WOLFSSL_CTX*            ctx;
    int                     itr;

    #ifndef NO_OLD_TLS
        const int versions[]  = {
                            #ifdef WOLFSSL_ALLOW_TLSV10
                                  WOLFSSL_TLSV1,
                            #endif
                                  WOLFSSL_TLSV1_1,
                                  WOLFSSL_TLSV1_2 };
    #elif !defined(WOLFSSL_NO_TLS12)
        const int versions[]  = { WOLFSSL_TLSV1_2 };
    #elif defined(WOLFSSL_TLS13)
        const int versions[]  = { WOLFSSL_TLSV1_3 };
    #else
        const int versions[0];
    #endif

    ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());

    for (itr = 0; itr < (int)(sizeof(versions)/sizeof(int)); itr++) {
        if (wolfSSL_CTX_SetMinVersion(ctx, *(versions + itr))
                != WOLFSSL_SUCCESS) {
            failFlag = WOLFSSL_FAILURE;
        }
    }

    wolfSSL_CTX_free(ctx);

    res = TEST_RES_CHECK(failFlag == WOLFSSL_SUCCESS);
#endif
    return res;

} /* END test_wolfSSL_CTX_SetMinVersion */


/*----------------------------------------------------------------------------*
 | OCSP Stapling
 *----------------------------------------------------------------------------*/


/* Testing wolfSSL_UseOCSPStapling function. OCSP stapling eliminates the need
 * need to contact the CA, lowering the cost of cert revocation checking.
 * PRE: HAVE_OCSP and HAVE_CERTIFICATE_STATUS_REQUEST
 * POST: 1 returned for success.
 */
static int test_wolfSSL_UseOCSPStapling(void)
{
    EXPECT_DECLS;
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) && defined(HAVE_OCSP) && \
    !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL_CTX*    ctx = NULL;
    WOLFSSL*        ssl = NULL;

#ifndef NO_WOLFSSL_CLIENT
    #ifndef WOLFSSL_NO_TLS12
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
    #else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
    #endif
#else
    #ifndef WOLFSSL_NO_TLS12
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()));
    #else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
    #endif
#endif
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    ExpectIntEQ(wolfSSL_UseOCSPStapling(NULL, WOLFSSL_CSR2_OCSP,
        WOLFSSL_CSR2_OCSP_USE_NONCE), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
    ExpectIntEQ(wolfSSL_UseOCSPStapling(ssl, WOLFSSL_CSR2_OCSP,
        WOLFSSL_CSR2_OCSP_USE_NONCE), 1);
#else
    ExpectIntEQ(wolfSSL_UseOCSPStapling(ssl, WOLFSSL_CSR2_OCSP,
        WOLFSSL_CSR2_OCSP_USE_NONCE), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
} /* END test_wolfSSL_UseOCSPStapling */


/* Testing OCSP stapling version 2, wolfSSL_UseOCSPStaplingV2 function. OCSP
 * stapling eliminates the need to contact the CA and lowers cert revocation
 * check.
 * PRE: HAVE_CERTIFICATE_STATUS_REQUEST_V2 and HAVE_OCSP defined.
 */
static int test_wolfSSL_UseOCSPStaplingV2(void)
{
    EXPECT_DECLS;
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) && defined(HAVE_OCSP) && \
    !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL_CTX*        ctx = NULL;
    WOLFSSL*            ssl = NULL;

#ifndef NO_WOLFSSL_CLIENT
    #ifndef WOLFSSL_NO_TLS12
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
    #else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
    #endif
#else
    #ifndef WOLFSSL_NO_TLS12
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()));
    #else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
    #endif
#endif
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    ExpectIntEQ(wolfSSL_UseOCSPStaplingV2(NULL, WOLFSSL_CSR2_OCSP,
        WOLFSSL_CSR2_OCSP_USE_NONCE), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
    ExpectIntEQ(wolfSSL_UseOCSPStaplingV2(ssl, WOLFSSL_CSR2_OCSP,
        WOLFSSL_CSR2_OCSP_USE_NONCE), 1);
#else
    ExpectIntEQ(wolfSSL_UseOCSPStaplingV2(ssl, WOLFSSL_CSR2_OCSP,
        WOLFSSL_CSR2_OCSP_USE_NONCE), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();

} /* END test_wolfSSL_UseOCSPStaplingV2 */

/*----------------------------------------------------------------------------*
 | Multicast Tests
 *----------------------------------------------------------------------------*/
static int test_wolfSSL_mcast(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) && \
    (defined(WOLFSSL_TLS13) || defined(WOLFSSL_SNIFFER)) && \
    !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;
    byte preMasterSecret[512];
    byte clientRandom[32];
    byte serverRandom[32];
    byte suite[2] = {0, 0xfe};  /* WDM_WITH_NULL_SHA256 */
    byte buf[256];
    word16 newId;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method()));

    ExpectIntEQ(wolfSSL_CTX_mcast_set_member_id(ctx, 0), WOLFSSL_SUCCESS);

    ExpectNotNull(ssl = wolfSSL_new(ctx));

    XMEMSET(preMasterSecret, 0x23, sizeof(preMasterSecret));
    XMEMSET(clientRandom, 0xA5, sizeof(clientRandom));
    XMEMSET(serverRandom, 0x5A, sizeof(serverRandom));
    ExpectIntEQ(wolfSSL_set_secret(ssl, 23, preMasterSecret,
        sizeof(preMasterSecret), clientRandom, serverRandom, suite),
        WOLFSSL_SUCCESS);

    ExpectIntLE(wolfSSL_mcast_read(ssl, &newId, buf, sizeof(buf)), 0);
    ExpectIntLE(newId, 100);

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif /* WOLFSSL_DTLS && WOLFSSL_MULTICAST && (WOLFSSL_TLS13 ||
        * WOLFSSL_SNIFFER) */
    return EXPECT_RESULT();
}


/*----------------------------------------------------------------------------*
 |  Wolfcrypt
 *----------------------------------------------------------------------------*/

/*
 * Testing wc_SetAcmeIdentifierExt() round-trip - the RFC 8737
 * id-pe-acmeIdentifier (1.3.6.1.5.5.7.1.31) extension used by
 * TLS-ALPN-01 ACME challenge certs.
 */
static int test_wc_SetAcmeIdentifierExt(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_ACME_OID) && defined(WOLFSSL_CERT_GEN) && \
    defined(HAVE_ECC) && !defined(NO_SHA256) && !defined(NO_ASN_TIME) && \
    !defined(WC_NO_RNG) && !defined(NO_RSA)
    Cert         cert;
    DecodedCert  decoded;
    WC_RNG       rng;
    ecc_key      key;
    byte         der[TWOK_BUF];
    int          derSz = 0;
    int          rngInited = 0, keyInited = 0;
    const char*  keyAuth = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
                           ".kZdq0qaDcXNVxKBkP_uiKvw2Yg5sRJ8KBfQa9Ru13nE";
    word32       keyAuthSz = (word32)XSTRLEN(keyAuth);
    byte         expected[WC_SHA256_DIGEST_SIZE];

    XMEMSET(&cert,    0, sizeof(cert));
    XMEMSET(&decoded, 0, sizeof(decoded));
    XMEMSET(&rng,     0, sizeof(rng));
    XMEMSET(&key,     0, sizeof(key));
    XMEMSET(der,      0, sizeof(der));

    /* Compute the expected digest */
    ExpectIntEQ(wc_Sha256Hash((const byte*)keyAuth, keyAuthSz, expected), 0);

    /* Input validation. */
    ExpectIntEQ(wc_SetAcmeIdentifierExt(NULL, (const byte*)keyAuth, keyAuthSz),
                WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_SetAcmeIdentifierExt(&cert, NULL, keyAuthSz),
                WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_SetAcmeIdentifierExt(&cert, (const byte*)keyAuth, 0),
                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Build a P-256 keypair to sign the cert. */
    ExpectIntEQ(wc_InitRng(&rng), 0);
    rngInited = 1;
    ExpectIntEQ(wc_ecc_init(&key), 0);
    keyInited = 1;
    ExpectIntEQ(wc_ecc_make_key_ex(&rng, KEY32, &key, ECC_SECP256R1), 0);

    /* Build a minimal self-signed cert template carrying the extension. */
    ExpectIntEQ(wc_InitCert(&cert), 0);
    cert.sigType   = CTC_SHA256wECDSA;
    cert.daysValid = 1;
    cert.isCA      = 0;
    XSTRNCPY(cert.subject.commonName, "acme-test.example", CTC_NAME_SIZE);

    ExpectIntEQ(wc_SetAcmeIdentifierExt(&cert, (const byte*)keyAuth,
                                        keyAuthSz), 0);
    ExpectIntEQ(cert.acmeIdentifierSz, WC_SHA256_DIGEST_SIZE);
    ExpectIntEQ(XMEMCMP(cert.acmeIdentifier, expected,
                        WC_SHA256_DIGEST_SIZE), 0);

    /* MakeCert + SignCert. ECC_TYPE selects the ECDSA signing path. */
    ExpectIntGT(derSz = wc_MakeCert_ex(&cert, der, sizeof(der),
                                       ECC_TYPE, &key, &rng), 0);
    ExpectIntGT(derSz = wc_SignCert_ex(cert.bodySz, cert.sigType,
                                       der, sizeof(der),
                                       ECC_TYPE, &key, &rng), 0);

    /* Parse the cert back and verify the extension survives the
     * round-trip via DecodeAcmeId. */
    wc_InitDecodedCert(&decoded, der, derSz, NULL);
    ExpectIntEQ(wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL), 0);
    ExpectIntEQ(decoded.extAcmeIdentifierSet, 1);
    ExpectIntEQ(decoded.extAcmeIdentifierCrit, 1);
    ExpectIntEQ(decoded.acmeIdentifierSz, WC_SHA256_DIGEST_SIZE);
    ExpectIntEQ(XMEMCMP(decoded.acmeIdentifier, expected,
                        WC_SHA256_DIGEST_SIZE), 0);

    wc_FreeDecodedCert(&decoded);
    if (keyInited) wc_ecc_free(&key);
    if (rngInited) wc_FreeRng(&rng);
#endif
    return EXPECT_RESULT();
} /* END test_wc_SetAcmeIdentifierExt */

/*
 * Testing wc_SetKeyUsage()
 */
static int test_wc_SetKeyUsage(void)
{
    EXPECT_DECLS;
#if !defined(NO_RSA) && defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN) && !defined(HAVE_FIPS)
    Cert myCert;

    ExpectIntEQ(wc_InitCert(&myCert), 0);

    ExpectIntEQ(wc_SetKeyUsage(&myCert, "keyEncipherment,keyAgreement"), 0);
    ExpectIntEQ(wc_SetKeyUsage(&myCert, "digitalSignature,nonRepudiation"), 0);
    ExpectIntEQ(wc_SetKeyUsage(&myCert, "contentCommitment,encipherOnly"), 0);
    ExpectIntEQ(wc_SetKeyUsage(&myCert, "decipherOnly"), 0);
    ExpectIntEQ(wc_SetKeyUsage(&myCert, "cRLSign,keyCertSign"), 0);

    /* Test bad args. */
    ExpectIntEQ(wc_SetKeyUsage(NULL, "decipherOnly"), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_SetKeyUsage(&myCert, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_SetKeyUsage(&myCert, ""), WC_NO_ERR_TRACE(KEYUSAGE_E));
    ExpectIntEQ(wc_SetKeyUsage(&myCert, ","), WC_NO_ERR_TRACE(KEYUSAGE_E));
    ExpectIntEQ(wc_SetKeyUsage(&myCert, "digitalSignature, cRLSign"),
        WC_NO_ERR_TRACE(KEYUSAGE_E));
#endif
    return EXPECT_RESULT();
} /* END  test_wc_SetKeyUsage */

#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
static void sample_mutex_cb (int flag, int type, const char* file, int line)
{
    (void)flag;
    (void)type;
    (void)file;
    (void)line;
}
#endif
/*
 * Testing wc_LockMutex_ex
 */
static int test_wc_LockMutex_ex(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
    int flag = CRYPTO_LOCK;
    int type = 0;
    const char* file = "./test-LockMutex_ex.txt";
    int line = 0;

    /* without SetMutexCb */
    ExpectIntEQ(wc_LockMutex_ex(flag, type, file, line), WC_NO_ERR_TRACE(BAD_STATE_E));
    /* with SetMutexCb */
    ExpectIntEQ(wc_SetMutexCb(sample_mutex_cb), 0);
    ExpectIntEQ(wc_LockMutex_ex(flag, type, file, line), 0);
    ExpectIntEQ(wc_SetMutexCb(NULL), 0);
#endif
    return EXPECT_RESULT();
} /* End test_wc_LockMutex_ex*/
/*
 * Testing wc_SetMutexCb
 */
static int test_wc_SetMutexCb(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
    ExpectIntEQ(wc_SetMutexCb(sample_mutex_cb), 0);
    ExpectIntEQ(wc_SetMutexCb(NULL), 0);
#endif
    return EXPECT_RESULT();
} /* End test_wc_SetMutexCb*/


/*
 * Testing ToTraditional
 */
static int test_ToTraditional(void)
{
    EXPECT_DECLS;
#if !defined(NO_ASN) && (defined(HAVE_PKCS8) || defined(HAVE_PKCS12)) && \
    (defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
     defined(OPENSSL_EXTRA_X509_SMALL)) && !defined(NO_FILESYSTEM)
    XFILE  f = XBADFILE;
    byte   input[TWOK_BUF];
    word32 sz = 0;

    ExpectTrue((f = XFOPEN("./certs/server-keyPkcs8.der", "rb")) != XBADFILE);
    ExpectTrue((sz = (word32)XFREAD(input, 1, sizeof(input), f)) > 0);
    if (f != XBADFILE)
        XFCLOSE(f);

    /* Good case */
    ExpectIntGT(ToTraditional(input, sz), 0);
    /* Bad cases */
    ExpectIntEQ(ToTraditional(NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(ToTraditional(NULL, sz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifdef WOLFSSL_ASN_TEMPLATE
    ExpectIntEQ(ToTraditional(input, 0), WC_NO_ERR_TRACE(BUFFER_E));
#else
    ExpectIntEQ(ToTraditional(input, 0), WC_NO_ERR_TRACE(ASN_PARSE_E));
#endif
#endif
    return EXPECT_RESULT();
} /* End test_ToTraditional*/


/*
 * Testing wc_SetSubjectBuffer
 */
static int test_wc_SetSubjectBuffer(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_CERT_GEN) && !defined(NO_RSA) && !defined(NO_FILESYSTEM)
    Cert   cert;
    XFILE  file = XBADFILE;
    byte*  der = NULL;
    word32 derSz;

    derSz = FOURK_BUF;
    ExpectNotNull(der = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT,
        DYNAMIC_TYPE_TMP_BUFFER));
    ExpectTrue((file = XFOPEN("./certs/ca-cert.der", "rb")) != XBADFILE);
    ExpectTrue((derSz = (word32)XFREAD(der, 1, FOURK_BUF, file)) > 0);
    if (file != XBADFILE)
        XFCLOSE(file);

    ExpectIntEQ(wc_InitCert(&cert), 0);
    ExpectIntEQ(wc_SetSubjectBuffer(&cert, der, (int)derSz), 0);
    ExpectIntEQ(wc_SetSubjectBuffer(NULL, der, (int)derSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    XFREE(der, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
#endif
    return EXPECT_RESULT();
} /* End test_wc_SetSubjectBuffer*/

/*
 * Testing wc_SetSubjectKeyIdFromPublicKey_ex
 */
static int test_wc_SetSubjectKeyIdFromPublicKey_ex(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN)
    WC_RNG      rng;
    Cert        cert;
#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)
    RsaKey      rsaKey;
    int         bits = 2048;
#endif
#if defined(HAVE_ECC)
    ecc_key     eccKey;
    int         ret;
#endif
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT)
    ed25519_key ed25519Key;
#endif
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT)
    ed448_key   ed448Key;
#endif

#ifndef HAVE_FIPS
    ExpectIntEQ(wc_InitRng_ex(&rng, HEAP_HINT, testDevId), 0);
#else
    ExpectIntEQ(wc_InitRng(&rng), 0);
#endif

    ExpectIntEQ(wc_InitCert(&cert), 0);

#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)
    /* RSA */
    XMEMSET(&rsaKey, 0, sizeof(RsaKey));
    ExpectIntEQ(wc_InitRsaKey(&rsaKey, HEAP_HINT), 0);
    ExpectIntEQ(MAKE_RSA_KEY(&rsaKey, bits, WC_RSA_EXPONENT, &rng), 0);
    ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, RSA_TYPE, &rsaKey),
        0);
    DoExpectIntEQ(wc_FreeRsaKey(&rsaKey), 0);
#endif

#if defined(HAVE_ECC)
    /* ECC */
    XMEMSET(&eccKey, 0, sizeof(ecc_key));
    ExpectIntEQ(wc_ecc_init(&eccKey), 0);
    ret = wc_ecc_make_key(&rng, KEY14, &eccKey);
#if defined(WOLFSSL_ASYNC_CRYPT)
    ret = wc_AsyncWait(ret, &eccKey.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
    ExpectIntEQ(ret, 0);
    ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &eccKey),
        0);
    DoExpectIntEQ(wc_ecc_free(&eccKey), 0);
#endif

#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT)
    /* ED25519 */
    XMEMSET(&ed25519Key, 0, sizeof(ed25519_key));
    ExpectIntEQ(wc_ed25519_init(&ed25519Key), 0);
    ExpectIntEQ(wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &ed25519Key), 0);
    ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ED25519_TYPE,
        &ed25519Key), 0);
    wc_ed25519_free(&ed25519Key);
#endif

#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT)
    /* ED448 */
    XMEMSET(&ed448Key, 0, sizeof(ed448_key));
    ExpectIntEQ(wc_ed448_init(&ed448Key), 0);
    ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &ed448Key), 0);
    ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ED448_TYPE,
        &ed448Key), 0);
    wc_ed448_free(&ed448Key);
#endif

    wc_FreeRng(&rng);
    DoExpectIntEQ(wc_FreeRng(&rng), 0);
#endif /* WOLFSSL_CERT_EXT && WOLFSSL_CERT_GEN */
    return EXPECT_RESULT();
} /* End test_wc_SetSubjectKeyIdFromPublicKey_ex*/

/*
 * Testing wc_SetAuthKeyIdFromPublicKey_ex
 */
static int test_wc_SetAuthKeyIdFromPublicKey_ex(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN)
    WC_RNG      rng;
    Cert        cert;
#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)
    RsaKey      rsaKey;
    int         bits = 2048;
#endif
#if defined(HAVE_ECC)
    ecc_key     eccKey;
    int         ret;
#endif
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT)
    ed25519_key ed25519Key;
#endif
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT)
    ed448_key   ed448Key;
#endif

#ifndef HAVE_FIPS
    ExpectIntEQ(wc_InitRng_ex(&rng, HEAP_HINT, testDevId), 0);
#else
    ExpectIntEQ(wc_InitRng(&rng), 0);
#endif

    ExpectIntEQ(wc_InitCert(&cert), 0);

#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)
    /* RSA */
    XMEMSET(&rsaKey, 0, sizeof(RsaKey));
    ExpectIntEQ(wc_InitRsaKey(&rsaKey, HEAP_HINT), 0);
    ExpectIntEQ(MAKE_RSA_KEY(&rsaKey, bits, WC_RSA_EXPONENT, &rng), 0);
    ExpectIntEQ(wc_SetAuthKeyIdFromPublicKey_ex(&cert, RSA_TYPE, &rsaKey), 0);
    DoExpectIntEQ(wc_FreeRsaKey(&rsaKey), 0);
#endif

#if defined(HAVE_ECC)
    /* ECC */
    XMEMSET(&eccKey, 0, sizeof(ecc_key));
    ExpectIntEQ(wc_ecc_init(&eccKey), 0);
    ret = wc_ecc_make_key(&rng, KEY14, &eccKey);
#if defined(WOLFSSL_ASYNC_CRYPT)
    ret = wc_AsyncWait(ret, &eccKey.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
    ExpectIntEQ(ret, 0);
    ExpectIntEQ(wc_SetAuthKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &eccKey), 0);
    DoExpectIntEQ(wc_ecc_free(&eccKey), 0);
#endif

#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT)
    /* ED25519 */
    XMEMSET(&ed25519Key, 0, sizeof(ed25519_key));
    ExpectIntEQ(wc_ed25519_init(&ed25519Key), 0);
    ExpectIntEQ(wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &ed25519Key), 0);
    ExpectIntEQ(wc_SetAuthKeyIdFromPublicKey_ex(&cert, ED25519_TYPE,
        &ed25519Key), 0);
    wc_ed25519_free(&ed25519Key);
#endif

#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT)
    /* ED448 */
    XMEMSET(&ed448Key, 0, sizeof(ed448_key));
    ExpectIntEQ(wc_ed448_init(&ed448Key), 0);
    ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &ed448Key), 0);
    ExpectIntEQ(wc_SetAuthKeyIdFromPublicKey_ex(&cert, ED448_TYPE, &ed448Key),
        0);
    wc_ed448_free(&ed448Key);
#endif

    DoExpectIntEQ(wc_FreeRng(&rng), 0);
#endif /* defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN)*/
    return EXPECT_RESULT();
} /* End test_wc_SetAuthKeyIdFromPublicKey_ex*/

static int test_wolfSSL_lhash(void)
{
    EXPECT_DECLS;
#ifdef OPENSSL_ALL
    const char testStr[] = "Like a true nature's child\n"
                           "We were born\n"
                           "Born to be wild";

#ifdef NO_SHA
    ExpectIntEQ(lh_strhash(testStr), 0xf9dc8a43);
#else
    ExpectIntEQ(lh_strhash(testStr), 0x5b7541dc);
#endif
#endif
    return EXPECT_RESULT();
}

static int test_wc_PemToDer(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && defined(WOLFSSL_PEM_TO_DER) && !defined(NO_FILESYSTEM)
    int ret;
    DerBuffer* pDer = NULL;
    const char* ca_cert = "./certs/server-cert.pem";
    const char* trusted_cert = "./certs/test/ossl-trusted-cert.pem";
    byte* cert_buf = NULL;
    size_t cert_sz = 0;
    int eccKey = 0;
    EncryptedInfo info;

    XMEMSET(&info, 0, sizeof(info));

    ExpectIntEQ(ret = load_file(ca_cert, &cert_buf, &cert_sz), 0);
    ExpectIntEQ(ret = wc_PemToDer(cert_buf, (long int)cert_sz, CERT_TYPE, &pDer, NULL,
        &info, &eccKey), 0);
    wc_FreeDer(&pDer);
    pDer = NULL;

    if (cert_buf != NULL) {
        XFREE(cert_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        cert_buf = NULL;
    }

    /* Test that -----BEGIN TRUSTED CERTIFICATE----- banner parses OK */
    ExpectIntEQ(ret = load_file(trusted_cert, &cert_buf, &cert_sz), 0);
    ExpectIntEQ(ret = wc_PemToDer(cert_buf, (long int)cert_sz, TRUSTED_CERT_TYPE, &pDer, NULL,
        &info, &eccKey), 0);
    wc_FreeDer(&pDer);
    pDer = NULL;

    if (cert_buf != NULL) {
        XFREE(cert_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        cert_buf = NULL;
    }

#ifdef HAVE_ECC
    {
        const char* ecc_private_key = "./certs/ecc-privOnlyKey.pem";
        byte key_buf[256] = {0};

        /* Test fail of loading a key with cert type */
        ExpectIntEQ(load_file(ecc_private_key, &cert_buf, &cert_sz), 0);
        key_buf[0] = '\n';
        ExpectNotNull(XMEMCPY(key_buf + 1, cert_buf, cert_sz));
        ExpectIntNE((ret = wc_PemToDer(key_buf, (long int)cert_sz + 1, CERT_TYPE,
            &pDer, NULL, &info, &eccKey)), 0);

    #ifdef OPENSSL_EXTRA
        ExpectIntEQ((ret = wc_PemToDer(key_buf, cert_sz + 1, PRIVATEKEY_TYPE,
            &pDer, NULL, &info, &eccKey)), 0);
    #endif
        wc_FreeDer(&pDer);
        if (cert_buf != NULL)
            XFREE(cert_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    }
#endif
    /* NULL buff, zero size, and negative size must be rejected up front. The
     * pre-fix code cast longSz to word32, so a negative value drove an
     * over-read inside PemToDer. */
    {
        const byte stub[] = "x";
        DerBuffer* badDer = NULL;
        ExpectIntEQ(wc_PemToDer(NULL, 100, CERT_TYPE, &badDer, NULL, &info,
            &eccKey), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
        ExpectIntEQ(wc_PemToDer(stub, 0, CERT_TYPE, &badDer, NULL, &info,
            &eccKey), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
        ExpectIntEQ(wc_PemToDer(stub, -1, CERT_TYPE, &badDer, NULL, &info,
            &eccKey), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    }
#endif
    return EXPECT_RESULT();
}

static int test_wc_AllocDer(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS)
    DerBuffer* pDer = NULL;
    word32 testSize = 1024;

    ExpectIntEQ(wc_AllocDer(NULL, testSize, CERT_TYPE, HEAP_HINT),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AllocDer(&pDer, testSize, CERT_TYPE, HEAP_HINT), 0);
    ExpectNotNull(pDer);
    wc_FreeDer(&pDer);
#endif
    return EXPECT_RESULT();
}

static int test_wc_CertPemToDer(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && defined(WOLFSSL_PEM_TO_DER) && !defined(NO_FILESYSTEM)
    const char* ca_cert = "./certs/ca-cert.pem";
    byte* cert_buf = NULL;
    size_t cert_sz = 0;
    size_t cert_dersz = 0;
    byte* cert_der = NULL;

    ExpectIntEQ(load_file(ca_cert, &cert_buf, &cert_sz), 0);
    cert_dersz = cert_sz; /* DER will be smaller than PEM */
    ExpectNotNull(cert_der = (byte*)malloc(cert_dersz));
    ExpectIntGE(wc_CertPemToDer(cert_buf, (int)cert_sz, cert_der,
        (int)cert_dersz, CERT_TYPE), 0);

    ExpectIntEQ(wc_CertPemToDer(NULL, (int)cert_sz, NULL, -1, CERT_TYPE),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_CertPemToDer(cert_buf, (int)cert_sz, NULL, -1, CERT_TYPE),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_CertPemToDer(NULL, (int)cert_sz, cert_der, -1, CERT_TYPE),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_CertPemToDer(NULL, (int)cert_sz, NULL, (int)cert_dersz,
        CERT_TYPE), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_CertPemToDer(NULL, (int)cert_sz, cert_der,
        (int)cert_dersz, CERT_TYPE), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_CertPemToDer(cert_buf, (int)cert_sz, NULL,
        (int)cert_dersz, CERT_TYPE), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_CertPemToDer(cert_buf, (int)cert_sz, cert_der, -1,
        CERT_TYPE), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_CertPemToDer(cert_buf, -1, cert_der, (int)cert_dersz,
        CERT_TYPE), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_CertPemToDer(cert_buf, 0, cert_der, (int)cert_dersz,
        CERT_TYPE), WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    if (cert_der != NULL)
        free(cert_der);
    if (cert_buf != NULL)
        XFREE(cert_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
    return EXPECT_RESULT();
}

static int test_wc_KeyPemToDer(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_PEM_TO_DER) && !defined(NO_FILESYSTEM) && !defined(NO_RSA)
    int ret = 0;
    const byte cert_buf[] = \
    "-----BEGIN PRIVATE KEY-----\n"
    "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDMG5KgWxP002pA\n"
    "QJIdA4H5N0oM1Wf0LrHcos5RYUlrHDkC2b5p2BUpVRPmgDAFD2+8leim98x0BvcB\n"
    "k48TNzrVynuwyVEY664+iQyzEBO5v27HPRydOddprbLCvRO036XINGIjauy1jHFi\n"
    "HaDVx3bexSwgp9aefUGAszFXi4q1J4GacV7Cr2b/wBqUHqWv4ZXPu6R9/UYngTkD\n"
    "UDJL5gLlLfcLzNyyodKPHPCIAKdWn6mSVdcHk8XVpK4y9lgz4E7YDWA6ohKZgWgG\n"
    "2RDha8CMilFMDgYa0G0SiS9g3PQx0qh3AMXJJsKSVhScFCZufAE0kV6KvjP7jAqP\n"
    "XBiSkRGPAgMBAAECggEAW7hmRyY2jRX2UMJThrM9VIs6fRLnYI0dQ0tsEJj536ay\n"
    "nevQjArc05KWW0Yujg+WRDZPcry3RUqd9Djlmhp/F3Si6dpF1b+PMS3wJYVrf9Sd\n"
    "SO5W7faArU4vnyBNe0HnY1Ta5xSVI65lg1RSIs88RTZwsooJwXYDGf0shq0/21CE\n"
    "V8HOb27DDYNcEnm35lzaONjFnMqQQT2Vs9anRrPiSEXNleEvTgLVXZtGTyCGTz6v\n"
    "x86Y8eSWL9YNHvPE1I+mDPuocfSR7eRNgRu7SK3mn94W5mqd7Ns072YKX/2XN1mO\n"
    "66+ZFHO6v4dK1u7cSjuwrU1EhLHpUsgDz6Bna5InyQKBgQDv5l8RPy8UneKSADaf\n"
    "M5L/5675I/5t4nqVjvbnQje00YveLTAEjlJBNR93Biln3sYgnvNamYDCxyEuUZ/I\n"
    "S/vmBL9PoxfGZow4FcsIBOEbIn3E0SYJgCBNWthquUvGpKsYDnThJuhO+1cVmxAJ\n"
    "BUOjLFnJYHM0a+Vmk9GexT2OBwKBgQDZzkUBOK7Im3eiYytFocUJyhqMH30d49X9\n"
    "ujC7kGw4UWAqVe7YCSvlBa8nzWpRWK2kRpu3M0272RU0V4geyWqT+nr/SvRRPtNP\n"
    "F5dY8l3yR7hjtSejqqjOfBcZT6ETJxI4tiG0+Nl5BlfM5M+0nxnkWpRcHuOR3j79\n"
    "YUFERyN+OQKBgQCjlOKeUAc6d65W/+4/AFvsQ378Q57qLtSHxsR1TKHPmlNVXFqx\n"
    "wJo1/JNIBduWCEHxXHF0BdfW+RGXE/FwEt/hKLuLAhrkHmjelX2sKieU6R/5ZOQa\n"
    "9lMQbDHGFDOncAF6leD85hriQGBRSzrT69MDIOrYdfwYcroqCAGX0cb3YQKBgQC8\n"
    "iIFQylj5SyHmjcMSNjKSA8CxFDzAV8yPIdE3Oo+CvGXqn5HsrRuy1hXE9VmXapR8\n"
    "A6ackSszdHiXY0FvrNe1mfdH7wDHJwPQjdIzazCJHS3uGQxj7sDKY7226ie6pXJv\n"
    "ZrCMr2/IBAaSVGm6ppHKCeIsT4ybYm7R85KEYLPHeQKBgBeJOMBinXQfWN/1jT9b\n"
    "6Ywrutvp2zP8hVxQGSZJ0WG4iewZyFLsPUlbWRXOSYNPElHmdD0ZomdLVm+lSpAA\n"
    "XSH5FJ/IFCwqq7Eft6Gf8NFRV+NjPMUny+PnjHe4oFP8YK/Ek22K3ttNG8Hw69Aw\n"
    "AQue5o6oVfhgLiJzMdo/77gw\n"
    "-----END PRIVATE KEY-----\n";
    const int cert_sz = sizeof(cert_buf);
    const char cert_pw[] = "password";
    int cert_dersz = 0;
    byte* cert_der = NULL;

    /* Bad arg: Cert buffer is NULL */
    ExpectIntEQ(wc_KeyPemToDer(NULL, cert_sz, cert_der, cert_dersz, ""),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Bad arg: Cert DER buffer non-NULL but size zero (or less) */
    ExpectIntEQ(wc_KeyPemToDer(cert_buf, cert_sz, (byte*)&cert_der, 0, ""),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Bad arg: negative or zero pemSz */
    ExpectIntEQ(wc_KeyPemToDer(cert_buf, -1, (byte*)&cert_der, cert_sz, ""),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_KeyPemToDer(cert_buf, 0, (byte*)&cert_der, cert_sz, ""),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Test normal operation */
    cert_dersz = cert_sz; /* DER will be smaller than PEM */
    ExpectNotNull(cert_der = (byte*)malloc((size_t)cert_dersz));
    ExpectIntGE(ret = wc_KeyPemToDer(cert_buf, cert_sz, cert_der, cert_dersz,
        cert_pw), 0);
    ExpectIntLE(ret, cert_sz);
    if (cert_der != NULL) {
        free(cert_der);
        cert_der = NULL;
    }

    /* Test NULL for DER buffer to return needed DER buffer size */
    ExpectIntGT(ret = wc_KeyPemToDer(cert_buf, cert_sz, NULL, 0, ""), 0);
    ExpectIntLE(ret, cert_sz);
    if (EXPECT_SUCCESS())
        cert_dersz = ret;
    ExpectNotNull(cert_der = (byte*)malloc((size_t)cert_dersz));
    ExpectIntGE(ret = wc_KeyPemToDer(cert_buf, cert_sz, cert_der, cert_dersz,
        cert_pw), 0);
    ExpectIntLE(ret, cert_sz);
    if (cert_der != NULL)
        free(cert_der);
#endif
    return EXPECT_RESULT();
}

static int test_wc_PubKeyPemToDer(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_PEM_TO_DER) && !defined(NO_FILESYSTEM) && \
   (defined(WOLFSSL_CERT_EXT) || defined(WOLFSSL_PUB_PEM_TO_DER))
    int ret = 0;
    const char* key = "./certs/ecc-client-keyPub.pem";
    byte* cert_buf = NULL;
    size_t cert_sz = 0, cert_dersz = 0;
    byte* cert_der = NULL;

    ExpectIntEQ(wc_PubKeyPemToDer(cert_buf, (int)cert_sz,
        cert_der, (int)cert_dersz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(load_file(key, &cert_buf, &cert_sz), 0);
    cert_dersz = cert_sz; /* DER will be smaller than PEM */
    ExpectNotNull(cert_der = (byte*)malloc(cert_dersz));
    ExpectIntEQ(wc_PubKeyPemToDer(cert_buf, -1, cert_der, (int)cert_dersz),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_PubKeyPemToDer(cert_buf, 0, cert_der, (int)cert_dersz),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntGE(wc_PubKeyPemToDer(cert_buf, (int)cert_sz, cert_der,
        (int)cert_dersz), 0);
    if (cert_der != NULL) {
        free(cert_der);
        cert_der = NULL;
    }

    /* Test NULL for DER buffer to return needed DER buffer size */
    ExpectIntGT(ret = wc_PubKeyPemToDer(cert_buf, (int)cert_sz, NULL, 0), 0);
    ExpectIntLE(ret, cert_sz);
    cert_dersz = (size_t)ret;
    ExpectNotNull(cert_der = (byte*)malloc(cert_dersz));
    ExpectIntGE(wc_PubKeyPemToDer(cert_buf, (int)cert_sz, cert_der,
        (int)cert_dersz), 0);
    if (cert_der != NULL) {
        free(cert_der);
    }

    if (cert_buf != NULL) {
        XFREE(cert_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    }
#endif
    return EXPECT_RESULT();
}

static int test_wc_PemPubKeyToDer(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && \
    (defined(WOLFSSL_CERT_EXT) || defined(WOLFSSL_PUB_PEM_TO_DER))
    const char* key = "./certs/ecc-client-keyPub.pem";
    size_t cert_dersz = 1024;
    byte* cert_der = NULL;

    ExpectIntGE(wc_PemPubKeyToDer(NULL, cert_der, (int)cert_dersz),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectNotNull(cert_der = (byte*)malloc(cert_dersz));
    ExpectIntGE(wc_PemPubKeyToDer(key, cert_der, (int)cert_dersz), 0);
    if (cert_der != NULL) {
        free(cert_der);
    }
#endif
    return EXPECT_RESULT();
}

static int test_wc_GetPubKeyDerFromCert(void)
{
    EXPECT_DECLS;
#if !defined(NO_RSA) || defined(HAVE_ECC)
    int ret;
    word32 idx = 0;
    byte keyDer[TWOK_BUF];  /* large enough for up to RSA 2048 */
    word32 keyDerSz = (word32)sizeof(keyDer);
    DecodedCert decoded;
#if !defined(NO_RSA) && defined(WOLFSSL_CERT_REQ) && !defined(NO_FILESYSTEM)
    byte certBuf[6000]; /* for PEM and CSR, client-cert.pem is 5-6kB */
    word32 certBufSz = sizeof(certBuf);
#endif
#if ((!defined(USE_CERT_BUFFERS_2048) && !defined(USE_CERT_BUFFERS_1024)) || \
     defined(WOLFSSL_CERT_REQ)) && !defined(NO_RSA) && !defined(NO_FILESYSTEM)
    XFILE fp = XBADFILE;
#endif
#ifndef NO_RSA
    RsaKey rsaKey;
    #if defined(USE_CERT_BUFFERS_2048)
        byte* rsaCertDer = (byte*)client_cert_der_2048;
        word32 rsaCertDerSz = sizeof_client_cert_der_2048;
    #elif defined(USE_CERT_BUFFERS_1024)
        byte* rsaCertDer = (byte*)client_cert_der_1024;
        word32 rsaCertDerSz = sizeof_client_cert_der_1024;
    #else
        unsigned char rsaCertDer[TWOK_BUF];
        word32 rsaCertDerSz;
    #endif
#endif
#ifdef HAVE_ECC
    ecc_key eccKey;
    #if defined(USE_CERT_BUFFERS_256)
        byte* eccCert = (byte*)cliecc_cert_der_256;
        word32 eccCertSz = sizeof_cliecc_cert_der_256;
    #else
        unsigned char eccCert[ONEK_BUF];
        word32 eccCertSz;
        XFILE fp2 = XBADFILE;
    #endif
#endif

#ifndef NO_RSA

#if !defined(USE_CERT_BUFFERS_1024) && !defined(USE_CERT_BUFFERS_2048)
    ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE);
    ExpectIntGT(rsaCertDerSz = (word32)XFREAD(rsaCertDer, 1, sizeof(rsaCertDer),
        fp), 0);
    if (fp != XBADFILE) {
        XFCLOSE(fp);
        fp = XBADFILE;
    }
#endif

    /* good test case - RSA DER cert */
    wc_InitDecodedCert(&decoded, rsaCertDer, rsaCertDerSz, NULL);
    ExpectIntEQ(wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL), 0);

    ExpectIntEQ(wc_GetPubKeyDerFromCert(&decoded, keyDer, &keyDerSz), 0);
    ExpectIntGT(keyDerSz, 0);

    /* sanity check, verify we can import DER public key */
    ret = wc_InitRsaKey(&rsaKey, HEAP_HINT);
    ExpectIntEQ(ret, 0);
    ExpectIntEQ(wc_RsaPublicKeyDecode(keyDer, &idx, &rsaKey, keyDerSz), 0);
    if (ret == 0) {
        wc_FreeRsaKey(&rsaKey);
    }

    /* test LENGTH_ONLY_E case */
    keyDerSz = 0;
    ExpectIntEQ(wc_GetPubKeyDerFromCert(&decoded, NULL, &keyDerSz),
        WC_NO_ERR_TRACE(LENGTH_ONLY_E));
    ExpectIntGT(keyDerSz, 0);

    /* bad args: DecodedCert NULL */
    ExpectIntEQ(wc_GetPubKeyDerFromCert(NULL, keyDer, &keyDerSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* bad args: output key buff size */
    ExpectIntEQ(wc_GetPubKeyDerFromCert(&decoded, keyDer, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* bad args: zero size output key buffer */
    keyDerSz = 0;
    ExpectIntEQ(ret = wc_GetPubKeyDerFromCert(&decoded, keyDer, &keyDerSz),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    wc_FreeDecodedCert(&decoded);

    /* Certificate Request Tests */
    #if defined(WOLFSSL_CERT_REQ) && !defined(NO_FILESYSTEM)
    {
        XMEMSET(certBuf, 0, sizeof(certBuf));
        ExpectTrue((fp = XFOPEN("./certs/csr.signed.der", "rb")) != XBADFILE);
        ExpectIntGT(certBufSz = (word32)XFREAD(certBuf, 1, certBufSz, fp), 0);
        if (fp != XBADFILE) {
            XFCLOSE(fp);
        }

        wc_InitDecodedCert(&decoded, certBuf, certBufSz, NULL);
        ExpectIntEQ(wc_ParseCert(&decoded, CERTREQ_TYPE, VERIFY, NULL), 0);

        /* good test case - RSA DER certificate request */
        keyDerSz = sizeof(keyDer);
        ExpectIntEQ(ret = wc_GetPubKeyDerFromCert(&decoded, keyDer, &keyDerSz),
            0);
        ExpectIntGT(keyDerSz, 0);

        /* sanity check, verify we can import DER public key */
        ret = wc_InitRsaKey(&rsaKey, HEAP_HINT);
        ExpectIntEQ(ret, 0);
        idx = 0;
        ExpectIntEQ(wc_RsaPublicKeyDecode(keyDer, &idx, &rsaKey, keyDerSz), 0);
        if (ret == 0) {
            wc_FreeRsaKey(&rsaKey);
        }

        wc_FreeDecodedCert(&decoded);
    }
    #endif /* WOLFSSL_CERT_REQ */
#endif /* NO_RSA */

#ifdef HAVE_ECC
    #ifndef USE_CERT_BUFFERS_256
        ExpectTrue((fp2 = XFOPEN("./certs/client-ecc-cert.der", "rb")) !=
            XBADFILE);
        ExpectIntGT(eccCertSz = (word32)XFREAD(eccCert, 1, ONEK_BUF, fp2), 0);
        if (fp2 != XBADFILE) {
            XFCLOSE(fp2);
        }
    #endif

    wc_InitDecodedCert(&decoded, eccCert, eccCertSz, NULL);
    ExpectIntEQ(wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL), 0);

    /* good test case - ECC */
    XMEMSET(keyDer, 0, sizeof(keyDer));
    keyDerSz = sizeof(keyDer);
    ExpectIntEQ(wc_GetPubKeyDerFromCert(&decoded, keyDer, &keyDerSz), 0);
    ExpectIntGT(keyDerSz, 0);

    /* sanity check, verify we can import DER public key */
    ret = wc_ecc_init(&eccKey);
    ExpectIntEQ(ret, 0);
    idx = 0; /* reset idx to 0, used above in RSA case */
    ExpectIntEQ(wc_EccPublicKeyDecode(keyDer, &idx, &eccKey, keyDerSz), 0);
    if (ret == 0) {
        wc_ecc_free(&eccKey);
    }

    /* test LENGTH_ONLY_E case */
    keyDerSz = 0;
    ExpectIntEQ(wc_GetPubKeyDerFromCert(&decoded, NULL, &keyDerSz),
        WC_NO_ERR_TRACE(LENGTH_ONLY_E));
    ExpectIntGT(keyDerSz, 0);

    wc_FreeDecodedCert(&decoded);
#endif
#endif /* !NO_RSA || HAVE_ECC */
    return EXPECT_RESULT();
}

static int test_wc_GetSubjectPubKeyInfoDerFromCert(void)
{
    EXPECT_DECLS;
#if !defined(NO_RSA) || defined(HAVE_ECC)
    int ret;
    word32 idx = 0;
    byte keyDer[TWOK_BUF];  /* large enough for up to RSA 2048 */
    word32 keyDerSz = (word32)sizeof(keyDer);
#if !defined(NO_RSA) && defined(WOLFSSL_CERT_REQ) && !defined(NO_FILESYSTEM)
    byte certBuf[6000]; /* for PEM and CSR, client-cert.pem is 5-6kB */
    word32 certBufSz = sizeof(certBuf);
#endif
#if ((!defined(USE_CERT_BUFFERS_2048) && !defined(USE_CERT_BUFFERS_1024)) || \
     defined(WOLFSSL_CERT_REQ)) && !defined(NO_RSA) && !defined(NO_FILESYSTEM)
    XFILE fp = XBADFILE;
#endif
#ifndef NO_RSA
    RsaKey rsaKey;
    #if defined(USE_CERT_BUFFERS_2048)
        byte* rsaCertDer = (byte*)client_cert_der_2048;
        word32 rsaCertDerSz = sizeof_client_cert_der_2048;
    #elif defined(USE_CERT_BUFFERS_1024)
        byte* rsaCertDer = (byte*)client_cert_der_1024;
        word32 rsaCertDerSz = sizeof_client_cert_der_1024;
    #else
        unsigned char rsaCertDer[TWOK_BUF];
        word32 rsaCertDerSz;
    #endif
#endif
#ifdef HAVE_ECC
    ecc_key eccKey;
    #if defined(USE_CERT_BUFFERS_256)
        byte* eccCert = (byte*)cliecc_cert_der_256;
        word32 eccCertSz = sizeof_cliecc_cert_der_256;
    #else
        unsigned char eccCert[ONEK_BUF];
        word32 eccCertSz;
        XFILE fp2 = XBADFILE;
    #endif
#endif

#ifndef NO_RSA

#if !defined(USE_CERT_BUFFERS_1024) && !defined(USE_CERT_BUFFERS_2048)
    ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE);
    ExpectIntGT(rsaCertDerSz = (word32)XFREAD(rsaCertDer, 1, sizeof(rsaCertDer),
        fp), 0);
    if (fp != XBADFILE) {
        XFCLOSE(fp);
        fp = XBADFILE;
    }
#endif

    /* good test case - RSA DER cert */
    ExpectIntEQ(wc_GetSubjectPubKeyInfoDerFromCert(rsaCertDer, rsaCertDerSz,
                                                   keyDer, &keyDerSz), 0);
    ExpectIntGT(keyDerSz, 0);

    /* sanity check, verify we can import DER public key */
    ret = wc_InitRsaKey(&rsaKey, HEAP_HINT);
    ExpectIntEQ(ret, 0);
    ExpectIntEQ(wc_RsaPublicKeyDecode(keyDer, &idx, &rsaKey, keyDerSz), 0);
    if (ret == 0) {
        wc_FreeRsaKey(&rsaKey);
    }

    /* bad args: certDer */
    keyDerSz = (word32)sizeof(keyDer);
    ExpectIntEQ(wc_GetSubjectPubKeyInfoDerFromCert(NULL, rsaCertDerSz, keyDer,
                                                   &keyDerSz),
                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* bad args: 0 sized certSz */
    keyDerSz = (word32)sizeof(keyDer);
    ExpectIntEQ(wc_GetSubjectPubKeyInfoDerFromCert(rsaCertDer, 0, keyDer,
                                                   &keyDerSz),
                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* bad args: NULL inout size */
    ExpectIntEQ(ret = wc_GetSubjectPubKeyInfoDerFromCert(rsaCertDer,
                                                         rsaCertDerSz, keyDer,
                                                         NULL),
                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Certificate Request Tests */
    #if defined(WOLFSSL_CERT_REQ) && !defined(NO_FILESYSTEM)
    {
        XMEMSET(certBuf, 0, sizeof(certBuf));
        ExpectTrue((fp = XFOPEN("./certs/csr.signed.der", "rb")) != XBADFILE);
        ExpectIntGT(certBufSz = (word32)XFREAD(certBuf, 1, certBufSz, fp), 0);
        if (fp != XBADFILE) {
            XFCLOSE(fp);
        }

        /* good test case - RSA DER certificate request */
        keyDerSz = sizeof(keyDer);
        ExpectIntEQ(ret = wc_GetSubjectPubKeyInfoDerFromCert(rsaCertDer,
                                                             rsaCertDerSz,
                                                             keyDer,
                                                             &keyDerSz), 0);
        ExpectIntGT(keyDerSz, 0);

        /* sanity check, verify we can import DER public key */
        ret = wc_InitRsaKey(&rsaKey, HEAP_HINT);
        ExpectIntEQ(ret, 0);
        idx = 0;
        ExpectIntEQ(wc_RsaPublicKeyDecode(keyDer, &idx, &rsaKey, keyDerSz), 0);
        if (ret == 0) {
            wc_FreeRsaKey(&rsaKey);
        }
    }
    #endif /* WOLFSSL_CERT_REQ */
#endif /* NO_RSA */

#ifdef HAVE_ECC
    #ifndef USE_CERT_BUFFERS_256
        ExpectTrue((fp2 = XFOPEN("./certs/client-ecc-cert.der", "rb")) !=
            XBADFILE);
        ExpectIntGT(eccCertSz = (word32)XFREAD(eccCert, 1, ONEK_BUF, fp2), 0);
        if (fp2 != XBADFILE) {
            XFCLOSE(fp2);
        }
    #endif

    /* good test case - ECC */
    XMEMSET(keyDer, 0, sizeof(keyDer));
    keyDerSz = sizeof(keyDer);
    ExpectIntEQ(wc_GetSubjectPubKeyInfoDerFromCert(eccCert, eccCertSz, keyDer,
                                                   &keyDerSz), 0);
    ExpectIntGT(keyDerSz, 0);

    /* sanity check, verify we can import DER public key */
    ret = wc_ecc_init(&eccKey);
    ExpectIntEQ(ret, 0);
    idx = 0; /* reset idx to 0, used above in RSA case */
    ExpectIntEQ(wc_EccPublicKeyDecode(keyDer, &idx, &eccKey, keyDerSz), 0);
    if (ret == 0) {
        wc_ecc_free(&eccKey);
    }

#endif
#endif /* !NO_RSA || HAVE_ECC */
    return EXPECT_RESULT();
}

static int test_wc_CheckCertSigPubKey(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
    !defined(NO_RSA) && defined(WOLFSSL_PEM_TO_DER) && defined(HAVE_ECC)
    int ret = 0;
    const char* ca_cert = "./certs/ca-cert.pem";
    byte* cert_buf = NULL;
    size_t cert_sz = 0;
    byte* cert_der = NULL;
    word32 cert_dersz = 0;
    byte keyDer[TWOK_BUF];  /* large enough for up to RSA 2048 */
    word32 keyDerSz = (word32)sizeof(keyDer);
    DecodedCert decoded;

    ExpectIntEQ(load_file(ca_cert, &cert_buf, &cert_sz), 0);
    cert_dersz = (word32)cert_sz; /* DER will be smaller than PEM */
    ExpectNotNull(cert_der = (byte*)malloc(cert_dersz));
    ExpectIntGE(ret = wc_CertPemToDer(cert_buf, (int)cert_sz, cert_der,
        (int)cert_dersz, CERT_TYPE), 0);

    wc_InitDecodedCert(&decoded, cert_der, cert_dersz, NULL);
    ExpectIntEQ(wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL), 0);

    ExpectIntEQ(wc_GetPubKeyDerFromCert(&decoded, keyDer, &keyDerSz), 0);
    ExpectIntGT(keyDerSz, 0);

    /* Good test case. */
    ExpectIntEQ(wc_CheckCertSigPubKey(cert_der, cert_dersz, NULL, keyDer,
        keyDerSz, RSAk), 0);

    /* No certificate. */
    ExpectIntEQ(wc_CheckCertSigPubKey(NULL, cert_dersz, NULL, keyDer, keyDerSz,
        ECDSAk), WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Bad cert size. */
    ExpectIntNE(ret = wc_CheckCertSigPubKey(cert_der, 0, NULL, keyDer, keyDerSz,
        RSAk), 0);
    ExpectTrue(ret == WC_NO_ERR_TRACE(ASN_PARSE_E) || ret == WC_NO_ERR_TRACE(BUFFER_E));

    /* No public key. */
    ExpectIntEQ(wc_CheckCertSigPubKey(cert_der, cert_dersz, NULL, NULL,
        keyDerSz, RSAk), WC_NO_ERR_TRACE(ASN_NO_SIGNER_E));

    /* Bad public key size. */
    ExpectIntEQ(wc_CheckCertSigPubKey(cert_der, cert_dersz, NULL, keyDer, 0,
        RSAk), WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Wrong algo. */
    ExpectIntEQ(wc_CheckCertSigPubKey(cert_der, cert_dersz, NULL, keyDer,
        keyDerSz, ECDSAk), WC_NO_ERR_TRACE(ASN_SIG_OID_E));

    wc_FreeDecodedCert(&decoded);
    if (cert_der != NULL)
        free(cert_der);
    if (cert_buf != NULL)
        XFREE(cert_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_X509_ext_d2i(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS)
    X509* x509 = NULL;

    ExpectNotNull(x509 = wolfSSL_X509_new());

    ExpectNull(wolfSSL_X509_get_ext_d2i(x509, NID_basic_constraints,
        NULL, NULL));
    ExpectNull(wolfSSL_X509_get_ext_d2i(x509, NID_subject_alt_name,
        NULL, NULL));
    ExpectNull(wolfSSL_X509_get_ext_d2i(x509, NID_authority_key_identifier,
        NULL, NULL));
    ExpectNull(wolfSSL_X509_get_ext_d2i(x509, NID_subject_key_identifier,
        NULL, NULL));
    ExpectNull(wolfSSL_X509_get_ext_d2i(x509, NID_key_usage,
        NULL, NULL));
    ExpectNull(wolfSSL_X509_get_ext_d2i(x509, NID_crl_distribution_points,
        NULL, NULL));
    ExpectNull(wolfSSL_X509_get_ext_d2i(x509, NID_ext_key_usage,
        NULL, NULL));
    ExpectNull(wolfSSL_X509_get_ext_d2i(x509, NID_info_access,
        NULL, NULL));
    ExpectNull(wolfSSL_X509_get_ext_d2i(x509, NID_certificate_policies,
        NULL, NULL));
    /* Invalid NID for an extension. */
    ExpectNull(wolfSSL_X509_get_ext_d2i(x509, NID_description,
        NULL, NULL));

    wolfSSL_X509_free(x509);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_certs(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
    !defined(NO_TLS) && !defined(NO_RSA)
    X509*  x509ext = NULL;
    X509*  x509 = NULL;
#ifdef OPENSSL_ALL
    WOLFSSL_X509_EXTENSION* ext = NULL;
    ASN1_OBJECT* obj = NULL;
#endif
    WOLFSSL*     ssl = NULL;
    WOLFSSL_CTX* ctx = NULL;
    STACK_OF(ASN1_OBJECT)* sk = NULL;
    ASN1_STRING* asn1_str = NULL;
    AUTHORITY_KEYID* akey = NULL;
    WOLFSSL_STACK* skid = NULL;
    BASIC_CONSTRAINTS* bc = NULL;
    int crit = 0;

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(SSLv23_server_method()));
#else
    ExpectNotNull(ctx = SSL_CTX_new(SSLv23_client_method()));
#endif
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, svrCertFile, SSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, SSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, cliKeyFile, SSL_FILETYPE_PEM));
    #if !defined(NO_CHECK_PRIVATE_KEY)
    ExpectIntEQ(SSL_CTX_check_private_key(ctx), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    #endif
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, SSL_FILETYPE_PEM));
    #if !defined(NO_CHECK_PRIVATE_KEY)
    ExpectIntEQ(SSL_CTX_check_private_key(ctx), SSL_SUCCESS);
    #endif
    ExpectNotNull(ssl = SSL_new(ctx));

    /* Invalid parameters. */
    ExpectIntEQ(SSL_use_certificate_file(NULL, NULL, WOLFSSL_FILETYPE_PEM),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(SSL_use_certificate_file(ssl, NULL, WOLFSSL_FILETYPE_PEM),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_use_certificate_file(NULL, "./certs/server-cert.pem",
        WOLFSSL_FILETYPE_PEM), WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    #if !defined(NO_CHECK_PRIVATE_KEY)
    ExpectIntEQ(wolfSSL_check_private_key(ssl), WOLFSSL_SUCCESS);
    #endif

    #ifdef HAVE_PK_CALLBACKS
    ExpectIntEQ((int)SSL_set_tlsext_debug_arg(ssl, NULL), WOLFSSL_SUCCESS);
    #endif /* HAVE_PK_CALLBACKS */

    /* Invalid parameters. */
    ExpectNotNull(x509 = wolfSSL_X509_new());
    ExpectIntEQ(SSL_use_certificate(NULL, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_use_certificate(ssl, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_use_certificate(NULL, x509), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    /* No data in certificate. */
    ExpectIntEQ(SSL_use_certificate(ssl, x509), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    wolfSSL_X509_free(x509);
    x509 = NULL;

    /* create and use x509 */
    ExpectNull(wolfSSL_X509_load_certificate_file(cliCertFileExt, -1));
    ExpectNull(wolfSSL_X509_load_certificate_file("/tmp/badfile",
        WOLFSSL_FILETYPE_PEM));
    ExpectNull(wolfSSL_X509_load_certificate_file(NULL, WOLFSSL_FILETYPE_PEM));
    ExpectNull(wolfSSL_X509_load_certificate_file(cliCertFileExt,
        WOLFSSL_FILETYPE_ASN1));
#ifdef OPENSSL_ALL
    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(cliCertFile,
        WOLFSSL_FILETYPE_PEM));
#endif
    ExpectNotNull(x509ext = wolfSSL_X509_load_certificate_file(cliCertFileExt,
        WOLFSSL_FILETYPE_PEM));
    ExpectIntEQ(SSL_use_certificate(ssl, x509ext), WOLFSSL_SUCCESS);

    #if !defined(NO_CHECK_PRIVATE_KEY)
    /* with loading in a new cert the check on private key should now fail */
    ExpectIntNE(wolfSSL_check_private_key(ssl), WOLFSSL_SUCCESS);
    #endif


    #if defined(USE_CERT_BUFFERS_2048)
        /* Invalid parameters. */
        ExpectIntEQ(SSL_use_certificate_ASN1(NULL, NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
        ExpectIntEQ(SSL_use_certificate_ASN1(ssl, NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
        ExpectIntEQ(SSL_use_certificate_ASN1(NULL,
                (unsigned char*)server_cert_der_2048, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
        /* No data. */
        ExpectIntEQ(SSL_use_certificate_ASN1(ssl,
                (unsigned char*)server_cert_der_2048, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

        ExpectIntEQ(SSL_use_certificate_ASN1(ssl,
                                  (unsigned char*)server_cert_der_2048,
                                  sizeof_server_cert_der_2048), WOLFSSL_SUCCESS);
    #endif

    #if !defined(NO_SHA) && !defined(NO_SHA256) && !defined(NO_PWDBASED)
    /************* Get Digest of Certificate ******************/
    {
        byte   digest[64]; /* max digest size */
        word32 digestSz;
        X509*  x509Empty = NULL;

        XMEMSET(digest, 0, sizeof(digest));
        ExpectIntEQ(X509_digest(NULL, wolfSSL_EVP_sha1(), digest, &digestSz),
                    WOLFSSL_FAILURE);
        ExpectIntEQ(X509_digest(x509ext, NULL, digest, &digestSz),
                    WOLFSSL_FAILURE);
        ExpectIntEQ(X509_digest(x509ext, wolfSSL_EVP_sha1(), NULL, &digestSz),
                    WOLFSSL_FAILURE);
        ExpectIntEQ(X509_digest(x509ext, wolfSSL_EVP_sha1(), digest, NULL),
                    WOLFSSL_SUCCESS);
        ExpectIntEQ(X509_digest(x509ext, wolfSSL_EVP_sha1(), digest, &digestSz),
                    WOLFSSL_SUCCESS);
        ExpectIntEQ(X509_digest(x509ext, wolfSSL_EVP_sha256(), digest,
                    &digestSz), WOLFSSL_SUCCESS);

        ExpectNotNull(x509Empty = wolfSSL_X509_new());
        ExpectIntEQ(X509_digest(x509Empty, wolfSSL_EVP_sha256(), digest,
                    &digestSz), WOLFSSL_FAILURE);
        wolfSSL_X509_free(x509Empty);
    }
    #endif /* !NO_SHA && !NO_SHA256 && !NO_PWDBASED */

    #if !defined(NO_SHA) && !defined(NO_SHA256) && !defined(NO_PWDBASED)
    /************* Get Digest of Certificate ******************/
    {
        byte   digest[64]; /* max digest size */
        word32 digestSz;
        X509*  x509Empty = NULL;

        XMEMSET(digest, 0, sizeof(digest));
        ExpectIntEQ(X509_pubkey_digest(NULL, wolfSSL_EVP_sha1(), digest,
                    &digestSz), WOLFSSL_FAILURE);
        ExpectIntEQ(X509_pubkey_digest(x509ext, NULL, digest, &digestSz),
                    WOLFSSL_FAILURE);
        ExpectIntEQ(X509_pubkey_digest(x509ext, wolfSSL_EVP_sha1(), NULL,
                    &digestSz), WOLFSSL_FAILURE);
        ExpectIntEQ(X509_pubkey_digest(x509ext, wolfSSL_EVP_sha1(), digest,
                    NULL), WOLFSSL_SUCCESS);
        ExpectIntEQ(X509_pubkey_digest(x509ext, wolfSSL_EVP_sha1(), digest,
                    &digestSz), WOLFSSL_SUCCESS);
        ExpectIntEQ(X509_pubkey_digest(x509ext, wolfSSL_EVP_sha256(), digest,
                    &digestSz), WOLFSSL_SUCCESS);

        ExpectNotNull(x509Empty = wolfSSL_X509_new());
        ExpectIntEQ(X509_pubkey_digest(x509Empty, wolfSSL_EVP_sha256(), digest,
                    &digestSz), WOLFSSL_FAILURE);
        wolfSSL_X509_free(x509Empty);
    }
    #endif /* !NO_SHA && !NO_SHA256 && !NO_PWDBASED */

    /* test and checkout X509 extensions */
    ExpectNotNull(bc = (BASIC_CONSTRAINTS*)X509_get_ext_d2i(x509ext,
        NID_basic_constraints, NULL, NULL));
    BASIC_CONSTRAINTS_free(bc);
    bc = NULL;
    ExpectNotNull(bc = (BASIC_CONSTRAINTS*)X509_get_ext_d2i(x509ext,
        NID_basic_constraints, &crit, NULL));
    ExpectIntEQ(crit, 0);

#ifdef OPENSSL_ALL
    ExpectNull(X509V3_EXT_i2d(NID_basic_constraints, crit, NULL));
    {
        int i;
        int unsupportedNid[] = {
            0,
            NID_inhibit_any_policy,
            NID_certificate_policies,
            NID_policy_mappings,
            NID_name_constraints,
            NID_policy_constraints,
            NID_crl_distribution_points
        };
        int unsupportedNidCnt = (int)(sizeof(unsupportedNid) /
                                      sizeof(*unsupportedNid));

        for (i = 0; i < unsupportedNidCnt; i++) {
            ExpectNotNull(ext = X509V3_EXT_i2d(unsupportedNid[i], crit, bc));
            X509_EXTENSION_free(ext);
            ext = NULL;
        }
    }
    ExpectNotNull(ext = X509V3_EXT_i2d(NID_basic_constraints, crit, bc));
    X509_EXTENSION_free(ext);
    ext = NULL;

    ExpectNotNull(ext = X509_EXTENSION_new());
    ExpectIntEQ(X509_EXTENSION_set_critical(NULL, 1), WOLFSSL_FAILURE);
    ExpectIntEQ(X509_EXTENSION_set_critical(ext, 1), WOLFSSL_SUCCESS);
    ExpectNotNull(obj = OBJ_nid2obj(NID_basic_constraints));
    ExpectIntEQ(X509_EXTENSION_set_object(NULL, NULL), SSL_FAILURE);
    ExpectIntEQ(X509_EXTENSION_set_object(NULL, obj), SSL_FAILURE);
    ExpectIntEQ(X509_EXTENSION_set_object(ext, NULL), SSL_SUCCESS);
    ExpectIntEQ(X509_EXTENSION_set_object(ext, obj), SSL_SUCCESS);
    /* Check old object is being freed. */
    ExpectIntEQ(X509_EXTENSION_set_object(ext, obj), SSL_SUCCESS);
    ASN1_OBJECT_free(obj);
    obj = NULL;
    X509_EXTENSION_free(ext);
    ext = NULL;

    ExpectNotNull(ext = X509_EXTENSION_new());
    ExpectIntEQ(X509_EXTENSION_set_critical(ext, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_EXTENSION_set_data(ext, NULL),
            WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectNotNull(asn1_str = (ASN1_STRING*)X509_get_ext_d2i(x509ext,
            NID_key_usage, NULL, NULL));
    ASN1_STRING_free(asn1_str);
    asn1_str = NULL;
    ExpectNotNull(asn1_str = (ASN1_STRING*)X509_get_ext_d2i(x509ext,
            NID_key_usage, &crit, NULL));
    ExpectIntEQ(X509_EXTENSION_set_data(ext, asn1_str), SSL_SUCCESS);
    ExpectIntEQ(X509_EXTENSION_set_data(ext, asn1_str), SSL_SUCCESS);
    ASN1_STRING_free(asn1_str); /* X509_EXTENSION_set_data has made a copy
                                 * and X509_get_ext_d2i has created new */
    asn1_str = NULL;
    X509_EXTENSION_free(ext);
    ext = NULL;

#endif
    BASIC_CONSTRAINTS_free(NULL);
    BASIC_CONSTRAINTS_free(bc);
    bc = NULL;

    ExpectNotNull(asn1_str = (ASN1_STRING*)X509_get_ext_d2i(x509ext,
        NID_key_usage, NULL, NULL));
    ASN1_STRING_free(asn1_str);
    asn1_str = NULL;
    ExpectNotNull(asn1_str = (ASN1_STRING*)X509_get_ext_d2i(x509ext,
        NID_key_usage, &crit, NULL));
    ExpectIntEQ(crit, 1);
    ExpectIntEQ(asn1_str->type, NID_key_usage);
#ifdef OPENSSL_ALL
    ExpectNotNull(ext = X509V3_EXT_i2d(NID_key_usage, crit, asn1_str));
    X509_EXTENSION_free(ext);
    ext = NULL;
#endif
    ASN1_STRING_free(asn1_str);
    asn1_str = NULL;

#ifdef OPENSSL_ALL
    ExpectNotNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509,
        NID_ext_key_usage, NULL, NULL));
    EXTENDED_KEY_USAGE_free(NULL);
    EXTENDED_KEY_USAGE_free(sk);
    sk = NULL;
    ExpectNotNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509,
        NID_ext_key_usage, &crit, NULL));
    ExpectNotNull(ext = X509V3_EXT_i2d(NID_ext_key_usage, crit, sk));
    X509_EXTENSION_free(ext);
    ext = NULL;
    EXTENDED_KEY_USAGE_free(sk);
    sk = NULL;
#else
    sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509ext, NID_ext_key_usage,
            &crit, NULL);
    ExpectNull(sk);
#endif

    ExpectNotNull(akey = (AUTHORITY_KEYID*)X509_get_ext_d2i(x509ext,
        NID_authority_key_identifier, NULL, NULL));
    wolfSSL_AUTHORITY_KEYID_free(NULL);
    wolfSSL_AUTHORITY_KEYID_free(akey);
    akey = NULL;
    ExpectNotNull(akey = (AUTHORITY_KEYID*)X509_get_ext_d2i(x509ext,
        NID_authority_key_identifier, &crit, NULL));
#ifdef OPENSSL_ALL
    ExpectNotNull(ext = X509V3_EXT_i2d(NID_authority_key_identifier, crit,
        akey));
    X509_EXTENSION_free(ext);
    ext = NULL;
#endif
    wolfSSL_AUTHORITY_KEYID_free(akey);
    akey = NULL;

    ExpectNotNull(skid = (WOLFSSL_STACK*)X509_get_ext_d2i(x509ext,
        NID_subject_key_identifier, NULL, NULL));
    wolfSSL_sk_ASN1_OBJECT_pop_free(skid, wolfSSL_ASN1_OBJECT_free);
    skid = NULL;
    ExpectNotNull(skid = (WOLFSSL_STACK*)X509_get_ext_d2i(x509ext,
        NID_subject_key_identifier, &crit, NULL));
#ifdef OPENSSL_ALL
    ExpectNotNull(ext = X509V3_EXT_i2d(NID_subject_key_identifier, crit,
        skid));
    X509_EXTENSION_free(ext);
    ext = NULL;
#endif
    wolfSSL_sk_ASN1_OBJECT_pop_free(skid, wolfSSL_ASN1_OBJECT_free);
    skid = NULL;

    /* NID not yet supported */
    ExpectNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509ext,
        NID_private_key_usage_period, &crit, NULL));
    ExpectIntEQ(crit, -1);
    sk_ASN1_OBJECT_free(sk);
    sk = NULL;

    ExpectNotNull(sk = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(x509ext,
        NID_subject_alt_name, NULL, NULL));
    sk_GENERAL_NAME_free(sk);
    sk = NULL;
    ExpectNotNull(sk = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(x509ext,
        NID_subject_alt_name, &crit, NULL));
    {
        int i;
        for (i = 0; i < sk_GENERAL_NAME_num(sk); i++) {
            GENERAL_NAME* gen = sk_GENERAL_NAME_value(sk, i);
            ExpectIntEQ(gen->type, GEN_DNS);
            ExpectIntEQ(gen->d.dNSName->type, V_ASN1_IA5STRING);
        }
    }
    sk_GENERAL_NAME_free(sk);
    sk = NULL;

    /* NID not yet supported */
    ExpectNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509ext,
        NID_issuer_alt_name, &crit, NULL));
    ExpectIntEQ(crit, -1);
    sk_ASN1_OBJECT_free(sk);
    sk = NULL;

    /* NID not yet supported */
    ExpectNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509ext,
        NID_info_access, &crit, NULL));
    sk_ASN1_OBJECT_free(sk);
    sk = NULL;

    /* NID not yet supported */
    ExpectNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509ext,
        NID_sinfo_access, &crit, NULL));
    ExpectIntEQ(crit, -1);
    sk_ASN1_OBJECT_free(sk);
    sk = NULL;

    /* NID not yet supported */
    ExpectNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509ext,
        NID_name_constraints, &crit, NULL));
    ExpectIntEQ(crit, -1);
    sk_ASN1_OBJECT_free(sk);
    sk = NULL;

    /* no cert policy set */
    ExpectNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509ext,
            NID_certificate_policies, &crit, NULL));
    sk_ASN1_OBJECT_free(sk);
    sk = NULL;

    /* NID not yet supported */
    ExpectNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509ext,
        NID_policy_mappings, &crit, NULL));
    ExpectIntEQ(crit, -1);
    sk_ASN1_OBJECT_free(sk);
    sk = NULL;

    /* NID not yet supported */
    ExpectNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509ext,
        NID_policy_constraints, &crit, NULL));
    ExpectIntEQ(crit, -1);
    sk_ASN1_OBJECT_free(sk);
    sk = NULL;

    /* NID not yet supported */
    ExpectNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509ext,
        NID_inhibit_any_policy, &crit, NULL));
    ExpectIntEQ(crit, -1);
    sk_ASN1_OBJECT_free(sk);
    sk = NULL;

    /* NID not yet supported */
    ExpectNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509ext,
        NID_tlsfeature, &crit, NULL));
    ExpectIntEQ(crit, -1);
    sk_ASN1_OBJECT_free(sk);
    sk = NULL;

    /* test invalid cases */
    crit = 0;
    ExpectNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509ext, -1, &crit,
        NULL));
    ExpectIntEQ(crit, -1);
    /* NULL passed for criticality. */
    ExpectNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(NULL,
        NID_tlsfeature, NULL, NULL));

    ExpectIntEQ(SSL_get_hit(ssl), 0);
#ifdef OPENSSL_ALL
    X509_free(x509);
#endif
    X509_free(x509ext);
    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif /* OPENSSL_EXTRA && !NO_CERTS */
    return EXPECT_RESULT();
}

static int test_wolfSSL_private_keys(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_TLS) && \
   !defined(NO_FILESYSTEM)
#if !defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)
    WOLFSSL*     ssl = NULL;
    WOLFSSL_CTX* ctx = NULL;
    EVP_PKEY* pkey = NULL;

    OpenSSL_add_all_digests();
    OpenSSL_add_all_algorithms();

#ifndef NO_RSA
    #ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
    #else
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
    #endif
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
        WOLFSSL_FILETYPE_PEM));
    /* Have to load a cert before you can check the private key against that
     * certificates public key! */
    #if !defined(NO_CHECK_PRIVATE_KEY)
    ExpectIntEQ(wolfSSL_CTX_check_private_key(ctx), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    #endif
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, svrCertFile,
        WOLFSSL_FILETYPE_PEM));
    #if !defined(NO_CHECK_PRIVATE_KEY)
    ExpectIntEQ(wolfSSL_CTX_check_private_key(ctx), WOLFSSL_SUCCESS);
    #endif
    ExpectNotNull(ssl = SSL_new(ctx));

    #if !defined(NO_CHECK_PRIVATE_KEY)
    ExpectIntEQ(wolfSSL_check_private_key(ssl), WOLFSSL_SUCCESS);
    #endif

    /* Invalid parameters. */
    ExpectIntEQ(SSL_use_PrivateKey_file(NULL, NULL, WOLFSSL_FILETYPE_PEM),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(SSL_use_PrivateKey_file(NULL, svrKeyFile, WOLFSSL_FILETYPE_PEM),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(SSL_use_PrivateKey_file(ssl, NULL, WOLFSSL_FILETYPE_PEM),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

#ifdef USE_CERT_BUFFERS_2048
    {
    const unsigned char* server_key = (const unsigned char*)server_key_der_2048;
    unsigned char buf[FOURK_BUF];
    word32 bufSz;

    /* Invalid parameters. */
    ExpectIntEQ(SSL_use_RSAPrivateKey_ASN1(NULL, NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_use_RSAPrivateKey_ASN1(ssl, NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_use_RSAPrivateKey_ASN1(NULL,
        (unsigned char*)client_key_der_2048, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_use_PrivateKey_ASN1(0, NULL, NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_use_PrivateKey_ASN1(0, ssl, NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_use_PrivateKey_ASN1(0, NULL, (unsigned char*)server_key, 0),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_CTX_use_PrivateKey_ASN1(0, NULL, NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_CTX_use_PrivateKey_ASN1(0, ctx, NULL, 0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_CTX_use_PrivateKey_ASN1(0, NULL, (unsigned char*)server_key,
        0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    ExpectIntEQ(SSL_use_RSAPrivateKey_ASN1(ssl,
                (unsigned char*)client_key_der_2048,
                sizeof_client_key_der_2048), WOLFSSL_SUCCESS);
    #if !defined(NO_CHECK_PRIVATE_KEY)
    /* Should mismatch now that a different private key loaded */
    ExpectIntNE(wolfSSL_check_private_key(ssl), WOLFSSL_SUCCESS);
    #endif

    ExpectIntEQ(SSL_use_PrivateKey_ASN1(0, ssl,
                (unsigned char*)server_key,
                sizeof_server_key_der_2048), WOLFSSL_SUCCESS);
    #if !defined(NO_CHECK_PRIVATE_KEY)
    /* After loading back in DER format of original key, should match */
    ExpectIntEQ(wolfSSL_check_private_key(ssl), WOLFSSL_SUCCESS);
    #endif

    /* test loading private key to the WOLFSSL_CTX */
    ExpectIntEQ(SSL_CTX_use_PrivateKey_ASN1(0, ctx,
                (unsigned char*)client_key_der_2048,
                sizeof_client_key_der_2048), WOLFSSL_SUCCESS);

    #if !defined(NO_CHECK_PRIVATE_KEY)
    /* Should mismatch now that a different private key loaded */
    ExpectIntNE(wolfSSL_CTX_check_private_key(ctx), WOLFSSL_SUCCESS);
    #endif

    ExpectIntEQ(SSL_CTX_use_PrivateKey_ASN1(0, ctx,
                (unsigned char*)server_key,
                sizeof_server_key_der_2048), WOLFSSL_SUCCESS);
    #if !defined(NO_CHECK_PRIVATE_KEY)
    /* After loading back in DER format of original key, should match */
    ExpectIntEQ(wolfSSL_CTX_check_private_key(ctx), WOLFSSL_SUCCESS);
    #endif

    /* Invalid parameters. */
    ExpectNotNull(pkey = wolfSSL_EVP_PKEY_new());
    ExpectIntEQ(SSL_use_PrivateKey(NULL, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_use_PrivateKey(ssl, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_use_PrivateKey(NULL, pkey), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    /* pkey is empty - no key data to use. */
    ExpectIntEQ(SSL_use_PrivateKey(ssl, pkey), WC_NO_ERR_TRACE(ASN_PARSE_E));
    wolfSSL_EVP_PKEY_free(pkey);
    pkey = NULL;

    /* set PKEY and test again */
    ExpectNotNull(wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, &pkey,
                &server_key, (long)sizeof_server_key_der_2048));
    ExpectIntEQ(SSL_use_PrivateKey(ssl, pkey), WOLFSSL_SUCCESS);

    /* reuse PKEY structure and test
     * this should be checked with a memory management sanity checker */
    ExpectFalse(server_key == (const unsigned char*)server_key_der_2048);
    server_key = (const unsigned char*)server_key_der_2048;
    ExpectNotNull(wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, &pkey,
                &server_key, (long)sizeof_server_key_der_2048));
    ExpectIntEQ(SSL_use_PrivateKey(ssl, pkey), WOLFSSL_SUCCESS);

    /* check striping PKCS8 header with wolfSSL_d2i_PrivateKey */
    bufSz = FOURK_BUF;
    ExpectIntGT((bufSz = (word32)wc_CreatePKCS8Key(buf, &bufSz,
                    (byte*)server_key_der_2048, sizeof_server_key_der_2048,
                    RSAk, NULL, 0)), 0);
    server_key = (const unsigned char*)buf;
    ExpectNotNull(wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, &pkey, &server_key,
                (long)bufSz));
    }
#endif


    EVP_PKEY_free(pkey);
    pkey = NULL;
    SSL_free(ssl); /* frees x509 also since loaded into ssl */
    ssl = NULL;
    SSL_CTX_free(ctx);
    ctx = NULL;
#endif /* end of RSA private key match tests */


#ifdef HAVE_ECC
    #ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
    #else
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
    #endif
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, eccCertFile,
                                                         WOLFSSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, eccKeyFile,
                                                         WOLFSSL_FILETYPE_PEM));
    ExpectNotNull(ssl = SSL_new(ctx));

    #if !defined(NO_CHECK_PRIVATE_KEY)
    ExpectIntEQ(wolfSSL_check_private_key(ssl), WOLFSSL_SUCCESS);
    #endif
    SSL_free(ssl);
    ssl = NULL;


    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, cliEccKeyFile,
                                                         WOLFSSL_FILETYPE_PEM));
    ExpectNotNull(ssl = SSL_new(ctx));

    #ifdef WOLFSSL_VALIDATE_ECC_IMPORT
    ExpectIntNE(wolfSSL_check_private_key(ssl), WOLFSSL_SUCCESS);
    #endif

    SSL_free(ssl);
    ssl = NULL;
    SSL_CTX_free(ctx);
    ctx = NULL;
#endif /* end of ECC private key match tests */

#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT)
    #ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
    #else
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
    #endif
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, edCertFile,
                                                         WOLFSSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, edKeyFile,
                                                         WOLFSSL_FILETYPE_PEM));
    ExpectNotNull(ssl = SSL_new(ctx));

    #if !defined(NO_CHECK_PRIVATE_KEY)
    ExpectIntEQ(wolfSSL_check_private_key(ssl), WOLFSSL_SUCCESS);
    #endif
    SSL_free(ssl);
    ssl = NULL;


    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, cliEdKeyFile,
                                                         WOLFSSL_FILETYPE_PEM));
    ExpectNotNull(ssl = SSL_new(ctx));

    #if !defined(NO_CHECK_PRIVATE_KEY)
    #ifdef HAVE_ED25519_MAKE_KEY
    ExpectIntNE(wolfSSL_check_private_key(ssl), WOLFSSL_SUCCESS);
    #else
    ExpectIntEQ(wolfSSL_check_private_key(ssl), WOLFSSL_SUCCESS);
    #endif
    #endif

    SSL_free(ssl);
    ssl = NULL;
    SSL_CTX_free(ctx);
    ctx = NULL;
#endif /* end of Ed25519 private key match tests */

#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
    #ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
    #else
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
    #endif
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, ed448CertFile,
                                                         WOLFSSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, ed448KeyFile,
                                                         WOLFSSL_FILETYPE_PEM));
    ExpectNotNull(ssl = SSL_new(ctx));

    #if !defined(NO_CHECK_PRIVATE_KEY)
    ExpectIntEQ(wolfSSL_check_private_key(ssl), WOLFSSL_SUCCESS);
    #endif
    SSL_free(ssl);
    ssl = NULL;


    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, cliEd448KeyFile,
                                                         WOLFSSL_FILETYPE_PEM));
    ExpectNotNull(ssl = SSL_new(ctx));

    #if !defined(NO_CHECK_PRIVATE_KEY)
    ExpectIntNE(wolfSSL_check_private_key(ssl), WOLFSSL_SUCCESS);
    #endif

    SSL_free(ssl);
    ssl = NULL;
    SSL_CTX_free(ctx);
    ctx = NULL;
#endif /* end of Ed448 private key match tests */

    EVP_cleanup();

    /* test existence of no-op macros in wolfssl/openssl/ssl.h */
    CONF_modules_free();
    ENGINE_cleanup();
    CONF_modules_unload();

    (void)ssl;
    (void)ctx;
    (void)pkey;
#endif /* !NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER */
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_CERTS) */
    return EXPECT_RESULT();
}

static int test_wolfSSL_tmp_dh(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
    !defined(NO_RSA) && !defined(NO_DH) && !defined(NO_BIO) && \
    !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    byte buff[6000];
    static const unsigned char p[] = {
        0xb0, 0xa1, 0x08, 0x06, 0x9c, 0x08, 0x13, 0xba,
        0x59, 0x06, 0x3c, 0xbc, 0x30, 0xd5, 0xf5, 0x00,
        0xc1, 0x4f, 0x44, 0xa7, 0xd6, 0xef, 0x4a, 0xc6,
        0x25, 0x27, 0x1c, 0xe8, 0xd2, 0x96, 0x53, 0x0a,
        0x5c, 0x91, 0xdd, 0xa2, 0xc2, 0x94, 0x84, 0xbf,
        0x7d, 0xb2, 0x44, 0x9f, 0x9b, 0xd2, 0xc1, 0x8a,
        0xc5, 0xbe, 0x72, 0x5c, 0xa7, 0xe7, 0x91, 0xe6,
        0xd4, 0x9f, 0x73, 0x07, 0x85, 0x5b, 0x66, 0x48,
        0xc7, 0x70, 0xfa, 0xb4, 0xee, 0x02, 0xc9, 0x3d,
        0x9a, 0x4a, 0xda, 0x3d, 0xc1, 0x46, 0x3e, 0x19,
        0x69, 0xd1, 0x17, 0x46, 0x07, 0xa3, 0x4d, 0x9f,
        0x2b, 0x96, 0x17, 0x39, 0x6d, 0x30, 0x8d, 0x2a,
        0xf3, 0x94, 0xd3, 0x75, 0xcf, 0xa0, 0x75, 0xe6,
        0xf2, 0x92, 0x1f, 0x1a, 0x70, 0x05, 0xaa, 0x04,
        0x83, 0x57, 0x30, 0xfb, 0xda, 0x76, 0x93, 0x38,
        0x50, 0xe8, 0x27, 0xfd, 0x63, 0xee, 0x3c, 0xe5,
        0xb7, 0xc8, 0x09, 0xae, 0x6f, 0x50, 0x35, 0x8e,
        0x84, 0xce, 0x4a, 0x00, 0xe9, 0x12, 0x7e, 0x5a,
        0x31, 0xd7, 0x33, 0xfc, 0x21, 0x13, 0x76, 0xcc,
        0x16, 0x30, 0xdb, 0x0c, 0xfc, 0xc5, 0x62, 0xa7,
        0x35, 0xb8, 0xef, 0xb7, 0xb0, 0xac, 0xc0, 0x36,
        0xf6, 0xd9, 0xc9, 0x46, 0x48, 0xf9, 0x40, 0x90,
        0x00, 0x2b, 0x1b, 0xaa, 0x6c, 0xe3, 0x1a, 0xc3,
        0x0b, 0x03, 0x9e, 0x1b, 0xc2, 0x46, 0xe4, 0x48,
        0x4e, 0x22, 0x73, 0x6f, 0xc3, 0x5f, 0xd4, 0x9a,
        0xd6, 0x30, 0x07, 0x48, 0xd6, 0x8c, 0x90, 0xab,
        0xd4, 0xf6, 0xf1, 0xe3, 0x48, 0xd3, 0x58, 0x4b,
        0xa6, 0xb9, 0xcd, 0x29, 0xbf, 0x68, 0x1f, 0x08,
        0x4b, 0x63, 0x86, 0x2f, 0x5c, 0x6b, 0xd6, 0xb6,
        0x06, 0x65, 0xf7, 0xa6, 0xdc, 0x00, 0x67, 0x6b,
        0xbb, 0xc3, 0xa9, 0x41, 0x83, 0xfb, 0xc7, 0xfa,
        0xc8, 0xe2, 0x1e, 0x7e, 0xaf, 0x00, 0x3f, 0x93
    };
    int pSz = (int)sizeof(p);
#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
    !defined(HAVE_SELFTEST)
    static const unsigned char bad_p[] = {
        0xb0, 0xa1, 0x08, 0x06, 0x9c, 0x08, 0x13, 0xba,
        0x59, 0x06, 0x3c, 0xbc, 0x30, 0xd5, 0xf5, 0x00,
        0xc1, 0x4f, 0x44, 0xa7, 0xd6, 0xef, 0x4a, 0xc6,
        0x25, 0x27, 0x1c, 0xe8, 0xd2, 0x96, 0x53, 0x0a,
        0x5c, 0x91, 0xdd, 0xa2, 0xc2, 0x94, 0x84, 0xbf,
        0x7d, 0xb2, 0x44, 0x9f, 0x9b, 0xd2, 0xc1, 0x8a,
        0xc5, 0xbe, 0x72, 0x5c, 0xa7, 0xe7, 0x91, 0xe6,
        0xd4, 0x9f, 0x73, 0x07, 0x85, 0x5b, 0x66, 0x48,
        0xc7, 0x70, 0xfa, 0xb4, 0xee, 0x02, 0xc9, 0x3d,
        0x9a, 0x4a, 0xda, 0x3d, 0xc1, 0x46, 0x3e, 0x19,
        0x69, 0xd1, 0x17, 0x46, 0x07, 0xa3, 0x4d, 0x9f,
        0x2b, 0x96, 0x17, 0x39, 0x6d, 0x30, 0x8d, 0x2a,
        0xf3, 0x94, 0xd3, 0x75, 0xcf, 0xa0, 0x75, 0xe6,
        0xf2, 0x92, 0x1f, 0x1a, 0x70, 0x05, 0xaa, 0x04,
        0x83, 0x57, 0x30, 0xfb, 0xda, 0x76, 0x93, 0x38,
        0x50, 0xe8, 0x27, 0xfd, 0x63, 0xee, 0x3c, 0xe5,
        0xb7, 0xc8, 0x09, 0xae, 0x6f, 0x50, 0x35, 0x8e,
        0x84, 0xce, 0x4a, 0x00, 0xe9, 0x12, 0x7e, 0x5a,
        0x31, 0xd7, 0x33, 0xfc, 0x21, 0x13, 0x76, 0xcc,
        0x16, 0x30, 0xdb, 0x0c, 0xfc, 0xc5, 0x62, 0xa7,
        0x35, 0xb8, 0xef, 0xb7, 0xb0, 0xac, 0xc0, 0x36,
        0xf6, 0xd9, 0xc9, 0x46, 0x48, 0xf9, 0x40, 0x90,
        0x00, 0x2b, 0x1b, 0xaa, 0x6c, 0xe3, 0x1a, 0xc3,
        0x0b, 0x03, 0x9e, 0x1b, 0xc2, 0x46, 0xe4, 0x48,
        0x4e, 0x22, 0x73, 0x6f, 0xc3, 0x5f, 0xd4, 0x9a,
        0xd6, 0x30, 0x07, 0x48, 0xd6, 0x8c, 0x90, 0xab,
        0xd4, 0xf6, 0xf1, 0xe3, 0x48, 0xd3, 0x58, 0x4b,
        0xa6, 0xb9, 0xcd, 0x29, 0xbf, 0x68, 0x1f, 0x08,
        0x4b, 0x63, 0x86, 0x2f, 0x5c, 0x6b, 0xd6, 0xb6,
        0x06, 0x65, 0xf7, 0xa6, 0xdc, 0x00, 0x67, 0x6b,
        0xbb, 0xc3, 0xa9, 0x41, 0x83, 0xfb, 0xc7, 0xfa,
        0xc8, 0xe2, 0x1e, 0x7e, 0xaf, 0x00, 0x3f, 0x91
    };
#endif
    static const unsigned char g[] = { 0x02 };
    int gSz = (int)sizeof(g);
#if !defined(NO_DSA)
    char file[] = "./certs/dsaparams.pem";
    DSA* dsa = NULL;
#else
    char file[] = "./certs/dh2048.pem";
#endif
    XFILE f = XBADFILE;
    int  bytes = 0;
    DH*  dh = NULL;
    DH*  dh2 = NULL;
    BIO*     bio = NULL;
    SSL*     ssl = NULL;
    SSL_CTX* ctx = NULL;
#ifndef NO_WOLFSSL_CLIENT
    SSL*     ssl_c = NULL;
    SSL_CTX* ctx_c = NULL;
#endif

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, svrCertFile,
        WOLFSSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
        WOLFSSL_FILETYPE_PEM));
    ExpectNotNull(ssl = SSL_new(ctx));
#endif
#ifndef NO_WOLFSSL_CLIENT
    ExpectNotNull(ctx_c = SSL_CTX_new(wolfSSLv23_client_method()));
    ExpectTrue(SSL_CTX_use_certificate_file(ctx_c, svrCertFile,
        WOLFSSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx_c, svrKeyFile,
        WOLFSSL_FILETYPE_PEM));
    ExpectNotNull(ssl_c = SSL_new(ctx_c));
#ifdef NO_WOLFSSL_SERVER
    ctx = ctx_c;
    ssl = ssl_c;
#endif
#endif

    XMEMSET(buff, 0, sizeof(buff));
    ExpectTrue((f = XFOPEN(file, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buff, 1, sizeof(buff), f), 0);
    if (f != XBADFILE)
        XFCLOSE(f);

    ExpectNotNull(bio = BIO_new_mem_buf((void*)buff, bytes));

#if !defined(NO_DSA)
    dsa = wolfSSL_PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
    ExpectNotNull(dsa);

    dh = wolfSSL_DSA_dup_DH(dsa);
#else
    dh = wolfSSL_PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
#endif
    ExpectNotNull(dh);
#if defined(WOLFSSL_DH_EXTRA) && \
    (defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH))
    ExpectNotNull(dh2 = wolfSSL_DH_dup(dh));
    DH_free(dh2);
    dh2 = NULL;
#endif

    /* Failure cases */
    ExpectIntEQ((int)wolfSSL_CTX_SetTmpDH(NULL, NULL, 0, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ((int)wolfSSL_CTX_SetTmpDH(ctx , NULL, 0, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ((int)wolfSSL_CTX_SetTmpDH(NULL, p   , 0, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ((int)wolfSSL_CTX_SetTmpDH(NULL, NULL, 0, g   , 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ((int)wolfSSL_CTX_SetTmpDH(ctx , p  , 0, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ((int)wolfSSL_CTX_SetTmpDH(ctx , NULL, 0, g   , 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ((int)wolfSSL_CTX_SetTmpDH(NULL, p   , 0, g   , 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ((int)wolfSSL_CTX_SetTmpDH(ctx , p   , 1, g   , 1),
        WC_NO_ERR_TRACE(DH_KEY_SIZE_E));
    ExpectIntEQ((int)wolfSSL_CTX_SetTmpDH(ctx , buff, 6000, g   , 1),
        WC_NO_ERR_TRACE(DH_KEY_SIZE_E));
#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
    !defined(HAVE_SELFTEST)
    ExpectIntEQ((int)wolfSSL_CTX_SetTmpDH(ctx, bad_p, pSz, g, gSz),
        WC_NO_ERR_TRACE(DH_CHECK_PUB_E));
#endif
    ExpectIntEQ((int)wolfSSL_SetTmpDH(NULL, NULL, 0, NULL, 0),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ((int)wolfSSL_SetTmpDH(ssl , NULL, 0, NULL, 0),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ((int)wolfSSL_SetTmpDH(NULL, p   , 0, NULL, 0),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ((int)wolfSSL_SetTmpDH(NULL, NULL, 0, g   , 0),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ((int)wolfSSL_SetTmpDH(ssl , p  , 0, NULL, 0),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ((int)wolfSSL_SetTmpDH(ssl , NULL, 0, g   , 0),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ((int)wolfSSL_SetTmpDH(NULL, p   , 0, g   , 0),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ((int)wolfSSL_SetTmpDH(ssl , p   , 1, g   , 1),
        WC_NO_ERR_TRACE(DH_KEY_SIZE_E));
    ExpectIntEQ((int)wolfSSL_SetTmpDH(ssl , buff, 6000, g   , 1),
        WC_NO_ERR_TRACE(DH_KEY_SIZE_E));
#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
    !defined(HAVE_SELFTEST)
#ifndef NO_WOLFSSL_SERVER
    /* Parameters will be tested later so it passes now. */
    ExpectIntEQ((int)wolfSSL_SetTmpDH(ssl, bad_p, pSz, g, gSz),
        WOLFSSL_SUCCESS);
#endif
#endif
#ifndef NO_WOLFSSL_CLIENT
    ExpectIntEQ((int)wolfSSL_SetTmpDH(ssl_c, p, pSz, g, gSz),
        WC_NO_ERR_TRACE(SIDE_ERROR));
#endif
    ExpectIntEQ((int)SSL_CTX_set_tmp_dh(NULL, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ((int)SSL_CTX_set_tmp_dh(ctx , NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ((int)SSL_CTX_set_tmp_dh(NULL, dh  ), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ((int)SSL_set_tmp_dh(NULL, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ((int)SSL_set_tmp_dh(ssl , NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ((int)SSL_set_tmp_dh(NULL, dh  ), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* No p/g to use. */
    dh2 = wolfSSL_DH_new();
    ExpectIntEQ((int)SSL_CTX_set_tmp_dh(ctx , dh2 ), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
    ExpectIntEQ((int)SSL_set_tmp_dh(ssl , dh2 ), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
    DH_free(dh2);
    dh2 = NULL;

    ExpectIntEQ((int)wolfSSL_CTX_SetTmpDH(ctx, p, pSz, g, gSz),
        WOLFSSL_SUCCESS);
    ExpectIntEQ((int)SSL_CTX_set_tmp_dh(ctx, dh), WOLFSSL_SUCCESS);
#ifndef NO_WOLFSSL_SERVER
    ExpectIntEQ((int)SSL_set_tmp_dh(ssl, dh), WOLFSSL_SUCCESS);
#else
    ExpectIntEQ((int)SSL_set_tmp_dh(ssl, dh), WC_NO_ERR_TRACE(SIDE_ERROR));
#endif

    BIO_free(bio);
#if !defined(NO_DSA)
    DSA_free(dsa);
#endif
    DH_free(dh);
    dh = NULL;
#ifndef NO_WOLFSSL_CLIENT
    if (ssl != ssl_c) {
        SSL_free(ssl_c);
    }
#endif
    SSL_free(ssl);
#ifndef NO_WOLFSSL_CLIENT
    if (ctx != ctx_c) {
        SSL_CTX_free(ctx_c);
    }
#endif
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

/* Tests SSL_CTX_set_tmp_dh with single-operand failure (p set, g missing)
 * and wolfSSL_CTX_SetTmpDH_buffer with WOLFSSL_FILETYPE_ASN1 DER input. */
static int test_wolfSSL_tmp_dh_regression(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_DH) && !defined(NO_CERTS) && \
    !defined(NO_FILESYSTEM) && !defined(NO_RSA) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_SERVER)
    SSL_CTX* ctx = NULL;

    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, svrCertFile,
        WOLFSSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
        WOLFSSL_FILETYPE_PEM));

#if defined(OPENSSL_ALL) || \
    (defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L)
    {
        /* Test single-operand failure: DH with p but no g. */
        DH* dh = NULL;
        WOLFSSL_BIGNUM* p_bn = NULL;

        ExpectNotNull(dh = wolfSSL_DH_new());
        ExpectNotNull(p_bn = wolfSSL_BN_new());
        ExpectIntEQ(wolfSSL_BN_set_word(p_bn, 0xFFFF), 1);
        if (dh != NULL && p_bn != NULL) {
            if (wolfSSL_DH_set0_pqg(dh, p_bn, NULL, NULL) == 1) {
                p_bn = NULL; /* ownership transferred on success */
            }
        }
        ExpectIntEQ((int)SSL_CTX_set_tmp_dh(ctx, dh), WOLFSSL_FATAL_ERROR);
        DH_free(dh);
        wolfSSL_BN_free(p_bn);
    }
#endif

    /* Test ASN1/DER path through wolfSSL_CTX_SetTmpDH_buffer. */
    {
        byte derBuf[4096];
        XFILE f = XBADFILE;
        int derSz = 0;

        ExpectTrue((f = XFOPEN("./certs/dh2048.der", "rb")) != XBADFILE);
        if (f != XBADFILE) {
            derSz = (int)XFREAD(derBuf, 1, sizeof(derBuf), f);
            XFCLOSE(f);
        }
        ExpectIntGT(derSz, 0);
        ExpectIntEQ(wolfSSL_CTX_SetTmpDH_buffer(ctx, derBuf, (long)derSz,
            WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
    }

    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_ctrl(void)
{
    EXPECT_DECLS;
#if defined (OPENSSL_EXTRA) && !defined(NO_BIO)
    byte buff[6000];
    BIO* bio = NULL;
    int  bytes;
    BUF_MEM* ptr = NULL;

    XMEMSET(buff, 0, sizeof(buff));

    bytes = sizeof(buff);
    ExpectNotNull(bio = BIO_new_mem_buf((void*)buff, bytes));
    ExpectNotNull(BIO_s_socket());

    ExpectIntEQ((int)wolfSSL_BIO_get_mem_ptr(bio, &ptr), WOLFSSL_SUCCESS);

    /* needs tested after stubs filled out @TODO
        SSL_ctrl
        SSL_CTX_ctrl
    */

    BIO_free(bio);
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_BIO) */
    return EXPECT_RESULT();
}


static int test_wolfSSL_CTX_add_extra_chain_cert(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_TLS) && \
   !defined(NO_FILESYSTEM) && !defined(NO_RSA) && !defined(NO_BIO)
#if !defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)
    char caFile[] = "./certs/client-ca.pem";
    char clientFile[] = "./certs/client-cert.pem";
    SSL_CTX* ctx = NULL;
    X509* x509 = NULL;
    BIO *bio = NULL;
    X509 *cert = NULL;
    X509 *ca = NULL;
    STACK_OF(X509) *chain = NULL;
    STACK_OF(X509) *chain2 = NULL;

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
#endif

    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(caFile,
        WOLFSSL_FILETYPE_PEM));

    /* Negative tests. */
    ExpectIntEQ((int)SSL_CTX_add_extra_chain_cert(NULL, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ((int)SSL_CTX_add_extra_chain_cert(ctx, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ((int)SSL_CTX_add_extra_chain_cert(NULL, x509), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    ExpectIntEQ((int)SSL_CTX_add_extra_chain_cert(ctx, x509), WOLFSSL_SUCCESS);

    ExpectNotNull(x509 = wolfSSL_X509_new());
    /* Empty certificate. */
    ExpectIntEQ((int)SSL_CTX_add_extra_chain_cert(ctx, x509), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    wolfSSL_X509_free(x509);
    x509 = NULL;

    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(clientFile,
        WOLFSSL_FILETYPE_PEM));

    /* additional test of getting EVP_PKEY key size from X509
     * Do not run with user RSA because wolfSSL_RSA_size is not currently
     * allowed with user RSA */
    {
        EVP_PKEY* pkey = NULL;
    #if defined(HAVE_ECC)
        X509* ecX509 = NULL;
    #endif /* HAVE_ECC */

        ExpectNotNull(pkey = X509_get_pubkey(x509));
        /* current RSA key is 2048 bit (256 bytes) */
        ExpectIntEQ(EVP_PKEY_size(pkey), 256);

        EVP_PKEY_free(pkey);
        pkey = NULL;

#if defined(HAVE_ECC)
    #if defined(USE_CERT_BUFFERS_256)
        ExpectNotNull(ecX509 = wolfSSL_X509_load_certificate_buffer(
                    cliecc_cert_der_256, sizeof_cliecc_cert_der_256,
                    SSL_FILETYPE_ASN1));
    #else
        ExpectNotNull(ecX509 = wolfSSL_X509_load_certificate_file(
            cliEccCertFile, SSL_FILETYPE_PEM));
    #endif
        pkey = X509_get_pubkey(ecX509);
        ExpectNotNull(pkey);
        /* current ECC key is 256 bit (32 bytes) */
        ExpectIntGE(EVP_PKEY_size(pkey), 72);

        X509_free(ecX509);
        ecX509 = NULL;
        EVP_PKEY_free(pkey);
        pkey = NULL;
#endif /* HAVE_ECC */
    }

    ExpectIntEQ((int)SSL_CTX_add_extra_chain_cert(ctx, x509), SSL_SUCCESS);
    if (EXPECT_SUCCESS()) {
        x509 = NULL;
    }

#ifdef WOLFSSL_ENCRYPTED_KEYS
    ExpectNull(SSL_CTX_get_default_passwd_cb(ctx));
    ExpectNull(SSL_CTX_get_default_passwd_cb_userdata(ctx));
#endif
    SSL_CTX_free(ctx);
    ctx = NULL;

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
#endif
    /* Test haproxy use case */
    ExpectNotNull(bio = BIO_new_file(svrCertFile, "r"));
    /* Read Certificate */
    ExpectNotNull(cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL));
    ExpectNotNull(ca = PEM_read_bio_X509(bio, NULL, NULL, NULL));
    ExpectNotNull(chain = sk_X509_new_null());
    ExpectIntEQ(sk_X509_push(chain, ca), 1);
    if (EXPECT_SUCCESS()) {
        ca = NULL;
    }
    ExpectNotNull(chain2 = X509_chain_up_ref(chain));
    ExpectNotNull(ca = sk_X509_shift(chain2));
    ExpectIntEQ(SSL_CTX_use_certificate(ctx, cert), 1);
    ExpectIntEQ(SSL_CTX_add_extra_chain_cert(ctx, ca), 1);
    if (EXPECT_SUCCESS()) {
        ca = NULL;
    }

    BIO_free(bio);
    X509_free(cert);
    X509_free(ca);
    X509_free(x509);
    sk_X509_pop_free(chain, X509_free);
    sk_X509_pop_free(chain2, X509_free);
    SSL_CTX_free(ctx);
#endif /* !NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER */
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
         !defined(NO_FILESYSTEM) && !defined(NO_RSA) && !defined (NO_BIO) */
    return EXPECT_RESULT();
}

#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
static int test_wolfSSL_ERR_peek_last_error_line(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
    !defined(NO_FILESYSTEM) && defined(DEBUG_WOLFSSL) && \
    !defined(NO_OLD_TLS) && !defined(WOLFSSL_NO_TLS12) && \
    defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(NO_ERROR_QUEUE)
    callback_functions client_cb;
    callback_functions server_cb;
    int         line = 0;
    int         flag = ERR_TXT_STRING;
    const char* file = NULL;
    const char* data = NULL;

    /* create a failed connection and inspect the error */
    XMEMSET(&client_cb, 0, sizeof(callback_functions));
    XMEMSET(&server_cb, 0, sizeof(callback_functions));
    client_cb.method  = wolfTLSv1_1_client_method;
    server_cb.method  = wolfTLSv1_2_server_method;

    test_wolfSSL_client_server_nofail(&client_cb, &server_cb);

    ExpectIntGT(ERR_get_error_line_data(NULL, NULL, &data, &flag), 0);
    ExpectNotNull(data);

    /* check clearing error state */
    ERR_remove_state(0);
    ExpectIntEQ((int)ERR_peek_last_error_line(NULL, NULL), 0);
    ERR_peek_last_error_line(NULL, &line);
    ExpectIntEQ(line, 0);
    ERR_peek_last_error_line(&file, NULL);
    ExpectNull(file);

    /* retry connection to fill error queue */
    XMEMSET(&client_cb, 0, sizeof(callback_functions));
    XMEMSET(&server_cb, 0, sizeof(callback_functions));
    client_cb.method  = wolfTLSv1_1_client_method;
    server_cb.method  = wolfTLSv1_2_server_method;

    test_wolfSSL_client_server_nofail(&client_cb, &server_cb);

    /* check that error code was stored */
    ExpectIntNE((int)ERR_peek_last_error_line(NULL, NULL), 0);
    ERR_peek_last_error_line(NULL, &line);
    ExpectIntNE(line, 0);
    ERR_peek_last_error_line(&file, NULL);
    ExpectNotNull(file);

    fprintf(stderr, "\nTesting error print out\n");
    ERR_print_errors_fp(stderr);
    fprintf(stderr, "Done testing print out\n\n");
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_CERTS) &&
        * !defined(NO_FILESYSTEM) && !defined(DEBUG_WOLFSSL) */
    return EXPECT_RESULT();
}
#endif /* !NO_WOLFSSL_CLIENT && !NO_WOLFSSL_SERVER */

static int test_wolfSSL_CTX_get0_set1_param(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
#if !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    SSL_CTX* ctx = NULL;
    WOLFSSL_X509_VERIFY_PARAM* pParam = NULL;
    WOLFSSL_X509_VERIFY_PARAM* pvpm = NULL;
    char testIPv4[] = "127.0.0.1";
    char testhostName[] = "foo.hoge.com";

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
#endif

    ExpectNull(SSL_CTX_get0_param(NULL));
    ExpectNotNull(pParam = SSL_CTX_get0_param(ctx));

    ExpectNotNull(pvpm = (WOLFSSL_X509_VERIFY_PARAM *)XMALLOC(
        sizeof(WOLFSSL_X509_VERIFY_PARAM), NULL, DYNAMIC_TYPE_OPENSSL));
    ExpectNotNull(XMEMSET(pvpm, 0, sizeof(WOLFSSL_X509_VERIFY_PARAM)));

    ExpectIntEQ(wolfSSL_X509_VERIFY_PARAM_set1_host(pvpm, testhostName,
        (int)XSTRLEN(testhostName)), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_X509_VERIFY_PARAM_set1_ip_asc(pvpm, testIPv4),
        WOLFSSL_SUCCESS);
    wolfSSL_X509_VERIFY_PARAM_set_hostflags(pvpm, 0x01);

    ExpectIntEQ(SSL_CTX_set1_param(ctx, pvpm), 1);
    ExpectIntEQ(0, XSTRNCMP(pParam->hostName, testhostName,
        (int)XSTRLEN(testhostName)));
    ExpectIntEQ(0x01, pParam->hostFlags);
    ExpectIntEQ(0, XSTRNCMP(pParam->ipasc, testIPv4, WOLFSSL_MAX_IPSTR));

    /* test for incorrect parameter */
    ExpectIntEQ(1,SSL_CTX_set1_param(ctx, NULL));
    ExpectIntEQ(1,SSL_CTX_set1_param(NULL, pvpm));
    ExpectIntEQ(1,SSL_CTX_set1_param(NULL, NULL));

    SSL_CTX_free(ctx);

    XFREE(pvpm, NULL, DYNAMIC_TYPE_OPENSSL);
#endif /* !NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER */
#endif /* OPENSSL_EXTRA && !defined(NO_RSA)*/
    return EXPECT_RESULT();
}

static int test_wolfSSL_get0_param(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)) && \
    !defined(NO_FILESYSTEM)
    SSL_CTX* ctx = NULL;
    SSL*     ssl = NULL;

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
#endif
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, svrCertFile,
        SSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, SSL_FILETYPE_PEM));
    ExpectNotNull(ssl = SSL_new(ctx));

    ExpectNotNull(SSL_get0_param(ssl));

    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_set1_host(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)) && \
    !defined(NO_FILESYSTEM)
    const char host[] = "www.test_wolfSSL_set1_host.com";
    const char emptyStr[] = "";
    SSL_CTX*   ctx = NULL;
    SSL*       ssl = NULL;
    WOLFSSL_X509_VERIFY_PARAM* pParam = NULL;

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
#endif
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, svrCertFile,
        SSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, SSL_FILETYPE_PEM));
    ExpectNotNull(ssl = SSL_new(ctx));

    pParam = SSL_get0_param(ssl);

    /* we should get back host string */
    ExpectIntEQ(SSL_set1_host(ssl, host), WOLFSSL_SUCCESS);
    ExpectIntEQ(XMEMCMP(pParam->hostName, host, sizeof(host)), 0);

    /* we should get back empty string */
    ExpectIntEQ(SSL_set1_host(ssl, emptyStr), WOLFSSL_SUCCESS);
    ExpectIntEQ(XMEMCMP(pParam->hostName, emptyStr, sizeof(emptyStr)), 0);

    /* we should get back host string */
    ExpectIntEQ(SSL_set1_host(ssl, host), WOLFSSL_SUCCESS);
    ExpectIntEQ(XMEMCMP(pParam->hostName, host, sizeof(host)), 0);

    /* we should get back empty string */
    ExpectIntEQ(SSL_set1_host(ssl, NULL), WOLFSSL_SUCCESS);
    ExpectIntEQ(XMEMCMP(pParam->hostName, emptyStr, sizeof(emptyStr)), 0);

    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_CERTS) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
    defined(HAVE_ECC) && !defined(NO_TLS) && defined(HAVE_AESGCM)
static int test_wolfSSL_get_client_ciphers_ctx_ready(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    ExpectTrue(wolfSSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES128-GCM-SHA256"));
    return EXPECT_RESULT();
}


static int test_wolfSSL_get_client_ciphers_on_result(WOLFSSL* ssl) {
    EXPECT_DECLS;
    WOLF_STACK_OF(WOLFSSL_CIPHER)* ciphers;

    ciphers = SSL_get_client_ciphers(ssl);
    if (wolfSSL_is_server(ssl) == 0) {
        ExpectNull(ciphers);
    }
    else {
        WOLFSSL_CIPHER* current;

        /* client should have only sent over one cipher suite */
        ExpectNotNull(ciphers);
        ExpectIntEQ(sk_SSL_CIPHER_num(ciphers), 1);
        current = sk_SSL_CIPHER_value(ciphers, 0);
        ExpectNotNull(current);
    #if !defined(WOLFSSL_CIPHER_INTERNALNAME) && !defined(NO_ERROR_STRINGS) && \
        !defined(WOLFSSL_QT)
        ExpectStrEQ("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
            SSL_CIPHER_get_name(current));
    #else
        ExpectStrEQ("ECDHE-RSA-AES128-GCM-SHA256",
            SSL_CIPHER_get_name(current));
    #endif
    }
    return EXPECT_RESULT();
}
#endif

static int test_wolfSSL_get_client_ciphers(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_CERTS) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
    defined(HAVE_ECC) && !defined(NO_TLS) && defined(HAVE_AESGCM)
    test_ssl_cbf server_cb;
    test_ssl_cbf client_cb;

    XMEMSET(&client_cb, 0, sizeof(test_ssl_cbf));
    XMEMSET(&server_cb, 0, sizeof(test_ssl_cbf));
    client_cb.method = wolfTLSv1_2_client_method;
    server_cb.method = wolfTLSv1_2_server_method;
    client_cb.devId = testDevId;
    server_cb.devId = testDevId;
    client_cb.ctx_ready = test_wolfSSL_get_client_ciphers_ctx_ready;
    client_cb.on_result = test_wolfSSL_get_client_ciphers_on_result;
    server_cb.on_result = test_wolfSSL_get_client_ciphers_on_result;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cb,
        &server_cb, NULL), TEST_SUCCESS);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_set_client_CA_list(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_CERTS) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
    !defined(NO_BIO) && !defined(NO_TLS)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;
    X509_NAME* name = NULL;
    STACK_OF(X509_NAME)* names = NULL;
    STACK_OF(X509_NAME)* ca_list = NULL;
    int names_len = 0;
    int i;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
    /* Send two X501 names in cert request */
    names = SSL_load_client_CA_file(cliCertFile);
    ExpectNotNull(names);
    ca_list = SSL_load_client_CA_file(caCertFile);
    ExpectNotNull(ca_list);
    ExpectNotNull(name = sk_X509_NAME_value(ca_list, 0));
    ExpectIntEQ(sk_X509_NAME_push(names, name), 2);
    if (EXPECT_FAIL()) {
        wolfSSL_X509_NAME_free(name);
        name = NULL;
    }
    SSL_CTX_set_client_CA_list(ctx, names);
    /* This should only free the stack structure */
    sk_X509_NAME_free(ca_list);
    ca_list = NULL;
    ExpectNotNull(ca_list = SSL_CTX_get_client_CA_list(ctx));
    ExpectIntEQ(sk_X509_NAME_num(ca_list), sk_X509_NAME_num(names));

    ExpectIntEQ(sk_X509_NAME_find(NULL, name), BAD_FUNC_ARG);
    ExpectIntEQ(sk_X509_NAME_find(names, NULL), WOLFSSL_FATAL_ERROR);
    ExpectIntGT((names_len = sk_X509_NAME_num(names)), 0);
    for (i = 0; i < names_len; i++) {
        ExpectNotNull(name = sk_X509_NAME_value(names, i));
        ExpectIntEQ(sk_X509_NAME_find(names, name), i);
    }

    /* Needed to be able to create ssl object */
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, svrCertFile,
        SSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, SSL_FILETYPE_PEM));
    ExpectNotNull(ssl = wolfSSL_new(ctx));
    /* load again as old names are responsibility of ctx to free*/
    names = SSL_load_client_CA_file(cliCertFile);
    ExpectNotNull(names);
    SSL_set_client_CA_list(ssl, names);
    ExpectNotNull(ca_list = SSL_get_client_CA_list(ssl));
    ExpectIntEQ(sk_X509_NAME_num(ca_list), sk_X509_NAME_num(names));

    ExpectIntGT((names_len = sk_X509_NAME_num(names)), 0);
    for (i = 0; i < names_len; i++) {
        ExpectNotNull(name = sk_X509_NAME_value(names, i));
        ExpectIntEQ(sk_X509_NAME_find(names, name), i);
    }

#if !defined(SINGLE_THREADED) && defined(SESSION_CERTS)
    {
        tcp_ready ready;
        func_args server_args;
        callback_functions server_cb;
        THREAD_TYPE serverThread;
        WOLFSSL* ssl_client = NULL;
        WOLFSSL_CTX* ctx_client = NULL;
        SOCKET_T sockfd = 0;

        /* wolfSSL_get_client_CA_list() with handshake */

        StartTCP();
        InitTcpReady(&ready);

        XMEMSET(&server_args, 0, sizeof(func_args));
        XMEMSET(&server_cb, 0, sizeof(callback_functions));

        server_args.signal    = &ready;
        server_args.callbacks = &server_cb;

        /* we are responsible for free'ing WOLFSSL_CTX */
        server_cb.ctx = ctx;
        server_cb.isSharedCtx = 1;

        ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_load_verify_locations(ctx,
            cliCertFile, 0));

        start_thread(test_server_nofail, &server_args, &serverThread);
        wait_tcp_ready(&server_args);

        tcp_connect(&sockfd, wolfSSLIP, server_args.signal->port, 0, 0, NULL);
        ExpectNotNull(ctx_client =
            wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
        ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_load_verify_locations(
            ctx_client, caCertFile, 0));
        ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_use_certificate_file(
            ctx_client, cliCertFile, SSL_FILETYPE_PEM));
        ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_use_PrivateKey_file(
            ctx_client, cliKeyFile, SSL_FILETYPE_PEM));

        ExpectNotNull(ssl_client = wolfSSL_new(ctx_client));
        ExpectIntEQ(wolfSSL_set_fd(ssl_client, sockfd), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_connect(ssl_client), WOLFSSL_SUCCESS);

        ExpectNotNull(ca_list = SSL_get_client_CA_list(ssl_client));
        /* We are expecting two cert names to be sent */
        ExpectIntEQ(sk_X509_NAME_num(ca_list), 2);

        ExpectNotNull(names = SSL_CTX_get_client_CA_list(ctx));
        for (i=0; i<sk_X509_NAME_num(ca_list); i++) {
            ExpectNotNull(name = sk_X509_NAME_value(ca_list, i));
            ExpectIntGE(sk_X509_NAME_find(names, name), 0);
        }

        wolfSSL_shutdown(ssl_client);
        wolfSSL_free(ssl_client);
        wolfSSL_CTX_free(ctx_client);

        CloseSocket(sockfd);

        join_thread(serverThread);
        FreeTcpReady(&ready);
    }
#endif

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif /* OPENSSL_EXTRA && !NO_RSA && !NO_CERTS && !NO_WOLFSSL_CLIENT &&
        * !NO_BIO */
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_add_client_CA(void)
{
    EXPECT_DECLS;
#if !defined(WOLFSSL_NO_CA_NAMES) && defined(OPENSSL_EXTRA) && \
    !defined(NO_RSA) && !defined(NO_CERTS) && \
    !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_FILESYSTEM)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL_X509* x509 = NULL;
    WOLFSSL_X509* x509_a = NULL;
    STACK_OF(X509_NAME)* ca_list = NULL;

    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
    /* Add client cert */
    ExpectNotNull(x509 = X509_load_certificate_file(cliCertFile,
        SSL_FILETYPE_PEM));
    ExpectIntEQ(SSL_CTX_add_client_CA(ctx, x509), SSL_SUCCESS);
    ExpectNotNull(ca_list = SSL_CTX_get_client_CA_list(ctx));
    /* Add another client cert */
    ExpectNotNull(x509_a = X509_load_certificate_file(cliCertFile,
        SSL_FILETYPE_PEM));
    ExpectIntEQ(SSL_CTX_add_client_CA(ctx, x509_a), SSL_SUCCESS);

    /* test for incorrect parameter */
    ExpectIntEQ(SSL_CTX_add_client_CA(NULL, x509), 0);
    ExpectIntEQ(SSL_CTX_add_client_CA(ctx, NULL), 0);
    ExpectIntEQ(SSL_CTX_add_client_CA(NULL, NULL), 0);

    X509_free(x509);
    X509_free(x509_a);
    SSL_CTX_free(ctx);
#endif /* OPENSSL_EXTRA  && !NO_RSA && !NO_CERTS && !NO_WOLFSSL_CLIENT */
    return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) && \
    defined(HAVE_IO_TESTS_DEPENDENCIES)
static THREAD_RETURN WOLFSSL_THREAD server_task_ech(void* args)
{
    callback_functions* callbacks = ((func_args*)args)->callbacks;
    WOLFSSL_CTX* ctx       = callbacks->ctx;
    WOLFSSL*  ssl   = NULL;
    SOCKET_T  sfd   = 0;
    SOCKET_T  cfd   = 0;
    word16    port;
    char      input[1024];
    int       idx;
    int       ret, err = 0;
    const char* privateName = "ech-private-name.com";
    int         privateNameLen = (int)XSTRLEN(privateName);

    ((func_args*)args)->return_code = TEST_FAIL;
    port = ((func_args*)args)->signal->port;

    AssertIntEQ(WOLFSSL_SUCCESS,
        wolfSSL_CTX_load_verify_locations(ctx, cliCertFile, 0));

    AssertIntEQ(WOLFSSL_SUCCESS,
        wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
            WOLFSSL_FILETYPE_PEM));

    AssertIntEQ(WOLFSSL_SUCCESS,
        wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
            WOLFSSL_FILETYPE_PEM));

    if (callbacks->ctx_ready)
        callbacks->ctx_ready(ctx);

    ssl = wolfSSL_new(ctx);
    AssertNotNull(ssl);

    /* set the sni for the server */
    AssertIntEQ(WOLFSSL_SUCCESS,
        wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, privateName,
            privateNameLen));

    tcp_accept(&sfd, &cfd, (func_args*)args, port, 0, 0, 0, 0, 1, NULL, NULL);
    CloseSocket(sfd);
    AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_set_fd(ssl, cfd));

    if (callbacks->ssl_ready)
        callbacks->ssl_ready(ssl);

    do {
        err = 0; /* Reset error */
        ret = wolfSSL_accept(ssl);
        if (ret != WOLFSSL_SUCCESS) {
            err = wolfSSL_get_error(ssl, 0);
        }
    } while (ret != WOLFSSL_SUCCESS && err == WC_NO_ERR_TRACE(WC_PENDING_E));

    if (ret != WOLFSSL_SUCCESS) {
        char buff[WOLFSSL_MAX_ERROR_SZ];
        fprintf(stderr, "error = %d, %s\n", err, wolfSSL_ERR_error_string(err,
                buff));
    }
    else {
        if (0 < (idx = wolfSSL_read(ssl, input, sizeof(input)-1))) {
            input[idx] = 0;
            fprintf(stderr, "Client message: %s\n", input);
        }

        AssertIntEQ(privateNameLen, wolfSSL_write(ssl, privateName,
            privateNameLen));
        ((func_args*)args)->return_code = TEST_SUCCESS;
    }

    if (callbacks->on_result)
        callbacks->on_result(ssl);

    wolfSSL_shutdown(ssl);
    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
    CloseSocket(cfd);

#ifdef FP_ECC
    wc_ecc_fp_free();
#endif

    WOLFSSL_RETURN_FROM_THREAD(0);
}
#endif /* HAVE_ECH && WOLFSSL_TLS13 */

#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
static void keyLog_callback(const WOLFSSL* ssl, const char* line)
{
    XFILE fp;
    const byte lf = '\n';

    AssertNotNull(ssl);
    AssertNotNull(line);

    fp = XFOPEN("./MyKeyLog.txt", "a");
    XFWRITE(line, 1, XSTRLEN(line), fp);
    XFWRITE((void*)&lf, 1, 1, fp);
    XFFLUSH(fp);
    XFCLOSE(fp);
}
#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */
static int test_wolfSSL_CTX_set_keylog_callback(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK) && \
                              !defined(NO_WOLFSSL_CLIENT)
    SSL_CTX* ctx = NULL;

    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
    SSL_CTX_set_keylog_callback(ctx, keyLog_callback );
    SSL_CTX_free(ctx);
    SSL_CTX_set_keylog_callback(NULL, NULL);
#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK && !NO_WOLFSSL_CLIENT */
    return EXPECT_RESULT();
}
static int test_wolfSSL_CTX_get_keylog_callback(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK) && \
                                !defined(NO_WOLFSSL_CLIENT)
    SSL_CTX* ctx = NULL;

    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
    ExpectPtrEq(SSL_CTX_get_keylog_callback(ctx),NULL);
    SSL_CTX_set_keylog_callback(ctx, keyLog_callback );
    ExpectPtrEq(SSL_CTX_get_keylog_callback(ctx),keyLog_callback);
    SSL_CTX_set_keylog_callback(ctx, NULL );
    ExpectPtrEq(SSL_CTX_get_keylog_callback(ctx),NULL);
    SSL_CTX_free(ctx);
#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK && !NO_WOLFSSL_CLIENT */
    return EXPECT_RESULT();
}

#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
static int test_wolfSSL_Tls12_Key_Logging_client_ctx_ready(WOLFSSL_CTX* ctx)
{
    /* set keylog callback */
    wolfSSL_CTX_set_keylog_callback(ctx, keyLog_callback);
    return TEST_SUCCESS;
}
#endif

static int test_wolfSSL_Tls12_Key_Logging_test(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
    /* This test is intended for checking whether keylog callback is called
     * in client during TLS handshake between the client and a server.
     */
    test_ssl_cbf server_cbf;
    test_ssl_cbf client_cbf;
    XFILE fp = XBADFILE;
    char  buff[500];
    int   found = 0;

    XMEMSET(&server_cbf, 0, sizeof(test_ssl_cbf));
    XMEMSET(&client_cbf, 0, sizeof(test_ssl_cbf));
    server_cbf.method     = wolfTLSv1_2_server_method;
    client_cbf.ctx_ready = &test_wolfSSL_Tls12_Key_Logging_client_ctx_ready;

    /* clean up keylog file */
    ExpectTrue((fp = XFOPEN("./MyKeyLog.txt", "w")) != XBADFILE);
    if (fp != XBADFILE) {
        XFFLUSH(fp);
        XFCLOSE(fp);
        fp = XBADFILE;
    }

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
        &server_cbf, NULL), TEST_SUCCESS);

    /* check if the keylog file exists */
    ExpectTrue((fp = XFOPEN("./MyKeyLog.txt", "rb")) != XBADFILE);
    XFFLUSH(fp); /* Just to make sure any buffers get flushed */

    XMEMSET(buff, 0, sizeof(buff));
    while (EXPECT_SUCCESS() && XFGETS(buff, (int)sizeof(buff), fp) != NULL) {
        if (0 == strncmp(buff,"CLIENT_RANDOM ", sizeof("CLIENT_RANDOM ")-1)) {
            found = 1;
            break;
        }
    }
    if (fp != XBADFILE) {
        XFCLOSE(fp);
    }
    /* a log starting with "CLIENT_RANDOM " should exit in the file */
    ExpectIntEQ(found, 1);
    /* clean up */
    ExpectIntEQ(rem_file("./MyKeyLog.txt"), 0);
#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */
    return EXPECT_RESULT();
}

#if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \
    defined(HAVE_SECRET_CALLBACK)
static int test_wolfSSL_Tls13_Key_Logging_client_ctx_ready(WOLFSSL_CTX* ctx)
{
    /* set keylog callback */
    wolfSSL_CTX_set_keylog_callback(ctx, keyLog_callback);
    return TEST_SUCCESS;
}
#endif

static int test_wolfSSL_Tls13_Key_Logging_test(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \
    defined(HAVE_SECRET_CALLBACK)
/* This test is intended for checking whether keylog callback is called
 * in client during TLS handshake between the client and a server.
 */
    test_ssl_cbf server_cbf;
    test_ssl_cbf client_cbf;
    XFILE fp = XBADFILE;

    XMEMSET(&server_cbf, 0, sizeof(test_ssl_cbf));
    XMEMSET(&client_cbf, 0, sizeof(test_ssl_cbf));
    server_cbf.method    = wolfTLSv1_3_server_method;  /* TLS1.3 */
    client_cbf.ctx_ready = &test_wolfSSL_Tls13_Key_Logging_client_ctx_ready;

    /* clean up keylog file */
    ExpectTrue((fp = XFOPEN("./MyKeyLog.txt", "w")) != XBADFILE);
    if (fp != XBADFILE) {
        XFCLOSE(fp);
        fp = XBADFILE;
    }

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
        &server_cbf, NULL), TEST_SUCCESS);

    /* check if the keylog file exists */
    {
        char buff[300] = {0};
        int  found[4]   = {0};
        int  numfnd = 0;
        int  i;

        ExpectTrue((fp = XFOPEN("./MyKeyLog.txt", "rb")) != XBADFILE);

        while (EXPECT_SUCCESS() &&
                XFGETS(buff, (int)sizeof(buff), fp) != NULL) {
            if (0 == strncmp(buff, "CLIENT_HANDSHAKE_TRAFFIC_SECRET ",
                    sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET ")-1)) {
                found[0] = 1;
                continue;
            }
            else if (0 == strncmp(buff, "SERVER_HANDSHAKE_TRAFFIC_SECRET ",
                    sizeof("SERVER_HANDSHAKE_TRAFFIC_SECRET ")-1)) {
                found[1] = 1;
                continue;
            }
            else if (0 == strncmp(buff, "CLIENT_TRAFFIC_SECRET_0 ",
                    sizeof("CLIENT_TRAFFIC_SECRET_0 ")-1)) {
                found[2] = 1;
                continue;
            }
            else if (0 == strncmp(buff, "SERVER_TRAFFIC_SECRET_0 ",
                    sizeof("SERVER_TRAFFIC_SECRET_0 ")-1)) {
                found[3] = 1;
                continue;
            }
        }
        if (fp != XBADFILE)
            XFCLOSE(fp);
        for (i = 0; i < 4; i++) {
            if (found[i] != 0)
                numfnd++;
        }
        ExpectIntEQ(numfnd, 4);
    }
#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK && WOLFSSL_TLS13 */
    return EXPECT_RESULT();
}

#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
#if defined(HAVE_IO_TESTS_DEPENDENCIES)
static int test_wolfSSL_Tls13_ECH_params(void)
{
    EXPECT_DECLS;
#if !defined(NO_WOLFSSL_CLIENT)
    byte testBuf[256];
    word32 outputLen = sizeof(testBuf);
    word16 tmpLen = 0;
    WOLFSSL_CTX* ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
    WOLFSSL*     ssl = wolfSSL_new(ctx);

    ExpectNotNull(ctx);
    ExpectNotNull(ssl);

    /* generation errors */

    /* invalid ctx */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(NULL,
        "ech-public-name.com", 0, 0, 0));
    /* invalid public name */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(ctx, NULL, 0,
        0, 0));
    /* invalid algorithms */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(ctx,
        "ech-public-name.com", 1000, 0, 0));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(ctx,
        "ech-public-name.com", 0, 1000, 0));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(ctx,
        "ech-public-name.com", 0, 0, 1000));

    /* bad function calls */

    /* NULL ctx */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(NULL, testBuf,
        sizeof(testBuf)));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(NULL, testBuf,
        sizeof(testBuf)));

    /* NULL configs */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx, NULL,
        sizeof(testBuf)));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, NULL,
        sizeof(testBuf)));

    /* 0 length */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx, testBuf, 0));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, testBuf, 0));

    /* stateful errors */

    /* actually generate configs */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(ctx,
        "ech-public-name.com", 0, 0, 0));

    /* bad get: NULL ctx, NULL output len, short output len */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(NULL, testBuf,
        &outputLen));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(ctx, testBuf, NULL));
    outputLen = 5;
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(ctx, testBuf,
        &outputLen));

    /* should be able to retrieve length with NULL buffer... */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(ctx, NULL,
        &outputLen));
    ExpectIntGE(sizeof(testBuf), outputLen);

    /* and the get should work with this length */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(ctx, testBuf,
        &outputLen));

    /* reject config with invalid total length */
    if (EXPECT_SUCCESS()) {
        ato16(testBuf, &tmpLen);
        testBuf[0] = 0xFF;
        testBuf[1] = 0xFF;
    }
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx, testBuf,
        outputLen));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, testBuf,
        outputLen));
    if (EXPECT_SUCCESS()) {
        c16toa(tmpLen, testBuf);
    }

    /* reject config with invalid version */
    if (EXPECT_SUCCESS()) {
        testBuf[2] ^= 0x01;
    }
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx, testBuf,
        outputLen));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, testBuf,
        outputLen));
    if (EXPECT_SUCCESS()) {
        testBuf[2] ^= 0x01;
    }

    /* reject config with bad length */
    if (EXPECT_SUCCESS()) {
        ato16(testBuf + 4, &tmpLen);
        testBuf[4] = 0xFF;
        testBuf[5] = 0xFF;
    }
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx, testBuf,
        outputLen));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, testBuf,
        outputLen));
    if (EXPECT_SUCCESS()) {
        c16toa(tmpLen, testBuf + 4);
    }

    /* set valid configs */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx, testBuf,
        outputLen));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, testBuf,
        outputLen));

    /* NULL ssl, NULL buffer, NULL output len */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_GetEchConfigs(NULL, testBuf,
        &outputLen));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_GetEchConfigs(ssl, NULL, &outputLen));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_GetEchConfigs(ssl, testBuf, NULL));

    /* reject setting configs when ssl already has them */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, testBuf,
        outputLen));

    /* unable to get configs from ssl with no configs (because of disable) */
    wolfSSL_SetEchEnable(ssl, 0);
    outputLen = sizeof(testBuf);
    ExpectIntNE(WOLFSSL_SUCCESS,
        wolfSSL_GetEchConfigs(ssl, testBuf, &outputLen));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif /* !NO_WOLFSSL_CLIENT */

    return EXPECT_RESULT();
}

static int test_wolfSSL_Tls13_ECH_params_b64(void)
{
    EXPECT_DECLS;
#if !defined(NO_WOLFSSL_CLIENT)
    /* base64 ech configs from cloudflare-ech.com (these are good configs) */
    const char* b64Valid = "AEX+DQBBFAAgACBuAoQI8+liEVYQbXKBDeVgTmF2rfXuKO2knhwrN7jgTgAEAAEAAQASY2xvdWRmbGFyZS1lY2guY29tAAA=";
    /* ech configs with bad version */
    const char* b64BadVers = "AEX+/gBBFAAgACBuAoQI8+liEVYQbXKBDeVgTmF2rfXuKO2knhwrN7jgTgAEAAEAAQASY2xvdWRmbGFyZS1lY2guY29tAAA=";
    /* ech configs with bad/unsupported algorithm */
    const char* b64BadAlgo = "AEX+DQBBFP7+ACBuAoQI8+liEVYQbXKBDeVgTmF2rfXuKO2knhwrN7jgTgAEAAEAAQASY2xvdWRmbGFyZS1lY2guY29tAAA=";
    /* ech configs with 0 length algorithm */
    const char* b64BadAlgo0 = "ACX+DQAhFAAgAAAABAABAAEAEmNsb3VkZmxhcmUtZWNoLmNvbQAA";
    /* ech configs with long algorithm */
    const char* b64BadAlgo33 = "AEb+DQBCFAAgACEBbgKECPPpYhFWEG1ygQ3lYE5hdq317ijtpJ4cKze44E4ABAABAAEAEmNsb3VkZmxhcmUtZWNoLmNvbQAA";
    /* ech configs with bad/unsupported ciphersuite */
    const char* b64BadCiph = "AEX+DQBBFAAgACBuAoQI8+liEVYQbXKBDeVgTmF2rfXuKO2knhwrN7jgTgAE/v4AAQASY2xvdWRmbGFyZS1lY2guY29tAAA=";
    /* ech configs with unrecognized mandatory extension */
    const char* b64Mandatory = "AEn+DQBFFAAgACBuAoQI8+liEVYQbXKBDeVgTmF2rfXuKO2knhwrN7jgTgAEAAEAAQASY2xvdWRmbGFyZS1lY2guY29tAAT6+gAA";
    /* ech configs with bad version first */
    const char* b64BadVers1 = "AIz+HQBCAQAgACCjR6+Qn9UYkMaWdXZzsby88vXFhPHJ2tWCDHQJLvMkEgAEAAEAAQATZWNoLXB1YmxpYy1uYW1lLmNvbQAA/g0AQgIAIAAgMM6vLrTbOfsfA6fTbJY/Iu0Lj2xeHEPGUJeUwQGAYF4ABAABAAEAE2VjaC1wdWJsaWMtbmFtZS5jb20AAA==";
    /* ech configs with bad version second */
    const char* b64BadVers2 = "AIz+DQBCAQAgACCjR6+Qn9UYkMaWdXZzsby88vXFhPHJ2tWCDHQJLvMkEgAEAAEAAQATZWNoLXB1YmxpYy1uYW1lLmNvbQAA/h0AQgIAIAAgMM6vLrTbOfsfA6fTbJY/Iu0Lj2xeHEPGUJeUwQGAYF4ABAABAAEAE2VjaC1wdWJsaWMtbmFtZS5jb20AAA==";
    byte testBuf[256];
    word32 outputLen;

    WOLFSSL_CTX* ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
    WOLFSSL*     ssl = wolfSSL_new(ctx);

    ExpectNotNull(ctx);
    ExpectNotNull(ssl);

    /* NULL ctx/ssl, short public key */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigsBase64(NULL,
        b64Valid, (word32)XSTRLEN(b64Valid)));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(NULL,
        b64Valid, (word32)XSTRLEN(b64Valid)));

    /* NULL configs */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigsBase64(ctx,
        NULL, (word32)XSTRLEN(b64Valid)));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(ssl,
        NULL, (word32)XSTRLEN(b64Valid)));

    /* 0 length */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigsBase64(ctx,
        b64Valid, 0));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(ssl,
        b64Valid, 0));

    /* bad version */
    ExpectIntEQ(UNSUPPORTED_PROTO_VERSION, wolfSSL_CTX_SetEchConfigsBase64(ctx,
        b64BadVers, (word32)XSTRLEN(b64BadVers)));
    ExpectIntEQ(UNSUPPORTED_PROTO_VERSION, wolfSSL_SetEchConfigsBase64(ssl,
        b64BadVers, (word32)XSTRLEN(b64BadVers)));

    /* bad algorithm */
    ExpectIntEQ(UNSUPPORTED_SUITE, wolfSSL_CTX_SetEchConfigsBase64(ctx,
        b64BadAlgo, (word32)XSTRLEN(b64BadAlgo)));
    ExpectIntEQ(UNSUPPORTED_SUITE, wolfSSL_SetEchConfigsBase64(ssl,
        b64BadAlgo, (word32)XSTRLEN(b64BadAlgo)));

    /* bad algorithm with 0 length key */
    ExpectIntEQ(BUFFER_E, wolfSSL_CTX_SetEchConfigsBase64(ctx,
        b64BadAlgo0, (word32)XSTRLEN(b64BadAlgo0)));
    ExpectIntEQ(BUFFER_E, wolfSSL_SetEchConfigsBase64(ssl,
        b64BadAlgo0, (word32)XSTRLEN(b64BadAlgo0)));

    /* bad algorithm with long key */
    ExpectIntEQ(BUFFER_E, wolfSSL_CTX_SetEchConfigsBase64(ctx,
        b64BadAlgo33, (word32)XSTRLEN(b64BadAlgo33)));
    ExpectIntEQ(BUFFER_E, wolfSSL_SetEchConfigsBase64(ssl,
        b64BadAlgo33, (word32)XSTRLEN(b64BadAlgo33)));

    /* bad ciphersuite */
    ExpectIntEQ(UNSUPPORTED_SUITE, wolfSSL_CTX_SetEchConfigsBase64(ctx,
        b64BadCiph, (word32)XSTRLEN(b64BadCiph)));
    ExpectIntEQ(UNSUPPORTED_SUITE, wolfSSL_SetEchConfigsBase64(ssl,
        b64BadCiph, (word32)XSTRLEN(b64BadCiph)));

    /* unrecognized mandatory extension */
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigsBase64(ctx,
        b64Mandatory, (word32)XSTRLEN(b64Mandatory)));
    ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(ssl,
        b64Mandatory, (word32)XSTRLEN(b64Mandatory)));

    /* bad version first, should only have config 2 set */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigsBase64(ctx,
        b64BadVers1, (word32)XSTRLEN(b64BadVers1)));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(ssl,
        b64BadVers1, (word32)XSTRLEN(b64BadVers1)));
    ExpectIntEQ(2, ctx->echConfigs->configId);
    ExpectIntEQ(2, ssl->echConfigs->configId);

    /* clear configs */
    wolfSSL_CTX_SetEchEnable(ctx, 0);
    wolfSSL_CTX_SetEchEnable(ctx, 1);
    wolfSSL_SetEchEnable(ssl, 0);
    wolfSSL_SetEchEnable(ssl, 1);

    /* bad version second, should only have config 1 set */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigsBase64(ctx,
        b64BadVers2, (word32)XSTRLEN(b64BadVers2)));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(ssl,
        b64BadVers2, (word32)XSTRLEN(b64BadVers2)));
    ExpectIntEQ(1, ctx->echConfigs->configId);
    ExpectIntEQ(1, ssl->echConfigs->configId);

    /* clear configs */
    wolfSSL_CTX_SetEchEnable(ctx, 0);
    wolfSSL_CTX_SetEchEnable(ctx, 1);
    wolfSSL_SetEchEnable(ssl, 0);
    wolfSSL_SetEchEnable(ssl, 1);

    /* base64 tests */

    /* set base64 configs */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigsBase64(ctx,
        b64Valid, (word32)XSTRLEN(b64Valid)));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(ssl,
        b64Valid, (word32)XSTRLEN(b64Valid)));

    /* disable and check ctx has no configs */
    wolfSSL_CTX_SetEchEnable(ctx, 0);
    outputLen = sizeof(testBuf);
    ExpectIntNE(WOLFSSL_SUCCESS,
        wolfSSL_CTX_GetEchConfigs(ctx, testBuf, &outputLen));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif /* !NO_WOLFSSL_CLIENT */

    return EXPECT_RESULT();
}

static int test_wolfSSL_ECH_conn_ex(method_provider serverMeth,
    method_provider clientMeth, int hrr)
{
    EXPECT_DECLS;
    tcp_ready ready;
    func_args client_args;
    func_args server_args;
    THREAD_TYPE serverThread;
    callback_functions server_cbf;
    callback_functions client_cbf;
    SOCKET_T sockfd = 0;
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL*     ssl = NULL;
    const char* publicName = "ech-public-name.com";
    const char* privateName = "ech-private-name.com";
    int privateNameLen = 20;
    char reply[1024];
    int replyLen = 0;
    byte rawEchConfig[128];
    word32 rawEchConfigLen = sizeof(rawEchConfig);

    InitTcpReady(&ready);
    ready.port = 22222;

    XMEMSET(&client_args, 0, sizeof(func_args));
    XMEMSET(&server_args, 0, sizeof(func_args));
    XMEMSET(&server_cbf, 0, sizeof(callback_functions));
    XMEMSET(&client_cbf, 0, sizeof(callback_functions));
    server_cbf.method     = serverMeth;

    /* create the server context here so we can get the ech config */
    ExpectNotNull(server_cbf.ctx = wolfSSL_CTX_new(serverMeth()));

    /* generate ech config */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(server_cbf.ctx,
        publicName, 0, 0, 0));

    /* get the config for the client to use */
    ExpectIntEQ(WOLFSSL_SUCCESS,
        wolfSSL_CTX_GetEchConfigs(server_cbf.ctx, rawEchConfig,
        &rawEchConfigLen));

    server_args.callbacks = &server_cbf;
    server_args.signal    = &ready;

    /* start server task */
    start_thread(server_task_ech, &server_args, &serverThread);
    wait_tcp_ready(&server_args);

    /* set the client TLS version and run */
    ExpectNotNull(ctx = wolfSSL_CTX_new(clientMeth()));
    ExpectIntEQ(WOLFSSL_SUCCESS,
        wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0));
    ExpectIntEQ(WOLFSSL_SUCCESS,
        wolfSSL_CTX_use_certificate_file(ctx, cliCertFile, SSL_FILETYPE_PEM));
    ExpectIntEQ(WOLFSSL_SUCCESS,
        wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile, SSL_FILETYPE_PEM));

    tcp_connect(&sockfd, wolfSSLIP, server_args.signal->port, 0, 0, NULL);

    /* get connected the server task */
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    /* set the ech configs for the client */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, rawEchConfig,
        rawEchConfigLen));

    /* set the sni for the client */
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME,
        privateName, privateNameLen));

    /* force hello retry request */
    if (hrr)
        ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_NoKeyShares(ssl));

    /* connect like normal */
    ExpectIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(ssl), WOLFSSL_ECH_STATUS_ACCEPTED);
    ExpectIntEQ(wolfSSL_write(ssl, privateName, privateNameLen),
        privateNameLen);
    ExpectIntGT((replyLen = wolfSSL_read(ssl, reply, sizeof(reply))), 0);
    /* add the null terminator for string compare */
    reply[replyLen] = '\0';
    /* check that the server replied with the private name */
    ExpectStrEQ(privateName, reply);
    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);

    CloseSocket(sockfd);

    join_thread(serverThread);

    FreeTcpReady(&ready);

    return EXPECT_RESULT();
}

static int test_wolfSSL_Tls13_ECH(void)
{
    return test_wolfSSL_ECH_conn_ex(wolfTLSv1_3_server_method,
                wolfTLSv1_3_client_method, 0);
}

static int test_wolfSSL_Tls13_ECH_HRR(void)
{
    return test_wolfSSL_ECH_conn_ex(wolfTLSv1_3_server_method,
                wolfTLSv1_3_client_method, 1);
}

static int test_wolfSSL_SubTls13_ECH(void)
{
    EXPECT_DECLS;

#ifndef WOLFSSL_NO_TLS12
    ExpectIntNE(test_wolfSSL_ECH_conn_ex(wolfTLSv1_3_server_method,
        wolfTLSv1_2_client_method, 0), WOLFSSL_SUCCESS);
    ExpectIntNE(test_wolfSSL_ECH_conn_ex(wolfTLSv1_2_server_method,
        wolfTLSv1_3_client_method, 0), WOLFSSL_SUCCESS);
    ExpectIntNE(test_wolfSSL_ECH_conn_ex(wolfSSLv23_server_method,
        wolfTLSv1_2_client_method, 0), WOLFSSL_SUCCESS);
#endif

    return EXPECT_RESULT();
}
#endif /* HAVE_IO_TESTS_DEPENDENCIES */

#ifdef HAVE_SSL_MEMIO_TESTS_DEPENDENCIES

/* Static storage for passing ECH config between server and client callbacks */
static byte   echCbTestConfigs[512];
static word32 echCbTestConfigsLen;
static const char* echCbTestPublicName = "example.com";
static const char* echCbTestPrivateName = "ech-private-name.com";
static word16 echCbTestKemID = 0;
static word16 echCbTestKdfID = 0;
static word16 echCbTestAeadID = 0;

/* the arg is whether the client has ech enabled or not */
static int test_ech_server_sni_callback(WOLFSSL* ssl, int* ad, void* arg)
{
    const char* name;

    if (!wolfSSL_SNI_GetRequest(ssl, WOLFSSL_SNI_HOST_NAME, (void**)&name)) {
        *ad = WOLFSSL_AD_UNRECOGNIZED_NAME;
        return fatal_return;
    }

    /* reached by *_disable_conn test: expect name to be the public SNI when
     * client has ECH enabled, otherwise it should be the private SNI */
    if (arg != NULL && *(int*)arg == 1 &&
            XSTRCMP(name, echCbTestPublicName) == 0) {
        return 0;
    }
    else if (XSTRCMP(name, echCbTestPrivateName) == 0) {
        return 0;
    }
    else {
        *ad = WOLFSSL_AD_UNRECOGNIZED_NAME;
        return fatal_return;
    }
}

/* Server ctx_ready callback: generate ECH config */
static int test_ech_server_ctx_ready(WOLFSSL_CTX* ctx)
{
    int ret;

    /* +20 for this isn't significant, it just exercises the padding code */
    ret = wolfSSL_CTX_GenerateEchConfigEx(ctx, echCbTestPublicName,
            echCbTestKemID, echCbTestKdfID, echCbTestAeadID,
            XSTRLEN(echCbTestPublicName) + 20);
    if (ret != WOLFSSL_SUCCESS)
        return TEST_FAIL;

    echCbTestConfigsLen = sizeof(echCbTestConfigs);
    ret = wolfSSL_CTX_GetEchConfigs(ctx, echCbTestConfigs,
            &echCbTestConfigsLen);
    if (ret != WOLFSSL_SUCCESS)
        return TEST_FAIL;

    return TEST_SUCCESS;
}

/* Server ctx_ready callback: generate ECH config and opt into trial
 * decryption at the CTX level so the SSL inherits it on creation */
static int test_ech_server_ctx_ready_trial_decrypt(WOLFSSL_CTX* ctx)
{
    int ret = test_ech_server_ctx_ready(ctx);
    if (ret == TEST_SUCCESS)
        wolfSSL_CTX_SetEchEnableTrialDecrypt(ctx, 1);
    return ret;
}

/* Server ssl_ready callback: set SNI */
static int test_ech_server_ssl_ready(WOLFSSL* ssl)
{
    int ret;

    ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, echCbTestPrivateName,
                         (word16)XSTRLEN(echCbTestPrivateName));
    if (ret != WOLFSSL_SUCCESS)
        return TEST_FAIL;

    return TEST_SUCCESS;
}

/* Client ssl_ready callback: set ECH configs and SNI */
static int test_ech_client_ssl_ready(WOLFSSL* ssl)
{
    int ret;

    ret = wolfSSL_SetEchConfigs(ssl, echCbTestConfigs, echCbTestConfigsLen);
    if (ret != WOLFSSL_SUCCESS)
        return TEST_FAIL;

    ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, echCbTestPrivateName,
                         (word16)XSTRLEN(echCbTestPrivateName));
    if (ret != WOLFSSL_SUCCESS)
        return TEST_FAIL;

    return TEST_SUCCESS;
}

static int test_wolfSSL_Tls13_ECH_all_algos_ex(void)
{
    EXPECT_DECLS;
    struct test_ssl_memio_ctx test_ctx;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
    test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_ACCEPTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_ACCEPTED);

    if (echCbTestKemID != 0 && echCbTestKdfID != 0 && echCbTestAeadID != 0) {
        TLSX* echX = TLSX_Find(test_ctx.c_ssl->extensions, TLSX_ECH);
        ExpectNotNull(echX);
        if (echX != NULL) {
            WOLFSSL_ECH* ech = (WOLFSSL_ECH*)echX->data;
            ExpectNotNull(ech);
            if (ech != NULL) {
                /* verify that the ech extension has the correct algos */
                ExpectIntEQ(ech->kemId, echCbTestKemID);
                ExpectIntEQ(ech->cipherSuite.kdfId, echCbTestKdfID);
                ExpectIntEQ(ech->cipherSuite.aeadId, echCbTestAeadID);
                if (ech->hpke != NULL) {
                    /* and that hpke was initialized with these algos */
                    ExpectIntEQ(ech->hpke->kem, echCbTestKemID);
                    ExpectIntEQ(ech->hpke->kdf, echCbTestKdfID);
                    ExpectIntEQ(ech->hpke->aead, echCbTestAeadID);
                }
                if (ech->echConfig != NULL) {
                    ExpectIntEQ(ech->echConfig->kemId, echCbTestKemID);
                }
            }
        }
    }

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

static int test_wolfSSL_Tls13_ECH_all_algos(void)
{
    EXPECT_DECLS;
    int i;
    int j;
    int k;
    static const word16 kems[] = {
#if defined(HAVE_ECC)
#if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && !defined(NO_SHA256)
        DHKEM_P256_HKDF_SHA256,
#endif
#if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \
    defined(WOLFSSL_SHA384)
        DHKEM_P384_HKDF_SHA384,
#endif
#if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \
    defined(WOLFSSL_SHA512)
        DHKEM_P521_HKDF_SHA512,
#endif
#endif /* HAVE_ECC */
#if defined(HAVE_CURVE25519) && !defined(NO_SHA256)
        DHKEM_X25519_HKDF_SHA256,
#endif
    };
    static const word16 kdfs[] = {
#if !defined(NO_SHA256)
        HKDF_SHA256,
#endif
#ifdef WOLFSSL_SHA384
        HKDF_SHA384,
#endif
#ifdef WOLFSSL_SHA512
        HKDF_SHA512,
#endif
    };
    static const word16 aeads[] = {
#ifdef WOLFSSL_AES_128
        HPKE_AES_128_GCM,
#endif
#ifdef WOLFSSL_AES_256
        HPKE_AES_256_GCM,
#endif
    };

    for (i = 0; i < (int)(sizeof(kems) / sizeof(*kems)); i++) {
        echCbTestKemID = kems[i];
        for (j = 0; j < (int)(sizeof(kdfs) / sizeof(*kdfs)); j++) {
            echCbTestKdfID = kdfs[j];
            for (k = 0; k < (int)(sizeof(aeads) / sizeof(*aeads)); k++) {
                echCbTestAeadID = aeads[k];
                ExpectIntEQ(test_wolfSSL_Tls13_ECH_all_algos_ex(),
                    TEST_SUCCESS);
            }
        }
    }

    echCbTestKemID = 0;
    echCbTestKdfID = 0;
    echCbTestAeadID = 0;

    return EXPECT_RESULT();
}

/* Test ECH when no private SNI is set */
static int test_wolfSSL_Tls13_ECH_no_private_name(void)
{
    EXPECT_DECLS;
    struct test_ssl_memio_ctx test_ctx;

    /* client sends private SNI, server does not have one set */

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_ACCEPTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_ACCEPTED);

    test_ssl_memio_cleanup(&test_ctx);

    /* client does not send private SNI, server has one set */

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, echCbTestConfigs,
        echCbTestConfigsLen), WOLFSSL_SUCCESS);

    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_NOT_OFFERED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_NOT_OFFERED);

    test_ssl_memio_cleanup(&test_ctx);

    /* client does not send private SNI, server does not have one set */

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, echCbTestConfigs,
        echCbTestConfigsLen), WOLFSSL_SUCCESS);

    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_NOT_OFFERED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_NOT_OFFERED);

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

/* Test ECH rejection when configs don't match */
static int test_wolfSSL_Tls13_ECH_bad_configs_ex(int hrr, int sniCb)
{
    EXPECT_DECLS;
    struct test_ssl_memio_ctx test_ctx;
    WOLFSSL_CTX* tempCtx = NULL;
    const char* badPrivateName = "ech-bad-private-name.com";
    byte badPublicConfig[128];
    word32 badPublicConfigLen = sizeof(badPublicConfig);

    /* verify with bad public SNI / config */

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    /* server generates its own ECH config */
    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* generate throwaway ECH config for client to use */
    ExpectNotNull(tempCtx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
    ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(tempCtx, echCbTestPublicName,
        0, 0, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(tempCtx, badPublicConfig,
        &badPublicConfigLen), WOLFSSL_SUCCESS);
    wolfSSL_CTX_free(tempCtx);
    tempCtx = NULL;

    /* set bad public config on client */
    ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, badPublicConfig,
        badPublicConfigLen), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
        echCbTestPrivateName, (word16)XSTRLEN(echCbTestPrivateName)),
        WOLFSSL_SUCCESS);

    /* client will send empty cert on rejection, so server should not ask for
     * cert */
    wolfSSL_set_verify(test_ctx.s_ssl, WOLFSSL_VERIFY_NONE, NULL);

    if (hrr) {
        ExpectIntEQ(wolfSSL_NoKeyShares(test_ctx.c_ssl), WOLFSSL_SUCCESS);
    }
    if (sniCb) {
        wolfSSL_CTX_set_servername_callback(test_ctx.s_ctx,
            test_ech_server_sni_callback);
    }

    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);

    test_ssl_memio_cleanup(&test_ctx);


    /* verify with bad private SNI */

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* set bad private SNI on client */
    ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, echCbTestConfigs,
        echCbTestConfigsLen), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
        badPrivateName, (word16)XSTRLEN(badPrivateName)), WOLFSSL_SUCCESS);

    /* client will send empty cert on rejection, so server should not ask for
     * cert */
    wolfSSL_set_verify(test_ctx.s_ssl, WOLFSSL_VERIFY_NONE, NULL);

    if (hrr) {
        ExpectIntEQ(wolfSSL_NoKeyShares(test_ctx.c_ssl), WOLFSSL_SUCCESS);
    }
    if (sniCb) {
        wolfSSL_CTX_set_servername_callback(test_ctx.s_ctx,
            test_ech_server_sni_callback);
    }

    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    /* server decrypts inner successfully but rejects SNI, thus the client does
     * not receive the acceptance signal */
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_ACCEPTED);

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

static int test_wolfSSL_Tls13_ECH_bad_configs(void)
{
    EXPECT_DECLS;

    ExpectIntEQ(test_wolfSSL_Tls13_ECH_bad_configs_ex(0, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(test_wolfSSL_Tls13_ECH_bad_configs_ex(0, 1), WOLFSSL_SUCCESS);
    ExpectIntEQ(test_wolfSSL_Tls13_ECH_bad_configs_ex(1, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(test_wolfSSL_Tls13_ECH_bad_configs_ex(1, 1), WOLFSSL_SUCCESS);

    return EXPECT_RESULT();
}

/* Test retry configs are returned after ECH rejection and are usable */
static int test_wolfSSL_Tls13_ECH_retry_configs_ex(int hrr)
{
    EXPECT_DECLS;
    test_ssl_memio_ctx test_ctx;
    WOLFSSL_CTX* tempCtx = NULL;
    byte badConfigs[256];
    word32 badConfigsLen = sizeof(badConfigs);
    byte retryConfigs[256];
    word32 retryConfigsLen = sizeof(retryConfigs);
    WOLFSSL_CTX* savedSCtx;

    /* --- first attempt: wrong ECH config -> ECH rejected --- */

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;
    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* throwaway ECH config the server won't recognise */
    ExpectNotNull(tempCtx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
    ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(tempCtx, echCbTestPublicName,
        0, 0, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(tempCtx, badConfigs, &badConfigsLen),
        WOLFSSL_SUCCESS);
    wolfSSL_CTX_free(tempCtx);
    tempCtx = NULL;

    ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, badConfigs,
        badConfigsLen), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
        echCbTestPrivateName, (word16)XSTRLEN(echCbTestPrivateName)),
        WOLFSSL_SUCCESS);

    if (hrr)
        ExpectIntEQ(wolfSSL_NoKeyShares(test_ctx.c_ssl), WOLFSSL_SUCCESS);

    /* ECH must fail and retry configs must be present */
    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
        WC_NO_ERR_TRACE(ECH_REQUIRED_E));

    /* capture retry configs */
    ExpectIntEQ(wolfSSL_GetEchRetryConfigs(test_ctx.c_ssl, retryConfigs,
        &retryConfigsLen), WOLFSSL_SUCCESS);
    ExpectIntEQ(test_ctx.c_ssl->error, ECH_REQUIRED_E);
    ExpectIntGT(retryConfigsLen, 0);

    if (EXPECT_SUCCESS()){
        /* keep server CTX so second attempt uses the same ECH keys */
        savedSCtx = test_ctx.s_ctx;
        test_ctx.s_cb.isSharedCtx = 1;
        test_ssl_memio_cleanup(&test_ctx);

        /* --- second attempt: same server CTX, retry configs -> accepted --- */
        XMEMSET(&test_ctx, 0, sizeof(test_ctx));
        test_ctx.s_cb.method = wolfTLSv1_3_server_method;
        test_ctx.c_cb.method = wolfTLSv1_3_client_method;
        test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
        /* restore server CTX; ctx_ready left NULL to skip ECH key regen */
        test_ctx.s_ctx = savedSCtx;
        test_ctx.s_cb.isSharedCtx = 1;

        ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

        ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, retryConfigs,
            retryConfigsLen), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
            echCbTestPrivateName, (word16)XSTRLEN(echCbTestPrivateName)),
            WOLFSSL_SUCCESS);

        if (hrr)
            ExpectIntEQ(wolfSSL_NoKeyShares(test_ctx.c_ssl), WOLFSSL_SUCCESS);

        ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL),
            TEST_SUCCESS);
        ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
            WOLFSSL_ECH_STATUS_ACCEPTED);
        ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
            WOLFSSL_ECH_STATUS_ACCEPTED);

        wolfSSL_CTX_free(test_ctx.s_ctx);
        test_ctx.s_ctx = NULL;
    }

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

static int test_wolfSSL_Tls13_ECH_retry_configs(void)
{
    EXPECT_DECLS;

    ExpectIntEQ(test_wolfSSL_Tls13_ECH_retry_configs_ex(0), TEST_SUCCESS);
    ExpectIntEQ(test_wolfSSL_Tls13_ECH_retry_configs_ex(1), TEST_SUCCESS);

    return EXPECT_RESULT();
}

/* Test retry configs are cleared when authentication fails */
static int test_wolfSSL_Tls13_ECH_retry_configs_auth_fail_ex(int hrr)
{
    EXPECT_DECLS;
    test_ssl_memio_ctx test_ctx;
    WOLFSSL_CTX* tempCtx = NULL;
    byte badConfigs[256];
    word32 badConfigsLen = sizeof(badConfigs);
    word32 retryConfigsLen = sizeof(badConfigs);
    const char* badPublicName = "ech-public-name.com";

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;
    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* generate mismatched ECH configs so retry_configs are sent
     * and use a bad public name so auth fails in outer hello */
    ExpectNotNull(tempCtx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
    ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(tempCtx, badPublicName,
        0, 0, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(tempCtx, badConfigs, &badConfigsLen),
        WOLFSSL_SUCCESS);
    wolfSSL_CTX_free(tempCtx);
    tempCtx = NULL;

    ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, badConfigs,
        badConfigsLen), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
        echCbTestPrivateName, (word16)XSTRLEN(echCbTestPrivateName)),
        WOLFSSL_SUCCESS);

    /* Do not require client cert on server so it does not send
     * CertificateRequest */
    wolfSSL_set_verify(test_ctx.s_ssl, WOLFSSL_VERIFY_NONE, NULL);
    wolfSSL_set_verify(test_ctx.c_ssl, WOLFSSL_VERIFY_PEER, NULL);

    /* use badPublicName so ECH public name matches */
    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.s_ssl, WOLFSSL_SNI_HOST_NAME,
        badPublicName, (word16)XSTRLEN(badPublicName)),
        WOLFSSL_SUCCESS);

    if (hrr)
        ExpectIntEQ(wolfSSL_NoKeyShares(test_ctx.c_ssl), WOLFSSL_SUCCESS);

    /* auth failure in outer handshake, not ech_required */
    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
        WC_NO_ERR_TRACE(DOMAIN_NAME_MISMATCH));

    /* retry configs must not be accessible */
    ExpectIntNE(wolfSSL_GetEchRetryConfigs(test_ctx.c_ssl, NULL,
        &retryConfigsLen), WOLFSSL_SUCCESS);

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

static int test_wolfSSL_Tls13_ECH_retry_configs_auth_fail(void)
{
    EXPECT_DECLS;

    ExpectIntEQ(test_wolfSSL_Tls13_ECH_retry_configs_auth_fail_ex(0),
        TEST_SUCCESS);
    ExpectIntEQ(test_wolfSSL_Tls13_ECH_retry_configs_auth_fail_ex(1),
        TEST_SUCCESS);

    return EXPECT_RESULT();
}

/* Test that bad retry configs (unsupported cipher suite) from the server are
 * ignored rather than propagating an error */
static int test_wolfSSL_Tls13_ECH_retry_configs_bad(void)
{
    EXPECT_DECLS;
    test_ssl_memio_ctx test_ctx;
    word32 retryConfigsLen = sizeof(echCbTestConfigs);

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;
    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
    test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* corrupt the server's cipher suite -> ECH decrypt will fail, and retry
     * configs will have an unsupported KDF/AEAD pair.
     * This will trigger the UNSUPPORTED_SUITE path in TLSX_ECH_Parse */
    if (EXPECT_SUCCESS() && test_ctx.s_ctx->echConfigs != NULL &&
            test_ctx.s_ctx->echConfigs->cipherSuites != NULL) {
        test_ctx.s_ctx->echConfigs->cipherSuites[0].aeadId = 0xFEFE;
    }

    /* bad retry configs are discarded - failure must be ECH_REQUIRED_E,
     * not a retry-config parse error */
    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
        WC_NO_ERR_TRACE(ECH_REQUIRED_E));

    /* no retry configs should be stored since they were all unsupported */
    ExpectIntNE(wolfSSL_GetEchRetryConfigs(test_ctx.c_ssl, NULL,
        &retryConfigsLen), WOLFSSL_SUCCESS);

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

/* Test that client info can be successfully decoded from one of multiple server
 * ECH configs
 * In this case the server is expected to try it's first config, fail, then try
 * its second config and succeed */
static int test_wolfSSL_Tls13_ECH_new_config(void)
{
    EXPECT_DECLS;
    test_ssl_memio_ctx test_ctx;
    byte altConfig[512];
    word32 altConfigLen = sizeof(altConfig);
    byte combinedConfigs[512];
    word32 combinedConfigsLen = sizeof(combinedConfigs);
    word16 firstConfigLen = 0;
    word16 secondConfigOffset = 0;
    word16 secondConfigLen = 0;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    /* server generates its own ECH config */
    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* generate a second ECH config for the server */
    ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(test_ctx.s_ctx,
        echCbTestPrivateName, 0, 0, 0), WOLFSSL_SUCCESS);
    ExpectNotNull(test_ctx.s_ctx->echConfigs->next);

    /* capture the second ECH config in the list for the client to use */
    ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(test_ctx.s_ctx, combinedConfigs,
        &combinedConfigsLen), WOLFSSL_SUCCESS);

    /* ECHConfigList: [2 byte list len] [ECHConfig]...
     * ECHConfig:     [2 byte version] [2 byte config len] [config data] */
    ExpectIntGE(combinedConfigsLen, OPAQUE16_LEN * 3);
    if (EXPECT_SUCCESS()) {
        ato16(combinedConfigs + OPAQUE16_LEN + OPAQUE16_LEN, &firstConfigLen);
        secondConfigOffset = OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN +
            firstConfigLen;
        ExpectIntGE(combinedConfigsLen,
            secondConfigOffset + OPAQUE16_LEN + OPAQUE16_LEN);
    }
    if (EXPECT_SUCCESS()) {
        ato16(combinedConfigs + secondConfigOffset + OPAQUE16_LEN,
            &secondConfigLen);
        secondConfigLen += OPAQUE16_LEN + OPAQUE16_LEN;
        ExpectIntGE(combinedConfigsLen, secondConfigOffset + secondConfigLen);
    }
    if (EXPECT_SUCCESS()) {
        /* build the ECHConfigList */
        c16toa(secondConfigLen, altConfig);
        ExpectIntLE(OPAQUE16_LEN + secondConfigLen, (word16)sizeof(altConfig));
        if (EXPECT_SUCCESS()) {
            XMEMCPY(altConfig + OPAQUE16_LEN,
                combinedConfigs + secondConfigOffset, secondConfigLen);
            altConfigLen = OPAQUE16_LEN + secondConfigLen;
        }
    }

    /* Set client configs - server should try both and succeed with second
     * Or seek the correct one immediately through the configId */
    ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, altConfig, altConfigLen),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
        echCbTestPrivateName, (word16)XSTRLEN(echCbTestPrivateName)),
        WOLFSSL_SUCCESS);

    ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_ACCEPTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_ACCEPTED);

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

/* Test trial decryption for ECH: server has a single config, client receives a
 * copy of it but its configId is overwritten so it cannot match the server's */
static int test_wolfSSL_Tls13_ECH_trial_decrypt(void)
{
    EXPECT_DECLS;
    test_ssl_memio_ctx test_ctx;

    /* --- CTX-enabled, SSL-disabled override: ECH rejected --- */

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    /* *_trial_decrypt sets enableEchTrialDecrypt to 1 - overriding the default
     * value of 0 */
    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready_trial_decrypt;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
    test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* SSL inherited the CTX setting */
    ExpectIntEQ(test_ctx.s_ctx->enableEchTrialDecrypt, 1);
    ExpectIntEQ(test_ctx.s_ssl->options.enableEchTrialDecrypt, 1);

    /* override on the SSL */
    wolfSSL_SetEchEnableTrialDecrypt(test_ctx.s_ssl, 0);
    ExpectIntEQ(test_ctx.s_ssl->options.enableEchTrialDecrypt, 0);

    /* alter the client's configId so it does not match the server's configId */
    ExpectNotNull(test_ctx.c_ssl->echConfigs);
    ExpectNotNull(test_ctx.s_ctx->echConfigs);
    if (EXPECT_SUCCESS()) {
        test_ctx.c_ssl->echConfigs->configId =
            (byte)(test_ctx.s_ctx->echConfigs->configId ^ 0x01);
    }

    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
        WC_NO_ERR_TRACE(ECH_REQUIRED_E));

    test_ssl_memio_cleanup(&test_ctx);

    /* --- trial decryption opted in on the SSL: ECH accepted --- */

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
    test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* opt into trial decryption on the SSL */
    wolfSSL_SetEchEnableTrialDecrypt(test_ctx.s_ssl, 1);
    ExpectIntEQ(test_ctx.s_ssl->options.enableEchTrialDecrypt, 1);

    /* alter the client's configId so it does not match the server's configId */
    ExpectNotNull(test_ctx.c_ssl->echConfigs);
    ExpectNotNull(test_ctx.s_ctx->echConfigs);
    if (EXPECT_SUCCESS()) {
        test_ctx.c_ssl->echConfigs->configId =
            (byte)(test_ctx.s_ctx->echConfigs->configId ^ 0x01);
    }

    ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_ACCEPTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_ACCEPTED);

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

/* Test GREASE ECH:
 * 1. client sends GREASE ECH extension but server has no ECH configs so it
 * ignores it, handshake succeeds normally
 * 2. client sends GREASE ECH extensions and server has ECH configs, handshake
 * succeeds
 * configs should never be received */
static int test_wolfSSL_Tls13_ECH_GREASE(void)
{
    EXPECT_DECLS;
    test_ssl_memio_ctx test_ctx;
    word32 retryConfigsLen = sizeof(test_ctx);

    /* GREASE when server has no ECH configs */

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
        echCbTestPrivateName, (word16)XSTRLEN(echCbTestPrivateName)),
        WOLFSSL_SUCCESS);

    /* verify ECH is enabled on the client and server */
    ExpectIntEQ(test_ctx.s_ssl->options.disableECH, 0);
    ExpectIntEQ(test_ctx.c_ssl->options.disableECH, 0);
    /* verify no ECH configs are set */
    ExpectNull(test_ctx.s_ctx->echConfigs);
    ExpectNull(test_ctx.c_ssl->echConfigs);

    /* handshake should succeed - server ignores the GREASE ECH extension */
    ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);

    /* server has no configs and client did not offer real ECH */
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_NOT_OFFERED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_GREASE);
    /* verify no ECH configs are received */
    ExpectNull(test_ctx.c_ssl->echConfigs);
    /* retry configs must not be saved */
    ExpectIntNE(wolfSSL_GetEchRetryConfigs(test_ctx.c_ssl, NULL,
        &retryConfigsLen), WOLFSSL_SUCCESS);

    test_ssl_memio_cleanup(&test_ctx);

    /* GREASE when server has ECH configs */

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    /* generate ECH configs */
    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
        echCbTestPrivateName, (word16)XSTRLEN(echCbTestPrivateName)),
        WOLFSSL_SUCCESS);

    /* verify ECH is enabled on the client and server */
    ExpectIntEQ(test_ctx.s_ssl->options.disableECH, 0);
    ExpectIntEQ(test_ctx.c_ssl->options.disableECH, 0);
    /* verify ECH configs are set on server */
    ExpectNotNull(test_ctx.s_ctx->echConfigs);
    ExpectNull(test_ctx.c_ssl->echConfigs);

    /* handshake should succeed - server responds to the GREASE ECH extension */
    ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);

    /* server was unable to decrypt the ECH extension's payload
     * client never offered real ECH */
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_GREASE);
    /* verify no ECH configs are received */
    ExpectNull(test_ctx.c_ssl->echConfigs);
    /* retry configs must not be saved */
    ExpectIntNE(wolfSSL_GetEchRetryConfigs(test_ctx.c_ssl, NULL,
        &retryConfigsLen), WOLFSSL_SUCCESS);

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

static int test_wolfSSL_Tls13_ECH_disable_conn_ex(int enableServer,
    int enableClient)
{
    EXPECT_DECLS;
    test_ssl_memio_ctx test_ctx;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    /* both server and client will be setup to use ECH */
    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
    test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* this callback will ensure that the correct SNI is being held */
    wolfSSL_CTX_set_servername_callback(test_ctx.s_ctx,
        test_ech_server_sni_callback);
    ExpectIntEQ(wolfSSL_CTX_set_servername_arg(test_ctx.s_ctx, &enableClient),
        WOLFSSL_SUCCESS);

    /* disable ECH on the appropriate side(s) */
    wolfSSL_SetEchEnable(test_ctx.s_ssl, enableServer);
    wolfSSL_SetEchEnable(test_ctx.c_ssl, enableClient);

    if (!enableClient) {
        /* client ECH disabled: no ECH extension sent, handshake succeeds
         * normally but ECH is not accepted */
        ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL),
            TEST_SUCCESS);
        ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
            WOLFSSL_ECH_STATUS_NOT_OFFERED);
    }
    else if (!enableServer) {
        /* client sends ECH but server can't process it: server has no ECH
         * keys so it processes the outer ClientHello, client detects ECH
         * rejection and aborts the handshake */
        ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL),
            TEST_SUCCESS);
        ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
            WOLFSSL_ECH_STATUS_REJECTED);
    }
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_NOT_OFFERED);

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

/* setup a server and client with ECH then disable on one, the other, or both.
 * Verifies that disabling ECH prevents ECH from being used and that the
 * public/private SNI's are verified correctly */
static int test_wolfSSL_Tls13_ECH_disable_conn(void)
{
    EXPECT_DECLS;

    ExpectIntEQ(test_wolfSSL_Tls13_ECH_disable_conn_ex(0, 1), TEST_SUCCESS);
    ExpectIntEQ(test_wolfSSL_Tls13_ECH_disable_conn_ex(1, 0), TEST_SUCCESS);
    ExpectIntEQ(test_wolfSSL_Tls13_ECH_disable_conn_ex(0, 0), TEST_SUCCESS);

    return EXPECT_RESULT();
}

/* Regression test: an inner SNI hostname >= MAX_PUBLIC_NAME_SZ (256) bytes
 * must not cause a stack-buffer-overflow in TLSX_EchRestoreSNI.  Before the
 * fix, the truncated copy omitted the NUL terminator and XSTRLEN read past
 * the buffer. */
static int test_wolfSSL_Tls13_ECH_long_SNI(void)
{
    EXPECT_DECLS;
#if !defined(NO_WOLFSSL_CLIENT)
    test_ssl_memio_ctx test_ctx;
    /* 300 chars > MAX_PUBLIC_NAME_SZ (256) to exercise truncation */
    char longName[300];

    XMEMSET(longName, 'a', sizeof(longName) - 1);
    longName[sizeof(longName) - 1] = '\0';

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* Set ECH configs on the client */
    ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, echCbTestConfigs,
        echCbTestConfigsLen), WOLFSSL_SUCCESS);

    /* Try to set the over-long SNI as the inner hostname -- after the fix, this
     * is expected to fail.
     */
    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
        longName, (word16)XSTRLEN(longName)), BAD_LENGTH_E);

    /* Before the fix, the handshake would trigger TLSX_EchChangeSNI /
     * TLSX_EchRestoreSNI, which would then stack-buffer-overflow in XSTRLEN.
     */
    (void)test_ssl_memio_do_handshake(&test_ctx, 10, NULL);

    test_ssl_memio_cleanup(&test_ctx);
#endif /* !NO_WOLFSSL_CLIENT */

    return EXPECT_RESULT();
}

static int ech_seek_extensions(byte* buf, word16* innerExtLen)
{
    word16 idx;
    byte sessionIdLen;
    word16 cipherSuitesLen;
    byte compressionLen;

    idx = OPAQUE16_LEN + RAN_LEN;

    sessionIdLen = buf[idx++];
    idx += sessionIdLen;

    ato16(buf + idx, &cipherSuitesLen);
    idx += OPAQUE16_LEN + cipherSuitesLen;

    compressionLen = buf[idx++];
    idx += compressionLen;

    ato16(buf + idx, innerExtLen);
    idx += OPAQUE16_LEN;

    return idx;
}

static int ech_find_extension(byte* buf, word16* idx_p, word16 extType)
{
    word16 idx;
    word16 innerExtIdx;
    word16 innerExtLen;

    innerExtIdx = ech_seek_extensions(buf + *idx_p, &innerExtLen) + *idx_p;
    idx = innerExtIdx;

    while (idx - innerExtIdx < innerExtLen) {
        word16 type;
        word16 len;

        ato16(buf + idx, &type);
        if (type == extType) {
            *idx_p = idx;
            return 0;
        }

        idx += OPAQUE16_LEN;
        ato16(buf + idx, &len);
        idx += OPAQUE16_LEN + len;
    }

    return BAD_FUNC_ARG;
}

/* Test the HRR ECH rejection fallback path:
 * client offers ECH, HRR is triggered, server sends HRR without ECH extension,
 * client falls back to the outer transcript, then aborts with ech_required. */
static int test_wolfSSL_Tls13_ECH_HRR_rejection(void)
{
    EXPECT_DECLS;
    test_ssl_memio_ctx test_ctx;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    /* Server generates ECH config with good public name */
    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    /* Client sets the correct ECH config and private SNI */
    test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* Server must not require a client certificate */
    wolfSSL_set_verify(test_ctx.s_ssl, WOLFSSL_VERIFY_NONE, NULL);
    wolfSSL_set_verify(test_ctx.c_ssl, WOLFSSL_VERIFY_PEER, NULL);

    /* Disable ECH on the server SSL object: the server ignores ECH in CH1 and
     * sends HRR without an ECH extension (confBuf stays NULL on the client) */
    wolfSSL_SetEchEnable(test_ctx.s_ssl, 0);
    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.s_ssl, WOLFSSL_SNI_HOST_NAME,
        echCbTestPublicName, (word16)XSTRLEN(echCbTestPublicName)),
        WOLFSSL_SUCCESS);

    /* Force HRR so client receives HRR with no ECH extension,
     * detects confBuf == NULL and frees hsHashesEch, falling back to the
     * outer transcript */
    ExpectIntEQ(wolfSSL_NoKeyShares(test_ctx.c_ssl), WOLFSSL_SUCCESS);

    /* Handshake must fail: client aborts with ech_required */
    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_NOT_OFFERED);
    /* hsHashesEch must have been freed by the HRR rejection code path */
    ExpectNull(test_ctx.c_ssl->hsHashesEch);
    ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
        WC_NO_ERR_TRACE(ECH_REQUIRED_E));

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

/* verify the server aborts if CH2 omits the ECH extension after the server
 * accepted ECH in the HRR round */
static int test_wolfSSL_Tls13_ECH_ch2_no_ech(void)
{
    EXPECT_DECLS;
    test_ssl_memio_ctx test_ctx;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
    test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* withhold key shares from CH1 so the server is forced to send HRR */
    ExpectIntEQ(wolfSSL_NoKeyShares(test_ctx.c_ssl), WOLFSSL_SUCCESS);

    /* one round: client sends CH1, server processes it and sends HRR */
    (void)test_ssl_memio_do_handshake(&test_ctx, 1, NULL);

    /* server must have committed to ECH acceptance in the HRR */
    ExpectIntEQ(test_ctx.s_ssl->options.serverState,
        SERVER_HELLO_RETRY_REQUEST_COMPLETE);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_ACCEPTED);

    /* disable ECH on the client so CH2 omits the ECH extension entirely */
    wolfSSL_SetEchEnable(test_ctx.c_ssl, 0);

    /* rest of handshake must fail */
    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_get_error(test_ctx.s_ssl, 0),
        WC_NO_ERR_TRACE(INCOMPLETE_DATA));

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

/* verify that a decryption failure in CH2 is caught
 * this also verifies that HPKE context is correctly reused */
static int test_wolfSSL_Tls13_ECH_ch2_decrypt_error(void)
{
    EXPECT_DECLS;
    test_ssl_memio_ctx test_ctx;
    word16 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
    test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* Withhold key shares so the server is forced to send HRR */
    ExpectIntEQ(wolfSSL_NoKeyShares(test_ctx.c_ssl), WOLFSSL_SUCCESS);

    /* One round: client sends CH1, server processes it and sends HRR */
    (void)test_ssl_memio_do_handshake(&test_ctx, 1, NULL);

    ExpectIntEQ(test_ctx.s_ssl->options.serverState,
        SERVER_HELLO_RETRY_REQUEST_COMPLETE);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_ACCEPTED);

    if (EXPECT_SUCCESS()) {
        /* Client reads HRR and writes CH2 into s_buff */
        (void)wolfSSL_connect(test_ctx.c_ssl);

        /* Corrupt one byte of the ECH ciphertext in the CH2 record in s_buff.
         * ECH outer extension layout after the 0xFE0D type marker:
         *   extLen(2) + outerType(1) + kdfId(2) + aeadId(2) + configId(1)
         *   + encLen(2) + payloadLen(2) = 12 bytes,
         * so the ciphertext starts 14 bytes past the first 0xFE byte. */
        ExpectIntEQ(ech_find_extension(test_ctx.s_buff, &idx, TLSXT_ECH), 0);
        if (EXPECT_SUCCESS() && (idx + 14 < test_ctx.s_len))
            test_ctx.s_buff[idx + 14] ^= 0xFF;

        /* Server processes the corrupted CH2.
         * hpkeContext is preserved, TLSX_ECH_Parse correctly identifies the CH2
         *   round and sends decrypt_error. */
        if (EXPECT_SUCCESS()) {
            (void)wolfSSL_accept(test_ctx.s_ssl);
            ExpectIntEQ(wolfSSL_get_error(test_ctx.s_ssl, 0),
                WC_NO_ERR_TRACE(DECRYPT_ERROR));
        }
    }

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

/* when ECH is rejected the certificate must match the public name of the chosen
 * ech config
 * the cert check should pass and the client aborts with ech_required */
static int test_wolfSSL_Tls13_ECH_rejected_cert_valid_ex(const char* publicName,
    int validName)
{
    EXPECT_DECLS;
    test_ssl_memio_ctx test_ctx;
    byte echConfigs[512];
    word32 echConfigsLen = sizeof(echConfigs);

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* Generate ECH config with given public_name */
    ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(test_ctx.s_ctx, publicName,
        0, 0, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(test_ctx.s_ctx, echConfigs,
        &echConfigsLen), WOLFSSL_SUCCESS);

    /* Client loads ECH configs and sets a private SNI */
    ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, echConfigs,
        echConfigsLen), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
        "ech-private.com", (word16)XSTRLEN("ech-private.com")),
        WOLFSSL_SUCCESS);

    /* Do not require client cert on server so it does not send
     * CertificateRequest */
    wolfSSL_set_verify(test_ctx.s_ssl, WOLFSSL_VERIFY_NONE, NULL);
    wolfSSL_set_verify(test_ctx.c_ssl, WOLFSSL_VERIFY_PEER, NULL);

    /* Disable ECH on the server side so ECH is rejected */
    wolfSSL_SetEchEnable(test_ctx.s_ssl, 0);

    /* Match the server SNI to the ECH public_name */
    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.s_ssl, WOLFSSL_SNI_HOST_NAME,
        publicName, (word16)XSTRLEN(publicName)), WOLFSSL_SUCCESS);

    /* client sends ECH but server can't process it, however it is possible to
     * fall back to the outer handshake */
    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_NOT_OFFERED);

    if (validName) {
        /* the server should see the handshake as successful
         * the client should abort because the server did not use ECH */
        ExpectIntEQ(wolfSSL_get_error(test_ctx.s_ssl, 0),
            WC_NO_ERR_TRACE(WOLFSSL_ERROR_NONE));
        ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
            WC_NO_ERR_TRACE(ECH_REQUIRED_E));
    }
    else {
        /* the client should abort with cert mismatch
         * the server error is then dependent on whether that cert mismatch
         * results in an abort */
        ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
            WC_NO_ERR_TRACE(DOMAIN_NAME_MISMATCH));
    }

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}

static int test_wolfSSL_Tls13_ECH_rejected_cert_valid(void)
{
    EXPECT_DECLS;

    /* "example.com" appears in the SAN of certs/server-cert.pem */
    ExpectIntEQ(test_wolfSSL_Tls13_ECH_rejected_cert_valid_ex("example.com", 1),
        TEST_SUCCESS);
    ExpectIntEQ(test_wolfSSL_Tls13_ECH_rejected_cert_valid_ex("badname.com", 0),
        TEST_SUCCESS);

    return EXPECT_RESULT();
}

/* when ECH is rejected and the server requests a client certificate the client
 * must respond with an empty cert */
static int test_wolfSSL_Tls13_ECH_rejected_empty_client_cert(void)
{
    EXPECT_DECLS;
    test_ssl_memio_ctx test_ctx;
    byte echConfigs[512];
    word32 echConfigsLen = sizeof(echConfigs);
    const char* publicName = "example.com";

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    test_ctx.s_cb.method = wolfTLSv1_3_server_method;
    test_ctx.c_cb.method = wolfTLSv1_3_client_method;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* Generate ECH config with public_name matching the server cert SAN */
    ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(test_ctx.s_ctx, publicName,
        0, 0, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(test_ctx.s_ctx, echConfigs,
        &echConfigsLen), WOLFSSL_SUCCESS);

    /* Client loads ECH configs and sets a private SNI */
    ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, echConfigs,
        echConfigsLen), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
        "ech-private.com", (word16)XSTRLEN("ech-private.com")),
        WOLFSSL_SUCCESS);

    wolfSSL_set_verify(test_ctx.s_ssl,
            WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
    wolfSSL_set_verify(test_ctx.c_ssl, WOLFSSL_VERIFY_PEER, NULL);

    /* Disable ECH on the server so ECH is rejected */
    wolfSSL_SetEchEnable(test_ctx.s_ssl, 0);

    /* Match the Server SNI to the ECH public_name */
    ExpectIntEQ(wolfSSL_UseSNI(test_ctx.s_ssl, WOLFSSL_SNI_HOST_NAME,
        publicName, (word16)XSTRLEN(publicName)), WOLFSSL_SUCCESS);

    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
        WOLFSSL_ECH_STATUS_REJECTED);
    ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
        WOLFSSL_ECH_STATUS_NOT_OFFERED);

    /* Server cert is valid for public_name, cert check passes, ech_required
     * is sent on the client side. */
    ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
        WC_NO_ERR_TRACE(ECH_REQUIRED_E));

    /* The server received an empty Certificate from the client.
     * With FAIL_IF_NO_PEER_CERT set, the server aborts with NO_PEER_CERT. */
    ExpectIntEQ(wolfSSL_get_error(test_ctx.s_ssl, 0),
        WC_NO_ERR_TRACE(NO_PEER_CERT));

    test_ssl_memio_cleanup(&test_ctx);

    return EXPECT_RESULT();
}
#endif /* HAVE_SSL_MEMIO_TESTS_DEPENDENCIES */

/* verify that ECH can be enabled/disabled without issue */
static int test_wolfSSL_Tls13_ECH_enable_disable(void)
{
    EXPECT_DECLS;
#if !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;
    byte echConfigs[128];
    word32 echConfigsLen = sizeof(echConfigs);

    /* NULL ctx, NULL ssl should not crash */
    wolfSSL_SetEchEnable(ssl, 0);
    wolfSSL_CTX_SetEchEnable(ctx, 0);

    /* test CTX level enable/disable */
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));

    ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(ctx, "public.com", 0, 0, 0),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(ctx, echConfigs, &echConfigsLen),
        WOLFSSL_SUCCESS);

    /* disable ECH at CTX level */
    wolfSSL_CTX_SetEchEnable(ctx, 0);
    ExpectIntEQ(ctx->disableECH, 1);
    ExpectNull(ctx->echConfigs);

    wolfSSL_CTX_SetEchEnable(ctx, 1);
    ExpectIntEQ(ctx->disableECH, 0);

    /* test SSL level enable/disable */
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    ExpectIntEQ(wolfSSL_SetEchConfigs(ssl, echConfigs, echConfigsLen),
        WOLFSSL_SUCCESS);

    /* disable ECH at SSL level */
    wolfSSL_SetEchEnable(ssl, 0);
    ExpectIntEQ(ssl->options.disableECH, 1);
    ExpectNull(ssl->echConfigs);

    wolfSSL_SetEchEnable(ssl, 1);
    ExpectIntEQ(ssl->options.disableECH, 0);

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif /* !NO_WOLFSSL_CLIENT */

    return EXPECT_RESULT();
}

#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) && \
    defined(WOLFSSL_TEST_ECH) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(WOLFSSL_NO_TLS12)
static int ech_tamper_downgrade(byte* innerCh, word32 innerChLen)
{
    int ret;
    word16 idx = 0;

    (void)innerChLen;

    ret = ech_find_extension(innerCh, &idx, TLSXT_SUPPORTED_VERSIONS);
    if (ret == 0) {
        /* change extension type to something unknown */
        innerCh[idx] = 0xFA;
        innerCh[idx + 1] = 0xFA;
        return 0;
    }
    else {
        return ret;
    }
}

static int ech_tamper_padding(byte* innerCh, word32 innerChLen)
{
    word16 idx;
    word16 innerExtLen;

    /* get the unpadded length */
    idx = ech_seek_extensions(innerCh, &innerExtLen);
    idx += innerExtLen;

    /* no padding, but the test would fail if the message is not incorrect...
     * so fail the callback */
    if (idx == innerChLen) {
        return BAD_FUNC_ARG;
    }
    else {
        innerCh[idx] = '\x01';
        return 0;
    }
}

static int ech_tamper_type(byte* innerCh, word32 innerChLen)
{
    int ret;
    word16 idx = 0;

    (void)innerChLen;

    ret = ech_find_extension(innerCh, &idx, TLSXT_ECH);
    if (ret == 0) {
        /* change type to outer */
        innerCh[idx + 4] = ECH_TYPE_OUTER;
        return 0;
    }
    else {
        return ret;
    }
}

static int ech_tamper_key_share(byte* innerCh, word32 innerChLen)
{
    int ret;
    word16 idx = 0;
    word16 len;

    (void)innerChLen;

    ret = ech_find_extension(innerCh, &idx, TLSXT_KEY_SHARE);
    if (ret == 0) {
        ato16(innerCh + idx + 8, &len);
        if (len == 0) {
            return BAD_FUNC_ARG;
        }
        else {
            /* tamper with public key data */
            innerCh[idx + 10] ^= 0xFF;
            return 0;
        }
    }
    else {
        return ret;
    }
}

static int ech_tamper_ciphersuite(byte* innerCh, word32 innerChLen)
{
    word16 idx;
    byte sessionIdLen;
    word16 cipherSuitesLen;

    (void)innerChLen;

    idx = OPAQUE16_LEN + RAN_LEN;

    sessionIdLen = innerCh[idx++];
    idx += sessionIdLen;

    ato16(innerCh + idx, &cipherSuitesLen);
    idx += OPAQUE16_LEN;

    if (cipherSuitesLen < 2) {
        return BAD_FUNC_ARG;
    }
    else {
        /* change all ciphersuites to unknown value */
        while (cipherSuitesLen > 0) {
            innerCh[idx] = '\xFA';
            innerCh[idx + 1] = '\xFA';
            idx += OPAQUE16_LEN;
            cipherSuitesLen -= OPAQUE16_LEN;
        }
        return 0;
    }
}

static int test_wolfSSL_Tls13_ECH_tamper_ex(struct test_ssl_memio_ctx* test_ctx)
{
    EXPECT_DECLS;

    test_ssl_memio_cleanup(test_ctx);
    XMEMSET(test_ctx, 0, sizeof(struct test_ssl_memio_ctx));

    test_ctx->s_cb.method = wolfTLSv1_3_server_method;
    test_ctx->c_cb.method = wolfTLSv1_3_client_method;

    test_ctx->s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx->s_cb.ssl_ready = test_ech_server_ssl_ready;
    test_ctx->c_cb.ssl_ready = test_ech_client_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(test_ctx), TEST_SUCCESS);

    return EXPECT_RESULT();
}

static int test_wolfSSL_Tls13_ECH_tamper_client(void)
{
    EXPECT_DECLS;
    int err;
    struct test_ssl_memio_ctx test_ctx;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    /* try to downgrade to TLS 1.2 in the inner hello */
    test_ctx.s_cb.method = wolfSSLv23_server_method;
    test_ctx.c_cb.method = wolfSSLv23_client_method;

    test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
    test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
    test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;

    ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);

    /* change supported_versions extension type to 0xFAFA: this will encourage a
     * downgrade to TLS 1.2 */
    test_ctx.c_ssl->echInnerHelloCb = ech_tamper_downgrade;

    /* the server MUST reject an inner ClientHello that tries to negotiate
     * TLS 1.2 or below */
    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_get_error(test_ctx.s_ssl, 0),
        WC_NO_ERR_TRACE(INVALID_PARAMETER));
    ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
        WC_NO_ERR_TRACE(FATAL_ERROR));

    /* non-zero padding byte */
    ExpectIntEQ(test_wolfSSL_Tls13_ECH_tamper_ex(&test_ctx), TEST_SUCCESS);
    test_ctx.c_ssl->echInnerHelloCb = ech_tamper_padding;
    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    if (EXPECT_SUCCESS()) {
        /* padding may have a length of zero which is not an error but the
         * callback will treat it as such (thus the BAD_FUNC_ARG) */
        err = wolfSSL_get_error(test_ctx.s_ssl, 0);
        ExpectTrue(err == WC_NO_ERR_TRACE(INVALID_PARAMETER) ||
                   err == WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    }
    ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
        WC_NO_ERR_TRACE(FATAL_ERROR));

    /* bad ECH type */
    ExpectIntEQ(test_wolfSSL_Tls13_ECH_tamper_ex(&test_ctx), TEST_SUCCESS);
    test_ctx.c_ssl->echInnerHelloCb = ech_tamper_type;
    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
    ExpectIntEQ(wolfSSL_get_error(test_ctx.s_ssl, 0),
        WC_NO_ERR_TRACE(INVALID_PARAMETER));
    ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
        WC_NO_ERR_TRACE(FATAL_ERROR));

    /* corrupted key share */
    ExpectIntEQ(test_wolfSSL_Tls13_ECH_tamper_ex(&test_ctx), TEST_SUCCESS);
    test_ctx.c_ssl->echInnerHelloCb = ech_tamper_key_share;
    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);

    /* bad ciphersuite */
    ExpectIntEQ(test_wolfSSL_Tls13_ECH_tamper_ex(&test_ctx), TEST_SUCCESS);
    test_ctx.c_ssl->echInnerHelloCb = ech_tamper_ciphersuite;
    ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);

    test_ssl_memio_cleanup(&test_ctx);
    return EXPECT_RESULT();
}
#endif /* WOLFSSL_TLS13 && HAVE_ECH && WOLFSSL_TEST_ECH &&
        * HAVE_SSL_MEMIO_TESTS_DEPENDENCIES && !WOLFSSL_NO_TLS12 */

#endif /* HAVE_ECH && WOLFSSL_TLS13 */

#if defined(HAVE_IO_TESTS_DEPENDENCIES) && \
defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
    defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
static int post_auth_version_cb(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    /* do handshake and then test version error */
    ExpectIntEQ(wolfSSL_accept(ssl), WOLFSSL_SUCCESS);
    ExpectStrEQ("TLSv1.2", wolfSSL_get_version(ssl));
    return EXPECT_RESULT();
}

static int post_auth_version_client_cb(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    /* do handshake and then test version error */
    ExpectIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS);
    ExpectStrEQ("TLSv1.2", wolfSSL_get_version(ssl));
    ExpectIntEQ(wolfSSL_verify_client_post_handshake(ssl), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#if defined(OPENSSL_ALL) && !defined(NO_ERROR_QUEUE)
    /* check was added to error queue */
    ExpectIntEQ(wolfSSL_ERR_get_error(), -WC_NO_ERR_TRACE(UNSUPPORTED_PROTO_VERSION));

    /* check the string matches expected string */
    #ifndef NO_ERROR_STRINGS
    ExpectStrEQ(wolfSSL_ERR_error_string(-WC_NO_ERR_TRACE(UNSUPPORTED_PROTO_VERSION), NULL),
            "WRONG_SSL_VERSION");
    #endif
#endif
    return EXPECT_RESULT();
}

static int post_auth_cb(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    WOLFSSL_X509* x509 = NULL;
    /* do handshake and then test version error */
    ExpectIntEQ(wolfSSL_accept(ssl), WOLFSSL_SUCCESS);
    ExpectStrEQ("TLSv1.3", wolfSSL_get_version(ssl));
    ExpectNull(x509 = wolfSSL_get_peer_certificate(ssl));
    wolfSSL_X509_free(x509);
    ExpectIntEQ(wolfSSL_verify_client_post_handshake(ssl), WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}

static int set_post_auth_cb(WOLFSSL* ssl)
{
    if (!wolfSSL_is_server(ssl)) {
        EXPECT_DECLS;
        ExpectIntEQ(wolfSSL_allow_post_handshake_auth(ssl), 0);
        return EXPECT_RESULT();
    }
    wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_POST_HANDSHAKE, NULL);
    return TEST_SUCCESS;
}
#endif

static int test_wolfSSL_Tls13_postauth(void)
{
    EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && \
    defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
    defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
    test_ssl_cbf server_cbf;
    test_ssl_cbf client_cbf;

    /* test version failure doing post auth with TLS 1.2 connection */
    XMEMSET(&server_cbf, 0, sizeof(server_cbf));
    XMEMSET(&client_cbf, 0, sizeof(client_cbf));
    server_cbf.method = wolfTLSv1_2_server_method;
    server_cbf.ssl_ready = set_post_auth_cb;
    server_cbf.on_result = post_auth_version_cb;
    client_cbf.ssl_ready = set_post_auth_cb;
    client_cbf.on_result = post_auth_version_client_cb;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
        &server_cbf, NULL), TEST_SUCCESS);

    /* tests on post auth with TLS 1.3 */
    XMEMSET(&server_cbf, 0, sizeof(server_cbf));
    XMEMSET(&client_cbf, 0, sizeof(client_cbf));
    server_cbf.method = wolfTLSv1_3_server_method;
    server_cbf.ssl_ready = set_post_auth_cb;
    client_cbf.ssl_ready = set_post_auth_cb;
    server_cbf.on_result = post_auth_cb;
    client_cbf.on_result = NULL;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
        &server_cbf, NULL), TEST_SUCCESS);
#endif
    return EXPECT_RESULT();
}


static int test_wolfSSL_CTX_set_srp_username(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) && \
    !defined(NO_SHA256) && !defined(WC_NO_RNG) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;
    const char *username = "TESTUSER";
    const char *password = "TESTPASSWORD";

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectIntEQ(wolfSSL_CTX_set_srp_username(ctx, (char *)username),
         SSL_SUCCESS);
    wolfSSL_CTX_free(ctx);
    ctx = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectIntEQ(wolfSSL_CTX_set_srp_password(ctx, (char *)password),
        SSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_set_srp_username(ctx, (char *)username),
        SSL_SUCCESS);

    ExpectNotNull(ssl = SSL_new(ctx));
    ExpectNotNull(SSL_get_srp_username(ssl));
    ExpectStrEQ(SSL_get_srp_username(ssl), username);

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif /* OPENSSL_EXTRA && WOLFCRYPT_HAVE_SRP */
       /* && !NO_SHA256 && !WC_NO_RNG && !NO_WOLFSSL_CLIENT */
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_set_srp_password(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) && \
    !defined(NO_SHA256) && !defined(WC_NO_RNG) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL_CTX* ctx = NULL;
    const char *username = "TESTUSER";
    const char *password = "TESTPASSWORD";

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectIntEQ(wolfSSL_CTX_set_srp_password(ctx, (char *)password),
        SSL_SUCCESS);
    wolfSSL_CTX_free(ctx);
    ctx = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectIntEQ(wolfSSL_CTX_set_srp_username(ctx, (char *)username),
        SSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_set_srp_password(ctx, (char *)password),
        SSL_SUCCESS);
    wolfSSL_CTX_free(ctx);
#endif /* OPENSSL_EXTRA && WOLFCRYPT_HAVE_SRP */
       /* && !NO_SHA256 && !WC_NO_RNG && !NO_WOLFSSL_CLIENT */
    return EXPECT_RESULT();
}

#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_TLS) && \
   !defined(NO_FILESYSTEM) && !defined(NO_RSA)
#define TEST_ARG 0x1234
static void msg_cb(int write_p, int version, int content_type,
                   const void *buf, size_t len, SSL *ssl, void *arg)
{
    (void)write_p;
    (void)version;
    (void)content_type;
    (void)buf;
    (void)len;
    (void)ssl;

    AssertTrue(arg == (void*)TEST_ARG);
}
#endif

#if defined(OPENSSL_EXTRA) && defined(DEBUG_WOLFSSL) && \
      defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
#if defined(SESSION_CERTS)
#include "wolfssl/internal.h"
#endif
static int msgSrvCb(SSL_CTX *ctx, SSL *ssl)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && defined(SESSION_CERTS) && !defined(NO_BIO)
    STACK_OF(X509)* sk = NULL;
    X509* x509 = NULL;
    int i, num;
    BIO* bio = NULL;
#endif

    ExpectNotNull(ctx);
    ExpectNotNull(ssl);

    fprintf(stderr, "\n===== msgSrvCb called ====\n");
#if defined(SESSION_CERTS) && defined(TEST_PEER_CERT_CHAIN)
    ExpectTrue(SSL_get_peer_cert_chain(ssl) != NULL);
    ExpectIntEQ(((WOLFSSL_X509_CHAIN *)SSL_get_peer_cert_chain(ssl))->count, 2);
    ExpectNotNull(SSL_get0_verified_chain(ssl));
#endif

#if defined(OPENSSL_ALL) && defined(SESSION_CERTS) && !defined(NO_BIO)
#ifdef KEEP_PEER_CERT
    {
        WOLFSSL_X509* peer = NULL;
        ExpectNotNull(peer= wolfSSL_get_peer_certificate(ssl));
        ExpectNotNull(bio = BIO_new_fp(stderr, BIO_NOCLOSE));
        fprintf(stderr, "Peer Certificate = :\n");
        X509_print(bio, peer);
        X509_free(peer);
    }
#endif

    ExpectNotNull(sk = SSL_get_peer_cert_chain(ssl));
    if (sk == NULL) {
        BIO_free(bio);
        return TEST_FAIL;
    }
    num = sk_X509_num(sk);
    ExpectTrue(num > 0);
    for (i = 0; i < num; i++) {
        ExpectNotNull(x509 = sk_X509_value(sk,i));
        if (x509 == NULL)
            break;
        fprintf(stderr, "Certificate at index [%d] = :\n",i);
        X509_print(bio,x509);
        fprintf(stderr, "\n\n");
    }
    BIO_free(bio);
#endif
    return EXPECT_RESULT();
}

static int msgCb(SSL_CTX *ctx, SSL *ssl)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && defined(SESSION_CERTS) && !defined(NO_BIO)
    STACK_OF(X509)* sk = NULL;
    X509* x509 = NULL;
    int i, num;
    BIO* bio = NULL;
#endif

    ExpectNotNull(ctx);
    ExpectNotNull(ssl);

    fprintf(stderr, "\n===== msgcb called ====\n");
#if defined(SESSION_CERTS) && defined(TEST_PEER_CERT_CHAIN)
    ExpectTrue(SSL_get_peer_cert_chain(ssl) != NULL);
    ExpectIntEQ(((WOLFSSL_X509_CHAIN *)SSL_get_peer_cert_chain(ssl))->count, 2);
    ExpectNotNull(SSL_get0_verified_chain(ssl));
#endif

#if defined(OPENSSL_ALL) && defined(SESSION_CERTS) && !defined(NO_BIO)
    ExpectNotNull(bio = BIO_new_fp(stderr, BIO_NOCLOSE));
    ExpectNotNull(sk = SSL_get_peer_cert_chain(ssl));
    if (sk == NULL) {
        BIO_free(bio);
        return TEST_FAIL;
    }
    num = sk_X509_num(sk);
    ExpectTrue(num > 0);
    for (i = 0; i < num; i++) {
        ExpectNotNull(x509 = sk_X509_value(sk,i));
        if (x509 == NULL)
            break;
        fprintf(stderr, "Certificate at index [%d] = :\n",i);
        X509_print(bio,x509);
        fprintf(stderr, "\n\n");
    }
    BIO_free(bio);
#endif
    return EXPECT_RESULT();
}
#endif

static int test_wolfSSL_msgCb(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(DEBUG_WOLFSSL) && \
      defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
    test_ssl_cbf client_cb;
    test_ssl_cbf server_cb;

    XMEMSET(&client_cb, 0, sizeof(client_cb));
    XMEMSET(&server_cb, 0, sizeof(server_cb));
#ifndef WOLFSSL_NO_TLS12
    client_cb.method  = wolfTLSv1_2_client_method;
    server_cb.method  = wolfTLSv1_2_server_method;
#else
    client_cb.method  = wolfTLSv1_3_client_method;
    server_cb.method  = wolfTLSv1_3_server_method;
#endif
    server_cb.caPemFile = caCertFile;
    client_cb.certPemFile = "./certs/intermediate/client-chain.pem";

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio_ex(&client_cb,
        &server_cb, msgCb, msgSrvCb), TEST_SUCCESS);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_either_side(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)) && \
    defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
    test_ssl_cbf client_cb;
    test_ssl_cbf server_cb;

    XMEMSET(&client_cb, 0, sizeof(client_cb));
    XMEMSET(&server_cb, 0, sizeof(server_cb));

    /* Use different CTX for client and server */
    client_cb.ctx = wolfSSL_CTX_new(wolfSSLv23_method());
    ExpectNotNull(client_cb.ctx);
    server_cb.ctx = wolfSSL_CTX_new(wolfSSLv23_method());
    ExpectNotNull(server_cb.ctx);
    /* we are responsible for free'ing WOLFSSL_CTX */
    server_cb.isSharedCtx = client_cb.isSharedCtx = 1;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cb,
        &server_cb, NULL), TEST_SUCCESS);

    wolfSSL_CTX_free(client_cb.ctx);
    wolfSSL_CTX_free(server_cb.ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_DTLS_either_side(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)) && \
    defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS)
    test_ssl_cbf client_cb;
    test_ssl_cbf server_cb;

    XMEMSET(&client_cb, 0, sizeof(client_cb));
    XMEMSET(&server_cb, 0, sizeof(server_cb));

    /* Use different CTX for client and server */
    client_cb.ctx = wolfSSL_CTX_new(wolfDTLS_method());
    ExpectNotNull(client_cb.ctx);
    server_cb.ctx = wolfSSL_CTX_new(wolfDTLS_method());
    ExpectNotNull(server_cb.ctx);
    /* we are responsible for free'ing WOLFSSL_CTX */
    server_cb.isSharedCtx = client_cb.isSharedCtx = 1;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cb,
        &server_cb, NULL), TEST_SUCCESS);

    wolfSSL_CTX_free(client_cb.ctx);
    wolfSSL_CTX_free(server_cb.ctx);
#endif
    return EXPECT_RESULT();
}

static int test_generate_cookie(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_DTLS) && defined(OPENSSL_EXTRA) && defined(USE_WOLFSSL_IO)
    SSL_CTX* ctx = NULL;
    SSL* ssl = NULL;
    byte    buf[FOURK_BUF] = {0};

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLS_method()));
    ExpectNotNull(ssl = SSL_new(ctx));

    /* Test unconnected */
    ExpectIntEQ(EmbedGenerateCookie(ssl, buf, FOURK_BUF, NULL), WC_NO_ERR_TRACE(GEN_COOKIE_E));

    wolfSSL_CTX_SetGenCookie(ctx, EmbedGenerateCookie);

    wolfSSL_SetCookieCtx(ssl, ctx);

    ExpectNotNull(wolfSSL_GetCookieCtx(ssl));

    ExpectNull(wolfSSL_GetCookieCtx(NULL));

    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_set_options(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_TLS) && !defined(NO_FILESYSTEM) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)) && \
    !defined(NO_RSA)
    WOLFSSL*     ssl = NULL;
    WOLFSSL_CTX* ctx = NULL;
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
    char appData[] = "extra msg";
#endif
#ifdef OPENSSL_EXTRA
    unsigned char protos[] = {
        7, 't', 'l', 's', '/', '1', '.', '2',
        8, 'h', 't', 't', 'p', '/', '1', '.', '1'
    };
    unsigned int len = sizeof(protos);
    void *arg = (void *)TEST_ARG;
#endif

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#endif
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
                                                CERT_FILETYPE));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
                                               CERT_FILETYPE));

    ExpectTrue(wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1)
               == WOLFSSL_OP_NO_TLSv1);
    ExpectTrue(wolfSSL_CTX_get_options(ctx) == WOLFSSL_OP_NO_TLSv1);

    ExpectIntGT((int)wolfSSL_CTX_set_options(ctx, (WOLFSSL_OP_COOKIE_EXCHANGE |
                WOLFSSL_OP_NO_SSLv2)), 0);
    ExpectTrue((wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_COOKIE_EXCHANGE) &
                WOLFSSL_OP_COOKIE_EXCHANGE) == WOLFSSL_OP_COOKIE_EXCHANGE);
    ExpectTrue((wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_2) &
                WOLFSSL_OP_NO_TLSv1_2) == WOLFSSL_OP_NO_TLSv1_2);
    ExpectTrue((wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_COMPRESSION) &
                WOLFSSL_OP_NO_COMPRESSION) == WOLFSSL_OP_NO_COMPRESSION);
    ExpectFalse((wolfSSL_CTX_clear_options(ctx, WOLFSSL_OP_NO_COMPRESSION) &
                                           WOLFSSL_OP_NO_COMPRESSION));

    wolfSSL_CTX_free(ctx);
    ctx = NULL;

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#endif
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
                                               CERT_FILETYPE));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
                                               CERT_FILETYPE));
#ifdef OPENSSL_EXTRA
    ExpectTrue(wolfSSL_CTX_set_msg_callback(ctx, msg_cb) == WOLFSSL_SUCCESS);
#endif

    ExpectNotNull(ssl = wolfSSL_new(ctx));
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
#ifdef HAVE_EX_DATA
    ExpectIntEQ(wolfSSL_set_app_data(ssl, (void*)appData), WOLFSSL_SUCCESS);
    ExpectNotNull(wolfSSL_get_app_data((const WOLFSSL*)ssl));
    if (ssl != NULL) {
        ExpectIntEQ(XMEMCMP(wolfSSL_get_app_data((const WOLFSSL*)ssl),
                    appData, sizeof(appData)), 0);
    }
#else
    ExpectIntEQ(wolfSSL_set_app_data(ssl, (void*)appData), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectNull(wolfSSL_get_app_data((const WOLFSSL*)ssl));
#endif
#endif

    ExpectTrue(wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1) ==
                                   WOLFSSL_OP_NO_TLSv1);

    ExpectTrue(wolfSSL_get_options(ssl) == WOLFSSL_OP_NO_TLSv1);

    ExpectIntGT((int)wolfSSL_set_options(ssl, (WOLFSSL_OP_COOKIE_EXCHANGE |
                                         WOLFSSL_OP_NO_SSLv2)), 0);

    ExpectTrue((wolfSSL_set_options(ssl, WOLFSSL_OP_COOKIE_EXCHANGE) &
                WOLFSSL_OP_COOKIE_EXCHANGE) == WOLFSSL_OP_COOKIE_EXCHANGE);

    ExpectTrue((wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1_2) &
                WOLFSSL_OP_NO_TLSv1_2) == WOLFSSL_OP_NO_TLSv1_2);

    ExpectTrue((wolfSSL_set_options(ssl, WOLFSSL_OP_NO_COMPRESSION) &
               WOLFSSL_OP_NO_COMPRESSION) == WOLFSSL_OP_NO_COMPRESSION);

#ifdef OPENSSL_EXTRA
    ExpectFalse((wolfSSL_clear_options(ssl, WOLFSSL_OP_NO_COMPRESSION) &
                                       WOLFSSL_OP_NO_COMPRESSION));
#endif

#ifdef OPENSSL_EXTRA
    ExpectTrue(wolfSSL_set_msg_callback(ssl, msg_cb) == WOLFSSL_SUCCESS);
    wolfSSL_set_msg_callback_arg(ssl, arg);
#ifdef WOLFSSL_ERROR_CODE_OPENSSL
    ExpectTrue(wolfSSL_CTX_set_alpn_protos(ctx, protos, len) == 0);
#else
    ExpectTrue(wolfSSL_CTX_set_alpn_protos(ctx, protos, len) == WOLFSSL_SUCCESS);
#endif
#endif

#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \
    defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_ALL) || \
    defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL)

#if defined(HAVE_ALPN) && !defined(NO_BIO)

#ifdef WOLFSSL_ERROR_CODE_OPENSSL
    ExpectTrue(wolfSSL_set_alpn_protos(ssl, protos, len) == 0);
#else
    ExpectTrue(wolfSSL_set_alpn_protos(ssl, protos, len) == WOLFSSL_SUCCESS);
#endif

#endif /* HAVE_ALPN && !NO_BIO */
#endif

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_sk_SSL_CIPHER(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_CERTS) && !defined(NO_TLS) && \
   !defined(NO_FILESYSTEM) && !defined(NO_RSA)
#if !defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)
    SSL*     ssl = NULL;
    SSL_CTX* ctx = NULL;
    STACK_OF(SSL_CIPHER) *sk = NULL;
    STACK_OF(SSL_CIPHER) *dupSk = NULL;

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
#endif
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, svrCertFile, SSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, SSL_FILETYPE_PEM));
    ExpectNotNull(ssl = SSL_new(ctx));
    ExpectNotNull(sk = SSL_get_ciphers(ssl));
    ExpectNotNull(dupSk = sk_SSL_CIPHER_dup(sk));
    ExpectIntGT(sk_SSL_CIPHER_num(sk), 0);
    ExpectIntEQ(sk_SSL_CIPHER_num(sk), sk_SSL_CIPHER_num(dupSk));

    /* error case because connection has not been established yet */
    ExpectIntEQ(sk_SSL_CIPHER_find(sk, SSL_get_current_cipher(ssl)), -1);
    sk_SSL_CIPHER_free(dupSk);

    /* sk is pointer to internal struct that should be free'd in SSL_free */
    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif /* !NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER */
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
         !defined(NO_FILESYSTEM) && !defined(NO_RSA) */
    return EXPECT_RESULT();
}

static int test_wolfSSL_set1_curves_list(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) && !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)) && \
    !defined(NO_FILESYSTEM)
    SSL*     ssl = NULL;
    SSL_CTX* ctx = NULL;

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
#endif
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, eccCertFile,
               SSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, eccKeyFile, SSL_FILETYPE_PEM));
    ExpectNotNull(ssl = SSL_new(ctx));

    ExpectIntEQ(SSL_CTX_set1_curves_list(ctx, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#ifdef HAVE_ECC
    ExpectIntEQ(SSL_CTX_set1_curves_list(ctx, "P-25X"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_CTX_set1_curves_list(ctx, "P-256"), WOLFSSL_SUCCESS);
#endif
#ifdef HAVE_CURVE25519
    ExpectIntEQ(SSL_CTX_set1_curves_list(ctx, "X25519"), WOLFSSL_SUCCESS);
#else
    ExpectIntEQ(SSL_CTX_set1_curves_list(ctx, "X25519"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif
#ifdef HAVE_CURVE448
    ExpectIntEQ(SSL_CTX_set1_curves_list(ctx, "X448"), WOLFSSL_SUCCESS);
#else
    ExpectIntEQ(SSL_CTX_set1_curves_list(ctx, "X448"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif

    ExpectIntEQ(SSL_set1_curves_list(ssl, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#ifdef HAVE_ECC
    ExpectIntEQ(SSL_set1_curves_list(ssl, "P-25X"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_set1_curves_list(ssl, "P-256"), WOLFSSL_SUCCESS);
#endif

#ifdef HAVE_CURVE25519
    ExpectIntEQ(SSL_set1_curves_list(ssl, "X25519"), WOLFSSL_SUCCESS);
#else
    ExpectIntEQ(SSL_set1_curves_list(ssl, "X25519"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif
#ifdef HAVE_CURVE448
    ExpectIntEQ(SSL_set1_curves_list(ssl, "X448"), WOLFSSL_SUCCESS);
#else
    ExpectIntEQ(SSL_set1_curves_list(ssl, "X448"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif

    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
        (defined(OPENSSL_EXTRA) || defined(HAVE_CURL)) && defined(HAVE_ECC)
static int test_wolfSSL_curves_mismatch_ctx_ready(WOLFSSL_CTX* ctx)
{
    static int counter = 0;
    EXPECT_DECLS;

    if (counter % 2) {
        ExpectIntEQ(wolfSSL_CTX_set1_curves_list(ctx, "P-256"),
                WOLFSSL_SUCCESS);
    }
    else {
        ExpectIntEQ(wolfSSL_CTX_set1_curves_list(ctx, "P-384"),
                WOLFSSL_SUCCESS);
    }

    /* Ciphersuites that require curves */
    wolfSSL_CTX_set_cipher_list(ctx, "TLS13-AES256-GCM-SHA384:"
            "TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES128-GCM-SHA256:"
            "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:"
            "ECDHE-ECDSA-AES128-GCM-SHA256:"
            "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:"
            "ECDHE-ECDSA-CHACHA20-POLY1305");

    counter++;
    return EXPECT_RESULT();
}
#endif

static int test_wolfSSL_curves_mismatch(void)
{
    EXPECT_DECLS;
#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
        (defined(OPENSSL_EXTRA) || defined(HAVE_CURL)) && defined(HAVE_ECC)
    test_ssl_cbf func_cb_client;
    test_ssl_cbf func_cb_server;
    size_t i;
    struct {
        method_provider client_meth;
        method_provider server_meth;
        const char* desc;
        int client_last_err;
        int server_last_err;
    } test_params[] = {
#ifdef WOLFSSL_TLS13
        {wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLS 1.3",
                /* Client gets error because server will attempt HRR */
                WC_NO_ERR_TRACE(BAD_KEY_SHARE_DATA),
                WC_NO_ERR_TRACE(FATAL_ERROR)
        },
#endif
#ifndef WOLFSSL_NO_TLS12
        {wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLS 1.2",
                WC_NO_ERR_TRACE(FATAL_ERROR),
                /* Server gets error because <=1.2 doesn't have a mechanism
                 * to negotiate curves. */
#ifdef OPENSSL_EXTRA
                WC_NO_ERR_TRACE(WOLFSSL_ERROR_SYSCALL)
#else
                WC_NO_ERR_TRACE(MATCH_SUITE_ERROR)
#endif
        },
#endif
#ifndef NO_OLD_TLS
        {wolfTLSv1_1_client_method, wolfTLSv1_1_server_method, "TLS 1.1",
                WC_NO_ERR_TRACE(FATAL_ERROR),
#ifdef OPENSSL_EXTRA
                WC_NO_ERR_TRACE(WOLFSSL_ERROR_SYSCALL)
#else
                WC_NO_ERR_TRACE(MATCH_SUITE_ERROR)
#endif
        },
#endif
    };

    for (i = 0; i < XELEM_CNT(test_params) && !EXPECT_FAIL(); i++) {
        XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
        XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));

        printf("\tTesting with %s...\n", test_params[i].desc);

        func_cb_client.ctx_ready = &test_wolfSSL_curves_mismatch_ctx_ready;
        func_cb_server.ctx_ready = &test_wolfSSL_curves_mismatch_ctx_ready;

        func_cb_client.method = test_params[i].client_meth;
        func_cb_server.method = test_params[i].server_meth;

        ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
            &func_cb_server, NULL), -1001);
        ExpectIntEQ(func_cb_client.last_err, test_params[i].client_last_err);
        ExpectIntEQ(func_cb_server.last_err, test_params[i].server_last_err);

        if (!EXPECT_SUCCESS())
            break;
        printf("\t%s passed\n", test_params[i].desc);
    }
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_set1_sigalgs_list(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_RSA) && \
    !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)) && \
    !defined(NO_FILESYSTEM)
    SSL*     ssl = NULL;
    SSL_CTX* ctx = NULL;

#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
#endif
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, svrCertFile,
               SSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, SSL_FILETYPE_PEM));
    ExpectNotNull(ssl = SSL_new(ctx));

    ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(NULL, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_set1_sigalgs_list(NULL, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, ""), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, ""), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

#ifndef NO_RSA
    #ifndef NO_SHA256
        ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(NULL, "RSA+SHA256"),
                    WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
        ExpectIntEQ(wolfSSL_set1_sigalgs_list(NULL, "RSA+SHA256"),
                    WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

        ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "RSA+SHA256"),
                    WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "RSA+SHA256"),
                    WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "RSA-SHA256"),
                    WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
        ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "RSA-SHA256"),
                    WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
        #ifdef WC_RSA_PSS
            ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "RSA-PSS+SHA256"),
                        WOLFSSL_SUCCESS);
            ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "RSA-PSS+SHA256"),
                        WOLFSSL_SUCCESS);
            ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "PSS+SHA256"),
                        WOLFSSL_SUCCESS);
            ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "PSS+SHA256"),
                        WOLFSSL_SUCCESS);
        #endif
        #ifdef WOLFSSL_SHA512
            ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx,
                       "RSA+SHA256:RSA+SHA512"), WOLFSSL_SUCCESS);
            ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl,
                       "RSA+SHA256:RSA+SHA512"), WOLFSSL_SUCCESS);
        #elif defined(WOLFSSL_SHA384)
            ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx,
                       "RSA+SHA256:RSA+SHA384"), WOLFSSL_SUCCESS);
            ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl,
                       "RSA+SHA256:RSA+SHA384"), WOLFSSL_SUCCESS);
        #endif
        ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "RSA"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
        ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "RSA"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
        ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "RSA:RSA+SHA256"),
                    WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
        ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "RSA:RSA+SHA256"),
                    WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

        ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "RSA+SHA256+SHA256"),
                    WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
        ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "RSA+SHA256+RSA"),
                    WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

        {
            const char entry[] = "RSA+SHA256";
            const int entryLen = (int)sizeof(entry) - 1;
            const int entries = WOLFSSL_MAX_SIGALGO + 1;
            int listSz = entries * (entryLen + 1);
            char* longList = (char*)XMALLOC(listSz, NULL,
                DYNAMIC_TYPE_TMP_BUFFER);
            int i;
            int pos = 0;

            ExpectNotNull(longList);
            if (longList != NULL) {
                for (i = 0; i < entries; i++) {
                    if (i != 0)
                        longList[pos++] = ':';
                    XMEMCPY(longList + pos, entry, entryLen);
                    pos += entryLen;
                }
                longList[pos] = '\0';
                ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, longList),
                    WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
                ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, longList),
                    WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
                XFREE(longList, NULL, DYNAMIC_TYPE_TMP_BUFFER);
            }
        }
    #endif
#endif
#ifdef HAVE_ECC
    #ifndef NO_SHA256
        ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "ECDSA+SHA256"),
                    WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "ECDSA+SHA256"),
            WOLFSSL_SUCCESS);
        #ifdef WOLFSSL_SHA512
            ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx,
                       "ECDSA+SHA256:ECDSA+SHA512"), WOLFSSL_SUCCESS);
            ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl,
                       "ECDSA+SHA256:ECDSA+SHA512"), WOLFSSL_SUCCESS);
        #elif defined(WOLFSSL_SHA384)
            ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx,
                       "ECDSA+SHA256:ECDSA+SHA384"), WOLFSSL_SUCCESS);
            ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl,
                       "ECDSA+SHA256:ECDSA+SHA384"), WOLFSSL_SUCCESS);
        #endif
    #endif
#endif
#ifdef HAVE_ED25519
    ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "ED25519"), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "ED25519"), WOLFSSL_SUCCESS);
#endif
#ifdef HAVE_ED448
    ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "ED448"), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "ED448"), WOLFSSL_SUCCESS);
#endif
#ifndef NO_DSA
    #ifndef NO_SHA256
        ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "DSA+SHA256"),
                    WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "DSA+SHA256"),
                    WOLFSSL_SUCCESS);
    #endif
    #if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || \
                                                defined(WOLFSSL_ALLOW_TLS_SHA1))
        ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "DSA+SHA1"),
                    WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "DSA+SHA1"),
                    WOLFSSL_SUCCESS);
    #endif
#endif

    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

/* Testing  wolfSSL_set_tlsext_status_type function.
 * PRE: OPENSSL and HAVE_CERTIFICATE_STATUS_REQUEST defined.
 */
static int test_wolfSSL_set_tlsext_status_type(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
    !defined(NO_RSA) && !defined(NO_WOLFSSL_SERVER)
    SSL*     ssl = NULL;
    SSL_CTX* ctx = NULL;

    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
    ExpectTrue(SSL_CTX_use_certificate_file(ctx, svrCertFile,
        SSL_FILETYPE_PEM));
    ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, SSL_FILETYPE_PEM));
    ExpectNotNull(ssl = SSL_new(ctx));
    ExpectIntEQ(SSL_set_tlsext_status_type(ssl,TLSEXT_STATUSTYPE_ocsp),
        SSL_SUCCESS);
    ExpectIntEQ(SSL_get_tlsext_status_type(ssl), TLSEXT_STATUSTYPE_ocsp);
    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif  /* OPENSSL_EXTRA && HAVE_CERTIFICATE_STATUS_REQUEST && !NO_RSA */
    return EXPECT_RESULT();
}


static int test_wolfSSL_a2i_IPADDRESS(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(WOLFSSL_USER_IO)
    const unsigned char* data = NULL;
    int dataSz = 0;
    ASN1_OCTET_STRING *st = NULL;

    const unsigned char ipv4_exp[] = {0x7F, 0, 0, 1};
    const unsigned char ipv6_exp[] = {
        0x20, 0x21, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x77, 0x77
    };
    const unsigned char ipv6_home[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
    };

    ExpectNull(st = a2i_IPADDRESS("127.0.0.1bad"));
    ExpectNotNull(st = a2i_IPADDRESS("127.0.0.1"));
    ExpectNotNull(data = ASN1_STRING_get0_data(st));
    ExpectIntEQ(dataSz = ASN1_STRING_length(st), WOLFSSL_IP4_ADDR_LEN);
    ExpectIntEQ(XMEMCMP(data, ipv4_exp, dataSz), 0);
    ASN1_STRING_free(st);
    st = NULL;

    ExpectNotNull(st = a2i_IPADDRESS("::1"));
    ExpectNotNull(data = ASN1_STRING_get0_data(st));
    ExpectIntEQ(dataSz = ASN1_STRING_length(st), WOLFSSL_IP6_ADDR_LEN);
    ExpectIntEQ(XMEMCMP(data, ipv6_home, dataSz), 0);
    ASN1_STRING_free(st);
    st = NULL;

    ExpectNotNull(st = a2i_IPADDRESS("2021:db8::ff00:42:7777"));
    ExpectNotNull(data = ASN1_STRING_get0_data(st));
    ExpectIntEQ(dataSz = ASN1_STRING_length(st), WOLFSSL_IP6_ADDR_LEN);
    ExpectIntEQ(XMEMCMP(data, ipv6_exp, dataSz), 0);
    ASN1_STRING_free(st);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_X509_ALGOR_get0(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_ALL) || defined(WOLFSSL_APACHE_HTTPD)) && \
    !defined(NO_SHA256) && !defined(NO_RSA)
    X509* x509 = NULL;
    const ASN1_OBJECT* obj = NULL;
    const X509_ALGOR* alg = NULL;
    X509_ALGOR* alg2 = NULL;
    int pptype = 0;
    const void *ppval = NULL;
    byte* der = NULL;
    const byte* tmp = NULL;
    const byte badObj[] = { 0x06, 0x00 };

    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(cliCertFile,
        SSL_FILETYPE_PEM));
    ExpectNotNull(alg = X509_get0_tbs_sigalg(x509));

    /* Invalid case */
    X509_ALGOR_get0(&obj, NULL, NULL, NULL);
    ExpectNull(obj);

    /* Valid case */
    X509_ALGOR_get0(NULL, NULL, NULL, alg);
    X509_ALGOR_get0(&obj, &pptype, &ppval, alg);
    ExpectNotNull(obj);
    ExpectNull(ppval);
    ExpectIntNE(pptype, 0);
    /* Make sure NID of X509_ALGOR is Sha256 with RSA */
    ExpectIntEQ(OBJ_obj2nid(obj), NID_sha256WithRSAEncryption);

    ExpectIntEQ(i2d_X509_ALGOR(NULL, NULL), WOLFSSL_FATAL_ERROR);
    ExpectIntEQ(i2d_X509_ALGOR(alg, &der), 15);
    ExpectNull(d2i_X509_ALGOR(NULL, NULL, 0));
    /* tmp is NULL. */
    ExpectNull(d2i_X509_ALGOR(NULL, &tmp, 0));
    tmp = badObj;
    ExpectNull(d2i_X509_ALGOR(NULL, &tmp, (long)sizeof(badObj)));
    tmp = der;
    ExpectNull(d2i_X509_ALGOR(NULL, &tmp, 0));
    ExpectNotNull(d2i_X509_ALGOR(&alg2, &tmp, 15));
    tmp = der;
    ExpectNotNull(d2i_X509_ALGOR(&alg2, &tmp, 15));

    XFREE(der, NULL, DYNAMIC_TYPE_ASN1);
    X509_free(x509);
    X509_ALGOR_free(NULL);
    X509_ALGOR_free(alg2);
    alg2 = NULL;
#endif
    return EXPECT_RESULT();
}


#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(WOLFSSL_HOSTNAME_VERIFY_ALT_NAME_ONLY)

static int test_wolfSSL_check_domain_verify_count = 0;

static WC_INLINE int test_wolfSSL_check_domain_verify_cb(int preverify,
        WOLFSSL_X509_STORE_CTX* store)
{
    EXPECT_DECLS;
    ExpectIntEQ(X509_STORE_CTX_get_error(store), 0);
    ExpectIntEQ(preverify, 1);
    ExpectIntGT(++test_wolfSSL_check_domain_verify_count, 0);
    return EXPECT_SUCCESS();
}

static int test_wolfSSL_check_domain_client_cb(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    X509_VERIFY_PARAM *param = NULL;

    ExpectNotNull(param = SSL_get0_param(ssl));

    /* Domain check should only be done on the leaf cert */
    X509_VERIFY_PARAM_set_hostflags(param,
        X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
    ExpectIntEQ(X509_VERIFY_PARAM_set1_host(param,
        "wolfSSL Server Chain", 0), 1);
    wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_PEER,
        test_wolfSSL_check_domain_verify_cb);
    return EXPECT_RESULT();
}

static int test_wolfSSL_check_domain_server_cb(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    /* Use a cert with different domains in chain */
    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_file(ctx,
        "certs/intermediate/server-chain.pem"), WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}

static int test_wolfSSL_check_domain(void)
{
    EXPECT_DECLS;
    test_ssl_cbf func_cb_client;
    test_ssl_cbf func_cb_server;

    XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
    XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));

    func_cb_client.ssl_ready = &test_wolfSSL_check_domain_client_cb;
    func_cb_server.ctx_ready = &test_wolfSSL_check_domain_server_cb;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
        &func_cb_server, NULL), TEST_SUCCESS);

    /* Should have been called once for each cert in sent chain */
#ifdef WOLFSSL_VERIFY_CB_ALL_CERTS
    ExpectIntEQ(test_wolfSSL_check_domain_verify_count, 3);
#else
    ExpectIntEQ(test_wolfSSL_check_domain_verify_count, 1);
#endif

    return EXPECT_RESULT();
}

#else

static int test_wolfSSL_check_domain(void)
{
    EXPECT_DECLS;
    return EXPECT_RESULT();
}

#endif /* OPENSSL_EXTRA && HAVE_SSL_MEMIO_TESTS_DEPENDENCIES */
#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(OPENSSL_COMPATIBLE_DEFAULTS) && !defined(NO_SHA256)
static const char* dn = NULL;
static int test_wolfSSL_check_domain_basic_client_ssl(WOLFSSL* ssl)
{
    EXPECT_DECLS;

    ExpectIntEQ(wolfSSL_check_domain_name(ssl, dn), WOLFSSL_SUCCESS);

    return EXPECT_RESULT();
}
/* Verify wolfSSL_check_domain_name() controls DNS-name matching during
 * handshake with expected fail/pass outcomes. */
static int test_wolfSSL_check_domain_basic(void)
{
    EXPECT_DECLS;
    test_ssl_cbf func_cb_client;
    test_ssl_cbf func_cb_server;

    XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
    XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));

    dn = "invalid.com";
    func_cb_client.ssl_ready = &test_wolfSSL_check_domain_basic_client_ssl;

    /* Expect to fail */
    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
        &func_cb_server, NULL), -1001);

    dn = "example.com";

    /* Expect to succeed */
    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
        &func_cb_server, NULL), TEST_SUCCESS);

    return EXPECT_RESULT();
}
#else
static int test_wolfSSL_check_domain_basic(void)
{
    EXPECT_DECLS;
    return EXPECT_RESULT();
}
#endif /* HAVE_SSL_MEMIO_TESTS_DEPENDENCIES */

#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    (defined(WOLFSSL_IP_ALT_NAME) || defined(OPENSSL_ALL)) && \
    !defined(OPENSSL_COMPATIBLE_DEFAULTS) && !defined(NO_SHA256)
static const char* ipaddr = NULL;
static int test_wolfSSL_check_ip_param_client_ssl(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    X509_VERIFY_PARAM* param = NULL;

    ExpectNotNull(param = SSL_get0_param(ssl));
    ExpectIntEQ(X509_VERIFY_PARAM_set1_ip_asc(param, ipaddr), WOLFSSL_SUCCESS);

    return EXPECT_RESULT();
}

/* Verify the OpenSSL-compat verify-param path:
 * SSL_get0_param() + X509_VERIFY_PARAM_set1_ip_asc() controls IP SAN matching
 * during handshake. */
static int test_wolfSSL_check_ip_param_basic(void)
{
    EXPECT_DECLS;
    test_ssl_cbf func_cb_client;
    test_ssl_cbf func_cb_server;

    XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
    XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));

    func_cb_client.ssl_ready = &test_wolfSSL_check_ip_param_client_ssl;

    ipaddr = "127.0.0.2";
    /* Expect to fail: cert SAN IP is 127.0.0.1 */
    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
        &func_cb_server, NULL), -1001);

    ipaddr = "127.0.0.1";
    /* Expect to succeed */
    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
        &func_cb_server, NULL), TEST_SUCCESS);

    return EXPECT_RESULT();
}
#else
static int test_wolfSSL_check_ip_param_basic(void)
{
    EXPECT_DECLS;
    return EXPECT_RESULT();
}
#endif

#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(OPENSSL_COMPATIBLE_DEFAULTS) && !defined(NO_SHA256) && \
    defined(WOLFSSL_IP_ALT_NAME)
static const char* ipaddr_api = NULL;
static int test_wolfSSL_check_ip_address_basic_client_ssl(WOLFSSL* ssl)
{
    EXPECT_DECLS;

    ExpectIntEQ(wolfSSL_check_ip_address(ssl, ipaddr_api), WOLFSSL_SUCCESS);

    return EXPECT_RESULT();
}

/* Verify wolfSSL convenience API path:
 * wolfSSL_check_ip_address() enables IP SAN matching during handshake,
 * including the non-OPENSSL_EXTRA storage/verification flow. */
static int test_wolfSSL_check_ip_address_basic(void)
{
    EXPECT_DECLS;
    test_ssl_cbf func_cb_client;
    test_ssl_cbf func_cb_server;

    XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
    XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));

    func_cb_client.ssl_ready = &test_wolfSSL_check_ip_address_basic_client_ssl;

    ipaddr_api = "127.0.0.2";
    /* Expect to fail: cert SAN IP is 127.0.0.1 */
    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
        &func_cb_server, NULL), -1001);

    ipaddr_api = "127.0.0.1";
    /* Expect to succeed */
    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
        &func_cb_server, NULL), TEST_SUCCESS);

    return EXPECT_RESULT();
}
#else
static int test_wolfSSL_check_ip_address_basic(void)
{
    EXPECT_DECLS;
    return EXPECT_RESULT();
}
#endif

static int test_wolfSSL_BUF(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    BUF_MEM* buf = NULL;
    ExpectNotNull(buf = BUF_MEM_new());
    ExpectIntEQ(BUF_MEM_grow(buf, 10), 10);
    ExpectIntEQ(BUF_MEM_grow(buf, -1), 0);
    BUF_MEM_free(buf);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_PKCS8_Compat(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && defined(HAVE_ECC) && \
    !defined(NO_BIO)
    PKCS8_PRIV_KEY_INFO* pt = NULL;
    PKCS8_PRIV_KEY_INFO* pt2 = NULL;
    BIO* bio = NULL;
    XFILE f = XBADFILE;
    int bytes = 0;
    char pkcs8_buffer[512];
#if defined(OPENSSL_ALL) || defined(WOLFSSL_WPAS_SMALL)
    EVP_PKEY *pkey = NULL;
#endif

    /* file from wolfssl/certs/ directory */
    ExpectTrue((f = XFOPEN("./certs/ecc-keyPkcs8.pem", "rb")) != XBADFILE);
    ExpectIntGT((bytes = (int)XFREAD(pkcs8_buffer, 1, sizeof(pkcs8_buffer), f)),
        0);
    if (f != XBADFILE)
        XFCLOSE(f);
    ExpectNotNull(bio = BIO_new_mem_buf((void*)pkcs8_buffer, bytes));
    ExpectNotNull(pt = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL));

#if defined(OPENSSL_ALL) || defined(WOLFSSL_WPAS_SMALL)
    ExpectNotNull(pkey = EVP_PKCS82PKEY(pt));
    ExpectIntEQ(EVP_PKEY_type(pkey->type), EVP_PKEY_EC);

    /* gets PKCS8 pointer to pkey */
    ExpectNotNull(pt2 = EVP_PKEY2PKCS8(pkey));

    EVP_PKEY_free(pkey);
#endif

    BIO_free(bio);
    PKCS8_PRIV_KEY_INFO_free(pt);
    PKCS8_PRIV_KEY_INFO_free(pt2);
#endif
    return EXPECT_RESULT();
}

#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_BIO)
static int NoPasswordCallBack(char* passwd, int sz, int rw, void* userdata)
{
    (void)passwd;
    (void)sz;
    (void)rw;
    (void)userdata;

    return -1;
}
#endif

static int test_wolfSSL_PKCS8_d2i(void)
{
    EXPECT_DECLS;
#if !defined(HAVE_FIPS) && defined(OPENSSL_EXTRA)
    /* This test ends up using HMAC as a part of PBKDF2, and HMAC
     * requires a 12 byte password in FIPS mode. This test ends up
     * trying to use an 8 byte password. */

#ifndef NO_FILESYSTEM
    unsigned char pkcs8_buffer[2048];
    const unsigned char* p = NULL;
    int bytes = 0;
    XFILE file = XBADFILE;
    WOLFSSL_EVP_PKEY* pkey = NULL;
#ifndef NO_BIO
    BIO* bio = NULL;
    #if defined(OPENSSL_ALL) && \
            ((!defined(NO_RSA) && !defined(NO_DES3)) || \
               defined(HAVE_ECC)) && \
        !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8)
    WOLFSSL_EVP_PKEY* evpPkey = NULL;
    #endif
#endif
#ifndef NO_RSA
    const char rsaDerPkcs8File[] = "./certs/server-keyPkcs8.der";
    const char rsaPemPkcs8File[] = "./certs/server-keyPkcs8.pem";
    #ifndef NO_DES3
    const char rsaDerPkcs8EncFile[] = "./certs/server-keyPkcs8Enc.der";
    #endif
#endif /* NO_RSA */
#ifdef HAVE_ECC
    const char ecDerPkcs8File[] = "certs/ecc-keyPkcs8.der";
    const char ecPemPkcs8File[] = "certs/ecc-keyPkcs8.pem";
    #ifndef NO_DES3
    const char ecDerPkcs8EncFile[] = "certs/ecc-keyPkcs8Enc.der";
    #endif
#endif /* HAVE_ECC */
#endif /* !NO_FILESYSTEM */

#if defined(OPENSSL_ALL) && (!defined(NO_RSA) || defined(HAVE_ECC))
#ifndef NO_RSA
    #ifdef USE_CERT_BUFFERS_1024
    const unsigned char* rsa = (unsigned char*)server_key_der_1024;
    int rsaSz = sizeof_server_key_der_1024;
    #else
    const unsigned char* rsa = (unsigned char*)server_key_der_2048;
    int rsaSz = sizeof_server_key_der_2048;
    #endif
#endif
#ifdef HAVE_ECC
    const unsigned char* ec = (unsigned char*)ecc_key_der_256;
    int ecSz = sizeof_ecc_key_der_256;
#endif
#endif /* OPENSSL_ALL && (!NO_RSA || HAVE_ECC) */


#ifndef NO_FILESYSTEM
   (void)pkcs8_buffer;
   (void)p;
   (void)bytes;
   (void)file;
#ifndef NO_BIO
   (void)bio;
#endif
#endif

#ifdef OPENSSL_ALL
#ifndef NO_RSA
    /* Try to auto-detect normal RSA private key */
    ExpectNotNull(pkey = d2i_AutoPrivateKey(NULL, &rsa, rsaSz));
    EVP_PKEY_free(pkey);
    pkey = NULL;
#endif
#ifdef HAVE_ECC
    /* Try to auto-detect normal EC private key */
    ExpectNotNull(pkey = d2i_AutoPrivateKey(NULL, &ec, ecSz));
    EVP_PKEY_free(pkey);
    pkey = NULL;
#endif
#endif /* OPENSSL_ALL */

#ifndef NO_FILESYSTEM
#if defined(OPENSSL_ALL) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8)
    ExpectIntEQ(PEM_write_PKCS8PrivateKey(XBADFILE, pkey, NULL, NULL, 0, NULL,
        NULL), 0);
    ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, NULL, NULL, NULL, 0, NULL,
        NULL), 0);
#endif

#ifndef NO_RSA
    /* Get DER encoded RSA PKCS#8 data. */
    ExpectTrue((file = XFOPEN(rsaDerPkcs8File, "rb")) != XBADFILE);
    ExpectNotNull(XMEMSET(pkcs8_buffer, 0, sizeof(pkcs8_buffer)));
    ExpectIntGT((bytes = (int)XFREAD(pkcs8_buffer, 1, sizeof(pkcs8_buffer),
        file)), 0);
    if (file != XBADFILE) {
        XFCLOSE(file);
        file = XBADFILE;
    }

    p = pkcs8_buffer;
#ifdef OPENSSL_ALL
    /* Try to decode - auto-detect key type. */
    ExpectNotNull(pkey = d2i_AutoPrivateKey(NULL, &p, bytes));
#else
    ExpectNotNull(pkey = d2i_PrivateKey(EVP_PKEY_RSA, NULL, &p, bytes));
#endif

    /* Get PEM encoded RSA PKCS#8 data. */
    ExpectTrue((file = XFOPEN(rsaPemPkcs8File, "rb")) != XBADFILE);
    ExpectIntGT((bytes = (int)XFREAD(pkcs8_buffer, 1, sizeof(pkcs8_buffer),
        file)), 0);
    if (file != XBADFILE) {
        XFCLOSE(file);
        file = XBADFILE;
    }
#if defined(OPENSSL_ALL) && \
    !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8)
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(NULL, pkey, NULL, NULL, 0, NULL,
        NULL), 0);
    ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, NULL, NULL, NULL, 0, NULL,
        NULL), 0);
    /* Write PKCS#8 PEM to BIO. */
    ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, NULL, NULL, 0, NULL,
        NULL), bytes);
    /* Write PKCS#8 PEM to stderr. */
    ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, NULL, NULL, 0, NULL,
        NULL), bytes);
    /* Compare file and written data */
    ExpectIntEQ(BIO_get_mem_data(bio, &p), bytes);
    ExpectIntEQ(XMEMCMP(p, pkcs8_buffer, bytes), 0);
    BIO_free(bio);
    bio = NULL;
#if !defined(NO_AES) && defined(HAVE_AESGCM)
    ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, EVP_aes_128_gcm(),
        NULL, 0, PasswordCallBack, (void*)"yassl123"), 0);
#endif
#if !defined(NO_DES3) && !defined(NO_SHA)
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    /* Write Encrypted PKCS#8 PEM to BIO. */
    bytes = 1834;
    ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, EVP_des_ede3_cbc(),
        NULL, 0, PasswordCallBack, (void*)"yassl123"), bytes);
    ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, EVP_des_ede3_cbc(),
        NULL, 0, PasswordCallBack, (void*)"yassl123"), bytes);
    ExpectNotNull(evpPkey = PEM_read_bio_PrivateKey(bio, NULL, PasswordCallBack,
        (void*)"yassl123"));
    EVP_PKEY_free(evpPkey);
    evpPkey = NULL;
    BIO_free(bio);
    bio = NULL;
#endif /* !NO_DES3 && !NO_SHA */
#endif /* !NO_BIO && !NO_PWDBASED && HAVE_PKCS8 */
    EVP_PKEY_free(pkey);
    pkey = NULL;

    /* PKCS#8 encrypted RSA key */
#ifndef NO_DES3
    ExpectTrue((file = XFOPEN(rsaDerPkcs8EncFile, "rb")) != XBADFILE);
    ExpectNotNull(XMEMSET(pkcs8_buffer, 0, sizeof(pkcs8_buffer)));
    ExpectIntGT((bytes = (int)XFREAD(pkcs8_buffer, 1, sizeof(pkcs8_buffer),
        file)), 0);
    if (file != XBADFILE) {
        XFCLOSE(file);
        file = XBADFILE;
    }
#if defined(OPENSSL_ALL) && \
    !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8)
    ExpectNotNull(bio = BIO_new_mem_buf((void*)pkcs8_buffer, bytes));
    ExpectNotNull(pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, PasswordCallBack,
        (void*)"yassl123"));
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;
#endif /* OPENSSL_ALL && !NO_BIO && !NO_PWDBASED && HAVE_PKCS8 */
#endif /* !NO_DES3 */
#endif /* NO_RSA */

#ifdef HAVE_ECC
    /* PKCS#8 encode EC key */
    ExpectTrue((file = XFOPEN(ecDerPkcs8File, "rb")) != XBADFILE);
    ExpectNotNull(XMEMSET(pkcs8_buffer, 0, sizeof(pkcs8_buffer)));
    ExpectIntGT((bytes = (int)XFREAD(pkcs8_buffer, 1, sizeof(pkcs8_buffer),
        file)), 0);
    if (file != XBADFILE) {
        XFCLOSE(file);
        file = XBADFILE;
    }

    p = pkcs8_buffer;
#ifdef OPENSSL_ALL
    /* Try to decode - auto-detect key type. */
    ExpectNotNull(pkey = d2i_AutoPrivateKey(NULL, &p, bytes));
#else
    ExpectNotNull(pkey = d2i_PrivateKey(EVP_PKEY_EC, NULL, &p, bytes));
#endif

    /* Get PEM encoded RSA PKCS#8 data. */
    ExpectTrue((file = XFOPEN(ecPemPkcs8File, "rb")) != XBADFILE);
    ExpectNotNull(XMEMSET(pkcs8_buffer, 0, sizeof(pkcs8_buffer)));
    ExpectIntGT((bytes = (int)XFREAD(pkcs8_buffer, 1, sizeof(pkcs8_buffer),
        file)), 0);
    if (file != XBADFILE) {
        XFCLOSE(file);
        file = XBADFILE;
    }
#if defined(OPENSSL_ALL) && \
    !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8) && \
    defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    /* Write PKCS#8 PEM to BIO. */
    ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, NULL, NULL, 0, NULL,
        NULL), bytes);
    ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, NULL, NULL, 0, NULL,
        NULL), bytes);
    /* Compare file and written data */
    ExpectIntEQ(BIO_get_mem_data(bio, &p), bytes);
    ExpectIntEQ(XMEMCMP(p, pkcs8_buffer, bytes), 0);
    BIO_free(bio);
    bio = NULL;
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    /* Write Encrypted PKCS#8 PEM to BIO (test write 0 then 379) */
    bytes = 379;
    ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, EVP_aes_256_cbc(),
        NULL, 0, NoPasswordCallBack, (void*)"yassl123"), 0);
    ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, EVP_aes_256_cbc(),
        NULL, 0, PasswordCallBack, (void*)"yassl123"), bytes);

    /* invalid cases to stderr */
    #ifdef WOLFSSL_AES_128
    ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, EVP_aes_128_cbc(),
        NULL, 0, PasswordCallBack, (void*)"yassl123"), bytes);
    ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, EVP_aes_128_cbc(),
        (char*)"yassl123", 8, PasswordCallBack, NULL), bytes);
    #endif
    ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, EVP_aes_256_cbc(),
        NULL, 0, PasswordCallBack, (void*)"yassl123"), bytes);
    ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, EVP_aes_256_cbc(),
        (char*)"yassl123", 8, PasswordCallBack, NULL), bytes);

    /* read/decode private key with password */
    ExpectNotNull(evpPkey = PEM_read_bio_PrivateKey(bio, NULL, PasswordCallBack,
        (void*)"yassl123"));
    EVP_PKEY_free(evpPkey);
    evpPkey = NULL;
    BIO_free(bio);
    bio = NULL;

    /* https://github.com/wolfSSL/wolfssl/issues/8610 */
    bytes = (int)XSTRLEN((char *)pkcs8_buffer);
    ExpectNotNull(bio = BIO_new_mem_buf((void*)pkcs8_buffer, bytes));
    ExpectIntEQ(BIO_get_mem_data(bio, &p), bytes);
    ExpectIntEQ(XMEMCMP(p, pkcs8_buffer, bytes), 0);

    ExpectNotNull(evpPkey = PEM_read_bio_PrivateKey(bio, NULL, NULL,
            (void*)"yassl123"));
    ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, evpPkey, NULL,
            NULL, 0, NULL, NULL), bytes);
    EVP_PKEY_free(evpPkey);
    evpPkey = NULL;
    BIO_free(bio);
    bio = NULL;
#endif /* OPENSSL_ALL && !NO_BIO && !NO_PWDBASED && HAVE_PKCS8 && HAVE_AES_CBC */
    EVP_PKEY_free(pkey);
    pkey = NULL;

    /* PKCS#8 encrypted EC key */
#ifndef NO_DES3
    ExpectTrue((file = XFOPEN(ecDerPkcs8EncFile, "rb")) != XBADFILE);
    ExpectNotNull(XMEMSET(pkcs8_buffer, 0, sizeof(pkcs8_buffer)));
    ExpectIntGT((bytes = (int)XFREAD(pkcs8_buffer, 1, sizeof(pkcs8_buffer),
        file)), 0);
    if (file != XBADFILE) {
        XFCLOSE(file);
        file = XBADFILE;
    }
#if defined(OPENSSL_ALL) && \
    !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8)
    ExpectNotNull(bio = BIO_new_mem_buf((void*)pkcs8_buffer, bytes));
    ExpectNotNull(pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, PasswordCallBack,
                                                            (void*)"yassl123"));
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;
#endif /* OPENSSL_ALL && !NO_BIO && !NO_PWDBASED && HAVE_PKCS8 */
#endif /* !NO_DES3 */
#endif /* HAVE_ECC */

#endif /* !NO_FILESYSTEM */
#endif /* HAVE_FIPS && OPENSSL_EXTRA */
    return EXPECT_RESULT();
}

#if !defined(SINGLE_THREADED) && defined(ERROR_QUEUE_PER_THREAD) && \
    !defined(NO_ERROR_QUEUE) && defined(OPENSSL_EXTRA) && \
    defined(DEBUG_WOLFSSL)
#define LOGGING_THREADS 5
#define ERROR_COUNT 10
/* copied from logging.c since this is not exposed otherwise */
#ifndef ERROR_QUEUE_MAX
#ifdef ERROR_QUEUE_PER_THREAD
    #define ERROR_QUEUE_MAX 16
#else
    /* this breaks from compat of unlimited error queue size */
    #define ERROR_QUEUE_MAX 100
#endif
#endif

static volatile int loggingThreadsReady;
static THREAD_RETURN WOLFSSL_THREAD test_logging(void* args)
{
    const char* file;
    int line;
    unsigned long err;
    int errorCount = 0;
    int i;

    (void)args;

    while (!loggingThreadsReady);
    for (i = 0; i < ERROR_COUNT; i++)
        ERR_put_error(ERR_LIB_PEM, SYS_F_ACCEPT, -990 - i, __FILE__, __LINE__);

    while ((err = ERR_get_error_line(&file, &line))) {
        AssertIntEQ(err, 990 + errorCount);
        errorCount++;
    }
    AssertIntEQ(errorCount, ERROR_COUNT);

    /* test max queue behavior, trying to add an arbitrary 3 errors over */
    ERR_clear_error(); /* ERR_get_error_line() does not remove */
    errorCount = 0;
    for (i = 0; i < ERROR_QUEUE_MAX + 3; i++)
        ERR_put_error(ERR_LIB_PEM, SYS_F_ACCEPT, -990 - i, __FILE__, __LINE__);

    while ((err = ERR_get_error_line(&file, &line))) {
        AssertIntEQ(err, 990 + errorCount);
        errorCount++;
    }

    /* test that the 3 errors over the max were dropped */
    AssertIntEQ(errorCount, ERROR_QUEUE_MAX);

    WOLFSSL_RETURN_FROM_THREAD(0);
}
#endif

static int test_error_queue_per_thread(void)
{
    int res = TEST_SKIPPED;
#if !defined(SINGLE_THREADED) && defined(ERROR_QUEUE_PER_THREAD) && \
    !defined(NO_ERROR_QUEUE) && defined(OPENSSL_EXTRA) && \
    defined(DEBUG_WOLFSSL)
    THREAD_TYPE loggingThreads[LOGGING_THREADS];
    int i;

    ERR_clear_error(); /* clear out any error nodes */

    loggingThreadsReady = 0;
    for (i = 0; i < LOGGING_THREADS; i++)
        start_thread(test_logging, NULL, &loggingThreads[i]);
    loggingThreadsReady = 1;
    for (i = 0; i < LOGGING_THREADS; i++)
        join_thread(loggingThreads[i]);

    res = TEST_SUCCESS;
#endif
    return res;
}

static int test_wolfSSL_ERR_put_error(void)
{
    EXPECT_DECLS;
#if !defined(NO_ERROR_QUEUE) && defined(OPENSSL_EXTRA) && \
    defined(DEBUG_WOLFSSL)
    const char* file;
    int line;

    ERR_clear_error(); /* clear out any error nodes */
    ERR_put_error(0,SYS_F_ACCEPT, 0, "this file", 0);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 0);
    ERR_put_error(0,SYS_F_BIND, 1, "this file", 1);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 1);
    ERR_put_error(0,SYS_F_CONNECT, 2, "this file", 2);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 2);
    ERR_put_error(0,SYS_F_FOPEN, 3, "this file", 3);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 3);
    ERR_put_error(0,SYS_F_FREAD, 4, "this file", 4);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 4);
    ERR_put_error(0,SYS_F_GETADDRINFO, 5, "this file", 5);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 5);
    ERR_put_error(0,SYS_F_GETSOCKOPT, 6, "this file", 6);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 6);
    ERR_put_error(0,SYS_F_GETSOCKNAME, 7, "this file", 7);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 7);
    ERR_put_error(0,SYS_F_GETHOSTBYNAME, 8, "this file", 8);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 8);
    ERR_put_error(0,SYS_F_GETNAMEINFO, 9, "this file", 9);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 9);
    ERR_put_error(0,SYS_F_GETSERVBYNAME, 10, "this file", 10);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 10);
    ERR_put_error(0,SYS_F_IOCTLSOCKET, 11, "this file", 11);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 11);
    ERR_put_error(0,SYS_F_LISTEN, 12, "this file", 12);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 12);
    ERR_put_error(0,SYS_F_OPENDIR, 13, "this file", 13);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 13);
    ERR_put_error(0,SYS_F_SETSOCKOPT, 14, "this file", 14);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 14);
    ERR_put_error(0,SYS_F_SOCKET, 15, "this file", 15);
    ExpectIntEQ(ERR_get_error_line(&file, &line), 15);

#if defined(OPENSSL_ALL) && defined(WOLFSSL_PYTHON)
    ERR_put_error(ERR_LIB_ASN1, SYS_F_ACCEPT, ASN1_R_HEADER_TOO_LONG,
            "this file", 100);
    ExpectIntEQ(wolfSSL_ERR_peek_last_error_line(&file, &line),
            (ERR_LIB_ASN1 << 24) | ASN1_R_HEADER_TOO_LONG);
    ExpectIntEQ(line, 100);
    ExpectIntEQ(wolfSSL_ERR_peek_error(),
            (ERR_LIB_ASN1 << 24) | ASN1_R_HEADER_TOO_LONG);
    ExpectIntEQ(ERR_get_error_line(&file, &line), ASN1_R_HEADER_TOO_LONG);
#endif

    /* try reading past end of error queue */
    file = NULL;
    ExpectIntEQ(ERR_get_error_line(&file, &line), 0);
    ExpectNull(file);
    ExpectIntEQ(ERR_get_error_line_data(&file, &line, NULL, NULL), 0);

    PEMerr(4,4);
    ExpectIntEQ(ERR_get_error(), 4);
    /* Empty and free up all error nodes */
    ERR_clear_error();

    /* Verify all nodes are cleared */
    ERR_put_error(0,SYS_F_ACCEPT, 0, "this file", 0);
    ERR_clear_error();
    ExpectIntEQ(ERR_get_error_line(&file, &line), 0);
#endif
    return EXPECT_RESULT();
}

/*
 * This is a regression test for a bug where the peek/get error functions were
 * drawing from the end of the queue rather than the front.
 */
static int test_wolfSSL_ERR_get_error_order(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_ERROR_QUEUE) && defined(OPENSSL_EXTRA)
    /* Empty the queue. */
    wolfSSL_ERR_clear_error();

    wolfSSL_ERR_put_error(0, 0, WC_NO_ERR_TRACE(ASN_NO_SIGNER_E), "test", 0);
    wolfSSL_ERR_put_error(0, 0, WC_NO_ERR_TRACE(ASN_SELF_SIGNED_E), "test", 0);

    ExpectIntEQ(wolfSSL_ERR_peek_error(), -WC_NO_ERR_TRACE(ASN_NO_SIGNER_E));
    ExpectIntEQ(wolfSSL_ERR_get_error(), -WC_NO_ERR_TRACE(ASN_NO_SIGNER_E));
    ExpectIntEQ(wolfSSL_ERR_peek_error(), -WC_NO_ERR_TRACE(ASN_SELF_SIGNED_E));
    ExpectIntEQ(wolfSSL_ERR_get_error(), -WC_NO_ERR_TRACE(ASN_SELF_SIGNED_E));
#endif /* WOLFSSL_HAVE_ERROR_QUEUE && OPENSSL_EXTRA */
    return EXPECT_RESULT();
}

#ifndef NO_BIO

static int test_wolfSSL_ERR_print_errors(void)
{
    EXPECT_DECLS;
#if !defined(NO_ERROR_QUEUE) && defined(OPENSSL_EXTRA) && \
    defined(DEBUG_WOLFSSL) && !defined(NO_ERROR_STRINGS)
    BIO* bio = NULL;
    char buf[1024];

    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ERR_clear_error(); /* clear out any error nodes */
    ERR_put_error(0,SYS_F_ACCEPT, -173, "ssl.c", 0);
    /* Choosing -600 as an unused errno. */
    ERR_put_error(0,SYS_F_BIND, -600, "asn.c", 100);

    ERR_print_errors(bio);
    ExpectIntEQ(BIO_gets(bio, buf, sizeof(buf)), 56);
    ExpectIntEQ(XSTRNCMP(
        "error:173:wolfSSL library:Bad function argument:ssl.c:0",
        buf, 55), 0);
    ExpectIntEQ(BIO_gets(bio, buf, sizeof(buf)), 57);
    ExpectIntEQ(XSTRNCMP(
        "error:600:wolfSSL library:unknown error number:asn.c:100",
        buf, 56), 0);
    ExpectIntEQ(BIO_gets(bio, buf, sizeof(buf)), 1);
    ExpectIntEQ(buf[0], '\0');
    ExpectIntEQ(ERR_get_error_line(NULL, NULL), 0);

    BIO_free(bio);
#endif
    return EXPECT_RESULT();
}

#if !defined(NO_ERROR_QUEUE) && defined(OPENSSL_EXTRA) && \
    defined(DEBUG_WOLFSSL)
static int test_wolfSSL_error_cb(const char *str, size_t len, void *u)
{
    if (u != NULL) {
        wolfSSL_BIO_write((BIO*)u, str, (int)len);
    }
    return 0;
}
#endif

static int test_wolfSSL_ERR_print_errors_cb(void)
{
    EXPECT_DECLS;
#if !defined(NO_ERROR_QUEUE) && defined(OPENSSL_EXTRA) && \
    defined(DEBUG_WOLFSSL)
    BIO* bio = NULL;
    char buf[1024];

    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ERR_clear_error(); /* clear out any error nodes */
    ERR_put_error(0,SYS_F_ACCEPT, -173, "ssl.c", 0);
    ERR_put_error(0,SYS_F_BIND, -275, "asn.c", 100);

    ERR_print_errors_cb(test_wolfSSL_error_cb, bio);
    ExpectIntEQ(BIO_gets(bio, buf, sizeof(buf)), 108);
    ExpectIntEQ(XSTRNCMP(
        "wolfSSL error occurred, error = 173 line:0 file:ssl.c",
        buf, 53), 0);
    ExpectIntEQ(XSTRNCMP(
         "wolfSSL error occurred, error = 275 line:100 file:asn.c",
         buf + 53, 55), 0);
    ExpectIntEQ(BIO_gets(bio, buf, sizeof(buf)), 0);

    BIO_free(bio);
#endif

    return EXPECT_RESULT();
}
/*
 * Testing WOLFSSL_ERROR_MSG
 */
static int test_WOLFSSL_ERROR_MSG(void)
{
    int res = TEST_SKIPPED;
#if defined(DEBUG_WOLFSSL) || defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) ||\
    defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA)
    const char* msg = TEST_STRING;

    WOLFSSL_ERROR_MSG(msg);

    res = TEST_SUCCESS;
#endif
    return res;
} /* End test_WOLFSSL_ERROR_MSG */
/*
 * Testing wc_ERR_remove_state
 */
static int test_wc_ERR_remove_state(void)
{
    int res = TEST_SKIPPED;
#if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)
    wc_ERR_remove_state();

    res = TEST_SUCCESS;
#endif
    return res;
} /* End test_wc_ERR_remove_state */
/*
 * Testing wc_ERR_print_errors_fp
 */
static int test_wc_ERR_print_errors_fp(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)) && \
    (!defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM))
    long sz;
    XFILE fp = XBADFILE;

    WOLFSSL_ERROR(WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectTrue((fp = XFOPEN("./tests/test-log-dump-to-file.txt", "a+")) !=
        XBADFILE);
    wc_ERR_print_errors_fp(fp);
#if defined(DEBUG_WOLFSSL)
    ExpectTrue(XFSEEK(fp, 0, XSEEK_END) == 0);
    #ifdef NO_ERROR_QUEUE
        ExpectIntEQ(sz = XFTELL(fp), 0);
    #else
        ExpectIntNE(sz = XFTELL(fp), 0);
    #endif
#endif
    if (fp != XBADFILE)
        XFCLOSE(fp);
    (void)sz;
#endif
    return EXPECT_RESULT();
} /* End test_wc_ERR_print_errors_fp */
#ifdef DEBUG_WOLFSSL
static void Logging_cb(const int logLevel, const char *const logMessage)
{
    (void)logLevel;
    (void)logMessage;
}
#endif
/*
 * Testing wolfSSL_GetLoggingCb
 */
static int test_wolfSSL_GetLoggingCb(void)
{
    EXPECT_DECLS;
#ifdef DEBUG_WOLFSSL
    /* Testing without wolfSSL_SetLoggingCb() */
    ExpectNull(wolfSSL_GetLoggingCb());
    /* Testing with wolfSSL_SetLoggingCb() */
    ExpectIntEQ(wolfSSL_SetLoggingCb(Logging_cb), 0);
    ExpectNotNull(wolfSSL_GetLoggingCb());
    ExpectIntEQ(wolfSSL_SetLoggingCb(NULL), 0);
#endif
    ExpectNull(wolfSSL_GetLoggingCb());

    return EXPECT_RESULT();
} /* End test_wolfSSL_GetLoggingCb */

#endif /* !NO_BIO */

/* Note the lack of wolfSSL_ prefix...this is a compatibility layer test. */
static int test_GENERAL_NAME_set0_othername(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
    defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && \
    defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ALT_NAMES) && \
    defined(WOLFSSL_CERT_EXT) && !defined(NO_FILESYSTEM) && \
    defined(WOLFSSL_FPKI) && !defined(NO_RSA)
    /* ./configure --enable-opensslall --enable-certgen --enable-certreq
     *  --enable-certext --enable-debug 'CPPFLAGS=-DWOLFSSL_CUSTOM_OID
     *  -DWOLFSSL_ALT_NAMES  -DWOLFSSL_FPKI' */
    const char * cert_fname = "./certs/server-cert.der";
    const char * key_fname = "./certs/server-key.der";
    X509* x509 = NULL;
    GENERAL_NAME* gn = NULL;
    GENERAL_NAMES* gns = NULL;
    ASN1_OBJECT* upn_oid = NULL;
    ASN1_UTF8STRING *utf8str = NULL;
    ASN1_TYPE *value = NULL;
    X509_EXTENSION * ext = NULL;

    byte* pt = NULL;
    byte der[4096];
    int derSz = 0;
    EVP_PKEY* priv = NULL;
    XFILE f = XBADFILE;

    ExpectTrue((f = XFOPEN(cert_fname, "rb")) != XBADFILE);
    ExpectNotNull(x509 = d2i_X509_fp(f, NULL));
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }
    ExpectNotNull(gn = GENERAL_NAME_new());
    ExpectNotNull(upn_oid = OBJ_txt2obj("1.3.6.1.4.1.311.20.2.3", 1));
    ExpectNotNull(utf8str = ASN1_UTF8STRING_new());
    ExpectIntEQ(ASN1_STRING_set(utf8str, "othername@wolfssl.com", -1), 1);
    ExpectNotNull(value = ASN1_TYPE_new());
    ASN1_TYPE_set(value, V_ASN1_UTF8STRING, utf8str);
    if ((value == NULL) || (value->value.ptr != (char*)utf8str)) {
        wolfSSL_ASN1_STRING_free(utf8str);
    }
    ExpectIntEQ(GENERAL_NAME_set0_othername(NULL, NULL   , NULL ),
        WOLFSSL_FAILURE);
    ExpectIntEQ(GENERAL_NAME_set0_othername(gn  , NULL   , NULL ),
        WOLFSSL_FAILURE);
    ExpectIntEQ(GENERAL_NAME_set0_othername(NULL, upn_oid, NULL ),
        WOLFSSL_FAILURE);
    ExpectIntEQ(GENERAL_NAME_set0_othername(NULL, NULL   , value),
        WOLFSSL_FAILURE);
    ExpectIntEQ(GENERAL_NAME_set0_othername(gn  , upn_oid, NULL ),
        WOLFSSL_FAILURE);
    ExpectIntEQ(GENERAL_NAME_set0_othername(gn  , NULL   , value),
        WOLFSSL_FAILURE);
    ExpectIntEQ(GENERAL_NAME_set0_othername(NULL, upn_oid, value ),
        WOLFSSL_FAILURE);
    ExpectIntEQ(GENERAL_NAME_set0_othername(gn, upn_oid, value), 1);
    if (EXPECT_FAIL()) {
        ASN1_TYPE_free(value);
    }
    ExpectNotNull(gns = sk_GENERAL_NAME_new(NULL));
    ExpectIntEQ(sk_GENERAL_NAME_push(gns, gn), 1);
    if (EXPECT_FAIL()) {
        GENERAL_NAME_free(gn);
        gn = NULL;
    }
    ExpectNotNull(ext = X509V3_EXT_i2d(NID_subject_alt_name, 0, gns));
    ExpectIntEQ(X509_add_ext(x509, ext, -1), 1);
    ExpectTrue((f = XFOPEN(key_fname, "rb")) != XBADFILE);
    ExpectIntGT(derSz = (int)XFREAD(der, 1, sizeof(der), f), 0);
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }
    pt = der;
    ExpectNotNull(priv = d2i_PrivateKey(EVP_PKEY_RSA, NULL,
        (const unsigned char**)&pt, derSz));
    ExpectIntGT(X509_sign(x509, priv, EVP_sha256()), 0);
    sk_GENERAL_NAME_pop_free(gns, GENERAL_NAME_free);
    gns = NULL;
    ExpectNotNull(gns = (GENERAL_NAMES*)X509_get_ext_d2i(x509,
        NID_subject_alt_name, NULL, NULL));

    ExpectIntEQ(sk_GENERAL_NAME_num(NULL), 0);
    ExpectIntEQ(sk_GENERAL_NAME_num(gns), 3);

    ExpectNull(sk_GENERAL_NAME_value(NULL, 0));
    ExpectNull(sk_GENERAL_NAME_value(gns, 20));
    ExpectNotNull(gn = sk_GENERAL_NAME_value(gns, 2));
    ExpectIntEQ(gn->type, 0);

    sk_GENERAL_NAME_pop_free(gns, GENERAL_NAME_free);

    ASN1_OBJECT_free(upn_oid);
    X509_EXTENSION_free(ext);
    X509_free(x509);
    EVP_PKEY_free(priv);
#endif
    return EXPECT_RESULT();
}

/* Test RID (Registered ID) GENERAL_NAME creation and freeing */
static int test_RID_GENERAL_NAME_free(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && defined(WOLFSSL_RID_ALT_NAME)
    /* RID OID: 1.2.3.4.5 in DER */
    const unsigned char ridData[] = { 0x06, 0x04, 0x2a, 0x03, 0x04, 0x05 };
    const unsigned char* p = ridData;
    GENERAL_NAME* gn = NULL;
    GENERAL_NAMES* gns = NULL;
    ASN1_OBJECT* ridObj = NULL;

    /* Create RID ASN1_OBJECT from DER */
    ExpectNotNull(ridObj = wolfSSL_d2i_ASN1_OBJECT(NULL, &p, sizeof(ridData)));

    /* Create GENERAL_NAME and set up as RID */
    ExpectNotNull(gn = GENERAL_NAME_new());
    if (gn != NULL) {
        /* GENERAL_NAME_new allocates ia5, must free before using as RID */
        gn->type = GEN_RID;
        wolfSSL_ASN1_STRING_free(gn->d.ia5);
        gn->d.ia5 = NULL;
        gn->d.registeredID = ridObj;
        ridObj = NULL; /* gn owns */
    }
    if (EXPECT_FAIL()) {
        wolfSSL_ASN1_OBJECT_free(ridObj);
    }

    /* Add to stack */
    ExpectNotNull(gns = sk_GENERAL_NAME_new(NULL));
    ExpectIntEQ(sk_GENERAL_NAME_push(gns, gn), 1);
    if (EXPECT_FAIL()) {
        GENERAL_NAME_free(gn);
        gn = NULL;
    }

    /* Verify RID is set up correctly */
    ExpectNotNull(gn = sk_GENERAL_NAME_value(gns, 0));
    ExpectIntEQ(gn->type, GEN_RID);
    ExpectNotNull(gn->d.registeredID);

    /* Free via sk_GENERAL_NAME_pop_free, exercises type_free for RID */
    sk_GENERAL_NAME_pop_free(gns, GENERAL_NAME_free);
#endif
    return EXPECT_RESULT();
}

/* Test RID (Registered ID) SAN parsing via X509_get_ext_d2i().
 * Uses rid-cert.der which contains a RID SAN with OID 1.2.3.4.5. This tests
 * that ASN_RID_TYPE case in wolfSSL_X509_get_ext_d2i() frees ia5 before
 * allocating registeredID. */
static int test_RID_X509_get_ext_d2i(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && defined(WOLFSSL_RID_ALT_NAME) && \
    !defined(NO_RSA) && !defined(NO_FILESYSTEM)
    int i;
    int numNames;
    int foundRID = 0;
    const char* ridCert = "./certs/rid-cert.der";
    X509* x509 = NULL;
    GENERAL_NAMES* gns = NULL;
    GENERAL_NAME* gn = NULL;
    XFILE f = XBADFILE;

    ExpectTrue((f = XFOPEN(ridCert, "rb")) != XBADFILE);
    ExpectNotNull(x509 = d2i_X509_fp(f, NULL));
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }

    /* Get SANs, will exercise ASN_RID_TYPE case */
    ExpectNotNull(gns = (GENERAL_NAMES*)X509_get_ext_d2i(x509,
        NID_subject_alt_name, NULL, NULL));

    /* rid-cert.der contains: UPN, RID (1.2.3.4.5), DNS, URI, othername */
    numNames = sk_GENERAL_NAME_num(gns);
    ExpectIntGE(numNames, 2);

    for (i = 0; i < numNames; i++) {
        gn = sk_GENERAL_NAME_value(gns, i);
        if (gn != NULL && gn->type == GEN_RID) {
            ExpectNotNull(gn->d.registeredID);
            foundRID = 1;
            break;
        }
    }
    ExpectIntEQ(foundRID, 1);

    /* Free via sk_GENERAL_NAME_pop_free, exercises type_free for RID */
    sk_GENERAL_NAME_pop_free(gns, GENERAL_NAME_free);
    X509_free(x509);
#endif
    return EXPECT_RESULT();
}

/* Note the lack of wolfSSL_ prefix...this is a compatibility layer test. */
static int test_othername_and_SID_ext(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_CERTS) && \
    defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && \
    defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ALT_NAMES) && \
    defined(WOLFSSL_CERT_EXT) && !defined(NO_FILESYSTEM) && \
    defined(WOLFSSL_FPKI) && defined(WOLFSSL_ASN_TEMPLATE) && !defined(NO_RSA)
    /* ./configure --enable-opensslall --enable-certgen --enable-certreq
     *  --enable-certext --enable-debug 'CPPFLAGS=-DWOLFSSL_CUSTOM_OID
     *  -DWOLFSSL_ALT_NAMES  -DWOLFSSL_FPKI' */
    const char* csr_fname = "./certs/csr.signed.der";
    const char* key_fname = "./certs/server-key.der";

    byte der[4096];
    int derSz = 0;
    byte badDer[2] = { 0x30, 0x00 };
    X509_REQ* x509 = NULL;
    STACK_OF(X509_EXTENSION) *exts = NULL;

    X509_EXTENSION * san_ext = NULL;
    X509_EXTENSION * ext = NULL;
    GENERAL_NAME* gn = NULL;
    GENERAL_NAMES* gns = NULL;
    ASN1_OBJECT* upn_oid = NULL;
    ASN1_UTF8STRING *utf8str = NULL;
    ASN1_TYPE *value = NULL;
    ASN1_STRING *extval = NULL;

    /* SID extension. SID data format explained here:
     * https://blog.qdsecurity.se/2022/05/27/manually-injecting-a-sid-in-a-certificate/
     */
    byte SidExtension[] = {
    48, 64, 160, 62, 6,  10, 43, 6,  1,  4,  1,  130, 55, 25, 2,  1,  160,
    48, 4,  46,  83, 45, 49, 45, 53, 45, 50, 49, 45,  50, 56, 52, 51, 57,
    48, 55, 52,  49, 56, 45, 51, 57, 50, 54, 50, 55,  55, 52, 50, 49, 45,
    51, 56, 49,  53, 57, 57, 51, 57, 55, 50, 45, 52,  54, 48, 49};

    byte expectedAltName[] = {
    0x30, 0x27, 0xA0, 0x25, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82,
    0x37, 0x14, 0x02, 0x03, 0xA0, 0x17, 0x0C, 0x15, 0x6F, 0x74, 0x68, 0x65,
    0x72, 0x6E, 0x61, 0x6D, 0x65, 0x40, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73,
    0x6C, 0x2E, 0x63, 0x6F, 0x6D};

    X509_EXTENSION *sid_ext = NULL;
    ASN1_OBJECT* sid_oid = NULL;
    ASN1_OCTET_STRING *sid_data = NULL;

    ASN1_OBJECT* alt_names_oid = NULL;

    EVP_PKEY* priv = NULL;
    XFILE f = XBADFILE;
    byte* pt = NULL;
    BIO* bio = NULL;

    ExpectTrue((f = XFOPEN(csr_fname, "rb")) != XBADFILE);
    ExpectNotNull(x509 = d2i_X509_REQ_fp(f, NULL));
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }
    ExpectIntEQ(X509_REQ_set_version(x509, 2), 1);
    ExpectNotNull(gn = GENERAL_NAME_new());
    ExpectNotNull(upn_oid = OBJ_txt2obj("1.3.6.1.4.1.311.20.2.3", 1));
    ExpectNotNull(utf8str = ASN1_UTF8STRING_new());
    ExpectIntEQ(ASN1_STRING_set(utf8str, "othername@wolfssl.com", -1), 1);
    ExpectNotNull(value = ASN1_TYPE_new());
    ASN1_TYPE_set(value, V_ASN1_UTF8STRING, utf8str);
    if (EXPECT_FAIL()) {
        ASN1_UTF8STRING_free(utf8str);
    }
    ExpectIntEQ(GENERAL_NAME_set0_othername(gn, upn_oid, value), 1);
    if (EXPECT_FAIL()) {
        ASN1_TYPE_free(value);
        GENERAL_NAME_free(gn);
        gn = NULL;
    }
    ExpectNotNull(gns = sk_GENERAL_NAME_new(NULL));
    ExpectIntEQ(sk_GENERAL_NAME_push(gns, gn), 1);
    if (EXPECT_FAIL()) {
        GENERAL_NAME_free(gn);
    }
    ExpectNotNull(san_ext = X509V3_EXT_i2d(NID_subject_alt_name, 0, gns));
    ExpectNotNull(sid_oid = OBJ_txt2obj("1.3.6.1.4.1.311.25.2", 1));
    ExpectNotNull(sid_data = ASN1_OCTET_STRING_new());
    ASN1_OCTET_STRING_set(sid_data, SidExtension, sizeof(SidExtension));
    ExpectNotNull(sid_ext = X509_EXTENSION_create_by_OBJ(NULL, sid_oid, 0,
                                                         sid_data));
    ExpectNotNull(exts = sk_X509_EXTENSION_new_null());
    wolfSSL_sk_X509_EXTENSION_free(exts);
    exts = NULL;
    ExpectNotNull(exts = sk_X509_EXTENSION_new_null());
    /* Ensure an empty stack doesn't raise an error. */
    ExpectIntEQ(X509_REQ_add_extensions(NULL, NULL), 0);
    ExpectIntEQ(X509_REQ_add_extensions(x509, NULL), 0);
    ExpectIntEQ(X509_REQ_add_extensions(NULL, exts), 0);
    ExpectIntEQ(X509_REQ_add_extensions(x509, exts), 1);
    ExpectIntEQ(sk_X509_EXTENSION_push(exts, san_ext), 1);
    if (EXPECT_FAIL()) {
        X509_EXTENSION_free(san_ext);
    }
    ExpectIntEQ(sk_X509_EXTENSION_push(exts, sid_ext), 2);
    if (EXPECT_FAIL()) {
        X509_EXTENSION_free(sid_ext);
    }
    ExpectIntEQ(X509_REQ_add_extensions(x509, exts), 1);
    ExpectTrue((f = XFOPEN(key_fname, "rb")) != XBADFILE);
    ExpectIntGT(derSz = (int)XFREAD(der, 1, sizeof(der), f), 0);
    if (f != XBADFILE)
        XFCLOSE(f);
    pt = der;
    ExpectNotNull(priv = d2i_PrivateKey(EVP_PKEY_RSA, NULL,
                                        (const unsigned char**)&pt, derSz));
    ExpectIntGT(X509_REQ_sign(x509, priv, EVP_sha256()), 0);
    pt = der;
    ExpectIntGT(derSz = i2d_X509_REQ(x509, &pt), 0);
    X509_REQ_free(x509);
    x509 = NULL;
    ExpectNull(d2i_X509_REQ_INFO(&x509, NULL, derSz));
    pt = badDer;
    ExpectNull(d2i_X509_REQ_INFO(&x509, (const unsigned char**)&pt,
        sizeof(badDer)));
    pt = der;
    ExpectNotNull(d2i_X509_REQ_INFO(&x509, (const unsigned char**)&pt, derSz));
    sk_GENERAL_NAME_pop_free(gns, GENERAL_NAME_free);
    gns = NULL;
    sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
    exts = NULL;
    ASN1_OBJECT_free(upn_oid);
    ASN1_OBJECT_free(sid_oid);
    sid_oid = NULL;
    ASN1_OCTET_STRING_free(sid_data);
    X509_REQ_free(x509);
    EVP_PKEY_free(priv);

    /* At this point everything used to generate what is in der is cleaned up.
     * We now read back from der to confirm the extensions were inserted
     * correctly. */
    bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem());
    ExpectNotNull(bio);

    ExpectIntEQ(BIO_write(bio, der, derSz), derSz); /* d2i consumes BIO */
    ExpectNotNull(d2i_X509_REQ_bio(bio, &x509));
    ExpectNotNull(x509);
    BIO_free(bio);
    ExpectNotNull(exts = (STACK_OF(X509_EXTENSION)*)X509_REQ_get_extensions(
        x509));
    ExpectIntEQ(sk_X509_EXTENSION_num(NULL), WOLFSSL_FATAL_ERROR);
    ExpectIntEQ(sk_X509_EXTENSION_num(exts), 2);

    /* Check the SID extension. */
    ExpectNotNull(sid_oid = OBJ_txt2obj("1.3.6.1.4.1.311.25.2", 1));
    ExpectNotNull(ext = sk_X509_EXTENSION_value(exts,
            X509_get_ext_by_OBJ(x509, sid_oid, -1)));
    ExpectNotNull(extval = X509_EXTENSION_get_data(ext));
    ExpectIntEQ(extval->length, sizeof(SidExtension));
    ExpectIntEQ(XMEMCMP(SidExtension, extval->data, sizeof(SidExtension)), 0);
    ASN1_OBJECT_free(sid_oid);

    /* Check the AltNames extension. */
    ExpectNotNull(alt_names_oid = OBJ_txt2obj("subjectAltName", 0));
    ExpectNotNull(ext = sk_X509_EXTENSION_value(exts,
            X509_get_ext_by_OBJ(x509, alt_names_oid, -1)));
    ExpectNotNull(extval = X509_EXTENSION_get_data(ext));
    ExpectIntEQ(extval->length, sizeof(expectedAltName));
    ExpectIntEQ(XMEMCMP(expectedAltName, extval->data, sizeof(expectedAltName)),
                0);
    ASN1_OBJECT_free(alt_names_oid);

    /* Cleanup */
    ExpectNotNull(gns = (GENERAL_NAMES*)X509_get_ext_d2i(x509,
        NID_subject_alt_name, NULL, NULL));
    ExpectIntEQ(sk_GENERAL_NAME_num(gns), 1);
    ExpectNotNull(gn = sk_GENERAL_NAME_value(gns, 0));
    ExpectIntEQ(gn->type, 0);

    sk_GENERAL_NAME_pop_free(gns, GENERAL_NAME_free);

    sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
    X509_REQ_free(x509);
#endif
    return EXPECT_RESULT();
}

#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)

/* test that the callback arg is correct */
static int certCbArg = 0;

static int certCb(WOLFSSL* ssl, void* arg)
{
    if (ssl == NULL || arg != &certCbArg)
        return 0;
    if (wolfSSL_is_server(ssl)) {
        if (wolfSSL_use_certificate_file(ssl, svrCertFile,
                WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS)
            return 0;
        if (wolfSSL_use_PrivateKey_file(ssl, svrKeyFile,
                WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS)
            return 0;
    }
    else {
        if (wolfSSL_use_certificate_file(ssl, cliCertFile,
                WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS)
            return 0;
        if (wolfSSL_use_PrivateKey_file(ssl, cliKeyFile,
                WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS)
            return 0;
    }
    return 1;
}

static int certSetupCb(WOLFSSL_CTX* ctx)
{
    SSL_CTX_set_cert_cb(ctx, certCb, &certCbArg);
    return TEST_SUCCESS;
}

/**
 * This is only done because test_wolfSSL_client_server_nofail_memio has no way
 * to stop certificate and key loading
 */
static int certClearCb(WOLFSSL* ssl)
{
    /* Clear the loaded certs to force the callbacks to set them up */
    SSL_certs_clear(ssl);
    return TEST_SUCCESS;
}

#endif

static int test_wolfSSL_cert_cb(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
    test_ssl_cbf func_cb_client;
    test_ssl_cbf func_cb_server;
    size_t i;
    struct {
        method_provider client_meth;
        method_provider server_meth;
        const char* desc;
    } test_params[] = {
#ifdef WOLFSSL_TLS13
        {wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLS 1.3"},
#endif
#ifndef WOLFSSL_NO_TLS12
        {wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLS 1.2"},
#endif
#ifndef NO_OLD_TLS
        {wolfTLSv1_1_client_method, wolfTLSv1_1_server_method, "TLS 1.1"},
#ifdef WOLFSSL_ALLOW_TLSV10
        {wolfTLSv1_client_method, wolfTLSv1_server_method, "TLS 1.0"},
#endif
#endif
    };

    for (i = 0; i < XELEM_CNT(test_params) && !EXPECT_FAIL(); i++) {
        XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
        XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));

        printf("\tTesting with %s...\n", test_params[i].desc);

        func_cb_client.method = test_params[i].client_meth;
        func_cb_server.method = test_params[i].server_meth;
        func_cb_client.ctx_ready = certSetupCb;
        func_cb_client.ssl_ready = certClearCb;
        func_cb_server.ctx_ready = certSetupCb;
        func_cb_server.ssl_ready = certClearCb;

        ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
            &func_cb_server, NULL), TEST_SUCCESS);
    }
#endif
    return EXPECT_RESULT();
}

#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)

static const char* test_wolfSSL_cert_cb_dyn_ciphers_client_cipher = NULL;
static const char* test_wolfSSL_cert_cb_dyn_ciphers_client_sigalgs = NULL;
static int test_wolfSSL_cert_cb_dyn_ciphers_client_ctx_ready(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    ExpectIntEQ(wolfSSL_CTX_set_cipher_list(ctx,
        test_wolfSSL_cert_cb_dyn_ciphers_client_cipher), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx,
        test_wolfSSL_cert_cb_dyn_ciphers_client_sigalgs), WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}

static int test_wolfSSL_cert_cb_dyn_ciphers_certCB(WOLFSSL* ssl, void* arg)
{
    const byte* suites = NULL;
    word16 suiteSz = 0;
    const byte* hashSigAlgo = NULL;
    word16 hashSigAlgoSz = 0;
    word16 idx = 0;
    int haveRSA = 0;
    int haveECC = 0;

    (void)arg;

    if (wolfSSL_get_client_suites_sigalgs(ssl, &suites, &suiteSz, &hashSigAlgo,
            &hashSigAlgoSz) != WOLFSSL_SUCCESS)
        return 0;
    if (suites == NULL || suiteSz == 0 || hashSigAlgo == NULL ||
            hashSigAlgoSz == 0)
        return 0;

    for (idx = 0; idx < suiteSz; idx += 2) {
        WOLFSSL_CIPHERSUITE_INFO info =
                wolfSSL_get_ciphersuite_info(suites[idx], suites[idx+1]);

        if (info.rsaAuth)
            haveRSA = 1;
        else if (info.eccAuth)
            haveECC = 1;
    }

    if (hashSigAlgoSz > 0) {
        /* sigalgs extension takes precedence over ciphersuites */
        haveRSA = 0;
        haveECC = 0;
    }
    for (idx = 0; idx < hashSigAlgoSz; idx += 2) {
        int hashAlgo = 0;
        int sigAlgo = 0;

        if (wolfSSL_get_sigalg_info(hashSigAlgo[idx+0], hashSigAlgo[idx+1],
                &hashAlgo, &sigAlgo) != 0)
            return 0;

        if (sigAlgo == RSAk || sigAlgo == RSAPSSk)
            haveRSA = 1;
        else if (sigAlgo == ECDSAk)
            haveECC = 1;
    }

    if (haveRSA) {
        if (wolfSSL_use_certificate_file(ssl, svrCertFile, WOLFSSL_FILETYPE_PEM)
                != WOLFSSL_SUCCESS)
            return 0;
        if (wolfSSL_use_PrivateKey_file(ssl, svrKeyFile, WOLFSSL_FILETYPE_PEM)
                != WOLFSSL_SUCCESS)
            return 0;
    }
    else if (haveECC) {
        if (wolfSSL_use_certificate_file(ssl, eccCertFile, WOLFSSL_FILETYPE_PEM)
                != WOLFSSL_SUCCESS)
            return 0;
        if (wolfSSL_use_PrivateKey_file(ssl, eccKeyFile, WOLFSSL_FILETYPE_PEM)
                != WOLFSSL_SUCCESS)
            return 0;
    }

    return 1;
}

static int test_wolfSSL_cert_cb_dyn_ciphers_server_ctx_ready(WOLFSSL_CTX* ctx)
{
    SSL_CTX_set_cert_cb(ctx, test_wolfSSL_cert_cb_dyn_ciphers_certCB, NULL);
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL);
    return TEST_SUCCESS;
}

#endif

/* Testing dynamic ciphers offered by client */
static int test_wolfSSL_cert_cb_dyn_ciphers(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
    test_ssl_cbf func_cb_client;
    test_ssl_cbf func_cb_server;
    struct {
        method_provider client_meth;
        const char* client_ciphers;
        const char* client_sigalgs;
        const char* client_ca;
        method_provider server_meth;
    } test_params[] = {
#if !defined(NO_SHA256) && defined(HAVE_AESGCM)
#ifdef WOLFSSL_TLS13
#if !defined(NO_RSA) && defined(WC_RSA_PSS)
        {wolfTLSv1_3_client_method,
                "TLS13-AES256-GCM-SHA384:TLS13-AES128-GCM-SHA256",
                "RSA-PSS+SHA256", caCertFile, wolfTLSv1_3_server_method},
#endif
#ifdef HAVE_ECC
        {wolfTLSv1_3_client_method,
                "TLS13-AES256-GCM-SHA384:TLS13-AES128-GCM-SHA256",
                "ECDSA+SHA256", caEccCertFile, wolfTLSv1_3_server_method},
#endif
#endif
#if !defined(WOLFSSL_NO_TLS12)  && !defined(WOLFSSL_HARDEN_TLS)
#if !defined(NO_RSA) && defined(WC_RSA_PSS) && !defined(NO_DH)
        {wolfTLSv1_2_client_method,
                "DHE-RSA-AES128-GCM-SHA256",
                "RSA-PSS+SHA256", caCertFile, wolfTLSv1_2_server_method},
#endif
#ifdef HAVE_ECC
        {wolfTLSv1_2_client_method,
                "ECDHE-ECDSA-AES128-GCM-SHA256",
                "ECDSA+SHA256", caEccCertFile, wolfTLSv1_2_server_method},
#endif
#endif
#endif
    };
    size_t i;
    size_t testCount = sizeof(test_params)/sizeof(*test_params);

    if (testCount > 0) {
        for (i = 0; i < testCount; i++) {
            printf("\tTesting %s ciphers with %s sigalgs\n",
                    test_params[i].client_ciphers,
                    test_params[i].client_sigalgs);

            XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
            XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));

            test_wolfSSL_cert_cb_dyn_ciphers_client_cipher =
                    test_params[i].client_ciphers;
            test_wolfSSL_cert_cb_dyn_ciphers_client_sigalgs =
                    test_params[i].client_sigalgs;
            func_cb_client.method = test_params[i].client_meth;
            func_cb_client.caPemFile = test_params[i].client_ca;
            func_cb_client.ctx_ready =
                    test_wolfSSL_cert_cb_dyn_ciphers_client_ctx_ready;

            func_cb_server.ctx_ready =
                    test_wolfSSL_cert_cb_dyn_ciphers_server_ctx_ready;
            func_cb_server.ssl_ready = certClearCb; /* Reuse from prev test */
            func_cb_server.method = test_params[i].server_meth;

            ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
                &func_cb_server, NULL), TEST_SUCCESS);
        }
    }
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_ciphersuite_auth(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    WOLFSSL_CIPHERSUITE_INFO info;

    (void)info;

#ifndef WOLFSSL_NO_TLS12
#ifdef HAVE_CHACHA
    info = wolfSSL_get_ciphersuite_info(CHACHA_BYTE,
            TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
    ExpectIntEQ(info.rsaAuth, 1);
    ExpectIntEQ(info.eccAuth, 0);
    ExpectIntEQ(info.eccStatic, 0);
    ExpectIntEQ(info.psk, 0);

    info = wolfSSL_get_ciphersuite_info(CHACHA_BYTE,
            TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);
    ExpectIntEQ(info.rsaAuth, 0);
    ExpectIntEQ(info.eccAuth, 1);
    ExpectIntEQ(info.eccStatic, 0);
    ExpectIntEQ(info.psk, 0);

    info = wolfSSL_get_ciphersuite_info(CHACHA_BYTE,
            TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256);
    ExpectIntEQ(info.rsaAuth, 0);
    ExpectIntEQ(info.eccAuth, 0);
    ExpectIntEQ(info.eccStatic, 0);
    ExpectIntEQ(info.psk, 1);
#endif
#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)
#ifndef NO_RSA
    info = wolfSSL_get_ciphersuite_info(ECC_BYTE,
            TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);
    ExpectIntEQ(info.rsaAuth, 1);
    ExpectIntEQ(info.eccAuth, 0);
    ExpectIntEQ(info.eccStatic, 0);
    ExpectIntEQ(info.psk, 0);

    info = wolfSSL_get_ciphersuite_info(ECC_BYTE,
            TLS_ECDH_RSA_WITH_AES_128_CBC_SHA);
    ExpectIntEQ(info.rsaAuth, 1);
    ExpectIntEQ(info.eccAuth, 0);
    ExpectIntEQ(info.eccStatic, 1);
    ExpectIntEQ(info.psk, 0);

    info = wolfSSL_get_ciphersuite_info(ECC_BYTE,
            TLS_ECDH_RSA_WITH_AES_256_CBC_SHA);
    ExpectIntEQ(info.rsaAuth, 1);
    ExpectIntEQ(info.eccAuth, 0);
    ExpectIntEQ(info.eccStatic, 1);
    ExpectIntEQ(info.psk, 0);
#endif
    info = wolfSSL_get_ciphersuite_info(ECC_BYTE,
            TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA);
    ExpectIntEQ(info.rsaAuth, 0);
    ExpectIntEQ(info.eccAuth, 1);
    ExpectIntEQ(info.eccStatic, 0);
    ExpectIntEQ(info.psk, 0);

    info = wolfSSL_get_ciphersuite_info(ECC_BYTE,
            TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA);
    ExpectIntEQ(info.rsaAuth, 0);
    ExpectIntEQ(info.eccAuth, 1);
    ExpectIntEQ(info.eccStatic, 1);
    ExpectIntEQ(info.psk, 0);

    info = wolfSSL_get_ciphersuite_info(ECDHE_PSK_BYTE,
            TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256);
    ExpectIntEQ(info.rsaAuth, 0);
    ExpectIntEQ(info.eccAuth, 0);
    ExpectIntEQ(info.eccStatic, 0);
    ExpectIntEQ(info.psk, 1);
#endif
#endif

#ifdef WOLFSSL_TLS13
    info = wolfSSL_get_ciphersuite_info(TLS13_BYTE,
            TLS_AES_128_GCM_SHA256);
    ExpectIntEQ(info.rsaAuth, 0);
    ExpectIntEQ(info.eccAuth, 0);
    ExpectIntEQ(info.eccStatic, 0);
    ExpectIntEQ(info.psk, 0);
#endif

#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_sigalg_info(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    byte hashSigAlgo[WOLFSSL_MAX_SIGALGO];
    word16 len = 0;
    word16 idx = 0;
    int allSigAlgs = SIG_ECDSA | SIG_RSA | SIG_SM2 | SIG_FALCON | SIG_MLDSA;

    InitSuitesHashSigAlgo(hashSigAlgo, allSigAlgs, 1, 1, 0xFFFFFFFF, &len);
    for (idx = 0; idx < len; idx += 2) {
        int hashAlgo = 0;
        int sigAlgo = 0;

        ExpectIntEQ(wolfSSL_get_sigalg_info(hashSigAlgo[idx+0],
                hashSigAlgo[idx+1], &hashAlgo, &sigAlgo), 0);

        ExpectIntNE(hashAlgo, 0);
        ExpectIntNE(sigAlgo, 0);
    }

    InitSuitesHashSigAlgo(hashSigAlgo, allSigAlgs | SIG_ANON, 1, 1,
            0xFFFFFFFF, &len);
    for (idx = 0; idx < len; idx += 2) {
        int hashAlgo = 0;
        int sigAlgo = 0;

        ExpectIntEQ(wolfSSL_get_sigalg_info(hashSigAlgo[idx+0],
                hashSigAlgo[idx+1], &hashAlgo, &sigAlgo), 0);

        ExpectIntNE(hashAlgo, 0);
    }

#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_d2i_SSL_SESSION_bounds_check(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_EXT_CACHE) && \
    defined(SESSION_CERTS) && !defined(NO_SESSION_CACHE)
    WOLFSSL_SESSION* sess = NULL;
    WOLFSSL_SESSION* restored = NULL;
    unsigned char* sessDer = NULL;
    unsigned char* modData = NULL;
    const unsigned char* ptr = NULL;
    unsigned char* pp = NULL;
    int sz = 0;
    int idx = 0;
    int sessionIDSz = 0;
    int altIDLen = 0;
    int chainOffset = 0;
    int newLen = 0;
    word16 oversized = 0;

    /* Create and serialize a valid empty session to learn the format */
    ExpectNotNull(sess = wolfSSL_SESSION_new());
    ExpectIntGT((sz = wolfSSL_i2d_SSL_SESSION(sess, NULL)), 0);
    ExpectNotNull(sessDer = (unsigned char*)XMALLOC(sz, NULL,
        DYNAMIC_TYPE_OPENSSL));
    pp = sessDer;
    ExpectIntGT(wolfSSL_i2d_SSL_SESSION(sess, &pp), 0);
    wolfSSL_SESSION_free(sess);
    sess = NULL;

    /* Calculate offset to chain.count field:
     *   side(1) + bornOn(4) + timeout(4) + sessionIDSz(1) + sessionID(var)
     *   + masterSecret(SECRET_LEN=48) + haveEMS(1) + altIDLen(1) + altID(var)
     */
    idx = 1 + 4 + 4;
    if (EXPECT_SUCCESS()) {
        sessionIDSz = sessDer[idx++];
        idx += sessionIDSz + SECRET_LEN + 1;
        altIDLen = sessDer[idx++];
        if (altIDLen == ID_LEN)
            idx += ID_LEN;
        chainOffset = idx;
    }

    /*
     * The deserialization must reject this with a BUFFER_ERROR (return NULL).
     */
    newLen = chainOffset + 1 + 50;
    ExpectNotNull(modData = (unsigned char*)XMALLOC(newLen, NULL,
        DYNAMIC_TYPE_TMP_BUFFER));
    if (EXPECT_SUCCESS()) {
        XMEMCPY(modData, sessDer, chainOffset);
        modData[chainOffset] = MAX_CHAIN_DEPTH + 1;
        XMEMSET(modData + chainOffset + 1, 0, newLen - chainOffset - 1);
    }
    ptr = modData;
    ExpectNull(restored = wolfSSL_d2i_SSL_SESSION(NULL, &ptr, (long)newLen));
    XFREE(modData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    modData = NULL;

    /*
     * chain.count is valid (1), but the cert length field is too large.
     */
    newLen = chainOffset + 1 + 2 + 100;
    ExpectNotNull(modData = (unsigned char*)XMALLOC(newLen, NULL,
        DYNAMIC_TYPE_TMP_BUFFER));
    if (EXPECT_SUCCESS()) {
        XMEMCPY(modData, sessDer, chainOffset);
        idx = chainOffset;
        modData[idx++] = 1;  /* chain.count = 1 */
        oversized = MAX_X509_SIZE + 1;
        modData[idx++] = (byte)(oversized >> 8);
        modData[idx++] = (byte)(oversized & 0xFF);
        XMEMSET(modData + idx, 0xCC, newLen - idx);
    }
    ptr = modData;
    ExpectNull(restored = wolfSSL_d2i_SSL_SESSION(NULL, &ptr, (long)newLen));
    XFREE(modData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    modData = NULL;

    XFREE(sessDer, NULL, DYNAMIC_TYPE_OPENSSL);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_SESSION(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
    !defined(NO_RSA) && !defined(NO_SHA256) && \
    defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(NO_SESSION_CACHE)
    WOLFSSL*     ssl = NULL;
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL_SESSION* sess = NULL;
    WOLFSSL_SESSION* sess_copy = NULL;
#ifdef OPENSSL_EXTRA
#ifdef HAVE_EXT_CACHE
    unsigned char* sessDer = NULL;
    unsigned char* ptr     = NULL;
    int sz = 0;
#endif
    const unsigned char context[] = "user app context";
    unsigned int contextSz = (unsigned int)sizeof(context);
#endif
    int ret = 0, err = 0;
    SOCKET_T sockfd;
    tcp_ready ready;
    func_args server_args;
    THREAD_TYPE serverThread;
    char msg[80];
    const char* sendGET = "GET";

    /* TLS v1.3 requires session tickets */
    /* CHACHA and POLY1305 required for myTicketEncCb */
#if !defined(WOLFSSL_NO_TLS12) && (!defined(WOLFSSL_TLS13) || \
    !(defined(HAVE_SESSION_TICKET) && ((defined(HAVE_CHACHA) && \
            defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))))
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
#else
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#endif

    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, cliCertFile,
        CERT_FILETYPE));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile,
        CERT_FILETYPE));
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0),
        WOLFSSL_SUCCESS);
#ifdef WOLFSSL_ENCRYPTED_KEYS
    wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
#endif
#ifdef HAVE_SESSION_TICKET
    /* Use session tickets, for ticket tests below */
    ExpectIntEQ(wolfSSL_CTX_UseSessionTicket(ctx), WOLFSSL_SUCCESS);
#endif

    XMEMSET(&server_args, 0, sizeof(func_args));
#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    StartTCP();
    InitTcpReady(&ready);

    server_args.signal = &ready;
    start_thread(test_server_nofail, &server_args, &serverThread);
    wait_tcp_ready(&server_args);

    /* client connection */
    ExpectNotNull(ssl = wolfSSL_new(ctx));
    tcp_connect(&sockfd, wolfSSLIP, ready.port, 0, 0, ssl);
    ExpectIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS);

    WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_connect(ssl),
                                ret != WOLFSSL_SUCCESS);
    ExpectIntEQ(ret, WOLFSSL_SUCCESS);

    WOLFSSL_ASYNC_WHILE_PENDING(
        ret = wolfSSL_write(ssl, sendGET, (int)XSTRLEN(sendGET)),
        ret <= 0);
    ExpectIntEQ(ret, (int)XSTRLEN(sendGET));

    WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_read(ssl, msg, sizeof(msg)),
                                ret != 23);
    ExpectIntEQ(ret, 23);

    ExpectPtrNE((sess = wolfSSL_get1_session(ssl)), NULL); /* ref count 1 */
    ExpectPtrNE((sess_copy = wolfSSL_get1_session(ssl)), NULL); /* ref count 2 */
    ExpectIntEQ(wolfSSL_SessionIsSetup(sess), 1);
#ifdef HAVE_EXT_CACHE
    ExpectPtrEq(sess, sess_copy); /* they should be the same pointer but without
                                   * HAVE_EXT_CACHE we get new objects each time */
#endif
    wolfSSL_SESSION_free(sess_copy); sess_copy = NULL;
    wolfSSL_SESSION_free(sess);      sess = NULL; /* free session ref */

    sess = wolfSSL_get_session(ssl);

#ifdef OPENSSL_EXTRA
    ExpectIntEQ(SSL_SESSION_is_resumable(NULL), 0);
    ExpectIntEQ(SSL_SESSION_is_resumable(sess), 1);

    ExpectIntEQ(wolfSSL_SESSION_has_ticket(NULL), 0);
    ExpectIntEQ(wolfSSL_SESSION_get_ticket_lifetime_hint(NULL), 0);
    #ifdef HAVE_SESSION_TICKET
    ExpectIntEQ(wolfSSL_SESSION_has_ticket(sess), 1);
    ExpectIntEQ(wolfSSL_SESSION_get_ticket_lifetime_hint(sess),
                SESSION_TICKET_HINT_DEFAULT);
    #else
    ExpectIntEQ(wolfSSL_SESSION_has_ticket(sess), 0);
    #endif
#else
    (void)sess;
#endif /* OPENSSL_EXTRA */

    /* Retain copy of the session for later testing */
    ExpectNotNull(sess = wolfSSL_get1_session(ssl));

    wolfSSL_shutdown(ssl);
    wolfSSL_free(ssl); ssl = NULL;

    CloseSocket(sockfd);

    join_thread(serverThread);

    FreeTcpReady(&ready);

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
    {
        X509 *x509 = NULL;
        char buf[30];
        int  bufSz = 0;

        ExpectNotNull(x509 = SSL_SESSION_get0_peer(sess));
        ExpectIntGT((bufSz = X509_NAME_get_text_by_NID(
            X509_get_subject_name(x509), NID_organizationalUnitName, buf,
            sizeof(buf))), 0);
        ExpectIntNE((bufSz == 7 || bufSz == 16), 0); /* should be one of these*/
        if (bufSz == 7) {
            ExpectIntEQ(XMEMCMP(buf, "Support", bufSz), 0);
        }
        if (bufSz == 16) {
            ExpectIntEQ(XMEMCMP(buf, "Programming-2048", bufSz), 0);
        }
    }
#endif

#ifdef HAVE_EXT_CACHE
    ExpectNotNull(sess_copy = wolfSSL_SESSION_dup(sess));
    wolfSSL_SESSION_free(sess_copy); sess_copy = NULL;
    sess_copy = NULL;
#endif

#if defined(OPENSSL_EXTRA) && defined(HAVE_EXT_CACHE)
    /* get session from DER and update the timeout */
    ExpectIntEQ(wolfSSL_i2d_SSL_SESSION(NULL, &sessDer), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntGT((sz = wolfSSL_i2d_SSL_SESSION(sess, &sessDer)), 0);
    wolfSSL_SESSION_free(sess); sess = NULL;
    sess = NULL;
    ptr = sessDer;
    ExpectNull(sess = wolfSSL_d2i_SSL_SESSION(NULL, NULL, sz));
    ExpectNotNull(sess = wolfSSL_d2i_SSL_SESSION(NULL,
                (const unsigned char**)&ptr, sz));
    XFREE(sessDer, NULL, DYNAMIC_TYPE_OPENSSL);
    sessDer = NULL;

    ExpectIntGT(wolfSSL_SESSION_get_time(sess), 0);
    ExpectIntEQ(wolfSSL_SSL_SESSION_set_timeout(sess, 500), SSL_SUCCESS);
#endif

    /* successful set session test */
    ExpectNotNull(ssl = wolfSSL_new(ctx));
    ExpectIntEQ(wolfSSL_set_session(ssl, sess), WOLFSSL_SUCCESS);

#ifdef HAVE_SESSION_TICKET
    /* Test set/get session ticket */
    {
        const char* ticket = "This is a session ticket";
        char buf[64] = {0};
        word32 bufSz = (word32)sizeof(buf);
        word32 retSz = 0;

        ExpectIntEQ(WOLFSSL_SUCCESS,
            wolfSSL_set_SessionTicket(ssl, (byte *)ticket,
                (word32)XSTRLEN(ticket)));
        ExpectIntEQ(WOLFSSL_SUCCESS,
            wolfSSL_get_SessionTicket(ssl, (byte *)buf, &bufSz));
        ExpectStrEQ(ticket, buf);

        /* return ticket length if buffer parameter is null */
        wolfSSL_get_SessionTicket(ssl, NULL, &retSz);
        ExpectIntEQ(bufSz, retSz);
    }
#endif

#ifdef OPENSSL_EXTRA
    /* session timeout case */
    /* make the session to be expired */
    ExpectIntEQ(SSL_SESSION_set_timeout(sess,1), SSL_SUCCESS);
    XSLEEP_MS(1200);

    /* SSL_set_session should reject specified session but return success
     * if WOLFSSL_ERROR_CODE_OPENSSL macro is defined for OpenSSL compatibility.
     */
#if defined(WOLFSSL_ERROR_CODE_OPENSSL)
    ExpectIntEQ(wolfSSL_set_session(ssl,sess), SSL_SUCCESS);
#else
    ExpectIntEQ(wolfSSL_set_session(ssl,sess), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif
    ExpectIntEQ(wolfSSL_SSL_SESSION_set_timeout(sess, 500), SSL_SUCCESS);

#ifdef WOLFSSL_SESSION_ID_CTX
    /* fail case with miss match session context IDs (use compatibility API) */
    ExpectIntEQ(SSL_set_session_id_context(ssl, context, contextSz),
            SSL_SUCCESS);
    ExpectIntEQ(wolfSSL_set_session(ssl, sess), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    wolfSSL_free(ssl); ssl = NULL;

    ExpectIntEQ(SSL_CTX_set_session_id_context(NULL, context, contextSz),
            WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_CTX_set_session_id_context(ctx, context, contextSz),
            SSL_SUCCESS);
    ExpectNotNull(ssl = wolfSSL_new(ctx));
    ExpectIntEQ(wolfSSL_set_session(ssl, sess), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif
#endif /* OPENSSL_EXTRA */

    wolfSSL_free(ssl);
    wolfSSL_SESSION_free(sess);
    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
    !defined(NO_RSA) && defined(HAVE_IO_TESTS_DEPENDENCIES) && \
    !defined(NO_SESSION_CACHE) && defined(OPENSSL_EXTRA) && \
    !defined(WOLFSSL_NO_TLS12)
static WOLFSSL_SESSION* test_wolfSSL_SESSION_expire_sess = NULL;

static void test_wolfSSL_SESSION_expire_downgrade_ctx_ready(WOLFSSL_CTX* ctx)
{
    #ifdef WOLFSSL_ERROR_CODE_OPENSSL
    /* returns previous timeout value */
    AssertIntEQ(wolfSSL_CTX_set_timeout(ctx, 1), 500);
    #else
    AssertIntEQ(wolfSSL_CTX_set_timeout(ctx, 1), WOLFSSL_SUCCESS);
    #endif
}


/* set the session to timeout in a second */
static void test_wolfSSL_SESSION_expire_downgrade_ssl_ready(WOLFSSL* ssl)
{
    AssertIntEQ(wolfSSL_set_timeout(ssl, 2), 1);
}


/* store the client side session from the first successful connection */
static void test_wolfSSL_SESSION_expire_downgrade_ssl_result(WOLFSSL* ssl)
{
    AssertPtrNE((test_wolfSSL_SESSION_expire_sess = wolfSSL_get1_session(ssl)),
        NULL); /* ref count 1 */
}


/* wait till session is expired then set it in the WOLFSSL struct for use */
static void test_wolfSSL_SESSION_expire_downgrade_ssl_ready_wait(WOLFSSL* ssl)
{
    AssertIntEQ(wolfSSL_set_timeout(ssl, 1), 1);
    AssertIntEQ(wolfSSL_set_session(ssl, test_wolfSSL_SESSION_expire_sess),
        WOLFSSL_SUCCESS);
    XSLEEP_MS(2000); /* wait 2 seconds for session to expire */
}


/* set expired session in the WOLFSSL struct for use */
static void test_wolfSSL_SESSION_expire_downgrade_ssl_ready_set(WOLFSSL* ssl)
{
    XSLEEP_MS(1200); /* wait a second for session to expire */

    /* set the expired session, call to set session fails but continuing on
       after failure should be handled here */
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL)
    AssertIntEQ(wolfSSL_set_session(ssl, test_wolfSSL_SESSION_expire_sess),
        WOLFSSL_SUCCESS);
#else
    AssertIntNE(wolfSSL_set_session(ssl, test_wolfSSL_SESSION_expire_sess),
        WOLFSSL_SUCCESS);
#endif
}


/* check that the expired session was not reused */
static void test_wolfSSL_SESSION_expire_downgrade_ssl_result_reuse(WOLFSSL* ssl)
{
    /* since the session has expired it should not have been reused */
    AssertIntEQ(wolfSSL_session_reused(ssl), 0);
}
#endif

static int test_wolfSSL_SESSION_expire_downgrade(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
    !defined(NO_RSA) && defined(HAVE_IO_TESTS_DEPENDENCIES) && \
    !defined(NO_SESSION_CACHE) && defined(OPENSSL_EXTRA) && \
    !defined(WOLFSSL_NO_TLS12)
    callback_functions server_cbf, client_cbf;

    XMEMSET(&server_cbf, 0, sizeof(callback_functions));
    XMEMSET(&client_cbf, 0, sizeof(callback_functions));

    /* force server side to use TLS 1.2 */
    server_cbf.method = wolfTLSv1_2_server_method;

    client_cbf.method = wolfSSLv23_client_method;
    server_cbf.ctx_ready = test_wolfSSL_SESSION_expire_downgrade_ctx_ready;
    client_cbf.ssl_ready = test_wolfSSL_SESSION_expire_downgrade_ssl_ready;
    client_cbf.on_result = test_wolfSSL_SESSION_expire_downgrade_ssl_result;

    test_wolfSSL_client_server_nofail(&client_cbf, &server_cbf);
    ExpectIntEQ(client_cbf.return_code, TEST_SUCCESS);
    ExpectIntEQ(server_cbf.return_code, TEST_SUCCESS);

    client_cbf.method = wolfSSLv23_client_method;
    server_cbf.ctx_ready = test_wolfSSL_SESSION_expire_downgrade_ctx_ready;
    client_cbf.ssl_ready = test_wolfSSL_SESSION_expire_downgrade_ssl_ready_wait;
    client_cbf.on_result =
        test_wolfSSL_SESSION_expire_downgrade_ssl_result_reuse;

    test_wolfSSL_client_server_nofail(&client_cbf, &server_cbf);
    ExpectIntEQ(client_cbf.return_code, TEST_SUCCESS);
    ExpectIntEQ(server_cbf.return_code, TEST_SUCCESS);

    client_cbf.method = wolfSSLv23_client_method;
    server_cbf.ctx_ready = test_wolfSSL_SESSION_expire_downgrade_ctx_ready;
    client_cbf.ssl_ready = test_wolfSSL_SESSION_expire_downgrade_ssl_ready_set;
    client_cbf.on_result =
        test_wolfSSL_SESSION_expire_downgrade_ssl_result_reuse;

    test_wolfSSL_client_server_nofail(&client_cbf, &server_cbf);
    ExpectIntEQ(client_cbf.return_code, TEST_SUCCESS);
    ExpectIntEQ(server_cbf.return_code, TEST_SUCCESS);

    wolfSSL_SESSION_free(test_wolfSSL_SESSION_expire_sess);
#endif
    return EXPECT_RESULT();
}

#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    defined(HAVE_EX_DATA) && !defined(NO_SESSION_CACHE)
#ifdef WOLFSSL_ATOMIC_OPS
    typedef wolfSSL_Atomic_Int SessRemCounter_t;
#else
    typedef int SessRemCounter_t;
#endif
static SessRemCounter_t clientSessRemCountMalloc;
static SessRemCounter_t serverSessRemCountMalloc;
static SessRemCounter_t clientSessRemCountFree;
static SessRemCounter_t serverSessRemCountFree;

static WOLFSSL_CTX* serverSessCtx = NULL;
static WOLFSSL_SESSION* serverSess = NULL;
#if (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) || \
        !defined(NO_SESSION_CACHE_REF)
static WOLFSSL_CTX* clientSessCtx = NULL;
static WOLFSSL_SESSION* clientSess = NULL;
#endif
static int serverSessRemIdx = 3;
static int sessRemCtx_Server = WOLFSSL_SERVER_END;
static int sessRemCtx_Client = WOLFSSL_CLIENT_END;

static void SessRemCtxCb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess)
{
    int* side;

    (void)ctx;

    side = (int*)SSL_SESSION_get_ex_data(sess, serverSessRemIdx);
    if (side != NULL) {
        if (*side == WOLFSSL_CLIENT_END)
            (void)wolfSSL_Atomic_Int_FetchAdd(&clientSessRemCountFree, 1);
        else
            (void)wolfSSL_Atomic_Int_FetchAdd(&serverSessRemCountFree, 1);

        SSL_SESSION_set_ex_data(sess, serverSessRemIdx, NULL);
    }
}

static int SessRemCtxSetupCb(WOLFSSL_CTX* ctx)
{
    SSL_CTX_sess_set_remove_cb(ctx, SessRemCtxCb);
#if defined(WOLFSSL_TLS13) && !defined(HAVE_SESSION_TICKET) && \
        !defined(NO_SESSION_CACHE_REF)
    {
        EXPECT_DECLS;
        /* Allow downgrade, set min version, and disable TLS 1.3.
         * Do this because without NO_SESSION_CACHE_REF we will want to return a
         * reference to the session cache. But with WOLFSSL_TLS13 and without
         * HAVE_SESSION_TICKET we won't have a session ID to be able to place
         * the session in the cache. In this case we need to downgrade to
         * previous versions to just use the legacy session ID field. */
        ExpectIntEQ(SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION),
            SSL_SUCCESS);
        ExpectIntEQ(SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION),
            SSL_SUCCESS);
        return EXPECT_RESULT();
    }
#else
    return TEST_SUCCESS;
#endif
}

static int SessRemSslSetupCb(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    int* side;

    if (SSL_is_server(ssl)) {
        side = &sessRemCtx_Server;
        (void)wolfSSL_Atomic_Int_FetchAdd(&serverSessRemCountMalloc, 1);
        ExpectNotNull(serverSess = SSL_get1_session(ssl));
        ExpectIntEQ(SSL_CTX_up_ref(serverSessCtx = SSL_get_SSL_CTX(ssl)),
                SSL_SUCCESS);
    }
    else {
        side = &sessRemCtx_Client;
        (void)wolfSSL_Atomic_Int_FetchAdd(&clientSessRemCountMalloc, 1);
#if (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) || \
    !defined(NO_SESSION_CACHE_REF)
        ExpectNotNull(clientSess = SSL_get1_session(ssl));
        ExpectIntEQ(SSL_CTX_up_ref(clientSessCtx = SSL_get_SSL_CTX(ssl)),
                SSL_SUCCESS);
#endif
    }
    ExpectIntEQ(SSL_SESSION_set_ex_data(SSL_get_session(ssl),
        serverSessRemIdx, side), SSL_SUCCESS);

    return EXPECT_RESULT();
}
#endif

static int test_wolfSSL_CTX_sess_set_remove_cb(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    defined(HAVE_EX_DATA) && !defined(NO_SESSION_CACHE)
    /* Check that the remove callback gets called for external data in a
     * session object */
    test_ssl_cbf func_cb;

    wolfSSL_Atomic_Int_Init(&clientSessRemCountMalloc, 0);
    wolfSSL_Atomic_Int_Init(&serverSessRemCountMalloc, 0);
    wolfSSL_Atomic_Int_Init(&clientSessRemCountFree, 0);
    wolfSSL_Atomic_Int_Init(&serverSessRemCountFree, 0);

    XMEMSET(&func_cb, 0, sizeof(func_cb));
    func_cb.ctx_ready = SessRemCtxSetupCb;
    func_cb.on_result = SessRemSslSetupCb;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb, &func_cb,
        NULL), TEST_SUCCESS);

    /* Both should have been allocated */
    ExpectIntEQ(clientSessRemCountMalloc, 1);
    ExpectIntEQ(serverSessRemCountMalloc, 1);

    /* This should not be called yet. Session wasn't evicted from cache yet. */
    ExpectIntEQ(clientSessRemCountFree, 0);
#if (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) || \
        !defined(NO_SESSION_CACHE_REF)
    /* Force a cache lookup */
    ExpectNotNull(SSL_SESSION_get_ex_data(clientSess, serverSessRemIdx));
    /* Force a cache update */
    ExpectNotNull(SSL_SESSION_set_ex_data(clientSess, serverSessRemIdx - 1, 0));
    /* This should set the timeout to 0 and call the remove callback from within
     * the session cache. Returns 1 per OpenSSL semantics (session was
     * present in the cache and removed). */
    ExpectIntEQ(SSL_CTX_remove_session(clientSessCtx, clientSess), 1);
    ExpectNull(SSL_SESSION_get_ex_data(clientSess, serverSessRemIdx));
    ExpectIntEQ(clientSessRemCountFree, 1);
#endif
    /* Server session is in the cache so ex_data isn't free'd with the SSL
     * object */
    ExpectIntEQ(serverSessRemCountFree, 0);
    /* Force a cache lookup */
    ExpectNotNull(SSL_SESSION_get_ex_data(serverSess, serverSessRemIdx));
    /* Force a cache update */
    ExpectNotNull(SSL_SESSION_set_ex_data(serverSess, serverSessRemIdx - 1, 0));
    /* This should set the timeout to 0 and call the remove callback from within
     * the session cache. Returns 1 per OpenSSL semantics (session was
     * present in the cache and removed). */
    ExpectIntEQ(SSL_CTX_remove_session(serverSessCtx, serverSess), 1);
    ExpectNull(SSL_SESSION_get_ex_data(serverSess, serverSessRemIdx));
    ExpectIntEQ(serverSessRemCountFree, 1);
    /* Need to free the references that we kept */
    SSL_CTX_free(serverSessCtx);
    SSL_SESSION_free(serverSess);
#if (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) || \
        !defined(NO_SESSION_CACHE_REF)
    SSL_CTX_free(clientSessCtx);
    SSL_SESSION_free(clientSess);
#endif
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_ticket_keys(void)
{
    EXPECT_DECLS;
#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
    !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS)
    WOLFSSL_CTX* ctx = NULL;
    byte keys[WOLFSSL_TICKET_KEYS_SZ];

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));

    ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(NULL, NULL, 0),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(ctx, NULL, 0),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(ctx, keys, 0),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(NULL, keys, 0),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(NULL, NULL, sizeof(keys)),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(ctx, NULL, sizeof(keys)),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(NULL, keys, sizeof(keys)),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(NULL, NULL, 0),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(ctx, NULL, 0),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(ctx, keys, 0),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(NULL, keys, 0),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(NULL, NULL, sizeof(keys)),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(ctx, NULL, sizeof(keys)),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(NULL, keys, sizeof(keys)),
                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(ctx, keys, sizeof(keys)),
                WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(ctx, keys, sizeof(keys)),
                WOLFSSL_SUCCESS);

    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

#ifndef NO_BIO

#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_HAVE_MLDSA)
/* Verify wc_MlDsaKey auto detects the expected ML-DSA level from the OID
 * in a SPKI / PKCS#8 DER buffer. Returns 0 on match. */
static int check_mldsa_der_level(const byte* der, word32 derSz,
    byte expectedLevel, int isPrivate)
{
    wc_MlDsaKey key;
    word32 idx = 0;
    byte level = 0;
    int rc;
#ifndef WOLFSSL_MLDSA_PRIVATE_KEY
    (void)isPrivate;
#endif

    if ((rc = wc_MlDsaKey_Init(&key, NULL, INVALID_DEVID)) != 0) {
        return rc;
    }

#if defined(WOLFSSL_MLDSA_PRIVATE_KEY)
    if (isPrivate) {
        rc = wc_MlDsaKey_PrivateKeyDecode(&key, der, derSz, &idx);
    }
    else
#endif
    {
        rc = wc_MlDsaKey_PublicKeyDecode(&key, der, derSz, &idx);
    }

    if (rc == 0) {
        rc = wc_MlDsaKey_GetParams(&key, &level);
    }

    if (rc == 0 && level != expectedLevel) {
        rc = -1;
    }

    wc_MlDsaKey_Free(&key);

    return rc;
}
#endif /* OPENSSL_EXTRA && WOLFSSL_HAVE_MLDSA */

static int test_wolfSSL_d2i_PUBKEY(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    BIO* bio = NULL;
    EVP_PKEY* pkey = NULL;

    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectNull(d2i_PUBKEY_bio(NULL, NULL));

#if defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA)
    /* RSA PUBKEY test */
    ExpectIntGT(BIO_write(bio, client_keypub_der_2048,
        sizeof_client_keypub_der_2048), 0);
    ExpectNotNull(pkey = d2i_PUBKEY_bio(bio, NULL));
    EVP_PKEY_free(pkey);
    pkey = NULL;
#endif

#if defined(USE_CERT_BUFFERS_256) && defined(HAVE_ECC)
    /* ECC PUBKEY test */
    ExpectIntGT(BIO_write(bio, ecc_clikeypub_der_256,
        sizeof_ecc_clikeypub_der_256), 0);
    ExpectNotNull(pkey = d2i_PUBKEY_bio(bio, NULL));
    EVP_PKEY_free(pkey);
    pkey = NULL;
#endif

#if defined(USE_CERT_BUFFERS_2048) && !defined(NO_DSA)
    /* DSA PUBKEY test */
    ExpectIntGT(BIO_write(bio, dsa_pub_key_der_2048,
        sizeof_dsa_pub_key_der_2048), 0);
    ExpectNotNull(pkey = d2i_PUBKEY_bio(bio, NULL));
    EVP_PKEY_free(pkey);
    pkey = NULL;
#endif

#if defined(USE_CERT_BUFFERS_2048) && !defined(NO_DH) && \
defined(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA)
#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
            (HAVE_FIPS_VERSION > 2))
    /* DH PUBKEY test */
    ExpectIntGT(BIO_write(bio, dh_pub_key_der_2048,
        sizeof_dh_pub_key_der_2048), 0);
    ExpectNotNull(pkey = d2i_PUBKEY_bio(bio, NULL));
    EVP_PKEY_free(pkey);
    pkey = NULL;
#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
#endif /*  USE_CERT_BUFFERS_2048 && !NO_DH &&  && OPENSSL_EXTRA */

#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_MLDSA_NO_VERIFY)

#if !defined(WOLFSSL_NO_ML_DSA_44)
    /* ML-DSA-44 PUBKEY test (raw key bytes) */
    ExpectIntGT(BIO_write(bio, bench_mldsa_44_pubkey,
        sizeof_bench_mldsa_44_pubkey), 0);
    ExpectNotNull(pkey = d2i_PUBKEY_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    EVP_PKEY_free(pkey);
    pkey = NULL;

    /* ML-DSA-44 PUBKEY test (LAMPS SubjectPublicKeyInfo DER) */
    ExpectIntGT(BIO_write(bio, mldsa44_pub_spki, sizeof_mldsa44_pub_spki), 0);
    ExpectNotNull(pkey = d2i_PUBKEY_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    ExpectIntEQ(check_mldsa_der_level(mldsa44_pub_spki,
        sizeof_mldsa44_pub_spki, WC_ML_DSA_44, 0), 0);
    EVP_PKEY_free(pkey);
    pkey = NULL;
#endif

#if !defined(WOLFSSL_NO_ML_DSA_65)
    /* ML-DSA-65 PUBKEY test (raw key bytes) */
    ExpectIntGT(BIO_write(bio, bench_mldsa_65_pubkey,
        sizeof_bench_mldsa_65_pubkey), 0);
    ExpectNotNull(pkey = d2i_PUBKEY_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    EVP_PKEY_free(pkey);
    pkey = NULL;

    /* ML-DSA-65 PUBKEY test (LAMPS SubjectPublicKeyInfo DER) */
    ExpectIntGT(BIO_write(bio, mldsa65_pub_spki, sizeof_mldsa65_pub_spki), 0);
    ExpectNotNull(pkey = d2i_PUBKEY_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    ExpectIntEQ(check_mldsa_der_level(mldsa65_pub_spki,
        sizeof_mldsa65_pub_spki, WC_ML_DSA_65, 0), 0);
    EVP_PKEY_free(pkey);
    pkey = NULL;
#endif

#if !defined(WOLFSSL_NO_ML_DSA_87)
    /* ML-DSA-87 PUBKEY test (raw key bytes) */
    ExpectIntGT(BIO_write(bio, bench_mldsa_87_pubkey,
        sizeof_bench_mldsa_87_pubkey), 0);
    ExpectNotNull(pkey = d2i_PUBKEY_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    EVP_PKEY_free(pkey);
    pkey = NULL;

    /* ML-DSA-87 PUBKEY test (LAMPS SubjectPublicKeyInfo DER) */
    ExpectIntGT(BIO_write(bio, mldsa87_pub_spki, sizeof_mldsa87_pub_spki), 0);
    ExpectNotNull(pkey = d2i_PUBKEY_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    ExpectIntEQ(check_mldsa_der_level(mldsa87_pub_spki,
        sizeof_mldsa87_pub_spki, WC_ML_DSA_87, 0), 0);
    EVP_PKEY_free(pkey);
    pkey = NULL;
#endif

#endif /* WOLFSSL_HAVE_MLDSA && !NO_VERIFY */

    /* Negative test, invalid input must return NULL */
    {
        BIO* nbio = NULL;
        unsigned char garbage[64];
        XMEMSET(garbage, 0xA5, sizeof(garbage));
        ExpectNotNull(nbio = BIO_new(BIO_s_mem()));
        ExpectIntGT(BIO_write(nbio, garbage, (int)sizeof(garbage)), 0);
        ExpectNull(d2i_PUBKEY_bio(nbio, NULL));
        BIO_free(nbio);
    }

    /* Negative test: unrecognized input with a pre-allocated *out must
     * return NULL, not the caller pre-existing key. */
    {
        unsigned char garbage[64];
        const unsigned char* p = garbage;
        EVP_PKEY* preAlloc = NULL;
        EVP_PKEY* result;

        XMEMSET(garbage, 0xA5, sizeof(garbage));
        ExpectNotNull(preAlloc = EVP_PKEY_new());
        result = preAlloc;
        ExpectNull(d2i_PUBKEY(&result, &p, (long)sizeof(garbage)));
        EVP_PKEY_free(preAlloc);
    }

    BIO_free(bio);

    (void)pkey;
#endif

    return EXPECT_RESULT();
}

#if (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO)) && !defined(NO_RSA) && \
    !defined(NO_TLS)
static int test_wolfSSL_d2i_PrivateKeys_bio(void)
{
    EXPECT_DECLS;
    BIO*      bio = NULL;
    EVP_PKEY* pkey  = NULL;
    WOLFSSL_CTX* ctx = NULL;

#if defined(WOLFSSL_KEY_GEN)
    unsigned char buff[4096];
    unsigned char* bufPtr = buff;
#endif

    /* test creating new EVP_PKEY with bad arg */
    ExpectNull((pkey = d2i_PrivateKey_bio(NULL, NULL)));

    /* test loading RSA key using BIO */
#if !defined(NO_RSA) && !defined(NO_FILESYSTEM)
    {
        XFILE file = XBADFILE;
        const char* fname = "./certs/server-key.der";
        long lsz = 0;
        size_t sz = 0;
        byte* buf = NULL;

        ExpectTrue((file = XFOPEN(fname, "rb")) != XBADFILE);
        ExpectTrue(XFSEEK(file, 0, XSEEK_END) == 0);
        ExpectTrue((lsz = XFTELL(file)) > 0);
        sz = (size_t)lsz;
        ExpectTrue(XFSEEK(file, 0, XSEEK_SET) == 0);
        ExpectNotNull(buf = (byte*)XMALLOC(sz, HEAP_HINT, DYNAMIC_TYPE_FILE));
        ExpectIntEQ(XFREAD(buf, 1, sz, file), sz);
        if (file != XBADFILE) {
            XFCLOSE(file);
        }

        /* Test using BIO new mem and loading DER private key */
        ExpectNotNull(bio = BIO_new_mem_buf(buf, (int)sz));
        ExpectNotNull((pkey = d2i_PrivateKey_bio(bio, NULL)));
        XFREE(buf, HEAP_HINT, DYNAMIC_TYPE_FILE);
        BIO_free(bio);
        bio = NULL;
        EVP_PKEY_free(pkey);
        pkey  = NULL;
    }
#endif

    /* test loading ECC key using BIO */
#if defined(HAVE_ECC) && !defined(NO_FILESYSTEM)
    {
        XFILE file = XBADFILE;
        const char* fname = "./certs/ecc-key.der";
        long lsz = 0;
        size_t sz = 0;
        byte* buf = NULL;

        ExpectTrue((file = XFOPEN(fname, "rb")) != XBADFILE);
        ExpectTrue(XFSEEK(file, 0, XSEEK_END) == 0);
        ExpectTrue((lsz = XFTELL(file)) > 0);
        sz = (size_t)lsz;
        ExpectTrue(XFSEEK(file, 0, XSEEK_SET) == 0);
        ExpectNotNull(buf = (byte*)XMALLOC(sz, HEAP_HINT, DYNAMIC_TYPE_FILE));
        ExpectIntEQ(XFREAD(buf, 1, sz, file), sz);
        if (file != XBADFILE)
            XFCLOSE(file);

        /* Test using BIO new mem and loading DER private key */
        ExpectNotNull(bio = BIO_new_mem_buf(buf, (int)sz));
        ExpectNotNull((pkey = d2i_PrivateKey_bio(bio, NULL)));
        XFREE(buf, HEAP_HINT, DYNAMIC_TYPE_FILE);
        BIO_free(bio);
        bio = NULL;
        EVP_PKEY_free(pkey);
        pkey = NULL;
    }
#endif

#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_MLDSA_NO_SIGN)
#if !defined(WOLFSSL_NO_ML_DSA_44)
    /* ML-DSA-44 PrivateKey test (raw bytes) */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntGT(BIO_write(bio, bench_mldsa_44_key,
        sizeof_bench_mldsa_44_key), 0);
    ExpectNotNull(pkey = d2i_PrivateKey_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;

    /* ML-DSA-44 PrivateKey test (LAMPS PKCS#8 priv-only DER) */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntGT(BIO_write(bio, mldsa44_priv_only,
        sizeof_mldsa44_priv_only), 0);
    ExpectNotNull(pkey = d2i_PrivateKey_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    ExpectIntEQ(check_mldsa_der_level(mldsa44_priv_only,
        sizeof_mldsa44_priv_only, WC_ML_DSA_44, 1), 0);
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;

    /* ML-DSA-44 PrivateKey test (LAMPS PKCS#8 seed-priv DER) */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntGT(BIO_write(bio, mldsa44_seed_priv,
        sizeof_mldsa44_seed_priv), 0);
    ExpectNotNull(pkey = d2i_PrivateKey_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;

#ifndef WOLFSSL_MLDSA_NO_MAKE_KEY
    /* ML-DSA-44 PrivateKey test (LAMPS PKCS#8 seed-only DER) --
     * requires wc_dilithium_make_key_from_seed to expand the seed. */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntGT(BIO_write(bio, mldsa44_seed_only,
        sizeof_mldsa44_seed_only), 0);
    ExpectNotNull(pkey = d2i_PrivateKey_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;
#endif
#endif

#if !defined(WOLFSSL_NO_ML_DSA_65)
    /* ML-DSA-65 PrivateKey test (raw bytes) */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntGT(BIO_write(bio, bench_mldsa_65_key,
        sizeof_bench_mldsa_65_key), 0);
    ExpectNotNull(pkey = d2i_PrivateKey_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;

    /* ML-DSA-65 PrivateKey test (LAMPS PKCS#8 priv-only DER) */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntGT(BIO_write(bio, mldsa65_priv_only,
        sizeof_mldsa65_priv_only), 0);
    ExpectNotNull(pkey = d2i_PrivateKey_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    ExpectIntEQ(check_mldsa_der_level(mldsa65_priv_only,
        sizeof_mldsa65_priv_only, WC_ML_DSA_65, 1), 0);
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;

    /* ML-DSA-65 PrivateKey test (LAMPS PKCS#8 seed-priv DER) */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntGT(BIO_write(bio, mldsa65_seed_priv,
        sizeof_mldsa65_seed_priv), 0);
    ExpectNotNull(pkey = d2i_PrivateKey_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;

#ifndef WOLFSSL_MLDSA_NO_MAKE_KEY
    /* ML-DSA-65 PrivateKey test (LAMPS PKCS#8 seed-only DER) --
     * requires wc_dilithium_make_key_from_seed to expand the seed. */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntGT(BIO_write(bio, mldsa65_seed_only,
        sizeof_mldsa65_seed_only), 0);
    ExpectNotNull(pkey = d2i_PrivateKey_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;
#endif
#endif

#if !defined(WOLFSSL_NO_ML_DSA_87)
    /* ML-DSA-87 PrivateKey test (raw bytes) */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntGT(BIO_write(bio, bench_mldsa_87_key,
        sizeof_bench_mldsa_87_key), 0);
    ExpectNotNull(pkey = d2i_PrivateKey_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;

    /* ML-DSA-87 PrivateKey test (LAMPS PKCS#8 priv-only DER) */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntGT(BIO_write(bio, mldsa87_priv_only,
        sizeof_mldsa87_priv_only), 0);
    ExpectNotNull(pkey = d2i_PrivateKey_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    ExpectIntEQ(check_mldsa_der_level(mldsa87_priv_only,
        sizeof_mldsa87_priv_only, WC_ML_DSA_87, 1), 0);
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;

    /* ML-DSA-87 PrivateKey test (LAMPS PKCS#8 seed-priv DER) */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntGT(BIO_write(bio, mldsa87_seed_priv,
        sizeof_mldsa87_seed_priv), 0);
    ExpectNotNull(pkey = d2i_PrivateKey_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;

#ifndef WOLFSSL_MLDSA_NO_MAKE_KEY
    /* ML-DSA-87 PrivateKey test (LAMPS PKCS#8 seed-only DER) --
     * requires wc_dilithium_make_key_from_seed to expand the seed. */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntGT(BIO_write(bio, mldsa87_seed_only,
        sizeof_mldsa87_seed_only), 0);
    ExpectNotNull(pkey = d2i_PrivateKey_bio(bio, NULL));
    ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
    EVP_PKEY_free(pkey);
    pkey = NULL;
    BIO_free(bio);
    bio = NULL;
#endif
#endif
#endif /* WOLFSSL_HAVE_MLDSA && !NO_SIGN */

    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
#ifndef NO_WOLFSSL_SERVER
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
#else
    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
#endif

#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA)
    {
        const unsigned char seqOnly[] = { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00 };
        RSA* rsa = NULL;
        /* Tests bad parameters */
        ExpectNull(d2i_RSAPrivateKey_bio(NULL, NULL));

        /* Test using bad data. */
        ExpectIntGT(BIO_write(bio, seqOnly, sizeof(seqOnly)), 0);
        ExpectNull(d2i_RSAPrivateKey_bio(bio, NULL));

        /* RSA not set yet, expecting to fail*/
        rsa = wolfSSL_RSA_new();
        ExpectIntEQ(SSL_CTX_use_RSAPrivateKey(ctx, rsa), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
        wolfSSL_RSA_free(rsa);
        rsa = NULL;

#if defined(USE_CERT_BUFFERS_2048) && defined(WOLFSSL_KEY_GEN)
        /* set RSA using bio*/
        ExpectIntGT(BIO_write(bio, client_key_der_2048,
                    sizeof_client_key_der_2048), 0);
        ExpectNotNull(d2i_RSAPrivateKey_bio(bio, &rsa));
        ExpectNotNull(rsa);

        /* Tests bad parameters */
        ExpectIntEQ(SSL_CTX_use_RSAPrivateKey(NULL, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
        ExpectIntEQ(SSL_CTX_use_RSAPrivateKey(ctx, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
        ExpectIntEQ(SSL_CTX_use_RSAPrivateKey(NULL, rsa), WC_NO_ERR_TRACE(BAD_FUNC_ARG));

        ExpectIntEQ(SSL_CTX_use_RSAPrivateKey(ctx, rsa), WOLFSSL_SUCCESS);

        /* i2d RSAprivate key tests */
        ExpectIntEQ(wolfSSL_i2d_RSAPrivateKey(NULL, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
        ExpectIntEQ(wolfSSL_i2d_RSAPrivateKey(rsa, NULL), 1192);
        ExpectIntEQ(wolfSSL_i2d_RSAPrivateKey(rsa, &bufPtr),
                                               sizeof_client_key_der_2048);
        bufPtr -= sizeof_client_key_der_2048;
        ExpectIntEQ(XMEMCMP(bufPtr, client_key_der_2048,
                            sizeof_client_key_der_2048), 0);
        bufPtr = NULL;
        ExpectIntEQ(wolfSSL_i2d_RSAPrivateKey(rsa, &bufPtr),
                                               sizeof_client_key_der_2048);
        ExpectNotNull(bufPtr);
        ExpectIntEQ(XMEMCMP(bufPtr, client_key_der_2048,
                            sizeof_client_key_der_2048), 0);
        XFREE(bufPtr, NULL, DYNAMIC_TYPE_OPENSSL);

        RSA_free(rsa);
        rsa = NULL;
        /* d2i_RSA_PUBKEY_bio should fail when given private key DER.
         * wc_RsaPublicKeyDecode correctly rejects private key format. */
        ExpectIntGT(BIO_write(bio, client_key_der_2048,
                    sizeof_client_key_der_2048), 0);
        ExpectNull(d2i_RSA_PUBKEY_bio(bio, &rsa));
        (void)BIO_reset(bio);

        rsa = RSA_new();
        ExpectIntEQ(wolfSSL_i2d_RSAPrivateKey(rsa, NULL), 0);
#endif /* USE_CERT_BUFFERS_2048 WOLFSSL_KEY_GEN */
        RSA_free(rsa);
    }
#endif /* WOLFSSL_KEY_GEN && !NO_RSA */

    /* Negative test, invalid input must return NULL */
    {
        BIO* nbio = NULL;
        unsigned char garbage[64];
        XMEMSET(garbage, 0xA5, sizeof(garbage));
        ExpectNotNull(nbio = BIO_new(BIO_s_mem()));
        ExpectIntGT(BIO_write(nbio, garbage, (int)sizeof(garbage)), 0);
        ExpectNull(d2i_PrivateKey_bio(nbio, NULL));
        BIO_free(nbio);
    }

    /* Negative test: unrecognized input with a pre-allocated *out must
     * return NULL, not the caller pre-existing key. */
    {
        unsigned char garbage[64];
        unsigned char* p = garbage;
        EVP_PKEY* preAlloc = NULL;
        EVP_PKEY* result;

        XMEMSET(garbage, 0xA5, sizeof(garbage));
        ExpectNotNull(preAlloc = EVP_PKEY_new());
        result = preAlloc;
        ExpectNull(wolfSSL_d2i_PrivateKey_EVP(&result, &p,
            (long)sizeof(garbage)));
        EVP_PKEY_free(preAlloc);
    }

    SSL_CTX_free(ctx);
    ctx = NULL;
    BIO_free(bio);
    bio = NULL;

    return EXPECT_RESULT();
}
#endif /* OPENSSL_ALL || (WOLFSSL_ASIO && !NO_RSA) */

#endif /* !NO_BIO */


static int test_wolfSSL_sk_GENERAL_NAME(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
    !defined(NO_RSA)
    X509* x509 = NULL;
    GENERAL_NAME* gn = NULL;
    GENERAL_NAME* dup_gn = NULL;
    unsigned char buf[4096];
    const unsigned char* bufPt = NULL;
    int bytes = 0;
    int i;
    int j;
    XFILE f = XBADFILE;
    STACK_OF(GENERAL_NAME)* sk = NULL;

    ExpectTrue((f = XFOPEN(cliCertDerFileExt, "rb")) != XBADFILE);
    ExpectIntGT((bytes = (int)XFREAD(buf, 1, sizeof(buf), f)), 0);
    if (f != XBADFILE)
        XFCLOSE(f);

    for (j = 0; j < 2; ++j) {
        bufPt = buf;
        ExpectNotNull(x509 = d2i_X509(NULL, &bufPt, bytes));

        ExpectNotNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509,
                    NID_subject_alt_name, NULL, NULL));

        ExpectIntEQ(sk_GENERAL_NAME_num(sk), 1);
        for (i = 0; i < sk_GENERAL_NAME_num(sk); i++) {
            ExpectNotNull(gn = sk_GENERAL_NAME_value(sk, i));

            if (gn != NULL) {
                switch (gn->type) {
                case GEN_DNS:
                    fprintf(stderr, "found type GEN_DNS\n");
                    break;
                case GEN_EMAIL:
                    fprintf(stderr, "found type GEN_EMAIL\n");
                    break;
                case GEN_URI:
                    fprintf(stderr, "found type GEN_URI\n");
                    break;
                }
            }

            ExpectNotNull(dup_gn = wolfSSL_GENERAL_NAME_dup(gn));
            wolfSSL_GENERAL_NAME_free(dup_gn);
            dup_gn = NULL;
        }
        X509_free(x509);
        x509 = NULL;
        if (j == 0) {
            sk_GENERAL_NAME_pop_free(sk, GENERAL_NAME_free);
        }
        else {
            /*
             * We had a bug where GENERAL_NAMES_free didn't free all the memory
             * it was supposed to. This is a regression test for that bug.
             */
            GENERAL_NAMES_free(sk);
        }
        sk = NULL;
    }

    ExpectNull(wolfSSL_GENERAL_NAME_dup(NULL));
    ExpectIntEQ(wolfSSL_GENERAL_NAME_set_type(NULL, WOLFSSL_GEN_IA5),
        BAD_FUNC_ARG);
    wolfSSL_GENERAL_NAMES_free(NULL);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_GENERAL_NAME_print(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_BIO) && !defined(NO_RSA)
    X509* x509 = NULL;
    GENERAL_NAME* gn = NULL;
    GENERAL_NAME* dup_gn = NULL;
    unsigned char buf[4096];
    const unsigned char* bufPt = NULL;
    int bytes = 0;
    XFILE f = XBADFILE;
    STACK_OF(GENERAL_NAME)* sk = NULL;
    BIO* out = NULL;
    unsigned char outbuf[128];

    X509_EXTENSION* ext = NULL;
    AUTHORITY_INFO_ACCESS* aia = NULL;
    ACCESS_DESCRIPTION* ad = NULL;
    ASN1_IA5STRING *dnsname = NULL;
    ASN1_OBJECT* ridObj = NULL;

    const unsigned char v4Addr[] = {192,168,53,1};
    const unsigned char v6Addr[] =
                            {0x20, 0x21, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
                             0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x77, 0x77};
    const unsigned char email[]  =
                             {'i', 'n', 'f', 'o', '@', 'w', 'o', 'l',
                              'f', 's', 's', 'l', '.', 'c', 'o', 'm'};
    const unsigned char ridData[] = { 0x06, 0x04, 0x2a, 0x03, 0x04, 0x05 };
    const unsigned char* p;
    unsigned long len;

    const char* dnsStr     = "DNS:example.com";
    const char* uriStr     = "URI:http://127.0.0.1:22220";
    const char* v4addStr   = "IP Address:192.168.53.1";
    const char* v6addStr   = "IP Address:2021:DB8:0:0:0:FF00:42:7777";
    const char* emailStr   = "email:info@wolfssl.com";
    const char* othrStr    = "othername:<unsupported>";
    const char* x400Str    = "X400Name:<unsupported>";
    const char* ediStr     = "EdiPartyName:<unsupported>";
    const char* dirNameStr = "DirName:";
    const char* ridStr     = "Registered ID:1.2.3.4.5";

    /* BIO to output */
    ExpectNotNull(out = BIO_new(BIO_s_mem()));

    /* test for NULL param */
    gn = NULL;

    ExpectIntEQ(GENERAL_NAME_print(NULL, NULL), 0);
    ExpectIntEQ(GENERAL_NAME_print(NULL, gn), 0);
    ExpectIntEQ(GENERAL_NAME_print(out, NULL), 0);


    /* test for GEN_DNS */
    ExpectTrue((f = XFOPEN(cliCertDerFileExt, "rb")) != XBADFILE);
    ExpectIntGT((bytes = (int)XFREAD(buf, 1, sizeof(buf), f)), 0);
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }

    bufPt = buf;
    ExpectNotNull(x509 = d2i_X509(NULL, &bufPt, bytes));
    ExpectNotNull(sk = (STACK_OF(ASN1_OBJECT)*)X509_get_ext_d2i(x509,
                NID_subject_alt_name, NULL, NULL));

    ExpectNotNull(gn = sk_GENERAL_NAME_value(sk, 0));
    ExpectIntEQ(GENERAL_NAME_print(out, gn), 1);

    XMEMSET(outbuf, 0, sizeof(outbuf));
    ExpectIntGT(BIO_read(out, outbuf, sizeof(outbuf)), 0);
    ExpectIntEQ(XSTRNCMP((const char*)outbuf, dnsStr, XSTRLEN(dnsStr)), 0);

    sk_GENERAL_NAME_pop_free(sk, GENERAL_NAME_free);
    gn = NULL;
    sk = NULL;
    X509_free(x509);
    x509 = NULL;

    /* Lets test for setting as well. */
    ExpectNotNull(gn = GENERAL_NAME_new());
    ExpectNotNull(dnsname = ASN1_IA5STRING_new());
    ExpectIntEQ(ASN1_STRING_set(dnsname, "example.com", -1), 1);
    GENERAL_NAME_set0_value(gn, GEN_DNS, dnsname);
    dnsname = NULL;
    ExpectIntEQ(GENERAL_NAME_print(out, gn), 1);
    XMEMSET(outbuf, 0, sizeof(outbuf));
    ExpectIntGT(BIO_read(out, outbuf, sizeof(outbuf)), 0);
    ExpectIntEQ(XSTRNCMP((const char*)outbuf, dnsStr, XSTRLEN(dnsStr)), 0);
    ExpectNotNull(dup_gn = GENERAL_NAME_dup(gn));
    wolfSSL_GENERAL_NAME_set0_value(NULL, WOLFSSL_GEN_IA5, NULL);
    wolfSSL_GENERAL_NAME_set0_value(dup_gn, WOLFSSL_GEN_IA5, NULL);
    wolfSSL_GENERAL_NAME_set0_value(NULL, WOLFSSL_GEN_DNS, NULL);
    wolfSSL_GENERAL_NAME_set0_value(NULL, WOLFSSL_GEN_IA5, outbuf);
    wolfSSL_GENERAL_NAME_set0_value(dup_gn, WOLFSSL_GEN_DNS, NULL);
    wolfSSL_GENERAL_NAME_set0_value(dup_gn, WOLFSSL_GEN_IA5, outbuf);
    wolfSSL_GENERAL_NAME_set0_value(NULL, WOLFSSL_GEN_DNS, outbuf);
    GENERAL_NAME_free(dup_gn);
    dup_gn = NULL;
    GENERAL_NAME_free(gn);

    /* test for GEN_URI */

    ExpectTrue((f = XFOPEN("./certs/ocsp/root-ca-cert.pem", "rb")) != XBADFILE);
    ExpectNotNull(x509 = wolfSSL_PEM_read_X509(f, NULL, NULL, NULL));
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }

    ExpectNotNull(ext = wolfSSL_X509_get_ext(x509, 4));
    ExpectNotNull(aia = (WOLFSSL_AUTHORITY_INFO_ACCESS*)wolfSSL_X509V3_EXT_d2i(
        ext));
    ExpectNotNull(ad = (WOLFSSL_ACCESS_DESCRIPTION *)wolfSSL_sk_value(aia, 0));

    if (ad != NULL) {
        gn = ad->location;
    }
    ExpectNotNull(dup_gn = GENERAL_NAME_dup(gn));
    GENERAL_NAME_free(dup_gn);
    dup_gn = NULL;
    ExpectIntEQ(GENERAL_NAME_print(out, gn), 1);
    gn = NULL;

    XMEMSET(outbuf,0,sizeof(outbuf));
    ExpectIntGT(BIO_read(out, outbuf, sizeof(outbuf)), 0);
    ExpectIntEQ(XSTRNCMP((const char*)outbuf, uriStr, XSTRLEN(uriStr)), 0);

    wolfSSL_sk_ACCESS_DESCRIPTION_pop_free(aia, NULL);
    aia = NULL;
    aia = (AUTHORITY_INFO_ACCESS*)wolfSSL_X509V3_EXT_d2i(ext);
    ExpectNotNull(aia);
    AUTHORITY_INFO_ACCESS_pop_free(aia, NULL);
    aia = NULL;
    X509_free(x509);
    x509 = NULL;

    /* test for GEN_IPADD */

    /* ip v4 address */
    ExpectNotNull(gn = wolfSSL_GENERAL_NAME_new());
    if (gn != NULL) {
        gn->type = GEN_IPADD;
        if (gn->d.iPAddress != NULL) {
            gn->d.iPAddress->length = sizeof(v4Addr);
        }
    }
    ExpectIntEQ(wolfSSL_ASN1_STRING_set(gn->d.iPAddress, v4Addr,
        sizeof(v4Addr)), 1);

    ExpectIntEQ(GENERAL_NAME_print(out, gn), 1);
    XMEMSET(outbuf,0,sizeof(outbuf));
    ExpectIntGT(BIO_read(out, outbuf, sizeof(outbuf)), 0);
    ExpectIntEQ(XSTRNCMP((const char*)outbuf, v4addStr, XSTRLEN(v4addStr)), 0);

    ExpectNotNull(dup_gn = GENERAL_NAME_dup(gn));
    GENERAL_NAME_free(dup_gn);
    dup_gn = NULL;

    GENERAL_NAME_free(gn);
    gn = NULL;

    /* ip v6 address */

    ExpectNotNull(gn = wolfSSL_GENERAL_NAME_new());
    if (gn != NULL) {
        gn->type = GEN_IPADD;
        if (gn->d.iPAddress != NULL) {
            gn->d.iPAddress->length = sizeof(v6Addr);
        }
    }
    ExpectIntEQ(wolfSSL_ASN1_STRING_set(gn->d.iPAddress, v6Addr,
        sizeof(v6Addr)), 1);

    ExpectIntEQ(GENERAL_NAME_print(out, gn), 1);
    XMEMSET(outbuf,0,sizeof(outbuf));
    ExpectIntGT(BIO_read(out, outbuf, sizeof(outbuf)), 0);
    ExpectIntEQ(XSTRNCMP((const char*)outbuf, v6addStr, XSTRLEN(v6addStr)), 0);

    ExpectNotNull(dup_gn = GENERAL_NAME_dup(gn));
    GENERAL_NAME_free(dup_gn);
    dup_gn = NULL;

    GENERAL_NAME_free(gn);
    gn = NULL;

    /* test for GEN_EMAIL */

    ExpectNotNull(gn = wolfSSL_GENERAL_NAME_new());
    if (gn != NULL) {
        gn->type = GEN_EMAIL;
        if (gn->d.rfc822Name != NULL) {
            gn->d.rfc822Name->length = sizeof(email);
        }
    }
    ExpectIntEQ(wolfSSL_ASN1_STRING_set(gn->d.rfc822Name, email, sizeof(email)),
        1);

    ExpectIntEQ(GENERAL_NAME_print(out, gn), 1);
    XMEMSET(outbuf,0,sizeof(outbuf));
    ExpectIntGT(BIO_read(out, outbuf, sizeof(outbuf)), 0);
    ExpectIntEQ(XSTRNCMP((const char*)outbuf, emailStr, XSTRLEN(emailStr)), 0);

    ExpectNotNull(dup_gn = GENERAL_NAME_dup(gn));
    GENERAL_NAME_free(dup_gn);
    dup_gn = NULL;

    GENERAL_NAME_free(gn);
    gn = NULL;

    /* test for  GEN_OTHERNAME */

    ExpectNotNull(gn = wolfSSL_GENERAL_NAME_new());
    if (gn != NULL) {
        gn->type = GEN_OTHERNAME;
    }

    ExpectIntEQ(GENERAL_NAME_print(out, gn), 1);
    XMEMSET(outbuf,0,sizeof(outbuf));
    ExpectIntGT(BIO_read(out, outbuf, sizeof(outbuf)), 0);
    ExpectIntEQ(XSTRNCMP((const char*)outbuf, othrStr, XSTRLEN(othrStr)), 0);

    GENERAL_NAME_free(gn);
    gn = NULL;

    /* test for  GEN_X400 */

    ExpectNotNull(gn = wolfSSL_GENERAL_NAME_new());
    if (gn != NULL) {
        gn->type = GEN_X400;
    }

    ExpectIntEQ(GENERAL_NAME_print(out, gn), 1);
    XMEMSET(outbuf,0,sizeof(outbuf));
    ExpectIntGT(BIO_read(out, outbuf, sizeof(outbuf)), 0);
    ExpectIntEQ(XSTRNCMP((const char*)outbuf, x400Str, XSTRLEN(x400Str)), 0);

    /* Restore to GEN_IA5 (default) to avoid memory leak. */
    if (gn != NULL) {
        gn->type = GEN_IA5;
    }

    /* Duplicating GEN_X400 not supported. */
    ExpectNull(GENERAL_NAME_dup(gn));

    GENERAL_NAME_free(gn);
    gn = NULL;

    /* test for GEN_EDIPARTY */

    ExpectNotNull(gn = wolfSSL_GENERAL_NAME_new());
    if (gn != NULL) {
        gn->type = GEN_EDIPARTY;
    }

    ExpectIntEQ(GENERAL_NAME_print(out, gn), 1);
    XMEMSET(outbuf,0,sizeof(outbuf));
    ExpectIntGT(BIO_read(out, outbuf, sizeof(outbuf)), 0);
    ExpectIntEQ(XSTRNCMP((const char*)outbuf, ediStr, XSTRLEN(ediStr)), 0);

    /* Restore to GEN_IA5 (default) to avoid memory leak. */
    if (gn != NULL) {
        gn->type = GEN_IA5;
    }

    /* Duplicating GEN_EDIPARTY not supported. */
    ExpectNull(dup_gn = GENERAL_NAME_dup(gn));

    GENERAL_NAME_free(gn);
    gn = NULL;

    /* test for GEN_DIRNAME */
    ExpectNotNull(gn = wolfSSL_GENERAL_NAME_new());
    if (gn != NULL) {
        gn->type = GEN_DIRNAME;
    }
    ExpectIntEQ(GENERAL_NAME_print(out, gn), 1);
    XMEMSET(outbuf,0,sizeof(outbuf));
    ExpectIntGT(BIO_read(out, outbuf, sizeof(outbuf)), 0);
    ExpectIntEQ(XSTRNCMP((const char*)outbuf, dirNameStr, XSTRLEN(dirNameStr)),
        0);
    /* Duplicating GEN_DIRNAME not supported. */
    ExpectNull(dup_gn = GENERAL_NAME_dup(gn));
    /* Restore to GEN_IA5 (default) to avoid memory leak. */
    if (gn != NULL) {
        gn->type = GEN_IA5;
    }
    GENERAL_NAME_free(gn);
    gn = NULL;

    /* test for GEN_RID */
    p = ridData;
    len = sizeof(ridData);
    ExpectNotNull(ridObj = wolfSSL_d2i_ASN1_OBJECT(NULL, &p, len));
    ExpectNotNull(gn = wolfSSL_GENERAL_NAME_new());
    if (gn != NULL) {
        gn->type = GEN_RID;
        wolfSSL_ASN1_STRING_free(gn->d.ia5);
        gn->d.registeredID = ridObj;
    }
    else {
        wolfSSL_ASN1_OBJECT_free(ridObj);
    }
    ExpectIntEQ(GENERAL_NAME_print(out, gn), 1);
    XMEMSET(outbuf,0,sizeof(outbuf));
    ExpectIntGT(BIO_read(out, outbuf, sizeof(outbuf)), 0);
    ExpectIntEQ(XSTRNCMP((const char*)outbuf, ridStr, XSTRLEN(ridStr)), 0);
    /* Duplicating GEN_DIRNAME not supported. */
    ExpectNull(dup_gn = GENERAL_NAME_dup(gn));
    GENERAL_NAME_free(gn);
    gn = NULL;

    BIO_free(out);
#endif /* OPENSSL_ALL */
    return EXPECT_RESULT();
}

static int test_wolfSSL_sk_DIST_POINT(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
    !defined(NO_RSA)
    X509* x509 = NULL;
    unsigned char buf[4096];
    const unsigned char* bufPt;
    int bytes = 0;
    int i = 0;
    int j = 0;
    XFILE f = XBADFILE;
    DIST_POINT* dp = NULL;
    DIST_POINT_NAME* dpn = NULL;
    GENERAL_NAME* gn = NULL;
    ASN1_IA5STRING* uri = NULL;
    STACK_OF(DIST_POINT)* dps = NULL;
    STACK_OF(GENERAL_NAME)* gns = NULL;
    const char cliCertDerCrlDistPoint[] = "./certs/client-crl-dist.der";

    ExpectTrue((f = XFOPEN(cliCertDerCrlDistPoint, "rb")) != XBADFILE);
    ExpectIntGT((bytes = (int)XFREAD(buf, 1, sizeof(buf), f)), 0);
    if (f != XBADFILE)
        XFCLOSE(f);

    bufPt = buf;
    ExpectNotNull(x509 = d2i_X509(NULL, &bufPt, bytes));

    ExpectNotNull(dps = (STACK_OF(DIST_POINT)*)X509_get_ext_d2i(x509,
        NID_crl_distribution_points, NULL, NULL));

    ExpectIntEQ(sk_DIST_POINT_num(dps), 1);
    for (i = 0; i < sk_DIST_POINT_num(dps); i++) {
        ExpectNotNull(dp = sk_DIST_POINT_value(dps, i));
        ExpectNotNull(dpn = dp->distpoint);

        /* this should be type 0, fullname */
        ExpectIntEQ(dpn->type, 0);

        ExpectNotNull(gns = dp->distpoint->name.fullname);
        ExpectIntEQ(sk_GENERAL_NAME_num(gns), 1);

        for (j = 0; j < sk_GENERAL_NAME_num(gns); j++) {
            ExpectNotNull(gn = sk_GENERAL_NAME_value(gns, j));
            ExpectIntEQ(gn->type, GEN_URI);
            ExpectNotNull(uri = gn->d.uniformResourceIdentifier);
            ExpectNotNull(uri->data);
            ExpectIntGT(uri->length, 0);
        }
    }

    ExpectNotNull(dp = wolfSSL_DIST_POINT_new());
    wolfSSL_DIST_POINT_free(NULL);
    wolfSSL_DIST_POINTS_free(NULL);
    wolfSSL_sk_DIST_POINT_free(NULL);
    ExpectIntEQ(wolfSSL_sk_DIST_POINT_push(NULL, NULL), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_sk_DIST_POINT_push(dps, NULL), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_sk_DIST_POINT_push(NULL, dp), WOLFSSL_FAILURE);
    ExpectNull(wolfSSL_sk_DIST_POINT_value(NULL, 0));
    ExpectIntEQ(wolfSSL_sk_DIST_POINT_num(NULL), WOLFSSL_FATAL_ERROR);
    wolfSSL_DIST_POINT_free(dp);

    X509_free(x509);
    CRL_DIST_POINTS_free(dps);

#endif
    return EXPECT_RESULT();
}



static int test_wolfSSL_verify_mode(void)
{
    EXPECT_DECLS;
#if !defined(NO_RSA) && !defined(NO_TLS) && (defined(OPENSSL_ALL) || \
    defined(HAVE_STUNNEL) || defined(WOLFSSL_MYSQL_COMPATIBLE) || \
    defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)) && \
    !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL*     ssl = NULL;
    WOLFSSL_CTX* ctx = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));

    ExpectNotNull(ssl = SSL_new(ctx));
    ExpectIntEQ(SSL_get_verify_mode(ssl), SSL_CTX_get_verify_mode(ctx));
    SSL_free(ssl);
    ssl = NULL;

    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 0);
    ExpectNotNull(ssl = SSL_new(ctx));
    ExpectIntEQ(SSL_get_verify_mode(ssl), SSL_CTX_get_verify_mode(ctx));
    ExpectIntEQ(SSL_get_verify_mode(ssl), SSL_VERIFY_PEER);

    wolfSSL_set_verify(ssl, SSL_VERIFY_NONE, 0);
    ExpectIntEQ(SSL_CTX_get_verify_mode(ctx), SSL_VERIFY_PEER);
    ExpectIntEQ(SSL_get_verify_mode(ssl), SSL_VERIFY_NONE);

    SSL_free(ssl);
    ssl = NULL;

    wolfSSL_CTX_set_verify(ctx,
        WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
    ExpectNotNull(ssl = SSL_new(ctx));
    ExpectIntEQ(SSL_get_verify_mode(ssl), SSL_CTX_get_verify_mode(ctx));
    ExpectIntEQ(SSL_get_verify_mode(ssl),
        WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT);

    wolfSSL_set_verify(ssl, SSL_VERIFY_PEER, 0);
    ExpectIntEQ(SSL_CTX_get_verify_mode(ctx),
        WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT);
    ExpectIntEQ(SSL_get_verify_mode(ssl), SSL_VERIFY_PEER);

    wolfSSL_set_verify(ssl, SSL_VERIFY_NONE, 0);
    ExpectIntEQ(SSL_get_verify_mode(ssl), SSL_VERIFY_NONE);

    wolfSSL_set_verify(ssl, SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
    ExpectIntEQ(SSL_get_verify_mode(ssl), SSL_VERIFY_FAIL_IF_NO_PEER_CERT);

    wolfSSL_set_verify(ssl, SSL_VERIFY_FAIL_EXCEPT_PSK, 0);
    ExpectIntEQ(SSL_get_verify_mode(ssl), SSL_VERIFY_FAIL_EXCEPT_PSK);

#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
    wolfSSL_set_verify(ssl, SSL_VERIFY_POST_HANDSHAKE, 0);
    ExpectIntEQ(SSL_get_verify_mode(ssl), SSL_VERIFY_POST_HANDSHAKE);
#endif

    ExpectIntEQ(SSL_CTX_get_verify_mode(ctx),
        WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT);

    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}


static int test_wolfSSL_verify_depth(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL*     ssl = NULL;
    WOLFSSL_CTX* ctx = NULL;
    long         depth = 0;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectIntGT((depth = SSL_CTX_get_verify_depth(ctx)), 0);

    ExpectNotNull(ssl = SSL_new(ctx));
    ExpectIntEQ(SSL_get_verify_depth(ssl), SSL_CTX_get_verify_depth(ctx));
    SSL_free(ssl);
    ssl = NULL;

    SSL_CTX_set_verify_depth(ctx, -1);
    ExpectIntEQ(depth, SSL_CTX_get_verify_depth(ctx));

    SSL_CTX_set_verify_depth(ctx, 2);
    ExpectIntEQ(2, SSL_CTX_get_verify_depth(ctx));
    ExpectNotNull(ssl = SSL_new(ctx));
    ExpectIntEQ(2, SSL_get_verify_depth(ssl));

    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_verify_result(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
    defined(OPENSSL_ALL)) && !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL*     ssl = NULL;
    WOLFSSL_CTX* ctx = NULL;
    long         result = 0xDEADBEEF;

    ExpectIntEQ(WC_NO_ERR_TRACE(WOLFSSL_FAILURE), wolfSSL_get_verify_result(ssl));

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = SSL_new(ctx));

    wolfSSL_set_verify_result(ssl, result);
    ExpectIntEQ(result, wolfSSL_get_verify_result(ssl));

    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_CLIENT)
static void sslMsgCb(int w, int version, int type, const void* buf,
        size_t sz, SSL* ssl, void* arg)
{
    int i;
    unsigned char* pt = (unsigned char*)buf;

    fprintf(stderr, "%s %d bytes of version %d , type %d : ",
            (w)?"Writing":"Reading", (int)sz, version, type);
    for (i = 0; i < (int)sz; i++) fprintf(stderr, "%02X", pt[i]);
    fprintf(stderr, "\n");
    (void)ssl;
    (void)arg;
}
#endif /* OPENSSL_EXTRA */

static int test_wolfSSL_msg_callback(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_TLS) && \
    !defined(NO_WOLFSSL_CLIENT)
    WOLFSSL*     ssl = NULL;
    WOLFSSL_CTX* ctx = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectNotNull(ssl = SSL_new(ctx));
    ExpectIntEQ(SSL_set_msg_callback(ssl, NULL), SSL_SUCCESS);
    ExpectIntEQ(SSL_set_msg_callback(ssl, &sslMsgCb), SSL_SUCCESS);
    ExpectIntEQ(SSL_set_msg_callback(NULL, &sslMsgCb), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_X509_SEP(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && defined(WOLFSSL_SEP)
    WOLFSSL_X509* x509 = NULL;
#if 0
    byte* out;
#endif
    int outSz;

    ExpectNotNull(x509 = wolfSSL_X509_new());

    outSz = 0;
    ExpectNull(wolfSSL_X509_get_device_type(NULL, NULL, NULL));
    ExpectNull(wolfSSL_X509_get_device_type(x509, NULL, NULL));
    ExpectNull(wolfSSL_X509_get_device_type(NULL, NULL, &outSz));
    ExpectNull(wolfSSL_X509_get_device_type(x509, NULL, &outSz));

    outSz = 0;
    ExpectNull(wolfSSL_X509_get_hw_type(NULL, NULL, NULL));
    ExpectNull(wolfSSL_X509_get_hw_type(x509, NULL, NULL));
    ExpectNull(wolfSSL_X509_get_hw_type(NULL, NULL, &outSz));
    ExpectNull(wolfSSL_X509_get_hw_type(x509, NULL, &outSz));

    outSz = 0;
    ExpectNull(wolfSSL_X509_get_hw_serial_number(NULL, NULL, NULL));
    ExpectNull(wolfSSL_X509_get_hw_serial_number(x509, NULL, NULL));
    ExpectNull(wolfSSL_X509_get_hw_serial_number(NULL, NULL, &outSz));
    ExpectNull(wolfSSL_X509_get_hw_serial_number(x509, NULL, &outSz));

    ExpectIntEQ(wolfSSL_X509_ext_isSet_by_NID(x509,
        WC_NID_certificate_policies), 0);

    wolfSSL_X509_free(x509);
    x509 = NULL;

#if 0
    /* Use certificate with the extension here. */
    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(svrCertFile,
        SSL_FILETYPE_PEM));

    outSz = 0;
    ExpectNotNull(out = wolfSSL_X509_get_device_type(x509, NULL, &outSz));
    ExpectIntGT(outSz, 0);
    XFREE(out, NULL, DYNAMIC_TYPE_OPENSSL);

    outSz = 0;
    ExpectNotNull(out = wolfSSL_X509_get_hw_type(x509, NULL, &outSz));
    ExpectIntGT(outSz, 0);
    XFREE(out, NULL, DYNAMIC_TYPE_OPENSSL);

    outSz = 0;
    ExpectNotNull(out = wolfSSL_X509_get_hw_serial_number(x509, NULL, &outSz));
    ExpectIntGT(outSz, 0);
    XFREE(out, NULL, DYNAMIC_TYPE_OPENSSL);

    wolfSSL_X509_free(x509);
#endif
#endif
    return EXPECT_RESULT();
}

/* Test wolfSSL_X509_set_* extension functions */
static int test_wolfSSL_X509_set_extensions(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS)
    WOLFSSL_X509* x509 = NULL;
#ifdef WOLFSSL_CERT_EXT
    byte skid[20] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
    byte akid[20] = {20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};
#endif
#ifndef IGNORE_NETSCAPE_CERT_TYPE
    int nsCertType = 0;
#endif

    ExpectNotNull(x509 = wolfSSL_X509_new());

#ifdef WOLFSSL_CERT_EXT
    /* Test wolfSSL_X509_set_subject_key_id */
    ExpectIntEQ(wolfSSL_X509_set_subject_key_id(NULL, skid, sizeof(skid)),
                WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_set_subject_key_id(x509, NULL, sizeof(skid)),
                WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_set_subject_key_id(x509, skid, 0),
                WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_set_subject_key_id(x509, skid, sizeof(skid)),
                WOLFSSL_SUCCESS);

    /* Test wolfSSL_X509_set_authority_key_id */
    ExpectIntEQ(wolfSSL_X509_set_authority_key_id(NULL, akid, sizeof(akid)),
                WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_set_authority_key_id(x509, NULL, sizeof(akid)),
                WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_set_authority_key_id(x509, akid, 0),
                WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_set_authority_key_id(x509, akid, sizeof(akid)),
                WOLFSSL_SUCCESS);

    /* Test wolfSSL_X509_CRL_add_dist_point */
    ExpectIntEQ(wolfSSL_X509_CRL_add_dist_point(NULL,
                "http://crl.example.com/ca.crl", 0), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_CRL_add_dist_point(x509, NULL, 0),
                WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_CRL_add_dist_point(x509,
                "http://crl.example.com/ca.crl", 0), WOLFSSL_SUCCESS);

    /* Test wolfSSL_X509_CRL_set_dist_points with raw DER */
    {
        /* Simple CRL DP DER encoding for "http://example.com/crl" */
        byte crlDer[] = {
            0x30, 0x1d, /* SEQUENCE (outer) */
            0x30, 0x1b, /* SEQUENCE (DistributionPoint) */
            0xa0, 0x19, /* [0] EXPLICIT */
            0xa0, 0x17, /* [0] IMPLICIT GeneralNames */
            0x86, 0x15, /* [6] URI */
            'h','t','t','p',':','/','/','e','x','a','m','p','l','e','.','c',
            'o','m','/','c','r','l'
        };
        ExpectIntEQ(wolfSSL_X509_CRL_set_dist_points(NULL, crlDer,
                    sizeof(crlDer)), WOLFSSL_FAILURE);
        ExpectIntEQ(wolfSSL_X509_CRL_set_dist_points(x509, NULL,
                    sizeof(crlDer)), WOLFSSL_FAILURE);
        ExpectIntEQ(wolfSSL_X509_CRL_set_dist_points(x509, crlDer, 0),
                    WOLFSSL_FAILURE);
        ExpectIntEQ(wolfSSL_X509_CRL_set_dist_points(x509, crlDer,
                    sizeof(crlDer)), WOLFSSL_SUCCESS);
    }
#endif /* WOLFSSL_CERT_EXT */

#ifndef IGNORE_NETSCAPE_CERT_TYPE
    /* Test wolfSSL_X509_set_ns_cert_type */
    nsCertType = WC_NS_SSL_CLIENT | WC_NS_SSL_SERVER;
    ExpectIntEQ(wolfSSL_X509_set_ns_cert_type(NULL, nsCertType),
                WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_set_ns_cert_type(x509, nsCertType),
                WOLFSSL_SUCCESS);
#endif

    wolfSSL_X509_free(x509);
#endif /* OPENSSL_EXTRA && !NO_CERTS */
    return EXPECT_RESULT();
}

/* Round trip test for wolfSSL_X509_set_authority_key_id() with a raw key ID.
 *
 * Builds a cert, calls the setter with a 20-byte raw keyId, signs the cert,
 * serializes to DER via wolfSSL_i2d_X509(), re-parses the DER, locates the
 * AKID extension, and asserts the OCTET STRING contents match the
 * AuthorityKeyIdentifier ASN.1 structure required by RFC 5280 4.2.1.1:
 *
 *     SEQUENCE (0x30) length 22 (0x16)
 *         [0] (0x80) length 20 (0x14)
 *             <20 keyId bytes>
 *
 * The keyId bytes inside the [0] tag must equal the input passed the setter. */
static int test_wolfSSL_X509_set_authority_key_id_roundtrip(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
    defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN) && \
    !defined(NO_RSA) && !defined(NO_FILESYSTEM) && !defined(NO_ASN_TIME)
    WOLFSSL_X509* src = NULL;
    WOLFSSL_X509* built = NULL;
    WOLFSSL_X509* parsed = NULL;
    WOLFSSL_EVP_PKEY* priv = NULL;
    WOLFSSL_EVP_PKEY* pub = NULL;
    WOLFSSL_ASN1_TIME* notBefore = NULL;
    WOLFSSL_ASN1_TIME* notAfter = NULL;
    WOLFSSL_X509_EXTENSION* ext = NULL;
    WOLFSSL_ASN1_STRING* extData = NULL;
    unsigned char* der = NULL;
    const unsigned char* derPtr = NULL;
    unsigned char* key = NULL;
    unsigned char* keyPt = NULL;
    char* name = NULL;
    char* header = NULL;
    long keySz = 0;
    int derSz = 0;
    int extIdx = -1;
    XFILE fp = XBADFILE;
    time_t t;

    /* Raw 20-byte key identifier */
    byte akid[20] = {
        0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,
        0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23
    };

    /* Load reference cert + key (RSA) */
    src = wolfSSL_X509_load_certificate_file(cliCertFile, WOLFSSL_FILETYPE_PEM);
    ExpectNotNull(src);

    ExpectTrue((fp = XFOPEN(cliKeyFile, "rb")) != XBADFILE);
    ExpectIntEQ(wolfSSL_PEM_read(fp, &name, &header, &key, &keySz),
        WOLFSSL_SUCCESS);
    if (fp != XBADFILE) {
        XFCLOSE(fp);
    }
    keyPt = key;
    ExpectNotNull(priv = wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, NULL,
        (const unsigned char**)&keyPt, keySz));

    /* Build a v3 cert and copy fields from src */
    ExpectNotNull(built = wolfSSL_X509_new());
    ExpectIntEQ(wolfSSL_X509_set_version(built, 2), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_X509_set_subject_name(built,
        wolfSSL_X509_get_subject_name(src)), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_X509_set_issuer_name(built,
        wolfSSL_X509_get_issuer_name(src)), WOLFSSL_SUCCESS);
    ExpectNotNull(pub = wolfSSL_X509_get_pubkey(src));
    ExpectIntEQ(wolfSSL_X509_set_pubkey(built, pub), WOLFSSL_SUCCESS);

    t = time(NULL);
    ExpectNotNull(notBefore = wolfSSL_ASN1_TIME_adj(NULL, t, 0, 0));
    ExpectNotNull(notAfter = wolfSSL_ASN1_TIME_adj(NULL, t, 365, 0));
    ExpectTrue(wolfSSL_X509_set_notBefore(built, notBefore));
    ExpectTrue(wolfSSL_X509_set_notAfter(built, notAfter));

    /* Set AKID with a raw key identifier */
    ExpectIntEQ(wolfSSL_X509_set_authority_key_id(built, akid, sizeof(akid)),
        WOLFSSL_SUCCESS);

    /* Sign and serialize. */
    ExpectIntGT(wolfSSL_X509_sign(built, priv, EVP_sha256()), 0);
    ExpectIntGT((derSz = wolfSSL_i2d_X509(built, &der)), 0);

    /* Re-parse the DER we just produced */
    derPtr = der;
    ExpectNotNull(parsed = wolfSSL_d2i_X509(NULL, &derPtr, derSz));

    /* Locate the AKID extension and pull out the OCTET STRING contents
     * (per RFC 5280 must be a SEQUENCE { [0] keyIdentifier ... }) */
    ExpectIntGE((extIdx = wolfSSL_X509_get_ext_by_NID(parsed,
        NID_authority_key_identifier, -1)), 0);
    ExpectNotNull(ext = wolfSSL_X509_get_ext(parsed, extIdx));
    ExpectNotNull(extData = wolfSSL_X509_EXTENSION_get_data(ext));

    /* Encoded inner extension structure for a 20-byte keyId is 24 bytes:
     *     SEQUENCE (0x30) length 22 (0x16)
     *         [0] (0x80) length 20 (0x14)
     *             <20 keyId bytes>
     */
    ExpectIntEQ(extData->length, 24);
    if (extData != NULL && extData->data != NULL && extData->length == 24) {
        ExpectIntEQ((unsigned char)extData->data[0], 0x30);
        ExpectIntEQ((unsigned char)extData->data[1], 0x16);
        ExpectIntEQ((unsigned char)extData->data[2], 0x80);
        ExpectIntEQ((unsigned char)extData->data[3], 0x14);
        ExpectIntEQ(XMEMCMP((const byte*)extData->data + 4, akid,
            sizeof(akid)), 0);
    }

    XFREE(der, HEAP_HINT, DYNAMIC_TYPE_OPENSSL);
    XFREE(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(name, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(header, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);

    wolfSSL_X509_free(src);
    wolfSSL_X509_free(built);
    wolfSSL_X509_free(parsed);

    wolfSSL_EVP_PKEY_free(priv);
    wolfSSL_EVP_PKEY_free(pub);

    wolfSSL_ASN1_TIME_free(notBefore);
    wolfSSL_ASN1_TIME_free(notAfter);
#endif
    return EXPECT_RESULT();
}

/* Round trip test for wolfSSL_X509_set_authority_key_id_ex().
 *
 * Inserts a known SubjectKeyIdentifier on the issuer cert, calls the _ex
 * variant of the setter (which derives the AKID keyId from the issuer SKID,
 * or from SHA-1 of the issuer public key when no SKID is set), signs,
 * serializes to DER, re-parses, and asserts the AKID extension OCTET STRING
 * contents match the RFC 5280 4.2.1.1 structure
 *
 *     SEQUENCE (0x30) length 22 (0x16)
 *         [0] (0x80) length 20 (0x14)
 *             <20 keyId bytes>
 *
 * with the embedded keyId equal to the issuer's SKID. */
static int test_wolfSSL_X509_set_authority_key_id_ex_roundtrip(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
    defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN) && \
    !defined(NO_RSA) && !defined(NO_FILESYSTEM) && !defined(NO_ASN_TIME) && \
    !defined(NO_SHA)
    WOLFSSL_X509* issuer = NULL;
    WOLFSSL_X509* built = NULL;
    WOLFSSL_X509* parsed = NULL;
    WOLFSSL_EVP_PKEY* priv = NULL;
    WOLFSSL_EVP_PKEY* pub = NULL;
    WOLFSSL_ASN1_TIME* notBefore = NULL;
    WOLFSSL_ASN1_TIME* notAfter = NULL;
    WOLFSSL_X509_EXTENSION* ext = NULL;
    WOLFSSL_ASN1_STRING* extData = NULL;
    unsigned char* der = NULL;
    const unsigned char* derPtr = NULL;
    unsigned char* key = NULL;
    unsigned char* keyPt = NULL;
    char* name = NULL;
    char* header = NULL;
    long keySz = 0;
    int derSz = 0;
    int extIdx = -1;
    XFILE fp = XBADFILE;
    time_t t;

    /* SKID on the issuer. The AKID on the built cert should match this. */
    byte issuerSkid[20] = {
        0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,
        0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43
    };

    /* Load the cert to use as both issuer and the source of subject/key. */
    ExpectNotNull(issuer = wolfSSL_X509_load_certificate_file(cliCertFile,
        WOLFSSL_FILETYPE_PEM));

    /* Stamp known SKID on the issuer so set_authority_key_id_ex has a
     * deterministic value to copy into the AKID. */
    ExpectIntEQ(wolfSSL_X509_set_subject_key_id(issuer, issuerSkid,
        sizeof(issuerSkid)), WOLFSSL_SUCCESS);

    ExpectTrue((fp = XFOPEN(cliKeyFile, "rb")) != XBADFILE);
    ExpectIntEQ(wolfSSL_PEM_read(fp, &name, &header, &key, &keySz),
        WOLFSSL_SUCCESS);

    if (fp != XBADFILE) {
        XFCLOSE(fp);
    }

    keyPt = key;
    ExpectNotNull(priv = wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, NULL,
        (const unsigned char**)&keyPt, keySz));

    ExpectNotNull(built = wolfSSL_X509_new());
    ExpectIntEQ(wolfSSL_X509_set_version(built, 2), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_X509_set_subject_name(built,
        wolfSSL_X509_get_subject_name(issuer)), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_X509_set_issuer_name(built,
        wolfSSL_X509_get_subject_name(issuer)), WOLFSSL_SUCCESS);
    ExpectNotNull(pub = wolfSSL_X509_get_pubkey(issuer));
    ExpectIntEQ(wolfSSL_X509_set_pubkey(built, pub), WOLFSSL_SUCCESS);

    t = time(NULL);
    ExpectNotNull(notBefore = wolfSSL_ASN1_TIME_adj(NULL, t, 0, 0));
    ExpectNotNull(notAfter = wolfSSL_ASN1_TIME_adj(NULL, t, 365, 0));
    ExpectTrue(wolfSSL_X509_set_notBefore(built, notBefore));
    ExpectTrue(wolfSSL_X509_set_notAfter(built, notAfter));

    /* Derive AKID from the issuer's SKID */
    ExpectIntEQ(wolfSSL_X509_set_authority_key_id_ex(built, issuer),
        WOLFSSL_SUCCESS);

    ExpectIntGT(wolfSSL_X509_sign(built, priv, EVP_sha256()), 0);
    ExpectIntGT((derSz = wolfSSL_i2d_X509(built, &der)), 0);

    derPtr = der;
    ExpectNotNull(parsed = wolfSSL_d2i_X509(NULL, &derPtr, derSz));

    ExpectIntGE((extIdx = wolfSSL_X509_get_ext_by_NID(parsed,
        NID_authority_key_identifier, -1)), 0);
    ExpectNotNull(ext = wolfSSL_X509_get_ext(parsed, extIdx));
    ExpectNotNull(extData = wolfSSL_X509_EXTENSION_get_data(ext));

    /* AuthorityKeyIdentifier inner structure for a 20-byte keyId is 24 bytes:
     * SEQUENCE { [0] keyId }. keyId on built cert must equal issuer SKID. */
    ExpectIntEQ(extData->length, 24);
    if (extData != NULL && extData->data != NULL && extData->length == 24) {
        ExpectIntEQ((unsigned char)extData->data[0], 0x30);
        ExpectIntEQ((unsigned char)extData->data[1], 0x16);
        ExpectIntEQ((unsigned char)extData->data[2], 0x80);
        ExpectIntEQ((unsigned char)extData->data[3], 0x14);
        ExpectIntEQ(XMEMCMP((const byte*)extData->data + 4, issuerSkid,
            sizeof(issuerSkid)), 0);
    }

    XFREE(der, HEAP_HINT, DYNAMIC_TYPE_OPENSSL);
    XFREE(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(name, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(header, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);

    wolfSSL_X509_free(issuer);
    wolfSSL_X509_free(built);
    wolfSSL_X509_free(parsed);

    wolfSSL_EVP_PKEY_free(priv);
    wolfSSL_EVP_PKEY_free(pub);

    wolfSSL_ASN1_TIME_free(notBefore);
    wolfSSL_ASN1_TIME_free(notAfter);
#endif
    return EXPECT_RESULT();
}

/* Verifies that wolfSSL_X509_set_authority_key_id() correctly handles being
 * called on a WOLFSSL_X509 that already has AKID storage.
 *
 * Case 1: two consecutive setter calls on a fresh built cert. Calls setter
 *         twice with different keyIds (second call should replace first AKID).
 * Case 2: setter called on an X509 loaded from a PEM file that already has
 *         an AKID extension.
 */
static int test_wolfSSL_X509_set_authority_key_id_overwrite(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
    defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN) && \
    !defined(NO_RSA) && !defined(NO_FILESYSTEM) && !defined(NO_ASN_TIME)
    WOLFSSL_X509* src = NULL;
    WOLFSSL_X509* built = NULL;
    WOLFSSL_X509* parsed = NULL;
    WOLFSSL_X509* loaded = NULL;
    WOLFSSL_EVP_PKEY* priv = NULL;
    WOLFSSL_EVP_PKEY* pub = NULL;
    WOLFSSL_ASN1_TIME* notBefore = NULL;
    WOLFSSL_ASN1_TIME* notAfter = NULL;
    WOLFSSL_X509_EXTENSION* ext = NULL;
    WOLFSSL_ASN1_STRING* extData = NULL;
    unsigned char* der = NULL;
    const unsigned char* derPtr = NULL;
    unsigned char* key = NULL;
    unsigned char* keyPt = NULL;
    char* name = NULL;
    char* header = NULL;
    long keySz = 0;
    int derSz = 0;
    int extIdx = -1;
    XFILE fp = XBADFILE;
    time_t t;

    byte akid1[20] = {
        0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,
        0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14
    };
    byte akid2[20] = {
        0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x00,0x11,0x22,0x33,
        0x44,0x55,0x66,0x77,0x88,0x99,0xa0,0xb0,0xc0,0xd0
    };

    /* Case 1: set twice on a fresh built cert */
    ExpectNotNull(src = wolfSSL_X509_load_certificate_file(cliCertFile,
        WOLFSSL_FILETYPE_PEM));
    ExpectTrue((fp = XFOPEN(cliKeyFile, "rb")) != XBADFILE);
    ExpectIntEQ(wolfSSL_PEM_read(fp, &name, &header, &key, &keySz),
        WOLFSSL_SUCCESS);
    if (fp != XBADFILE) {
        XFCLOSE(fp);
    }

    keyPt = key;
    ExpectNotNull(priv = wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, NULL,
        (const unsigned char**)&keyPt, keySz));

    ExpectNotNull(built = wolfSSL_X509_new());
    ExpectIntEQ(wolfSSL_X509_set_version(built, 2), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_X509_set_subject_name(built,
        wolfSSL_X509_get_subject_name(src)), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_X509_set_issuer_name(built,
        wolfSSL_X509_get_issuer_name(src)), WOLFSSL_SUCCESS);
    ExpectNotNull(pub = wolfSSL_X509_get_pubkey(src));
    ExpectIntEQ(wolfSSL_X509_set_pubkey(built, pub), WOLFSSL_SUCCESS);

    t = time(NULL);
    ExpectNotNull(notBefore = wolfSSL_ASN1_TIME_adj(NULL, t, 0, 0));
    ExpectNotNull(notAfter = wolfSSL_ASN1_TIME_adj(NULL, t, 365, 0));
    ExpectTrue(wolfSSL_X509_set_notBefore(built, notBefore));
    ExpectTrue(wolfSSL_X509_set_notAfter(built, notAfter));

    /* Two setter calls with distinct keyIds, no prior AKID on cert */
    ExpectIntEQ(wolfSSL_X509_set_authority_key_id(built, akid1,
        sizeof(akid1)), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_X509_set_authority_key_id(built, akid2,
        sizeof(akid2)), WOLFSSL_SUCCESS);

    ExpectIntGT(wolfSSL_X509_sign(built, priv, EVP_sha256()), 0);
    ExpectIntGT((derSz = wolfSSL_i2d_X509(built, &der)), 0);

    derPtr = der;
    ExpectNotNull(parsed = wolfSSL_d2i_X509(NULL, &derPtr, derSz));

    ExpectIntGE((extIdx = wolfSSL_X509_get_ext_by_NID(parsed,
        NID_authority_key_identifier, -1)), 0);
    ExpectNotNull(ext = wolfSSL_X509_get_ext(parsed, extIdx));
    ExpectNotNull(extData = wolfSSL_X509_EXTENSION_get_data(ext));
    /* AKID extension must hold akid2, wrapped in:
     * SEQUENCE { [0] keyId } (24 bytes for a 20-byte keyId) */
    ExpectIntEQ(extData->length, 24);
    if (extData != NULL && extData->data != NULL && extData->length == 24) {
        ExpectIntEQ((unsigned char)extData->data[0], 0x30);
        ExpectIntEQ((unsigned char)extData->data[2], 0x80);
        ExpectIntEQ((unsigned char)extData->data[3], 0x14);
        ExpectIntEQ(XMEMCMP((const byte*)extData->data + 4, akid2,
            sizeof(akid2)), 0);
    }

    /* Free DER/parsed cert so Case 2 can reuse the variables. */
    XFREE(der, HEAP_HINT, DYNAMIC_TYPE_OPENSSL);
    der = NULL;
    derSz = 0;
    wolfSSL_X509_free(parsed);
    parsed = NULL;

    /* Case 2: set on cert loaded from PEM file that already has an AKID. */
    ExpectNotNull(loaded = wolfSSL_X509_load_certificate_file(cliCertFile,
        WOLFSSL_FILETYPE_PEM));
    ExpectIntEQ(wolfSSL_X509_set_authority_key_id(loaded, akid1,
        sizeof(akid1)), WOLFSSL_SUCCESS);

    /* Re-sign with priv and re-encode so we can inspect the freshly
     * encoded AKID. Signature/issuer binding correctness is not part of
     * this test; only the DER round-trip of the AKID extension is. */
    ExpectIntGT(wolfSSL_X509_sign(loaded, priv, EVP_sha256()), 0);
    ExpectIntGT((derSz = wolfSSL_i2d_X509(loaded, &der)), 0);

    derPtr = der;
    ExpectNotNull(parsed = wolfSSL_d2i_X509(NULL, &derPtr, derSz));

    extIdx = -1;
    ExpectIntGE((extIdx = wolfSSL_X509_get_ext_by_NID(parsed,
        NID_authority_key_identifier, -1)), 0);
    ExpectNotNull(ext = wolfSSL_X509_get_ext(parsed, extIdx));
    ExpectNotNull(extData = wolfSSL_X509_EXTENSION_get_data(ext));
    /* AKID extension must hold akid1 wrapped in SEQUENCE { [0] keyId }
     * (24 bytes for 20-byte keyId), not the original parsed-cert AKID. */
    ExpectIntEQ(extData->length, 24);
    if (extData != NULL && extData->data != NULL && extData->length == 24) {
        ExpectIntEQ((unsigned char)extData->data[0], 0x30);
        ExpectIntEQ((unsigned char)extData->data[2], 0x80);
        ExpectIntEQ((unsigned char)extData->data[3], 0x14);
        ExpectIntEQ(XMEMCMP((const byte*)extData->data + 4, akid1,
            sizeof(akid1)), 0);
    }

    XFREE(der, HEAP_HINT, DYNAMIC_TYPE_OPENSSL);
    XFREE(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(name, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(header, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);

    wolfSSL_X509_free(src);
    wolfSSL_X509_free(built);
    wolfSSL_X509_free(parsed);
    wolfSSL_X509_free(loaded);

    wolfSSL_EVP_PKEY_free(priv);
    wolfSSL_EVP_PKEY_free(pub);

    wolfSSL_ASN1_TIME_free(notBefore);
    wolfSSL_ASN1_TIME_free(notAfter);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_OpenSSL_add_all_algorithms(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    ExpectIntEQ(wolfSSL_add_all_algorithms(), WOLFSSL_SUCCESS);

    ExpectIntEQ(wolfSSL_OpenSSL_add_all_algorithms_noconf(), WOLFSSL_SUCCESS);

    ExpectIntEQ(wolfSSL_OpenSSL_add_all_algorithms_conf(), WOLFSSL_SUCCESS);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_OPENSSL_hexstr2buf(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    #define MAX_HEXSTR_BUFSZ 9
    #define NUM_CASES        5
    struct Output {
        const unsigned char buffer[MAX_HEXSTR_BUFSZ];
        long ret;
    };
    int i;
    int j;

    const char* inputs[NUM_CASES] = {
        "aabcd1357e",
        "01:12:23:34:a5:b6:c7:d8:e9",
        ":01:02",
        "012",
        ":ab:ac:d"
    };
    struct Output expectedOutputs[NUM_CASES] = {
        {{0xaa, 0xbc, 0xd1, 0x35, 0x7e}, 5},
        {{0x01, 0x12, 0x23, 0x34, 0xa5, 0xb6, 0xc7, 0xd8, 0xe9}, 9},
        {{0x01, 0x02}, 2},
        {{0x00}, 0},
        {{0x00}, 0}
    };
    long len = 0;
    unsigned char* returnedBuf = NULL;

    for (i = 0; i < NUM_CASES && !EXPECT_FAIL(); ++i) {
        returnedBuf = wolfSSL_OPENSSL_hexstr2buf(inputs[i], &len);
        if (returnedBuf == NULL) {
            ExpectIntEQ(expectedOutputs[i].ret, 0);
            continue;
        }

        ExpectIntEQ(expectedOutputs[i].ret, len);

        for (j = 0; j < len; ++j) {
            ExpectIntEQ(expectedOutputs[i].buffer[j], returnedBuf[j]);
        }
        OPENSSL_free(returnedBuf);
    }
#endif
    return EXPECT_RESULT();
}

#if defined(OPENSSL_ALL)
static int test_wolfSSL_sk_CIPHER_description(void)
{
    EXPECT_DECLS;
#if !defined(NO_RSA) && !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT)
    const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION;
    int i;
    int numCiphers = 0;
    const SSL_METHOD *method = NULL;
    const SSL_CIPHER *cipher = NULL;
    STACK_OF(SSL_CIPHER) *supportedCiphers = NULL;
    SSL_CTX *ctx = NULL;
    SSL *ssl = NULL;
    char buf[256];
    char test_str[9] = "0000000";
    const char badStr[] = "unknown";
    const char certPath[] = "./certs/client-cert.pem";
    XMEMSET(buf, 0, sizeof(buf));

    ExpectNotNull(method = TLSv1_2_client_method());
    ExpectNotNull(ctx = SSL_CTX_new(method));
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 0);
    SSL_CTX_set_verify_depth(ctx, 4);
    SSL_CTX_set_options(ctx, flags);
    ExpectIntEQ(SSL_CTX_load_verify_locations(ctx, certPath, NULL),
                WOLFSSL_SUCCESS);

    ExpectNotNull(ssl = SSL_new(ctx));
    /* SSL_get_ciphers returns a stack of all configured ciphers
     * A flag, getCipherAtOffset, is set to later have SSL_CIPHER_description
     */
    ExpectNotNull(supportedCiphers = SSL_get_ciphers(ssl));

    /* loop through the amount of supportedCiphers */
    numCiphers = sk_num(supportedCiphers);
    for (i = 0; i < numCiphers; ++i) {
        int j;
        /* sk_value increments "sk->data.cipher->cipherOffset".
         * wolfSSL_sk_CIPHER_description sets the description for
         * the cipher based on the provided offset.
         */
        if ((cipher = (const WOLFSSL_CIPHER*)sk_value(supportedCiphers, i))) {
            SSL_CIPHER_description(cipher, buf, sizeof(buf));
        }

        /* Search cipher description string for "unknown" descriptor */
        for (j = 0; j < (int)XSTRLEN(buf); j++) {
            int k = 0;
            while ((k < (int)XSTRLEN(badStr)) && (buf[j] == badStr[k])) {
                test_str[k] = badStr[k];
                j++;
                k++;
            }
        }
        /* Fail if test_str == badStr == "unknown" */
        ExpectStrNE(test_str,badStr);
    }
    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_get_ciphers_compat(void)
{
    EXPECT_DECLS;
#if !defined(NO_RSA) && !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT)
    const SSL_METHOD *method = NULL;
    const char certPath[] = "./certs/client-cert.pem";
    STACK_OF(SSL_CIPHER) *supportedCiphers = NULL;
    SSL_CTX *ctx = NULL;
    WOLFSSL *ssl = NULL;
    const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION;

    ExpectNotNull(method = SSLv23_client_method());
    ExpectNotNull(ctx = SSL_CTX_new(method));
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 0);
    SSL_CTX_set_verify_depth(ctx, 4);
    SSL_CTX_set_options(ctx, flags);
    ExpectIntEQ(SSL_CTX_load_verify_locations(ctx, certPath, NULL),
                WOLFSSL_SUCCESS);

    ExpectNotNull(ssl = SSL_new(ctx));

    /* Test Bad NULL input */
    ExpectNull(supportedCiphers = SSL_get_ciphers(NULL));
    /* Test for Good input */
    ExpectNotNull(supportedCiphers = SSL_get_ciphers(ssl));
    /* Further usage of SSL_get_ciphers/wolfSSL_get_ciphers_compat is
     * tested in test_wolfSSL_sk_CIPHER_description according to Qt usage */

    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

/* Test that wolfSSL_get_ciphers_compat returns NULL (not an empty stack)
 * when no ciphers are available for a given protocol configuration.
 * wolfSSL_get_ciphers_compat() is mapped to SSL_get_ciphers(), which has
 * an expected return of NULL when no ciphers are available. */
static int test_wolfSSL_get_ciphers_compat_empty(void)
{
    EXPECT_DECLS;
#if !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT)
    const SSL_METHOD *method = NULL;
    SSL_CTX *ctx = NULL;
    WOLFSSL *ssl = NULL;
    STACK_OF(SSL_CIPHER) *ciphers = NULL;

    ExpectNotNull(method = SSLv23_client_method());
    ExpectNotNull(ctx = SSL_CTX_new(method));
    ExpectNotNull(ssl = SSL_new(ctx));

    /* Disable all protocol versions via options mask so that
     * sslCipherMinMaxCheck filters out every cipher suite */
    wolfSSL_set_options(ssl, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 |
        SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3);

    ciphers = wolfSSL_get_ciphers_compat(ssl);

    /* Must be NULL, not a non-NULL empty stack */
    ExpectNull(ciphers);

    SSL_free(ssl);
    SSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_ctrl(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_TLS) && \
    !defined(NO_FILESYSTEM) && !defined(NO_RSA) && !defined(NO_WOLFSSL_SERVER)
    char caFile[] = "./certs/client-ca.pem";
    char clientFile[] = "./certs/client-cert.pem";
    SSL_CTX* ctx = NULL;
    X509* x509 = NULL;
#if !defined(NO_DH) && !defined(NO_DSA) && !defined(NO_BIO)
    byte buf[6000];
    char file[] = "./certs/dsaparams.pem";
    XFILE f = XBADFILE;
    int  bytes = 0;
    BIO* bio = NULL;
    DSA* dsa = NULL;
    DH*  dh = NULL;
#endif
#ifdef HAVE_ECC
    WOLFSSL_EC_KEY* ecKey = NULL;
#endif

    ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));

    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(caFile,
         WOLFSSL_FILETYPE_PEM));
    ExpectIntEQ((int)SSL_CTX_add_extra_chain_cert(ctx, x509), WOLFSSL_SUCCESS);
    if (EXPECT_FAIL()) {
        wolfSSL_X509_free(x509);
    }

    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(clientFile,
         WOLFSSL_FILETYPE_PEM));

#if !defined(NO_DH) && !defined(NO_DSA) && !defined(NO_BIO)
    /* Initialize DH */
    ExpectTrue((f = XFOPEN(file, "rb")) != XBADFILE);
    ExpectIntGT(bytes = (int)XFREAD(buf, 1, sizeof(buf), f), 0);
    if (f != XBADFILE)
        XFCLOSE(f);

    ExpectNotNull(bio = BIO_new_mem_buf((void*)buf, bytes));

    ExpectNotNull(dsa = wolfSSL_PEM_read_bio_DSAparams(bio, NULL, NULL, NULL));

    ExpectNotNull(dh = wolfSSL_DSA_dup_DH(dsa));
#endif
#ifdef HAVE_ECC
    /* Initialize WOLFSSL_EC_KEY */
    ExpectNotNull(ecKey = wolfSSL_EC_KEY_new());
    ExpectIntEQ(wolfSSL_EC_KEY_generate_key(ecKey), 1);
#endif

    /* additional test of getting EVP_PKEY key size from X509
     * Do not run with user RSA because wolfSSL_RSA_size is not currently
     * allowed with user RSA */
    {
        EVP_PKEY* pkey = NULL;
#if defined(HAVE_ECC)
        X509* ecX509 = NULL;
#endif /* HAVE_ECC */

        ExpectNotNull(pkey = X509_get_pubkey(x509));
        /* current RSA key is 2048 bit (256 bytes) */
        ExpectIntEQ(EVP_PKEY_size(pkey), 256);

        EVP_PKEY_free(pkey);
        pkey = NULL;

#if defined(HAVE_ECC)
#if defined(USE_CERT_BUFFERS_256)
        ExpectNotNull(ecX509 = wolfSSL_X509_load_certificate_buffer(
            cliecc_cert_der_256, sizeof_cliecc_cert_der_256,
            SSL_FILETYPE_ASN1));
#else
        ExpectNotNull(ecX509 = wolfSSL_X509_load_certificate_file(
            cliEccCertFile, SSL_FILETYPE_PEM));
#endif
        ExpectNotNull(pkey = X509_get_pubkey(ecX509));
        /* current ECC key is 256 bit (32 bytes) */
        ExpectIntGE(EVP_PKEY_size(pkey), 72);

        X509_free(ecX509);
        EVP_PKEY_free(pkey);
#endif /* HAVE_ECC */
    }

    /* Tests should fail with passed in NULL pointer */
    ExpectIntEQ((int)wolfSSL_CTX_ctrl(ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0, NULL),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#if !defined(NO_DH) && !defined(NO_DSA)
    ExpectIntEQ((int)wolfSSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_DH, 0, NULL),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif
#ifdef HAVE_ECC
    ExpectIntEQ((int)wolfSSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_ECDH, 0, NULL),
        WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif

    /* Test with SSL_CTRL_EXTRA_CHAIN_CERT
     * wolfSSL_CTX_ctrl should succesffuly call SSL_CTX_add_extra_chain_cert
     */
    ExpectIntEQ((int)wolfSSL_CTX_ctrl(ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0, x509),
        SSL_SUCCESS);
    if (EXPECT_FAIL()) {
        wolfSSL_X509_free(x509);
    }

    /* Test with SSL_CTRL_OPTIONS
     * wolfSSL_CTX_ctrl should succesffuly call SSL_CTX_set_options
     */
    ExpectTrue(wolfSSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, SSL_OP_NO_TLSv1,
        NULL) == SSL_OP_NO_TLSv1);
    ExpectTrue(SSL_CTX_get_options(ctx) == SSL_OP_NO_TLSv1);

    /* Test with SSL_CTRL_SET_TMP_DH
     * wolfSSL_CTX_ctrl should succesffuly call wolfSSL_SSL_CTX_set_tmp_dh
     */
#if !defined(NO_DH) && !defined(NO_DSA) && !defined(NO_BIO)
    ExpectIntEQ((int)wolfSSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_DH, 0, dh),
        SSL_SUCCESS);
#endif

    /* Test with SSL_CTRL_SET_TMP_ECDH
     * wolfSSL_CTX_ctrl should succesffuly call wolfSSL_SSL_CTX_set_tmp_ecdh
     */
#ifdef HAVE_ECC
    ExpectIntEQ((int)wolfSSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_ECDH, 0, ecKey),
        SSL_SUCCESS);
#endif

#ifdef WOLFSSL_ENCRYPTED_KEYS
    ExpectNull(SSL_CTX_get_default_passwd_cb(ctx));
    ExpectNull(SSL_CTX_get_default_passwd_cb_userdata(ctx));
#endif

    /* Test for min/max proto */
#ifndef WOLFSSL_NO_TLS12
    ExpectIntEQ((int)wolfSSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION,
        0, NULL), SSL_SUCCESS);
    ExpectIntEQ((int)wolfSSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION,
        TLS1_2_VERSION, NULL), SSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx), TLS1_2_VERSION);
#endif
#ifdef WOLFSSL_TLS13
    ExpectIntEQ((int)wolfSSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION,
        0, NULL), SSL_SUCCESS);

    ExpectIntEQ((int)wolfSSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION,
        TLS1_3_VERSION, NULL), SSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_get_max_proto_version(ctx), TLS1_3_VERSION);
#ifndef WOLFSSL_NO_TLS12
    ExpectIntEQ((int)wolfSSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION,
        TLS1_2_VERSION, NULL), SSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_get_max_proto_version(ctx), TLS1_2_VERSION);
#endif
#endif
    /* Cleanup and Pass */
#if !defined(NO_DH) && !defined(NO_DSA)
#ifndef NO_BIO
    BIO_free(bio);
    DSA_free(dsa);
    DH_free(dh);
    dh = NULL;
#endif
#endif
#ifdef HAVE_ECC
    wolfSSL_EC_KEY_free(ecKey);
#endif
    SSL_CTX_free(ctx);
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
        * !defined(NO_FILESYSTEM) && !defined(NO_RSA) */
    return EXPECT_RESULT();
}

#if !defined(NO_BIO)
static word32 TXT_DB_hash(const WOLFSSL_STRING *s)
{
    return (word32)lh_strhash(s[3]);
}

static int TXT_DB_cmp(const WOLFSSL_STRING *a, const WOLFSSL_STRING *b)
{
    return XSTRCMP(a[3], b[3]);
}
#endif

static int test_wolfSSL_TXT_DB(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_BIO)
    BIO *bio = NULL;
    TXT_DB *db = NULL;
    const int columns = 6;
    const char *fields[6] = {
        "V",
        "320926161116Z",
        "",
        "12BD",
        "unknown",
        "/CN=rsa doe",
    };
    char** fields_copy = NULL;

    /* Test read */
    ExpectNotNull(bio = BIO_new(BIO_s_file()));
    ExpectIntGT(BIO_read_filename(bio, "./tests/TXT_DB.txt"), 0);
    ExpectNotNull(db = TXT_DB_read(bio, columns));
    ExpectNotNull(fields_copy = (char**)XMALLOC(sizeof(fields), NULL,
        DYNAMIC_TYPE_OPENSSL));
    if (fields_copy != NULL) {
        XMEMCPY(fields_copy, fields, sizeof(fields));
    }
    ExpectIntEQ(TXT_DB_insert(db, fields_copy), 1);
    if (EXPECT_FAIL()) {
        XFREE(fields_copy, NULL, DYNAMIC_TYPE_OPENSSL);
    }
    BIO_free(bio);
    bio = NULL;

    /* Test write */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntEQ(TXT_DB_write(bio, db), 1484);
    BIO_free(bio);

    /* Test index */
    ExpectIntEQ(TXT_DB_create_index(db, 3, NULL,
        (wolf_sk_hash_cb)(wc_ptr_t)TXT_DB_hash,
        (wolf_lh_compare_cb)TXT_DB_cmp), 1);
    ExpectNotNull(TXT_DB_get_by_index(db, 3, (WOLFSSL_STRING*)fields));
    fields[3] = "12DA";
    ExpectNotNull(TXT_DB_get_by_index(db, 3, (WOLFSSL_STRING*)fields));
    fields[3] = "FFFF";
    ExpectNull(TXT_DB_get_by_index(db, 3, (WOLFSSL_STRING*)fields));
    fields[3] = "";
    ExpectNull(TXT_DB_get_by_index(db, 3, (WOLFSSL_STRING*)fields));

    TXT_DB_free(db);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_NCONF(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_BIO)
    const char* confFile = "./tests/NCONF_test.cnf";
    CONF* conf = NULL;
    long eline = 0;
    long num = 0;

    ExpectNotNull(conf = NCONF_new(NULL));

    ExpectIntEQ(NCONF_load(conf, confFile, &eline), 1);
    ExpectIntEQ(NCONF_get_number(conf, NULL, "port", &num), 1);
    ExpectIntEQ(num, 1234);
    ExpectIntEQ(NCONF_get_number(conf, "section2", "port", &num), 1);
    ExpectIntEQ(num, 4321);
    ExpectStrEQ(NCONF_get_string(conf, NULL, "dir"), "./test-dir");
    ExpectStrEQ(NCONF_get_string(conf, "section1", "file1_copy"),
        "./test-dir/file1");
    ExpectStrEQ(NCONF_get_string(conf, "section2", "file_list"),
        "./test-dir/file1:./test-dir/file2:./section1:file2");

    NCONF_free(conf);
#endif
    return EXPECT_RESULT();
}
#endif /* OPENSSL_ALL */

static int test_wolfSSL_d2i_and_i2d_PublicKey(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA)
    EVP_PKEY* pkey = NULL;
    const unsigned char* p = NULL;
    unsigned char *der = NULL;
    unsigned char *tmp = NULL;
    int derLen = 0;

    p = client_keypub_der_2048;
    /* Check that key can be successfully decoded. */
    ExpectNotNull(pkey = wolfSSL_d2i_PublicKey(EVP_PKEY_RSA, NULL, &p,
        sizeof_client_keypub_der_2048));
    /* Check that key can be successfully encoded. */
    ExpectIntGE((derLen = wolfSSL_i2d_PublicKey(pkey, &der)), 0);
    /* Ensure that the encoded version matches the original. */
    ExpectIntEQ(derLen, sizeof_client_keypub_der_2048);
    ExpectIntEQ(XMEMCMP(der, client_keypub_der_2048, derLen), 0);

    /* Do same test except with pre-allocated buffer to ensure the der pointer
     * is advanced. */
    tmp = der;
    ExpectIntGE((derLen = wolfSSL_i2d_PublicKey(pkey, &tmp)), 0);
    ExpectIntEQ(derLen, sizeof_client_keypub_der_2048);
    ExpectIntEQ(XMEMCMP(der, client_keypub_der_2048, derLen), 0);
    ExpectTrue(der + derLen == tmp);

    XFREE(der, HEAP_HINT, DYNAMIC_TYPE_OPENSSL);
    EVP_PKEY_free(pkey);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_d2i_and_i2d_PublicKey_ecc(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) && !defined(NO_CERTS) && \
    !defined(NO_ASN) && !defined(NO_PWDBASED)
    EVP_PKEY* pkey = NULL;
    const unsigned char* p;
    unsigned char *der = NULL;
    unsigned char *tmp = NULL;
    int derLen = -1;
    unsigned char pub_buf[65];
    unsigned char pub_spki_buf[91];
    const int pub_len = 65;
    const int pub_spki_len = 91;
    BN_CTX* ctx = NULL;
    EC_GROUP* curve = NULL;
    EC_KEY* ephemeral_key = NULL;
    const EC_POINT* h = NULL;
    ecc_key *eccKey = NULL;

    /* Generate an x963 key pair and get public part into pub_buf */
    ExpectNotNull(ctx = BN_CTX_new());
    ExpectNotNull(curve = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
    ExpectNotNull(ephemeral_key = EC_KEY_new_by_curve_name(
        NID_X9_62_prime256v1));
    ExpectIntEQ(EC_KEY_generate_key(ephemeral_key), 1);
    ExpectNotNull(h = EC_KEY_get0_public_key(ephemeral_key));
    ExpectIntEQ(pub_len, EC_POINT_point2oct(curve, h,
        POINT_CONVERSION_UNCOMPRESSED, pub_buf, pub_len, ctx));
    /* Create an ecc key struct from the point.
       Use it to create a DER with the appropriate
       SubjectPublicKeyInfo format. */
    ExpectNotNull(eccKey = (ecc_key *)XMALLOC(sizeof(*eccKey), NULL,
        DYNAMIC_TYPE_ECC));
    ExpectIntEQ(wc_ecc_init(eccKey), 0);
    ExpectIntEQ(wc_ecc_import_x963(pub_buf, pub_len, eccKey), 0);
    ExpectIntEQ(derLen = wc_EccPublicKeyDerSize(eccKey, 1),
        pub_spki_len);
    ExpectIntEQ(derLen = wc_EccPublicKeyToDer(eccKey, pub_spki_buf,
        pub_spki_len, 1), pub_spki_len);
    /* Prepare the EVP_PKEY */
    ExpectNotNull(pkey = EVP_PKEY_new());

    p = pub_buf;
    /* Check that key can be successfully decoded. */
    ExpectNotNull(wolfSSL_d2i_PublicKey(EVP_PKEY_EC, &pkey, &p,
        pub_len));

    /* Check that key can be successfully encoded. */
    ExpectIntGE((derLen = wolfSSL_i2d_PublicKey(pkey, &der)), 0);
    /* Ensure that the encoded version matches the original. */
    ExpectIntEQ(derLen, pub_spki_len);
    ExpectIntEQ(XMEMCMP(der, pub_spki_buf, derLen), 0);

    /* Do same test except with pre-allocated buffer to ensure the der pointer
     * is advanced. */
    tmp = der;
    ExpectIntGE((derLen = wolfSSL_i2d_PublicKey(pkey, &tmp)), 0);
    ExpectIntEQ(derLen, pub_spki_len);
    ExpectIntEQ(XMEMCMP(der, pub_spki_buf, derLen), 0);
    ExpectTrue(der + derLen == tmp);

    wc_ecc_free(eccKey);
    XFREE(eccKey, NULL, DYNAMIC_TYPE_ECC);
    XFREE(der, HEAP_HINT, DYNAMIC_TYPE_OPENSSL);
    EVP_PKEY_free(pkey);
    EC_KEY_free(ephemeral_key);
    EC_GROUP_free(curve);
    BN_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_d2i_and_i2d_DSAparams(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_DSA)
    DSA* dsa = NULL;
    byte derIn[] = {
        0x30, 0x82, 0x01, 0x1f, 0x02, 0x81, 0x81, 0x00,
        0xcd, 0xde, 0x25, 0x68, 0x80, 0x53, 0x0d, 0xe5,
        0x77, 0xd6, 0xd2, 0x90, 0x39, 0x3f, 0x90, 0xa2,
        0x3f, 0x33, 0x94, 0x6e, 0xe8, 0x4f, 0x2b, 0x63,
        0xab, 0x30, 0xab, 0x15, 0xba, 0x11, 0xea, 0x8a,
        0x5d, 0x8d, 0xcc, 0xb8, 0xd4, 0xa1, 0xd5, 0xc1,
        0x47, 0x9d, 0x5a, 0x73, 0x6a, 0x62, 0x49, 0xd1,
        0x06, 0x07, 0x67, 0xf6, 0x2f, 0xa3, 0x39, 0xbd,
        0x4e, 0x0d, 0xb4, 0xd3, 0x22, 0x23, 0x84, 0xec,
        0x93, 0x26, 0x5a, 0x49, 0xee, 0x7c, 0x89, 0x48,
        0x66, 0x4d, 0xe8, 0xe8, 0xd8, 0x50, 0xfb, 0xa5,
        0x71, 0x9f, 0x22, 0x18, 0xe5, 0xe6, 0x0b, 0x46,
        0x87, 0x66, 0xee, 0x52, 0x8f, 0x46, 0x4f, 0xb5,
        0x03, 0xce, 0xed, 0xe3, 0xbe, 0xe5, 0xb5, 0x81,
        0xd2, 0x59, 0xe9, 0xc0, 0xad, 0x4d, 0xd0, 0x4d,
        0x26, 0xf7, 0xba, 0x50, 0xe8, 0xc9, 0x8f, 0xfe,
        0x24, 0x19, 0x3d, 0x2e, 0xa7, 0x52, 0x3c, 0x6d,
        0x02, 0x15, 0x00, 0xfb, 0x47, 0xfb, 0xec, 0x81,
        0x20, 0xc8, 0x1c, 0xe9, 0x4a, 0xba, 0x04, 0x6f,
        0x19, 0x9b, 0x94, 0xee, 0x82, 0x67, 0xd3, 0x02,
        0x81, 0x81, 0x00, 0x9b, 0x95, 0xbb, 0x85, 0xc5,
        0x58, 0x4a, 0x32, 0x9c, 0xaa, 0x44, 0x85, 0xd6,
        0x68, 0xdc, 0x3e, 0x14, 0xf4, 0xce, 0x6d, 0xa3,
        0x49, 0x38, 0xea, 0xd6, 0x61, 0x48, 0x92, 0x5a,
        0x40, 0x95, 0x49, 0x38, 0xaa, 0xe1, 0x39, 0x29,
        0x68, 0x58, 0x47, 0x8a, 0x4b, 0x01, 0xe1, 0x2e,
        0x8e, 0x6c, 0x63, 0x6f, 0x40, 0xca, 0x50, 0x3f,
        0x8c, 0x0b, 0x99, 0xe4, 0x72, 0x42, 0xb8, 0xb1,
        0xc2, 0x26, 0x48, 0xf1, 0x9c, 0x83, 0xc6, 0x37,
        0x2e, 0x5a, 0xae, 0x11, 0x09, 0xd9, 0xf3, 0xad,
        0x1f, 0x6f, 0xad, 0xad, 0x50, 0xe3, 0x78, 0x32,
        0xe6, 0xde, 0x8e, 0xaa, 0xbf, 0xd1, 0x00, 0x9f,
        0xb3, 0x02, 0x12, 0x19, 0xa2, 0x15, 0xec, 0x14,
        0x18, 0x5c, 0x0e, 0x26, 0xce, 0xf9, 0xae, 0xcc,
        0x7b, 0xb5, 0xd1, 0x26, 0xfc, 0x85, 0xfe, 0x14,
        0x93, 0xb6, 0x9d, 0x7d, 0x76, 0xe3, 0x35, 0x97,
        0x1e, 0xde, 0xc4
    };
    int derInLen = sizeof(derIn);
    byte* derOut = NULL;
    int derOutLen = -1;
    byte* p = derIn;

    /* Check that params can be successfully decoded. */
    ExpectNotNull(dsa = d2i_DSAparams(NULL, (const byte**)&p, derInLen));
    /* Check that params can be successfully encoded. */
    ExpectIntGE((derOutLen = i2d_DSAparams(dsa, &derOut)), 0);
    /* Ensure that the encoded version matches the original. */
    ExpectIntEQ(derInLen, derOutLen);
    ExpectIntEQ(XMEMCMP(derIn, derOut, derInLen), 0);

    XFREE(derOut, HEAP_HINT, DYNAMIC_TYPE_OPENSSL);
    DSA_free(dsa);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_i2d_PrivateKey(void)
{
    EXPECT_DECLS;
#if (!defined(NO_RSA) || defined(HAVE_ECC)) && defined(OPENSSL_EXTRA) && \
    !defined(NO_ASN) && !defined(NO_PWDBASED)

#if !defined(NO_RSA) && defined(USE_CERT_BUFFERS_2048)
    {
        EVP_PKEY* pkey = NULL;
        const unsigned char* server_key =
            (const unsigned char*)server_key_der_2048;
        unsigned char buf[FOURK_BUF];
        unsigned char* pt = NULL;
        int bufSz = 0;

        ExpectNotNull(pkey = d2i_PrivateKey(EVP_PKEY_RSA, NULL, &server_key,
            (long)sizeof_server_key_der_2048));
        ExpectIntEQ(i2d_PrivateKey(pkey, NULL), 1193);
        pt = buf;
        ExpectIntEQ((bufSz = i2d_PrivateKey(pkey, &pt)), 1193);
        ExpectIntNE((pt - buf), 0);
        ExpectIntEQ(XMEMCMP(buf, server_key_der_2048, bufSz), 0);
        EVP_PKEY_free(pkey);
    }
#endif
#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256)
    {
        EVP_PKEY* pkey = NULL;
        const unsigned char* client_key =
            (const unsigned char*)ecc_clikey_der_256;
        unsigned char buf[FOURK_BUF];
        unsigned char* pt = NULL;
        int bufSz = 0;

        ExpectNotNull((pkey = d2i_PrivateKey(EVP_PKEY_EC, NULL, &client_key,
            (long)sizeof_ecc_clikey_der_256)));
        ExpectIntEQ(i2d_PrivateKey(pkey, NULL), 121);
        pt = buf;
        ExpectIntEQ((bufSz = i2d_PrivateKey(pkey, &pt)), 121);
        ExpectIntNE((pt - buf), 0);
        ExpectIntEQ(XMEMCMP(buf, ecc_clikey_der_256, bufSz), 0);
        EVP_PKEY_free(pkey);
    }
#endif
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_OCSP_id_get0_info(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY)) && \
    defined(HAVE_OCSP) && !defined(NO_FILESYSTEM) && !defined(NO_RSA) && \
    !defined(WOLFSSL_SM2) && !defined(WOLFSSL_SM3)
    X509* cert = NULL;
    X509* issuer = NULL;
    OCSP_CERTID* id = NULL;
    OCSP_CERTID* id2 = NULL;

    ASN1_STRING* name = NULL;
    ASN1_OBJECT* pmd  = NULL;
    ASN1_STRING* keyHash = NULL;
    ASN1_INTEGER* serial = NULL;
    ASN1_INTEGER* x509Int = NULL;

    ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(svrCertFile,
        SSL_FILETYPE_PEM));
    ExpectNotNull(issuer = wolfSSL_X509_load_certificate_file(caCertFile,
        SSL_FILETYPE_PEM));

    ExpectNotNull(id = OCSP_cert_to_id(NULL, cert, issuer));
    ExpectNotNull(id2 = OCSP_cert_to_id(NULL, cert, issuer));

    ExpectIntEQ(OCSP_id_get0_info(NULL, NULL, NULL, NULL, NULL), 0);
    ExpectIntEQ(OCSP_id_get0_info(NULL, NULL, NULL, NULL, id), 1);

    /* name, pmd, keyHash not supported yet, expect failure if not NULL */
    ExpectIntEQ(OCSP_id_get0_info(&name, NULL, NULL, NULL, id), 0);
    ExpectIntEQ(OCSP_id_get0_info(NULL, &pmd, NULL, NULL, id), 0);
    ExpectIntEQ(OCSP_id_get0_info(NULL, NULL, &keyHash, NULL, id), 0);

    ExpectIntEQ(OCSP_id_get0_info(NULL, NULL, NULL, &serial, id), 1);
    ExpectNotNull(serial);

    /* compare serial number to one in cert, should be equal */
    ExpectNotNull(x509Int = X509_get_serialNumber(cert));
    ExpectIntEQ(x509Int->length, serial->length);
    ExpectIntEQ(XMEMCMP(x509Int->data, serial->data, serial->length), 0);
    ExpectNotNull(x509Int = X509_get_serialNumber(cert));

    /* test OCSP_id_cmp */
    ExpectIntNE(OCSP_id_cmp(NULL, NULL), 0);
    ExpectIntNE(OCSP_id_cmp(id, NULL), 0);
    ExpectIntNE(OCSP_id_cmp(NULL, id2), 0);
    ExpectIntEQ(OCSP_id_cmp(id, id2), 0);
    if (id != NULL) {
        id->issuerHash[0] = ~id->issuerHash[0];
    }
    ExpectIntNE(OCSP_id_cmp(id, id2), 0);

    OCSP_CERTID_free(id);
    OCSP_CERTID_free(id2);
    X509_free(cert); /* free's x509Int */
    X509_free(issuer);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_i2d_OCSP_CERTID(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY)) && defined(HAVE_OCSP)
    WOLFSSL_OCSP_CERTID certId;
    byte* targetBuffer = NULL;
    byte* p;
    /* OCSP CertID bytes taken from PCAP */
    byte rawCertId[] = {
        0x30, 0x49, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
        0x00, 0x04, 0x14, 0x80, 0x51, 0x06, 0x01, 0x32, 0xad, 0x9a, 0xc2, 0x7d,
        0x51, 0x87, 0xa0, 0xe8, 0x87, 0xfb, 0x01, 0x62, 0x01, 0x55, 0xee, 0x04,
        0x14, 0x03, 0xde, 0x50, 0x35, 0x56, 0xd1, 0x4c, 0xbb, 0x66, 0xf0, 0xa3,
        0xe2, 0x1b, 0x1b, 0xc3, 0x97, 0xb2, 0x3d, 0xd1, 0x55, 0x02, 0x10, 0x01,
        0xfd, 0xa3, 0xeb, 0x6e, 0xca, 0x75, 0xc8, 0x88, 0x43, 0x8b, 0x72, 0x4b,
        0xcf, 0xbc, 0x91
    };
    int ret = 0;
    int i;

    XMEMSET(&certId, 0, sizeof(WOLFSSL_OCSP_CERTID));
    certId.rawCertId = rawCertId;
    certId.rawCertIdSize = sizeof(rawCertId);

    ExpectNotNull(targetBuffer = (byte*)XMALLOC(sizeof(rawCertId), NULL,
        DYNAMIC_TYPE_TMP_BUFFER));
    p = targetBuffer;
    /* Function returns the size of the encoded data. */
    ExpectIntEQ(ret = wolfSSL_i2d_OCSP_CERTID(&certId, &p), sizeof(rawCertId));
    /* If target buffer is not null, function increments targetBuffer to point
     * just past the end of the encoded data. */
    ExpectPtrEq(p, (targetBuffer + sizeof(rawCertId)));
    for (i = 0; EXPECT_SUCCESS() && i < ret; ++i) {
        ExpectIntEQ(targetBuffer[i], rawCertId[i]);
    }
    XFREE(targetBuffer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    targetBuffer = NULL;

    /* If target buffer is null, function allocates memory for a buffer and
     * copies the encoded data into it. targetBuffer then points to the start of
     * this newly allocate buffer. */
    ExpectIntEQ(ret = wolfSSL_i2d_OCSP_CERTID(&certId, &targetBuffer),
        sizeof(rawCertId));
    for (i = 0; EXPECT_SUCCESS() && i < ret; ++i) {
        ExpectIntEQ(targetBuffer[i], rawCertId[i]);
    }
    XFREE(targetBuffer, NULL, DYNAMIC_TYPE_OPENSSL);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_d2i_OCSP_CERTID(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY)) && defined(HAVE_OCSP)
    WOLFSSL_OCSP_CERTID* certIdGood = NULL;
    WOLFSSL_OCSP_CERTID* certIdBad = NULL;
    const unsigned char* rawCertIdPtr = NULL;

    const unsigned char rawCertId[] = {
        0x30, 0x49, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
        0x00, 0x04, 0x14, 0x80, 0x51, 0x06, 0x01, 0x32, 0xad, 0x9a, 0xc2, 0x7d,
        0x51, 0x87, 0xa0, 0xe8, 0x87, 0xfb, 0x01, 0x62, 0x01, 0x55, 0xee, 0x04,
        0x14, 0x03, 0xde, 0x50, 0x35, 0x56, 0xd1, 0x4c, 0xbb, 0x66, 0xf0, 0xa3,
        0xe2, 0x1b, 0x1b, 0xc3, 0x97, 0xb2, 0x3d, 0xd1, 0x55, 0x02, 0x10, 0x01,
        0xfd, 0xa3, 0xeb, 0x6e, 0xca, 0x75, 0xc8, 0x88, 0x43, 0x8b, 0x72, 0x4b,
        0xcf, 0xbc, 0x91
    };

    rawCertIdPtr = &rawCertId[0];

    /* If the cert ID is NULL the function should allocate it and copy the
     * data to it. */
    {
        WOLFSSL_OCSP_CERTID* certId = NULL;
        ExpectNotNull(certId = wolfSSL_d2i_OCSP_CERTID(&certId, &rawCertIdPtr,
                                                       sizeof(rawCertId)));
        if (certId != NULL) {
            XFREE(certId->rawCertId, NULL, DYNAMIC_TYPE_OPENSSL);
            wolfSSL_OCSP_CERTID_free(certId);
        }
    }

    /* If the cert ID is not NULL the function will just copy the data to it. */
    {
        WOLFSSL_OCSP_CERTID* certId = NULL;
        ExpectNotNull(certId = (WOLFSSL_OCSP_CERTID*)XMALLOC(sizeof(*certId), NULL,
                                                             DYNAMIC_TYPE_TMP_BUFFER));
        ExpectNotNull(certId);
        if (certId != NULL)
            XMEMSET(certId, 0, sizeof(*certId));

        /* Reset rawCertIdPtr since it was push forward in the previous call. */
        rawCertIdPtr = &rawCertId[0];
        ExpectNotNull(certIdGood = wolfSSL_d2i_OCSP_CERTID(&certId, &rawCertIdPtr,
                                                           sizeof(rawCertId)));
        ExpectPtrEq(certIdGood, certId);
        if (certId != NULL) {
            XFREE(certId->rawCertId, NULL, DYNAMIC_TYPE_OPENSSL);
            wolfSSL_OCSP_CERTID_free(certId);
            certId = NULL;
        }
    }

    /* The below tests should fail when passed bad parameters. NULL should
     * always be returned. */
    {
        WOLFSSL_OCSP_CERTID* certId = NULL;
        ExpectNull(certIdBad = wolfSSL_d2i_OCSP_CERTID(&certId, NULL,
                                                       sizeof(rawCertId)));
        ExpectNull(certIdBad = wolfSSL_d2i_OCSP_CERTID(&certId, &rawCertIdPtr, 0));
    }
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_OCSP_id_cmp(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && defined(HAVE_OCSP)
    OCSP_CERTID id1;
    OCSP_CERTID id2;

    XMEMSET(&id1, 0, sizeof(id1));
    XMEMSET(&id2, 0, sizeof(id2));
    ExpectIntEQ(OCSP_id_cmp(&id1, &id2), 0);
    ExpectIntNE(OCSP_id_cmp(NULL, NULL), 0);
    ExpectIntNE(OCSP_id_cmp(&id1, NULL), 0);
    ExpectIntNE(OCSP_id_cmp(NULL, &id2), 0);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_OCSP_SINGLERESP_get0_id(void)
{
    EXPECT_DECLS;
#if defined(HAVE_OCSP) && defined(OPENSSL_EXTRA)
    WOLFSSL_OCSP_SINGLERESP single;
    const WOLFSSL_OCSP_CERTID* certId;

    XMEMSET(&single, 0, sizeof(single));

    certId = wolfSSL_OCSP_SINGLERESP_get0_id(&single);
    ExpectPtrEq(&single, certId);

    ExpectNull(wolfSSL_OCSP_SINGLERESP_get0_id(NULL));
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_OCSP_single_get0_status(void)
{
    EXPECT_DECLS;
#if defined(HAVE_OCSP) && defined(OPENSSL_EXTRA) && \
    defined(WOLFSSL_OCSP_PARSE_STATUS)
    WOLFSSL_OCSP_SINGLERESP single;
    CertStatus certStatus;
    WOLFSSL_ASN1_TIME* thisDate;
    WOLFSSL_ASN1_TIME* nextDate;
    int ret, i;

    XMEMSET(&single,     0, sizeof(WOLFSSL_OCSP_SINGLERESP));
    XMEMSET(&certStatus, 0, sizeof(CertStatus));

    /* Fill the date fields with some dummy data. */
    for (i = 0; i < CTC_DATE_SIZE; ++i) {
        certStatus.thisDateParsed.data[i] = i;
        certStatus.nextDateParsed.data[i] = i;
    }
    certStatus.status = CERT_GOOD;
    single.status = &certStatus;

    ret = wolfSSL_OCSP_single_get0_status(&single, NULL, NULL, &thisDate,
                                          &nextDate);
    ExpectIntEQ(ret, CERT_GOOD);
    ExpectPtrEq(thisDate, &certStatus.thisDateParsed);
    ExpectPtrEq(nextDate, &certStatus.nextDateParsed);

    ExpectIntEQ(wolfSSL_OCSP_single_get0_status(NULL, NULL, NULL, NULL, NULL),
        -1);
    ExpectIntEQ(wolfSSL_OCSP_single_get0_status(&single, NULL, NULL, NULL,
        NULL), CERT_GOOD);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_OCSP_resp_count(void)
{
    EXPECT_DECLS;
#if defined(HAVE_OCSP) && defined(OPENSSL_EXTRA)
    WOLFSSL_OCSP_BASICRESP basicResp;
    WOLFSSL_OCSP_SINGLERESP singleRespOne;
    WOLFSSL_OCSP_SINGLERESP singleRespTwo;

    XMEMSET(&basicResp,     0, sizeof(WOLFSSL_OCSP_BASICRESP));
    XMEMSET(&singleRespOne, 0, sizeof(WOLFSSL_OCSP_SINGLERESP));
    XMEMSET(&singleRespTwo, 0, sizeof(WOLFSSL_OCSP_SINGLERESP));

    ExpectIntEQ(wolfSSL_OCSP_resp_count(&basicResp), 0);
    basicResp.single = &singleRespOne;
    ExpectIntEQ(wolfSSL_OCSP_resp_count(&basicResp), 1);
    singleRespOne.next = &singleRespTwo;
    ExpectIntEQ(wolfSSL_OCSP_resp_count(&basicResp), 2);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_OCSP_resp_get0(void)
{
    EXPECT_DECLS;
#if defined(HAVE_OCSP) && defined(OPENSSL_EXTRA)
    WOLFSSL_OCSP_BASICRESP basicResp;
    WOLFSSL_OCSP_SINGLERESP singleRespOne;
    WOLFSSL_OCSP_SINGLERESP singleRespTwo;

    XMEMSET(&basicResp,     0, sizeof(WOLFSSL_OCSP_BASICRESP));
    XMEMSET(&singleRespOne, 0, sizeof(WOLFSSL_OCSP_SINGLERESP));
    XMEMSET(&singleRespTwo, 0, sizeof(WOLFSSL_OCSP_SINGLERESP));

    basicResp.single = &singleRespOne;
    singleRespOne.next = &singleRespTwo;
    ExpectPtrEq(wolfSSL_OCSP_resp_get0(&basicResp, 0), &singleRespOne);
    ExpectPtrEq(wolfSSL_OCSP_resp_get0(&basicResp, 1), &singleRespTwo);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_OCSP_parse_url(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_OCSP)
#define CK_OPU_OK(u, h, po, pa, s) do { \
    char* host = NULL; \
    char* port = NULL; \
    char* path = NULL; \
    int isSsl = 0; \
    ExpectIntEQ(OCSP_parse_url(u, &host, &port, &path, &isSsl), 1); \
    ExpectStrEQ(host, h); \
    ExpectStrEQ(port, po); \
    ExpectStrEQ(path, pa); \
    ExpectIntEQ(isSsl, s); \
    XFREE(host, NULL, DYNAMIC_TYPE_OPENSSL); \
    XFREE(port, NULL, DYNAMIC_TYPE_OPENSSL); \
    XFREE(path, NULL, DYNAMIC_TYPE_OPENSSL); \
} while(0)

#define CK_OPU_FAIL(u) do { \
    char* host = NULL; \
    char* port = NULL; \
    char* path = NULL; \
    int isSsl = 0; \
    ExpectIntEQ(OCSP_parse_url(u, &host, &port, &path, &isSsl), 0); \
    XFREE(host, NULL, DYNAMIC_TYPE_OPENSSL); \
    XFREE(port, NULL, DYNAMIC_TYPE_OPENSSL); \
    XFREE(path, NULL, DYNAMIC_TYPE_OPENSSL); \
} while(0)

    CK_OPU_OK("http://localhost", "localhost", "80", "/", 0);
    CK_OPU_OK("https://wolfssl.com", "wolfssl.com", "443", "/", 1);
    CK_OPU_OK("https://www.wolfssl.com/fips-140-3-announcement-to-the-world/",
         "www.wolfssl.com", "443", "/fips-140-3-announcement-to-the-world/", 1);
    CK_OPU_OK("http://localhost:1234", "localhost", "1234", "/", 0);
    CK_OPU_OK("https://localhost:1234", "localhost", "1234", "/", 1);

    CK_OPU_FAIL("ftp://localhost");
    /* two strings to cppcheck doesn't mark it as a c++ style comment */
    CK_OPU_FAIL("http/""/localhost");
    CK_OPU_FAIL("http:/localhost");
    CK_OPU_FAIL("https://localhost/path:1234");

#undef CK_OPU_OK
#undef CK_OPU_FAIL
#endif
    return EXPECT_RESULT();
}

#if defined(OPENSSL_ALL) && defined(HAVE_OCSP) && \
    defined(WOLFSSL_SIGNER_DER_CERT) && !defined(NO_FILESYSTEM) && \
    !defined(NO_ASN_TIME) && \
    !defined(WOLFSSL_SM2) && !defined(WOLFSSL_SM3)
static time_t test_wolfSSL_OCSP_REQ_CTX_time_cb(time_t* t)
{
    if (t != NULL) {
        *t = 1722006780;
    }

    return 1722006780;
}
#endif

static int test_wolfSSL_OCSP_REQ_CTX(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && defined(HAVE_OCSP) && \
    defined(WOLFSSL_SIGNER_DER_CERT) && !defined(NO_FILESYSTEM) && \
    !defined(WOLFSSL_SM2) && !defined(WOLFSSL_SM3)
    /* This buffer was taken from the ocsp-stapling.test test case 1. The ocsp
     * response was captured in wireshark. It contains both the http and binary
     * parts. The time test_wolfSSL_OCSP_REQ_CTX_time_cb is set exactly so that
     * the time check passes. */
    unsigned char ocspRespBin[] = {
      0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, 0x30, 0x30,
      0x20, 0x4f, 0x4b, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
      0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69,
      0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2d,
      0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x0d, 0x0a, 0x43, 0x6f,
      0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68,
      0x3a, 0x20, 0x31, 0x38, 0x32, 0x31, 0x0d, 0x0a, 0x0d, 0x0a, 0x30, 0x82,
      0x07, 0x19, 0x0a, 0x01, 0x00, 0xa0, 0x82, 0x07, 0x12, 0x30, 0x82, 0x07,
      0x0e, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01,
      0x04, 0x82, 0x06, 0xff, 0x30, 0x82, 0x06, 0xfb, 0x30, 0x82, 0x01, 0x19,
      0xa1, 0x81, 0xa1, 0x30, 0x81, 0x9e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
      0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06,
      0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e,
      0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04,
      0x07, 0x0c, 0x07, 0x53, 0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x31, 0x10,
      0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f, 0x6c,
      0x66, 0x53, 0x53, 0x4c, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04,
      0x0b, 0x0c, 0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69,
      0x6e, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
      0x16, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, 0x4f, 0x43, 0x53,
      0x50, 0x20, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x31,
      0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
      0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c,
      0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x18, 0x0f, 0x32, 0x30,
      0x32, 0x34, 0x30, 0x37, 0x32, 0x36, 0x31, 0x35, 0x31, 0x32, 0x30, 0x35,
      0x5a, 0x30, 0x62, 0x30, 0x60, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b,
      0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x71, 0x4d, 0x82, 0x23, 0x40, 0x59,
      0xc0, 0x96, 0xa1, 0x37, 0x43, 0xfa, 0x31, 0xdb, 0xba, 0xb1, 0x43, 0x18,
      0xda, 0x04, 0x04, 0x14, 0x83, 0xc6, 0x3a, 0x89, 0x2c, 0x81, 0xf4, 0x02,
      0xd7, 0x9d, 0x4c, 0xe2, 0x2a, 0xc0, 0x71, 0x82, 0x64, 0x44, 0xda, 0x0e,
      0x02, 0x01, 0x05, 0x80, 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x34, 0x30,
      0x37, 0x32, 0x36, 0x31, 0x35, 0x31, 0x32, 0x30, 0x35, 0x5a, 0xa0, 0x11,
      0x18, 0x0f, 0x32, 0x30, 0x32, 0x34, 0x30, 0x37, 0x32, 0x36, 0x31, 0x35,
      0x31, 0x33, 0x30, 0x35, 0x5a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
      0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
      0x00, 0x89, 0x7a, 0xe9, 0x6b, 0x66, 0x47, 0x8e, 0x52, 0x16, 0xf9, 0x8a,
      0x5a, 0x1e, 0x7a, 0x35, 0xbb, 0x1d, 0x6c, 0xd8, 0x31, 0xbb, 0x24, 0xd2,
      0xd7, 0xa4, 0x30, 0x27, 0x06, 0x17, 0x66, 0xd1, 0xf9, 0x8d, 0x24, 0xb0,
      0x49, 0x37, 0x62, 0x13, 0x78, 0x5e, 0xa6, 0x6d, 0xea, 0xe3, 0xd0, 0x30,
      0x82, 0x7d, 0xb6, 0xf6, 0x55, 0x82, 0x11, 0xdc, 0xe7, 0x0f, 0xd6, 0x24,
      0xb4, 0x80, 0x23, 0x4f, 0xfd, 0xa7, 0x9a, 0x4b, 0xac, 0xf2, 0xd3, 0xde,
      0x42, 0x10, 0xfb, 0x4b, 0x29, 0x06, 0x02, 0x7b, 0x47, 0x36, 0x70, 0x75,
      0x45, 0x38, 0x8d, 0x3e, 0x55, 0x9c, 0xce, 0x78, 0xd8, 0x18, 0x45, 0x47,
      0x2d, 0x2a, 0x46, 0x65, 0x13, 0x93, 0x1a, 0x98, 0x90, 0xc6, 0x2d, 0xd5,
      0x05, 0x2a, 0xfc, 0xcb, 0xac, 0x53, 0x73, 0x93, 0x42, 0x4e, 0xdb, 0x17,
      0x91, 0xcb, 0xe1, 0x08, 0x03, 0xd1, 0x33, 0x57, 0x4b, 0x1d, 0xb8, 0x71,
      0x84, 0x01, 0x04, 0x47, 0x6f, 0x06, 0xfa, 0x76, 0x7d, 0xd9, 0x37, 0x64,
      0x57, 0x37, 0x3a, 0x8f, 0x4d, 0x88, 0x11, 0xa5, 0xd4, 0xaa, 0xcb, 0x49,
      0x47, 0x86, 0xdd, 0xcf, 0x46, 0xa6, 0xfa, 0x8e, 0xf2, 0x62, 0x0f, 0xc9,
      0x25, 0xf2, 0x39, 0x62, 0x3e, 0x2d, 0x35, 0xc4, 0x76, 0x7b, 0xae, 0xd5,
      0xe8, 0x85, 0xa1, 0xa6, 0x2d, 0x41, 0xd6, 0x8e, 0x3c, 0xfa, 0xdc, 0x6c,
      0x66, 0xe2, 0x61, 0xe7, 0xe5, 0x90, 0xa1, 0xfd, 0x7f, 0xdb, 0x18, 0xd0,
      0xeb, 0x6d, 0x73, 0x08, 0x5f, 0x6a, 0x65, 0x44, 0x50, 0xad, 0x38, 0x9d,
      0xb6, 0xfb, 0xbf, 0x28, 0x55, 0x84, 0x65, 0xfa, 0x0e, 0x34, 0xfc, 0x43,
      0x19, 0x80, 0x5c, 0x7d, 0x2d, 0x5b, 0xd8, 0x60, 0xec, 0x0e, 0xf9, 0x1e,
      0x6e, 0x32, 0x3f, 0x35, 0xf7, 0xec, 0x7e, 0x47, 0xba, 0xb5, 0xd2, 0xaa,
      0x5a, 0x9d, 0x07, 0x2c, 0xc5, 0xa0, 0x82, 0x04, 0xc6, 0x30, 0x82, 0x04,
      0xc2, 0x30, 0x82, 0x04, 0xbe, 0x30, 0x82, 0x03, 0xa6, 0xa0, 0x03, 0x02,
      0x01, 0x02, 0x02, 0x01, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
      0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x97, 0x31,
      0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
      0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57,
      0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30,
      0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, 0x61, 0x74,
      0x74, 0x6c, 0x65, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a,
      0x0c, 0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x14, 0x30,
      0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x0b, 0x45, 0x6e, 0x67, 0x69,
      0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x31, 0x18, 0x30, 0x16, 0x06,
      0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53,
      0x4c, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1f, 0x30,
      0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
      0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73,
      0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34,
      0x30, 0x37, 0x32, 0x36, 0x31, 0x35, 0x31, 0x32, 0x30, 0x34, 0x5a, 0x17,
      0x0d, 0x32, 0x37, 0x30, 0x34, 0x32, 0x32, 0x31, 0x35, 0x31, 0x32, 0x30,
      0x34, 0x5a, 0x30, 0x81, 0x9e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
      0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
      0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67,
      0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07,
      0x0c, 0x07, 0x53, 0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, 0x30,
      0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f, 0x6c, 0x66,
      0x53, 0x53, 0x4c, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b,
      0x0c, 0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e,
      0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16,
      0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, 0x4f, 0x43, 0x53, 0x50,
      0x20, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x31, 0x1f,
      0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
      0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66,
      0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30,
      0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
      0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
      0x82, 0x01, 0x01, 0x00, 0xb8, 0xba, 0x23, 0xb4, 0xf6, 0xc3, 0x7b, 0x14,
      0xc3, 0xa4, 0xf5, 0x1d, 0x61, 0xa1, 0xf5, 0x1e, 0x63, 0xb9, 0x85, 0x23,
      0x34, 0x50, 0x6d, 0xf8, 0x7c, 0xa2, 0x8a, 0x04, 0x8b, 0xd5, 0x75, 0x5c,
      0x2d, 0xf7, 0x63, 0x88, 0xd1, 0x07, 0x7a, 0xea, 0x0b, 0x45, 0x35, 0x2b,
      0xeb, 0x1f, 0xb1, 0x22, 0xb4, 0x94, 0x41, 0x38, 0xe2, 0x9d, 0x74, 0xd6,
      0x8b, 0x30, 0x22, 0x10, 0x51, 0xc5, 0xdb, 0xca, 0x3f, 0x46, 0x2b, 0xfe,
      0xe5, 0x5a, 0x3f, 0x41, 0x74, 0x67, 0x75, 0x95, 0xa9, 0x94, 0xd5, 0xc3,
      0xee, 0x42, 0xf8, 0x8d, 0xeb, 0x92, 0x95, 0xe1, 0xd9, 0x65, 0xb7, 0x43,
      0xc4, 0x18, 0xde, 0x16, 0x80, 0x90, 0xce, 0x24, 0x35, 0x21, 0xc4, 0x55,
      0xac, 0x5a, 0x51, 0xe0, 0x2e, 0x2d, 0xb3, 0x0a, 0x5a, 0x4f, 0x4a, 0x73,
      0x31, 0x50, 0xee, 0x4a, 0x16, 0xbd, 0x39, 0x8b, 0xad, 0x05, 0x48, 0x87,
      0xb1, 0x99, 0xe2, 0x10, 0xa7, 0x06, 0x72, 0x67, 0xca, 0x5c, 0xd1, 0x97,
      0xbd, 0xc8, 0xf1, 0x76, 0xf8, 0xe0, 0x4a, 0xec, 0xbc, 0x93, 0xf4, 0x66,
      0x4c, 0x28, 0x71, 0xd1, 0xd8, 0x66, 0x03, 0xb4, 0x90, 0x30, 0xbb, 0x17,
      0xb0, 0xfe, 0x97, 0xf5, 0x1e, 0xe8, 0xc7, 0x5d, 0x9b, 0x8b, 0x11, 0x19,
      0x12, 0x3c, 0xab, 0x82, 0x71, 0x78, 0xff, 0xae, 0x3f, 0x32, 0xb2, 0x08,
      0x71, 0xb2, 0x1b, 0x8c, 0x27, 0xac, 0x11, 0xb8, 0xd8, 0x43, 0x49, 0xcf,
      0xb0, 0x70, 0xb1, 0xf0, 0x8c, 0xae, 0xda, 0x24, 0x87, 0x17, 0x3b, 0xd8,
      0x04, 0x65, 0x6c, 0x00, 0x76, 0x50, 0xef, 0x15, 0x08, 0xd7, 0xb4, 0x73,
      0x68, 0x26, 0x14, 0x87, 0x95, 0xc3, 0x5f, 0x6e, 0x61, 0xb8, 0x87, 0x84,
      0xfa, 0x80, 0x1a, 0x0a, 0x8b, 0x98, 0xf3, 0xe3, 0xff, 0x4e, 0x44, 0x1c,
      0x65, 0x74, 0x7c, 0x71, 0x54, 0x65, 0xe5, 0x39, 0x02, 0x03, 0x01, 0x00,
      0x01, 0xa3, 0x82, 0x01, 0x0a, 0x30, 0x82, 0x01, 0x06, 0x30, 0x09, 0x06,
      0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03,
      0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x32, 0x67, 0xe1, 0xb1, 0x79,
      0xd2, 0x81, 0xfc, 0x9f, 0x23, 0x0c, 0x70, 0x40, 0x50, 0xb5, 0x46, 0x56,
      0xb8, 0x30, 0x36, 0x30, 0x81, 0xc4, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
      0x81, 0xbc, 0x30, 0x81, 0xb9, 0x80, 0x14, 0x73, 0xb0, 0x1c, 0xa4, 0x2f,
      0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, 0x7e,
      0x72, 0x15, 0x21, 0xa1, 0x81, 0x9d, 0xa4, 0x81, 0x9a, 0x30, 0x81, 0x97,
      0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
      0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a,
      0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10,
      0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, 0x61,
      0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04,
      0x0a, 0x0c, 0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x14,
      0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x0b, 0x45, 0x6e, 0x67,
      0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x31, 0x18, 0x30, 0x16,
      0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x77, 0x6f, 0x6c, 0x66, 0x53,
      0x53, 0x4c, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1f,
      0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
      0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66,
      0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x01, 0x63, 0x30, 0x13,
      0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08, 0x2b,
      0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x09, 0x30, 0x0d, 0x06, 0x09, 0x2a,
      0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82,
      0x01, 0x01, 0x00, 0x37, 0xb9, 0x66, 0xd3, 0xa1, 0x08, 0xfc, 0x37, 0x58,
      0x4e, 0xe0, 0x8c, 0xd3, 0x7f, 0xa6, 0x0f, 0x59, 0xd3, 0x14, 0xf7, 0x4b,
      0x36, 0xf7, 0x2e, 0x98, 0xeb, 0x7c, 0x03, 0x3f, 0x3a, 0xd6, 0x9c, 0xcd,
      0xb4, 0x9e, 0x8d, 0x5f, 0x92, 0xa6, 0x6f, 0x63, 0x87, 0x34, 0xe8, 0x83,
      0xfd, 0x6d, 0x34, 0x64, 0xb5, 0xf0, 0x9c, 0x71, 0x02, 0xb8, 0xf6, 0x2f,
      0x10, 0xa0, 0x92, 0x8f, 0x3f, 0x86, 0x3e, 0xe2, 0x01, 0x5a, 0x56, 0x39,
      0x0a, 0x8d, 0xb1, 0xbe, 0x03, 0xf7, 0xf8, 0xa7, 0x88, 0x46, 0xef, 0x81,
      0xa0, 0xad, 0x86, 0xc9, 0xe6, 0x23, 0x89, 0x1d, 0xa6, 0x24, 0x45, 0xf2,
      0x6a, 0x83, 0x2d, 0x8e, 0x92, 0x17, 0x1e, 0x44, 0x19, 0xfa, 0x0f, 0x47,
      0x6b, 0x8f, 0x4a, 0xa2, 0xda, 0xab, 0xd5, 0x2b, 0xcd, 0xcb, 0x14, 0xf0,
      0xb5, 0xcf, 0x7c, 0x76, 0x42, 0x32, 0x90, 0x21, 0xdc, 0xdd, 0x52, 0xfc,
      0x53, 0x7e, 0xff, 0x7f, 0xd9, 0x58, 0x6b, 0x1f, 0x73, 0xee, 0x83, 0xf4,
      0x67, 0xfa, 0x4a, 0x4f, 0x24, 0xe4, 0x2b, 0x10, 0x74, 0x89, 0x52, 0x9a,
      0xf7, 0xa4, 0xe0, 0xaf, 0xf5, 0x63, 0xd7, 0xfa, 0x0b, 0x2c, 0xc9, 0x39,
      0x5d, 0xbd, 0x44, 0x93, 0x69, 0xa4, 0x1d, 0x01, 0xe2, 0x66, 0xe7, 0xc1,
      0x11, 0x44, 0x7d, 0x0a, 0x7e, 0x5d, 0x1d, 0x26, 0xc5, 0x4a, 0x26, 0x2e,
      0xa3, 0x58, 0xc4, 0xf7, 0x10, 0xcb, 0xba, 0xe6, 0x27, 0xfc, 0xdb, 0x54,
      0xe2, 0x60, 0x08, 0xc2, 0x0e, 0x4b, 0xd4, 0xaa, 0x22, 0x23, 0x93, 0x9f,
      0xe1, 0xcb, 0x85, 0xa4, 0x41, 0x6f, 0x26, 0xa7, 0x77, 0x8a, 0xef, 0x66,
      0xd0, 0xf8, 0x33, 0xf6, 0xfd, 0x6d, 0x37, 0x7a, 0x89, 0xcc, 0x88, 0x3b,
      0x82, 0xd0, 0xa9, 0xdf, 0xf1, 0x3d, 0xdc, 0xb0, 0x06, 0x1c, 0xe4, 0x4b,
      0x57, 0xb4, 0x0c, 0x65, 0xb9, 0xb4, 0x6c
    };
    OCSP_REQ_CTX *ctx = NULL;
    OCSP_REQUEST *req = NULL;
    OCSP_CERTID *cid = NULL;
    OCSP_RESPONSE *rsp = NULL;
    BIO* bio1 = NULL;
    BIO* bio2 = NULL;
    X509* cert = NULL;
    X509* empty = NULL;
    X509 *issuer = NULL;
    X509_LOOKUP *lookup = NULL;
    X509_STORE *store = NULL;
    STACK_OF(X509_OBJECT) *str_objs = NULL;
    X509_OBJECT *x509_obj = NULL;
    STACK_OF(WOLFSSL_STRING) *skStr = NULL;

    ExpectNotNull(bio1 = BIO_new(BIO_s_bio()));
    ExpectNotNull(bio2 = BIO_new(BIO_s_bio()));
    ExpectIntEQ(BIO_make_bio_pair(bio1, bio2), WOLFSSL_SUCCESS);

    /* Load the leaf cert */
    ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(
            "certs/ocsp/server1-cert.pem", WOLFSSL_FILETYPE_PEM));
    ExpectNull(wolfSSL_X509_get1_ocsp(NULL));
    ExpectNotNull(skStr = wolfSSL_X509_get1_ocsp(cert));
    wolfSSL_X509_email_free(NULL);
    wolfSSL_X509_email_free(skStr);
    ExpectNotNull(empty = wolfSSL_X509_new());
    ExpectNull(wolfSSL_X509_get1_ocsp(empty));
    wolfSSL_X509_free(empty);

    ExpectNotNull(store = X509_STORE_new());
    ExpectNotNull(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()));
    ExpectIntEQ(X509_LOOKUP_load_file(lookup, "certs/ocsp/server1-cert.pem",
            X509_FILETYPE_PEM), 1);
    ExpectNotNull(str_objs = X509_STORE_get0_objects(store));
    ExpectNull(X509_OBJECT_retrieve_by_subject(NULL, X509_LU_X509, NULL));
    ExpectNull(X509_OBJECT_retrieve_by_subject(str_objs, X509_LU_X509, NULL));
    ExpectNull(X509_OBJECT_retrieve_by_subject(NULL, X509_LU_X509,
            X509_get_issuer_name(cert)));
    ExpectNull(X509_OBJECT_retrieve_by_subject(str_objs,
            X509_LU_CRL, X509_get_issuer_name(cert)));
    ExpectNotNull(x509_obj = X509_OBJECT_retrieve_by_subject(str_objs,
            X509_LU_X509, X509_get_issuer_name(cert)));
    ExpectNotNull(issuer = X509_OBJECT_get0_X509(x509_obj));
    ExpectTrue(wolfSSL_X509_OBJECT_get_type(NULL) == WOLFSSL_X509_LU_NONE);
#ifndef NO_WOLFSSL_STUB
    /* Not implemented and not in OpenSSL 1.1.0+ */
    wolfSSL_X509_OBJECT_free_contents(x509_obj);
#endif
    wolfSSL_X509_OBJECT_free(NULL);

    ExpectNotNull(req = OCSP_REQUEST_new());
    ExpectNotNull(cid = OCSP_cert_to_id(EVP_sha1(), cert, issuer));
    ExpectNotNull(OCSP_request_add0_id(req, cid));
    ExpectIntEQ(OCSP_request_add1_nonce(req, NULL, -1), 1);

    ExpectNotNull(ctx = OCSP_sendreq_new(bio1, "/", NULL, -1));
    ExpectIntEQ(OCSP_REQ_CTX_add1_header(ctx, "Host", "127.0.0.1"), 1);
    ExpectIntEQ(OCSP_REQ_CTX_set1_req(ctx, req), 1);
    ExpectIntEQ(OCSP_sendreq_nbio(&rsp, ctx), -1);
    ExpectIntEQ(BIO_write(bio2, ocspRespBin, sizeof(ocspRespBin)),
            sizeof(ocspRespBin));
#ifndef NO_ASN_TIME
    ExpectIntEQ(wc_SetTimeCb(test_wolfSSL_OCSP_REQ_CTX_time_cb), 0);
    ExpectIntEQ(OCSP_sendreq_nbio(&rsp, ctx), 1);
    ExpectIntEQ(wc_SetTimeCb(NULL), 0);
    ExpectNotNull(rsp);
#endif

    OCSP_REQ_CTX_free(ctx);
    OCSP_REQUEST_free(req);
    OCSP_RESPONSE_free(rsp);
    BIO_free(bio1);
    BIO_free(bio2);
    X509_free(cert);
    X509_STORE_free(store);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_X509_get1_ca_issuers(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) || \
    defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)) && \
    defined(WOLFSSL_ASN_CA_ISSUER) && !defined(NO_FILESYSTEM) && \
    !defined(NO_RSA)
    X509* cert = NULL;
    STACK_OF(WOLFSSL_STRING) *skStr = NULL;
    WOLFSSL_STRING url = NULL;
    const char* expected = "http://example.com/ca.pem";

    ExpectNull(wolfSSL_X509_get1_ca_issuers(NULL));
    ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(
            "certs/aia/ca-issuers-cert.pem", WOLFSSL_FILETYPE_PEM));
    ExpectNotNull(skStr = wolfSSL_X509_get1_ca_issuers(cert));
    ExpectIntEQ(wolfSSL_sk_WOLFSSL_STRING_num(skStr), 1);
    ExpectNotNull(url = wolfSSL_sk_WOLFSSL_STRING_value(skStr, 0));
    ExpectIntEQ(XSTRCMP(url, expected), 0);

    wolfSSL_X509_email_free(skStr);
    wolfSSL_X509_free(cert);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_X509_get1_aia_multi(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) || \
    defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)) && \
    defined(WOLFSSL_ASN_CA_ISSUER) && !defined(NO_FILESYSTEM) && \
    !defined(NO_RSA)
    X509* cert = NULL;
    STACK_OF(WOLFSSL_STRING) *ocsp = NULL;
    STACK_OF(WOLFSSL_STRING) *ca = NULL;
    const char* ocspExp1 = "http://127.0.0.1:22221";
    const char* ocspExp2 = "http://127.0.0.1:22222";
    const char* caExp1 = "http://www.wolfssl.com/ca.pem";
    const char* caExp2 = "https://www.wolfssl.com/ca2.pem";
    int i;
    int ocspFound1 = 0, ocspFound2 = 0;
    int caFound1 = 0, caFound2 = 0;

    ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(
            "certs/aia/multi-aia-cert.pem", WOLFSSL_FILETYPE_PEM));
    ExpectIntEQ(wolfSSL_X509_get_aia_overflow(cert), 0);

    ExpectNotNull(ocsp = wolfSSL_X509_get1_ocsp(cert));
    ExpectIntEQ(wolfSSL_sk_WOLFSSL_STRING_num(ocsp), 2);
    for (i = 0; i < wolfSSL_sk_WOLFSSL_STRING_num(ocsp); i++) {
        WOLFSSL_STRING url = wolfSSL_sk_WOLFSSL_STRING_value(ocsp, i);
        if (url == NULL)
            continue;
        if (XSTRCMP(url, ocspExp1) == 0) ocspFound1 = 1;
        if (XSTRCMP(url, ocspExp2) == 0) ocspFound2 = 1;
    }
    ExpectIntEQ(ocspFound1, 1);
    ExpectIntEQ(ocspFound2, 1);

    ExpectNotNull(ca = wolfSSL_X509_get1_ca_issuers(cert));
    ExpectIntEQ(wolfSSL_sk_WOLFSSL_STRING_num(ca), 2);
    for (i = 0; i < wolfSSL_sk_WOLFSSL_STRING_num(ca); i++) {
        WOLFSSL_STRING url = wolfSSL_sk_WOLFSSL_STRING_value(ca, i);
        if (url == NULL)
            continue;
        if (XSTRCMP(url, caExp1) == 0) caFound1 = 1;
        if (XSTRCMP(url, caExp2) == 0) caFound2 = 1;
    }
    ExpectIntEQ(caFound1, 1);
    ExpectIntEQ(caFound2, 1);

    wolfSSL_X509_email_free(ocsp);
    wolfSSL_X509_email_free(ca);
    wolfSSL_X509_free(cert);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_X509_get1_aia_overflow(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) || \
    defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)) && \
    !defined(NO_FILESYSTEM) && !defined(NO_RSA)
    X509* cert = NULL;
    STACK_OF(WOLFSSL_STRING) *ocsp = NULL;
    int count;

    ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(
            "certs/aia/overflow-aia-cert.pem", WOLFSSL_FILETYPE_PEM));

    ExpectNotNull(ocsp = wolfSSL_X509_get1_ocsp(cert));
    count = wolfSSL_sk_WOLFSSL_STRING_num(ocsp);
    ExpectIntEQ(count, 8);
    ExpectIntEQ(wolfSSL_X509_get_aia_overflow(cert), 1);

    wolfSSL_X509_email_free(ocsp);
    wolfSSL_X509_free(cert);
#endif
    return EXPECT_RESULT();
}

/* Parse a certificate whose subjectInfoAccess extension is present but does
 * not contain an id-ad-caRepository entry. RFC 5280 4.2.2.2 only requires
 * the SIA sequence be non-empty; previously wolfSSL incorrectly rejected
 * such certificates with ASN_PARSE_E. */
static int test_wolfSSL_SubjectInfoAccess_no_caRepository(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_SUBJ_INFO_ACC) && !defined(NO_RSA) && \
    !defined(NO_FILESYSTEM) && defined(WOLFSSL_PEM_TO_DER)
    const char* siaCert = "./certs/sia/timestamping-sia-cert.pem";
    byte* pemBuf = NULL;
    size_t pemSz = 0;
    byte* derBuf = NULL;
    word32 derSz = 0;
    DecodedCert cert;
    int ret = 0;

    ExpectIntEQ(load_file(siaCert, &pemBuf, &pemSz), 0);
    derSz = (word32)pemSz; /* DER will be smaller than PEM */
    ExpectNotNull(derBuf = (byte*)malloc(derSz));
    ExpectIntGE(ret = wc_CertPemToDer(pemBuf, (int)pemSz, derBuf, (int)derSz,
        CERT_TYPE), 0);

    if (ret > 0)
    {
        derSz = (word32)ret;
        wc_InitDecodedCert(&cert, derBuf, derSz, NULL);
        ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);

        /* SIA was present and decoded successfully. */
        ExpectIntEQ(cert.extSubjInfoAccSet, 1);
        /* No id-ad-caRepository entry exists in this cert's SIA. */
        ExpectNull(cert.extSubjInfoAccCaRepo);
        ExpectIntEQ((int)cert.extSubjInfoAccCaRepoSz, 0);

        wc_FreeDecodedCert(&cert);
    }

    free(derBuf);
    XFREE(pemBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
    return EXPECT_RESULT();
}

static int test_no_op_functions(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    /* this makes sure wolfSSL can compile and run these no-op functions */
    SSL_load_error_strings();
    ENGINE_load_builtin_engines();
    OpenSSL_add_all_ciphers();
    ExpectIntEQ(CRYPTO_malloc_init(), 0);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CRYPTO_memcmp(void)
{
    EXPECT_DECLS;
#ifdef OPENSSL_EXTRA
    char a[] = "wolfSSL (formerly CyaSSL) is a small, fast, portable "
               "implementation of TLS/SSL for embedded devices to the cloud.";
    char b[] = "wolfSSL (formerly CyaSSL) is a small, fast, portable "
               "implementation of TLS/SSL for embedded devices to the cloud.";
    char c[] = "wolfSSL (formerly CyaSSL) is a small, fast, portable "
               "implementation of TLS/SSL for embedded devices to the cloud!";

    ExpectIntEQ(CRYPTO_memcmp(a, b, sizeof(a)), 0);
    ExpectIntNE(CRYPTO_memcmp(a, c, sizeof(a)), 0);
#endif
    return EXPECT_RESULT();
}

/*----------------------------------------------------------------------------*
 | wolfCrypt ASN
 *----------------------------------------------------------------------------*/

static int test_wc_CreateEncryptedPKCS8Key(void)
{
    EXPECT_DECLS;
#if defined(HAVE_PKCS8) && !defined(NO_PWDBASED) && defined(WOLFSSL_AES_256) \
 && !defined(NO_AES_CBC) && !defined(NO_RSA) && !defined(NO_SHA) && \
    !defined(NO_ASN_CRYPT)
    WC_RNG rng;
    byte* encKey = NULL;
    word32 encKeySz = 0;
    word32 decKeySz = 0;
    const char password[] = "Lorem ipsum dolor sit amet";
    word32 passwordSz = (word32)XSTRLEN(password);
    word32 tradIdx = 0;

    XMEMSET(&rng, 0, sizeof(WC_RNG));
    ExpectIntEQ(wc_InitRng(&rng), 0);
    PRIVATE_KEY_UNLOCK();
    /* Call with NULL for out buffer to get necessary length. */
    ExpectIntEQ(wc_CreateEncryptedPKCS8Key((byte*)server_key_der_2048,
        sizeof_server_key_der_2048, NULL, &encKeySz, password, (int)passwordSz,
        PKCS5, PBES2, AES256CBCb, NULL, 0, WC_PKCS12_ITT_DEFAULT, &rng, NULL),
        WC_NO_ERR_TRACE(LENGTH_ONLY_E));
    ExpectNotNull(encKey = (byte*)XMALLOC(encKeySz, HEAP_HINT,
        DYNAMIC_TYPE_TMP_BUFFER));
    /* Call with the allocated out buffer. */
    ExpectIntGT(wc_CreateEncryptedPKCS8Key((byte*)server_key_der_2048,
        sizeof_server_key_der_2048, encKey, &encKeySz, password, (int)passwordSz,
        PKCS5, PBES2, AES256CBCb, NULL, 0, WC_PKCS12_ITT_DEFAULT, &rng, NULL),
        0);
    /* Decrypt the encrypted PKCS8 key we just made. */
    ExpectIntGT((decKeySz = (word32)wc_DecryptPKCS8Key(encKey, encKeySz, password,
        (int)passwordSz)), 0);
    /* encKey now holds the decrypted key (decrypted in place). */
    ExpectIntGT(wc_GetPkcs8TraditionalOffset(encKey, &tradIdx, decKeySz), 0);
    /* Check that the decrypted key matches the key prior to encryption. */
    ExpectIntEQ(XMEMCMP(encKey + tradIdx, server_key_der_2048,
        sizeof_server_key_der_2048), 0);
    PRIVATE_KEY_LOCK();

    XFREE(encKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    wc_FreeRng(&rng);
#endif
    return EXPECT_RESULT();
}

static int test_wc_DecryptedPKCS8Key(void)
{
    EXPECT_DECLS;
#if defined(HAVE_PKCS8) && !defined(NO_PWDBASED) && defined(WOLFSSL_AES_256) \
 && !defined(NO_AES_CBC) && !defined(NO_RSA) && !defined(NO_SHA) && \
    !defined(NO_ASN_CRYPT)
    static byte badPkcs5RsaEnc[] = {
        0x30, 0x82, 0x05, 0x2d, 0x30, 0x57, 0x06, 0x09,
        0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05,
        0x0d, 0x30, 0x4a, 0x30, 0x29, 0x06, 0x09, 0x2a,
        0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c,
        0x30, 0x1c, 0x04, 0x09, 0xad, 0x8f, 0xb7, 0x90,
        0x43, 0xd9, 0x3f, 0xe5, 0x02, 0x02, 0x04, 0x02,
        0x02, 0x04, 0x80, 0x30, 0x0c, 0x06, 0x08, 0x2a,
        0xbc, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x09, 0x05,
        0x00, 0x30, 0x1d, 0x06, 0x09, 0x60, 0x86, 0x48,
        0x01, 0x65, 0x03, 0x04, 0x01, 0x2a, 0x04, 0x10,
        0x90, 0xf9, 0xa4, 0xd7, 0xf2, 0xae, 0x58, 0xd6,
        0xe1, 0x7c, 0x60, 0x7b, 0x84, 0xc0, 0x8c, 0x44,
        0x04, 0x50, 0xc8, 0xd0, 0x03, 0xa7, 0x79, 0xa9,
        0x11, 0x8b, 0xbd, 0xd6, 0xcb, 0xd9, 0x9e, 0xd7,
        0x2d, 0xac, 0x2c, 0xb8, 0xc9, 0x5f, 0xe7, 0x8b,
        0x36, 0x26, 0x26, 0x23, 0x2a, 0x21, 0x25, 0x6f,
        0xd0, 0x52, 0xd3, 0xeb, 0xff, 0x1f, 0x06, 0xb0,
        0x40, 0xd1, 0x4b, 0x9e, 0x73, 0xbf, 0x17, 0x24,
        0x0b, 0x2d, 0xf6, 0x4f, 0xce, 0xb4, 0x47, 0x82,
        0x7c, 0x23, 0x21, 0xdc, 0x71, 0xc7, 0x1c, 0x71,
        0xc7, 0x1c, 0x71, 0xc7, 0x1c, 0x71, 0xc7, 0x1c,
        0x71, 0xc7, 0x1c, 0x71, 0xc7, 0x1c, 0x71, 0xc7,
        0x1c, 0x71, 0xc7, 0x1c, 0x71, 0xc7, 0x1c, 0x71,
        0xc7, 0x1c, 0x71, 0xc7, 0x1c, 0x71, 0xc7, 0x07,
        0x27, 0x82, 0xcd, 0x36, 0xd7, 0xf4, 0xa1, 0xb5,
        0xc5, 0x17, 0x5f, 0xe6, 0xd0, 0xf3, 0x97, 0x3e,
        0x1a, 0xcd, 0x39, 0x9d, 0x41, 0xce, 0xed, 0x14,
        0xdb, 0x3d, 0xa5, 0x7b, 0xd3, 0xcb, 0x93, 0x1a,
        0x4c, 0x32, 0x0e, 0x8b, 0xa3, 0x41, 0xbe, 0xcb,
        0xa3, 0xd5, 0xfb, 0x8d, 0xb6, 0x8a, 0x4e, 0x0b,
        0x0b, 0xbd, 0x74, 0x33, 0xd2, 0xb6, 0x43, 0x20,
        0x96, 0xf9, 0x46, 0x57, 0x66, 0x54, 0x94, 0xfa,
        0x1c, 0x3a, 0xe4, 0xf7, 0x0a, 0x59, 0x37, 0x5f,
        0x6a, 0xc2, 0xba, 0xea, 0xfd, 0xd4, 0xd7, 0x64,
        0xee, 0x53, 0x40, 0xe9, 0x3c, 0x71, 0xbf, 0x93,
        0x87, 0xf3, 0x53, 0x0c, 0x92, 0x0b, 0xbe, 0x4c,
        0xde, 0x35, 0xd7, 0xb0, 0x60, 0xc6, 0x37, 0x1c,
        0x4c, 0x08, 0x8f, 0xe1, 0x95, 0xba, 0xde, 0x42,
        0x68, 0x6a, 0x76, 0x0b, 0x84, 0x14, 0xc6, 0x5e,
        0xb1, 0xa1, 0x45, 0xa7, 0x31, 0x72, 0xfe, 0xaa,
        0x43, 0x86, 0xa3, 0x31, 0x41, 0x68, 0x66, 0x41,
        0x31, 0xe0, 0xa4, 0x63, 0x1d, 0x62, 0x57, 0x2c,
        0x49, 0x9b, 0x9c, 0x32, 0x4a, 0x4f, 0x3c, 0xf3,
        0xcf, 0x3c, 0xf3, 0xcf, 0x3c, 0xf3, 0xcf, 0x3c,
        0xf3, 0xcf, 0x3c, 0xf3, 0xcf, 0x3c, 0xf3, 0xcf,
        0x3c, 0xf3, 0xcf, 0x3c, 0xf3, 0xcf, 0x3c, 0xf3,
        0xcf, 0x3c, 0xf3, 0xcf, 0x3c, 0xf3, 0xcf, 0x3c,
        0xf3, 0xcf, 0x3c, 0xf3, 0xcf, 0x3c, 0xf3, 0xcf,
        0x3c, 0xf3, 0xcf, 0x3c, 0xf3, 0xcf, 0x3c, 0xf3,
        0xcf, 0x3c, 0xf3, 0xcf, 0x3c, 0xf3, 0xcf, 0x3c,
        0xf3, 0xcf, 0x3c, 0xf3, 0xcf, 0x3d, 0x4c, 0x72,
        0x7d, 0xc7, 0xa8, 0x07, 0x4f, 0xa4, 0x52, 0x1f,
        0xb8, 0xa9, 0x89, 0x4c, 0x65, 0xd1, 0x8f, 0x3c,
        0xf3, 0xcf, 0x3c, 0xf3, 0xcf, 0x3f, 0x1e, 0x31,
        0x53, 0x77, 0x37, 0xaf, 0xe4, 0x43, 0x23, 0x34,
        0xfc, 0x8e, 0xc2, 0xba, 0x32, 0x40, 0xb3, 0xe7,
        0xab, 0x6d, 0xc3, 0xa0, 0x9e, 0xc7, 0x6c, 0x13,
        0xe7, 0x77, 0xd5, 0x0a, 0x1a, 0x04, 0xb7, 0xd4,
        0x13, 0xcd, 0x04, 0x39, 0x22, 0x67, 0xc4, 0x00,
        0xe4, 0xd0, 0x1f, 0xf7, 0x9d, 0x2b, 0x73, 0xda,
        0xee, 0x00, 0x1b, 0x9a, 0x5c, 0xb0, 0x4c, 0x90,
        0x9b, 0x38, 0x41, 0xd3, 0x13, 0xd0, 0xfa, 0xec,
        0x0f, 0x65, 0xe9, 0x02, 0x90, 0x39, 0xa8, 0xe4,
        0xd4, 0x52, 0xa6, 0x1f, 0x7a, 0x54, 0x00, 0x19,
        0x13, 0x94, 0xae, 0x7a, 0xf2, 0xa7, 0xce, 0xf5,
        0x29, 0x78, 0x66, 0x1c, 0x03, 0x26, 0x65, 0xe8,
        0x03, 0x8e, 0x97, 0x67, 0x20, 0x61, 0x4c, 0xbd,
        0xa0, 0xb3, 0x88, 0x10, 0x8b, 0x74, 0x40, 0x8d,
        0xc6, 0xe6, 0x26, 0x32, 0x0f, 0x01, 0x47, 0x35,
        0xb3, 0x86, 0x87, 0xa9, 0x6d, 0xf8, 0xf8, 0x9f,
        0xca, 0x30, 0x69, 0xf7, 0x5d, 0x89, 0x3f, 0xf5,
        0x1d, 0xd5, 0x26, 0xd7, 0xef, 0x43, 0x26, 0x06,
        0x26, 0x7b, 0xf0, 0xdd, 0x86, 0xa6, 0x58, 0x71,
        0xd6, 0xcb, 0x45, 0xb4, 0x4f, 0x52, 0xd7, 0xf1,
        0xae, 0x06, 0xad, 0xc7, 0x94, 0x17, 0xe8, 0x44,
        0x59, 0x02, 0xe1, 0x22, 0x9e, 0x59, 0xa6, 0xcc,
        0x3b, 0x20, 0x5b, 0x95, 0xf1, 0x34, 0x31, 0x52,
        0x7e, 0x6d, 0xff, 0x4b, 0x45, 0x9a, 0xff, 0xba,
        0x1a, 0x41, 0x48, 0x20, 0x49, 0xb8, 0x62, 0xef,
        0x82, 0xca, 0x14, 0x7e, 0x14, 0xfa, 0x49, 0x3f,
        0xfb, 0x5e, 0xb1, 0x60, 0x30, 0x94, 0x4c, 0xee,
        0x4b, 0x78, 0xa2, 0x79, 0xb2, 0xa1, 0xbd, 0xb1,
        0x94, 0x24, 0xd6, 0x9c, 0xf0, 0x41, 0x3b, 0xc6,
        0xf2, 0x30, 0x8c, 0x8a, 0xdd, 0x2e, 0x44, 0x41,
        0x7e, 0x92, 0x3b, 0x09, 0x2e, 0x19, 0x9d, 0xb3,
        0xb8, 0xa6, 0x9f, 0x86, 0x7e, 0x88, 0x5d, 0xe0,
        0x13, 0x7c, 0x89, 0xf6, 0x96, 0xb1, 0x66, 0x3f,
        0xc2, 0x8f, 0x71, 0x43, 0x6a, 0xd5, 0x8c, 0x6e,
        0xae, 0xdf, 0x80, 0xd6, 0x01, 0x7a, 0x50, 0xf6,
        0x2b, 0x25, 0x0f, 0x8d, 0x84, 0x3b, 0xd5, 0xb5,
        0x61, 0xb1, 0x61, 0x58, 0xff, 0x4c, 0xe8, 0x6a,
        0xa4, 0xae, 0x2b, 0xf5, 0xfe, 0xee, 0xeb, 0xa6,
        0xf2, 0xf3, 0xc5, 0xa1, 0x63, 0x92, 0xde, 0x67,
        0x2f, 0x40, 0xfc, 0x3b, 0x36, 0x64, 0xcc, 0x7b,
        0xe9, 0xd8, 0xf7, 0x5d, 0x40, 0x56, 0x10, 0xaf,
        0xd4, 0x52, 0xe2, 0xa6, 0x7c, 0xe9, 0xe4, 0x4b,
        0x0b, 0xbd, 0x74, 0x33, 0xd2, 0xb6, 0x43, 0xd6,
        0x0a, 0xe0, 0x12, 0x21, 0xa7, 0xab, 0x45, 0x19,
        0x6e, 0xae, 0x71, 0x83, 0x22, 0x1a, 0x0d, 0xde,
        0xd5, 0xb6, 0x82, 0xd2, 0xd7, 0xd8, 0x14, 0x6d,
        0xfa, 0xb4, 0xae, 0xee, 0x55, 0x43, 0xd2, 0x1e,
        0x59, 0xe2, 0x01, 0xe0, 0xfa, 0x53, 0x43, 0x3b,
        0x40, 0x17, 0x06, 0x6a, 0x5e, 0x5f, 0x42, 0xc2,
        0x6a, 0x4e, 0x7c, 0x5a, 0x69, 0x41, 0x8b, 0x62,
        0x76, 0xd4, 0x1b, 0x00, 0xbc, 0x24, 0x27, 0x71,
        0xf8, 0xf3, 0xca, 0x57, 0x10, 0xb9, 0x32, 0x14,
        0x9b, 0x92, 0x35, 0xdd, 0xb7, 0xb8, 0x2e, 0xd8,
        0xb3, 0xe9, 0x62, 0x8e, 0xe2, 0x5e, 0x16, 0xd4,
        0xed, 0xf4, 0xd3, 0xc1, 0xba, 0x5d, 0x49, 0xce,
        0x78, 0x5c, 0xf5, 0xbb, 0xad, 0x61, 0x1f, 0x64,
        0x52, 0x22, 0xb4, 0xa3, 0x07, 0x18, 0x3d, 0xd3,
        0x9d, 0xec, 0xe6, 0x9e, 0xb5, 0xad, 0x0c, 0xd3,
        0x3b, 0xb6, 0xeb, 0xcd, 0x9c, 0x69, 0x45, 0xf2,
        0x07, 0x24, 0xe9, 0xd7, 0xe0, 0xe7, 0x62, 0xe5,
        0x01, 0x34, 0x24, 0x4e, 0xf6, 0x32, 0xe8, 0x42,
        0x97, 0x3e, 0x14, 0xaf, 0xbc, 0x26, 0xbd, 0x73,
        0xc5, 0xde, 0x5a, 0x8e, 0x65, 0x61, 0x97, 0x81,
        0x31, 0x52, 0xa3, 0xbd, 0x9b, 0x9e, 0xda, 0xdd,
        0x37, 0x15, 0x30, 0xfb, 0x3b, 0x59, 0x0c, 0x91,
        0x8b, 0x54, 0x49, 0x68, 0xc6, 0x41, 0x38, 0x77,
        0x1c, 0x00, 0xb2, 0xc3, 0x37, 0xe2, 0x50, 0x67,
        0xeb, 0x49, 0xa4, 0xde, 0x04, 0x1e, 0xf5, 0xcc,
        0x49, 0x24, 0x5a, 0x8d, 0x94, 0x33, 0xbf, 0x55,
        0xf8, 0x70, 0x7d, 0x1e, 0x5b, 0xe3, 0x74, 0x6b,
        0x34, 0xb3, 0xf6, 0x8a, 0x47, 0xf9, 0x2f, 0xc9,
        0xcb, 0x6a, 0x80, 0x89, 0xf2, 0x19, 0x24, 0x5b,
        0xdf, 0x04, 0x9a, 0x53, 0x1c, 0x9f, 0x71, 0xea,
        0x01, 0xd3, 0xe9, 0x14, 0x87, 0xee, 0x2a, 0x62,
        0x53, 0x19, 0x74, 0x64, 0x19, 0x03, 0x00, 0xd6,
        0xa1, 0xcb, 0xdf, 0x59, 0x77, 0x6b, 0xa9, 0x25,
        0x32, 0xff, 0xe9, 0xa9, 0x41, 0x06, 0x0c, 0x06,
        0xd4, 0xae, 0xfb, 0x58, 0x20, 0x2e, 0xe3, 0xe0,
        0xce, 0x53, 0xea, 0x03, 0xcb, 0x3f, 0x64, 0xe9,
        0xd9, 0xc1, 0x0e, 0xf8, 0xec, 0x97, 0xee, 0x05,
        0x42, 0x41, 0x61, 0xcc, 0x75, 0x13, 0x8d, 0x88,
        0x62, 0x84, 0xa1, 0x3c, 0xa3, 0x30, 0xce, 0x12,
        0xf1, 0x84, 0xee, 0x26, 0x08, 0x04, 0xae, 0x67,
        0x56, 0xa0, 0x84, 0x91, 0x8a, 0xbd, 0xc4, 0xba,
        0x07, 0xb3, 0x06, 0xe7, 0xc8, 0x12, 0xae, 0x56,
        0x46, 0xcd, 0x8d, 0x5c, 0x91, 0x05, 0x90, 0x11,
        0x37, 0xef, 0xe0, 0x3e, 0xf3, 0xc6, 0x95, 0x13,
        0xeb, 0x2f, 0xe4, 0x3e, 0xfc, 0xe4, 0xc0, 0x61,
        0xfb, 0x1b, 0x74, 0x78, 0xe9, 0x6b, 0x7d, 0xe4,
        0xa2, 0xc4, 0x6d, 0x26, 0x6d, 0xc0, 0x06, 0xba,
        0x9f, 0x7e, 0x7d, 0x5e, 0x7f, 0xfa, 0x66, 0x08,
        0xd9, 0x70, 0x39, 0x05, 0xfa, 0x10, 0xfd, 0x5f,
        0xaa, 0xc4, 0x9d, 0x02, 0xd4, 0xf8, 0x0f, 0x3f,
        0xd3, 0xbe, 0xaa, 0x86, 0x4a, 0x0f, 0x8e, 0x23,
        0x02, 0xbf, 0x48, 0x26, 0x93, 0x5f, 0xc2, 0xc5,
        0x05, 0xca, 0xa1, 0x6d, 0x96, 0xd1, 0x3a, 0x30,
        0x66, 0xe1, 0x97, 0x1d, 0x4c, 0xb0, 0x93, 0xd7,
        0x8d, 0x3c, 0xc0, 0xf9, 0x2b, 0x81, 0x0d, 0xd7,
        0x68, 0x49, 0x18, 0xab, 0xdc, 0x4b, 0xa0, 0x7b,
        0x30, 0x6e, 0x7c, 0x81, 0x2a, 0xe5, 0x64, 0x6c,
        0xd8, 0xd5, 0xc9, 0x10, 0x59, 0x01, 0x13, 0x7e,
        0xfe, 0x03, 0xef, 0x3c, 0x69, 0x51, 0x3e, 0xb2,
        0xfe, 0x43, 0xef, 0xce, 0x4c, 0x06, 0x1f, 0xb1,
        0xb7, 0x47, 0x8e, 0x96, 0xb7, 0xde, 0x4a, 0x2c,
        0x46, 0xd2, 0x66, 0xdc, 0x00, 0x6b, 0xa9, 0xf7,
        0xe7, 0xd5, 0xe7, 0xff, 0xa6, 0x60, 0x8d, 0x97,
        0x03, 0x90, 0x5f, 0xa1, 0x0f, 0xd5, 0xfa, 0xac,
        0x49, 0xd0, 0x2d, 0x4f, 0x80, 0xf3, 0xfd, 0x3b,
        0xea, 0xa8, 0x64, 0xa0, 0xf8, 0xe2, 0x30, 0x2b,
        0xf4, 0x80, 0x2c, 0x50, 0x5c, 0xaa, 0x16, 0xd9,
        0x6d, 0x13, 0xa3, 0x06, 0x6e, 0x19, 0x71, 0xd4,
        0xcb, 0x09, 0x3d, 0x78, 0xd3, 0xcc, 0x0f, 0x92,
        0xb8, 0x10, 0xdd, 0x76, 0x88, 0x97, 0x1b, 0x7f,
        0xf0, 0x5c, 0xfb, 0x97, 0x66, 0x3e, 0x7f, 0x66,
        0xf9, 0xa4, 0xd5, 0x29, 0xb5, 0x54, 0x8a, 0xaa,
        0xfc, 0xe2, 0xdb, 0xb7,
    };
    const char password[] = "password";
    word32 passwordSz = (word32)XSTRLEN(password);

    /* Decrypt the encrypted PKCS8 key we just made. */
    ExpectIntEQ(wc_DecryptPKCS8Key(badPkcs5RsaEnc, sizeof(badPkcs5RsaEnc),
        password, (int)passwordSz), ASN_PARSE_E);
#endif
    return EXPECT_RESULT();
}

static int test_wc_GetPkcs8TraditionalOffset(void)
{
    EXPECT_DECLS;
#if !defined(NO_ASN) && !defined(NO_FILESYSTEM) && defined(HAVE_PKCS8)
    int length;
    int derSz = 0;
    word32 inOutIdx;
    const char* path = "./certs/server-keyPkcs8.der";
    const char* pathAttributes = "./certs/ca-key-pkcs8-attribute.der";
    XFILE file = XBADFILE;
    byte der[2048];

    ExpectTrue((file = XFOPEN(path, "rb")) != XBADFILE);
    ExpectIntGT(derSz = (int)XFREAD(der, 1, sizeof(der), file), 0);
    if (file != XBADFILE)
        XFCLOSE(file);
    file = XBADFILE; /* reset file to avoid warning of use after close */

    /* valid case */
    inOutIdx = 0;
    ExpectIntGT(length = wc_GetPkcs8TraditionalOffset(der, &inOutIdx, (word32)derSz),
        0);

    /* inOutIdx > sz */
    inOutIdx = 4000;
    ExpectIntEQ(length = wc_GetPkcs8TraditionalOffset(der, &inOutIdx, (word32)derSz),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* null input */
    inOutIdx = 0;
    ExpectIntEQ(length = wc_GetPkcs8TraditionalOffset(NULL, &inOutIdx, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* invalid input, fill buffer with 1's */
    XMEMSET(der, 1, sizeof(der));
    inOutIdx = 0;
    ExpectIntEQ(length = wc_GetPkcs8TraditionalOffset(der, &inOutIdx, (word32)derSz),
        WC_NO_ERR_TRACE(ASN_PARSE_E));

    /* test parsing with attributes */
    ExpectTrue((file = XFOPEN(pathAttributes, "rb")) != XBADFILE);
    ExpectIntGT(derSz = (int)XFREAD(der, 1, sizeof(der), file), 0);
    if (file != XBADFILE)
        XFCLOSE(file);

    inOutIdx = 0;
    ExpectIntGT(length = wc_GetPkcs8TraditionalOffset(der, &inOutIdx,
        (word32)derSz), 0);
#endif /* NO_ASN */
    return EXPECT_RESULT();
}

static int test_wc_SetSubjectRaw(void)
{
    EXPECT_DECLS;
#if !defined(NO_ASN) && !defined(NO_FILESYSTEM) && defined(OPENSSL_EXTRA) && \
    defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && !defined(NO_RSA)
    const char* joiCertFile = "./certs/test/cert-ext-joi.der";
    WOLFSSL_X509* x509 = NULL;
    int peerCertSz;
    const byte* peerCertBuf = NULL;
    Cert forgedCert;

    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(joiCertFile,
        WOLFSSL_FILETYPE_ASN1));

    ExpectNotNull(peerCertBuf = wolfSSL_X509_get_der(x509, &peerCertSz));

    ExpectIntEQ(0, wc_InitCert(&forgedCert));

    ExpectIntEQ(0, wc_SetSubjectRaw(&forgedCert, peerCertBuf, peerCertSz));

    wolfSSL_FreeX509(x509);
#endif
    return EXPECT_RESULT();
}

static int test_wc_GetSubjectRaw(void)
{
    EXPECT_DECLS;
#if !defined(NO_ASN) && !defined(NO_FILESYSTEM) && defined(OPENSSL_EXTRA) && \
    defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT)
    Cert cert;
    byte *subjectRaw;

    ExpectIntEQ(0, wc_InitCert(&cert));
    ExpectIntEQ(0, wc_GetSubjectRaw(&subjectRaw, &cert));
#endif
    return EXPECT_RESULT();
}

static int test_wc_SetIssuerRaw(void)
{
    EXPECT_DECLS;
#if !defined(NO_ASN) && !defined(NO_FILESYSTEM) && defined(OPENSSL_EXTRA) && \
    defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && !defined(NO_RSA)
    const char* joiCertFile = "./certs/test/cert-ext-joi.der";
    WOLFSSL_X509* x509 = NULL;
    int peerCertSz;
    const byte* peerCertBuf = NULL;
    Cert forgedCert;

    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(joiCertFile,
        WOLFSSL_FILETYPE_ASN1));

    ExpectNotNull(peerCertBuf = wolfSSL_X509_get_der(x509, &peerCertSz));

    ExpectIntEQ(0, wc_InitCert(&forgedCert));

    ExpectIntEQ(0, wc_SetIssuerRaw(&forgedCert, peerCertBuf, peerCertSz));

    wolfSSL_FreeX509(x509);
#endif
    return EXPECT_RESULT();
}

static int test_wc_SetIssueBuffer(void)
{
    EXPECT_DECLS;
#if !defined(NO_ASN) && !defined(NO_FILESYSTEM) && defined(OPENSSL_EXTRA) && \
    defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && !defined(NO_RSA)
    const char* joiCertFile = "./certs/test/cert-ext-joi.der";
    WOLFSSL_X509* x509 = NULL;
    int peerCertSz;
    const byte* peerCertBuf = NULL;
    Cert forgedCert;

    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(joiCertFile,
        WOLFSSL_FILETYPE_ASN1));

    ExpectNotNull(peerCertBuf = wolfSSL_X509_get_der(x509, &peerCertSz));

    ExpectIntEQ(0, wc_InitCert(&forgedCert));

    ExpectIntEQ(0, wc_SetIssuerBuffer(&forgedCert, peerCertBuf, peerCertSz));

    wolfSSL_FreeX509(x509);
#endif
    return EXPECT_RESULT();
}

/*
 * Testing wc_SetSubjectKeyId
 */
static int test_wc_SetSubjectKeyId(void)
{
    EXPECT_DECLS;
#if !defined(NO_ASN) && !defined(NO_FILESYSTEM) && defined(OPENSSL_EXTRA) && \
    defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && defined(HAVE_ECC)
    Cert cert;
    const char* file = "certs/ecc-client-keyPub.pem";

    ExpectIntEQ(0, wc_InitCert(&cert));
    ExpectIntEQ(0, wc_SetSubjectKeyId(&cert, file));

    ExpectIntEQ(WC_NO_ERR_TRACE(BAD_FUNC_ARG), wc_SetSubjectKeyId(NULL, file));
    ExpectIntGT(0, wc_SetSubjectKeyId(&cert, "badfile.name"));
#endif
    return EXPECT_RESULT();
} /* END test_wc_SetSubjectKeyId */

/*
 * Testing wc_SetSubject
 */
static int test_wc_SetSubject(void)
{
    EXPECT_DECLS;
#if !defined(NO_ASN) && !defined(NO_FILESYSTEM) && defined(OPENSSL_EXTRA) && \
    defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && defined(HAVE_ECC)
    Cert cert;
    const char* file = "./certs/ca-ecc-cert.pem";

    ExpectIntEQ(0, wc_InitCert(&cert));
    ExpectIntEQ(0, wc_SetSubject(&cert, file));

    ExpectIntEQ(WC_NO_ERR_TRACE(BAD_FUNC_ARG), wc_SetSubject(NULL, file));
    ExpectIntGT(0, wc_SetSubject(&cert, "badfile.name"));
#endif
    return EXPECT_RESULT();
} /* END test_wc_SetSubject */


static int test_CheckCertSignature(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && defined(WOLFSSL_SMALL_CERT_VERIFY)
    WOLFSSL_CERT_MANAGER* cm = NULL;
#if !defined(NO_FILESYSTEM) && (!defined(NO_RSA) || defined(HAVE_ECC))
    XFILE fp = XBADFILE;
    byte  cert[4096];
    int   certSz;
#endif

    ExpectIntEQ(WC_NO_ERR_TRACE(BAD_FUNC_ARG), wc_CheckCertSignature(NULL, 0, NULL, NULL));
    ExpectNotNull(cm = wolfSSL_CertManagerNew_ex(NULL));
    ExpectIntEQ(WC_NO_ERR_TRACE(BAD_FUNC_ARG), wc_CheckCertSignature(NULL, 0, NULL, cm));

#ifndef NO_RSA
#ifdef USE_CERT_BUFFERS_1024
    ExpectIntEQ(WC_NO_ERR_TRACE(ASN_NO_SIGNER_E), wc_CheckCertSignature(server_cert_der_1024,
                sizeof_server_cert_der_1024, NULL, cm));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CertManagerLoadCABuffer(cm,
                ca_cert_der_1024, sizeof_ca_cert_der_1024,
                WOLFSSL_FILETYPE_ASN1));
    ExpectIntEQ(0, wc_CheckCertSignature(server_cert_der_1024,
                sizeof_server_cert_der_1024, NULL, cm));
#elif defined(USE_CERT_BUFFERS_2048)
    ExpectIntEQ(WC_NO_ERR_TRACE(ASN_NO_SIGNER_E), wc_CheckCertSignature(server_cert_der_2048,
                sizeof_server_cert_der_2048, NULL, cm));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CertManagerLoadCABuffer(cm,
                ca_cert_der_2048, sizeof_ca_cert_der_2048,
                WOLFSSL_FILETYPE_ASN1));
    ExpectIntEQ(0, wc_CheckCertSignature(server_cert_der_2048,
                sizeof_server_cert_der_2048, NULL, cm));
#endif
#endif

#if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256)
    ExpectIntEQ(WC_NO_ERR_TRACE(ASN_NO_SIGNER_E), wc_CheckCertSignature(serv_ecc_der_256,
                sizeof_serv_ecc_der_256, NULL, cm));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CertManagerLoadCABuffer(cm,
                ca_ecc_cert_der_256, sizeof_ca_ecc_cert_der_256,
                WOLFSSL_FILETYPE_ASN1));
    ExpectIntEQ(0, wc_CheckCertSignature(serv_ecc_der_256, sizeof_serv_ecc_der_256,
                NULL, cm));
#endif

#if !defined(NO_FILESYSTEM)
    wolfSSL_CertManagerFree(cm);
    cm = NULL;
    ExpectNotNull(cm = wolfSSL_CertManagerNew_ex(NULL));
#ifndef NO_RSA
    ExpectTrue((fp = XFOPEN("./certs/server-cert.der", "rb")) != XBADFILE);
    ExpectIntGT((certSz = (int)XFREAD(cert, 1, sizeof(cert), fp)), 0);
    if (fp != XBADFILE) {
        XFCLOSE(fp);
        fp = XBADFILE;
    }
    ExpectIntEQ(WC_NO_ERR_TRACE(ASN_NO_SIGNER_E), wc_CheckCertSignature(cert, certSz, NULL, cm));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CertManagerLoadCA(cm,
                "./certs/ca-cert.pem", NULL));
    ExpectIntEQ(0, wc_CheckCertSignature(cert, certSz, NULL, cm));
#endif
#ifdef HAVE_ECC
    ExpectTrue((fp = XFOPEN("./certs/server-ecc.der", "rb")) != XBADFILE);
    ExpectIntGT((certSz = (int)XFREAD(cert, 1, sizeof(cert), fp)), 0);
    if (fp != XBADFILE) {
        XFCLOSE(fp);
        fp = XBADFILE;
    }
    ExpectIntEQ(WC_NO_ERR_TRACE(ASN_NO_SIGNER_E), wc_CheckCertSignature(cert, certSz, NULL, cm));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CertManagerLoadCA(cm,
                "./certs/ca-ecc-cert.pem", NULL));
    ExpectIntEQ(0, wc_CheckCertSignature(cert, certSz, NULL, cm));
#endif
#endif

#if !defined(NO_FILESYSTEM) && (!defined(NO_RSA) || defined(HAVE_ECC))
    (void)fp;
    (void)cert;
    (void)certSz;
#endif

    wolfSSL_CertManagerFree(cm);
#endif
    return EXPECT_RESULT();
}

static int test_wc_ParseCert(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_RSA)
    DecodedCert decodedCert;
    const byte* rawCert = client_cert_der_2048;
    const int rawCertSize = sizeof_client_cert_der_2048;

    wc_InitDecodedCert(&decodedCert, rawCert, rawCertSize, NULL);
    ExpectIntEQ(wc_ParseCert(&decodedCert, CERT_TYPE, NO_VERIFY, NULL), 0);
#ifndef IGNORE_NAME_CONSTRAINTS
    /* check that the subjects emailAddress was not put in the alt name list */
    ExpectNotNull(decodedCert.subjectEmail);
    ExpectNull(decodedCert.altEmailNames);
#endif
    wc_FreeDecodedCert(&decodedCert);
#endif
    return EXPECT_RESULT();
}

/* Test wc_ParseCert decoding of various encodings and scenarios ensuring that
 * the API safely errors out on badly-formed ASN input.
 * NOTE: Test not compatible with released FIPS implementations!
 */
static int test_wc_ParseCert_Error(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_RSA) && !defined(HAVE_SELFTEST) && \
    (!defined(HAVE_FIPS) || \
    (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2)))
    DecodedCert decodedCert;
    int i;

    /* Certificate data */
    const byte c0[] = { 0x30, 0x04, 0x30, 0x02, 0x02, 0x80, 0x00, 0x00};
    const byte c1[] = { 0x30, 0x04, 0x30, 0x04, 0x02, 0x80, 0x00, 0x00};
    const byte c2[] = { 0x30, 0x06, 0x30, 0x04, 0x02, 0x80, 0x00, 0x00};
    const byte c3[] = { 0x30, 0x07, 0x30, 0x05, 0x02, 0x80, 0x10, 0x00, 0x00};
    const byte c4[] = { 0x02, 0x80, 0x10, 0x00, 0x00};

    /* Test data */
    struct testStruct {
        const byte* c;
        word32 cSz;
        int expRet;
    } t[5];
    const int tSz = (int)(sizeof(t) / sizeof(struct testStruct));

    #define INIT_TEST_DATA(i,x,y) \
        t[i].c = x; t[i].cSz = sizeof(x); t[i].expRet = y
    INIT_TEST_DATA(0, c0, WC_NO_ERR_TRACE(ASN_PARSE_E) );
    INIT_TEST_DATA(1, c1, WC_NO_ERR_TRACE(ASN_PARSE_E) );
    INIT_TEST_DATA(2, c2, WC_NO_ERR_TRACE(ASN_PARSE_E) );
    INIT_TEST_DATA(3, c3, WC_NO_ERR_TRACE(ASN_PARSE_E) );
    INIT_TEST_DATA(4, c4, WC_NO_ERR_TRACE(ASN_PARSE_E) );
    #undef INIT_TEST_DATA

    for (i = 0; i < tSz; i++) {
        WOLFSSL_MSG_EX("i == %d", i);
        wc_InitDecodedCert(&decodedCert, t[i].c, t[i].cSz, NULL);
        ExpectIntEQ(wc_ParseCert(&decodedCert, CERT_TYPE, NO_VERIFY, NULL), t[i].expRet);
        wc_FreeDecodedCert(&decodedCert);
    }
#endif
    return EXPECT_RESULT();
}

static int test_MakeCertWithPathLen(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_CERT_REQ) && !defined(NO_ASN_TIME) && \
    defined(WOLFSSL_CERT_GEN) && defined(HAVE_ECC)
    const byte expectedPathLen = 7;
    Cert cert;
    DecodedCert decodedCert;
    byte der[FOURK_BUF];
    int derSize = 0;
    WC_RNG rng;
    ecc_key key;
    int ret;

    XMEMSET(&rng, 0, sizeof(WC_RNG));
    XMEMSET(&key, 0, sizeof(ecc_key));
    XMEMSET(&cert, 0, sizeof(Cert));
    XMEMSET(&decodedCert, 0, sizeof(DecodedCert));

    ExpectIntEQ(wc_InitRng(&rng), 0);
    ExpectIntEQ(wc_ecc_init(&key), 0);
    ExpectIntEQ(wc_ecc_make_key(&rng, 32, &key), 0);
    ExpectIntEQ(wc_InitCert(&cert), 0);

    (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.state, "state", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.locality, "Bozeman", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.org, "yourOrgNameHere", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.unit, "yourUnitNameHere", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.commonName, "www.yourDomain.com",
        CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.email, "yourEmail@yourDomain.com",
        CTC_NAME_SIZE);

    cert.selfSigned = 1;
    cert.isCA       = 1;
    cert.pathLen    = expectedPathLen;
    cert.pathLenSet = 1;
    cert.sigType    = CTC_SHA256wECDSA;

#ifdef WOLFSSL_CERT_EXT
    cert.keyUsage |= KEYUSE_KEY_CERT_SIGN;
#endif

    ExpectIntGE(wc_MakeCert(&cert, der, FOURK_BUF, NULL, &key, &rng), 0);
    ExpectIntGE(derSize = wc_SignCert(cert.bodySz, cert.sigType, der,
        FOURK_BUF, NULL, &key, &rng), 0);

    wc_InitDecodedCert(&decodedCert, der, (word32)derSize, NULL);
    ExpectIntEQ(wc_ParseCert(&decodedCert, CERT_TYPE, NO_VERIFY, NULL), 0);
    ExpectIntEQ(decodedCert.pathLength, expectedPathLen);

    wc_FreeDecodedCert(&decodedCert);
    ret = wc_ecc_free(&key);
    ExpectIntEQ(ret, 0);
    ret = wc_FreeRng(&rng);
    ExpectIntEQ(ret, 0);
#endif
    return EXPECT_RESULT();
}

static int test_PathLenSelfIssued(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_CERT_REQ) && !defined(NO_ASN_TIME) && \
    defined(WOLFSSL_CERT_GEN) && defined(HAVE_ECC) && \
    defined(WOLFSSL_CERT_EXT) && !defined(NO_CERTS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH))
    Cert cert;
    DecodedCert decodedCert;
    byte rootDer[FOURK_BUF];
    byte icaDer[FOURK_BUF];
    byte entityDer[FOURK_BUF];
    int rootDerSz = 0;
    int icaDerSz = 0;
    int entityDerSz = 0;
    WC_RNG rng;
    ecc_key rootKey;
    ecc_key icaKey;
    ecc_key entityKey;
    WOLFSSL_CERT_MANAGER* cm = NULL;

    XMEMSET(&rng, 0, sizeof(WC_RNG));
    XMEMSET(&rootKey, 0, sizeof(ecc_key));
    XMEMSET(&icaKey, 0, sizeof(ecc_key));
    XMEMSET(&entityKey, 0, sizeof(ecc_key));

    ExpectIntEQ(wc_InitRng(&rng), 0);
    ExpectIntEQ(wc_ecc_init(&rootKey), 0);
    ExpectIntEQ(wc_ecc_init(&icaKey), 0);
    ExpectIntEQ(wc_ecc_init(&entityKey), 0);
    ExpectIntEQ(wc_ecc_make_key(&rng, 32, &rootKey), 0);
    ExpectIntEQ(wc_ecc_make_key(&rng, 32, &icaKey), 0);
    ExpectIntEQ(wc_ecc_make_key(&rng, 32, &entityKey), 0);

    /* Step 1: Create root CA with pathLen=0 */
    ExpectIntEQ(wc_InitCert(&cert), 0);
    (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.state, "MT", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.locality, "Bozeman", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.org, "TestCA", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.unit, "Test", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.commonName, "TestRootCA", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.email, "root@test.com", CTC_NAME_SIZE);
    cert.selfSigned = 1;
    cert.isCA       = 1;
    cert.pathLen    = 0;
    cert.pathLenSet = 1;
    cert.sigType    = CTC_SHA256wECDSA;
    cert.keyUsage   = KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN;
    ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey),
        0);

    ExpectIntGE(wc_MakeCert(&cert, rootDer, FOURK_BUF, NULL, &rootKey, &rng),
        0);
    ExpectIntGE(rootDerSz = wc_SignCert(cert.bodySz, cert.sigType, rootDer,
        FOURK_BUF, NULL, &rootKey, &rng), 0);

    /* Step 2: Create self-issued intermediate (same subject DN as root,
     * different key, signed by root) - this should be blocked by pathLen=0 */
    ExpectIntEQ(wc_InitCert(&cert), 0);
    cert.selfSigned = 0;
    cert.isCA       = 1;
    cert.sigType    = CTC_SHA256wECDSA;
    cert.keyUsage   = KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN;
    /* Set both subject and issuer from the root cert so they match */
    ExpectIntEQ(wc_SetSubjectBuffer(&cert, rootDer, rootDerSz), 0);
    ExpectIntEQ(wc_SetIssuerBuffer(&cert, rootDer, rootDerSz), 0);
    ExpectIntEQ(wc_SetAuthKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey), 0);
    ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &icaKey),
        0);

    ExpectIntGE(wc_MakeCert(&cert, icaDer, FOURK_BUF, NULL, &icaKey, &rng), 0);
    ExpectIntGE(icaDerSz = wc_SignCert(cert.bodySz, cert.sigType, icaDer,
        FOURK_BUF, NULL, &rootKey, &rng), 0);

    /* Step 3: Create entity cert signed by the intermediate */
    ExpectIntEQ(wc_InitCert(&cert), 0);
    cert.selfSigned = 0;
    cert.isCA       = 0;
    cert.sigType    = CTC_SHA256wECDSA;
    (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.state, "MT", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.locality, "Bozeman", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.org, "TestEntity", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.commonName, "entity.test", CTC_NAME_SIZE);
    ExpectIntEQ(wc_SetIssuerBuffer(&cert, icaDer, icaDerSz), 0);
    ExpectIntEQ(wc_SetAuthKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &icaKey), 0);

    ExpectIntGE(wc_MakeCert(&cert, entityDer, FOURK_BUF, NULL, &entityKey,
        &rng), 0);
    ExpectIntGE(entityDerSz = wc_SignCert(cert.bodySz, cert.sigType, entityDer,
        FOURK_BUF, NULL, &icaKey, &rng), 0);

    /* Step 4: Load root CA into cert manager */
    ExpectNotNull(cm = wolfSSL_CertManagerNew());
    ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, rootDer, rootDerSz,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    /* Step 5: Parse the self-issued intermediate as a chain cert.
     * This simulates TLS chain verification where the intermediate is
     * received as part of the certificate chain.
     * Root CA has pathLen=0, so it should NOT be allowed to sign any
     * intermediate CA (including self-issued ones).
     * BUG: wolfSSL sets selfSigned=1 for this cert (issuer==subject DN),
     * which causes the pathLen enforcement to be entirely skipped. */
    wc_InitDecodedCert(&decodedCert, icaDer, (word32)icaDerSz, NULL);
    ExpectIntEQ(wc_ParseCert(&decodedCert, CHAIN_CERT_TYPE, VERIFY,
        cm), WC_NO_ERR_TRACE(ASN_PATHLEN_INV_E));
    wc_FreeDecodedCert(&decodedCert);

    /* Step 6: Parse the trust anchor itself as a chain cert.
     * A peer is allowed to include the root in the chain it sends.
     * Per RFC 5280 6.1 the trust anchor is not part of the prospective
     * certification path, so its own pathLen=0 must not fire against
     * itself. */
    wc_InitDecodedCert(&decodedCert, rootDer, (word32)rootDerSz, NULL);
    ExpectIntEQ(wc_ParseCert(&decodedCert, CHAIN_CERT_TYPE, VERIFY, cm), 0);
    wc_FreeDecodedCert(&decodedCert);

    wolfSSL_CertManagerFree(cm);
    wc_ecc_free(&entityKey);
    wc_ecc_free(&icaKey);
    wc_ecc_free(&rootKey);
    wc_FreeRng(&rng);
#endif
    return EXPECT_RESULT();
}

/* Verifies that a self-issued intermediate under a CA with pathLen > 0 is
 * accepted AND that maxPathLen is propagated as min(ca->maxPathLen,
 * cert->pathLength) without being decremented (RFC 5280 6.1.4(l)).
 * Pins the `else` branch in asn.c so deletion or an accidental decrement
 * (like the non-self-issued path) is detected. */
static int test_PathLenSelfIssuedAllowed(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_CERT_REQ) && !defined(NO_ASN_TIME) && \
    defined(WOLFSSL_CERT_GEN) && defined(HAVE_ECC) && \
    defined(WOLFSSL_CERT_EXT) && !defined(NO_CERTS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH))
    Cert cert;
    DecodedCert decodedCert;
    byte rootDer[FOURK_BUF];
    byte icaDer[FOURK_BUF];
    int rootDerSz = 0;
    int icaDerSz = 0;
    WC_RNG rng;
    ecc_key rootKey;
    ecc_key icaKey;
    WOLFSSL_CERT_MANAGER* cm = NULL;

    XMEMSET(&rng, 0, sizeof(WC_RNG));
    XMEMSET(&rootKey, 0, sizeof(ecc_key));
    XMEMSET(&icaKey, 0, sizeof(ecc_key));

    ExpectIntEQ(wc_InitRng(&rng), 0);
    ExpectIntEQ(wc_ecc_init(&rootKey), 0);
    ExpectIntEQ(wc_ecc_init(&icaKey), 0);
    ExpectIntEQ(wc_ecc_make_key(&rng, 32, &rootKey), 0);
    ExpectIntEQ(wc_ecc_make_key(&rng, 32, &icaKey), 0);

    /* Step 1: Create root CA with pathLen=1 */
    ExpectIntEQ(wc_InitCert(&cert), 0);
    (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.state, "MT", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.locality, "Bozeman", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.org, "TestCA3", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.unit, "Test", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.commonName, "TestRootCA3", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.email, "root@test3.com", CTC_NAME_SIZE);
    cert.selfSigned = 1;
    cert.isCA       = 1;
    cert.pathLen    = 1;
    cert.pathLenSet = 1;
    cert.sigType    = CTC_SHA256wECDSA;
    cert.keyUsage   = KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN;
    ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey),
        0);

    ExpectIntGE(wc_MakeCert(&cert, rootDer, FOURK_BUF, NULL, &rootKey, &rng),
        0);
    ExpectIntGE(rootDerSz = wc_SignCert(cert.bodySz, cert.sigType, rootDer,
        FOURK_BUF, NULL, &rootKey, &rng), 0);

    /* Step 2: Create a self-issued intermediate with its OWN pathLen=5.
     * The intentionally-larger pathLen lets the test distinguish:
     *   - Correct self-issued path: maxPathLen = min(1, 5) = 1
     *   - Deleted else branch:      maxPathLen stays at 5 (cert->pathLength)
     *   - Mutated to decrement:     maxPathLen = min(0, 5) = 0 */
    ExpectIntEQ(wc_InitCert(&cert), 0);
    cert.selfSigned = 0;
    cert.isCA       = 1;
    cert.pathLen    = 5;
    cert.pathLenSet = 1;
    cert.sigType    = CTC_SHA256wECDSA;
    cert.keyUsage   = KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN;
    /* Same subject/issuer DN as root -> self-issued */
    ExpectIntEQ(wc_SetSubjectBuffer(&cert, rootDer, rootDerSz), 0);
    ExpectIntEQ(wc_SetIssuerBuffer(&cert, rootDer, rootDerSz), 0);
    ExpectIntEQ(wc_SetAuthKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey), 0);
    ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &icaKey),
        0);

    ExpectIntGE(wc_MakeCert(&cert, icaDer, FOURK_BUF, NULL, &icaKey, &rng), 0);
    ExpectIntGE(icaDerSz = wc_SignCert(cert.bodySz, cert.sigType, icaDer,
        FOURK_BUF, NULL, &rootKey, &rng), 0);

    /* Step 3: Load root CA into cert manager */
    ExpectNotNull(cm = wolfSSL_CertManagerNew());
    ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, rootDer, rootDerSz,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    /* Step 4: Parse the self-issued intermediate. Must be accepted AND
     * maxPathLen must be exactly 1 (honors root's constraint without
     * decrementing). */
    wc_InitDecodedCert(&decodedCert, icaDer, (word32)icaDerSz, NULL);
    ExpectIntEQ(wc_ParseCert(&decodedCert, CHAIN_CERT_TYPE, VERIFY, cm), 0);
    ExpectIntEQ(decodedCert.maxPathLen, 1);
    wc_FreeDecodedCert(&decodedCert);

    wolfSSL_CertManagerFree(cm);
    wc_ecc_free(&icaKey);
    wc_ecc_free(&rootKey);
    wc_FreeRng(&rng);
#endif
    return EXPECT_RESULT();
}

static int test_PathLenNoKeyUsage(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_CERT_REQ) && !defined(NO_ASN_TIME) && \
    defined(WOLFSSL_CERT_GEN) && defined(HAVE_ECC) && \
    defined(WOLFSSL_CERT_EXT) && !defined(NO_CERTS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH))
    Cert cert;
    DecodedCert decodedCert;
    byte rootDer[FOURK_BUF];
    byte icaDer[FOURK_BUF];
    int rootDerSz = 0;
    int icaDerSz = 0;
    WC_RNG rng;
    ecc_key rootKey;
    ecc_key icaKey;
    WOLFSSL_CERT_MANAGER* cm = NULL;

    XMEMSET(&rng, 0, sizeof(WC_RNG));
    XMEMSET(&rootKey, 0, sizeof(ecc_key));
    XMEMSET(&icaKey, 0, sizeof(ecc_key));

    ExpectIntEQ(wc_InitRng(&rng), 0);
    ExpectIntEQ(wc_ecc_init(&rootKey), 0);
    ExpectIntEQ(wc_ecc_init(&icaKey), 0);
    ExpectIntEQ(wc_ecc_make_key(&rng, 32, &rootKey), 0);
    ExpectIntEQ(wc_ecc_make_key(&rng, 32, &icaKey), 0);

    /* Step 1: Create root CA with pathLen=0 and KeyUsage */
    ExpectIntEQ(wc_InitCert(&cert), 0);
    (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.state, "MT", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.locality, "Bozeman", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.org, "TestCA2", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.unit, "Test", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.commonName, "TestRootCA2", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.email, "root@test2.com", CTC_NAME_SIZE);
    cert.selfSigned = 1;
    cert.isCA       = 1;
    cert.pathLen    = 0;
    cert.pathLenSet = 1;
    cert.sigType    = CTC_SHA256wECDSA;
    cert.keyUsage   = KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN;
    ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey),
        0);

    ExpectIntGE(wc_MakeCert(&cert, rootDer, FOURK_BUF, NULL, &rootKey, &rng),
        0);
    ExpectIntGE(rootDerSz = wc_SignCert(cert.bodySz, cert.sigType, rootDer,
        FOURK_BUF, NULL, &rootKey, &rng), 0);

    /* Step 2: Create intermediate CA WITHOUT KeyUsage extension.
     * Per RFC 5280, when KeyUsage is absent all uses are valid.
     * The root's pathLen=0 should still block this intermediate CA.
     * BUG: pathLen check requires extKeyUsageSet which is false when
     * KeyUsage is absent, so the check is skipped entirely. */
    ExpectIntEQ(wc_InitCert(&cert), 0);
    cert.selfSigned = 0;
    cert.isCA       = 1;
    cert.sigType    = CTC_SHA256wECDSA;
    /* Intentionally do NOT set keyUsage - test that pathLen is still enforced */
    cert.keyUsage   = 0;
    (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.state, "MT", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.locality, "Bozeman", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.org, "TestICA", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.unit, "Test", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.commonName, "TestICA-NoKU", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.email, "ica@test2.com", CTC_NAME_SIZE);
    ExpectIntEQ(wc_SetIssuerBuffer(&cert, rootDer, rootDerSz), 0);
    ExpectIntEQ(wc_SetAuthKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey), 0);
    ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &icaKey),
        0);

    ExpectIntGE(wc_MakeCert(&cert, icaDer, FOURK_BUF, NULL, &icaKey, &rng), 0);
    ExpectIntGE(icaDerSz = wc_SignCert(cert.bodySz, cert.sigType, icaDer,
        FOURK_BUF, NULL, &rootKey, &rng), 0);

    /* Step 3: Load root CA into cert manager */
    ExpectNotNull(cm = wolfSSL_CertManagerNew());
    ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, rootDer, rootDerSz,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    /* Step 4: Parse the intermediate (no KeyUsage) as a chain cert.
     * Root CA has pathLen=0, this intermediate CA should be rejected.
     * The intermediate does NOT have the KeyUsage extension, but per
     * RFC 5280 4.2.1.3 all key uses are valid when the extension is
     * absent, so pathLen must still be enforced. */
    wc_InitDecodedCert(&decodedCert, icaDer, (word32)icaDerSz, NULL);
    ExpectIntEQ(wc_ParseCert(&decodedCert, CHAIN_CERT_TYPE, VERIFY,
        cm), WC_NO_ERR_TRACE(ASN_PATHLEN_INV_E));
    wc_FreeDecodedCert(&decodedCert);

    wolfSSL_CertManagerFree(cm);
    wc_ecc_free(&icaKey);
    wc_ecc_free(&rootKey);
    wc_FreeRng(&rng);
#endif
    return EXPECT_RESULT();
}

/* Exhaustive matrix coverage of the serial-0 predicate in
 * ParseCertRelative (asn.c). Inputs are openssl-generated PEM fixtures
 * under certs/test-serial0/ -- no cert-under-test data is generated by
 * wolfSSL, so the test cannot pass for the wrong reason if wc_MakeCert
 * encoding ever drifts.
 *
 * Predicate exempts only (CA_TYPE|TRUSTED_PEER_TYPE) && isCA && selfSigned.
 *
 *   Fixture                          isCA selfSigned CERT_TYPE CA_TYPE
 *   root_serial0.pem                 1    1          reject    accept
 *   intermediate_serial0.pem         1    0          reject    reject
 *   selfsigned_nonca_serial0.pem     0    1          reject    reject
 *   ee_serial0.pem                   0    0          reject    reject
 */
static int test_ParseSerial0FixtureMatrix(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_FILESYSTEM) && !defined(NO_RSA) && \
    defined(WOLFSSL_PEM_TO_DER) && !defined(WOLFSSL_NO_PEM) && \
    !defined(WOLFSSL_NO_ASN_STRICT) && !defined(WOLFSSL_PYTHON) && \
    !defined(WOLFSSL_ASN_ALLOW_0_SERIAL)
    /* Fixture certs are RSA-2048; NO_RSA builds can't parse them. Mirrors
     * the gate on the sibling test_SerialNumber0_RootCA. */
    /* Each case asserts a policy outcome (accept vs reject), not a specific
     * error code. wc_ParseCert can fail via several distinct codes
     * (ASN_PARSE_E, ASN_UNKNOWN_OID_E, etc.) depending on which
     * OID-recognition features are compiled into the build; matching any
     * specific code is brittle across configs. */
    struct {
        const char* path;
        int  certTypeShouldPass; /* 1: expect ret == 0; 0: expect ret != 0 */
        int  caTypeShouldPass;
    } cases[] = {
        /* Root CA serial 0 is rejected as CERT_TYPE, accepted as trust
         * anchor (CA_TYPE) per the exemption in ParseCertRelative. */
        { "./certs/test-serial0/root_serial0.pem",         0, 1 },
        /* Intermediate CA: CA:TRUE but issuer != subject, so the trust
         * anchor exemption (cert->selfSigned) does not apply. */
        { "./certs/test-serial0/intermediate_serial0.pem", 0, 0 },
        { "./certs/test-serial0/selfsigned_nonca_serial0.pem", 0, 0 },
        { "./certs/test-serial0/ee_serial0.pem",           0, 0 },
    };
    size_t i;

    for (i = 0; i < sizeof(cases) / sizeof(cases[0]); ++i) {
        byte*  pemBuf = NULL;
        size_t pemSz  = 0;
        byte*  derBuf = NULL;
        int    derSz  = 0;
        DecodedCert dc;
        int    ret;

        ExpectIntEQ(load_file(cases[i].path, &pemBuf, &pemSz), 0);
        ExpectNotNull(derBuf = (byte*)XMALLOC(pemSz, NULL,
            DYNAMIC_TYPE_TMP_BUFFER));
        ExpectIntGE(derSz = wc_CertPemToDer(pemBuf, (int)pemSz, derBuf,
            (int)pemSz, CERT_TYPE), 0);

        if (EXPECT_SUCCESS()) {
            wc_InitDecodedCert(&dc, derBuf, (word32)derSz, NULL);
            ret = wc_ParseCert(&dc, CERT_TYPE, NO_VERIFY, NULL);
            if (cases[i].certTypeShouldPass)
                ExpectIntEQ(ret, 0);
            else
                ExpectIntNE(ret, 0);
            wc_FreeDecodedCert(&dc);

            wc_InitDecodedCert(&dc, derBuf, (word32)derSz, NULL);
            ret = wc_ParseCert(&dc, CA_TYPE, NO_VERIFY, NULL);
            if (cases[i].caTypeShouldPass)
                ExpectIntEQ(ret, 0);
            else
                ExpectIntNE(ret, 0);
            wc_FreeDecodedCert(&dc);
        }

        XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        XFREE(pemBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    }
#endif
    return EXPECT_RESULT();
}

#if defined(WOLFSSL_ASN_TEMPLATE) && \
    defined(WOLFSSL_CERT_REQ) && !defined(NO_ASN_TIME) && \
    defined(WOLFSSL_CERT_GEN) && defined(HAVE_ECC) && \
    defined(WOLFSSL_CERT_EXT) && !defined(NO_CERTS) && \
    defined(WOLFSSL_ALT_NAMES) && defined(WOLFSSL_CUSTOM_OID) && \
    defined(HAVE_OID_ENCODING) && !defined(IGNORE_NAME_CONSTRAINTS)

/* Build a SubjectAltName extension value (a SEQUENCE wrapping a single
 * otherName GeneralName) for the Microsoft UPN OID 1.3.6.1.4.1.311.20.2.3
 * with the given 7-byte UTF8String value. */
static word32 build_otherName_san(byte* out, word32 outSz, const char* val7)
{
    static const byte prefix[] = {
        0x30, 0x19,                                     /* SEQUENCE, 25 */
        0xA0, 0x17,                                     /* [0] CONSTRUCTED, 23 */
        0x06, 0x0A,                                     /* OBJECT ID, 10 */
            0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37,
            0x14, 0x02, 0x03,                           /* UPN OID */
        0xA0, 0x09,                                     /* [0] EXPLICIT, 9 */
            0x0C, 0x07                                  /* UTF8String, 7 */
    };
    if (outSz < sizeof(prefix) + 7)
        return 0;
    XMEMCPY(out, prefix, sizeof(prefix));
    XMEMCPY(out + sizeof(prefix), val7, 7);
    return (word32)(sizeof(prefix) + 7);
}

/* Build a SubjectAltName extension value with a single registeredID
 * GeneralName for OID 1.2.3.4, to use as the leaf SAN in RID tests. */
static word32 build_registeredID_san(byte* out, word32 outSz)
{
    static const byte ridSan[] = {
        0x30, 0x05,                                     /* SEQUENCE, 5 */
        0x88, 0x03,                                     /* [8] regId, 3 */
            0x2A, 0x03, 0x04                            /* OID 1.2.3.4 */
    };
    if (outSz < sizeof(ridSan))
        return 0;
    XMEMCPY(out, ridSan, sizeof(ridSan));
    return (word32)sizeof(ridSan);
}

/* Build a NameConstraints extension value with a single excludedSubtree
 * carrying a registeredID GeneralName for OID 1.2.3.4. wolfSSL enforces
 * registeredID name constraints by byte-comparing OID bodies, so a leaf
 * whose registeredID SAN matches this exclusion must be rejected. */
static word32 build_registeredID_nameConstraints(byte* out, word32 outSz)
{
    static const byte ridNc[] = {
        0x30, 0x09,                                     /* SEQUENCE, 9 */
        0xA1, 0x07,                                     /* [1] excluded, 7 */
        0x30, 0x05,                                     /* GeneralSubtree, 5 */
        0x88, 0x03,                                     /* [8] regId, 3 */
            0x2A, 0x03, 0x04                            /* OID 1.2.3.4 */
    };
    if (outSz < sizeof(ridNc))
        return 0;
    XMEMCPY(out, ridNc, sizeof(ridNc));
    return (word32)sizeof(ridNc);
}

/* Build a NameConstraints extension value carrying a single subtree of
 * the given list type ([0] permitted or [1] excluded) for an otherName
 * UPN whose UTF8 value is the given 7-byte string. */
static word32 build_otherName_nameConstraints(byte* out, word32 outSz,
    int excluded, const char* val7)
{
    static const byte common[] = {
        0x30, 0x1D,                                     /* SEQUENCE, 29 */
        0x00, 0x1B,                                     /* listTag, 27 (patched) */
        0x30, 0x19,                                     /* GeneralSubtree, 25 */
        0xA0, 0x17,                                     /* [0] CONSTRUCTED, 23 */
        0x06, 0x0A,
            0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37,
            0x14, 0x02, 0x03,
        0xA0, 0x09,
            0x0C, 0x07
    };
    if (outSz < sizeof(common) + 7)
        return 0;
    XMEMCPY(out, common, sizeof(common));
    out[2] = excluded ? 0xA1 : 0xA0;                    /* listTag */
    XMEMCPY(out + sizeof(common), val7, 7);
    return (word32)(sizeof(common) + 7);
}

/* Build a chain (root -> intermediate -> leaf) where the intermediate
 * carries `nameConstraintsDer` as a (possibly critical) nameConstraints
 * extension and the leaf carries `sanDer` as its SAN. Loads root and
 * intermediate as trusted CAs into a fresh CertManager, parses the leaf
 * with VERIFY, and returns the result code from wc_ParseCert(). */
static int verify_with_otherName_chain(const byte* nameConstraintsDer,
    word32 nameConstraintsDerSz, int critical,
    const byte* sanDer, word32 sanDerSz)
{
    Cert cert;
    DecodedCert decodedCert;
    byte rootDer[FOURK_BUF];
    byte icaDer[FOURK_BUF];
    byte leafDer[FOURK_BUF];
    int  rootDerSz = 0, icaDerSz = 0, leafDerSz = 0;
    int  parseRet = -1;
    WC_RNG rng;
    ecc_key rootKey, icaKey, leafKey;
    WOLFSSL_CERT_MANAGER* cm = NULL;

    XMEMSET(&rng,     0, sizeof(rng));
    XMEMSET(&rootKey, 0, sizeof(rootKey));
    XMEMSET(&icaKey,  0, sizeof(icaKey));
    XMEMSET(&leafKey, 0, sizeof(leafKey));

    if (wc_InitRng(&rng) != 0) goto done;
    if (wc_ecc_init(&rootKey) != 0) goto done;
    if (wc_ecc_init(&icaKey)  != 0) goto done;
    if (wc_ecc_init(&leafKey) != 0) goto done;
    if (wc_ecc_make_key(&rng, 32, &rootKey) != 0) goto done;
    if (wc_ecc_make_key(&rng, 32, &icaKey)  != 0) goto done;
    if (wc_ecc_make_key(&rng, 32, &leafKey) != 0) goto done;

    /* Self-signed root. */
    if (wc_InitCert(&cert) != 0) goto done;
    (void)XSTRNCPY(cert.subject.country,    "US",          CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.org,        "OtherNCRoot", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.commonName, "OtherNCRoot", CTC_NAME_SIZE);
    cert.selfSigned = 1;
    cert.isCA       = 1;
    cert.sigType    = CTC_SHA256wECDSA;
    cert.keyUsage   = KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN;
    if (wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey) != 0)
        goto done;
    if (wc_MakeCert(&cert, rootDer, FOURK_BUF, NULL, &rootKey, &rng) < 0)
        goto done;
    rootDerSz = wc_SignCert(cert.bodySz, cert.sigType, rootDer, FOURK_BUF,
        NULL, &rootKey, &rng);
    if (rootDerSz < 0) goto done;

    /* Intermediate, signed by root, carrying nameConstraints. */
    if (wc_InitCert(&cert) != 0) goto done;
    cert.selfSigned = 0;
    cert.isCA       = 1;
    cert.sigType    = CTC_SHA256wECDSA;
    cert.keyUsage   = KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN;
    (void)XSTRNCPY(cert.subject.country,    "US",         CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.org,        "OtherNCICA", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.commonName, "OtherNCICA", CTC_NAME_SIZE);
    if (wc_SetIssuerBuffer(&cert, rootDer, rootDerSz) != 0) goto done;
    if (wc_SetAuthKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey) != 0)
        goto done;
    if (wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &icaKey) != 0)
        goto done;
    if (nameConstraintsDer != NULL) {
        /* nameConstraints OID = 2.5.29.30 */
        if (wc_SetCustomExtension(&cert, critical ? 1 : 0, "2.5.29.30",
                nameConstraintsDer, nameConstraintsDerSz) != 0)
            goto done;
    }
    if (wc_MakeCert(&cert, icaDer, FOURK_BUF, NULL, &icaKey, &rng) < 0)
        goto done;
    icaDerSz = wc_SignCert(cert.bodySz, cert.sigType, icaDer, FOURK_BUF,
        NULL, &rootKey, &rng);
    if (icaDerSz < 0) goto done;

    /* Leaf, signed by intermediate, carrying the otherName SAN. */
    if (wc_InitCert(&cert) != 0) goto done;
    cert.selfSigned = 0;
    cert.isCA       = 0;
    cert.sigType    = CTC_SHA256wECDSA;
    (void)XSTRNCPY(cert.subject.country,    "US",          CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.org,        "OtherNCLeaf", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.commonName, "OtherNCLeaf", CTC_NAME_SIZE);
    if (wc_SetIssuerBuffer(&cert, icaDer, icaDerSz) != 0) goto done;
    if (wc_SetAuthKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &icaKey) != 0)
        goto done;
    if (wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &leafKey) != 0)
        goto done;
    if (sanDer != NULL && sanDerSz > 0) {
        if (sanDerSz > sizeof(cert.altNames)) goto done;
        XMEMCPY(cert.altNames, sanDer, sanDerSz);
        cert.altNamesSz = (int)sanDerSz;
    }
    if (wc_MakeCert(&cert, leafDer, FOURK_BUF, NULL, &leafKey, &rng) < 0)
        goto done;
    leafDerSz = wc_SignCert(cert.bodySz, cert.sigType, leafDer, FOURK_BUF,
        NULL, &icaKey, &rng);
    if (leafDerSz < 0) goto done;

    cm = wolfSSL_CertManagerNew();
    if (cm == NULL) goto done;
    if (wolfSSL_CertManagerLoadCABuffer(cm, rootDer, rootDerSz,
            WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS) goto done;
    if (wolfSSL_CertManagerLoadCABuffer(cm, icaDer, icaDerSz,
            WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS) goto done;

    wc_InitDecodedCert(&decodedCert, leafDer, (word32)leafDerSz, NULL);
    parseRet = wc_ParseCert(&decodedCert, CERT_TYPE, VERIFY, cm);
    wc_FreeDecodedCert(&decodedCert);

done:
    if (cm != NULL) wolfSSL_CertManagerFree(cm);
    wc_ecc_free(&leafKey);
    wc_ecc_free(&icaKey);
    wc_ecc_free(&rootKey);
    wc_FreeRng(&rng);
    return parseRet;
}
#endif

/* Verifies wolfSSL enforces an issuing CA's nameConstraints extension on a
 * leaf certificate's otherName SAN (RFC 5280 4.2.1.10). The vulnerability
 * was that ConfirmNameConstraints() ignored ASN_OTHER_TYPE entirely, so a
 * malicious intermediate could issue leaves whose otherName SAN violated
 * its own subtree.
 *
 * Coverage:
 *   1. Critical excluded subtree, leaf SAN matches            -> reject
 *   2. Critical excluded subtree, leaf SAN does NOT match     -> accept
 *      (positive control: distinguishes 'right rule fired' from
 *       'broke everything with otherName')
 *   3. Non-critical excluded subtree, leaf SAN matches        -> reject
 *      (excluded is enforced regardless of criticality)
 *   4. Critical permitted subtree, leaf SAN matches           -> accept
 *   5. Critical permitted subtree, leaf SAN does NOT match    -> reject
 *   6. Critical excluded registeredID subtree, leaf SAN matches -> reject
 *      (registeredID is enforced by byte-comparison of OID bodies)
 *   7. Non-critical excluded registeredID subtree, leaf SAN matches -> reject
 *      (excluded subtrees are enforced regardless of criticality)
 *   8. Critical excluded registeredID subtree, leaf has no RID SAN -> accept
 *      (no match in excluded list, constraint is satisfied)
 */
static int test_NameConstraints_OtherName(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_ASN_TEMPLATE) && \
    defined(WOLFSSL_CERT_REQ) && !defined(NO_ASN_TIME) && \
    defined(WOLFSSL_CERT_GEN) && defined(HAVE_ECC) && \
    defined(WOLFSSL_CERT_EXT) && !defined(NO_CERTS) && \
    defined(WOLFSSL_ALT_NAMES) && defined(WOLFSSL_CUSTOM_OID) && \
    defined(HAVE_OID_ENCODING) && !defined(IGNORE_NAME_CONSTRAINTS)
    byte sanBlocked[64];
    byte sanAllowed[64];
    byte sanRegisteredID[16];
    byte ncExcludedBlocked[64];
    byte ncPermittedAllowed[64];
    byte ncRegisteredID[16];
    word32 sanBlockedSz, sanAllowedSz, sanRegisteredIDSz;
    word32 ncExcludedBlockedSz, ncPermittedAllowedSz, ncRegisteredIDSz;

    sanBlockedSz =
        build_otherName_san(sanBlocked, sizeof(sanBlocked), "blocked");
    sanAllowedSz =
        build_otherName_san(sanAllowed, sizeof(sanAllowed), "allowed");
    sanRegisteredIDSz =
        build_registeredID_san(sanRegisteredID, sizeof(sanRegisteredID));
    ncExcludedBlockedSz = build_otherName_nameConstraints(
        ncExcludedBlocked, sizeof(ncExcludedBlocked), 1, "blocked");
    ncPermittedAllowedSz = build_otherName_nameConstraints(
        ncPermittedAllowed, sizeof(ncPermittedAllowed), 0, "allowed");
    ncRegisteredIDSz = build_registeredID_nameConstraints(
        ncRegisteredID, sizeof(ncRegisteredID));
    ExpectIntGT((int)sanBlockedSz, 0);
    ExpectIntGT((int)sanAllowedSz, 0);
    ExpectIntGT((int)sanRegisteredIDSz, 0);
    ExpectIntGT((int)ncExcludedBlockedSz, 0);
    ExpectIntGT((int)ncPermittedAllowedSz, 0);
    ExpectIntGT((int)ncRegisteredIDSz, 0);

    /* (1) Original bypass scenario: critical excluded otherName matches
     *     the leaf's otherName SAN. Must be rejected. */
    ExpectIntEQ(verify_with_otherName_chain(
            ncExcludedBlocked, ncExcludedBlockedSz, 1,
            sanBlocked, sanBlockedSz),
        WC_NO_ERR_TRACE(ASN_NAME_INVALID_E));

    /* (2) Positive control: same critical excluded subtree, but the leaf
     *     carries a DIFFERENT otherName value, so byte-comparison says no
     *     match and the chain MUST verify. This pins the rejection in (1)
     *     to the matching path rather than to a blanket 'reject any
     *     otherName under critical'. */
    ExpectIntEQ(verify_with_otherName_chain(
            ncExcludedBlocked, ncExcludedBlockedSz, 1,
            sanAllowed, sanAllowedSz),
        0);

    /* (3) Non-critical excluded subtree, leaf SAN matches: exclusion is
     *     enforced regardless of criticality. */
    ExpectIntEQ(verify_with_otherName_chain(
            ncExcludedBlocked, ncExcludedBlockedSz, 0,
            sanBlocked, sanBlockedSz),
        WC_NO_ERR_TRACE(ASN_NAME_INVALID_E));

    /* (4) Critical permitted subtree, leaf SAN inside the permitted set:
     *     verification succeeds. */
    ExpectIntEQ(verify_with_otherName_chain(
            ncPermittedAllowed, ncPermittedAllowedSz, 1,
            sanAllowed, sanAllowedSz),
        0);

    /* (5) Critical permitted subtree, leaf SAN outside the permitted set:
     *     verification rejects. */
    ExpectIntEQ(verify_with_otherName_chain(
            ncPermittedAllowed, ncPermittedAllowedSz, 1,
            sanBlocked, sanBlockedSz),
        WC_NO_ERR_TRACE(ASN_NAME_INVALID_E));

    /* (6) Critical excluded registeredID subtree, leaf SAN matches:
     *     registeredID is now enforced by byte-comparing OID bodies, so a
     *     matching excluded entry must be rejected. */
    ExpectIntEQ(verify_with_otherName_chain(
            ncRegisteredID, ncRegisteredIDSz, 1,
            sanRegisteredID, sanRegisteredIDSz),
        WC_NO_ERR_TRACE(ASN_NAME_INVALID_E));

    /* (7) Non-critical excluded registeredID subtree, leaf SAN matches:
     *     excluded subtrees are enforced regardless of criticality. */
    ExpectIntEQ(verify_with_otherName_chain(
            ncRegisteredID, ncRegisteredIDSz, 0,
            sanRegisteredID, sanRegisteredIDSz),
        WC_NO_ERR_TRACE(ASN_NAME_INVALID_E));

    /* (8) Critical excluded registeredID subtree, leaf has no RID SAN:
     *     no excluded match, so verification succeeds. */
    ExpectIntEQ(verify_with_otherName_chain(
            ncRegisteredID, ncRegisteredIDSz, 1, NULL, 0),
        0);
#endif
    return EXPECT_RESULT();
}

static int test_MakeCertWithCaFalse(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_ALLOW_ENCODING_CA_FALSE) && defined(WOLFSSL_CERT_REQ) && \
    !defined(NO_ASN_TIME) && defined(WOLFSSL_CERT_GEN) && defined(HAVE_ECC)
    const byte expectedIsCa = 0;
    Cert cert;
    DecodedCert decodedCert;
    byte der[FOURK_BUF];
    int derSize = 0;
    WC_RNG rng;
    ecc_key key;
    int ret;

    XMEMSET(&rng, 0, sizeof(WC_RNG));
    XMEMSET(&key, 0, sizeof(ecc_key));
    XMEMSET(&cert, 0, sizeof(Cert));
    XMEMSET(&decodedCert, 0, sizeof(DecodedCert));

    ExpectIntEQ(wc_InitRng(&rng), 0);
    ExpectIntEQ(wc_ecc_init(&key), 0);
    ExpectIntEQ(wc_ecc_make_key(&rng, 32, &key), 0);
    ExpectIntEQ(wc_InitCert(&cert), 0);

    (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.state, "state", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.locality, "Bozeman", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.org, "yourOrgNameHere", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.unit, "yourUnitNameHere", CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.commonName, "www.yourDomain.com",
        CTC_NAME_SIZE);
    (void)XSTRNCPY(cert.subject.email, "yourEmail@yourDomain.com",
        CTC_NAME_SIZE);

    cert.selfSigned = 1;
    cert.isCA       = expectedIsCa;
    cert.isCaSet    = 1;
    cert.sigType    = CTC_SHA256wECDSA;

    ExpectIntGE(wc_MakeCert(&cert, der, FOURK_BUF, NULL, &key, &rng), 0);
    ExpectIntGE(derSize = wc_SignCert(cert.bodySz, cert.sigType, der,
        FOURK_BUF, NULL, &key, &rng), 0);

    wc_InitDecodedCert(&decodedCert, der, derSize, NULL);
    ExpectIntEQ(wc_ParseCert(&decodedCert, CERT_TYPE, NO_VERIFY, NULL), 0);
    ExpectIntEQ(decodedCert.isCA, expectedIsCa);

    wc_FreeDecodedCert(&decodedCert);
    ret = wc_ecc_free(&key);
    ExpectIntEQ(ret, 0);
    ret = wc_FreeRng(&rng);
    ExpectIntEQ(ret, 0);
#endif
    return EXPECT_RESULT();
}

/* Mock callback for testing wc_SignCert_cb */
#if defined(WOLFSSL_CERT_SIGN_CB) && (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_REQ))
/* Context structure for mock signing callback */
typedef struct {
    void* key;      /* Pointer to RSA or ECC key */
    WC_RNG* rng;    /* Random number generator (required for ECC) */
} MockSignCtx;

static int mockSignCb(const byte* in, word32 inLen, byte* out, word32* outLen,
                      int sigAlgo, int keyType, void* ctx)
{
    int ret = 0;
    MockSignCtx* signCtx = (MockSignCtx*)ctx;

    if (signCtx == NULL || signCtx->key == NULL || in == NULL ||
        out == NULL || outLen == NULL) {
        return BAD_FUNC_ARG;
    }

    (void)sigAlgo;

#ifndef NO_RSA
    if (keyType == RSA_TYPE) {
        RsaKey* rsaKey = (RsaKey*)signCtx->key;
        word32 outSz = *outLen;

        /* For RSA, input is DER-encoded digest (DigestInfo structure) */
        ret = wc_RsaSSL_Sign(in, inLen, out, outSz, rsaKey, signCtx->rng);
        if (ret > 0) {
            *outLen = (word32)ret;
            ret = 0;
        }
    }
    else
#endif
#ifdef HAVE_ECC
    if (keyType == ECC_TYPE) {
        ecc_key* eccKey = (ecc_key*)signCtx->key;
        word32 outSz = *outLen;

        /* For ECC, input is raw hash, sign it (RNG required for ECDSA k value) */
        ret = wc_ecc_sign_hash(in, inLen, out, &outSz, signCtx->rng, eccKey);
        if (ret == 0) {
            *outLen = outSz;
        }
    }
    else
#endif
    {
        ret = BAD_FUNC_ARG;
    }

    return ret;
}

/* Mock callback that always returns an error for testing */
static int mockSignCbError(const byte* in, word32 inLen, byte* out,
                           word32* outLen, int sigAlgo, int keyType, void* ctx)
{
    (void)in;
    (void)inLen;
    (void)out;
    (void)outLen;
    (void)sigAlgo;
    (void)keyType;
    (void)ctx;
    return BAD_STATE_E; /* Return an error */
}
#endif

#ifdef WOLFSSL_CERT_SIGN_CB
static int test_wc_SignCert_cb(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_CERT_GEN) && !defined(NO_ASN_TIME)

#ifdef HAVE_ECC
    /* Test with ECC key */
    {
        Cert cert;
        byte der[FOURK_BUF];
        int derSize = 0;
        WC_RNG rng;
        ecc_key key;
        MockSignCtx signCtx;
        DecodedCert decodedCert;
        int ret;

        XMEMSET(&rng, 0, sizeof(WC_RNG));
        XMEMSET(&key, 0, sizeof(ecc_key));
        XMEMSET(&cert, 0, sizeof(Cert));
        XMEMSET(&signCtx, 0, sizeof(MockSignCtx));
        XMEMSET(&decodedCert, 0, sizeof(DecodedCert));

        ExpectIntEQ(wc_InitRng(&rng), 0);
        ExpectIntEQ(wc_ecc_init(&key), 0);
        ExpectIntEQ(wc_ecc_make_key(&rng, 32, &key), 0);
        ExpectIntEQ(wc_InitCert(&cert), 0);

        (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE);
        (void)XSTRNCPY(cert.subject.state, "state", CTC_NAME_SIZE);
        (void)XSTRNCPY(cert.subject.locality, "locality", CTC_NAME_SIZE);
        (void)XSTRNCPY(cert.subject.org, "org", CTC_NAME_SIZE);
        (void)XSTRNCPY(cert.subject.unit, "unit", CTC_NAME_SIZE);
        (void)XSTRNCPY(cert.subject.commonName, "www.example.com",
            CTC_NAME_SIZE);
        (void)XSTRNCPY(cert.subject.email, "test@example.com", CTC_NAME_SIZE);

        cert.selfSigned = 1;
        cert.isCA       = 0;
        cert.sigType    = CTC_SHA256wECDSA;

        /* Make cert body */
        ExpectIntGT(wc_MakeCert(&cert, der, FOURK_BUF, NULL, &key, &rng), 0);

        /* Setup signing context with key and RNG */
        signCtx.key = &key;
        signCtx.rng = &rng;

        /* Sign using callback API */
        ExpectIntGT(derSize = wc_SignCert_cb(cert.bodySz, cert.sigType, der,
            FOURK_BUF, ECC_TYPE, mockSignCb, &signCtx, &rng), 0);

        /* Verify the certificate was created properly */
        ExpectIntGT(derSize, 0);

        /* Parse the certificate and verify it's well-formed */
        if (EXPECT_SUCCESS()) {
            wc_InitDecodedCert(&decodedCert, der, (word32)derSize, NULL);
            ExpectIntEQ(wc_ParseCert(&decodedCert, CERT_TYPE, NO_VERIFY, NULL),
                0);
            /* Verify signature algorithm matches what we set */
            ExpectIntEQ(decodedCert.signatureOID, CTC_SHA256wECDSA);
            wc_FreeDecodedCert(&decodedCert);
        }

        /* Test error cases */
        /* NULL callback */
        ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
            FOURK_BUF, ECC_TYPE, NULL, &signCtx, &rng), BAD_FUNC_ARG);
        /* NULL buffer */
        ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, NULL,
            FOURK_BUF, ECC_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
        /* Zero buffer size */
        ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
            0, ECC_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
        /* Negative requestSz - should return the negative value */
        ExpectIntLT(wc_SignCert_cb(-1, cert.sigType, der,
            FOURK_BUF, ECC_TYPE, mockSignCb, &signCtx, &rng), 0);
        /* Callback returning error */
        ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
            FOURK_BUF, ECC_TYPE, mockSignCbError, &signCtx, &rng), BAD_STATE_E);
    #ifndef NO_RSA
        /* Invalid keyType for ECC signature */
        ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
            FOURK_BUF, ED25519_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
    #endif

        ret = wc_ecc_free(&key);
        ExpectIntEQ(ret, 0);
        ret = wc_FreeRng(&rng);
        ExpectIntEQ(ret, 0);
    }
#endif /* HAVE_ECC */

#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)
    /* Test with RSA key */
    {
        Cert cert;
        byte der[FOURK_BUF];
        int derSize = 0;
        WC_RNG rng;
        RsaKey key;
        MockSignCtx signCtx;
        DecodedCert decodedCert;
        int ret;

        XMEMSET(&rng, 0, sizeof(WC_RNG));
        XMEMSET(&key, 0, sizeof(RsaKey));
        XMEMSET(&cert, 0, sizeof(Cert));
        XMEMSET(&signCtx, 0, sizeof(MockSignCtx));
        XMEMSET(&decodedCert, 0, sizeof(DecodedCert));

        ExpectIntEQ(wc_InitRng(&rng), 0);
        ExpectIntEQ(wc_InitRsaKey(&key, NULL), 0);
        ExpectIntEQ(wc_MakeRsaKey(&key, 2048, WC_RSA_EXPONENT, &rng), 0);
        ExpectIntEQ(wc_InitCert(&cert), 0);

        (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE);
        (void)XSTRNCPY(cert.subject.state, "state", CTC_NAME_SIZE);
        (void)XSTRNCPY(cert.subject.locality, "locality", CTC_NAME_SIZE);
        (void)XSTRNCPY(cert.subject.org, "org", CTC_NAME_SIZE);
        (void)XSTRNCPY(cert.subject.unit, "unit", CTC_NAME_SIZE);
        (void)XSTRNCPY(cert.subject.commonName, "www.example.com",
            CTC_NAME_SIZE);
        (void)XSTRNCPY(cert.subject.email, "test@example.com", CTC_NAME_SIZE);

        cert.selfSigned = 1;
        cert.isCA       = 0;
        cert.sigType    = CTC_SHA256wRSA;

        /* Make cert body */
        ExpectIntGT(wc_MakeCert(&cert, der, FOURK_BUF, &key, NULL, &rng), 0);

        /* Setup signing context with key and RNG */
        signCtx.key = &key;
        signCtx.rng = &rng;

        /* Sign using callback API with RSA */
        ExpectIntGT(derSize = wc_SignCert_cb(cert.bodySz, cert.sigType, der,
            FOURK_BUF, RSA_TYPE, mockSignCb, &signCtx, &rng), 0);

        /* Verify the certificate was created properly */
        ExpectIntGT(derSize, 0);

        /* Parse the certificate and verify it's well-formed */
        if (EXPECT_SUCCESS()) {
            wc_InitDecodedCert(&decodedCert, der, (word32)derSize, NULL);
            ExpectIntEQ(wc_ParseCert(&decodedCert, CERT_TYPE, NO_VERIFY, NULL),
                0);
            /* Verify signature algorithm matches what we set */
            ExpectIntEQ(decodedCert.signatureOID, CTC_SHA256wRSA);
            wc_FreeDecodedCert(&decodedCert);
        }

        /* Test error cases */
        /* NULL callback */
        ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
            FOURK_BUF, RSA_TYPE, NULL, &signCtx, &rng), BAD_FUNC_ARG);
        /* NULL buffer */
        ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, NULL,
            FOURK_BUF, RSA_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
        /* Zero buffer size */
        ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
            0, RSA_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
        /* Callback returning error */
        ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
            FOURK_BUF, RSA_TYPE, mockSignCbError, &signCtx, &rng), BAD_STATE_E);
    #ifdef HAVE_ECC
        /* Invalid keyType */
        ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
            FOURK_BUF, ED448_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
    #endif

        ret = wc_FreeRsaKey(&key);
        ExpectIntEQ(ret, 0);
        ret = wc_FreeRng(&rng);
        ExpectIntEQ(ret, 0);
    }
#endif /* !NO_RSA && WOLFSSL_KEY_GEN */

#endif /* WOLFSSL_CERT_GEN && !NO_ASN_TIME */
    return EXPECT_RESULT();
}
#endif /* WOLFSSL_CERT_SIGN_CB */

static int test_ERR_load_crypto_strings(void)
{
#if defined(OPENSSL_ALL)
    ERR_load_crypto_strings();
    return TEST_SUCCESS;
#else
    return TEST_SKIPPED;
#endif
}

#if defined(OPENSSL_ALL) && !defined(NO_CERTS)
static WOLFSSL_X509 x1;
static WOLFSSL_X509 x2;
static void free_x509(X509* x)
{
    AssertIntEQ((x == &x1 || x == &x2), 1);
}
#endif

static int test_sk_X509(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_CERTS)
    {
        STACK_OF(X509)* s = NULL;

        ExpectNotNull(s = wolfSSL_sk_X509_new(NULL));
        ExpectIntEQ(sk_X509_num(s), 0);
        sk_X509_pop_free(s, NULL);
        s = NULL;

        ExpectNotNull(s = sk_X509_new_null());
        ExpectIntEQ(sk_X509_num(s), 0);
        sk_X509_pop_free(s, NULL);
        s = NULL;

        ExpectNotNull(s = sk_X509_new_null());

        /* Test invalid parameters. */
        ExpectIntEQ(sk_X509_push(NULL, NULL), WOLFSSL_FAILURE);
        ExpectIntEQ(sk_X509_push(s, NULL), WOLFSSL_FAILURE);
        ExpectIntEQ(sk_X509_push(NULL, (X509*)1), WOLFSSL_FAILURE);
        ExpectNull(sk_X509_pop(NULL));
        ExpectNull(sk_X509_value(NULL, 0));
        ExpectNull(sk_X509_value(NULL, 1));

        sk_X509_push(s, &x1);
        ExpectIntEQ(sk_X509_num(s), 1);
        ExpectIntEQ((sk_X509_value(s, 0) == &x1), 1);
        sk_X509_push(s, &x2);
        ExpectIntEQ(sk_X509_num(s), 2);
        ExpectNull(sk_X509_value(s, 2));
        ExpectIntEQ((sk_X509_value(s, 0) == &x1), 1);
        ExpectIntEQ((sk_X509_value(s, 1) == &x2), 1);
        sk_X509_push(s, &x2);

        sk_X509_pop_free(s, free_x509);
    }

    {
        /* Push a list of 10 X509s onto stack, then verify that
         * value(), push(), shift(), and pop() behave as expected. */
        STACK_OF(X509)* s = NULL;
        X509*     xList[10];
        int       i = 0;
        const int len = (sizeof(xList) / sizeof(xList[0]));

        for (i = 0; i < len; ++i) {
            xList[i] = NULL;
            ExpectNotNull(xList[i] = X509_new());
        }

        /* test push, pop, and free */
        ExpectNotNull(s = sk_X509_new_null());

        for (i = 0; i < len; ++i) {
            sk_X509_push(s, xList[i]);
            ExpectIntEQ(sk_X509_num(s), i + 1);
            ExpectIntEQ((sk_X509_value(s, 0) == xList[0]), 1);
            ExpectIntEQ((sk_X509_value(s, i) == xList[i]), 1);
        }

        /* pop returns and removes last pushed on stack, which is the last index
         * in sk_x509_value */
        for (i = len-1; i >= 0; --i) {
            X509 * x = sk_X509_value(s, i);
            X509 * y = sk_X509_pop(s);
            X509 * z = xList[i];

            ExpectPtrEq(x, y);
            ExpectPtrEq(x, z);
            ExpectIntEQ(sk_X509_num(s), i);
        }

        sk_free(s);
        s = NULL;

        /* test push, shift, and free */
        ExpectNotNull(s = sk_X509_new_null());

        for (i = 0; i < len; ++i) {
            sk_X509_push(s, xList[i]);
            ExpectIntEQ(sk_X509_num(s), i + 1);
            ExpectIntEQ((sk_X509_value(s, 0) == xList[0]), 1);
            ExpectIntEQ((sk_X509_value(s, i) == xList[i]), 1);
        }

        /* shift returns and removes first pushed on stack, which is index i
         * in sk_x509_value() */
        for (i = 0; i < len; ++i) {
            X509 * x = sk_X509_value(s, 0);
            X509 * y = sk_X509_shift(s);
            X509 * z = xList[i];

            ExpectIntEQ((x == y), 1);
            ExpectIntEQ((x == z), 1);
            ExpectIntEQ(sk_X509_num(s), len - 1 - i);
        }
        ExpectNull(sk_X509_shift(NULL));
        ExpectNull(sk_X509_shift(s));

        sk_free(s);

        for (i = 0; i < len; ++i)
            X509_free(xList[i]);
    }
#endif
    return EXPECT_RESULT();
}

static int test_sk_X509_CRL_decode(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
    defined(HAVE_CRL) && !defined(NO_RSA)
    X509_CRL* crl = NULL;
    XFILE fp = XBADFILE;
    STACK_OF(X509_CRL)* s = NULL;
#ifndef NO_BIO
    BIO* bio = NULL;
#endif
#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)
    RevokedCert* rev = NULL;
    byte buff[1024];
    int len = 0;
#endif
#if (!defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)) || \
    !defined(NO_BIO)
    X509_CRL empty;
#endif
    WOLFSSL_X509_REVOKED revoked;
    WOLFSSL_ASN1_INTEGER* asnInt = NULL;
    const WOLFSSL_ASN1_INTEGER* sn = NULL;

    XMEMSET(&revoked, 0, sizeof(revoked));
    revoked.reason = CRL_REASON_NONE;

#if (!defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)) || \
    !defined(NO_BIO)
    XMEMSET(&empty, 0, sizeof(X509_CRL));
#endif

#ifndef NO_BIO
    ExpectNotNull(bio = BIO_new_file("./certs/crl/crl.der", "rb"));
    ExpectNull(wolfSSL_d2i_X509_CRL_bio(NULL, NULL));
    ExpectNotNull(crl = wolfSSL_d2i_X509_CRL_bio(bio, NULL));
    BIO_free(bio);
    bio = NULL;

    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntEQ(wolfSSL_X509_CRL_print(NULL, NULL), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_CRL_print(bio, NULL), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_CRL_print(NULL, crl), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_CRL_print(bio, &empty), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_CRL_print(bio, crl), WOLFSSL_SUCCESS);
#ifndef NO_ASN_TIME
    ExpectIntEQ(BIO_get_mem_data(bio, NULL), 1466);
#else
    ExpectIntEQ(BIO_get_mem_data(bio, NULL), 1324);
#endif
    BIO_free(bio);
    bio = NULL;
    wolfSSL_X509_CRL_free(crl);
    crl = NULL;

#ifndef NO_ASN_TIME
    /* Test CRL with invalid GeneralizedTime */
    ExpectNotNull(bio = BIO_new_file("./certs/crl/bad_time_fmt.pem", "rb"));
    ExpectNotNull(crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL));
    BIO_free(bio);
    bio = NULL;
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntEQ(wolfSSL_X509_CRL_print(bio, crl), WOLFSSL_FAILURE);

    BIO_free(bio);
    bio = NULL;
    wolfSSL_X509_CRL_free(crl);
    crl = NULL;
#endif /* !NO_ASN_TIME */
#endif /* !NO_BIO */

#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)
    ExpectTrue((fp = XFOPEN("./certs/crl/crl.der", "rb")) != XBADFILE);
    ExpectNotNull(crl = d2i_X509_CRL_fp(fp, (X509_CRL **)NULL));
    if (fp != XBADFILE) {
        XFCLOSE(fp);
        fp = XBADFILE;
    }
    wolfSSL_X509_CRL_free(crl);
    crl = NULL;

    ExpectTrue((fp = XFOPEN("./certs/crl/crl.der", "rb")) != XBADFILE);
    ExpectIntEQ(len = (int)XFREAD(buff, 1, sizeof(buff), fp), 520);
    if (fp != XBADFILE) {
        XFCLOSE(fp);
        fp = XBADFILE;
    }
    ExpectNull(crl = d2i_X509_CRL((X509_CRL **)NULL, NULL, len));
    ExpectNotNull(crl = d2i_X509_CRL((X509_CRL **)NULL, buff, len));
    ExpectNotNull(rev = crl->crlList->certs);

    ExpectNull(wolfSSL_X509_CRL_get_issuer_name(NULL));
    ExpectNull(wolfSSL_X509_CRL_get_issuer_name(&empty));
    ExpectIntEQ(wolfSSL_X509_CRL_version(NULL), 0);
    ExpectIntEQ(wolfSSL_X509_CRL_version(&empty), 0);
    ExpectIntEQ(wolfSSL_X509_CRL_get_signature_type(NULL), 0);
    ExpectIntEQ(wolfSSL_X509_CRL_get_signature_type(&empty), 0);
    ExpectIntEQ(wolfSSL_X509_CRL_get_signature_nid(NULL), 0);
    ExpectIntEQ(wolfSSL_X509_CRL_get_signature_nid(&empty), 0);
    {
        int sigSz = 0;
        ExpectIntEQ(wolfSSL_X509_CRL_get_signature(NULL, NULL, NULL),
            BAD_FUNC_ARG);
        ExpectIntEQ(wolfSSL_X509_CRL_get_signature(crl, NULL, NULL),
            BAD_FUNC_ARG);
        ExpectIntEQ(wolfSSL_X509_CRL_get_signature(NULL, NULL, &sigSz),
            BAD_FUNC_ARG);
        ExpectIntEQ(wolfSSL_X509_CRL_get_signature(&empty, NULL, &sigSz),
            BAD_FUNC_ARG);
    }
    ExpectIntEQ(wolfSSL_X509_REVOKED_get_serial_number(NULL, NULL, NULL),
        BAD_FUNC_ARG);
    ExpectIntEQ(wolfSSL_X509_REVOKED_get_serial_number(rev , NULL, NULL),
        BAD_FUNC_ARG);
    ExpectIntEQ(wolfSSL_X509_REVOKED_get_serial_number(NULL, NULL, &len),
        BAD_FUNC_ARG);
    ExpectNull(wolfSSL_X509_CRL_get_lastUpdate(NULL));
    ExpectNull(wolfSSL_X509_CRL_get_lastUpdate(&empty));
    ExpectNull(wolfSSL_X509_CRL_get_nextUpdate(NULL));
    ExpectNull(wolfSSL_X509_CRL_get_nextUpdate(&empty));

    ExpectNotNull(wolfSSL_X509_CRL_get_issuer_name(crl));
    ExpectIntEQ(wolfSSL_X509_CRL_version(crl), 2);
    ExpectIntEQ(wolfSSL_X509_CRL_get_signature_type(crl), CTC_SHA256wRSA);
    ExpectIntEQ(wolfSSL_X509_CRL_get_signature_nid(crl),
        WC_NID_sha256WithRSAEncryption);
    {
        int sigSz = 0;
        ExpectIntEQ(wolfSSL_X509_CRL_get_signature(crl, NULL, &sigSz),
            WOLFSSL_SUCCESS);
        ExpectIntEQ(sigSz, 256);
    }
    ExpectNotNull(wolfSSL_X509_CRL_get_lastUpdate(crl));
    ExpectNotNull(wolfSSL_X509_CRL_get_nextUpdate(crl));

    ExpectIntEQ(wolfSSL_X509_REVOKED_get_serial_number(rev, NULL, &len),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(len, 1);
    len--;
    ExpectIntEQ(wolfSSL_X509_REVOKED_get_serial_number(rev, buff, &len),
        BUFFER_E);
    len += 2;
    ExpectIntEQ(wolfSSL_X509_REVOKED_get_serial_number(rev, buff, &len),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(len, 1);

    /* Test X509_CRL_get_REVOKED and stack iteration */
    ExpectIntEQ(wolfSSL_sk_X509_REVOKED_num(NULL), 0);
    ExpectNull(wolfSSL_X509_CRL_get_REVOKED(NULL));
    {
        WOLFSSL_STACK* revokedSk = NULL;
        ExpectNotNull(revokedSk = wolfSSL_X509_CRL_get_REVOKED(crl));
        if (revokedSk != NULL) {
            int numRevoked = wolfSSL_sk_X509_REVOKED_num(revokedSk);
            ExpectIntGT(numRevoked, 0);
            /* Verify first revoked entry has a serial number */
            {
                WOLFSSL_X509_REVOKED* r = NULL;
                ExpectNotNull(r = wolfSSL_sk_X509_REVOKED_value(revokedSk, 0));
                if (r != NULL) {
                    ExpectNotNull(r->serialNumber);
                    /* Verify revocation date is populated */
                    ExpectNotNull(
                        wolfSSL_X509_REVOKED_get0_revocation_date(r));
                    /* Verify sequence field (first entry should be 0) */
                    ExpectIntEQ(r->sequence, 0);
                }
            }
        }
        ExpectNull(wolfSSL_sk_X509_REVOKED_value(NULL, 0));
    }
#ifndef NO_WOLFSSL_STUB
    ExpectIntEQ(wolfSSL_X509_CRL_verify(NULL, NULL), 0);
    ExpectIntEQ(X509_OBJECT_set1_X509_CRL(NULL, NULL), 0);
    ExpectIntEQ(X509_OBJECT_set1_X509(NULL, NULL), 0);
#endif

    wolfSSL_X509_CRL_free(crl);
    crl = NULL;
#endif

    ExpectNotNull(asnInt = wolfSSL_ASN1_INTEGER_new());
    ExpectIntEQ(wolfSSL_ASN1_INTEGER_set(asnInt, 1), 1);
    revoked.serialNumber = asnInt;
    ExpectNull(wolfSSL_X509_REVOKED_get0_serial_number(NULL));
    ExpectNotNull(sn = wolfSSL_X509_REVOKED_get0_serial_number(&revoked));
    ExpectPtrEq(sn, asnInt);
    ExpectNull(wolfSSL_X509_REVOKED_get0_revocation_date(NULL));
    /* revoked on stack has no revocationDate set, so should be NULL */
    ExpectNull(wolfSSL_X509_REVOKED_get0_revocation_date(&revoked));
    wolfSSL_ASN1_INTEGER_free(asnInt);

    ExpectTrue((fp = XFOPEN("./certs/crl/crl.pem", "rb")) != XBADFILE);
    ExpectNotNull(crl = (X509_CRL*)PEM_read_X509_CRL(fp, (X509_CRL **)NULL,
        NULL, NULL));
    if (fp != XBADFILE)
        XFCLOSE(fp);

    ExpectNotNull(s = sk_X509_CRL_new());

    ExpectIntEQ(sk_X509_CRL_push(NULL, NULL), WOLFSSL_FAILURE);
    ExpectIntEQ(sk_X509_CRL_push(NULL, crl), WOLFSSL_FAILURE);
    ExpectIntEQ(sk_X509_CRL_push(s, NULL), WOLFSSL_FAILURE);
    ExpectNull(sk_X509_CRL_value(NULL, 0));
    ExpectIntEQ(sk_X509_CRL_num(NULL), 0);

    ExpectIntEQ(sk_X509_CRL_num(s), 0);
    ExpectIntEQ(sk_X509_CRL_push(s, crl), 1);
    if (EXPECT_FAIL()) {
        X509_CRL_free(crl);
    }
    ExpectIntEQ(sk_X509_CRL_num(s), 1);
    ExpectPtrEq(sk_X509_CRL_value(s, 0), crl);

    sk_X509_CRL_free(s);
#endif
    return EXPECT_RESULT();
}

#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
    defined(HAVE_CRL) && defined(WOLFSSL_CERT_GEN)
/* Ensure oversized caller-provided revocationDate is rejected. */
static int test_wolfSSL_X509_CRL_add_revoked_oversized_revocation_date(void)
{
    EXPECT_DECLS;
    WOLFSSL_X509_CRL* crl = NULL;
    WOLFSSL_ASN1_INTEGER* serial = NULL;
    WOLFSSL_X509_REVOKED revoked;
    WOLFSSL_ASN1_TIME revDate;
    byte serialData[] = { 0x01 };

    XMEMSET(&revoked, 0, sizeof(revoked));
    XMEMSET(&revDate, 0, sizeof(revDate));

    ExpectNotNull(crl = wolfSSL_X509_CRL_new());
    ExpectNotNull(serial = wolfSSL_ASN1_INTEGER_new());
    if (serial != NULL) {
        serial->data = serialData;
        serial->dataMax = (int)sizeof(serialData);
        serial->length = (int)sizeof(serialData);
        serial->isDynamic = 0;
    }

    revDate.length = MAX_DATE_SIZE + 1; /* intentionally too large */
    revDate.type = ASN_GENERALIZED_TIME;

    revoked.serialNumber = serial;
    revoked.revocationDate = &revDate;
    revoked.reason = CRL_REASON_NONE;

    ExpectIntEQ(wolfSSL_X509_CRL_add_revoked(crl, &revoked), BAD_FUNC_ARG);

    wolfSSL_ASN1_INTEGER_free(serial);
    wolfSSL_X509_CRL_free(crl);

    return EXPECT_RESULT();
}
#endif

#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
    defined(HAVE_CRL) && !defined(NO_FILESYSTEM) && \
    !defined(NO_STDIO_FILESYSTEM)
/* Ensure reason-code parsing handles optional critical BOOLEAN in entry ext. */
static int test_wolfSSL_X509_CRL_reason_critical_boolean(void)
{
    EXPECT_DECLS;
    int reasonCode = CRL_REASON_NONE;
    /* One Extension SEQUENCE with:
     * OID: 2.5.29.21 (CRL Reason Code)
     * critical: TRUE
     * extnValue: OCTET STRING wrapping ENUMERATED 2 (CA compromise) */
    static const byte ext[] = {
        0x30, 0x0d, 0x06, 0x03, 0x55, 0x1d, 0x15,
        0x01, 0x01, 0xff, 0x04, 0x03, 0x0a, 0x01, 0x02
    };

    ExpectIntEQ(wc_ParseCRLReasonFromExtensions(ext, (word32)sizeof(ext),
                                                 &reasonCode), 0);
    ExpectIntEQ(reasonCode, CRL_REASON_CA_COMPROMISE);

    return EXPECT_RESULT();
}
#endif

#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
    defined(HAVE_CRL) && !defined(NO_FILESYSTEM) && \
    !defined(NO_STDIO_FILESYSTEM) && defined(WOLFSSL_CERT_GEN) && \
    !defined(NO_ASN_TIME)
/* Helper function to create, sign, and write a CRL */
static int generate_crl_test(const char* keyFile, const char* certFile,
                             const char* derFile, const char* pemFile,
                             const char* certToRevokePath)
{
    EXPECT_DECLS;
    X509_NAME* issuer = NULL;
    X509_NAME* decodedIssuer = NULL;
    WOLFSSL_X509* cert = NULL;
    WOLFSSL_ASN1_TIME asnTime;
    XFILE fp = XBADFILE;
    WOLFSSL_X509_CRL* crl = NULL;
    WOLFSSL_X509_CRL* decodedCrl = NULL;
    WOLFSSL_EVP_PKEY* pkey = NULL;
    int i = 0;
    int revokedCount = 0;
    byte certSerial[EXTERNAL_SERIAL_SIZE];
    int certSerialSz = 0;
    byte serialsToRevokeBytes[][1] = { { 0x02 }, { 0x03 }, { 0x04 } };
    static const int numSerials =
        (int)(sizeof(serialsToRevokeBytes) /
              sizeof(serialsToRevokeBytes[0]));
    WOLFSSL_ASN1_INTEGER serialsToRevoke[3] = {
        { .intData = {0}, .negative = 0,
          .data = serialsToRevokeBytes[0],
          .dataMax = sizeof(serialsToRevokeBytes[0]),
          .isDynamic = 0,
          .length = sizeof(serialsToRevokeBytes[0]),
          .type = 0 },
        { .intData = {0}, .negative = 0,
          .data = serialsToRevokeBytes[1],
          .dataMax = sizeof(serialsToRevokeBytes[1]),
          .isDynamic = 0,
          .length = sizeof(serialsToRevokeBytes[1]),
          .type = 0 },
        { .intData = {0}, .negative = 0,
          .data = serialsToRevokeBytes[2],
          .dataMax = sizeof(serialsToRevokeBytes[2]),
          .isDynamic = 0,
          .length = sizeof(serialsToRevokeBytes[2]),
          .type = 0 }
    };
    WOLFSSL_X509_REVOKED revoked[3];
    WOLFSSL_X509* certToRevoke = NULL;

    /* Load certificate to get issuer name (CRL issuer = cert subject) */
    ExpectTrue((fp = XFOPEN(certFile, "rb")) != XBADFILE);
    if (fp != XBADFILE) {
        ExpectNotNull(cert = PEM_read_X509(fp, NULL, NULL, NULL));
        XFCLOSE(fp);
        fp = XBADFILE;
    }

    /* Create a new empty CRL */
    ExpectNotNull(crl = wolfSSL_X509_CRL_new());
    ExpectIntEQ(wolfSSL_X509_CRL_version(crl), 2);

    /* Set issuer name, must match certificate subject for verification */
    ExpectNotNull(issuer = X509_get_subject_name(cert));
    ExpectIntEQ(wolfSSL_X509_CRL_set_issuer_name(crl, issuer), WOLFSSL_SUCCESS);

    /* Set thisUpdate to current time */
    XMEMSET(&asnTime, 0, sizeof(asnTime));
    ExpectNotNull(wolfSSL_ASN1_TIME_adj(&asnTime, XTIME(NULL), 0, 0));
    ExpectIntEQ(wolfSSL_X509_CRL_set_lastUpdate(crl, &asnTime),
        WOLFSSL_SUCCESS);

    /* Set nextUpdate to 30 days from now */
    ExpectNotNull(wolfSSL_ASN1_TIME_adj(&asnTime, XTIME(NULL), 30, 0));
    ExpectIntEQ(wolfSSL_X509_CRL_set_nextUpdate(crl, &asnTime),
        WOLFSSL_SUCCESS);

    XMEMSET(revoked, 0, sizeof(revoked));
    for (i = 0; i < numSerials; i++) {
        revoked[i].serialNumber = &serialsToRevoke[i];
        revoked[i].reason = CRL_REASON_NONE;
    }

    /* Add revoked certificates based on serial numbers */
    for (i = 0; i < numSerials; i++) {
        ExpectIntEQ(wolfSSL_X509_CRL_add_revoked(crl, &revoked[i]),
            WOLFSSL_SUCCESS);
    }

    /* Add a revoked certificate entry to CRL by parsing a different
     * certificate buffer */
    ExpectTrue((fp = XFOPEN(certToRevokePath, "rb")) != XBADFILE);
    if (fp != XBADFILE) {
        ExpectNotNull(certToRevoke = PEM_read_X509(fp, NULL, NULL, NULL));
        XFCLOSE(fp);
        fp = XBADFILE;
    }
    {
        const byte* certDer = NULL;
        int certDerSz = 0;

        ExpectNotNull(certDer =
            wolfSSL_X509_get_der(certToRevoke, &certDerSz));
        ExpectIntEQ(wolfSSL_X509_CRL_add_revoked_cert(crl, certDer, certDerSz),
            WOLFSSL_SUCCESS);
    }

    /* Save cert serial for verification after round-trip */
    certSerialSz = (int)sizeof(certSerial);
    ExpectIntEQ(wolfSSL_X509_get_serial_number(certToRevoke, certSerial,
        &certSerialSz), WOLFSSL_SUCCESS);

    wolfSSL_X509_free(certToRevoke);
    certToRevoke = NULL;

    /* Count revoked certificates - should be 'numSerials' + 1 */
    revokedCount = 0;
    if (EXPECT_SUCCESS() && crl != NULL && crl->crlList != NULL) {
        RevokedCert* rev = crl->crlList->certs;
        while (rev != NULL) {
            revokedCount++;
            rev = rev->next;
        }
    }
    ExpectIntEQ(revokedCount, numSerials + 1);

    /* Load private key for signing */
    ExpectTrue((fp = XFOPEN(keyFile, "rb")) != XBADFILE);
    if (fp != XBADFILE) {
        ExpectNotNull(pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL));
        XFCLOSE(fp);
        fp = XBADFILE;
    }

    /* Sign the CRL */
    ExpectIntEQ(wolfSSL_X509_CRL_sign(crl, pkey, wolfSSL_EVP_sha256()),
        WOLFSSL_SUCCESS);

    /* Encode CRL to DER */
    ExpectIntEQ(wolfSSL_write_X509_CRL(crl, derFile, WOLFSSL_FILETYPE_ASN1),
        WOLFSSL_SUCCESS);

    /* Encode CRL to PEM */
    ExpectIntEQ(wolfSSL_write_X509_CRL(crl, pemFile, WOLFSSL_FILETYPE_PEM),
        WOLFSSL_SUCCESS);

    /* ===== Validate encoded DER CRL by decoding and checking contents ===== */
    ExpectTrue((fp = XFOPEN(derFile, "rb")) != XBADFILE);
    if (fp != XBADFILE) {
        ExpectNotNull(decodedCrl = d2i_X509_CRL_fp(fp, NULL));
        XFCLOSE(fp);
        fp = XBADFILE;
    }

    /* Verify CRL version is v2 */
    ExpectIntEQ(wolfSSL_X509_CRL_version(decodedCrl), 2);

    /* Verify issuer name matches */
    ExpectNotNull(decodedIssuer = wolfSSL_X509_CRL_get_issuer_name(decodedCrl));
    ExpectIntEQ(X509_NAME_cmp(issuer, decodedIssuer), 0);

    /* Verify signature type is SHA256 with RSA or ECDSA */
    ExpectIntNE(wolfSSL_X509_CRL_get_signature_type(decodedCrl), 0);

    /* Verify lastUpdate and nextUpdate are set */
    ExpectNotNull(wolfSSL_X509_CRL_get_lastUpdate(decodedCrl));
    ExpectNotNull(wolfSSL_X509_CRL_get_nextUpdate(decodedCrl));

    /* Count revoked certificates and verify serial values.
     * CRL parsing prepends entries, so decoded list is in reverse order. */
    revokedCount = 0;
    if (EXPECT_SUCCESS() && decodedCrl != NULL && decodedCrl->crlList != NULL) {
        RevokedCert* rev = decodedCrl->crlList->certs;
        while (rev != NULL) {
            if (revokedCount == 0) {
                /* Last added (cert serial) appears first in decoded list */
                ExpectIntEQ(rev->serialSz, certSerialSz);
                ExpectIntEQ(XMEMCMP(rev->serialNumber, certSerial,
                    rev->serialSz), 0);
            }
            else {
                /* Remaining serials in reverse: index numSerials-revokedCount */
                int idx = numSerials - revokedCount;
                ExpectIntEQ(rev->serialSz,
                    (int)sizeof(serialsToRevokeBytes[0]));
                ExpectIntEQ(XMEMCMP(rev->serialNumber,
                    serialsToRevokeBytes[idx], rev->serialSz), 0);
            }
            revokedCount++;
            rev = rev->next;
        }
    }
    ExpectIntEQ(revokedCount, numSerials + 1);

    wolfSSL_X509_CRL_free(decodedCrl);
    decodedCrl = NULL;

    /* ===== Validate encoded PEM CRL by decoding and checking contents ===== */
    ExpectTrue((fp = XFOPEN(pemFile, "rb")) != XBADFILE);
    if (fp != XBADFILE) {
        ExpectNotNull(decodedCrl = (X509_CRL*)PEM_read_X509_CRL(fp, NULL,
            NULL, NULL));
        XFCLOSE(fp);
        fp = XBADFILE;
    }

    /* Verify CRL version is v2 */
    ExpectIntEQ(wolfSSL_X509_CRL_version(decodedCrl), 2);

    /* Verify issuer name matches */
    ExpectNotNull(decodedIssuer = wolfSSL_X509_CRL_get_issuer_name(decodedCrl));
    ExpectIntEQ(X509_NAME_cmp(issuer, decodedIssuer), 0);

    /* Count revoked certificates from PEM and verify serial values.
     * CRL parsing prepends entries, so decoded list is in reverse order. */
    revokedCount = 0;
    if (EXPECT_SUCCESS() && decodedCrl != NULL && decodedCrl->crlList != NULL) {
        RevokedCert* rev = decodedCrl->crlList->certs;
        while (rev != NULL) {
            if (revokedCount == 0) {
                ExpectIntEQ(rev->serialSz, certSerialSz);
                ExpectIntEQ(XMEMCMP(rev->serialNumber, certSerial,
                    rev->serialSz), 0);
            }
            else {
                int idx = numSerials - revokedCount;
                ExpectIntEQ(rev->serialSz,
                    (int)sizeof(serialsToRevokeBytes[0]));
                ExpectIntEQ(XMEMCMP(rev->serialNumber,
                    serialsToRevokeBytes[idx], rev->serialSz), 0);
            }
            revokedCount++;
            rev = rev->next;
        }
    }
    ExpectIntEQ(revokedCount, numSerials + 1);

    wolfSSL_X509_CRL_free(decodedCrl);

    wolfSSL_EVP_PKEY_free(pkey);
    wolfSSL_X509_CRL_free(crl);
    wolfSSL_X509_free(cert);

    return EXPECT_RESULT();
}
#endif

static int test_sk_X509_CRL_encode(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
    defined(HAVE_CRL) && !defined(NO_FILESYSTEM) && \
    !defined(NO_STDIO_FILESYSTEM) && defined(WOLFSSL_CERT_GEN) && \
    !defined(NO_ASN_TIME)
#ifndef NO_RSA
    static const char* crlRsaPemFile = "./certs/crl/crlRsaOut.pem";
    static const char* crlRsaDerFile = "./certs/crl/crlRsaOut.der";
    static const char* testRsaKeyFile  = "./certs/ca-key.pem";
    /* Use ca-cert.pem to match ca-key.pem for proper CRL verification */
    static const char* testRsaCertFile = "./certs/ca-cert.pem";
    static const char* revokeRsaCertFile = "./certs/server-cert.pem";
#endif
#ifdef HAVE_ECC
    static const char* crlEccPemFile = "./certs/crl/crlEccOut.pem";
    static const char* crlEccDerFile = "./certs/crl/crlEccOut.der";
    static const char* testEccKeyFile  = "./certs/ca-ecc-key.pem";
    /* Use ca-ecc-cert.pem to match ca-ecc-key.pem for proper CRL
     * verification */
    static const char* testEccCertFile = "./certs/ca-ecc-cert.pem";
    static const char* revokeEccCertFile = "./certs/server-ecc.pem";
#endif

#ifndef NO_RSA
    /* Generate RSA-signed CRL (PEM and DER) */
    ExpectIntEQ(generate_crl_test(testRsaKeyFile, testRsaCertFile,
        crlRsaDerFile, crlRsaPemFile, revokeRsaCertFile), TEST_SUCCESS);
#endif

#ifdef HAVE_ECC
    /* Generate ECC-signed CRL (PEM and DER) */
    ExpectIntEQ(generate_crl_test(testEccKeyFile, testEccCertFile,
        crlEccDerFile, crlEccPemFile, revokeEccCertFile), TEST_SUCCESS);
#endif
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_X509_CRL_sign_large(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
    defined(HAVE_CRL) && !defined(NO_FILESYSTEM) && \
    !defined(NO_STDIO_FILESYSTEM) && defined(WOLFSSL_CERT_GEN) && \
    !defined(NO_ASN_TIME)
#ifndef NO_RSA
    static const char* testRsaKeyFile  = "./certs/ca-key.pem";
    static const char* testRsaCertFile = "./certs/ca-cert.pem";
    X509_NAME* issuer = NULL;
    WOLFSSL_X509* cert = NULL;
    WOLFSSL_X509_CRL* crl = NULL;
    WOLFSSL_EVP_PKEY* pkey = NULL;
    WOLFSSL_ASN1_TIME asnTime;
    WOLFSSL_X509_REVOKED revoked;
    XFILE fp = XBADFILE;
    int i;
    byte serial[4];

    ExpectTrue((fp = XFOPEN(testRsaCertFile, "rb")) != XBADFILE);
    if (fp != XBADFILE) {
        ExpectNotNull(cert = PEM_read_X509(fp, NULL, NULL, NULL));
        XFCLOSE(fp);
        fp = XBADFILE;
    }

    ExpectNotNull(crl = wolfSSL_X509_CRL_new());
    ExpectNotNull(issuer = X509_get_subject_name(cert));
    ExpectIntEQ(wolfSSL_X509_CRL_set_issuer_name(crl, issuer), WOLFSSL_SUCCESS);

    XMEMSET(&asnTime, 0, sizeof(asnTime));
    ExpectNotNull(wolfSSL_ASN1_TIME_adj(&asnTime, XTIME(NULL), 0, 0));
    ExpectIntEQ(wolfSSL_X509_CRL_set_lastUpdate(crl, &asnTime),
        WOLFSSL_SUCCESS);

    ExpectNotNull(wolfSSL_ASN1_TIME_adj(&asnTime, XTIME(NULL), 30, 0));
    ExpectIntEQ(wolfSSL_X509_CRL_set_nextUpdate(crl, &asnTime),
        WOLFSSL_SUCCESS);

    XMEMSET(&revoked, 0, sizeof(revoked));
    revoked.serialNumber = wolfSSL_ASN1_INTEGER_new();
    ExpectNotNull(revoked.serialNumber);
    revoked.reason = CRL_REASON_NONE;
    if (revoked.serialNumber != NULL) {
        revoked.serialNumber->data = serial;
        revoked.serialNumber->length = (int)sizeof(serial);
    }

    for (i = 1; i <= 1024; i++) {
        serial[0] = (byte)(i & 0xff);
        serial[1] = (byte)((i >> 8) & 0xff);
        serial[2] = (byte)((i >> 16) & 0xff);
        serial[3] = (byte)((i >> 24) & 0xff);
        ExpectIntEQ(wolfSSL_X509_CRL_add_revoked(crl, &revoked),
            WOLFSSL_SUCCESS);
    }

    ExpectTrue((fp = XFOPEN(testRsaKeyFile, "rb")) != XBADFILE);
    if (fp != XBADFILE) {
        ExpectNotNull(pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL));
        XFCLOSE(fp);
        fp = XBADFILE;
    }

    ExpectIntEQ(wolfSSL_X509_CRL_sign(crl, pkey, wolfSSL_EVP_sha256()),
        WOLFSSL_SUCCESS);

    if (revoked.serialNumber != NULL) {
        revoked.serialNumber->data = NULL;
        wolfSSL_ASN1_INTEGER_free(revoked.serialNumber);
        revoked.serialNumber = NULL;
    }

    wolfSSL_EVP_PKEY_free(pkey);
    wolfSSL_X509_CRL_free(crl);
    wolfSSL_X509_free(cert);
#endif /* !NO_RSA */
#endif
    return EXPECT_RESULT();
}

/* Test round-trip of a CRL with the maximum size CRL number (CRL_MAX_NUM_SZ
 * = 20 bytes). Build TBS with wc_MakeCRL_ex, sign with wc_SignCRL_ex, then
 * decode with d2i_X509_CRL and verify the CRL number survives.
 * Then patch the DER to make the CRL number negative and verify rejection. */
static int test_wc_MakeCRL_max_crlnum(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_CERT_GEN) && defined(HAVE_CRL) && !defined(NO_RSA) && \
    !defined(NO_FILESYSTEM) && !defined(NO_ASN) && defined(OPENSSL_EXTRA)
    const char* caCertDerFile = "./certs/ca-cert.der";
    const char* caKeyDerFile  = "./certs/ca-key.der";
    byte certBuf[4096];
    byte keyBuf[4096];
    int  certSz = 0;
    int  keySz  = 0;
    XFILE f = XBADFILE;
    DecodedCert caCert;
    int caCertInit = 0;
    RsaKey rsaKey;
    WC_RNG rng;
    word32 idx = 0;
    int rsaKeyInit = 0;
    int rngInit = 0;

    /* 20-byte CRL number: 0x01..0x14.  First byte < 0x80 so no ASN.1
     * padding byte is needed - the encoded INTEGER content is exactly
     * 20 bytes, matching CRL_MAX_NUM_SZ. */
    byte crlNum[CRL_MAX_NUM_SZ];
    const char* expHex =
        "0102030405060708090A0B0C0D0E0F1011121314";

    /* thisUpdate/nextUpdate dates in UTC time format */
    const byte thisUpdate[] = "260101000000Z";  /* Jan 1, 2026 */
    const byte nextUpdate[] = "270101000000Z";  /* Jan 1, 2027 */

    /* issuer DER (SEQUENCE-wrapped Name) */
    byte issuerDer[512];
    word32 issuerDerSz = 0;

    byte* tbsBuf = NULL;
    int   tbsSz  = 0;
    byte* crlBuf = NULL;
    int   crlSz  = 0;
    int   bufSz  = 0;

    WOLFSSL_X509_CRL* decodedCrl = NULL;
    int i;

    /* CRL Number OID 2.5.29.20: used to locate the extension in the DER */
    static const byte crlNumOid[] = { 0x55, 0x1D, 0x14 };

    /* Fill CRL number with 0x01..0x14 */
    for (i = 0; i < (int)CRL_MAX_NUM_SZ; i++) {
        crlNum[i] = (byte)(i + 1);
    }

    /* Load CA cert DER */
    ExpectTrue((f = XFOPEN(caCertDerFile, "rb")) != XBADFILE);
    if (f != XBADFILE) {
        ExpectIntGT(certSz = (int)XFREAD(certBuf, 1, sizeof(certBuf), f), 0);
        XFCLOSE(f);
        f = XBADFILE;
    }

    /* Load CA key DER */
    ExpectTrue((f = XFOPEN(caKeyDerFile, "rb")) != XBADFILE);
    if (f != XBADFILE) {
        ExpectIntGT(keySz = (int)XFREAD(keyBuf, 1, sizeof(keyBuf), f), 0);
        XFCLOSE(f);
        f = XBADFILE;
    }

    /* Parse CA cert to extract the subject (= CRL issuer) DER.
     * subjectRaw is the Name contents without the outer SEQUENCE tag,
     * so we re-wrap it with SetSequence to produce a valid issuer Name. */
    wc_InitDecodedCert(&caCert, certBuf, (word32)certSz, NULL);
    caCertInit = 1;
    ExpectIntEQ(wc_ParseCert(&caCert, CERT_TYPE, 0, NULL), 0);
    if (EXPECT_SUCCESS()) {
        word32 seqHdrSz = SetSequence((word32)caCert.subjectRawLen, issuerDer);
        XMEMCPY(issuerDer + seqHdrSz, caCert.subjectRaw,
            (size_t)caCert.subjectRawLen);
        issuerDerSz = seqHdrSz + (word32)caCert.subjectRawLen;
    }

    /* Decode RSA private key */
    ExpectIntEQ(wc_InitRsaKey(&rsaKey, NULL), 0);
    if (EXPECT_SUCCESS()) {
        rsaKeyInit = 1;
    }
    idx = 0;
    ExpectIntEQ(wc_RsaPrivateKeyDecode(keyBuf, &idx, &rsaKey, (word32)keySz),
        0);

    /* Init RNG for signing */
    ExpectIntEQ(wc_InitRng(&rng), 0);
    if (EXPECT_SUCCESS()) {
        rngInit = 1;
    }

    /* --- Build TBS --- */
    /* First call with NULL output to get required size */
    tbsSz = wc_MakeCRL_ex(
        issuerDer, issuerDerSz,
        thisUpdate, ASN_UTC_TIME,                    /* thisUpdate */
        nextUpdate, ASN_UTC_TIME,                    /* nextUpdate */
        NULL,                                        /* no revoked certs */
        crlNum, (word32)sizeof(crlNum),              /* max-size CRL number */
        CTC_SHA256wRSA, 2,                           /* v2 for extensions */
        NULL, 0);
    ExpectIntGT(tbsSz, 0);

    /* Allocate buffer large enough for TBS + signature overhead */
    if (EXPECT_SUCCESS()) {
        bufSz = tbsSz + 512; /* generous room for signature wrapper */
        ExpectNotNull(tbsBuf = (byte*)XMALLOC(bufSz, NULL,
            DYNAMIC_TYPE_TMP_BUFFER));
    }

    /* Second call to actually encode TBS */
    if (EXPECT_SUCCESS()) {
        tbsSz = wc_MakeCRL_ex(
            issuerDer, issuerDerSz,
            thisUpdate, ASN_UTC_TIME,
            nextUpdate, ASN_UTC_TIME,
            NULL,
            crlNum, (word32)sizeof(crlNum),
            CTC_SHA256wRSA, 2,
            tbsBuf, (word32)bufSz);
        ExpectIntGT(tbsSz, 0);
    }

    /* --- Sign the CRL --- */
    if (EXPECT_SUCCESS()) {
        ExpectNotNull(crlBuf = (byte*)XMALLOC(bufSz, NULL,
            DYNAMIC_TYPE_TMP_BUFFER));
    }
    if (EXPECT_SUCCESS()) {
        crlSz = wc_SignCRL_ex(tbsBuf, tbsSz, CTC_SHA256wRSA,
            crlBuf, (word32)bufSz, &rsaKey, NULL, &rng);
        ExpectIntGT(crlSz, 0);
    }

    /* --- Decode the CRL and verify CRL number --- */
    if (EXPECT_SUCCESS()) {
        ExpectNotNull(decodedCrl = d2i_X509_CRL(NULL, crlBuf, crlSz));
    }
    if (decodedCrl != NULL && decodedCrl->crlList != NULL) {
        ExpectTrue(decodedCrl->crlList->crlNumberSet);
        if (decodedCrl->crlList->crlNumberSet) {
            ExpectIntEQ(XMEMCMP(decodedCrl->crlList->crlNumber, expHex,
                XSTRLEN(expHex)), 0);
        }
    }
    wolfSSL_X509_CRL_free(decodedCrl);
    decodedCrl = NULL;

    /* --- Negative test: patch the CRL number to be negative --- */
    /* The encoded CRL number INTEGER is: 02 14 01 02 03 ... 14
     * (tag=0x02, length=0x14=20, content bytes 0x01..0x14).
     * Flip the high bit of the first content byte (0x01 -> 0x81) to make
     * the INTEGER negative.  No lengths change, so the DER stays
     * structurally valid.  The signature is now wrong, but d2i_X509_CRL
     * uses NO_VERIFY so that doesn't matter. */
    if (EXPECT_SUCCESS()) {
        /* Find CRL Number OID (55 1D 14) in the DER */
        int found = 0;
        for (i = 0; i < crlSz - (int)sizeof(crlNumOid); i++) {
            if (XMEMCMP(crlBuf + i, crlNumOid, sizeof(crlNumOid)) == 0) {
                /* OID found at i.  Skip past: OID (3 bytes) -> OCTET STRING
                 * tag (1) + length (1) -> INTEGER tag (1) + length (1) ->
                 * first content byte. */
                int contentIdx = i + 3 + 2 + 2;
                if (contentIdx < crlSz) {
                    crlBuf[contentIdx] |= 0x80;
                    found = 1;
                }
                break;
            }
        }
        ExpectTrue(found);
    }
    /* Decoding the patched CRL must fail - the CRL number is negative. */
    if (EXPECT_SUCCESS()) {
        decodedCrl = d2i_X509_CRL(NULL, crlBuf, crlSz);
        ExpectNull(decodedCrl);
        wolfSSL_X509_CRL_free(decodedCrl);
    }

    XFREE(crlBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(tbsBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    if (caCertInit) {
        wc_FreeDecodedCert(&caCert);
    }
    if (rngInit) {
        wc_FreeRng(&rng);
    }
    if (rsaKeyInit) {
        wc_FreeRsaKey(&rsaKey);
    }
#endif
    return EXPECT_RESULT();
}

static int test_X509_REQ(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_CERTS) && \
    defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && !defined(NO_BIO)
    X509_NAME* name = NULL;
#ifndef NO_RSA
    X509_NAME* subject = NULL;
#endif
#if !defined(NO_RSA) || defined(HAVE_ECC)
    X509_REQ* req = NULL;
    EVP_PKEY* priv = NULL;
    EVP_PKEY* pub = NULL;
    unsigned char* der = NULL;
    int len;
#endif
#ifndef NO_RSA
    EVP_MD_CTX *mctx = NULL;
    EVP_PKEY_CTX *pkctx = NULL;
    #ifdef USE_CERT_BUFFERS_1024
    const unsigned char* rsaPriv = (const unsigned char*)client_key_der_1024;
    const unsigned char* rsaPub = (unsigned char*)client_keypub_der_1024;
    #elif defined(USE_CERT_BUFFERS_2048)
    const unsigned char* rsaPriv = (const unsigned char*)client_key_der_2048;
    const unsigned char* rsaPub = (unsigned char*)client_keypub_der_2048;
    #endif
#endif
#ifdef HAVE_ECC
    const unsigned char* ecPriv = (const unsigned char*)ecc_clikey_der_256;
    const unsigned char* ecPub = (unsigned char*)ecc_clikeypub_der_256;
    BIO* bio = NULL;
#endif
    unsigned char tooLongPassword[WC_CTC_NAME_SIZE + 1];

    XMEMSET(tooLongPassword, 0, sizeof(tooLongPassword));

    ExpectNotNull(name = X509_NAME_new());
    ExpectIntEQ(X509_NAME_add_entry_by_txt(name, "commonName", MBSTRING_UTF8,
        (byte*)"wolfssl.com", 11, 0, 1), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_NAME_add_entry_by_txt(name, "emailAddress", MBSTRING_UTF8,
        (byte*)"support@wolfssl.com", 19, -1, 1), WOLFSSL_SUCCESS);

#ifndef NO_RSA
    ExpectNotNull(priv = d2i_PrivateKey(EVP_PKEY_RSA, NULL, &rsaPriv,
        (long)sizeof_client_key_der_2048));
    ExpectNotNull(pub = d2i_PUBKEY(NULL, &rsaPub,
        (long)sizeof_client_keypub_der_2048));
    ExpectNotNull(req = X509_REQ_new());
    ExpectIntEQ(X509_REQ_set_subject_name(NULL, name), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(X509_REQ_set_subject_name(req, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(X509_REQ_set_subject_name(req, name), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_set_pubkey(NULL, pub), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(X509_REQ_set_pubkey(req, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(X509_REQ_set_pubkey(req, pub), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_sign(NULL, priv, EVP_sha256()), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(X509_REQ_sign(req, NULL, EVP_sha256()), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(X509_REQ_sign(req, priv, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(X509_REQ_sign(req, priv, EVP_sha256()), WOLFSSL_SUCCESS);
    ExpectIntEQ(i2d_X509_REQ(NULL, NULL), BAD_FUNC_ARG);
    ExpectIntEQ(i2d_X509_REQ(req, NULL), BAD_FUNC_ARG);
    ExpectIntEQ(i2d_X509_REQ(NULL, &der), BAD_FUNC_ARG);
    len = i2d_X509_REQ(req, &der);
    DEBUG_WRITE_DER(der, len, "req.der");
#ifdef USE_CERT_BUFFERS_1024
    ExpectIntEQ(len, 381);
#else
    ExpectIntEQ(len, 643);
#endif
    XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
    der = NULL;

    mctx = EVP_MD_CTX_new();
    ExpectIntEQ(EVP_DigestSignInit(mctx, &pkctx, EVP_sha256(), NULL, priv),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_sign_ctx(NULL, NULL), WOLFSSL_FAILURE);
    ExpectIntEQ(X509_REQ_sign_ctx(req, NULL), WOLFSSL_FAILURE);
    ExpectIntEQ(X509_REQ_sign_ctx(NULL, mctx), WOLFSSL_FAILURE);
    ExpectIntEQ(X509_REQ_sign_ctx(req, mctx), WOLFSSL_SUCCESS);

    EVP_MD_CTX_free(mctx);
    mctx = NULL;
    X509_REQ_free(NULL);
    X509_REQ_free(req);
    req = NULL;

    /* Test getting the subject from a newly created X509_REQ */
    ExpectNotNull(req = X509_REQ_new());
    ExpectNotNull(subject = X509_REQ_get_subject_name(req));
    ExpectIntEQ(X509_NAME_add_entry_by_NID(subject, NID_commonName,
        MBSTRING_UTF8, (unsigned char*)"www.wolfssl.com", -1, -1, 0), 1);
    ExpectIntEQ(X509_NAME_add_entry_by_NID(subject, NID_countryName,
        MBSTRING_UTF8, (unsigned char*)"US", -1, -1, 0), 1);
    ExpectIntEQ(X509_NAME_add_entry_by_NID(subject, NID_localityName,
        MBSTRING_UTF8, (unsigned char*)"Bozeman", -1, -1, 0), 1);
    ExpectIntEQ(X509_NAME_add_entry_by_NID(subject, NID_stateOrProvinceName,
        MBSTRING_UTF8, (unsigned char*)"Montana", -1, -1, 0), 1);
    ExpectIntEQ(X509_NAME_add_entry_by_NID(subject, NID_organizationName,
        MBSTRING_UTF8, (unsigned char*)"wolfSSL", -1, -1, 0), 1);
    ExpectIntEQ(X509_NAME_add_entry_by_NID(subject, NID_organizationalUnitName,
        MBSTRING_UTF8, (unsigned char*)"Testing", -1, -1, 0), 1);
    ExpectIntEQ(X509_REQ_set_pubkey(req, pub), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_sign(req, priv, EVP_sha256()), WOLFSSL_SUCCESS);
    len = i2d_X509_REQ(req, &der);
    DEBUG_WRITE_DER(der, len, "req2.der");
#ifdef USE_CERT_BUFFERS_1024
    ExpectIntEQ(len, 435);
#else
    ExpectIntEQ(len, 696);
#endif
    XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
    der = NULL;

    EVP_PKEY_free(pub);
    pub = NULL;
    EVP_PKEY_free(priv);
    priv = NULL;
    X509_REQ_free(req);
    req = NULL;
#endif
#ifdef HAVE_ECC
    ExpectNotNull(priv = wolfSSL_d2i_PrivateKey(EVP_PKEY_EC, NULL, &ecPriv,
        sizeof_ecc_clikey_der_256));
    ExpectNotNull(pub = wolfSSL_d2i_PUBKEY(NULL, &ecPub,
        sizeof_ecc_clikeypub_der_256));
    ExpectNotNull(req = X509_REQ_new());
    ExpectIntEQ(X509_REQ_set_subject_name(req, name), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_set_pubkey(req, pub), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_sign(req, priv, EVP_sha256()), WOLFSSL_SUCCESS);
    /* Signature is random and may be shorter or longer. */
    ExpectIntGE((len = i2d_X509_REQ(req, &der)), 245);
    ExpectIntLE(len, 253);
    ExpectNotNull(bio = BIO_new_fp(stderr, BIO_NOCLOSE));
    ExpectIntEQ(X509_REQ_print(bio, req), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_print(bio, NULL), WOLFSSL_FAILURE);
    BIO_free(bio);
    XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
    X509_REQ_free(req);
    req = NULL;
    EVP_PKEY_free(pub);
    EVP_PKEY_free(priv);

#ifdef FP_ECC
    wc_ecc_fp_free();
#endif
#endif /* HAVE_ECC */

    X509_NAME_free(name);

    ExpectNull(wolfSSL_X509_REQ_get_extensions(NULL));
    /* Stub function. */
    ExpectNull(wolfSSL_X509_to_X509_REQ(NULL, NULL, NULL));

    ExpectNotNull(req = X509_REQ_new());
#ifdef HAVE_LIBEST
    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(NULL, NULL,
        WOLFSSL_MBSTRING_UTF8, NULL, 0), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(req, NULL,
        WOLFSSL_MBSTRING_UTF8, NULL, 0), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(NULL, "name",
        WOLFSSL_MBSTRING_UTF8, NULL, 0), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(NULL, NULL,
        WOLFSSL_MBSTRING_ASC, NULL, 0), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(NULL, NULL,
        WOLFSSL_MBSTRING_UTF8, (byte*)"1.3.6.1.1.1.1.22", 16), WOLFSSL_FAILURE);


    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(NULL, "name",
        WOLFSSL_MBSTRING_ASC, (byte*)"1.3.6.1.1.1.1.22", 16), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(req, NULL,
        WOLFSSL_MBSTRING_ASC, (byte*)"1.3.6.1.1.1.1.22", 16), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(req, "name",
        WOLFSSL_MBSTRING_UTF8, (byte*)"1.3.6.1.1.1.1.22", 16), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(req, "name",
        WOLFSSL_MBSTRING_ASC, NULL, 0), WOLFSSL_FAILURE);

    /* Unsupported bytes. */
    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(req, "name",
        WOLFSSL_MBSTRING_ASC, (byte*)"1.3.6.1.1.1.1.23", 16), WOLFSSL_FAILURE);

    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(req, "MAC Address",
        WOLFSSL_MBSTRING_ASC, (byte*)"1.3.6.1.1.1.1.22", 16), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(req, "ecpublicKey",
        WOLFSSL_MBSTRING_ASC, (byte*)"1.2.840.10045.2.1", -1), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(req, "ecdsa-with-SHA384",
        WOLFSSL_MBSTRING_ASC, (byte*)"1.2.840.10045.4.3.3", -1),
        WOLFSSL_SUCCESS);
#else
    /* Stub function. */
    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(NULL, NULL,
        WOLFSSL_MBSTRING_UTF8, NULL, 0), WOLFSSL_FAILURE);
    ExpectIntEQ(wolfSSL_X509_REQ_add1_attr_by_txt(req, "MAC Address",
        WOLFSSL_MBSTRING_ASC, (byte*)"1.3.6.1.1.1.1.22", 16), WOLFSSL_FAILURE);
#endif

    ExpectIntEQ(X509_REQ_add1_attr_by_NID(NULL, WC_NID_subject_alt_name,
        WOLFSSL_MBSTRING_UTF8, NULL, 0), WOLFSSL_FAILURE);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_subject_alt_name,
        WOLFSSL_MBSTRING_UTF8, NULL, 0), WOLFSSL_FAILURE);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(NULL, WC_NID_subject_alt_name,
        WOLFSSL_MBSTRING_ASC, NULL, 0), WOLFSSL_FAILURE);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(NULL, WC_NID_pkcs9_challengePassword,
        WOLFSSL_MBSTRING_UTF8, NULL, 0), WOLFSSL_FAILURE);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(NULL, WC_NID_subject_alt_name,
        WOLFSSL_MBSTRING_UTF8, (byte*)"password", 8), WOLFSSL_FAILURE);

    ExpectIntEQ(X509_REQ_add1_attr_by_NID(NULL, WC_NID_pkcs9_challengePassword,
        WOLFSSL_MBSTRING_ASC, (byte*)"password", 8), WOLFSSL_FAILURE);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_subject_alt_name,
        WOLFSSL_MBSTRING_ASC, (byte*)"password", 8), WOLFSSL_FAILURE);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_pkcs9_challengePassword,
        WOLFSSL_MBSTRING_UTF8, (byte*)"password", 8), WOLFSSL_FAILURE);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_pkcs9_challengePassword,
        WOLFSSL_MBSTRING_ASC, NULL, -1), WOLFSSL_FAILURE);

    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_pkcs9_challengePassword,
        WOLFSSL_MBSTRING_ASC, (byte*)"password", -1), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_pkcs9_challengePassword,
        WOLFSSL_MBSTRING_ASC, tooLongPassword, sizeof(tooLongPassword)),
        WOLFSSL_FAILURE);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_serialNumber,
        WOLFSSL_MBSTRING_ASC, (byte*)"123456", -1), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_serialNumber,
        WOLFSSL_MBSTRING_ASC, tooLongPassword, sizeof(tooLongPassword)),
        WOLFSSL_FAILURE);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_pkcs9_unstructuredName,
        WOLFSSL_MBSTRING_ASC, (byte*)"name", 4), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_pkcs9_contentType,
        WOLFSSL_MBSTRING_ASC, (byte*)"type", 4), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_surname,
        WOLFSSL_MBSTRING_ASC, (byte*)"surname", 7), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_initials,
        WOLFSSL_MBSTRING_ASC, (byte*)"s.g", 3), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_givenName,
        WOLFSSL_MBSTRING_ASC, (byte*)"givenname", 9), WOLFSSL_SUCCESS);
    ExpectIntEQ(X509_REQ_add1_attr_by_NID(req, WC_NID_dnQualifier,
        WOLFSSL_MBSTRING_ASC, (byte*)"dnQualifier", 11), WOLFSSL_SUCCESS);

    wolfSSL_X509_REQ_free(req);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_X509_REQ_print(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_CERTS) && \
    defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && !defined(NO_BIO)
    WOLFSSL_X509* req = NULL;
    XFILE fp = XBADFILE;
    const char* csrFileName = "certs/csr.attr.der";
    const char* csrExtFileName = "certs/csr.ext.der";
    BIO* bio = NULL;

    ExpectTrue((fp = XFOPEN(csrFileName, "rb")) != XBADFILE);
    ExpectNotNull(req = d2i_X509_REQ_fp(fp, NULL));
    if (fp != XBADFILE) {
        XFCLOSE(fp);
        fp = XBADFILE;
    }

    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntEQ(wolfSSL_X509_REQ_print(bio, req), WOLFSSL_SUCCESS);
    ExpectIntEQ(BIO_get_mem_data(bio, NULL), 2681);

    BIO_free(bio);
    bio = NULL;
    wolfSSL_X509_REQ_free(req);
    req = NULL;

    ExpectTrue((fp = XFOPEN(csrExtFileName, "rb")) != XBADFILE);
    ExpectNotNull(req = d2i_X509_REQ_fp(fp, NULL));
    if (fp != XBADFILE) {
        XFCLOSE(fp);
    }

    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntEQ(wolfSSL_X509_REQ_print(bio, req), WOLFSSL_SUCCESS);
    ExpectIntEQ(BIO_get_mem_data(bio, NULL), 1889);

    BIO_free(bio);
    wolfSSL_X509_REQ_free(req);
#endif
    return EXPECT_RESULT();
}

/*----------------------------------------------------------------------------*
 | Certificate Failure Checks
 *----------------------------------------------------------------------------*/
#if !defined(NO_CERTS) && (!defined(NO_WOLFSSL_CLIENT) || \
                   !defined(WOLFSSL_NO_CLIENT_AUTH)) && !defined(NO_FILESYSTEM)
#if (!defined(NO_RSA) || defined(HAVE_ECC)) && !defined(NO_SHA256)
/* Use the Cert Manager(CM) API to generate the error ASN_SIG_CONFIRM_E */
#ifndef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
static int verify_sig_cm(const char* ca, byte* cert_buf, size_t cert_sz,
    int type)
{
    int ret;
    WOLFSSL_CERT_MANAGER* cm = NULL;

    switch (type) {
        case TESTING_RSA:
        #ifdef NO_RSA
            fprintf(stderr, "RSA disabled, skipping test\n");
            return ASN_SIG_CONFIRM_E;
        #else
            break;
        #endif
        case TESTING_ECC:
        #ifndef HAVE_ECC
            fprintf(stderr, "ECC disabled, skipping test\n");
            return ASN_SIG_CONFIRM_E;
        #else
            break;
        #endif
        default:
            fprintf(stderr, "Bad function argument\n");
            return BAD_FUNC_ARG;
    }
    cm = wolfSSL_CertManagerNew();
    if (cm == NULL) {
        fprintf(stderr, "wolfSSL_CertManagerNew failed\n");
        return -1;
    }

#ifndef NO_FILESYSTEM
    ret = wolfSSL_CertManagerLoadCA(cm, ca, 0);
    if (ret != WOLFSSL_SUCCESS) {
        fprintf(stderr, "wolfSSL_CertManagerLoadCA failed\n");
        wolfSSL_CertManagerFree(cm);
        return ret;
    }
#else
    (void)ca;
#endif

    ret = wolfSSL_CertManagerVerifyBuffer(cm, cert_buf, (long int)cert_sz,
        WOLFSSL_FILETYPE_ASN1);
    /* Let ExpectIntEQ handle return code */

    wolfSSL_CertManagerFree(cm);

    return ret;
}


#if !defined(NO_FILESYSTEM)
static int test_RsaSigFailure_cm(void)
{
    EXPECT_DECLS;
#ifndef NO_RSA
#ifdef WOLFSSL_PEM_TO_DER
    const char* ca_cert = "./certs/ca-cert.pem";
#else
    const char* ca_cert = "./certs/ca-cert.der";
#endif
    const char* server_cert = "./certs/server-cert.der";
    byte* cert_buf = NULL;
    size_t cert_sz = 0;

    ExpectIntEQ(load_file(server_cert, &cert_buf, &cert_sz), 0);
    if ((cert_buf != NULL) && (cert_sz > 0)) {
        /* corrupt DER - invert last byte, which is signature */
        cert_buf[cert_sz-1] = ~cert_buf[cert_sz-1];
        /* test bad cert */
#if defined(NO_WOLFSSL_CLIENT) && defined(NO_WOLFSSL_SERVER)
        ExpectIntEQ(verify_sig_cm(ca_cert, cert_buf, cert_sz, TESTING_RSA),
           WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
#elif defined(NO_ASN_CRYPT)
        /* RSA verify is not called when ASN crypt support is disabled */
        ExpectIntEQ(verify_sig_cm(ca_cert, cert_buf, cert_sz, TESTING_RSA),
           WOLFSSL_SUCCESS);
#else
        ExpectIntEQ(verify_sig_cm(ca_cert, cert_buf, cert_sz, TESTING_RSA),
           WC_NO_ERR_TRACE(ASN_SIG_CONFIRM_E));
#endif
    }

    /* load_file() uses XMALLOC. */
    if (cert_buf != NULL) {
        XFREE(cert_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    }
#endif /* !NO_RSA */
    return EXPECT_RESULT();
}

static int test_EccSigFailure_cm(void)
{
    EXPECT_DECLS;
#ifdef HAVE_ECC
    /* self-signed ECC cert, so use server cert as CA */
#ifdef WOLFSSL_PEM_TO_DER
    const char* ca_cert = "./certs/ca-ecc-cert.pem";
#else
    const char* ca_cert = "./certs/ca-ecc-cert.der";
#endif
    const char* server_cert = "./certs/server-ecc.der";
    byte* cert_buf = NULL;
    size_t cert_sz = 0;

    ExpectIntEQ(load_file(server_cert, &cert_buf, &cert_sz), 0);
    if (cert_buf != NULL && cert_sz > 0) {
        /* corrupt DER - invert last byte, which is signature */
        cert_buf[cert_sz-1] = ~cert_buf[cert_sz-1];

        /* test bad cert */
#if defined(NO_WOLFSSL_CLIENT) && defined(NO_WOLFSSL_SERVER)
        ExpectIntEQ(verify_sig_cm(ca_cert, cert_buf, cert_sz, TESTING_ECC),
           WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
#elif defined(NO_ASN_CRYPT)
        /* ECC verify is not called when ASN crypt support is disabled */
        ExpectIntEQ(verify_sig_cm(ca_cert, cert_buf, cert_sz, TESTING_ECC),
           WOLFSSL_SUCCESS);
#else
        ExpectIntEQ(verify_sig_cm(ca_cert, cert_buf, cert_sz, TESTING_ECC),
           WC_NO_ERR_TRACE(ASN_SIG_CONFIRM_E));
#endif
    }

    /* load_file() uses XMALLOC. */
    if (cert_buf != NULL) {
        XFREE(cert_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    }
#ifdef FP_ECC
    wc_ecc_fp_free();
#endif
#endif /* HAVE_ECC */
    return EXPECT_RESULT();
}
#endif /* !NO_FILESYSTEM */
#endif /* !WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION*/
#endif /* !NO_RSA || HAVE_ECC */
#endif /* NO_CERTS */

static int test_wc_CheckPrivateKey_RSA_pub_only(void)
{
    EXPECT_DECLS;
#if !defined(NO_RSA) && !defined(NO_ASN_CRYPT) && \
    !defined(NO_CHECK_PRIVATE_KEY) && \
    (defined(WOLFSSL_RSA_PUBLIC_ONLY) || defined(WOLFSSL_RSA_VERIFY_ONLY))
    /* With RSA public-only or verify-only, wc_CheckPrivateKey should return
     * NOT_COMPILED_IN for RSA key types since private key operations are not
     * available. */
    ExpectIntEQ(wc_CheckPrivateKey(server_key_der_2048,
        sizeof_server_key_der_2048, server_cert_der_2048,
        sizeof_server_cert_der_2048, RSAk, NULL),
        WC_NO_ERR_TRACE(NOT_COMPILED_IN));
#endif
    return EXPECT_RESULT();
}

#if defined(HAVE_PK_CALLBACKS) && !defined(WOLFSSL_NO_TLS12)
#if !defined(NO_FILESYSTEM) && !defined(NO_DH) && \
        !defined(NO_AES) && defined(HAVE_AES_CBC) && \
         defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
static int my_DhCallback(WOLFSSL* ssl, struct DhKey* key,
        const unsigned char* priv, unsigned int privSz,
        const unsigned char* pubKeyDer, unsigned int pubKeySz,
        unsigned char* out, unsigned int* outlen,
        void* ctx)
{
    int result;
    /* Test fail when context associated with WOLFSSL is NULL */
    if (ctx == NULL) {
        return -1;
    }

    (void)ssl;
    /* return 0 on success */
    PRIVATE_KEY_UNLOCK();
    result = wc_DhAgree(key, out, outlen, priv, privSz, pubKeyDer, pubKeySz);
    PRIVATE_KEY_LOCK();
    return result;
}

static int test_dh_ctx_setup(WOLFSSL_CTX* ctx) {
    EXPECT_DECLS;
    wolfSSL_CTX_SetDhAgreeCb(ctx, my_DhCallback);
#if defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128)
    ExpectIntEQ(wolfSSL_CTX_set_cipher_list(ctx, "DHE-RSA-AES128-SHA256"),
            WOLFSSL_SUCCESS);
#endif
#if defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
    ExpectIntEQ(wolfSSL_CTX_set_cipher_list(ctx, "DHE-RSA-AES256-SHA256"),
            WOLFSSL_SUCCESS);
#endif
    return EXPECT_RESULT();
}

static int test_dh_ssl_setup(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    static int dh_test_ctx = 1;
    int ret;

    wolfSSL_SetDhAgreeCtx(ssl, &dh_test_ctx);
    ExpectIntEQ(*((int*)wolfSSL_GetDhAgreeCtx(ssl)), dh_test_ctx);
    ret = wolfSSL_SetTmpDH_file(ssl, dhParamFile, WOLFSSL_FILETYPE_PEM);
    if (ret != WOLFSSL_SUCCESS && ret != WC_NO_ERR_TRACE(SIDE_ERROR)) {
        ExpectIntEQ(ret, WOLFSSL_SUCCESS);
    }
    return EXPECT_RESULT();
}

static int test_dh_ssl_setup_fail(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    int ret;

    wolfSSL_SetDhAgreeCtx(ssl, NULL);
    ExpectNull(wolfSSL_GetDhAgreeCtx(ssl));
    ret = wolfSSL_SetTmpDH_file(ssl, dhParamFile, WOLFSSL_FILETYPE_PEM);
    if (ret != WOLFSSL_SUCCESS && ret != WC_NO_ERR_TRACE(SIDE_ERROR)) {
        ExpectIntEQ(ret, WOLFSSL_SUCCESS);
    }
    return EXPECT_RESULT();
}
#endif

static int test_DhCallbacks(void)
{
    EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_DH) && \
        !defined(NO_AES) && defined(HAVE_AES_CBC) && \
         defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
    WOLFSSL_CTX *ctx = NULL;
    WOLFSSL     *ssl = NULL;
    int  test;
    test_ssl_cbf func_cb_client;
    test_ssl_cbf func_cb_server;

    /* Test that DH callback APIs work. */
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectIntEQ(wolfSSL_CTX_set_cipher_list(NULL, "NONE"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    wolfSSL_CTX_SetDhAgreeCb(ctx, &my_DhCallback);
    /* load client ca cert */
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0),
            WOLFSSL_SUCCESS);
    /* test with NULL arguments */
    wolfSSL_SetDhAgreeCtx(NULL, &test);
    ExpectNull(wolfSSL_GetDhAgreeCtx(NULL));
    /* test success case */
    test = 1;
    ExpectNotNull(ssl = wolfSSL_new(ctx));
    wolfSSL_SetDhAgreeCtx(ssl, &test);
    ExpectIntEQ(*((int*)wolfSSL_GetDhAgreeCtx(ssl)), test);
    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);


    XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
    XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));

    /* set callbacks to use DH functions */
    func_cb_client.ctx_ready = &test_dh_ctx_setup;
    func_cb_client.ssl_ready = &test_dh_ssl_setup;
    func_cb_client.method = wolfTLSv1_2_client_method;

    func_cb_server.ctx_ready = &test_dh_ctx_setup;
    func_cb_server.ssl_ready = &test_dh_ssl_setup;
    func_cb_server.method = wolfTLSv1_2_server_method;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
        &func_cb_server, NULL), TEST_SUCCESS);

    /* Test fail */
    XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
    XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));

    /* set callbacks to use DH functions */
    func_cb_client.ctx_ready = &test_dh_ctx_setup;
    func_cb_client.ssl_ready = &test_dh_ssl_setup_fail;
    func_cb_client.method = wolfTLSv1_2_client_method;

    func_cb_server.ctx_ready = &test_dh_ctx_setup;
    func_cb_server.ssl_ready = &test_dh_ssl_setup_fail;
    func_cb_server.method = wolfTLSv1_2_server_method;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
        &func_cb_server, NULL), -1001);
#endif
    return EXPECT_RESULT();
}
#endif /* HAVE_PK_CALLBACKS */


static int test_wolfSSL_X509_CRL(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_CRL)
    X509_CRL *crl = NULL;
    char pem[][100] = {
        "./certs/crl/crl.pem",
        "./certs/crl/crl2.pem",
        "./certs/crl/caEccCrl.pem",
        "./certs/crl/eccCliCRL.pem",
        "./certs/crl/eccSrvCRL.pem",
        ""
    };
#ifndef NO_BIO
    BIO *bio = NULL;
#endif

#ifdef HAVE_TEST_d2i_X509_CRL_fp
    char der[][100] = {
        "./certs/crl/crl.der",
        "./certs/crl/crl2.der",
        ""};
#endif

    XFILE fp = XBADFILE;
    int i;

    for (i = 0; pem[i][0] != '\0'; i++)
    {
        ExpectTrue((fp = XFOPEN(pem[i], "rb")) != XBADFILE);
        ExpectNotNull(crl = (X509_CRL *)PEM_read_X509_CRL(fp, (X509_CRL **)NULL,
            NULL, NULL));
        ExpectNotNull(crl);
        X509_CRL_free(crl);
        if (fp != XBADFILE) {
            XFCLOSE(fp);
            fp = XBADFILE;
        }
        ExpectTrue((fp = XFOPEN(pem[i], "rb")) != XBADFILE);
        ExpectNotNull((X509_CRL *)PEM_read_X509_CRL(fp, (X509_CRL **)&crl, NULL,
            NULL));
        if (EXPECT_FAIL()) {
            crl = NULL;
        }
        ExpectNotNull(crl);
        X509_CRL_free(crl);
        crl = NULL;
        if (fp != XBADFILE) {
            XFCLOSE(fp);
            fp = XBADFILE;
        }
    }

#ifndef NO_BIO
    for (i = 0; pem[i][0] != '\0'; i++)
    {
        ExpectNotNull(bio = BIO_new_file(pem[i], "rb"));
        ExpectNotNull(crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL));
        X509_CRL_free(crl);
        crl = NULL;
        BIO_free(bio);
        bio = NULL;
    }
#endif

#ifdef HAVE_TEST_d2i_X509_CRL_fp
    for (i = 0; der[i][0] != '\0'; i++) {
        ExpectTrue((fp = XFOPEN(der[i], "rb")) != XBADFILE);
        ExpectTrue((fp != XBADFILE));
        ExpectNotNull(crl = (X509_CRL *)d2i_X509_CRL_fp((fp, X509_CRL **)NULL));
        ExpectNotNull(crl);
        X509_CRL_free(crl);
        if (fp != XBADFILE) {
            XFCLOSE(fp);
            fp = XBADFILE;
        }
        fp = XFOPEN(der[i], "rb");
        ExpectTrue((fp != XBADFILE));
        ExpectNotNull((X509_CRL *)d2i_X509_CRL_fp(fp, (X509_CRL **)&crl));
        if (EXPECT_FAIL()) {
            crl = NULL;
        }
        ExpectNotNull(crl);
        X509_CRL_free(crl);
        crl = NULL;
        if (fp != XBADFILE) {
            XFCLOSE(fp);
            fp = XBADFILE;
        }
    }
#endif
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_d2i_X509_REQ(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_CERT_REQ) && !defined(NO_RSA) && !defined(NO_BIO) && \
    (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && \
    !defined(WOLFSSL_SP_MATH)
    /* ./certs/csr.signed.der, ./certs/csr.ext.der, and ./certs/csr.attr.der
     * were generated by libest
     * ./certs/csr.attr.der contains sample attributes
     * ./certs/csr.ext.der contains sample extensions */
    const char* csrFile = "./certs/csr.signed.der";
    const char* csrPopFile = "./certs/csr.attr.der";
    const char* csrExtFile = "./certs/csr.ext.der";
    /* ./certs/csr.dsa.pem is generated using
     * openssl req -newkey dsa:certs/dsaparams.pem \
     *     -keyout certs/csr.dsa.key.pem -keyform PEM -out certs/csr.dsa.pem \
     *     -outform PEM
     * with the passphrase "wolfSSL"
     */
#if !defined(NO_DSA) && !defined(HAVE_SELFTEST)
    const char* csrDsaFile = "./certs/csr.dsa.pem";
    XFILE f = XBADFILE;
#endif
    BIO* bio = NULL;
    X509* req = NULL;
    EVP_PKEY *pub_key = NULL;

    {
        ExpectNotNull(bio = BIO_new_file(csrFile, "rb"));
        ExpectNotNull(d2i_X509_REQ_bio(bio, &req));

        /*
         * Extract the public key from the CSR
         */
        ExpectNotNull(pub_key = X509_REQ_get_pubkey(req));

        /*
         * Verify the signature in the CSR
         */
        ExpectIntEQ(X509_REQ_verify(req, pub_key), 1);

        X509_free(req);
        req = NULL;
        BIO_free(bio);
        bio = NULL;
        EVP_PKEY_free(pub_key);
        pub_key = NULL;
    }
    {
        X509_REQ* empty = NULL;
#ifdef OPENSSL_ALL
        X509_ATTRIBUTE* attr = NULL;
        ASN1_TYPE *at = NULL;
#endif

        ExpectNotNull(empty = wolfSSL_X509_REQ_new());
        ExpectNotNull(bio = BIO_new_file(csrPopFile, "rb"));
        ExpectNotNull(d2i_X509_REQ_bio(bio, &req));

        /*
         * Extract the public key from the CSR
         */
        ExpectNotNull(pub_key = X509_REQ_get_pubkey(req));

        /*
         * Verify the signature in the CSR
         */
        ExpectIntEQ(X509_REQ_verify(req, pub_key), 1);

        ExpectIntEQ(wolfSSL_X509_REQ_get_attr_count(NULL), 0);
        ExpectIntEQ(wolfSSL_X509_REQ_get_attr_count(empty), 0);
#ifdef OPENSSL_ALL
        ExpectIntEQ(wolfSSL_X509_REQ_get_attr_count(req), 2);
#else
        ExpectIntEQ(wolfSSL_X509_REQ_get_attr_count(req), 0);
#endif
#ifdef OPENSSL_ALL
        /*
         * Obtain the challenge password from the CSR
         */
        ExpectIntEQ(X509_REQ_get_attr_by_NID(NULL, NID_pkcs9_challengePassword,
            -1), -1);
        ExpectIntEQ(X509_REQ_get_attr_by_NID(req, NID_pkcs9_challengePassword,
            -1), 1);
        ExpectNull(X509_REQ_get_attr(NULL, 3));
        ExpectNull(X509_REQ_get_attr(req, 3));
        ExpectNull(X509_REQ_get_attr(NULL, 0));
        ExpectNull(X509_REQ_get_attr(empty, 0));
        ExpectNotNull(attr = X509_REQ_get_attr(req, 1));
        ExpectNull(X509_ATTRIBUTE_get0_type(NULL, 1));
        ExpectNull(X509_ATTRIBUTE_get0_type(attr, 1));
        ExpectNull(X509_ATTRIBUTE_get0_type(NULL, 0));
        ExpectNotNull(at = X509_ATTRIBUTE_get0_type(attr, 0));
        ExpectNotNull(at->value.asn1_string);
        ExpectStrEQ((char*)ASN1_STRING_data(at->value.asn1_string),
            "2xIE+qqp/rhyTXP+");
        ExpectIntEQ(X509_get_ext_by_NID(req, NID_subject_alt_name, -1), -1);
#endif

        X509_free(req);
        req = NULL;
        BIO_free(bio);
        bio = NULL;
        EVP_PKEY_free(pub_key);
        pub_key = NULL;
        wolfSSL_X509_REQ_free(empty);
    }
    {
#ifdef OPENSSL_ALL
        X509_ATTRIBUTE* attr = NULL;
        ASN1_TYPE *at = NULL;
        STACK_OF(X509_EXTENSION) *exts = NULL;
#endif
        ExpectNotNull(bio = BIO_new_file(csrExtFile, "rb"));
        /* This CSR contains an Extension Request attribute so
         * we test extension parsing in a CSR attribute here. */
        ExpectNotNull(d2i_X509_REQ_bio(bio, &req));

        /*
         * Extract the public key from the CSR
         */
        ExpectNotNull(pub_key = X509_REQ_get_pubkey(req));

        /*
         * Verify the signature in the CSR
         */
        ExpectIntEQ(X509_REQ_verify(req, pub_key), 1);

#ifdef OPENSSL_ALL
        ExpectNotNull(exts = (STACK_OF(X509_EXTENSION)*)X509_REQ_get_extensions(
            req));
        ExpectIntEQ(sk_X509_EXTENSION_num(exts), 2);
        sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
        /*
         * Obtain the challenge password from the CSR
         */
        ExpectIntEQ(X509_REQ_get_attr_by_NID(req, NID_pkcs9_challengePassword,
            -1), 0);
        ExpectNotNull(attr = X509_REQ_get_attr(req, 0));
        ExpectNotNull(at = X509_ATTRIBUTE_get0_type(attr, 0));
        ExpectNotNull(at->value.asn1_string);
        ExpectStrEQ((char*)ASN1_STRING_data(at->value.asn1_string), "IGCu/xNL4/0/wOgo");
        ExpectIntGE(X509_get_ext_by_NID(req, NID_key_usage, -1), 0);
        ExpectIntGE(X509_get_ext_by_NID(req, NID_subject_alt_name, -1), 0);
#endif

        X509_free(req);
        req = NULL;
        BIO_free(bio);
        bio = NULL;
        EVP_PKEY_free(pub_key);
        pub_key = NULL;
    }
#if !defined(NO_DSA) && !defined(HAVE_SELFTEST)
    {
        ExpectNotNull(bio = BIO_new_file(csrDsaFile, "rb"));
        ExpectNotNull(PEM_read_bio_X509_REQ(bio, &req, NULL, NULL));

        /*
         * Extract the public key from the CSR
         */
        ExpectNotNull(pub_key = X509_REQ_get_pubkey(req));

        /*
         * Verify the signature in the CSR
         */
        ExpectIntEQ(X509_REQ_verify(req, pub_key), 1);

        X509_free(req);
        req = NULL;
        BIO_free(bio);

        /* Run the same test, but with a file pointer instead of a BIO.
         * (PEM_read_X509_REQ)*/
        ExpectTrue((f = XFOPEN(csrDsaFile, "rb")) != XBADFILE);
        ExpectNull(PEM_read_X509_REQ(XBADFILE, &req, NULL, NULL));
        if (EXPECT_SUCCESS())
            ExpectNotNull(PEM_read_X509_REQ(f, &req, NULL, NULL));
        else if (f != XBADFILE)
            XFCLOSE(f);
        ExpectIntEQ(X509_REQ_verify(req, pub_key), 1);

        X509_free(req);
        EVP_PKEY_free(pub_key);
    }
#endif /* !NO_DSA && !HAVE_SELFTEST */
#endif /* WOLFSSL_CERT_REQ && (OPENSSL_ALL || OPENSSL_EXTRA) */
    return EXPECT_RESULT();
}

static int test_wolfSSL_PEM_read(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_BIO)
    const char* filename = "./certs/server-keyEnc.pem";
    XFILE fp = XBADFILE;
    char* name = NULL;
    char* header = NULL;
    byte* data = NULL;
    long len;
    EVP_CIPHER_INFO cipher;
    WOLFSSL_BIO* bio = NULL;
    byte* fileData = NULL;
    size_t fileDataSz = 0;
    byte* out;

    ExpectNotNull(bio = BIO_new_file(filename, "rb"));
    ExpectIntEQ(PEM_read_bio(bio, NULL, &header, &data, &len), 0);
    ExpectIntEQ(PEM_read_bio(bio, &name, NULL, &data, &len), 0);
    ExpectIntEQ(PEM_read_bio(bio, &name, &header, NULL, &len), 0);
    ExpectIntEQ(PEM_read_bio(bio, &name, &header, &data, NULL), 0);

    ExpectIntEQ(PEM_read_bio(bio, &name, &header, &data, &len), 1);
    ExpectIntEQ(XSTRNCMP(name, "RSA PRIVATE KEY", 15), 0);
    ExpectIntGT(XSTRLEN(header), 0);
    ExpectIntGT(len, 0);
    XFREE(name, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    name = NULL;
    XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    header = NULL;
    XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    data = NULL;
    BIO_free(bio);
    bio = NULL;

    ExpectTrue((fp = XFOPEN(filename, "rb")) != XBADFILE);

    /* Fail cases. */
    ExpectIntEQ(PEM_read(fp, NULL, &header, &data, &len), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(PEM_read(fp, &name, NULL, &data, &len), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(PEM_read(fp, &name, &header, NULL, &len), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(PEM_read(fp, &name, &header, &data, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    ExpectIntEQ(PEM_read(fp, &name, &header, &data, &len), WOLFSSL_SUCCESS);

    ExpectIntEQ(XSTRNCMP(name, "RSA PRIVATE KEY", 15), 0);
    ExpectIntGT(XSTRLEN(header), 0);
    ExpectIntGT(len, 0);

    ExpectIntEQ(XFSEEK(fp, 0, SEEK_END), 0);
    ExpectIntGT((fileDataSz = XFTELL(fp)), 0);
    ExpectIntEQ(XFSEEK(fp, 0, SEEK_SET), 0);
    ExpectNotNull(fileData = (unsigned char*)XMALLOC(fileDataSz, NULL,
        DYNAMIC_TYPE_TMP_BUFFER));
    ExpectIntEQ(XFREAD(fileData, 1, fileDataSz, fp), fileDataSz);
    if (fp != XBADFILE) {
        XFCLOSE(fp);
        fp = XBADFILE;
    }

    ExpectNotNull(bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()));

    /* Fail cases. */
    ExpectIntEQ(PEM_write_bio(NULL, name, header, data, len), 0);
    ExpectIntEQ(PEM_write_bio(bio, NULL, header, data, len), 0);
    ExpectIntEQ(PEM_write_bio(bio, name, NULL, data, len), 0);
    ExpectIntEQ(PEM_write_bio(bio, name, header, NULL, len), 0);

    ExpectIntEQ(PEM_write_bio(bio, name, header, data, len), fileDataSz);
    ExpectIntEQ(wolfSSL_BIO_get_mem_data(bio, &out), fileDataSz);
    ExpectIntEQ(XMEMCMP(out, fileData, fileDataSz), 0);

    /* Fail cases. */
    ExpectIntEQ(PEM_write(XBADFILE, name, header, data, len), 0);
    ExpectIntEQ(PEM_write(stderr, NULL, header, data, len), 0);
    ExpectIntEQ(PEM_write(stderr, name, NULL, data, len), 0);
    ExpectIntEQ(PEM_write(stderr, name, header, NULL, len), 0);
    /* Pass case */
    ExpectIntEQ(PEM_write(stderr, name, header, data, len), fileDataSz);

    XFREE(name, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    name = NULL;
    XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    header = NULL;
    XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    data = NULL;
    /* Read out of a fixed buffer BIO - forces malloc in PEM_read_bio. */
    ExpectIntEQ(PEM_read_bio(bio, &name, &header, &data, &len), 1);
    ExpectIntEQ(XSTRNCMP(name, "RSA PRIVATE KEY", 15), 0);
    ExpectIntGT(XSTRLEN(header), 0);
    ExpectIntGT(len, 0);

    /* Fail cases. */
    ExpectIntEQ(PEM_get_EVP_CIPHER_INFO(NULL, &cipher), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(PEM_get_EVP_CIPHER_INFO(header, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(PEM_get_EVP_CIPHER_INFO((char*)"", &cipher), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

#ifndef NO_DES3
    ExpectIntEQ(PEM_get_EVP_CIPHER_INFO(header, &cipher), WOLFSSL_SUCCESS);
#endif

    /* Fail cases. */
    ExpectIntEQ(PEM_do_header(NULL, data, &len, PasswordCallBack,
        (void*)"yassl123"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(PEM_do_header(&cipher, NULL, &len, PasswordCallBack,
        (void*)"yassl123"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(PEM_do_header(&cipher, data, NULL, PasswordCallBack,
        (void*)"yassl123"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(PEM_do_header(&cipher, data, &len, NULL,
        (void*)"yassl123"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    ExpectIntEQ(PEM_do_header(&cipher, data, &len, NoPasswordCallBack,
                              (void*)"yassl123"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#if !defined(NO_DES3) && !defined(NO_MD5)
    ExpectIntEQ(PEM_do_header(&cipher, data, &len, PasswordCallBack,
                              (void*)"yassl123"), WOLFSSL_SUCCESS);
#else
    ExpectIntEQ(PEM_do_header(&cipher, data, &len, PasswordCallBack,
                              (void*)"yassl123"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif

    BIO_free(bio);
    bio = NULL;
    XFREE(fileData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    fileData = NULL;
    XFREE(name, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER);

    name = NULL;
    header = NULL;
    data = NULL;
    ExpectTrue((fp = XFOPEN(svrKeyFile, "rb")) != XBADFILE);
    ExpectIntEQ(PEM_read(fp, &name, &header, &data, &len), WOLFSSL_SUCCESS);
    ExpectIntEQ(XSTRNCMP(name, "RSA PRIVATE KEY", 15), 0);
    ExpectIntEQ(XSTRLEN(header), 0);
    ExpectIntGT(len, 0);

    ExpectIntEQ(XFSEEK(fp, 0, SEEK_END), 0);
    ExpectIntGT((fileDataSz = XFTELL(fp)), 0);
    ExpectIntEQ(XFSEEK(fp, 0, SEEK_SET), 0);
    ExpectNotNull(fileData = (unsigned char*)XMALLOC(fileDataSz, NULL,
        DYNAMIC_TYPE_TMP_BUFFER));
    ExpectIntEQ(XFREAD(fileData, 1, fileDataSz, fp), fileDataSz);
    if (fp != XBADFILE)
        XFCLOSE(fp);

    ExpectNotNull(bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()));
    ExpectIntEQ(PEM_write_bio(bio, name, header, data, len), fileDataSz);
    ExpectIntEQ(wolfSSL_BIO_get_mem_data(bio, &out), fileDataSz);
    ExpectIntEQ(XMEMCMP(out, fileData, fileDataSz), 0);

    BIO_free(bio);
    XFREE(fileData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(name, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_dup_CA_list(void)
{
    int res = TEST_SKIPPED;
#if defined(OPENSSL_ALL)
    EXPECT_DECLS;
    STACK_OF(X509_NAME) *originalStack = NULL;
    STACK_OF(X509_NAME) *copyStack = NULL;
    int originalCount = 0;
    int copyCount = 0;
    X509_NAME *name = NULL;
    int i;

    originalStack = sk_X509_NAME_new_null();
    ExpectNotNull(originalStack);

    for (i = 0; i < 3; i++) {
        name = X509_NAME_new();
        ExpectNotNull(name);
        ExpectIntEQ(sk_X509_NAME_push(originalStack, name), i+1);
        if (EXPECT_FAIL()) {
            X509_NAME_free(name);
        }
    }

    copyStack = SSL_dup_CA_list(originalStack);
    ExpectNotNull(copyStack);
    ExpectIntEQ(sk_X509_NAME_num(NULL), BAD_FUNC_ARG);
    originalCount = sk_X509_NAME_num(originalStack);
    copyCount = sk_X509_NAME_num(copyStack);

    ExpectIntEQ(originalCount, copyCount);
    sk_X509_NAME_pop_free(originalStack, X509_NAME_free);
    sk_X509_NAME_pop_free(copyStack, X509_NAME_free);

    originalStack = NULL;
    copyStack = NULL;

    originalStack = sk_X509_NAME_new_null();
    ExpectNull(sk_X509_NAME_pop(NULL));
    ExpectNull(sk_X509_NAME_pop(originalStack));
    for (i = 0; i < 3; i++) {
        name = X509_NAME_new();
        ExpectNotNull(name);
        ExpectIntEQ(sk_X509_NAME_push(originalStack, name), i+1);
        if (EXPECT_FAIL()) {
            X509_NAME_free(name);
        }
        name = NULL;
    }
    ExpectNotNull(name = sk_X509_NAME_pop(originalStack));
    X509_NAME_free(name);
    wolfSSL_sk_X509_NAME_set_cmp_func(NULL, NULL);
    wolfSSL_sk_X509_NAME_set_cmp_func(originalStack, NULL);
    wolfSSL_sk_X509_NAME_pop_free(originalStack, X509_NAME_free);

    res = EXPECT_RESULT();
#endif /* OPENSSL_ALL */
    return res;
}

static int test_ForceZero(void)
{
    EXPECT_DECLS;
    unsigned char data[32];
    unsigned int i, j, len;

    /* Test case with 0 length */
    ForceZero(data, 0);

    /* Test ForceZero */
    for (i = 0; i < sizeof(data); i++) {
        for (len = 1; len < sizeof(data) - i; len++) {
            for (j = 0; j < sizeof(data); j++)
                data[j] = ((unsigned char)j + 1);

            ForceZero(data + i, len);

            for (j = 0; j < sizeof(data); j++) {
                if (j < i || j >= i + len) {
                    ExpectIntNE(data[j], 0x00);
                }
                else {
                    ExpectIntEQ(data[j], 0x00);
                }
            }
        }
    }

    return EXPECT_RESULT();
}

#ifndef NO_BIO

static int test_wolfSSL_X509_print(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && \
   !defined(NO_RSA) && defined(XSNPRINTF) && !defined(WC_DISABLE_RADIX_ZERO_PAD)
    X509 *x509 = NULL;
    BIO *bio = NULL;
#if defined(OPENSSL_ALL) && !defined(NO_WOLFSSL_DIR)
    const X509_ALGOR *cert_sig_alg = NULL;
#endif

    ExpectNotNull(x509 = X509_load_certificate_file(svrCertFile,
        WOLFSSL_FILETYPE_PEM));

    /* print to memory */
    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntEQ(X509_print(bio, x509), SSL_SUCCESS);

#if defined(OPENSSL_ALL) || defined(WOLFSSL_IP_ALT_NAME)
  #if defined(WC_DISABLE_RADIX_ZERO_PAD)
     /* Will print IP address subject alt name. */
     ExpectIntEQ(BIO_get_mem_data(bio, NULL), 3349);
  #elif defined(NO_ASN_TIME)
      /* Will print IP address subject alt name but not Validity. */
     ExpectIntEQ(BIO_get_mem_data(bio, NULL), 3235);
  #else
      /* Will print IP address subject alt name. */
     ExpectIntEQ(BIO_get_mem_data(bio, NULL), 3350);
  #endif
#elif defined(IGNORE_NAME_CONSTRAINTS)
    /* DecodeGeneralName skips iPAddress entries when name constraints
     * are disabled, so the IP SAN never reaches the print path. */
  #if defined(NO_ASN_TIME)
    ExpectIntEQ(BIO_get_mem_data(bio, NULL), 3213);
  #else
    ExpectIntEQ(BIO_get_mem_data(bio, NULL), 3328);
  #endif
#elif defined(NO_ASN_TIME)
    /* With NO_ASN_TIME defined, X509_print skips printing Validity.
     * iPAddress SAN now always parsed; prints as
     * "IP Address:<unavailable>" (+26 bytes) without
     * WOLFSSL_IP_ALT_NAME. */
    ExpectIntEQ(BIO_get_mem_data(bio, NULL), 3239);
#else
    /* iPAddress SAN now always parsed; prints as
     * "IP Address:<unavailable>" (+26 bytes) without
     * WOLFSSL_IP_ALT_NAME. */
    ExpectIntEQ(BIO_get_mem_data(bio, NULL), 3354);
#endif
    BIO_free(bio);
    bio = NULL;

    ExpectNotNull(bio = BIO_new_fd(STDERR_FILENO, BIO_NOCLOSE));

#if defined(OPENSSL_ALL) && !defined(NO_WOLFSSL_DIR)
    /* Print signature */
    ExpectNotNull(cert_sig_alg = X509_get0_tbs_sigalg(x509));
    ExpectIntEQ(X509_signature_print(bio, cert_sig_alg, NULL), SSL_SUCCESS);
#endif

    /* print to stderr */
#if !defined(NO_WOLFSSL_DIR)
    ExpectIntEQ(X509_print(bio, x509), SSL_SUCCESS);
#endif
    /* print again */
    ExpectIntEQ(X509_print_fp(stderr, x509), SSL_SUCCESS);

    X509_free(x509);
    BIO_free(bio);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_X509_CRL_print(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && defined(HAVE_CRL) && \
    !defined(NO_RSA) && !defined(NO_FILESYSTEM) && defined(XSNPRINTF)
    X509_CRL* crl = NULL;
    BIO *bio = NULL;
    XFILE fp = XBADFILE;

    ExpectTrue((fp = XFOPEN("./certs/crl/crl.pem", "rb")) != XBADFILE);
    ExpectNotNull(crl = (X509_CRL*)PEM_read_X509_CRL(fp, (X509_CRL **)NULL,
        NULL, NULL));
    if (fp != XBADFILE)
        XFCLOSE(fp);

    ExpectNotNull(bio = BIO_new(BIO_s_mem()));
    ExpectIntEQ(X509_CRL_print(bio, crl), SSL_SUCCESS);

    X509_CRL_free(crl);
    BIO_free(bio);
#endif
    return EXPECT_RESULT();
}

#endif /* !NO_BIO */

#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
    defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && \
    !defined(NO_ASN_TIME)
static int test_openssl_make_self_signed_certificate(EVP_PKEY* pkey,
        int expectedDerSz)
{
    EXPECT_DECLS;
    X509* x509 = NULL;
    BIGNUM* serial_number = NULL;
    X509_NAME* name = NULL;
    time_t epoch_off = 0;
    ASN1_INTEGER* asn1_serial_number = NULL;
    long not_before, not_after;
    int derSz;

    ExpectNotNull(x509 = X509_new());

    ExpectIntNE(X509_set_pubkey(x509, pkey), 0);

    ExpectNotNull(serial_number = BN_new());
    ExpectIntNE(BN_pseudo_rand(serial_number, 64, 0, 0), 0);
    ExpectNotNull(asn1_serial_number = X509_get_serialNumber(x509));
    ExpectNotNull(BN_to_ASN1_INTEGER(serial_number, asn1_serial_number));

    /* version 3 */
    ExpectIntNE(X509_set_version(x509, 2L), 0);

    ExpectNotNull(name = X509_NAME_new());

    ExpectIntNE(X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_UTF8,
        (unsigned char*)"www.wolfssl.com", -1, -1, 0), 0);
    ExpectIntNE(X509_NAME_add_entry_by_NID(name, NID_pkcs9_contentType,
                MBSTRING_UTF8,(unsigned char*)"Server", -1, -1, 0), 0);

    ExpectIntNE(X509_set_subject_name(x509, name), 0);
    ExpectIntNE(X509_set_issuer_name(x509, name), 0);

    not_before = (long)wc_Time(NULL);
    not_after = not_before + (365 * 24 * 60 * 60);
    ExpectNotNull(X509_time_adj(X509_get_notBefore(x509), not_before,
        &epoch_off));
    ExpectNotNull(X509_time_adj(X509_get_notAfter(x509), not_after,
        &epoch_off));

    ExpectIntNE(X509_sign(x509, pkey, EVP_sha256()), 0);

    ExpectNotNull(wolfSSL_X509_get_der(x509, &derSz));
    ExpectIntGE(derSz, expectedDerSz);

    BN_free(serial_number);
    X509_NAME_free(name);
    X509_free(x509);

    return EXPECT_RESULT();
}
#endif

static int test_openssl_generate_key_and_cert(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    int expectedDerSz;
    EVP_PKEY* pkey = NULL;
#ifdef HAVE_ECC
    EC_KEY* ec_key = NULL;
#endif
#if !defined(NO_RSA)
    int key_length = 2048;
    BIGNUM* exponent = NULL;
    RSA* rsa = NULL;

    ExpectNotNull(pkey = EVP_PKEY_new());
    ExpectNotNull(exponent = BN_new());
    ExpectNotNull(rsa = RSA_new());

    ExpectIntNE(BN_set_word(exponent, WC_RSA_EXPONENT), 0);
#ifndef WOLFSSL_KEY_GEN
    ExpectIntEQ(RSA_generate_key_ex(rsa, key_length, exponent, NULL), 0);

    #if defined(USE_CERT_BUFFERS_1024)
    ExpectIntNE(wolfSSL_RSA_LoadDer_ex(rsa, server_key_der_1024,
        sizeof_server_key_der_1024, WOLFSSL_RSA_LOAD_PRIVATE), 0);
    key_length = 1024;
    #elif defined(USE_CERT_BUFFERS_2048)
    ExpectIntNE(wolfSSL_RSA_LoadDer_ex(rsa, server_key_der_2048,
        sizeof_server_key_der_2048, WOLFSSL_RSA_LOAD_PRIVATE), 0);
    #else
    RSA_free(rsa);
    rsa = NULL;
    #endif
#else
    ExpectIntEQ(RSA_generate_key_ex(NULL, key_length, exponent, NULL), 0);
    ExpectIntEQ(RSA_generate_key_ex(rsa, 0, exponent, NULL), 0);
    ExpectIntEQ(RSA_generate_key_ex(rsa, key_length, NULL, NULL), 0);
    ExpectIntNE(RSA_generate_key_ex(rsa, key_length, exponent, NULL), 0);
#endif

    if (rsa) {
        ExpectIntNE(EVP_PKEY_assign_RSA(pkey, rsa), 0);
        if (EXPECT_FAIL()) {
            RSA_free(rsa);
        }

    #if !defined(NO_CERTS) && defined(WOLFSSL_CERT_GEN) && \
            defined(WOLFSSL_CERT_REQ) && !defined(NO_ASN_TIME)
        expectedDerSz = 743;
        ExpectIntEQ(test_openssl_make_self_signed_certificate(pkey,
                    expectedDerSz), TEST_SUCCESS);
    #endif
    }

    EVP_PKEY_free(pkey);
    pkey = NULL;
    BN_free(exponent);
#endif /* !NO_RSA */

#ifdef HAVE_ECC
    ExpectNotNull(pkey = EVP_PKEY_new());
    ExpectNotNull(ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));

#ifndef NO_WOLFSSL_STUB
    EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE);
#endif

    ExpectIntNE(EC_KEY_generate_key(ec_key), 0);
    ExpectIntNE(EVP_PKEY_assign_EC_KEY(pkey, ec_key), 0);
    if (EXPECT_FAIL()) {
        EC_KEY_free(ec_key);
    }

#if !defined(NO_CERTS) && defined(WOLFSSL_CERT_GEN) && \
        defined(WOLFSSL_CERT_REQ) && !defined(NO_ASN_TIME)
    expectedDerSz = 344;
    ExpectIntEQ(test_openssl_make_self_signed_certificate(pkey, expectedDerSz),
                TEST_SUCCESS);
#endif

    EVP_PKEY_free(pkey);
#endif /* HAVE_ECC */
    (void)pkey;
    (void)expectedDerSz;
#endif /* OPENSSL_EXTRA */

    return EXPECT_RESULT();
}

static int test_stubs_are_stubs(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_STUB) && \
    !defined(NO_TLS) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL_CTX* ctxN = NULL;
  #ifndef NO_WOLFSSL_CLIENT
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
  #elif !defined(NO_WOLFSSL_SERVER)
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
  #endif

    #define CHECKZERO_RET(x, y, z) ExpectIntEQ((int) x(y), 0); \
                     ExpectIntEQ((int) x(z), 0)
    /* test logic, all stubs return same result regardless of ctx being NULL
     * as there are no sanity checks, it's just a stub! If at some
     * point a stub is not a stub it should begin to return BAD_FUNC_ARG
     * if invalid inputs are supplied. Test calling both
     * with and without valid inputs, if a stub functionality remains unchanged.
     */
    CHECKZERO_RET(wolfSSL_CTX_sess_accept, ctx, ctxN);
    CHECKZERO_RET(wolfSSL_CTX_sess_connect, ctx, ctxN);
    CHECKZERO_RET(wolfSSL_CTX_sess_accept_good, ctx, ctxN);
    CHECKZERO_RET(wolfSSL_CTX_sess_connect_good, ctx, ctxN);
    CHECKZERO_RET(wolfSSL_CTX_sess_accept_renegotiate, ctx, ctxN);
    CHECKZERO_RET(wolfSSL_CTX_sess_connect_renegotiate, ctx, ctxN);
    CHECKZERO_RET(wolfSSL_CTX_sess_hits, ctx, ctxN);
    CHECKZERO_RET(wolfSSL_CTX_sess_cb_hits, ctx, ctxN);
    CHECKZERO_RET(wolfSSL_CTX_sess_cache_full, ctx, ctxN);
    CHECKZERO_RET(wolfSSL_CTX_sess_misses, ctx, ctxN);
    CHECKZERO_RET(wolfSSL_CTX_sess_timeouts, ctx, ctxN);

    /* when implemented this should take WOLFSSL object instead, right now
     * always returns 0 */
    ExpectPtrEq(SSL_get_current_expansion(NULL), NULL);

    wolfSSL_CTX_free(ctx);
    ctx = NULL;

    ExpectStrEQ(SSL_COMP_get_name(NULL), "not supported");
    ExpectPtrEq(SSL_get_current_expansion(NULL), NULL);
#endif /* OPENSSL_EXTRA && !NO_WOLFSSL_STUB && (!NO_WOLFSSL_CLIENT ||
        * !NO_WOLFSSL_SERVER) */
    return EXPECT_RESULT();
}

static int test_CONF_modules_xxx(void)
{
    int res = TEST_SKIPPED;
#if defined(OPENSSL_EXTRA)
    CONF_modules_free();

    CONF_modules_unload(0);
    CONF_modules_unload(1);
    CONF_modules_unload(-1);

    res = TEST_SUCCESS;
#endif /* OPENSSL_EXTRA */
    return res;
}
static int test_CRYPTO_set_dynlock_xxx(void)
{
    int res = TEST_SKIPPED;
#if defined(OPENSSL_EXTRA)
    CRYPTO_set_dynlock_create_callback(
        (struct CRYPTO_dynlock_value *(*)(const char*, int))NULL);

    CRYPTO_set_dynlock_create_callback(
        (struct CRYPTO_dynlock_value *(*)(const char*, int))1);

    CRYPTO_set_dynlock_destroy_callback(
        (void (*)(struct CRYPTO_dynlock_value*, const char*, int))NULL);

    CRYPTO_set_dynlock_destroy_callback(
        (void (*)(struct CRYPTO_dynlock_value*, const char*, int))1);

    CRYPTO_set_dynlock_lock_callback(
        (void (*)(int, struct CRYPTO_dynlock_value *, const char*, int))NULL);

    CRYPTO_set_dynlock_lock_callback(
        (void (*)(int, struct CRYPTO_dynlock_value *, const char*, int))1);

    res = TEST_SUCCESS;
#endif /* OPENSSL_EXTRA */
    return res;
}
static int test_CRYPTO_THREADID_xxx(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    CRYPTO_THREADID_current((CRYPTO_THREADID*)NULL);
    CRYPTO_THREADID_current((CRYPTO_THREADID*)1);
    ExpectIntEQ(CRYPTO_THREADID_hash((const CRYPTO_THREADID*)NULL), 0);
#endif /* OPENSSL_EXTRA */
    return EXPECT_RESULT();
}
static int test_ENGINE_cleanup(void)
{
    int res = TEST_SKIPPED;
#if defined(OPENSSL_EXTRA)
    ENGINE_cleanup();

    res = TEST_SUCCESS;
#endif /* OPENSSL_EXTRA */
    return res;
}

static int test_wolfSSL_CTX_LoadCRL(void)
{
    EXPECT_DECLS;
#if defined(HAVE_CRL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \
    (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
    WOLFSSL_CERT_MANAGER* cm = NULL;
    const char* issuerCert = "./certs/client-cert.pem";
    const char* validFilePath = "./certs/crl/cliCrl.pem";
    int pemType = WOLFSSL_FILETYPE_PEM;
#ifndef NO_TLS
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;
    const char* badPath = "dummypath";
    const char* validPath = "./certs/crl";
    int derType = WOLFSSL_FILETYPE_ASN1;
#ifdef HAVE_CRL_MONITOR
    int monitor = WOLFSSL_CRL_MONITOR;
#else
    int monitor = 0;
#endif

    #define FAIL_T1(x, y, z, p, d) ExpectIntEQ((int) x(y, z, p, d), \
                                       WC_NO_ERR_TRACE(BAD_FUNC_ARG))
    #define FAIL_T2(x, y, z, p, d) ExpectIntEQ((int) x(y, z, p, d), \
                                    WC_NO_ERR_TRACE(NOT_COMPILED_IN))
    #define SUCC_T(x, y, z, p, d) ExpectIntEQ((int) x(y, z, p, d), \
                                                WOLFSSL_SUCCESS)
#ifndef NO_WOLFSSL_CLIENT
    #define NEW_CTX(ctx) ExpectNotNull( \
            (ctx) = wolfSSL_CTX_new(wolfSSLv23_client_method()))
#elif !defined(NO_WOLFSSL_SERVER)
    #define NEW_CTX(ctx) ExpectNotNull( \
            (ctx) = wolfSSL_CTX_new(wolfSSLv23_server_method()))
#else
    #define NEW_CTX(ctx) return
#endif

    FAIL_T1(wolfSSL_CTX_LoadCRL, ctx, validPath, pemType, monitor);

    NEW_CTX(ctx);

#ifndef HAVE_CRL_MONITOR
    FAIL_T2(wolfSSL_CTX_LoadCRL, ctx, validPath, pemType, WOLFSSL_CRL_MONITOR);
    wolfSSL_CTX_free(ctx);
    NEW_CTX(ctx);
#endif

    SUCC_T (wolfSSL_CTX_LoadCRL, ctx, validPath, pemType, monitor);
    SUCC_T (wolfSSL_CTX_LoadCRL, ctx, badPath, pemType, monitor);
    SUCC_T (wolfSSL_CTX_LoadCRL, ctx, badPath, derType, monitor);

    wolfSSL_CTX_free(ctx);
    ctx = NULL;

    NEW_CTX(ctx);
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx, issuerCert, NULL),
            WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_LoadCRLFile(ctx, validFilePath, pemType), WOLFSSL_SUCCESS);
    wolfSSL_CTX_free(ctx);
    ctx = NULL;

    NEW_CTX(ctx);
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx, issuerCert, NULL),
            WOLFSSL_SUCCESS);
    ExpectNotNull(ssl = wolfSSL_new(ctx));
    ExpectIntEQ(wolfSSL_LoadCRLFile(ssl, validFilePath, pemType), WOLFSSL_SUCCESS);
    wolfSSL_free(ssl);
    ssl = NULL;
    wolfSSL_CTX_free(ctx);
    ctx = NULL;
#endif /* !NO_TLS */

    ExpectNotNull(cm = wolfSSL_CertManagerNew());
    ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, issuerCert, NULL),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CertManagerLoadCRLFile(cm, validFilePath, pemType),
        WOLFSSL_SUCCESS);
    wolfSSL_CertManagerFree(cm);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_LoadCRL_largeCRLnum(void)
{
    EXPECT_DECLS;
#if defined(HAVE_CRL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \
    defined(HAVE_CRL_UPDATE_CB)
    WOLFSSL_CERT_MANAGER* cm = NULL;
    const char* caCert     =  "./certs/ca-cert.pem";
    const char* crl_lrgcrlnum = "./certs/crl/extra-crls/large_crlnum.pem";
    const char* crl_lrgcrlnum2 = "./certs/crl/extra-crls/large_crlnum2.pem";
    const char* crl_57oct = "./certs/crl/extra-crls/crlnum_57oct.pem";
    const char* crl_64oct = "./certs/crl/extra-crls/crlnum_64oct.pem";
    const char* exp_crlnum = "D8AFADA7F08B38E6178BD0E5CD7B0DF80071BA74";
    byte *crlLrgCrlNumBuff = NULL;
    word32  crlLrgCrlNumSz;
    CrlInfo crlInfo;
    XFILE f;
    word32 sz;

    cm = wolfSSL_CertManagerNew();
    ExpectNotNull(cm);
    ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, caCert, NULL),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CertManagerLoadCRLFile(cm, crl_lrgcrlnum,
                                                WOLFSSL_FILETYPE_PEM),
        WOLFSSL_SUCCESS);

    AssertTrue((f = XFOPEN(crl_lrgcrlnum, "rb")) != XBADFILE);
    AssertTrue(XFSEEK(f, 0, XSEEK_END) == 0);
    AssertIntGE(sz = (word32) XFTELL(f), 1);
    AssertTrue(XFSEEK(f, 0, XSEEK_SET) == 0);
    AssertTrue( \
        (crlLrgCrlNumBuff =
            (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)) != NULL);
    AssertTrue(XFREAD(crlLrgCrlNumBuff, 1, sz, f) == sz);
    XFCLOSE(f);
    crlLrgCrlNumSz = sz;

    AssertIntEQ(wolfSSL_CertManagerGetCRLInfo(
        cm, &crlInfo, crlLrgCrlNumBuff, crlLrgCrlNumSz, WOLFSSL_FILETYPE_PEM),
        WOLFSSL_SUCCESS);
    AssertIntEQ(XMEMCMP(
        crlInfo.crlNumber, exp_crlnum, XSTRLEN(exp_crlnum)), 0);
    /* Expect to fail loading CRL because of >21 octets CRL number */
    ExpectIntEQ(wolfSSL_CertManagerLoadCRLFile(cm, crl_lrgcrlnum2,
                                                WOLFSSL_FILETYPE_PEM),
        ASN_PARSE_E);

    /* Expect to fail loading CRL because of >57 octets CRL number */
    ExpectIntEQ(wolfSSL_CertManagerLoadCRLFile(cm, crl_57oct,
                                                WOLFSSL_FILETYPE_PEM),
        ASN_PARSE_E);
    /* Expect to fail loading CRL because of >64 octets CRL number */
    ExpectIntEQ(wolfSSL_CertManagerLoadCRLFile(cm, crl_64oct,
                                                WOLFSSL_FILETYPE_PEM),
        ASN_PARSE_E);

    XFREE(crlLrgCrlNumBuff, NULL, DYNAMIC_TYPE_FILE);
    wolfSSL_CertManagerFree(cm);
#endif
    return EXPECT_RESULT();

}

#if defined(HAVE_CRL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \
    defined(HAVE_CRL_UPDATE_CB)
int crlUpdateTestStatus = 0;
WOLFSSL_CERT_MANAGER* updateCrlTestCm = NULL;
static void updateCrlCb(CrlInfo* old, CrlInfo* cnew)
{
    const char* crl1 = "./certs/crl/crl.pem";
    const char* crlRevoked = "./certs/crl/crl.revoked";
    byte *crl1Buff = NULL;
    word32 crl1Sz;
    byte *crlRevBuff = NULL;
    word32  crlRevSz;
    WOLFSSL_CERT_MANAGER* cm = updateCrlTestCm;
    XFILE f;
    word32 sz;
    CrlInfo crl1Info;
    CrlInfo crlRevInfo;

    crlUpdateTestStatus = 0;
    if (old == NULL || cnew == NULL) {
        return;
    }

    AssertTrue((f = XFOPEN(crl1, "rb")) != XBADFILE);
    AssertTrue(XFSEEK(f, 0, XSEEK_END) == 0);
    AssertIntGE(sz = (word32) XFTELL(f), 1);
    AssertTrue(XFSEEK(f, 0, XSEEK_SET) == 0);
    AssertTrue( \
        (crl1Buff = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)) != NULL);
    AssertTrue(XFREAD(crl1Buff, 1, sz, f) == sz);
    XFCLOSE(f);
    crl1Sz = sz;

    AssertTrue((f = XFOPEN(crlRevoked, "rb")) != XBADFILE);
    AssertTrue(XFSEEK(f, 0, XSEEK_END) == 0);
    AssertIntGE(sz = (word32) XFTELL(f), 1);
    AssertTrue(XFSEEK(f, 0, XSEEK_SET) == 0);
    AssertTrue( \
        (crlRevBuff = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)) != NULL);
    AssertTrue(XFREAD(crlRevBuff, 1, sz, f) == sz);
    XFCLOSE(f);
    crlRevSz = sz;

    AssertIntEQ(wolfSSL_CertManagerGetCRLInfo(
        cm, &crl1Info, crl1Buff, crl1Sz, WOLFSSL_FILETYPE_PEM),
        WOLFSSL_SUCCESS);
    AssertIntEQ(wolfSSL_CertManagerGetCRLInfo(
        cm, &crlRevInfo, crlRevBuff, crlRevSz, WOLFSSL_FILETYPE_PEM),
        WOLFSSL_SUCCESS);

    /* Old entry being replaced should match crl1 */
    AssertIntEQ(crl1Info.issuerHashLen,  old->issuerHashLen);
    AssertIntEQ(crl1Info.lastDateMaxLen, old->lastDateMaxLen);
    AssertIntEQ(crl1Info.lastDateFormat, old->lastDateFormat);
    AssertIntEQ(crl1Info.nextDateMaxLen, old->nextDateMaxLen);
    AssertIntEQ(crl1Info.nextDateFormat, old->nextDateFormat);
    AssertIntEQ(XMEMCMP(
        crl1Info.crlNumber, old->crlNumber, sizeof(old->crlNumber)), 0);
    AssertIntEQ(XMEMCMP(
        crl1Info.issuerHash, old->issuerHash, old->issuerHashLen), 0);
    AssertIntEQ(XMEMCMP(
        crl1Info.lastDate, old->lastDate, old->lastDateMaxLen), 0);
    AssertIntEQ(XMEMCMP(
        crl1Info.nextDate, old->nextDate, old->nextDateMaxLen), 0);

    /* Newer entry should match crl revoked */
    AssertIntEQ(crlRevInfo.issuerHashLen,  cnew->issuerHashLen);
    AssertIntEQ(crlRevInfo.lastDateMaxLen, cnew->lastDateMaxLen);
    AssertIntEQ(crlRevInfo.lastDateFormat, cnew->lastDateFormat);
    AssertIntEQ(crlRevInfo.nextDateMaxLen, cnew->nextDateMaxLen);
    AssertIntEQ(crlRevInfo.nextDateFormat, cnew->nextDateFormat);
    AssertIntEQ(XMEMCMP(
        crlRevInfo.crlNumber, cnew->crlNumber, sizeof(cnew->crlNumber)), 0);
    AssertIntEQ(XMEMCMP(
        crlRevInfo.issuerHash, cnew->issuerHash, cnew->issuerHashLen), 0);
    AssertIntEQ(XMEMCMP(
        crlRevInfo.lastDate, cnew->lastDate, cnew->lastDateMaxLen), 0);
    AssertIntEQ(XMEMCMP(
        crlRevInfo.nextDate, cnew->nextDate, cnew->nextDateMaxLen), 0);

    XFREE(crl1Buff, NULL, DYNAMIC_TYPE_FILE);
    XFREE(crlRevBuff, NULL, DYNAMIC_TYPE_FILE);
    crlUpdateTestStatus = 1;
}
#endif

static int test_wolfSSL_crl_update_cb(void)
{
    EXPECT_DECLS;
#if defined(HAVE_CRL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \
    defined(HAVE_CRL_UPDATE_CB)
    const char* crl1 =        "./certs/crl/crl.pem";
    const char* crlRevoked =  "./certs/crl/crl.revoked";
    const char* issuerCert =  "./certs/client-cert.pem";
    const char* caCert     =  "./certs/ca-cert.pem";
    const char* goodCert =    "./certs/server-cert.pem";
    const char* revokedCert = "./certs/server-revoked-cert.pem";
    int pemType = WOLFSSL_FILETYPE_PEM;
    WOLFSSL_CERT_MANAGER* cm = NULL;

    updateCrlTestCm = wolfSSL_CertManagerNew();
    ExpectNotNull(updateCrlTestCm);
    cm = updateCrlTestCm;
    ExpectIntEQ(wolfSSL_CertManagerSetCRLUpdate_Cb(cm, updateCrlCb),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, caCert, NULL),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, issuerCert, NULL),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CertManagerLoadCRLFile(cm, crl1, pemType),
        WOLFSSL_SUCCESS);
    /* CRL1 does not have good cert revoked */
    ExpectIntEQ(wolfSSL_CertManagerVerify(cm, goodCert, pemType),
        WOLFSSL_SUCCESS);
    ExpectIntNE(wolfSSL_CertManagerVerify(cm, revokedCert, pemType),
        WOLFSSL_SUCCESS);
    /* Load newer CRL from same issuer, callback verifies CRL entry details */
    ExpectIntEQ(wolfSSL_CertManagerLoadCRLFile(cm, crlRevoked, pemType),
        WOLFSSL_SUCCESS);
    /* CRL callback verified entry info was as expected */
    ExpectIntEQ(crlUpdateTestStatus, 1);
    /* Ensure that both certs fail with newer CRL */
    ExpectIntNE(wolfSSL_CertManagerVerify(cm, goodCert, pemType),
        WOLFSSL_SUCCESS);
    ExpectIntNE(wolfSSL_CertManagerVerify(cm, revokedCert, pemType),
        WOLFSSL_SUCCESS);
#endif
    return EXPECT_RESULT();
}

static int test_SetTmpEC_DHE_Sz(void)
{
    EXPECT_DECLS;
#if defined(HAVE_ECC) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS)
    WOLFSSL_CTX *ctx = NULL;
    WOLFSSL *ssl = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpEC_DHE_Sz(ctx, 32));
    ExpectNotNull(ssl = wolfSSL_new(ctx));
    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetTmpEC_DHE_Sz(ssl, 32));

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif

    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_get0_privatekey(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_TLS)
    WOLFSSL_CTX* ctx = NULL;

    (void)ctx;

#ifndef NO_RSA
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method()));
    ExpectNull(SSL_CTX_get0_privatekey(ctx));
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
                                                WOLFSSL_FILETYPE_PEM));
    ExpectNull(SSL_CTX_get0_privatekey(ctx));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
                                               WOLFSSL_FILETYPE_PEM));
    ExpectNotNull(SSL_CTX_get0_privatekey(ctx));
    wolfSSL_CTX_free(ctx);
    ctx = NULL;
#endif
#ifdef HAVE_ECC
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method()));
    ExpectNull(SSL_CTX_get0_privatekey(ctx));
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, eccCertFile,
                                                WOLFSSL_FILETYPE_PEM));
    ExpectNull(SSL_CTX_get0_privatekey(ctx));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, eccKeyFile,
                                               WOLFSSL_FILETYPE_PEM));
    ExpectNotNull(SSL_CTX_get0_privatekey(ctx));
    wolfSSL_CTX_free(ctx);
#endif
#endif

    return EXPECT_RESULT();
}

static int test_wolfSSL_dtls_set_mtu(void)
{
    EXPECT_DECLS;
#if (defined(WOLFSSL_DTLS_MTU) || defined(WOLFSSL_SCTP)) && \
    !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_DTLS) && \
    !defined(WOLFSSL_NO_TLS12)
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL*     ssl = NULL;
    const char* testCertFile;
    const char* testKeyFile;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method()));
#ifndef NO_RSA
        testCertFile = svrCertFile;
        testKeyFile = svrKeyFile;
#elif defined(HAVE_ECC)
        testCertFile = eccCertFile;
        testKeyFile = eccKeyFile;
#endif
    if  (testCertFile != NULL && testKeyFile != NULL) {
        ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, testCertFile,
                                                    WOLFSSL_FILETYPE_PEM));
        ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, testKeyFile,
                                                   WOLFSSL_FILETYPE_PEM));
    }
    ExpectNotNull(ssl = wolfSSL_new(ctx));

    ExpectIntEQ(wolfSSL_CTX_dtls_set_mtu(NULL, 1488), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_dtls_set_mtu(NULL, 1488), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_dtls_set_mtu(ctx, 20000), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl, 20000), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_get_error(ssl, WC_NO_ERR_TRACE(WOLFSSL_FAILURE)), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_dtls_set_mtu(ctx, 1488), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl, 1488), WOLFSSL_SUCCESS);

#ifdef OPENSSL_EXTRA
    ExpectIntEQ(SSL_set_mtu(ssl, 1488), WOLFSSL_SUCCESS);
#endif

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
#endif

    return EXPECT_RESULT();
}

#if defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(SINGLE_THREADED) && \
    defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12)

static WC_INLINE void generateDTLSMsg(byte* out, int outSz, word32 seq,
        enum HandShakeType hsType, word16 length)
{
    size_t idx = 0;
    byte* l;

    /* record layer */
    /* handshake type */
    out[idx++] = handshake;
    /* protocol version */
    out[idx++] = 0xfe;
    out[idx++] = 0xfd; /* DTLS 1.2 */
    /* epoch 0 */
    XMEMSET(out + idx, 0, 2);
    idx += 2;
    /* sequence number */
    XMEMSET(out + idx, 0, 6);
    c32toa(seq, out + idx + 2);
    idx += 6;
    /* length in BE */
    if (length)
        c16toa(length, out + idx);
    else
        c16toa(outSz - idx - 2, out + idx);
    idx += 2;

    /* handshake layer */
    /* handshake type */
    out[idx++] = (byte)hsType;
    /* length */
    l = out + idx;
    idx += 3;
    /* message seq */
    c16toa(0, out + idx);
    idx += 2;
    /* frag offset */
    c32to24(0, out + idx);
    idx += 3;
    /* frag length */
    c32to24((word32)outSz - (word32)idx - 3, l);
    c32to24((word32)outSz - (word32)idx - 3, out + idx);
    idx += 3;
    XMEMSET(out + idx, 0, outSz - idx);
}

static void test_wolfSSL_dtls_plaintext_server(WOLFSSL* ssl)
{
    byte msg[] = "This is a msg for the client";
    byte reply[40];
    AssertIntGT(wolfSSL_read(ssl, reply, sizeof(reply)),0);
    reply[sizeof(reply) - 1] = '\0';
    fprintf(stderr, "Client message: %s\n", reply);
    AssertIntEQ(wolfSSL_write(ssl, msg, sizeof(msg)), sizeof(msg));
}

static void test_wolfSSL_dtls_plaintext_client(WOLFSSL* ssl)
{
    byte ch[50];
    int fd = wolfSSL_get_wfd(ssl);
    byte msg[] = "This is a msg for the server";
    byte reply[40];

    AssertIntGE(fd, 0);
    generateDTLSMsg(ch, sizeof(ch), 20, client_hello, 0);
    /* Server should ignore this datagram */
    AssertIntEQ(send(fd, (MESSAGE_TYPE_CAST)ch, sizeof(ch), 0), sizeof(ch));
    generateDTLSMsg(ch, sizeof(ch), 20, client_hello, 10000);
    /* Server should ignore this datagram */
    AssertIntEQ(send(fd, (MESSAGE_TYPE_CAST)ch, sizeof(ch), 0), sizeof(ch));

    AssertIntEQ(wolfSSL_write(ssl, msg, sizeof(msg)), sizeof(msg));
    AssertIntGT(wolfSSL_read(ssl, reply, sizeof(reply)),0);
    reply[sizeof(reply) - 1] = '\0';
    fprintf(stderr, "Server response: %s\n", reply);
}

static int test_wolfSSL_dtls_plaintext(void)
{
    callback_functions func_cb_client;
    callback_functions func_cb_server;
    size_t i;
    struct test_params {
        method_provider client_meth;
        method_provider server_meth;
        ssl_callback on_result_server;
        ssl_callback on_result_client;
    } params[] = {
        {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method,
                test_wolfSSL_dtls_plaintext_server,
                test_wolfSSL_dtls_plaintext_client},
    };

    for (i = 0; i < sizeof(params)/sizeof(*params); i++) {
        XMEMSET(&func_cb_client, 0, sizeof(callback_functions));
        XMEMSET(&func_cb_server, 0, sizeof(callback_functions));

        func_cb_client.doUdp = func_cb_server.doUdp = 1;
        func_cb_server.method = params[i].server_meth;
        func_cb_client.method = params[i].client_meth;
        func_cb_client.on_result = params[i].on_result_client;
        func_cb_server.on_result = params[i].on_result_server;

        test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);

        if (!func_cb_client.return_code)
            return TEST_FAIL;
        if (!func_cb_server.return_code)
            return TEST_FAIL;
    }

    return TEST_RES_CHECK(1);
}
#else
static int test_wolfSSL_dtls_plaintext(void)
{
    return TEST_SKIPPED;
}
#endif

#if defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(SINGLE_THREADED) && \
    defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12)

static void test_wolfSSL_dtls12_fragments_spammer(WOLFSSL* ssl)
{
    byte b[1100]; /* buffer for the messages to send */
    size_t idx = 0;
    size_t seq_offset = 0;
    size_t msg_offset = 0;
    int i;
    int fd = wolfSSL_get_wfd(ssl);
    int ret = wolfSSL_connect_cert(ssl); /* This gets us past the cookie */
    word32 seq_number = 100; /* start high so server definitely reads this */
    word16 msg_number = 50; /* start high so server has to buffer this */
    AssertIntEQ(ret, 1);
    /* Now let's start spamming the peer with fragments it needs to store */
    XMEMSET(b, -1, sizeof(b));

    /* record layer */
    /* handshake type */
    b[idx++] = 22;
    /* protocol version */
    b[idx++] = 0xfe;
    b[idx++] = 0xfd; /* DTLS 1.2 */
    /* epoch 0 */
    XMEMSET(b + idx, 0, 2);
    idx += 2;
    /* sequence number */
    XMEMSET(b + idx, 0, 6);
    seq_offset = idx + 2; /* increment only the low 32 bits */
    idx += 6;
    /* static length in BE */
    c16toa(42, b + idx);
    idx += 2;

    /* handshake layer */
    /* cert type */
    b[idx++] = 11;
    /* length */
    c32to24(1000, b + idx);
    idx += 3;
    /* message seq */
    c16toa(0, b + idx);
    msg_offset = idx;
    idx += 2;
    /* frag offset */
    c32to24(500, b + idx);
    idx += 3;
    /* frag length */
    c32to24(30, b + idx);
    idx += 3;
    (void)idx; /* inhibit clang-analyzer-deadcode.DeadStores */

    for (i = 0; i < DTLS_POOL_SZ * 2 && ret > 0;
            seq_number++, msg_number++, i++) {
        struct timespec delay;
        XMEMSET(&delay, 0, sizeof(delay));
        delay.tv_nsec = 10000000; /* wait 0.01 seconds */
        c32toa(seq_number, b + seq_offset);
        c16toa(msg_number, b + msg_offset);
        ret = (int)send(fd, (MESSAGE_TYPE_CAST)b, 55, 0);
        nanosleep(&delay, NULL);
    }
}

#ifdef WOLFSSL_DTLS13
static void test_wolfSSL_dtls13_fragments_spammer(WOLFSSL* ssl)
{
    const word16 sendCountMax = 100;
    byte b[150]; /* buffer for the messages to send */
    size_t idx = 0;
    size_t msg_offset = 0;
    int fd = wolfSSL_get_wfd(ssl);
    word16 msg_number = 10; /* start high so server has to buffer this */
    int ret = wolfSSL_connect_cert(ssl); /* This gets us past the cookie */
    AssertIntEQ(ret, 1);
    /* Now let's start spamming the peer with fragments it needs to store */
    XMEMSET(b, -1, sizeof(b));

    /* handshake type */
    b[idx++] = 11;
    /* length */
    c32to24(10000, b + idx);
    idx += 3;
    /* message_seq */
    msg_offset = idx;
    idx += 2;
    /* fragment_offset */
    c32to24(5000, b + idx);
    idx += 3;
    /* fragment_length */
    c32to24(100, b + idx);
    idx += 3;
    /* fragment contents */
    idx += 100;

    for (; ret > 0 && msg_number < sendCountMax; msg_number++) {
        byte sendBuf[150];
        int sendSz = sizeof(sendBuf);
        struct timespec delay;
        XMEMSET(&delay, 0, sizeof(delay));
        delay.tv_nsec = 10000000; /* wait 0.01 seconds */
        c16toa(msg_number, b + msg_offset);
        ret = sendSz = BuildTls13Message(ssl, sendBuf, sendSz, b,
            (int)idx, handshake, 0, 0, 0);
        if (sendSz > 0)
            ret = (int)send(fd, (MESSAGE_TYPE_CAST)sendBuf, (size_t)sendSz, 0);
        nanosleep(&delay, NULL);
    }
}
#endif

static int test_wolfSSL_dtls_fragments(void)
{
    EXPECT_DECLS;
    callback_functions func_cb_client;
    callback_functions func_cb_server;
    size_t i;
    struct test_params {
        method_provider client_meth;
        method_provider server_meth;
        ssl_callback spammer;
    } params[] = {
#if !defined(WOLFSSL_NO_TLS12)
        {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method,
                test_wolfSSL_dtls12_fragments_spammer},
#endif
#ifdef WOLFSSL_DTLS13
        {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method,
                test_wolfSSL_dtls13_fragments_spammer},
#endif
    };

    for (i = 0; i < sizeof(params)/sizeof(*params); i++) {
        XMEMSET(&func_cb_client, 0, sizeof(callback_functions));
        XMEMSET(&func_cb_server, 0, sizeof(callback_functions));

        func_cb_client.doUdp = func_cb_server.doUdp = 1;
        func_cb_server.method = params[i].server_meth;
        func_cb_client.method = params[i].client_meth;
        func_cb_client.ssl_ready = params[i].spammer;

        test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);

        /* If the client failed, check that the error it encountered was from
         * the server aborting, resulting in a socket error, fatal error or
         * reading a close notify alert.
         *
         * Under slow execution (e.g. valgrind + noasm), the server may
         * still be processing fragments when the client completes its
         * handshake and write, so the client may succeed -- in that
         * case return_code is TEST_SUCCESS and these checks don't apply.
         */
        if (func_cb_client.return_code == TEST_FAIL) {
            if (func_cb_client.last_err != WC_NO_ERR_TRACE(SOCKET_ERROR_E) &&
                    func_cb_client.last_err != WOLFSSL_ERROR_ZERO_RETURN &&
                    func_cb_client.last_err != WC_NO_ERR_TRACE(FATAL_ERROR)) {
                ExpectIntEQ(func_cb_client.last_err, WC_NO_ERR_TRACE(SOCKET_ERROR_E));
            }
        }
        /* Check the server returned an error indicating the msg buffer
         * was full.
         *
         * Under slow execution (e.g. valgrind + noasm), the real handshake
         * from wolfSSL_negotiate() may complete before enough spam fragments
         * accumulate to trigger DTLS_TOO_MANY_FRAGMENTS_E. Accept both
         * outcomes: server hit the fragment limit, or completed normally.
         */
        if (func_cb_server.return_code == TEST_FAIL) {
            ExpectIntEQ(func_cb_server.last_err, WC_NO_ERR_TRACE(DTLS_TOO_MANY_FRAGMENTS_E));
        }

        if (EXPECT_FAIL())
            break;
    }

    return EXPECT_RESULT();
}

static void test_wolfSSL_dtls_send_alert(WOLFSSL* ssl)
{
    int fd, ret;
    byte alert_msg[] = {
        0x15, /* alert type */
        0xfe, 0xfd, /* version */
        0x00, 0x00, /* epoch */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* seq number */
        0x00, 0x02, /* length */
        0x02, /* level: fatal */
        0x46 /* protocol version */
    };

    fd = wolfSSL_get_wfd(ssl);
    AssertIntGE(fd, 0);
    ret = (int)send(fd, (MESSAGE_TYPE_CAST)alert_msg, sizeof(alert_msg), 0);
    AssertIntGT(ret, 0);
}

static int _test_wolfSSL_ignore_alert_before_cookie(byte version12)
{
    callback_functions client_cbs, server_cbs;

    XMEMSET(&client_cbs, 0, sizeof(client_cbs));
    XMEMSET(&server_cbs, 0, sizeof(server_cbs));
    client_cbs.doUdp = server_cbs.doUdp = 1;
    if (version12) {
#if !defined(WOLFSSL_NO_TLS12)
        client_cbs.method = wolfDTLSv1_2_client_method;
        server_cbs.method = wolfDTLSv1_2_server_method;
#else
        return TEST_SKIPPED;
#endif
    }
    else
    {
#ifdef WOLFSSL_DTLS13
        client_cbs.method = wolfDTLSv1_3_client_method;
        server_cbs.method = wolfDTLSv1_3_server_method;
#else
        return TEST_SKIPPED;
#endif /* WOLFSSL_DTLS13 */
    }

    client_cbs.ssl_ready = test_wolfSSL_dtls_send_alert;
    test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs);

    if (!client_cbs.return_code)
        return TEST_FAIL;
    if (!server_cbs.return_code)
        return TEST_FAIL;

    return TEST_SUCCESS;
}

static int test_wolfSSL_ignore_alert_before_cookie(void)
{
    int ret;
    ret =_test_wolfSSL_ignore_alert_before_cookie(0);
    if (ret != 0)
        return ret;
    ret =_test_wolfSSL_ignore_alert_before_cookie(1);
    if (ret != 0)
        return ret;
    return 0;
}

static void test_wolfSSL_send_bad_record(WOLFSSL* ssl)
{
    int ret;
    int fd;

    byte bad_msg[] = {
        0x17, /* app data  */
        0xaa, 0xfd, /* bad version */
        0x00, 0x01, /* epoch 1 */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* not seen seq number */
        0x00, 0x26, /* length: 38 bytes */
        0xae, 0x30, 0x31, 0xb1, 0xf1, 0xb9, 0x6f, 0xda, 0x17, 0x19, 0xd9, 0x57,
        0xa9, 0x9d, 0x5c, 0x51, 0x9b, 0x53, 0x63, 0xa5, 0x24, 0x70, 0xa1,
        0xae, 0xdf, 0x1c, 0xb9, 0xfc, 0xe3, 0xd7, 0x77, 0x6d, 0xb6, 0x89, 0x0f,
        0x03, 0x18, 0x72
    };

    fd = wolfSSL_get_wfd(ssl);
    AssertIntGE(fd, 0);
    ret = (int)send(fd, (MESSAGE_TYPE_CAST)bad_msg, sizeof(bad_msg), 0);
    AssertIntEQ(ret, sizeof(bad_msg));
    ret = wolfSSL_write(ssl, "badrecordtest", sizeof("badrecordtest"));
    AssertIntEQ(ret, sizeof("badrecordtest"));
}

static void test_wolfSSL_read_string(WOLFSSL* ssl)
{
    byte buf[100];
    int ret;

    ret = wolfSSL_read(ssl, buf, sizeof(buf));
    AssertIntGT(ret, 0);
    AssertIntEQ(strcmp((char*)buf, "badrecordtest"), 0);
}

static int _test_wolfSSL_dtls_bad_record(
    method_provider client_method, method_provider server_method)
{
    callback_functions client_cbs, server_cbs;

    XMEMSET(&client_cbs, 0, sizeof(client_cbs));
    XMEMSET(&server_cbs, 0, sizeof(server_cbs));
    client_cbs.doUdp = server_cbs.doUdp = 1;
    client_cbs.method = client_method;
    server_cbs.method = server_method;

    client_cbs.on_result = test_wolfSSL_send_bad_record;
    server_cbs.on_result = test_wolfSSL_read_string;

    test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs);

    if (!client_cbs.return_code)
        return TEST_FAIL;
    if (!server_cbs.return_code)
        return TEST_FAIL;

    return TEST_SUCCESS;
}

static int test_wolfSSL_dtls_bad_record(void)
{
    int ret = TEST_SUCCESS;
#if !defined(WOLFSSL_NO_TLS12)
    ret = _test_wolfSSL_dtls_bad_record(wolfDTLSv1_2_client_method,
        wolfDTLSv1_2_server_method);
#endif
#ifdef WOLFSSL_DTLS13
    if (ret == TEST_SUCCESS) {
        ret = _test_wolfSSL_dtls_bad_record(wolfDTLSv1_3_client_method,
        wolfDTLSv1_3_server_method);
    }
#endif /* WOLFSSL_DTLS13 */
    return ret;

}

#else
static int test_wolfSSL_dtls_fragments(void)
{
    return TEST_SKIPPED;
}
static int test_wolfSSL_ignore_alert_before_cookie(void)
{
    return TEST_SKIPPED;
}
static int test_wolfSSL_dtls_bad_record(void)
{
    return TEST_SKIPPED;
}
#endif

#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
    defined(HAVE_IO_TESTS_DEPENDENCIES)
static volatile int test_AEAD_seq_num = 0;
#ifdef WOLFSSL_NO_ATOMICS
static volatile int test_AEAD_done = 0;
#else
wolfSSL_Atomic_Int test_AEAD_done = WOLFSSL_ATOMIC_INITIALIZER(0);
#endif
#ifdef WOLFSSL_MUTEX_INITIALIZER
static wolfSSL_Mutex test_AEAD_mutex = WOLFSSL_MUTEX_INITIALIZER(test_AEAD_mutex);
#endif

static int test_AEAD_fail_decryption = 0;
static int test_AEAD_cbiorecv(WOLFSSL *ssl, char *buf, int sz, void *ctx)
{
    int fd = wolfSSL_get_fd(ssl);
    int ret = -1;
    if (fd >= 0 && (ret = (int)recv(fd, buf, sz, 0)) > 0) {
        if (test_AEAD_fail_decryption) {
            /* Modify the packet to trigger a decryption failure */
            buf[ret/2] ^= 0xFF;
            if (test_AEAD_fail_decryption == 1)
                test_AEAD_fail_decryption = 0;
        }
    }
    (void)ctx;
    return ret;
}

static void test_AEAD_get_limits(WOLFSSL* ssl, w64wrapper* hardLimit,
        w64wrapper* keyUpdateLimit, w64wrapper* sendLimit)
{
    if (sendLimit)
        w64Zero(sendLimit);
    switch (ssl->specs.bulk_cipher_algorithm) {
        case wolfssl_aes_gcm:
            if (sendLimit)
                *sendLimit = AEAD_AES_LIMIT;
            FALL_THROUGH;
        case wolfssl_chacha:
            if (hardLimit)
                *hardLimit = DTLS_AEAD_AES_GCM_CHACHA_FAIL_LIMIT;
            if (keyUpdateLimit)
                *keyUpdateLimit = DTLS_AEAD_AES_GCM_CHACHA_FAIL_KU_LIMIT;
            break;
        case wolfssl_aes_ccm:
            if (sendLimit)
                *sendLimit = DTLS_AEAD_AES_CCM_LIMIT;
            if (ssl->specs.aead_mac_size == AES_CCM_8_AUTH_SZ) {
                if (hardLimit)
                    *hardLimit = DTLS_AEAD_AES_CCM_8_FAIL_LIMIT;
                if (keyUpdateLimit)
                    *keyUpdateLimit = DTLS_AEAD_AES_CCM_8_FAIL_KU_LIMIT;
            }
            else {
                if (hardLimit)
                    *hardLimit = DTLS_AEAD_AES_CCM_FAIL_LIMIT;
                if (keyUpdateLimit)
                    *keyUpdateLimit = DTLS_AEAD_AES_CCM_FAIL_KU_LIMIT;
            }
            break;
        default:
            fprintf(stderr, "Unrecognized bulk cipher");
            AssertFalse(1);
            break;
    }
}

static void test_AEAD_limit_client(WOLFSSL* ssl)
{
    int ret;
    int i;
    int didReKey = 0;
    char msgBuf[20];
    w64wrapper hardLimit;
    w64wrapper keyUpdateLimit;
    w64wrapper counter;
    w64wrapper sendLimit;

    test_AEAD_get_limits(ssl, &hardLimit, &keyUpdateLimit, &sendLimit);

    w64Zero(&counter);
    AssertTrue(w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13Epoch)->dropCount, counter));

    wolfSSL_SSLSetIORecv(ssl, test_AEAD_cbiorecv);

    for (i = 0; i < 10; i++) {
        /* Test some failed decryptions */
        test_AEAD_fail_decryption = 1;
        w64Increment(&counter);
        ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf));
        /* Should succeed since decryption failures are dropped */
        AssertIntGT(ret, 0);
        AssertTrue(w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount, counter));
    }

    test_AEAD_fail_decryption = 1;
    Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount = keyUpdateLimit;
    w64Increment(&Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount);
    /* 100 read calls should be enough to complete the key update */
    w64Zero(&counter);
    for (i = 0; i < 100; i++) {
        /* Key update should be sent and negotiated */
        ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf));
        AssertIntGT(ret, 0);
        /* Epoch after one key update is 4 */
        if (w64Equal(ssl->dtls13PeerEpoch, w64From32(0, 4)) &&
                w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount, counter)) {
            didReKey = 1;
            break;
        }
    }
    AssertTrue(didReKey);

    if (!w64IsZero(sendLimit)) {
        /* Test the sending limit for AEAD ciphers */
#ifdef WOLFSSL_MUTEX_INITIALIZER
        (void)wc_LockMutex(&test_AEAD_mutex);
#endif
        Dtls13GetEpoch(ssl, ssl->dtls13Epoch)->nextSeqNumber = sendLimit;
        test_AEAD_seq_num = 1;
        XMEMSET(msgBuf, 0, sizeof(msgBuf));
        ret = wolfSSL_write(ssl, msgBuf, sizeof(msgBuf));
        AssertIntGT(ret, 0);
        didReKey = 0;
        w64Zero(&counter);
#ifdef WOLFSSL_MUTEX_INITIALIZER
        wc_UnLockMutex(&test_AEAD_mutex);
#endif
        /* 100 read calls should be enough to complete the key update */
        for (i = 0; i < 100; i++) {
            /* Key update should be sent and negotiated */
            ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf));
            AssertIntGT(ret, 0);
            /* Epoch after another key update is 5 */
            if (w64Equal(ssl->dtls13Epoch, w64From32(0, 5)) &&
                    w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13Epoch)->dropCount, counter)) {
                didReKey = 1;
                break;
            }
        }
        AssertTrue(didReKey);
    }

    test_AEAD_fail_decryption = 2;
    Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount = hardLimit;
    w64Decrement(&Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount);
    /* Connection should fail with a DECRYPT_ERROR */
    ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf));
    AssertIntEQ(ret, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
    AssertIntEQ(wolfSSL_get_error(ssl, ret), WC_NO_ERR_TRACE(DECRYPT_ERROR));

#ifdef WOLFSSL_ATOMIC_INITIALIZER
    WOLFSSL_ATOMIC_STORE(test_AEAD_done, 1);
#else
    test_AEAD_done = 1;
#endif
}

int counter = 0;
static void test_AEAD_limit_server(WOLFSSL* ssl)
{
    char msgBuf[] = "Sending data";
    int ret = WOLFSSL_SUCCESS;
    w64wrapper sendLimit;
    SOCKET_T fd = wolfSSL_get_fd(ssl);
    struct timespec delay;
    XMEMSET(&delay, 0, sizeof(delay));
    delay.tv_nsec = 100000000; /* wait 0.1 seconds */
    tcp_set_nonblocking(&fd); /* So that read doesn't block */
    wolfSSL_dtls_set_using_nonblock(ssl, 1);
    test_AEAD_get_limits(ssl, NULL, NULL, &sendLimit);
    while (!
    #ifdef WOLFSSL_ATOMIC_INITIALIZER
           WOLFSSL_ATOMIC_LOAD(test_AEAD_done)
    #else
           test_AEAD_done
    #endif
           && ret > 0)
    {
        counter++;
#ifdef WOLFSSL_MUTEX_INITIALIZER
        (void)wc_LockMutex(&test_AEAD_mutex);
#endif
        if (test_AEAD_seq_num) {
            /* We need to update the seq number so that we can understand the
             * peer. Otherwise we will incorrectly interpret the seq number. */
            Dtls13Epoch* e = Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch);
            AssertNotNull(e);
            e->nextPeerSeqNumber = sendLimit;
            test_AEAD_seq_num = 0;
        }
#ifdef WOLFSSL_MUTEX_INITIALIZER
        wc_UnLockMutex(&test_AEAD_mutex);
#endif
        (void)wolfSSL_read(ssl, msgBuf, sizeof(msgBuf));
        ret = wolfSSL_write(ssl, msgBuf, sizeof(msgBuf));
        nanosleep(&delay, NULL);
    }
}

static int test_wolfSSL_dtls_AEAD_limit(void)
{
    callback_functions func_cb_client;
    callback_functions func_cb_server;
    XMEMSET(&func_cb_client, 0, sizeof(callback_functions));
    XMEMSET(&func_cb_server, 0, sizeof(callback_functions));

    func_cb_client.doUdp = func_cb_server.doUdp = 1;
    func_cb_server.method = wolfDTLSv1_3_server_method;
    func_cb_client.method = wolfDTLSv1_3_client_method;
    func_cb_server.on_result = test_AEAD_limit_server;
    func_cb_client.on_result = test_AEAD_limit_client;

    test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);

    if (!func_cb_client.return_code)
        return TEST_FAIL;
    if (!func_cb_server.return_code)
        return TEST_FAIL;

    return TEST_SUCCESS;
}
#else
static int test_wolfSSL_dtls_AEAD_limit(void)
{
    return TEST_SKIPPED;
}
#endif

#if defined(WOLFSSL_DTLS) && \
    defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(SINGLE_THREADED) && \
    !defined(DEBUG_VECTOR_REGISTER_ACCESS_FUZZING)
static void test_wolfSSL_dtls_send_ch(WOLFSSL* ssl)
{
    int fd, ret;
    byte ch_msg[] = {
        0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
        0xfa, 0x01, 0x00, 0x01, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
        0xee, 0xfe, 0xfd, 0xc0, 0xca, 0xb5, 0x6f, 0x3d, 0x23, 0xcc, 0x53, 0x9a,
        0x67, 0x17, 0x70, 0xd3, 0xfb, 0x23, 0x16, 0x9e, 0x4e, 0xd6, 0x7e, 0x29,
        0xab, 0xfa, 0x4c, 0xa5, 0x84, 0x95, 0xc3, 0xdb, 0x21, 0x9a, 0x52, 0x00,
        0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0,
        0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc,
        0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0,
        0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00,
        0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x01,
        0x8e, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x0d, 0x00, 0x20,
        0x00, 0x1e, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02, 0x03, 0x08, 0x06,
        0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06, 0x01,
        0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x0a, 0x00, 0x0c,
        0x00, 0x0a, 0x00, 0x19, 0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01, 0x00,
        0x00, 0x16, 0x00, 0x00, 0x00, 0x33, 0x01, 0x4b, 0x01, 0x49, 0x00, 0x17,
        0x00, 0x41, 0x04, 0x96, 0xcb, 0x2e, 0x4e, 0xd9, 0x88, 0x71, 0xc7, 0xf3,
        0x1a, 0x16, 0xdd, 0x7a, 0x7c, 0xf7, 0x67, 0x8a, 0x5d, 0x9a, 0x55, 0xa6,
        0x4a, 0x90, 0xd9, 0xfb, 0xc7, 0xfb, 0xbe, 0x09, 0xa9, 0x8a, 0xb5, 0x7a,
        0xd1, 0xde, 0x83, 0x74, 0x27, 0x31, 0x1c, 0xaa, 0xae, 0xef, 0x58, 0x43,
        0x13, 0x7d, 0x15, 0x4d, 0x7f, 0x68, 0xf6, 0x8a, 0x38, 0xef, 0x0e, 0xb3,
        0xcf, 0xb8, 0x4a, 0xa9, 0xb4, 0xd7, 0xcb, 0x01, 0x00, 0x01, 0x00, 0x1d,
        0x0a, 0x22, 0x8a, 0xd1, 0x78, 0x85, 0x1e, 0x5a, 0xe1, 0x1d, 0x1e, 0xb7,
        0x2d, 0xbc, 0x5f, 0x52, 0xbc, 0x97, 0x5d, 0x8b, 0x6a, 0x8b, 0x9d, 0x1e,
        0xb1, 0xfc, 0x8a, 0xb2, 0x56, 0xcd, 0xed, 0x4b, 0xfb, 0x66, 0x3f, 0x59,
        0x3f, 0x15, 0x5d, 0x09, 0x9e, 0x2f, 0x60, 0x5b, 0x31, 0x81, 0x27, 0xf0,
        0x1c, 0xda, 0xcd, 0x48, 0x66, 0xc6, 0xbb, 0x25, 0xf0, 0x5f, 0xda, 0x4c,
        0xcf, 0x1d, 0x88, 0xc8, 0xda, 0x1b, 0x53, 0xea, 0xbd, 0xce, 0x6d, 0xf6,
        0x4a, 0x76, 0xdb, 0x75, 0x99, 0xaf, 0xcf, 0x76, 0x4a, 0xfb, 0xe3, 0xef,
        0xb2, 0xcb, 0xae, 0x4a, 0xc0, 0xe8, 0x63, 0x1f, 0xd6, 0xe8, 0xe6, 0x45,
        0xf9, 0xea, 0x0d, 0x06, 0x19, 0xfc, 0xb1, 0xfd, 0x5d, 0x92, 0x89, 0x7b,
        0xc7, 0x9f, 0x1a, 0xb3, 0x2b, 0xc7, 0xad, 0x0e, 0xfb, 0x13, 0x41, 0x83,
        0x84, 0x58, 0x3a, 0x25, 0xb9, 0x49, 0x35, 0x1c, 0x23, 0xcb, 0xd6, 0xe7,
        0xc2, 0x8c, 0x4b, 0x2a, 0x73, 0xa1, 0xdf, 0x4f, 0x73, 0x9b, 0xb3, 0xd2,
        0xb2, 0x95, 0x00, 0x3c, 0x26, 0x09, 0x89, 0x71, 0x05, 0x39, 0xc8, 0x98,
        0x8f, 0xed, 0x32, 0x15, 0x78, 0xcd, 0xd3, 0x7e, 0xfb, 0x5a, 0x78, 0x2a,
        0xdc, 0xca, 0x20, 0x09, 0xb5, 0x14, 0xf9, 0xd4, 0x58, 0xf6, 0x69, 0xf8,
        0x65, 0x9f, 0xb7, 0xe4, 0x93, 0xf1, 0xa3, 0x84, 0x7e, 0x1b, 0x23, 0x5d,
        0xea, 0x59, 0x3e, 0x4d, 0xca, 0xfd, 0xa5, 0x55, 0xdd, 0x99, 0xb5, 0x02,
        0xf8, 0x0d, 0xe5, 0xf4, 0x06, 0xb0, 0x43, 0x9e, 0x2e, 0xbf, 0x05, 0x33,
        0x65, 0x7b, 0x13, 0x8c, 0xf9, 0x16, 0x4d, 0xc5, 0x15, 0x0b, 0x40, 0x2f,
        0x66, 0x94, 0xf2, 0x43, 0x95, 0xe7, 0xa9, 0xb6, 0x39, 0x99, 0x73, 0xb3,
        0xb0, 0x06, 0xfe, 0x52, 0x9e, 0x57, 0xba, 0x75, 0xfd, 0x76, 0x7b, 0x20,
        0x31, 0x68, 0x4c
    };

    fd = wolfSSL_get_wfd(ssl);
    AssertIntGE(fd, 0);
    ret = (int)send(fd, (MESSAGE_TYPE_CAST)ch_msg, sizeof(ch_msg), 0);
    AssertIntGT(ret, 0);
    /* consume the HRR otherwise handshake will fail */
    ret = (int)recv(fd, (MESSAGE_TYPE_CAST)ch_msg, sizeof(ch_msg), 0);
    AssertIntGT(ret, 0);
}

#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
static void test_wolfSSL_dtls_send_ch_with_invalid_cookie(WOLFSSL* ssl)
{
    int fd, ret;
    byte ch_msh_invalid_cookie[] = {
      0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
      0x4e, 0x01, 0x00, 0x02, 0x42, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02,
      0x42, 0xfe, 0xfd, 0x69, 0xca, 0x77, 0x60, 0x6f, 0xfc, 0xd1, 0x5b, 0x60,
      0x5d, 0xf1, 0xa6, 0x5c, 0x44, 0x71, 0xae, 0xca, 0x62, 0x19, 0x0c, 0xb6,
      0xf7, 0x2c, 0xa6, 0xd5, 0xd2, 0x99, 0x9d, 0x18, 0xae, 0xac, 0x11, 0x00,
      0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0,
      0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc,
      0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0,
      0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00,
      0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x01,
      0xe2, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x0d, 0x00, 0x20,
      0x00, 0x1e, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02, 0x03, 0x08, 0x06,
      0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06, 0x01,
      0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x2c, 0x00, 0x45,
      0x00, 0x43, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x2d, 0x00,
      0x03, 0x02, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x19,
      0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01, 0x00, 0x00, 0x16, 0x00, 0x00,
      0x00, 0x33, 0x01, 0x4b, 0x01, 0x49, 0x00, 0x17, 0x00, 0x41, 0x04, 0x7c,
      0x5a, 0xc2, 0x5a, 0xfd, 0xcd, 0x2b, 0x08, 0xb2, 0xeb, 0x8e, 0xc0, 0x02,
      0x03, 0x9d, 0xb1, 0xc1, 0x0d, 0x7b, 0x7f, 0x46, 0x43, 0xdf, 0xf3, 0xee,
      0x2b, 0x78, 0x0e, 0x29, 0x8c, 0x42, 0x11, 0x2c, 0xde, 0xd7, 0x41, 0x0f,
      0x28, 0x94, 0x80, 0x41, 0x70, 0xc4, 0x17, 0xfd, 0x6d, 0xfa, 0xee, 0x9a,
      0xf2, 0xc4, 0x15, 0x4c, 0x5f, 0x54, 0xb6, 0x78, 0x6e, 0xf9, 0x63, 0x27,
      0x33, 0xb8, 0x7b, 0x01, 0x00, 0x01, 0x00, 0xd4, 0x46, 0x62, 0x9c, 0xbf,
      0x8f, 0x1b, 0x65, 0x9b, 0xf0, 0x29, 0x64, 0xd8, 0x50, 0x0e, 0x74, 0xf1,
      0x58, 0x10, 0xc9, 0xd9, 0x82, 0x5b, 0xd9, 0xbe, 0x14, 0xdf, 0xde, 0x86,
      0xb4, 0x2e, 0x15, 0xee, 0x4f, 0xf6, 0x74, 0x9e, 0x59, 0x11, 0x36, 0x2d,
      0xb9, 0x67, 0xaa, 0x5a, 0x09, 0x9b, 0x45, 0xf1, 0x01, 0x4c, 0x4e, 0xf6,
      0xda, 0x6a, 0xae, 0xa7, 0x73, 0x7b, 0x2e, 0xb6, 0x24, 0x89, 0x99, 0xb7,
      0x52, 0x16, 0x62, 0x0a, 0xab, 0x58, 0xf8, 0x3f, 0x10, 0x5b, 0x83, 0xfd,
      0x7b, 0x81, 0x77, 0x81, 0x8d, 0xef, 0x24, 0x56, 0x6d, 0xba, 0x49, 0xd4,
      0x8b, 0xb5, 0xa0, 0xb1, 0xc9, 0x8c, 0x32, 0x95, 0x1c, 0x5e, 0x0a, 0x4b,
      0xf6, 0x00, 0x50, 0x0a, 0x87, 0x99, 0x59, 0xcf, 0x6f, 0x9d, 0x02, 0xd0,
      0x1b, 0xa1, 0x96, 0x45, 0x28, 0x76, 0x40, 0x33, 0x28, 0xc9, 0xa1, 0xfd,
      0x46, 0xab, 0x2c, 0x9e, 0x5e, 0xc6, 0x74, 0x19, 0x9a, 0xf5, 0x9b, 0x51,
      0x11, 0x4f, 0xc8, 0xb9, 0x99, 0x6b, 0x4e, 0x3e, 0x31, 0x64, 0xb4, 0x92,
      0xf4, 0x0d, 0x41, 0x4b, 0x2c, 0x65, 0x23, 0xf7, 0x47, 0xe3, 0xa5, 0x2e,
      0xe4, 0x9c, 0x2b, 0xc9, 0x41, 0x22, 0x83, 0x8a, 0x23, 0xef, 0x29, 0x7e,
      0x4f, 0x3f, 0xa3, 0xbf, 0x73, 0x2b, 0xd7, 0xcc, 0xc8, 0xc6, 0xe9, 0xbc,
      0x01, 0xb7, 0x32, 0x63, 0xd4, 0x7e, 0x7f, 0x9a, 0xaf, 0x5f, 0x05, 0x31,
      0x53, 0xd6, 0x1f, 0xa2, 0xd0, 0xdf, 0x67, 0x56, 0xf1, 0x9c, 0x4a, 0x9d,
      0x83, 0xb4, 0xef, 0xb3, 0xf2, 0xcc, 0xf1, 0x91, 0x6c, 0x47, 0xc3, 0x8b,
      0xd0, 0x92, 0x79, 0x3d, 0xa0, 0xc0, 0x3a, 0x57, 0x26, 0x6d, 0x0a, 0xad,
      0x5f, 0xad, 0xb4, 0x74, 0x48, 0x4a, 0x51, 0xe1, 0xb5, 0x82, 0x0a, 0x4c,
      0x4f, 0x9d, 0xaf, 0xee, 0x5a, 0xa2, 0x4d, 0x4d, 0x5f, 0xe0, 0x17, 0x00,
      0x23, 0x00, 0x00
    };
    byte alert_reply[50];
    byte expected_alert_reply[] = {
        0x15, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
        0x02, 0x02, 0x2f
    };

    fd = wolfSSL_get_wfd(ssl);
    if (fd >= 0) {
        ret = (int)send(fd, (MESSAGE_TYPE_CAST)ch_msh_invalid_cookie,
                sizeof(ch_msh_invalid_cookie), 0);
        AssertIntGT(ret, 0);
        /* should reply with an illegal_parameter reply */
        ret = (int)recv(fd, (MESSAGE_TYPE_CAST)alert_reply, sizeof(alert_reply), 0);
        AssertIntEQ(ret, sizeof(expected_alert_reply));
        AssertIntEQ(XMEMCMP(alert_reply, expected_alert_reply,
                sizeof(expected_alert_reply)), 0);
    }
}
#endif

static word32 test_wolfSSL_dtls_stateless_HashWOLFSSL(const WOLFSSL* ssl)
{
#ifndef NO_MD5
    enum wc_HashType hashType = WC_HASH_TYPE_MD5;
#elif !defined(NO_SHA)
    enum wc_HashType hashType = WC_HASH_TYPE_SHA;
#elif !defined(NO_SHA256)
    enum wc_HashType hashType = WC_HASH_TYPE_SHA256;
#else
    #error "We need a digest to hash the WOLFSSL object"
#endif
    byte hashBuf[WC_MAX_DIGEST_SIZE];
    wc_HashAlg hash;
    const TLSX* exts = ssl->extensions;
    WOLFSSL sslCopy; /* Use a copy to omit certain fields */
#ifndef WOLFSSL_SMALL_STACK_CACHE
    HS_Hashes* hsHashes = ssl->hsHashes; /* Is re-allocated in
                                          * InitHandshakeHashes */
#endif

    XMEMCPY(&sslCopy, ssl, sizeof(*ssl));
    XMEMSET(hashBuf, 0, sizeof(hashBuf));

    /* Following fields are not important to compare */
    XMEMSET(sslCopy.buffers.inputBuffer.staticBuffer, 0, STATIC_BUFFER_LEN);
    sslCopy.buffers.inputBuffer.buffer = NULL;
    sslCopy.buffers.inputBuffer.bufferSize = 0;
    sslCopy.buffers.inputBuffer.dynamicFlag = 0;
    sslCopy.buffers.inputBuffer.offset = 0;
    XMEMSET(sslCopy.buffers.outputBuffer.staticBuffer, 0, STATIC_BUFFER_LEN);
    sslCopy.buffers.outputBuffer.buffer = NULL;
    sslCopy.buffers.outputBuffer.bufferSize = 0;
    sslCopy.buffers.outputBuffer.dynamicFlag = 0;
    sslCopy.buffers.outputBuffer.offset = 0;
    sslCopy.error = 0;
    sslCopy.curSize = 0;
    sslCopy.curStartIdx = 0;
    sslCopy.keys.curSeq_lo = 0;
    XMEMSET(&sslCopy.curRL, 0, sizeof(sslCopy.curRL));
#ifdef WOLFSSL_DTLS13
    XMEMSET(&sslCopy.keys.curSeq, 0, sizeof(sslCopy.keys.curSeq));
    sslCopy.dtls13FastTimeout = 0;
#endif
    sslCopy.keys.dtls_peer_handshake_number = 0;
    XMEMSET(&sslCopy.alert_history, 0, sizeof(sslCopy.alert_history));
    sslCopy.hsHashes = NULL;
#if !defined(WOLFSSL_NO_CLIENT_AUTH) && \
    ((defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)) || \
     (defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \
     (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH)))
    sslCopy.options.cacheMessages = 0;
#endif
#ifdef WOLFSSL_ASYNC_IO
#ifdef WOLFSSL_ASYNC_CRYPT
    sslCopy.asyncDev = NULL;
#endif
    sslCopy.async = NULL;
#endif

    AssertIntEQ(wc_HashInit(&hash, hashType), 0);
    AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)&sslCopy, sizeof(sslCopy)), 0);
    /* hash extension list */
    while (exts != NULL) {
        AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)exts, sizeof(*exts)), 0);
        exts = exts->next;
    }
    /* Hash suites */
    if (sslCopy.suites != NULL) {
        AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)sslCopy.suites,
                sizeof(struct Suites)), 0);
    }

#ifdef WOLFSSL_SMALL_STACK_CACHE
    /* with WOLFSSL_SMALL_STACK_CACHE, the SHA-2 objects always differ after
     * initialization because of cached W and (for SHA512) X buffers.
     */
#else
    /* Hash hsHashes */
    AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)hsHashes,
            sizeof(*hsHashes)), 0);
#endif

    AssertIntEQ(wc_HashFinal(&hash, hashType, hashBuf), 0);
    AssertIntEQ(wc_HashFree(&hash, hashType), 0);

    return MakeWordFromHash(hashBuf);
}

static CallbackIORecv test_wolfSSL_dtls_compare_stateless_cb;
static int test_wolfSSL_dtls_compare_stateless_cb_call_once;
static int test_wolfSSL_dtls_compare_stateless_read_cb_once(WOLFSSL *ssl,
        char *buf, int sz, void *ctx)
{
    if (test_wolfSSL_dtls_compare_stateless_cb_call_once) {
        test_wolfSSL_dtls_compare_stateless_cb_call_once = 0;
        return test_wolfSSL_dtls_compare_stateless_cb(ssl, buf, sz, ctx);
    }
    else {
        return WOLFSSL_CBIO_ERR_WANT_READ;
    }
}

static void test_wolfSSL_dtls_compare_stateless(WOLFSSL* ssl)
{
    /* Compare the ssl object before and after one ClientHello msg */
    SOCKET_T fd = wolfSSL_get_fd(ssl);
    int res;
    int err;
    word32 initHash;

    test_wolfSSL_dtls_compare_stateless_cb = ssl->CBIORecv;
    test_wolfSSL_dtls_compare_stateless_cb_call_once = 1;
    wolfSSL_dtls_set_using_nonblock(ssl, 1);
    ssl->CBIORecv = test_wolfSSL_dtls_compare_stateless_read_cb_once;

    initHash = test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl);
    (void)initHash;

    res = tcp_select(fd, 5);
    /* We are expecting a msg. A timeout indicates failure. */
    AssertIntEQ(res, TEST_RECV_READY);

    res = wolfSSL_accept(ssl);
    err = wolfSSL_get_error(ssl, res);
    AssertIntEQ(res, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
    AssertIntEQ(err, WOLFSSL_ERROR_WANT_READ);

    AssertIntEQ(initHash, test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl));

    wolfSSL_dtls_set_using_nonblock(ssl, 0);
    ssl->CBIORecv = test_wolfSSL_dtls_compare_stateless_cb;

}

#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
static void test_wolfSSL_dtls_enable_hrrcookie(WOLFSSL* ssl)
{
    int ret;
    ret = wolfSSL_send_hrr_cookie(ssl, NULL, 0);
    AssertIntEQ(ret, WOLFSSL_SUCCESS);
    test_wolfSSL_dtls_compare_stateless(ssl);
}
#endif

static int test_wolfSSL_dtls_stateless(void)
{
    callback_functions client_cbs, server_cbs;
    size_t i;
    struct {
        method_provider client_meth;
        method_provider server_meth;
        ssl_callback client_ssl_ready;
        ssl_callback server_ssl_ready;
    } test_params[] = {
#if !defined(WOLFSSL_NO_TLS12)
        {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method,
                test_wolfSSL_dtls_send_ch, test_wolfSSL_dtls_compare_stateless},
#endif
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
        {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method,
                test_wolfSSL_dtls_send_ch, test_wolfSSL_dtls_enable_hrrcookie},
        {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method,
                test_wolfSSL_dtls_send_ch_with_invalid_cookie, test_wolfSSL_dtls_enable_hrrcookie},
#endif
    };

    if (0 == sizeof(test_params)){
        return TEST_SKIPPED;
    }

    for (i = 0; i < sizeof(test_params)/sizeof(*test_params); i++) {
        XMEMSET(&client_cbs, 0, sizeof(client_cbs));
        XMEMSET(&server_cbs, 0, sizeof(server_cbs));
        client_cbs.doUdp = server_cbs.doUdp = 1;
        client_cbs.method = test_params[i].client_meth;
        server_cbs.method = test_params[i].server_meth;

        client_cbs.ssl_ready = test_params[i].client_ssl_ready;
        server_cbs.ssl_ready = test_params[i].server_ssl_ready;
        test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs);

        if (!client_cbs.return_code)
            return TEST_FAIL;
        if (!server_cbs.return_code)
            return TEST_FAIL;
    }

    return TEST_SUCCESS;
}

/* DTLS stateless API handling multiple CHs with different HRR groups */
static int test_wolfSSL_dtls_stateless_hrr_group(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_SEND_HRR_COOKIE)
    size_t i;
    word32 initHash;
    struct {
        method_provider client_meth;
        method_provider server_meth;
    } params[] = {
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_DTLS13)
        { wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method },
#endif
#if !defined(WOLFSSL_NO_TLS12) && defined(WOLFSSL_DTLS)
        { wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method },
#endif
    };
    for (i = 0; i < XELEM_CNT(params) && !EXPECT_FAIL(); i++) {
        WOLFSSL_CTX *ctx_s = NULL, *ctx_c = NULL;
        WOLFSSL *ssl_s = NULL, *ssl_c = NULL, *ssl_c2 = NULL;
        struct test_memio_ctx test_ctx;
        int groups_1[] = {
            WOLFSSL_ECC_SECP256R1,
            WOLFSSL_ECC_SECP384R1,
            WOLFSSL_ECC_SECP521R1
        };
        int groups_2[] = {
            WOLFSSL_ECC_SECP384R1,
            WOLFSSL_ECC_SECP521R1
        };
        char hrrBuf[1000];
        int hrrSz = sizeof(hrrBuf);

        XMEMSET(&test_ctx, 0, sizeof(test_ctx));

        ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
                params[i].client_meth, params[i].server_meth), 0);

        ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c2, NULL,
                params[i].client_meth, params[i].server_meth), 0);


        wolfSSL_SetLoggingPrefix("server");
        wolfSSL_dtls_set_using_nonblock(ssl_s, 1);

        initHash = test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl_s);

        /* Set groups and disable key shares. This ensures that only the given
         * groups are in the SupportedGroups extension and that an empty key
         * share extension is sent in the initial ClientHello of each session.
         * This triggers the server to send a HelloRetryRequest with the first
         * group in the SupportedGroups extension selected. */
        wolfSSL_SetLoggingPrefix("client1");
        ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups_1, 3), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c), WOLFSSL_SUCCESS);

        wolfSSL_SetLoggingPrefix("client2");
        ExpectIntEQ(wolfSSL_set_groups(ssl_c2, groups_2, 2), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c2), WOLFSSL_SUCCESS);

        /* Start handshake, send first ClientHello */
        wolfSSL_SetLoggingPrefix("client1");
        ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
        ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);

        /* Read first ClientHello, send HRR with WOLFSSL_ECC_SECP256R1 */
        wolfSSL_SetLoggingPrefix("server");
        ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), 0);
        ExpectIntEQ(test_memio_copy_message(&test_ctx, 1, hrrBuf, &hrrSz, 0), 0);
        ExpectIntGT(hrrSz, 0);
        ExpectIntEQ(initHash, test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl_s));
        test_memio_clear_buffer(&test_ctx, 1);

        /* Send second ClientHello */
        wolfSSL_SetLoggingPrefix("client2");
        ExpectIntEQ(wolfSSL_connect(ssl_c2), -1);
        ExpectIntEQ(wolfSSL_get_error(ssl_c2, -1), WOLFSSL_ERROR_WANT_READ);

        /* Read second ClientHello, send HRR now with WOLFSSL_ECC_SECP384R1 */
        wolfSSL_SetLoggingPrefix("server");
        ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), 0);
        ExpectIntEQ(initHash, test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl_s));
        test_memio_clear_buffer(&test_ctx, 1);

        /* Complete first handshake with WOLFSSL_ECC_SECP256R1 */
        wolfSSL_SetLoggingPrefix("client1");
        ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, hrrBuf, hrrSz), 0);
        ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
        ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);

        wolfSSL_SetLoggingPrefix("server");
        ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_SUCCESS);

        ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

        wolfSSL_free(ssl_s);
        wolfSSL_free(ssl_c);
        wolfSSL_free(ssl_c2);
        wolfSSL_CTX_free(ctx_s);
        wolfSSL_CTX_free(ctx_c);
    }
#endif /* WOLFSSL_SEND_HRR_COOKIE */
    return EXPECT_RESULT();
}
#else
static int test_wolfSSL_dtls_stateless(void)
{
    return TEST_SKIPPED;
}

static int test_wolfSSL_dtls_stateless_hrr_group(void)
{
    return TEST_SKIPPED;
}
#endif /* WOLFSSL_DTLS13 && WOLFSSL_SEND_HRR_COOKIE &&
        * HAVE_IO_TESTS_DEPENDENCIES && !SINGLE_THREADED */

#if defined(HAVE_KEYING_MATERIAL) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
static int test_export_keying_material_cb(WOLFSSL_CTX *ctx, WOLFSSL *ssl)
{
    EXPECT_DECLS;
    byte ekm[100] = {0};

    (void)ctx;

    /* Success Cases */
    ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
            "Test label", XSTR_SIZEOF("Test label"), NULL, 0, 0), 1);
    ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
            "Test label", XSTR_SIZEOF("Test label"), NULL, 0, 1), 1);
    /* Use some random context */
    ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
            "Test label", XSTR_SIZEOF("Test label"), ekm, 10, 1), 1);
    /* Failure cases */
    ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
            "client finished", XSTR_SIZEOF("client finished"), NULL, 0, 0), 0);
    ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
            "server finished", XSTR_SIZEOF("server finished"), NULL, 0, 0), 0);
    ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
            "master secret", XSTR_SIZEOF("master secret"), NULL, 0, 0), 0);
    ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
            "extended master secret", XSTR_SIZEOF("extended master secret"),
            NULL, 0, 0), 0);
    ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
            "key expansion", XSTR_SIZEOF("key expansion"), NULL, 0, 0), 0);
    /* contextLen overflow: values exceeding UINT16_MAX must be rejected to
     * prevent integer overflow in seedLen calculation (ZD #21242). */
    ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
            "Test label", XSTR_SIZEOF("Test label"), ekm,
            (size_t)0xFFFF + 1, 1), 0);

    return EXPECT_RESULT();
}

static int test_export_keying_material_ssl_cb(WOLFSSL* ssl)
{
    wolfSSL_KeepArrays(ssl);
    return TEST_SUCCESS;
}

static int test_export_keying_material(void)
{
    EXPECT_DECLS;
    test_ssl_cbf serverCb;
    test_ssl_cbf clientCb;

    XMEMSET(&serverCb, 0, sizeof(serverCb));
    XMEMSET(&clientCb, 0, sizeof(clientCb));
    clientCb.ssl_ready = test_export_keying_material_ssl_cb;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&clientCb,
        &serverCb, test_export_keying_material_cb), TEST_SUCCESS);

    return EXPECT_RESULT();
}
#endif /* HAVE_KEYING_MATERIAL */

static int test_wolfSSL_THREADID_hash(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    CRYPTO_THREADID id;

    CRYPTO_THREADID_current(NULL);
    /* Hash result is word32. */
    ExpectTrue(CRYPTO_THREADID_hash(NULL) == 0UL);
    XMEMSET(&id, 0, sizeof(id));
    ExpectTrue(CRYPTO_THREADID_hash(&id) == 0UL);
#endif /* OPENSSL_EXTRA */
    return EXPECT_RESULT();
}
static int test_wolfSSL_set_ecdh_auto(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    WOLFSSL* ssl = NULL;

    ExpectIntEQ(SSL_set_ecdh_auto(NULL,0), 1);
    ExpectIntEQ(SSL_set_ecdh_auto(NULL,1), 1);
    ExpectIntEQ(SSL_set_ecdh_auto(ssl,0), 1);
    ExpectIntEQ(SSL_set_ecdh_auto(ssl,1), 1);
#endif /* OPENSSL_EXTRA */
    return EXPECT_RESULT();
}
static int test_wolfSSL_CTX_set_ecdh_auto(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    WOLFSSL_CTX* ctx = NULL;

    ExpectIntEQ(SSL_CTX_set_ecdh_auto(NULL,0), 1);
    ExpectIntEQ(SSL_CTX_set_ecdh_auto(NULL,1), 1);
    ExpectIntEQ(SSL_CTX_set_ecdh_auto(ctx,0), 1);
    ExpectIntEQ(SSL_CTX_set_ecdh_auto(ctx,1), 1);
#endif /* OPENSSL_EXTRA */
    return EXPECT_RESULT();
}

#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL) && \
    defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12)
static THREAD_RETURN WOLFSSL_THREAD SSL_read_test_server_thread(void* args)
{
    EXPECT_DECLS;
    callback_functions* callbacks = NULL;
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL*     ssl = NULL;
    SOCKET_T     sfd = 0;
    SOCKET_T     cfd = 0;
    word16       port;
    char msg[] = "I hear you fa shizzle!";
    int  len   = (int) XSTRLEN(msg);
    char input[1024];
    int  ret = 0;
    int  err = 0;

    if (!args)
        WOLFSSL_RETURN_FROM_THREAD(0);

    ((func_args*)args)->return_code = TEST_FAIL;

    callbacks   = ((func_args*)args)->callbacks;
    ctx         = wolfSSL_CTX_new(callbacks->method());

#if defined(USE_WINDOWS_API)
    port = ((func_args*)args)->signal->port;
#else
    /* Let tcp_listen assign port */
    port = 0;
#endif

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_load_verify_locations(ctx,
        caCertFile, 0));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_use_certificate_file(ctx,
        svrCertFile, WOLFSSL_FILETYPE_PEM));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_use_PrivateKey_file(ctx,
        svrKeyFile, WOLFSSL_FILETYPE_PEM));

#if !defined(NO_FILESYSTEM) && !defined(NO_DH)
    ExpectIntEQ(wolfSSL_CTX_SetTmpDH_file(ctx, dhParamFile,
            WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
#elif !defined(NO_DH)
    SetDHCtx(ctx);  /* will repick suites with DHE, higher priority than PSK */
#endif

    if (callbacks->ctx_ready)
        callbacks->ctx_ready(ctx);

    ssl = wolfSSL_new(ctx);
    ExpectNotNull(ssl);

    /* listen and accept */
    tcp_accept(&sfd, &cfd, (func_args*)args, port, 0, 0, 0, 0, 1, 0, 0);
    CloseSocket(sfd);

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_set_fd(ssl, cfd));

    if (callbacks->ssl_ready)
        callbacks->ssl_ready(ssl);

    if (EXPECT_SUCCESS()) {
        do {
            err = 0; /* Reset error */
            ret = wolfSSL_accept(ssl);
            if (ret != WOLFSSL_SUCCESS) {
                err = wolfSSL_get_error(ssl, 0);
            }
        } while (ret != WOLFSSL_SUCCESS && err == WC_NO_ERR_TRACE(WC_PENDING_E));
    }

    ExpectIntEQ(ret, WOLFSSL_SUCCESS);

    /* read and write data */
    XMEMSET(input, 0, sizeof(input));

    while (EXPECT_SUCCESS()) {
        ret = wolfSSL_read(ssl, input, sizeof(input));
        if (ret > 0) {
            break;
        }
        else {
            err = wolfSSL_get_error(ssl,ret);
            if (err == WOLFSSL_ERROR_WANT_READ) {
                continue;
            }
            break;
        }
    }

    if (EXPECT_SUCCESS() && (err == WOLFSSL_ERROR_ZERO_RETURN)) {
        do {
            ret = wolfSSL_write(ssl, msg, len);
            if (ret > 0) {
                break;
            }
        } while (ret < 0);
    }

    /* bidirectional shutdown */
    while (EXPECT_SUCCESS()) {
        ret = wolfSSL_shutdown(ssl);
        ExpectIntNE(ret, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
        if (ret == WOLFSSL_SUCCESS) {
            break;
        }
    }

    if (EXPECT_SUCCESS()) {
        /* wait for the peer to disconnect the tcp connection */
        do {
            ret = wolfSSL_read(ssl, input, sizeof(input));
            err = wolfSSL_get_error(ssl, ret);
        } while (ret > 0 || err != WOLFSSL_ERROR_ZERO_RETURN);
    }

    /* detect TCP disconnect */
    ExpectIntLE(ret,WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_get_error(ssl, ret), WOLFSSL_ERROR_ZERO_RETURN);

    ((func_args*)args)->return_code = EXPECT_RESULT();

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
    CloseSocket(cfd);
#if defined(HAVE_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS)
    wc_ecc_fp_free();  /* free per thread cache */
#endif
    WOLFSSL_RETURN_FROM_THREAD(0);
}
static THREAD_RETURN WOLFSSL_THREAD SSL_read_test_client_thread(void* args)
{
    EXPECT_DECLS;
    callback_functions* callbacks = NULL;
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL*     ssl = NULL;
    SOCKET_T     sfd = 0;
    char msg[] = "hello wolfssl server!";
    int  len   = (int) XSTRLEN(msg);
    char input[1024];
    int  idx = 0;
    int  ret = 0, err = 0;

    if (!args)
        WOLFSSL_RETURN_FROM_THREAD(0);

    ((func_args*)args)->return_code = TEST_FAIL;
    callbacks   = ((func_args*)args)->callbacks;
    ctx         = wolfSSL_CTX_new(callbacks->method());

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_load_verify_locations(ctx,
        caCertFile, 0));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_use_certificate_file(ctx,
        cliCertFile, WOLFSSL_FILETYPE_PEM));

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_use_PrivateKey_file(ctx,
        cliKeyFile, WOLFSSL_FILETYPE_PEM));

    ExpectNotNull((ssl = wolfSSL_new(ctx)));

    tcp_connect(&sfd, wolfSSLIP, ((func_args*)args)->signal->port, 0, 0, ssl);

    ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_set_fd(ssl, sfd));

    if (EXPECT_SUCCESS()) {
        do {
            err = 0; /* Reset error */
            ret = wolfSSL_connect(ssl);
            if (ret != WOLFSSL_SUCCESS) {
                err = wolfSSL_get_error(ssl, 0);
            }
        } while (ret != WOLFSSL_SUCCESS && err == WC_NO_ERR_TRACE(WC_PENDING_E));
    }

    ExpectIntGE(wolfSSL_write(ssl, msg, len), 0);

    if (EXPECT_SUCCESS()) {
        if (0 < (idx = wolfSSL_read(ssl, input, sizeof(input)-1))) {
            input[idx] = 0;
        }
    }

    if (EXPECT_SUCCESS()) {
        ret = wolfSSL_shutdown(ssl);
        if (ret == WC_NO_ERR_TRACE(WOLFSSL_SHUTDOWN_NOT_DONE)) {
            ret = wolfSSL_shutdown(ssl);
        }
    }
    ExpectIntEQ(ret, WOLFSSL_SUCCESS);

    ((func_args*)args)->return_code = EXPECT_RESULT();

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);
    CloseSocket(sfd);
#if defined(HAVE_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS)
    wc_ecc_fp_free();  /* free per thread cache */
#endif
    WOLFSSL_RETURN_FROM_THREAD(0);
}
#endif /* OPENSSL_EXTRA && WOLFSSL_ERROR_CODE_OPENSSL &&
          HAVE_IO_TESTS_DEPENDENCIES && !WOLFSSL_NO_TLS12 */

/* This test is to check wolfSSL_read behaves as same as
 * openSSL when it is called after SSL_shutdown completes.
 */
static int test_wolfSSL_read_detect_TCP_disconnect(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL) && \
    defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12)
    tcp_ready ready;
    func_args client_args;
    func_args server_args;
    THREAD_TYPE serverThread;
    THREAD_TYPE clientThread;
    callback_functions server_cbf;
    callback_functions client_cbf;

#ifdef WOLFSSL_TIRTOS
    fdOpenSession(Task_self());
#endif
    StartTCP();
    InitTcpReady(&ready);

    XMEMSET(&client_args, 0, sizeof(func_args));
    XMEMSET(&server_args, 0, sizeof(func_args));

    XMEMSET(&server_cbf, 0, sizeof(callback_functions));
    XMEMSET(&client_cbf, 0, sizeof(callback_functions));

    server_cbf.method = wolfTLSv1_2_server_method;
    client_cbf.method = wolfTLSv1_2_client_method;

    server_args.callbacks = &server_cbf;
    client_args.callbacks = &client_cbf;

    server_args.signal = &ready;
    client_args.signal = &ready;

    start_thread(SSL_read_test_server_thread, &server_args, &serverThread);

    wait_tcp_ready(&server_args);

    start_thread(SSL_read_test_client_thread, &client_args, &clientThread);

    join_thread(clientThread);
    join_thread(serverThread);

    ExpectTrue(client_args.return_code);
    ExpectTrue(server_args.return_code);

    FreeTcpReady(&ready);
#endif
    return EXPECT_RESULT();
}
static int test_wolfSSL_CTX_get_min_proto_version(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_TLS)
    WOLFSSL_CTX *ctx = NULL;

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method()));
    ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, SSL3_VERSION),
        WOLFSSL_SUCCESS);
    #ifdef WOLFSSL_ALLOW_SSLV3
        ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx), SSL3_VERSION);
    #else
        ExpectIntGT(wolfSSL_CTX_get_min_proto_version(ctx), SSL3_VERSION);
    #endif
    wolfSSL_CTX_free(ctx);
    ctx = NULL;

    #ifndef NO_OLD_TLS
    #ifdef WOLFSSL_ALLOW_TLSV10
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_method()));
    #else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method()));
    #endif
    ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, TLS1_VERSION),
        WOLFSSL_SUCCESS);
    #ifdef WOLFSSL_ALLOW_TLSV10
        ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx), TLS1_VERSION);
    #else
        ExpectIntGT(wolfSSL_CTX_get_min_proto_version(ctx), TLS1_VERSION);
    #endif
    wolfSSL_CTX_free(ctx);
    ctx = NULL;
    #endif

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method()));
    ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION),
        WOLFSSL_SUCCESS);
    #ifndef NO_OLD_TLS
        ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx), TLS1_1_VERSION);
    #else
        ExpectIntGT(wolfSSL_CTX_get_min_proto_version(ctx), TLS1_1_VERSION);
    #endif
    wolfSSL_CTX_free(ctx);
    ctx = NULL;

    #ifndef WOLFSSL_NO_TLS12
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_method()));
        ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION),
            WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx), TLS1_2_VERSION);
        wolfSSL_CTX_free(ctx);
        ctx = NULL;
    #endif

    #ifdef WOLFSSL_TLS13
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_method()));
        ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION),
            WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx), TLS1_3_VERSION);
        wolfSSL_CTX_free(ctx);
        ctx = NULL;
    #endif
#endif
    return EXPECT_RESULT();
}

#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \
    (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \
    defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \
    defined(WOLFSSL_OPENSSH) || defined(HAVE_SBLIM_SFCB)))
static int test_wolfSSL_set_SSL_CTX(void)
{
    EXPECT_DECLS;
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) \
    && !defined(WOLFSSL_NO_TLS12) && defined(WOLFSSL_TLS13) && \
    !defined(NO_RSA)  && !defined(NO_WOLFSSL_SERVER)
    WOLFSSL_CTX *ctx1 = NULL;
    WOLFSSL_CTX *ctx2 = NULL;
    WOLFSSL *ssl = NULL;
    const byte *session_id1 = (const byte *)"CTX1";
    const byte *session_id2 = (const byte *)"CTX2";

    ExpectNotNull(ctx1 = wolfSSL_CTX_new(wolfTLS_server_method()));
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx1, svrCertFile,
        WOLFSSL_FILETYPE_PEM));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx1, svrKeyFile,
        WOLFSSL_FILETYPE_PEM));
    ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx1, TLS1_2_VERSION),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx1), TLS1_2_VERSION);
    ExpectIntEQ(wolfSSL_CTX_get_max_proto_version(ctx1), TLS1_3_VERSION);
    ExpectIntEQ(wolfSSL_CTX_set_session_id_context(ctx1, session_id1, 4),
        WOLFSSL_SUCCESS);

    ExpectNotNull(ctx2 = wolfSSL_CTX_new(wolfTLS_server_method()));
    ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx2, svrCertFile,
        WOLFSSL_FILETYPE_PEM));
    ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx2, svrKeyFile,
        WOLFSSL_FILETYPE_PEM));
    ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx2, TLS1_2_VERSION),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx2, TLS1_2_VERSION),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx2), TLS1_2_VERSION);
    ExpectIntEQ(wolfSSL_CTX_get_max_proto_version(ctx2), TLS1_2_VERSION);
    ExpectIntEQ(wolfSSL_CTX_set_session_id_context(ctx2, session_id2, 4),
        WOLFSSL_SUCCESS);

#ifdef HAVE_SESSION_TICKET
    ExpectIntEQ((wolfSSL_CTX_get_options(ctx1) & SSL_OP_NO_TICKET), 0);
    wolfSSL_CTX_set_options(ctx2, SSL_OP_NO_TICKET);
    ExpectIntNE((wolfSSL_CTX_get_options(ctx2) & SSL_OP_NO_TICKET), 0);
#endif

    ExpectNotNull(ssl = wolfSSL_new(ctx2));
    ExpectIntNE((wolfSSL_get_options(ssl) & WOLFSSL_OP_NO_TLSv1_3), 0);
#ifdef WOLFSSL_INT_H
#ifdef WOLFSSL_SESSION_ID_CTX
    ExpectIntEQ(XMEMCMP(ssl->sessionCtx, session_id2, 4), 0);
#endif
#ifdef WOLFSSL_COPY_CERT
    if (ctx2 != NULL && ctx2->certificate != NULL) {
        ExpectFalse(ssl->buffers.certificate == ctx2->certificate);
    }
    if (ctx2 != NULL && ctx2->certChain != NULL) {
        ExpectFalse(ssl->buffers.certChain == ctx2->certChain);
    }
#else
    ExpectTrue(ssl->buffers.certificate == ctx2->certificate);
    ExpectTrue(ssl->buffers.certChain == ctx2->certChain);
#endif
#endif

#ifdef HAVE_SESSION_TICKET
    ExpectIntNE((wolfSSL_get_options(ssl) & SSL_OP_NO_TICKET), 0);
#endif

    /* Set the ctx1 that has TLSv1.3 as max proto version */
    ExpectNotNull(wolfSSL_set_SSL_CTX(ssl, ctx1));

    /* MUST not change proto versions of ssl */
    ExpectIntNE((wolfSSL_get_options(ssl) & WOLFSSL_OP_NO_TLSv1_3), 0);
#ifdef HAVE_SESSION_TICKET
    /* MUST not change */
    ExpectIntNE((wolfSSL_get_options(ssl) & SSL_OP_NO_TICKET), 0);
#endif
    /* MUST change */
#ifdef WOLFSSL_INT_H
#ifdef WOLFSSL_COPY_CERT
    if (ctx1 != NULL && ctx1->certificate != NULL) {
        ExpectFalse(ssl->buffers.certificate == ctx1->certificate);
    }
    if (ctx1 != NULL && ctx1->certChain != NULL) {
        ExpectFalse(ssl->buffers.certChain == ctx1->certChain);
    }
#else
    ExpectTrue(ssl->buffers.certificate == ctx1->certificate);
    ExpectTrue(ssl->buffers.certChain == ctx1->certChain);
#endif
#ifdef WOLFSSL_SESSION_ID_CTX
    ExpectIntEQ(XMEMCMP(ssl->sessionCtx, session_id1, 4), 0);
#endif
#endif

    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx1);
    wolfSSL_CTX_free(ctx2);
#endif /* defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) */
    return EXPECT_RESULT();
}
#endif /* defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \
    (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \
    defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \
    defined(WOLFSSL_OPENSSH) || defined(HAVE_SBLIM_SFCB))) */

static int test_wolfSSL_security_level(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    SSL_CTX *ctx = NULL;

    #ifdef WOLFSSL_TLS13
        #ifdef NO_WOLFSSL_SERVER
            ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
        #else
            ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
        #endif
        SSL_CTX_set_security_level(NULL, 1);
        SSL_CTX_set_security_level(ctx, 1);
        #if defined(WOLFSSL_SYS_CRYPTO_POLICY)
        ExpectIntEQ(SSL_CTX_get_security_level(NULL), BAD_FUNC_ARG);
        #else
        ExpectIntEQ(SSL_CTX_get_security_level(NULL), 0);
        #endif /* WOLFSSL_SYS_CRYPTO_POLICY */
        /* Stub so nothing happens. */
        ExpectIntEQ(SSL_CTX_get_security_level(ctx), 0);

        SSL_CTX_free(ctx);
    #else
        (void)ctx;
    #endif
#endif
    return EXPECT_RESULT();
}

/* System wide crypto-policy test.
 *
 * Loads three different policies (legacy, default, future),
 * then tests crypt_policy api.
 * */
static int test_wolfSSL_crypto_policy(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_SYS_CRYPTO_POLICY) && !defined(NO_TLS)
    int          rc = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
    const char * policy_list[] = {
        "examples/crypto_policies/legacy/wolfssl.txt",
        "examples/crypto_policies/default/wolfssl.txt",
        "examples/crypto_policies/future/wolfssl.txt",
    };
    const char * ciphers_list[] = {
        "@SECLEVEL=1:EECDH:kRSA:EDH:PSK:DHEPSK:ECDHEPSK:RSAPSK"
        ":!eNULL:!aNULL",
        "@SECLEVEL=2:EECDH:kRSA:EDH:PSK:DHEPSK:ECDHEPSK:RSAPSK"
        ":!RC4:!eNULL:!aNULL",
        "@SECLEVEL=3:EECDH:EDH:PSK:DHEPSK:ECDHEPSK:!RSAPSK:!kRSA"
        ":!AES128:!RC4:!eNULL:!aNULL:!SHA1",
    };
    int          seclevel_list[] = { 1, 2, 3 };
    int          i = 0;

    for (i = 0; i < 3; ++i) {
        const char *  ciphers = NULL;
        int           n_diff = 0;
        WOLFSSL_CTX * ctx = NULL;
        WOLFSSL     * ssl = NULL;

        /* Enable crypto policy. */
        rc = wolfSSL_crypto_policy_enable(policy_list[i]);
        ExpectIntEQ(rc, WOLFSSL_SUCCESS);

        rc = wolfSSL_crypto_policy_is_enabled();
        ExpectIntEQ(rc, 1);

        /* Trying to enable while already enabled should return
         * forbidden. */
        rc = wolfSSL_crypto_policy_enable(policy_list[i]);
        ExpectIntEQ(rc, CRYPTO_POLICY_FORBIDDEN);

        /* Security level and ciphers should match what is expected. */
        rc = wolfSSL_crypto_policy_get_level();
        ExpectIntEQ(rc, seclevel_list[i]);

        ciphers = wolfSSL_crypto_policy_get_ciphers();
        ExpectNotNull(ciphers);

        if (ciphers != NULL) {
            n_diff = XSTRNCMP(ciphers, ciphers_list[i], strlen(ciphers));
            #ifdef DEBUG_WOLFSSL
            if (n_diff) {
                printf("error: got \n%s, expected \n%s\n",
                       ciphers, ciphers_list[i]);
            }
            #endif /* DEBUG_WOLFSSL */
            ExpectIntEQ(n_diff, 0);
        }

        /* TLSv1_2_method should work for all policies. */
        ctx = wolfSSL_CTX_new(wolfTLSv1_2_method());
        ExpectNotNull(ctx);

        if (ctx != NULL) {
            ssl = wolfSSL_new(ctx);
            ExpectNotNull(ssl);

            /* These API should be rejected while enabled. */
            rc = wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_3);
            ExpectIntEQ(rc, CRYPTO_POLICY_FORBIDDEN);

            rc = wolfSSL_SetMinVersion(ssl, WOLFSSL_TLSV1_3);
            ExpectIntEQ(rc, CRYPTO_POLICY_FORBIDDEN);
        }

        if (ctx != NULL) {
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }

        if (ssl != NULL) {
            wolfSSL_free(ssl);
            ssl = NULL;
        }

        wolfSSL_crypto_policy_disable();

        /* Do the same test by buffer. */
        rc = wolfSSL_crypto_policy_enable_buffer(ciphers_list[i]);
        ExpectIntEQ(rc, WOLFSSL_SUCCESS);

        rc = wolfSSL_crypto_policy_is_enabled();
        ExpectIntEQ(rc, 1);

        /* Security level and ciphers should match what is expected. */
        rc = wolfSSL_crypto_policy_get_level();
        ExpectIntEQ(rc, seclevel_list[i]);

        ciphers = wolfSSL_crypto_policy_get_ciphers();
        ExpectNotNull(ciphers);

        if (ciphers != NULL) {
            n_diff = XSTRNCMP(ciphers, ciphers_list[i], strlen(ciphers));
            #ifdef DEBUG_WOLFSSL
            if (n_diff) {
                printf("error: got \n%s, expected \n%s\n",
                       ciphers, ciphers_list[i]);
            }
            #endif /* DEBUG_WOLFSSL */
            ExpectIntEQ(n_diff, 0);
        }

        wolfSSL_crypto_policy_disable();
    }

    wolfSSL_crypto_policy_disable();

#endif /* WOLFSSL_SYS_CRYPTO_POLICY && !NO_TLS */
    return EXPECT_RESULT();
}

/* System wide crypto-policy test: certs and keys.
 *
 * Loads three different policies (legacy, default, future),
 * then tests loading different certificates and keys of
 * varying strength.
 * */
static int test_wolfSSL_crypto_policy_certs_and_keys(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_SYS_CRYPTO_POLICY) && !defined(NO_TLS)
    int          rc = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
    const char * policy_list[] = {
        "examples/crypto_policies/legacy/wolfssl.txt",
        "examples/crypto_policies/default/wolfssl.txt",
        "examples/crypto_policies/future/wolfssl.txt",
    };
    int          i = 0;

    for (i = 0; i < 3; ++i) {
        WOLFSSL_CTX * ctx = NULL;
        WOLFSSL     * ssl = NULL;
        int           is_legacy = 0;
        int           is_future = 0;
        /* certs */
        const char *  cert1024 = "certs/1024/client-cert.pem";
        const char *  cert2048 = "certs/client-cert.pem";
        const char *  cert3072 = "certs/3072/client-cert.pem";
        const char *  cert256 = "certs/client-ecc-cert.pem";
        const char *  cert384 = "certs/client-ecc384-cert.pem";
        /* keys */
        const char *  key1024 = "certs/1024/client-key.pem";
        const char *  key2048 = "certs/client-key.pem";
        const char *  key3072 = "certs/3072/client-key.pem";
        const char *  key256 = "certs/ecc-key.pem";
        const char *  key384 = "certs/client-ecc384-key.pem";

        is_legacy = (XSTRSTR(policy_list[i], "legacy") != NULL) ? 1 : 0;
        is_future = (XSTRSTR(policy_list[i], "future") != NULL) ? 1 : 0;

        /* Enable crypto policy. */
        rc = wolfSSL_crypto_policy_enable(policy_list[i]);
        ExpectIntEQ(rc, WOLFSSL_SUCCESS);

        rc = wolfSSL_crypto_policy_is_enabled();
        ExpectIntEQ(rc, 1);

        /* TLSv1_2_method should work for all policies. */
        ctx = wolfSSL_CTX_new(wolfTLSv1_2_method());
        ExpectNotNull(ctx);

        /* Test certs of varying strength. */
        if (ctx != NULL) {
            /* VERIFY_PEER must be set for key/cert checks to be done. */
            wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);

            /* Test loading a cert with 1024 RSA key size.
             * This should fail for all but legacy. */
            rc = wolfSSL_CTX_use_certificate_chain_file(ctx, cert1024);

            if (is_legacy) {
                ExpectIntEQ(rc, WOLFSSL_SUCCESS);
            }
            else {
                ExpectIntEQ(rc, WOLFSSL_FAILURE);
            }

            /* Test loading a cert with 2048 RSA key size.
             * Future crypto-policy is min 3072 RSA and DH key size,
             * and should fail. */
            rc = wolfSSL_CTX_use_certificate_chain_file(ctx, cert2048);

            if (is_future) {
                /* Future crypto-policy is min 3072 RSA and DH key size, this
                 * and should fail. */
                ExpectIntEQ(rc, WOLFSSL_FAILURE);

                /* Set to VERIFY_NONE. This will disable key size checks,
                 * it should now succeed. */
                wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL);
                rc = wolfSSL_CTX_use_certificate_chain_file(ctx, cert2048);

                ExpectIntEQ(rc, WOLFSSL_SUCCESS);

                /* Set back to verify peer. */
                wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);

            }
            else {
                ExpectIntEQ(rc, WOLFSSL_SUCCESS);
            }

            /* Test loading a CA cert with 3072 RSA key size.
             * This should succeed for all policies. */
            rc = wolfSSL_CTX_use_certificate_chain_file(ctx, cert3072);
            ExpectIntEQ(rc, WOLFSSL_SUCCESS);

            /* Test loading an ecc cert with 256 key size.
             * This should succeed for all policies. */
            rc = wolfSSL_CTX_use_certificate_chain_file(ctx, cert256);
            ExpectIntEQ(rc, WOLFSSL_SUCCESS);

            /* Test loading an ecc cert with 384 key size.
             * This should succeed for all policies. */
            rc = wolfSSL_CTX_use_certificate_chain_file(ctx, cert384);
            ExpectIntEQ(rc, WOLFSSL_SUCCESS);

            /* cleanup */
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }

        /* TLSv1_2_method should work for all policies. */
        ctx = wolfSSL_CTX_new(wolfTLSv1_2_method());
        ExpectNotNull(ctx);

        /* Repeat same tests for keys of varying strength. */
        if (ctx != NULL) {
            /* 1024 RSA */
            rc = SSL_CTX_use_PrivateKey_file(ctx, key1024,
                                             SSL_FILETYPE_PEM);

            if (is_legacy) {
                ExpectIntEQ(rc, WOLFSSL_SUCCESS);
            }
            else {
                ExpectIntEQ(rc, WOLFSSL_FAILURE);
            }

            /* 2048 RSA */
            rc = SSL_CTX_use_PrivateKey_file(ctx, key2048,
                                             SSL_FILETYPE_PEM);

            if (!is_future) {
                ExpectIntEQ(rc, WOLFSSL_SUCCESS);
            }
            else {
                ExpectIntEQ(rc, WOLFSSL_FAILURE);
            }

            /* 3072 RSA */
            rc = SSL_CTX_use_PrivateKey_file(ctx, key3072,
                                             SSL_FILETYPE_PEM);
            ExpectIntEQ(rc, WOLFSSL_SUCCESS);

            /* 256 ecc */
            rc = SSL_CTX_use_PrivateKey_file(ctx, key256,
                                             SSL_FILETYPE_PEM);
            ExpectIntEQ(rc, WOLFSSL_SUCCESS);

            /* 384 ecc */
            rc = SSL_CTX_use_PrivateKey_file(ctx, key384,
                                             SSL_FILETYPE_PEM);
            ExpectIntEQ(rc, WOLFSSL_SUCCESS);

            /* cleanup */
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }

        #ifdef HAVE_ECC
        /* Test set ecc min key size. */
        ctx = wolfSSL_CTX_new(wolfTLSv1_2_method());
        ExpectNotNull(ctx);

        if (ctx != NULL) {
            ssl = SSL_new(ctx);
            ExpectNotNull(ssl);

            /* Test setting ctx. */
            rc = wolfSSL_CTX_SetMinEccKey_Sz(ctx, 160);
            if (is_legacy) {
                ExpectIntEQ(rc, WOLFSSL_SUCCESS);
            }
            else {
                ExpectIntEQ(rc, CRYPTO_POLICY_FORBIDDEN);
            }

            rc = wolfSSL_CTX_SetMinEccKey_Sz(ctx, 224);
            if (!is_future) {
                ExpectIntEQ(rc, WOLFSSL_SUCCESS);
            }
            else {
                ExpectIntEQ(rc, CRYPTO_POLICY_FORBIDDEN);
            }

            rc = wolfSSL_CTX_SetMinEccKey_Sz(ctx, 256);
            ExpectIntEQ(rc, WOLFSSL_SUCCESS);

            /* Test setting ssl. */
            if (ssl != NULL) {
                rc = wolfSSL_SetMinEccKey_Sz(ssl, 160);
                if (is_legacy) {
                    ExpectIntEQ(rc, WOLFSSL_SUCCESS);
                }
                else {
                    ExpectIntEQ(rc, CRYPTO_POLICY_FORBIDDEN);
                }

                rc = wolfSSL_SetMinEccKey_Sz(ssl, 224);
                if (!is_future) {
                    ExpectIntEQ(rc, WOLFSSL_SUCCESS);
                }
                else {
                    ExpectIntEQ(rc, CRYPTO_POLICY_FORBIDDEN);
                }

                rc = wolfSSL_SetMinEccKey_Sz(ssl, 256);
                ExpectIntEQ(rc, WOLFSSL_SUCCESS);

                wolfSSL_free(ssl);
                ssl = NULL;
            }

            /* cleanup */
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }
        #endif /* HAVE_ECC */

        #if !defined(NO_RSA)
        /* Test set rsa min key size. */
        ctx = wolfSSL_CTX_new(wolfTLSv1_2_method());
        ExpectNotNull(ctx);

        if (ctx != NULL) {
            ssl = SSL_new(ctx);
            ExpectNotNull(ssl);

            /* Test setting ctx. */
            rc = wolfSSL_CTX_SetMinRsaKey_Sz(ctx, 1024);
            if (is_legacy) {
                ExpectIntEQ(rc, WOLFSSL_SUCCESS);
            }
            else {
                ExpectIntEQ(rc, CRYPTO_POLICY_FORBIDDEN);
            }

            rc = wolfSSL_CTX_SetMinRsaKey_Sz(ctx, 2048);
            if (!is_future) {
                ExpectIntEQ(rc, WOLFSSL_SUCCESS);
            }
            else {
                ExpectIntEQ(rc, CRYPTO_POLICY_FORBIDDEN);
            }

            rc = wolfSSL_CTX_SetMinRsaKey_Sz(ctx, 3072);
            ExpectIntEQ(rc, WOLFSSL_SUCCESS);

            /* Test setting ssl. */
            if (ssl != NULL) {
                rc = wolfSSL_SetMinRsaKey_Sz(ssl, 1024);
                if (is_legacy) {
                    ExpectIntEQ(rc, WOLFSSL_SUCCESS);
                }
                else {
                    ExpectIntEQ(rc, CRYPTO_POLICY_FORBIDDEN);
                }

                rc = wolfSSL_SetMinRsaKey_Sz(ssl, 2048);
                if (!is_future) {
                    ExpectIntEQ(rc, WOLFSSL_SUCCESS);
                }
                else {
                    ExpectIntEQ(rc, CRYPTO_POLICY_FORBIDDEN);
                }

                rc = wolfSSL_SetMinRsaKey_Sz(ssl, 3072);
                ExpectIntEQ(rc, WOLFSSL_SUCCESS);

                wolfSSL_free(ssl);
                ssl = NULL;
            }

            /* cleanup */
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }
        #endif /* !NO_RSA */

        wolfSSL_crypto_policy_disable();
    }

    wolfSSL_crypto_policy_disable();
#endif /* WOLFSSL_SYS_CRYPTO_POLICY && !NO_TLS */
    return EXPECT_RESULT();
}

/* System wide crypto-policy test: tls and dtls methods.
 * */
static int test_wolfSSL_crypto_policy_tls_methods(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_SYS_CRYPTO_POLICY) && !defined(NO_TLS)
    int          rc = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
    const char * policy_list[] = {
        "examples/crypto_policies/legacy/wolfssl.txt",
        "examples/crypto_policies/default/wolfssl.txt",
        "examples/crypto_policies/future/wolfssl.txt",
    };
    int          i = 0;

    for (i = 0; i < 3; ++i) {
        WOLFSSL_CTX * ctx = NULL;
        int           is_legacy = 0;

        is_legacy = (XSTRSTR(policy_list[i], "legacy") != NULL) ? 1 : 0;

        /* Enable crypto policy. */
        rc = wolfSSL_crypto_policy_enable(policy_list[i]);
        ExpectIntEQ(rc, WOLFSSL_SUCCESS);

        rc = wolfSSL_crypto_policy_is_enabled();
        ExpectIntEQ(rc, 1);

        /* Try to use old TLS methods. Only allowed with legacy. */
        #if !defined(NO_OLD_TLS)
        ctx = wolfSSL_CTX_new(wolfTLSv1_1_method());

        if (is_legacy) {
            ExpectNotNull(ctx);
        }
        else {
            ExpectNull(ctx);
        }

        if (ctx != NULL) {
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }

        #if defined(WOLFSSL_ALLOW_TLSV10)
        ctx = wolfSSL_CTX_new(wolfTLSv1_method());

        if (is_legacy) {
            ExpectNotNull(ctx);
        }
        else {
            ExpectNull(ctx);
        }

        if (ctx != NULL) {
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }
        #endif /* WOLFSSL_ALLOW_TLSV10 */
        #else
        (void) is_legacy;
        #endif /* !NO_OLD_TLS */

        /* TLSv1_2_method should work for all policies. */
        ctx = wolfSSL_CTX_new(wolfTLSv1_2_method());
        ExpectNotNull(ctx);

        if (ctx != NULL) {
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }

        ctx = wolfSSL_CTX_new(wolfTLSv1_3_method());
        ExpectNotNull(ctx);

        if (ctx != NULL) {
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }

        ctx = wolfSSL_CTX_new(TLS_method());
        ExpectNotNull(ctx);

        if (ctx != NULL) {
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }

        #ifdef WOLFSSL_DTLS
        ctx = wolfSSL_CTX_new(DTLS_method());
        ExpectNotNull(ctx);

        if (ctx != NULL) {
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }

        ctx = wolfSSL_CTX_new(wolfDTLSv1_2_method());
        ExpectNotNull(ctx);

        if (ctx != NULL) {
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }

        #ifndef NO_OLD_TLS
        /* Only allowed with legacy. */
        ctx = wolfSSL_CTX_new(wolfDTLSv1_method());

        if (is_legacy) {
            ExpectNotNull(ctx);
        }
        else {
            ExpectNull(ctx);
        }

        if (ctx != NULL) {
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }
        #endif /* !NO_OLD_TLS */
        #endif /* WOLFSSL_DTLS */

        wolfSSL_crypto_policy_disable();
    }

    wolfSSL_crypto_policy_disable();
#endif /* WOLFSSL_SYS_CRYPTO_POLICY && !NO_TLS */
    return EXPECT_RESULT();
}

#if defined(WOLFSSL_SYS_CRYPTO_POLICY) && !defined(NO_TLS)
/*  Helper function for test_wolfSSL_crypto_policy_ciphers.
 *  Searches ssl suites for cipher string.
 *
 *  Returns   1 if found.
 *  Returns   0 if not found.
 *  Returns < 0 if error.
 * */
static int crypto_policy_cipher_found(const WOLFSSL * ssl,
                                      const char *    cipher,
                                      int             match)
{
    WOLF_STACK_OF(WOLFSSL_CIPHER) * sk = NULL;
    WOLFSSL_CIPHER *                current = NULL;
    const char *                    suite;
    int                             found = 0;
    int                             i = 0;

    if (ssl == NULL || cipher == NULL || *cipher == '\0') {
        return -1;
    }

    sk = wolfSSL_get_ciphers_compat(ssl);

    if (sk == NULL) {
        return -1;
    }

    do {
        current = wolfSSL_sk_SSL_CIPHER_value(sk, i++);
        if (current) {
            suite = wolfSSL_CIPHER_get_name(current);
            if (suite) {
                if (match == 1) {
                    /* prefix match */
                    if (XSTRNCMP(suite, cipher, XSTRLEN(cipher)) == 0) {
                        found = 1;
                        break;
                    }
                }
                else if (match == -1) {
                    /* postfix match */
                    if (XSTRLEN(suite) > XSTRLEN(cipher)) {
                        const char * postfix = suite + XSTRLEN(suite)
                                               - XSTRLEN(cipher);
                        if (XSTRNCMP(postfix, cipher, XSTRLEN(cipher)) == 0) {
                            found = 1;
                            break;
                        }
                    }
                }
                else {
                    /* needle in haystack match */
                    if (XSTRSTR(suite, cipher)) {
                        found = 1;
                        break;
                    }
                }
            }
        }
    } while (current);

    return found == 1;
}
#endif /* WOLFSSL_SYS_CRYPTO_POLICY && !NO_TLS */

/* System wide crypto-policy test: ciphers.
 * */
static int test_wolfSSL_crypto_policy_ciphers(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_SYS_CRYPTO_POLICY) && !defined(NO_TLS)
    int          rc = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
    const char * policy_list[] = {
        "examples/crypto_policies/legacy/wolfssl.txt",
        "examples/crypto_policies/default/wolfssl.txt",
        "examples/crypto_policies/future/wolfssl.txt",
    };
    int          seclevel_list[] = { 1, 2, 3 };
    int          i = 0;
    int          is_legacy = 0;
    int          is_future = 0;

    for (i = 0; i < 3; ++i) {
        WOLFSSL_CTX * ctx = NULL;
        WOLFSSL     * ssl = NULL;
        int           found = 0;

        is_legacy = (XSTRSTR(policy_list[i], "legacy") != NULL) ? 1 : 0;
        is_future = (XSTRSTR(policy_list[i], "future") != NULL) ? 1 : 0;

        (void) is_legacy;

        /* Enable crypto policy. */
        rc = wolfSSL_crypto_policy_enable(policy_list[i]);
        ExpectIntEQ(rc, WOLFSSL_SUCCESS);

        rc = wolfSSL_crypto_policy_is_enabled();
        ExpectIntEQ(rc, 1);

        ctx = wolfSSL_CTX_new(TLS_method());
        ExpectNotNull(ctx);

        ssl = SSL_new(ctx);
        ExpectNotNull(ssl);

        rc = wolfSSL_CTX_get_security_level(ctx);
        ExpectIntEQ(rc, seclevel_list[i]);

        rc = wolfSSL_get_security_level(ssl);
        ExpectIntEQ(rc, seclevel_list[i]);

        found = crypto_policy_cipher_found(ssl, "RC4", 0);
        ExpectIntEQ(found, is_legacy);

        /* We return a different cipher string depending on build settings. */
        #if !defined(WOLFSSL_CIPHER_INTERNALNAME) && \
        !defined(NO_ERROR_STRINGS) && !defined(WOLFSSL_QT)
        found = crypto_policy_cipher_found(ssl, "AES_128", 0);
        ExpectIntEQ(found, !is_future);

        found = crypto_policy_cipher_found(ssl, "TLS_DHE_RSA_WITH_AES", 1);
        ExpectIntEQ(found, !is_future);

        found = crypto_policy_cipher_found(ssl, "_SHA", -1);
        ExpectIntEQ(found, !is_future);
        #else
        found = crypto_policy_cipher_found(ssl, "AES128", 0);
        ExpectIntEQ(found, !is_future);

        found = crypto_policy_cipher_found(ssl, "DHE-RSA-AES", 1);
        ExpectIntEQ(found, !is_future);

        found = crypto_policy_cipher_found(ssl, "-SHA", -1);
        ExpectIntEQ(found, !is_future);
        #endif

        if (ssl != NULL) {
            SSL_free(ssl);
            ssl = NULL;
        }

        if (ctx != NULL) {
            wolfSSL_CTX_free(ctx);
            ctx = NULL;
        }

        wolfSSL_crypto_policy_disable();
    }

    wolfSSL_crypto_policy_disable();

#endif /* WOLFSSL_SYS_CRYPTO_POLICY && !NO_TLS */
    return EXPECT_RESULT();
}

static int test_wolfSSL_SSL_in_init(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_BIO) && !defined(NO_TLS)
    SSL_CTX* ctx = NULL;
    SSL*     ssl = NULL;
    const char* testCertFile;
    const char* testKeyFile;

#ifdef WOLFSSL_TLS13
    #ifdef NO_WOLFSSL_SERVER
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
    #else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
    #endif
#else
    #ifdef NO_WOLFSSL_SERVER
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    #else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
    #endif
#endif
#ifndef NO_RSA
    testCertFile = svrCertFile;
    testKeyFile = svrKeyFile;
#elif defined(HAVE_ECC)
    testCertFile = eccCertFile;
    testKeyFile = eccKeyFile;
#else
    testCertFile = NULL;
    testKeyFile = NULL;
#endif
    if ((testCertFile != NULL) && (testKeyFile != NULL)) {
        ExpectTrue(SSL_CTX_use_certificate_file(ctx, testCertFile,
            SSL_FILETYPE_PEM));
        ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, testKeyFile,
            SSL_FILETYPE_PEM));
    }

    ExpectNotNull(ssl = SSL_new(ctx));
    ExpectIntEQ(SSL_in_init(ssl), 1);

    SSL_CTX_free(ctx);
    SSL_free(ssl);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_set_timeout(void)
{
    EXPECT_DECLS;
#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) && \
    !defined(NO_SESSION_CACHE)
    WOLFSSL_CTX* ctx = NULL;
#if defined(WOLFSSL_ERROR_CODE_OPENSSL)
    int timeout;
#endif

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));

#if defined(WOLFSSL_ERROR_CODE_OPENSSL)
    /* in WOLFSSL_ERROR_CODE_OPENSSL macro guard,
     * wolfSSL_CTX_set_timeout returns previous timeout value on success.
     */
    ExpectIntEQ(wolfSSL_CTX_set_timeout(NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* giving 0 as timeout value sets default timeout */
    timeout = wolfSSL_CTX_set_timeout(ctx, 0);
    ExpectIntEQ(wolfSSL_CTX_set_timeout(ctx, 20), timeout);
    ExpectIntEQ(wolfSSL_CTX_set_timeout(ctx, 30), 20);

#else
    ExpectIntEQ(wolfSSL_CTX_set_timeout(NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wolfSSL_CTX_set_timeout(ctx, 100), 1);
    ExpectIntEQ(wolfSSL_CTX_set_timeout(ctx, 0), 1);
#endif

    wolfSSL_CTX_free(ctx);
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_OpenSSL_version(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
    const char* ver;

#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L
    ExpectNotNull(ver = OpenSSL_version(0));
#else
    ExpectNotNull(ver = OpenSSL_version());
#endif
    ExpectIntEQ(XMEMCMP(ver, "wolfSSL " LIBWOLFSSL_VERSION_STRING,
        XSTRLEN("wolfSSL " LIBWOLFSSL_VERSION_STRING)), 0);
#endif
    return EXPECT_RESULT();
}

static int test_CONF_CTX_CMDLINE(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_TLS) && !defined(NO_WOLFSSL_SERVER)
    SSL_CTX* ctx = NULL;
    SSL_CONF_CTX* cctx = NULL;

    ExpectNotNull(cctx = SSL_CONF_CTX_new());

    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
    SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);

    /* set flags */
    ExpectIntEQ(SSL_CONF_CTX_set_flags(cctx, WOLFSSL_CONF_FLAG_CMDLINE),
        WOLFSSL_CONF_FLAG_CMDLINE);
    ExpectIntEQ(SSL_CONF_CTX_set_flags(cctx, WOLFSSL_CONF_FLAG_CERTIFICATE),
        WOLFSSL_CONF_FLAG_CMDLINE | WOLFSSL_CONF_FLAG_CERTIFICATE);
    /* cmd invalid command */
    ExpectIntEQ(SSL_CONF_cmd(cctx, "foo", "foobar"), -2);
    ExpectIntEQ(SSL_CONF_cmd(cctx, "foo", NULL), -2);
    ExpectIntEQ(SSL_CONF_cmd(cctx, NULL, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_CONF_cmd(cctx, NULL, "foobar"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_CONF_cmd(NULL, "-curves", "foobar"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    /* cmd Certificate and Private Key*/
    {
    #if !defined(NO_CERTS) && !defined(NO_RSA)
        const char*  ourCert = svrCertFile;
        const char*  ourKey  = svrKeyFile;

        ExpectIntEQ(SSL_CONF_cmd(cctx, "-cert", NULL), -3);
        ExpectIntEQ(SSL_CONF_cmd(cctx, "-cert", ourCert), WOLFSSL_SUCCESS);
        ExpectIntEQ(SSL_CONF_cmd(cctx, "-key", NULL), -3);
        ExpectIntEQ(SSL_CONF_cmd(cctx, "-key", ourKey), WOLFSSL_SUCCESS);
        ExpectIntEQ(SSL_CONF_CTX_finish(cctx), WOLFSSL_SUCCESS);
    #endif
    }

    /* cmd curves */
    {
    #if defined(HAVE_ECC)
        const char* curve = "secp256r1";

        ExpectIntEQ(SSL_CONF_cmd(cctx, "-curves", NULL), -3);
        ExpectIntEQ(SSL_CONF_cmd(cctx, "-curves", curve), WOLFSSL_SUCCESS);
        ExpectIntEQ(SSL_CONF_CTX_finish(cctx), WOLFSSL_SUCCESS);
    #endif
    }

    /* cmd CipherString */
    {
        char* cipher = wolfSSL_get_cipher_list(0/*top priority*/);

        ExpectIntEQ(SSL_CONF_cmd(cctx, "-cipher", NULL), -3);
        ExpectIntEQ(SSL_CONF_cmd(cctx, "-cipher", cipher), WOLFSSL_SUCCESS);
        ExpectIntEQ(SSL_CONF_CTX_finish(cctx), WOLFSSL_SUCCESS);
    }

    /* cmd DH parameter */
    {
    #if !defined(NO_DH) && !defined(NO_BIO)
        const char* ourdhcert = "./certs/dh2048.pem";

        ExpectIntEQ(SSL_CONF_cmd(cctx, "-dhparam", NULL), -3);
        ExpectIntEQ(SSL_CONF_cmd(cctx, "-dhparam", ourdhcert), WOLFSSL_SUCCESS);
        ExpectIntEQ(SSL_CONF_CTX_finish(cctx), WOLFSSL_SUCCESS);

    #endif
    }

    SSL_CTX_free(ctx);
    SSL_CONF_CTX_free(cctx);
#endif /* OPENSSL_EXTRA */
    return EXPECT_RESULT();
}

static int test_CONF_CTX_FILE(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_TLS) && !defined(NO_WOLFSSL_SERVER)
    SSL_CTX* ctx = NULL;
    SSL_CONF_CTX* cctx = NULL;

    ExpectNotNull(cctx = SSL_CONF_CTX_new());
    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
    SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);

    /* set flags */
    ExpectIntEQ(SSL_CONF_CTX_set_flags(cctx, WOLFSSL_CONF_FLAG_FILE),
        WOLFSSL_CONF_FLAG_FILE);
    ExpectIntEQ(SSL_CONF_CTX_set_flags(cctx, WOLFSSL_CONF_FLAG_CERTIFICATE),
        WOLFSSL_CONF_FLAG_FILE | WOLFSSL_CONF_FLAG_CERTIFICATE);
    /* sanity check */
    ExpectIntEQ(SSL_CONF_cmd(cctx, "foo", "foobar"), -2);
    ExpectIntEQ(SSL_CONF_cmd(cctx, "foo", NULL), -2);
    ExpectIntEQ(SSL_CONF_cmd(cctx, NULL, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_CONF_cmd(cctx, NULL, "foobar"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(SSL_CONF_cmd(NULL, "-curves", "foobar"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

    /* cmd Certificate and Private Key*/
    {
    #if !defined(NO_CERTS) && !defined(NO_RSA)
        const char*  ourCert = svrCertFile;
        const char*  ourKey  = svrKeyFile;

        ExpectIntEQ(SSL_CONF_cmd(cctx, "Certificate", NULL), -3);
        ExpectIntEQ(SSL_CONF_cmd(cctx, "PrivateKey", NULL), -3);

        ExpectIntEQ(SSL_CONF_cmd(cctx, "Certificate", ourCert),
            WOLFSSL_SUCCESS);
        ExpectIntEQ(SSL_CONF_cmd(cctx, "PrivateKey", ourKey), WOLFSSL_SUCCESS);
        ExpectIntEQ(SSL_CONF_CTX_finish(cctx), WOLFSSL_SUCCESS);
    #endif
    }

    /* cmd curves */
    {
    #if defined(HAVE_ECC)
        const char* curve = "secp256r1";

        ExpectIntEQ(SSL_CONF_cmd(cctx, "Curves", NULL), -3);
        ExpectIntEQ(SSL_CONF_cmd(cctx, "Curves", curve), WOLFSSL_SUCCESS);
        ExpectIntEQ(SSL_CONF_CTX_finish(cctx), WOLFSSL_SUCCESS);
    #endif
    }

    /* cmd CipherString */
    {
        char* cipher = wolfSSL_get_cipher_list(0/*top priority*/);

        ExpectIntEQ(SSL_CONF_cmd(cctx, "CipherString", NULL), -3);
        ExpectIntEQ(SSL_CONF_cmd(cctx, "CipherString", cipher),
            WOLFSSL_SUCCESS);
        ExpectIntEQ(SSL_CONF_CTX_finish(cctx), WOLFSSL_SUCCESS);
    }

    /* cmd DH parameter */
    {
    #if !defined(NO_DH) && !defined(NO_BIO) && defined(HAVE_FFDHE_3072)
        const char* ourdhcert = "./certs/dh3072.pem";

        ExpectIntEQ(SSL_CONF_cmd(cctx, "DHParameters", NULL), -3);
        ExpectIntEQ(SSL_CONF_cmd(cctx, "DHParameters", ourdhcert),
            WOLFSSL_SUCCESS);
        ExpectIntEQ(SSL_CONF_CTX_finish(cctx), WOLFSSL_SUCCESS);

    #endif
    }

    SSL_CTX_free(ctx);
    SSL_CONF_CTX_free(cctx);
#endif /* OPENSSL_EXTRA */
    return EXPECT_RESULT();
}

static int test_wolfSSL_CRYPTO_get_ex_new_index(void)
{
    EXPECT_DECLS;
#ifdef HAVE_EX_DATA_CRYPTO
    int idx1, idx2;

    /* test for unsupported class index */
    ExpectIntEQ(wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_X509_STORE,
        0,NULL, NULL, NULL, NULL ), -1);
    ExpectIntEQ(wolfSSL_CRYPTO_get_ex_new_index(
        WOLF_CRYPTO_EX_INDEX_X509_STORE_CTX,
        0,NULL, NULL, NULL, NULL ), -1);
    ExpectIntEQ(wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_DH,
        0,NULL, NULL, NULL, NULL ), -1);
    ExpectIntEQ(wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_DSA,
        0,NULL, NULL, NULL, NULL ), -1);
    ExpectIntEQ(wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_EC_KEY,
        0,NULL, NULL, NULL, NULL ), -1);
    ExpectIntEQ(wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_RSA,
        0,NULL, NULL, NULL, NULL ), -1);
    ExpectIntEQ(wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_ENGINE,
        0,NULL, NULL, NULL, NULL ), -1);
    ExpectIntEQ(wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_UI,
        0,NULL, NULL, NULL, NULL ), -1);
    ExpectIntEQ(wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_BIO,
        0,NULL, NULL, NULL, NULL ), -1);
    ExpectIntEQ(wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_APP,
        0,NULL, NULL, NULL, NULL ), -1);
    ExpectIntEQ(wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_UI_METHOD,
        0,NULL, NULL, NULL, NULL ), -1);
    ExpectIntEQ(wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_DRBG,
        0,NULL, NULL, NULL, NULL ), -1);
    ExpectIntEQ(wolfSSL_CRYPTO_get_ex_new_index(20,
        0,NULL, NULL, NULL, NULL ), -1);

    /* test for supported class index */
    idx1 = wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL,
        0,NULL, NULL, NULL, NULL );
    idx2 = wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL,
        0,NULL, NULL, NULL, NULL );
    ExpectIntNE(idx1, -1);
    ExpectIntNE(idx2, -1);
    ExpectIntNE(idx1, idx2);

    idx1 = wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL_CTX,
        0,NULL, NULL, NULL, NULL );
    idx2 = wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL_CTX,
        0,NULL, NULL, NULL, NULL );
    ExpectIntNE(idx1, -1);
    ExpectIntNE(idx2, -1);
    ExpectIntNE(idx1, idx2);

    idx1 = wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_X509,
        0,NULL, NULL, NULL, NULL );
    idx2 = wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_X509,
        0,NULL, NULL, NULL, NULL );
    ExpectIntNE(idx1, -1);
    ExpectIntNE(idx2, -1);
    ExpectIntNE(idx1, idx2);


    idx1 = wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL_SESSION,
        0,NULL, NULL, NULL, NULL );
    idx2 = wolfSSL_CRYPTO_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL_SESSION,
        0,NULL, NULL, NULL, NULL );
    ExpectIntNE(idx1, -1);
    ExpectIntNE(idx2, -1);
    ExpectIntNE(idx1, idx2);
#endif /* HAVE_EX_DATA_CRYPTO */
    return EXPECT_RESULT();
}

#if defined(HAVE_EX_DATA_CRYPTO) && defined(OPENSSL_EXTRA)

#define SESSION_NEW_IDX_LONG 0xDEADBEEF
#define SESSION_NEW_IDX_VAL  ((void*)0xAEADAEAD)
#define SESSION_DUP_IDX_VAL  ((void*)0xDEDEDEDE)
#define SESSION_NEW_IDX_PTR  "Testing"

static void test_wolfSSL_SESSION_get_ex_new_index_new_cb(void* p, void* ptr,
        CRYPTO_EX_DATA* a, int idx, long argValue, void* arg)
{
    AssertNotNull(p);
    AssertNull(ptr);
    AssertIntEQ(CRYPTO_set_ex_data(a, idx, SESSION_NEW_IDX_VAL), SSL_SUCCESS);
    AssertIntEQ(argValue, SESSION_NEW_IDX_LONG);
    AssertStrEQ(arg, SESSION_NEW_IDX_PTR);
}

static int test_wolfSSL_SESSION_get_ex_new_index_dup_cb(CRYPTO_EX_DATA* out,
        const CRYPTO_EX_DATA* in, void* inPtr, int idx, long argV,
        void* arg)
{
    EXPECT_DECLS;

    ExpectNotNull(out);
    ExpectNotNull(in);
    ExpectPtrEq(*(void**)inPtr, SESSION_NEW_IDX_VAL);
    ExpectPtrEq(CRYPTO_get_ex_data(in, idx), SESSION_NEW_IDX_VAL);
    ExpectPtrEq(CRYPTO_get_ex_data(out, idx), SESSION_NEW_IDX_VAL);
    ExpectIntEQ(argV, SESSION_NEW_IDX_LONG);
    ExpectStrEQ(arg, SESSION_NEW_IDX_PTR);
    *(void**)inPtr = SESSION_DUP_IDX_VAL;
    if (EXPECT_SUCCESS()) {
        return SSL_SUCCESS;
    }
    else {
        return SSL_FAILURE;
    }
}

static int test_wolfSSL_SESSION_get_ex_new_index_free_cb_called = 0;
static void test_wolfSSL_SESSION_get_ex_new_index_free_cb(void* p, void* ptr,
        CRYPTO_EX_DATA* a, int idx, long argValue, void* arg)
{
    EXPECT_DECLS;

    ExpectNotNull(p);
    ExpectNull(ptr);
    ExpectPtrNE(CRYPTO_get_ex_data(a, idx), 0);
    ExpectIntEQ(argValue, SESSION_NEW_IDX_LONG);
    ExpectStrEQ(arg, SESSION_NEW_IDX_PTR);
    if (EXPECT_SUCCESS()) {
        test_wolfSSL_SESSION_get_ex_new_index_free_cb_called++;
    }
}

static int test_wolfSSL_SESSION_get_ex_new_index(void)
{
    EXPECT_DECLS;
    int idx = SSL_SESSION_get_ex_new_index(SESSION_NEW_IDX_LONG,
                (void*)SESSION_NEW_IDX_PTR,
                test_wolfSSL_SESSION_get_ex_new_index_new_cb,
                test_wolfSSL_SESSION_get_ex_new_index_dup_cb,
                test_wolfSSL_SESSION_get_ex_new_index_free_cb);
    SSL_SESSION* s = SSL_SESSION_new();
    SSL_SESSION* d = NULL;

    ExpectNotNull(s);
    ExpectPtrEq(SSL_SESSION_get_ex_data(s, idx), SESSION_NEW_IDX_VAL);
    ExpectNotNull(d = SSL_SESSION_dup(s));
    ExpectPtrEq(SSL_SESSION_get_ex_data(d, idx), SESSION_DUP_IDX_VAL);
    SSL_SESSION_free(s);
    ExpectIntEQ(test_wolfSSL_SESSION_get_ex_new_index_free_cb_called, 1);
    SSL_SESSION_free(d);
    ExpectIntEQ(test_wolfSSL_SESSION_get_ex_new_index_free_cb_called, 2);

    crypto_ex_cb_free(crypto_ex_cb_ctx_session);
    crypto_ex_cb_ctx_session = NULL;
    return EXPECT_RESULT();
}
#else
static int test_wolfSSL_SESSION_get_ex_new_index(void)
{
    return TEST_SKIPPED;
}
#endif

static int test_wolfSSL_set_psk_use_session_callback(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_PSK) && !defined(NO_TLS)
    SSL_CTX* ctx = NULL;
    SSL*     ssl = NULL;
    const char* testCertFile;
    const char* testKeyFile;

#ifdef WOLFSSL_TLS13
    #ifdef NO_WOLFSSL_SERVER
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
    #else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
    #endif
#else
    #ifdef NO_WOLFSSL_SERVER
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    #else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
    #endif
#endif
#ifndef NO_RSA
    testCertFile = svrCertFile;
    testKeyFile = svrKeyFile;
#elif defined(HAVE_ECC)
    testCertFile = eccCertFile;
    testKeyFile = eccKeyFile;
#else
    testCertFile = NULL;
    testKeyFile = NULL;
#endif
    if ((testCertFile != NULL) && (testKeyFile != NULL)) {
        ExpectTrue(SSL_CTX_use_certificate_file(ctx, testCertFile,
            SSL_FILETYPE_PEM));
        ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, testKeyFile,
            SSL_FILETYPE_PEM));
    }

    ExpectNotNull(ssl = SSL_new(ctx));

    SSL_set_psk_use_session_callback(ssl, my_psk_use_session_cb);

    SSL_CTX_free(ctx);
    SSL_free(ssl);
#endif
    return EXPECT_RESULT();
}

/* similar to error_test() in wolfcrypt/test/test.c, but adding error codes from
 * TLS layer.
 */
static int error_test(void)
{
    EXPECT_DECLS;
    const char* errStr;
    const char* unknownStr = wc_GetErrorString(WC_LAST_E - 1);

#ifdef NO_ERROR_STRINGS
    /* Ensure a valid error code's string matches an invalid code's.
     * The string is that error strings are not available.
     */
    errStr = wc_GetErrorString(OPEN_RAN_E);
    ExpectIntEQ(XSTRCMP(errStr, unknownStr), 0);
    if (EXPECT_FAIL())
        return OPEN_RAN_E;
#else
    int start_idx = 0;
    int i;
    int j = 0;
    /* Values that are not or no longer error codes. */
    static const struct {
        int first;
        int last;
    } missing[] = {
#ifndef OPENSSL_EXTRA
        { 0, 0 },
#endif

#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
    defined(HAVE_WEBSERVER) || defined(HAVE_MEMCACHED)
        {11, 11},
        {17, 15},
        {19, 19},
        {24, 24},
        {27, 26 },
        {61, 30},
        {63, 63},
        {78, 65},
#endif
        { -9, WC_SPAN1_FIRST_E + 1 },
        { -300, -300 },
        { -335, -336 },
        { -346, -349 },
        { -356, -356 },
        { -358, -358 },
        { -384, -384 },
        { -466, -499 },
        { WOLFSSL_LAST_E - 1, WC_SPAN2_FIRST_E + 1 },
        { WC_SPAN2_LAST_E - 1, MIN_CODE_E }
    };

    /* Check that all errors have a string and it's the same through the two
     * APIs. Check that the values that are not errors map to the unknown
     * string.
     */
#if defined(OPENSSL_EXTRA)
    start_idx = WC_OSSL_V509_V_ERR_MAX - 1;
#endif
    for (i = start_idx; i >= MIN_CODE_E; i--) {
        int this_missing = 0;
        for (j = 0; j < (int)XELEM_CNT(missing); ++j) {
            if ((i <= missing[j].first) && (i >= missing[j].last)) {
                this_missing = 1;
                break;
            }
        }
        errStr = wolfSSL_ERR_reason_error_string((word32)i);

        if (! this_missing) {
            ExpectIntNE(XSTRCMP(errStr, unknownStr), 0);
            if (EXPECT_FAIL()) {
                return i;
            }
            ExpectTrue(XSTRLEN(errStr) < WOLFSSL_MAX_ERROR_SZ);
            if (EXPECT_FAIL()) {
                return i;
            }
        }
        else {
            j++;
            ExpectIntEQ(XSTRCMP(errStr, unknownStr), 0);
            if (EXPECT_FAIL()) {
                return i;
            }
        }
    }
#endif

    return 1;
}

static int test_wolfSSL_ERR_strings(void)
{
    EXPECT_DECLS;

#if !defined(NO_ERROR_STRINGS)
    const char* err1 = "unsupported cipher suite";
    const char* err2 = "wolfSSL PEM routines";
    const char* err  = NULL;

    (void)err;
    (void)err1;
    (void)err2;

#if defined(OPENSSL_EXTRA)
    ExpectNotNull(err = ERR_reason_error_string(WC_NO_ERR_TRACE(UNSUPPORTED_SUITE)));
    ExpectIntEQ(XSTRNCMP(err, err1, XSTRLEN(err1)), 0);

    ExpectNotNull(err = ERR_func_error_string(WC_NO_ERR_TRACE(UNSUPPORTED_SUITE)));
    ExpectIntEQ((*err == '\0'), 1);

    ExpectNotNull(err = ERR_lib_error_string(PEM_R_PROBLEMS_GETTING_PASSWORD));
    ExpectIntEQ(XSTRNCMP(err, err2, XSTRLEN(err2)), 0);
#else
    ExpectNotNull(err = wolfSSL_ERR_reason_error_string(WC_NO_ERR_TRACE((word32)UNSUPPORTED_SUITE)));
    ExpectIntEQ(XSTRNCMP(err, err1, XSTRLEN(err1)), 0);

    ExpectNotNull(err = wolfSSL_ERR_func_error_string(WC_NO_ERR_TRACE((word32)UNSUPPORTED_SUITE)));
    ExpectIntEQ((*err == '\0'), 1);

    ExpectNotNull(err = wolfSSL_ERR_lib_error_string(-WOLFSSL_PEM_R_PROBLEMS_GETTING_PASSWORD_E));
    ExpectIntEQ((*err == '\0'), 1);
#endif
#endif

    ExpectIntEQ(error_test(), 1);

    return EXPECT_RESULT();
}

static int test_SSL_CIPHER_get_xxx(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_CERTS) && \
    !defined(NO_FILESYSTEM) && !defined(NO_TLS)
    const SSL_CIPHER* cipher = NULL;
    STACK_OF(SSL_CIPHER) *supportedCiphers = NULL;
    int i, numCiphers = 0;
    SSL_CTX* ctx = NULL;
    SSL*     ssl = NULL;
    const char* testCertFile;
    const char* testKeyFile;
    char buf[256] = {0};

    const char* cipher_id = NULL;
    int   expect_nid1 = NID_undef;
    int   expect_nid2 = NID_undef;
    int   expect_nid3 = NID_undef;
    int   expect_nid4 = NID_undef;
    int   expect_nid5 = 0;

    const char* cipher_id2 = NULL;
    int   expect_nid21 = NID_undef;
    int   expect_nid22 = NID_undef;
    int   expect_nid23 = NID_undef;
    int   expect_nid24 = NID_undef;
    int   expect_nid25 = 0;

    (void)cipher;
    (void)supportedCiphers;
    (void)i;
    (void)numCiphers;
    (void)ctx;
    (void)ssl;
    (void)testCertFile;
    (void)testKeyFile;

#if defined(WOLFSSL_TLS13)
    cipher_id = "TLS13-AES128-GCM-SHA256";
    expect_nid1 = NID_auth_rsa;
    expect_nid2 = NID_aes_128_gcm;
    expect_nid3 = NID_sha256;
    expect_nid4 = NID_kx_any;
    expect_nid5 = 1;

    #if !defined(WOLFSSL_NO_TLS12)
    cipher_id2 = "ECDHE-RSA-AES256-GCM-SHA384";
    expect_nid21 = NID_auth_rsa;
    expect_nid22 = NID_aes_256_gcm;
    expect_nid23 = NID_sha384;
    expect_nid24 = NID_kx_ecdhe;
    expect_nid25 = 1;
    #endif
#endif

    #ifdef NO_WOLFSSL_SERVER
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
    #else
        ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
    #endif

    if (cipher_id) {
    #ifndef NO_RSA
        testCertFile = svrCertFile;
        testKeyFile = svrKeyFile;
    #elif defined(HAVE_ECC)
        testCertFile = eccCertFile;
        testKeyFile = eccKeyFile;
    #else
        testCertFile = NULL;
        testKeyFile = NULL;
    #endif
        if  (testCertFile != NULL && testKeyFile != NULL) {
            ExpectTrue(SSL_CTX_use_certificate_file(ctx, testCertFile,
                                                    SSL_FILETYPE_PEM));
            ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, testKeyFile,
                                                    SSL_FILETYPE_PEM));
        }

        ExpectNotNull(ssl = SSL_new(ctx));
        ExpectIntEQ(SSL_in_init(ssl), 1);

        supportedCiphers = SSL_get_ciphers(ssl);
        numCiphers = sk_num(supportedCiphers);

        for (i = 0; i < numCiphers; ++i) {

            if ((cipher = (const WOLFSSL_CIPHER*)sk_value(supportedCiphers, i))) {
                SSL_CIPHER_description(cipher, buf, sizeof(buf));
            }

            if (XMEMCMP(cipher_id, buf, XSTRLEN(cipher_id)) == 0) {
                break;
            }
        }
        /* test case for */
        if (i != numCiphers) {
            ExpectIntEQ(wolfSSL_CIPHER_get_auth_nid(cipher), expect_nid1);
            ExpectIntEQ(wolfSSL_CIPHER_get_cipher_nid(cipher), expect_nid2);
            ExpectIntEQ(wolfSSL_CIPHER_get_digest_nid(cipher), expect_nid3);
            ExpectIntEQ(wolfSSL_CIPHER_get_kx_nid(cipher), expect_nid4);
            ExpectIntEQ(wolfSSL_CIPHER_is_aead(cipher), expect_nid5);
        }

        if (cipher_id2) {

            for (i = 0; i < numCiphers; ++i) {

                if ((cipher = (const WOLFSSL_CIPHER*)sk_value(supportedCiphers, i))) {
                    SSL_CIPHER_description(cipher, buf, sizeof(buf));
                }

                if (XMEMCMP(cipher_id2, buf, XSTRLEN(cipher_id2)) == 0) {
                    break;
                }
            }
            /* test case for */
            if (i != numCiphers) {
                ExpectIntEQ(wolfSSL_CIPHER_get_auth_nid(cipher), expect_nid21);
                ExpectIntEQ(wolfSSL_CIPHER_get_cipher_nid(cipher), expect_nid22);
                ExpectIntEQ(wolfSSL_CIPHER_get_digest_nid(cipher), expect_nid23);
                ExpectIntEQ(wolfSSL_CIPHER_get_kx_nid(cipher), expect_nid24);
                ExpectIntEQ(wolfSSL_CIPHER_is_aead(cipher), expect_nid25);
            }
        }
    }

    SSL_CTX_free(ctx);
    SSL_free(ssl);
#endif

    return EXPECT_RESULT();
}

#if defined(WOLF_CRYPTO_CB) && defined(HAVE_IO_TESTS_DEPENDENCIES) && \
    (!defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \
     !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA))

static int load_pem_key_file_as_der(const char* privKeyFile, DerBuffer** pDer,
    int* keyFormat)
{
    int ret;
    byte* key_buf = NULL;
    size_t key_sz = 0;
    EncryptedInfo encInfo;

    XMEMSET(&encInfo, 0, sizeof(encInfo));

    ret = load_file(privKeyFile, &key_buf, &key_sz);
    if (ret == 0) {
        ret = wc_PemToDer(key_buf, key_sz, PRIVATEKEY_TYPE, pDer,
            NULL, &encInfo, keyFormat);
    }

    if (key_buf != NULL) {
        XFREE(key_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); key_buf = NULL;
    }
    (void)encInfo; /* not used in this test */

#ifdef DEBUG_WOLFSSL
    fprintf(stderr, "%s (%d): Loading PEM %s (len %d) to DER (len %d)\n",
        (ret == 0) ? "Success" : "Failure", ret, privKeyFile, (int)key_sz,
        (*pDer)->length);
#endif

    return ret;
}
static int test_CryptoCb_Func(int thisDevId, wc_CryptoInfo* info, void* ctx)
{
    int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
    const char* privKeyFile = (const char*)ctx;
    DerBuffer* pDer = NULL;
    int keyFormat = 0;

    if (info->algo_type == WC_ALGO_TYPE_PK) {
    #ifdef DEBUG_WOLFSSL
        fprintf(stderr, "test_CryptoCb_Func: Pk Type %d\n", info->pk.type);
    #endif

    #ifndef NO_RSA
        if (info->pk.type == WC_PK_TYPE_RSA) {
            switch (info->pk.rsa.type) {
                case RSA_PUBLIC_ENCRYPT:
                case RSA_PUBLIC_DECRYPT:
                    /* perform software based RSA public op */
                    ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); /* fallback to software */
                    break;
                case RSA_PRIVATE_ENCRYPT:
                case RSA_PRIVATE_DECRYPT:
                {
                    RsaKey key;

                    /* perform software based RSA private op */
                #ifdef DEBUG_WOLFSSL
                    fprintf(stderr, "test_CryptoCb_Func: RSA Priv\n");
                #endif

                    ret = load_pem_key_file_as_der(privKeyFile, &pDer,
                        &keyFormat);
                    if (ret != 0) {
                        return ret;
                    }
                    ret = wc_InitRsaKey(&key, HEAP_HINT);
                    if (ret == 0) {
                        word32 keyIdx = 0;
                        /* load RSA private key and perform private transform */
                        ret = wc_RsaPrivateKeyDecode(pDer->buffer, &keyIdx,
                            &key, pDer->length);
                        if (ret == 0) {
                            ret = wc_RsaFunction(
                                info->pk.rsa.in, info->pk.rsa.inLen,
                                info->pk.rsa.out, info->pk.rsa.outLen,
                                info->pk.rsa.type, &key, info->pk.rsa.rng);
                        }
                        else {
                            /* if decode fails, then fall-back to software based crypto */
                            fprintf(stderr, "test_CryptoCb_Func: RSA private "
                                "key decode failed %d, falling back to "
                                "software\n", ret);
                            ret = CRYPTOCB_UNAVAILABLE;
                        }
                        wc_FreeRsaKey(&key);
                    }
                    wc_FreeDer(&pDer); pDer = NULL;
                    break;
                }
            }
        #ifdef DEBUG_WOLFSSL
            fprintf(stderr, "test_CryptoCb_Func: RSA Type %d, Ret %d, Out %d\n",
                info->pk.rsa.type, ret, *info->pk.rsa.outLen);
        #endif
        }
        #ifdef WOLF_CRYPTO_CB_RSA_PAD
        else if (info->pk.type == WC_PK_TYPE_RSA_PKCS ||
                 info->pk.type == WC_PK_TYPE_RSA_PSS  ||
                 info->pk.type == WC_PK_TYPE_RSA_OAEP) {
            RsaKey key;

            if (info->pk.rsa.type == RSA_PUBLIC_ENCRYPT ||
                info->pk.rsa.type == RSA_PUBLIC_DECRYPT) {
                /* Have all public key ops fall back to SW */
                return CRYPTOCB_UNAVAILABLE;
            }

            if (info->pk.rsa.padding == NULL) {
                return BAD_FUNC_ARG;
            }

            /* Initialize key */
            ret = load_pem_key_file_as_der(privKeyFile, &pDer,
                &keyFormat);
            if (ret != 0) {
                return ret;
            }

            ret = wc_InitRsaKey(&key, HEAP_HINT);
            if (ret == 0) {
                word32 keyIdx = 0;
                /* load RSA private key and perform private transform */
                ret = wc_RsaPrivateKeyDecode(pDer->buffer, &keyIdx,
                    &key, pDer->length);
            }
            /* Perform RSA operation */
            if ((ret == 0) && (info->pk.type == WC_PK_TYPE_RSA_PKCS)) {
            #if !defined(WOLFSSL_RSA_PUBLIC_ONLY) && !defined(WOLFSSL_RSA_VERIFY_ONLY)
                ret = wc_RsaSSL_Sign(info->pk.rsa.in, info->pk.rsa.inLen,
                    info->pk.rsa.out, *info->pk.rsa.outLen, &key,
                    info->pk.rsa.rng);
            #else
                ret = CRYPTOCB_UNAVAILABLE;
            #endif
            }
            if ((ret == 0) && (info->pk.type == WC_PK_TYPE_RSA_PSS)) {
            #ifdef WC_RSA_PSS
                ret = wc_RsaPSS_Sign_ex(info->pk.rsa.in, info->pk.rsa.inLen,
                    info->pk.rsa.out, *info->pk.rsa.outLen,
                    info->pk.rsa.padding->hash, info->pk.rsa.padding->mgf,
                    info->pk.rsa.padding->saltLen, &key, info->pk.rsa.rng);
            #else
                ret = CRYPTOCB_UNAVAILABLE;
            #endif
            }
            if ((ret == 0) && (info->pk.type == WC_PK_TYPE_RSA_OAEP)) {
            #if !defined(WC_NO_RSA_OAEP) || defined(WC_RSA_NO_PADDING)
                ret = wc_RsaPrivateDecrypt_ex(
                    info->pk.rsa.in, info->pk.rsa.inLen,
                    info->pk.rsa.out, *info->pk.rsa.outLen,
                    &key, WC_RSA_OAEP_PAD, info->pk.rsa.padding->hash,
                    info->pk.rsa.padding->mgf, info->pk.rsa.padding->label,
                    info->pk.rsa.padding->labelSz);
            #else
                ret = CRYPTOCB_UNAVAILABLE;
            #endif
            }

            if (ret > 0) {
                *info->pk.rsa.outLen = ret;
            }

            wc_FreeRsaKey(&key);
            wc_FreeDer(&pDer); pDer = NULL;
        }
        #endif /* ifdef WOLF_CRYPTO_CB_RSA_PAD */
    #endif /* !NO_RSA */
    #ifdef HAVE_ECC
        if (info->pk.type == WC_PK_TYPE_EC_KEYGEN) {
            /* mark this key as ephemeral */
            if (info->pk.eckg.key != NULL) {
                XSTRNCPY(info->pk.eckg.key->label, "ephemeral",
                    sizeof(info->pk.eckg.key->label));
                info->pk.eckg.key->labelLen = (int)XSTRLEN(info->pk.eckg.key->label);
            }
        }
        else if (info->pk.type == WC_PK_TYPE_ECDSA_SIGN) {
            ecc_key key;

            /* perform software based ECC sign */
        #ifdef DEBUG_WOLFSSL
            fprintf(stderr, "test_CryptoCb_Func: ECC Sign\n");
        #endif

            if (info->pk.eccsign.key != NULL &&
                XSTRCMP(info->pk.eccsign.key->label, "ephemeral") == 0) {
                /* this is an empheral key */
            #ifdef DEBUG_WOLFSSL
                fprintf(stderr, "test_CryptoCb_Func: skipping signing op on "
                    "ephemeral key\n");
            #endif
                return CRYPTOCB_UNAVAILABLE;
            }

            ret = load_pem_key_file_as_der(privKeyFile, &pDer, &keyFormat);
            if (ret != 0) {
                return ret;
            }

            ret = wc_ecc_init(&key);
            if (ret == 0) {
                word32 keyIdx = 0;
                /* load ECC private key and perform private transform */
                ret = wc_EccPrivateKeyDecode(pDer->buffer, &keyIdx,
                    &key, pDer->length);
                if (ret == 0) {
                    ret = wc_ecc_sign_hash(
                        info->pk.eccsign.in, info->pk.eccsign.inlen,
                        info->pk.eccsign.out, info->pk.eccsign.outlen,
                        info->pk.eccsign.rng, &key);
                }
                else {
                    /* if decode fails, then fall-back to software based crypto */
                    fprintf(stderr, "test_CryptoCb_Func: ECC private key "
                        "decode failed %d, falling back to software\n", ret);
                    ret = CRYPTOCB_UNAVAILABLE;
                }
                wc_ecc_free(&key);
            }
            wc_FreeDer(&pDer); pDer = NULL;

        #ifdef DEBUG_WOLFSSL
            fprintf(stderr, "test_CryptoCb_Func: ECC Ret %d, Out %d\n",
                ret, *info->pk.eccsign.outlen);
        #endif
        }
        else if (info->pk.type == WC_PK_TYPE_EC_GET_SIZE) {
            WC_DECLARE_VAR(tmpEcc, ecc_key, 1, NULL);
            WC_ALLOC_VAR(tmpEcc, ecc_key, 1, NULL);
            if (!WC_VAR_OK(tmpEcc)) {
                ret = MEMORY_E;
            }
            else {
                XMEMCPY(tmpEcc, info->pk.ecc_get_size.key, sizeof(ecc_key));
                tmpEcc->devId = INVALID_DEVID;
                *info->pk.ecc_get_size.keySize = wc_ecc_size(tmpEcc);
                WC_FREE_VAR(tmpEcc, NULL);
                ret = 0;
            }
        }
        else if (info->pk.type == WC_PK_TYPE_EC_GET_SIG_SIZE) {
            WC_DECLARE_VAR(tmpEcc, ecc_key, 1, NULL);
            WC_ALLOC_VAR(tmpEcc, ecc_key, 1, NULL);
            if (!WC_VAR_OK(tmpEcc)) {
                ret = MEMORY_E;
            }
            else {
                XMEMCPY(tmpEcc, info->pk.ecc_get_sig_size.key,
                    sizeof(ecc_key));
                tmpEcc->devId = INVALID_DEVID;
                *info->pk.ecc_get_sig_size.sigSize = wc_ecc_sig_size(tmpEcc);
                WC_FREE_VAR(tmpEcc, NULL);
                ret = 0;
            }
        }
    #endif /* HAVE_ECC */
    #ifdef HAVE_ED25519
        if (info->pk.type == WC_PK_TYPE_ED25519_SIGN) {
            ed25519_key key;

            /* perform software based ED25519 sign */
        #ifdef DEBUG_WOLFSSL
            fprintf(stderr, "test_CryptoCb_Func: ED25519 Sign\n");
        #endif

            ret = load_pem_key_file_as_der(privKeyFile, &pDer, &keyFormat);
            if (ret != 0) {
                return ret;
            }
            ret = wc_ed25519_init(&key);
            if (ret == 0) {
                word32 keyIdx = 0;
                /* load ED25519 private key and perform private transform */
                ret = wc_Ed25519PrivateKeyDecode(pDer->buffer, &keyIdx,
                    &key, pDer->length);
                if (ret == 0) {
                    /* calculate public key */
                    ret = wc_ed25519_make_public(&key, key.p, ED25519_PUB_KEY_SIZE);
                    if (ret == 0) {
                        key.pubKeySet = 1;
                        ret = wc_ed25519_sign_msg_ex(
                            info->pk.ed25519sign.in, info->pk.ed25519sign.inLen,
                            info->pk.ed25519sign.out, info->pk.ed25519sign.outLen,
                            &key, info->pk.ed25519sign.type,
                            info->pk.ed25519sign.context,
                            info->pk.ed25519sign.contextLen);
                    }
                }
                else {
                    /* if decode fails, then fall-back to software based crypto */
                    fprintf(stderr, "test_CryptoCb_Func: ED25519 private key "
                        "decode failed %d, falling back to software\n", ret);
                    ret = CRYPTOCB_UNAVAILABLE;
                }
                wc_ed25519_free(&key);
            }
            wc_FreeDer(&pDer); pDer = NULL;

        #ifdef DEBUG_WOLFSSL
            fprintf(stderr, "test_CryptoCb_Func: ED25519 Ret %d, Out %d\n",
                ret, *info->pk.ed25519sign.outLen);
        #endif
        }
    #endif /* HAVE_ED25519 */
    }
#ifdef WOLF_CRYPTO_CB_COPY
    else if (info->algo_type == WC_ALGO_TYPE_COPY) {
    #ifdef DEBUG_WOLFSSL
        fprintf(stderr, "test_CryptoCb_Func: Copy Algo=%d Type=%d\n",
                info->copy.algo, info->copy.type);
    #endif
        if (info->copy.algo == WC_ALGO_TYPE_HASH) {
            switch (info->copy.type) {
    #ifndef NO_SHA
                case WC_HASH_TYPE_SHA:
                {
                    wc_Sha* src = (wc_Sha*)info->copy.src;
                    wc_Sha* dst = (wc_Sha*)info->copy.dst;
                    src->devId = INVALID_DEVID;
                    ret = wc_ShaCopy(src, dst);
                    src->devId = thisDevId;
                    if (ret == 0) {
                        dst->devId = thisDevId;
                    }
                    break;
                }
    #endif
    #ifdef WOLFSSL_SHA224
                case WC_HASH_TYPE_SHA224:
                {
                    wc_Sha224* src = (wc_Sha224*)info->copy.src;
                    wc_Sha224* dst = (wc_Sha224*)info->copy.dst;
                    src->devId = INVALID_DEVID;
                    ret = wc_Sha224Copy(src, dst);
                    src->devId = thisDevId;
                    if (ret == 0) {
                        dst->devId = thisDevId;
                    }
                    break;
                }
    #endif
    #ifndef NO_SHA256
                case WC_HASH_TYPE_SHA256:
                {
                    wc_Sha256* src = (wc_Sha256*)info->copy.src;
                    wc_Sha256* dst = (wc_Sha256*)info->copy.dst;
                    /* set devId to invalid, so software is used */
                    src->devId = INVALID_DEVID;
                    ret = wc_Sha256Copy(src, dst);

                    /* reset devId */
                    src->devId = thisDevId;
                    if (ret == 0) {
                        /* Set the devId of the destination to the same */
                        /* since we used the software implementation of copy */
                        /* so dst would have been set to INVALID_DEVID */
                        dst->devId = thisDevId;
                    }
                    break;
                }
    #endif /* !NO_SHA256 */
    #ifdef WOLFSSL_SHA384
                case WC_HASH_TYPE_SHA384:
                {
                    wc_Sha384* src = (wc_Sha384*)info->copy.src;
                    wc_Sha384* dst = (wc_Sha384*)info->copy.dst;
                    src->devId = INVALID_DEVID;
                    ret = wc_Sha384Copy(src, dst);
                    src->devId = thisDevId;
                    if (ret == 0) {
                        dst->devId = thisDevId;
                    }
                    break;
                }
    #endif
    #ifdef WOLFSSL_SHA512
                case WC_HASH_TYPE_SHA512:
                {
                    wc_Sha512* src = (wc_Sha512*)info->copy.src;
                    wc_Sha512* dst = (wc_Sha512*)info->copy.dst;
                    src->devId = INVALID_DEVID;
                    ret = wc_Sha512Copy(src, dst);
                    src->devId = thisDevId;
                    if (ret == 0) {
                        dst->devId = thisDevId;
                    }
                    break;
                }
    #endif
    #if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_224)
                case WC_HASH_TYPE_SHA3_224:
                {
                    wc_Sha3* src = (wc_Sha3*)info->copy.src;
                    wc_Sha3* dst = (wc_Sha3*)info->copy.dst;
                    src->devId = INVALID_DEVID;
                    ret = wc_Sha3_224_Copy(src, dst);
                    src->devId = thisDevId;
                    if (ret == 0) {
                        dst->devId = thisDevId;
                    }
                    break;
                }
    #endif
    #if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_256)
                case WC_HASH_TYPE_SHA3_256:
                {
                    wc_Sha3* src = (wc_Sha3*)info->copy.src;
                    wc_Sha3* dst = (wc_Sha3*)info->copy.dst;
                    src->devId = INVALID_DEVID;
                    ret = wc_Sha3_256_Copy(src, dst);
                    src->devId = thisDevId;
                    if (ret == 0) {
                        dst->devId = thisDevId;
                    }
                    break;
                }
    #endif
    #if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_384)
                case WC_HASH_TYPE_SHA3_384:
                {
                    wc_Sha3* src = (wc_Sha3*)info->copy.src;
                    wc_Sha3* dst = (wc_Sha3*)info->copy.dst;
                    src->devId = INVALID_DEVID;
                    ret = wc_Sha3_384_Copy(src, dst);
                    src->devId = thisDevId;
                    if (ret == 0) {
                        dst->devId = thisDevId;
                    }
                    break;
                }
    #endif
    #if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_512)
                case WC_HASH_TYPE_SHA3_512:
                {
                    wc_Sha3* src = (wc_Sha3*)info->copy.src;
                    wc_Sha3* dst = (wc_Sha3*)info->copy.dst;
                    src->devId = INVALID_DEVID;
                    ret = wc_Sha3_512_Copy(src, dst);
                    src->devId = thisDevId;
                    if (ret == 0) {
                        dst->devId = thisDevId;
                    }
                    break;
                }
    #endif
                default:
                    ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
                    break;
            }
        }
        else {
            ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
        }
    }
#endif /* WOLF_CRYPTO_CB_COPY */
#ifdef WOLF_CRYPTO_CB_FREE
    else if (info->algo_type == WC_ALGO_TYPE_FREE) {
    #ifdef DEBUG_WOLFSSL
        fprintf(stderr, "test_CryptoCb_Func: Free Algo=%d Type=%d\n",
                info->free.algo, info->free.type);
    #endif

        if (info->free.algo == WC_ALGO_TYPE_HASH) {
            switch (info->free.type) {
    #ifndef NO_SHA
                case WC_HASH_TYPE_SHA:
                {
                    wc_Sha* sha = (wc_Sha*)info->free.obj;
                    sha->devId = INVALID_DEVID;
                    wc_ShaFree(sha);
                    ret = 0;
                    break;
                }
    #endif
    #ifdef WOLFSSL_SHA224
                case WC_HASH_TYPE_SHA224:
                {
                    wc_Sha224* sha = (wc_Sha224*)info->free.obj;
                    sha->devId = INVALID_DEVID;
                    wc_Sha224Free(sha);
                    ret = 0;
                    break;
                }
    #endif
    #ifndef NO_SHA256
                case WC_HASH_TYPE_SHA256:
                {
                    wc_Sha256* sha = (wc_Sha256*)info->free.obj;

                    /* set devId to invalid, so software is used */
                    sha->devId = INVALID_DEVID;

                    /* Call the actual free function */
                    wc_Sha256Free(sha);

                    /* Note: devId doesn't need to be restored as object is freed */
                    ret = 0;
                    break;
                }
    #endif
    #ifdef WOLFSSL_SHA384
                case WC_HASH_TYPE_SHA384:
                {
                    wc_Sha384* sha = (wc_Sha384*)info->free.obj;
                    sha->devId = INVALID_DEVID;
                    wc_Sha384Free(sha);
                    ret = 0;
                    break;
                }
    #endif
    #ifdef WOLFSSL_SHA512
                case WC_HASH_TYPE_SHA512:
                {
                    wc_Sha512* sha = (wc_Sha512*)info->free.obj;
                    sha->devId = INVALID_DEVID;
                    wc_Sha512Free(sha);
                    ret = 0;
                    break;
                }
    #endif
    #if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_224)
                case WC_HASH_TYPE_SHA3_224:
                {
                    wc_Sha3* sha = (wc_Sha3*)info->free.obj;
                    sha->devId = INVALID_DEVID;
                    wc_Sha3_224_Free(sha);
                    ret = 0;
                    break;
                }
    #endif
    #if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_256)
                case WC_HASH_TYPE_SHA3_256:
                {
                    wc_Sha3* sha = (wc_Sha3*)info->free.obj;
                    sha->devId = INVALID_DEVID;
                    wc_Sha3_256_Free(sha);
                    ret = 0;
                    break;
                }
    #endif
    #if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_384)
                case WC_HASH_TYPE_SHA3_384:
                {
                    wc_Sha3* sha = (wc_Sha3*)info->free.obj;
                    sha->devId = INVALID_DEVID;
                    wc_Sha3_384_Free(sha);
                    ret = 0;
                    break;
                }
    #endif
    #if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_512)
                case WC_HASH_TYPE_SHA3_512:
                {
                    wc_Sha3* sha = (wc_Sha3*)info->free.obj;
                    sha->devId = INVALID_DEVID;
                    wc_Sha3_512_Free(sha);
                    ret = 0;
                    break;
                }
    #endif
                default:
                    ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
                    break;
            }
        }
        else if (info->free.algo == WC_ALGO_TYPE_CIPHER) {
            switch (info->free.type) {
    #ifndef NO_AES
                case WC_CIPHER_AES:
                {
                    Aes* aes = (Aes*)info->free.obj;
                    aes->devId = INVALID_DEVID;
                    wc_AesFree(aes);
                    ret = 0;
                    break;
                }
    #endif
                default:
                    ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
                    break;
            }
        }
        else {
            ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
        }
    }
#endif /* WOLF_CRYPTO_CB_FREE */
#ifdef WOLF_CRYPTO_CB_SETKEY
    else if (info->algo_type == WC_ALGO_TYPE_SETKEY) {
    #ifdef DEBUG_WOLFSSL
        fprintf(stderr, "test_CryptoCb_Func: SetKey Type=%d\n",
                info->setkey.type);
    #endif
        switch (info->setkey.type) {
    #ifndef NO_AES
            case WC_SETKEY_AES:
            {
                Aes* aes = (Aes*)info->setkey.obj;
                aes->devId = INVALID_DEVID;
                ret = wc_AesSetKey(aes,
                    (const byte*)info->setkey.key, info->setkey.keySz,
                    (const byte*)info->setkey.aux, info->setkey.flags);
                aes->devId = thisDevId;
                break;
            }
    #endif /* !NO_AES */
    #ifndef NO_HMAC
            case WC_SETKEY_HMAC:
            {
                Hmac* hmac = (Hmac*)info->setkey.obj;
                hmac->devId = INVALID_DEVID;
                ret = wc_HmacSetKey(hmac, hmac->macType,
                    (const byte*)info->setkey.key, info->setkey.keySz);
                hmac->devId = thisDevId;
                break;
            }
    #endif /* !NO_HMAC */
    #if !defined(NO_RSA) && defined(WOLFSSL_KEY_TO_DER)
            case WC_SETKEY_RSA_PUB:
            {
                RsaKey* rsaObj = (RsaKey*)info->setkey.obj;
                RsaKey* rsaTmp = (RsaKey*)info->setkey.key;
                int derSz;
                word32 idx = 0;
                byte* der = NULL;

                derSz = wc_RsaPublicKeyDerSize(rsaTmp, 1);
                if (derSz <= 0) { ret = derSz; break; }

                der = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
                if (der == NULL) { ret = MEMORY_E; break; }

                derSz = wc_RsaKeyToPublicDer_ex(rsaTmp, der,
                    (word32)derSz, 1);
                if (derSz <= 0) {
                    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
                    ret = derSz; break;
                }

                rsaObj->devId = INVALID_DEVID;
                ret = wc_RsaPublicKeyDecode(der, &idx, rsaObj,
                    (word32)derSz);
                rsaObj->devId = thisDevId;
                XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
                break;
            }
            case WC_SETKEY_RSA_PRIV:
            {
                RsaKey* rsaObj = (RsaKey*)info->setkey.obj;
                RsaKey* rsaTmp = (RsaKey*)info->setkey.key;
                int derSz;
                word32 idx = 0;
                byte* der = NULL;

                derSz = wc_RsaKeyToDer(rsaTmp, NULL, 0);
                if (derSz <= 0) { ret = derSz; break; }

                der = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
                if (der == NULL) { ret = MEMORY_E; break; }

                derSz = wc_RsaKeyToDer(rsaTmp, der, (word32)derSz);
                if (derSz <= 0) {
                    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
                    ret = derSz; break;
                }

                rsaObj->devId = INVALID_DEVID;
                ret = wc_RsaPrivateKeyDecode(der, &idx, rsaObj,
                    (word32)derSz);
                rsaObj->devId = thisDevId;
                XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
                break;
            }
    #endif /* !NO_RSA && WOLFSSL_KEY_TO_DER */
    #if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && \
        defined(HAVE_ECC_KEY_IMPORT)
            case WC_SETKEY_ECC_PUB:
            {
                ecc_key* eccObj = (ecc_key*)info->setkey.obj;
                ecc_key* eccTmp = (ecc_key*)info->setkey.key;
                word32 bufSz = ECC_BUFSIZE;
                int curveId;
                WC_DECLARE_VAR(buf, byte, ECC_BUFSIZE, NULL);
                WC_ALLOC_VAR(buf, byte, ECC_BUFSIZE, NULL);
                if (!WC_VAR_OK(buf)) {
                    ret = MEMORY_E;
                    break;
                }

                ret = wc_ecc_export_x963(eccTmp, buf, &bufSz);
                if (ret != 0) {
                    WC_FREE_VAR(buf, NULL);
                    break;
                }

                curveId = wc_ecc_get_curve_id(eccTmp->idx);
                eccObj->devId = INVALID_DEVID;
                ret = wc_ecc_import_x963_ex2(buf, bufSz, eccObj, curveId, 0);
                eccObj->devId = thisDevId;

                WC_FREE_VAR(buf, NULL);
                break;
            }
            case WC_SETKEY_ECC_PRIV:
            {
                ecc_key* eccObj = (ecc_key*)info->setkey.obj;
                ecc_key* eccTmp = (ecc_key*)info->setkey.key;
                word32 pubSz = ECC_BUFSIZE;
                word32 privSz = MAX_ECC_BYTES;
                byte* pubPtr = NULL;
                int curveId;
                WC_DECLARE_VAR(pubBuf, byte, ECC_BUFSIZE, NULL);
                WC_DECLARE_VAR(privBuf, byte, MAX_ECC_BYTES, NULL);
                WC_ALLOC_VAR(pubBuf, byte, ECC_BUFSIZE, NULL);
                WC_ALLOC_VAR(privBuf, byte, MAX_ECC_BYTES, NULL);
                if (!WC_VAR_OK(pubBuf) || !WC_VAR_OK(privBuf)) {
                    WC_FREE_VAR(pubBuf, NULL);
                    WC_FREE_VAR(privBuf, NULL);
                    ret = MEMORY_E;
                    break;
                }

                /* Export public key from temp (if available) */
                if (eccTmp->type != ECC_PRIVATEKEY_ONLY) {
                    ret = wc_ecc_export_x963(eccTmp, pubBuf, &pubSz);
                    if (ret != 0) {
                        WC_FREE_VAR(pubBuf, NULL);
                        WC_FREE_VAR(privBuf, NULL);
                        break;
                    }
                    pubPtr = pubBuf;
                }

                ret = wc_ecc_export_private_only(eccTmp, privBuf, &privSz);
                if (ret != 0) {
                    WC_FREE_VAR(pubBuf, NULL);
                    WC_FREE_VAR(privBuf, NULL);
                    break;
                }

                curveId = wc_ecc_get_curve_id(eccTmp->idx);
                eccObj->devId = INVALID_DEVID;
                ret = wc_ecc_import_private_key_ex(privBuf, privSz,
                    pubPtr, (pubPtr != NULL) ? pubSz : 0,
                    eccObj, curveId);
                eccObj->devId = thisDevId;

                WC_FREE_VAR(pubBuf, NULL);
                WC_FREE_VAR(privBuf, NULL);
                break;
            }
    #endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT && HAVE_ECC_KEY_IMPORT */
            default:
                ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
                break;
        }
    }
#endif /* WOLF_CRYPTO_CB_SETKEY */
#ifdef WOLF_CRYPTO_CB_EXPORT_KEY
    else if (info->algo_type == WC_ALGO_TYPE_EXPORT_KEY) {
    #ifdef DEBUG_WOLFSSL
        fprintf(stderr, "test_CryptoCb_Func: ExportKey Type=%d\n",
                info->export_key.type);
    #endif
        switch (info->export_key.type) {
    #if !defined(NO_RSA) && defined(WOLFSSL_KEY_TO_DER)
            case WC_PK_TYPE_RSA:
            {
                RsaKey* src = (RsaKey*)info->export_key.obj;
                RsaKey* dst = (RsaKey*)info->export_key.out;
                int derSz;
                word32 idx = 0;
                byte* der = NULL;

                /* Try private key export first, fall back to public */
                derSz = wc_RsaKeyToDer(src, NULL, 0);
                if (derSz > 0) {
                    der = (byte*)XMALLOC(derSz, NULL,
                        DYNAMIC_TYPE_TMP_BUFFER);
                    if (der == NULL) { ret = MEMORY_E; break; }
                    derSz = wc_RsaKeyToDer(src, der, (word32)derSz);
                    if (derSz > 0) {
                        ret = wc_RsaPrivateKeyDecode(der, &idx, dst,
                            (word32)derSz);
                    }
                    else {
                        ret = derSz;
                    }
                    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
                }
                else {
                    /* Public key only */
                    derSz = wc_RsaPublicKeyDerSize(src, 1);
                    if (derSz <= 0) { ret = derSz; break; }
                    der = (byte*)XMALLOC(derSz, NULL,
                        DYNAMIC_TYPE_TMP_BUFFER);
                    if (der == NULL) { ret = MEMORY_E; break; }
                    derSz = wc_RsaKeyToPublicDer_ex(src, der,
                        (word32)derSz, 1);
                    if (derSz > 0) {
                        ret = wc_RsaPublicKeyDecode(der, &idx, dst,
                            (word32)derSz);
                    }
                    else {
                        ret = derSz;
                    }
                    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
                }
                break;
            }
    #endif /* !NO_RSA && WOLFSSL_KEY_TO_DER */
    #if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && \
        defined(HAVE_ECC_KEY_IMPORT)
            case WC_PK_TYPE_ECDSA_SIGN: /* ECC key */
            {
                ecc_key* src = (ecc_key*)info->export_key.obj;
                ecc_key* dst = (ecc_key*)info->export_key.out;
                word32 pubSz = ECC_BUFSIZE;
                word32 privSz = MAX_ECC_BYTES;
                byte* pubPtr = NULL;
                int curveId;
                WC_DECLARE_VAR(pubBuf, byte, ECC_BUFSIZE, NULL);
                WC_DECLARE_VAR(privBuf, byte, MAX_ECC_BYTES, NULL);
                WC_ALLOC_VAR(pubBuf, byte, ECC_BUFSIZE, NULL);
                WC_ALLOC_VAR(privBuf, byte, MAX_ECC_BYTES, NULL);
                if (!WC_VAR_OK(pubBuf) || !WC_VAR_OK(privBuf)) {
                    WC_FREE_VAR(pubBuf, NULL);
                    WC_FREE_VAR(privBuf, NULL);
                    ret = MEMORY_E;
                    break;
                }

                /* Use software to export from src - prevent recursion */
                {
                    int savedDevId = src->devId;
                    src->devId = INVALID_DEVID;

                    /* Export public key if available */
                    if (src->type != ECC_PRIVATEKEY_ONLY) {
                        ret = wc_ecc_export_x963(src, pubBuf, &pubSz);
                        if (ret != 0) {
                            src->devId = savedDevId;
                            WC_FREE_VAR(pubBuf, NULL);
                            WC_FREE_VAR(privBuf, NULL);
                            break;
                        }
                        pubPtr = pubBuf;
                    }

                    /* Export private key if available */
                    if (src->type != ECC_PUBLICKEY) {
                        ret = wc_ecc_export_private_only(src, privBuf,
                            &privSz);
                        if (ret != 0) {
                            src->devId = savedDevId;
                            WC_FREE_VAR(pubBuf, NULL);
                            WC_FREE_VAR(privBuf, NULL);
                            break;
                        }

                        curveId = wc_ecc_get_curve_id(src->idx);
                        ret = wc_ecc_import_private_key_ex(privBuf, privSz,
                            pubPtr, (pubPtr != NULL) ? pubSz : 0,
                            dst, curveId);
                    }
                    else {
                        /* Public key only */
                        curveId = wc_ecc_get_curve_id(src->idx);
                        ret = wc_ecc_import_x963_ex2(pubBuf, pubSz, dst,
                            curveId, 0);
                    }

                    src->devId = savedDevId;
                }
                WC_FREE_VAR(pubBuf, NULL);
                WC_FREE_VAR(privBuf, NULL);
                break;
            }
    #endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT && HAVE_ECC_KEY_IMPORT */
            default:
                ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
                break;
        }
    }
#endif /* WOLF_CRYPTO_CB_EXPORT_KEY */
    (void)thisDevId;
    (void)keyFormat;

    return ret;
}

/* tlsVer: WOLFSSL_TLSV1_2 or WOLFSSL_TLSV1_3 */
static int test_wc_CryptoCb_TLS(int tlsVer,
    const char* cliCaPemFile, const char* cliCertPemFile,
    const char* cliPrivKeyPemFile, const char* cliPubKeyPemFile,
    const char* svrCaPemFile, const char* svrCertPemFile,
    const char* svrPrivKeyPemFile, const char* svrPubKeyPemFile)
{
    EXPECT_DECLS;
    callback_functions client_cbf;
    callback_functions server_cbf;

    XMEMSET(&client_cbf, 0, sizeof(client_cbf));
    XMEMSET(&server_cbf, 0, sizeof(server_cbf));

    if (tlsVer == WOLFSSL_TLSV1_3) {
    #ifdef WOLFSSL_TLS13
        server_cbf.method = wolfTLSv1_3_server_method;
        client_cbf.method = wolfTLSv1_3_client_method;
    #endif
    }
    else if (tlsVer == WOLFSSL_TLSV1_2) {
    #ifndef WOLFSSL_NO_TLS12
        server_cbf.method = wolfTLSv1_2_server_method;
        client_cbf.method = wolfTLSv1_2_client_method;
    #endif
    }
    else if (tlsVer == WOLFSSL_TLSV1_1) {
    #ifndef NO_OLD_TLS
        server_cbf.method = wolfTLSv1_1_server_method;
        client_cbf.method = wolfTLSv1_1_client_method;
    #endif
    }
    else if (tlsVer == WOLFSSL_TLSV1) {
    #if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10)
        server_cbf.method = wolfTLSv1_server_method;
        client_cbf.method = wolfTLSv1_client_method;
    #endif
    }
    else if (tlsVer == WOLFSSL_SSLV3) {
    #if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_SSLV3) && \
         defined(WOLFSSL_STATIC_RSA)
        server_cbf.method = wolfSSLv3_server_method;
        client_cbf.method = wolfSSLv3_client_method;
    #endif
    }
    else if (tlsVer == WOLFSSL_DTLSV1_2) {
    #if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12)
        server_cbf.method = wolfDTLSv1_2_server_method;
        client_cbf.method = wolfDTLSv1_2_client_method;
    #endif
    }
    else if (tlsVer == WOLFSSL_DTLSV1) {
    #if defined(WOLFSSL_DTLS) && !defined(NO_OLD_TLS)
        server_cbf.method = wolfDTLSv1_server_method;
        client_cbf.method = wolfDTLSv1_client_method;
    #endif
    }

    if (server_cbf.method == NULL) {
        /* not enabled */
        return TEST_SUCCESS;
    }

    /* Setup the keys for the TLS test */
    client_cbf.certPemFile = cliCertPemFile;
    client_cbf.keyPemFile = cliPubKeyPemFile;
    client_cbf.caPemFile = cliCaPemFile;

    server_cbf.certPemFile = svrCertPemFile;
    server_cbf.keyPemFile = svrPubKeyPemFile;
    server_cbf.caPemFile = svrCaPemFile;

    /* Setup a crypto callback with pointer to private key file for testing */
    client_cbf.devId = 1;
    wc_CryptoCb_RegisterDevice(client_cbf.devId, test_CryptoCb_Func,
        (void*)cliPrivKeyPemFile);
    server_cbf.devId = 2;
    wc_CryptoCb_RegisterDevice(server_cbf.devId, test_CryptoCb_Func,
        (void*)svrPrivKeyPemFile);

    /* Perform TLS server and client test */
    /* First test is at WOLFSSL_CTX level */
    test_wolfSSL_client_server(&client_cbf, &server_cbf);
    /* Check for success */
    ExpectIntEQ(server_cbf.return_code, TEST_SUCCESS);
    ExpectIntEQ(client_cbf.return_code, TEST_SUCCESS);

    if (EXPECT_SUCCESS()) {
        /* Second test is a WOLFSSL object level */
        client_cbf.loadToSSL = 1; server_cbf.loadToSSL = 1;
        test_wolfSSL_client_server(&client_cbf, &server_cbf);
    }

    /* Check for success */
    ExpectIntEQ(server_cbf.return_code, TEST_SUCCESS);
    ExpectIntEQ(client_cbf.return_code, TEST_SUCCESS);

    /* Un register the devId's */
    wc_CryptoCb_UnRegisterDevice(client_cbf.devId);
    client_cbf.devId = INVALID_DEVID;
    wc_CryptoCb_UnRegisterDevice(server_cbf.devId);
    server_cbf.devId = INVALID_DEVID;

    return EXPECT_RESULT();
}
#endif /* WOLF_CRYPTO_CB && HAVE_IO_TESTS_DEPENDENCIES */

static int test_wc_CryptoCb(void)
{
    EXPECT_DECLS;
#if defined(WOLF_CRYPTO_CB) && \
    (!defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \
     !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA))
    /* TODO: Add crypto callback API tests */

#ifdef HAVE_IO_TESTS_DEPENDENCIES
    #if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519)
    int tlsVer;
    #endif

    #ifndef NO_RSA
    for (tlsVer = WOLFSSL_SSLV3; tlsVer <= WOLFSSL_DTLSV1; tlsVer++) {
        ExpectIntEQ(test_wc_CryptoCb_TLS(tlsVer,
            svrCertFile, cliCertFile, cliKeyFile, cliKeyPubFile,
            cliCertFile, svrCertFile, svrKeyFile, svrKeyPubFile),
            TEST_SUCCESS);
    }
    #endif
    #ifdef HAVE_ECC
    for (tlsVer = WOLFSSL_TLSV1; tlsVer <= WOLFSSL_DTLSV1; tlsVer++) {
        ExpectIntEQ(test_wc_CryptoCb_TLS(tlsVer,
            caEccCertFile,  cliEccCertFile, cliEccKeyFile, cliEccKeyPubFile,
            cliEccCertFile, eccCertFile,    eccKeyFile,    eccKeyPubFile),
            TEST_SUCCESS);
    }
    #endif
    #ifdef HAVE_ED25519
    for (tlsVer = WOLFSSL_TLSV1_2; tlsVer <= WOLFSSL_DTLSV1_2; tlsVer++) {
        if (tlsVer == WOLFSSL_DTLSV1) continue;
        ExpectIntEQ(test_wc_CryptoCb_TLS(tlsVer,
            caEdCertFile,  cliEdCertFile, cliEdKeyFile, cliEdKeyPubFile,
            cliEdCertFile, edCertFile,    edKeyFile,    edKeyPubFile),
            TEST_SUCCESS);
    }
    #endif
#endif /* HAVE_IO_TESTS_DEPENDENCIES */
#endif /* WOLF_CRYPTO_CB */
    return EXPECT_RESULT();
}

#if defined(WOLFSSL_STATIC_MEMORY) && defined(HAVE_IO_TESTS_DEPENDENCIES)

/* tlsVer: Example: WOLFSSL_TLSV1_2 or WOLFSSL_TLSV1_3 */
static int test_wolfSSL_CTX_StaticMemory_TLS(int tlsVer,
    const char* cliCaPemFile, const char* cliCertPemFile,
    const char* cliPrivKeyPemFile,
    const char* svrCaPemFile, const char* svrCertPemFile,
    const char* svrPrivKeyPemFile,
    byte* cliMem, word32 cliMemSz, byte* svrMem, word32 svrMemSz)
{
    EXPECT_DECLS;
    callback_functions client_cbf;
    callback_functions server_cbf;

    XMEMSET(&client_cbf, 0, sizeof(client_cbf));
    XMEMSET(&server_cbf, 0, sizeof(server_cbf));

    if (tlsVer == WOLFSSL_TLSV1_3) {
    #ifdef WOLFSSL_TLS13
        server_cbf.method_ex = wolfTLSv1_3_server_method_ex;
        client_cbf.method_ex = wolfTLSv1_3_client_method_ex;
    #endif
    }
    else if (tlsVer == WOLFSSL_TLSV1_2) {
    #ifndef WOLFSSL_NO_TLS12
        server_cbf.method_ex = wolfTLSv1_2_server_method_ex;
        client_cbf.method_ex = wolfTLSv1_2_client_method_ex;
    #endif
    }
    else if (tlsVer == WOLFSSL_TLSV1_1) {
    #ifndef NO_OLD_TLS
        server_cbf.method_ex = wolfTLSv1_1_server_method_ex;
        client_cbf.method_ex = wolfTLSv1_1_client_method_ex;
    #endif
    }
    else if (tlsVer == WOLFSSL_TLSV1) {
    #if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10)
        server_cbf.method_ex = wolfTLSv1_server_method_ex;
        client_cbf.method_ex = wolfTLSv1_client_method_ex;
    #endif
    }
    else if (tlsVer == WOLFSSL_SSLV3) {
    #if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_SSLV3) && \
         defined(WOLFSSL_STATIC_RSA)
        server_cbf.method_ex = wolfSSLv3_server_method_ex;
        client_cbf.method_ex = wolfSSLv3_client_method_ex;
    #endif
    }
    else if (tlsVer == WOLFSSL_DTLSV1_2) {
    #if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12)
        server_cbf.method_ex = wolfDTLSv1_2_server_method_ex;
        client_cbf.method_ex = wolfDTLSv1_2_client_method_ex;
    #endif
    }
    else if (tlsVer == WOLFSSL_DTLSV1) {
    #if defined(WOLFSSL_DTLS) && !defined(NO_OLD_TLS)
        server_cbf.method_ex = wolfDTLSv1_server_method_ex;
        client_cbf.method_ex = wolfDTLSv1_client_method_ex;
    #endif
    }

    if (server_cbf.method_ex == NULL) {
        /* not enabled */
        return TEST_SUCCESS;
    }

    /* Setup the keys for the TLS test */
    client_cbf.certPemFile = cliCertPemFile;
    client_cbf.keyPemFile = cliPrivKeyPemFile;
    client_cbf.caPemFile = cliCaPemFile;

    server_cbf.certPemFile = svrCertPemFile;
    server_cbf.keyPemFile = svrPrivKeyPemFile;
    server_cbf.caPemFile = svrCaPemFile;

    client_cbf.mem = cliMem;
    client_cbf.memSz = cliMemSz;
    server_cbf.mem = svrMem;
    server_cbf.memSz = svrMemSz;

    client_cbf.devId = INVALID_DEVID;
    server_cbf.devId = INVALID_DEVID;

    /* Perform TLS server and client test */
    /* First test is at WOLFSSL_CTX level */
    test_wolfSSL_client_server(&client_cbf, &server_cbf);
    /* Check for success */
    ExpectIntEQ(server_cbf.return_code, TEST_SUCCESS);
    ExpectIntEQ(client_cbf.return_code, TEST_SUCCESS);

    if (EXPECT_SUCCESS()) {
       /* Second test is a WOLFSSL object level */
       client_cbf.loadToSSL = 1; server_cbf.loadToSSL = 1;
       test_wolfSSL_client_server(&client_cbf, &server_cbf);
    }

    /* Check for success */
    ExpectIntEQ(server_cbf.return_code, TEST_SUCCESS);
    ExpectIntEQ(client_cbf.return_code, TEST_SUCCESS);

    return EXPECT_RESULT();
}
#endif /* WOLFSSL_STATIC_MEMORY && HAVE_IO_TESTS_DEPENDENCIES */

#if defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFCRYPT_ONLY)
static int test_wolfSSL_CTX_StaticMemory_SSL(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    WOLFSSL *ssl1 = NULL, *ssl2 = NULL, *ssl3 = NULL;
    WOLFSSL_MEM_STATS mem_stats;
    WOLFSSL_MEM_CONN_STATS ssl_stats;

#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_RSA)
    ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
        WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
        WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
#endif

    ExpectNotNull((ssl1 = wolfSSL_new(ctx)));
    ExpectNotNull((ssl2 = wolfSSL_new(ctx)));

#ifndef WOLFSSL_STATIC_MEMORY_LEAN
    /* this should fail because kMaxCtxClients == 2 */
    ExpectNull((ssl3 = wolfSSL_new(ctx)));
#else
    (void)ssl3;
#endif

    if (wolfSSL_is_static_memory(ssl1, &ssl_stats) == 1) {
    #if defined(DEBUG_WOLFSSL) && !defined(WOLFSSL_STATIC_MEMORY_LEAN)
        wolfSSL_PrintStatsConn(&ssl_stats);
    #endif
        (void)ssl_stats;
    }

    /* display collected statistics */
    if (wolfSSL_CTX_is_static_memory(ctx, &mem_stats) == 1) {
    #if defined(DEBUG_WOLFSSL) && !defined(WOLFSSL_STATIC_MEMORY_LEAN)
        wolfSSL_PrintStats(&mem_stats);
    #endif
        (void)mem_stats;
    }

    wolfSSL_free(ssl1);
    wolfSSL_free(ssl2);

    return EXPECT_RESULT();
}
#endif /* WOLFSSL_STATIC_MEMORY && !WOLFCRYPT_ONLY */

static int test_wolfSSL_CTX_StaticMemory(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFCRYPT_ONLY)
    wolfSSL_method_func method_func;
    WOLFSSL_CTX* ctx;
    const int kMaxCtxClients = 2;
    #ifdef HAVE_IO_TESTS_DEPENDENCIES
    #if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519)
    int tlsVer;
    byte cliMem[TEST_TLS_STATIC_MEMSZ];
    #endif
    #endif
    byte svrMem[TEST_TLS_STATIC_MEMSZ];

#ifndef NO_WOLFSSL_SERVER
    #ifndef WOLFSSL_NO_TLS12
        method_func = wolfTLSv1_2_server_method_ex;
    #else
        method_func = wolfTLSv1_3_server_method_ex;
    #endif
#else
    #ifndef WOLFSSL_NO_TLS12
        method_func = wolfTLSv1_2_client_method_ex;
    #else
        method_func = wolfTLSv1_3_client_method_ex;
    #endif
#endif

    /* Test creating CTX directly from static memory pool */
    ctx = NULL;
    ExpectIntEQ(wolfSSL_CTX_load_static_memory(&ctx, method_func, svrMem,
        sizeof(svrMem), 0, kMaxCtxClients), WOLFSSL_SUCCESS);
    ExpectIntEQ(test_wolfSSL_CTX_StaticMemory_SSL(ctx), TEST_SUCCESS);
    wolfSSL_CTX_free(ctx);
    ctx = NULL;

    /* Test for heap allocated CTX, then assigning static pool to it */
    ExpectNotNull(ctx = wolfSSL_CTX_new(method_func(NULL)));
    ExpectIntEQ(wolfSSL_CTX_load_static_memory(&ctx, NULL, svrMem,
        sizeof(svrMem), 0, kMaxCtxClients), WOLFSSL_SUCCESS);
    ExpectIntEQ(test_wolfSSL_CTX_StaticMemory_SSL(ctx), TEST_SUCCESS);
    wolfSSL_CTX_free(ctx);

    /* TLS Level Tests using static memory */
#ifdef HAVE_IO_TESTS_DEPENDENCIES
    #ifndef NO_RSA
    for (tlsVer = WOLFSSL_SSLV3; tlsVer <= WOLFSSL_DTLSV1; tlsVer++) {
        ExpectIntEQ(test_wolfSSL_CTX_StaticMemory_TLS(tlsVer,
            svrCertFile, cliCertFile, cliKeyFile,
            cliCertFile, svrCertFile, svrKeyFile,
            cliMem, (word32)sizeof(cliMem), svrMem, (word32)sizeof(svrMem)),
            TEST_SUCCESS);
    }
    #endif
    #ifdef HAVE_ECC
    for (tlsVer = WOLFSSL_TLSV1; tlsVer <= WOLFSSL_DTLSV1; tlsVer++) {
        ExpectIntEQ(test_wolfSSL_CTX_StaticMemory_TLS(tlsVer,
            caEccCertFile,  cliEccCertFile, cliEccKeyFile,
            cliEccCertFile, eccCertFile,    eccKeyFile,
            cliMem, (word32)sizeof(cliMem), svrMem, (word32)sizeof(svrMem)),
            TEST_SUCCESS);
    }
    #endif
    #ifdef HAVE_ED25519
    for (tlsVer = WOLFSSL_TLSV1_2; tlsVer <= WOLFSSL_DTLSV1_2; tlsVer++) {
        if (tlsVer == WOLFSSL_DTLSV1) continue;
        ExpectIntEQ(test_wolfSSL_CTX_StaticMemory_TLS(tlsVer,
            caEdCertFile,  cliEdCertFile, cliEdKeyFile,
            cliEdCertFile, edCertFile,    edKeyFile,
            cliMem, (word32)sizeof(cliMem), svrMem, (word32)sizeof(svrMem)),
            TEST_SUCCESS);
    }
    #endif
#endif /* HAVE_IO_TESTS_DEPENDENCIES */
#endif /* WOLFSSL_STATIC_MEMORY && !WOLFCRYPT_ONLY */
    return EXPECT_RESULT();
}

static int test_openssl_FIPS_drbg(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(WC_NO_RNG) && defined(HAVE_HASHDRBG)
    DRBG_CTX* dctx = NULL;
    byte data1[32], data2[32], zeroData[32];
    byte testSeed[16];
    size_t dlen = sizeof(data1);
    int i;

    XMEMSET(data1, 0, dlen);
    XMEMSET(data2, 0, dlen);
    XMEMSET(zeroData, 0, sizeof(zeroData));
    for (i = 0; i < (int)sizeof(testSeed); i++) {
        testSeed[i] = (byte)i;
    }

    ExpectNotNull(dctx = FIPS_get_default_drbg());
    ExpectIntEQ(FIPS_drbg_init(dctx, 0, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(FIPS_drbg_set_callbacks(dctx, NULL, NULL, 20, NULL, NULL),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(FIPS_drbg_instantiate(dctx, NULL, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(FIPS_drbg_generate(dctx, data1, dlen, 0, NULL, 0),
        WOLFSSL_SUCCESS);
    ExpectIntNE(XMEMCMP(data1, zeroData, dlen), 0);
    ExpectIntEQ(FIPS_drbg_reseed(dctx, testSeed, sizeof(testSeed)),
        WOLFSSL_SUCCESS);
    ExpectIntEQ(FIPS_drbg_generate(dctx, data2, dlen, 0, NULL, 0),
        WOLFSSL_SUCCESS);
    ExpectIntNE(XMEMCMP(data1, zeroData, dlen), 0);
    ExpectIntNE(XMEMCMP(data1, data2, dlen), 0);
    ExpectIntEQ(FIPS_drbg_uninstantiate(dctx), WOLFSSL_SUCCESS);
#ifndef HAVE_GLOBAL_RNG
    /* gets freed by wolfSSL_Cleanup() when HAVE_GLOBAL_RNG defined */
    wolfSSL_FIPS_drbg_free(dctx);
#endif
#endif
    return EXPECT_RESULT();
}

static int test_wolfSSL_FIPS_mode(void)
{
    EXPECT_DECLS;
#if defined(OPENSSL_ALL)
#ifdef HAVE_FIPS
    ExpectIntEQ(wolfSSL_FIPS_mode(), 1);
    ExpectIntEQ(wolfSSL_FIPS_mode_set(0), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
    ExpectIntEQ(wolfSSL_FIPS_mode_set(1), WOLFSSL_SUCCESS);
#else
    ExpectIntEQ(wolfSSL_FIPS_mode(), 0);
    ExpectIntEQ(wolfSSL_FIPS_mode_set(0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_FIPS_mode_set(1), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif
#endif
    return EXPECT_RESULT();
}

#ifdef WOLFSSL_DTLS

/* Prints out the current window */
static void DUW_TEST_print_window_binary(word32 h, word32 l, word32* w) {
#ifdef WOLFSSL_DEBUG_DTLS_WINDOW
    int i;
    for (i = WOLFSSL_DTLS_WINDOW_WORDS - 1; i >= 0; i--) {
        word32 b = w[i];
        int j;
        /* Prints out a 32 bit binary number in big endian order */
        for (j = 0; j < 32; j++, b <<= 1) {
            if (b & (((word32)1) << 31))
                fprintf(stderr, "1");
            else
                fprintf(stderr, "0");
        }
        fprintf(stderr, " ");
    }
    fprintf(stderr, "cur_hi %u cur_lo %u\n", h, l);
#else
    (void)h;
    (void)l;
    (void)w;
#endif
}

/* a - cur_hi
 * b - cur_lo
 * c - next_hi
 * d - next_lo
 * e - window
 * f - expected next_hi
 * g - expected next_lo
 * h - expected window[1]
 * i - expected window[0]
 */
#define DUW_TEST(a,b,c,d,e,f,g,h,i) do { \
    ExpectIntEQ(wolfSSL_DtlsUpdateWindow((a), (b), &(c), &(d), (e)), 1); \
    DUW_TEST_print_window_binary((a), (b), (e)); \
    ExpectIntEQ((c), (f)); \
    ExpectIntEQ((d), (g)); \
    ExpectIntEQ((e)[1], (h)); \
    ExpectIntEQ((e)[0], (i)); \
} while (0)

static int test_wolfSSL_DtlsUpdateWindow(void)
{
    EXPECT_DECLS;
    word32 window[WOLFSSL_DTLS_WINDOW_WORDS];
    word32 next_lo = 0;
    word16 next_hi = 0;

#ifdef WOLFSSL_DEBUG_DTLS_WINDOW
    fprintf(stderr, "\n");
#endif

    XMEMSET(window, 0, sizeof window);
    DUW_TEST(0, 0, next_hi, next_lo, window, 0, 1, 0, 0x01);
    DUW_TEST(0, 1, next_hi, next_lo, window, 0, 2, 0, 0x03);
    DUW_TEST(0, 5, next_hi, next_lo, window, 0, 6, 0, 0x31);
    DUW_TEST(0, 4, next_hi, next_lo, window, 0, 6, 0, 0x33);
    DUW_TEST(0, 100, next_hi, next_lo, window, 0, 101, 0, 0x01);
    DUW_TEST(0, 101, next_hi, next_lo, window, 0, 102, 0, 0x03);
    DUW_TEST(0, 133, next_hi, next_lo, window, 0, 134, 0x03, 0x01);
    DUW_TEST(0, 200, next_hi, next_lo, window, 0, 201, 0, 0x01);
    DUW_TEST(0, 264, next_hi, next_lo, window, 0, 265, 0, 0x01);
    DUW_TEST(0, 0xFFFFFFFF, next_hi, next_lo, window, 1, 0, 0, 0x01);
    DUW_TEST(0, 0xFFFFFFFD, next_hi, next_lo, window, 1, 0, 0, 0x05);
    DUW_TEST(0, 0xFFFFFFFE, next_hi, next_lo, window, 1, 0, 0, 0x07);
    DUW_TEST(1, 3, next_hi, next_lo, window, 1, 4, 0, 0x71);
    DUW_TEST(1, 0, next_hi, next_lo, window, 1, 4, 0, 0x79);
    DUW_TEST(1, 0xFFFFFFFF, next_hi, next_lo, window, 2, 0, 0, 0x01);
    DUW_TEST(2, 3, next_hi, next_lo, window, 2, 4, 0, 0x11);
    DUW_TEST(2, 0, next_hi, next_lo, window, 2, 4, 0, 0x19);
    DUW_TEST(2, 25, next_hi, next_lo, window, 2, 26, 0, 0x6400001);
    DUW_TEST(2, 27, next_hi, next_lo, window, 2, 28, 0, 0x19000005);
    DUW_TEST(2, 29, next_hi, next_lo, window, 2, 30, 0, 0x64000015);
    DUW_TEST(2, 33, next_hi, next_lo, window, 2, 34, 6, 0x40000151);
    DUW_TEST(2, 60, next_hi, next_lo, window, 2, 61, 0x3200000A, 0x88000001);
    DUW_TEST(1, 0xFFFFFFF0, next_hi, next_lo, window, 2, 61, 0x3200000A, 0x88000001);
    DUW_TEST(2, 0xFFFFFFFD, next_hi, next_lo, window, 2, 0xFFFFFFFE, 0, 0x01);
    DUW_TEST(3, 1, next_hi, next_lo, window, 3, 2, 0, 0x11);
    DUW_TEST(99, 66, next_hi, next_lo, window, 99, 67, 0, 0x01);
    DUW_TEST(50, 66, next_hi, next_lo, window, 99, 67, 0, 0x01);
    DUW_TEST(100, 68, next_hi, next_lo, window, 100, 69, 0, 0x01);
    DUW_TEST(99, 50, next_hi, next_lo, window, 100, 69, 0, 0x01);
    DUW_TEST(99, 0xFFFFFFFF, next_hi, next_lo, window, 100, 69, 0, 0x01);
    DUW_TEST(150, 0xFFFFFFFF, next_hi, next_lo, window, 151, 0, 0, 0x01);
    DUW_TEST(152, 0xFFFFFFFF, next_hi, next_lo, window, 153, 0, 0, 0x01);

    return EXPECT_RESULT();
}
#endif /* WOLFSSL_DTLS */

#ifdef WOLFSSL_DTLS
static int DFB_TEST(WOLFSSL* ssl, word32 seq, word32 len, word32 f_offset,
        word32 f_len, word32 f_count, byte ready, word32 bytesReceived)
{
    EXPECT_DECLS;
    DtlsMsg* cur = NULL;
    static byte msg[100];
    static byte msgInit = 0;

    if (!msgInit) {
        int i;
        for (i = 0; i < 100; i++)
            msg[i] = i + 1;
        msgInit = 1;
    }

    /* Sanitize test parameters */
    ExpectIntLE(len, sizeof(msg));
    ExpectIntLE(f_offset + f_len, sizeof(msg));

    if (EXPECT_SUCCESS())
        DtlsMsgStore(ssl, 0, seq, msg + f_offset, len, certificate, f_offset, f_len, NULL);

    ExpectNotNull(ssl->dtls_rx_msg_list);

    ExpectNotNull(cur = DtlsMsgFind(ssl->dtls_rx_msg_list, 0, seq));
    ExpectIntEQ(cur->fragBucketListCount, f_count);
    ExpectIntEQ(cur->ready, ready);
    ExpectIntEQ(cur->bytesReceived, bytesReceived);
    if (ready) {
        ExpectNull(cur->fragBucketList);
        ExpectBufEQ(cur->fullMsg, msg, cur->sz);
    }
    else {
        DtlsFragBucket* fb;
        ExpectNotNull(cur->fragBucketList);
        for (fb = cur != NULL ? cur->fragBucketList : NULL;
                EXPECT_SUCCESS() && fb != NULL; fb = fb->m.m.next)
            ExpectBufEQ(fb->buf, msg + fb->m.m.offset, fb->m.m.sz);
    }
    if (EXPECT_FAIL()) {
        printf("Test parameters: seq %u len %u f_offset %u f_len %u f_count %u ready %u bytesReceived %u\n",
                                 seq, len, f_offset, f_len, f_count, ready, bytesReceived);
    }
    return EXPECT_RESULT();
}

static int test_wolfSSL_DTLS_fragment_buckets(void)
{
    EXPECT_DECLS;
    WOLFSSL ssl[1];

    XMEMSET(ssl, 0, sizeof(*ssl));

    EXPECT_TEST(DFB_TEST(ssl, 0, 100, 0, 100, 0, 1, 100)); /*  0-100 */

    EXPECT_TEST(DFB_TEST(ssl, 1, 100,  0, 20, 1, 0,  20)); /*  0-20  */
    EXPECT_TEST(DFB_TEST(ssl, 1, 100, 20, 20, 1, 0,  40)); /* 20-40  */
    EXPECT_TEST(DFB_TEST(ssl, 1, 100, 40, 20, 1, 0,  60)); /* 40-60  */
    EXPECT_TEST(DFB_TEST(ssl, 1, 100, 60, 20, 1, 0,  80)); /* 60-80  */
    EXPECT_TEST(DFB_TEST(ssl, 1, 100, 80, 20, 0, 1, 100)); /* 80-100 */

    /* Test all permutations of 3 regions */
    /* 1 2 3 */
    EXPECT_TEST(DFB_TEST(ssl, 2, 100,  0, 30, 1, 0,  30)); /*  0-30  */
    EXPECT_TEST(DFB_TEST(ssl, 2, 100, 30, 30, 1, 0,  60)); /* 30-60  */
    EXPECT_TEST(DFB_TEST(ssl, 2, 100, 60, 40, 0, 1, 100)); /* 60-100 */
    /* 1 3 2 */
    EXPECT_TEST(DFB_TEST(ssl, 3, 100,  0, 30, 1, 0,  30)); /*  0-30  */
    EXPECT_TEST(DFB_TEST(ssl, 3, 100, 60, 40, 2, 0,  70)); /* 60-100 */
    EXPECT_TEST(DFB_TEST(ssl, 3, 100, 30, 30, 0, 1, 100)); /* 30-60  */
    /* 2 1 3 */
    EXPECT_TEST(DFB_TEST(ssl, 4, 100, 30, 30, 1, 0,  30)); /* 30-60  */
    EXPECT_TEST(DFB_TEST(ssl, 4, 100,  0, 30, 1, 0,  60)); /*  0-30  */
    EXPECT_TEST(DFB_TEST(ssl, 4, 100, 60, 40, 0, 1, 100)); /* 60-100 */
    /* 2 3 1 */
    EXPECT_TEST(DFB_TEST(ssl, 5, 100, 30, 30, 1, 0,  30)); /* 30-60  */
    EXPECT_TEST(DFB_TEST(ssl, 5, 100, 60, 40, 1, 0,  70)); /* 60-100 */
    EXPECT_TEST(DFB_TEST(ssl, 5, 100,  0, 30, 0, 1, 100)); /*  0-30  */
    /* 3 1 2 */
    EXPECT_TEST(DFB_TEST(ssl, 6, 100, 60, 40, 1, 0,  40)); /* 60-100 */
    EXPECT_TEST(DFB_TEST(ssl, 6, 100,  0, 30, 2, 0,  70)); /*  0-30  */
    EXPECT_TEST(DFB_TEST(ssl, 6, 100, 30, 30, 0, 1, 100)); /* 30-60  */
    /* 3 2 1 */
    EXPECT_TEST(DFB_TEST(ssl, 7, 100, 60, 40, 1, 0,  40)); /* 60-100 */
    EXPECT_TEST(DFB_TEST(ssl, 7, 100, 30, 30, 1, 0,  70)); /* 30-60  */
    EXPECT_TEST(DFB_TEST(ssl, 7, 100,  0, 30, 0, 1, 100)); /*  0-30  */

    /* Test overlapping regions */
    EXPECT_TEST(DFB_TEST(ssl, 8, 100,  0, 30, 1, 0,  30)); /*  0-30  */
    EXPECT_TEST(DFB_TEST(ssl, 8, 100, 20, 10, 1, 0,  30)); /* 20-30  */
    EXPECT_TEST(DFB_TEST(ssl, 8, 100, 70, 10, 2, 0,  40)); /* 70-80  */
    EXPECT_TEST(DFB_TEST(ssl, 8, 100, 20, 30, 2, 0,  60)); /* 20-50  */
    EXPECT_TEST(DFB_TEST(ssl, 8, 100, 40, 60, 0, 1, 100)); /* 40-100 */

    /* Test overlapping multiple regions */
    EXPECT_TEST(DFB_TEST(ssl, 9, 100,  0, 20, 1, 0,  20)); /*  0-20  */
    EXPECT_TEST(DFB_TEST(ssl, 9, 100, 30,  5, 2, 0,  25)); /* 30-35  */
    EXPECT_TEST(DFB_TEST(ssl, 9, 100, 40,  5, 3, 0,  30)); /* 40-45  */
    EXPECT_TEST(DFB_TEST(ssl, 9, 100, 50,  5, 4, 0,  35)); /* 50-55  */
    EXPECT_TEST(DFB_TEST(ssl, 9, 100, 60,  5, 5, 0,  40)); /* 60-65  */
    EXPECT_TEST(DFB_TEST(ssl, 9, 100, 70,  5, 6, 0,  45)); /* 70-75  */
    EXPECT_TEST(DFB_TEST(ssl, 9, 100, 30, 25, 4, 0,  55)); /* 30-55  */
    EXPECT_TEST(DFB_TEST(ssl, 9, 100, 55, 15, 2, 0,  65)); /* 55-70  */
    EXPECT_TEST(DFB_TEST(ssl, 9, 100, 75, 25, 2, 0,  90)); /* 75-100 */
    EXPECT_TEST(DFB_TEST(ssl, 9, 100, 10, 25, 0, 1, 100)); /* 10-35 */

    EXPECT_TEST(DFB_TEST(ssl,10, 100,  0, 20, 1, 0,  20)); /*  0-20  */
    EXPECT_TEST(DFB_TEST(ssl,10, 100, 30, 20, 2, 0,  40)); /* 30-50  */
    EXPECT_TEST(DFB_TEST(ssl,10, 100,  0, 40, 1, 0,  50)); /*  0-40  */
    EXPECT_TEST(DFB_TEST(ssl,10, 100, 50, 50, 0, 1, 100)); /* 50-100 */

    /* Test region between other regions */
    EXPECT_TEST(DFB_TEST(ssl,11, 100,  0, 20, 1, 0,  20)); /*  0-20  */
    EXPECT_TEST(DFB_TEST(ssl,11, 100, 80, 20, 2, 0,  40)); /* 80-100 */
    EXPECT_TEST(DFB_TEST(ssl,11, 100, 40, 20, 3, 0,  60)); /* 40-60  */
    EXPECT_TEST(DFB_TEST(ssl,11, 100, 20, 20, 2, 0,  80)); /* 20-40  */
    EXPECT_TEST(DFB_TEST(ssl,11, 100, 60, 20, 0, 1, 100)); /* 60-80  */

    /* Test gap before first bucket (prev==NULL in gap-before branch) */
    EXPECT_TEST(DFB_TEST(ssl,12, 100, 50, 20, 1, 0,  20)); /* 50-70  */
    EXPECT_TEST(DFB_TEST(ssl,12, 100,  0, 20, 2, 0,  40)); /*  0-20  gap before first */
    EXPECT_TEST(DFB_TEST(ssl,12, 100, 20, 30, 1, 0,  70)); /* 20-50  bridges gap */
    EXPECT_TEST(DFB_TEST(ssl,12, 100, 70, 30, 0, 1, 100)); /* 70-100 */

    /* Test fragment after message is already complete (ready early return) */
    EXPECT_TEST(DFB_TEST(ssl,13, 100,  0,100, 0, 1, 100)); /*  0-100 complete */
    EXPECT_TEST(DFB_TEST(ssl,13, 100,  0, 50, 0, 1, 100)); /*  0-50  dup on ready */

    /* Test combine where next bucket is larger than cur (chosenBucket=&next) */
    EXPECT_TEST(DFB_TEST(ssl,14, 100,  0, 10, 1, 0,  10)); /*  0-10  */
    EXPECT_TEST(DFB_TEST(ssl,14, 100, 30, 50, 2, 0,  60)); /* 30-80  */
    EXPECT_TEST(DFB_TEST(ssl,14, 100,  5, 30, 1, 0,  80)); /*  5-35  next>cur */
    EXPECT_TEST(DFB_TEST(ssl,14, 100, 80, 20, 0, 1, 100)); /* 80-100 */

    /* Test super fragment covering all existing buckets */
    EXPECT_TEST(DFB_TEST(ssl,15, 100, 10, 10, 1, 0,  10)); /* 10-20  */
    EXPECT_TEST(DFB_TEST(ssl,15, 100, 30, 10, 2, 0,  20)); /* 30-40  */
    EXPECT_TEST(DFB_TEST(ssl,15, 100, 60, 10, 3, 0,  30)); /* 60-70  */
    EXPECT_TEST(DFB_TEST(ssl,15, 100,  0,100, 0, 1, 100)); /*  0-100 super frag */

    /* Test exact duplicate fragment */
    EXPECT_TEST(DFB_TEST(ssl,16, 100, 20, 40, 1, 0,  40)); /* 20-60  */
    EXPECT_TEST(DFB_TEST(ssl,16, 100, 20, 40, 1, 0,  40)); /* 20-60  exact dup */
    EXPECT_TEST(DFB_TEST(ssl,16, 100,  0, 20, 1, 0,  60)); /*  0-20  */
    EXPECT_TEST(DFB_TEST(ssl,16, 100, 60, 40, 0, 1, 100)); /* 60-100 */

    /* Test combine bridging two buckets (combineNext, cur->data) */
    EXPECT_TEST(DFB_TEST(ssl,17, 100,  0, 30, 1, 0,  30)); /*  0-30  */
    EXPECT_TEST(DFB_TEST(ssl,17, 100, 60, 20, 2, 0,  50)); /* 60-80  */
    EXPECT_TEST(DFB_TEST(ssl,17, 100, 20, 45, 1, 0,  80)); /* 20-65  bridge */
    EXPECT_TEST(DFB_TEST(ssl,17, 100, 80, 20, 0, 1, 100)); /* 80-100 */

    /* Test progressive left-extension with partial overlaps */
    EXPECT_TEST(DFB_TEST(ssl,18, 100, 70, 30, 1, 0,  30)); /* 70-100 */
    EXPECT_TEST(DFB_TEST(ssl,18, 100, 50, 30, 1, 0,  50)); /* 50-80  extend left */
    EXPECT_TEST(DFB_TEST(ssl,18, 100, 30, 30, 1, 0,  70)); /* 30-60  extend left */
    EXPECT_TEST(DFB_TEST(ssl,18, 100,  0, 40, 0, 1, 100)); /*  0-40  complete left */

    DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap);
    ssl->dtls_rx_msg_list = NULL;
    ssl->dtls_rx_msg_list_sz = 0;
    return EXPECT_RESULT();
}

#endif


#if !defined(NO_FILESYSTEM) && \
     defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \
     defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(NO_RSA)

static int test_wolfSSL_dtls_stateless2(void)
{
    EXPECT_DECLS;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_c2 = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0);
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c2, NULL,
        wolfDTLSv1_2_client_method, NULL), 0);
    ExpectFalse(wolfSSL_is_stateful(ssl_s));
    /* send CH */
    ExpectTrue((wolfSSL_connect(ssl_c2) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_c2->error == WC_NO_ERR_TRACE(WANT_READ)));
    ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_FAILURE);
    ExpectFalse(wolfSSL_is_stateful(ssl_s));
    ExpectIntNE(test_ctx.c_len, 0);
    /* consume HRR */
    test_memio_clear_buffer(&test_ctx, 1);
    /* send CH1 */
    ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
            WOLFSSL_ERROR_WANT_READ);
    /* send HRR */
    ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_FAILURE);
    /* send CH2 */
    ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
            WOLFSSL_ERROR_WANT_READ);
    /* send HRR */
    ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_SUCCESS);
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
    ExpectTrue(wolfSSL_is_stateful(ssl_s));

    wolfSSL_free(ssl_c2);
    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
    return EXPECT_RESULT();
}

#ifdef HAVE_MAX_FRAGMENT
static int test_wolfSSL_dtls_stateless_maxfrag(void)
{
    EXPECT_DECLS;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_c2 = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    word16 max_fragment = 0;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0);
    ExpectNotNull(ssl_s);
    ExpectNotNull(ssl_c2 = wolfSSL_new(ctx_c));
    ExpectIntEQ(wolfSSL_UseMaxFragment(ssl_c2, WOLFSSL_MFL_2_8),
        WOLFSSL_SUCCESS);
    wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx);
    wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx);
    if (EXPECT_SUCCESS()) {
        max_fragment = ssl_s->max_fragment;
    }
    /* send CH */
    ExpectTrue((wolfSSL_connect(ssl_c2) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_c2->error == WC_NO_ERR_TRACE(WANT_READ)));
    ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ)));
    /* CH without cookie shouldn't change state */
    ExpectIntEQ(ssl_s->max_fragment, max_fragment);
    ExpectIntNE(test_ctx.c_len, 0);

    /* consume HRR from buffer */
    test_memio_clear_buffer(&test_ctx, 1);
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

    wolfSSL_free(ssl_c2);
    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
    return EXPECT_RESULT();
}
#endif /* HAVE_MAX_FRAGMENT */

#if defined(WOLFSSL_DTLS_NO_HVR_ON_RESUME)
#define ROUNDS_WITH_HVR 4
#define ROUNDS_WITHOUT_HVR 2
#define HANDSHAKE_TYPE_OFFSET DTLS_RECORD_HEADER_SZ
static int buf_is_hvr(const byte *data, int len)
{
    if (len < DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ)
        return 0;
    return data[HANDSHAKE_TYPE_OFFSET] == hello_verify_request;
}

static int _test_wolfSSL_dtls_stateless_resume(byte useticket, byte bad)
{
    EXPECT_DECLS;
    struct test_memio_ctx test_ctx;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    WOLFSSL_SESSION *sess = NULL;
    int round_trips;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c,
        &ssl_s, wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0);
#ifdef HAVE_SESSION_TICKET
    if (useticket) {
        ExpectIntEQ(wolfSSL_UseSessionTicket(ssl_c), WOLFSSL_SUCCESS);
    }
#endif
    round_trips = ROUNDS_WITH_HVR;
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, round_trips,
        &round_trips), 0);
    ExpectIntEQ(round_trips, ROUNDS_WITH_HVR);
    ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
    wolfSSL_shutdown(ssl_c);
    wolfSSL_shutdown(ssl_s);
    wolfSSL_free(ssl_c);
    ssl_c = NULL;
    wolfSSL_free(ssl_s);
    ssl_s = NULL;

    test_memio_clear_buffer(&test_ctx, 1);
    test_memio_clear_buffer(&test_ctx, 0);
    /* make resumption invalid */
    if (bad && (sess != NULL)) {
        if (useticket) {
#ifdef HAVE_SESSION_TICKET
            if (sess->ticket != NULL) {
                sess->ticket[0] = !sess->ticket[0];
            }
#endif /* HAVE_SESSION_TICKET */
        }
        else {
            sess->sessionID[0] = !sess->sessionID[0];
        }
    }
    ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
    ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
    wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
    wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
    wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
    wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
    ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
    ExpectTrue((wolfSSL_connect(ssl_c) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_c->error == WC_NO_ERR_TRACE(WANT_READ)));
    ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ)));
    ExpectFalse(bad && !buf_is_hvr(test_ctx.c_buff, test_ctx.c_len));
    ExpectFalse(!bad && buf_is_hvr(test_ctx.c_buff, test_ctx.c_len));
    if (!useticket) {
        ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, &round_trips), 0);
        ExpectFalse(bad && round_trips != ROUNDS_WITH_HVR - 1);
        ExpectFalse(!bad && round_trips != ROUNDS_WITHOUT_HVR - 1);
    }
    wolfSSL_SESSION_free(sess);
    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
    return EXPECT_RESULT();
}

static int test_wolfSSL_dtls_stateless_resume(void)
{
    EXPECT_DECLS;
#ifdef HAVE_SESSION_TICKET
    ExpectIntEQ(_test_wolfSSL_dtls_stateless_resume(1, 0), TEST_SUCCESS);
    ExpectIntEQ(_test_wolfSSL_dtls_stateless_resume(1, 1), TEST_SUCCESS);
#endif /* HAVE_SESION_TICKET */
    ExpectIntEQ(_test_wolfSSL_dtls_stateless_resume(0, 0), TEST_SUCCESS);
    ExpectIntEQ(_test_wolfSSL_dtls_stateless_resume(0, 1), TEST_SUCCESS);
    return EXPECT_RESULT();
}
#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */

#if !defined(NO_OLD_TLS)
static int test_wolfSSL_dtls_stateless_downgrade(void)
{
    EXPECT_DECLS;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_c2 = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_c2 = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0);
    ExpectIntEQ(wolfSSL_CTX_SetMinVersion(ctx_s, WOLFSSL_DTLSV1),
        WOLFSSL_SUCCESS);
    ExpectNotNull(ctx_c2 = wolfSSL_CTX_new(wolfDTLSv1_client_method()));
    wolfSSL_SetIORecv(ctx_c2, test_memio_read_cb);
    wolfSSL_SetIOSend(ctx_c2, test_memio_write_cb);
    ExpectNotNull(ssl_c2 = wolfSSL_new(ctx_c2));
    wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx);
    wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx);
    /* send CH */
    ExpectTrue((wolfSSL_connect(ssl_c2) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_c2->error == WC_NO_ERR_TRACE(WANT_READ)));
    ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ)));
    ExpectIntNE(test_ctx.c_len, 0);
    /* consume HRR */
    test_memio_clear_buffer(&test_ctx, 1);
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

    wolfSSL_free(ssl_c2);
    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_c2);
    wolfSSL_CTX_free(ctx_s);

    return EXPECT_RESULT();
}
#endif /* !defined(NO_OLD_TLS) */

#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)*/

#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \
    !defined(NO_OLD_TLS) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
static int test_WOLFSSL_dtls_version_alert(void)
{
    EXPECT_DECLS;
    struct test_memio_ctx test_ctx;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_2_client_method, wolfDTLSv1_server_method), 0);

    /* client hello */
    ExpectTrue((wolfSSL_connect(ssl_c) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_c->error == WC_NO_ERR_TRACE(WANT_READ)));
    /* hrr */
    ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ)));
    /* client hello 1 */
    ExpectTrue((wolfSSL_connect(ssl_c) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_c->error == WC_NO_ERR_TRACE(WANT_READ)));
    /* server hello */
    ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ)));
    /* should fail */
    ExpectTrue((wolfSSL_connect(ssl_c) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_c->error == WC_NO_ERR_TRACE(VERSION_ERROR)));
    /* shuould fail */
    ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_s->error == WC_NO_ERR_TRACE(VERSION_ERROR) || ssl_s->error == WC_NO_ERR_TRACE(FATAL_ERROR)));

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);

    return EXPECT_RESULT();
}
#else
static int test_WOLFSSL_dtls_version_alert(void)
{
    return TEST_SKIPPED;
}
#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) &&
        * !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) &&
        * !defined(NO_OLD_TLS) && !defined(NO_RSA)
        */


#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && defined(HAVE_SESSION_TICKET)       \
    && defined(WOLFSSL_TLS13) &&                                               \
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))\
    && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
static int send_new_session_ticket(WOLFSSL *ssl, byte nonceLength, byte filler)
{
    struct test_memio_ctx *test_ctx;
    byte buf[2048];
    int idx, sz;
    word32 tmp;
    int ret;

    idx = 5; /* space for record header */

    buf[idx] = session_ticket; /* type */
    idx++;

    tmp = OPAQUE32_LEN +
        OPAQUE32_LEN +
        OPAQUE8_LEN + nonceLength +
        OPAQUE16_LEN + OPAQUE8_LEN + OPAQUE16_LEN;
    c32to24(tmp, buf + idx);
    idx += OPAQUE24_LEN;

    c32toa((word32)12345, buf+idx); /* lifetime */
    idx += OPAQUE32_LEN;
    c32toa((word32)12345, buf+idx); /* add */
    idx += OPAQUE32_LEN;
    buf[idx] = nonceLength; /* nonce length */
    idx++;
    XMEMSET(&buf[idx], filler, nonceLength); /* nonce */
    idx += nonceLength;
    tmp = 1; /* ticket len */
    c16toa((word16)tmp, buf+idx);
    idx += 2;
    buf[idx] = 0xFF; /* ticket */
    idx++;
    tmp = 0; /* ext len */
    c16toa((word16)tmp, buf+idx);
    idx += 2;

    sz = BuildTls13Message(ssl, buf, 2048, buf+5, idx - 5,
        handshake, 0, 0, 0);
    AssertIntGT(sz, 0);
    test_ctx = (struct test_memio_ctx*)wolfSSL_GetIOWriteCtx(ssl);
    AssertNotNull(test_ctx);
    ret = test_memio_write_cb(ssl, (char*)buf, sz, test_ctx);
    return !(ret == sz);
}

static int test_ticket_nonce_check(WOLFSSL_SESSION *sess, byte len)
{
    int ret = 0;

    if ((sess == NULL) || (sess->ticketNonce.len != len)) {
        ret = -1;
    }
    else {
        int i;
        for (i = 0; i < len; i++) {
            if (sess->ticketNonce.data[i] != len) {
                ret = -1;
                break;
            }
        }
    }

    return ret;
}

static int test_ticket_nonce_malloc_do(WOLFSSL *ssl_s, WOLFSSL *ssl_c, byte len)
{
    EXPECT_DECLS;
    char *buf[1024];

    ExpectIntEQ(send_new_session_ticket(ssl_s, len, len), 0);
    ExpectTrue((wolfSSL_recv(ssl_c, buf, 1024, 0) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
        (ssl_c->error == WC_NO_ERR_TRACE(WANT_READ)));

    ExpectIntEQ(test_ticket_nonce_check(ssl_c->session, len), 0);

    return EXPECT_RESULT();
}

static int test_ticket_nonce_cache(WOLFSSL *ssl_s, WOLFSSL *ssl_c, byte len)
{
    EXPECT_DECLS;
    WOLFSSL_SESSION *sess = NULL;
    WOLFSSL_SESSION *cached = NULL;
    WOLFSSL_CTX *ctx = ssl_c->ctx;

    ExpectIntEQ(test_ticket_nonce_malloc_do(ssl_s, ssl_c, len), TEST_SUCCESS);
    ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));

    ExpectIntEQ(AddSessionToCache(ctx, sess, sess->sessionID, sess->sessionIDSz,
        NULL, ssl_c->options.side, 1,NULL), 0);

    ExpectNotNull(cached = wolfSSL_SESSION_new());

    ExpectIntEQ(wolfSSL_GetSessionFromCache(ssl_c, cached), WOLFSSL_SUCCESS);

    ExpectIntEQ(test_ticket_nonce_check(cached, len), 0);

    wolfSSL_SESSION_free(cached);
    wolfSSL_SESSION_free(sess);

    return EXPECT_RESULT();
}

static int test_ticket_nonce_malloc(void)
{
    EXPECT_DECLS;
    struct test_memio_ctx test_ctx;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    byte small;
    byte medium;
    byte big;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);

    /* will send ticket manually */
    ExpectIntEQ(wolfSSL_no_ticket_TLSv13(ssl_s), 0);

    wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, 0);
    wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, 0);

    while (EXPECT_SUCCESS() && (ssl_c->options.handShakeDone == 0) &&
            (ssl_s->options.handShakeDone == 0)) {
        ExpectTrue((wolfSSL_connect(ssl_c) == WOLFSSL_SUCCESS) ||
            (ssl_c->error == WC_NO_ERR_TRACE(WANT_READ)));

        ExpectTrue((wolfSSL_accept(ssl_s) == WOLFSSL_SUCCESS) ||
            (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ)));
    }

    small = TLS13_TICKET_NONCE_STATIC_SZ;
#if TLS13_TICKET_NONCE_STATIC_SZ + 20 <= 255
    medium = small + 20;
#else
    medium = 255;
#endif
#if TLS13_TICKET_NONCE_STATIC_SZ + 20 + 20 <= 255
    big = small + 20;
#else
    big = 255;
#endif

    ExpectIntEQ(test_ticket_nonce_malloc_do(ssl_s, ssl_c, small), TEST_SUCCESS);
    ExpectPtrEq(ssl_c->session->ticketNonce.data,
         ssl_c->session->ticketNonce.dataStatic);
    ExpectIntEQ(test_ticket_nonce_malloc_do(ssl_s, ssl_c, medium),
        TEST_SUCCESS);
    ExpectIntEQ(test_ticket_nonce_malloc_do(ssl_s, ssl_c, big), TEST_SUCCESS);
    ExpectIntEQ(test_ticket_nonce_malloc_do(ssl_s, ssl_c, medium),
        TEST_SUCCESS);
    ExpectIntEQ(test_ticket_nonce_malloc_do(ssl_s, ssl_c, small), TEST_SUCCESS);
    ExpectIntEQ(test_ticket_nonce_cache(ssl_s, ssl_c, small), TEST_SUCCESS);
    ExpectIntEQ(test_ticket_nonce_cache(ssl_s, ssl_c, medium), TEST_SUCCESS);
    ExpectIntEQ(test_ticket_nonce_cache(ssl_s, ssl_c, big), TEST_SUCCESS);
    ExpectIntEQ(test_ticket_nonce_cache(ssl_s, ssl_c, medium), TEST_SUCCESS);
    ExpectIntEQ(test_ticket_nonce_cache(ssl_s, ssl_c, small), TEST_SUCCESS);

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);

    return EXPECT_RESULT();
}

#endif /* WOLFSSL_TICKET_NONCE_MALLOC */

#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_TLS12) && \
    !defined(WOLFSSL_TICKET_DECRYPT_NO_CREATE) &&                 \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
    !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && !defined(NO_RSA) && \
    defined(HAVE_ECC) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)

static int test_ticket_ret_create(void)
{
    EXPECT_DECLS;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    byte ticket[SESSION_TICKET_LEN];
    struct test_memio_ctx test_ctx;
    WOLFSSL_SESSION *sess = NULL;
    word16 ticketLen = 0;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
    wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, 0);
    wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, 0);
    ExpectIntEQ(wolfSSL_CTX_UseSessionTicket(ctx_c), WOLFSSL_SUCCESS);

    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

    ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
    ExpectIntLE(sess->ticketLen, SESSION_TICKET_LEN);
    if (sess != NULL) {
        ticketLen = sess->ticketLen;
        XMEMCPY(ticket, sess->ticket, sess->ticketLen);
    }
    wolfSSL_free(ssl_c);
    ssl_c = NULL;
    wolfSSL_free(ssl_s);
    ssl_s = NULL;

    ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
    wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
    wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
    ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
    wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
    wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);

    ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
    ExpectIntLE(ssl_c->session->ticketLen, SESSION_TICKET_LEN);
    ExpectIntEQ(ssl_c->session->ticketLen, ticketLen);
    ExpectTrue(XMEMCMP(ssl_c->session->ticket, ticket, ticketLen) != 0);

    wolfSSL_SESSION_free(sess);
    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);

    return EXPECT_RESULT();
}
#else
static int test_ticket_ret_create(void)
{
    return TEST_SKIPPED;
}
#endif

/* Build a valid TLS 1.2 ticket by completing an initial handshake, then tamper
 * with enc_len so it is larger than the true encrypted payload. */
#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_TLS12) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
    !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
    !defined(NO_RSA) && defined(HAVE_ECC) && \
    defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)

static int test_ticket_enc_corrupted_cb(WOLFSSL* ssl,
    byte key_name[WOLFSSL_TICKET_NAME_SZ], byte iv[WOLFSSL_TICKET_IV_SZ],
    byte mac[WOLFSSL_TICKET_MAC_SZ], int enc, byte* ticket, int inLen,
    int* outLen, void* userCtx)
{
    (void)ssl;
    (void)key_name;
    (void)iv;
    (void)mac;
    (void)userCtx;
    (void)outLen;

    if (!enc) {
        XMEMSET(ticket, 0, (size_t)inLen);
        return WOLFSSL_TICKET_RET_REJECT; /* keep handshake progressing */
    }
    return WOLFSSL_TICKET_RET_CREATE;
}

static int test_ticket_enc_corrupted(void)
{
    EXPECT_DECLS;
    struct test_memio_ctx test_ctx;
    WOLFSSL_CTX* ctx_c = NULL;
    WOLFSSL_CTX* ctx_s = NULL;
    WOLFSSL*     ssl_c = NULL;
    WOLFSSL*     ssl_s = NULL;
    WOLFSSL_SESSION* sess = NULL;
    ExternalTicket* et;
    word16 encLen;
    int actualEncLen;
    int craftedBadLen = 0;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
    wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, 0);
    wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, 0);
    ExpectIntEQ(wolfSSL_CTX_UseSessionTicket(ctx_c), WOLFSSL_SUCCESS);
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
    ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
    if (sess != NULL) {
        ExpectIntGT(sess->ticketLen, WOLFSSL_TICKET_FIXED_SZ);

        /* Force enc_len to exceed actual encrypted ticket payload while still
         * staying <= WOLFSSL_TICKET_ENC_SZ, so callback is reached. */
        et = (ExternalTicket*)sess->ticket;
        ato16(et->enc_len, &encLen);
        actualEncLen = (int)(sess->ticketLen - WOLFSSL_TICKET_FIXED_SZ);
        if (actualEncLen + 100 <= (int)WOLFSSL_TICKET_ENC_SZ) {
            encLen = (word16)(actualEncLen + 100);
            c16toa(encLen, et->enc_len);
            craftedBadLen = 1;
        }
        else if (actualEncLen + 1 <= (int)WOLFSSL_TICKET_ENC_SZ) {
            encLen = (word16)(actualEncLen + 1);
            c16toa(encLen, et->enc_len);
            craftedBadLen = 1;
        }
    }

    wolfSSL_free(ssl_c);
    ssl_c = NULL;
    wolfSSL_free(ssl_s);
    ssl_s = NULL;
    test_memio_clear_buffer(&test_ctx, 1);
    test_memio_clear_buffer(&test_ctx, 0);

    ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
    wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
    wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
    ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
    wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
    wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
    wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, 0);
    wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, 0);
    if (sess != NULL) {
        if (!craftedBadLen) {
            wolfSSL_SESSION_free(sess);
            wolfSSL_free(ssl_c);
            wolfSSL_free(ssl_s);
            wolfSSL_CTX_free(ctx_c);
            wolfSSL_CTX_free(ctx_s);
            return TEST_SKIPPED;
        }
        ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CTX_set_TicketEncCb(ctx_s,
            test_ticket_enc_corrupted_cb), WOLFSSL_SUCCESS);
        ExpectTrue((wolfSSL_connect(ssl_c) ==
            WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
            (ssl_c->error == WC_NO_ERR_TRACE(WANT_READ)));
        ExpectTrue((wolfSSL_accept(ssl_s) ==
            WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
            (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ)));
    }

    wolfSSL_SESSION_free(sess);
    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);

    return EXPECT_RESULT();
}
#else
static int test_ticket_enc_corrupted(void) { return TEST_SKIPPED; }
#endif

#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
    defined(HAVE_SESSION_TICKET) && defined(OPENSSL_EXTRA) && \
    defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_AESGCM) && \
    !defined(NO_SHA256) && defined(WOLFSSL_AES_128) && \
    defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256)
static void test_ticket_and_psk_mixing_on_result(WOLFSSL* ssl)
{
    int ret;
    WOLFSSL_SESSION* session = NULL;

    AssertIntEQ(wolfSSL_get_current_cipher_suite(ssl), 0x1301);
    if (!wolfSSL_is_server(ssl)) {
        session = wolfSSL_SESSION_dup(wolfSSL_get_session(ssl));
        AssertNotNull(session);
    }
    do {
        ret = wolfSSL_shutdown(ssl);
    } while (ret == WC_NO_ERR_TRACE(WOLFSSL_SHUTDOWN_NOT_DONE));
    AssertIntEQ(wolfSSL_clear(ssl), WOLFSSL_SUCCESS);
    wolfSSL_set_psk_callback_ctx(ssl, (void*)"TLS13-AES256-GCM-SHA384");
#ifndef OPENSSL_COMPATIBLE_DEFAULTS
    /* OpenSSL considers PSK to be verified. We error out with NO_PEER_CERT. */
    wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_NONE, NULL);
#endif

    if (!wolfSSL_is_server(ssl)) {
        /* client */
        AssertIntEQ(wolfSSL_set_cipher_list(ssl, "TLS13-AES256-GCM-SHA384:"
                "TLS13-AES128-GCM-SHA256"), WOLFSSL_SUCCESS);
        wolfSSL_set_session(ssl, session);
        wolfSSL_SESSION_free(session);
        wolfSSL_set_psk_client_tls13_callback(ssl, my_psk_client_tls13_cb);
        AssertIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS);
    }
    else {
        /* server */
        /* Different ciphersuite so that the ticket will be invalidated based on
         * the ciphersuite */
        AssertIntEQ(wolfSSL_set_cipher_list(ssl, "TLS13-AES256-GCM-SHA384"),
            WOLFSSL_SUCCESS);
        wolfSSL_set_psk_server_tls13_callback(ssl, my_psk_server_tls13_cb);
        AssertIntEQ(wolfSSL_accept(ssl), WOLFSSL_SUCCESS);
    }
}

static void test_ticket_and_psk_mixing_ssl_ready(WOLFSSL* ssl)
{
    AssertIntEQ(wolfSSL_UseSessionTicket(ssl), WOLFSSL_SUCCESS);
    AssertIntEQ(wolfSSL_set_cipher_list(ssl, "TLS13-AES128-GCM-SHA256"),
        WOLFSSL_SUCCESS);
}

static int test_ticket_and_psk_mixing(void)
{
    EXPECT_DECLS;
    /* Test mixing tickets and regular PSK */
    callback_functions client_cbs, server_cbs;

    XMEMSET(&client_cbs, 0, sizeof(client_cbs));
    XMEMSET(&server_cbs, 0, sizeof(server_cbs));

    client_cbs.method = wolfTLSv1_3_client_method;
    server_cbs.method = wolfTLSv1_3_server_method;

    client_cbs.ssl_ready = test_ticket_and_psk_mixing_ssl_ready;

    client_cbs.on_result = test_ticket_and_psk_mixing_on_result;
    server_cbs.on_result = test_ticket_and_psk_mixing_on_result;

    test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs);

    ExpectIntEQ(client_cbs.return_code, TEST_SUCCESS);
    ExpectIntEQ(server_cbs.return_code, TEST_SUCCESS);

    return EXPECT_RESULT();
}
#else
static int test_ticket_and_psk_mixing(void)
{
    return TEST_SKIPPED;
}
#endif

#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && defined(HAVE_SESSION_TICKET) \
    && defined(OPENSSL_EXTRA) && defined(HAVE_IO_TESTS_DEPENDENCIES) && \
    defined(HAVE_AESGCM) && !defined(NO_SHA256) && defined(WOLFSSL_AES_128) && \
    defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256)
static int test_prioritize_psk_cb_called = FALSE;

static unsigned int test_prioritize_psk_cb(WOLFSSL* ssl,
        const char* identity, unsigned char* key, unsigned int key_max_len,
        const char** ciphersuite)
{
    test_prioritize_psk_cb_called = TRUE;
    return my_psk_server_tls13_cb(ssl, identity, key, key_max_len, ciphersuite);
}

static void test_prioritize_psk_on_result(WOLFSSL* ssl)
{
    int ret;
    WOLFSSL_SESSION* session = NULL;
    AssertIntEQ(wolfSSL_get_current_cipher_suite(ssl), 0x1301);
    if (!wolfSSL_is_server(ssl)) {
        session = wolfSSL_SESSION_dup(wolfSSL_get_session(ssl));
        AssertNotNull(session);
    }
    do {
        ret = wolfSSL_shutdown(ssl);
    } while (ret == WC_NO_ERR_TRACE(WOLFSSL_SHUTDOWN_NOT_DONE));
    AssertIntEQ(wolfSSL_clear(ssl), WOLFSSL_SUCCESS);
    wolfSSL_set_psk_callback_ctx(ssl, (void*)"TLS13-AES256-GCM-SHA384");
    /* Previous connection was made with TLS13-AES128-GCM-SHA256. Order is
     * important. */
    AssertIntEQ(wolfSSL_set_cipher_list(ssl, "TLS13-AES256-GCM-SHA384:"
            "TLS13-AES128-GCM-SHA256"), WOLFSSL_SUCCESS);
#ifndef OPENSSL_COMPATIBLE_DEFAULTS
    /* OpenSSL considers PSK to be verified. We error out with NO_PEER_CERT. */
    wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_NONE, NULL);
#endif

    if (!wolfSSL_is_server(ssl)) {
        /* client */
        wolfSSL_set_psk_client_tls13_callback(ssl, my_psk_client_tls13_cb);
        wolfSSL_set_session(ssl, session);
        wolfSSL_SESSION_free(session);
        AssertIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS);
    }
    else {
        /* server */
        wolfSSL_set_psk_server_tls13_callback(ssl, test_prioritize_psk_cb);
        AssertIntEQ(wolfSSL_accept(ssl), WOLFSSL_SUCCESS);
#ifdef WOLFSSL_PRIORITIZE_PSK
        /* The ticket should be first tried with all ciphersuites and chosen */
        AssertFalse(test_prioritize_psk_cb_called);
#else
        /* Ciphersuites should be tried with each PSK. This triggers the PSK
         * callback that sets this var. */
        AssertTrue(test_prioritize_psk_cb_called);
#endif
    }
}

static void test_prioritize_psk_ssl_ready(WOLFSSL* ssl)
{
    if (!wolfSSL_is_server(ssl))
        AssertIntEQ(wolfSSL_set_cipher_list(ssl, "TLS13-AES128-GCM-SHA256"),
                WOLFSSL_SUCCESS);
    else
        AssertIntEQ(wolfSSL_set_cipher_list(ssl, "TLS13-AES256-GCM-SHA384:"
                "TLS13-AES128-GCM-SHA256"), WOLFSSL_SUCCESS);
}

static int test_prioritize_psk(void)
{
    EXPECT_DECLS;
    /* We always send the ticket first. With WOLFSSL_PRIORITIZE_PSK the order
     * of the PSK's will be followed instead of the ciphersuite. */
    callback_functions client_cbs, server_cbs;

    XMEMSET(&client_cbs, 0, sizeof(client_cbs));
    XMEMSET(&server_cbs, 0, sizeof(server_cbs));

    client_cbs.method = wolfTLSv1_3_client_method;
    server_cbs.method = wolfTLSv1_3_server_method;

    client_cbs.ssl_ready = test_prioritize_psk_ssl_ready;
    server_cbs.ssl_ready = test_prioritize_psk_ssl_ready;

    client_cbs.on_result = test_prioritize_psk_on_result;
    server_cbs.on_result = test_prioritize_psk_on_result;

    test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs);

    ExpectIntEQ(client_cbs.return_code, TEST_SUCCESS);
    ExpectIntEQ(server_cbs.return_code, TEST_SUCCESS);

    return EXPECT_RESULT();
}
#else
static int test_prioritize_psk(void)
{
    return TEST_SKIPPED;
}
#endif

#if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \
    defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_AESGCM) && \
    !defined(NO_SHA256) && defined(WOLFSSL_AES_128) && \
    !defined(WOLFSSL_NO_TLS12)
static int test_wolfSSL_CTX_set_ciphersuites_ctx_ready_server(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    ExpectTrue(SSL_CTX_set_cipher_list(ctx, "DEFAULT"));
    /* Set TLS 1.3 specific suite */
    ExpectTrue(SSL_CTX_set_ciphersuites(ctx, "TLS13-AES128-GCM-SHA256"));
    return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_set_ciphersuites(void)
{
    EXPECT_DECLS;
    /* Test using SSL_CTX_set_cipher_list and SSL_CTX_set_ciphersuites and then
     * do a 1.2 connection. */
    test_ssl_cbf client_cbs, server_cbs;

    XMEMSET(&client_cbs, 0, sizeof(client_cbs));
    XMEMSET(&server_cbs, 0, sizeof(server_cbs));

    client_cbs.method = wolfTLSv1_2_client_method;
    server_cbs.method = wolfTLS_server_method; /* Allow downgrade */

    server_cbs.ctx_ready = test_wolfSSL_CTX_set_ciphersuites_ctx_ready_server;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbs,
        &server_cbs, NULL), TEST_SUCCESS);

    return EXPECT_RESULT();
}
#else
static int test_wolfSSL_CTX_set_ciphersuites(void)
{
    return TEST_SKIPPED;
}
#endif

#if defined(HAVE_CRL) && defined(WOLFSSL_CHECK_ALERT_ON_ERR) && \
        defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
static int test_wolfSSL_CRL_CERT_REVOKED_alert_ctx_ready(WOLFSSL_CTX* ctx)
{
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
    return TEST_SUCCESS;
}

static int test_wolfSSL_CRL_CERT_REVOKED_alert_on_cleanup(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    WOLFSSL_ALERT_HISTORY h;
    ExpectIntEQ(wolfSSL_get_alert_history(ssl, &h), WOLFSSL_SUCCESS);
    ExpectIntEQ(h.last_rx.level, alert_fatal);
    ExpectIntEQ(h.last_rx.code, certificate_revoked);
    return EXPECT_RESULT();
}

static int test_wolfSSL_CRL_CERT_REVOKED_alert(void)
{
    EXPECT_DECLS;
    test_ssl_cbf client_cbs, server_cbs;

    XMEMSET(&client_cbs, 0, sizeof(client_cbs));
    XMEMSET(&server_cbs, 0, sizeof(server_cbs));

    server_cbs.certPemFile = "./certs/server-revoked-cert.pem";
    server_cbs.keyPemFile = "./certs/server-revoked-key.pem";
    client_cbs.crlPemFile = "./certs/crl/crl.revoked";

    client_cbs.ctx_ready = test_wolfSSL_CRL_CERT_REVOKED_alert_ctx_ready;
    server_cbs.on_cleanup = test_wolfSSL_CRL_CERT_REVOKED_alert_on_cleanup;

    ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbs,
        &server_cbs, NULL), -1001);

    return EXPECT_RESULT();
}
#else
static int test_wolfSSL_CRL_CERT_REVOKED_alert(void)
{
    return TEST_SKIPPED;
}
#endif

#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) \
    && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_AESGCM) && \
    !defined(NO_SHA256) && defined(WOLFSSL_AES_128) && \
    defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256) && \
    !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)

static WOLFSSL_CTX* test_TLS_13_ticket_different_ciphers_ctx = NULL;
static WOLFSSL_SESSION* test_TLS_13_ticket_different_ciphers_session = NULL;
static int test_TLS_13_ticket_different_ciphers_run = 0;

static int test_TLS_13_ticket_different_ciphers_ssl_ready(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    switch (test_TLS_13_ticket_different_ciphers_run) {
        case 0:
            /* First run */
            ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "TLS13-AES128-GCM-SHA256"),
                WOLFSSL_SUCCESS);
            if (wolfSSL_is_server(ssl)) {
                ExpectNotNull(test_TLS_13_ticket_different_ciphers_ctx =
                    wolfSSL_get_SSL_CTX(ssl));
                ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_up_ref(
                    test_TLS_13_ticket_different_ciphers_ctx));
            }
            break;
        case 1:
            /* Second run */
            ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "TLS13-AES256-GCM-SHA384:"
                                                     "TLS13-AES128-GCM-SHA256"),
                            WOLFSSL_SUCCESS);
            if (!wolfSSL_is_server(ssl)) {
                ExpectIntEQ(wolfSSL_set_session(ssl,
                    test_TLS_13_ticket_different_ciphers_session),
                    WOLFSSL_SUCCESS);
            }
            break;
        default:
            /* Bad state? */
            Fail(("Should not enter here"), ("Should not enter here"));
    }

    return EXPECT_RESULT();
}

static int test_TLS_13_ticket_different_ciphers_on_result(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    switch (test_TLS_13_ticket_different_ciphers_run) {
        case 0:
            /* First run */
            ExpectNotNull(test_TLS_13_ticket_different_ciphers_session =
                    wolfSSL_get1_session(ssl));
            break;
        case 1:
            /* Second run */
            ExpectTrue(wolfSSL_session_reused(ssl));
            break;
        default:
            /* Bad state? */
            Fail(("Should not enter here"), ("Should not enter here"));
    }
    return EXPECT_RESULT();
}

static int test_TLS_13_ticket_different_ciphers(void)
{
    EXPECT_DECLS;
    /* Check that we handle the connection when the ticket doesn't match
     * the first ciphersuite. */
    test_ssl_cbf client_cbs, server_cbs;
    struct test_params {
        method_provider client_meth;
        method_provider server_meth;
        int doUdp;
    } params[] = {
#ifdef WOLFSSL_DTLS13
        /* Test that the stateless code handles sessions correctly */
        {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, 1},
#endif
        {wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, 0},
    };
    size_t i;

    for (i = 0; i < sizeof(params)/sizeof(*params); i++) {
        XMEMSET(&client_cbs, 0, sizeof(client_cbs));
        XMEMSET(&server_cbs, 0, sizeof(server_cbs));

        test_TLS_13_ticket_different_ciphers_run = 0;

        client_cbs.doUdp = server_cbs.doUdp = params[i].doUdp;

        client_cbs.method = params[i].client_meth;
        server_cbs.method = params[i].server_meth;

        client_cbs.ssl_ready = test_TLS_13_ticket_different_ciphers_ssl_ready;
        server_cbs.ssl_ready = test_TLS_13_ticket_different_ciphers_ssl_ready;

        client_cbs.on_result = test_TLS_13_ticket_different_ciphers_on_result;

        server_cbs.ticNoInit = 1;

        ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbs,
            &server_cbs, NULL), TEST_SUCCESS);

        test_TLS_13_ticket_different_ciphers_run++;

        server_cbs.ctx = test_TLS_13_ticket_different_ciphers_ctx;

        ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbs,
            &server_cbs, NULL), TEST_SUCCESS);

        wolfSSL_SESSION_free(test_TLS_13_ticket_different_ciphers_session);
        test_TLS_13_ticket_different_ciphers_session = NULL;
        wolfSSL_CTX_free(test_TLS_13_ticket_different_ciphers_ctx);
        test_TLS_13_ticket_different_ciphers_ctx = NULL;
    }

    return EXPECT_RESULT();
}
#else
static int test_TLS_13_ticket_different_ciphers(void)
{
    return TEST_SKIPPED;
}
#endif
#if defined(WOLFSSL_EXTRA_ALERTS) && !defined(WOLFSSL_NO_TLS12) &&             \
    defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)

#define TEST_WRONG_CS_CLIENT "DHE-RSA-AES128-SHA"
/* AKA TLS_DHE_RSA_WITH_AES_128_CBC_SHA */

byte test_extra_alerts_wrong_cs_sh[] = {
  0x16, 0x03, 0x03, 0x00, 0x56, 0x02, 0x00, 0x00, 0x52, 0x03, 0x03, 0xef,
  0x0c, 0x30, 0x98, 0xa2, 0xac, 0xfa, 0x68, 0xe9, 0x3e, 0xaa, 0x5c, 0xcf,
  0xa7, 0x42, 0x72, 0xaf, 0xa0, 0xe8, 0x39, 0x2b, 0x3e, 0x81, 0xa7, 0x7a,
  0xa5, 0x62, 0x8a, 0x0e, 0x41, 0xba, 0xda, 0x20, 0x18, 0x9f, 0xe1, 0x8c,
  0x1d, 0xc0, 0x37, 0x9c, 0xf4, 0x90, 0x5d, 0x8d, 0xa0, 0x79, 0xa7, 0x4b,
  0xa8, 0x79, 0xdf, 0xcd, 0x8d, 0xf5, 0xb5, 0x50, 0x5f, 0xf1, 0xdb, 0x4d,
  0xbb, 0x07, 0x54, 0x1c,
  0x00, 0x02, /* TLS_RSA_WITH_NULL_SHA */
  0x00, 0x00, 0x0a, 0x00, 0x0b, 0x00,
  0x02, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00
};

static int test_extra_alerts_wrong_cs(void)
{
    EXPECT_DECLS;
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
    struct test_memio_ctx test_ctx;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_ALERT_HISTORY h;
    WOLFSSL *ssl_c = NULL;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL,
        wolfTLSv1_2_client_method, NULL), 0);

    ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, TEST_WRONG_CS_CLIENT),
        WOLFSSL_SUCCESS);

    /* CH */
    ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);

    /* consume CH */
    test_memio_clear_buffer(&test_ctx, 0);
    /* inject SH */
    ExpectIntEQ(test_memio_inject_message(&test_ctx, 1,
        (const char *)test_extra_alerts_wrong_cs_sh,
        sizeof(test_extra_alerts_wrong_cs_sh)), 0);

    ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
    ExpectIntNE(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);
    ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
    ExpectIntEQ(h.last_tx.code, handshake_failure);
    ExpectIntEQ(h.last_tx.level, alert_fatal);

    wolfSSL_free(ssl_c);
    wolfSSL_CTX_free(ctx_c);
#endif
    return EXPECT_RESULT();
}
#else
static int test_extra_alerts_wrong_cs(void)
{
    return TEST_SKIPPED;
}
#endif

#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_TLS12) &&   \
    defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_AES_256)

#define TEST_CS_DOWNGRADE_CLIENT "ECDHE-RSA-AES256-GCM-SHA384"

byte test_wrong_cs_downgrade_sh[] = {
  0x16, 0x03, 0x03, 0x00, 0x56, 0x02, 0x00, 0x00, 0x52, 0x03, 0x03, 0x10,
  0x2c, 0x88, 0xd9, 0x7a, 0x23, 0xc9, 0xbd, 0x11, 0x3b, 0x64, 0x24, 0xab,
  0x5b, 0x45, 0x33, 0xf6, 0x2c, 0x34, 0xe4, 0xcf, 0xf4, 0x78, 0xc8, 0x62,
  0x06, 0xc7, 0xe5, 0x30, 0x39, 0xbf, 0xa1, 0x20, 0xa3, 0x06, 0x74, 0xc3,
  0xa9, 0x74, 0x52, 0x8a, 0xfb, 0xae, 0xf0, 0xd8, 0x6f, 0xb2, 0x9d, 0xfe,
  0x78, 0xf0, 0x3f, 0x51, 0x8f, 0x9c, 0xcf, 0xbe, 0x61, 0x43, 0x9d, 0xf8,
  0x85, 0xe5, 0x2f, 0x54,
  0xc0, 0x2f, /* ECDHE-RSA-AES128-GCM-SHA256 */
  0x00, 0x00, 0x0a, 0x00, 0x0b, 0x00,
  0x02, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00
};

static int test_wrong_cs_downgrade(void)
{
    EXPECT_DECLS;
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    struct test_memio_ctx test_ctx;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL *ssl_c = NULL;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL,
        wolfSSLv23_client_method, NULL), 0);

    ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, TEST_CS_DOWNGRADE_CLIENT),
        WOLFSSL_SUCCESS);

    /* CH */
    ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);

    /* consume CH */
    test_memio_clear_buffer(&test_ctx, 0);
    /* inject SH */
    ExpectIntEQ(test_memio_inject_message(&test_ctx, 1,
        (const char *)test_wrong_cs_downgrade_sh,
        sizeof(test_wrong_cs_downgrade_sh)), 0);

    ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
#ifdef OPENSSL_EXTRA
    ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WC_NO_ERR_TRACE(WOLFSSL_ERROR_SYSCALL));
#else
    ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WC_NO_ERR_TRACE(MATCH_SUITE_ERROR));
#endif /* OPENSSL_EXTRA */


    wolfSSL_free(ssl_c);
    wolfSSL_CTX_free(ctx_c);
#endif
    return EXPECT_RESULT();
}
#else
static int test_wrong_cs_downgrade(void)
{
    return TEST_SKIPPED;
}
#endif

#if !defined(WOLFSSL_NO_TLS12) && defined(WOLFSSL_EXTRA_ALERTS) &&             \
    defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_SP_MATH)

static int test_remove_hs_msg_from_buffer(struct test_memio_ctx *test_ctx, byte type,
    byte *found)
{
    const unsigned int  _HANDSHAKE_HEADER_SZ = 4;
    const unsigned int _RECORD_HEADER_SZ = 5;
    const int _change_cipher_hs = 55;
    const int _change_cipher = 20;
    const int _handshake = 22;
    unsigned int tail_len;
    byte *idx;
    int curr;
    word8 currType;
    word16 rLength;
    word32 hLength;

    idx = test_ctx->c_buff;
    tail_len = (unsigned int)test_ctx->c_len;
    *found = 0;
    while (tail_len > _RECORD_HEADER_SZ) {
        curr = (int)(idx - test_ctx->c_buff);
        currType = *idx;
        ato16(idx + 3, &rLength);
        idx += _RECORD_HEADER_SZ;
        tail_len -= _RECORD_HEADER_SZ;

        if (tail_len < rLength)
            return -1;

        if (type == _change_cipher_hs && currType == _change_cipher) {
            if (rLength != 1)
                return -1;
            /* match */
            test_memio_remove_from_buffer(test_ctx, 1, curr,
                _RECORD_HEADER_SZ + rLength);
            *found = 1;
            return 0;
        }

        if (currType != _handshake) {
            idx += rLength;
            tail_len -= rLength;
            continue;
        }

        if (rLength < _HANDSHAKE_HEADER_SZ)
            return -1;
        currType = *idx;
        ato24(idx+1, &hLength);
        hLength += _HANDSHAKE_HEADER_SZ;
        if (tail_len < hLength)
            return -1;
        if (currType != type) {
            idx += hLength;
            tail_len -= hLength;
            continue;
        }

        /* match */
        test_memio_remove_from_buffer(test_ctx, 1, curr,
            hLength + _RECORD_HEADER_SZ);
        *found = 1;
        return 0;
    }

    /* not found */
    return 0;
}

static int test_remove_hs_message(byte hs_message_type,
    int extra_round, byte alert_type)
{
    EXPECT_DECLS;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    WOLFSSL_ALERT_HISTORY h;
    byte found = 0;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);

    ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);

    ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);

    if (extra_round) {
        ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
            WOLFSSL_ERROR_WANT_READ);

        /* this will complete handshake from server side */
        ExpectIntEQ(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
    }

    ExpectIntEQ(test_remove_hs_msg_from_buffer(&test_ctx, hs_message_type, &found), 0);

    if (!found) {
        wolfSSL_free(ssl_c);
        wolfSSL_CTX_free(ctx_c);
        wolfSSL_free(ssl_s);
        wolfSSL_CTX_free(ctx_s);
        return TEST_SKIPPED;
    }

    ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
    ExpectIntNE(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);
    ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
    ExpectTrue(alert_type == 0xff || h.last_tx.code == alert_type);
    ExpectIntEQ(h.last_tx.level, alert_fatal);

    wolfSSL_free(ssl_c);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_s);

    return EXPECT_RESULT();
}

static int test_extra_alerts_skip_hs(void)
{
    EXPECT_DECLS;
    const byte _server_key_exchange = 12;
    const byte _server_hello = 2;
    const byte _certificate = 11;

    /* server_hello */
    ExpectIntNE(test_remove_hs_message(_server_hello, 0,
        unexpected_message), TEST_FAIL);
    ExpectIntNE(test_remove_hs_message(_certificate, 0,
        0xff), TEST_FAIL);
    ExpectIntNE(test_remove_hs_message(_server_key_exchange, 0,
        unexpected_message), TEST_FAIL);

    return EXPECT_RESULT();
}
#else
static int test_extra_alerts_skip_hs(void)
{
    return TEST_SKIPPED;
}
#endif

#if !defined(WOLFSSL_NO_TLS12) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)\
    && defined(WOLFSSL_EXTRA_ALERTS) && !defined(NO_PSK) && !defined(NO_DH)

static unsigned int test_server_psk_cb(WOLFSSL* ssl, const char* id,
    unsigned char* key, unsigned int key_max_len)
{
    (void)ssl;
    (void)id;
    (void)key_max_len;
    /* zero means error */
    key[0] = 0x10;
    return 1;
}

static int test_extra_alerts_bad_psk(void)
{
    EXPECT_DECLS;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    WOLFSSL_ALERT_HISTORY h;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);

    ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, "DHE-PSK-AES128-GCM-SHA256"),
        WOLFSSL_SUCCESS);

    ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, "DHE-PSK-AES128-GCM-SHA256"),
        WOLFSSL_SUCCESS);

    wolfSSL_set_psk_server_callback(ssl_s, test_server_psk_cb);

    ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);

    ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);

    ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
    ExpectIntNE(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);
    ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
    ExpectIntEQ(h.last_tx.code, handshake_failure);
    ExpectIntEQ(h.last_tx.level, alert_fatal);

    wolfSSL_free(ssl_c);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_s);

    return EXPECT_RESULT();
}
#else
static int test_extra_alerts_bad_psk(void)
{
    return TEST_SKIPPED;
}
#endif

#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12)
static int test_multiple_shutdown_nonblocking(void)
{
    EXPECT_DECLS;
    size_t size_of_last_packet = 0;
    int dummy_recv_buffer;

    /* declare wolfSSL objects */
    struct test_memio_ctx test_ctx;
    WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL, *ssl_s = NULL;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    /* Create and initialize WOLFSSL_CTX and WOLFSSL objects */
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
         wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);

    ExpectNotNull(ctx_c);
    ExpectNotNull(ssl_c);
    ExpectNotNull(ctx_s);
    ExpectNotNull(ssl_s);

    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

    /* buffers should be empty now */
    ExpectIntEQ(test_ctx.c_len, 0);
    ExpectIntEQ(test_ctx.s_len, 0);
    ExpectIntEQ(ssl_c->buffers.outputBuffer.length, 0);

    test_memio_simulate_want_write(&test_ctx, 1, 1);

    /*
     * We call wolfSSL_shutdown multiple times to  to check that it doesn't add
     * the CLOSE_NOTIFY packet multiple times on the output buffer.
     * */
    ExpectIntEQ(wolfSSL_shutdown(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, 0), WOLFSSL_ERROR_WANT_WRITE);

    /* store the size of the packet */
    if (ssl_c != NULL) {
        size_of_last_packet = ssl_c->buffers.outputBuffer.length;
    }

    /* invoke it multiple times shouldn't change the wolfssl internal output buffer size */
    ExpectIntEQ(wolfSSL_shutdown(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, 0), WOLFSSL_ERROR_WANT_WRITE);
    ExpectIntEQ(wolfSSL_shutdown(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, 0), WOLFSSL_ERROR_WANT_WRITE);

    ExpectIntEQ(ssl_c->buffers.outputBuffer.length, size_of_last_packet);

    /* now send the CLOSE_NOTIFY to the server for real, expecting shutdown not done */
    test_memio_simulate_want_write(&test_ctx, 1, 0);
    ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SHUTDOWN_NOT_DONE);

    /* output buffer should be empty and socket buffer should contain the message */
    ExpectIntEQ(ssl_c->buffers.outputBuffer.length, 0);
    ExpectIntEQ(test_ctx.s_len, size_of_last_packet);


    /* this should try to read from the socket */
    ExpectIntEQ(wolfSSL_shutdown(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);

    /* complete the bidirectional shutdown */

    /* check that server received the shutdown alert */
    ExpectIntEQ(wolfSSL_recv(ssl_s, &dummy_recv_buffer, 0, 0), 0);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, 0), WOLFSSL_ERROR_ZERO_RETURN);

    /* send the shutdown from the server side */
    ExpectIntEQ(wolfSSL_shutdown(ssl_s), WOLFSSL_SUCCESS);

    /* This should return success and zero return */
    ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, 0), WOLFSSL_ERROR_ZERO_RETURN);

    /* Cleanup and return */
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_free(ssl_c);
    wolfSSL_CTX_free(ctx_s);
    wolfSSL_free(ssl_s);

    return EXPECT_RESULT();
}
#else
static int test_multiple_shutdown_nonblocking(void)
{
    return TEST_SKIPPED;
}
#endif

#if defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_NO_TLS12) && \
        defined(HAVE_IO_TESTS_DEPENDENCIES)
static int test_harden_no_secure_renegotiation_io_cb(WOLFSSL *ssl, char *buf,
        int sz, void *ctx)
{
    static int sentServerHello = FALSE;

    if (!sentServerHello) {
        byte renegExt[] = { 0xFF, 0x01, 0x00, 0x01, 0x00 };
        size_t i;

        if (sz < (int)sizeof(renegExt))
            return WOLFSSL_CBIO_ERR_GENERAL;

        /* Remove SCR from ServerHello */
        for (i = 0; i < sz - sizeof(renegExt); i++) {
            if (XMEMCMP(buf + i, renegExt, sizeof(renegExt)) == 0) {
                /* Found the extension. Change it to something unrecognized. */
                buf[i+1] = 0x11;
                break;
            }
        }
        sentServerHello = TRUE;
    }

    return EmbedSend(ssl, buf, sz, ctx);
}

static void test_harden_no_secure_renegotiation_ssl_ready(WOLFSSL* ssl)
{
    wolfSSL_SSLSetIOSend(ssl, test_harden_no_secure_renegotiation_io_cb);
}

static void test_harden_no_secure_renegotiation_on_cleanup(WOLFSSL* ssl)
{
    WOLFSSL_ALERT_HISTORY h;
    AssertIntEQ(wolfSSL_get_alert_history(ssl, &h), WOLFSSL_SUCCESS);
    AssertIntEQ(h.last_rx.code, handshake_failure);
    AssertIntEQ(h.last_rx.level, alert_fatal);
}

static int test_harden_no_secure_renegotiation(void)
{
    EXPECT_DECLS;
    callback_functions client_cbs, server_cbs;

    XMEMSET(&client_cbs, 0, sizeof(client_cbs));
    XMEMSET(&server_cbs, 0, sizeof(server_cbs));

    client_cbs.method = wolfTLSv1_2_client_method;
    server_cbs.method = wolfTLSv1_2_server_method;

    server_cbs.ssl_ready = test_harden_no_secure_renegotiation_ssl_ready;
    server_cbs.on_cleanup = test_harden_no_secure_renegotiation_on_cleanup;
    test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs);

    ExpectIntEQ(client_cbs.return_code, TEST_FAIL);
    ExpectIntEQ(client_cbs.last_err, WC_NO_ERR_TRACE(SECURE_RENEGOTIATION_E));
    ExpectIntEQ(server_cbs.return_code, TEST_FAIL);
    ExpectTrue(server_cbs.last_err == WC_NO_ERR_TRACE(SOCKET_ERROR_E) ||
               server_cbs.last_err == WC_NO_ERR_TRACE(FATAL_ERROR));

    return EXPECT_RESULT();
}
#else
static int test_harden_no_secure_renegotiation(void)
{
    return TEST_SKIPPED;
}
#endif

#if defined(HAVE_OCSP) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
static int test_override_alt_cert_chain_cert_cb(int preverify,
        WOLFSSL_X509_STORE_CTX* store)
{
    fprintf(stderr, "preverify: %d\n", preverify);
    fprintf(stderr, "store->error: %d\n", store->error);
    fprintf(stderr, "error reason: %s\n", wolfSSL_ERR_reason_error_string(store->error));
    if (store->error == WC_NO_ERR_TRACE(OCSP_INVALID_STATUS)) {
        fprintf(stderr, "Overriding OCSP error\n");
        return 1;
    }
#ifndef WOLFSSL_ALT_CERT_CHAINS
    else if ((store->error == WC_NO_ERR_TRACE(ASN_NO_SIGNER_E) ||
              store->error == WC_NO_ERR_TRACE(ASN_SELF_SIGNED_E)
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
    defined(HAVE_WEBSERVER)
            || store->error == WOLFSSL_X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
#endif
            ) && store->error_depth == store->totalCerts - 1) {
        fprintf(stderr, "Overriding no signer error only for root cert\n");
        return 1;
    }
#endif
    else
        return preverify;
}

static int test_override_alt_cert_chain_ocsp_cb(void* ioCtx, const char* url,
        int urlSz, unsigned char* request, int requestSz,
        unsigned char** response)
{
    (void)ioCtx;
    (void)url;
    (void)urlSz;
    (void)request;
    (void)requestSz;
    (void)response;
    return WOLFSSL_CBIO_ERR_GENERAL;
}

static int test_override_alt_cert_chain_client_ctx_ready(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER,
            test_override_alt_cert_chain_cert_cb);
    ExpectIntEQ(wolfSSL_CTX_EnableOCSP(ctx, WOLFSSL_OCSP_CHECKALL |
            WOLFSSL_OCSP_URL_OVERRIDE), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_SetOCSP_Cb(ctx,
            test_override_alt_cert_chain_ocsp_cb, NULL, NULL), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_SetOCSP_OverrideURL(ctx, "not a url"),
            WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}

static int test_override_alt_cert_chain_client_ctx_ready2(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
    ExpectIntEQ(wolfSSL_CTX_EnableOCSP(ctx, WOLFSSL_OCSP_CHECKALL |
            WOLFSSL_OCSP_URL_OVERRIDE), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_SetOCSP_Cb(ctx,
            test_override_alt_cert_chain_ocsp_cb, NULL, NULL), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_SetOCSP_OverrideURL(ctx, "not a url"),
            WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}

static int test_override_alt_cert_chain_server_ctx_ready(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_file(ctx,
            "./certs/intermediate/server-chain-alt.pem"), WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}

static int test_override_alt_cert_chain(void)
{
    EXPECT_DECLS;
    size_t i;
    struct test_params {
        ctx_cb client_ctx_cb;
        ctx_cb server_ctx_cb;
        int result;
    } params[] = {
        {test_override_alt_cert_chain_client_ctx_ready,
                test_override_alt_cert_chain_server_ctx_ready, TEST_SUCCESS},
        {test_override_alt_cert_chain_client_ctx_ready2,
                test_override_alt_cert_chain_server_ctx_ready, -1001},
    };

    for (i = 0; i < sizeof(params)/sizeof(*params); i++) {
        test_ssl_cbf client_cbs, server_cbs;
        XMEMSET(&client_cbs, 0, sizeof(client_cbs));
        XMEMSET(&server_cbs, 0, sizeof(server_cbs));

        fprintf(stderr, "test config: %d\n", (int)i);

        client_cbs.ctx_ready = params[i].client_ctx_cb;
        server_cbs.ctx_ready = params[i].server_ctx_cb;

        ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbs,
            &server_cbs, NULL), params[i].result);

        ExpectIntEQ(client_cbs.return_code,
                    params[i].result <= 0 ? -1000 : TEST_SUCCESS);
        ExpectIntEQ(server_cbs.return_code,
                    params[i].result <= 0 ? -1000 : TEST_SUCCESS);
    }

    return EXPECT_RESULT();
}
#else
static int test_override_alt_cert_chain(void)
{
    return TEST_SKIPPED;
}
#endif

static int test_rpk_set_xxx_cert_type(void)
{
    EXPECT_DECLS;
#if defined(HAVE_RPK) && !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT)

    char ctype[MAX_CLIENT_CERT_TYPE_CNT + 1];   /* prepare bigger buffer */
    WOLFSSL_CTX* ctx = NULL;
    WOLFSSL* ssl = NULL;
    int tp;

    ctx = wolfSSL_CTX_new(wolfTLS_client_method());
    ExpectNotNull(ctx);

    ssl = wolfSSL_new(ctx);
    ExpectNotNull(ssl);

    XMEMSET(ctype, 0, sizeof(ctype));
    /*--------------------------------------------*/
    /* tests for wolfSSL_CTX_set_client_cert_type */
    /*--------------------------------------------*/

    /* illegal parameter test caces */
    ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(NULL, ctype,
                                                MAX_CLIENT_CERT_TYPE_CNT),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, ctype,
                                                sizeof(ctype)),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ctype[0] = WOLFSSL_CERT_TYPE_RPK;  /* set an identical cert type */
    ctype[1] = WOLFSSL_CERT_TYPE_RPK;

    ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, ctype,
                                                MAX_CLIENT_CERT_TYPE_CNT),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ctype[0] = WOLFSSL_CERT_TYPE_X509;
    ctype[1] = 10;                      /* set unknown cert type */

    ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, ctype,
                                                MAX_CLIENT_CERT_TYPE_CNT),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* pass larger type count */
    ctype[0] = WOLFSSL_CERT_TYPE_RPK;
    ctype[1] = WOLFSSL_CERT_TYPE_X509;
    ctype[2] = 1;                       /* pass unacceptable type count */

    ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, ctype,
                                                MAX_CLIENT_CERT_TYPE_CNT + 1),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* should accept NULL for type buffer */
    ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, NULL,
                                                MAX_CLIENT_CERT_TYPE_CNT),
                                                WOLFSSL_SUCCESS);

    /* should accept zero for type count */
    ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, ctype,
                                                0),
                                                WOLFSSL_SUCCESS);

    ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, ctype,
                                                MAX_CLIENT_CERT_TYPE_CNT),
                                                WOLFSSL_SUCCESS);

    /*--------------------------------------------*/
    /* tests for wolfSSL_CTX_set_server_cert_type */
    /*--------------------------------------------*/

    ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(NULL, ctype,
                                                MAX_SERVER_CERT_TYPE_CNT),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, ctype,
                                                sizeof(ctype)),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ctype[0] = WOLFSSL_CERT_TYPE_RPK;  /* set an identical cert type */
    ctype[1] = WOLFSSL_CERT_TYPE_RPK;

    ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, ctype,
                                                MAX_SERVER_CERT_TYPE_CNT),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ctype[0] = WOLFSSL_CERT_TYPE_X509;
    ctype[1] = 10;                      /* set unknown cert type */

    ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, ctype,
                                                MAX_SERVER_CERT_TYPE_CNT),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* pass larger type count */
    ctype[0] = WOLFSSL_CERT_TYPE_RPK;
    ctype[1] = WOLFSSL_CERT_TYPE_X509;
    ctype[2] = 1;                       /* pass unacceptable type count */

    ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, ctype,
                                                MAX_SERVER_CERT_TYPE_CNT + 1),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* should accept NULL for type buffer */
    ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, NULL,
                                                MAX_SERVER_CERT_TYPE_CNT),
                                                WOLFSSL_SUCCESS);

    /* should accept zero for type count */
    ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, ctype,
                                                0),
                                                WOLFSSL_SUCCESS);

    ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, ctype,
                                                MAX_CLIENT_CERT_TYPE_CNT),
                                                WOLFSSL_SUCCESS);

    /*--------------------------------------------*/
    /* tests for wolfSSL_set_client_cert_type */
    /*--------------------------------------------*/

    ExpectIntEQ(wolfSSL_set_client_cert_type(NULL, ctype,
                                                MAX_CLIENT_CERT_TYPE_CNT),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, ctype,
                                                sizeof(ctype)),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ctype[0] = WOLFSSL_CERT_TYPE_RPK;  /* set an identical cert type */
    ctype[1] = WOLFSSL_CERT_TYPE_RPK;

    ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, ctype,
                                                MAX_CLIENT_CERT_TYPE_CNT),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ctype[0] = WOLFSSL_CERT_TYPE_X509;
    ctype[1] = 10;                      /* set unknown cert type */

    ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, ctype,
                                                MAX_CLIENT_CERT_TYPE_CNT),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* pass larger type count */
    ctype[0] = WOLFSSL_CERT_TYPE_RPK;
    ctype[1] = WOLFSSL_CERT_TYPE_X509;
    ctype[2] = 1;                       /* pass unacceptable type count */

    ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, ctype,
                                                MAX_CLIENT_CERT_TYPE_CNT + 1),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* should accept NULL for type buffer */
    ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, NULL,
                                                MAX_CLIENT_CERT_TYPE_CNT),
                                                WOLFSSL_SUCCESS);

    /* should accept zero for type count */
    ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, ctype,
                                                0),
                                                WOLFSSL_SUCCESS);

    ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, ctype,
                                                MAX_CLIENT_CERT_TYPE_CNT),
                                                WOLFSSL_SUCCESS);

    /*--------------------------------------------*/
    /* tests for wolfSSL_CTX_set_server_cert_type */
    /*--------------------------------------------*/

    ExpectIntEQ(wolfSSL_set_server_cert_type(NULL, ctype,
                                                MAX_SERVER_CERT_TYPE_CNT),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, ctype,
                                                sizeof(ctype)),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ctype[0] = WOLFSSL_CERT_TYPE_RPK;  /* set an identical cert type */
    ctype[1] = WOLFSSL_CERT_TYPE_RPK;

    ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, ctype,
                                                MAX_SERVER_CERT_TYPE_CNT),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ctype[0] = WOLFSSL_CERT_TYPE_X509;
    ctype[1] = 10;                      /* set unknown cert type */

    ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, ctype,
                                                MAX_SERVER_CERT_TYPE_CNT),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* pass larger type count */
    ctype[0] = WOLFSSL_CERT_TYPE_RPK;
    ctype[1] = WOLFSSL_CERT_TYPE_X509;
    ctype[2] = 1;                       /* pass unacceptable type count */

    ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, ctype,
                                                MAX_SERVER_CERT_TYPE_CNT + 1),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* should accept NULL for type buffer */
    ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, NULL,
                                                MAX_SERVER_CERT_TYPE_CNT),
                                                WOLFSSL_SUCCESS);

    /* should accept zero for type count */
    ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, ctype,
                                                0),
                                                WOLFSSL_SUCCESS);

    ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, ctype,
                                                MAX_SERVER_CERT_TYPE_CNT),
                                                WOLFSSL_SUCCESS);

    /*------------------------------------------------*/
    /* tests for wolfSSL_get_negotiated_xxx_cert_type */
    /*------------------------------------------------*/

    ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(NULL, &tp),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl, NULL),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(NULL, &tp),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl, NULL),
                                                WC_NO_ERR_TRACE(BAD_FUNC_ARG));


    /* clean up */
    wolfSSL_free(ssl);
    wolfSSL_CTX_free(ctx);

#endif
    return EXPECT_RESULT();
}

#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)


static int test_dtls13_bad_epoch_ch(void)
{
    EXPECT_DECLS;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    const int EPOCH_OFF = 3;
    int groups[] = {
        WOLFSSL_ECC_SECP256R1,
        WOLFSSL_ECC_SECP384R1,
    };

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);

    /* disable hrr cookie so we can later check msgsReceived.got_client_hello
     *  with just one message */
    ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS);

    /* Set client groups to traditional only to avoid CH fragmentation */
    ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 2), WOLFSSL_SUCCESS);

    ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);

    ExpectIntGE(test_ctx.s_len, EPOCH_OFF + 2);

    /* first CH should use epoch 0x0 */
    ExpectTrue((test_ctx.s_buff[EPOCH_OFF] == 0x0) &&
        (test_ctx.s_buff[EPOCH_OFF + 1] == 0x0));

    /* change epoch to 2 */
    test_ctx.s_buff[EPOCH_OFF + 1] = 0x2;

    ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);

    ExpectIntNE(ssl_s->msgsReceived.got_client_hello, 1);

    /* resend the CH */
    ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS);

    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

    wolfSSL_free(ssl_c);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_s);

    return EXPECT_RESULT();
}
#else
static int test_dtls13_bad_epoch_ch(void)
{
    return TEST_SKIPPED;
}
#endif

#if ((defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
      defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TICKET_HAVE_ID) && \
      !defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)) || \
     (!defined(NO_OLD_TLS) && ((!defined(NO_AES) && !defined(NO_AES_CBC)) || \
      !defined(NO_DES3))) || !defined(WOLFSSL_NO_TLS12)) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
    defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(NO_SESSION_CACHE) && !defined(NO_SHA256)
static int test_short_session_id_ssl_ready(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    WOLFSSL_SESSION *sess = NULL;
    /* Setup the session to avoid errors */
    ssl->session->timeout = (word32)-1;
    ssl->session->side = WOLFSSL_CLIENT_END;
    ssl->session->version = ssl->version;
    /* Force a short session ID to be sent */
    ssl->session->sessionIDSz = 4;
#ifndef NO_SESSION_CACHE_REF
    /* Allow the client cache to be used */
    ssl->session->idLen = 4;
#endif
    ssl->session->isSetup = 1;
    ExpectNotNull(sess = wolfSSL_get_session(ssl));
    ExpectIntEQ(wolfSSL_set_session(ssl, sess), WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}

static int test_short_session_id(void)
{
    EXPECT_DECLS;
    test_ssl_cbf client_cbf;
    test_ssl_cbf server_cbf;
    size_t i;
    struct {
        method_provider client_meth;
        method_provider server_meth;
        const char* tls_version;
    } params[] = {
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
    defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TICKET_HAVE_ID) && \
    !defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
/* With WOLFSSL_TLS13_MIDDLEBOX_COMPAT a short ID will result in an error */
        { wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLSv1_3" },
#ifdef WOLFSSL_DTLS13
        { wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLSv1_3" },
#endif
#endif
#ifndef WOLFSSL_NO_TLS12
        { wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLSv1_2" },
#ifdef WOLFSSL_DTLS
        { wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "DTLSv1_2" },
#endif
#endif
#if !defined(NO_OLD_TLS) && ((!defined(NO_AES) && !defined(NO_AES_CBC)) || \
        !defined(NO_DES3))
        { wolfTLSv1_1_client_method, wolfTLSv1_1_server_method, "TLSv1_1" },
#ifdef WOLFSSL_DTLS
        { wolfDTLSv1_client_method, wolfDTLSv1_server_method, "DTLSv1_0" },
#endif
#endif
    };

    fprintf(stderr, "\n");

    for (i = 0; i < sizeof(params)/sizeof(*params) && !EXPECT_FAIL(); i++) {
        XMEMSET(&client_cbf, 0, sizeof(client_cbf));
        XMEMSET(&server_cbf, 0, sizeof(server_cbf));

        fprintf(stderr, "\tTesting short ID with %s\n", params[i].tls_version);

        client_cbf.ssl_ready = test_short_session_id_ssl_ready;
        client_cbf.method = params[i].client_meth;
        server_cbf.method = params[i].server_meth;

        ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
            &server_cbf, NULL), TEST_SUCCESS);
    }
    return EXPECT_RESULT();
}
#else
static int test_short_session_id(void)
{
    return TEST_SKIPPED;
}
#endif

#if defined(HAVE_NULL_CIPHER) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) \
    && defined(WOLFSSL_DTLS13)
static byte* test_find_string(const char *string,
    byte *buf, int buf_size)
{
    int string_size, i;

    string_size = (int)XSTRLEN(string);
    for (i = 0; i < buf_size - string_size - 1; i++) {
        if (XSTRCMP((char*)&buf[i], string) == 0)
            return &buf[i];
    }
    return NULL;
}

static int test_wolfSSL_dtls13_null_cipher(void)
{
    EXPECT_DECLS;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    const char *test_str = "test";
    int test_str_size;
    byte buf[255], *ptr = NULL;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    test_ctx.c_ciphers = test_ctx.s_ciphers = "TLS13-SHA256-SHA256";
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
    test_str_size = XSTRLEN("test") + 1;
    ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size);
    ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), test_str_size);
    ExpectIntEQ(XSTRCMP((char*)buf, test_str), 0);

    ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size);

    /* check that the packet was sent cleartext */
    ExpectNotNull(ptr = test_find_string(test_str, test_ctx.s_buff,
        test_ctx.s_len));
    if (ptr != NULL) {
        /* modify the message */
        *ptr = 'H';
        /* bad messages should be ignored in DTLS */
        ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), -1);
        ExpectIntEQ(ssl_s->error, WC_NO_ERR_TRACE(WANT_READ));
    }

    ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SHUTDOWN_NOT_DONE);
    ExpectIntEQ(wolfSSL_shutdown(ssl_s), WOLFSSL_SHUTDOWN_NOT_DONE);
    ExpectIntEQ(wolfSSL_shutdown(ssl_c), 1);
    ExpectIntEQ(wolfSSL_shutdown(ssl_s), 1);

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
    return TEST_SUCCESS;
}
#else
static int test_wolfSSL_dtls13_null_cipher(void)
{
    return TEST_SKIPPED;
}
#endif
#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) &&          \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) &&   \
    !defined(SINGLE_THREADED) && !defined(NO_RSA)

static int test_dtls_msg_get_connected_port(int fd, word16 *port)
{
    SOCKADDR_S peer;
    XSOCKLENT len;
    int ret;

    XMEMSET((byte*)&peer, 0, sizeof(peer));
    len = sizeof(peer);
    ret = getpeername(fd,  (SOCKADDR*)&peer, &len);
    if (ret != 0 || len > (XSOCKLENT)sizeof(peer))
        return -1;
    switch (peer.ss_family) {
#ifdef WOLFSSL_IPV6
    case WOLFSSL_IP6: {
        *port = ntohs(((SOCKADDR_IN6*)&peer)->sin6_port);
        break;
    }
#endif /* WOLFSSL_IPV6 */
    case WOLFSSL_IP4:
        *port = ntohs(((SOCKADDR_IN*)&peer)->sin_port);
        break;
    default:
        return -1;
    }
    return 0;
}

static int test_dtls_msg_from_other_peer_cb(WOLFSSL_CTX *ctx, WOLFSSL *ssl)
{
    char buf[1] = {'t'};
    SOCKADDR_IN_T addr;
    int sock_fd;
    word16 port;
    int err;

    (void)ssl;
    (void)ctx;

    if (ssl == NULL)
        return -1;

    err = test_dtls_msg_get_connected_port(wolfSSL_get_fd(ssl), &port);
    if (err != 0)
        return -1;

    sock_fd = socket(AF_INET_V, SOCK_DGRAM, 0);
    if (sock_fd == -1)
        return -1;
    build_addr(&addr, wolfSSLIP, port, 1, 0);

    /* send a packet to the server. Being another socket, the kernel will ensure
     * the source port will be different. */
    err = (int)sendto(sock_fd, buf, sizeof(buf), 0, (SOCKADDR*)&addr,
        sizeof(addr));

    close(sock_fd);
    if (err == -1)
        return -1;

    return 0;
}

/* setup a SSL session but just after the handshake send a packet to the server
 * with a source address different than the one of the connected client. The I/O
 * callback EmbedRecvFrom should just ignore the packet. Sending of the packet
 * is done in test_dtls_msg_from_other_peer_cb */
static int test_dtls_msg_from_other_peer(void)
{
    EXPECT_DECLS;
    callback_functions client_cbs;
    callback_functions server_cbs;

    XMEMSET((byte*)&client_cbs, 0, sizeof(client_cbs));
    XMEMSET((byte*)&server_cbs, 0, sizeof(server_cbs));

    client_cbs.method = wolfDTLSv1_2_client_method;
    server_cbs.method = wolfDTLSv1_2_server_method;
    client_cbs.doUdp = 1;
    server_cbs.doUdp = 1;

    test_wolfSSL_client_server_nofail_ex(&client_cbs, &server_cbs,
        test_dtls_msg_from_other_peer_cb);

    ExpectIntEQ(client_cbs.return_code, WOLFSSL_SUCCESS);
    ExpectIntEQ(server_cbs.return_code, WOLFSSL_SUCCESS);

    return EXPECT_RESULT();
}
#else
static int test_dtls_msg_from_other_peer(void)
{
    return TEST_SKIPPED;
}
#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) &&          \
        *  !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) &&  \
        *  !defined(SINGLE_THREADED) && !defined(NO_RSA) */
#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_IPV6) &&               \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) &&   \
    defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) \
    && !defined(USE_WINDOWS_API)
static int test_dtls_ipv6_check(void)
{
    EXPECT_DECLS;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    SOCKADDR_IN fake_addr6;
    int sockfd = -1;

    ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfDTLSv1_2_client_method()));
    ExpectNotNull(ssl_c  = wolfSSL_new(ctx_c));
    ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfDTLSv1_2_server_method()));
    ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile,
        WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile,
        WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    ExpectNotNull(ssl_s  = wolfSSL_new(ctx_s));
    XMEMSET((byte*)&fake_addr6, 0, sizeof(fake_addr6));
    /* mimic a sockaddr_in6 struct, this way we can't test without
     *  WOLFSSL_IPV6 */
    fake_addr6.sin_family = WOLFSSL_IP6;
    ExpectIntNE(sockfd = socket(AF_INET, SOCK_DGRAM, 0), -1);
    ExpectIntEQ(wolfSSL_set_fd(ssl_c, sockfd), WOLFSSL_SUCCESS);
    /* can't return error here, as the peer is opaque for wolfssl library at
     * this point */
    ExpectIntEQ(wolfSSL_dtls_set_peer(ssl_c, &fake_addr6, sizeof(fake_addr6)),
        WOLFSSL_SUCCESS);
    ExpectIntNE(fcntl(sockfd, F_SETFL, O_NONBLOCK), -1);
    wolfSSL_dtls_set_using_nonblock(ssl_c, 1);
    ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
    ExpectIntEQ(ssl_c->error, WC_NO_ERR_TRACE(SOCKET_ERROR_E));

    ExpectIntEQ(wolfSSL_dtls_set_peer(ssl_s, &fake_addr6, sizeof(fake_addr6)),
        WOLFSSL_SUCCESS);
    /* reuse the socket */
    ExpectIntEQ(wolfSSL_set_fd(ssl_c, sockfd), WOLFSSL_SUCCESS);
    wolfSSL_dtls_set_using_nonblock(ssl_s, 1);
    ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
    ExpectIntEQ(ssl_s->error, WC_NO_ERR_TRACE(SOCKET_ERROR_E));
    if (sockfd != -1)
        close(sockfd);

    wolfSSL_free(ssl_c);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_s);
    return EXPECT_RESULT();
}
#else
static int test_dtls_ipv6_check(void)
{
    return TEST_SKIPPED;
}
#endif

#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) &&   \
    defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_SECURE_RENEGOTIATION)

static WOLFSSL_SESSION* test_wolfSSL_SCR_after_resumption_session = NULL;

static void test_wolfSSL_SCR_after_resumption_ctx_ready(WOLFSSL_CTX* ctx)
{
    AssertIntEQ(wolfSSL_CTX_UseSecureRenegotiation(ctx), WOLFSSL_SUCCESS);
}

static void test_wolfSSL_SCR_after_resumption_on_result(WOLFSSL* ssl)
{
    if (test_wolfSSL_SCR_after_resumption_session == NULL) {
        test_wolfSSL_SCR_after_resumption_session = wolfSSL_get1_session(ssl);
        AssertNotNull(test_wolfSSL_SCR_after_resumption_session);
    }
    else {
        char testMsg[] = "Message after SCR";
        char msgBuf[sizeof(testMsg)];
        int ret;
        if (!wolfSSL_is_server(ssl)) {
            AssertIntEQ(WOLFSSL_SUCCESS,
                    wolfSSL_set_session(ssl,
                       test_wolfSSL_SCR_after_resumption_session));
        }
        AssertIntEQ(wolfSSL_Rehandshake(ssl), WOLFSSL_SUCCESS);
        AssertIntEQ(wolfSSL_write(ssl, testMsg, sizeof(testMsg)),
                    sizeof(testMsg));
        ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf));
        if (ret != sizeof(msgBuf)) /* Possibly APP_DATA_READY error. Retry. */
            ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf));
        AssertIntEQ(ret, sizeof(msgBuf));
    }
}

static void test_wolfSSL_SCR_after_resumption_ssl_ready(WOLFSSL* ssl)
{
    AssertIntEQ(WOLFSSL_SUCCESS,
           wolfSSL_set_session(ssl, test_wolfSSL_SCR_after_resumption_session));
}

static int test_wolfSSL_SCR_after_resumption(void)
{
    EXPECT_DECLS;
    callback_functions func_cb_client;
    callback_functions func_cb_server;

    XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
    XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));

    func_cb_client.method = wolfTLSv1_2_client_method;
    func_cb_client.ctx_ready = test_wolfSSL_SCR_after_resumption_ctx_ready;
    func_cb_client.on_result = test_wolfSSL_SCR_after_resumption_on_result;
    func_cb_server.method = wolfTLSv1_2_server_method;
    func_cb_server.ctx_ready = test_wolfSSL_SCR_after_resumption_ctx_ready;

    test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);

    ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS);
    ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS);

    if (EXPECT_SUCCESS()) {
        func_cb_client.ssl_ready = test_wolfSSL_SCR_after_resumption_ssl_ready;
        func_cb_server.on_result = test_wolfSSL_SCR_after_resumption_on_result;

        test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);

        ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS);
        ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS);
    }

    wolfSSL_SESSION_free(test_wolfSSL_SCR_after_resumption_session);

    return EXPECT_RESULT();
}

#else
static int test_wolfSSL_SCR_after_resumption(void)
{
    return TEST_SKIPPED;
}
#endif

static int test_wolfSSL_configure_args(void)
{
    EXPECT_DECLS;
#if defined(LIBWOLFSSL_CONFIGURE_ARGS) && defined(HAVE_WC_INTROSPECTION)
    ExpectNotNull(wolfSSL_configure_args());
#endif
    return EXPECT_RESULT();
}

static int test_dtls_no_extensions(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_DTLS) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(WOLFSSL_NO_TLS12)
    WOLFSSL *ssl_s = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    struct test_memio_ctx test_ctx;
    const byte chNoExtensions[] = {
        /* Handshake type */
        0x16,
        /* Version */
        0xfe, 0xff,
        /* Epoch */
        0x00, 0x00,
        /* Seq number */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        /* Length */
        0x00, 0x40,
        /* CH type */
        0x01,
        /* Length */
        0x00, 0x00, 0x34,
        /* Msg Seq */
        0x00, 0x00,
        /* Frag offset */
        0x00, 0x00, 0x00,
        /* Frag length */
        0x00, 0x00, 0x34,
        /* Version */
        0xfe, 0xff,
        /* Random */
        0x62, 0xfe, 0xbc, 0xfe, 0x2b, 0xfe, 0x3f, 0xeb, 0x03, 0xc4, 0xea, 0x37,
        0xe7, 0x47, 0x7e, 0x8a, 0xd9, 0xbf, 0x77, 0x0f, 0x6c, 0xb6, 0x77, 0x0b,
        0x03, 0x3f, 0x82, 0x2b, 0x21, 0x64, 0x57, 0x1d,
        /* Session Length */
        0x00,
        /* Cookie Length */
        0x00,
        /* CS Length */
        0x00, 0x0c,
        /* CS */
        0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x39, 0x00, 0x33,
        /* Comp Meths Length */
        0x01,
        /* Comp Meths */
        0x00
        /* And finally... no extensions */
    };
    int i;
#ifdef OPENSSL_EXTRA
    int repeats = 2;
#else
    int repeats = 1;
#endif

    for (i = 0; i < repeats; i++) {
        XMEMSET(&test_ctx, 0, sizeof(test_ctx));
        ssl_s = NULL;
        ctx_s = NULL;

        ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s,
            NULL, wolfDTLS_server_method), 0);

        test_memio_clear_buffer(&test_ctx, 0);
        ExpectIntEQ(
            test_memio_inject_message(&test_ctx, 1,
                (const char *)chNoExtensions, sizeof(chNoExtensions)), 0);


#ifdef OPENSSL_EXTRA
        if (i > 0) {
            ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_s, DTLS1_2_VERSION),
                        WOLFSSL_SUCCESS);
        }
#endif

        ExpectIntEQ(wolfSSL_accept(ssl_s), -1);
        ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);

        /* Expecting a handshake msg. Either HVR or SH. */
        ExpectIntGT(test_ctx.c_len, 0);
        ExpectIntEQ(test_ctx.c_buff[0], 0x16);

        wolfSSL_free(ssl_s);
        wolfSSL_CTX_free(ctx_s);
    }
#endif
    return EXPECT_RESULT();
}

static int test_tls_alert_no_server_hello(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12)
    WOLFSSL *ssl_c = NULL;
    WOLFSSL_CTX *ctx_c = NULL;
    struct test_memio_ctx test_ctx;
    unsigned char alert_msg[] = { 0x15, 0x03, 0x01, 0x00, 0x02, 0x02, 0x28 };

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ssl_c = NULL;
    ctx_c = NULL;

    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL,
        wolfTLSv1_2_client_method, NULL), 0);

    test_memio_clear_buffer(&test_ctx, 1);
    ExpectIntEQ(test_memio_inject_message(&test_ctx, 1,
        (const char *)alert_msg, sizeof(alert_msg)), 0);

    ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WC_NO_ERR_TRACE(FATAL_ERROR));

    wolfSSL_free(ssl_c);
    wolfSSL_CTX_free(ctx_c);
#endif
    return EXPECT_RESULT();
}

static int test_TLSX_CA_NAMES_bad_extension(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
    !defined(NO_CERTS) && !defined(WOLFSSL_NO_CA_NAMES) && \
    defined(OPENSSL_EXTRA) && defined(BUILD_TLS_CHACHA20_POLY1305_SHA256) && \
    defined(HAVE_ECC) && !defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
    /* This test should only fail (with BUFFER_ERROR) when we actually try to
     * parse the CA Names extension. Otherwise it will return other non-related
     * errors. If CA Names will be parsed in more configurations, that should
     * be reflected in the macro guard above. */
    WOLFSSL *ssl_c = NULL;
    WOLFSSL_CTX *ctx_c = NULL;
    struct test_memio_ctx test_ctx;
    /* HRR + SH using TLS_CHACHA20_POLY1305_SHA256 */
    const byte shBadCaNamesExt[] = {
        0x16, 0x03, 0x04, 0x00, 0x3f, 0x02, 0x00, 0x00, 0x3b, 0x03, 0x03, 0xcf,
        0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, 0x1e,
        0x65, 0xb8, 0x91, 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, 0x07,
        0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c, 0x00, 0x13, 0x03, 0x00, 0x00,
        0x13, 0x94, 0x7e, 0x00, 0x03, 0x0b, 0xf7, 0x03, 0x00, 0x2b, 0x00, 0x02,
        0x03, 0x04, 0x00, 0x33, 0x00, 0x02, 0x00, 0x19, 0x16, 0x03, 0x03, 0x00,
        0x5c, 0x02, 0x00, 0x00, 0x3b, 0x03, 0x03, 0x03, 0xcf, 0x21, 0xad, 0x74,
        0x00, 0x00, 0x83, 0x3f, 0x3b, 0x80, 0x01, 0xac, 0x65, 0x8c, 0x19, 0x2a,
        0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x02, 0x00, 0x9e, 0x09, 0x1c, 0xe8,
        0xa8, 0x09, 0x9c, 0x00, 0x13, 0x03, 0x00, 0x00, 0x11, 0x8f, 0x00, 0x00,
        0x03, 0x3f, 0x00, 0x0c, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04, 0x13, 0x05,
        0x00, 0x00, 0x08, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00,
        0x0d, 0x00, 0x00, 0x11, 0x00, 0x00, 0x0d, 0x00, 0x2f, 0x00, 0x01, 0xff,
        0xff, 0xff, 0xff, 0xfa, 0x0d, 0x00, 0x00, 0x00, 0xad, 0x02
    };
    const byte shBadCaNamesExt2[] = {
        0x16, 0x03, 0x04, 0x00, 0x3f, 0x02, 0x00, 0x00, 0x3b, 0x03, 0x03, 0xcf,
        0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, 0x1e,
        0x65, 0xb8, 0x91, 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, 0x07,
        0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c, 0x00, 0x13, 0x03, 0x00, 0x00,
        0x13, 0x94, 0x7e, 0x00, 0x03, 0x0b, 0xf7, 0x03, 0x00, 0x2b, 0x00, 0x02,
        0x03, 0x04, 0x00, 0x33, 0x00, 0x02, 0x00, 0x19, 0x16, 0x03, 0x03, 0x00,
        0x5e, 0x02, 0x00, 0x00, 0x3b, 0x03, 0x03, 0x7f, 0xd0, 0x2d, 0xea, 0x6e,
        0x53, 0xa1, 0x6a, 0xc9, 0xc8, 0x54, 0xef, 0x75, 0xe4, 0xd9, 0xc6, 0x3e,
        0x74, 0xcb, 0x30, 0x80, 0xcc, 0x83, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0xc0, 0x5a, 0x00, 0x13, 0x03, 0x00, 0x00, 0x11, 0x8f, 0x00, 0x00,
        0x03, 0x03, 0x00, 0x0c, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04, 0x53, 0x25,
        0x00, 0x00, 0x08, 0x00, 0x00, 0x06, 0x00, 0x04, 0x02, 0x05, 0x00, 0x00,
        0x0d, 0x00, 0x00, 0x11, 0x00, 0x00, 0x0d, 0x00, 0x2f, 0x00, 0x06, 0x00,
        0x04, 0x00, 0x03, 0x30, 0x00, 0x13, 0x94, 0x00, 0x06, 0x00, 0x04, 0x02
    };
    int groups[2] = {
        WOLFSSL_ECC_SECP256R1,
        WOLFSSL_ECC_SECP521R1,
    };
    int i = 0;

    for (i = 0; i < 2; i++) {
        XMEMSET(&test_ctx, 0, sizeof(test_ctx));

        ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL,
            wolfTLSv1_3_client_method, NULL), 0);

        switch (i) {
            case 0:
                test_memio_clear_buffer(&test_ctx, 0);
                ExpectIntEQ(test_memio_inject_message(&test_ctx, 1,
                    (const char *)shBadCaNamesExt, sizeof(shBadCaNamesExt)), 0);
                break;
            case 1:
                test_memio_clear_buffer(&test_ctx, 0);
                ExpectIntEQ(test_memio_inject_message(&test_ctx, 1,
                    (const char *)shBadCaNamesExt2,
                    sizeof(shBadCaNamesExt2)), 0);
                break;
        }

        /* Ensure the correct groups are used for the test */
        ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 2), WOLFSSL_SUCCESS);

        ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
#ifndef WOLFSSL_DISABLE_EARLY_SANITY_CHECKS
        ExpectIntEQ(wolfSSL_get_error(ssl_c, -1),
                                        WC_NO_ERR_TRACE(UNSUPPORTED_EXTENSION));
#else
        ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WC_NO_ERR_TRACE(BUFFER_ERROR));
#endif

        wolfSSL_free(ssl_c);
        ssl_c = NULL;
        wolfSSL_CTX_free(ctx_c);
        ctx_c = NULL;
    }

#endif
    return EXPECT_RESULT();
}

#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \
    defined(HAVE_IO_TESTS_DEPENDENCIES)
static void test_dtls_1_0_hvr_downgrade_ctx_ready(WOLFSSL_CTX* ctx)
{
    AssertIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_DTLSV1_2),
                WOLFSSL_SUCCESS);
}

static int test_dtls_1_0_hvr_downgrade(void)
{
    EXPECT_DECLS;
    callback_functions func_cb_client;
    callback_functions func_cb_server;

    XMEMSET(&func_cb_client, 0, sizeof(callback_functions));
    XMEMSET(&func_cb_server, 0, sizeof(callback_functions));

    func_cb_client.doUdp = func_cb_server.doUdp = 1;
    func_cb_client.method = wolfDTLS_client_method;
    func_cb_server.method = wolfDTLSv1_2_server_method;
    func_cb_client.ctx_ready = test_dtls_1_0_hvr_downgrade_ctx_ready;

    test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);

    ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS);
    ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS);

    return EXPECT_RESULT();
}
#else
static int test_dtls_1_0_hvr_downgrade(void)
{
    EXPECT_DECLS;
    return EXPECT_RESULT();
}
#endif

#if defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) && \
        defined(HAVE_SESSION_TICKET)

static WOLFSSL_SESSION* test_session_ticket_no_id_session = NULL;

static void test_session_ticket_no_id_on_result(WOLFSSL* ssl)
{
    test_session_ticket_no_id_session = wolfSSL_get1_session(ssl);
    AssertNotNull(test_session_ticket_no_id_session);
}

static void test_session_ticket_no_id_ctx_ready(WOLFSSL_CTX* ctx)
{
    AssertIntEQ(wolfSSL_CTX_UseSessionTicket(ctx), WOLFSSL_SUCCESS);
}

static void test_session_ticket_no_id_ssl_ready(WOLFSSL* ssl)
{
    test_session_ticket_no_id_session->sessionIDSz = 0;
    AssertIntEQ(WOLFSSL_SUCCESS,
           wolfSSL_set_session(ssl, test_session_ticket_no_id_session));
}

static int test_session_ticket_no_id(void)
{
    /* We are testing an expired (invalid crypto context in out case since the
     * ctx changes) session ticket being sent with the session ID being 0
     * length. */
    EXPECT_DECLS;
    callback_functions func_cb_client;
    callback_functions func_cb_server;

    XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
    XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));
    func_cb_client.method = wolfTLSv1_2_client_method;
    func_cb_client.ctx_ready = test_session_ticket_no_id_ctx_ready;
    func_cb_client.on_result = test_session_ticket_no_id_on_result;
    func_cb_server.method = wolfTLSv1_2_server_method;
    func_cb_server.ctx_ready = test_session_ticket_no_id_ctx_ready;

    test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);

    ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS);
    ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS);

    XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
    XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));
    func_cb_client.method = wolfTLSv1_2_client_method;
    func_cb_client.ctx_ready = test_session_ticket_no_id_ctx_ready;
    func_cb_client.ssl_ready = test_session_ticket_no_id_ssl_ready;
    func_cb_server.method = wolfTLSv1_2_server_method;
    func_cb_server.ctx_ready = test_session_ticket_no_id_ctx_ready;

    test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);

    ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS);
    ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS);

    wolfSSL_SESSION_free(test_session_ticket_no_id_session);

    return EXPECT_RESULT();
}
#else
static int test_session_ticket_no_id(void)
{
    EXPECT_DECLS;
    return EXPECT_RESULT();
}
#endif

static int test_session_ticket_hs_update(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
    defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
    struct test_memio_ctx test_ctx;
    struct test_memio_ctx test_ctx2;
    struct test_memio_ctx test_ctx3;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_c2 = NULL;
    WOLFSSL *ssl_c3 = NULL;
    WOLFSSL *ssl_s = NULL;
    WOLFSSL *ssl_s2 = NULL;
    WOLFSSL *ssl_s3 = NULL;
    WOLFSSL_SESSION *sess = NULL;
    byte read_data[1];

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    XMEMSET(&test_ctx2, 0, sizeof(test_ctx2));
    XMEMSET(&test_ctx3, 0, sizeof(test_ctx3));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);

    /* Generate tickets */
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
    wolfSSL_SetLoggingPrefix("client");
    /* Read the ticket msg */
    ExpectIntEQ(wolfSSL_read(ssl_c, read_data, sizeof(read_data)),
            WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
    ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);
    wolfSSL_SetLoggingPrefix(NULL);

    ExpectIntEQ(test_memio_setup(&test_ctx2, &ctx_c, &ctx_s, &ssl_c2, &ssl_s2,
        wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
    ExpectIntEQ(test_memio_setup(&test_ctx3, &ctx_c, &ctx_s, &ssl_c3, &ssl_s3,
        wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);

    ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
    ExpectIntEQ(wolfSSL_set_session(ssl_c2, sess), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_set_session(ssl_c3, sess), WOLFSSL_SUCCESS);

    wolfSSL_SetLoggingPrefix("client");
    /* Exchange initial flights for the second connection */
    ExpectIntEQ(wolfSSL_connect(ssl_c2), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
    ExpectIntEQ(wolfSSL_get_error(ssl_c2, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);
    wolfSSL_SetLoggingPrefix(NULL);
    wolfSSL_SetLoggingPrefix("server");
    ExpectIntEQ(wolfSSL_accept(ssl_s2), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
    ExpectIntEQ(wolfSSL_get_error(ssl_s2, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);
    wolfSSL_SetLoggingPrefix(NULL);

    /* Complete third connection so that new tickets are exchanged */
    ExpectIntEQ(test_memio_do_handshake(ssl_c3, ssl_s3, 10, NULL), 0);
    /* Read the ticket msg */
    wolfSSL_SetLoggingPrefix("client");
    ExpectIntEQ(wolfSSL_read(ssl_c3, read_data, sizeof(read_data)),
            WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
    ExpectIntEQ(wolfSSL_get_error(ssl_c3, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);
    wolfSSL_SetLoggingPrefix(NULL);

    /* Complete second connection */
    ExpectIntEQ(test_memio_do_handshake(ssl_c2, ssl_s2, 10, NULL), 0);

    ExpectIntEQ(wolfSSL_session_reused(ssl_c2), 1);
    ExpectIntEQ(wolfSSL_session_reused(ssl_c3), 1);

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_c2);
    wolfSSL_free(ssl_c3);
    wolfSSL_free(ssl_s);
    wolfSSL_free(ssl_s2);
    wolfSSL_free(ssl_s3);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
    wolfSSL_SESSION_free(sess);
#endif
    return EXPECT_RESULT();
}

#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \
    defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_SECURE_RENEGOTIATION)
static void test_dtls_downgrade_scr_server_ctx_ready_server(WOLFSSL_CTX* ctx)
{
    AssertIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_DTLSV1_2),
                WOLFSSL_SUCCESS);
    AssertIntEQ(wolfSSL_CTX_UseSecureRenegotiation(ctx), WOLFSSL_SUCCESS);
}

static void test_dtls_downgrade_scr_server_ctx_ready(WOLFSSL_CTX* ctx)
{
    AssertIntEQ(wolfSSL_CTX_UseSecureRenegotiation(ctx), WOLFSSL_SUCCESS);
}

static void test_dtls_downgrade_scr_server_on_result(WOLFSSL* ssl)
{
    char testMsg[] = "Message after SCR";
    char msgBuf[sizeof(testMsg)];
    if (wolfSSL_is_server(ssl)) {
        AssertIntEQ(wolfSSL_Rehandshake(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
        AssertIntEQ(wolfSSL_get_error(ssl, -1), WC_NO_ERR_TRACE(APP_DATA_READY));
        AssertIntEQ(wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)), sizeof(msgBuf));
        AssertIntEQ(wolfSSL_Rehandshake(ssl), WOLFSSL_SUCCESS);
        AssertIntEQ(wolfSSL_write(ssl, testMsg, sizeof(testMsg)),
                    sizeof(testMsg));
    }
    else {
        AssertIntEQ(wolfSSL_write(ssl, testMsg, sizeof(testMsg)),
                    sizeof(testMsg));
        AssertIntEQ(wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)), sizeof(msgBuf));
    }
}

static int test_dtls_downgrade_scr_server(void)
{
    EXPECT_DECLS;
    callback_functions func_cb_client;
    callback_functions func_cb_server;

    XMEMSET(&func_cb_client, 0, sizeof(callback_functions));
    XMEMSET(&func_cb_server, 0, sizeof(callback_functions));

    func_cb_client.doUdp = func_cb_server.doUdp = 1;
    func_cb_client.method = wolfDTLSv1_2_client_method;
    func_cb_server.method = wolfDTLS_server_method;
    func_cb_client.ctx_ready = test_dtls_downgrade_scr_server_ctx_ready;
    func_cb_server.ctx_ready = test_dtls_downgrade_scr_server_ctx_ready_server;
    func_cb_client.on_result = test_dtls_downgrade_scr_server_on_result;
    func_cb_server.on_result = test_dtls_downgrade_scr_server_on_result;

    test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);

    ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS);
    ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS);

    return EXPECT_RESULT();
}
#else
static int test_dtls_downgrade_scr_server(void)
{
    EXPECT_DECLS;
    return EXPECT_RESULT();
}
#endif

#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \
    defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_SECURE_RENEGOTIATION)
static void test_dtls_downgrade_scr_ctx_ready(WOLFSSL_CTX* ctx)
{
    AssertIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_DTLSV1_2),
                WOLFSSL_SUCCESS);
    AssertIntEQ(wolfSSL_CTX_UseSecureRenegotiation(ctx), WOLFSSL_SUCCESS);
}

static void test_dtls_downgrade_scr_on_result(WOLFSSL* ssl)
{
    char testMsg[] = "Message after SCR";
    char msgBuf[sizeof(testMsg)];
    if (wolfSSL_is_server(ssl)) {
        AssertIntEQ(wolfSSL_Rehandshake(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
        AssertIntEQ(wolfSSL_get_error(ssl, -1), WC_NO_ERR_TRACE(APP_DATA_READY));
        AssertIntEQ(wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)), sizeof(msgBuf));
        AssertIntEQ(wolfSSL_Rehandshake(ssl), WOLFSSL_SUCCESS);
        AssertIntEQ(wolfSSL_write(ssl, testMsg, sizeof(testMsg)),
                    sizeof(testMsg));
    }
    else {
        AssertIntEQ(wolfSSL_write(ssl, testMsg, sizeof(testMsg)),
                    sizeof(testMsg));
        AssertIntEQ(wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)), sizeof(msgBuf));
    }
}

static int test_dtls_downgrade_scr(void)
{
    EXPECT_DECLS;
    callback_functions func_cb_client;
    callback_functions func_cb_server;

    XMEMSET(&func_cb_client, 0, sizeof(callback_functions));
    XMEMSET(&func_cb_server, 0, sizeof(callback_functions));

    func_cb_client.doUdp = func_cb_server.doUdp = 1;
    func_cb_client.method = wolfDTLS_client_method;
    func_cb_server.method = wolfDTLSv1_2_server_method;
    func_cb_client.ctx_ready = test_dtls_downgrade_scr_ctx_ready;
    func_cb_client.on_result = test_dtls_downgrade_scr_on_result;
    func_cb_server.on_result = test_dtls_downgrade_scr_on_result;

    test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);

    ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS);
    ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS);

    return EXPECT_RESULT();
}
#else
static int test_dtls_downgrade_scr(void)
{
    EXPECT_DECLS;
    return EXPECT_RESULT();
}
#endif

#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \
    && !defined(WOLFSSL_NO_TLS12)

static int test_dtls_client_hello_timeout_downgrade_read_cb(WOLFSSL *ssl,
        char *data, int sz, void *ctx)
{
    static int call_counter = 0;
    call_counter++;
    (void)ssl;
    (void)data;
    (void)sz;
    (void)ctx;
    switch (call_counter) {
        case 1:
        case 2:
            return WOLFSSL_CBIO_ERR_TIMEOUT;
        case 3:
            return WOLFSSL_CBIO_ERR_WANT_READ;
        default:
            AssertIntLE(call_counter, 3);
            return -1;
    }
}
#endif

/* Make sure we don't send acks before getting a server hello */
static int test_dtls_client_hello_timeout_downgrade(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \
    && !defined(WOLFSSL_NO_TLS12)

    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    DtlsRecordLayerHeader* dtlsRH;
    size_t len;
    byte sequence_number[8];
    int i;

    for (i = 0; i < 2; i++) {
        XMEMSET(&test_ctx, 0, sizeof(test_ctx));

        ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
            wolfDTLS_client_method, wolfDTLSv1_2_server_method), 0);

        if (i == 0) {
            /* First time simulate timeout in IO layer */
            /* CH1 */
            ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
            /* HVR */
            ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
            /* CH2 */
            ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
            /* SH flight */
            ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
            /* Drop the SH */
            if (EXPECT_SUCCESS()) {
                ExpectIntEQ(test_memio_drop_message(&test_ctx, 1, 0), 0);
            }
            /* Read the remainder of the flight */
            ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
            wolfSSL_SSLSetIORecv(ssl_c,
                    test_dtls_client_hello_timeout_downgrade_read_cb);
            /* CH3 */
            ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
            wolfSSL_SSLSetIORecv(ssl_c, test_memio_read_cb);
        }
        else {
            /* Second time call wolfSSL_dtls_got_timeout */
            /* CH1 */
            ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
            /* HVR */
            ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
            /* CH2 */
            ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
            /* SH flight */
            ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
            /* Drop the SH */
            if (EXPECT_SUCCESS()) {
                ExpectIntEQ(test_memio_drop_message(&test_ctx, 1, 0), 0);
            }
            /* Read the remainder of the flight */
            ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
            /* Quick timeout should be set as we received at least one msg */
            ExpectIntEQ(wolfSSL_dtls13_use_quick_timeout(ssl_c), 1);
            ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS);
            /* Quick timeout should be cleared after a quick timeout */
            /* CH3 */
            ExpectIntEQ(wolfSSL_dtls13_use_quick_timeout(ssl_c), 0);
            ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS);
        }

        /* Parse out to make sure we got exactly one ClientHello message */
        XMEMSET(&sequence_number, 0, sizeof(sequence_number));
        /* Second ClientHello after HVR */
        sequence_number[7] = 2;
        dtlsRH = (DtlsRecordLayerHeader*)test_ctx.s_buff;
        ExpectIntEQ(dtlsRH->type, handshake);
        ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR);
        ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR);
        ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number,
                sizeof(sequence_number)), 0);
        len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]);
        ExpectIntEQ(sizeof(DtlsRecordLayerHeader) + len, test_ctx.s_len);

        /* Connection should be able to continue */
        ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

        wolfSSL_free(ssl_c);
        wolfSSL_free(ssl_s);
        wolfSSL_CTX_free(ctx_c);
        wolfSSL_CTX_free(ctx_s);
        ssl_c = NULL;
        ssl_s = NULL;
        ctx_c = NULL;
        ctx_s = NULL;
        if (!EXPECT_SUCCESS())
            break;
    }

#endif
    return EXPECT_RESULT();
}

#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
static int test_dtls_client_hello_timeout_read_cb(WOLFSSL *ssl, char *data,
        int sz, void *ctx)
{
    static int call_counter = 0;
    call_counter++;
    (void)ssl;
    (void)data;
    (void)sz;
    (void)ctx;
    switch (call_counter) {
        case 1:
            return WOLFSSL_CBIO_ERR_TIMEOUT;
        case 2:
            return WOLFSSL_CBIO_ERR_WANT_READ;
        default:
            AssertIntLE(call_counter, 2);
            return -1;
    }
}
#endif

/* Make sure we don't send acks before getting a server hello */
static int test_dtls_client_hello_timeout(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
    WOLFSSL *ssl_c = NULL;
    WOLFSSL_CTX *ctx_c = NULL;
    struct test_memio_ctx test_ctx;
    DtlsRecordLayerHeader* dtlsRH;
    size_t idx;
    size_t len;
    byte sequence_number[8];
    int i;

    for (i = 0; i < 2; i++) {
        XMEMSET(&test_ctx, 0, sizeof(test_ctx));

        ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL,
            wolfDTLSv1_3_client_method, NULL), 0);

        if (i == 0) {
            /* First time simulate timeout in IO layer */
            wolfSSL_SSLSetIORecv(ssl_c, test_dtls_client_hello_timeout_read_cb);
            ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
        }
        else {
            /* Second time call wolfSSL_dtls_got_timeout */
            ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
            ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS);
        }

        /* Parse out to make sure we got exactly two ClientHello messages */
        idx = 0;
        XMEMSET(&sequence_number, 0, sizeof(sequence_number));
        /* First ClientHello */
        dtlsRH = (DtlsRecordLayerHeader*)(test_ctx.s_buff + idx);
        ExpectIntEQ(dtlsRH->type, handshake);
        ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR);
        ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR);
        ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number,
                sizeof(sequence_number)), 0);
        len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]);
        ExpectIntLT(idx + sizeof(DtlsRecordLayerHeader) + len, test_ctx.s_len);
        idx += sizeof(DtlsRecordLayerHeader) + len;
        /* Second ClientHello */
        sequence_number[7] = 1;
        dtlsRH = (DtlsRecordLayerHeader*)(test_ctx.s_buff + idx);
        ExpectIntEQ(dtlsRH->type, handshake);
        ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR);
        ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR);
        ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number,
                sizeof(sequence_number)), 0);
        len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]);
        ExpectIntEQ(idx + sizeof(DtlsRecordLayerHeader) + len, test_ctx.s_len);

        wolfSSL_free(ssl_c);
        wolfSSL_CTX_free(ctx_c);
        ssl_c = NULL;
        ctx_c = NULL;
        if (!EXPECT_SUCCESS())
            break;
    }

#endif
    return EXPECT_RESULT();
}

/* DTLS test when dropping the changed cipher spec message */
static int test_dtls_dropped_ccs(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) \
    && !defined(WOLFSSL_NO_TLS12)

    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    DtlsRecordLayerHeader* dtlsRH;
    size_t len;
    byte data[1];


    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0);

    /* CH1 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* HVR */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* CH2 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Server first flight */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* Client flight */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Server ccs + finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1);

    /* Drop the ccs */
    dtlsRH = (DtlsRecordLayerHeader*)test_ctx.c_buff;
    len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]);
    ExpectIntEQ(len, 1);
    ExpectIntEQ(dtlsRH->type, change_cipher_spec);
    if (EXPECT_SUCCESS()) {
        ExpectIntEQ(test_memio_drop_message(&test_ctx, 1, 0), 0);
    }

    /* Client rtx flight */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS);
    /* Server ccs + finished rtx */
    ExpectIntEQ(wolfSSL_read(ssl_s, data, sizeof(data)), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* Client processes finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1);

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
#endif
    return EXPECT_RESULT();
}

#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) \
    && !defined(WOLFSSL_NO_TLS12)
static int test_dtls_seq_num_downgrade_check_num(byte* ioBuf, int ioBufLen,
        byte seq_num)
{
    EXPECT_DECLS;
    DtlsRecordLayerHeader* dtlsRH;
    byte sequence_number[8];

    XMEMSET(&sequence_number, 0, sizeof(sequence_number));

    ExpectIntGE(ioBufLen, sizeof(*dtlsRH));
    dtlsRH = (DtlsRecordLayerHeader*)ioBuf;
    ExpectIntEQ(dtlsRH->type, handshake);
    ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR);
    ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR);
    sequence_number[7] = seq_num;
    ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number,
            sizeof(sequence_number)), 0);

    return EXPECT_RESULT();
}
#endif

/*
 * Make sure that we send the correct sequence number after a HelloVerifyRequest
 * and after a HelloRetryRequest. This is testing the server side as it is
 * operating statelessly and should copy the sequence number of the ClientHello.
 */
static int test_dtls_seq_num_downgrade(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) \
    && !defined(WOLFSSL_NO_TLS12)
    WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
    struct test_memio_ctx test_ctx;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_2_client_method, wolfDTLS_server_method), 0);

    /* CH1 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    ExpectIntEQ(test_dtls_seq_num_downgrade_check_num(test_ctx.s_buff,
            test_ctx.s_len, 0), TEST_SUCCESS);
    /* HVR */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    ExpectIntEQ(test_dtls_seq_num_downgrade_check_num(test_ctx.c_buff,
            test_ctx.c_len, 0), TEST_SUCCESS);
    /* CH2 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    ExpectIntEQ(test_dtls_seq_num_downgrade_check_num(test_ctx.s_buff,
            test_ctx.s_len, 1), TEST_SUCCESS);
    /* Server first flight */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    ExpectIntEQ(test_dtls_seq_num_downgrade_check_num(test_ctx.c_buff,
            test_ctx.c_len, 1), TEST_SUCCESS);

    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

    wolfSSL_free(ssl_c);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_s);
#endif
    return EXPECT_RESULT();
}

/**
 * Make sure we don't send RSA Signature Hash Algorithms in the
 * CertificateRequest when we don't have any such ciphers set.
 * @return EXPECT_RESULT()
 */
static int test_certreq_sighash_algos(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(WOLFSSL_MAX_STRENGTH) && defined(HAVE_ECC) && \
    !defined(NO_SHA256) && defined(WOLFSSL_SHA384) && \
    defined(WOLFSSL_AES_256) && defined(HAVE_AES_CBC) && \
    !defined(WOLFSSL_NO_TLS12)
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    int idx = 0;
    int maxIdx = 0;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    test_ctx.c_ciphers = test_ctx.s_ciphers =
            "ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA384";
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);

    ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_c,
            caEccCertFile, NULL), WOLFSSL_SUCCESS);

    wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER, NULL);
    ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
            CERT_FILETYPE), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
            CERT_FILETYPE), WOLFSSL_SUCCESS);

    ExpectIntEQ(wolfSSL_connect(ssl_c), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
    ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);

    ExpectIntEQ(wolfSSL_accept(ssl_s), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
    ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
        WOLFSSL_ERROR_WANT_READ);

    /* Find the CertificateRequest message */
    for (idx = 0; idx < test_ctx.c_len && EXPECT_SUCCESS();) {
        word16 len;
        ExpectIntEQ(test_ctx.c_buff[idx++], handshake);
        ExpectIntEQ(test_ctx.c_buff[idx++], SSLv3_MAJOR);
        ExpectIntEQ(test_ctx.c_buff[idx++], TLSv1_2_MINOR);
        ato16(test_ctx.c_buff + idx, &len);
        idx += OPAQUE16_LEN;
        if (test_ctx.c_buff[idx] == certificate_request) {
            idx++;
            /* length */
            idx += OPAQUE24_LEN;
            /* cert types */
            idx += 1 + test_ctx.c_buff[idx];
            /* Sig algos */
            ato16(test_ctx.c_buff + idx, &len);
            idx += OPAQUE16_LEN;
            maxIdx = idx + (int)len;
            for (; idx < maxIdx && EXPECT_SUCCESS(); idx += OPAQUE16_LEN) {
                if (test_ctx.c_buff[idx+1] == ED25519_SA_MINOR ||
                        test_ctx.c_buff[idx+1] == ED448_SA_MINOR ||
                        test_ctx.c_buff[idx+1] ==
                                      ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR ||
                        test_ctx.c_buff[idx+1] ==
                                      ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR ||
                        test_ctx.c_buff[idx+1] ==
                                      ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR)
                    ExpectIntEQ(test_ctx.c_buff[idx], NEW_SA_MAJOR);
                else
                    ExpectIntEQ(test_ctx.c_buff[idx+1], ecc_dsa_sa_algo);
            }
            break;
        }
        else {
            idx += (int)len;
        }
    }
    ExpectIntLT(idx, test_ctx.c_len);


    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
#endif
    return EXPECT_RESULT();
}

#if defined(HAVE_CRL) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(WOLFSSL_CRL_ALLOW_MISSING_CDP)
static int test_revoked_loaded_int_cert_ctx_ready1(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, myVerify);
    myVerifyAction = VERIFY_USE_PREVERIFY;
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx,
            "./certs/ca-cert.pem", NULL, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx,
            "./certs/intermediate/ca-int-cert.pem", NULL, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_EnableCRL(ctx, WOLFSSL_CRL_CHECKALL),
            WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_LoadCRLFile(ctx,
            "./certs/crl/extra-crls/ca-int-cert-revoked.pem",
            WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_LoadCRLFile(ctx,
            "./certs/crl/ca-int.pem",
            WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}

static int test_revoked_loaded_int_cert_ctx_ready2(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, myVerify);
    myVerifyAction = VERIFY_USE_PREVERIFY;
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx,
            "./certs/ca-cert.pem", NULL, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx,
            "./certs/intermediate/ca-int-cert.pem", NULL, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx,
            "./certs/intermediate/ca-int2-cert.pem", NULL, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_EnableCRL(ctx, WOLFSSL_CRL_CHECKALL),
            WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_LoadCRLFile(ctx,
            "./certs/crl/ca-int2.pem",
            WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_LoadCRLFile(ctx,
            "./certs/crl/extra-crls/ca-int-cert-revoked.pem",
            WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_LoadCRLFile(ctx,
            "./certs/crl/ca-int.pem",
            WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}

static int test_revoked_loaded_int_cert_ctx_ready3_crl_missing_cb(int ret,
        WOLFSSL_CRL* crl, WOLFSSL_CERT_MANAGER* cm, void* ctx)
{
    (void)crl;
    (void)cm;
    (void)ctx;
    if (ret == WC_NO_ERR_TRACE(CRL_MISSING))
        return 1;
    return 0;
}

/* Here we are allowing missing CRL's but want to error out when its revoked */
static int test_revoked_loaded_int_cert_ctx_ready3(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, myVerify);
    myVerifyAction = VERIFY_USE_PREVERIFY;
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx,
            "./certs/ca-cert.pem", NULL, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx,
            "./certs/intermediate/ca-int-cert.pem", NULL, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations_ex(ctx,
            "./certs/intermediate/ca-int2-cert.pem", NULL, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_EnableCRL(ctx, WOLFSSL_CRL_CHECKALL),
            WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_LoadCRLFile(ctx,
            "./certs/crl/extra-crls/ca-int-cert-revoked.pem",
            WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_SetCRL_ErrorCb(ctx,
            test_revoked_loaded_int_cert_ctx_ready3_crl_missing_cb, NULL),
            WOLFSSL_SUCCESS);
    return EXPECT_RESULT();
}
#endif

static int test_revoked_loaded_int_cert(void)
{
    EXPECT_DECLS;
#if defined(HAVE_CRL) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(WOLFSSL_CRL_ALLOW_MISSING_CDP)
    test_ssl_cbf client_cbf;
    test_ssl_cbf server_cbf;
    struct {
        const char* certPemFile;
        const char* keyPemFile;
        ctx_cb      client_ctx_ready;
    } test_params[] = {
        {"./certs/intermediate/ca-int2-cert.pem",
            "./certs/intermediate/ca-int2-key.pem",
            test_revoked_loaded_int_cert_ctx_ready1},
        {"./certs/intermediate/server-chain.pem",
            "./certs/server-key.pem", test_revoked_loaded_int_cert_ctx_ready2},
        {"./certs/intermediate/server-chain-short.pem",
            "./certs/server-key.pem", test_revoked_loaded_int_cert_ctx_ready2},
        {"./certs/intermediate/server-chain-short.pem",
            "./certs/server-key.pem", test_revoked_loaded_int_cert_ctx_ready3},
    };
    size_t i;

    printf("\n");

    for (i = 0; i < XELEM_CNT(test_params); i++) {
        XMEMSET(&client_cbf, 0, sizeof(client_cbf));
        XMEMSET(&server_cbf, 0, sizeof(server_cbf));

        printf("\tTesting with %s...\n", test_params[i].certPemFile);

        server_cbf.certPemFile = test_params[i].certPemFile;
        server_cbf.keyPemFile  = test_params[i].keyPemFile;

        client_cbf.ctx_ready = test_params[i].client_ctx_ready;

        ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
            &server_cbf, NULL), -1001);
        ExpectIntEQ(client_cbf.last_err, WC_NO_ERR_TRACE(CRL_CERT_REVOKED));
        ExpectIntEQ(server_cbf.last_err, WC_NO_ERR_TRACE(FATAL_ERROR));

        if (!EXPECT_SUCCESS())
            break;
        printf("\t%s passed\n", test_params[i].certPemFile);
    }
#endif
    return EXPECT_RESULT();
}

static int test_dtls13_frag_ch_pq(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \
    && defined(WOLFSSL_DTLS_CH_FRAG) && defined(WOLFSSL_HAVE_MLKEM)
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    const char *test_str = "test";
    int test_str_size;
    byte buf[255];
#if defined(WOLFSSL_MLKEM_KYBER)
    #if !defined(WOLFSSL_NO_KYBER1024)
    int group = WOLFSSL_KYBER_LEVEL5;
    const char *group_name = "KYBER_LEVEL5";
    #elif !defined(WOLFSSL_NO_KYBER768)
    int group = WOLFSSL_KYBER_LEVEL3;
    const char *group_name = "KYBER_LEVEL3";
    #else
    int group = WOLFSSL_KYBER_LEVEL1;
    const char *group_name = "KYBER_LEVEL1";
    #endif
#elif !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
    #if !defined(WOLFSSL_NO_ML_KEM_1024)
    int group = WOLFSSL_ML_KEM_1024;
    const char *group_name = "ML_KEM_1024";
    #elif !defined(WOLFSSL_NO_ML_KEM_768)
    int group = WOLFSSL_ML_KEM_768;
    const char *group_name = "ML_KEM_768";
    #else
    int group = WOLFSSL_ML_KEM_512;
    const char *group_name = "ML_KEM_512";
    #endif
#elif defined(WOLFSSL_PQC_HYBRIDS)
    #if defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768)
    int group = WOLFSSL_X25519MLKEM768;
    const char *group_name = "X25519MLKEM768";
    #elif !defined(WOLFSSL_NO_ML_KEM_768)
    int group = WOLFSSL_SECP256R1MLKEM768;
    const char *group_name = "SecP256r1MLKEM768";
    #else
    int group = WOLFSSL_SECP384R1MLKEM1024;
    const char *group_name = "SecP384r1MLKEM1024";
    #endif
#endif

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
    /* Add in a large post-quantum key share to make the CH long. */
    ExpectIntEQ(wolfSSL_set_groups(ssl_c, &group, 1), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, group), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_dtls13_allow_ch_frag(ssl_s, 1), WOLFSSL_SUCCESS);
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
    ExpectStrEQ(wolfSSL_get_curve_name(ssl_c), group_name);
    ExpectStrEQ(wolfSSL_get_curve_name(ssl_s), group_name);
    test_str_size = XSTRLEN("test") + 1;
    ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size);
    ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), test_str_size);
    ExpectIntEQ(XSTRCMP((char*)buf, test_str), 0);
    ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size);
    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
#endif
    return EXPECT_RESULT();
}

#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) \
    && defined(WOLFSSL_DTLS_MTU) && defined(WOLFSSL_DTLS_CH_FRAG) && \
    defined(WOLFSSL_AES_256)
static int test_dtls_frag_ch_count_records(byte* b, int len)
{
    DtlsRecordLayerHeader* dtlsRH;
    int records = 0;
    size_t recordLen;
    while (len > 0) {
        records++;
        dtlsRH = (DtlsRecordLayerHeader*)b;
        recordLen = (dtlsRH->length[0] << 8) | dtlsRH->length[1];
        if (recordLen > (size_t)len)
            break;
        b += sizeof(DtlsRecordLayerHeader) + recordLen;
        len -= sizeof(DtlsRecordLayerHeader) + recordLen;
    }
    return records;
}
#endif

static int test_dtls_frag_ch(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \
    && defined(WOLFSSL_DTLS_MTU) && defined(WOLFSSL_DTLS_CH_FRAG) && \
    defined(WOLFSSL_AES_256)
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    static unsigned int DUMMY_MTU = 256;
    unsigned int len;
    unsigned char four_frag_CH[] = {
      0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0xda, 0x01, 0x00, 0x02, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0xce, 0xfe, 0xfd, 0xf3, 0x94, 0x01, 0x33, 0x2c, 0xcf, 0x2c, 0x47, 0xb1,
      0xe5, 0xa1, 0x7b, 0x19, 0x3e, 0xac, 0x68, 0xdd, 0xe6, 0x17, 0x6b, 0x85,
      0xad, 0x5f, 0xfc, 0x7f, 0x6e, 0xf0, 0xb9, 0xe0, 0x2e, 0xca, 0x47, 0x00,
      0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0,
      0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc,
      0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0,
      0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00,
      0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x02,
      0x7c, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x0d, 0x00, 0x20,
      0x00, 0x1e, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02, 0x03, 0x08, 0x06,
      0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06, 0x01,
      0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x0a, 0x00, 0x0c,
      0x00, 0x0a, 0x00, 0x19, 0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01, 0x00,
      0x00, 0x16, 0x00, 0x00, 0x00, 0x33, 0x02, 0x39, 0x02, 0x37, 0x00, 0x17,
      0x00, 0x41, 0x04, 0x94, 0xdf, 0x36, 0xd7, 0xb3, 0x90, 0x6d, 0x01, 0xa1,
      0xe6, 0xed, 0x67, 0xf4, 0xd9, 0x9d, 0x2c, 0xac, 0x57, 0x74, 0xff, 0x19,
      0xbe, 0x5a, 0xc9, 0x30, 0x11, 0xb7, 0x2b, 0x59, 0x47, 0x80, 0x7c, 0xa9,
      0xb7, 0x31, 0x8c, 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x01, 0x00, 0xda, 0x01, 0x00, 0x02, 0xdc, 0x00, 0x00, 0x00, 0x00,
      0xce, 0x00, 0x00, 0xce, 0x9e, 0x13, 0x74, 0x3b, 0x86, 0xba, 0x69, 0x1f,
      0x12, 0xf7, 0xcd, 0x78, 0x53, 0xe8, 0x50, 0x4d, 0x71, 0x3f, 0x4b, 0x4e,
      0xeb, 0x3e, 0xe5, 0x43, 0x54, 0x78, 0x17, 0x6d, 0x00, 0x18, 0x00, 0x61,
      0x04, 0xd1, 0x99, 0x66, 0x4f, 0xda, 0xc7, 0x12, 0x3b, 0xff, 0xb2, 0xd6,
      0x2f, 0x35, 0xb6, 0x17, 0x1f, 0xb3, 0xd0, 0xb6, 0x52, 0xff, 0x97, 0x8b,
      0x01, 0xe8, 0xd9, 0x68, 0x71, 0x40, 0x02, 0xd5, 0x68, 0x3a, 0x58, 0xb2,
      0x5d, 0xee, 0xa4, 0xe9, 0x5f, 0xf4, 0xaf, 0x3e, 0x30, 0x9c, 0x3e, 0x2b,
      0xda, 0x61, 0x43, 0x99, 0x02, 0x35, 0x33, 0x9f, 0xcf, 0xb5, 0xd3, 0x28,
      0x19, 0x9d, 0x1c, 0xbe, 0x69, 0x07, 0x9e, 0xfc, 0xe4, 0x8e, 0xcd, 0x86,
      0x4a, 0x1b, 0xf0, 0xfc, 0x17, 0x94, 0x66, 0x53, 0xda, 0x24, 0x5e, 0xaf,
      0xce, 0xec, 0x62, 0x4c, 0x06, 0xb4, 0x52, 0x94, 0xb1, 0x4a, 0x7a, 0x8c,
      0x4f, 0x00, 0x19, 0x00, 0x85, 0x04, 0x00, 0x27, 0xeb, 0x99, 0x49, 0x7f,
      0xcb, 0x2c, 0x46, 0x54, 0x2d, 0x93, 0x5d, 0x25, 0x92, 0x58, 0x5e, 0x06,
      0xc3, 0x7c, 0xfb, 0x9a, 0xa7, 0xec, 0xcd, 0x9f, 0xe1, 0x6b, 0x2d, 0x78,
      0xf5, 0x16, 0xa9, 0x20, 0x52, 0x48, 0x19, 0x0f, 0x1a, 0xd0, 0xce, 0xd8,
      0x68, 0xb1, 0x4e, 0x7f, 0x33, 0x03, 0x7d, 0x0c, 0x39, 0xdb, 0x9c, 0x4b,
      0xf4, 0xe7, 0xc2, 0xf5, 0xdd, 0x51, 0x9b, 0x03, 0xa8, 0x53, 0x2b, 0xe6,
      0x00, 0x15, 0x4b, 0xff, 0xd2, 0xa0, 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xda, 0x01, 0x00, 0x02, 0xdc, 0x00,
      0x00, 0x00, 0x01, 0x9c, 0x00, 0x00, 0xce, 0x58, 0x30, 0x10, 0x3d, 0x46,
      0xcc, 0xca, 0x1a, 0x44, 0xc8, 0x58, 0x9b, 0x27, 0x17, 0x67, 0x31, 0x96,
      0x8a, 0x66, 0x39, 0xf4, 0xcc, 0xc1, 0x9f, 0x12, 0x1f, 0x01, 0x30, 0x50,
      0x16, 0xd6, 0x89, 0x97, 0xa3, 0x66, 0xd7, 0x99, 0x50, 0x09, 0x6e, 0x80,
      0x87, 0xe4, 0xa2, 0x88, 0xae, 0xb4, 0x23, 0x57, 0x2f, 0x12, 0x60, 0xe7,
      0x7d, 0x44, 0x2d, 0xad, 0xbe, 0xe9, 0x0d, 0x01, 0x00, 0x01, 0x00, 0xd5,
      0xdd, 0x62, 0xee, 0xf3, 0x0e, 0xd9, 0x30, 0x0e, 0x38, 0xf3, 0x48, 0xf4,
      0xc9, 0x8f, 0x8c, 0x20, 0xf7, 0xd3, 0xa8, 0xb3, 0x87, 0x3c, 0x98, 0x5d,
      0x70, 0xc5, 0x03, 0x76, 0xb7, 0xd5, 0x0b, 0x7b, 0x23, 0x97, 0x6b, 0xe3,
      0xb5, 0x18, 0xeb, 0x64, 0x55, 0x18, 0xb2, 0x8a, 0x90, 0x1a, 0x8f, 0x0e,
      0x15, 0xda, 0xb1, 0x8e, 0x7f, 0xee, 0x1f, 0xe0, 0x3b, 0xb9, 0xed, 0xfc,
      0x4e, 0x3f, 0x78, 0x16, 0x39, 0x95, 0x5f, 0xb7, 0xcb, 0x65, 0x55, 0x72,
      0x7b, 0x7d, 0x86, 0x2f, 0x8a, 0xe5, 0xee, 0xf7, 0x57, 0x40, 0xf3, 0xc4,
      0x96, 0x4f, 0x11, 0x4d, 0x85, 0xf9, 0x56, 0xfa, 0x3d, 0xf0, 0xc9, 0xa4,
      0xec, 0x1e, 0xaa, 0x47, 0x90, 0x53, 0xdf, 0xe1, 0xb7, 0x78, 0x18, 0xeb,
      0xdd, 0x0d, 0x89, 0xb7, 0xf6, 0x15, 0x0e, 0x55, 0x12, 0xb3, 0x23, 0x17,
      0x0b, 0x59, 0x6f, 0x83, 0x05, 0x6b, 0xa6, 0xf8, 0x6c, 0x3a, 0x9b, 0x1b,
      0x50, 0x93, 0x51, 0xea, 0x95, 0x2d, 0x99, 0x96, 0x38, 0x16, 0xfe, 0xfd,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x7e, 0x01, 0x00,
      0x02, 0xdc, 0x00, 0x00, 0x00, 0x02, 0x6a, 0x00, 0x00, 0x72, 0x2d, 0x66,
      0x3e, 0xf2, 0x36, 0x5a, 0xf2, 0x23, 0x8f, 0x28, 0x09, 0xa9, 0x55, 0x8c,
      0x8f, 0xc0, 0x0d, 0x61, 0x98, 0x33, 0x56, 0x87, 0x7a, 0xfd, 0xa7, 0x50,
      0x71, 0x84, 0x2e, 0x41, 0x58, 0x00, 0x87, 0xd9, 0x27, 0xe5, 0x7b, 0xf4,
      0x6d, 0x84, 0x4e, 0x2e, 0x0c, 0x80, 0x0c, 0xf3, 0x8a, 0x02, 0x4b, 0x99,
      0x3a, 0x1f, 0x9f, 0x18, 0x7d, 0x1c, 0xec, 0xad, 0x60, 0x54, 0xa6, 0xa3,
      0x2c, 0x82, 0x5e, 0xf8, 0x8f, 0xae, 0xe1, 0xc4, 0x82, 0x7e, 0x43, 0x43,
      0xc5, 0x99, 0x49, 0x05, 0xd3, 0xf6, 0xdf, 0xa1, 0xb5, 0x2d, 0x0c, 0x13,
      0x2f, 0x1e, 0xb6, 0x28, 0x7c, 0x5c, 0xa1, 0x02, 0x6b, 0x8d, 0xa3, 0xeb,
      0xd4, 0x58, 0xe6, 0xa0, 0x7e, 0x6b, 0xaa, 0x09, 0x43, 0x67, 0x71, 0x87,
      0xa5, 0xcb, 0x68, 0xf3
    };

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);

    /* Fragment msgs */
    ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_c, DUMMY_MTU), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_s, DUMMY_MTU), WOLFSSL_SUCCESS);

    /* Add in some key shares to make the CH long */
    ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_SECP256R1),
            WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_SECP384R1),
            WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_SECP521R1),
            WOLFSSL_SUCCESS);
#ifdef HAVE_FFDHE_2048
    ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_FFDHE_2048),
            WOLFSSL_SUCCESS);
#endif
#ifdef HAVE_FFDHE_3072
    ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_FFDHE_3072),
            WOLFSSL_SUCCESS);
#endif
#ifdef HAVE_FFDHE_4096
    ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_FFDHE_4096),
            WOLFSSL_SUCCESS);
#endif

    ExpectIntEQ(wolfSSL_dtls13_allow_ch_frag(ssl_s, 1), WOLFSSL_SUCCESS);

    /* Reject fragmented first CH */
    ExpectIntEQ(test_dtls_frag_ch_count_records(four_frag_CH,
            sizeof(four_frag_CH)), 4);
    len = sizeof(four_frag_CH);
    test_memio_clear_buffer(&test_ctx, 0);
    while (len > 0 && EXPECT_SUCCESS()) {
        unsigned int inj_len = len > DUMMY_MTU ? DUMMY_MTU : len;
        unsigned char *idx = four_frag_CH + sizeof(four_frag_CH) - len;
        ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char *)idx,
            inj_len), 0);
        len -= inj_len;
    }
    ExpectIntEQ(test_ctx.s_len, sizeof(four_frag_CH));
    while (test_ctx.s_len > 0 && EXPECT_SUCCESS()) {
        int s_len = test_ctx.s_len;
        ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
        ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
        /* Fail if we didn't advance the buffer to avoid infinite loops */
        ExpectIntLT(test_ctx.s_len, s_len);
    }
    /* Expect all fragments read */
    ExpectIntEQ(test_ctx.s_len, 0);
    /* Expect quietly dropping fragmented first CH */
    ExpectIntEQ(test_ctx.c_len, 0);

#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
    /* Disable ECH as it pushes it over our MTU */
    wolfSSL_SetEchEnable(ssl_c, 0);
#endif

    /* Limit options to make the CH a fixed length */
    /* See wolfSSL_parse_cipher_list for reason why we provide 1.3 AND 1.2
     * ciphersuite. This is only necessary when building with OPENSSL_EXTRA. */
#ifdef OPENSSL_EXTRA
    ExpectTrue(wolfSSL_set_cipher_list(ssl_c, "TLS13-AES256-GCM-SHA384"
                                       ":DHE-RSA-AES256-GCM-SHA384"));
#else
    ExpectTrue(wolfSSL_set_cipher_list(ssl_c, "TLS13-AES256-GCM-SHA384"));
#endif

    /* CH1 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Count records. Expect 1 unfragmented CH */
    ExpectIntEQ(test_dtls_frag_ch_count_records(test_ctx.s_buff,
            test_ctx.s_len), 1);
    /* HRR */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* CH2 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Count records. Expect fragmented CH */
    ExpectIntGT(test_dtls_frag_ch_count_records(test_ctx.s_buff,
            test_ctx.s_len), 1);

    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
    ssl_c = ssl_s = NULL;
    ctx_c = ctx_s = NULL;
#endif
    return EXPECT_RESULT();
}

static int test_dtls_empty_keyshare_with_cookie(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    unsigned char ch_empty_keyshare_with_cookie[] = {
        0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
        0x12, 0x01, 0x00, 0x01, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
        0x06, 0xfe, 0xfd, 0xfb, 0x8c, 0x9b, 0x28, 0xae, 0x50, 0x1c, 0x4d, 0xf3,
        0xb8, 0xcf, 0x4d, 0xd8, 0x7e, 0x93, 0x13, 0x7b, 0x9e, 0xd9, 0xeb, 0xe9,
        0x13, 0x4b, 0x0d, 0x7f, 0x2e, 0x43, 0x62, 0x8c, 0xe4, 0x57, 0x79, 0x00,
        0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0,
        0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc,
        0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0,
        0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00,
        0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x00,
        0xa6, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x2c, 0x00, 0x47,
        0x00, 0x45, 0x20, 0xee, 0x4b, 0x17, 0x70, 0x63, 0xa0, 0x4c, 0x82, 0xbf,
        0x43, 0x01, 0x7d, 0x8d, 0xc1, 0x1b, 0x4e, 0x9b, 0xa0, 0x3c, 0x53, 0x1f,
        0xb7, 0xd1, 0x10, 0x81, 0xa8, 0xdf, 0xdf, 0x8c, 0x7f, 0xf3, 0x11, 0x13,
        0x01, 0x02, 0x3d, 0x3b, 0x7d, 0x14, 0x2c, 0x31, 0xb3, 0x60, 0x72, 0x4d,
        0xe5, 0x1a, 0xb2, 0xa3, 0x61, 0x77, 0x73, 0x03, 0x40, 0x0e, 0x5f, 0xc5,
        0x61, 0x38, 0x43, 0x56, 0x21, 0x4a, 0x95, 0xd5, 0x35, 0xa8, 0x0d, 0x00,
        0x0d, 0x00, 0x2a, 0x00, 0x28, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02,
        0x03, 0xfe, 0x0b, 0xfe, 0x0e, 0xfe, 0xa0, 0xfe, 0xa3, 0xfe, 0xa5, 0x08,
        0x06, 0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06,
        0x01, 0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x0a, 0x00,
        0x18, 0x00, 0x16, 0x00, 0x19, 0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01,
        0x00, 0x02, 0x3a, 0x02, 0x3c, 0x02, 0x3d, 0x2f, 0x3a, 0x2f, 0x3c, 0x2f,
        0x3d, 0x00, 0x16, 0x00, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x00
    };
    DtlsRecordLayerHeader* dtlsRH;
    byte sequence_number[8];

    XMEMSET(&sequence_number, 0, sizeof(sequence_number));
    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s,
        NULL, wolfDTLSv1_3_server_method), 0);
    ExpectIntEQ(test_memio_inject_message(&test_ctx, 0,
            (const char *)ch_empty_keyshare_with_cookie,
            sizeof(ch_empty_keyshare_with_cookie)), 0);

    /* CH1 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* Expect an alert. A plaintext alert should be exactly 15 bytes. */
    ExpectIntEQ(test_ctx.c_len, 15);
    dtlsRH = (DtlsRecordLayerHeader*)test_ctx.c_buff;
    ExpectIntEQ(dtlsRH->type, alert);
    ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR);
    ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR);
    sequence_number[7] = 1;
    ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number,
            sizeof(sequence_number)), 0);
    ExpectIntEQ(dtlsRH->length[0], 0);
    ExpectIntEQ(dtlsRH->length[1], 2);
    ExpectIntEQ(test_ctx.c_buff[13], alert_fatal);
    ExpectIntEQ(test_ctx.c_buff[14], illegal_parameter);

    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_s);
#endif
    return EXPECT_RESULT();
}

static int test_dtls_old_seq_number(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \
    !defined(WOLFSSL_NO_TLS12)
    WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
    struct test_memio_ctx test_ctx;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0);

    /* CH1 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* HVR */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* CH2 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Server first flight */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* Client second flight */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Modify the sequence number */
    {
        DtlsRecordLayerHeader* dtlsRH = (DtlsRecordLayerHeader*)test_ctx.s_buff;
        XMEMSET(dtlsRH->sequence_number, 0, sizeof(dtlsRH->sequence_number));
    }
    /* Server second flight */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* Server should not do anything as a pkt was dropped */
    ExpectIntEQ(test_ctx.c_len, 0);
    ExpectIntEQ(test_ctx.s_len, 0);
    /* Trigger rtx */
    ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS);

    /* Complete connection */
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

    wolfSSL_free(ssl_c);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_s);
#endif
    return EXPECT_RESULT();
}

static int test_dtls12_missing_finished(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \
    !defined(WOLFSSL_NO_TLS12)
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    const char test_str[] = "test string";
    char test_buf[sizeof(test_str)];

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0);

    /* CH1 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* HVR */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* CH2 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Server first flight */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* Client second flight with finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Server second flight with finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1);
    /* Let's clear the output */
    test_memio_clear_buffer(&test_ctx, 1);
    /* Let's send some app data */
    ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)),
                sizeof(test_str));
    /* Client should not error out on a missing finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Server rtx second flight with finished */
    ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1);
    /* Client process rest of handshake */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1);

    /* Let's send some app data */
    ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)),
                sizeof(test_str));
    ExpectIntEQ(wolfSSL_read(ssl_c, test_buf, sizeof(test_buf)),
                sizeof(test_str));
    ExpectBufEQ(test_buf, test_str, sizeof(test_str));

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
#endif
    return EXPECT_RESULT();
}

static int test_dtls13_missing_finished_client(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    const char test_str[] = "test string";
    char test_buf[sizeof(test_str)];

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);

    /* CH1 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* HRR */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* CH2 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Server first flight with finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* Let's clear the output */
    test_memio_clear_buffer(&test_ctx, 1);
    /* Let's send some app data */
    ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)),
                sizeof(test_str));
    /* Client second flight with finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Server should not error out on a missing finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* Client rtx second flight with finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Server */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1);
    /* Client */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1);
    /* Let's send some app data */
    ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)),
                sizeof(test_str));
    ExpectIntEQ(wolfSSL_read(ssl_c, test_buf, sizeof(test_buf)),
                sizeof(test_str));
    ExpectBufEQ(test_buf, test_str, sizeof(test_str));

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
#endif
    return EXPECT_RESULT();
}

static int test_dtls13_missing_finished_server(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    const char test_str[] = "test string";
    char test_buf[sizeof(test_str)];

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);

    /* CH1 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* HRR */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* CH2 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Server first flight with finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* Client second flight with finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Let's clear the output */
    test_memio_clear_buffer(&test_ctx, 0);
    ExpectFalse(wolfSSL_is_init_finished(ssl_c));
    /* Let's send some app data */
    ExpectIntEQ(wolfSSL_write(ssl_c, test_str, sizeof(test_str)),
                sizeof(test_str));
    /* Server should not error out on a missing finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* Client rtx second flight with finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Server first flight with finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1);
    /* Let's send some app data */
    ExpectIntEQ(wolfSSL_write(ssl_c, test_str, sizeof(test_str)),
                sizeof(test_str));
    ExpectIntEQ(wolfSSL_read(ssl_s, test_buf, sizeof(test_buf)),
                sizeof(test_str));
    ExpectBufEQ(test_buf, test_str, sizeof(test_str));

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
#endif
    return EXPECT_RESULT();
}

static int test_dtls13_finished_send_error_propagation(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
        wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);

    /* CH1 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* HRR */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* CH2 */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    /* Server first flight with finished */
    ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
    /* Client second flight with finished - block sends to force error */
    test_ctx.s_len = TEST_MEMIO_BUF_SZ;
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    /* Verify the error is propagated, not silently swallowed as success */
    ExpectIntNE(wolfSSL_get_error(ssl_c, -1), 0);

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
#endif
    return EXPECT_RESULT();
}


#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
static int test_self_signed_stapling_client_v1_ctx_ready(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(ctx), 1);
    ExpectIntEQ(wolfSSL_CTX_UseOCSPStapling(ctx, WOLFSSL_CSR_OCSP,
            WOLFSSL_CSR_OCSP_USE_NONCE), 1);
    return EXPECT_RESULT();
}
#endif

#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
static int test_self_signed_stapling_client_v2_ctx_ready(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(ctx), 1);
    ExpectIntEQ(wolfSSL_CTX_UseOCSPStaplingV2(ctx, WOLFSSL_CSR2_OCSP,
            WOLFSSL_CSR2_OCSP_USE_NONCE), 1);
    return EXPECT_RESULT();
}

static int test_self_signed_stapling_client_v2_multi_ctx_ready(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(ctx), 1);
    ExpectIntEQ(wolfSSL_CTX_UseOCSPStaplingV2(ctx, WOLFSSL_CSR2_OCSP_MULTI,
            0), 1);
    return EXPECT_RESULT();
}
#endif

#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
 || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
static int test_self_signed_stapling_server_ctx_ready(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(ctx), 1);
    return EXPECT_RESULT();
}
#endif
#endif

static int test_self_signed_stapling(void)
{
    EXPECT_DECLS;
#if (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
     defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) && \
     !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
    test_ssl_cbf client_cbf;
    test_ssl_cbf server_cbf;
    size_t i;
    struct {
        method_provider client_meth;
        method_provider server_meth;
        ctx_cb client_ctx;
        const char* tls_version;
    } params[] = {
#if defined(WOLFSSL_TLS13) && defined(HAVE_CERTIFICATE_STATUS_REQUEST)
        { wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
            test_self_signed_stapling_client_v1_ctx_ready, "TLSv1_3 v1" },
#endif
#ifndef WOLFSSL_NO_TLS12
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
        { wolfTLSv1_2_client_method, wolfTLSv1_2_server_method,
            test_self_signed_stapling_client_v1_ctx_ready, "TLSv1_2 v1" },
#endif
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
        { wolfTLSv1_2_client_method, wolfTLSv1_2_server_method,
            test_self_signed_stapling_client_v2_ctx_ready, "TLSv1_2 v2" },
        { wolfTLSv1_2_client_method, wolfTLSv1_2_server_method,
            test_self_signed_stapling_client_v2_multi_ctx_ready,
            "TLSv1_2 v2 multi" },
#endif
#endif
    };

    for (i = 0; i < sizeof(params)/sizeof(*params) && !EXPECT_FAIL(); i++) {
        XMEMSET(&client_cbf, 0, sizeof(client_cbf));
        XMEMSET(&server_cbf, 0, sizeof(server_cbf));

        printf("\nTesting self-signed cert with status request: %s\n",
                params[i].tls_version);

        client_cbf.method = params[i].client_meth;
        client_cbf.ctx_ready = params[i].client_ctx;

        server_cbf.method = params[i].server_meth;
        server_cbf.certPemFile = "certs/ca-cert.pem";
        server_cbf.keyPemFile  = "certs/ca-key.pem";
        server_cbf.ctx_ready = test_self_signed_stapling_server_ctx_ready;

        ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
            &server_cbf, NULL), TEST_SUCCESS);
    }
#endif
    return EXPECT_RESULT();
}

static int test_tls_multi_handshakes_one_record(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(WOLFSSL_NO_TLS12) && !defined(NO_SHA256)
    struct test_memio_ctx test_ctx;
    WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
    RecordLayerHeader* rh = NULL;
    byte   *len ;
    int newRecIdx;
    int idx;
    byte buff[64 * 1024];
    word16 recLen;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
            wolfTLS_client_method, wolfTLSv1_2_server_method), 0);

    ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    ExpectIntEQ(wolfSSL_accept(ssl_s), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);

    XMEMSET(buff, 0, sizeof(buff));
    rh = (RecordLayerHeader*)(test_ctx.c_buff);
    len = &rh->length[0];
    ato16((const byte*)len, &recLen);

    ExpectIntLE(RECORD_HEADER_SZ + recLen, (int)sizeof(buff));
    ExpectIntLE(RECORD_HEADER_SZ + recLen, test_ctx.c_len);

    if (EXPECT_SUCCESS()) {
        XMEMCPY(buff, test_ctx.c_buff, RECORD_HEADER_SZ + recLen);
        newRecIdx = idx = RECORD_HEADER_SZ + recLen;
        /* Combine server handshake msgs into one record */
        while (idx < test_ctx.c_len) {

            rh = (RecordLayerHeader*)(test_ctx.c_buff + idx);
            len = &rh->length[0];

            ato16((const byte*)len, &recLen);
            ExpectIntLE(idx + RECORD_HEADER_SZ + recLen, test_ctx.c_len);
            ExpectIntLE(newRecIdx + recLen, (int)sizeof(buff));

            if (!EXPECT_SUCCESS()) {
                break;
            }

            idx += RECORD_HEADER_SZ;

            XMEMCPY(buff + newRecIdx, test_ctx.c_buff + idx,
                    (size_t)recLen);

            newRecIdx += recLen;
            idx += recLen;
        }
        if (EXPECT_SUCCESS()) {
            rh = (RecordLayerHeader*)(buff);
            len = &rh->length[0];
            c16toa((word16)newRecIdx - RECORD_HEADER_SZ, len);
            test_memio_clear_buffer(&test_ctx, 1);
            test_memio_inject_message(&test_ctx, 1, (const char*)buff,
                                      newRecIdx);

            ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);

            ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
        }
    }


    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
#endif
    return EXPECT_RESULT();
}


static int test_write_dup(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_WRITE_DUP)
    size_t i, j, k;
    char hiWorld[] = "dup message";
    char readData[sizeof(hiWorld) + 5];
#ifdef WOLFSSL_TLS13
    int required;
#endif
    struct {
        method_provider client_meth;
        method_provider server_meth;
        const char* version_name;
        int version;
    } methods[] = {
#ifndef WOLFSSL_NO_TLS12
        {wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLS 1.2", WOLFSSL_TLSV1_2},
#ifdef WOLFSSL_DTLS
        {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "DTLS 1.2", WOLFSSL_TLSV1_2},
#endif
#endif
#ifdef WOLFSSL_TLS13
        {wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLS 1.3", WOLFSSL_TLSV1_3},
#ifdef WOLFSSL_DTLS13
        {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLS 1.3", WOLFSSL_TLSV1_3},
#endif
#endif
    };
    struct {
        const char* cipher;
        int version;
    } ciphers[] = {
/* For simplicity the macros are copied from internal.h */
/* TLS 1.2 */
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && !defined(NO_SHA256)
    #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)
        #ifndef NO_RSA
            {"ECDHE-RSA-CHACHA20-POLY1305", WOLFSSL_TLSV1_2},
        #endif
    #endif
    #if !defined(NO_DH) && !defined(NO_RSA) && !defined(NO_TLS_DH)
        {"DHE-RSA-CHACHA20-POLY1305", WOLFSSL_TLSV1_2},
    #endif
#endif
#if !defined(NO_DH) && !defined(NO_AES) && !defined(NO_TLS) && \
    !defined(NO_RSA) && defined(HAVE_AESGCM) && !defined(NO_TLS_DH)
    #if !defined(NO_SHA256) && defined(WOLFSSL_AES_128)
        {"DHE-RSA-AES128-GCM-SHA256", WOLFSSL_TLSV1_2},
    #endif
    #if defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256)
        {"DHE-RSA-AES256-GCM-SHA384", WOLFSSL_TLSV1_2},
    #endif
#endif
#if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)) \
                                         && !defined(NO_TLS) && !defined(NO_AES)
    #ifdef HAVE_AESGCM
        #if !defined(NO_SHA256) && defined(WOLFSSL_AES_128)
            #ifndef NO_RSA
                {"ECDHE-RSA-AES128-GCM-SHA256", WOLFSSL_TLSV1_2},
            #endif
        #endif
        #if defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256)
            #ifndef NO_RSA
                {"ECDHE-RSA-AES256-GCM-SHA384", WOLFSSL_TLSV1_2},
            #endif
        #endif
    #endif
#endif
/* TLS 1.3 */
#ifdef WOLFSSL_TLS13
    #ifdef HAVE_AESGCM
        #if !defined(NO_SHA256) && defined(WOLFSSL_AES_128)
            {"TLS13-AES128-GCM-SHA256", WOLFSSL_TLSV1_3},
        #endif
        #if defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256)
            {"TLS13-AES256-GCM-SHA384", WOLFSSL_TLSV1_3},
        #endif
    #endif
    #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
        #ifndef NO_SHA256
            {"TLS13-CHACHA20-POLY1305-SHA256", WOLFSSL_TLSV1_3},
        #endif
    #endif
    #ifdef HAVE_AESCCM
        #if !defined(NO_SHA256) && defined(WOLFSSL_AES_128)
            {"TLS13-AES128-CCM-SHA256", WOLFSSL_TLSV1_3},
        #endif
    #endif
#endif
    };

/* Macro capturing local variables for concise bidirectional data exchange. */
#define EXCHANGE_DATA do { \
    ExpectIntEQ(wolfSSL_write(ssl_s, hiWorld, sizeof(hiWorld)), \
            sizeof(hiWorld)); \
    ExpectIntEQ(wolfSSL_read(ssl_c, readData, sizeof(readData)), \
            sizeof(hiWorld)); \
    ExpectIntEQ(wolfSSL_write(ssl_c2, hiWorld, sizeof(hiWorld)), \
            sizeof(hiWorld)); \
    ExpectIntEQ(wolfSSL_read(ssl_s, readData, sizeof(readData)), \
            sizeof(hiWorld)); \
} while (0)

    for (i = 0; i < XELEM_CNT(methods); i++) {
        for (j = 0; j < XELEM_CNT(ciphers) && !EXPECT_FAIL(); j++) {
            struct test_memio_ctx test_ctx;
            WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
            WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
            WOLFSSL *ssl_c2 = NULL;

            if (methods[i].version != ciphers[j].version)
                continue;

            if (i == 0 && j == 0)
                printf("\n");

            printf("Testing %s with %s... ", methods[i].version_name,
                    ciphers[j].cipher);

            XMEMSET(&test_ctx, 0, sizeof(test_ctx));

            test_ctx.c_ciphers = test_ctx.s_ciphers = ciphers[j].cipher;

            ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
                    methods[i].client_meth, methods[i].server_meth), 0);
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
            if (methods[i].version == WOLFSSL_TLSV1_3) {
                ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_c, cliCertFile,
                        WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
                ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_c, cliKeyFile,
                        WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
                ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliCertFile,
                        WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
                ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile,
                        WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
                ExpectIntEQ(wolfSSL_allow_post_handshake_auth(ssl_c), 0);
                ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, caCertFile,
                        NULL), WOLFSSL_SUCCESS);
            }
#endif
            ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

            ExpectNotNull(ssl_c2 = wolfSSL_write_dup(ssl_c));
            ExpectIntEQ(wolfSSL_write(ssl_c, hiWorld, sizeof(hiWorld)),
                    WC_NO_ERR_TRACE(WRITE_DUP_WRITE_E));
            EXCHANGE_DATA;
            ExpectIntEQ(wolfSSL_read(ssl_c2, readData, sizeof(readData)),
                    WC_NO_ERR_TRACE(WRITE_DUP_READ_E));
#ifdef WOLFSSL_DTLS13
            /* The initial EXCHANGE_DATA above processes the post-handshake
             * NewSessionTicket (S2C part delegates ACK) and triggers the
             * ACK (C2S part sends it). Verify it completed. */
            if (methods[i].client_meth == wolfDTLSv1_3_client_method) {
                ExpectNotNull(ssl_c->dupWrite);
                ExpectIntEQ(ssl_c->dupWrite->sendAcks, 0);
                ExpectNull(ssl_s->dtls13Rtx.rtxRecords);
            }
#endif
            for (k = 0; k < 10; k++)
                EXCHANGE_DATA;

#ifdef WOLFSSL_TLS13
            if (methods[i].version == WOLFSSL_TLSV1_3) {
                /* Client-initiated key update. */
                ExpectIntEQ(wolfSSL_update_keys(ssl_c2), WOLFSSL_SUCCESS);
                ExpectIntEQ(wolfSSL_key_update_response(ssl_c2, &required), 0);
                ExpectIntEQ(required, 1);
                for (k = 0; k < 10; k++)
                    EXCHANGE_DATA;
            }

            if (methods[i].version == WOLFSSL_TLSV1_3) {
                /* Server-initiated key update. */
                ExpectIntEQ(wolfSSL_update_keys(ssl_s), WOLFSSL_SUCCESS);
                ExpectIntEQ(wolfSSL_key_update_response(ssl_s, &required), 0);
                ExpectIntEQ(required, 1);
                for (k = 0; k < 10; k++)
                    EXCHANGE_DATA;
                ExpectIntEQ(wolfSSL_key_update_response(ssl_s, &required), 0);
                ExpectIntEQ(required, 0);
            }
#endif /* WOLFSSL_TLS13 */

#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
            if (methods[i].version == WOLFSSL_TLSV1_3) {
                WOLFSSL_X509_CHAIN* chain = NULL;
                ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
                ExpectIntEQ(wolfSSL_get_chain_count(chain), 0);
                ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
                EXCHANGE_DATA;
                ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
                ExpectIntEQ(wolfSSL_get_chain_count(chain), 1);
                for (k = 0; k < 10; k++)
                    EXCHANGE_DATA;
            }
#endif

            if (EXPECT_SUCCESS())
                printf("ok\n");
            else
                printf("failed\n");

            wolfSSL_free(ssl_c);
            wolfSSL_free(ssl_c2);
            wolfSSL_free(ssl_s);
            wolfSSL_CTX_free(ctx_c);
            wolfSSL_CTX_free(ctx_s);
        }
    }
#undef EXCHANGE_DATA
#endif
    return EXPECT_RESULT();
}

static int test_write_dup_want_write(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_WRITE_DUP)
    size_t i, k;
    char hiWorld[] = "dup message";
    char readData[sizeof(hiWorld) + 5];
#ifdef WOLFSSL_TLS13
    int required;
#endif
    struct {
        method_provider client_meth;
        method_provider server_meth;
        const char* version_name;
        int version;
    } methods[] = {
#ifndef WOLFSSL_NO_TLS12
        {wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLS 1.2", WOLFSSL_TLSV1_2},
#ifdef WOLFSSL_DTLS
        {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "DTLS 1.2", WOLFSSL_TLSV1_2},
#endif
#endif
#ifdef WOLFSSL_TLS13
        {wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLS 1.3", WOLFSSL_TLSV1_3},
#ifdef WOLFSSL_DTLS13
        {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLS 1.3", WOLFSSL_TLSV1_3},
#endif
#endif
    };

/* Same as test_write_dup's EXCHANGE_DATA but every client (write-dup side)
 * write is preceded by a simulated WANT_WRITE that must be retried. */
#define EXCHANGE_DATA do { \
    ExpectIntEQ(wolfSSL_write(ssl_s, hiWorld, sizeof(hiWorld)), \
            sizeof(hiWorld)); \
    ExpectIntEQ(wolfSSL_read(ssl_c, readData, sizeof(readData)), \
            sizeof(hiWorld)); \
    test_memio_simulate_want_write(&test_ctx, 1, 1); \
    ExpectIntEQ(wolfSSL_write(ssl_c2, hiWorld, sizeof(hiWorld)), \
            WOLFSSL_FATAL_ERROR); \
    ExpectIntEQ(wolfSSL_get_error(ssl_c2, WOLFSSL_FATAL_ERROR), \
            WOLFSSL_ERROR_WANT_WRITE); \
    test_memio_simulate_want_write(&test_ctx, 1, 0); \
    ExpectIntEQ(wolfSSL_write(ssl_c2, hiWorld, sizeof(hiWorld)), \
            sizeof(hiWorld)); \
    ExpectIntEQ(wolfSSL_read(ssl_s, readData, sizeof(readData)), \
            sizeof(hiWorld)); \
} while (0)

    for (i = 0; i < XELEM_CNT(methods) && !EXPECT_FAIL(); i++) {
        struct test_memio_ctx test_ctx;
        WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
        WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
        WOLFSSL *ssl_c2 = NULL;

        if (i == 0)
            printf("\n");
        printf("Testing write_dup WANT_WRITE %s... ",
                methods[i].version_name);

        XMEMSET(&test_ctx, 0, sizeof(test_ctx));

        ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
                methods[i].client_meth, methods[i].server_meth), 0);
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
        if (methods[i].version == WOLFSSL_TLSV1_3) {
            ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_c, cliCertFile,
                    WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
            ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_c, cliKeyFile,
                    WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
            ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliCertFile,
                    WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
            ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile,
                    WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
            ExpectIntEQ(wolfSSL_allow_post_handshake_auth(ssl_c), 0);
            ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, caCertFile,
                    NULL), WOLFSSL_SUCCESS);
        }
#endif
        ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

        ExpectNotNull(ssl_c2 = wolfSSL_write_dup(ssl_c));

        for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
            EXCHANGE_DATA;

#ifdef WOLFSSL_TLS13
        if (methods[i].version == WOLFSSL_TLSV1_3) {
            /* Client-initiated key update with WANT_WRITE. */
            ExpectIntEQ(wolfSSL_update_keys(ssl_c2), WOLFSSL_SUCCESS);
            ExpectIntEQ(wolfSSL_key_update_response(ssl_c2, &required), 0);
            ExpectIntEQ(required, 1);
            for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
                EXCHANGE_DATA;

            /* Server-initiated key update: response goes through write side
             * with WANT_WRITE. */
            ExpectIntEQ(wolfSSL_update_keys(ssl_s), WOLFSSL_SUCCESS);
            ExpectIntEQ(wolfSSL_key_update_response(ssl_s, &required), 0);
            ExpectIntEQ(required, 1);
            for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
                EXCHANGE_DATA;
            ExpectIntEQ(wolfSSL_key_update_response(ssl_s, &required), 0);
            ExpectIntEQ(required, 0);
        }
#endif /* WOLFSSL_TLS13 */

#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
        if (methods[i].version == WOLFSSL_TLSV1_3) {
            WOLFSSL_X509_CHAIN* chain = NULL;
            ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
            ExpectIntEQ(wolfSSL_get_chain_count(chain), 0);
            ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
            EXCHANGE_DATA;
            ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
            ExpectIntEQ(wolfSSL_get_chain_count(chain), 1);
            for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
                EXCHANGE_DATA;
        }
#endif /* WOLFSSL_POST_HANDSHAKE_AUTH */

        if (EXPECT_SUCCESS())
            printf("ok\n");
        else
            printf("failed\n");

        wolfSSL_free(ssl_c);
        wolfSSL_free(ssl_c2);
        wolfSSL_free(ssl_s);
        wolfSSL_CTX_free(ctx_c);
        wolfSSL_CTX_free(ctx_s);
    }
#undef EXCHANGE_DATA
#endif
    return EXPECT_RESULT();
}

/* Simultaneous key update and cert req */
static int test_write_dup_want_write_simul(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_WRITE_DUP) && \
    defined(WOLFSSL_POST_HANDSHAKE_AUTH) && defined(WOLFSSL_TLS13)
    size_t i, k;
    char hiWorld[] = "dup message";
    char readData[sizeof(hiWorld) + 5];
    int required;
    struct {
        method_provider client_meth;
        method_provider server_meth;
        const char* version_name;
    } methods[] = {
#ifdef WOLFSSL_TLS13
        {wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLS 1.3"},
#ifdef WOLFSSL_DTLS13
        {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLS 1.3"},
#endif
#endif
    };

/* Same as test_write_dup's EXCHANGE_DATA but every client (write-dup side)
 * write is preceded by a simulated WANT_WRITE that must be retried. */
#define EXCHANGE_DATA do { \
    ExpectIntEQ(wolfSSL_write(ssl_s, hiWorld, sizeof(hiWorld)), \
            sizeof(hiWorld)); \
    ExpectIntEQ(wolfSSL_read(ssl_c, readData, sizeof(readData)), \
            sizeof(hiWorld)); \
    test_memio_simulate_want_write(&test_ctx, 1, 1); \
    ExpectIntEQ(wolfSSL_write(ssl_c2, hiWorld, sizeof(hiWorld)), \
            WOLFSSL_FATAL_ERROR); \
    ExpectIntEQ(wolfSSL_get_error(ssl_c2, WOLFSSL_FATAL_ERROR), \
            WOLFSSL_ERROR_WANT_WRITE); \
    test_memio_simulate_want_write(&test_ctx, 1, 0); \
    ExpectIntEQ(wolfSSL_write(ssl_c2, hiWorld, sizeof(hiWorld)), \
            sizeof(hiWorld)); \
    ExpectIntEQ(wolfSSL_read(ssl_s, readData, sizeof(readData)), \
            sizeof(hiWorld)); \
} while (0)

    for (i = 0; i < XELEM_CNT(methods) && !EXPECT_FAIL(); i++) {
        struct test_memio_ctx test_ctx;
        WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
        WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
        WOLFSSL *ssl_c2 = NULL;
        WOLFSSL_X509_CHAIN* chain = NULL;

        if (i == 0)
            printf("\n");
        printf("Testing write_dup WANT_WRITE %s... ",
                methods[i].version_name);

        XMEMSET(&test_ctx, 0, sizeof(test_ctx));

        ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
                methods[i].client_meth, methods[i].server_meth), 0);
        ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_c, cliCertFile,
                WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_c, cliKeyFile,
                WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliCertFile,
                WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile,
                WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_allow_post_handshake_auth(ssl_c), 0);
        ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, caCertFile,
                NULL), WOLFSSL_SUCCESS);
        ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

        ExpectNotNull(ssl_c2 = wolfSSL_write_dup(ssl_c));

        for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
            EXCHANGE_DATA;

        /* Server-initiated key update and cert req: response goes through
         * write side with WANT_WRITE. */
        ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
        ExpectIntEQ(wolfSSL_get_chain_count(chain), 0);
        ExpectIntEQ(wolfSSL_update_keys(ssl_s), WOLFSSL_SUCCESS);
        ExpectIntEQ(wolfSSL_key_update_response(ssl_s, &required), 0);
        ExpectIntEQ(required, 1);
        ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
        for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
            EXCHANGE_DATA;
        ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
        ExpectIntEQ(wolfSSL_get_chain_count(chain), 1);
        ExpectIntEQ(wolfSSL_key_update_response(ssl_s, &required), 0);
        ExpectIntEQ(required, 0);

        if (EXPECT_SUCCESS())
            printf("ok\n");
        else
            printf("failed\n");

        wolfSSL_free(ssl_c);
        wolfSSL_free(ssl_c2);
        wolfSSL_free(ssl_s);
        wolfSSL_CTX_free(ctx_c);
        wolfSSL_CTX_free(ctx_s);
    }
#undef EXCHANGE_DATA
#endif
    return EXPECT_RESULT();
}

#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_WRITE_DUP) && \
    defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && !defined(NO_SHA256) &&    \
    (defined(HAVE_ECC) || defined(HAVE_CURVE25519) ||                           \
     defined(HAVE_CURVE448)) &&                                                 \
    !defined(NO_RSA) && defined(USE_WOLFSSL_MEMORY) &&                          \
    !defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) &&           \
    !defined(WOLFSSL_KERNEL_MODE) && !defined(WOLFSSL_NO_TLS12) &&              \
    !defined(NO_TLS)
#include <wolfssl/wolfcrypt/poly1305.h>

/* Custom allocator state for test_write_dup_oom.
 * The allocator counts allocations of size oom_match_size (set to
 * sizeof(Poly1305) by the test). The Nth such allocation is forced to
 * fail if oom_fail_at_match == N; oom_failed is then set so callers can
 * confirm the fault was actually injected. The test runs in two phases:
 *   1) Measure: oom_fail_at_match = 0 (no failures), record oom_match_count
 *      after a successful wolfSSL_write_dup(). The Poly1305 alloc in
 *      DupSSL() is the LAST sizeof(Poly1305) allocation in the call path,
 *      so that count is the index that targets it.
 *   2) Trigger: oom_fail_at_match = recorded count, run write_dup again on
 *      a fresh handshake. The Nth match is the Poly1305 alloc, so the
 *      failure exercises exactly the bug under test. */
static size_t oom_match_size = 0;
static int    oom_match_count = 0;
static int    oom_fail_at_match = 0;
static int    oom_failed = 0;

#ifdef WOLFSSL_DEBUG_MEMORY
static void* oom_malloc_cb(size_t size, const char* func, unsigned int line)
{
    (void)func;
    (void)line;
#else
static void* oom_malloc_cb(size_t size)
{
#endif
    if (!oom_failed && oom_match_size != 0 && size == oom_match_size) {
        oom_match_count++;
        if (oom_fail_at_match != 0 && oom_match_count == oom_fail_at_match) {
            oom_failed = 1;
            return NULL;
        }
    }
    return malloc(size);
}

#ifdef WOLFSSL_DEBUG_MEMORY
static void oom_free_cb(void* ptr, const char* func, unsigned int line)
{
    (void)func;
    (void)line;
#else
static void oom_free_cb(void* ptr)
{
#endif
    free(ptr);
}

#ifdef WOLFSSL_DEBUG_MEMORY
static void* oom_realloc_cb(void* ptr, size_t size, const char* func,
        unsigned int line)
{
    (void)func;
    (void)line;
#else
static void* oom_realloc_cb(void* ptr, size_t size)
{
#endif
    return realloc(ptr, size);
}
#endif

/* Regression test for the DupSSL() error-path bug: an allocation failure on
 * the Poly1305 alloc must not leave the original ssl object with a zeroed
 * encrypt context or a non-NULL ssl->dupWrite.
 *
 * Pass 0 measures the count of sizeof(Poly1305) allocations during a
 * successful wolfSSL_write_dup(); pass 1 fails the same-indexed allocation
 * on a fresh handshake to deterministically target the DupSSL() Poly1305
 * alloc regardless of any incidental size collisions. */
static int test_write_dup_oom(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_WRITE_DUP) && \
    defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && !defined(NO_SHA256) &&    \
    (defined(HAVE_ECC) || defined(HAVE_CURVE25519) ||                           \
     defined(HAVE_CURVE448)) &&                                                 \
    !defined(NO_RSA) && defined(USE_WOLFSSL_MEMORY) &&                          \
    !defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) &&           \
    !defined(WOLFSSL_KERNEL_MODE) && !defined(WOLFSSL_NO_TLS12) &&              \
    !defined(NO_TLS)
    char hiWorld[] = "dup message";
    char readData[sizeof(hiWorld) + 5];
    wolfSSL_Malloc_cb  prev_mc = NULL;
    wolfSSL_Free_cb    prev_fc = NULL;
    wolfSSL_Realloc_cb prev_rc = NULL;
    int allocators_set = 0;
    int target_match = 0;
    int pass;

    ExpectIntEQ(wolfSSL_GetAllocators(&prev_mc, &prev_fc, &prev_rc), 0);
    ExpectIntEQ(wolfSSL_SetAllocators(oom_malloc_cb, oom_free_cb,
            oom_realloc_cb), 0);
    if (EXPECT_SUCCESS())
        allocators_set = 1;

    for (pass = 0; pass < 2 && EXPECT_SUCCESS(); pass++) {
        struct test_memio_ctx test_ctx;
        WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
        WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
        WOLFSSL *ssl_c2 = NULL;

        XMEMSET(&test_ctx, 0, sizeof(test_ctx));
        test_ctx.c_ciphers = test_ctx.s_ciphers =
                "ECDHE-RSA-CHACHA20-POLY1305";

        ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
                wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
        ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

        /* Start counting sizeof(Poly1305) allocations only now, after the
         * handshake, so the count reflects only allocations on the
         * wolfSSL_write_dup() code path. */
        oom_match_size = sizeof(Poly1305);
        oom_match_count = 0;
        oom_failed = 0;
        oom_fail_at_match = (pass == 0) ? 0 : target_match;

        if (pass == 0) {
            ExpectNotNull(ssl_c2 = wolfSSL_write_dup(ssl_c));
            target_match = oom_match_count;
            /* Sanity: at least one Poly1305 alloc must occur on this path,
             * otherwise the test setup was wrong (feature compiled out, or
             * negotiated cipher does not use Poly1305). */
            ExpectIntGE(target_match, 1);
        }
        else {
            ExpectNull(wolfSSL_write_dup(ssl_c));
            /* Confirm the targeted Poly1305 allocation actually failed. */
            ExpectIntEQ(oom_failed, 1);
            /* Stop further failures so the recovery path can run. */
            oom_fail_at_match = 0;

            /* The original ssl_c must NOT be poisoned: the WriteDup must have
             * been cleaned up, the encrypt cipher context must still be
             * intact, and a fresh wolfSSL_write_dup() must succeed. */
            ExpectNull(ssl_c->dupWrite);
            ExpectNotNull(ssl_c2 = wolfSSL_write_dup(ssl_c));

            /* Round-trip data both directions to confirm both sides still
             * encrypt with the original ssl_c context preserved. */
            ExpectIntEQ(wolfSSL_write(ssl_s, hiWorld, sizeof(hiWorld)),
                    sizeof(hiWorld));
            ExpectIntEQ(wolfSSL_read(ssl_c, readData, sizeof(readData)),
                    sizeof(hiWorld));
            ExpectIntEQ(wolfSSL_write(ssl_c2, hiWorld, sizeof(hiWorld)),
                    sizeof(hiWorld));
            ExpectIntEQ(wolfSSL_read(ssl_s, readData, sizeof(readData)),
                    sizeof(hiWorld));
        }

        /* Disable matching/failure during teardown so frees and any internal
         * allocations of the same size during cleanup are unaffected. */
        oom_match_size = 0;
        oom_fail_at_match = 0;

        wolfSSL_free(ssl_c);
        wolfSSL_free(ssl_c2);
        wolfSSL_free(ssl_s);
        wolfSSL_CTX_free(ctx_c);
        wolfSSL_CTX_free(ctx_s);
    }

    /* Restore previous allocators only after every object allocated under the
     * test allocators has been freed, so allocator bookkeeping (in builds
     * that wrap the default allocators) is not desynchronised. */
    if (allocators_set)
        (void)wolfSSL_SetAllocators(prev_mc, prev_fc, prev_rc);
#endif
    return EXPECT_RESULT();
}

static int test_read_write_hs(void)
{

    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(WOLFSSL_NO_TLS12) && !defined(NO_SHA256)
    WOLFSSL_CTX *ctx_s = NULL, *ctx_c = NULL;
    WOLFSSL *ssl_s = NULL, *ssl_c = NULL;
    struct test_memio_ctx test_ctx;
    byte test_buffer[16];
    unsigned int test;

    /* test == 0 : client writes, server reads */
    /* test == 1 : server writes, client reads */
    for (test = 0; test < 2; test++) {
        XMEMSET(&test_ctx, 0, sizeof(test_ctx));
        ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s,  &ssl_c, &ssl_s,
                                     wolfTLSv1_2_client_method,
                                     wolfTLSv1_2_server_method), 0);
        ExpectIntEQ(wolfSSL_set_group_messages(ssl_s), WOLFSSL_SUCCESS);
        /* CH -> */
        if (test == 0) {
            ExpectIntEQ(wolfSSL_write(ssl_c, "hello", 5), -1);
        } else {
            ExpectIntEQ(wolfSSL_read(ssl_c, test_buffer,
                                     sizeof(test_buffer)),  -1);
        }
        ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);

        /* <- SH + SKE + SHD */
        if (test == 0) {
            ExpectIntEQ(wolfSSL_read(ssl_s, test_buffer,
                                     sizeof(test_buffer)), -1);
        } else {
            ExpectIntEQ(wolfSSL_write(ssl_s, "hello", 5), -1);
        }
        ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);

        /* -> CKE + CLIENT FINISHED */
        if (test == 0) {
            ExpectIntEQ(wolfSSL_write(ssl_c, "hello", 5), -1);
        } else {
            ExpectIntEQ(wolfSSL_read(ssl_c, test_buffer,
                                     sizeof(test_buffer)), -1);
        }
        ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);

        /* abide clang static analyzer */
        if (ssl_s != NULL) {
            /* disable group message to separate sending of ChangeCipherspec
             * from Finished */
            ssl_s->options.groupMessages = 0;
        }
        /* allow writing of CS, but not FINISHED */
        test_ctx.c_len = TEST_MEMIO_BUF_SZ - 6;

        /* <- CS */
        if (test == 0) {
            ExpectIntEQ(wolfSSL_read(ssl_s, test_buffer,
                                     sizeof(test_buffer)), -1);
        } else {
            ExpectIntEQ(wolfSSL_write(ssl_s, "hello", 5), -1);
        }
        ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_WRITE);

        /* move CS message where the client can read it */
        memmove(test_ctx.c_buff,
                (test_ctx.c_buff + TEST_MEMIO_BUF_SZ - 6), 6);
        test_ctx.c_len = 6;
        /* read CS */
        if (test == 0) {
            ExpectIntEQ(wolfSSL_write(ssl_c, "hello", 5), -1);
        } else {
            ExpectIntEQ(wolfSSL_read(ssl_c, test_buffer,
                                     sizeof(test_buffer)), -1);
        }
        ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
        ExpectIntEQ(test_ctx.c_len, 0);

        if (test == 0) {
            /* send SERVER FINISHED */
            ExpectIntEQ(wolfSSL_read(ssl_s, test_buffer,
                                     sizeof(test_buffer)), -1);
            ExpectIntEQ(wolfSSL_get_error(ssl_s, -1),
                        WOLFSSL_ERROR_WANT_READ);
        } else {
            /* send SERVER FINISHED + App Data */
            ExpectIntEQ(wolfSSL_write(ssl_s, "hello", 5), 5);
        }

        ExpectIntGT(test_ctx.c_len, 0);

        /* Send and receive the data */
        if (test == 0) {
            ExpectIntEQ(wolfSSL_write(ssl_c, "hello", 5), 5);
            ExpectIntEQ(wolfSSL_read(ssl_s, test_buffer,
                                     sizeof(test_buffer)), 5);
        } else {
            ExpectIntEQ(wolfSSL_read(ssl_c, test_buffer,
                                     sizeof(test_buffer)), 5);
        }

        ExpectBufEQ(test_buffer, "hello", 5);

        wolfSSL_free(ssl_c);
        wolfSSL_free(ssl_s);
        wolfSSL_CTX_free(ctx_c);
        wolfSSL_CTX_free(ctx_s);
        ssl_c = ssl_s = NULL;
        ctx_c = ctx_s = NULL;
    }

#endif
    return EXPECT_RESULT();
}

#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && defined(OPENSSL_EXTRA)
static const char* test_get_signature_nid_siglag;
static int test_get_signature_nid_sig;
static int test_get_signature_nid_hash;

static int test_get_signature_nid_ssl_ready(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "ALL"), WOLFSSL_SUCCESS);
    if (!wolfSSL_is_server(ssl)) {
        ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl,
            test_get_signature_nid_siglag), WOLFSSL_SUCCESS);
    }
    return EXPECT_RESULT();
}

static int test_get_signature_nid_on_hs_client(WOLFSSL_CTX **ctx, WOLFSSL **ssl)
{
    EXPECT_DECLS;
    int nid = 0;
    (void)ctx;
    if (XSTRSTR(wolfSSL_get_cipher(*ssl), "TLS_RSA_") == NULL) {
        ExpectIntEQ(SSL_get_peer_signature_type_nid(*ssl, &nid), WOLFSSL_SUCCESS);
        ExpectIntEQ(nid, test_get_signature_nid_sig);
        ExpectIntEQ(SSL_get_peer_signature_nid(*ssl, &nid), WOLFSSL_SUCCESS);
        ExpectIntEQ(nid, test_get_signature_nid_hash);
    }
    else /* No sigalg info on static ciphersuite */
        return TEST_SUCCESS;
    return EXPECT_RESULT();
}

static int test_get_signature_nid_on_hs_server(WOLFSSL_CTX **ctx, WOLFSSL **ssl)
{
    EXPECT_DECLS;
    int nid = 0;
    (void)ctx;
    ExpectIntEQ(SSL_get_signature_type_nid(*ssl, &nid), WOLFSSL_SUCCESS);
    ExpectIntEQ(nid, test_get_signature_nid_sig);
    ExpectIntEQ(SSL_get_signature_nid(*ssl, &nid), WOLFSSL_SUCCESS);
    ExpectIntEQ(nid, test_get_signature_nid_hash);
    return EXPECT_RESULT();
}
#endif

static int test_get_signature_nid(void)
{
    EXPECT_DECLS;
#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && defined(OPENSSL_EXTRA)
    test_ssl_cbf client_cbf;
    test_ssl_cbf server_cbf;
    size_t i;
#define TGSN_TLS12_RSA(sigalg, sig_nid, hash_nid) \
        { sigalg, sig_nid, hash_nid, WOLFSSL_TLSV1_2, svrCertFile, svrKeyFile, \
          caCertFile }
#define TGSN_TLS12_ECDSA(sigalg, sig_nid, hash_nid) \
        { sigalg, sig_nid, hash_nid, WOLFSSL_TLSV1_2, eccCertFile, eccKeyFile, \
          caEccCertFile }
#define TGSN_TLS13_RSA(sigalg, sig_nid, hash_nid) \
        { sigalg, sig_nid, hash_nid, WOLFSSL_TLSV1_3, svrCertFile, svrKeyFile, \
          caCertFile }
#define TGSN_TLS13_ECDSA(sigalg, sig_nid, hash_nid) \
        { sigalg, sig_nid, hash_nid, WOLFSSL_TLSV1_3, eccCertFile, eccKeyFile, \
          caEccCertFile }
#define TGSN_TLS13_ED25519(sigalg, sig_nid, hash_nid) \
        { sigalg, sig_nid, hash_nid, WOLFSSL_TLSV1_3, edCertFile, edKeyFile, \
            caEdCertFile }
#define TGSN_TLS13_ED448(sigalg, sig_nid, hash_nid) \
        { sigalg, sig_nid, hash_nid, WOLFSSL_TLSV1_3, ed448CertFile, ed448KeyFile, \
            caEd448CertFile }
    struct {
        const char* siglag;
        int sig_nid;
        int hash_nid;
        int tls_ver;
        const char* server_cert;
        const char* server_key;
        const char* client_ca;
    } params[] = {
#ifndef NO_RSA
    #ifndef NO_SHA256
        TGSN_TLS12_RSA("RSA+SHA256", NID_rsaEncryption, NID_sha256),
        #ifdef WC_RSA_PSS
        TGSN_TLS12_RSA("RSA-PSS+SHA256", NID_rsassaPss, NID_sha256),
        TGSN_TLS13_RSA("RSA-PSS+SHA256", NID_rsassaPss, NID_sha256),
        #endif
    #endif
    #ifdef WOLFSSL_SHA512
        TGSN_TLS12_RSA("RSA+SHA512", NID_rsaEncryption, NID_sha512),
        #ifdef WC_RSA_PSS
        TGSN_TLS12_RSA("RSA-PSS+SHA512", NID_rsassaPss, NID_sha512),
        TGSN_TLS13_RSA("RSA-PSS+SHA512", NID_rsassaPss, NID_sha512),
        #endif
    #endif
#endif
#ifdef HAVE_ECC
    #ifndef NO_SHA256
        TGSN_TLS12_ECDSA("ECDSA+SHA256", NID_X9_62_id_ecPublicKey, NID_sha256),
        TGSN_TLS13_ECDSA("ECDSA+SHA256", NID_X9_62_id_ecPublicKey, NID_sha256),
    #endif
#endif
#ifdef HAVE_ED25519
        TGSN_TLS13_ED25519("ED25519", NID_ED25519, NID_sha512),
#endif
#ifdef HAVE_ED448
        TGSN_TLS13_ED448("ED448", NID_ED448, NID_sha512),
#endif
    };
    /* These correspond to WOLFSSL_SSLV3...WOLFSSL_DTLSV1_3 */
    const char* tls_desc[] = {
        "SSLv3", "TLSv1.0", "TLSv1.1", "TLSv1.2", "TLSv1.3",
        "DTLSv1.0", "DTLSv1.2", "DTLSv1.3"
    };

    printf("\n");

    for (i = 0; i < XELEM_CNT(params) && !EXPECT_FAIL(); i++) {

        XMEMSET(&client_cbf, 0, sizeof(client_cbf));
        XMEMSET(&server_cbf, 0, sizeof(server_cbf));

        printf("Testing %s with %s...", tls_desc[params[i].tls_ver],
                params[i].siglag);

        switch (params[i].tls_ver) {
#ifndef WOLFSSL_NO_TLS12
            case WOLFSSL_TLSV1_2:
                client_cbf.method = wolfTLSv1_2_client_method;
                server_cbf.method = wolfTLSv1_2_server_method;
                break;
#endif
#ifdef WOLFSSL_TLS13
            case WOLFSSL_TLSV1_3:
                client_cbf.method = wolfTLSv1_3_client_method;
                server_cbf.method = wolfTLSv1_3_server_method;
                break;
#endif
            default:
                printf("skipping\n");
                continue;
        }

        test_get_signature_nid_siglag = params[i].siglag;
        test_get_signature_nid_sig = params[i].sig_nid;
        test_get_signature_nid_hash = params[i].hash_nid;

        client_cbf.ssl_ready = test_get_signature_nid_ssl_ready;
        server_cbf.ssl_ready = test_get_signature_nid_ssl_ready;

        client_cbf.on_handshake = test_get_signature_nid_on_hs_client;
        server_cbf.on_handshake = test_get_signature_nid_on_hs_server;

        server_cbf.certPemFile = params[i].server_cert;
        server_cbf.keyPemFile = params[i].server_key;

        client_cbf.caPemFile = params[i].client_ca;

        ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
            &server_cbf, NULL), TEST_SUCCESS);
        if (EXPECT_SUCCESS())
            printf("passed\n");
    }

#endif
    return EXPECT_RESULT();
}

#ifndef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
#if !defined(NO_CERTS) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(NO_SHA256)
static word32 test_tls_cert_store_unchanged_HashCaTable(Signer** caTable)
{
#ifndef NO_MD5
    enum wc_HashType hashType = WC_HASH_TYPE_MD5;
#elif !defined(NO_SHA)
    enum wc_HashType hashType = WC_HASH_TYPE_SHA;
#elif !defined(NO_SHA256)
    enum wc_HashType hashType = WC_HASH_TYPE_SHA256;
#else
    #error "We need a digest to hash the Signer object"
#endif
    byte hashBuf[WC_MAX_DIGEST_SIZE];
    wc_HashAlg hash;
    size_t i;

    AssertIntEQ(wc_HashInit(&hash, hashType), 0);
    for (i = 0; i < CA_TABLE_SIZE; i++) {
        Signer* cur;
        for (cur = caTable[i]; cur != NULL; cur = cur->next)
            AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)cur,
                    sizeof(*cur)), 0);
    }
    AssertIntEQ(wc_HashFinal(&hash, hashType, hashBuf), 0);
    AssertIntEQ(wc_HashFree(&hash, hashType), 0);

    return MakeWordFromHash(hashBuf);
}

static word32 test_tls_cert_store_unchanged_before_hashes[2];
static size_t test_tls_cert_store_unchanged_before_hashes_idx;
static word32 test_tls_cert_store_unchanged_after_hashes[2];
static size_t test_tls_cert_store_unchanged_after_hashes_idx;

static int test_tls_cert_store_unchanged_ctx_ready(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;

    ExpectIntNE(test_tls_cert_store_unchanged_before_hashes
        [test_tls_cert_store_unchanged_before_hashes_idx++] =
            test_tls_cert_store_unchanged_HashCaTable(ctx->cm->caTable), 0);

    wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER |
            WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);

    return EXPECT_RESULT();
}

static int test_tls_cert_store_unchanged_ctx_cleanup(WOLFSSL_CTX* ctx)
{
    EXPECT_DECLS;
    ExpectIntEQ(wolfSSL_CTX_UnloadIntermediateCerts(ctx), WOLFSSL_SUCCESS);
    ExpectIntNE(test_tls_cert_store_unchanged_after_hashes
        [test_tls_cert_store_unchanged_after_hashes_idx++] =
            test_tls_cert_store_unchanged_HashCaTable(ctx->cm->caTable), 0);

    return EXPECT_RESULT();
}

static int test_tls_cert_store_unchanged_on_hs(WOLFSSL_CTX **ctx, WOLFSSL **ssl)
{
    EXPECT_DECLS;
    WOLFSSL_CERT_MANAGER* cm;

    (void)ssl;
    /* WARNING: this approach bypasses the reference counter check in
     * wolfSSL_CTX_UnloadIntermediateCerts. It is not recommended as it may
     * cause unexpected behaviour when other active connections try accessing
     * the caTable. */
    ExpectNotNull(cm = wolfSSL_CTX_GetCertManager(*ctx));
    ExpectIntEQ(wolfSSL_CertManagerUnloadIntermediateCerts(cm),
            WOLFSSL_SUCCESS);
    ExpectIntNE(test_tls_cert_store_unchanged_after_hashes
        [test_tls_cert_store_unchanged_after_hashes_idx++] =
            test_tls_cert_store_unchanged_HashCaTable((*ctx)->cm->caTable), 0);

    return EXPECT_RESULT();
}

static int test_tls_cert_store_unchanged_ssl_ready(WOLFSSL* ssl)
{
    EXPECT_DECLS;
    WOLFSSL_CTX* ctx;

    ExpectNotNull(ctx = wolfSSL_get_SSL_CTX(ssl));

    return EXPECT_RESULT();
}
#endif

static int test_tls_cert_store_unchanged(void)
{
    EXPECT_DECLS;
#if !defined(NO_CERTS) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(NO_SHA256)
    test_ssl_cbf client_cbf;
    test_ssl_cbf server_cbf;
    int i;

    for (i = 0; i < 2; i++) {
        XMEMSET(&client_cbf, 0, sizeof(client_cbf));
        XMEMSET(&server_cbf, 0, sizeof(server_cbf));

        test_tls_cert_store_unchanged_before_hashes_idx = 0;
        XMEMSET(test_tls_cert_store_unchanged_before_hashes, 0,
                sizeof(test_tls_cert_store_unchanged_before_hashes));
        test_tls_cert_store_unchanged_after_hashes_idx = 0;
        XMEMSET(test_tls_cert_store_unchanged_after_hashes, 0,
                sizeof(test_tls_cert_store_unchanged_after_hashes));

        client_cbf.ctx_ready = test_tls_cert_store_unchanged_ctx_ready;
        server_cbf.ctx_ready = test_tls_cert_store_unchanged_ctx_ready;

        client_cbf.ssl_ready = test_tls_cert_store_unchanged_ssl_ready;
        server_cbf.ssl_ready = test_tls_cert_store_unchanged_ssl_ready;

        switch (i) {
            case 0:
                client_cbf.on_ctx_cleanup =
                        test_tls_cert_store_unchanged_ctx_cleanup;
                server_cbf.on_ctx_cleanup =
                        test_tls_cert_store_unchanged_ctx_cleanup;
                break;
            case 1:
                client_cbf.on_handshake = test_tls_cert_store_unchanged_on_hs;
                server_cbf.on_handshake = test_tls_cert_store_unchanged_on_hs;
                break;
            default:
                Fail(("Should not enter here"), ("Entered here"));
        }

#ifdef WOLFSSL_PEM_TO_DER
        client_cbf.certPemFile = "certs/intermediate/client-chain.pem";
        server_cbf.certPemFile = "certs/intermediate/server-chain.pem";
#else
        client_cbf.certPemFile = "certs/intermediate/client-chain.der";
        server_cbf.certPemFile = "certs/intermediate/server-chain.der";
#endif

        server_cbf.caPemFile = caCertFile;

        ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf,
            &server_cbf, NULL), TEST_SUCCESS);

        ExpectBufEQ(test_tls_cert_store_unchanged_before_hashes,
                test_tls_cert_store_unchanged_after_hashes,
                sizeof(test_tls_cert_store_unchanged_after_hashes));
    }
#endif
    return EXPECT_RESULT();
}
#endif /* !WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */

static int test_wolfSSL_SendUserCanceled(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
    size_t i;
    struct {
        method_provider client_meth;
        method_provider server_meth;
        const char* tls_version;
    } params[] = {
#if defined(WOLFSSL_TLS13)
/* With WOLFSSL_TLS13_MIDDLEBOX_COMPAT a short ID will result in an error */
        { wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLSv1_3" },
#ifdef WOLFSSL_DTLS13
        { wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLSv1_3" },
#endif
#endif
#ifndef WOLFSSL_NO_TLS12
        { wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLSv1_2" },
#ifdef WOLFSSL_DTLS
        { wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "DTLSv1_2" },
#endif
#endif
#if !defined(NO_OLD_TLS)
        { wolfTLSv1_1_client_method, wolfTLSv1_1_server_method, "TLSv1_1" },
#ifdef WOLFSSL_DTLS
        { wolfDTLSv1_client_method, wolfDTLSv1_server_method, "DTLSv1_0" },
#endif
#endif
    };

    for (i = 0; i < sizeof(params)/sizeof(*params) && !EXPECT_FAIL(); i++) {
        WOLFSSL_CTX *ctx_c = NULL;
        WOLFSSL_CTX *ctx_s = NULL;
        WOLFSSL *ssl_c = NULL;
        WOLFSSL *ssl_s = NULL;
        struct test_memio_ctx test_ctx;
        WOLFSSL_ALERT_HISTORY h;

        printf("Testing %s\n", params[i].tls_version);

        XMEMSET(&h, 0, sizeof(h));
        XMEMSET(&test_ctx, 0, sizeof(test_ctx));
        ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
                params[i].client_meth, params[i].server_meth), 0);

        /* CH1 */
        ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
        ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);

        ExpectIntEQ(wolfSSL_SendUserCanceled(ssl_s), WOLFSSL_SHUTDOWN_NOT_DONE);

        /* Alert closed connection */
        ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
        ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_ZERO_RETURN);

        /* Last alert will be close notify because user_canceled should be
         * followed by a close_notify */
        ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
        ExpectIntEQ(h.last_rx.code, close_notify);
        ExpectIntEQ(h.last_rx.level, alert_warning);

        wolfSSL_free(ssl_c);
        wolfSSL_free(ssl_s);
        wolfSSL_CTX_free(ctx_c);
        wolfSSL_CTX_free(ctx_s);
    }
#endif
    return EXPECT_RESULT();
}
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
    defined(HAVE_OCSP) && \
    defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
    !defined(WOLFSSL_NO_TLS12)
static int test_ocsp_callback_fails_cb(void* ctx, const char* url, int urlSz,
                        byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
{
    (void)ctx;
    (void)url;
    (void)urlSz;
    (void)ocspReqBuf;
    (void)ocspReqSz;
    (void)ocspRespBuf;
    return WOLFSSL_CBIO_ERR_GENERAL;
}
static int test_ocsp_callback_fails(void)
{
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL_CTX *ctx_s = NULL;
    WOLFSSL *ssl_c = NULL;
    WOLFSSL *ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    EXPECT_DECLS;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
            wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
    ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(ctx_c), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(ctx_s), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_UseOCSPStapling(ssl_c, WOLFSSL_CSR_OCSP,0), WOLFSSL_SUCCESS);
    /* override URL to avoid exing from SendCertificateStatus because of no AuthInfo on the certificate */
    ExpectIntEQ(wolfSSL_CTX_SetOCSP_OverrideURL(ctx_s, "http://dummy.test"), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_EnableOCSP(ctx_s, WOLFSSL_OCSP_NO_NONCE    | WOLFSSL_OCSP_URL_OVERRIDE), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, caCertFile, 0), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_SetOCSP_Cb(ssl_s, test_ocsp_callback_fails_cb, NULL, NULL), WOLFSSL_SUCCESS);
    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WC_NO_ERR_TRACE(OCSP_INVALID_STATUS));

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);

    return EXPECT_RESULT();
}
#else
static int test_ocsp_callback_fails(void)
{
    return TEST_SKIPPED;
}
#endif /* defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
    defined(HAVE_OCSP) && \
    defined(HAVE_CERTIFICATE_STATUS_REQUEST) */

#ifdef HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES
static int test_wolfSSL_SSLDisableRead_recv(WOLFSSL *ssl, char *buf, int sz,
                                             void *ctx)
{
    (void)ssl;
    (void)buf;
    (void)sz;
    (void)ctx;
    return WOLFSSL_CBIO_ERR_GENERAL;
}

static int test_wolfSSL_SSLDisableRead(void)
{
    EXPECT_DECLS;
    WOLFSSL_CTX *ctx_c = NULL;
    WOLFSSL *ssl_c = NULL;
    struct test_memio_ctx test_ctx;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL,
            wolfTLS_client_method, NULL), 0);
    wolfSSL_SSLSetIORecv(ssl_c, test_wolfSSL_SSLDisableRead_recv);
    wolfSSL_SSLDisableRead(ssl_c);

    /* Disabling reading should not even go into the IO layer */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
    wolfSSL_SSLEnableRead(ssl_c);
    /* By enabling reading we should reach the IO that will return an error */
    ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), SOCKET_ERROR_E);

    wolfSSL_free(ssl_c);
    wolfSSL_CTX_free(ctx_c);
    return EXPECT_RESULT();
}
#else
static int test_wolfSSL_SSLDisableRead(void)
{
    EXPECT_DECLS;
    return EXPECT_RESULT();
}
#endif

static int test_wolfSSL_inject(void)
{
    EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(NO_SHA256)
    size_t i;
    struct {
        method_provider client_meth;
        method_provider server_meth;
        const char* tls_version;
    } params[] = {
#if defined(WOLFSSL_TLS13)
/* With WOLFSSL_TLS13_MIDDLEBOX_COMPAT a short ID will result in an error */
        { wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLSv1_3" },
#ifdef WOLFSSL_DTLS13
        { wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLSv1_3" },
#endif
#endif
#ifndef WOLFSSL_NO_TLS12
        { wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLSv1_2" },
#ifdef WOLFSSL_DTLS
        { wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "DTLSv1_2" },
#endif
#endif
#if !defined(NO_OLD_TLS)
        { wolfTLSv1_1_client_method, wolfTLSv1_1_server_method, "TLSv1_1" },
#ifdef WOLFSSL_DTLS
        { wolfDTLSv1_client_method, wolfDTLSv1_server_method, "DTLSv1_0" },
#endif
#endif
    };

    for (i = 0; i < XELEM_CNT(params) && !EXPECT_FAIL(); i++) {
        WOLFSSL_CTX *ctx_c = NULL;
        WOLFSSL_CTX *ctx_s = NULL;
        WOLFSSL *ssl_c = NULL;
        WOLFSSL *ssl_s = NULL;
        struct test_memio_ctx test_ctx;
        WOLFSSL_ALERT_HISTORY h;
        int rounds;
        int hs_c = 0;
        int hs_s = 0;

        printf("Testing %s\n", params[i].tls_version);

        XMEMSET(&h, 0, sizeof(h));
        XMEMSET(&test_ctx, 0, sizeof(test_ctx));
        ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
                params[i].client_meth, params[i].server_meth), 0);

        for (rounds = 0; rounds < 10 && EXPECT_SUCCESS(); rounds++) {
            if (!hs_c) {
                wolfSSL_SetLoggingPrefix("client");
                if (wolfSSL_negotiate(ssl_c) != 1) {
                    ExpectIntEQ(wolfSSL_get_error(ssl_c, -1),
                            WOLFSSL_ERROR_WANT_READ);
                }
                else
                    hs_c = 1;
            }
            if (!hs_s) {
                wolfSSL_SetLoggingPrefix("server");
                if (test_ctx.s_len > 0) {
                    ExpectIntEQ(wolfSSL_inject(ssl_s, test_ctx.s_buff,
                                            test_ctx.s_len), 1);
                    test_memio_clear_buffer(&test_ctx, 0);
                }
                if (wolfSSL_negotiate(ssl_s) != 1) {
                    ExpectIntEQ(wolfSSL_get_error(ssl_s, -1),
                            WOLFSSL_ERROR_WANT_READ);
                }
                else
                    hs_s = 1;
            }
            if (!hs_c) {
                wolfSSL_SetLoggingPrefix("client");
                if (test_ctx.c_len > 0) {
                    ExpectIntEQ(wolfSSL_inject(ssl_c, test_ctx.c_buff,
                                            test_ctx.c_len), 1);
                    test_memio_clear_buffer(&test_ctx, 1);
                }
            }
            wolfSSL_SetLoggingPrefix(NULL);
        }
        ExpectIntEQ(hs_c, 1);
        ExpectIntEQ(hs_s, 1);

        wolfSSL_free(ssl_c);
        wolfSSL_free(ssl_s);
        wolfSSL_CTX_free(ctx_c);
        wolfSSL_CTX_free(ctx_s);
    }
#endif
    return EXPECT_RESULT();
}

/*----------------------------------------------------------------------------*
 | Main
 *----------------------------------------------------------------------------*/

int testAll = 1;
int stopOnFail = 0;

/*----------------------------------------------------------------------------*/
/* LMS tests                                                                  */
/*----------------------------------------------------------------------------*/
int test_wc_LmsKey_sign_verify(void);
int test_wc_LmsKey_reload_cache(void);
int test_rfc9802_lms_x509_verify(void);
int test_rfc9802_xmss_x509_verify(void);

#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)

#include <wolfssl/wolfcrypt/wc_lms.h>

#define LMS_TEST_PRIV_KEY_FILE "/tmp/wolfssl_test_lms.key"

static int test_lms_write_key(const byte* priv, word32 privSz, void* context)
{
    FILE* f = fopen((const char*)context, "wb");
    int ret = WC_LMS_RC_SAVED_TO_NV_MEMORY;
    if (f == NULL)
        return -1;
    if (fwrite(priv, 1, privSz, f) != privSz)
        ret = -1;
    fclose(f);
    return ret;
}

static int test_lms_read_key(byte* priv, word32 privSz, void* context)
{
    FILE* f = fopen((const char*)context, "rb");
    if (f == NULL)
        return -1;
    if (fread(priv, 1, privSz, f) == 0) {
        fclose(f);
        return -1;
    }
    fclose(f);
    return WC_LMS_RC_READ_TO_MEMORY;
}

/* Helper: init an LMS key with callbacks and L1-H10-W8 params */
static int test_lms_init_key(LmsKey* key, WC_RNG* rng)
{
    int ret;

    ret = wc_LmsKey_Init(key, NULL, INVALID_DEVID);
    if (ret != 0) return ret;

#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10)
    ret = wc_LmsKey_SetParameters(key, 1, 10, 8);
#else
    ret = wc_LmsKey_SetParameters(key, 1, 5, 8);
#endif
    if (ret != 0) return ret;

    ret = wc_LmsKey_SetWriteCb(key, test_lms_write_key);
    if (ret != 0) return ret;

    ret = wc_LmsKey_SetReadCb(key, test_lms_read_key);
    if (ret != 0) return ret;

    ret = wc_LmsKey_SetContext(key, (void*)LMS_TEST_PRIV_KEY_FILE);
    if (ret != 0) return ret;

    (void)rng;
    return 0;
}

#endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */

/*
 * Test basic LMS sign/verify with multiple signings.
 * Uses L1-H10-W8 (1024 total signatures, 32-entry leaf cache).
 */
int test_wc_LmsKey_sign_verify(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
    LmsKey  key;
    WC_RNG  rng;
    byte    msg[] = "test message for LMS signing";
    byte    sig[2048];
    word32  sigSz;
    int     i;
    int     numSigs = 5;

    ExpectIntEQ(wc_InitRng(&rng), 0);

    remove(LMS_TEST_PRIV_KEY_FILE);
    ExpectIntEQ(test_lms_init_key(&key, &rng), 0);
    ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0);

    for (i = 0; i < numSigs; i++) {
        sigSz = sizeof(sig);
        ExpectIntEQ(wc_LmsKey_Sign(&key, sig, &sigSz, msg, sizeof(msg)), 0);
        ExpectIntEQ(wc_LmsKey_Verify(&key, sig, sigSz, msg, sizeof(msg)), 0);
    }

    wc_LmsKey_Free(&key);
    wc_FreeRng(&rng);
    remove(LMS_TEST_PRIV_KEY_FILE);
#endif
    return EXPECT_RESULT();
}

/*
 * Test LMS key reload after advancing past the leaf cache window.
 *
 * Reproduces a heap-buffer-overflow bug in wc_lms_treehash_init() where the
 * leaf cache write uses (i * hash_len) instead of ((i - leaf->idx) * hash_len).
 * When q > max_cb (default 32), wc_LmsKey_Reload calls wc_hss_init_auth_path
 * which calls wc_lms_treehash_init with q > 0, causing writes past the end of
 * the leaf cache buffer.
 *
 * Reproduction steps:
 *   1. Generate L1-H10-W8 key (cacheBits=5, max_cb=32)
 *   2. Sign 33 times to advance q past the cache window
 *   3. Free the key and reload from persisted state
 *   4. Sign and verify after reload
 *
 * Without the fix: heap-buffer-overflow at wc_lms_impl.c:1965
 * With the fix:    all operations succeed, signatures verify
 */
int test_wc_LmsKey_reload_cache(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) && \
    (!defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10))
    LmsKey  key;
    LmsKey  vkey;
    WC_RNG  rng;
    byte    msg[] = "test message for LMS signing";
    byte    sig[2048];
    word32  sigSz;
    byte    pub[64];
    word32  pubSz = sizeof(pub);
    int     i;
    /* Sign 33 times to advance q past the 32-entry cache window. */
    int     preSigs = 33;

    ExpectIntEQ(wc_InitRng(&rng), 0);

    /* Phase 1: Generate key and sign past cache window */
    remove(LMS_TEST_PRIV_KEY_FILE);
    ExpectIntEQ(test_lms_init_key(&key, &rng), 0);
    ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0);

    for (i = 0; i < preSigs; i++) {
        sigSz = sizeof(sig);
        ExpectIntEQ(wc_LmsKey_Sign(&key, sig, &sigSz, msg, sizeof(msg)), 0);
    }

    /* Save public key for verification after reload */
    ExpectIntEQ(wc_LmsKey_ExportPubRaw(&key, pub, &pubSz), 0);

    wc_LmsKey_Free(&key);

    /* Phase 2: Reload key. Triggers wc_lms_treehash_init with q=33 */
    ExpectIntEQ(test_lms_init_key(&key, &rng), 0);
    ExpectIntEQ(wc_LmsKey_Reload(&key), 0);

    /* Phase 3: Sign after reload and verify with separate verify-only key */
    sigSz = sizeof(sig);
    ExpectIntEQ(wc_LmsKey_Sign(&key, sig, &sigSz, msg, sizeof(msg)), 0);

    ExpectIntEQ(wc_LmsKey_Init(&vkey, NULL, INVALID_DEVID), 0);
#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10)
    ExpectIntEQ(wc_LmsKey_SetParameters(&vkey, 1, 10, 8), 0);
#else
    ExpectIntEQ(wc_LmsKey_SetParameters(&vkey, 1, 5, 8), 0);
#endif
    ExpectIntEQ(wc_LmsKey_ImportPubRaw(&vkey, pub, pubSz), 0);
    ExpectIntEQ(wc_LmsKey_Verify(&vkey, sig, sigSz, msg, sizeof(msg)), 0);

    wc_LmsKey_Free(&vkey);
    wc_LmsKey_Free(&key);
    wc_FreeRng(&rng);
    remove(LMS_TEST_PRIV_KEY_FILE);
#endif
    return EXPECT_RESULT();
}

/*----------------------------------------------------------------------------*/
/* RFC 9802 (HSS/LMS and XMSS/XMSS^MT in X.509) tests                         */
/*----------------------------------------------------------------------------*/

/* For every committed self-signed test certificate confirm:
 *   - wc_ParseCert succeeds on the RFC 9802 AlgorithmIdentifier encoding
 *     (OID-only SEQUENCE, no NULL parameters)
 *   - keyOID and signatureOID are set to the expected values
 *   - loading as a trust anchor and verifying the same bytes through
 *     wolfSSL_CertManagerVerifyBuffer exercises the ConfirmSignature
 *     path and succeeds on a valid cert
 *   - flipping a byte in the signature AND flipping a byte in the
 *     TBSCertificate both cause verification to fail.
 *
 * Test vectors are in certs/lms/ and certs/xmss/, generated with Bouncy
 * Castle 1.81. BC's default XMSS / XMSS^MT X.509 encoding uses pre-
 * standard ISARA OIDs and wraps the raw RFC 8391 pub key in an OCTET
 * STRING, so the fixtures were produced with a small generator that
 * overrides the AlgorithmIdentifier and SPKI to match RFC 9802. */
#if (defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS)) && \
    !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
/* Sanity bound on a test fixture cert. The largest BC-generated
 * fixture we ship (XMSS^MT 40/8) is ~19 KiB; 1 MiB is well above
 * any realistic RFC 9802 cert and catches a wild XFTELL. Typed as
 * long to match XFTELL's return so the size comparison below isn't
 * a mixed long-vs-int compare. */
#define RFC9802_TEST_MAX_CERT_SIZE ((long)(1L << 20))

/* Load a whole file into a freshly-allocated buffer. Caller frees. */
static int rfc9802_load_file(const char* path, byte** out, int* outLen)
{
    EXPECT_DECLS;
    XFILE  f = XBADFILE;
    long   sz = 0;
    size_t got = 0;
    byte*  buf = NULL;

    *out = NULL;
    *outLen = 0;
    ExpectTrue((f = XFOPEN(path, "rb")) != XBADFILE);
    if (f == XBADFILE)
        return TEST_FAIL;
    if (XFSEEK(f, 0, XSEEK_END) == 0)
        sz = XFTELL(f);
    (void)XFSEEK(f, 0, XSEEK_SET);
    ExpectIntGT(sz, 0);
    ExpectIntLT(sz, RFC9802_TEST_MAX_CERT_SIZE);
    /* Hard-fail before XMALLOC if XFSEEK / XFTELL produced an unusable
     * size: ExpectInt* records the failure but doesn't short-circuit,
     * so without this guard a -1 from XFTELL would cast to a multi-GiB
     * (size_t) allocation, and a 0 would request a zero-byte malloc. */
    if (sz <= 0 || sz >= RFC9802_TEST_MAX_CERT_SIZE) {
        XFCLOSE(f);
        return TEST_FAIL;
    }
    ExpectNotNull(buf = (byte*)XMALLOC((size_t)sz, NULL,
        DYNAMIC_TYPE_TMP_BUFFER));
    if (buf != NULL) {
        got = XFREAD(buf, 1, (size_t)sz, f);
        ExpectIntEQ(got, (size_t)sz);
        /* On a short read the caller would otherwise proceed with a
         * partially-initialized buffer and produce cascading parse
         * failures driven by the uninitialized tail. Free here so the
         * caller's `if (buf == NULL) return TEST_FAIL;` short-circuits
         * cleanly with a single recorded failure. */
        if (got != (size_t)sz) {
            XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
            buf = NULL;
            sz = 0;
        }
    }
    XFCLOSE(f);
    *out = buf;
    *outLen = (int)sz;
    return EXPECT_RESULT();
}

static int rfc9802_verify_one_cert(const char* path, word32 expectedKeyOID,
    word32 expectedSigOID)
{
    EXPECT_DECLS;
    byte*                 buf = NULL;
    byte*                 tampered = NULL;
    int                   bytes = 0;
    DecodedCert           cert;
    WOLFSSL_CERT_MANAGER* cm = NULL;
    word32                certBegin = 0;
    word32                sigIndex = 0;

    ExpectIntEQ(rfc9802_load_file(path, &buf, &bytes), TEST_SUCCESS);
    if (buf == NULL)
        return TEST_FAIL;

    /* Parse + check OIDs, capture certBegin and sigIndex for later tamper. */
    wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL);
    ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
    ExpectIntEQ((int)cert.keyOID, (int)expectedKeyOID);
    ExpectIntEQ((int)cert.signatureOID, (int)expectedSigOID);
    certBegin = cert.certBegin;
    sigIndex  = cert.sigIndex;
    wc_FreeDecodedCert(&cert);

    /* Full verify against a self-installed trust anchor. */
    ExpectNotNull(cm = wolfSSL_CertManagerNew());
    ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, buf, (long)bytes,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
    if (cm != NULL) {
        wolfSSL_CertManagerFree(cm);
        cm = NULL;
    }

    ExpectNotNull(tampered = (byte*)XMALLOC((size_t)bytes, NULL,
        DYNAMIC_TYPE_TMP_BUFFER));

    /* Negative 1: flip a byte inside the signatureValue BIT STRING.
     * Everything after sigIndex is the signatureAlgorithm + the BIT
     * STRING payload, so flipping the last byte is always inside the
     * signature content. */
    if (tampered != NULL) {
        XMEMCPY(tampered, buf, (size_t)bytes);
        tampered[bytes - 1] ^= 0x01;
        ExpectNotNull(cm = wolfSSL_CertManagerNew());
        ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes,
            WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
        ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, tampered,
            (long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
        if (cm != NULL) {
            wolfSSL_CertManagerFree(cm);
            cm = NULL;
        }
    }

    /* Negative 2: flip a byte at the midpoint of the TBSCertificate. The
     * TBS is the first element of the outer Certificate SEQUENCE and
     * its bytes lie between (certBegin + outerSeqHeader) and sigIndex.
     * Picking the midpoint ensures we're inside TBS regardless of the
     * fixture's DN / extensions layout. */
    if (tampered != NULL && sigIndex > certBegin + 8U) {
        word32 midTbs = certBegin + 8 + ((sigIndex - (certBegin + 8)) / 2);
        XMEMCPY(tampered, buf, (size_t)bytes);
        tampered[midTbs] ^= 0x01;
        ExpectNotNull(cm = wolfSSL_CertManagerNew());
        ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes,
            WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
        ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, tampered,
            (long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
        if (cm != NULL) {
            wolfSSL_CertManagerFree(cm);
            cm = NULL;
        }
    }

    /* The fixtures MUST carry a KeyUsage extension with at least one of
     * digitalSignature / nonRepudiation / keyCertSign / cRLSign set per
     * RFC 9802 sec 3. Re-parse and assert that wolfSSL recorded a non-
     * empty set of KeyUsage bits from one of those values. */
    wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL);
    ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
    ExpectIntEQ(cert.extKeyUsageSet, 1);
    ExpectIntNE(cert.extKeyUsage & (KEYUSE_DIGITAL_SIG | KEYUSE_CONTENT_COMMIT |
        KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN), 0);
    wc_FreeDecodedCert(&cert);

    XFREE(tampered, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    return EXPECT_RESULT();
}
#endif

/* Direct wolfCrypt-level negative tests for the parameter-derivation
 * helpers used by the RFC 9802 parse path. These exercise failure modes
 * (unknown algorithm bytes, truncated inputs, mismatches) that a real
 * cert body wouldn't easily reach. */
#if defined(WOLFSSL_HAVE_LMS)
static int rfc9802_lms_import_negative(void)
{
    EXPECT_DECLS;
    LmsKey key;
    /* 60-byte buffer matches HSS_PUBLIC_KEY_LEN(32), just like a valid
     * SHA-256/M32/H5 key; the algorithm-type bytes are junk so param
     * derivation must fail cleanly. */
    byte   junk[60];

    XMEMSET(junk, 0, sizeof(junk));
    /* levels=1, lmsType=0xFFFFFFFF, lmOtsType=0xFFFFFFFF. */
    junk[3] = 1;
    XMEMSET(junk + 4, 0xFF, 4);
    XMEMSET(junk + 8, 0xFF, 4);

    /* Unknown algorithm types must be rejected. */
    ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, junk, sizeof(junk)),
        WC_NO_ERR_TRACE(NOT_COMPILED_IN));
    wc_LmsKey_Free(&key);

    /* Too-short buffer: only L + lmsType, no lmOtsType. */
    ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, junk, 8),
        WC_NO_ERR_TRACE(BUFFER_E));
    wc_LmsKey_Free(&key);

#if !defined(WOLFSSL_NO_LMS_SHA256_256)
    /* The two cases below pin specific SHA-256/M32 parameter codes
     * (L1_H5_W8, L1_H5_W4, L1_H10_W2). Skip them in builds where the
     * SHA-256/M32 family is disabled -- the family-agnostic checks
     * above (junk algorithm types, too-short buffer, GetSigLen on
     * unconfigured key) still cover the universal invariants. */

    /* Pre-set params that disagree with the raw key's algorithm bytes:
     * configure H=5/W=8 but feed buffer that claims H=10 / W=2. */
    XMEMSET(junk, 0, sizeof(junk));
    junk[3] = 1;       /* levels=1     */
    junk[7] = 6;       /* lmsType = LMS_SHA256_M32_H10 = 6 */
    junk[11] = 2;      /* lmOtsType = LMOTS_SHA256_N32_W2 = 2 */
    ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_LmsKey_SetParameters(&key, 1, 5, 8), 0);
    ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, junk, sizeof(junk)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    wc_LmsKey_Free(&key);
#endif /* !WOLFSSL_NO_LMS_SHA256_256 */

    /* GetSigLen on a key with no params set must not NULL-deref the
     * params pointer; it must return BAD_FUNC_ARG instead. */
    {
        word32 sigLen = 0;
        ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_LmsKey_GetSigLen(&key, &sigLen),
            WC_NO_ERR_TRACE(BAD_FUNC_ARG));
        wc_LmsKey_Free(&key);
    }

#if !defined(WOLFSSL_NO_LMS_SHA256_256)
    /* Partial-write invariant: a length mismatch after a successful
     * auto-derive must leave key->params NULL. Build a buffer whose
     * leading u32str(L) || lmsType || lmOtsType identifies a known
     * parameter set, but truncate to one byte less than the real pub
     * key length so the post-derive length check fails. */
    {
        byte truncated[59];   /* HSS_PUBLIC_KEY_LEN(32) is 60 */
        XMEMSET(truncated, 0, sizeof(truncated));
        truncated[3] = 1;     /* L = 1 */
        truncated[7] = 5;     /* lmsType = LMS_SHA256_M32_H5 */
        truncated[11] = 4;    /* lmOtsType = LMOTS_SHA256_N32_W4 */
        ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0);
        ExpectNull(key.params);
        ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, truncated,
            sizeof(truncated)), WC_NO_ERR_TRACE(BUFFER_E));
        ExpectNull(key.params);
        wc_LmsKey_Free(&key);
    }
#endif /* !WOLFSSL_NO_LMS_SHA256_256 */

    return EXPECT_RESULT();
}
#endif

#if defined(WOLFSSL_HAVE_XMSS)
static int rfc9802_xmss_import_negative(void)
{
    EXPECT_DECLS;
    XmssKey key;
    byte    junk[8];

    XMEMSET(junk, 0, sizeof(junk));

    /* Too-short buffer. */
    ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, junk, 2, 0),
        WC_NO_ERR_TRACE(BUFFER_E));
    wc_XmssKey_Free(&key);

    /* Unknown OID (all-zero) for both XMSS and XMSS^MT. */
    ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, junk, sizeof(junk), 0),
        WC_NO_ERR_TRACE(NOT_COMPILED_IN));
    wc_XmssKey_Free(&key);
    ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, junk, sizeof(junk), 1),
        WC_NO_ERR_TRACE(NOT_COMPILED_IN));
    wc_XmssKey_Free(&key);

    /* NULL key / input. */
    ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(NULL, junk, sizeof(junk), 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, NULL, 8, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    wc_XmssKey_Free(&key);

    /* GetSigLen on a key with no params set must not NULL-deref the
     * params pointer; it must return BAD_FUNC_ARG instead. */
    {
        word32 sigLen = 0;
        ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_XmssKey_GetSigLen(&key, &sigLen),
            WC_NO_ERR_TRACE(BAD_FUNC_ARG));
        wc_XmssKey_Free(&key);
    }

    /* Once params have been configured (state != INITED), the OID
     * prefix in the raw key MUST match key->oid and is_xmssmt MUST
     * match key->is_xmssmt. Set XMSS-SHA2_10_256 and feed a valid-
     * sized buffer whose 4-byte OID prefix is bogus -> BAD_FUNC_ARG. */
    {
        byte mismatch[XMSS_SHA256_PUBLEN];
        ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"), 0);
        XMEMSET(mismatch, 0, sizeof(mismatch));
        mismatch[3] = 0x77; /* nonsense OID */
        ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, mismatch,
            sizeof(mismatch), 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
        /* Same buffer with the correct OID, but is_xmssmt hint
         * contradicts the configured family -> BAD_FUNC_ARG. */
        mismatch[3] = 0x01; /* WC_XMSS_OID_SHA2_10_256 */
        ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, mismatch,
            sizeof(mismatch), 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
        wc_XmssKey_Free(&key);
    }

    /* Partial-write invariant: a length mismatch after a successful
     * auto-derive must leave the key in its INITED state, with
     * key->params NULL. */
    {
        byte truncated[XMSS_SHA256_PUBLEN - 1];
        XMEMSET(truncated, 0, sizeof(truncated));
        truncated[3] = 0x01;
        ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0);
        ExpectNull(key.params);
        ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, truncated,
            sizeof(truncated), 0), WC_NO_ERR_TRACE(BUFFER_E));
        ExpectNull(key.params);
        wc_XmssKey_Free(&key);
    }

    /* is_xmssmt disambiguation: XMSS oid=1 and XMSS^MT oid=1 share
     * the wire-numeric value but resolve to different parameter sets.
     * Importing the same 68-byte buffer with hint=0 vs hint=1 must
     * land in different tables and produce distinct is_xmssmt. */
    {
        byte buf[XMSS_SHA256_PUBLEN];
        XMEMSET(buf, 0, sizeof(buf));
        buf[3] = 0x01;

        ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 0), 0);
        ExpectIntEQ((int)key.is_xmssmt, 0);
        wc_XmssKey_Free(&key);

        ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 1), 0);
        ExpectIntEQ((int)key.is_xmssmt, 1);
        wc_XmssKey_Free(&key);
    }

    /* Lenient state: re-importing the same pub key into a VERIFYONLY
     * key (params set, no private material) succeeds. The second
     * call exercises the lenient-state branch. */
    {
        byte buf[XMSS_SHA256_PUBLEN];
        XMEMSET(buf, 0, sizeof(buf));
        buf[3] = 0x01;

        ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 0), 0);
        ExpectIntEQ((int)key.state, (int)WC_XMSS_STATE_VERIFYONLY);
        ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 0), 0);
        ExpectIntEQ((int)key.state, (int)WC_XMSS_STATE_VERIFYONLY);
        wc_XmssKey_Free(&key);
    }

    /* Strict signature-length check: wc_XmssKey_Verify rejects any
     * sigLen != key->params->sig_len. This guards every consumer
     * (RFC 9802 X.509, PKCS#7, CMS, ...) against a longer wrapper that
     * happens to start with a valid signature. Construct a key in
     * VERIFYONLY state, then verify with sig_len + 1 and sig_len - 1
     * byte buffers; both must fail with BUFFER_E before any crypto
     * runs. The buffer contents are irrelevant since the length check
     * fires first. */
    {
        byte    pub[XMSS_SHA256_PUBLEN];
        byte*   sigBuf = NULL;
        word32  sigLen = 0;
        const byte msg[1] = { 0 };

        XMEMSET(pub, 0, sizeof(pub));
        pub[3] = 0x01;
        ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, pub, sizeof(pub), 0), 0);
        ExpectIntEQ((int)key.state, (int)WC_XMSS_STATE_VERIFYONLY);
        ExpectIntEQ(wc_XmssKey_GetSigLen(&key, &sigLen), 0);
        ExpectIntGT(sigLen, 0);
        ExpectNotNull(sigBuf = (byte*)XMALLOC((size_t)sigLen + 1, NULL,
            DYNAMIC_TYPE_TMP_BUFFER));
        if (sigBuf != NULL) {
            XMEMSET(sigBuf, 0, (size_t)sigLen + 1);
            ExpectIntEQ(wc_XmssKey_Verify(&key, sigBuf, sigLen + 1,
                msg, (int)sizeof(msg)), WC_NO_ERR_TRACE(BUFFER_E));
            ExpectIntEQ(wc_XmssKey_Verify(&key, sigBuf, sigLen - 1,
                msg, (int)sizeof(msg)), WC_NO_ERR_TRACE(BUFFER_E));
            XFREE(sigBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        }
        wc_XmssKey_Free(&key);
    }

    /* BAD_STATE_E branch: WC_XMSS_STATE_OK must be rejected. Reaching
     * OK normally requires a successful private-key Reload / sign,
     * which is unavailable in WOLFSSL_XMSS_VERIFY_ONLY builds. Force
     * the state directly to exercise the rejection without coupling
     * this helper to the signing test fixture; sk stays NULL so Free
     * is still safe. */
    {
        byte pub[XMSS_SHA256_PUBLEN];

        XMEMSET(pub, 0, sizeof(pub));
        pub[3] = 0x01;
        ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"), 0);
        key.state = WC_XMSS_STATE_OK;
        ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, pub, sizeof(pub), 0),
            WC_NO_ERR_TRACE(BAD_STATE_E));
        wc_XmssKey_Free(&key);
    }

    return EXPECT_RESULT();
}
#endif

/* Walk the AlgorithmIdentifier SEQUENCE that begins at sigIndex and
 * locate the byte offset of the last byte of its OID content. Handles
 * both short-form (length < 128) and long-form DER length encodings,
 * so a future fixture-regenerator that emits longer OIDs / SEQUENCEs
 * still drives this test rather than tripping the loud-fail branch.
 *
 * Returns 0 on success with *oidLastByte set; returns -1 on any DER
 * shape mismatch. */
#if defined(WOLFSSL_HAVE_XMSS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
static int rfc9802_find_sig_alg_oid_last_byte(const byte* buf, word32 bufLen,
    word32 sigIndex, word32* oidLastByte)
{
    word32 idx = sigIndex;
    word32 oidContentLen = 0;

    /* AlgorithmIdentifier ::= SEQUENCE { algorithm OID, ... } */
    if (idx >= bufLen || buf[idx] != 0x30)
        return -1;
    idx++;
    /* Skip SEQUENCE length (short or long form). */
    if (idx >= bufLen)
        return -1;
    if (buf[idx] < 0x80) {
        idx++;
    }
    else {
        word32 nbytes = (word32)(buf[idx] & 0x7F);
        if (nbytes == 0 || nbytes > 4 || idx + 1 + nbytes > bufLen)
            return -1;
        idx += 1 + nbytes;
    }
    /* algorithm OID tag. */
    if (idx >= bufLen || buf[idx] != 0x06)
        return -1;
    idx++;
    /* OID length (short or long form). */
    if (idx >= bufLen)
        return -1;
    if (buf[idx] < 0x80) {
        oidContentLen = buf[idx];
        idx++;
    }
    else {
        word32 nbytes = (word32)(buf[idx] & 0x7F);
        word32 i;
        if (nbytes == 0 || nbytes > 4 || idx + 1 + nbytes > bufLen)
            return -1;
        for (i = 0; i < nbytes; i++)
            oidContentLen = (oidContentLen << 8) | buf[idx + 1 + i];
        idx += 1 + nbytes;
    }
    if (oidContentLen == 0 || idx + oidContentLen > bufLen)
        return -1;
    *oidLastByte = idx + oidContentLen - 1;
    return 0;
}

/* Helper: load fixture, locate last byte of outer signatureAlgorithm
 * OID, patch it from `expected` to `swap`, and assert that verifying
 * the patched cert against itself as a trust anchor fails. */
static int rfc9802_assert_oid_patch_breaks_verify(const char* path,
    byte expectedLastByte, byte patchedLastByte)
{
    EXPECT_DECLS;
    byte*                 buf = NULL;
    int                   bytes = 0;
    DecodedCert           cert;
    WOLFSSL_CERT_MANAGER* cm = NULL;
    word32                sigIndex = 0;
    word32                lastOidByte = 0;

    ExpectIntEQ(rfc9802_load_file(path, &buf, &bytes), TEST_SUCCESS);
    if (buf == NULL)
        return TEST_FAIL;

    wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL);
    ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
    sigIndex = cert.sigIndex;
    wc_FreeDecodedCert(&cert);

    ExpectIntEQ(rfc9802_find_sig_alg_oid_last_byte(buf, (word32)bytes,
        sigIndex, &lastOidByte), 0);
    /* Sanity-check the fixture matches the family the caller asserted,
     * so a future regenerator swapping fixtures fails loudly here
     * rather than silently testing the wrong direction. */
    ExpectIntEQ((int)buf[lastOidByte], (int)expectedLastByte);

    if (lastOidByte < (word32)bytes &&
            buf[lastOidByte] == expectedLastByte) {
        buf[lastOidByte] = patchedLastByte;
        ExpectNotNull(cm = wolfSSL_CertManagerNew());
        /* After the patch the cert's outer signatureAlgorithm and SPKI
         * disagree. Verification must fail somewhere (at parse, at
         * load, or at ConfirmSignature). The load is best-effort -
         * some shape changes get caught there, others only at verify. */
        (void)wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes,
            WOLFSSL_FILETYPE_ASN1);
        ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, buf,
            (long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
        if (cm != NULL) {
            wolfSSL_CertManagerFree(cm);
            cm = NULL;
        }
    }

    XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    return EXPECT_RESULT();
}

/* X.509-level negative: swap the outer signatureAlgorithm OID byte so
 * the cert declares XMSS where the SPKI is XMSS^MT, and vice versa.
 * SigOidMatchesKeyOid must reject both directions before any crypto. */
static int rfc9802_xmss_sig_oid_mismatch(void)
{
    EXPECT_DECLS;
    /* XMSS sigOID ends 0x22; XMSS^MT sigOID ends 0x23. Patch each
     * direction so the asymmetric-key path is exercised both ways -
     * a regression that only stripped the check from one branch of
     * SigOidMatchesKeyOid would otherwise be missed. */
    ExpectIntEQ(rfc9802_assert_oid_patch_breaks_verify(
        "./certs/xmss/bc_xmss_sha2_10_256_root.der",
        /* expected XMSS */ 0x22, /* patched to XMSS^MT */ 0x23),
        TEST_SUCCESS);
    ExpectIntEQ(rfc9802_assert_oid_patch_breaks_verify(
        "./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der",
        /* expected XMSS^MT */ 0x23, /* patched to XMSS */ 0x22),
        TEST_SUCCESS);
    return EXPECT_RESULT();
}
#endif

/* Exercise a real CA -> leaf certificate chain, not just self-signed.
 * Loads the CA as a trust anchor and verifies the leaf against it. */
#if defined(WOLFSSL_HAVE_LMS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
static int rfc9802_lms_chain_verify(void)
{
    EXPECT_DECLS;
    byte*                 caBuf   = NULL;
    byte*                 leafBuf = NULL;
    int                   caLen   = 0;
    int                   leafLen = 0;
    WOLFSSL_CERT_MANAGER* cm      = NULL;

    ExpectIntEQ(rfc9802_load_file("./certs/lms/bc_lms_chain_ca.der",
        &caBuf, &caLen), TEST_SUCCESS);
    ExpectIntEQ(rfc9802_load_file("./certs/lms/bc_lms_chain_leaf.der",
        &leafBuf, &leafLen), TEST_SUCCESS);

    ExpectNotNull(cm = wolfSSL_CertManagerNew());
    /* Only the CA is a trust anchor; the leaf is verified against it. */
    ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    /* Without loading the CA the leaf must NOT verify. */
    if (cm != NULL) {
        wolfSSL_CertManagerFree(cm);
        cm = NULL;
    }
    ExpectNotNull(cm = wolfSSL_CertManagerNew());
    ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
    if (cm != NULL) {
        wolfSSL_CertManagerFree(cm);
        cm = NULL;
    }

    XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(caBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    return EXPECT_RESULT();
}
#endif

/* Mirror of rfc9802_lms_chain_verify but for an XMSS CA -> leaf pair. */
#if defined(WOLFSSL_HAVE_XMSS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
static int rfc9802_xmss_chain_verify(void)
{
    EXPECT_DECLS;
    byte*                 caBuf   = NULL;
    byte*                 leafBuf = NULL;
    int                   caLen   = 0;
    int                   leafLen = 0;
    WOLFSSL_CERT_MANAGER* cm      = NULL;

    ExpectIntEQ(rfc9802_load_file("./certs/xmss/bc_xmss_chain_ca.der",
        &caBuf, &caLen), TEST_SUCCESS);
    ExpectIntEQ(rfc9802_load_file("./certs/xmss/bc_xmss_chain_leaf.der",
        &leafBuf, &leafLen), TEST_SUCCESS);

    ExpectNotNull(cm = wolfSSL_CertManagerNew());
    ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

    if (cm != NULL) {
        wolfSSL_CertManagerFree(cm);
        cm = NULL;
    }
    ExpectNotNull(cm = wolfSSL_CertManagerNew());
    ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen,
        WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
    if (cm != NULL) {
        wolfSSL_CertManagerFree(cm);
        cm = NULL;
    }

    XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(caBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    return EXPECT_RESULT();
}
#endif

int test_rfc9802_lms_x509_verify(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_LMS)
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
    !defined(WOLFSSL_NO_LMS_SHA256_256)
    /* Mixed single-level LMS and multi-level HSS fixtures. The HSS
     * public key carries only the top-level LMS/LM-OTS types, so
     * wc_LmsKey_ImportPubRaw's auto-derive path searches the map
     * by (levels, lmsType, lmOtsType). The bc_lms_native_bc_root
     * fixture is generated through Bouncy Castle's stock
     * JcaContentSignerBuilder("LMS") + JcaX509v3CertificateBuilder
     * with no overrides; including it here is the cross-impl interop
     * gate (BC's native LMS X.509 path is RFC 9802-compliant for HSS/
     * LMS, so wolfSSL must accept it end-to-end).
     *
     * All fixtures use the SHA-256/M32 family, so the whole block
     * is gated on that family being compiled in. Truncated SHA-256/192
     * or SHAKE-only builds skip this block. */
    static const char* const lmsFiles[] = {
        "./certs/lms/bc_lms_sha256_h5_w4_root.der",
#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10)
        "./certs/lms/bc_lms_sha256_h10_w8_root.der",
#endif
#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 2)
        "./certs/lms/bc_hss_L2_H5_W8_root.der",
#endif
#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 3)
        "./certs/lms/bc_hss_L3_H5_W4_root.der",
#endif
        "./certs/lms/bc_lms_native_bc_root.der",
    };
    size_t i;
    for (i = 0; i < sizeof(lmsFiles) / sizeof(lmsFiles[0]); i++) {
        ExpectIntEQ(rfc9802_verify_one_cert(lmsFiles[i],
            HSS_LMSk, CTC_HSS_LMS), TEST_SUCCESS);
    }
    ExpectIntEQ(rfc9802_lms_chain_verify(), TEST_SUCCESS);
#endif /* !NO_FILESYSTEM && !NO_CERTS && !WOLFSSL_NO_LMS_SHA256_256 */
    /* Pure wolfCrypt-level negative tests don't need filesystem or cert
     * support, so they run for any LMS-enabled build. */
    ExpectIntEQ(rfc9802_lms_import_negative(), TEST_SUCCESS);
#endif
    return EXPECT_RESULT();
}

int test_rfc9802_xmss_x509_verify(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_XMSS)
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
    static const char* const xmssFiles[] = {
        "./certs/xmss/bc_xmss_sha2_10_256_root.der",
        "./certs/xmss/bc_xmss_sha2_16_256_root.der",
    };
    static const char* const xmssmtFiles[] = {
        "./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der",
        "./certs/xmss/bc_xmssmt_sha2_20_4_256_root.der",
        "./certs/xmss/bc_xmssmt_sha2_40_8_256_root.der",
    };
    size_t i;
    for (i = 0; i < sizeof(xmssFiles) / sizeof(xmssFiles[0]); i++) {
        ExpectIntEQ(rfc9802_verify_one_cert(xmssFiles[i],
            XMSSk, CTC_XMSS), TEST_SUCCESS);
    }
    for (i = 0; i < sizeof(xmssmtFiles) / sizeof(xmssmtFiles[0]); i++) {
        ExpectIntEQ(rfc9802_verify_one_cert(xmssmtFiles[i],
            XMSSMTk, CTC_XMSSMT), TEST_SUCCESS);
    }
    ExpectIntEQ(rfc9802_xmss_sig_oid_mismatch(), TEST_SUCCESS);
    ExpectIntEQ(rfc9802_xmss_chain_verify(), TEST_SUCCESS);
#endif /* !NO_FILESYSTEM && !NO_CERTS */
    /* Pure wolfCrypt-level negative tests don't need filesystem or cert
     * support, so they run for any XMSS-enabled build. */
    ExpectIntEQ(rfc9802_xmss_import_negative(), TEST_SUCCESS);
#endif
    return EXPECT_RESULT();
}

#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_CHAIN_INPUT)
static int test_sniffer_chain_input_overflow(void)
{
    EXPECT_DECLS;
    struct iovec chain[3];
    byte* data = NULL;
    char error[WOLFSSL_MAX_ERROR_SZ];
    int ret;
    byte dummy[1] = {0};

    /* Test 1: iov_len values that sum to more than INT_MAX.
     * Before the fix, these size_t values would be truncated when accumulated
     * into an int, causing an undersized allocation followed by an oversized
     * copy (heap buffer overflow). After the fix, the function should detect
     * the overflow and return an error without allocating or copying. */
    chain[0].iov_base = dummy;
    chain[0].iov_len  = (size_t)0x80000000UL; /* 2GB */
    chain[1].iov_base = dummy;
    chain[1].iov_len  = (size_t)0x80000000UL; /* 2GB */
    chain[2].iov_base = dummy;
    chain[2].iov_len  = (size_t)0x80000000UL; /* 2GB */

    XMEMSET(error, 0, sizeof(error));
    ret = ssl_DecodePacketWithChain(chain, 3, &data, error);
    ExpectIntEQ(ret, WOLFSSL_SNIFFER_ERROR);

    /* Test 2: total exactly at INT_MAX boundary should also be rejected since
     * it would require a ~2GB allocation that is unreasonable for a packet. */
    chain[0].iov_len = (size_t)0x7FFFFFFFUL; /* INT_MAX */
    chain[1].iov_len = (size_t)1;
    chain[2].iov_len = (size_t)0;

    XMEMSET(error, 0, sizeof(error));
    ret = ssl_DecodePacketWithChain(chain, 2, &data, error);
    ExpectIntEQ(ret, WOLFSSL_SNIFFER_ERROR);

    return EXPECT_RESULT();
}
#endif /* WOLFSSL_SNIFFER && WOLFSSL_SNIFFER_CHAIN_INPUT */

/* Test: wc_DhAgree must reject p-1 as peer public key.
 * ffdhe2048 p ends with ...FFFFFFFFFFFFFFFF so p-1 ends ...FFFFFFFFFFFFFFFE */
static int test_DhAgree_rejects_p_minus_1(void)
{
    EXPECT_DECLS;
#if !defined(HAVE_SELFTEST) && !defined(NO_DH) && \
    defined(HAVE_FFDHE_2048) && !defined(WOLFSSL_NO_MALLOC) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
    DhKey key;
    WC_RNG rng;
    byte priv[256], pub[256], agree[256];
    word32 privSz = sizeof(priv), pubSz = sizeof(pub), agreeSz;

    /* ffdhe2048 p - copied from wolfcrypt/src/dh.c dh_ffdhe2048_p.
     * p ends with 0xFF*8 so p-1 ends with ...0xFE */
    static const byte ffdhe2048_p[256] = {
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xAD,0xF8,0x54,0x58,0xA2,0xBB,0x4A,0x9A,
        0xAF,0xDC,0x56,0x20,0x27,0x3D,0x3C,0xF1,
        0xD8,0xB9,0xC5,0x83,0xCE,0x2D,0x36,0x95,
        0xA9,0xE1,0x36,0x41,0x14,0x64,0x33,0xFB,
        0xCC,0x93,0x9D,0xCE,0x24,0x9B,0x3E,0xF9,
        0x7D,0x2F,0xE3,0x63,0x63,0x0C,0x75,0xD8,
        0xF6,0x81,0xB2,0x02,0xAE,0xC4,0x61,0x7A,
        0xD3,0xDF,0x1E,0xD5,0xD5,0xFD,0x65,0x61,
        0x24,0x33,0xF5,0x1F,0x5F,0x06,0x6E,0xD0,
        0x85,0x63,0x65,0x55,0x3D,0xED,0x1A,0xF3,
        0xB5,0x57,0x13,0x5E,0x7F,0x57,0xC9,0x35,
        0x98,0x4F,0x0C,0x70,0xE0,0xE6,0x8B,0x77,
        0xE2,0xA6,0x89,0xDA,0xF3,0xEF,0xE8,0x72,
        0x1D,0xF1,0x58,0xA1,0x36,0xAD,0xE7,0x35,
        0x30,0xAC,0xCA,0x4F,0x48,0x3A,0x79,0x7A,
        0xBC,0x0A,0xB1,0x82,0xB3,0x24,0xFB,0x61,
        0xD1,0x08,0xA9,0x4B,0xB2,0xC8,0xE3,0xFB,
        0xB9,0x6A,0xDA,0xB7,0x60,0xD7,0xF4,0x68,
        0x1D,0x4F,0x42,0xA3,0xDE,0x39,0x4D,0xF4,
        0xAE,0x56,0xED,0xE7,0x63,0x72,0xBB,0x19,
        0x0B,0x07,0xA7,0xC8,0xEE,0x0A,0x6D,0x70,
        0x9E,0x02,0xFC,0xE1,0xCD,0xF7,0xE2,0xEC,
        0xC0,0x34,0x04,0xCD,0x28,0x34,0x2F,0x61,
        0x91,0x72,0xFE,0x9C,0xE9,0x85,0x83,0xFF,
        0x8E,0x4F,0x12,0x32,0xEE,0xF2,0x81,0x83,
        0xC3,0xFE,0x3B,0x1B,0x4C,0x6F,0xAD,0x73,
        0x3B,0xB5,0xFC,0xBC,0x2E,0xC2,0x20,0x05,
        0xC5,0x8E,0xF1,0x83,0x7D,0x16,0x83,0xB2,
        0xC6,0xF3,0x4A,0x26,0xC1,0xB2,0xEF,0xFA,
        0x88,0x6B,0x42,0x38,0x61,0x28,0x5C,0x97,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
    };
    byte pMinus1[256];

    XMEMSET(&key, 0, sizeof(DhKey));
    XMEMSET(&rng, 0, sizeof(WC_RNG));

    ExpectIntEQ(wc_InitRng(&rng), 0);
    ExpectIntEQ(wc_InitDhKey(&key), 0);
    ExpectIntEQ(wc_DhSetNamedKey(&key, WC_FFDHE_2048), 0);
    ExpectIntEQ(wc_DhGenerateKeyPair(&key, &rng, priv, &privSz,
                                      pub, &pubSz), 0);

    /* Construct p-1: last byte FF -> FE */
    XMEMCPY(pMinus1, ffdhe2048_p, sizeof(ffdhe2048_p));
    pMinus1[255] -= 1;

    /* wc_DhAgree must reject p-1 */
    agreeSz = sizeof(agree);
    ExpectIntNE(wc_DhAgree(&key, agree, &agreeSz, priv, privSz,
                            pMinus1, sizeof(pMinus1)), 0);

    wc_FreeDhKey(&key);
    wc_FreeRng(&rng);
#endif
    return EXPECT_RESULT();
}


/* ML-DSA HashML-DSA verify must reject hashLen > WC_MAX_DIGEST_SIZE */
static int test_mldsa_verify_hash(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_MLDSA) && \
    !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \
    !defined(WOLFSSL_MLDSA_NO_VERIFY)
    wc_MlDsaKey key;
    WC_RNG rng;
    int res = 0;
    byte sig[4000];
    byte hash[4096]; /* larger than WC_MAX_DIGEST_SIZE */

    XMEMSET(&key, 0, sizeof(key));
    XMEMSET(&rng, 0, sizeof(rng));
    XMEMSET(sig, 0x41, sizeof(sig));
    XMEMSET(hash, 'A', sizeof(hash));

    ExpectIntEQ(wc_InitRng(&rng), 0);
    ExpectIntEQ(wc_MlDsaKey_Init(&key, NULL, INVALID_DEVID), 0);
#ifndef WOLFSSL_NO_ML_DSA_65
    ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_65), 0);
#elif !defined(WOLFSSL_NO_ML_DSA_44)
    ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_44), 0);
#else
    ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_87), 0);
#endif
    ExpectIntEQ(wc_MlDsaKey_MakeKey(&key, &rng), 0);

    /* hashLen=4096 must be rejected, not overflow the stack */
    ExpectIntEQ(wc_MlDsaKey_VerifyCtxHash(&key, sig, sizeof(sig), NULL, 0,
        hash, sizeof(hash), WC_HASH_TYPE_SHA256, &res),
        WC_NO_ERR_TRACE(BAD_LENGTH_E));

    wc_MlDsaKey_Free(&key);
    DoExpectIntEQ(wc_FreeRng(&rng), 0);
#endif
    return EXPECT_RESULT();
}

/* Test: Ed448 must reject identity public key (0,1) */
static int test_ed448_rejects_identity_key(void)
{
    EXPECT_DECLS;
#if defined(HAVE_ED448) && !defined(HAVE_SELFTEST) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0))
    ed448_key key;
    byte identity[ED448_PUB_KEY_SIZE];
    byte forged_sig[ED448_SIG_SIZE];
    const byte msg[] = "test message";
    int res = 0;

    XMEMSET(identity, 0, sizeof(identity));
    identity[0] = 0x01;  /* identity (0,1) encoding */

    XMEMSET(forged_sig, 0, sizeof(forged_sig));
    forged_sig[0] = 0x01;  /* R = identity, S = 0 */

    ExpectIntEQ(wc_ed448_init(&key), 0);

    /* The identity public key must be rejected at import time. */
    ExpectIntNE(wc_ed448_import_public(identity, sizeof(identity), &key), 0);

    /* If import somehow succeeded, verify must also reject the forgery. */
    if (EXPECT_SUCCESS() && key.pubKeySet) {
        int verifyRet = wc_ed448_verify_msg(forged_sig, sizeof(forged_sig),
                                             msg, sizeof(msg) - 1,
                                             &res, &key, NULL, 0);
        ExpectTrue(verifyRet != 0 || res == 0);
    }

    wc_ed448_free(&key);
#endif
    return EXPECT_RESULT();
}

/* Test: wc_PKCS7_DecodeEncryptedData must respect outputSz.
 * 588-byte EncryptedData blob: 496 bytes of 'A' encrypted with
 * AES-256-CBC under all-zero key/IV. Decrypted content is 496 bytes,
 * but we pass a 128-byte output buffer. Must return BUFFER_E. */
static int test_pkcs7_decode_encrypted_outputsz(void)
{
    EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
    !defined(WOLFSSL_NO_MALLOC) && defined(WOLFSSL_AES_256)
    wc_PKCS7* p7 = NULL;
    byte key[32];
    byte out[128]; /* smaller than 496-byte decrypted content */

    static const byte encBlob[] = {
        0x30,0x82,0x02,0x48,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
        0x01,0x07,0x06,0xa0,0x82,0x02,0x39,0x30,0x82,0x02,0x35,0x02,
        0x01,0x00,0x30,0x82,0x02,0x2e,0x06,0x09,0x2a,0x86,0x48,0x86,
        0xf7,0x0d,0x01,0x07,0x01,0x30,0x1d,0x06,0x09,0x60,0x86,0x48,
        0x01,0x65,0x03,0x04,0x01,0x2a,0x04,0x10,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x80,0x82,0x02,0x00,0x7e,0x0e,0x75,0x77,0xef,0x9c,0x30,0xa6,
        0xbf,0x0b,0x25,0xe0,0x62,0x1e,0x82,0x7e,0x76,0xf7,0x57,0xef,
        0x12,0x71,0xc5,0x74,0x0e,0x60,0xc3,0x3c,0x8e,0xc3,0xce,0x70,
        0xbd,0x3c,0xb4,0x60,0x76,0xb1,0xea,0xb5,0x4b,0xc1,0xfe,0x5b,
        0x88,0xfa,0x43,0x46,0x03,0x28,0x9d,0xab,0x3d,0xb5,0x88,0x50,
        0x07,0xfc,0x3c,0xc9,0x49,0x4d,0x68,0x97,0xb1,0x59,0xb6,0x35,
        0xa1,0x68,0x80,0xb0,0x8f,0xb2,0x21,0x9b,0xfc,0xd8,0xf0,0x67,
        0xbc,0x4b,0x9b,0x28,0x1c,0x3b,0xa0,0x40,0x76,0x8f,0x1f,0x9f,
        0x87,0xe6,0xe4,0xa5,0xdc,0x9a,0x9a,0x84,0x86,0xff,0x43,0x8a,
        0x57,0x8d,0x97,0xd2,0x8f,0x67,0x90,0xd8,0x4f,0x0f,0x0d,0xac,
        0x56,0x6d,0x51,0x33,0xa3,0x37,0x9e,0xe9,0xbf,0x07,0xab,0x93,
        0xbc,0xbe,0xc1,0x64,0x07,0x30,0xf0,0xff,0x89,0x0a,0x36,0x1c,
        0xc8,0xe9,0xae,0x24,0x1f,0x95,0x5c,0xa1,0x8a,0x3e,0x15,0x86,
        0x49,0x70,0x55,0xc2,0xa5,0x90,0xb9,0xda,0x2b,0x97,0x6f,0x5f,
        0x60,0x61,0xc9,0xcf,0x4d,0x3a,0xb1,0xe4,0x9f,0x37,0x0f,0xf3,
        0xba,0x85,0x04,0x52,0x68,0x00,0x47,0x3d,0x83,0xc1,0x3f,0xc6,
        0x70,0x97,0xc1,0x0c,0xc0,0x0b,0xa2,0xcb,0x8c,0x88,0xb5,0x01,
        0x29,0x7f,0x7e,0xd2,0x46,0x24,0x82,0x92,0x28,0xdd,0x49,0x53,
        0x0f,0x76,0xad,0x4b,0x81,0x85,0x3a,0x9f,0xda,0x0d,0x69,0xe2,
        0x57,0xb9,0xe9,0xfa,0x53,0xed,0x20,0x6f,0x62,0x43,0x1d,0x21,
        0xa9,0x53,0x3d,0xd5,0xb9,0x1a,0x4b,0x3e,0xb7,0x05,0x87,0xb6,
        0xe3,0xfe,0x03,0x09,0xe1,0x74,0x34,0x42,0x84,0xb1,0x06,0xf9,
        0xfe,0x64,0xc1,0xd2,0xce,0x3d,0x29,0xf4,0x94,0xb8,0xfc,0xbe,
        0xb1,0x90,0xd6,0x38,0x61,0x4e,0x43,0x36,0x4e,0x27,0x87,0xd3,
        0x24,0xdc,0x34,0xf0,0x28,0x2d,0xc8,0xff,0x89,0x9f,0xeb,0xee,
        0x0d,0x45,0xfb,0xc5,0x53,0xd3,0xdf,0xcb,0xf8,0xeb,0x7e,0xcb,
        0x2a,0xd7,0xa2,0xd6,0x6a,0xf1,0xb8,0x24,0xa1,0x05,0x16,0x56,
        0x2e,0x03,0xfe,0x21,0x19,0x36,0x8a,0xeb,0x50,0x8d,0x42,0x31,
        0x1d,0xb3,0x0a,0x13,0x1d,0x16,0x09,0x0b,0x40,0x4e,0x90,0x78,
        0xbf,0x41,0x5f,0x4d,0xd9,0xce,0x91,0xaa,0xd0,0x38,0x5c,0xfb,
        0xc4,0x9f,0x55,0x4e,0x04,0x9d,0xd0,0xca,0x74,0x3c,0x6c,0x01,
        0x1b,0x84,0x76,0xfa,0xba,0x5d,0x2d,0x35,0x7e,0xe3,0x37,0x8b,
        0x72,0x0a,0xbb,0xa4,0x4d,0x56,0x2b,0x3b,0x9f,0x5a,0xa0,0xe3,
        0x60,0x26,0x65,0x09,0xed,0xfc,0x10,0x0c,0xa1,0x4f,0x12,0x76,
        0xe2,0x4c,0xbd,0x1b,0x67,0xb4,0xb4,0x54,0x5c,0x38,0x47,0x8b,
        0x7e,0x35,0x8e,0x4d,0x4e,0xef,0x91,0x3f,0xff,0x16,0x0a,0x42,
        0x0b,0xe5,0x28,0x26,0x24,0x9f,0x6f,0xb4,0x63,0x8a,0xa1,0x52,
        0x22,0x3a,0xdb,0xd9,0x8e,0x76,0x6e,0x6a,0xa9,0xa1,0xec,0xf2,
        0x9c,0x58,0xf8,0x6b,0xdd,0xf2,0xf8,0x2d,0xcb,0x8c,0x96,0xda,
        0xb4,0x9c,0x44,0xdc,0xab,0x43,0x2c,0x22,0xf3,0xfe,0x1a,0xb9,
        0x3b,0x82,0x30,0xa2,0xc7,0xef,0x52,0x08,0x7b,0x4f,0x3f,0x7a,
        0x7e,0x28,0xd7,0x67,0xb9,0xb1,0x69,0x9b,0x96,0x3e,0xc5,0xe4,
        0x45,0xb0,0x23,0x75,0x00,0xda,0xee,0xdb,0x6d,0xa9,0xe7,0x98
    };

    XMEMSET(key, 0, sizeof(key));

    p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
    ExpectNotNull(p7);
    if (p7 != NULL) {
        p7->encryptionKey = key;
        p7->encryptionKeySz = sizeof(key);

        /* 496-byte content into 128-byte buffer must return BUFFER_E */
        ExpectIntLT(wc_PKCS7_DecodeEncryptedData(p7, (byte*)encBlob,
                    (word32)sizeof(encBlob), out, sizeof(out)), 0);

        wc_PKCS7_Free(p7);
    }
#endif
    return EXPECT_RESULT();
}

/* Dummy ORI callback for PKCS#7 ORI overflow test */
#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC)
static int test_dummy_ori_cb(wc_PKCS7* pkcs7, byte* oriType, word32 oriTypeSz,
                              byte* oriValue, word32 oriValueSz,
                              byte* decryptedKey, word32* decryptedKeySz,
                              void* ctx)
{
    (void)pkcs7; (void)oriType; (void)oriTypeSz;
    (void)oriValue; (void)oriValueSz;
    (void)decryptedKey; (void)decryptedKeySz; (void)ctx;
    return -1;
}
#endif

/* Test: PKCS#7 ORI must reject OID larger than MAX_OID_SZ (32) */
static int test_pkcs7_ori_oversized_oid(void)
{
    EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC)
    wc_PKCS7* p7 = NULL;
    byte out[256];

    /* EnvelopedData with [4] IMPLICIT ORI containing an 80-byte OID */
    static const byte poc[] = {
        0x30, 0x6b,
          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
          0xa0, 0x5e,
            0x30, 0x5c,
              0x02, 0x01, 0x00,
              0x31, 0x57,
                0xa4, 0x55,
                  0x06, 0x50,
                    0x2a,
                    0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                    0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                    0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                    0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                    0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                    0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                    0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                    0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                  0x04, 0x01, 0x00
    };

    p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
    ExpectNotNull(p7);
    if (p7 != NULL) {
        wc_PKCS7_SetOriDecryptCb(p7, test_dummy_ori_cb);

        /* Must return error (ASN_PARSE_E), not overflow the stack */
        ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
                                                  out, sizeof(out)), 0);

        wc_PKCS7_Free(p7);
    }
#endif
    return EXPECT_RESULT();
}

/* ORI callback that flags if oriValueSz looks like an underflow (>= 0x80000000) */
#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC)
static int test_ori_underflow_cb(wc_PKCS7* pkcs7, byte* oriType,
                                 word32 oriTypeSz, byte* oriValue,
                                 word32 oriValueSz, byte* decryptedKey,
                                 word32* decryptedKeySz, void* ctx)
{
    int* called = (int*)ctx;
    (void)pkcs7; (void)oriType; (void)oriTypeSz;
    (void)oriValue; (void)decryptedKey; (void)decryptedKeySz;
    if (called != NULL)
        *called = (int)oriValueSz;  /* record what we received */
    return -1;
}
#endif

/* Test: PKCS#7 ORI must reject when OID consumption exceeds the [4] implicit
 * SEQUENCE length (integer underflow in oriValueSz computation).
 *
 * With implicit tagging, [4] CONSTRUCTED replaces the SEQUENCE tag, so
 * wc_PKCS7_DecryptOri reads seqSz directly from the [4] length field.
 * We set [4] length = 5 while the OID inside consumes 22 bytes
 * (tag + length + 20 content), triggering oriValueSz = 5 - 22 = underflow.
 *
 * The buffer includes a dummy EncryptedContentInfo after the RecipientInfos
 * so the total message is large enough for the PKCS7 streaming code (which
 * requests the full remaining message before parsing the ORI). */
static int test_pkcs7_ori_seqsz_underflow(void)
{
    EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC)
    wc_PKCS7* p7 = NULL;
    byte out[256];
    int cbCalled = 0;

    /*
     * Byte layout (all outer lengths match actual byte counts on wire):
     *
     * OID inside [4]: 06 14 <20 bytes>                  = 22 bytes
     * [4] (declared len 5, actual content 22):
     *   a4 05 <22 bytes>                                = 24 bytes on wire
     * SET: 31 18 <24 bytes>                             = 26 bytes on wire
     * version: 02 01 00                                 = 3 bytes
     * EncryptedContentInfo (filler, never parsed):
     *   30 0b { 06 09 <9 bytes OID> }                   = 13 bytes on wire
     * EnvelopedData: 30 2a <3+26+13=42 bytes>           = 44 bytes on wire
     * [0] EXPLICIT: a0 2c <44 bytes>                    = 46 bytes on wire
     * OID(envelopedData): 06 09 <9 bytes>               = 11 bytes on wire
     * ContentInfo: 30 39 <11+46=57 bytes>               = 59 bytes total
     */
    static const byte poc[] = {
        /* ContentInfo SEQUENCE (length 57) */
        0x30, 0x39,
          /* contentType = envelopedData 1.2.840.113549.1.7.3 */
          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
          /* [0] EXPLICIT (length 44) */
          0xa0, 0x2c,
            /* EnvelopedData SEQUENCE (length 42) */
            0x30, 0x2a,
              /* version = 0 */
              0x02, 0x01, 0x00,
              /* RecipientInfos SET (length 24) */
              0x31, 0x18,
                /* [4] CONSTRUCTED = ORI implicit SEQUENCE, declared len 5 */
                /* Actual OID is 22 bytes -> exceeds declared 5 */
                0xa4, 0x05,
                  /* OID: tag=06, len=0x14(20), content=20 bytes = 22 total */
                  0x06, 0x14,
                  0x2a, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
                  0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
                  0x12, 0x13, 0x14, 0x15,
              /* EncryptedContentInfo SEQUENCE (length 11) - filler so
               * streaming has enough data; never actually parsed because
               * DecryptOri fails before we get here */
              0x30, 0x0b,
                /* contentType = data 1.2.840.113549.1.7.1 */
                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
                0x01
    };

    p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
    ExpectNotNull(p7);
    if (p7 != NULL) {
        wc_PKCS7_SetOriDecryptCb(p7, test_ori_underflow_cb);
        wc_PKCS7_SetOriDecryptCtx(p7, &cbCalled);

        /* Must return an error before the callback sees an underflowed size */
        ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
                                                  out, sizeof(out)), 0);

        /* The callback must NOT have been invoked with a wrapped oriValueSz.
         * cbCalled == 0 means the callback was never reached (ideal).
         * cbCalled < 0 would indicate the underflow was passed through. */
        ExpectIntGE(cbCalled, 0);

        wc_PKCS7_Free(p7);
    }
#endif
    return EXPECT_RESULT();
}

/* Test: PKCS#7 ORI must reject when seqSz extends oriValue past input buffer.
 *
 * The first ORI bounds check (OID exceeds SEQUENCE boundary) is covered by
 * test_pkcs7_ori_seqsz_underflow. This test covers the *second* check:
 * oriValue region extends past the end of the input buffer. We craft a
 * message where the [4] SEQUENCE length is valid relative to the OID
 * (OID fits inside it), but the remaining oriValue portion extends past
 * the end of the actual input buffer.
 *
 * To bypass GetLength's own bounds validation, we set the outer lengths
 * (EnvelopedData SEQUENCE, RecipientInfos SET) to match the [4] claim,
 * but truncate the actual buffer we pass to DecodeEnvelopedData. */
static int test_pkcs7_ori_orivalue_overflow(void)
{
    EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC)
    wc_PKCS7* p7 = NULL;
    byte out[256];

    /* EnvelopedData with [4] ORI whose seqSz (40) is valid for the OID
     * (6 bytes consumed) but oriValueSz (34) extends past the truncated
     * input buffer.
     *
     * Layout:
     * ContentInfo SEQUENCE
     *   OID envelopedData
     *   [0] EXPLICIT
     *     EnvelopedData SEQUENCE
     *       version = 0
     *       RecipientInfos SET
     *         [4] CONSTRUCTED (seqSz = 40)
     *           OID (tag 06, len 04, 4 content bytes = 6 total)
     *           oriValue should be 34 bytes but input is truncated
     *       EncryptedContentInfo (filler for streaming)
     *
     * We pass the full array to DecodeEnvelopedData, but the actual
     * input ends before [4]'s declared 40 bytes are consumed.
     */
    static const byte poc[] = {
        /* ContentInfo SEQUENCE */
        0x30, 0x43,
          /* contentType = envelopedData 1.2.840.113549.1.7.3 */
          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
          /* [0] EXPLICIT */
          0xa0, 0x36,
            /* EnvelopedData SEQUENCE */
            0x30, 0x34,
              /* version = 0 */
              0x02, 0x01, 0x00,
              /* RecipientInfos SET (len = 44 covers [4] tag+len+40) */
              0x31, 0x2c,
                /* [4] CONSTRUCTED = ORI implicit SEQUENCE, seqSz = 40 */
                0xa4, 0x28,
                  /* OID: tag=06, len=04, 4 content bytes = 6 total */
                  0x06, 0x04, 0x2a, 0x03, 0x04, 0x05,
                  /* Only 4 bytes of oriValue here, but seqSz claims 34 more */
                  0x00, 0x00, 0x00, 0x00,
              /* EncryptedContentInfo SEQUENCE (filler) */
              0x30, 0x0b,
                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
                0x01
    };

    p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
    ExpectNotNull(p7);
    if (p7 != NULL) {
        wc_PKCS7_SetOriDecryptCb(p7, test_dummy_ori_cb);

        /* Must return error - oriValue extends past input buffer */
        ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
                                                  out, sizeof(out)), 0);

        wc_PKCS7_Free(p7);
    }
#endif
    return EXPECT_RESULT();
}

/* Test: PKCS#7 KTRI must not match recipient when SKID length differs
 * from expected keyIdSize.
 *
 * The fix adds a `length == keyIdSize` check before comparing the SKID
 * bytes. Without this check, XMEMCMP could compare against data beyond
 * the SKID content. This test crafts a KTRI RecipientInfo where the
 * [0] SubjectKeyIdentifier has length 5 instead of KEYID_SIZE (20).
 * The decode must return an error (no matching recipient). */
static int test_pkcs7_ktri_skid_length_mismatch(void)
{
    EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(WOLFSSL_NO_MALLOC)
    wc_PKCS7* p7 = NULL;
    byte out[256];

    /* Minimal EnvelopedData with KTRI using version=2 (SKID path).
     * The SKID [0] has length 5 instead of 20.
     *
     * ContentInfo SEQUENCE
     *   OID envelopedData
     *   [0] EXPLICIT
     *     EnvelopedData SEQUENCE
     *       version = 2
     *       RecipientInfos SET
     *         KTRI SEQUENCE
     *           version = 2
     *           [0] SKID (5 bytes, should be 20)
     *           AlgorithmIdentifier (RSA OID)
     *           OCTET STRING (fake encrypted key)
     *       EncryptedContentInfo (filler)
     */
    static const byte poc[] = {
        /* ContentInfo SEQUENCE */
        0x30, 0x46,
          /* contentType = envelopedData 1.2.840.113549.1.7.3 */
          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
          /* [0] EXPLICIT */
          0xa0, 0x39,
            /* EnvelopedData SEQUENCE */
            0x30, 0x37,
              /* version = 2 (triggers SKID-based recipient identification) */
              0x02, 0x01, 0x02,
              /* RecipientInfos SET */
              0x31, 0x21,
                /* KTRI SEQUENCE */
                0x30, 0x1f,
                  /* version = 2 (SKID) */
                  0x02, 0x01, 0x02,
                  /* [0] IMPLICIT SubjectKeyIdentifier, length = 5 (wrong!) */
                  0x80, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05,
                  /* AlgorithmIdentifier: RSA 1.2.840.113549.1.1.1 */
                  0x30, 0x0d,
                    0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
                    0x01, 0x01, 0x01,
                    0x05, 0x00, /* NULL params */
                  /* encryptedKey OCTET STRING (2 bytes fake) */
                  0x04, 0x02, 0xAA, 0xBB,
              /* EncryptedContentInfo SEQUENCE (filler) */
              0x30, 0x0b,
                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
                0x01
    };

    p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
    ExpectNotNull(p7);
    if (p7 != NULL) {
        /* Decode without a cert - SKID will never match, and the
         * mismatched SKID length must not cause out-of-bounds reads */
        ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
                                                  out, sizeof(out)), 0);

        wc_PKCS7_Free(p7);
    }
#endif
    return EXPECT_RESULT();
}

/* Test: PKCS#7 KARI must reject BIT STRING with length < 2 in
 * OriginatorPublicKey.
 *
 * The fix adds `if (length < 2) return ASN_PARSE_E` after parsing
 * the BIT STRING tag and length. A BIT STRING must have at least
 * the unused-bits byte plus one byte of content. This test crafts
 * a KARI [1] RecipientInfo where the OriginatorPublicKey's BIT STRING
 * has length 1 (degenerate). The PKCS7 object is initialized with a
 * real ECC cert so that KariParseRecipCert succeeds and parsing reaches
 * the BIT STRING validation. */
static int test_pkcs7_kari_degenerate_bitstring(void)
{
    EXPECT_DECLS;
#if defined(HAVE_PKCS7) && defined(HAVE_ECC) && defined(HAVE_X963_KDF) && \
    !defined(WOLFSSL_NO_MALLOC)
    wc_PKCS7* p7 = NULL;
    byte out[256];
    byte* eccCert = NULL;
    byte* eccPrivKey = NULL;
    word32 eccCertSz = 0;
    word32 eccPrivKeySz = 0;
#if !defined(USE_CERT_BUFFERS_256) && !defined(NO_FILESYSTEM)
    XFILE f = XBADFILE;
#endif

    /* Minimal EnvelopedData with KARI [1] containing a degenerate
     * BIT STRING (length 1) in OriginatorPublicKey.
     *
     * ContentInfo SEQUENCE
     *   OID envelopedData
     *   [0] EXPLICIT
     *     EnvelopedData SEQUENCE
     *       version = 2
     *       RecipientInfos SET
     *         [1] CONSTRUCTED (KARI)
     *           version = 3
     *           [0] CONSTRUCTED (OriginatorIdentifierOrKey)
     *             [1] CONSTRUCTED (OriginatorPublicKey)
     *               AlgorithmIdentifier (ECDSAk)
     *               BIT STRING length=1 (degenerate!)
     *       EncryptedContentInfo (filler)
     */
    static const byte poc[] = {
        /* ContentInfo SEQUENCE */
        0x30, 0x44,
          /* contentType = envelopedData 1.2.840.113549.1.7.3 */
          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
          /* [0] EXPLICIT */
          0xa0, 0x37,
            /* EnvelopedData SEQUENCE */
            0x30, 0x35,
              /* version = 2 */
              0x02, 0x01, 0x02,
              /* RecipientInfos SET */
              0x31, 0x1f,
                /* [1] CONSTRUCTED (KARI implicit) */
                0xa1, 0x1d,
                  /* version = 3 */
                  0x02, 0x01, 0x03,
                  /* [0] CONSTRUCTED (OriginatorIdentifierOrKey) */
                  0xa0, 0x18,
                    /* [1] CONSTRUCTED (OriginatorPublicKey) */
                    0xa1, 0x16,
                      /* AlgorithmIdentifier SEQUENCE */
                      0x30, 0x13,
                        /* OID: id-ecPublicKey 1.2.840.10045.2.1 */
                        0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
                        /* OID: prime256v1 1.2.840.10045.3.1.7 */
                        0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03,
                        0x01, 0x07,
                      /* BIT STRING with length 1 - degenerate! */
                      0x03, 0x01, 0x00,
              /* EncryptedContentInfo SEQUENCE (filler) */
              0x30, 0x0b,
                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
                0x01
    };

    /* Load ECC cert and key so KariParseRecipCert succeeds and
     * parsing reaches the BIT STRING check */
#ifdef USE_CERT_BUFFERS_256
    eccCertSz = (word32)sizeof_cliecc_cert_der_256;
    ExpectNotNull(eccCert = (byte*)XMALLOC(eccCertSz, HEAP_HINT,
        DYNAMIC_TYPE_TMP_BUFFER));
    if (eccCert != NULL)
        XMEMCPY(eccCert, cliecc_cert_der_256, eccCertSz);
    eccPrivKeySz = (word32)sizeof_ecc_clikey_der_256;
    ExpectNotNull(eccPrivKey = (byte*)XMALLOC(eccPrivKeySz, HEAP_HINT,
        DYNAMIC_TYPE_TMP_BUFFER));
    if (eccPrivKey != NULL)
        XMEMCPY(eccPrivKey, ecc_clikey_der_256, eccPrivKeySz);
#elif !defined(NO_FILESYSTEM)
    eccCertSz = FOURK_BUF;
    ExpectNotNull(eccCert = (byte*)XMALLOC(eccCertSz, HEAP_HINT,
        DYNAMIC_TYPE_TMP_BUFFER));
    ExpectTrue((f = XFOPEN("./certs/client-ecc-cert.der", "rb")) != XBADFILE);
    ExpectTrue((eccCertSz = (word32)XFREAD(eccCert, 1, eccCertSz, f)) > 0);
    if (f != XBADFILE) {
        XFCLOSE(f);
        f = XBADFILE;
    }
    eccPrivKeySz = FOURK_BUF;
    ExpectNotNull(eccPrivKey = (byte*)XMALLOC(eccPrivKeySz, HEAP_HINT,
        DYNAMIC_TYPE_TMP_BUFFER));
    ExpectTrue((f = XFOPEN("./certs/ecc-client-key.der", "rb")) != XBADFILE);
    ExpectTrue((eccPrivKeySz = (word32)XFREAD(eccPrivKey, 1, eccPrivKeySz,
        f)) > 0);
    if (f != XBADFILE)
        XFCLOSE(f);
#else
    eccCert = NULL;
    eccCertSz = 0;
    eccPrivKey = NULL;
    eccPrivKeySz = 0;
#endif

    p7 = wc_PKCS7_New(HEAP_HINT, INVALID_DEVID);
    ExpectNotNull(p7);
    if (p7 != NULL && eccCert != NULL) {
        ExpectIntEQ(wc_PKCS7_InitWithCert(p7, eccCert, eccCertSz), 0);
        if (p7 != NULL) {
            p7->privateKey = eccPrivKey;
            p7->privateKeySz = eccPrivKeySz;
        }

        /* Must return error - BIT STRING length < 2 is invalid */
        ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
                                                  out, sizeof(out)), 0);

        if (p7 != NULL) {
            p7->privateKey = NULL;
            p7->privateKeySz = 0;
        }
        wc_PKCS7_Free(p7);
    }
    else if (p7 != NULL) {
        wc_PKCS7_Free(p7);
    }

    XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(eccPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
#endif
    return EXPECT_RESULT();
}

/* Test: PKCS#7 EncryptedData must reject when encryptedContentSz exceeds
 * the remaining input buffer.
 *
 * The fix adds `encryptedContentSz > (int)(pkiMsgSz - idx)` to the
 * existing `encryptedContentSz <= 0` check in stage 6. This test crafts
 * a minimal EncryptedData where the [0] IMPLICIT content length claims
 * 0x200 (512) bytes but only 32 bytes of ciphertext are present. */
static int test_pkcs7_encrypted_content_size_overflow(void)
{
    EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
    defined(WOLFSSL_AES_256) && !defined(NO_PKCS7_ENCRYPTED_DATA) && \
    !defined(WOLFSSL_NO_MALLOC)
    wc_PKCS7* p7 = NULL;
    byte key[32];
    byte out[256];

    /* EncryptedData with [0] content claiming 512 bytes but only 32 present.
     *
     * ContentInfo SEQUENCE
     *   OID encryptedData (1.2.840.113549.1.7.6)
     *   [0] EXPLICIT
     *     EncryptedData SEQUENCE
     *       version = 0
     *       EncryptedContentInfo SEQUENCE
     *         OID data (1.2.840.113549.1.7.1)
     *         AlgorithmIdentifier
     *           OID AES-256-CBC (2.16.840.1.101.3.4.1.42)
     *           OCTET STRING IV (16 zero bytes)
     *         [0] IMPLICIT content (claimed len=0x200, actual=32 bytes)
     */
    static const byte poc[] = {
        /* ContentInfo SEQUENCE (len covers entire message) */
        0x30, 0x50,
          /* OID encryptedData 1.2.840.113549.1.7.6 */
          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06,
          /* [0] EXPLICIT */
          0xa0, 0x43,
            /* EncryptedData SEQUENCE */
            0x30, 0x41,
              /* version = 0 */
              0x02, 0x01, 0x00,
              /* EncryptedContentInfo SEQUENCE */
              0x30, 0x3c,
                /* OID data 1.2.840.113549.1.7.1 */
                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
                0x01,
                /* AlgorithmIdentifier SEQUENCE */
                0x30, 0x1d,
                  /* OID AES-256-CBC 2.16.840.1.101.3.4.1.42 */
                  0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01,
                  0x2a,
                  /* IV: OCTET STRING (16 zero bytes) */
                  0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                /* [0] IMPLICIT encryptedContent - claims 512 bytes!
                 * Only 16 bytes of fake ciphertext follow. */
                0x80, 0x82, 0x02, 0x00,
                0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
                0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
    };

    XMEMSET(key, 0, sizeof(key));

    p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
    ExpectNotNull(p7);
    if (p7 != NULL) {
        p7->encryptionKey = key;
        p7->encryptionKeySz = sizeof(key);

        /* Must return error - content extends past input buffer */
        ExpectIntLT(wc_PKCS7_DecodeEncryptedData(p7, (byte*)poc, sizeof(poc),
                                                  out, sizeof(out)), 0);

        wc_PKCS7_Free(p7);
    }
#endif
    return EXPECT_RESULT();
}

/* Test: PKCS#7 SignedData must reject when the signature field is not
 * an OCTET STRING.
 *
 * The fix adds `else if (ret == 0) { ret = ASN_PARSE_E; }` so that
 * when the tag at the signature position is not ASN_OCTET_STRING,
 * parsing returns an error instead of silently continuing with no
 * signature. This test encodes a valid SignedData, then corrupts
 * the signature OCTET STRING tag and verifies that decode fails. */
static int test_pkcs7_signed_bad_sig_tag(void)
{
    EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \
    !defined(WOLFSSL_NO_MALLOC)
    PKCS7* pkcs7 = NULL;
    WC_RNG rng;
    byte  encoded[FOURK_BUF];
    int   encodedSz = 0;
    int   i;
    byte* rsaCert = NULL;
    byte* rsaPrivKey = NULL;
    word32 rsaCertSz = 0;
    word32 rsaPrivKeySz = 0;
#if !defined(USE_CERT_BUFFERS_2048) && !defined(USE_CERT_BUFFERS_1024) && \
    !defined(NO_FILESYSTEM)
    XFILE f = XBADFILE;
#endif

    const byte data[] = "Test signed data";

    XMEMSET(&rng, 0, sizeof(WC_RNG));

    /* Load RSA cert and key */
#if defined(USE_CERT_BUFFERS_2048)
    rsaCertSz = (word32)sizeof_client_cert_der_2048;
    ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
        DYNAMIC_TYPE_TMP_BUFFER));
    if (rsaCert != NULL)
        XMEMCPY(rsaCert, client_cert_der_2048, rsaCertSz);
    rsaPrivKeySz = (word32)sizeof_client_key_der_2048;
    ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
        DYNAMIC_TYPE_TMP_BUFFER));
    if (rsaPrivKey != NULL)
        XMEMCPY(rsaPrivKey, client_key_der_2048, rsaPrivKeySz);
#elif defined(USE_CERT_BUFFERS_1024)
    rsaCertSz = (word32)sizeof_client_cert_der_1024;
    ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
        DYNAMIC_TYPE_TMP_BUFFER));
    if (rsaCert != NULL)
        XMEMCPY(rsaCert, client_cert_der_1024, rsaCertSz);
    rsaPrivKeySz = (word32)sizeof_client_key_der_1024;
    ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
        DYNAMIC_TYPE_TMP_BUFFER));
    if (rsaPrivKey != NULL)
        XMEMCPY(rsaPrivKey, client_key_der_1024, rsaPrivKeySz);
#elif !defined(NO_FILESYSTEM)
    rsaCertSz = FOURK_BUF;
    ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
        DYNAMIC_TYPE_TMP_BUFFER));
    ExpectTrue((f = XFOPEN("./certs/client-cert.der", "rb")) != XBADFILE);
    ExpectTrue((rsaCertSz = (word32)XFREAD(rsaCert, 1, rsaCertSz, f)) > 0);
    if (f != XBADFILE) { XFCLOSE(f); f = XBADFILE; }
    rsaPrivKeySz = FOURK_BUF;
    ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
        DYNAMIC_TYPE_TMP_BUFFER));
    ExpectTrue((f = XFOPEN("./certs/client-key.der", "rb")) != XBADFILE);
    ExpectTrue((rsaPrivKeySz = (word32)XFREAD(rsaPrivKey, 1,
        rsaPrivKeySz, f)) > 0);
    if (f != XBADFILE) XFCLOSE(f);
#else
    rsaCert = NULL; rsaCertSz = 0;
    rsaPrivKey = NULL; rsaPrivKeySz = 0;
#endif

    if (rsaCert == NULL || rsaPrivKey == NULL) {
        XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
        XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
        return TEST_SKIPPED;
    }

    ExpectIntEQ(wc_InitRng(&rng), 0);

    /* Encode a valid SignedData */
    ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
    ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
    if (pkcs7 != NULL) {
        pkcs7->content    = (byte*)data;
        pkcs7->contentSz  = (word32)sizeof(data);
        pkcs7->contentOID = DATA;
        pkcs7->hashOID    = SHA256h;
        pkcs7->encryptOID = RSAk;
        pkcs7->privateKey = rsaPrivKey;
        pkcs7->privateKeySz = rsaPrivKeySz;
        pkcs7->rng = &rng;
    }

    ExpectIntGT(encodedSz = wc_PKCS7_EncodeSignedData(pkcs7, encoded,
        sizeof(encoded)), 0);
    wc_PKCS7_Free(pkcs7);
    pkcs7 = NULL;

    /* Find the signature OCTET STRING tag (0x04) near the end of the
     * encoded message and corrupt it. The signature is the last large
     * OCTET STRING in the SignerInfo. Search backwards for 0x04 followed
     * by a length that looks like an RSA signature (>= 64 bytes).
     * This heuristic depends on the signature being the last large
     * OCTET STRING; the found==1 assertion below guards against
     * silent false passes if encoding changes. */
    if (EXPECT_SUCCESS()) {
        int found = 0;
        for (i = encodedSz - 10; i > 10; i--) {
            if (encoded[i] == 0x04) {
                int len = 0, lbytes = 0;
                if (encoded[i+1] < 0x80) {
                    len = encoded[i+1]; lbytes = 1;
                }
                else if (encoded[i+1] == 0x81) {
                    len = encoded[i+2]; lbytes = 2;
                }
                else if (encoded[i+1] == 0x82) {
                    len = (encoded[i+2] << 8) | encoded[i+3]; lbytes = 3;
                }
                /* RSA signature is typically >= 128 bytes */
                if (len >= 64 && i + 1 + lbytes + len <= encodedSz) {
                    /* Corrupt the OCTET STRING tag to INTEGER */
                    encoded[i] = 0x02; /* ASN_INTEGER instead of OCTET STRING */
                    found = 1;
                    break;
                }
            }
        }
        ExpectIntEQ(found, 1);
    }

    /* Verify the corrupted SignedData - must fail */
    if (EXPECT_SUCCESS()) {
        ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
        ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0);
        ExpectIntLT(wc_PKCS7_VerifySignedData(pkcs7, encoded,
            (word32)encodedSz), 0);
        wc_PKCS7_Free(pkcs7);
        pkcs7 = NULL;
    }

    DoExpectIntEQ(wc_FreeRng(&rng), 0);
    XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
#endif
    return EXPECT_RESULT();
}

/* Test: PKCS#7 EnvelopedData must reject when encryptedContentTotalSz
 * exceeds the remaining input buffer.
 *
 * The fix adds a bounds check under NO_PKCS7_STREAM, but the same
 * crafted message should also be properly handled in streaming mode.
 * This test crafts an EnvelopedData where the [0] content length
 * claims 512 bytes but only minimal data follows. */
static int test_pkcs7_enveloped_content_size_overflow(void)
{
    EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC) && !defined(NO_RSA)
    wc_PKCS7* p7 = NULL;
    byte out[256];

    /* EnvelopedData with KTRI where the EncryptedContentInfo [0] claims
     * 512 bytes but only 16 are present.
     *
     * The outer structure is valid enough to reach the content parsing:
     *   ContentInfo -> EnvelopedData -> version=0 ->
     *   RecipientInfos (empty SET) -> EncryptedContentInfo ->
     *   contentType + AlgorithmIdentifier + [0] oversized content */
    static const byte poc[] = {
        /* ContentInfo SEQUENCE */
        0x30, 0x50,
          /* OID envelopedData 1.2.840.113549.1.7.3 */
          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
          /* [0] EXPLICIT */
          0xa0, 0x43,
            /* EnvelopedData SEQUENCE */
            0x30, 0x41,
              /* version = 0 */
              0x02, 0x01, 0x00,
              /* RecipientInfos SET (empty - no recipients) */
              0x31, 0x00,
              /* EncryptedContentInfo SEQUENCE */
              0x30, 0x3c,
                /* OID data 1.2.840.113549.1.7.1 */
                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
                0x01,
                /* AlgorithmIdentifier SEQUENCE */
                0x30, 0x1d,
                  /* OID AES-256-CBC 2.16.840.1.101.3.4.1.42 */
                  0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01,
                  0x2a,
                  /* IV: OCTET STRING (16 zero bytes) */
                  0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                /* [0] IMPLICIT encryptedContent - claims 512 bytes! */
                0x80, 0x82, 0x02, 0x00,
                0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
                0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
    };

    p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
    ExpectNotNull(p7);
    if (p7 != NULL) {
        /* With an empty RecipientInfos SET, the function may fail at
         * the recipient matching stage before reaching the content-size
         * bounds check.  The ExpectIntLT assertion ensures the
         * oversized content does not cause a buffer over-read. */
        ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
                                                  out, sizeof(out)), 0);

        wc_PKCS7_Free(p7);
    }
#endif
    return EXPECT_RESULT();
}

/* Dilithium verify_ctx_msg must reject absurdly large msgLen */
static int test_dilithium_hash(void)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_MLDSA) && \
    !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \
    !defined(WOLFSSL_MLDSA_NO_VERIFY)
    wc_MlDsaKey key;
    WC_RNG rng;
    int res = 0;
    byte sig[4000];
    byte msg[64];

    XMEMSET(&key, 0, sizeof(key));
    XMEMSET(&rng, 0, sizeof(rng));
    XMEMSET(sig, 0, sizeof(sig));
    XMEMSET(msg, 'A', sizeof(msg));

    ExpectIntEQ(wc_InitRng(&rng), 0);
    ExpectIntEQ(wc_MlDsaKey_Init(&key, NULL, INVALID_DEVID), 0);
#ifndef WOLFSSL_NO_ML_DSA_65
    ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_65), 0);
#elif !defined(WOLFSSL_NO_ML_DSA_44)
    ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_44), 0);
#else
    ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_87), 0);
#endif
    ExpectIntEQ(wc_MlDsaKey_MakeKey(&key, &rng), 0);

    ExpectIntEQ(wc_MlDsaKey_VerifyCtx(&key, sig, sizeof(sig), NULL, 0,
        msg, 0xFFFFFFC0, &res), WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    wc_MlDsaKey_Free(&key);
    DoExpectIntEQ(wc_FreeRng(&rng), 0);
#endif
    return EXPECT_RESULT();
}

/* PKCS7 CBC must validate all padding bytes */
static int test_pkcs7_padding(void)
{
    EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
    defined(WOLFSSL_AES_256) && !defined(NO_PKCS7_ENCRYPTED_DATA)
    PKCS7 pkcs7;
    byte key[32];
    byte plaintext[27]; /* 27 bytes -> padded to 32 -> padding = 05 05 05 05 05 */
    byte encoded[4096];
    byte output[256];
    byte modified[4096];
    int encodedSz = 0;
    int outSz;
    int ctOff = -1;
    int ctLen = 0;

    XMEMSET(key, 0xAA, sizeof(key));
    XMEMSET(plaintext, 'X', sizeof(plaintext));

    /* Encode EncryptedData */
    XMEMSET(&pkcs7, 0, sizeof(pkcs7));
    ExpectIntEQ(wc_PKCS7_Init(&pkcs7, NULL, INVALID_DEVID), 0);
    pkcs7.content      = plaintext;
    pkcs7.contentSz    = sizeof(plaintext);
    pkcs7.contentOID   = DATA;
    pkcs7.encryptOID   = AES256CBCb;
    pkcs7.encryptionKey   = key;
    pkcs7.encryptionKeySz = sizeof(key);

    ExpectIntGT(encodedSz = wc_PKCS7_EncodeEncryptedData(&pkcs7, encoded,
        sizeof(encoded)), 0);

    /* Verify normal decrypt works */
    ExpectIntEQ(outSz = wc_PKCS7_DecodeEncryptedData(&pkcs7, encoded,
        (word32)encodedSz, output, sizeof(output)), (int)sizeof(plaintext));
    wc_PKCS7_Free(&pkcs7);

    /* encryptedContent is the last element in the DER, so it ends at encodedSz;
     * 27-byte plaintext -> 32-byte AES-256-CBC ciphertext. */
    ctLen = 32;
    ctOff = encodedSz - ctLen;

    /* Corrupt an interior padding byte via CBC bit-flip */
    if (EXPECT_SUCCESS()) {
        XMEMCPY(modified, encoded, (size_t)encodedSz);
        /* Flip byte in penultimate block to corrupt interior padding */
        modified[ctOff + ctLen - 32 + 11] ^= 0x42;

        /* Decrypt modified ciphertext - must fail, not succeed */
        XMEMSET(&pkcs7, 0, sizeof(pkcs7));
        ExpectIntEQ(wc_PKCS7_Init(&pkcs7, NULL, INVALID_DEVID), 0);
        pkcs7.encryptionKey   = key;
        pkcs7.encryptionKeySz = sizeof(key);

        outSz = wc_PKCS7_DecodeEncryptedData(&pkcs7, modified,
            (word32)encodedSz, output, sizeof(output));
        /* Must return an error - if it returns plaintext size, padding
         * oracle vulnerability exists */
        ExpectIntLT(outSz, 0);
        wc_PKCS7_Free(&pkcs7);
    }
#endif
    return EXPECT_RESULT();
}

TEST_CASE testCases[] = {
    TEST_DECL(test_fileAccess),

    /*********************************
     * wolfcrypt
     *********************************/

    TEST_DECL(test_ForceZero),

    TEST_DECL(test_wolfCrypt_Init),

    TEST_DECL(test_wc_LoadStaticMemory_ex),
    TEST_DECL(test_wc_LoadStaticMemory_CTX),

    TEST_DECL(test_wc_FreeCertList),
    /* Locking with Compat Mutex */
    TEST_DECL(test_wc_SetMutexCb),
    TEST_DECL(test_wc_LockMutex_ex),

    /* Digests */
    /* test_md2.c */
    TEST_MD2_DECLS,
    /* test_md4.c */
    TEST_MD4_DECLS,
    /* test_md5.c */
    TEST_MD5_DECLS,
    /* test_sha.c */
    TEST_SHA_DECLS,
    /* test_sha256.c */
    TEST_SHA256_DECLS,
    TEST_SHA224_DECLS,
    /* test_sha512.c */
    TEST_SHA512_DECLS,
    TEST_SHA512_224_DECLS,
    TEST_SHA512_256_DECLS,
    TEST_SHA384_DECLS,
    /* test_sha3.c */
    TEST_SHA3_DECLS,
    TEST_SHAKE128_DECLS,
    TEST_SHAKE256_DECLS,
    /* test_blake.c */
    TEST_BLAKE2B_DECLS,
    TEST_BLAKE2S_DECLS,
    /* test_sm3.c: SM3 Digest */
    TEST_SM3_DECLS,
    /* test_ripemd.c */
    TEST_RIPEMD_DECLS,
    /* test_hash.c */
    TEST_HASH_DECLS,

    /* HMAC */
    TEST_HMAC_DECLS,
    /* CMAC */
    TEST_CMAC_DECLS,
    /* SHE */
    TEST_SHE_DECLS,
#ifdef WOLFSSL_SHE_EXTENDED
    TEST_SHE_EXT_DECLS,
#endif
#if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE)
    TEST_SHE_CB_DECLS,
#endif

    /* Cipher */
    /* Triple-DES */
    TEST_DES3_DECLS,
    /* Chacha20 */
    TEST_CHACHA_DECLS,
    /* Poly1305 */
    TEST_POLY1305_DECLS,
    /* Chacha20-Poly1305 and Xchacha20-Poly1305 */
    TEST_CHACHA20_POLY1305_DECLS,
    /* Camellia */
    TEST_CAMELLIA_DECLS,
    /* ARC4 */
    TEST_ARC4_DECLS,
    /* RC2 */
    TEST_RC2_DECLS,

    /* AES cipher and GMAC. */
    TEST_AES_DECLS,
#if defined(WOLFSSL_AES_EAX) && defined(WOLFSSL_AES_256) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 3)) && !defined(HAVE_SELFTEST)
    TEST_AES_EAX_DECLS,
#endif /* WOLFSSL_AES_EAX */
#if defined(WOLFSSL_AES_SIV) && defined(WOLFSSL_AES_128)
    TEST_AES_SIV_DECLS,
#endif /* WOLFSSL_AES_SIV && WOLFSSL_AES_128 */
    TEST_GMAC_DECLS,
    /* Ascon */
    TEST_ASCON_DECLS,
    /* SM4 cipher */
    TEST_SM4_DECLS,
    /* wc_encrypt API */
    TEST_WC_ENCRYPT_DECLS,

    /* RNG tests */
    TEST_RANDOM_DECLS,

    /* Public key */
    /* wolfmath MP API tests */
    TEST_WOLFMATH_DECLS,
    /* RSA */
    TEST_RSA_DECLS,
    /* DSA */
    TEST_DSA_DECLS,
    /* DH */
    TEST_DH_DECLS,
    /* wolfCrypt ECC tests */
    TEST_ECC_DECLS,
    /* SM2 elliptic curve */
    TEST_SM2_DECLS,
    /* Curve25519 */
    TEST_CURVE25519_DECLS,
    /* ED25519 */
    TEST_ED25519_DECLS,
    /* Curve448 */
    TEST_CURVE448_DECLS,
    /* Ed448 */
    TEST_ED448_DECLS,
    /* Kyber */
    TEST_MLKEM_DECLS,
    /* Dilithium */
    TEST_MLDSA_DECLS,
    /* SLH-DSA */
    TEST_SLHDSA_DECLS,
    /* Signature API */
    TEST_SIGNATURE_DECLS,

    /* ASN */
    TEST_ASN_DECLS,

    /* LMS */
    TEST_DECL_GROUP("lms", test_wc_LmsKey_sign_verify),
    TEST_DECL_GROUP("lms", test_wc_LmsKey_reload_cache),

    /* RFC 9802 (HSS/LMS and XMSS/XMSS^MT in X.509) */
    TEST_DECL_GROUP("lms", test_rfc9802_lms_x509_verify),
    TEST_DECL_GROUP("xmss", test_rfc9802_xmss_x509_verify),

    /* PEM and DER APIs. */
    TEST_DECL(test_wc_PemToDer),
    TEST_DECL(test_wc_AllocDer),
    TEST_DECL(test_wc_CertPemToDer),
    TEST_DECL(test_wc_KeyPemToDer),
    TEST_DECL(test_wc_PubKeyPemToDer),
    TEST_DECL(test_wc_PemPubKeyToDer),
    TEST_DECL(test_wc_GetPubKeyDerFromCert),
    TEST_DECL(test_wc_GetSubjectPubKeyInfoDerFromCert),
    TEST_DECL(test_wc_CheckCertSigPubKey),

    /* wolfCrypt ASN tests */
    TEST_DECL(test_ToTraditional),
    TEST_DECL(test_wc_CreateEncryptedPKCS8Key),
    TEST_DECL(test_wc_DecryptedPKCS8Key),
    TEST_DECL(test_wc_GetPkcs8TraditionalOffset),

    /* Certificate */
    TEST_DECL(test_wc_SetSubjectRaw),
    TEST_DECL(test_wc_GetSubjectRaw),
    TEST_DECL(test_wc_SetIssuerRaw),
    TEST_DECL(test_wc_SetIssueBuffer),
    TEST_DECL(test_wc_SetSubjectKeyId),
    TEST_DECL(test_wc_SetSubject),
    TEST_DECL(test_CheckCertSignature),
    TEST_DECL(test_wc_ParseCert),
    TEST_DECL(test_wc_ParseCert_Error),
    TEST_DECL(test_MakeCertWithPathLen),
    TEST_DECL(test_PathLenSelfIssued),
    TEST_DECL(test_PathLenSelfIssuedAllowed),
    TEST_DECL(test_PathLenNoKeyUsage),
    TEST_DECL(test_NameConstraints_OtherName),
    TEST_DECL(test_ParseSerial0FixtureMatrix),
    TEST_DECL(test_MakeCertWithCaFalse),
#ifdef WOLFSSL_CERT_SIGN_CB
    TEST_DECL(test_wc_SignCert_cb),
#endif
    TEST_DECL(test_wc_SetAcmeIdentifierExt),
    TEST_DECL(test_wc_SetKeyUsage),
    TEST_DECL(test_wc_SetAuthKeyIdFromPublicKey_ex),
    TEST_DECL(test_wc_SetSubjectBuffer),
    TEST_DECL(test_wc_SetSubjectKeyIdFromPublicKey_ex),

    /* wolfcrypt PKCS#7 */
    TEST_PKCS7_DECLS,
    TEST_PKCS7_SIGNED_DATA_DECLS,
    TEST_PKCS7_ENCRYPTED_DATA_DECLS,
    TEST_PKCS7_SIGNED_ENCRYPTED_DATA_DECLS,
    TEST_PKCS7_COMPRESSED_DATA_DECLS,

    /* wolfCrypt PKCS#12 */
    TEST_PKCS12_DECLS,

    /* wolfCrypt pwdbased (PBKDF1/PBKDF2) */
    TEST_PWDBASED_DECLS,

    /*
     * test_wolfCrypt_Cleanup needs to come after the above wolfCrypt tests to
     * avoid memory leaks.
     */
    TEST_DECL(test_wolfCrypt_Cleanup),

    TEST_DECL(test_wolfSSL_Init),

    /* x509 -- must appear after test_wolfSSL_Init(). */
    TEST_X509_DECLS,

    TEST_DECL(test_dual_alg_support),
    TEST_DECL(test_dual_alg_crit_ext_support),

    TEST_DECL(test_dual_alg_ecdsa_mldsa),

    TEST_DECL(test_wolfSSL_use_AltPrivateKey_Id),
    TEST_DECL(test_wolfSSL_use_AltPrivateKey_Label),

    /*********************************
     * OpenSSL compatibility API tests
     *********************************/

    /* If at some point a stub get implemented this test should fail indicating
     * a need to implement a new test case
     */
    TEST_DECL(test_stubs_are_stubs),

    /* ASN.1 compatibility API tests */
    TEST_OSSL_ASN1_BIT_STRING_DECLS,
    TEST_OSSL_ASN1_INTEGER_DECLS,
    TEST_OSSL_ASN1_OBJECT_DECLS,
    TEST_OSSL_ASN1_STRING_DECLS,
    TEST_OSSL_ASN1_TIME_DECLS,
    TEST_OSSL_ASN1_TYPE_DECLS,

    TEST_SSL_SK_DECLS,

    TEST_DECL(test_wolfSSL_lhash),

    TEST_DECL(test_wolfSSL_certs),
    TEST_DECL(test_wolfSSL_X509_ext_d2i),

    TEST_DECL(test_wolfSSL_private_keys),
    TEST_SSL_PEM_DECLS,

    /* EVP API testing */
    TEST_EVP_ENC_DECLS,
    TEST_EVP_DIGEST_DECLS,
    TEST_EVP_CIPHER_DECLS,
    TEST_EVP_PKEY_DECLS,

    TEST_DECL(test_wolfSSL_d2i_and_i2d_PublicKey),
    TEST_DECL(test_wolfSSL_d2i_and_i2d_PublicKey_ecc),
#ifndef NO_BIO
    TEST_DECL(test_wolfSSL_d2i_PUBKEY),
#endif
    TEST_DECL(test_wolfSSL_d2i_and_i2d_DSAparams),
    TEST_DECL(test_wolfSSL_i2d_PrivateKey),
#if (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO)) && !defined(NO_RSA) && \
    !defined(NO_TLS)
#ifndef NO_BIO
    TEST_DECL(test_wolfSSL_d2i_PrivateKeys_bio),
#endif /* !NO_BIO */
#endif


#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
    TEST_DECL(test_wolfSSL_ERR_peek_last_error_line),
#endif
#ifndef NO_BIO
    TEST_DECL(test_wolfSSL_ERR_print_errors_cb),
    TEST_DECL(test_wolfSSL_GetLoggingCb),
    TEST_DECL(test_WOLFSSL_ERROR_MSG),
    TEST_DECL(test_wc_ERR_remove_state),
    TEST_DECL(test_wc_ERR_print_errors_fp),
#endif
    TEST_DECL(test_wolfSSL_configure_args),
    TEST_DECL(test_wolfSSL_sk_SSL_CIPHER),
    TEST_DECL(test_wolfSSL_set1_curves_list),
    TEST_DECL(test_wolfSSL_curves_mismatch),
    TEST_DECL(test_wolfSSL_set1_sigalgs_list),

    TEST_DECL(test_wolfSSL_OtherName),
    TEST_DECL(test_wolfSSL_FPKI),
    TEST_DECL(test_wolfSSL_URI),

    /* X509 tests */
    TEST_OSSL_X509_DECLS,
    TEST_OSSL_X509_NAME_DECLS,
    TEST_OSSL_X509_EXT_DECLS,
    TEST_OSSL_X509_PK_DECLS,
    TEST_OSSL_X509_VFY_PARAMS_DECLS,
    TEST_OSSL_X509_IO_DECLS,
    TEST_OSSL_X509_CRYPTO_DECLS,
    TEST_OSSL_X509_ACERT_DECLS,
    TEST_OSSL_X509_INFO_DECLS,

    TEST_DECL(test_wolfSSL_X509_ALGOR_get0),
    TEST_DECL(test_wolfSSL_X509_SEP),
    TEST_DECL(test_wolfSSL_X509_set_extensions),
    TEST_DECL(test_wolfSSL_X509_set_authority_key_id_roundtrip),
    TEST_DECL(test_wolfSSL_X509_set_authority_key_id_ex_roundtrip),
    TEST_DECL(test_wolfSSL_X509_set_authority_key_id_overwrite),
    TEST_DECL(test_wolfSSL_X509_CRL),
#ifndef NO_BIO
    TEST_DECL(test_wolfSSL_X509_print),
    TEST_DECL(test_wolfSSL_X509_CRL_print),
#endif

    /* X509 Store tests */
    TEST_OSSL_X509_STORE_DECLS,
    TEST_OSSL_X509_LOOKUP_DECLS,

    TEST_DECL(test_GENERAL_NAME_set0_othername),
    TEST_DECL(test_RID_GENERAL_NAME_free),
    TEST_DECL(test_RID_X509_get_ext_d2i),
    TEST_DECL(test_othername_and_SID_ext),
    TEST_DECL(test_wolfSSL_dup_CA_list),
    /* OpenSSL sk_X509 API test */
    TEST_DECL(test_sk_X509),
    /* OpenSSL sk_X509_CRL API test */
    TEST_DECL(test_sk_X509_CRL_decode),
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
    defined(HAVE_CRL) && defined(WOLFSSL_CERT_GEN)
    TEST_DECL(test_wolfSSL_X509_CRL_add_revoked_oversized_revocation_date),
#endif
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
    defined(HAVE_CRL) && !defined(NO_FILESYSTEM) && \
    !defined(NO_STDIO_FILESYSTEM)
    TEST_DECL(test_wolfSSL_X509_CRL_reason_critical_boolean),
#endif
    TEST_DECL(test_sk_X509_CRL_encode),
    TEST_DECL(test_wolfSSL_X509_CRL_sign_large),
    TEST_DECL(test_wc_MakeCRL_max_crlnum),

    /* OpenSSL X509 REQ API test */
    TEST_DECL(test_wolfSSL_d2i_X509_REQ),
    TEST_DECL(test_X509_REQ),
    TEST_DECL(test_wolfSSL_X509_REQ_print),

    /* RAND compatibility API */
    TEST_OSSL_RAND_DECLS,

    /* BN compatibility API */
    TEST_OSSL_ASN1_BN_DECLS,

    /* OpenSSL PKCS5 API test */
    TEST_DECL(test_wolfSSL_PKCS5),

    /* OpenSSL PKCS8 API test */
    TEST_DECL(test_wolfSSL_PKCS8_Compat),
    TEST_DECL(test_wolfSSL_PKCS8_d2i),

    /* OpenSSL PKCS7 API test */
    TEST_OSSL_PKCS7_DECLS,
    TEST_OSSL_SMIME_DECLS,
    /* OpenSSL PKCS12 API test */
    TEST_OSSL_PKCS12_DECLS,

    /* Can't memory test as callbacks use Assert. */
    TEST_DECL(test_error_queue_per_thread),
    TEST_DECL(test_wolfSSL_ERR_put_error),
    TEST_DECL(test_wolfSSL_ERR_get_error_order),
#ifndef NO_BIO
    TEST_DECL(test_wolfSSL_ERR_print_errors),
#endif

    TEST_OSSL_OBJ_DECLS,

#ifndef NO_BIO
    TEST_OSSL_BIO_DECLS,
#endif

    TEST_DECL(test_wolfSSL_check_domain),
    TEST_DECL(test_wolfSSL_check_domain_basic),
    TEST_DECL(test_wolfSSL_check_ip_param_basic),
    TEST_DECL(test_wolfSSL_check_ip_address_basic),
    TEST_DECL(test_wolfSSL_cert_cb),
    TEST_DECL(test_wolfSSL_cert_cb_dyn_ciphers),
    TEST_DECL(test_wolfSSL_ciphersuite_auth),
    TEST_DECL(test_wolfSSL_sigalg_info),
    /* Can't memory test as tcp_connect aborts. */
    TEST_DECL(test_wolfSSL_d2i_SSL_SESSION_bounds_check),
    TEST_DECL(test_wolfSSL_SESSION),
    TEST_DECL(test_wolfSSL_SESSION_expire_downgrade),
    TEST_DECL(test_wolfSSL_CTX_sess_set_remove_cb),
    TEST_DECL(test_wolfSSL_ticket_keys),
    TEST_DECL(test_wolfSSL_sk_GENERAL_NAME),
    TEST_DECL(test_wolfSSL_GENERAL_NAME_print),
    TEST_DECL(test_wolfSSL_sk_DIST_POINT),
    TEST_DECL(test_wolfSSL_verify_mode),
    TEST_DECL(test_wolfSSL_verify_depth),
    TEST_DECL(test_wolfSSL_verify_result),
    TEST_DECL(test_wolfSSL_msg_callback),

    TEST_DECL(test_wolfSSL_OCSP_id_get0_info),
    TEST_DECL(test_wolfSSL_i2d_OCSP_CERTID),
    TEST_DECL(test_wolfSSL_d2i_OCSP_CERTID),
    TEST_DECL(test_wolfSSL_OCSP_id_cmp),
    TEST_DECL(test_wolfSSL_OCSP_SINGLERESP_get0_id),
    TEST_DECL(test_wolfSSL_OCSP_single_get0_status),
    TEST_DECL(test_wolfSSL_OCSP_resp_count),
    TEST_DECL(test_wolfSSL_OCSP_resp_get0),
    TEST_DECL(test_wolfSSL_OCSP_parse_url),
    TEST_DECL(test_wolfSSL_OCSP_REQ_CTX),
    TEST_DECL(test_wolfSSL_X509_get1_ca_issuers),
    TEST_DECL(test_wolfSSL_X509_get1_aia_multi),
    TEST_DECL(test_wolfSSL_X509_get1_aia_overflow),
    TEST_DECL(test_wolfSSL_SubjectInfoAccess_no_caRepository),

    TEST_DECL(test_wolfSSL_PEM_read),

    TEST_DECL(test_wolfSSL_OpenSSL_version),
    TEST_DECL(test_wolfSSL_OpenSSL_add_all_algorithms),
    TEST_DECL(test_wolfSSL_OPENSSL_hexstr2buf),

    TEST_DECL(test_CONF_modules_xxx),
#ifdef OPENSSL_ALL
    TEST_DECL(test_wolfSSL_TXT_DB),
    TEST_DECL(test_wolfSSL_NCONF),
#endif

    TEST_DECL(test_wolfSSL_CRYPTO_memcmp),
    TEST_DECL(test_wolfSSL_CRYPTO_get_ex_new_index),
    TEST_DECL(test_wolfSSL_SESSION_get_ex_new_index),
    TEST_DECL(test_CRYPTO_set_dynlock_xxx),
    TEST_DECL(test_CRYPTO_THREADID_xxx),
    TEST_DECL(test_ENGINE_cleanup),
    /* test the no op functions for compatibility */
    TEST_DECL(test_no_op_functions),
    /* OpenSSL error API tests */
    TEST_DECL(test_ERR_load_crypto_strings),

#ifdef OPENSSL_ALL
    TEST_DECL(test_wolfSSL_sk_CIPHER_description),
    TEST_DECL(test_wolfSSL_get_ciphers_compat),
    TEST_DECL(test_wolfSSL_get_ciphers_compat_empty),

    TEST_DECL(test_wolfSSL_CTX_ctrl),
#endif /* OPENSSL_ALL */
#if (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO)) && !defined(NO_RSA)
    TEST_DECL(test_wolfSSL_CTX_use_certificate_ASN1),
#endif /* (OPENSSL_ALL || WOLFSSL_ASIO) && !NO_RSA */

    /*********************************
     * Crypto API tests
     *********************************/

    TEST_OSSL_DIGEST_DECLS,
    TEST_OSSL_MAC_DECLS,
    TEST_OSSL_CIPHER_DECLS,
    TEST_OSSL_RSA_DECLS,
    TEST_OSSL_DH_DECLS,
#if defined(HAVE_ECC) && !defined(OPENSSL_NO_PK)
    TEST_OSSL_EC_DECLS,
#endif
#ifdef OPENSSL_EXTRA
    TEST_OSSL_ECX_DECLS,
#endif
    TEST_OSSL_DSA_DECLS,

    TEST_DECL(test_openssl_generate_key_and_cert),

    TEST_DECL(test_wolfSSL_FIPS_mode),
    TEST_DECL(test_openssl_FIPS_drbg),

    /*********************************
     * CertManager API tests
     *********************************/
    TEST_CERTMAN_DECLS,

    TEST_DECL(test_wolfSSL_CheckOCSPResponse),

    /*********************************
     * SSL/TLS API tests
     *********************************/

    TEST_DECL(test_wolfSSL_Method_Allocators),
#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS)
    TEST_DECL(test_wolfSSL_CTX_new),
#endif
    TEST_DECL(test_server_wolfSSL_new),
    TEST_DECL(test_client_wolfSSL_new),
#if (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)) && \
    !defined(NO_TLS) && \
    (!defined(NO_RSA) || defined(HAVE_ECC)) && !defined(NO_FILESYSTEM)
    TEST_DECL(test_for_double_Free),
#endif
    TEST_DECL(test_wolfSSL_set_options),

    TEST_TLS13_DECLS,

    TEST_DECL(test_wolfSSL_tmp_dh),
    TEST_DECL(test_wolfSSL_tmp_dh_regression),
    TEST_DECL(test_wolfSSL_ctrl),

    TEST_DECL(test_wolfSSL_get0_param),
    TEST_DECL(test_wolfSSL_set1_host),

#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \
    (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \
    defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \
    defined(WOLFSSL_OPENSSH) || defined(HAVE_SBLIM_SFCB)))
    TEST_DECL(test_wolfSSL_set_SSL_CTX),
#endif
    TEST_DECL(test_wolfSSL_CTX_get_min_proto_version),
    TEST_DECL(test_wolfSSL_security_level),
    TEST_DECL(test_wolfSSL_crypto_policy),
    TEST_DECL(test_wolfSSL_crypto_policy_certs_and_keys),
    TEST_DECL(test_wolfSSL_crypto_policy_tls_methods),
    TEST_DECL(test_wolfSSL_crypto_policy_ciphers),
    TEST_DECL(test_wolfSSL_SSL_in_init),
    TEST_DECL(test_wolfSSL_CTX_set_timeout),
    TEST_DECL(test_wolfSSL_set_psk_use_session_callback),

    TEST_DECL(test_CONF_CTX_FILE),
    TEST_DECL(test_CONF_CTX_CMDLINE),

#if !defined(NO_CERTS) && (!defined(NO_WOLFSSL_CLIENT) || \
    !defined(WOLFSSL_NO_CLIENT_AUTH)) && !defined(NO_FILESYSTEM) && \
    !defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION) && \
    (!defined(NO_RSA) || defined(HAVE_ECC)) && !defined(NO_SHA256)
    /* Use the Cert Manager(CM) API to generate the error ASN_SIG_CONFIRM_E */
    /* Bad certificate signature tests */
    TEST_DECL(test_EccSigFailure_cm),
    TEST_DECL(test_RsaSigFailure_cm),
#endif
    TEST_DECL(test_wc_CheckPrivateKey_RSA_pub_only),

    /* PKCS8 testing */
    TEST_DECL(test_wolfSSL_no_password_cb),
    TEST_DECL(test_wolfSSL_PKCS8),
    TEST_DECL(test_wolfSSL_PKCS8_ED25519),
    TEST_DECL(test_wolfSSL_PKCS8_ED448),

#ifdef HAVE_IO_TESTS_DEPENDENCIES
    TEST_DECL(test_wolfSSL_get_finished),
    /* Uses Assert in handshake callback. */
    TEST_DECL(test_wolfSSL_CTX_add_session),
    /* Large number of memory allocations. */
    TEST_DECL(test_wolfSSL_CTX_add_session_ext_tls13),
    /* Large number of memory allocations. */
    TEST_DECL(test_wolfSSL_CTX_add_session_ext_dtls13),
    /* Large number of memory allocations. */
    TEST_DECL(test_wolfSSL_CTX_add_session_ext_tls12),
    /* Large number of memory allocations. */
    TEST_DECL(test_wolfSSL_CTX_add_session_ext_dtls12),
    /* Large number of memory allocations. */
    TEST_DECL(test_wolfSSL_CTX_add_session_ext_tls11),
    /* Large number of memory allocations. */
    TEST_DECL(test_wolfSSL_CTX_add_session_ext_dtls1),
#endif
    TEST_DECL(test_SSL_CIPHER_get_xxx),
    TEST_DECL(test_wolfSSL_ERR_strings),
    TEST_DECL(test_wolfSSL_CTX_set_cipher_list_bytes),
    TEST_DECL(test_wolfSSL_set_cipher_list_tls12_keeps_tls13),
    TEST_DECL(test_wolfSSL_set_cipher_list_tls13_keeps_tls12),
    TEST_DECL(test_wolfSSL_set_cipher_list_tls12_with_version),
    TEST_DECL(test_wolfSSL_set_cipher_list_tls13_with_version),
    TEST_DECL(test_wolfSSL_set_alpn_protos_default_fails),
    TEST_DECL(test_wolfSSL_CTX_use_certificate),
    TEST_DECL(test_wolfSSL_CTX_use_certificate_file),
    TEST_DECL(test_wolfSSL_CTX_use_certificate_buffer),
    TEST_DECL(test_wolfSSL_use_certificate_buffer),
    TEST_DECL(test_wolfSSL_CTX_use_PrivateKey_file),
    TEST_DECL(test_wolfSSL_CTX_use_RSAPrivateKey_file),
    TEST_DECL(test_wolfSSL_use_RSAPrivateKey_file),
    TEST_DECL(test_wolfSSL_CTX_use_PrivateKey),
    TEST_DECL(test_wolfSSL_CTX_load_verify_locations),
    /* Large number of memory allocations. */
    TEST_DECL(test_wolfSSL_CTX_load_system_CA_certs),
    TEST_DECL(test_wolfSSL_CTX_add_extra_chain_cert),

#if defined(HAVE_CERT_CHAIN_VALIDATION) && \
    !defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
    TEST_DECL(test_wolfSSL_CertRsaPss),
#endif
    TEST_DECL(test_wolfSSL_CTX_load_verify_locations_ex),
    TEST_DECL(test_wolfSSL_CTX_load_verify_buffer_ex),
    TEST_DECL(test_wolfSSL_CTX_load_verify_chain_buffer_format),
    TEST_DECL(test_wolfSSL_CTX_add1_chain_cert),
    TEST_DECL(test_wolfSSL_add_to_chain_overflow),
    TEST_DECL(test_wolfSSL_CTX_use_certificate_chain_buffer_format),
    TEST_DECL(test_wolfSSL_CTX_use_certificate_chain_file_format),
    TEST_DECL(test_wolfSSL_use_certificate_chain_file),
    TEST_DECL(test_wolfSSL_CTX_trust_peer_cert),
    TEST_DECL(test_wolfSSL_CTX_LoadCRL),
    TEST_DECL(test_wolfSSL_CTX_LoadCRL_largeCRLnum),
    TEST_DECL(test_wolfSSL_crl_update_cb),
    TEST_DECL(test_wolfSSL_CTX_SetTmpDH_file),
    TEST_DECL(test_wolfSSL_CTX_SetTmpDH_buffer),
    TEST_DECL(test_wolfSSL_CTX_SetMinMaxDhKey_Sz),
    TEST_DECL(test_wolfSSL_CTX_der_load_verify_locations),
    TEST_DECL(test_wolfSSL_CTX_enable_disable),
    TEST_DECL(test_wolfSSL_CTX_ticket_API),
    TEST_DECL(test_wolfSSL_SetTmpDH_file),
    TEST_DECL(test_wolfSSL_SetTmpDH_buffer),
    TEST_DECL(test_wolfSSL_SetMinMaxDhKey_Sz),
    TEST_DECL(test_SetTmpEC_DHE_Sz),
    TEST_DECL(test_wolfSSL_CTX_get0_privatekey),
#ifdef WOLFSSL_DTLS
    TEST_DECL(test_wolfSSL_DtlsUpdateWindow),
    TEST_DECL(test_wolfSSL_DTLS_fragment_buckets),
#endif
    TEST_DECL(test_wolfSSL_dtls_set_mtu),
    /* Uses Assert in handshake callback. */
    TEST_DECL(test_wolfSSL_dtls_plaintext),
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
    defined(HAVE_IO_TESTS_DEPENDENCIES)
    TEST_DECL(test_wolfSSL_read_write),
    TEST_DECL(test_wolfSSL_read_write_ex),
    /* Can't memory test as server hangs if client fails before second connect.
     */
    TEST_DECL(test_wolfSSL_reuse_WOLFSSLobj),
    TEST_DECL(test_wolfSSL_CTX_verifyDepth_ServerClient_1),
    TEST_DECL(test_wolfSSL_CTX_verifyDepth_ServerClient_2),
    TEST_DECL(test_wolfSSL_CTX_verifyDepth_ServerClient_3),
    TEST_DECL(test_wolfSSL_CTX_set_cipher_list),
    /* Can't memory test as server hangs. */
    TEST_DECL(test_wolfSSL_dtls_export),
    /* Uses Assert in handshake callback. */
    TEST_DECL(test_wolfSSL_tls_export),
#endif
    TEST_DECL(test_wolfSSL_dtls_export_peers),
    TEST_DECL(test_wolfSSL_dtls_import_state_extra_window_words),
    TEST_DECL(test_wolfSSL_SetMinVersion),
    TEST_DECL(test_wolfSSL_CTX_SetMinVersion),

    /* wolfSSL handshake APIs. */
    TEST_DECL(test_wolfSSL_CTX_get0_set1_param),
    TEST_DECL(test_wolfSSL_a2i_IPADDRESS),
    TEST_DECL(test_wolfSSL_BUF),
    TEST_DECL(test_wolfSSL_set_tlsext_status_type),
    TEST_DECL(test_wolfSSL_get_client_ciphers),
    /* Can't memory test as server hangs. */
    TEST_DECL(test_wolfSSL_CTX_set_client_CA_list),
    TEST_DECL(test_wolfSSL_CTX_add_client_CA),
    TEST_DECL(test_wolfSSL_CTX_set_srp_username),
    TEST_DECL(test_wolfSSL_CTX_set_srp_password),
    TEST_DECL(test_wolfSSL_CTX_set_keylog_callback),
    TEST_DECL(test_wolfSSL_CTX_get_keylog_callback),
    TEST_DECL(test_wolfSSL_Tls12_Key_Logging_test),
    /* Can't memory test as server hangs. */
    TEST_DECL(test_wolfSSL_Tls13_Key_Logging_test),
    TEST_DECL(test_wolfSSL_Tls13_postauth),
    TEST_DECL(test_wolfSSL_set_ecdh_auto),
    TEST_DECL(test_wolfSSL_CTX_set_ecdh_auto),
    TEST_DECL(test_wolfSSL_set_minmax_proto_version),
    TEST_DECL(test_wolfSSL_CTX_set_max_proto_version),
    TEST_DECL(test_wolfSSL_THREADID_hash),

    /* TLS extensions tests */
#ifdef HAVE_IO_TESTS_DEPENDENCIES
#ifdef HAVE_SNI
    TEST_DECL(test_wolfSSL_UseSNI_params),
    /* Uses Assert in handshake callback. */
    TEST_DECL(test_wolfSSL_UseSNI_connection),
    TEST_DECL(test_wolfSSL_SNI_GetFromBuffer),
#endif /* HAVE_SNI */
#endif
    TEST_DECL(test_wolfSSL_UseTrustedCA),
    TEST_DECL(test_wolfSSL_UseMaxFragment),
    TEST_DECL(test_wolfSSL_UseTruncatedHMAC),
    TEST_DECL(test_wolfSSL_UseSupportedCurve),
#if defined(HAVE_ALPN) && defined(HAVE_IO_TESTS_DEPENDENCIES)
    /* Uses Assert in handshake callback. */
    TEST_DECL(test_wolfSSL_UseALPN_connection),
    TEST_DECL(test_wolfSSL_UseALPN_params),
#endif
#ifdef HAVE_ALPN_PROTOS_SUPPORT
    /* Uses Assert in handshake callback. */
    TEST_DECL(test_wolfSSL_set_alpn_protos),
    TEST_DECL(test_wolfSSL_select_next_proto),
#endif
    TEST_DECL(test_tls_ems_downgrade),
    TEST_DECL(test_tls_ems_resumption_downgrade),
    TEST_DECL(test_tls12_chacha20_poly1305_bad_tag),
    TEST_DECL(test_tls13_null_cipher_bad_hmac),
    TEST_DECL(test_scr_verify_data_mismatch),
    TEST_DECL(test_tls13_hrr_cipher_suite_mismatch),
    TEST_DECL(test_tls13_ticket_age_out_of_window),
    TEST_DECL(test_wolfSSL_DisableExtendedMasterSecret),
    TEST_DECL(test_certificate_authorities_certificate_request),
    TEST_DECL(test_certificate_authorities_client_hello),
    TEST_DECL(test_TLSX_TCA_Find),
    TEST_DECL(test_TLSX_SNI_GetSize_overflow),
    TEST_DECL(test_TLSX_ECH_msg_type_validation),
    TEST_DECL(test_TLSX_SRTP_msg_type_validation),
    TEST_DECL(test_wolfSSL_wolfSSL_UseSecureRenegotiation),
    TEST_DECL(test_wolfSSL_clear_secure_renegotiation),
    TEST_DECL(test_wolfSSL_SCR_Reconnect),
    TEST_DECL(test_wolfSSL_SCR_check_enabled),
    TEST_DECL(test_wolfSSL_ticket_keycb_bad_hmac),
    TEST_DECL(test_tls_ext_duplicate),
    TEST_DECL(test_tls_ext_word16_overflow),
    TEST_DECL(test_tls_bad_legacy_version),
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
#if defined(HAVE_IO_TESTS_DEPENDENCIES)
    TEST_DECL(test_wolfSSL_Tls13_ECH_params),
    TEST_DECL(test_wolfSSL_Tls13_ECH_params_b64),
    /* Uses Assert in handshake callback. */
    TEST_DECL(test_wolfSSL_Tls13_ECH),
    TEST_DECL(test_wolfSSL_Tls13_ECH_HRR),
    TEST_DECL(test_wolfSSL_SubTls13_ECH),
#endif
#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
    TEST_DECL(test_wolfSSL_Tls13_ECH_all_algos),
    TEST_DECL(test_wolfSSL_Tls13_ECH_no_private_name),
    TEST_DECL(test_wolfSSL_Tls13_ECH_bad_configs),
    TEST_DECL(test_wolfSSL_Tls13_ECH_retry_configs),
    TEST_DECL(test_wolfSSL_Tls13_ECH_retry_configs_bad),
    TEST_DECL(test_wolfSSL_Tls13_ECH_retry_configs_auth_fail),
    TEST_DECL(test_wolfSSL_Tls13_ECH_new_config),
    TEST_DECL(test_wolfSSL_Tls13_ECH_trial_decrypt),
    TEST_DECL(test_wolfSSL_Tls13_ECH_GREASE),
    TEST_DECL(test_wolfSSL_Tls13_ECH_disable_conn),
    TEST_DECL(test_wolfSSL_Tls13_ECH_long_SNI),
    TEST_DECL(test_wolfSSL_Tls13_ECH_HRR_rejection),
    TEST_DECL(test_wolfSSL_Tls13_ECH_ch2_no_ech),
    TEST_DECL(test_wolfSSL_Tls13_ECH_ch2_decrypt_error),
    TEST_DECL(test_wolfSSL_Tls13_ECH_rejected_cert_valid),
    TEST_DECL(test_wolfSSL_Tls13_ECH_rejected_empty_client_cert),
#endif
#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TEST_ECH) && \
    !defined(WOLFSSL_NO_TLS12)
    TEST_DECL(test_wolfSSL_Tls13_ECH_tamper_client),
#endif
    TEST_DECL(test_wolfSSL_Tls13_ECH_enable_disable),
#endif /* WOLFSSL_TLS13 && HAVE_ECH */

    TEST_DECL(test_wolfSSL_X509_TLS_version_test_1),
    TEST_DECL(test_wolfSSL_X509_TLS_version_test_2),

    /* OCSP Stapling */
    TEST_DECL(test_wolfSSL_UseOCSPStapling),
    TEST_DECL(test_wolfSSL_UseOCSPStaplingV2),
    TEST_DECL(test_self_signed_stapling),
    TEST_DECL(test_ocsp_callback_fails),

    /* Multicast */
    TEST_DECL(test_wolfSSL_mcast),

    TEST_DECL(test_wolfSSL_read_detect_TCP_disconnect),

    TEST_DECL(test_wolfSSL_msgCb),
    TEST_DECL(test_wolfSSL_either_side),
    TEST_DECL(test_wolfSSL_DTLS_either_side),
    /* Uses Assert in handshake callback. */
    TEST_DECL(test_wolfSSL_dtls_fragments),
    /* Uses Assert in handshake callback. */
    TEST_DECL(test_wolfSSL_dtls_AEAD_limit),
    /* Uses Assert in handshake callback. */
    TEST_DECL(test_wolfSSL_ignore_alert_before_cookie),
    /* Uses Assert in handshake callback. */
    TEST_DECL(test_wolfSSL_dtls_bad_record),
    /* Uses Assert in handshake callback. */
    TEST_DECL(test_wolfSSL_dtls_stateless),
    TEST_DECL(test_wolfSSL_dtls_stateless_hrr_group),
    TEST_DECL(test_generate_cookie),

#ifndef NO_BIO
    TEST_OSSL_BIO_TLS_DECLS,
#endif

#if defined(HAVE_PK_CALLBACKS) && !defined(WOLFSSL_NO_TLS12)
    TEST_DECL(test_DhCallbacks),
#endif

#if defined(HAVE_KEYING_MATERIAL) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
    TEST_DECL(test_export_keying_material),
#endif

    /* Can't memory test as client/server Asserts in thread. */
    TEST_DECL(test_ticket_and_psk_mixing),
    /* Can't memory test as client/server Asserts in thread. */
    TEST_DECL(test_prioritize_psk),

    /* Can't memory test as client/server hangs. */
    TEST_DECL(test_wc_CryptoCb),
    /* Can't memory test as client/server hangs. */
    TEST_DECL(test_wolfSSL_CTX_StaticMemory),
#if !defined(NO_FILESYSTEM) &&                                                 \
     defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) &&                    \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME
    TEST_DECL(test_wolfSSL_dtls_stateless_resume),
#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */
#ifdef HAVE_MAX_FRAGMENT
    TEST_DECL(test_wolfSSL_dtls_stateless_maxfrag),
#endif /* HAVE_MAX_FRAGMENT */
#ifndef NO_RSA
    TEST_DECL(test_wolfSSL_dtls_stateless2),
#if !defined(NO_OLD_TLS)
    TEST_DECL(test_wolfSSL_dtls_stateless_downgrade),
#endif /* !defined(NO_OLD_TLS) */
#endif /* ! NO_RSA */
#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) &&     \
        *  !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) */
    TEST_DECL(test_wolfSSL_CTX_set_ciphersuites),
    TEST_DECL(test_wolfSSL_CRL_CERT_REVOKED_alert),
    TEST_DECL(test_TLS_13_ticket_different_ciphers),
    TEST_DECL(test_WOLFSSL_dtls_version_alert),

#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && defined(HAVE_SESSION_TICKET)       \
    && defined(WOLFSSL_TLS13) &&                                               \
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))\
    && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
    TEST_DECL(test_ticket_nonce_malloc),
#endif
    TEST_DECL(test_ticket_ret_create),
    TEST_DECL(test_ticket_enc_corrupted),
    TEST_DECL(test_wrong_cs_downgrade),
    TEST_DECL(test_extra_alerts_wrong_cs),
    TEST_DECL(test_extra_alerts_skip_hs),
    TEST_DECL(test_extra_alerts_bad_psk),
    TEST_DECL(test_multiple_shutdown_nonblocking),
    /* Can't memory test as client/server Asserts. */
    TEST_DECL(test_harden_no_secure_renegotiation),
    TEST_DECL(test_override_alt_cert_chain),
    TEST_DECL(test_rpk_set_xxx_cert_type),
    TEST_DECL(test_dtls13_bad_epoch_ch),
    TEST_DECL(test_short_session_id),
    TEST_DECL(test_wolfSSL_dtls13_null_cipher),
    /* Can't memory test as client/server hangs. */
    TEST_DECL(test_dtls_msg_from_other_peer),
    TEST_DECL(test_dtls_ipv6_check),
    TEST_DECL(test_wolfSSL_SCR_after_resumption),
    TEST_DECL(test_dtls_no_extensions),
    TEST_DECL(test_tls_alert_no_server_hello),
    TEST_DECL(test_TLSX_CA_NAMES_bad_extension),
    TEST_DECL(test_dtls_1_0_hvr_downgrade),
    TEST_DECL(test_session_ticket_no_id),
    TEST_DECL(test_session_ticket_hs_update),
    TEST_DECL(test_dtls_downgrade_scr_server),
    TEST_DECL(test_dtls_downgrade_scr),
    TEST_DECL(test_dtls_client_hello_timeout_downgrade),
    TEST_DECL(test_dtls_client_hello_timeout),
    TEST_DECL(test_dtls_dropped_ccs),
    TEST_DECL(test_dtls_seq_num_downgrade),
    TEST_DECL(test_certreq_sighash_algos),
    TEST_DECL(test_revoked_loaded_int_cert),
    TEST_DECL(test_dtls_frag_ch),
    TEST_DECL(test_dtls13_frag_ch_pq),
    TEST_DECL(test_dtls_empty_keyshare_with_cookie),
    TEST_DECL(test_dtls_old_seq_number),
    TEST_DECL(test_dtls12_missing_finished),
    TEST_DECL(test_dtls13_missing_finished_client),
    TEST_DECL(test_dtls13_missing_finished_server),
    TEST_DECL(test_dtls13_finished_send_error_propagation),
    TEST_DTLS_DECLS,
    TEST_DECL(test_tls_multi_handshakes_one_record),
    TEST_DECL(test_write_dup),
    TEST_DECL(test_write_dup_want_write),
    TEST_DECL(test_write_dup_want_write_simul),
    TEST_DECL(test_write_dup_oom),
    TEST_DECL(test_read_write_hs),
    TEST_DECL(test_get_signature_nid),
#ifndef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
    TEST_DECL(test_tls_cert_store_unchanged),
#endif
    TEST_DECL(test_wolfSSL_SendUserCanceled),
    TEST_DECL(test_wolfSSL_SSLDisableRead),
    TEST_DECL(test_wolfSSL_inject),
    TEST_DECL(test_ocsp_status_callback),
    TEST_DECL(test_ocsp_basic_verify),
    TEST_DECL(test_ocsp_responder_keyhash_binding),
    TEST_DECL(test_ocsp_response_parsing),
    TEST_DECL(test_ocsp_certid_enc_dec),
    TEST_DECL(test_ocsp_certid_dup),
    TEST_DECL(test_ocsp_tls_cert_cb),
    TEST_DECL(test_ocsp_cert_unknown_crl_fallback),
    TEST_DECL(test_ocsp_cert_unknown_crl_fallback_nonleaf),
    TEST_DECL(test_tls13_nonblock_ocsp_low_mfl),
    TEST_DECL(test_ocsp_responder),
    TEST_TLS_DECLS,
    TEST_DECL(test_wc_DhSetNamedKey),
    TEST_DECL(test_DhAgree_rejects_p_minus_1),
    TEST_DECL(test_ed448_rejects_identity_key),
    TEST_DECL(test_pkcs7_decode_encrypted_outputsz),
    TEST_DECL(test_pkcs7_ori_oversized_oid),
    TEST_DECL(test_pkcs7_ori_seqsz_underflow),
    TEST_DECL(test_pkcs7_ori_orivalue_overflow),
    TEST_DECL(test_pkcs7_ktri_skid_length_mismatch),
    TEST_DECL(test_pkcs7_kari_degenerate_bitstring),
    TEST_DECL(test_pkcs7_encrypted_content_size_overflow),
    TEST_DECL(test_pkcs7_signed_bad_sig_tag),
    TEST_DECL(test_pkcs7_enveloped_content_size_overflow),
    TEST_DECL(test_pkcs7_padding),

#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_CHAIN_INPUT)
    TEST_DECL(test_sniffer_chain_input_overflow),
#endif

    TEST_DECL(test_mldsa_verify_hash),
    TEST_DECL(test_dilithium_hash),
    /* This test needs to stay at the end to clean up any caches allocated. */
    TEST_DECL(test_wolfSSL_Cleanup)
};

#define TEST_CASE_CNT (int)(sizeof(testCases) / sizeof(*testCases))

static void TestSetup(void)
{
#ifdef WOLFSSL_SWDEV
    /* Re-arm the swdev cryptocb registration in case the previous test
     * tore down wolfCrypt and wiped gCryptoDev. */
    (void)wc_SwDev_Init();
#endif
}

static void TestCleanup(void)
{
#if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)
    /* Clear any errors added to the error queue during the test run. */
    wolfSSL_ERR_clear_error();
#endif /* OPENSSL_EXTRA || DEBUG_WOLFSSL_VERBOSE */
#ifdef WOLFSSL_SWDEV
    wc_SwDev_Cleanup();
#endif
}

void ApiTest_StopOnFail(void)
{
    stopOnFail = 1;
}

/* Print out all API test cases with numeric identifier.
 */
void ApiTest_PrintTestCases(void)
{
    int i;
    const char* lastGroup = NULL;

    printf("All Test Cases:\n");
    for (i = 0; i < TEST_CASE_CNT; i++) {
        if ((lastGroup != NULL) && ((testCases[i].group == NULL) ||
                XSTRCMP(testCases[i].group, lastGroup) != 0)) {
            printf("End Group  : %s\n", lastGroup);
        }
        if ((testCases[i].group != NULL) && ((lastGroup == NULL) ||
                XSTRCMP(testCases[i].group, lastGroup) != 0)) {
            printf("Begin Group: %s\n", testCases[i].group);
        }
        lastGroup = testCases[i].group;
        printf("%3d: %s\n", i + 1, testCases[i].name);
    }
}

/* Print out all API group names.
 */
void ApiTest_PrintGroups(void)
{
    int i;
    const char* lastGroup = NULL;

    printf("All Groups:\n");
    for (i = 0; i < TEST_CASE_CNT; i++) {
        if ((testCases[i].group != NULL) && ((lastGroup == NULL) ||
                XSTRCMP(testCases[i].group, lastGroup) != 0)) {
            printf("  %s\n", testCases[i].group);
        }
        lastGroup = testCases[i].group;
    }
}


/* Add test case with group name to the list to run.
 *
 * @param [in]  name  Group name of test case to run.
 * @return  0 on success.
 * @return  BAD_FUNC_ARG when group name does not select any tests.
 */
int ApiTest_RunGroup(char* name)
{
    int i;
    int cnt = 0;

    for (i = 0; i < TEST_CASE_CNT; i++) {
        if ((testCases[i].group != NULL) &&
                (XSTRCMP(testCases[i].group, name) == 0)) {
            testAll = 0;
            testCases[i].run = 1;
            cnt++;
        }
    }

    if (cnt == 0) {
        printf("Group name not found: %s\n", name);
        printf("Use --groups to see all test group names.\n");
        return BAD_FUNC_ARG;
    }
    return 0;
}

/* Add test case with index to the list to run.
 *
 * @param [in]  idx  Index of test case to run starting at 1.
 * @return  0 on success.
 * @return  BAD_FUNC_ARG when index is out of range of test case identifiers.
 */
int ApiTest_RunIdx(int idx)
{
    if (idx < 1 || idx > TEST_CASE_CNT) {
        printf("Index out of range (1 - %d): %d\n", TEST_CASE_CNT, idx);
        return BAD_FUNC_ARG;
    }

    testAll = 0;
    testCases[idx-1].run = 1;

    return 0;
}

/* Add test cases with part of the name to the list to run.
 *
 * @param [in]  name  Part of the name of test cases to run.
 * @return  0 on success.
 * @return  BAD_FUNC_ARG when name is not a known test case name.
 */
int ApiTest_RunPartName(char* name)
{
    int i;
    int cnt = 0;

    for (i = 0; i < TEST_CASE_CNT; i++) {
        if (XSTRSTR(testCases[i].name, name) != NULL) {
            cnt++;
            testAll = 0;
            testCases[i].run = 1;
        }
    }
    if (cnt > 0)
        return 0;

    printf("Not found a test case with: %s\n", name);
    printf("Use --list to see all test case names.\n");
    return BAD_FUNC_ARG;
}

/* Add test case with name to the list to run.
 *
 * @param [in]  name  Name of test case to run.
 * @return  0 on success.
 * @return  BAD_FUNC_ARG when name is not a known test case name.
 */
int ApiTest_RunName(char* name)
{
    int i;

    for (i = 0; i < TEST_CASE_CNT; i++) {
        if (XSTRCMP(testCases[i].name, name) == 0) {
            testAll = 0;
            testCases[i].run = 1;
            return 0;
        }
    }

    printf("Test case name not found: %s\n", name);
    printf("Use --list to see all test case names.\n");
    return BAD_FUNC_ARG;
}

/* Converts the result code to a string.
 *
 * @param [in]  res  Test result code.
 * @return  String describing test result.
 */
static const char* apitest_res_string(int res)
{
    const char* str = "invalid result";

    switch (res) {
    case TEST_SUCCESS:
        str = "passed";
        break;
    case TEST_FAIL:
        str = "failed";
        break;
    case TEST_SKIPPED:
        str = "skipped";
        break;
    }

    return str;
}

#ifndef WOLFSSL_UNIT_TEST_NO_TIMING
static double gettime_secs(void)
    #if defined(_WIN32) && (defined(_MSC_VER) || defined(__WATCOMC__))
    {
        /* there's no gettimeofday for Windows, so we'll use system time */
        #define EPOCH_DIFF 11644473600LL
        FILETIME currentFileTime;
        ULARGE_INTEGER uli = { 0, 0 };

    #if defined(__WATCOMC__)
        GetSystemTimeAsFileTime(&currentFileTime);
    #else
        GetSystemTimePreciseAsFileTime(&currentFileTime);
    #endif

        uli.LowPart = currentFileTime.dwLowDateTime;
        uli.HighPart = currentFileTime.dwHighDateTime;

        /* Convert to seconds since Unix epoch */
        return (double)((uli.QuadPart - (EPOCH_DIFF * 10000000)) / 10000000.0);
    }
    #else
    {
        struct timeval tv;
        LIBCALL_CHECK_RET(gettimeofday(&tv, 0));

        return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
    }
    #endif
#endif

int ApiTest(void)
{
    int i;
    int ret;
    int res = 0;
#ifndef WOLFSSL_UNIT_TEST_NO_TIMING
    double timeDiff;
#endif
    int passed = 0;
    int skipped = 0;
    int failed = 0;

    printf(" Begin API Tests\n");
    fflush(stdout);

#ifdef WOLFCRYPT_ONLY
    if (wolfCrypt_Init() != 0) {
        printf("wolfCrypt Initialization failed\n");
        res = 1;
    }
#else
    if (wolfSSL_Init() != WOLFSSL_SUCCESS) {
        printf("wolfSSL Initialization failed\n");
        res = 1;
    }
#endif

#ifdef WOLFSSL_SWDEV
    if (res == 0 && wc_SwDev_Init() != 0) {
        printf("wc_SwDev_Init failed\n");
        res = 1;
    }
#endif

    #ifdef WOLFSSL_DUMP_MEMIO_STREAM
    if (res == 0) {
        if (create_tmp_dir(tmpDirName, sizeof(tmpDirName) - 1) == NULL) {
            printf("failed to create tmp dir\n");
            res = 1;
        }
        else {
            tmpDirNameSet = 1;
        }
    }
    #endif

    if (res == 0) {
        const char* lastGroup = NULL;

        for (i = 0; i < TEST_CASE_CNT; ++i) {
            EXPECT_DECLS;

        #ifdef WOLFSSL_DUMP_MEMIO_STREAM
            currentTestName = testCases[i].name;
        #endif

            /* When not testing all cases then skip if not marked for running.
             */
            if (!testAll && !testCases[i].run) {
                continue;
            }

            TestSetup();

            if ((lastGroup != NULL) && ((testCases[i].group == NULL) ||
                    XSTRCMP(testCases[i].group, lastGroup) != 0)) {
                printf("  End Group  : %s\n", lastGroup);
            }
            if ((testCases[i].group != NULL) && ((lastGroup == NULL) ||
                    XSTRCMP(testCases[i].group, lastGroup) != 0)) {
                printf("  Begin Group: %s\n", testCases[i].group);
            }
            lastGroup = testCases[i].group;

            printf("   %4d: %-51s:", i + 1, testCases[i].name);
            fflush(stdout);
        #ifndef WOLFSSL_UNIT_TEST_NO_TIMING
            timeDiff = gettime_secs();
        #endif
            ret = testCases[i].func();
        #ifndef WOLFSSL_UNIT_TEST_NO_TIMING
            timeDiff = gettime_secs() - timeDiff;
        #endif
        #ifndef WOLFSSL_UNIT_TEST_NO_TIMING
            if (ret != TEST_SKIPPED) {
                printf(" %s (%9.5lf)\n", apitest_res_string(ret), timeDiff);
            }
            else
        #endif
            {
                printf(" %s\n", apitest_res_string(ret));
            }
            fflush(stdout);
            /* if return code is < 0 and not skipped then assert error */
            Expect((ret > 0 || ret == TEST_SKIPPED),
                ("Test failed\n"),
                ("ret %d", ret));
            testCases[i].fail = ((ret <= 0) && (ret != TEST_SKIPPED));
            res |= ((ret <= 0) && (ret != TEST_SKIPPED));

            if (testCases[i].fail)
                failed++;
            else if (ret == TEST_SKIPPED)
                skipped++;
            else
                passed++;

            TestCleanup();

            if (testCases[i].fail && stopOnFail) {
                testAll = 0;
                break;
            }
        }
        if (lastGroup != NULL) {
            printf("  End Group  : %s\n", lastGroup);
        }
    }

#if defined(HAVE_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS) \
                      && (defined(NO_MAIN_DRIVER) || defined(HAVE_STACK_SIZE))
    wc_ecc_fp_free();  /* free per thread cache */
#endif

#ifdef WOLFSSL_SWDEV
    wc_SwDev_Cleanup();
#endif

#ifdef WOLFCRYPT_ONLY
    wolfCrypt_Cleanup();
#else
    wolfSSL_Cleanup();
#endif

    (void)testDevId;

    if (res != 0) {
        printf("\nFAILURES:\n");
        for (i = 0; i < TEST_CASE_CNT; ++i) {
            if (testCases[i].fail) {
                printf("   %3d: %s\n", i + 1, testCases[i].name);
            }
        }
        printf("\n");
        fflush(stdout);
    }

#ifdef WOLFSSL_DUMP_MEMIO_STREAM
    if (tmpDirNameSet) {
        printf("\nBinary dumps of the memio streams can be found in the\n"
                "%s directory. This can be imported into\n"
                "Wireshark by transforming the file with\n"
                "\tod -Ax -tx1 -v stream.dump > stream.dump.hex\n"
                "And then loading test_output.dump.hex into Wireshark using\n"
                "the \"Import from Hex Dump...\" option and selecting the\n"
                "TCP encapsulation option.\n", tmpDirName);
    }
#endif

    printf(" End API Tests\n");
    printf(" Failed/Skipped/Passed/All: %d/%d/%d/%d\n", failed, skipped, passed,
        failed + skipped + passed);
    fflush(stdout);
    return res;
}
