Files
wolfssl/tests/api/test_tls13.c
T
Tobias Frauenschläger 1d15e1f27f Make OCSP stapling request ownership explicit
The OcspRequest carried a "void* ssl" back-pointer that the stapling
paths wrote just before handing the request to the OCSP layer. For the
request cached on the WOLFSSL_CTX that field is shared by every
connection using it, so concurrent handshakes raced on it. Drop the
field and pass the connection to CheckOcspRequest() and
CheckOcspResponse() as an argument instead, which is the only thing it
was ever read for.

Ownership of the cached request was equally implicit. Publication moves
out of CreateOcspRequest() into CreateOcspResponse(), and callers now
learn whether the CTX took ownership from a "ctxOwnsRequest" flag rather
than by comparing pointers against ssl->ctx->certOcspRequest, which was
read without the lock that guards it. The flag and the request are
handed back together on success and both left untouched on failure, so a
caller never decides ownership against a request it is not holding.

The cache is a field of the WOLFSSL_CTX, so serialize it with a lock
scoped to the CTX. SSL_CM(ssl) can resolve to a per-SSL cert manager
when WOLFSSL_LOCAL_X509_STORE is defined, which left two connections on
one CTX taking different locks for a check-then-set on the same pointer.
GetCtxOcspLock() keys off ssl->ctx->cm for both the reader and the
publisher, and a failure to take it is logged instead of silently
disabling the cache.

CheckOcspRequest() also loses its heap argument. It was only ever the
hint for the response buffer it hands back, which the caller frees
against the connection, so take it from the connection rather than from
a parameter every caller had to keep in step with its own free.

Smaller fixes in the same paths: zero the caller's response buffer
before the argument check can return, since SendCertificateStatus()
frees it without checking the return code; fold the ocsp_stapling NULL
check into the single early skip so the later uses need no guard;
gate the SetupOcspResp() free on success like the other two callers;
split the three differently owned requests in the
WOLFSSL_CSR2_OCSP_MULTI case into separate variables; and let that
case's allocation failures fall through to its shared cleanup instead of
returning, which leaked an already built leaf response.

Add test_ocsp_ctx_request_cache, which runs three handshakes over one
CTX pair and checks that the later ones reuse the cached request rather
than building another. The responder callback answers with a canned good
response, so stapling runs all the way through and the ownership
decision each connection makes is actually acted on: a connection that
freed the shared request shows up as a use after free on the next pass
and a double free at CTX teardown. The cached request is marked before
the last pass and the encoded request the callback sees is compared,
since a request rebuilt from the same certificate would otherwise be
identical byte for byte. The test is gated on !WOLFSSL_COPY_CERT:
OPENSSL_ALL implies it, and it gives every WOLFSSL its own certificate
copy, which takes the cache out of play. A new ocsp.yml job covers the
plain stapling build, an --enable-all build with the copy turned back
off, and an ASan build.

Also gate test_tls13_pha_status_request on KEEP_PEER_CERT. It checks the
received client certificate with wolfSSL_get_peer_certificate(), which is
only built when that macro is defined, so a post-handshake auth build with
stapling but without the OpenSSL compatibility layer failed to link
tests/unit.test.

Fixes F-7230 and F-7231.
2026-07-31 22:02:42 +02:00

8868 lines
345 KiB
C

/* test_tls13.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <tests/unit.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#include <wolfssl/ssl.h>
#include <wolfssl/internal.h>
#include <tests/api/api.h>
#include <tests/utils.h>
#include <tests/api/test_tls13.h>
#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER)
#ifdef WC_SHA384_DIGEST_SIZE
WC_MAYBE_UNUSED static byte fixedKey[WC_SHA384_DIGEST_SIZE] = { 0, };
#else
WC_MAYBE_UNUSED static byte fixedKey[WC_SHA256_DIGEST_SIZE] = { 0, };
#endif
#endif
#ifdef WOLFSSL_EARLY_DATA
static const char earlyData[] = "Early Data";
static char earlyDataBuffer[1];
#endif
int test_tls13_apis(void)
{
EXPECT_DECLS;
#ifdef WOLFSSL_TLS13
#if defined(HAVE_SUPPORTED_CURVES) && defined(HAVE_ECC) && \
(!defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT))
int ret;
#endif
#ifndef WOLFSSL_NO_TLS12
#ifndef NO_WOLFSSL_CLIENT
WOLFSSL_CTX* clientTls12Ctx = NULL;
WOLFSSL* clientTls12Ssl = NULL;
#endif
#ifndef NO_WOLFSSL_SERVER
WOLFSSL_CTX* serverTls12Ctx = NULL;
WOLFSSL* serverTls12Ssl = NULL;
#endif
#endif
#ifndef NO_WOLFSSL_CLIENT
WOLFSSL_CTX* clientCtx = NULL;
WOLFSSL* clientSsl = NULL;
#endif
#ifndef NO_WOLFSSL_SERVER
WOLFSSL_CTX* serverCtx = NULL;
WOLFSSL* serverSsl = NULL;
#if !defined(NO_CERTS) && !defined(NO_FILESYSTEM)
#ifndef NO_RSA
const char* ourCert = svrCertFile;
const char* ourKey = svrKeyFile;
#elif defined(HAVE_ECC)
const char* ourCert = eccCertFile;
const char* ourKey = eccKeyFile;
#elif defined(HAVE_ED25519)
const char* ourCert = edCertFile;
const char* ourKey = edKeyFile;
#elif defined(HAVE_ED448)
const char* ourCert = ed448CertFile;
const char* ourKey = ed448KeyFile;
#endif
#endif
#endif
int required;
#ifdef WOLFSSL_EARLY_DATA
int outSz;
#endif
#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
int groups[2] = { WOLFSSL_ECC_SECP256R1,
#if defined(WOLFSSL_HAVE_MLKEM) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
!defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
#ifdef WOLFSSL_MLKEM_KYBER
#ifndef WOLFSSL_NO_KYBER512
WOLFSSL_KYBER_LEVEL1
#elif !defined(WOLFSSL_NO_KYBER768)
WOLFSSL_KYBER_LEVEL3
#else
WOLFSSL_KYBER_LEVEL5
#endif
#elif !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
#ifndef WOLFSSL_NO_ML_KEM_512
WOLFSSL_ML_KEM_512
#elif !defined(WOLFSSL_NO_ML_KEM_768)
WOLFSSL_ML_KEM_768
#else
WOLFSSL_ML_KEM_1024
#endif
#else
#ifndef WOLFSSL_NO_ML_KEM_768
WOLFSSL_SECP256R1MLKEM768
#else
WOLFSSL_ECC_SECP256R1
#endif
#endif
#else
WOLFSSL_ECC_SECP256R1
#endif
};
#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT)
int bad_groups[2] = { 0xDEAD, 0xBEEF };
#endif /* !NO_WOLFSSL_SERVER || !NO_WOLFSSL_CLIENT */
int numGroups = 2;
#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_CLIENT)
int too_many_groups[WOLFSSL_MAX_GROUP_COUNT + 1];
#endif
#endif
#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC)
char groupList[] =
#ifdef HAVE_CURVE25519
"X25519:"
#endif
#ifdef HAVE_CURVE448
"X448:"
#endif
#ifndef NO_ECC_SECP
#if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521
"P-521:secp521r1:"
#endif
#if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384
"P-384:secp384r1:"
#endif
#if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256
"P-256:secp256r1"
#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_MALLOC) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
!defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
#ifdef WOLFSSL_MLKEM_KYBER
#ifndef WOLFSSL_NO_KYBER512
":P256_KYBER_LEVEL1"
#elif !defined(WOLFSSL_NO_KYBER768)
":P256_KYBER_LEVEL3"
#elif !defined(WOLFSSL_NO_KYBER1024)
":P256_KYBER_LEVEL5"
#endif
#else
#if !defined(WOLFSSL_NO_ML_KEM_512) && defined(WOLFSSL_EXTRA_PQC_HYBRIDS)
":SecP256r1MLKEM512"
#elif !defined(WOLFSSL_NO_ML_KEM_768) && defined(WOLFSSL_PQC_HYBRIDS)
":SecP256r1MLKEM768"
#elif !defined(WOLFSSL_NO_ML_KEM_1024) && defined(WOLFSSL_PQC_HYBRIDS)
":SecP384r1MLKEM1024"
#elif !defined(WOLFSSL_NO_ML_KEM_1024) && \
!defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
":ML_KEM_1024"
#elif !defined(WOLFSSL_NO_ML_KEM_768) && \
!defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
":ML_KEM_768"
#endif
#endif
#endif
#endif
#endif /* !defined(NO_ECC_SECP) */
#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_MALLOC) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
!defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
#ifdef WOLFSSL_MLKEM_KYBER
#ifndef WOLFSSL_NO_KYBER512
":KYBER_LEVEL1"
#elif !defined(WOLFSSL_NO_KYBER768)
":KYBER_LEVEL3"
#elif !defined(WOLFSSL_NO_KYBER1024)
":KYBER_LEVEL5"
#endif
#elif !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
#if !defined(WOLFSSL_NO_ML_KEM_512)
":ML_KEM_512"
#elif !defined(WOLFSSL_NO_ML_KEM_768)
":ML_KEM_768"
#elif !defined(WOLFSSL_NO_ML_KEM_1024)
":ML_KEM_1024"
#endif
#endif
#endif
"";
#endif /* defined(OPENSSL_EXTRA) && defined(HAVE_ECC) */
#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_MALLOC) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
!defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
defined(HAVE_SUPPORTED_CURVES) && \
(!defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) || \
(defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768)) || \
(defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768)))
int mlkemLevel;
#endif
#ifndef WOLFSSL_NO_TLS12
#ifndef NO_WOLFSSL_CLIENT
clientTls12Ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method());
clientTls12Ssl = wolfSSL_new(clientTls12Ctx);
#endif
#ifndef NO_WOLFSSL_SERVER
serverTls12Ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method());
#if !defined(NO_CERTS)
#if !defined(NO_FILESYSTEM)
wolfSSL_CTX_use_certificate_chain_file(serverTls12Ctx, ourCert);
wolfSSL_CTX_use_PrivateKey_file(serverTls12Ctx, ourKey,
CERT_FILETYPE);
#elif defined(USE_CERT_BUFFERS_2048)
wolfSSL_CTX_use_certificate_chain_buffer_format(serverTls12Ctx,
server_cert_der_2048, sizeof_server_cert_der_2048,
WOLFSSL_FILETYPE_ASN1);
wolfSSL_CTX_use_PrivateKey_buffer(serverTls12Ctx, server_key_der_2048,
sizeof_server_key_der_2048, WOLFSSL_FILETYPE_ASN1);
#elif defined(USE_CERT_BUFFERS_256)
wolfSSL_CTX_use_certificate_chain_buffer_format(serverTls12Ctx,
serv_ecc_der_256, sizeof_serv_ecc_der_256, WOLFSSL_FILETYPE_ASN1);
wolfSSL_CTX_use_PrivateKey_buffer(serverTls12Ctx, ecc_key_der_256,
sizeof_ecc_key_der_256, WOLFSSL_FILETYPE_ASN1);
#endif
#endif
serverTls12Ssl = wolfSSL_new(serverTls12Ctx);
#endif
#endif
#ifndef NO_WOLFSSL_CLIENT
clientCtx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
clientSsl = wolfSSL_new(clientCtx);
#endif
#ifndef NO_WOLFSSL_SERVER
serverCtx = wolfSSL_CTX_new(wolfTLSv1_3_server_method());
#if !defined(NO_CERTS)
/* ignore load failures, since we just need the server to have a cert set */
#if !defined(NO_FILESYSTEM)
wolfSSL_CTX_use_certificate_chain_file(serverCtx, ourCert);
wolfSSL_CTX_use_PrivateKey_file(serverCtx, ourKey, CERT_FILETYPE);
#elif defined(USE_CERT_BUFFERS_2048)
wolfSSL_CTX_use_certificate_chain_buffer_format(serverCtx,
server_cert_der_2048, sizeof_server_cert_der_2048,
WOLFSSL_FILETYPE_ASN1);
wolfSSL_CTX_use_PrivateKey_buffer(serverCtx, server_key_der_2048,
sizeof_server_key_der_2048, WOLFSSL_FILETYPE_ASN1);
#elif defined(USE_CERT_BUFFERS_256)
wolfSSL_CTX_use_certificate_chain_buffer_format(serverCtx, serv_ecc_der_256,
sizeof_serv_ecc_der_256, WOLFSSL_FILETYPE_ASN1);
wolfSSL_CTX_use_PrivateKey_buffer(serverCtx, ecc_key_der_256,
sizeof_ecc_key_der_256, WOLFSSL_FILETYPE_ASN1);
#endif
#endif
serverSsl = wolfSSL_new(serverCtx);
ExpectNotNull(serverSsl);
#endif
#ifdef WOLFSSL_SEND_HRR_COOKIE
ExpectIntEQ(wolfSSL_send_hrr_cookie(NULL, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
ExpectIntEQ(wolfSSL_send_hrr_cookie(clientSsl, NULL, 0),
WC_NO_ERR_TRACE(SIDE_ERROR));
#endif
#ifndef NO_WOLFSSL_SERVER
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_send_hrr_cookie(serverTls12Ssl, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_send_hrr_cookie(serverSsl, NULL, 0), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_send_hrr_cookie(serverSsl, fixedKey, sizeof(fixedKey)),
WOLFSSL_SUCCESS);
#endif
#endif
#ifdef HAVE_SUPPORTED_CURVES
#ifdef HAVE_ECC
ExpectIntEQ(wolfSSL_UseKeyShare(NULL, WOLFSSL_ECC_SECP256R1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_SERVER
do {
ret = wolfSSL_UseKeyShare(serverSsl, WOLFSSL_ECC_SECP256R1);
#ifdef WOLFSSL_ASYNC_CRYPT
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E))
wolfSSL_AsyncPoll(serverSsl, WOLF_POLL_FLAG_CHECK_HW);
#endif
}
while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
#endif
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
do {
ret = wolfSSL_UseKeyShare(clientTls12Ssl, WOLFSSL_ECC_SECP256R1);
#ifdef WOLFSSL_ASYNC_CRYPT
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E))
wolfSSL_AsyncPoll(clientTls12Ssl, WOLF_POLL_FLAG_CHECK_HW);
#endif
}
while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
#endif
do {
ret = wolfSSL_UseKeyShare(clientSsl, WOLFSSL_ECC_SECP256R1);
#ifdef WOLFSSL_ASYNC_CRYPT
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E))
wolfSSL_AsyncPoll(clientSsl, WOLF_POLL_FLAG_CHECK_HW);
#endif
}
while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
#endif
#elif defined(HAVE_CURVE25519)
ExpectIntEQ(wolfSSL_UseKeyShare(NULL, WOLFSSL_ECC_X25519),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_UseKeyShare(serverSsl, WOLFSSL_ECC_X25519),
WOLFSSL_SUCCESS);
#endif
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_UseKeyShare(clientTls12Ssl, WOLFSSL_ECC_X25519),
WOLFSSL_SUCCESS);
#endif
ExpectIntEQ(wolfSSL_UseKeyShare(clientSsl, WOLFSSL_ECC_X25519),
WOLFSSL_SUCCESS);
#endif
#elif defined(HAVE_CURVE448)
ExpectIntEQ(wolfSSL_UseKeyShare(NULL, WOLFSSL_ECC_X448),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_UseKeyShare(serverSsl, WOLFSSL_ECC_X448),
WOLFSSL_SUCCESS);
#endif
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_UseKeyShare(clientTls12Ssl, WOLFSSL_ECC_X448),
WOLFSSL_SUCCESS);
#endif
ExpectIntEQ(wolfSSL_UseKeyShare(clientSsl, WOLFSSL_ECC_X448),
WOLFSSL_SUCCESS);
#endif
#else
ExpectIntEQ(wolfSSL_UseKeyShare(NULL, WOLFSSL_ECC_SECP256R1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_UseKeyShare(clientTls12Ssl, WOLFSSL_ECC_SECP256R1),
WC_NO_ERR_TRACE(NOT_COMPILED_IN));
#endif
ExpectIntEQ(wolfSSL_UseKeyShare(clientSsl, WOLFSSL_ECC_SECP256R1),
WC_NO_ERR_TRACE(NOT_COMPILED_IN));
#endif
#endif
#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_MALLOC) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
!defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
(!defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) || \
(defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768)) || \
(defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768)))
#ifndef WOLFSSL_NO_ML_KEM
#ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE
#ifndef WOLFSSL_NO_ML_KEM_768
mlkemLevel = WOLFSSL_ML_KEM_768;
#elif !defined(WOLFSSL_NO_ML_KEM_1024)
mlkemLevel = WOLFSSL_ML_KEM_1024;
#else
mlkemLevel = WOLFSSL_ML_KEM_512;
#endif
#else
#if defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768)
mlkemLevel = WOLFSSL_X25519MLKEM768;
#elif defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768)
mlkemLevel = WOLFSSL_SECP256R1MLKEM768;
#endif
#endif
#else
#ifndef WOLFSSL_NO_KYBER768
mlkemLevel = WOLFSSL_KYBER_LEVEL3;
#elif !defined(WOLFSSL_NO_KYBER1024)
mlkemLevel = WOLFSSL_KYBER_LEVEL5;
#else
mlkemLevel = WOLFSSL_KYBER_LEVEL1;
#endif
#endif
ExpectIntEQ(wolfSSL_UseKeyShare(NULL, mlkemLevel),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_UseKeyShare(serverSsl, mlkemLevel),
WOLFSSL_SUCCESS);
#endif
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_UseKeyShare(clientTls12Ssl, mlkemLevel),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_UseKeyShare(clientSsl, mlkemLevel),
WOLFSSL_SUCCESS);
#endif
#endif
ExpectIntEQ(wolfSSL_NoKeyShares(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_NoKeyShares(serverSsl), WC_NO_ERR_TRACE(SIDE_ERROR));
#endif
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_NoKeyShares(clientTls12Ssl), WOLFSSL_SUCCESS);
#endif
ExpectIntEQ(wolfSSL_NoKeyShares(clientSsl), WOLFSSL_SUCCESS);
#endif
#endif /* HAVE_SUPPORTED_CURVES */
ExpectIntEQ(wolfSSL_CTX_no_ticket_TLSv13(NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
ExpectIntEQ(wolfSSL_CTX_no_ticket_TLSv13(clientCtx),
WC_NO_ERR_TRACE(SIDE_ERROR));
#endif
#ifndef NO_WOLFSSL_SERVER
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_CTX_no_ticket_TLSv13(serverTls12Ctx),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_CTX_no_ticket_TLSv13(serverCtx), 0);
#endif
ExpectIntEQ(wolfSSL_no_ticket_TLSv13(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
ExpectIntEQ(wolfSSL_no_ticket_TLSv13(clientSsl),
WC_NO_ERR_TRACE(SIDE_ERROR));
#endif
#ifndef NO_WOLFSSL_SERVER
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_no_ticket_TLSv13(serverTls12Ssl),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_no_ticket_TLSv13(serverSsl), 0);
#endif
ExpectIntEQ(wolfSSL_CTX_no_dhe_psk(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_CTX_no_dhe_psk(clientTls12Ctx),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_CTX_no_dhe_psk(clientCtx), 0);
#endif
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_CTX_no_dhe_psk(serverCtx), 0);
#endif
ExpectIntEQ(wolfSSL_no_dhe_psk(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_no_dhe_psk(clientTls12Ssl),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_no_dhe_psk(clientSsl), 0);
#endif
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_no_dhe_psk(serverSsl), 0);
#endif
ExpectIntEQ(wolfSSL_update_keys(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_update_keys(clientTls12Ssl),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_update_keys(clientSsl),
WC_NO_ERR_TRACE(BUILD_MSG_ERROR));
#endif
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_update_keys(serverSsl),
WC_NO_ERR_TRACE(BUILD_MSG_ERROR));
#endif
ExpectIntEQ(wolfSSL_key_update_response(NULL, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_key_update_response(NULL, &required),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_key_update_response(clientTls12Ssl, &required),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_key_update_response(clientSsl, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_key_update_response(serverSsl, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
#if !defined(NO_CERTS) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
ExpectIntEQ(wolfSSL_CTX_allow_post_handshake_auth(NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_CTX_allow_post_handshake_auth(serverCtx),
WC_NO_ERR_TRACE(SIDE_ERROR));
#endif
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_CTX_allow_post_handshake_auth(clientTls12Ctx),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_CTX_allow_post_handshake_auth(clientCtx), 0);
#endif
ExpectIntEQ(wolfSSL_allow_post_handshake_auth(NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_allow_post_handshake_auth(serverSsl),
WC_NO_ERR_TRACE(SIDE_ERROR));
#endif
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_allow_post_handshake_auth(clientTls12Ssl),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_allow_post_handshake_auth(clientSsl), 0);
#endif
ExpectIntEQ(wolfSSL_request_certificate(NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
ExpectIntEQ(wolfSSL_request_certificate(clientSsl),
WC_NO_ERR_TRACE(SIDE_ERROR));
#endif
#ifndef NO_WOLFSSL_SERVER
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_request_certificate(serverTls12Ssl),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_request_certificate(serverSsl),
WC_NO_ERR_TRACE(NOT_READY_ERROR));
#endif
#endif
#ifdef HAVE_ECC
#ifndef WOLFSSL_NO_SERVER_GROUPS_EXT
ExpectIntEQ(wolfSSL_preferred_group(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_preferred_group(serverSsl),
WC_NO_ERR_TRACE(SIDE_ERROR));
#endif
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_preferred_group(clientTls12Ssl),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_preferred_group(clientSsl),
WC_NO_ERR_TRACE(NOT_READY_ERROR));
#endif
#endif
#ifdef HAVE_SUPPORTED_CURVES
ExpectIntEQ(wolfSSL_CTX_set_groups(NULL, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_CTX_set_groups(NULL, groups, numGroups),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_CTX_set_groups(clientTls12Ctx, groups, numGroups),
WOLFSSL_SUCCESS);
#endif
ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, groups,
WOLFSSL_MAX_GROUP_COUNT + 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, groups, numGroups),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, groups, -1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(clientCtx->numGroups, numGroups);
ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, bad_groups, numGroups),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_CTX_set_groups(serverCtx, groups, numGroups),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_set_groups(serverCtx, bad_groups, numGroups),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_set_groups(NULL, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
ExpectIntEQ(wolfSSL_set_groups(clientSsl, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_set_groups(NULL, groups, numGroups),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_set_groups(clientTls12Ssl, groups, numGroups),
WOLFSSL_SUCCESS);
#endif
ExpectIntEQ(wolfSSL_set_groups(clientSsl, groups,
WOLFSSL_MAX_GROUP_COUNT + 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_set_groups(clientSsl, groups, numGroups),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_groups(clientSsl, groups, -1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(clientSsl->numGroups, numGroups);
ExpectIntEQ(wolfSSL_set_groups(clientSsl, bad_groups, numGroups),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_set_groups(serverSsl, groups, numGroups),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_groups(serverSsl, bad_groups, numGroups),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
#ifdef OPENSSL_EXTRA
ExpectIntEQ(wolfSSL_CTX_set1_groups_list(NULL, NULL),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#ifndef NO_WOLFSSL_CLIENT
ExpectIntEQ(wolfSSL_CTX_set1_groups_list(clientCtx, NULL),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif
ExpectIntEQ(wolfSSL_CTX_set1_groups_list(NULL, groupList),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_CLIENT)
{
int idx;
for (idx = 0; idx < WOLFSSL_MAX_GROUP_COUNT + 1; idx++)
too_many_groups[idx] = WOLFSSL_ECC_SECP256R1;
}
ExpectIntEQ(wolfSSL_CTX_set1_groups(clientCtx, too_many_groups,
WOLFSSL_MAX_GROUP_COUNT + 1), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_set1_groups(clientSsl, too_many_groups,
WOLFSSL_MAX_GROUP_COUNT + 1), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_set1_groups(clientCtx, NULL, 1),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_set1_groups(clientSsl, NULL, 1),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_set1_groups(clientCtx, groups, numGroups),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_set1_groups(clientCtx, groups, -1),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(clientCtx->numGroups, numGroups);
ExpectIntEQ(wolfSSL_set1_groups(clientSsl, groups, numGroups),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set1_groups(clientSsl, groups, -1),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(clientSsl->numGroups, numGroups);
#endif
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_CTX_set1_groups_list(clientTls12Ctx, groupList),
WOLFSSL_SUCCESS);
#endif
ExpectIntEQ(wolfSSL_CTX_set1_groups_list(clientCtx, groupList),
WOLFSSL_SUCCESS);
#endif
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_CTX_set1_groups_list(serverCtx, groupList),
WOLFSSL_SUCCESS);
#endif
ExpectIntEQ(wolfSSL_set1_groups_list(NULL, NULL),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#ifndef NO_WOLFSSL_CLIENT
ExpectIntEQ(wolfSSL_set1_groups_list(clientSsl, NULL),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif
ExpectIntEQ(wolfSSL_set1_groups_list(NULL, groupList),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_set1_groups_list(clientTls12Ssl, groupList),
WOLFSSL_SUCCESS);
#endif
ExpectIntEQ(wolfSSL_set1_groups_list(clientSsl, groupList),
WOLFSSL_SUCCESS);
#endif
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_set1_groups_list(serverSsl, groupList),
WOLFSSL_SUCCESS);
#endif
#endif /* OPENSSL_EXTRA */
#endif /* HAVE_SUPPORTED_CURVES */
#endif /* HAVE_ECC */
#ifdef WOLFSSL_EARLY_DATA
#ifndef OPENSSL_EXTRA
ExpectIntEQ(wolfSSL_CTX_set_max_early_data(NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_CTX_get_max_early_data(NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#else
ExpectIntEQ(SSL_CTX_set_max_early_data(NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(SSL_CTX_get_max_early_data(NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
#ifndef NO_WOLFSSL_CLIENT
#ifndef OPENSSL_EXTRA
ExpectIntEQ(wolfSSL_CTX_set_max_early_data(clientCtx, 0),
WC_NO_ERR_TRACE(SIDE_ERROR));
ExpectIntEQ(wolfSSL_CTX_get_max_early_data(clientCtx),
WC_NO_ERR_TRACE(SIDE_ERROR));
#else
ExpectIntEQ(SSL_CTX_set_max_early_data(clientCtx, 0),
WC_NO_ERR_TRACE(SIDE_ERROR));
ExpectIntEQ(SSL_CTX_get_max_early_data(clientCtx),
WC_NO_ERR_TRACE(SIDE_ERROR));
#endif
#endif
#ifndef NO_WOLFSSL_SERVER
#ifndef WOLFSSL_NO_TLS12
#ifndef OPENSSL_EXTRA
ExpectIntEQ(wolfSSL_CTX_set_max_early_data(serverTls12Ctx, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_CTX_get_max_early_data(serverTls12Ctx),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#else
ExpectIntEQ(SSL_CTX_set_max_early_data(serverTls12Ctx, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(SSL_CTX_get_max_early_data(serverTls12Ctx),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
#endif
#ifndef OPENSSL_EXTRA
#ifdef WOLFSSL_ERROR_CODE_OPENSSL
ExpectIntEQ(wolfSSL_CTX_set_max_early_data(serverCtx, 32),
WOLFSSL_SUCCESS);
#else
ExpectIntEQ(wolfSSL_CTX_set_max_early_data(serverCtx, 32), 0);
#endif
ExpectIntEQ(wolfSSL_CTX_get_max_early_data(serverCtx), 32);
#else
ExpectIntEQ(SSL_CTX_set_max_early_data(serverCtx, 32), 1);
ExpectIntEQ(SSL_CTX_get_max_early_data(serverCtx), 32);
#endif
#endif
#ifndef OPENSSL_EXTRA
ExpectIntEQ(wolfSSL_set_max_early_data(NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_get_max_early_data(NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#else
ExpectIntEQ(SSL_set_max_early_data(NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(SSL_get_max_early_data(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
#ifndef NO_WOLFSSL_CLIENT
#ifndef OPENSSL_EXTRA
#ifdef WOLFSSL_ERROR_CODE_OPENSSL
ExpectIntEQ(wolfSSL_set_max_early_data(clientSsl, 17), WOLFSSL_SUCCESS);
#else
ExpectIntEQ(wolfSSL_set_max_early_data(clientSsl, 17), 0);
#endif
ExpectIntEQ(wolfSSL_get_max_early_data(clientSsl), 17);
#else
ExpectIntEQ(SSL_set_max_early_data(clientSsl, 17), WOLFSSL_SUCCESS);
ExpectIntEQ(SSL_get_max_early_data(clientSsl), 17);
#endif
#endif
#ifndef NO_WOLFSSL_SERVER
#ifndef WOLFSSL_NO_TLS12
#ifndef OPENSSL_EXTRA
ExpectIntEQ(wolfSSL_set_max_early_data(serverTls12Ssl, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_get_max_early_data(serverTls12Ssl),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#else
ExpectIntEQ(SSL_set_max_early_data(serverTls12Ssl, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(SSL_get_max_early_data(serverTls12Ssl),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
#endif
#ifndef OPENSSL_EXTRA
#ifdef WOLFSSL_ERROR_CODE_OPENSSL
ExpectIntEQ(wolfSSL_set_max_early_data(serverSsl, 16), WOLFSSL_SUCCESS);
#else
ExpectIntEQ(wolfSSL_set_max_early_data(serverSsl, 16), 0);
#endif
ExpectIntEQ(wolfSSL_get_max_early_data(serverSsl), 16);
#else
ExpectIntEQ(SSL_set_max_early_data(serverSsl, 16), 1);
ExpectIntEQ(SSL_get_max_early_data(serverSsl), 16);
#endif
#endif
ExpectIntEQ(wolfSSL_write_early_data(NULL, earlyData, sizeof(earlyData),
&outSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_CLIENT
ExpectIntEQ(wolfSSL_write_early_data(clientSsl, NULL, sizeof(earlyData),
&outSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_write_early_data(clientSsl, earlyData, -1, &outSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_write_early_data(clientSsl, earlyData,
sizeof(earlyData), NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_write_early_data(serverSsl, earlyData,
sizeof(earlyData), &outSz), WC_NO_ERR_TRACE(SIDE_ERROR));
#endif
#ifndef NO_WOLFSSL_CLIENT
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_write_early_data(clientTls12Ssl, earlyData,
sizeof(earlyData), &outSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
/* invoking without session or psk cbs */
ExpectIntEQ(wolfSSL_write_early_data(clientSsl, earlyData,
sizeof(earlyData), &outSz), WC_NO_ERR_TRACE(BAD_STATE_E));
/* verify *outSz is initialized to 0 even on non-success paths */
outSz = 42;
ExpectIntEQ(wolfSSL_write_early_data(clientSsl, earlyData,
sizeof(earlyData), &outSz), WC_NO_ERR_TRACE(BAD_STATE_E));
ExpectIntEQ(outSz, 0);
#endif
ExpectIntEQ(wolfSSL_read_early_data(NULL, earlyDataBuffer,
sizeof(earlyDataBuffer), &outSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef NO_WOLFSSL_SERVER
ExpectIntEQ(wolfSSL_read_early_data(serverSsl, NULL,
sizeof(earlyDataBuffer), &outSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_read_early_data(serverSsl, earlyDataBuffer, -1,
&outSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_read_early_data(serverSsl, earlyDataBuffer,
sizeof(earlyDataBuffer), NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
#ifndef NO_WOLFSSL_CLIENT
ExpectIntEQ(wolfSSL_read_early_data(clientSsl, earlyDataBuffer,
sizeof(earlyDataBuffer), &outSz), WC_NO_ERR_TRACE(SIDE_ERROR));
#endif
#ifndef NO_WOLFSSL_SERVER
#ifndef WOLFSSL_NO_TLS12
ExpectIntEQ(wolfSSL_read_early_data(serverTls12Ssl, earlyDataBuffer,
sizeof(earlyDataBuffer), &outSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
ExpectIntEQ(wolfSSL_read_early_data(serverSsl, earlyDataBuffer,
sizeof(earlyDataBuffer), &outSz), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
#endif
#endif
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_EARLY_DATA)
ExpectIntLT(SSL_get_early_data_status(NULL), 0);
#endif
#ifndef NO_WOLFSSL_SERVER
wolfSSL_free(serverSsl);
wolfSSL_CTX_free(serverCtx);
#endif
#ifndef NO_WOLFSSL_CLIENT
wolfSSL_free(clientSsl);
wolfSSL_CTX_free(clientCtx);
#endif
#ifndef WOLFSSL_NO_TLS12
#ifndef NO_WOLFSSL_SERVER
wolfSSL_free(serverTls12Ssl);
wolfSSL_CTX_free(serverTls12Ctx);
#endif
#ifndef NO_WOLFSSL_CLIENT
wolfSSL_free(clientTls12Ssl);
wolfSSL_CTX_free(clientTls12Ctx);
#endif
#endif
#endif /* WOLFSSL_TLS13 */
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
!defined(NO_PSK)
int test_tls13_cert_with_extern_psk_apis(void)
{
EXPECT_DECLS;
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
ExpectIntEQ(wolfSSL_CTX_set_cert_with_extern_psk(NULL, 0), WOLFSSL_FAILURE);
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(NULL, 0), WOLFSSL_FAILURE);
ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
ExpectNotNull(ctx);
ssl = wolfSSL_new(ctx);
ExpectNotNull(ssl);
if (EXPECT_SUCCESS()) {
/* Any non-zero value enables cert_with_extern_psk. */
ExpectIntEQ(wolfSSL_CTX_set_cert_with_extern_psk(ctx, -1),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_set_cert_with_extern_psk(ctx, 2),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl, -1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl, 2), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_set_cert_with_extern_psk(ctx, 1),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl, 0), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl, 1), WOLFSSL_SUCCESS);
}
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
return EXPECT_RESULT();
}
#else
int test_tls13_cert_with_extern_psk_apis(void)
{
return TEST_SKIPPED;
}
#endif
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
!defined(NO_PSK) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
/* 32-byte external PSK (SHA-256 digest size) used by cwep test callbacks. */
static const unsigned char test_tls13_cwep_psk[32] = {
0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A
};
static unsigned int test_tls13_cwep_client_cb(WOLFSSL* ssl, const char* hint,
char* identity, unsigned int id_max_len, unsigned char* key,
unsigned int key_max_len)
{
(void)ssl;
(void)hint;
if (id_max_len == 0 || key_max_len < sizeof(test_tls13_cwep_psk))
return 0;
XSTRNCPY(identity, "cwep_client", id_max_len);
XMEMCPY(key, test_tls13_cwep_psk, sizeof(test_tls13_cwep_psk));
return (unsigned int)sizeof(test_tls13_cwep_psk);
}
static unsigned int test_tls13_cwep_server_cb(WOLFSSL* ssl, const char* id,
unsigned char* key, unsigned int key_max_len)
{
(void)ssl;
if (key_max_len < sizeof(test_tls13_cwep_psk) || id == NULL)
return 0;
if (XSTRCMP(id, "cwep_client") != 0)
return 0;
XMEMCPY(key, test_tls13_cwep_psk, sizeof(test_tls13_cwep_psk));
return (unsigned int)sizeof(test_tls13_cwep_psk);
}
#endif
int test_tls13_cert_with_extern_psk_handshake(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
!defined(NO_PSK) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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 appMsg[] = "cert_with_extern_psk test";
char readBuf[sizeof(appMsg)];
int readSz;
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);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_PEER, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
#if !defined(NO_CERTS) && !defined(NO_FILESYSTEM)
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_load_verify_locations(ctx_c, caEccCertFile,
NULL) == WOLFSSL_SUCCESS);
#elif !defined(NO_RSA)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_load_verify_locations(ctx_c, caCertFile,
NULL) == WOLFSSL_SUCCESS);
#endif
#endif
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_cwep_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_cwep_server_cb);
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl_c, 1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl_s, 1), WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(ssl_c->options.pskNegotiated, 1);
ExpectIntEQ(ssl_s->options.pskNegotiated, 1);
ExpectIntEQ(ssl_c->options.certWithExternPsk, 1);
ExpectIntEQ(ssl_s->options.certWithExternPsk, 1);
ExpectIntEQ(ssl_c->msgsReceived.got_certificate, 1);
ExpectIntEQ(ssl_c->msgsReceived.got_certificate_verify, 1);
/* Verify application data exchange works with the derived keys. */
ExpectIntEQ(wolfSSL_write(ssl_c, appMsg, (int)XSTRLEN(appMsg)),
(int)XSTRLEN(appMsg));
readSz = wolfSSL_read(ssl_s, readBuf, sizeof(readBuf));
ExpectIntEQ(readSz, (int)XSTRLEN(appMsg));
ExpectIntEQ(XMEMCMP(readBuf, appMsg, (size_t)readSz), 0);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_cert_with_extern_psk_client_requires_cert(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
!defined(NO_PSK) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && !defined(NO_CERTS) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
/* The client requests cert_with_extern_psk and mandates a peer certificate
* (WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT). The server negotiates the external
* PSK but does NOT enable cert_with_extern_psk, so it completes a PSK-only
* handshake without sending a Certificate/CertificateVerify. The client
* must therefore reject in DoTls13Finished with NO_PEER_CERT instead of
* accepting a PSK-only handshake. */
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_cwep_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_cwep_server_cb);
/* Only the client requests cert_with_extern_psk. */
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl_c, 1), WOLFSSL_SUCCESS);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(NO_PEER_CERT));
ExpectIntEQ(ssl_c->options.pskNegotiated, 1);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_cert_with_extern_psk_requires_key_share(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
!defined(NO_PSK) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
#if !defined(NO_CERTS) && !defined(NO_FILESYSTEM)
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#elif !defined(NO_RSA)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#endif
#endif
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_cwep_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_cwep_server_cb);
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl_c, 1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl_s, 1), WOLFSSL_SUCCESS);
/* Omit key_share in CH1 to force the server to send an HRR. */
ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c), WOLFSSL_SUCCESS);
/* CH1: client -> server (no key_share). */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WOLFSSL_ERROR_WANT_READ);
/* HRR: server reads CH1, sends HRR requesting a key_share group. */
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WOLFSSL_ERROR_WANT_READ);
ExpectIntEQ(ssl_s->options.serverState,
SERVER_HELLO_RETRY_REQUEST_COMPLETE);
/* Complete the handshake: client sends CH2 (with key_share), server
* responds with SH + cert + cert-verify + Finished, client finishes. */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
/* Verify that cert_with_extern_psk was negotiated end-to-end. */
ExpectIntEQ(ssl_c->options.pskNegotiated, 1);
ExpectIntEQ(ssl_s->options.pskNegotiated, 1);
ExpectIntEQ(ssl_c->options.certWithExternPsk, 1);
ExpectIntEQ(ssl_s->options.certWithExternPsk, 1);
ExpectIntEQ(ssl_c->msgsReceived.got_certificate, 1);
ExpectIntEQ(ssl_c->msgsReceived.got_certificate_verify, 1);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_cert_with_extern_psk_rejects_resumption(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
!defined(NO_PSK) && defined(HAVE_SESSION_TICKET) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
(defined(HAVE_ECC) || !defined(NO_RSA))
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
WOLFSSL_SESSION *sess = NULL;
struct test_memio_ctx test_ctx;
byte readBuf[16];
/* Step 1: plain TLS 1.3 handshake to obtain a session ticket. The same
* server CTX is reused below so the ticket encryption key matches. */
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);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
/* Load on ssl_s, not ctx_s: ssl_s already exists (test_memio_setup created
* it) and shares the CTX key buffers. Reloading on ctx_s would free those
* buffers, leaving ssl_s with a dangling key that crashes when the server
* decodes it for CertificateVerify. */
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#endif
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Drain the NewSessionTicket post-handshake message. */
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
wolfSSL_free(ssl_c);
ssl_c = NULL;
wolfSSL_free(ssl_s);
ssl_s = NULL;
/* Step 2: attempt to resume while also offering cert_with_extern_psk.
* RFC 9973 Sect. 5.1 requires all PSKs offered alongside
* cert_with_extern_psk to be external PSKs. The client MUST therefore
* suppress the resumption ticket identity from the pre_shared_key
* extension. The handshake succeeds as a cert_with_extern_psk handshake
* using only the external PSK. */
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);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_cwep_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_cwep_server_cb);
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl_c, 1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl_s, 1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
/* Handshake succeeds; the client correctly omits the resumption ticket. */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
/* Verify we got a cert_with_extern_psk handshake, not a resumption. */
ExpectIntEQ(ssl_c->options.certWithExternPsk, 1);
ExpectIntEQ(ssl_s->options.certWithExternPsk, 1);
wolfSSL_SESSION_free(sess);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
!defined(NO_PSK) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
/* Locate the extensions block of a TLS 1.3 ServerHello record. On success,
* writes the offset of the 2-byte extensions_length field into *ext_len_off
* and returns 0. Returns -1 on malformed input. Only the plaintext SH
* record (type 0x16, handshake subtype 0x02) is supported. */
static int test_cwep_sh_find_ext_block(const byte* sh, int sh_len,
int* ext_len_off)
{
int idx;
int sid_len;
/* 5 byte record hdr + 4 byte handshake hdr + 2 byte legacy_version
* + 32 byte random + 1 byte legacy_session_id length. */
if (sh_len < 5 + 4 + 2 + 32 + 1)
return -1;
if (sh[0] != 0x16 || sh[5] != 0x02)
return -1;
idx = 5 + 4 + 2 + 32;
sid_len = sh[idx];
idx += 1 + sid_len + 2 + 1; /* skip sid + cipher_suite + compression */
if (idx + 2 > sh_len)
return -1;
*ext_len_off = idx;
return 0;
}
/* Apply a delta to the record, handshake and extensions length fields of a
* TLS 1.3 SH record. Negative values shrink the message. */
static void test_cwep_sh_adjust_lengths(byte* sh, int ext_len_off, int delta)
{
int v;
v = (int)(((word32)sh[3] << 8) | sh[4]) + delta;
sh[3] = (byte)(v >> 8);
sh[4] = (byte)v;
v = (int)(((word32)sh[6] << 16) | ((word32)sh[7] << 8) | sh[8]) + delta;
sh[6] = (byte)(v >> 16);
sh[7] = (byte)(v >> 8);
sh[8] = (byte)v;
v = (int)(((word32)sh[ext_len_off] << 8) | sh[ext_len_off + 1]) + delta;
sh[ext_len_off] = (byte)(v >> 8);
sh[ext_len_off + 1] = (byte)v;
}
/* Remove the first extension of the given type from a TLS 1.3 SH record.
* Returns the new record length, or -1 if the extension was not present. */
static int test_cwep_sh_strip_extension(byte* sh, int sh_len, word16 ext_type)
{
int ext_len_off;
int ext_base, ext_end;
int p;
word16 ext_total;
if (test_cwep_sh_find_ext_block(sh, sh_len, &ext_len_off) != 0)
return -1;
ext_total = (word16)(((word16)sh[ext_len_off] << 8) | sh[ext_len_off + 1]);
ext_base = ext_len_off + 2;
ext_end = ext_base + ext_total;
if (ext_end > sh_len)
return -1;
p = ext_base;
while (p + 4 <= ext_end) {
word16 t = (word16)(((word16)sh[p] << 8) | sh[p + 1]);
word16 l = (word16)(((word16)sh[p + 2] << 8) | sh[p + 3]);
int entry = 4 + (int)l;
if (p + entry > ext_end)
return -1;
if (t == ext_type) {
XMEMMOVE(sh + p, sh + p + entry,
(size_t)(sh_len - p - entry));
test_cwep_sh_adjust_lengths(sh, ext_len_off, -entry);
return sh_len - entry;
}
p += entry;
}
return -1;
}
#if defined(HAVE_SESSION_TICKET)
/* Append a zero-length extension of the given type to a TLS 1.3 SH record.
* The SH body must be the tail of the record, which is the normal case. */
static int test_cwep_sh_append_empty_extension(byte* sh, int sh_len,
int sh_cap, word16 ext_type)
{
int ext_len_off;
int ext_base, ext_end;
word16 ext_total;
if (test_cwep_sh_find_ext_block(sh, sh_len, &ext_len_off) != 0)
return -1;
ext_total = (word16)(((word16)sh[ext_len_off] << 8) | sh[ext_len_off + 1]);
ext_base = ext_len_off + 2;
ext_end = ext_base + ext_total;
if (ext_end != sh_len)
return -1;
if (sh_len + 4 > sh_cap)
return -1;
sh[sh_len + 0] = (byte)(ext_type >> 8);
sh[sh_len + 1] = (byte)ext_type;
sh[sh_len + 2] = 0;
sh[sh_len + 3] = 0;
test_cwep_sh_adjust_lengths(sh, ext_len_off, 4);
return sh_len + 4;
}
#endif /* HAVE_SESSION_TICKET */
#endif
int test_tls13_cert_with_extern_psk_sh_missing_key_share(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
!defined(NO_PSK) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
(defined(HAVE_ECC) || !defined(NO_RSA))
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
byte sh_buf[4096];
const char* sh_bytes = NULL;
int sh_sz = 0;
int new_sz;
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);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
/* Load on ssl_s, not ctx_s: ssl_s already exists (test_memio_setup created
* it) and shares the CTX key buffers. Reloading on ctx_s would free those
* buffers, leaving ssl_s with a dangling key that crashes when the server
* decodes it for CertificateVerify. */
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#endif
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_cwep_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_cwep_server_cb);
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl_c, 1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl_s, 1), WOLFSSL_SUCCESS);
/* Drive the client to emit the ClientHello, then let the server produce
* its flight. */
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);
/* The first "message" recorded by memio may contain several concatenated
* records (SH + CCS + first encrypted handshake record). Slice the
* plaintext SH record out using its own length field. */
ExpectIntEQ(test_memio_get_message(&test_ctx, 1, &sh_bytes, &sh_sz, 0), 0);
if (sh_sz >= 5 && (byte)sh_bytes[0] == 0x16) {
int rec_body = ((int)(byte)sh_bytes[3] << 8) | (byte)sh_bytes[4];
sh_sz = 5 + rec_body;
}
ExpectTrue(sh_sz > 0 && sh_sz <= (int)sizeof(sh_buf));
if (sh_sz > 0 && sh_sz <= (int)sizeof(sh_buf)) {
XMEMCPY(sh_buf, sh_bytes, (size_t)sh_sz);
/* Strip the key_share extension from the SH so the resulting SH
* confirms cert_with_extern_psk without negotiating (EC)DHE. */
new_sz = test_cwep_sh_strip_extension(sh_buf, sh_sz, 0x0033);
ExpectIntGT(new_sz, 0);
}
else {
new_sz = -1;
}
/* Throw away the entire server flight and feed only the tampered SH. */
test_memio_clear_buffer(&test_ctx, 1);
if (new_sz > 0) {
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1,
(const char*)sh_buf, new_sz), 0);
}
/* Client must reject the SH with EXT_MISSING. */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
EXT_MISSING);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_cert_with_extern_psk_sh_confirms_resumption(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
!defined(NO_PSK) && defined(HAVE_SESSION_TICKET) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
(defined(HAVE_ECC) || !defined(NO_RSA))
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
WOLFSSL_SESSION *sess = NULL;
struct test_memio_ctx test_ctx;
byte sh_buf[4096];
const char* sh_bytes = NULL;
byte drain[16];
int sh_sz = 0;
int new_sz;
/* Phase 1: plain handshake so the client gets a session ticket. The
* server CTX is reused below to keep the ticket encryption key. */
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);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
/* Load on ssl_s, not ctx_s: ssl_s already exists (test_memio_setup created
* it) and shares the CTX key buffers. Reloading on ctx_s would free those
* buffers, leaving ssl_s with a dangling key that crashes when the server
* decodes it for CertificateVerify. */
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#endif
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Drain the NewSessionTicket post-handshake message. */
ExpectIntEQ(wolfSSL_read(ssl_c, drain, sizeof(drain)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
wolfSSL_free(ssl_c);
ssl_c = NULL;
wolfSSL_free(ssl_s);
ssl_s = NULL;
/* Phase 2: client resumes WITHOUT cert_with_extern_psk. The server
* performs a normal resumption. We then tamper the SH to inject an
* unsolicited cert_with_extern_psk extension. The client must reject
* it because it never offered the extension. */
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);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
/* Run client CH then server flight. */
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);
ExpectIntEQ(test_memio_get_message(&test_ctx, 1, &sh_bytes, &sh_sz, 0), 0);
if (sh_sz >= 5 && (byte)sh_bytes[0] == 0x16) {
int rec_body = ((int)(byte)sh_bytes[3] << 8) | (byte)sh_bytes[4];
sh_sz = 5 + rec_body;
}
ExpectTrue(sh_sz > 0 && sh_sz <= (int)sizeof(sh_buf));
if (sh_sz > 0 && sh_sz <= (int)sizeof(sh_buf)) {
XMEMCPY(sh_buf, sh_bytes, (size_t)sh_sz);
/* Append an unsolicited cert_with_extern_psk (0x0021) extension.
* The client never offered this extension, so it must be rejected. */
new_sz = test_cwep_sh_append_empty_extension(sh_buf, sh_sz,
(int)sizeof(sh_buf), 0x0021);
ExpectIntGT(new_sz, 0);
}
else {
new_sz = -1;
}
test_memio_clear_buffer(&test_ctx, 1);
if (new_sz > 0) {
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1,
(const char*)sh_buf, new_sz), 0);
}
/* Client must reject the unsolicited extension. */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
wolfSSL_SESSION_free(sess);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_api(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT)
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
(void)ctx;
(void)ssl;
/* NULL arguments are rejected. */
ExpectIntEQ(wolfSSL_CTX_require_psk(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_require_psk(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* The failNoPSK bit is only settable when external-PSK or session-ticket
* support is compiled in; mirror the guard used by the API itself. */
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
/* wolfSSL_CTX_require_psk() sets the failNoPSK bit on the CTX, and a new
* SSL object inherits it. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
ExpectIntEQ(wolfSSL_CTX_require_psk(ctx), 0);
ExpectIntEQ(ctx->failNoPSK, 1);
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(ssl->options.failNoPSK, 1);
wolfSSL_free(ssl);
ssl = NULL;
wolfSSL_CTX_free(ctx);
ctx = NULL;
/* wolfSSL_require_psk() sets the option directly on the SSL object. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(ssl->options.failNoPSK, 0);
ExpectIntEQ(wolfSSL_require_psk(ssl), 0);
ExpectIntEQ(ssl->options.failNoPSK, 1);
wolfSSL_free(ssl);
ssl = NULL;
wolfSSL_CTX_free(ctx);
ctx = NULL;
/* The requirement is fail-closed: on a downgrade-capable context (created
* from a v23 method) require_psk() disables version downgrade so the
* handshake cannot silently fall back to (D)TLS 1.2 without a PSK. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
ExpectIntEQ(wolfSSL_CTX_require_psk(ctx), 0);
ExpectIntEQ(ctx->method->downgrade, 0);
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(ssl->options.downgrade, 0);
wolfSSL_free(ssl);
ssl = NULL;
wolfSSL_CTX_free(ctx);
ctx = NULL;
#endif
#ifndef WOLFSSL_NO_TLS12
/* The API is TLS 1.3 only - a TLS 1.2 context is rejected so users are not
* misled into thinking the option applies to TLS 1.2. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
ExpectIntEQ(wolfSSL_CTX_require_psk(ctx), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
wolfSSL_CTX_free(ctx);
ctx = NULL;
#endif
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
/* 32-byte external PSK used by the fail-if-no-PSK test callbacks. */
static const unsigned char test_tls13_fnp_psk[32] = {
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A
};
static unsigned int test_tls13_fnp_client_cb(WOLFSSL* ssl, const char* hint,
char* identity, unsigned int id_max_len, unsigned char* key,
unsigned int key_max_len)
{
(void)ssl;
(void)hint;
if (id_max_len == 0 || key_max_len < sizeof(test_tls13_fnp_psk))
return 0;
XSTRNCPY(identity, "fnp_client", id_max_len);
XMEMCPY(key, test_tls13_fnp_psk, sizeof(test_tls13_fnp_psk));
return (unsigned int)sizeof(test_tls13_fnp_psk);
}
static unsigned int test_tls13_fnp_server_cb(WOLFSSL* ssl, const char* id,
unsigned char* key, unsigned int key_max_len)
{
(void)ssl;
if (key_max_len < sizeof(test_tls13_fnp_psk) || id == NULL)
return 0;
if (XSTRCMP(id, "fnp_client") != 0)
return 0;
XMEMCPY(key, test_tls13_fnp_psk, sizeof(test_tls13_fnp_psk));
return (unsigned int)sizeof(test_tls13_fnp_psk);
}
/* Server PSK callback that finds no PSK for any offered identity (returns 0),
* mirroring an application whose lookup misses. */
static unsigned int test_tls13_fnp_reject_server_cb(WOLFSSL* ssl,
const char* id, unsigned char* key, unsigned int key_max_len)
{
(void)ssl;
(void)id;
(void)key;
(void)key_max_len;
return 0;
}
#endif
int test_tls13_fail_if_no_psk_handshake(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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 appMsg[] = "fail_if_no_psk test";
char readBuf[sizeof(appMsg)];
int readSz;
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);
/* Both endpoints require a PSK to be negotiated. */
wolfSSL_require_psk(ssl_c);
wolfSSL_require_psk(ssl_s);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
/* A PSK is configured on both ends, so the handshake completes. */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(ssl_c->options.failNoPSK, 1);
ExpectIntEQ(ssl_s->options.failNoPSK, 1);
ExpectIntEQ(ssl_c->options.pskNegotiated, 1);
ExpectIntEQ(ssl_s->options.pskNegotiated, 1);
/* Application data flows over the PSK-derived keys. */
ExpectIntEQ(wolfSSL_write(ssl_c, appMsg, (int)XSTRLEN(appMsg)),
(int)XSTRLEN(appMsg));
readSz = wolfSSL_read(ssl_s, readBuf, sizeof(readBuf));
ExpectIntEQ(readSz, (int)XSTRLEN(appMsg));
ExpectIntEQ(XMEMCMP(readBuf, appMsg, (size_t)readSz), 0);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_rejects_no_psk(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
(defined(HAVE_ECC) || !defined(NO_RSA))
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,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
/* The server requires a PSK and has one configured, but the client offers
* none. The server must abort the handshake with PSK_MISSING_ERROR rather
* than fall back to a certificate-only handshake. */
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_require_psk(ssl_s);
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#endif
/* Only the server installs a PSK callback; the client sends no PSK. */
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_MISSING_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_client_no_psk_configured(void)
{
EXPECT_DECLS;
/* WOLFSSL_QT force-enables havePSK on every CTX (see wolfSSL_CTX_new), so the
* "no PSK configured" precondition this test relies on cannot be set up there. */
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && !defined(WOLFSSL_QT) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
(defined(HAVE_ECC) || !defined(NO_RSA))
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,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
/* The client requires a PSK but configures none. Because failNoPSK is gated
* on havePSK, this must NOT hard-fail: a normal certificate handshake is
* expected to succeed instead of raising PSK_MISSING_ERROR. */
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_PEER, NULL);
wolfSSL_require_psk(ssl_c);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_load_verify_locations(ctx_c, caEccCertFile,
NULL) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_load_verify_locations(ctx_c, caCertFile,
NULL) == WOLFSSL_SUCCESS);
#endif
ExpectIntEQ(ssl_c->options.failNoPSK, 1);
ExpectIntEQ(ssl_c->options.havePSK, 0);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(ssl_c->options.pskNegotiated, 0);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_client_rejects(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
(defined(HAVE_ECC) || !defined(NO_RSA))
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,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
/* The client requires a PSK and has one configured, but the server has no
* PSK callback so it never selects one. The client must abort with
* PSK_MISSING_ERROR rather than fall back to a cert-only handshake. */
wolfSSL_require_psk(ssl_c);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#endif
/* Only the client installs a PSK callback. */
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_MISSING_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_requires_dhe(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
/* Baseline: a pure psk_ke handshake (no DHE) succeeds when the PSK is
* optional, confirming the setup itself is valid. */
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);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_c), 0);
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_s), 0);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(ssl_s->options.pskNegotiated, 1);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
ssl_c = NULL; ssl_s = NULL; ctx_c = NULL; ctx_s = NULL;
/* With failNoPSK on the server, the same pure psk_ke negotiation (no
* forward secrecy) must be rejected with PSK_KEY_ERROR. */
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);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_require_psk(ssl_s);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_c), 0);
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_s), 0);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_KEY_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_client_requires_dhe(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
/* Only the client mandates the PSK (failNoPSK). The server does NOT set
* failNoPSK and is configured for pure psk_ke (wolfSSL_no_dhe_psk), so it
* accepts the PSK and replies with a ServerHello that omits a key_share.
* When the client processes that ServerHello in SetupPskKey, the mandatory
* external PSK has no (EC)DHE for forward secrecy, so the client must
* reject it with PSK_KEY_ERROR. This exercises the client-side branch that
* the server-only requires_dhe test cannot reach (there the server rejects
* the pure psk_ke negotiation first). */
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);
wolfSSL_require_psk(ssl_c);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
/* Force the server to negotiate a pure psk_ke (no (EC)DHE) exchange. */
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_s), 0);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_KEY_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_resumption_exempt_from_dhe(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && defined(HAVE_SESSION_TICKET) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
(defined(HAVE_ECC) || !defined(NO_RSA))
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
WOLFSSL_SESSION *sess = NULL;
struct test_memio_ctx test_ctx;
byte readBuf[16];
/* Step 1: full TLS 1.3 handshake to obtain a session ticket. The server
* cert/key are already loaded by test_memio_setup; the default ticket
* encryption callback lets a fresh server CTX below decrypt the ticket. */
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);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Drain the NewSessionTicket post-handshake message. */
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
wolfSSL_free(ssl_c); ssl_c = NULL;
wolfSSL_free(ssl_s); ssl_s = NULL;
/* Step 2: resume with a pure psk_ke (no (EC)DHE) exchange while the server
* has the mandatory-PSK requirement set. A session-ticket resumption is
* exempt from the mandatory-(EC)DHE rule, so the handshake must succeed
* (an external PSK in the same situation would be rejected). */
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);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_require_psk(ssl_s);
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_c), 0);
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(ssl_c->options.resuming, 1);
ExpectIntEQ(ssl_s->options.resuming, 1);
wolfSSL_SESSION_free(sess);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_server_rejects_offered_psk(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
/* Baseline: the client offers a PSK but the server's callback rejects it
* (returns 0). Without failNoPSK the server (which has a certificate from
* test_memio_setup) falls back to a normal certificate handshake, which
* succeeds and negotiates no PSK. */
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);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_reject_server_cb);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(ssl_s->options.pskNegotiated, 0);
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;
/* With failNoPSK the same rejected-PSK negotiation must abort with
* PSK_MISSING_ERROR instead of falling back to the certificate handshake. */
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);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_require_psk(ssl_s);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_reject_server_cb);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_MISSING_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_no_cert_server(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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));
/* Build the CTXs manually so the server has NO certificate configured,
* matching a PSK-only deployment. The client offers a PSK, the server's
* callback rejects it, and failNoPSK is set: the server must report
* PSK_MISSING_ERROR (not BAD_BINDER, and no certificate fallback). */
ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
wolfSSL_SetIORecv(ctx_c, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_c, test_memio_write_cb);
/* PSK callbacks are set on the CTX so PSK cipher suites are available when
* the (cert-less) SSL objects are created. */
wolfSSL_CTX_set_psk_client_callback(ctx_c, test_tls13_fnp_client_cb);
ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
wolfSSL_SetIORecv(ctx_s, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_s, test_memio_write_cb);
wolfSSL_CTX_set_psk_server_callback(ctx_s, test_tls13_fnp_reject_server_cb);
wolfSSL_CTX_require_psk(ctx_s);
ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_MISSING_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_dtls13_handshake(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_DTLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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 appMsg[] = "fail_if_no_psk dtls13 test";
char readBuf[sizeof(appMsg)];
int readSz;
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);
/* Both endpoints require a PSK to be negotiated over DTLS 1.3, exercising
* the HRR/cookie flow through DoTls13ServerHello and CheckPreSharedKeys. */
wolfSSL_require_psk(ssl_c);
wolfSSL_require_psk(ssl_s);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
/* A PSK is configured on both ends, so the handshake completes. */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(ssl_c->options.failNoPSK, 1);
ExpectIntEQ(ssl_s->options.failNoPSK, 1);
ExpectIntEQ(ssl_c->options.pskNegotiated, 1);
ExpectIntEQ(ssl_s->options.pskNegotiated, 1);
/* Application data flows over the PSK-derived keys. */
ExpectIntEQ(wolfSSL_write(ssl_c, appMsg, (int)XSTRLEN(appMsg)),
(int)XSTRLEN(appMsg));
readSz = wolfSSL_read(ssl_s, readBuf, sizeof(readBuf));
ExpectIntEQ(readSz, (int)XSTRLEN(appMsg));
ExpectIntEQ(XMEMCMP(readBuf, appMsg, (size_t)readSz), 0);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_dtls13_rejects_no_psk(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_DTLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
(defined(HAVE_ECC) || !defined(NO_RSA))
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);
/* The server requires a PSK and has one configured, but the client offers
* none. Over DTLS 1.3 the server must still abort with PSK_MISSING_ERROR
* rather than fall back to a certificate-only handshake. */
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_require_psk(ssl_s);
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#endif
/* Only the server installs a PSK callback; the client sends no PSK. */
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_MISSING_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
!defined(NO_WOLFSSL_SERVER) && defined(HAVE_ECC) && \
defined(BUILD_TLS_AES_128_GCM_SHA256) && \
defined(BUILD_TLS_AES_256_GCM_SHA384)
/* Called when writing. */
static int CsSend(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 CsRecv(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 -= len;
/* Amount actually copied. */
return len;
}
#endif
int test_tls13_cipher_suites(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
!defined(NO_WOLFSSL_SERVER) && defined(HAVE_ECC) && \
defined(BUILD_TLS_AES_128_GCM_SHA256) && \
defined(BUILD_TLS_AES_256_GCM_SHA384)
WOLFSSL_CTX* ctx = NULL;
WOLFSSL *ssl = NULL;
int i;
byte clientHello[] = {
0x16, 0x03, 0x03, 0x01, 0x9b, 0x01, 0x00, 0x01,
0x97, 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,
/* Cipher suites: 0x13, 0x01 = TLS13-AES128-GCM-SHA256, twice. */
0x13, 0x01,
0x13, 0x01, 0x01, 0x00, 0x01, 0x4a, 0x00, 0x2d,
0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x33, 0x00,
0x47, 0x00, 0x45, 0x00, 0x17, 0x00, 0x41, 0x04,
0x90, 0xfc, 0xe2, 0x97, 0x05, 0x7c, 0xb5, 0x23,
0x5d, 0x5f, 0x5b, 0xcd, 0x0c, 0x1e, 0xe0, 0xe9,
0xab, 0x38, 0x6b, 0x1e, 0x20, 0x5c, 0x1c, 0x90,
0x2a, 0x9e, 0x68, 0x8e, 0x70, 0x05, 0x10, 0xa8,
0x02, 0x1b, 0xf9, 0x5c, 0xef, 0xc9, 0xaf, 0xca,
0x1a, 0x3b, 0x16, 0x8b, 0xe4, 0x1b, 0x3c, 0x15,
0xb8, 0x0d, 0xbd, 0xaf, 0x62, 0x8d, 0xa7, 0x13,
0xa0, 0x7c, 0xe0, 0x59, 0x0c, 0x4f, 0x8a, 0x6d,
0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04, 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, 0x04, 0x00,
0x02, 0x00, 0x17, 0x00, 0x16, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x29, 0x00, 0xb9, 0x00,
0x94, 0x00, 0x8e, 0x0f, 0x12, 0xfa, 0x84, 0x1f,
0x76, 0x94, 0xd7, 0x09, 0x5e, 0xad, 0x08, 0x51,
0xb6, 0x80, 0x28, 0x31, 0x8b, 0xfd, 0xc6, 0xbd,
0x9e, 0xf5, 0x3b, 0x4d, 0x02, 0xbe, 0x1d, 0x73,
0xea, 0x13, 0x68, 0x00, 0x4c, 0xfd, 0x3d, 0x48,
0x51, 0xf9, 0x06, 0xbb, 0x92, 0xed, 0x42, 0x9f,
0x7f, 0x2c, 0x73, 0x9f, 0xd9, 0xb4, 0xef, 0x05,
0x26, 0x5b, 0x60, 0x5c, 0x0a, 0xfc, 0xa3, 0xbd,
0x2d, 0x2d, 0x8b, 0xf9, 0xaa, 0x5c, 0x96, 0x3a,
0xf2, 0xec, 0xfa, 0xe5, 0x57, 0x2e, 0x87, 0xbe,
0x27, 0xc5, 0x3d, 0x4f, 0x5d, 0xdd, 0xde, 0x1c,
0x1b, 0xb3, 0xcc, 0x27, 0x27, 0x57, 0x5a, 0xd9,
0xea, 0x99, 0x27, 0x23, 0xa6, 0x0e, 0xea, 0x9c,
0x0d, 0x85, 0xcb, 0x72, 0xeb, 0xd7, 0x93, 0xe3,
0xfe, 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, 0xfb, 0x92, 0xce, 0xaa, 0x00, 0x21, 0x20,
0xcb, 0x73, 0x25, 0x80, 0x46, 0x78, 0x4f, 0xe5,
0x34, 0xf6, 0x91, 0x13, 0x7f, 0xc8, 0x8d, 0xdc,
0x81, 0x04, 0xb7, 0x0d, 0x49, 0x85, 0x2e, 0x12,
0x7a, 0x07, 0x23, 0xe9, 0x13, 0xa4, 0x6d, 0x8c
};
WOLFSSL_BUFFER_INFO msg;
/* Offset into ClientHello message data of first cipher suite. */
const int csOff = 78;
/* Server cipher list. */
const char* serverCs = "TLS13-AES256-GCM-SHA384:TLS13-AES128-GCM-SHA256";
/* Suite list with duplicates. */
const char* dupCs = "TLS13-AES128-GCM-SHA256:"
"TLS13-AES128-GCM-SHA256:"
"TLS13-AES256-GCM-SHA384:"
"TLS13-AES256-GCM-SHA384:"
"TLS13-AES128-GCM-SHA256";
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_SET_CIPHER_BYTES)
const byte dupCsBytes[] = { TLS13_BYTE, TLS_AES_256_GCM_SHA384,
TLS13_BYTE, TLS_AES_256_GCM_SHA384,
TLS13_BYTE, TLS_AES_128_GCM_SHA256,
TLS13_BYTE, TLS_AES_128_GCM_SHA256,
TLS13_BYTE, TLS_AES_256_GCM_SHA384 };
#endif
/* Set up wolfSSL context. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, eccCertFile,
CERT_FILETYPE));
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, eccKeyFile,
CERT_FILETYPE));
/* Read from 'msg'. */
wolfSSL_SetIORecv(ctx, CsRecv);
/* No where to send to - dummy sender. */
wolfSSL_SetIOSend(ctx, CsSend);
/* Test cipher suite list with many copies of a cipher suite. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
msg.buffer = clientHello;
msg.length = (unsigned int)sizeof(clientHello);
wolfSSL_SetIOReadCtx(ssl, &msg);
/* Force server to have as many occurrences of same cipher suite as
* possible. */
if (ssl != NULL) {
Suites* suites = (Suites*)WOLFSSL_SUITES(ssl);
suites->suiteSz = WOLFSSL_MAX_SUITE_SZ;
for (i = 0; i < suites->suiteSz; i += 2) {
suites->suites[i + 0] = TLS13_BYTE;
suites->suites[i + 1] = TLS_AES_128_GCM_SHA256;
}
}
/* Test multiple occurrences of same cipher suite. */
ExpectIntEQ(wolfSSL_accept_TLSv13(ssl),
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
wolfSSL_free(ssl);
ssl = NULL;
/* Set client order opposite to server order:
* TLS13-AES128-GCM-SHA256:TLS13-AES256-GCM-SHA384 */
clientHello[csOff + 0] = TLS13_BYTE;
clientHello[csOff + 1] = TLS_AES_128_GCM_SHA256;
clientHello[csOff + 2] = TLS13_BYTE;
clientHello[csOff + 3] = TLS_AES_256_GCM_SHA384;
/* Test server order negotiation. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
msg.buffer = clientHello;
msg.length = (unsigned int)sizeof(clientHello);
wolfSSL_SetIOReadCtx(ssl, &msg);
/* Server order: TLS13-AES256-GCM-SHA384:TLS13-AES128-GCM-SHA256 */
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, serverCs), WOLFSSL_SUCCESS);
/* Negotiate cipher suites in server order: TLS13-AES256-GCM-SHA384 */
ExpectIntEQ(wolfSSL_accept_TLSv13(ssl),
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
/* Check refined order - server order. */
ExpectIntEQ(ssl->suites->suiteSz, 4);
ExpectIntEQ(ssl->suites->suites[0], TLS13_BYTE);
ExpectIntEQ(ssl->suites->suites[1], TLS_AES_256_GCM_SHA384);
ExpectIntEQ(ssl->suites->suites[2], TLS13_BYTE);
ExpectIntEQ(ssl->suites->suites[3], TLS_AES_128_GCM_SHA256);
wolfSSL_free(ssl);
ssl = NULL;
/* Test client order negotiation. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
msg.buffer = clientHello;
msg.length = (unsigned int)sizeof(clientHello);
wolfSSL_SetIOReadCtx(ssl, &msg);
/* Server order: TLS13-AES256-GCM-SHA384:TLS13-AES128-GCM-SHA256 */
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, serverCs), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_UseClientSuites(ssl), 0);
/* Negotiate cipher suites in client order: TLS13-AES128-GCM-SHA256 */
ExpectIntEQ(wolfSSL_accept_TLSv13(ssl),
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
/* Check refined order - client order. */
ExpectIntEQ(ssl->suites->suiteSz, 4);
ExpectIntEQ(ssl->suites->suites[0], TLS13_BYTE);
ExpectIntEQ(ssl->suites->suites[1], TLS_AES_128_GCM_SHA256);
ExpectIntEQ(ssl->suites->suites[2], TLS13_BYTE);
ExpectIntEQ(ssl->suites->suites[3], TLS_AES_256_GCM_SHA384);
wolfSSL_free(ssl);
ssl = NULL;
/* Check duplicate detection is working. */
ExpectIntEQ(wolfSSL_CTX_set_cipher_list(ctx, dupCs), WOLFSSL_SUCCESS);
ExpectIntEQ(ctx->suites->suiteSz, 4);
ExpectIntEQ(ctx->suites->suites[0], TLS13_BYTE);
ExpectIntEQ(ctx->suites->suites[1], TLS_AES_128_GCM_SHA256);
ExpectIntEQ(ctx->suites->suites[2], TLS13_BYTE);
ExpectIntEQ(ctx->suites->suites[3], TLS_AES_256_GCM_SHA384);
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_SET_CIPHER_BYTES)
ExpectIntEQ(wolfSSL_CTX_set_cipher_list_bytes(ctx, dupCsBytes,
sizeof(dupCsBytes)), WOLFSSL_SUCCESS);
ExpectIntEQ(ctx->suites->suiteSz, 4);
ExpectIntEQ(ctx->suites->suites[0], TLS13_BYTE);
ExpectIntEQ(ctx->suites->suites[1], TLS_AES_256_GCM_SHA384);
ExpectIntEQ(ctx->suites->suites[2], TLS13_BYTE);
ExpectIntEQ(ctx->suites->suites[3], TLS_AES_128_GCM_SHA256);
#endif
wolfSSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)\
&& !defined(NO_PSK)
static unsigned int test_tls13_bad_psk_binder_client_cb(WOLFSSL* ssl,
const char* hint, char* identity, unsigned int id_max_len,
unsigned char* key, unsigned int key_max_len)
{
(void)ssl;
(void)hint;
(void)key_max_len;
/* see internal.h MAX_PSK_ID_LEN for PSK identity limit */
XSTRNCPY(identity, "Client_identity", id_max_len);
key[0] = 0x20;
return 1;
}
static unsigned int test_tls13_bad_psk_binder_server_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;
}
#endif
int test_tls13_bad_psk_binder(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)\
&& !defined(NO_PSK)
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_3_client_method, wolfTLSv1_3_server_method), 0);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_bad_psk_binder_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_bad_psk_binder_server_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)),
WC_NO_ERR_TRACE(BAD_BINDER));
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(FATAL_ERROR));
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_rx.code, illegal_parameter);
ExpectIntEQ(h.last_rx.level, alert_fatal);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD) && \
!defined(NO_PSK)
static unsigned int test_tls13_psk_no_cert_client_cb(WOLFSSL* ssl,
const char* hint, char* identity, unsigned int id_max_len,
unsigned char* key, unsigned int key_max_len)
{
(void)ssl;
(void)hint;
(void)key_max_len;
/* Offer a PSK so the client sends a pre_shared_key extension. */
XSTRNCPY(identity, "Client_identity", id_max_len);
key[0] = 0x20;
return 1;
}
static unsigned int test_tls13_psk_no_cert_server_cb(WOLFSSL* ssl,
const char* id, unsigned char* key, unsigned int key_max_len)
{
(void)ssl;
(void)id;
(void)key;
(void)key_max_len;
/* Reject every identity so the server finds no matching PSK. */
return 0;
}
#endif
/* When no offered PSK matches and the server has no certificate to fall back
* to, the server must abort the handshake with BAD_BINDER rather than silently
* continuing. This covers both configurations:
* - NO_CERTS defined: the certificate fall-back branch is compiled out.
* - certificates compiled in but none loaded: ssl->buffers.certificate is
* NULL, so the runtime check takes the same abort path.
* The contexts are built by hand (no certificate loaded) so the test exercises
* whichever branch the build provides.
* When certificates are compiled in, a second connection sets a certificate
* and key against the server context and verifies the opposite branch: the
* non-matching PSK is ignored and the handshake falls back to a full
* certificate handshake instead of aborting. */
int test_tls13_psk_no_cert_bad_binder(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD) && \
!defined(NO_PSK)
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));
/* Don't use test_memio_setup(): it loads a default server certificate,
* which would let the server fall back to a certificate handshake. Build
* the contexts by hand so the server has no certificate loaded. */
ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
if (ctx_c != NULL) {
wolfSSL_SetIORecv(ctx_c, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_c, test_memio_write_cb);
}
if (ctx_s != NULL) {
wolfSSL_SetIORecv(ctx_s, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_s, test_memio_write_cb);
}
/* Set the PSK callbacks on the contexts, not the SSL objects: with
* certificates compiled in, creating a server-side SSL object without a
* certificate and key fails (NO_PRIVATE_KEY) unless ctx->havePSK is
* already set when wolfSSL_new() is called. */
wolfSSL_CTX_set_psk_client_callback(ctx_c,
test_tls13_psk_no_cert_client_cb);
wolfSSL_CTX_set_psk_server_callback(ctx_s,
test_tls13_psk_no_cert_server_cb);
ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
if (ssl_c != NULL) {
wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
}
if (ssl_s != NULL) {
wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
}
/* Confirm the precondition: the server really has no certificate. */
#ifndef NO_CERTS
if (ssl_s != NULL) {
ExpectNull(ssl_s->buffers.certificate);
}
#endif
/* Client sends ClientHello (with PSK) and waits for the response. */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WOLFSSL_ERROR_WANT_READ);
/* Server processes ClientHello: no PSK matches and no certificate is
* available, so it must abort with BAD_BINDER. */
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(BAD_BINDER));
/* Client reads the server's alert: BAD_BINDER maps to a fatal
* illegal_parameter alert (see TranslateErrorToAlert). */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(FATAL_ERROR));
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_rx.code, illegal_parameter);
ExpectIntEQ(h.last_rx.level, alert_fatal);
wolfSSL_free(ssl_c);
ssl_c = NULL;
wolfSSL_CTX_free(ctx_c);
ctx_c = NULL;
wolfSSL_free(ssl_s);
ssl_s = NULL;
wolfSSL_CTX_free(ctx_s);
ctx_s = NULL;
#ifndef NO_CERTS
/* Conversely, with a certificate and key set against the server context,
* a non-matching PSK must not leak the mismatch: the server ignores the
* PSK and falls back to a full certificate handshake. test_memio_setup()
* loads the default CA, server certificate and key. */
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);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_psk_no_cert_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_psk_no_cert_server_cb);
/* Confirm the precondition: the server has a certificate this time. */
if (ssl_s != NULL) {
ExpectNotNull(ssl_s->buffers.certificate);
}
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 /* !NO_CERTS */
#endif
return EXPECT_RESULT();
}
#if defined(HAVE_RPK) && !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) && \
!defined(NO_WOLFSSL_SERVER)
#define svrRpkCertFile "./certs/rpk/server-cert-rpk.der"
#define clntRpkCertFile "./certs/rpk/client-cert-rpk.der"
#if defined(WOLFSSL_ALWAYS_VERIFY_CB) && defined(WOLFSSL_TLS13)
static int MyRpkVerifyCb(int mode, WOLFSSL_X509_STORE_CTX* strctx)
{
int ret = WOLFSSL_SUCCESS;
(void)mode;
(void)strctx;
WOLFSSL_ENTER("MyRpkVerifyCb");
return ret;
}
#endif /* WOLFSSL_ALWAYS_VERIFY_CB && WOLFSSL_TLS13 */
#if !defined(NO_SHA256)
/* Pin the peer's Raw Public Key so it is authenticated out of band (RFC 7250).
* In this test the RPK cert files are DER SubjectPublicKeyInfo (passed as
* WOLFSSL_FILETYPE_ASN1), which is exactly what is sent on the wire, so the raw
* file bytes are the pin. PEM files are X.509 and are left unpinned. */
static int test_rpk_pin_peer(WOLFSSL_CTX* ctx, const char* file, int fmt)
{
byte* buf = NULL;
size_t sz = 0;
int ret = 0;
if (fmt != WOLFSSL_FILETYPE_ASN1)
return 0; /* not an RPK file - nothing to pin */
if (load_file(file, &buf, &sz) != 0)
return -1;
if (wolfSSL_CTX_set_expected_rpk(ctx, buf, (unsigned int)sz)
!= WOLFSSL_SUCCESS) {
ret = -1;
}
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
#endif /* !NO_SHA256 */
static WC_INLINE int test_rpk_memio_setup(
struct test_memio_ctx *ctx,
WOLFSSL_CTX **ctx_c,
WOLFSSL_CTX **ctx_s,
WOLFSSL **ssl_c,
WOLFSSL **ssl_s,
method_provider method_c,
method_provider method_s,
const char* certfile_c, int fmt_cc, /* client cert file path and format */
const char* certfile_s, int fmt_cs, /* server cert file path and format */
const char* pkey_c, int fmt_kc, /* client private key and format */
const char* pkey_s, int fmt_ks /* server private key and format */
)
{
int ret;
if (ctx_c != NULL && *ctx_c == NULL) {
*ctx_c = wolfSSL_CTX_new(method_c());
if (*ctx_c == NULL) {
return -1;
}
wolfSSL_CTX_set_verify(*ctx_c, WOLFSSL_VERIFY_PEER, NULL);
ret = wolfSSL_CTX_load_verify_locations(*ctx_c, caCertFile, 0);
if (ret != WOLFSSL_SUCCESS) {
return -1;
}
wolfSSL_SetIORecv(*ctx_c, test_memio_read_cb);
wolfSSL_SetIOSend(*ctx_c, test_memio_write_cb);
ret = wolfSSL_CTX_use_certificate_file(*ctx_c, certfile_c, fmt_cc);
if (ret != WOLFSSL_SUCCESS) {
return -1;
}
ret = wolfSSL_CTX_use_PrivateKey_file(*ctx_c, pkey_c, fmt_kc);
if (ret != WOLFSSL_SUCCESS) {
return -1;
}
/* This helper sets WOLFSSL_VERIFY_PEER on both ends, so the RPK
* handshake cases below rely on the peer key being pinned here to
* complete (otherwise they fail closed). Pinning needs SHA-256; the
* RPK + NO_SHA256 combination is not exercised because the unit test
* suite does not build under NO_SHA256 (e.g. test_random.c). */
#if !defined(NO_SHA256)
/* client must trust the server's RPK (if the server presents one) */
if (test_rpk_pin_peer(*ctx_c, certfile_s, fmt_cs) != 0) {
return -1;
}
#endif
}
if (ctx_s != NULL && *ctx_s == NULL) {
*ctx_s = wolfSSL_CTX_new(method_s());
if (*ctx_s == NULL) {
return -1;
}
wolfSSL_CTX_set_verify(*ctx_s, WOLFSSL_VERIFY_PEER, NULL);
ret = wolfSSL_CTX_load_verify_locations(*ctx_s, cliCertFile, 0);
if (ret != WOLFSSL_SUCCESS) {
return -1;
}
ret = wolfSSL_CTX_use_PrivateKey_file(*ctx_s, pkey_s, fmt_ks);
if (ret != WOLFSSL_SUCCESS) {
return -1;
}
ret = wolfSSL_CTX_use_certificate_file(*ctx_s, certfile_s, fmt_cs);
if (ret != WOLFSSL_SUCCESS) {
return -1;
}
#if !defined(NO_SHA256)
/* server must trust the client's RPK (if the client presents one) */
if (test_rpk_pin_peer(*ctx_s, certfile_c, fmt_cc) != 0) {
return -1;
}
#endif
wolfSSL_SetIORecv(*ctx_s, test_memio_read_cb);
wolfSSL_SetIOSend(*ctx_s, test_memio_write_cb);
if (ctx->s_ciphers != NULL) {
ret = wolfSSL_CTX_set_cipher_list(*ctx_s, ctx->s_ciphers);
if (ret != WOLFSSL_SUCCESS) {
return -1;
}
}
}
if (ctx_c != NULL && ssl_c != NULL) {
*ssl_c = wolfSSL_new(*ctx_c);
if (*ssl_c == NULL) {
return -1;
}
wolfSSL_SetIOWriteCtx(*ssl_c, ctx);
wolfSSL_SetIOReadCtx(*ssl_c, ctx);
}
if (ctx_s != NULL && ssl_s != NULL) {
*ssl_s = wolfSSL_new(*ctx_s);
if (*ssl_s == NULL) {
return -1;
}
wolfSSL_SetIOWriteCtx(*ssl_s, ctx);
wolfSSL_SetIOReadCtx(*ssl_s, ctx);
#if !defined(NO_DH)
SetDH(*ssl_s);
#endif
}
return 0;
}
#endif /* HAVE_RPK && !NO_TLS && !NO_WOLFSSL_CLIENT && !NO_WOLFSSL_SERVER */
int test_tls13_rpk_handshake(void)
{
EXPECT_DECLS;
#if defined(HAVE_RPK) && \
(!defined(WOLFSSL_NO_TLS12) || defined(WOLFSSL_TLS13)) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
#ifdef WOLFSSL_TLS13
int ret = 0;
#endif
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
int err;
char certType_c[MAX_CLIENT_CERT_TYPE_CNT];
char certType_s[MAX_CLIENT_CERT_TYPE_CNT];
int typeCnt_c;
int typeCnt_s;
int tp = 0;
#if defined(WOLFSSL_ALWAYS_VERIFY_CB) && defined(WOLFSSL_TLS13)
int isServer;
#endif
(void)err;
(void)typeCnt_c;
(void)typeCnt_s;
(void)certType_c;
(void)certType_s;
#ifndef WOLFSSL_NO_TLS12
/* TLS1.2
* Both client and server load x509 cert and start handshaking.
* Check no negotiation occurred.
*/
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(
test_rpk_memio_setup(
&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method,
cliCertFile, CERT_FILETYPE,
svrCertFile, CERT_FILETYPE,
cliKeyFile, CERT_FILETYPE,
svrKeyFile, CERT_FILETYPE)
, 0);
/* set client certificate type in client end */
certType_c[0] = WOLFSSL_CERT_TYPE_RPK;
certType_c[1] = WOLFSSL_CERT_TYPE_X509;
typeCnt_c = 2;
certType_s[0] = WOLFSSL_CERT_TYPE_RPK;
certType_s[1] = WOLFSSL_CERT_TYPE_X509;
typeCnt_s = 2;
/* both client and server do not call client/server_cert_type APIs,
* expecting default settings works and no negotiation performed.
*/
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* confirm no negotiation occurred */
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ((int)tp, WOLFSSL_CERT_TYPE_UNKNOWN);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN);
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN);
(void)typeCnt_c;
(void)typeCnt_s;
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
ssl_c = ssl_s = NULL;
ctx_c = ctx_s = NULL;
#endif
#ifdef WOLFSSL_TLS13
/* Both client and server load x509 cert and start handshaking.
* Check no negotiation occurred.
*/
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(
test_rpk_memio_setup(
&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
cliCertFile, CERT_FILETYPE,
svrCertFile, CERT_FILETYPE,
cliKeyFile, CERT_FILETYPE,
svrKeyFile, CERT_FILETYPE )
, 0);
/* set client certificate type in client end */
certType_c[0] = WOLFSSL_CERT_TYPE_RPK;
certType_c[1] = WOLFSSL_CERT_TYPE_X509;
typeCnt_c = 2;
certType_s[0] = WOLFSSL_CERT_TYPE_RPK;
certType_s[1] = WOLFSSL_CERT_TYPE_X509;
typeCnt_s = 2;
/* both client and server do not call client/server_cert_type APIs,
* expecting default settings works and no negotiation performed.
*/
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* confirm no negotiation occurred */
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ((int)tp, WOLFSSL_CERT_TYPE_UNKNOWN);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN);
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN);
/* x509 handshake: peer cert was verified against a CA, so the verify
* result stays WOLFSSL_X509_V_OK. This is the contrast case for the
* RPK checks below. */
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
ExpectIntEQ(wolfSSL_get_verify_result(ssl_c), WOLFSSL_X509_V_OK);
ExpectIntEQ(wolfSSL_get_verify_result(ssl_s), WOLFSSL_X509_V_OK);
#endif
(void)typeCnt_c;
(void)typeCnt_s;
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
ssl_c = ssl_s = NULL;
ctx_c = ctx_s = NULL;
/* Both client and server load RPK cert and start handshaking.
* Confirm negotiated cert types match as expected.
*/
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(
test_rpk_memio_setup(
&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
clntRpkCertFile, WOLFSSL_FILETYPE_ASN1,
svrRpkCertFile, WOLFSSL_FILETYPE_ASN1,
cliKeyFile, CERT_FILETYPE,
svrKeyFile, CERT_FILETYPE )
, 0);
/* set client certificate type in client end */
certType_c[0] = WOLFSSL_CERT_TYPE_RPK;
certType_c[1] = WOLFSSL_CERT_TYPE_X509;
typeCnt_c = 2;
certType_s[0] = WOLFSSL_CERT_TYPE_RPK;
certType_s[1] = WOLFSSL_CERT_TYPE_X509;
typeCnt_s = 2;
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* set server certificate type in client end */
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s),
WOLFSSL_SUCCESS);
/* set client certificate type in server end */
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* set server certificate type in server end */
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_s, certType_s, typeCnt_s),
WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
/* TLS1.3 RPK: an RPK cert (RFC 7250) has no issuer and no signature chain,
* so it is only authenticated by the out-of-band pin established in
* test_rpk_memio_setup(). Because the peer's key was pinned, the handshake
* completes and wolfSSL_get_verify_result() reports WOLFSSL_X509_V_OK. */
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
ExpectIntEQ(wolfSSL_get_verify_result(ssl_c), WOLFSSL_X509_V_OK);
ExpectIntEQ(wolfSSL_get_verify_result(ssl_s), WOLFSSL_X509_V_OK);
#endif
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
ssl_c = ssl_s = NULL;
ctx_c = ctx_s = NULL;
#endif
#ifndef WOLFSSL_NO_TLS12
/* TLS1.2
* Both client and server load RPK cert and start handshaking.
* Confirm negotiated cert types match as expected.
*/
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(
test_rpk_memio_setup(
&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method,
clntRpkCertFile, WOLFSSL_FILETYPE_ASN1,
svrRpkCertFile, WOLFSSL_FILETYPE_ASN1,
cliKeyFile, CERT_FILETYPE,
svrKeyFile, CERT_FILETYPE )
, 0);
/* set client certificate type in client end */
certType_c[0] = WOLFSSL_CERT_TYPE_RPK;
certType_c[1] = WOLFSSL_CERT_TYPE_X509;
typeCnt_c = 2;
certType_s[0] = WOLFSSL_CERT_TYPE_RPK;
certType_s[1] = WOLFSSL_CERT_TYPE_X509;
typeCnt_s = 2;
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* set server certificate type in client end */
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s),
WOLFSSL_SUCCESS);
/* set client certificate type in server end */
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* set server certificate type in server end */
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_s, certType_s, typeCnt_s),
WOLFSSL_SUCCESS);
if (test_memio_do_handshake(ssl_c, ssl_s, 10, NULL) != 0)
return TEST_FAIL;
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
/* TLS1.2 RPK: same as the TLS1.3 case above - the peer's key was pinned
* out of band, so the verify result is WOLFSSL_X509_V_OK. */
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
ExpectIntEQ(wolfSSL_get_verify_result(ssl_c), WOLFSSL_X509_V_OK);
ExpectIntEQ(wolfSSL_get_verify_result(ssl_s), WOLFSSL_X509_V_OK);
#endif
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
ssl_c = ssl_s = NULL;
ctx_c = ctx_s = NULL;
#endif
#ifdef WOLFSSL_TLS13
/* Both client and server load x509 cert.
* Have client call set_client_cert_type with both RPK and x509.
* This doesn't makes client add client cert type extension to ClientHello,
* since it does not load RPK cert actually.
*/
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(
test_rpk_memio_setup(
&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
cliCertFile, CERT_FILETYPE,
svrCertFile, CERT_FILETYPE,
cliKeyFile, CERT_FILETYPE,
svrKeyFile, CERT_FILETYPE )
, 0);
/* set client certificate type in client end
*
* client indicates both RPK and x509 certs are available but loaded RPK
* cert only. It does not have client add client-cert-type extension in CH.
*/
certType_c[0] = WOLFSSL_CERT_TYPE_RPK;
certType_c[1] = WOLFSSL_CERT_TYPE_X509;
typeCnt_c = 2;
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* client indicates both RPK and x509 certs are acceptable */
certType_s[0] = WOLFSSL_CERT_TYPE_RPK;
certType_s[1] = WOLFSSL_CERT_TYPE_X509;
typeCnt_s = 2;
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s),
WOLFSSL_SUCCESS);
/* server indicates both RPK and x509 certs are acceptable */
certType_c[0] = WOLFSSL_CERT_TYPE_RPK;
certType_c[1] = WOLFSSL_CERT_TYPE_X509;
typeCnt_c = 2;
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* server should indicate only RPK cert is available */
certType_s[0] = WOLFSSL_CERT_TYPE_X509;
certType_s[1] = -1;
typeCnt_s = 1;
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_s, certType_s, typeCnt_s),
WOLFSSL_SUCCESS);
if (test_memio_do_handshake(ssl_c, ssl_s, 10, NULL) != 0)
return TEST_FAIL;
/* Negotiation for client-cert-type should NOT happen. Therefore -1 should
* be returned as cert type.
*/
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509);
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
ssl_c = ssl_s = NULL;
ctx_c = ctx_s = NULL;
/* Have client load RPK cert and have server load x509 cert.
* Check the negotiation result from both ends.
*/
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(
test_rpk_memio_setup(
&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
clntRpkCertFile, WOLFSSL_FILETYPE_ASN1,
svrCertFile, CERT_FILETYPE,
cliKeyFile, CERT_FILETYPE,
svrKeyFile, CERT_FILETYPE )
, 0);
/* have client tell to use RPK cert */
certType_c[0] = WOLFSSL_CERT_TYPE_RPK;
certType_c[1] = -1;
typeCnt_c = 1;
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* have client tell to accept both RPK and x509 cert */
certType_s[0] = WOLFSSL_CERT_TYPE_X509;
certType_s[1] = WOLFSSL_CERT_TYPE_RPK;
typeCnt_s = 2;
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s),
WOLFSSL_SUCCESS);
/* have server accept to both RPK and x509 cert */
certType_c[0] = WOLFSSL_CERT_TYPE_X509;
certType_c[1] = WOLFSSL_CERT_TYPE_RPK;
typeCnt_c = 2;
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* does not call wolfSSL_set_server_cert_type intentionally in sesrver
* end, expecting the default setting works.
*/
if (test_memio_do_handshake(ssl_c, ssl_s, 10, NULL) != 0)
return TEST_FAIL;
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509);
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
ssl_c = ssl_s = NULL;
ctx_c = ctx_s = NULL;
/* Have both client and server load RPK cert, however, have server
* indicate its cert type x509.
* Client is expected to detect the cert type mismatch then to send alert
* with "unsupported_certificate".
*/
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(
test_rpk_memio_setup(
&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
clntRpkCertFile, WOLFSSL_FILETYPE_ASN1,
svrRpkCertFile, WOLFSSL_FILETYPE_ASN1, /* server sends RPK cert */
cliKeyFile, CERT_FILETYPE,
svrKeyFile, CERT_FILETYPE )
, 0);
/* have client tell to use RPK cert */
certType_c[0] = WOLFSSL_CERT_TYPE_RPK;
certType_c[1] = -1;
typeCnt_c = 1;
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* have client tell to accept both RPK and x509 cert */
certType_s[0] = WOLFSSL_CERT_TYPE_X509;
certType_s[1] = WOLFSSL_CERT_TYPE_RPK;
typeCnt_s = 2;
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s),
WOLFSSL_SUCCESS);
/* have server accept to both RPK and x509 cert */
certType_c[0] = WOLFSSL_CERT_TYPE_X509;
certType_c[1] = WOLFSSL_CERT_TYPE_RPK;
typeCnt_c = 2;
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* have server tell to use x509 cert intentionally. This will bring
* certificate type mismatch in client side.
*/
certType_s[0] = WOLFSSL_CERT_TYPE_X509;
certType_s[1] = -1;
typeCnt_s = 1;
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_s, certType_s, typeCnt_s),
WOLFSSL_SUCCESS);
/* expect client detect cert type mismatch then send Alert */
ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL);
if (ret != -1)
return TEST_FAIL;
ExpectIntEQ(wolfSSL_get_error(ssl_c, ret),
WC_NO_ERR_TRACE(UNSUPPORTED_CERTIFICATE));
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509);
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
ssl_c = ssl_s = NULL;
ctx_c = ctx_s = NULL;
/* Have client load x509 cert and server load RPK cert,
* however, have client indicate its cert type RPK.
* Server is expected to detect the cert type mismatch then to send alert
* with "unsupported_certificate".
*/
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(
test_rpk_memio_setup(
&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
cliCertFile, CERT_FILETYPE,
svrRpkCertFile, WOLFSSL_FILETYPE_ASN1,
cliKeyFile, CERT_FILETYPE,
svrKeyFile, CERT_FILETYPE )
, 0);
/* have client tell to use RPK cert intentionally */
certType_c[0] = WOLFSSL_CERT_TYPE_RPK;
certType_c[1] = -1;
typeCnt_c = 1;
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* have client tell to accept both RPK and x509 cert */
certType_s[0] = WOLFSSL_CERT_TYPE_X509;
certType_s[1] = WOLFSSL_CERT_TYPE_RPK;
typeCnt_s = 2;
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s),
WOLFSSL_SUCCESS);
/* have server accept to both RPK and x509 cert */
certType_c[0] = WOLFSSL_CERT_TYPE_X509;
certType_c[1] = WOLFSSL_CERT_TYPE_RPK;
typeCnt_c = 2;
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* have server tell to use x509 cert intentionally. This will bring
* certificate type mismatch in client side.
*/
certType_s[0] = WOLFSSL_CERT_TYPE_X509;
certType_s[1] = -1;
typeCnt_s = 1;
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_s, certType_s, typeCnt_s),
WOLFSSL_SUCCESS);
ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL);
/* expect server detect cert type mismatch then send Alert */
ExpectIntNE(ret, 0);
err = wolfSSL_get_error(ssl_c, ret);
ExpectIntEQ(err, WC_NO_ERR_TRACE(UNSUPPORTED_CERTIFICATE));
/* client did not load RPK cert actually, so negotiation did not happen */
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509);
/* client did not load RPK cert actually, so negotiation did not happen */
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
ssl_c = ssl_s = NULL;
ctx_c = ctx_s = NULL;
#if defined(WOLFSSL_ALWAYS_VERIFY_CB)
/* Both client and server load RPK cert and set certificate verify
* callbacks then start handshaking.
* Confirm both side can refer the peer's cert.
*/
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(
test_rpk_memio_setup(
&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
clntRpkCertFile, WOLFSSL_FILETYPE_ASN1,
svrRpkCertFile, WOLFSSL_FILETYPE_ASN1,
cliKeyFile, CERT_FILETYPE,
svrKeyFile, CERT_FILETYPE )
, 0);
/* set client certificate type in client end */
certType_c[0] = WOLFSSL_CERT_TYPE_RPK;
certType_c[1] = WOLFSSL_CERT_TYPE_X509;
typeCnt_c = 2;
certType_s[0] = WOLFSSL_CERT_TYPE_RPK;
certType_s[1] = WOLFSSL_CERT_TYPE_X509;
typeCnt_s = 2;
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* set server certificate type in client end */
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s),
WOLFSSL_SUCCESS);
/* set client certificate type in server end */
ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c),
WOLFSSL_SUCCESS);
/* set server certificate type in server end */
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_s, certType_s, typeCnt_s),
WOLFSSL_SUCCESS);
/* set certificate verify callback to both client and server */
isServer = 0;
wolfSSL_SetCertCbCtx(ssl_c, &isServer);
wolfSSL_set_verify(ssl_c, SSL_VERIFY_PEER, MyRpkVerifyCb);
isServer = 1;
wolfSSL_SetCertCbCtx(ssl_c, &isServer);
wolfSSL_set_verify(ssl_s, SSL_VERIFY_PEER, MyRpkVerifyCb);
ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL);
if (ret != 0)
return TEST_FAIL;
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
ssl_c = ssl_s = NULL;
ctx_c = ctx_s = NULL;
#endif /* WOLFSSL_ALWAYS_VERIFY_CB */
#endif /* WOLFSSL_TLS13 */
#endif /* HAVE_RPK && (!WOLFSSL_NO_TLS12 || WOLFSSL_TLS13) */
return EXPECT_RESULT();
}
/* Regression: a peer must not present a raw public key (RPK) that was never
* negotiated. Neither side calls set_client/server_cert_type, so RPK is not
* negotiated and the default type is X.509; a received bare key must be
* rejected instead of accepted without any chain verification (auth bypass).
* Covers both directions: server presenting an RPK to the client, and client
* presenting an RPK to the server. */
int test_tls13_rpk_handshake_no_negotiation(void)
{
EXPECT_DECLS;
#if defined(HAVE_RPK) && defined(WOLFSSL_TLS13) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
int tp = 0;
/* Direction 1: server loads an RPK cert, client is a plain X.509 client. */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(
test_rpk_memio_setup(
&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
cliCertFile, CERT_FILETYPE,
svrRpkCertFile, WOLFSSL_FILETYPE_ASN1,
cliKeyFile, CERT_FILETYPE,
svrKeyFile, CERT_FILETYPE)
, 0);
/* Handshake must fail and the client must not record RPK as negotiated. */
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp),
WOLFSSL_SUCCESS);
ExpectIntNE(tp, WOLFSSL_CERT_TYPE_RPK);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
ssl_c = ssl_s = NULL;
ctx_c = ctx_s = NULL;
/* Direction 2: client loads an RPK cert and the server requests client
* auth (VERIFY_PEER, set in the helper). The server expects X.509 and must
* reject the client's un-negotiated bare key. */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(
test_rpk_memio_setup(
&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
clntRpkCertFile, WOLFSSL_FILETYPE_ASN1,
svrCertFile, CERT_FILETYPE,
cliKeyFile, CERT_FILETYPE,
svrKeyFile, CERT_FILETYPE)
, 0);
/* Handshake must fail and the server must not record RPK as negotiated. */
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp),
WOLFSSL_SUCCESS);
ExpectIntNE(tp, WOLFSSL_CERT_TYPE_RPK);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* Post-handshake authentication (PHA) positive guard. A server configured with
* WOLFSSL_VERIFY_POST_HANDSHAKE must complete the initial handshake WITHOUT a
* client certificate (verification is deferred) and then be able to request one
* post-handshake. This guards the property the auth-bypass fix must preserve:
* the missing-certificate exemption stays in force while no post-handshake
* request is outstanding (certReqCtx == NULL). If the fix wrongly treated the
* initial handshake as a pending PHA request, the handshake below would fail.
*
* Scope: this is a positive guard only.
* - The bypass itself is NOT reproduced here: the
* SanityCheckTls13MsgReceived / DoTls13Finished branches the fix re-enables
* only fire when a client sends a Finished with NO Certificate message at all
* (got_certificate == 0). A conformant wolfSSL client always sends at least
* an empty Certificate, so reproducing the bypass needs a non-conformant
* client; the report used a state-machine model. The negative direction
* rests on code review.
* - Driving the full post-handshake certificate exchange to completion is
* intentionally not asserted: whether the peer chain ends up populated
* depends on build options unrelated to this fix (it differs between
* --enable-all and the user_settings_all header build), so it is not a
* portable assertion. */
int test_tls13_pha(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
defined(WOLFSSL_POST_HANDSHAKE_AUTH) && defined(SESSION_CERTS) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_RSA) && !defined(NO_CERTS)
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
WOLFSSL_X509_CHAIN* chain = NULL;
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);
/* Server: trust the (self-signed) client certificate and defer
* verification to post-handshake. */
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, cliCertFile, NULL),
WOLFSSL_SUCCESS);
wolfSSL_set_verify(ssl_s,
WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_POST_HANDSHAKE, NULL);
/* Client: load a cert/key and advertise post-handshake auth. */
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);
/* Initial handshake must complete even though no client cert was sent -
* the verifyPostHandshake exemption (certReqCtx == NULL) is intact. */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
ExpectIntEQ(wolfSSL_get_chain_count(chain), 0);
/* And the server can issue a post-handshake certificate request. */
ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
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_RPK) && defined(WOLFSSL_TLS13) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_SHA256)
/* Verify callback that unconditionally accepts the peer (returns "ok"),
* overriding any error - used to exercise the documented RPK override path.
* Only used by test_tls13_rpk_trust(), which requires SHA-256. */
static int test_rpk_accept_cb(int preverify, WOLFSSL_X509_STORE_CTX* store)
{
(void)preverify;
(void)store;
return 1;
}
/* Mimics a real-world X.509 verify callback that accepts ONLY the "issuer not
* found locally" errors (the pattern used elsewhere to allow an unchained or
* self-signed leaf). It must NOT rescue an untrusted RPK: because the RPK
* failure now reports WOLFSSL_X509_V_ERR_RPK_UNTRUSTED (not the X.509
* issuer-lookup codes), these checks no longer match and the RPK stays rejected.
* Returns 1 (accept) only for the X.509 issuer codes, otherwise rejects. */
static int test_rpk_x509_issuer_accept_cb(int preverify,
WOLFSSL_X509_STORE_CTX* store)
{
(void)preverify;
if ((store->error == WC_NO_ERR_TRACE(ASN_NO_SIGNER_E))
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
|| (store->error ==
WOLFSSL_X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
#endif
) {
return 1; /* would wrongly accept an RPK that reused these codes */
}
return 0; /* reject everything else, including WOLFSSL_X509_V_ERR_RPK_* */
}
#endif /* HAVE_RPK && WOLFSSL_TLS13 && client && server && !NO_SHA256 */
#if defined(HAVE_RPK) && \
(defined(WOLFSSL_TLS13) || !defined(WOLFSSL_NO_TLS12)) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
/* Build a client/server pair (protocol chosen by the caller) that both present
* a Raw Public Key but pin NOTHING (unlike test_rpk_memio_setup, which pins the
* peer key). Verify mode is left at the CTX default; the caller sets it on the
* SSL objects before the handshake. Returns 0 on success. */
static int test_rpk_nopin_setup(struct test_memio_ctx* tctx,
WOLFSSL_CTX** ctx_c, WOLFSSL_CTX** ctx_s,
WOLFSSL** ssl_c, WOLFSSL** ssl_s,
method_provider method_c, method_provider method_s)
{
char certType[MAX_CLIENT_CERT_TYPE_CNT];
*ctx_c = wolfSSL_CTX_new(method_c());
*ctx_s = wolfSSL_CTX_new(method_s());
if ((*ctx_c == NULL) || (*ctx_s == NULL))
return -1;
if (wolfSSL_CTX_load_verify_locations(*ctx_c, caCertFile, 0)
!= WOLFSSL_SUCCESS)
return -1;
if (wolfSSL_CTX_use_certificate_file(*ctx_c, clntRpkCertFile,
WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS)
return -1;
if (wolfSSL_CTX_use_PrivateKey_file(*ctx_c, cliKeyFile, CERT_FILETYPE)
!= WOLFSSL_SUCCESS)
return -1;
wolfSSL_SetIORecv(*ctx_c, test_memio_read_cb);
wolfSSL_SetIOSend(*ctx_c, test_memio_write_cb);
if (wolfSSL_CTX_load_verify_locations(*ctx_s, cliCertFile, 0)
!= WOLFSSL_SUCCESS)
return -1;
if (wolfSSL_CTX_use_PrivateKey_file(*ctx_s, svrKeyFile, CERT_FILETYPE)
!= WOLFSSL_SUCCESS)
return -1;
if (wolfSSL_CTX_use_certificate_file(*ctx_s, svrRpkCertFile,
WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS)
return -1;
wolfSSL_SetIORecv(*ctx_s, test_memio_read_cb);
wolfSSL_SetIOSend(*ctx_s, test_memio_write_cb);
*ssl_c = wolfSSL_new(*ctx_c);
*ssl_s = wolfSSL_new(*ctx_s);
if ((*ssl_c == NULL) || (*ssl_s == NULL))
return -1;
wolfSSL_SetIOWriteCtx(*ssl_c, tctx);
wolfSSL_SetIOReadCtx(*ssl_c, tctx);
wolfSSL_SetIOWriteCtx(*ssl_s, tctx);
wolfSSL_SetIOReadCtx(*ssl_s, tctx);
#if !defined(NO_DH)
SetDH(*ssl_s);
#endif
/* let both sides negotiate RPK in either direction */
certType[0] = WOLFSSL_CERT_TYPE_RPK;
certType[1] = WOLFSSL_CERT_TYPE_X509;
if ((wolfSSL_set_client_cert_type(*ssl_c, certType, 2) != WOLFSSL_SUCCESS) ||
(wolfSSL_set_server_cert_type(*ssl_c, certType, 2) != WOLFSSL_SUCCESS) ||
(wolfSSL_set_client_cert_type(*ssl_s, certType, 2) != WOLFSSL_SUCCESS) ||
(wolfSSL_set_server_cert_type(*ssl_s, certType, 2) != WOLFSSL_SUCCESS))
return -1;
return 0;
}
#endif /* HAVE_RPK && (WOLFSSL_TLS13 || !WOLFSSL_NO_TLS12) && client && server */
/* Regression test for the RPK fail-closed behaviour: a peer that presents a
* Raw Public Key (RFC 7250) without an out-of-band pin must NOT be silently
* accepted while it is being authenticated. Covers both an explicit
* WOLFSSL_VERIFY_PEER client and a default-verify client (verify mode never
* set), since RPK server
* authentication is gated on !verifyNone, matching the X.509 path. Runs for
* every available protocol version, since the fail-closed code in
* ProcessPeerCerts is shared between the TLS 1.2 and TLS 1.3 state machines. */
int test_tls13_rpk_untrusted(void)
{
EXPECT_DECLS;
#if defined(HAVE_RPK) && \
(defined(WOLFSSL_TLS13) || !defined(WOLFSSL_NO_TLS12)) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
int explicitVerifyPeer;
size_t v;
struct {
method_provider c;
method_provider s;
} methods[2];
size_t methodCnt = 0;
#ifdef WOLFSSL_TLS13
methods[methodCnt].c = wolfTLSv1_3_client_method;
methods[methodCnt].s = wolfTLSv1_3_server_method;
methodCnt++;
#endif
#ifndef WOLFSSL_NO_TLS12
methods[methodCnt].c = wolfTLSv1_2_client_method;
methods[methodCnt].s = wolfTLSv1_2_server_method;
methodCnt++;
#endif
for (v = 0; v < methodCnt; v++) {
/* round 0: explicit WOLFSSL_VERIFY_PEER on both ends.
* round 1: default authenticating client - verifyNone=0 but verifyPeer
* never set. Both must fail closed against an unpinned RPK server. */
for (explicitVerifyPeer = 1; explicitVerifyPeer >= 0;
explicitVerifyPeer--) {
ctx_c = ctx_s = NULL;
ssl_c = ssl_s = NULL;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_rpk_nopin_setup(&test_ctx, &ctx_c, &ctx_s,
&ssl_c, &ssl_s, methods[v].c, methods[v].s), 0);
if (explicitVerifyPeer) {
/* explicit mutual WOLFSSL_VERIFY_PEER on both ends */
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_PEER, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER, NULL);
}
else {
/* Default authenticating client: verifyNone=0 with verifyPeer
* NOT set. WOLFSSL_VERIFY_DEFAULT sets exactly that state, and
* it is applied explicitly so the test is deterministic
* regardless of OPENSSL_COMPATIBLE_DEFAULTS (which would
* otherwise default the CTX to WOLFSSL_VERIFY_NONE and skip
* authentication). The server is left non-requesting
* (verifyPeer=0) so the only authentication is the client
* validating the server's RPK - isolating the !verifyNone gate:
* it must fail closed even though verifyPeer was never set. */
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_DEFAULT, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_DEFAULT, NULL);
}
/* With no pin and the peer being authenticated the handshake must
* NOT complete. */
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
/* and the failure is specifically the untrusted RPK */
ExpectIntEQ(wolfSSL_get_verify_result(ssl_c),
WOLFSSL_X509_V_ERR_RPK_UNTRUSTED);
#endif
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
}
}
#endif /* HAVE_RPK && (WOLFSSL_TLS13 || !WOLFSSL_NO_TLS12) && client&&server */
return EXPECT_RESULT();
}
/* Exercises the trust-establishment paths around the RPK fail-closed change:
* - WOLFSSL_VERIFY_NONE: handshake completes, get_verify_result() still
* reports the key as untrusted.
* - verify callback override: an untrusted RPK is accepted because the
* callback returns ok.
* - SSL-level pin via wolfSSL_set_expected_rpk(): pinned key -> V_OK.
* - pinning API argument and capacity errors. */
int test_tls13_rpk_trust(void)
{
EXPECT_DECLS;
#if defined(HAVE_RPK) && defined(WOLFSSL_TLS13) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_SHA256)
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
byte* svrSpki = NULL;
byte* cliSpki = NULL;
size_t svrSpkiSz = 0;
size_t cliSpkiSz = 0;
int i;
ExpectIntEQ(load_file(svrRpkCertFile, &svrSpki, &svrSpkiSz), 0);
ExpectIntEQ(load_file(clntRpkCertFile, &cliSpki, &cliSpkiSz), 0);
/* If either pin failed to load, stop before feeding NULL/zero-length
* buffers into the pinning calls below (which would only produce
* misleading downstream failures). */
if (EXPECT_FAIL()) {
XFREE(svrSpki, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(cliSpki, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return EXPECT_RESULT();
}
/* --- WOLFSSL_VERIFY_NONE: completes, but reported as untrusted --- */
ctx_c = ctx_s = NULL;
ssl_c = ssl_s = NULL;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_rpk_nopin_setup(&test_ctx, &ctx_c, &ctx_s,
&ssl_c, &ssl_s, wolfTLSv1_3_client_method,
wolfTLSv1_3_server_method), 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
ExpectIntEQ(wolfSSL_get_verify_result(ssl_c),
WOLFSSL_X509_V_ERR_RPK_UNTRUSTED);
#endif
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
/* --- verify callback overrides the untrusted RPK -> completes --- */
ctx_c = ctx_s = NULL;
ssl_c = ssl_s = NULL;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_rpk_nopin_setup(&test_ctx, &ctx_c, &ctx_s,
&ssl_c, &ssl_s, wolfTLSv1_3_client_method,
wolfTLSv1_3_server_method), 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_PEER, test_rpk_accept_cb);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER, test_rpk_accept_cb);
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);
/* --- a callback that accepts only X.509 issuer-lookup errors must NOT
* rescue an untrusted RPK: the RPK failure reports its own error code, so
* the callback's X.509 checks do not match and the handshake fails closed.
* (Would complete if the RPK reused ASN_NO_SIGNER_E / the issuer-lookup
* verify-result code.) --- */
ctx_c = ctx_s = NULL;
ssl_c = ssl_s = NULL;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_rpk_nopin_setup(&test_ctx, &ctx_c, &ctx_s,
&ssl_c, &ssl_s, wolfTLSv1_3_client_method,
wolfTLSv1_3_server_method), 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_PEER,
test_rpk_x509_issuer_accept_cb);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER,
test_rpk_x509_issuer_accept_cb);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
ExpectIntEQ(wolfSSL_get_verify_result(ssl_c),
WOLFSSL_X509_V_ERR_RPK_UNTRUSTED);
#endif
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
/* --- SSL-level pin via wolfSSL_set_expected_rpk() -> V_OK --- */
ctx_c = ctx_s = NULL;
ssl_c = ssl_s = NULL;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_rpk_nopin_setup(&test_ctx, &ctx_c, &ctx_s,
&ssl_c, &ssl_s, wolfTLSv1_3_client_method,
wolfTLSv1_3_server_method), 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_PEER, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER, NULL);
/* client trusts the server's key, server trusts the client's key */
ExpectIntEQ(wolfSSL_set_expected_rpk(ssl_c, svrSpki,
(unsigned int)svrSpkiSz), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_expected_rpk(ssl_s, cliSpki,
(unsigned int)cliSpkiSz), WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
ExpectIntEQ(wolfSSL_get_verify_result(ssl_c), WOLFSSL_X509_V_OK);
ExpectIntEQ(wolfSSL_get_verify_result(ssl_s), WOLFSSL_X509_V_OK);
#endif
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
/* --- non-matching pin: table populated, but with the WRONG key ---
* The client pins the *client's* own key, which is not what the server
* presents (the server's key), so RpkIsTrusted's compare loop runs to
* completion and finds no match -> fail closed. Distinct from the no-pin
* case (empty table) above. */
ctx_c = ctx_s = NULL;
ssl_c = ssl_s = NULL;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_rpk_nopin_setup(&test_ctx, &ctx_c, &ctx_s,
&ssl_c, &ssl_s, wolfTLSv1_3_client_method,
wolfTLSv1_3_server_method), 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_PEER, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER, NULL);
/* wrong key pinned on the client: it expects cliSpki but gets svrSpki */
ExpectIntEQ(wolfSSL_set_expected_rpk(ssl_c, cliSpki,
(unsigned int)cliSpkiSz), WOLFSSL_SUCCESS);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
ExpectIntEQ(wolfSSL_get_verify_result(ssl_c),
WOLFSSL_X509_V_ERR_RPK_UNTRUSTED);
#endif
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
/* --- pinning API argument and capacity errors --- */
ctx_c = NULL;
ssl_c = NULL;
ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
/* NULL handle / NULL spki / zero length all report BAD_FUNC_ARG */
ExpectIntEQ(wolfSSL_set_expected_rpk(NULL, svrSpki,
(unsigned int)svrSpkiSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_set_expected_rpk(ssl_c, NULL,
(unsigned int)svrSpkiSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_set_expected_rpk(ssl_c, svrSpki, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* fill the pin table, then the next add overflows with BUFFER_E */
for (i = 0; i < WOLFSSL_MAX_RPK_PINS; i++) {
ExpectIntEQ(wolfSSL_set_expected_rpk(ssl_c, svrSpki,
(unsigned int)svrSpkiSz), WOLFSSL_SUCCESS);
}
ExpectIntEQ(wolfSSL_set_expected_rpk(ssl_c, svrSpki,
(unsigned int)svrSpkiSz), WC_NO_ERR_TRACE(BUFFER_E));
/* clear empties the (full) table so an add succeeds again */
ExpectIntEQ(wolfSSL_clear_expected_rpk(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_clear_expected_rpk(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_expected_rpk(ssl_c, svrSpki,
(unsigned int)svrSpkiSz), WOLFSSL_SUCCESS);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
/* same argument/capacity errors for the CTX-level wrapper */
ctx_c = NULL;
ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
ExpectIntEQ(wolfSSL_CTX_set_expected_rpk(NULL, svrSpki,
(unsigned int)svrSpkiSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_CTX_set_expected_rpk(ctx_c, NULL,
(unsigned int)svrSpkiSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_CTX_set_expected_rpk(ctx_c, svrSpki, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
for (i = 0; i < WOLFSSL_MAX_RPK_PINS; i++) {
ExpectIntEQ(wolfSSL_CTX_set_expected_rpk(ctx_c, svrSpki,
(unsigned int)svrSpkiSz), WOLFSSL_SUCCESS);
}
ExpectIntEQ(wolfSSL_CTX_set_expected_rpk(ctx_c, svrSpki,
(unsigned int)svrSpkiSz), WC_NO_ERR_TRACE(BUFFER_E));
/* clear empties the (full) table so an add succeeds again */
ExpectIntEQ(wolfSSL_CTX_clear_expected_rpk(NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_CTX_clear_expected_rpk(ctx_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_set_expected_rpk(ctx_c, svrSpki,
(unsigned int)svrSpkiSz), WOLFSSL_SUCCESS);
wolfSSL_CTX_free(ctx_c);
XFREE(svrSpki, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(cliSpki, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif /* HAVE_RPK && WOLFSSL_TLS13 && client && server && !NO_SHA256 */
return EXPECT_RESULT();
}
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
(!defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) || \
(defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768)) || \
(defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768)))
static void test_tls13_pq_groups_ctx_ready(WOLFSSL_CTX* ctx)
{
#ifdef WOLFSSL_MLKEM_KYBER
#if !defined(WOLFSSL_NO_KYBER1024)
int group = WOLFSSL_KYBER_LEVEL5;
#elif !defined(WOLFSSL_NO_KYBER768)
int group = WOLFSSL_KYBER_LEVEL3;
#else
int group = WOLFSSL_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;
#elif !defined(WOLFSSL_NO_ML_KEM_768)
int group = WOLFSSL_ML_KEM_768;
#else
int group = WOLFSSL_ML_KEM_512;
#endif
#elif defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768) && \
defined(WOLFSSL_PQC_HYBRIDS)
int group = WOLFSSL_SECP256R1MLKEM768;
#elif defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768) && \
defined(WOLFSSL_PQC_HYBRIDS)
int group = WOLFSSL_X25519MLKEM768;
#endif
AssertIntEQ(wolfSSL_CTX_set_groups(ctx, &group, 1), WOLFSSL_SUCCESS);
}
static void test_tls13_pq_groups_on_result(WOLFSSL* ssl)
{
#ifdef WOLFSSL_MLKEM_KYBER
#if !defined(WOLFSSL_NO_KYBER1024)
AssertStrEQ(wolfSSL_get_curve_name(ssl), "KYBER_LEVEL5");
#elif !defined(WOLFSSL_NO_KYBER768)
AssertStrEQ(wolfSSL_get_curve_name(ssl), "KYBER_LEVEL3");
#else
AssertStrEQ(wolfSSL_get_curve_name(ssl), "KYBER_LEVEL1");
#endif
#elif !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
#if !defined(WOLFSSL_NO_ML_KEM_1024)
AssertStrEQ(wolfSSL_get_curve_name(ssl), "ML_KEM_1024");
#elif !defined(WOLFSSL_NO_ML_KEM_768)
AssertStrEQ(wolfSSL_get_curve_name(ssl), "ML_KEM_768");
#else
AssertStrEQ(wolfSSL_get_curve_name(ssl), "ML_KEM_512");
#endif
#elif defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768) && \
defined(WOLFSSL_PQC_HYBRIDS)
AssertStrEQ(wolfSSL_get_curve_name(ssl), "SecP256r1MLKEM768");
#elif defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768) && \
defined(WOLFSSL_PQC_HYBRIDS)
AssertStrEQ(wolfSSL_get_curve_name(ssl), "X25519MLKEM768");
#endif
}
#endif
int test_tls13_pq_groups(void)
{
EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
(!defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) || \
(defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768)) || \
(defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768)))
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.method = wolfTLSv1_3_client_method;
func_cb_server.method = wolfTLSv1_3_server_method;
func_cb_client.ctx_ready = test_tls13_pq_groups_ctx_ready;
func_cb_client.on_result = test_tls13_pq_groups_on_result;
func_cb_server.on_result = test_tls13_pq_groups_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);
#endif
return EXPECT_RESULT();
}
/* Regression test handling multiple PQC key shares in the ClientHello.
*
* Previously, the server eagerly ran KEM encapsulation on every PQC/hybrid
* key_share entry while parsing the ClientHello, clobbering
* ssl->arrays->preMasterSecret with whichever entry was parsed last.
* When the ClientHello offers both SecP384R1_MLKEM1024 and pure
* ML_KEM_1024, the resulting handshake either produces keys that the
* client cannot decrypt (hybrid chosen, pure-ML-KEM secret written) or
* trips a BUFFER_E inside the second encapsulation. Either ordering
* causes the handshake to fail.
*
* The test runs a memio TLS 1.3 handshake for both orderings and
* expects the handshake to complete successfully with the hybrid group
* selected (higher server preference rank). */
#if defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_PQC_HYBRIDS) && \
!defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) && \
!defined(WOLFSSL_NO_ML_KEM_1024) && \
!defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
defined(HAVE_ECC) && (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \
ECC_MIN_KEY_SZ <= 384 && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
#define TEST_TLS13_MULTI_PQC_KEY_SHARE_ENABLED
/* Run one TLS 1.3 memio handshake where the client offers both
* WOLFSSL_SECP384R1MLKEM1024 and WOLFSSL_ML_KEM_1024 in the key_share
* extension, in the order dictated by `hybridFirst`. */
static int test_tls13_multi_pqc_key_share_once(int hybridFirst)
{
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(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
/* Force the client to include both PQC key shares in the ClientHello
* by calling UseKeyShare twice. The order of the UseKeyShare calls
* determines the order of the entries in the key_share extension. */
if (hybridFirst) {
ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_SECP384R1MLKEM1024),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ML_KEM_1024),
WOLFSSL_SUCCESS);
}
else {
ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ML_KEM_1024),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_SECP384R1MLKEM1024),
WOLFSSL_SUCCESS);
}
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* The server ranks SecP384R1_MLKEM1024 higher than ML_KEM_1024, so
* the hybrid group must be selected regardless of client ordering. */
ExpectStrEQ(wolfSSL_get_curve_name(ssl_s), "SecP384r1MLKEM1024");
ExpectStrEQ(wolfSSL_get_curve_name(ssl_c), "SecP384r1MLKEM1024");
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
return EXPECT_RESULT();
}
#endif /* TEST_TLS13_MULTI_PQC_KEY_SHARE_ENABLED */
int test_tls13_multi_pqc_key_share(void)
{
EXPECT_DECLS;
#ifdef TEST_TLS13_MULTI_PQC_KEY_SHARE_ENABLED
/* Hybrid first, then pure ML-KEM: pre-fix the server selected the
* hybrid but had overwritten preMasterSecret with the pure-KEM
* result, producing 32-byte KE Secret instead of 80 and causing the
* client to fail to decrypt the server's first encrypted record. */
ExpectIntEQ(test_tls13_multi_pqc_key_share_once(1), TEST_SUCCESS);
/* Pure ML-KEM first, then hybrid: pre-fix the server tripped
* BUFFER_E inside the second encapsulation because preMasterSz was
* left at 32 from the first call, and the hybrid handler then
* overflowed the preMasterSecret buffer. */
ExpectIntEQ(test_tls13_multi_pqc_key_share_once(0), TEST_SUCCESS);
#endif
return EXPECT_RESULT();
}
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_EARLY_DATA) && defined(HAVE_SESSION_TICKET)
static int test_tls13_read_until_write_ok(WOLFSSL* ssl, void* buf, int bufLen)
{
int ret, err;
int tries = 5;
err = 0;
do {
ret = wolfSSL_read(ssl, buf, bufLen);
if (ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) {
err = wolfSSL_get_error(ssl, ret);
}
} while (tries-- && ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR) &&
err == WC_NO_ERR_TRACE(WOLFSSL_ERROR_WANT_WRITE));
return ret;
}
static int test_tls13_connect_until_write_ok(WOLFSSL* ssl)
{
int ret, err;
int tries = 5;
err = 0;
do {
ret = wolfSSL_connect(ssl);
if (ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) {
err = wolfSSL_get_error(ssl, ret);
}
} while (tries-- && ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR) &&
err == WC_NO_ERR_TRACE(WOLFSSL_ERROR_WANT_WRITE));
return ret;
}
static int test_tls13_write_until_write_ok(WOLFSSL* ssl, const void* msg,
int msgLen)
{
int ret, err;
int tries = 5;
err = 0;
do {
ret = wolfSSL_write(ssl, msg, msgLen);
if (ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) {
err = wolfSSL_get_error(ssl, ret);
}
} while (tries-- && ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR) &&
err == WC_NO_ERR_TRACE(WOLFSSL_ERROR_WANT_WRITE));
return ret;
}
static int test_tls13_early_data_read_until_write_ok(WOLFSSL* ssl, void* buf,
int bufLen, int* read)
{
int ret, err;
int tries = 5;
err = 0;
do {
ret = wolfSSL_read_early_data(ssl, buf, bufLen, read);
if (ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) {
err = wolfSSL_get_error(ssl, ret);
}
} while (tries-- && ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR) &&
err == WC_NO_ERR_TRACE(WOLFSSL_ERROR_WANT_WRITE));
return ret;
}
static int test_tls13_early_data_write_until_write_ok(WOLFSSL* ssl,
const void* msg, int msgLen, int* written)
{
int ret, err;
int tries = 5;
err = 0;
do {
ret = wolfSSL_write_early_data(ssl, msg, msgLen, written);
if (ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) {
err = wolfSSL_get_error(ssl, ret);
}
} while (tries-- && ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR) &&
err == WC_NO_ERR_TRACE(WOLFSSL_ERROR_WANT_WRITE));
return ret;
}
struct test_tls13_wwrite_ctx {
int want_write;
struct test_memio_ctx *test_ctx;
};
static int test_tls13_mock_wantwrite_cb(WOLFSSL* ssl, char* data, int sz,
void* ctx)
{
struct test_tls13_wwrite_ctx *wwctx = (struct test_tls13_wwrite_ctx *)ctx;
#ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
/* Write ChangeCipherSpec message. */
if (data[0] != 0x14)
#endif
{
wwctx->want_write = !wwctx->want_write;
if (wwctx->want_write) {
return WOLFSSL_CBIO_ERR_WANT_WRITE;
}
}
return test_memio_write_cb(ssl, data, sz, wwctx->test_ctx);
}
#endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES && WOLFSSL_EARLY_DATA */
int test_tls13_early_data(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_EARLY_DATA) && defined(HAVE_SESSION_TICKET)
int written = 0;
int read = 0;
size_t i;
char msg[] = "This is early data";
char msg2[] = "This is client data";
char msg3[] = "This is server data";
char msg4[] = "This is server immediate data";
char msgBuf[50];
struct {
method_provider client_meth;
method_provider server_meth;
const char* tls_version;
int isUdp;
int splitEarlyData;
int everyWriteWantWrite;
} params[] = {
#ifdef WOLFSSL_TLS13
{ wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
"TLS 1.3", 0, 0, 0 },
{ wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
"TLS 1.3", 0, 1, 0 },
{ wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
"TLS 1.3", 0, 0, 1 },
{ wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
"TLS 1.3", 0, 1, 1 },
#endif
#ifdef WOLFSSL_DTLS13
{ wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method,
"DTLS 1.3", 1, 0, 0 },
{ wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method,
"DTLS 1.3", 1, 1, 0 },
{ wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method,
"DTLS 1.3", 1, 0, 1 },
{ wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method,
"DTLS 1.3", 1, 1, 1 },
#endif
};
for (i = 0; i < sizeof(params)/sizeof(*params) && !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_SESSION *sess = NULL;
int splitEarlyData = params[i].splitEarlyData;
int everyWriteWantWrite = params[i].everyWriteWantWrite;
struct test_tls13_wwrite_ctx wwrite_ctx_s, wwrite_ctx_c;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMSET(&wwrite_ctx_c, 0, sizeof(wwrite_ctx_c));
XMEMSET(&wwrite_ctx_s, 0, sizeof(wwrite_ctx_s));
fprintf(stderr, "\tEarly data with %s%s%s\n", params[i].tls_version,
splitEarlyData ? " (split early data)" : "",
everyWriteWantWrite ? " (every write WANT_WRITE)" : "");
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c,
&ssl_s, params[i].client_meth, params[i].server_meth), 0);
/* Opt the server into 0-RTT (off by default per RFC 8446 E.5). */
ExpectIntGE(wolfSSL_CTX_set_max_early_data(ctx_s, MAX_EARLY_DATA_SZ),
0);
ExpectIntGE(wolfSSL_set_max_early_data(ssl_s, MAX_EARLY_DATA_SZ), 0);
if (params[i].isUdp) {
/* Early data is incompatible with HRR usage. Hence, we have to make
* sure a group is negotiated that does not cause a fragemented CH.
*/
int group[1] = {
#ifdef HAVE_ECC
WOLFSSL_ECC_SECP256R1,
#elif defined(HAVE_CURVE25519)
WOLFSSL_ECC_X25519,
#elif defined(HAVE_CURVE448)
WOLFSSL_ECC_X448,
#elif defined(HAVE_FFDHE_2048)
WOLFSSL_FFDHE_2048,
#endif
};
ExpectIntEQ(wolfSSL_set_groups(ssl_c, group, 1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_groups(ssl_s, group, 1), WOLFSSL_SUCCESS);
}
/* Get a ticket so that we can do 0-RTT on the next connection */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Make sure we read the ticket */
ExpectIntEQ(wolfSSL_read(ssl_c, msgBuf, sizeof(msgBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
wolfSSL_free(ssl_c);
ssl_c = NULL;
wolfSSL_free(ssl_s);
ssl_s = NULL;
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);
wolfSSL_SetLoggingPrefix("client");
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
#ifdef WOLFSSL_DTLS13
if (params[i].isUdp) {
wolfSSL_SetLoggingPrefix("server");
#ifdef WOLFSSL_DTLS13_NO_HRR_ON_RESUME
ExpectIntEQ(wolfSSL_dtls13_no_hrr_on_resume(ssl_s, 1),
WOLFSSL_SUCCESS);
#else
/* Let's test this but we generally don't recommend turning off
* the cookie exchange */
ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS);
#endif
}
#endif
if (everyWriteWantWrite) {
wwrite_ctx_c.test_ctx = &test_ctx;
wwrite_ctx_s.test_ctx = &test_ctx;
wolfSSL_SetIOWriteCtx(ssl_c, &wwrite_ctx_c);
wolfSSL_SSLSetIOSend(ssl_c, test_tls13_mock_wantwrite_cb);
wolfSSL_SetIOWriteCtx(ssl_s, &wwrite_ctx_s);
wolfSSL_SSLSetIOSend(ssl_s, test_tls13_mock_wantwrite_cb);
}
/* Test 0-RTT data */
wolfSSL_SetLoggingPrefix("client");
ExpectIntEQ(test_tls13_early_data_write_until_write_ok(ssl_c, msg,
sizeof(msg), &written),
sizeof(msg));
ExpectIntEQ(written, sizeof(msg));
if (splitEarlyData) {
ExpectIntEQ(test_tls13_early_data_write_until_write_ok(ssl_c, msg,
sizeof(msg), &written),
sizeof(msg));
ExpectIntEQ(written, sizeof(msg));
}
/* Read first 0-RTT data (if split otherwise entire data) */
wolfSSL_SetLoggingPrefix("server");
ExpectIntEQ(test_tls13_early_data_read_until_write_ok(ssl_s, msgBuf,
sizeof(msgBuf), &read),
sizeof(msg));
ExpectIntEQ(read, sizeof(msg));
ExpectStrEQ(msg, msgBuf);
/* Test 0.5-RTT data */
ExpectIntEQ(test_tls13_write_until_write_ok(ssl_s, msg4, sizeof(msg4)),
sizeof(msg4));
if (splitEarlyData) {
/* Read second 0-RTT data */
ExpectIntEQ(test_tls13_early_data_read_until_write_ok(ssl_s, msgBuf,
sizeof(msgBuf), &read),
sizeof(msg));
ExpectIntEQ(read, sizeof(msg));
ExpectStrEQ(msg, msgBuf);
}
if (params[i].isUdp) {
wolfSSL_SetLoggingPrefix("client");
ExpectIntEQ(test_tls13_connect_until_write_ok(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1),
WC_NO_ERR_TRACE(APP_DATA_READY));
/* Read server 0.5-RTT data */
ExpectIntEQ(
test_tls13_read_until_write_ok(ssl_c, msgBuf, sizeof(msgBuf)),
sizeof(msg4));
ExpectStrEQ(msg4, msgBuf);
/* Complete handshake */
ExpectIntEQ(test_tls13_connect_until_write_ok(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1),
WOLFSSL_ERROR_WANT_READ);
/* Use wolfSSL_is_init_finished to check if handshake is
* complete. Normally a user would loop until it is true but
* here we control both sides so we just assert the expected
* value. wolfSSL_read_early_data does not provide handshake
* status to us with non-blocking IO and we can't use
* wolfSSL_accept as TLS layer may return ZERO_RETURN due to
* early data parsing logic. */
wolfSSL_SetLoggingPrefix("server");
ExpectFalse(wolfSSL_is_init_finished(ssl_s));
ExpectIntEQ(test_tls13_early_data_read_until_write_ok(ssl_s, msgBuf,
sizeof(msgBuf), &read),
0);
ExpectIntEQ(read, 0);
ExpectTrue(wolfSSL_is_init_finished(ssl_s));
wolfSSL_SetLoggingPrefix("client");
ExpectIntEQ(test_tls13_connect_until_write_ok(ssl_c),
WOLFSSL_SUCCESS);
}
else {
wolfSSL_SetLoggingPrefix("client");
ExpectIntEQ(test_tls13_connect_until_write_ok(ssl_c),
WOLFSSL_SUCCESS);
wolfSSL_SetLoggingPrefix("server");
ExpectFalse(wolfSSL_is_init_finished(ssl_s));
ExpectIntEQ(test_tls13_early_data_read_until_write_ok(ssl_s, msgBuf,
sizeof(msgBuf), &read),
0);
ExpectIntEQ(read, 0);
ExpectTrue(wolfSSL_is_init_finished(ssl_s));
/* Read server 0.5-RTT data */
wolfSSL_SetLoggingPrefix("client");
ExpectIntEQ(
test_tls13_read_until_write_ok(ssl_c, msgBuf, sizeof(msgBuf)),
sizeof(msg4));
ExpectStrEQ(msg4, msgBuf);
}
/* Test bi-directional write */
wolfSSL_SetLoggingPrefix("client");
ExpectIntEQ(test_tls13_write_until_write_ok(ssl_c, msg2, sizeof(msg2)),
sizeof(msg2));
wolfSSL_SetLoggingPrefix("server");
ExpectIntEQ(
test_tls13_read_until_write_ok(ssl_s, msgBuf, sizeof(msgBuf)),
sizeof(msg2));
ExpectStrEQ(msg2, msgBuf);
ExpectIntEQ(test_tls13_write_until_write_ok(ssl_s, msg3, sizeof(msg3)),
sizeof(msg3));
wolfSSL_SetLoggingPrefix("client");
ExpectIntEQ(
test_tls13_read_until_write_ok(ssl_c, msgBuf, sizeof(msgBuf)),
sizeof(msg3));
ExpectStrEQ(msg3, msgBuf);
wolfSSL_SetLoggingPrefix(NULL);
ExpectTrue(wolfSSL_session_reused(ssl_c));
ExpectTrue(wolfSSL_session_reused(ssl_s));
wolfSSL_SESSION_free(sess);
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_TLS13) && defined(WOLFSSL_EARLY_DATA) && \
defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TICKET_HAVE_ID) && \
!defined(NO_SESSION_CACHE) && defined(HAVE_EXT_CACHE)
/* Single-slot external session cache keyed by altSessionID, used by
* test_tls13_early_data_0rtt_replay to assert the 0-RTT anti-replay
* fix clears both caches. */
static struct {
byte id[ID_LEN];
byte has_entry;
WOLFSSL_SESSION* sess;
int new_calls;
int get_calls;
int rem_calls;
} test_tls13_0rtt_replay_cache;
static void test_tls13_0rtt_replay_cache_reset(void)
{
/* wolfSSL_SESSION_free is NULL-safe, so unconditionally drop any
* stored session without touching has_entry first. */
wolfSSL_SESSION_free(test_tls13_0rtt_replay_cache.sess);
XMEMSET(&test_tls13_0rtt_replay_cache, 0,
sizeof(test_tls13_0rtt_replay_cache));
}
/* Stateful-ticket sessions always have haveAltSessionID set, so key the
* cache on altSessionID directly (wolfSSL_SESSION_get_id is only
* declared under the OpenSSL compatibility layer). */
static int test_tls13_0rtt_replay_new_cb(WOLFSSL* ssl, WOLFSSL_SESSION* s)
{
(void)ssl;
test_tls13_0rtt_replay_cache.new_calls++;
if (s == NULL || !s->haveAltSessionID)
return 0;
wolfSSL_SESSION_free(test_tls13_0rtt_replay_cache.sess);
XMEMCPY(test_tls13_0rtt_replay_cache.id, s->altSessionID, ID_LEN);
test_tls13_0rtt_replay_cache.sess = s;
test_tls13_0rtt_replay_cache.has_entry = 1;
return 1; /* retain the reference; freed in the rem callback */
}
static WOLFSSL_SESSION* test_tls13_0rtt_replay_get_cb(WOLFSSL* ssl,
const byte* id, int idLen, int* ref)
{
(void)ssl;
test_tls13_0rtt_replay_cache.get_calls++;
*ref = 1; /* keep ownership; wolfSSL duplicates from us */
if (!test_tls13_0rtt_replay_cache.has_entry || idLen != ID_LEN)
return NULL;
if (XMEMCMP(test_tls13_0rtt_replay_cache.id, id, ID_LEN) != 0)
return NULL;
return test_tls13_0rtt_replay_cache.sess;
}
static void test_tls13_0rtt_replay_rem_cb(WOLFSSL_CTX* ctx,
WOLFSSL_SESSION* s)
{
const byte* id;
(void)ctx;
if (!test_tls13_0rtt_replay_cache.has_entry || s == NULL)
return;
/* Internal-cache-evicted sessions have haveAltSessionID cleared
* (that field sits before the DupSession copy offset), so fall
* back to sessionID when altSessionID is not set. Both carry the
* ID_LEN lookup key. */
if (s->haveAltSessionID)
id = s->altSessionID;
else if (s->sessionIDSz == ID_LEN)
id = s->sessionID;
else
return;
if (XMEMCMP(test_tls13_0rtt_replay_cache.id, id, ID_LEN) != 0)
return;
wolfSSL_SESSION_free(test_tls13_0rtt_replay_cache.sess);
test_tls13_0rtt_replay_cache.sess = NULL;
test_tls13_0rtt_replay_cache.has_entry = 0;
test_tls13_0rtt_replay_cache.rem_calls++;
}
/* RFC 8446 section 8 anti-replay: a 0-RTT-eligible session must be
* evicted from both the internal and external caches on resumption so
* the same ClientHello cannot replay early data. */
int test_tls13_early_data_0rtt_replay(void)
{
EXPECT_DECLS;
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
WOLFSSL_SESSION *sess = NULL;
char buf[64];
int round;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
test_tls13_0rtt_replay_cache_reset();
/* Step 1: full handshake populates both caches. */
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method),
0);
/* Stateful tickets + 0-RTT enabled. */
ExpectTrue(wolfSSL_set_options(ssl_s, WOLFSSL_OP_NO_TICKET) != 0);
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_ERROR_CODE_OPENSSL)
ExpectIntEQ(wolfSSL_set_max_early_data(ssl_s, 128), WOLFSSL_SUCCESS);
#else
ExpectIntEQ(wolfSSL_set_max_early_data(ssl_s, 128), 0);
#endif
wolfSSL_CTX_sess_set_new_cb(ctx_s, test_tls13_0rtt_replay_new_cb);
wolfSSL_CTX_sess_set_get_cb(ctx_s, test_tls13_0rtt_replay_get_cb);
wolfSSL_CTX_sess_set_remove_cb(ctx_s, test_tls13_0rtt_replay_rem_cb);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Let the client consume NewSessionTicket. */
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
ExpectIntEQ(wolfSSL_SessionIsSetup(sess), 1);
/* Stateful (ID-only) ticket on the client side. */
ExpectIntEQ(sess->ticketLen, ID_LEN);
ExpectIntEQ((int)sess->maxEarlyDataSz, 128);
/* External cache saw the add. */
ExpectIntGT(test_tls13_0rtt_replay_cache.new_calls, 0);
ExpectIntEQ(test_tls13_0rtt_replay_cache.has_entry, 1);
wolfSSL_free(ssl_c); ssl_c = NULL;
wolfSSL_free(ssl_s); ssl_s = NULL;
/* Resume the same session twice, offering 0-RTT each time. */
for (round = 0; round < 2 && !EXPECT_FAIL(); round++) {
const char earlyMsg[] = "early-data-0rtt";
int written = 0;
int earlyRead = 0;
char earlyBuf[sizeof(earlyMsg)];
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMSET(earlyBuf, 0, sizeof(earlyBuf));
/* Reuse the CTXs so both caches survive (test_memio_setup
* leaves *ctx alone when non-NULL). */
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c,
&ssl_s, wolfTLSv1_3_client_method,
wolfTLSv1_3_server_method), 0);
ExpectTrue(wolfSSL_set_options(ssl_s, WOLFSSL_OP_NO_TICKET) != 0);
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_ERROR_CODE_OPENSSL)
ExpectIntEQ(wolfSSL_set_max_early_data(ssl_s, 128),
WOLFSSL_SUCCESS);
#else
ExpectIntEQ(wolfSSL_set_max_early_data(ssl_s, 128), 0);
#endif
ExpectIntEQ(wolfSSL_SessionIsSetup(sess), 1);
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
ExpectIntEQ(test_tls13_early_data_write_until_write_ok(ssl_c,
earlyMsg, (int)sizeof(earlyMsg), &written),
sizeof(earlyMsg));
ExpectIntEQ(written, sizeof(earlyMsg));
(void)test_tls13_early_data_read_until_write_ok(ssl_s, earlyBuf,
sizeof(earlyBuf), &earlyRead);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
if (round == 0) {
ExpectTrue(wolfSSL_session_reused(ssl_s));
ExpectIntEQ(earlyRead, sizeof(earlyMsg));
ExpectStrEQ(earlyMsg, earlyBuf);
/* Fix fired exactly once to evict the cached entry. */
ExpectIntEQ(test_tls13_0rtt_replay_cache.rem_calls, 1);
}
else {
ExpectFalse(wolfSSL_session_reused(ssl_s));
ExpectIntEQ(earlyRead, 0);
/* No additional eviction in the replay round. */
ExpectIntEQ(test_tls13_0rtt_replay_cache.rem_calls, 1);
}
wolfSSL_free(ssl_c); ssl_c = NULL;
wolfSSL_free(ssl_s); ssl_s = NULL;
}
wolfSSL_SESSION_free(sess);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
test_tls13_0rtt_replay_cache_reset();
return EXPECT_RESULT();
}
#else
int test_tls13_early_data_0rtt_replay(void)
{
EXPECT_DECLS;
return EXPECT_RESULT();
}
#endif
/* Verify that maxEarlyDataSz defaults to 0 (RFC 8446 E.5): a server that
* has not called wolfSSL_set_max_early_data must not advertise 0-RTT in its
* NewSessionTicket. Fails without the ctx->maxEarlyDataSz=0 default fix
* because the old default was MAX_EARLY_DATA_SZ (4096). */
int test_tls13_0rtt_default_off(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_TLS13) && defined(WOLFSSL_EARLY_DATA) && \
defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
WOLFSSL_SESSION *sess = NULL;
char buf[64];
int written = 0;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
/* Step 1: handshake WITHOUT opting into 0-RTT on the server. */
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method),
0);
/* Deliberately do NOT call wolfSSL_set_max_early_data. */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Consume NewSessionTicket. */
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
wolfSSL_free(ssl_c); ssl_c = NULL;
wolfSSL_free(ssl_s); ssl_s = NULL;
/* Step 2: resume - early data write must fail because the ticket
* was issued without max_early_data_size. Without the default-to-0
* fix the old default (4096) would let this succeed. */
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);
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_write_early_data(ssl_c, "test", 4, &written),
WOLFSSL_FATAL_ERROR);
wolfSSL_SESSION_free(sess);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* Verify that a stateless self-encrypted ticket can carry 0-RTT exactly
* once: the first resumption succeeds with early data, the second (replay)
* refuses it because wolfSSL_SSL_CTX_remove_session evicted the cache entry.
* Fails without the WOLFSSL_TICKET_HAVE_ID implication + the
* remove_session-based gate because the old code either never populated
* the cache for stateless tickets or never checked the return value. */
int test_tls13_0rtt_stateless_replay(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_TLS13) && defined(WOLFSSL_EARLY_DATA) && \
defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TICKET_HAVE_ID) && \
!defined(NO_SESSION_CACHE) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
WOLFSSL_SESSION *sess = NULL;
char buf[64];
int round;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
/* Step 1: full handshake to get a stateless ticket with 0-RTT. */
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method),
0);
/* Do NOT set WOLFSSL_OP_NO_TICKET - keep stateless tickets. */
ExpectIntGE(wolfSSL_CTX_set_max_early_data(ctx_s, MAX_EARLY_DATA_SZ), 0);
ExpectIntGE(wolfSSL_set_max_early_data(ssl_s, MAX_EARLY_DATA_SZ), 0);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
ExpectIntEQ(wolfSSL_SessionIsSetup(sess), 1);
wolfSSL_free(ssl_c); ssl_c = NULL;
wolfSSL_free(ssl_s); ssl_s = NULL;
/* Suppress ticket reissuance on resume so the eviction from round 0
* is not undone by AddSession from a new NewSessionTicket. */
ExpectIntEQ(wolfSSL_CTX_set_num_tickets(ctx_s, 0), WOLFSSL_SUCCESS);
/* Step 2: resume twice. Round 0 = first use, round 1 = replay. */
for (round = 0; round < 2 && !EXPECT_FAIL(); round++) {
const char earlyMsg[] = "stateless-0rtt";
int written = 0;
int earlyRead = 0;
char earlyBuf[sizeof(earlyMsg)];
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMSET(earlyBuf, 0, sizeof(earlyBuf));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c,
&ssl_s, wolfTLSv1_3_client_method,
wolfTLSv1_3_server_method), 0);
ExpectIntGE(wolfSSL_set_max_early_data(ssl_s, MAX_EARLY_DATA_SZ), 0);
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
ExpectIntEQ(test_tls13_early_data_write_until_write_ok(ssl_c,
earlyMsg, (int)sizeof(earlyMsg), &written),
sizeof(earlyMsg));
ExpectIntEQ(written, sizeof(earlyMsg));
(void)test_tls13_early_data_read_until_write_ok(ssl_s, earlyBuf,
sizeof(earlyBuf), &earlyRead);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
if (round == 0) {
/* First use: 0-RTT accepted. */
ExpectIntEQ(earlyRead, sizeof(earlyMsg));
ExpectStrEQ(earlyMsg, earlyBuf);
}
else {
/* Replay: 0-RTT refused, handshake still completes (1-RTT). */
ExpectIntEQ(earlyRead, 0);
}
wolfSSL_free(ssl_c); ssl_c = NULL;
wolfSSL_free(ssl_s); ssl_s = NULL;
}
wolfSSL_SESSION_free(sess);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* Verify wolfSSL_SSL_CTX_remove_session returns OpenSSL-compatible values:
* 1 when the session was in the cache and removed, 0 otherwise.
* Fails without the return-value fix because the old code returned 0/
* BAD_FUNC_ARG. */
int test_tls13_remove_session_return(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
defined(WOLFSSL_TICKET_HAVE_ID) && !defined(NO_SESSION_CACHE) && \
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
WOLFSSL_SESSION *sess = NULL;
char buf[64];
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);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Consume NewSessionTicket so the cache is populated (AddSession fires
* because WOLFSSL_TICKET_HAVE_ID is defined). */
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectNotNull(sess = wolfSSL_get1_session(ssl_s));
/* Session is in the cache - first remove returns 1. */
ExpectIntEQ(wolfSSL_SSL_CTX_remove_session(ctx_s, sess), 1);
/* Already removed - second remove returns 0. */
ExpectIntEQ(wolfSSL_SSL_CTX_remove_session(ctx_s, sess), 0);
/* NULL args - returns 0 (not BAD_FUNC_ARG). */
ExpectIntEQ(wolfSSL_SSL_CTX_remove_session(NULL, sess), 0);
ExpectIntEQ(wolfSSL_SSL_CTX_remove_session(ctx_s, NULL), 0);
wolfSSL_SESSION_free(sess);
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_TLS13) && defined(WOLFSSL_EARLY_DATA) && \
defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TICKET_HAVE_ID) && \
!defined(NO_SESSION_CACHE) && defined(HAVE_EXT_CACHE)
/* Thin external cache: only tracks rem_calls to verify that
* wolfSSL_SSL_CTX_remove_session counts the callback as "found". */
static int test_0rtt_ext_only_rem_calls;
static int test_0rtt_ext_only_new_cb(WOLFSSL* ssl, WOLFSSL_SESSION* s)
{
(void)ssl; (void)s;
return 0; /* don't retain */
}
static WOLFSSL_SESSION* test_0rtt_ext_only_get_cb(WOLFSSL* ssl,
const byte* id, int idLen, int* ref)
{
(void)ssl; (void)id; (void)idLen;
*ref = 0;
return NULL;
}
static void test_0rtt_ext_only_rem_cb(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* s)
{
(void)ctx; (void)s;
test_0rtt_ext_only_rem_calls++;
}
#endif
/* Verify that when the internal cache is off but an external cache callback
* is registered, wolfSSL_SSL_CTX_remove_session returns 1 (the ext callback
* fired, so we assume the session was present). Fails without the fix
* because the old code only set found=1 on an internal-cache hit. */
int test_tls13_0rtt_ext_cache_eviction(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_TLS13) && defined(WOLFSSL_EARLY_DATA) && \
defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TICKET_HAVE_ID) && \
!defined(NO_SESSION_CACHE) && defined(HAVE_EXT_CACHE) && \
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
WOLFSSL_SESSION *sess = NULL;
char buf[64];
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
test_0rtt_ext_only_rem_calls = 0;
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method),
0);
/* Turn off internal cache; rely on external callbacks only. */
ExpectIntEQ(wolfSSL_CTX_set_session_cache_mode(ctx_s,
WOLFSSL_SESS_CACHE_NO_INTERNAL), WOLFSSL_SUCCESS);
wolfSSL_CTX_sess_set_new_cb(ctx_s, test_0rtt_ext_only_new_cb);
wolfSSL_CTX_sess_set_get_cb(ctx_s, test_0rtt_ext_only_get_cb);
wolfSSL_CTX_sess_set_remove_cb(ctx_s, test_0rtt_ext_only_rem_cb);
ExpectTrue(wolfSSL_set_options(ssl_s, WOLFSSL_OP_NO_TICKET) != 0);
ExpectIntGE(wolfSSL_set_max_early_data(ssl_s, MAX_EARLY_DATA_SZ), 0);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* remove_session on an ext-cache-only server: rem_cb should fire and
* the function should return 1 (assumes the ext cache had it). */
ExpectNotNull(sess = wolfSSL_get1_session(ssl_s));
ExpectIntEQ(wolfSSL_SSL_CTX_remove_session(ctx_s, sess), 1);
ExpectIntGT(test_0rtt_ext_only_rem_calls, 0);
wolfSSL_SESSION_free(sess);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* Check that the client won't send the same CH after a HRR. An HRR without
* a KeyShare or a Cookie extension will trigger the error. */
int test_tls13_same_ch(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_TLS13) && defined(WOLFSSL_AES_128) && \
defined(HAVE_AESGCM) && !defined(NO_SHA256) && \
/* middlebox compat requires that the session ID is echoed */ \
!defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL *ssl_c = NULL;
struct test_memio_ctx test_ctx;
/* Transport Layer Security
* TLSv1.3 Record Layer: Handshake Protocol: Hello Retry Request
* Content Type: Handshake (22)
* Version: TLS 1.2 (0x0303)
* Length: 50
* Handshake Protocol: Hello Retry Request
* Handshake Type: Server Hello (2)
* Length: 46
* Version: TLS 1.2 (0x0303)
* Random: cf21ad74e59a6111be1d8c021e65b891c2a211167abb8c5e079e09e2c8a8339c (HelloRetryRequest magic)
* Session ID Length: 0
* Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
* Compression Method: null (0)
* Extensions Length: 6
* Extension: supported_versions (len=2) TLS 1.3 */
unsigned char hrr[] = {
0x16, 0x03, 0x03, 0x00, 0x32, 0x02, 0x00, 0x00, 0x2e, 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, 0x01, 0x00, 0x00,
0x06, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04
};
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);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, (char*)hrr,
sizeof(hrr)), 0);
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
/* issue 9653: use a more appropriate error than DUPLICATE_MSG_E.
* Since the cause of this is missing extension, return that. */
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), EXT_MISSING);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
#endif
return EXPECT_RESULT();
}
int test_tls13_hrr_different_cs(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_TLS13) && \
defined(BUILD_TLS_AES_256_GCM_SHA384) && \
defined(BUILD_TLS_CHACHA20_POLY1305_SHA256) && \
defined(HAVE_ECC) && defined(HAVE_ECC384) && \
!defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
/*
* TLSv1.3 Record Layer: Handshake Protocol: Hello Retry Request
* Content Type: Handshake (22)
* Version: TLS 1.2 (0x0303)
* Length: 56
* Handshake Protocol: Hello Retry Request
* Handshake Type: Server Hello (2)
* Length: 52
* Version: TLS 1.2 (0x0303)
* Random: cf21ad74e59a6111be1d8c021e65b891c2a211167abb8c5e079e09e2c8a8339c (HelloRetryRequest magic)
* Session ID Length: 0
* Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302)
* Compression Method: null (0)
* Extensions Length: 12
* Extension: supported_versions (len=2) TLS 1.3
* Extension: key_share (len=2) secp384r1
*
*/
unsigned char hrr[] = {
0x16, 0x03, 0x03, 0x00, 0x38, 0x02, 0x00, 0x00, 0x34, 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, 0x02, 0x00, 0x00,
0x0c, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04, 0x00, 0x33, 0x00, 0x02, 0x00,
0x18
};
/*
* TLSv1.3 Record Layer: Handshake Protocol: Server Hello
* Content Type: Handshake (22)
* Version: TLS 1.2 (0x0303)
* Length: 155
* Handshake Protocol: Server Hello
* Handshake Type: Server Hello (2)
* Length: 151
* Version: TLS 1.2 (0x0303)
* Random: 0101010101010101010101010101010101010101010101010101010101010101
* Session ID Length: 0
* Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303)
* Compression Method: null (0)
* Extensions Length: 111
* Extension: key_share (len=101) secp384r1
* Extension: supported_versions (len=2) TLS 1.3
*
*/
unsigned char sh[] = {
0x16, 0x03, 0x03, 0x00, 0x9b, 0x02, 0x00, 0x00, 0x97, 0x03, 0x03, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x13, 0x03, 0x00, 0x00,
0x6f, 0x00, 0x33, 0x00, 0x65, 0x00, 0x18, 0x00, 0x61, 0x04, 0x53, 0x3e,
0xe5, 0xbf, 0x40, 0xec, 0x2d, 0x67, 0x98, 0x8b, 0x77, 0xf3, 0x17, 0x48,
0x9b, 0xb6, 0xdf, 0x95, 0x29, 0x25, 0xc7, 0x09, 0xfc, 0x03, 0x81, 0x11,
0x1a, 0x59, 0x56, 0xf2, 0xd7, 0x58, 0x11, 0x0e, 0x59, 0xd3, 0xd7, 0xc1,
0x72, 0x9e, 0x2c, 0x0d, 0x70, 0xea, 0xf7, 0x73, 0xe6, 0x12, 0x01, 0x16,
0x42, 0x6d, 0xe2, 0x43, 0x6a, 0x2f, 0x5f, 0xdd, 0x7f, 0xe5, 0x4f, 0xaf,
0x95, 0x2b, 0x04, 0xfd, 0x13, 0xf5, 0x16, 0xce, 0x62, 0x7f, 0x89, 0xd2,
0x01, 0x9d, 0x4c, 0x87, 0x96, 0x95, 0x9e, 0x43, 0x33, 0xc7, 0x06, 0x5b,
0x49, 0x6c, 0xa6, 0x34, 0xd5, 0xdc, 0x63, 0xbd, 0xe9, 0x1f, 0x00, 0x2b,
0x00, 0x02, 0x03, 0x04
};
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,
wolfTLSv1_3_client_method, NULL), 0);
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, (char*)hrr,
sizeof(hrr)), 0);
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, (char*)sh,
sizeof(sh)), 0);
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), INVALID_PARAMETER);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
#endif
return EXPECT_RESULT();
}
/* Server-side complement to test_tls13_hrr_different_cs: the client sends a
* different cipher suite in CH2 than what the server selected in the HRR. */
int test_tls13_ch2_different_cs(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER) && \
defined(BUILD_TLS_AES_256_GCM_SHA384) && \
defined(BUILD_TLS_AES_128_GCM_SHA256) && \
defined(HAVE_ECC) && defined(HAVE_ECC384)
/*
* First ClientHello: cipher suite TLS_AES_256_GCM_SHA384 (0x1302),
* empty key_share, secp384r1 in supported_groups. This triggers the
* server to send a HelloRetryRequest selecting TLS_AES_256_GCM_SHA384
* and requesting a secp384r1 key share.
*/
/*
* TLSv1.3 Record Layer: Handshake Protocol: Client Hello
* Content Type: Handshake (22)
* Version: TLS 1.2 (0x0303)
* Length: 110
* Handshake Protocol: Client Hello
* Handshake Type: Client Hello (1)
* Length: 106
* Version: TLS 1.2 (0x0303)
* Random: 0101010101010101010101010101010101010101010101010101010101010101
* Session ID Length: 32
* Session ID: 0303030303030303030303030303030303030303030303030303030303030303
* Cipher Suites Length: 2
* Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302)
* Compression Methods Length: 1
* Compression Method: null (0)
* Extensions Length: 31
* Extension: supported_groups (len=4) secp384r1 (0x0018)
* Extension: signature_algorithms (len=6) rsa_pkcs1_sha256 (0x0401),
* rsa_pss_rsae_sha256 (0x0804)
* Extension: key_share (len=2) client_shares length=0 (empty)
* Extension: supported_versions (len=3) TLS 1.3 (0x0304)
*/
unsigned char ch1[] = {
0x16, 0x03, 0x03, 0x00, 0x6e, 0x01, 0x00, 0x00, 0x6a, 0x03, 0x03, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x00, 0x02, 0x13, 0x02, 0x01, 0x00, 0x00, 0x1f,
0x00, 0x0a, 0x00, 0x04, 0x00, 0x02, 0x00, 0x18, 0x00, 0x0d, 0x00, 0x06,
0x00, 0x04, 0x04, 0x01, 0x08, 0x04, 0x00, 0x33, 0x00, 0x02, 0x00, 0x00,
0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04
};
/*
* TLSv1.3 Record Layer: Handshake Protocol: Client Hello
* Content Type: Handshake (22)
* Version: TLS 1.2 (0x0303)
* Length: 211
* Handshake Protocol: Client Hello
* Handshake Type: Client Hello (1)
* Length: 207
* Version: TLS 1.2 (0x0303)
* Random: 0101010101010101010101010101010101010101010101010101010101010101
* Session ID Length: 32
* Session ID: 0303030303030303030303030303030303030303030303030303030303030303
* Cipher Suites Length: 2
* Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
* Compression Methods Length: 1
* Compression Method: null (0)
* Extensions Length: 132
* Extension: supported_groups (len=4) secp384r1 (0x0018)
* Extension: signature_algorithms (len=6) rsa_pkcs1_sha256 (0x0401),
* rsa_pss_rsae_sha256 (0x0804)
* Extension: key_share (len=103)
* client_shares length: 101
* KeyShareEntry: group secp384r1 (0x0018), key_exchange length: 97
* key_exchange: 04 || X(48) || Y(48) (uncompressed P-384 point)
* Extension: supported_versions (len=3) TLS 1.3 (0x0304)
*/
unsigned char ch2[] = {
0x16, 0x03, 0x03, 0x00, 0xd3, 0x01, 0x00, 0x00, 0xcf, 0x03, 0x03, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x00, 0x02, 0x13, 0x01, 0x01, 0x00, 0x00, 0x84,
0x00, 0x0a, 0x00, 0x04, 0x00, 0x02, 0x00, 0x18, 0x00, 0x0d, 0x00, 0x06,
0x00, 0x04, 0x04, 0x01, 0x08, 0x04, 0x00, 0x33, 0x00, 0x67, 0x00, 0x65,
0x00, 0x18, 0x00, 0x61, 0x04, 0x53, 0x3e, 0xe5, 0xbf, 0x40, 0xec, 0x2d,
0x67, 0x98, 0x8b, 0x77, 0xf3, 0x17, 0x48, 0x9b, 0xb6, 0xdf, 0x95, 0x29,
0x25, 0xc7, 0x09, 0xfc, 0x03, 0x81, 0x11, 0x1a, 0x59, 0x56, 0xf2, 0xd7,
0x58, 0x11, 0x0e, 0x59, 0xd3, 0xd7, 0xc1, 0x72, 0x9e, 0x2c, 0x0d, 0x70,
0xea, 0xf7, 0x73, 0xe6, 0x12, 0x01, 0x16, 0x42, 0x6d, 0xe2, 0x43, 0x6a,
0x2f, 0x5f, 0xdd, 0x7f, 0xe5, 0x4f, 0xaf, 0x95, 0x2b, 0x04, 0xfd, 0x13,
0xf5, 0x16, 0xce, 0x62, 0x7f, 0x89, 0xd2, 0x01, 0x9d, 0x4c, 0x87, 0x96,
0x95, 0x9e, 0x43, 0x33, 0xc7, 0x06, 0x5b, 0x49, 0x6c, 0xa6, 0x34, 0xd5,
0xdc, 0x63, 0xbd, 0xe9, 0x1f, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04
};
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s,
NULL, wolfTLSv1_3_server_method), 0);
/* Server reads CH1, sends HRR, then waits for CH2 */
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (char*)ch1,
sizeof(ch1)), 0);
ExpectIntEQ(wolfSSL_accept(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
/* Server must reject CH2 because the cipher suite changed from the HRR */
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (char*)ch2,
sizeof(ch2)), 0);
ExpectIntEQ(wolfSSL_accept(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), INVALID_PARAMETER);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER) && \
defined(HAVE_ECC) && !defined(NO_FILESYSTEM)
/* Called when writing. */
static int MESend(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 MERecv(WOLFSSL* ssl, char* buf, int sz, void* ctx)
{
WOLFSSL_BUFFER_INFO* msg = (WOLFSSL_BUFFER_INFO*)ctx;
int len = (int)msg->length;
(void)ssl;
/* 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 -= len;
/* Amount actually copied. */
return len;
}
#endif
int test_tls13_sg_missing(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER) && \
defined(HAVE_ECC) && !defined(NO_FILESYSTEM)
WOLFSSL_CTX *ctx = NULL;
WOLFSSL *ssl = NULL;
byte clientHello[] = {
0x16, 0x03, 0x03, 0x00, 0xcb, 0x01, 0x00, 0x00,
0xc7, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x20, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x00, 0x02, 0x13, 0x01,
0x01, 0x00, 0x00, 0x7c, 0x00, 0x0d, 0x00, 0x06,
0x00, 0x04, 0x04, 0x01, 0x08, 0x04,
/* KeyShare */
0x00, 0x33,
0x00, 0x67, 0x00, 0x65, 0x00, 0x18, 0x00, 0x61,
0x04, 0x53, 0x3e, 0xe5, 0xbf, 0x40, 0xec, 0x2d,
0x67, 0x98, 0x8b, 0x77, 0xf3, 0x17, 0x48, 0x9b,
0xb6, 0xdf, 0x95, 0x29, 0x25, 0xc7, 0x09, 0xfc,
0x03, 0x81, 0x11, 0x1a, 0x59, 0x56, 0xf2, 0xd7,
0x58, 0x11, 0x0e, 0x59, 0xd3, 0xd7, 0xc1, 0x72,
0x9e, 0x2c, 0x0d, 0x70, 0xea, 0xf7, 0x73, 0xe6,
0x12, 0x01, 0x16, 0x42, 0x6d, 0xe2, 0x43, 0x6a,
0x2f, 0x5f, 0xdd, 0x7f, 0xe5, 0x4f, 0xaf, 0x95,
0x2b, 0x04, 0xfd, 0x13, 0xf5, 0x16, 0xce, 0x62,
0x7f, 0x89, 0xd2, 0x01, 0x9d, 0x4c, 0x87, 0x96,
0x95, 0x9e, 0x43, 0x33, 0xc7, 0x06, 0x5b, 0x49,
0x6c, 0xa6, 0x34, 0xd5, 0xdc, 0x63, 0xbd, 0xe9,
0x1f,
/* SupportedVersions */
0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04
/* Missing SupportedGroups. */
};
WOLFSSL_BUFFER_INFO msg;
WOLFSSL_ALERT_HISTORY h;
/* Set up wolfSSL context. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, eccCertFile,
CERT_FILETYPE));
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, eccKeyFile,
CERT_FILETYPE));
/* Read from 'msg'. */
wolfSSL_SetIORecv(ctx, MERecv);
/* No where to send to - dummy sender. */
wolfSSL_SetIOSend(ctx, MESend);
/* Test cipher suite list with many copies of a cipher suite. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
msg.buffer = clientHello;
msg.length = (unsigned int)sizeof(clientHello);
wolfSSL_SetIOReadCtx(ssl, &msg);
ExpectIntEQ(wolfSSL_accept_TLSv13(ssl),
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
ExpectIntEQ(wolfSSL_get_alert_history(ssl, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_tx.code, missing_extension);
ExpectIntEQ(h.last_tx.level, alert_fatal);
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
int test_tls13_ks_missing(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER) && \
defined(HAVE_ECC) && !defined(NO_FILESYSTEM)
WOLFSSL_CTX *ctx = NULL;
WOLFSSL *ssl = NULL;
byte clientHello[] = {
0x16, 0x03, 0x03, 0x00, 0x66, 0x01, 0x00, 0x00,
0x62, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x20, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x00, 0x02, 0x13, 0x01,
0x01, 0x00, 0x00, 0x17, 0x00, 0x0d, 0x00, 0x06,
0x00, 0x04, 0x04, 0x01, 0x08, 0x04,
/* SupportedGroups */
0x00, 0x0a,
0x00, 0x02, 0x00, 0x18,
/* SupportedVersions */
0x00, 0x2b, 0x00, 0x03,
0x02, 0x03, 0x04
/* Missing KeyShare. */
};
WOLFSSL_BUFFER_INFO msg;
WOLFSSL_ALERT_HISTORY h;
/* Set up wolfSSL context. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, eccCertFile,
CERT_FILETYPE));
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, eccKeyFile,
CERT_FILETYPE));
/* Read from 'msg'. */
wolfSSL_SetIORecv(ctx, MERecv);
/* No where to send to - dummy sender. */
wolfSSL_SetIOSend(ctx, MESend);
/* Test cipher suite list with many copies of a cipher suite. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
msg.buffer = clientHello;
msg.length = (unsigned int)sizeof(clientHello);
wolfSSL_SetIOReadCtx(ssl, &msg);
ExpectIntEQ(wolfSSL_accept_TLSv13(ssl),
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
ExpectIntEQ(wolfSSL_get_alert_history(ssl, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_tx.code, missing_extension);
ExpectIntEQ(h.last_tx.level, alert_fatal);
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT) && \
defined(HAVE_ECC)
/* Called when writing. */
static int DESend(WOLFSSL* ssl, char* buf, int sz, void* ctx)
{
(void)ssl;
(void)buf;
(void)sz;
(void)ctx;
return sz;
}
/* Called when reading. */
static int DERecv(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 -= len;
/* Amount actually copied. */
return len;
}
#endif
int test_tls13_duplicate_extension(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT) && \
defined(HAVE_ECC)
WOLFSSL_CTX *ctx = NULL;
WOLFSSL *ssl = NULL;
byte serverHello[] = {
0x16, 0x03, 0x03, 0x00, 0x81, 0x02, 0x00, 0x00,
0x7d, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x00, 0x13, 0x01, 0x00, 0x00,
0x55, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04, 0x00,
0x33, 0x00, 0x45, 0x00, 0x17, 0x00, 0x41, 0x04,
0x0c, 0x90, 0x1d, 0x42, 0x3c, 0x83, 0x1c, 0xa8,
0x5e, 0x27, 0xc7, 0x3c, 0x26, 0x3b, 0xa1, 0x32,
0x72, 0x1b, 0xb9, 0xd7, 0xa8, 0x4c, 0x4f, 0x03,
0x80, 0xb2, 0xa6, 0x75, 0x6f, 0xd6, 0x01, 0x33,
0x1c, 0x88, 0x70, 0x23, 0x4d, 0xec, 0x87, 0x85,
0x04, 0xc1, 0x74, 0x14, 0x4f, 0xa4, 0xb1, 0x4b,
0x66, 0xa6, 0x51, 0x69, 0x16, 0x06, 0xd8, 0x17,
0x3e, 0x55, 0xbd, 0x37, 0xe3, 0x81, 0x56, 0x9e,
0x00, 0x2b, 0x00, 0x02, 0x03, 0x04
};
WOLFSSL_BUFFER_INFO msg;
WOLFSSL_ALERT_HISTORY h;
/* Set up wolfSSL context. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
/* Read from 'msg'. */
wolfSSL_SetIORecv(ctx, DERecv);
/* No where to send to - dummy sender. */
wolfSSL_SetIOSend(ctx, DESend);
/* Test cipher suite list with many copies of a cipher suite. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
msg.buffer = serverHello;
msg.length = (unsigned int)sizeof(serverHello);
wolfSSL_SetIOReadCtx(ssl, &msg);
ExpectIntEQ(wolfSSL_connect_TLSv13(ssl),
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
ExpectIntEQ(wolfSSL_get_alert_history(ssl, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_tx.code, illegal_parameter);
ExpectIntEQ(h.last_tx.level, alert_fatal);
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) && \
!defined(NO_WOLFSSL_SERVER) && !defined(NO_FILESYSTEM) && \
(!defined(NO_RSA) || defined(HAVE_ECC))
static int DupEchSend(WOLFSSL* ssl, char* buf, int sz, void* ctx)
{
(void)ssl;
(void)buf;
(void)sz;
(void)ctx;
return sz;
}
static int DupEchRecv(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;
if (len > sz)
len = sz;
XMEMCPY(buf, msg->buffer, len);
msg->buffer += len;
msg->length -= len;
return len;
}
#endif
/* Test detection of duplicate ECH extension (type 0xfe0d) in ClientHello.
* ECH has a semaphore mapping in TLSX_ToSemaphore() and needs to be included
* in the duplicate-detection gate in TLSX_Parse(). RFC 8446 section 4.2
* requires rejecting messages with duplicate extensions.
*/
int test_tls13_duplicate_ech_extension(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) && \
!defined(NO_WOLFSSL_SERVER) && !defined(NO_FILESYSTEM) && \
(!defined(NO_RSA) || defined(HAVE_ECC))
/* TLS 1.3 ClientHello with two ECH extensions (type 0xfe0d).
* Extensions block contains: supported_versions + ECH + ECH (dup). */
const unsigned char clientHelloDupEch[] = {
0x16, 0x03, 0x03, 0x00, 0x40, 0x01, 0x00, 0x00,
0x3c, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x13, 0x01,
0x01, 0x00, 0x00, 0x11, 0x00, 0x2b, 0x00, 0x03,
0x02, 0x03, 0x04, 0xfe, 0x0d, 0x00, 0x01, 0x00,
0xfe, 0x0d, 0x00, 0x01, 0x00
};
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(wolfTLSv1_3_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, DupEchRecv);
/* No where to send to - dummy sender. */
wolfSSL_SetIOSend(ctx, DupEchSend);
ssl = wolfSSL_new(ctx);
ExpectNotNull(ssl);
msg.buffer = (unsigned char*)clientHelloDupEch;
msg.length = (unsigned int)sizeof(clientHelloDupEch);
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();
}
int test_key_share_mismatch(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
defined(HAVE_SUPPORTED_CURVES) && defined(HAVE_ECC) && \
defined(BUILD_TLS_AES_128_GCM_SHA256) && (!defined(WOLFSSL_SP_MATH) || \
(defined(WOLFSSL_SP_521) && !defined(WOLFSSL_SP_NO_256) && \
defined(WOLFSSL_SP_384)))
/* Taken from payload in https://github.com/wolfSSL/wolfssl/issues/9362 */
const byte ch1_bin[] = {
0x16, 0x03, 0x03, 0x00, 0x96, 0x01, 0x00, 0x00, 0x92, 0x03, 0x03, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x00, 0x02, 0x13, 0x01, 0x01, 0x00, 0x00, 0x47,
0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x18, 0x00, 0x17, 0x00, 0x1d,
0x00, 0x0d, 0x00, 0x06, 0x00, 0x04, 0x04, 0x01, 0x08, 0x04, 0x00, 0x33,
0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x07, 0xaa, 0xff, 0x3e,
0x9f, 0xc1, 0x67, 0x27, 0x55, 0x44, 0xf4, 0xc3, 0xa6, 0xa1, 0x7c, 0xd8,
0x37, 0xf2, 0xec, 0x6e, 0x78, 0xcd, 0x8a, 0x57, 0xb1, 0xe3, 0xdf, 0xb3,
0xcc, 0x03, 0x5a, 0x76, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04
};
const byte ch2_bin[] = {
0x16, 0x03, 0x03, 0x00, 0xb7, 0x01, 0x00, 0x00, 0xb3, 0x03, 0x03, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x00, 0x02, 0x13, 0x01, 0x01, 0x00, 0x00, 0x68,
0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x18, 0x00, 0x17, 0x00, 0x1d,
0x00, 0x0d, 0x00, 0x06, 0x00, 0x04, 0x04, 0x01, 0x08, 0x04, 0x00, 0x33,
0x00, 0x47, 0x00, 0x45, 0x00, 0x17, 0x00, 0x41, 0x04, 0x0c, 0x90, 0x1d,
0x42, 0x3c, 0x83, 0x1c, 0xa8, 0x5e, 0x27, 0xc7, 0x3c, 0x26, 0x3b, 0xa1,
0x32, 0x72, 0x1b, 0xb9, 0xd7, 0xa8, 0x4c, 0x4f, 0x03, 0x80, 0xb2, 0xa6,
0x75, 0x6f, 0xd6, 0x01, 0x33, 0x1c, 0x88, 0x70, 0x23, 0x4d, 0xec, 0x87,
0x85, 0x04, 0xc1, 0x74, 0x14, 0x4f, 0xa4, 0xb1, 0x4b, 0x66, 0xa6, 0x51,
0x69, 0x16, 0x06, 0xd8, 0x17, 0x3e, 0x55, 0xbd, 0x37, 0xe3, 0x81, 0x56,
0x9e, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04
};
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
int client_group[] = {WOLFSSL_ECC_SECP521R1};
int server_group[] = {WOLFSSL_ECC_SECP384R1, WOLFSSL_ECC_SECP256R1};
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);
ExpectIntEQ(wolfSSL_set_groups(ssl_c,
client_group, XELEM_CNT(client_group)), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_groups(ssl_s,
server_group, XELEM_CNT(server_group)), WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), BAD_KEY_SHARE_DATA);
wolfSSL_free(ssl_s);
ssl_s = NULL;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s,
NULL, wolfTLSv1_3_server_method), 0);
ExpectIntEQ(wolfSSL_set_groups(ssl_s,
server_group, XELEM_CNT(server_group)), WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char*)ch1_bin,
sizeof(ch1_bin)), 0);
ExpectIntEQ(wolfSSL_accept(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char*)ch2_bin,
sizeof(ch2_bin)), 0);
ExpectIntEQ(wolfSSL_accept(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), BAD_KEY_SHARE_DATA);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && !defined(NO_RSA) && defined(HAVE_ECC) && \
defined(HAVE_AESGCM) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_FILESYSTEM)
/* Called when writing. */
static int Tls13PTASend(WOLFSSL* ssl, char* buf, int sz, void* ctx)
{
(void)ssl;
(void)buf;
(void)ctx;
return sz;
}
static int Tls13PTARecv(WOLFSSL* ssl, char* buf, int sz, void* ctx)
{
WOLFSSL_BUFFER_INFO* msg = (WOLFSSL_BUFFER_INFO*)ctx;
int len;
(void)ssl;
if (msg->length == 0) {
/* Only do as many alerts as required to get to max alert count. */
msg->buffer[0]--;
if (msg->buffer[0] > 0) {
msg->buffer -= 7;
msg->length += 7;
}
else {
return -1;
}
}
len = (int)msg->length;
/* 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 -= len;
/* Amount actually copied. */
return len;
}
#endif
/* Test that when a TLS 1.3 client sends a ClientHello with an empty
* legacy_session_id (indicating no middlebox compatibility), the server
* should NOT send a ChangeCipherSpec message. Per RFC 8446 Appendix D.4,
* the server only sends CCS if the client's ClientHello contains a
* non-empty session_id.
*
* This test reproduces the bug reported in GitHub issue #9156 where
* wolfSSL server always sends CCS when compiled with
* WOLFSSL_TLS13_MIDDLEBOX_COMPAT, regardless of the client's session_id.
*/
int test_tls13_middlebox_compat_empty_session_id(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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 i;
int found_ccs = 0;
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);
/* Disable middlebox compatibility on the client so it sends an empty
* legacy_session_id in ClientHello. The server should respect this and
* NOT send a ChangeCipherSpec. */
if (EXPECT_SUCCESS()) {
ssl_c->options.tls13MiddleBoxCompat = 0;
}
/* Client sends ClientHello with empty session ID */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c,
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)), WOLFSSL_ERROR_WANT_READ);
/* Server processes ClientHello and sends its flight:
* ServerHello, EncryptedExtensions, Certificate, CertVerify, Finished
* (and potentially an unwanted CCS) */
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s,
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)), WOLFSSL_ERROR_WANT_READ);
/* Now examine the server's output (stored in c_buff, since the server
* writes to the client's read buffer). Scan through TLS records looking
* for a ChangeCipherSpec record (content type 0x14 = 20). */
if (EXPECT_SUCCESS()) {
i = 0;
while (i + 5 <= test_ctx.c_len) {
byte content_type = test_ctx.c_buff[i];
int record_len = (test_ctx.c_buff[i + 3] << 8) |
test_ctx.c_buff[i + 4];
if (content_type == 20) { /* change_cipher_spec */
found_ccs = 1;
break;
}
/* Move to next TLS record: 5 byte header + payload */
i += 5 + record_len;
}
}
/* The server should NOT have sent CCS since the client's ClientHello
* had an empty legacy_session_id. If found_ccs is 1, this demonstrates
* the bug from issue #9156. */
ExpectIntEQ(found_ccs, 0);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_plaintext_alert(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_RSA) && defined(HAVE_ECC) && \
defined(HAVE_AESGCM) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_FILESYSTEM)
byte clientMsgs[] = {
/* Client Hello */
0x16, 0x03, 0x03, 0x01, 0x9b, 0x01, 0x00, 0x01,
0x97, 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,
0x13, 0x02, 0x01, 0x00, 0x01, 0x4a, 0x00, 0x2d,
0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x33, 0x00,
0x47, 0x00, 0x45, 0x00, 0x17, 0x00, 0x41, 0x04,
0x90, 0xfc, 0xe2, 0x97, 0x05, 0x7c, 0xb5, 0x23,
0x5d, 0x5f, 0x5b, 0xcd, 0x0c, 0x1e, 0xe0, 0xe9,
0xab, 0x38, 0x6b, 0x1e, 0x20, 0x5c, 0x1c, 0x90,
0x2a, 0x9e, 0x68, 0x8e, 0x70, 0x05, 0x10, 0xa8,
0x02, 0x1b, 0xf9, 0x5c, 0xef, 0xc9, 0xaf, 0xca,
0x1a, 0x3b, 0x16, 0x8b, 0xe4, 0x1b, 0x3c, 0x15,
0xb8, 0x0d, 0xbd, 0xaf, 0x62, 0x8d, 0xa7, 0x13,
0xa0, 0x7c, 0xe0, 0x59, 0x0c, 0x4f, 0x8a, 0x6d,
0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04, 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, 0x04, 0x00,
0x02, 0x00, 0x17, 0x00, 0x16, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x29, 0x00, 0xb9, 0x00,
0x94, 0x00, 0x8e, 0x0f, 0x12, 0xfa, 0x84, 0x1f,
0x76, 0x94, 0xd7, 0x09, 0x5e, 0xad, 0x08, 0x51,
0xb6, 0x80, 0x28, 0x31, 0x8b, 0xfd, 0xc6, 0xbd,
0x9e, 0xf5, 0x3b, 0x4d, 0x02, 0xbe, 0x1d, 0x73,
0xea, 0x13, 0x68, 0x00, 0x4c, 0xfd, 0x3d, 0x48,
0x51, 0xf9, 0x06, 0xbb, 0x92, 0xed, 0x42, 0x9f,
0x7f, 0x2c, 0x73, 0x9f, 0xd9, 0xb4, 0xef, 0x05,
0x26, 0x5b, 0x60, 0x5c, 0x0a, 0xfc, 0xa3, 0xbd,
0x2d, 0x2d, 0x8b, 0xf9, 0xaa, 0x5c, 0x96, 0x3a,
0xf2, 0xec, 0xfa, 0xe5, 0x57, 0x2e, 0x87, 0xbe,
0x27, 0xc5, 0x3d, 0x4f, 0x5d, 0xdd, 0xde, 0x1c,
0x1b, 0xb3, 0xcc, 0x27, 0x27, 0x57, 0x5a, 0xd9,
0xea, 0x99, 0x27, 0x23, 0xa6, 0x0e, 0xea, 0x9c,
0x0d, 0x85, 0xcb, 0x72, 0xeb, 0xd7, 0x93, 0xe3,
0xfe, 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, 0xfb, 0x92, 0xce, 0xaa, 0x00, 0x21, 0x20,
0xcb, 0x73, 0x25, 0x80, 0x46, 0x78, 0x4f, 0xe5,
0x34, 0xf6, 0x91, 0x13, 0x7f, 0xc8, 0x8d, 0xdc,
0x81, 0x04, 0xb7, 0x0d, 0x49, 0x85, 0x2e, 0x12,
0x7a, 0x07, 0x23, 0xe9, 0x13, 0xa4, 0x6d, 0x8c,
0x15, 0x03, 0x03, 0x00, 0x02, 0x01, 0x00, 0x00
};
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
WOLFSSL_BUFFER_INFO msg;
#ifdef WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC
/* We fail on WOLFSSL_ALERT_COUNT_MAX alerts. */
/* Set up wolfSSL context. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
CERT_FILETYPE));
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
CERT_FILETYPE));
if (EXPECT_SUCCESS()) {
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL);
}
/* Read from 'msg'. */
wolfSSL_SetIORecv(ctx, Tls13PTARecv);
/* No where to send to - dummy sender. */
wolfSSL_SetIOSend(ctx, Tls13PTASend);
ExpectNotNull(ssl = wolfSSL_new(ctx));
msg.buffer = clientMsgs;
msg.length = (unsigned int)sizeof(clientMsgs) - 1;
clientMsgs[sizeof(clientMsgs) - 1] = WOLFSSL_ALERT_COUNT_MAX;
if (EXPECT_SUCCESS()) {
wolfSSL_SetIOReadCtx(ssl, &msg);
}
/* Alert will be ignored until too many. */
/* Read all message include CertificateVerify with invalid signature
* algorithm. */
ExpectIntEQ(wolfSSL_accept(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
/* Expect an invalid parameter error. */
ExpectIntEQ(wolfSSL_get_error(ssl, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(ALERT_COUNT_E));
wolfSSL_free(ssl);
ssl = NULL;
wolfSSL_CTX_free(ctx);
ctx = NULL;
/* Set up wolfSSL context. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
CERT_FILETYPE));
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
CERT_FILETYPE));
if (EXPECT_SUCCESS()) {
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL);
}
/* Read from 'msg'. */
wolfSSL_SetIORecv(ctx, Tls13PTARecv);
/* No where to send to - dummy sender. */
wolfSSL_SetIOSend(ctx, Tls13PTASend);
ExpectNotNull(ssl = wolfSSL_new(ctx));
msg.buffer = clientMsgs;
msg.length = (unsigned int)sizeof(clientMsgs) - 1;
clientMsgs[sizeof(clientMsgs) - 1] = WOLFSSL_ALERT_COUNT_MAX - 1;
if (EXPECT_SUCCESS()) {
wolfSSL_SetIOReadCtx(ssl, &msg);
}
/* Alert will be ignored until too many. */
/* Read all message include CertificateVerify with invalid signature
* algorithm. */
ExpectIntEQ(wolfSSL_accept(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
/* Expect an invalid parameter error. */
ExpectIntEQ(wolfSSL_get_error(ssl, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(SOCKET_ERROR_E));
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
ssl = NULL;
ctx = NULL;
/* Negative test: a plaintext alert must NOT be ignored once the peer has
* responded with an encrypted handshake message. Complete a handshake so
* the peer is encrypting, then feed the client a plaintext alert. */
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_FILESYSTEM)
{
WOLFSSL_CTX* ctx_c = NULL;
WOLFSSL_CTX* ctx_s = NULL;
WOLFSSL* ssl_c = NULL;
WOLFSSL* ssl_s = NULL;
struct test_memio_ctx test_ctx;
/* Plaintext alert record: fatal (2), handshake_failure (40). */
byte ptAlert[] = { 0x15, 0x03, 0x03, 0x00, 0x02, 0x02, 0x28 };
char data[16];
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);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Drop any post-handshake data (e.g. session tickets) queued for the
* client and feed it only the plaintext alert. */
test_memio_clear_buffer(&test_ctx, 1);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, (const char*)ptAlert,
(int)sizeof(ptAlert)), 0);
/* Plaintext alert is rejected as the peer is encrypting. */
ExpectIntLT(wolfSSL_read(ssl_c, data, (int)sizeof(data)), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(PARSE_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
}
/* Negative test (server): a plaintext alert must NOT be ignored once the
* client has sent an encrypted handshake message, even before the
* handshake is complete. Use client authentication so that the client
* sends an encrypted Certificate message before Finished. */
{
WOLFSSL_CTX* ctx_c = NULL;
WOLFSSL_CTX* ctx_s = NULL;
WOLFSSL* ssl_c = NULL;
WOLFSSL* ssl_s = NULL;
struct test_memio_ctx test_ctx;
/* Plaintext alert record: fatal (2), handshake_failure (40). */
byte ptAlert[] = { 0x15, 0x03, 0x03, 0x00, 0x02, 0x02, 0x28 };
int end = 0;
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);
/* Server requires a client certificate. */
ExpectTrue(wolfSSL_CTX_load_verify_locations(ctx_s, cliCertFile,
NULL) == WOLFSSL_SUCCESS);
if (EXPECT_SUCCESS()) {
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER |
WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
}
ExpectTrue(wolfSSL_use_certificate_file(ssl_c, cliCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
/* Client Hello. */
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* Server flight including CertificateRequest. */
ExpectIntEQ(wolfSSL_accept(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
/* Client flight: [CCS,] Certificate, CertificateVerify, Finished. */
ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
/* Find the end of the first encrypted record (outer content type
* application_data) the client sent - the Certificate message. */
while (end + 5 <= test_ctx.s_len) {
byte recType = test_ctx.s_buff[end];
end += 5 + ((test_ctx.s_buff[end + 3] << 8) |
test_ctx.s_buff[end + 4]);
if (recType == 0x17)
break;
}
ExpectIntLE(end, test_ctx.s_len);
ExpectIntGT(end, 0);
/* Remove the records after it (CertificateVerify and Finished),
* working backwards a message at a time. */
while (EXPECT_SUCCESS() && test_ctx.s_len > end) {
int i;
int msgOff = 0;
for (i = 0; i < test_ctx.s_msg_count - 1; i++)
msgOff += test_ctx.s_msg_sizes[i];
if (msgOff >= end) {
/* Last message is wholly after the Certificate record. */
ExpectIntEQ(test_memio_drop_message(&test_ctx, 0,
test_ctx.s_msg_count - 1), 0);
}
else {
/* Last message also holds the records to keep. */
ExpectIntEQ(test_memio_remove_from_buffer(&test_ctx, 0, end,
test_ctx.s_len - end), 0);
}
}
/* Follow the encrypted Certificate message with a plaintext alert. */
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0,
(const char*)ptAlert, (int)sizeof(ptAlert)), 0);
/* Plaintext alert is rejected as the client has sent an encrypted
* handshake message. */
ExpectIntEQ(wolfSSL_accept(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(PARSE_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
}
#endif
#else
/* Fail on plaintext alert when encryption keys on. */
/* Set up wolfSSL context. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
CERT_FILETYPE));
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
CERT_FILETYPE));
if (EXPECT_SUCCESS()) {
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL);
}
/* Read from 'msg'. */
wolfSSL_SetIORecv(ctx, Tls13PTARecv);
/* No where to send to - dummy sender. */
wolfSSL_SetIOSend(ctx, Tls13PTASend);
ExpectNotNull(ssl = wolfSSL_new(ctx));
msg.buffer = clientMsgs;
msg.length = (unsigned int)sizeof(clientMsgs) - 1;
clientMsgs[sizeof(clientMsgs) - 1] = 1;
if (EXPECT_SUCCESS()) {
wolfSSL_SetIOReadCtx(ssl, &msg);
}
/* Alert will be ignored until too many. */
/* Read all message include CertificateVerify with invalid signature
* algorithm. */
ExpectIntEQ(wolfSSL_accept(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
/* Expect an invalid parameter error. */
ExpectIntEQ(wolfSSL_get_error(ssl, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(PARSE_ERROR));
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
#endif
#endif
return EXPECT_RESULT();
}
/* Test that TLS 1.3 warning-level alerts are treated as fatal (RFC 8446
* Section 6.2).
* A peer sending e.g. {alert_warning, handshake_failure} must still cause the
* connection to be terminated, not silently continued.
*/
int test_tls13_warning_alert_is_fatal(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL *ssl_c = NULL;
struct test_memio_ctx test_ctx;
WOLFSSL_ALERT_HISTORY h;
/* TLS record: content_type=alert(0x15), version=TLS1.2(0x0303), len=2,
* level=warning(0x01), code=handshake_failure(0x28=40) */
static const unsigned char warn_alert[] =
{ 0x15, 0x03, 0x03, 0x00, 0x02, 0x01, 0x28 };
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);
/* Client sends ClientHello, then waits for the server response. */
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* Inject a warning-level handshake_failure alert as if from the server.
* RFC 8446 Section 6.2: In TLS 1.3, all error alerts MUST be treated as
* fatalregardless of the AlertLevel byte. */
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1,
(const char *)warn_alert, sizeof(warn_alert)), 0);
/* Expect the connection to be terminated, not silently continued. */
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WC_NO_ERR_TRACE(FATAL_ERROR));
/* The alert details should be recorded correctly. */
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_rx.code, handshake_failure);
ExpectIntEQ(h.last_rx.level, alert_warning);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
#endif
return EXPECT_RESULT();
}
/* Test that an unknown extension in a TLS 1.3 server-to-client message is
* rejected with unsupported_extension (RFC 8446 Sec. 4.2). The client MUST
* abort the handshake when it receives an extension it did not advertise.
*/
int test_tls13_unknown_ext_rejected(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && defined(WOLFSSL_AES_128) && \
defined(HAVE_AESGCM) && !defined(NO_SHA256) && \
!defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL *ssl_c = NULL;
struct test_memio_ctx test_ctx;
/* HelloRetryRequest carrying TLS_AES_128_GCM_SHA256, supported_versions
* (TLS 1.3), and an extra unknown extension type 0xFABC.
*
* The base HRR (from test_tls13_same_ch) extended with 4 bytes:
* extensions length: 6 -> 10 (0x00,0x0a)
* handshake body length: 46 -> 50 (0x00,0x00,0x32)
* record body length: 50 -> 54 (0x00,0x36)
* appended: 0xfa,0xbc,0x00,0x00 (unknown type, zero-length value)
*/
static const unsigned char hrr_unknown_ext[] = {
/* TLS record header: handshake, TLS 1.2 compat, len=54 */
0x16, 0x03, 0x03, 0x00, 0x36,
/* Handshake header: ServerHello, len=50 */
0x02, 0x00, 0x00, 0x32,
/* legacy_version: TLS 1.2 */
0x03, 0x03,
/* HelloRetryRequest magic random */
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,
/* session ID length: 0 */
0x00,
/* cipher suite: TLS_AES_128_GCM_SHA256 */
0x13, 0x01,
/* compression: null */
0x00,
/* extensions length: 10 */
0x00, 0x0a,
/* supported_versions: TLS 1.3 (0x0304) */
0x00, 0x2b, 0x00, 0x02, 0x03, 0x04,
/* unknown extension type 0xFABC, zero-length value */
0xfa, 0xbc, 0x00, 0x00
};
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);
/* Inject the crafted HRR before the client starts the handshake.
* wolfSSL_connect will send the ClientHello and then read this message. */
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1,
(const char *)hrr_unknown_ext, sizeof(hrr_unknown_ext)), 0);
/* RFC 8446 Sec. 4.2: the client MUST abort with unsupported_extension. */
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1),
WC_NO_ERR_TRACE(UNSUPPORTED_EXTENSION));
/* The client MUST also transmit the fatal unsupported_extension alert
* on the wire, not merely surface a local error. The client's outgoing
* data lands in test_ctx.s_buff; at this point in the handshake no
* traffic keys are derived yet, so the alert record is plaintext.
* Expected record: type=alert(0x15), version=TLS1.2(0x0303), len=2,
* level=fatal(0x02), description=unsupported_extension(0x6e=110). */
{
static const unsigned char expected_alert[] =
{ 0x15, 0x03, 0x03, 0x00, 0x02, 0x02, 0x6e };
int found = 0;
int i;
for (i = 0;
i + (int)sizeof(expected_alert) <= test_ctx.s_len;
i++) {
if (XMEMCMP(test_ctx.s_buff + i, expected_alert,
sizeof(expected_alert)) == 0) {
found = 1;
break;
}
}
ExpectIntEQ(found, 1);
}
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
#endif
return EXPECT_RESULT();
}
/* Regression test for a malformed HelloRetryRequest sent to a downgrade capable
* (TLS 1.2 and TLS 1.3) client. Both crafted messages bear the HelloRetryRequest
* sentinel Random but omit supported_versions, which an HRR MUST carry, so the
* client must reject them with missing_extension (RFC 8446 Sec. 4.1.4/4.2.1/9.2
* - a missing mandatory extension) rather than downgrading to TLS 1.2 and losing
* the HRR context:
* 1. has-extensions form: carries a server_name extension (recognized but not
* permitted in an HRR). Before the fix the downgrade reparsed it as a plain
* server_hello, where server_name is allowed, and the client wrongly sent
* unsupported_extension (when SNI is compiled in). The fix rejects it in
* the version-negotiation step, so the assertions hold regardless of SNI.
* 2. no-extensions form: no extensions field at all. Before the fix this
* downgraded silently, treating the sentinel Random as a normal
* ServerHello.Random.
*/
int test_tls13_hrr_recognized_ext_downgrade(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_TLS12) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && \
defined(WOLFSSL_AES_128) && defined(HAVE_AESGCM) && !defined(NO_SHA256) && \
!defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL *ssl_c = NULL;
struct test_memio_ctx test_ctx;
WOLFSSL_ALERT_HISTORY h;
/* HelloRetryRequest bearing the sentinel Random and TLS_AES_128_GCM_SHA256,
* with NO supported_versions extension and a zero-length server_name
* extension (type 0x0000).
* extensions length: 4 (0x00,0x04)
* handshake body length: 44 (0x00,0x00,0x2c)
* record body length: 48 (0x00,0x30)
*/
static const unsigned char hrr_sni_no_sv[] = {
/* TLS record header: handshake, TLS 1.2 compat, len=48 */
0x16, 0x03, 0x03, 0x00, 0x30,
/* Handshake header: ServerHello, len=44 */
0x02, 0x00, 0x00, 0x2c,
/* legacy_version: TLS 1.2 */
0x03, 0x03,
/* HelloRetryRequest magic random */
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,
/* session ID length: 0 */
0x00,
/* cipher suite: TLS_AES_128_GCM_SHA256 */
0x13, 0x01,
/* compression: null */
0x00,
/* extensions length: 4 */
0x00, 0x04,
/* server_name extension type 0x0000, zero-length value */
0x00, 0x00, 0x00, 0x00
};
/* HelloRetryRequest bearing the sentinel Random with NO extensions field.
* handshake body length: 38 (0x00,0x00,0x26)
* record body length: 42 (0x00,0x2a)
*/
static const unsigned char hrr_no_ext[] = {
/* TLS record header: handshake, TLS 1.2 compat, len=42 */
0x16, 0x03, 0x03, 0x00, 0x2a,
/* Handshake header: ServerHello, len=38 */
0x02, 0x00, 0x00, 0x26,
/* legacy_version: TLS 1.2 */
0x03, 0x03,
/* HelloRetryRequest magic random */
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,
/* session ID length: 0 */
0x00,
/* cipher suite: TLS_AES_128_GCM_SHA256 */
0x13, 0x01,
/* compression: null */
0x00
};
/* Scenario 1: HelloRetryRequest with a not-permitted server_name extension
* and no supported_versions. */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMSET(&h, 0, sizeof(h));
/* Client allows both TLS 1.2 and TLS 1.3 so the missing supported_versions
* would otherwise trigger a downgrade. */
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL,
wolfSSLv23_client_method, NULL), 0);
/* Inject the crafted HelloRetryRequest before the client starts the
* handshake. wolfSSL_connect sends the ClientHello then reads this. */
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1,
(const char *)hrr_sni_no_sv, sizeof(hrr_sni_no_sv)), 0);
/* Handshake must fail because the mandatory supported_versions extension
* is absent from the HelloRetryRequest. The HRR is rejected before the
* downgrade reparses the remaining (server_name) extension, so the result
* is the missing mandatory extension (INCOMPLETE_DATA). */
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1),
WC_NO_ERR_TRACE(INCOMPLETE_DATA));
/* RFC 8446 Sec. 4.1.4/4.2: a mandatory-but-absent extension MUST abort with
* a missing_extension (109) alert. */
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_tx.code, missing_extension);
ExpectIntEQ(h.last_tx.level, alert_fatal);
wolfSSL_free(ssl_c);
ssl_c = NULL;
wolfSSL_CTX_free(ctx_c);
ctx_c = NULL;
/* Scenario 2: HelloRetryRequest sentinel with no extensions field at all.
* Must also be rejected with missing_extension rather than downgraded. */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMSET(&h, 0, sizeof(h));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL,
wolfSSLv23_client_method, NULL), 0);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1,
(const char *)hrr_no_ext, sizeof(hrr_no_ext)), 0);
/* An HRR with no extensions field at all is still missing the mandatory
* supported_versions extension, so - consistently with scenario 1 - the
* client aborts with missing_extension (RFC 8446 4.2.1/9.2). */
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1),
WC_NO_ERR_TRACE(INCOMPLETE_DATA));
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_tx.code, missing_extension);
ExpectIntEQ(h.last_tx.level, alert_fatal);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
#endif
return EXPECT_RESULT();
}
/* Test that wolfSSL_set1_sigalgs_list() is honored in TLS 1.3
*/
int test_tls13_cert_req_sigalgs(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_CERTS) && !defined(NO_RSA) && defined(WC_RSA_PSS) && \
defined(HAVE_ECC) && !defined(NO_WOLFSSL_CLIENT) && \
!defined(NO_WOLFSSL_SERVER) && defined(OPENSSL_EXTRA) && \
!defined(NO_FILESYSTEM)
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,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
/* Server: require client cert and load ECC client cert for verification */
if (EXPECT_SUCCESS()) {
wolfSSL_set_verify(ssl_s,
WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s,
cliEccCertFile, 0), WOLFSSL_SUCCESS);
}
/* Server: restrict CertificateRequest to RSA-PSS+SHA256 only */
if (EXPECT_SUCCESS()) {
ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl_s, "RSA-PSS+SHA256"),
WOLFSSL_SUCCESS);
}
/* Client: load ECC cert/key */
if (EXPECT_SUCCESS()) {
ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliEccCertFile,
CERT_FILETYPE), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliEccKeyFile,
CERT_FILETYPE), WOLFSSL_SUCCESS);
}
/* Handshake must fail: ECC client cannot match RSA-PSS+SHA256 */
ExpectIntNE(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;
wolfSSL_CTX_free(ctx_s); 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_3_client_method, wolfTLSv1_3_server_method), 0);
/* Server: require client cert and load RSA client cert for verification */
if (EXPECT_SUCCESS()) {
wolfSSL_set_verify(ssl_s,
WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s,
cliCertFile, 0), WOLFSSL_SUCCESS);
}
/* Server: restrict CertificateRequest to RSA-PSS+SHA256 only */
if (EXPECT_SUCCESS()) {
ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl_s, "RSA-PSS+SHA256"),
WOLFSSL_SUCCESS);
}
/* Client: load RSA cert/key */
if (EXPECT_SUCCESS()) {
ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliCertFile,
CERT_FILETYPE), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile,
CERT_FILETYPE), WOLFSSL_SUCCESS);
}
/* Handshake must succeed: RSA client satisfies RSA-PSS+SHA256 */
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;
wolfSSL_CTX_free(ctx_s); ctx_s = NULL;
#endif
return EXPECT_RESULT();
}
int test_tls13_derive_keys_no_key(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
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,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
/* DeriveTls13Keys with no_key should succeed (skip secret derivation,
* only derive keys/IVs from existing secrets). This is used with early
* data to derive keys without re-deriving the secrets. */
ExpectIntEQ(DeriveTls13Keys(ssl_s, no_key, DECRYPT_SIDE_ONLY, 0), 0);
ExpectIntEQ(DeriveTls13Keys(ssl_s, no_key, ENCRYPT_SIDE_ONLY, 0), 0);
ExpectIntEQ(DeriveTls13Keys(ssl_c, no_key, ENCRYPT_AND_DECRYPT_SIDE, 0),
0);
/* Unknown secret type should return BAD_FUNC_ARG */
ExpectIntEQ(DeriveTls13Keys(ssl_c, -1, ENCRYPT_SIDE_ONLY, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* Test that a truncated PQC hybrid KeyShare in a ServerHello does not cause a
* heap use-after-free during cleanup. A malicious server sends
* SECP256R1MLKEM768 with only 10 bytes of key exchange data (expected: 1120+).
* This exercises the error path in TLSX_KeyShare_ProcessPqcHybridClient().
* Under ASAN the UAF manifests as ForceZero writing to freed MlKemKey memory
* during wolfSSL_free -> TLSX_FreeAll -> TLSX_KeyShare_FreeAll. */
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT) && \
defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_PQC_HYBRIDS) && \
!defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY)
/* Called when writing - discard output. */
static int PqcHybridUafSend(WOLFSSL* ssl, char* buf, int sz, void* ctx)
{
(void)ssl;
(void)buf;
(void)ctx;
return sz;
}
/* Called when reading - feed from buffer. */
static int PqcHybridUafRecv(WOLFSSL* ssl, char* buf, int sz, void* ctx)
{
WOLFSSL_BUFFER_INFO* msg = (WOLFSSL_BUFFER_INFO*)ctx;
int len = (int)msg->length;
(void)ssl;
if (len > sz)
len = sz;
XMEMCPY(buf, msg->buffer, len);
msg->buffer += len;
msg->length -= len;
return len;
}
#endif
int test_tls13_pqc_hybrid_truncated_keyshare(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT) && \
defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_PQC_HYBRIDS) && \
!defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY)
WOLFSSL_CTX *ctx = NULL;
WOLFSSL *ssl = NULL;
/* Crafted TLS 1.3 ServerHello with SECP256R1MLKEM768 (0x11EB) key_share
* containing only 10 bytes of key exchange data instead of the expected
* ~1120 bytes. This triggers the error cleanup path. */
byte serverHello[] = {
/* TLS record: Handshake, TLS 1.2 compat, length 68 */
0x16, 0x03, 0x03, 0x00, 0x44,
/* Handshake: ServerHello (0x02), length 64 */
0x02, 0x00, 0x00, 0x40,
/* legacy_version */
0x03, 0x03,
/* random (32 bytes) */
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
/* legacy_session_id_echo length: 0 */
0x00,
/* cipher_suite: TLS_AES_128_GCM_SHA256 */
0x13, 0x01,
/* legacy_compression_method: null */
0x00,
/* extensions length: 24 */
0x00, 0x18,
/* extension: supported_versions -> TLS 1.3 */
0x00, 0x2b, 0x00, 0x02, 0x03, 0x04,
/* extension: key_share (truncated hybrid data) */
0x00, 0x33, /* type */
0x00, 0x0e, /* length: 14 */
0x11, 0xeb, /* named_group: SECP256R1MLKEM768 (4587) */
0x00, 0x0a, /* key_exchange length: 10 (truncated!) */
0x41, 0x41, 0x41, 0x41, 0x41, /* bogus key data */
0x41, 0x41, 0x41, 0x41, 0x41
};
WOLFSSL_BUFFER_INFO msg;
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
wolfSSL_SetIORecv(ctx, PqcHybridUafRecv);
wolfSSL_SetIOSend(ctx, PqcHybridUafSend);
ExpectNotNull(ssl = wolfSSL_new(ctx));
/* Generate the client-side PQC hybrid key share so the truncated
* ServerHello key_share will be processed (group must match). */
ExpectIntEQ(wolfSSL_UseKeyShare(ssl, WOLFSSL_SECP256R1MLKEM768),
WOLFSSL_SUCCESS);
msg.buffer = serverHello;
msg.length = (unsigned int)sizeof(serverHello);
wolfSSL_SetIOReadCtx(ssl, &msg);
/* Connect should fail gracefully on the truncated key share. */
ExpectIntEQ(wolfSSL_connect_TLSv13(ssl),
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
/* The UAF, if present, triggers here: wolfSSL_free -> TLSX_FreeAll ->
* TLSX_KeyShare_FreeAll -> ForceZero on already-freed MlKemKey. */
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
/* Test that a malformed ECDH portion in a correctly-sized PQC hybrid
* KeyShare does not leave a dangling pointer in keyShareEntry->key.
*
* The earlier truncated-keyshare test is rejected by the keLen <= ctSz
* check before TLSX_KeyShare_ProcessPqcHybridClient sets up the
* ecc_kse->key = keyShareEntry->key alias, so it does not exercise the
* dangling-pointer path. This test sends a SECP256R1MLKEM768 key_share
* whose total length is correct (65-byte ECDH point + 1088-byte ML-KEM
* ciphertext = 1153 bytes) but whose ECDH leading byte (0x05) is not a
* valid X9.63 marker. ProcessEcc_ex then fails at wc_ecc_import_x963
* AFTER its unconditional cleanup at the end of the function frees the
* aliased key. Without the fix, the outer keyShareEntry->key still
* holds the freed pointer; wolfSSL_free -> TLSX_KeyShare_FreeAll calls
* wc_ecc_free + XFREE on it, producing a use-after-free and a double
* free that ASAN flags. */
int test_tls13_pqc_hybrid_malformed_ecdh(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT) && \
defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_PQC_HYBRIDS) && \
!defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
(!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \
!defined(NO_ECC_SECP)
WOLFSSL_CTX *ctx = NULL;
WOLFSSL *ssl = NULL;
/* 5 (record) + 4 (HS) + 1207 (ServerHello body) = 1216 bytes. */
static byte serverHello[1216];
word32 i = 0;
WOLFSSL_BUFFER_INFO msg;
XMEMSET(serverHello, 0, sizeof(serverHello));
/* Record: handshake, TLS 1.2 compat, length 1211 (0x04bb). */
serverHello[i++] = 0x16; serverHello[i++] = 0x03; serverHello[i++] = 0x03;
serverHello[i++] = 0x04; serverHello[i++] = 0xbb;
/* Handshake: ServerHello (0x02), length 1207 (0x0004b7). */
serverHello[i++] = 0x02;
serverHello[i++] = 0x00; serverHello[i++] = 0x04; serverHello[i++] = 0xb7;
/* legacy_version */
serverHello[i++] = 0x03; serverHello[i++] = 0x03;
/* random (32 bytes) */
XMEMSET(&serverHello[i], 0x42, 32); i += 32;
/* legacy_session_id_echo length: 0 */
serverHello[i++] = 0x00;
/* cipher_suite: TLS_AES_128_GCM_SHA256 */
serverHello[i++] = 0x13; serverHello[i++] = 0x01;
/* legacy_compression_method: null */
serverHello[i++] = 0x00;
/* extensions length: 1167 (0x048f) */
serverHello[i++] = 0x04; serverHello[i++] = 0x8f;
/* extension: supported_versions -> TLS 1.3 */
serverHello[i++] = 0x00; serverHello[i++] = 0x2b;
serverHello[i++] = 0x00; serverHello[i++] = 0x02;
serverHello[i++] = 0x03; serverHello[i++] = 0x04;
/* extension: key_share, extension_data length 1157 (0x0485) */
serverHello[i++] = 0x00; serverHello[i++] = 0x33;
serverHello[i++] = 0x04; serverHello[i++] = 0x85;
/* server_share.group: SECP256R1MLKEM768 (0x11eb) */
serverHello[i++] = 0x11; serverHello[i++] = 0xeb;
/* key_exchange length: 1153 (0x0481) */
serverHello[i++] = 0x04; serverHello[i++] = 0x81;
/* ECDH portion (65 bytes): leading 0x05 is not a valid X9.63 marker
* (valid markers: 0x04, 0x06, 0x07). The remaining 64 bytes stay zero
* from the initial XMEMSET. */
serverHello[i++] = 0x05;
i += 64;
/* PQC portion (1088 bytes): all zero from the initial XMEMSET. */
i += 1088;
AssertIntEQ((int)i, (int)sizeof(serverHello));
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
wolfSSL_SetIORecv(ctx, PqcHybridUafRecv);
wolfSSL_SetIOSend(ctx, PqcHybridUafSend);
ExpectNotNull(ssl = wolfSSL_new(ctx));
/* Match the server's offered group so this key_share is processed. */
ExpectIntEQ(wolfSSL_UseKeyShare(ssl, WOLFSSL_SECP256R1MLKEM768),
WOLFSSL_SUCCESS);
msg.buffer = serverHello;
msg.length = (unsigned int)sizeof(serverHello);
wolfSSL_SetIOReadCtx(ssl, &msg);
/* Connect should fail gracefully on the malformed ECDH point. */
ExpectIntEQ(wolfSSL_connect_TLSv13(ssl),
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
/* Without the fix, this triggers UAF + double-free in
* TLSX_KeyShare_FreeAll. */
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
/* Regression test for the async hybrid PQC server key share. Drives a full
* TLS 1.3 P-256 + ML-KEM-768 handshake through the software async simulator
* while forcing the server's ECDH keygen to complete synchronously so that
* only the ECDH shared-secret derivation suspends. This "B-first" ordering is
* what Intel QAT exhibits and previously dropped the server's KEM ciphertext,
* failing the handshake with SSL_connect -173. */
int test_tls13_pqc_hybrid_async_server(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_ASYNC_CRYPT) && \
defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_PQC_HYBRIDS) && \
!defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
!defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
(!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) && \
!defined(WC_ECC_NONBLOCK) && !defined(WOLFSSL_SP_NONBLOCK)
/* Non-blocking math livelocks the hybrid async re-drive; not applicable. */
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
int group = WOLFSSL_SECP256R1MLKEM768;
int devId = INVALID_DEVID;
/* Open the software async device so the handshake runs the async path. */
ExpectIntEQ(wolfAsync_DevOpen(&devId), 0);
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);
ExpectIntEQ(wolfSSL_SetDevId(ssl_c, devId), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_SetDevId(ssl_s, devId), WOLFSSL_SUCCESS);
/* Negotiate the P-256 + ML-KEM-768 hybrid group on both ends. */
ExpectIntEQ(wolfSSL_set_groups(ssl_c, &group, 1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_groups(ssl_s, &group, 1), WOLFSSL_SUCCESS);
/* Force the server's ECDH keygen to run synchronously so that only the
* ECDH shared-secret derivation suspends (the QAT "B-first" ordering). */
wolfAsync_SwForceSyncType(ASYNC_SW_ECC_MAKE);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
/* Server selected and completed the hybrid group end-to-end. */
ExpectIntEQ(ssl_s->namedGroup, WOLFSSL_SECP256R1MLKEM768);
/* Restore default simulator ordering for subsequent tests. */
wolfAsync_SwForceSyncType(ASYNC_SW_NONE);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
wolfAsync_DevClose(&devId);
#endif
return EXPECT_RESULT();
}
/* Test that a TLS 1.3 NewSessionTicket with a ticket shorter than ID_LEN
* (32 bytes) does not cause an unsigned integer underflow / OOB read in
* SetTicket. Uses a full memio handshake, then injects a crafted
* NewSessionTicket with a 5-byte ticket into the client's read path. */
int test_tls13_empty_record_limit(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
int recSz = 0;
/* Send exactly WOLFSSL_MAX_EMPTY_RECORDS to pin the boundary check.
* The Nth record increments the counter to N, and `N >= N` triggers
* the error. Sending one more would let a `>=` -> `>` mutation survive
* (the extra record would still trip the mutated check). */
int numRecs = WOLFSSL_MAX_EMPTY_RECORDS;
byte rec[128]; /* buffer for one encrypted record */
byte *allRecs = NULL;
int i;
char buf[64];
/* Test 1: Exceeding the empty record limit returns an error. */
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);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
if (EXPECT_SUCCESS()) {
/* Consume any post-handshake messages (e.g. NewSessionTicket). */
wolfSSL_read(ssl_c, buf, sizeof(buf));
test_memio_clear_buffer(&test_ctx, 0);
test_memio_clear_buffer(&test_ctx, 1);
/* Get the size of an encrypted zero-length app data record. */
recSz = BuildTls13Message(ssl_c, NULL, 0, NULL, 0,
application_data, 0, 1, 0);
ExpectIntGT(recSz, 0);
ExpectIntLE(recSz, (int)sizeof(rec));
}
/* Build all empty records into one contiguous buffer. */
if (EXPECT_SUCCESS()) {
allRecs = (byte*)XMALLOC((size_t)(recSz * numRecs), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(allRecs);
}
for (i = 0; i < numRecs && EXPECT_SUCCESS(); i++) {
XMEMSET(rec, 0, sizeof(rec));
ExpectIntEQ(BuildTls13Message(ssl_c, rec, (int)sizeof(rec), rec +
RECORD_HEADER_SZ, 0, application_data, 0, 0, 0),
recSz);
XMEMCPY(allRecs + i * recSz, rec, (size_t)recSz);
}
/* Inject all records as a single message. */
if (EXPECT_SUCCESS()) {
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0,
(const char*)allRecs, recSz * numRecs), 0);
}
/* The server's wolfSSL_read should fail with EMPTY_RECORD_LIMIT_E. */
if (EXPECT_SUCCESS()) {
ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)),
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(EMPTY_RECORD_LIMIT_E));
}
XFREE(allRecs, NULL, DYNAMIC_TYPE_TMP_BUFFER);
allRecs = NULL;
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;
/* Test 2: Counter resets on non-empty record.
* Send (limit - 1) empty records, then 1 non-empty, then (limit - 1)
* more empty records. Should succeed without hitting the limit. */
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);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
if (EXPECT_SUCCESS()) {
wolfSSL_read(ssl_c, buf, sizeof(buf));
test_memio_clear_buffer(&test_ctx, 0);
test_memio_clear_buffer(&test_ctx, 1);
recSz = BuildTls13Message(ssl_c, NULL, 0, NULL, 0,
application_data, 0, 1, 0);
ExpectIntGT(recSz, 0);
}
if (EXPECT_SUCCESS()) {
int emptyBefore = WOLFSSL_MAX_EMPTY_RECORDS - 1;
int emptyAfter = WOLFSSL_MAX_EMPTY_RECORDS - 1;
int dataRecSz = 0;
byte dataRec[128];
byte payload[1] = { 'a' };
int totalSz = 0;
if (EXPECT_SUCCESS()) {
dataRecSz = BuildTls13Message(ssl_c, NULL, 0, NULL, 1,
application_data, 0, 1, 0);
ExpectIntGT(dataRecSz, 0);
}
if (EXPECT_SUCCESS()) {
totalSz = recSz * (emptyBefore + emptyAfter) + dataRecSz;
allRecs = (byte*)XMALLOC((size_t)totalSz, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(allRecs);
}
/* Build (limit - 1) empty records */
for (i = 0; i < emptyBefore && EXPECT_SUCCESS(); i++) {
XMEMSET(rec, 0, sizeof(rec));
ExpectIntEQ(BuildTls13Message(ssl_c, rec, (int)sizeof(rec),
rec + RECORD_HEADER_SZ, 0, application_data,
0, 0, 0), recSz);
XMEMCPY(allRecs + i * recSz, rec, (size_t)recSz);
}
/* Build 1 non-empty record */
if (EXPECT_SUCCESS()) {
XMEMSET(dataRec, 0, sizeof(dataRec));
XMEMCPY(dataRec + RECORD_HEADER_SZ, payload, sizeof(payload));
ExpectIntEQ(BuildTls13Message(ssl_c, dataRec, (int)sizeof(dataRec),
dataRec + RECORD_HEADER_SZ, 1, application_data,
0, 0, 0), dataRecSz);
XMEMCPY(allRecs + emptyBefore * recSz, dataRec,
(size_t)dataRecSz);
}
/* Build (limit - 1) more empty records */
for (i = 0; i < emptyAfter && EXPECT_SUCCESS(); i++) {
XMEMSET(rec, 0, sizeof(rec));
ExpectIntEQ(BuildTls13Message(ssl_c, rec, (int)sizeof(rec),
rec + RECORD_HEADER_SZ, 0, application_data,
0, 0, 0), recSz);
XMEMCPY(allRecs + emptyBefore * recSz + dataRecSz + i * recSz,
rec, (size_t)recSz);
}
if (EXPECT_SUCCESS()) {
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0,
(const char*)allRecs, totalSz), 0);
}
}
/* wolfSSL_read should return the 1-byte payload. The counter resets
* on the non-empty record so neither batch of (limit - 1) empties
* triggers the error. */
if (EXPECT_SUCCESS()) {
ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), 1);
ExpectIntEQ(buf[0], 'a');
}
XFREE(allRecs, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* Test that a TLS 1.3 NewSessionTicket with a ticket shorter than ID_LEN
* (32 bytes) does not cause an unsigned integer underflow / OOB read in
* SetTicket. Uses a full memio handshake, then injects a crafted
* NewSessionTicket with a 5-byte ticket into the client's read path. */
int test_tls13_short_session_ticket(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
char buf[64];
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);
/* Complete a TLS 1.3 handshake. The server will send a
* NewSessionTicket as part of post-handshake messages. */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Read on client to consume the server's NewSessionTicket. */
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* Now directly test SetTicket with a short ticket by poking the
* session. The session object is accessible; replicate the exact
* vulnerable arithmetic: ticket + length - ID_LEN with length=5.
* With the fix, sessIdLen is capped to length so no underflow. */
if (EXPECT_SUCCESS()) {
byte shortTicket[5] = { 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
word32 length = sizeof(shortTicket);
word32 sessIdLen = ID_LEN;
if (length < ID_LEN)
sessIdLen = length;
XMEMCPY(ssl_c->session->staticTicket, shortTicket, length);
ssl_c->session->ticketLen = (word16)length;
ssl_c->session->ticket = ssl_c->session->staticTicket;
/* This is the exact code from SetTicket. Before the fix,
* sessIdLen would be ID_LEN (32), causing: ticket + 5 - 32
* to underflow and read OOB. */
XMEMSET(ssl_c->session->sessionID, 0, ID_LEN);
XMEMCPY(ssl_c->session->sessionID,
ssl_c->session->ticket + length - sessIdLen,
sessIdLen);
ssl_c->session->sessionIDSz = ID_LEN;
/* Verify: sessionID should contain only the 5 ticket bytes,
* zero-padded, not garbage from an OOB read. */
ExpectBufEQ(ssl_c->session->sessionID, shortTicket, 5);
}
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_TLS13) && defined(HAVE_SESSION_TICKET)
/* Custom ticket encryption callback with no key-lifetime limit, so the server
* issues a ticket for any hint (the default callback refuses a hint of at least
* half the key lifetime). */
static int test_tls13_max_lifetime_ticketEncCb(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)
{
int i;
(void)ssl;
(void)userCtx;
if (enc) {
XMEMSET(key_name, 0x2A, WOLFSSL_TICKET_NAME_SZ);
XMEMSET(iv, 0x2A, WOLFSSL_TICKET_IV_SZ);
XMEMSET(mac, 0x2A, WOLFSSL_TICKET_MAC_SZ);
}
for (i = 0; i < inLen; i++)
ticket[i] = (byte)(ticket[i] ^ 0xA5);
*outLen = inLen;
return WOLFSSL_TICKET_RET_OK;
}
#endif
/* RFC 8446 Section 4.6.1: a NewSessionTicket lifetime greater than
* MAX_LIFETIME (604800 seconds, 7 days) must be rejected. The public
* wolfSSL_CTX_set_TicketHint setter clamps the value, so write the
* out-of-range hint directly into the server CTX. A custom encryption callback
* is installed so the default callback's key-lifetime limit does not block
* issuance, forcing the server to encode the over-limit lifetime onto the wire
* and confirming the client's DoTls13NewSessionTicket bound check fires. */
int test_tls13_new_session_ticket_max_lifetime(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
char buf[64];
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);
wolfSSL_CTX_set_TicketEncCb(ctx_s, test_tls13_max_lifetime_ticketEncCb);
/* Bypass the public-API clamp at 604800. */
if (EXPECT_SUCCESS()) {
ctx_s->ticketHint = MAX_LIFETIME + 1;
}
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Reading the post-handshake NewSessionTicket should surface the
* over-limit lifetime as SERVER_HINT_ERROR. */
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)), WOLFSSL_FATAL_ERROR);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(SERVER_HINT_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* A TLS 1.3 client that does not retain its handshake arrays after the
* handshake (e.g. built without HAVE_SESSION_TICKET, as on a small embedded
* target) must still be able to receive a post-handshake NewSessionTicket that
* the negotiated max_fragment_length has split across multiple records.
*
* Regression test: the handshake-message defragmentation buffer used to live
* inside ssl->arrays, which FreeHandshakeResources() releases once the
* handshake completes. A fragmented NewSessionTicket arriving afterwards could
* therefore not be reassembled and the connection was torn down with
* INCOMPLETE_DATA (-310). Fragmentation *during* the handshake was unaffected
* because the arrays still existed then.
*
* The test completes a normal handshake, forces the post-handshake
* "arrays released" state with FreeArrays(), then injects a NewSessionTicket
* fragmented across two records and confirms the client reassembles and
* consumes it (WANT_READ, no application data) instead of failing with
* INCOMPLETE_DATA. */
int test_tls13_fragmented_session_ticket(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
char buf[64];
/* NewSessionTicket: lifetime(4) + age_add(4) + nonce(1+8) + ticket(2+32) +
* extensions(2) = 53 byte body, 4 + 53 = 57 byte handshake message. */
byte ticketMsg[57];
byte rec[256];
int recSz = 0;
int split = 20; /* fragment boundary inside the message */
int readRet, errRet;
int i, idx;
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);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Drain any genuine NewSessionTicket the server already sent so the
* application-data record sequence numbers of both peers stay in sync with
* the records injected below. */
if (EXPECT_SUCCESS()) {
readRet = wolfSSL_read(ssl_c, buf, sizeof(buf));
errRet = wolfSSL_get_error(ssl_c, readRet);
ExpectIntEQ(readRet, -1);
ExpectIntEQ(errRet, WOLFSSL_ERROR_WANT_READ);
}
/* Reproduce the embedded/no-session-ticket configuration in which the
* client's handshake arrays are released once the handshake completes
* (FreeHandshakeResources() -> FreeArrays()). It is done here inline using
* the library's own allocation types rather than calling FreeArrays(),
* which is an internal-only symbol hidden in shared-library builds. In
* configurations that already release the arrays (e.g. no HAVE_SESSION_TICKET)
* they are NULL at this point and the free is skipped. */
if (EXPECT_SUCCESS() && ssl_c->arrays != NULL) {
/* Zero before freeing so WOLFSSL_CHECK_MEM_ZERO builds don't abort. */
if (ssl_c->arrays->preMasterSecret != NULL) {
ForceZero(ssl_c->arrays->preMasterSecret, ENCRYPT_LEN);
XFREE(ssl_c->arrays->preMasterSecret, ssl_c->heap,
DYNAMIC_TYPE_SECRET);
ssl_c->arrays->preMasterSecret = NULL;
}
ForceZero(ssl_c->arrays, sizeof(Arrays));
XFREE(ssl_c->arrays, ssl_c->heap, DYNAMIC_TYPE_ARRAYS);
ssl_c->arrays = NULL;
}
/* The post-handshake NewSessionTicket must now be processed with
* ssl->arrays == NULL, which is what historically broke reassembly. */
if (EXPECT_SUCCESS()) {
ExpectNull(ssl_c->arrays);
}
/* Encode a syntactically valid NewSessionTicket so that a client built with
* HAVE_SESSION_TICKET parses it cleanly; a client built without it simply
* skips the body. Either way reassembly must succeed first. */
if (EXPECT_SUCCESS()) {
idx = 0;
ticketMsg[idx++] = session_ticket; /* handshake msg type */
ticketMsg[idx++] = 0x00; /* 24-bit body length */
ticketMsg[idx++] = 0x00;
ticketMsg[idx++] = 0x35; /* = 53 */
ticketMsg[idx++] = 0x00; ticketMsg[idx++] = 0x00; /* lifetime = 3600 */
ticketMsg[idx++] = 0x0E; ticketMsg[idx++] = 0x10;
ticketMsg[idx++] = 0x01; ticketMsg[idx++] = 0x02; /* ticket_age_add */
ticketMsg[idx++] = 0x03; ticketMsg[idx++] = 0x04;
ticketMsg[idx++] = 0x08; /* nonce length */
for (i = 0; i < 8; i++)
ticketMsg[idx++] = (byte)(0xA0 + i); /* nonce */
ticketMsg[idx++] = 0x00; ticketMsg[idx++] = 0x20; /* ticket length=32 */
for (i = 0; i < 32; i++)
ticketMsg[idx++] = (byte)(0x40 + i); /* ticket */
ticketMsg[idx++] = 0x00; ticketMsg[idx++] = 0x00; /* extensions: none */
ExpectIntEQ(idx, (int)sizeof(ticketMsg));
}
/* Fragment 1: bytes [0, split) of the handshake message, encrypted with the
* server's keys, injected into the client's read path. */
if (EXPECT_SUCCESS()) {
recSz = BuildTls13Message(ssl_s, rec, (int)sizeof(rec), ticketMsg,
split, handshake, 0, 0, 0);
ExpectIntGT(recSz, 0);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, (const char*)rec,
recSz), 0);
}
/* Fragment 2: the remaining bytes of the handshake message. */
if (EXPECT_SUCCESS()) {
recSz = BuildTls13Message(ssl_s, rec, (int)sizeof(rec),
ticketMsg + split,
(int)sizeof(ticketMsg) - split, handshake,
0, 0, 0);
ExpectIntGT(recSz, 0);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, (const char*)rec,
recSz), 0);
}
/* Before the fix the first fragment reaches DoTls13HandShakeMsg while
* ssl->arrays is NULL, cannot be buffered, and the read fails with
* INCOMPLETE_DATA. With the fix the two records reassemble into the
* NewSessionTicket, which is consumed, leaving no application data. */
if (EXPECT_SUCCESS()) {
readRet = wolfSSL_read(ssl_c, buf, sizeof(buf));
errRet = wolfSSL_get_error(ssl_c, readRet);
ExpectIntEQ(readRet, -1);
ExpectIntNE(errRet, WC_NO_ERR_TRACE(INCOMPLETE_DATA));
ExpectIntEQ(errRet, WOLFSSL_ERROR_WANT_READ);
}
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* Test that a corrupted TLS 1.3 Finished verify_data is properly rejected
* with VERIFY_FINISHED_ERROR. We run the handshake step-by-step and corrupt
* the server's client_write_MAC_secret before it processes the client's
* Finished, causing the HMAC comparison to fail.
*/
int test_tls13_corrupted_finished(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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 ret;
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);
/* Step 1: Client sends ClientHello */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
/* Step 2: Server processes CH, sends SH + EE + Cert + CV + Finished */
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
/* Step 3: Client processes server flight, verifies server Finished,
* sends client Finished */
ret = wolfSSL_connect(ssl_c);
if (ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) {
/* Actually: Server sent HelloRetryRequest */
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
/* Step 1: Client sends ClientHello */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
/* Step 2: Server processes CH, sends SH + EE + Cert + CV + Finished */
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
/* Step 3: Client processes server flight, verifies server Finished,
* sends client Finished */
ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
}
else {
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
}
/* Corrupt the server's client_write_MAC_secret so that when it computes
* the expected Finished HMAC, the result won't match the client's actual
* Finished message. */
if (EXPECT_SUCCESS()) {
XMEMSET(ssl_s->keys.client_write_MAC_secret, 0xFF,
sizeof(ssl_s->keys.client_write_MAC_secret));
}
/* Step 4: Server processes client Finished - should fail */
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(VERIFY_FINISHED_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* Test that DoTls13CertificateVerify rejects a CertificateVerify whose
* signature algorithm is not one the receiver advertised.
*
* This drives the validSigAlgo == 0 path in src/tls13.c: the loop that scans
* the receiver's hashSigAlgo list for the algorithm carried in the
* CertificateVerify message. When no entry matches, validSigAlgo stays 0 and
* the message is rejected with INVALID_PARAMETER.
*
* The client sends its ClientHello (advertising its real signature
* algorithms), the server picks one of them to sign its CertificateVerify, and
* then - before the client processes the server flight - the client's accepted
* signature algorithm list is overwritten with a bogus entry. The server's
* (legitimately chosen) algorithm is therefore absent from the client's list
* at verification time, so the lookup fails.
*/
int test_tls13_certificate_verify_bad_sigalgo(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS)
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 group = WOLFSSL_ECC_SECP256R1;
Suites* suites = NULL;
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);
/* Constrain both peers to a single, mutually-supported key share group so
* the server never sends a HelloRetryRequest. That keeps the message
* stepping below deterministic: one ClientHello, then the full server
* flight (which contains the CertificateVerify we want to corrupt). */
ExpectIntEQ(wolfSSL_set_groups(ssl_c, &group, 1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, group), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_groups(ssl_s, &group, 1), WOLFSSL_SUCCESS);
/* Step 1: Client sends ClientHello, advertising its real signature
* algorithms. */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
/* Step 2: Server processes the ClientHello and emits SH + EE + Cert +
* CertVerify + Finished, signing the CertVerify with an algorithm taken
* from the list the client just advertised. */
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
/* The ClientHello has now been sent, so changing the client's accepted
* signature algorithms no longer affects what it advertised. Replace the
* list with a single bogus pair (not a valid SignatureScheme) that the
* server cannot have used. When the client verifies the server's
* CertificateVerify, the lookup loop finds no match -> validSigAlgo == 0. */
if (EXPECT_SUCCESS()) {
suites = (Suites*)WOLFSSL_SUITES(ssl_c);
ExpectNotNull(suites);
}
if (suites != NULL) {
suites->hashSigAlgo[0] = 0xFE;
suites->hashSigAlgo[1] = 0xFE;
suites->hashSigAlgoSz = 2;
}
/* Step 3: Client processes the server flight. DoTls13CertificateVerify
* must reject the CertificateVerify with INVALID_PARAMETER. */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(INVALID_PARAMETER));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* Test the TLS 1.3 peerAuthGood fail-safe checks on both sides.
* The client branch queues a real server flight before forcing
* FIRST_REPLY_SECOND on a live handshake object, and the server branch clears
* peerAuthGood just before processing the client's Finished.
*/
int test_tls13_peerauth_failsafe(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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 ret;
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);
if (EXPECT_SUCCESS()) {
/* Queue ClientHello and server flight. */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
ssl_c->options.peerAuthGood = 0;
ssl_c->options.sendVerify = 0;
ssl_c->options.connectState = FIRST_REPLY_SECOND;
ret = wolfSSL_connect(ssl_c);
ExpectIntEQ(ret, WOLFSSL_FATAL_ERROR);
ExpectIntEQ(ssl_c->options.connectState, FIRST_REPLY_SECOND);
}
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ctx_c = NULL;
ctx_s = NULL;
ssl_c = NULL;
ssl_s = NULL;
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
if (EXPECT_SUCCESS()) {
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
ret = wolfSSL_connect(ssl_c);
if (ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) {
/* HelloRetryRequest sent by server. */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
}
else {
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
}
ssl_s->options.peerAuthGood = 0;
ret = wolfSSL_accept(ssl_s);
ExpectIntEQ(ret, WOLFSSL_FATAL_ERROR);
ExpectIntEQ(ssl_s->options.peerAuthGood, 0);
}
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* Test that a corrupted HRR cookie HMAC is rejected with HRR_COOKIE_ERROR. */
int test_tls13_hrr_bad_cookie(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_SEND_HRR_COOKIE) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
ExpectIntEQ(wolfSSL_send_hrr_cookie(ssl_s, NULL, 0), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c), WOLFSSL_SUCCESS);
/* Step 1: Client sends CH1 (no key shares) */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
/* Step 2: Server sends HRR with cookie */
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
/* Step 3: Client processes HRR, sends CH2 with cookie */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
/* Corrupt the server-side cookie secret after HRR so CH2's cookie no longer
* verifies in TlsCheckCookie(). */
if (EXPECT_SUCCESS()) {
ExpectNotNull(ssl_s->buffers.tls13CookieSecret.buffer);
ExpectIntGT(ssl_s->buffers.tls13CookieSecret.length, 0);
ssl_s->buffers.tls13CookieSecret.buffer[
ssl_s->buffers.tls13CookieSecret.length - 1] ^= 0xFF;
}
/* Step 4: Server processes corrupted CH2 - should fail */
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(HRR_COOKIE_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* Test that a TLS 1.3 encrypted record whose inner content type resolves to
* zero is rejected in removeMsgInnerPadding() with PARSE_ERROR and an
* unexpected_message alert. */
int test_tls13_zero_inner_content_type(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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 record[64];
byte dummy = 0;
char readBuf[8];
int recordSz;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMSET(&h, 0, sizeof(h));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
ExpectIntEQ(wolfSSL_no_ticket_TLSv13(ssl_s), 0);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
if (EXPECT_SUCCESS()) {
ExpectIntEQ(test_ctx.c_len, 0);
ExpectIntEQ(test_ctx.s_len, 0);
recordSz = BuildTls13Message(ssl_c, record, (int)sizeof(record), &dummy,
0, no_type, 0, 0, 0);
ExpectIntGT(recordSz, 0);
ExpectIntEQ(wolfSSL_inject(ssl_s, record, recordSz), WOLFSSL_SUCCESS);
}
ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, (int)sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WC_NO_ERR_TRACE(PARSE_ERROR));
ExpectIntEQ(wolfSSL_get_alert_history(ssl_s, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_tx.code, unexpected_message);
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);
#endif
return EXPECT_RESULT();
}
/* RFC 8446 Section 4.6.2: A client that receives a post-handshake
* CertificateRequest message without having sent the "post_handshake_auth"
* extension MUST send an "unexpected_message" fatal alert.
*
* This test completes a TLS 1.3 handshake in which the client never enabled
* post-handshake auth (so no extension was sent in the ClientHello), then
* forces the server to transmit a post-handshake CertificateRequest anyway.
* The client must reject the message with an unexpected_message fatal
* alert. */
int test_tls13_post_handshake_auth_no_ext(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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;
char readBuf[8];
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMSET(&h, 0, sizeof(h));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
/* Keep the post-handshake byte stream simple by suppressing the server's
* NewSessionTicket so the only post-handshake record from the server is
* the CertificateRequest under test. */
ExpectIntEQ(wolfSSL_no_ticket_TLSv13(ssl_s), 0);
/* Intentionally do NOT call wolfSSL_allow_post_handshake_auth() on the
* client so the post_handshake_auth extension is omitted from the
* ClientHello. */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* The server's wolfSSL_request_certificate() refuses to send a
* post-handshake CertificateRequest unless its postHandshakeAuth flag is
* set (normally set when parsing the client's extension). To exercise
* the receive-side check we are testing, simulate a server that sends
* one anyway by toggling the flag directly. */
if (ssl_s != NULL)
ssl_s->options.postHandshakeAuth = 1;
/* OPENSSL_COMPATIBLE_DEFAULTS may leave groupMessages set on ssl_s; that
* suppresses SendBuffered() for the post-handshake CertificateRequest. */
ExpectIntEQ(wolfSSL_clear_group_messages(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
ExpectIntGT(test_ctx.c_len, 0);
/* The client must reject the unsolicited CertificateRequest. */
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, (int)sizeof(readBuf)),
WOLFSSL_FATAL_ERROR);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(OUT_OF_ORDER_E));
/* And the client must transmit a fatal unexpected_message alert. */
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_tx.code, unexpected_message);
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);
#endif
return EXPECT_RESULT();
}
/* wolfSSL_allow_post_handshake_auth() must be called before the handshake
* starts. A late call must fail with BAD_STATE_E and must not enable
* post-handshake authentication for the connection. */
int test_tls13_post_handshake_auth_late_allow(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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;
char readBuf[8];
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMSET(&h, 0, sizeof(h));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
ExpectIntEQ(wolfSSL_no_ticket_TLSv13(ssl_s), 0);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Too late: handshake is complete. */
ExpectIntEQ(wolfSSL_allow_post_handshake_auth(ssl_c),
WC_NO_ERR_TRACE(BAD_STATE_E));
if (ssl_s != NULL)
ssl_s->options.postHandshakeAuth = 1;
/* OPENSSL_COMPATIBLE_DEFAULTS may leave groupMessages set on ssl_s; that
* suppresses SendBuffered() for the post-handshake CertificateRequest. */
ExpectIntEQ(wolfSSL_clear_group_messages(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
ExpectIntGT(test_ctx.c_len, 0);
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, (int)sizeof(readBuf)),
WOLFSSL_FATAL_ERROR);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(OUT_OF_ORDER_E));
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_tx.code, unexpected_message);
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);
#endif
return EXPECT_RESULT();
}
/* Test that a TLS 1.3-capable client rejects downgrade sentinels in a
* downgraded ServerHello random for both TLS 1.2 and TLS 1.1-or-lower. */
int test_tls13_downgrade_sentinel(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
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 randomOff = 11 + 24;
static const byte downgradeTls12[8] = {
0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01
};
#ifndef NO_OLD_TLS
static const byte downgradeTls11[8] = {
0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00
};
#endif
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMSET(&h, 0, sizeof(h));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLS_client_method, wolfTLSv1_2_server_method), 0);
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
if (EXPECT_SUCCESS()) {
ExpectIntGT(test_ctx.c_len, randomOff + (int)sizeof(downgradeTls12));
XMEMCPY(test_ctx.c_buff + randomOff, downgradeTls12,
sizeof(downgradeTls12));
}
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(VERSION_ERROR));
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
ExpectTrue(h.last_tx.code == illegal_parameter ||
h.last_tx.code == wolfssl_alert_protocol_version);
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);
#ifndef NO_OLD_TLS
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMSET(&h, 0, sizeof(h));
ctx_c = NULL;
ctx_s = NULL;
ssl_c = NULL;
ssl_s = NULL;
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLS_client_method, wolfTLSv1_1_server_method), 0);
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
if (EXPECT_SUCCESS()) {
ExpectIntGT(test_ctx.c_len, randomOff + (int)sizeof(downgradeTls11));
XMEMCPY(test_ctx.c_buff + randomOff, downgradeTls11,
sizeof(downgradeTls11));
}
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(VERSION_ERROR));
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
ExpectTrue(h.last_tx.code == illegal_parameter ||
h.last_tx.code == wolfssl_alert_protocol_version);
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);
#endif
#endif
return EXPECT_RESULT();
}
/* Test that a TLS 1.3 client rejects ServerHello cipher suites that are not
* TLS 1.3 suites or were not offered by the client. */
int test_tls13_serverhello_bad_cipher_suites(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(WOLFSSL_NO_TLS12) && \
defined(BUILD_TLS_AES_128_GCM_SHA256) && \
defined(BUILD_TLS_AES_256_GCM_SHA384)
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_CTX *ctx12_c = NULL;
WOLFSSL_CTX *ctx12_s = NULL;
WOLFSSL *ssl12_c = NULL;
WOLFSSL *ssl12_s = NULL;
struct test_memio_ctx test_ctx12;
int suiteOff;
byte tls12Suite0 = 0;
byte tls12Suite = 0;
XMEMSET(&test_ctx12, 0, sizeof(test_ctx12));
ExpectIntEQ(test_memio_setup(&test_ctx12, &ctx12_c, &ctx12_s, &ssl12_c,
&ssl12_s, wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
ExpectIntEQ(test_memio_do_handshake(ssl12_c, ssl12_s, 10, NULL), 0);
if (EXPECT_SUCCESS()) {
tls12Suite0 = ssl12_c->options.cipherSuite0;
tls12Suite = ssl12_c->options.cipherSuite;
ExpectIntNE(tls12Suite0, TLS13_BYTE);
}
wolfSSL_free(ssl12_c);
wolfSSL_CTX_free(ctx12_c);
wolfSSL_free(ssl12_s);
wolfSSL_CTX_free(ctx12_s);
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);
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, "TLS13-AES128-GCM-SHA256"),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, "TLS13-AES128-GCM-SHA256"),
WOLFSSL_SUCCESS);
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
suiteOff = 44 + (byte)test_ctx.c_buff[43];
if (EXPECT_SUCCESS()) {
ExpectIntGT(test_ctx.c_len, suiteOff + 1);
ExpectNotNull(ssl_c->suites);
ssl_c->suites->suiteSz = 2;
ssl_c->suites->suites[0] = tls12Suite0;
ssl_c->suites->suites[1] = tls12Suite;
test_ctx.c_buff[suiteOff + 0] = tls12Suite0;
test_ctx.c_buff[suiteOff + 1] = tls12Suite;
}
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(INVALID_PARAMETER));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ctx_c = NULL;
ctx_s = NULL;
ssl_c = NULL;
ssl_s = NULL;
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, "TLS13-AES128-GCM-SHA256"),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, "TLS13-AES128-GCM-SHA256"),
WOLFSSL_SUCCESS);
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
suiteOff = 44 + (byte)test_ctx.c_buff[43];
if (EXPECT_SUCCESS()) {
ExpectIntGT(test_ctx.c_len, suiteOff + 1);
test_ctx.c_buff[suiteOff + 0] = TLS13_BYTE;
test_ctx.c_buff[suiteOff + 1] = TLS_AES_256_GCM_SHA384;
}
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(INVALID_PARAMETER));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* Verify that a peer certificate restored from a session ticket is re-verified
* against the current trust store. After CA removal, the cert must not be
* installed into ssl->peerCert even though the ticket itself decrypts fine. */
int test_tls13_ticket_peer_cert_reverify(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
defined(OPENSSL_ALL) && defined(KEEP_PEER_CERT) && \
!defined(NO_CERT_IN_TICKET) && !defined(WOLFSSL_NO_TLS12) && \
!defined(NO_RSA) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
WOLFSSL_SESSION *sess = NULL;
WOLFSSL_X509 *peer = NULL;
char readBuf[64];
/* --- Step 1: mTLS handshake, obtain a session ticket --- */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
/* Set up CTXs manually so we can configure mTLS before SSL creation */
ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_c, caCertFile, 0),
WOLFSSL_SUCCESS);
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);
wolfSSL_SetIORecv(ctx_c, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_c, test_memio_write_cb);
ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
/* Server trusts both its own CA and the client CA for mTLS */
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, caCertFile, 0),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s,
"certs/client-ca.pem", 0), WOLFSSL_SUCCESS);
wolfSSL_CTX_set_verify(ctx_s, WOLFSSL_VERIFY_PEER |
WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
wolfSSL_SetIORecv(ctx_s, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_s, test_memio_write_cb);
/* Create SSL objects from fully-configured CTXs */
ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Drain post-handshake NewSessionTicket */
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* Peer cert should be available after initial handshake */
ExpectNotNull(peer = wolfSSL_get_peer_certificate(ssl_s));
wolfSSL_X509_free(peer);
peer = NULL;
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
wolfSSL_free(ssl_c);
ssl_c = NULL;
wolfSSL_free(ssl_s);
ssl_s = NULL;
/* --- Step 2: remove the client CA from the server trust store --- */
ExpectIntEQ(wolfSSL_CTX_UnloadCAs(ctx_s), WOLFSSL_SUCCESS);
/* Re-load only the server's own CA so TLS works, but not the client CA */
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, caCertFile, 0),
WOLFSSL_SUCCESS);
/* --- Step 3: resume with the old ticket --- */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
/* Resumption handshake succeeds (the ticket master secret is fine) */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* The session should have been resumed via PSK. */
ExpectIntEQ(wolfSSL_session_reused(ssl_s), 1);
/* But the peer cert must NOT be restored because the issuing CA is
* no longer in the trust store. Check the peerCert directly rather
* than wolfSSL_get_peer_certificate which has a session-chain
* fallback that may see stale cache state. */
ExpectIntEQ(ssl_s->peerCert.issuer.sz, 0);
wolfSSL_SESSION_free(sess);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_clear_preserves_psk_dhe(void)
{
EXPECT_DECLS;
#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) && \
defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES) && \
(defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \
!defined(NO_WOLFSSL_CLIENT)
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
ExpectIntEQ(wolfSSL_CTX_no_dhe_psk(ctx), 0);
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(ssl->options.noPskDheKe, 1);
/* SSL reuse must preserve the CTX-level noPskDheKe; resetting to 0
* would silently re-enable psk_dhe_ke for the next handshake. */
ExpectIntEQ(wolfSSL_clear(ssl), WOLFSSL_SUCCESS);
ExpectIntEQ(ssl->options.noPskDheKe, 1);
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
(defined(BUILD_TLS_AES_128_GCM_SHA256) || \
defined(BUILD_TLS_AES_256_GCM_SHA384) || \
defined(BUILD_TLS_CHACHA20_POLY1305_SHA256) || \
defined(BUILD_TLS_AES_128_CCM_SHA256) || \
defined(BUILD_TLS_AES_128_CCM_8_SHA256))
/* One iteration of the AEAD fuzz test: run a fresh handshake
* up to the point where the first AEAD-protected record from the side under
* test sits in the receiver's input buffer, flip one random byte of the
* encrypted payload to a random non-zero value, and confirm the receiver
* fails with VERIFY_MAC_ERROR. side==0 fuzzes the server's first encrypted
* record (EncryptedExtensions, read by the client). side==1 fuzzes the
* client's first encrypted record (Finished, read by the server). */
static int test_tls13_cipher_fuzz_once(WC_RNG* rng,
const char* cipher, int side)
{
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;
byte *buf = NULL;
int buf_len = 0;
int rec_off = 0;
int rec_len = 0;
int fuzz_off;
byte fuzz_xor;
word32 rand32;
int ret;
int err;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
test_ctx.c_ciphers = cipher;
test_ctx.s_ciphers = cipher;
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
/* Drive the handshake forward until the side being fuzzed has written
* its first AEAD-encrypted record into the peer's read buffer. The
* server's first encrypted record is queued after its first
* wolfSSL_accept() (EncryptedExtensions, immediately following
* ServerHello). The client's first encrypted record is queued once
* wolfSSL_connect() returns success and the client has sent its
* Finished. */
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
/* The default groups can lead the server to respond with a
* HelloRetryRequest, in which case it is waiting on a new ClientHello and
* has not yet sent any encrypted record. Drive another connect/accept round
* so the buffers hold the real flight before fuzzing. */
if (EXPECT_SUCCESS() && test_memio_msg_is_hello_retry_request(&test_ctx)) {
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
}
if (side == 1) {
ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
buf = test_ctx.s_buff;
buf_len = test_ctx.s_len;
}
else {
buf = test_ctx.c_buff;
buf_len = test_ctx.c_len;
}
/* Walk the TLS records in the target buffer and locate the first
* application_data record (content type 0x17), which holds the first
* encrypted handshake message. Plaintext records (ServerHello,
* ChangeCipherSpec for middlebox compatibility) precede it and must be
* skipped over. */
if (EXPECT_SUCCESS()) {
int off = 0;
while (off + 5 <= buf_len) {
int this_len = ((int)buf[off + 3] << 8) | (int)buf[off + 4];
if (buf[off] == 0x17) {
rec_off = off;
rec_len = this_len;
break;
}
off += 5 + this_len;
}
}
ExpectIntGT(rec_len, 0);
ExpectIntLE(rec_off + 5 + rec_len, buf_len);
/* Pick a random offset within the encrypted payload (skipping the
* 5-byte record header) and XOR it with a non-zero value so the byte
* is guaranteed to change. */
if (EXPECT_SUCCESS()) {
rand32 = 0;
fuzz_off = 0;
ExpectIntEQ(wc_RNG_GenerateBlock(rng, (byte*)&rand32,
sizeof(rand32)), 0);
if (EXPECT_SUCCESS()) {
fuzz_off = rec_off + 5 + (int)(rand32 % (word32)rec_len);
}
do {
ExpectIntEQ(wc_RNG_GenerateByte(rng, &fuzz_xor), 0);
} while (EXPECT_SUCCESS() && fuzz_xor == 0);
if (EXPECT_SUCCESS()) {
buf[fuzz_off] ^= fuzz_xor;
}
}
/* Drive the receiving side. It must report VERIFY_MAC_ERROR - the
* corrupted cipher text or tag must surface as a hard error. */
if (EXPECT_SUCCESS()) {
if (side == 1) {
ret = wolfSSL_accept(ssl_s);
err = wolfSSL_get_error(ssl_s, ret);
}
else {
ret = wolfSSL_connect(ssl_c);
err = wolfSSL_get_error(ssl_c, ret);
}
ExpectIntEQ(ret, WOLFSSL_FATAL_ERROR);
ExpectTrue((err == WC_NO_ERR_TRACE(VERIFY_MAC_ERROR)) ||
(err == WC_NO_ERR_TRACE(AES_GCM_AUTH_E)) ||
(err == WC_NO_ERR_TRACE(AES_CCM_AUTH_E)));
}
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
return EXPECT_RESULT();
}
/* Run 5 fuzz iterations per side for a single cipher suite. */
static int test_tls13_cipher_fuzz_cs(WC_RNG* rng, const char* cipher)
{
EXPECT_DECLS;
int side;
int iter;
for (side = 0; side < 2 && EXPECT_SUCCESS(); side++) {
for (iter = 0; iter < 5 && EXPECT_SUCCESS(); iter++) {
int _r = test_tls13_cipher_fuzz_once(rng, cipher, side);
if (_r != TEST_SUCCESS) {
fprintf(stderr, "FAIL cipher=%s side=%d iter=%d\n",
cipher, side, iter);
}
ExpectIntEQ(_r, TEST_SUCCESS);
}
}
return EXPECT_RESULT();
}
#endif
/* Each per-cipher-suite test below runs the fuzz body (test_tls13_cipher_fuzz_cs)
* against a single AEAD cipher: it flips a random byte of the first encrypted
* record on each side of a TLS 1.3 handshake and expects the receiver to fail
* authentication. AEAD authentication makes it cryptographically infeasible
* for any single-byte change in the ciphertext or tag to leave authentication
* intact, so the receiver must report a hard auth error. */
int test_tls13_cipher_fuzz_aes128_gcm_sha256(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
defined(BUILD_TLS_AES_128_GCM_SHA256)
WC_RNG rng;
int rngInit = 0;
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_InitRng(&rng), 0);
if (EXPECT_SUCCESS())
rngInit = 1;
ExpectIntEQ(test_tls13_cipher_fuzz_cs(&rng, "TLS13-AES128-GCM-SHA256"),
TEST_SUCCESS);
if (rngInit)
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}
int test_tls13_cipher_fuzz_aes256_gcm_sha384(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
defined(BUILD_TLS_AES_256_GCM_SHA384)
WC_RNG rng;
int rngInit = 0;
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_InitRng(&rng), 0);
if (EXPECT_SUCCESS())
rngInit = 1;
ExpectIntEQ(test_tls13_cipher_fuzz_cs(&rng, "TLS13-AES256-GCM-SHA384"),
TEST_SUCCESS);
if (rngInit)
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}
int test_tls13_cipher_fuzz_chacha20_poly1305_sha256(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
defined(BUILD_TLS_CHACHA20_POLY1305_SHA256)
WC_RNG rng;
int rngInit = 0;
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_InitRng(&rng), 0);
if (EXPECT_SUCCESS())
rngInit = 1;
ExpectIntEQ(test_tls13_cipher_fuzz_cs(&rng,
"TLS13-CHACHA20-POLY1305-SHA256"), TEST_SUCCESS);
if (rngInit)
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}
int test_tls13_cipher_fuzz_aes128_ccm_sha256(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
defined(BUILD_TLS_AES_128_CCM_SHA256)
WC_RNG rng;
int rngInit = 0;
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_InitRng(&rng), 0);
if (EXPECT_SUCCESS())
rngInit = 1;
ExpectIntEQ(test_tls13_cipher_fuzz_cs(&rng, "TLS13-AES128-CCM-SHA256"),
TEST_SUCCESS);
if (rngInit)
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}
int test_tls13_cipher_fuzz_aes128_ccm_8_sha256(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
defined(BUILD_TLS_AES_128_CCM_8_SHA256)
WC_RNG rng;
int rngInit = 0;
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_InitRng(&rng), 0);
if (EXPECT_SUCCESS())
rngInit = 1;
ExpectIntEQ(test_tls13_cipher_fuzz_cs(&rng, "TLS13-AES128-CCM-8-SHA256"),
TEST_SUCCESS);
if (rngInit)
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}
/* Regression test for the AEAD record-protection limit constants in
* internal.h. The macros expand to w64From32(hi, lo). A prior version split
* the intended 32-bit constants into 16-bit halves and passed each half as
* a separate 32-bit argument, producing a 64-bit value many orders of
* magnitude larger than RFC 8446 / RFC 9147 require. That made
* CheckTLS13AEADSendLimit's key-update trigger effectively unreachable.
* Compare against the hard-coded spec values so a recurrence is caught even
* if the macro is reused on both sides of the comparison. */
int test_tls13_AEAD_limit_macros(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS)
w64wrapper limit;
/* RFC 8446 5.5: 2^24.5 ~= 23726566 (0x016A09E6). */
limit = AEAD_AES_LIMIT;
ExpectIntEQ(w64GetHigh32(limit), 0);
ExpectIntEQ(w64GetLow32(limit), 0x016A09E6);
#ifdef WOLFSSL_DTLS13
/* RFC 9147 (AES-CCM integrity): 2^23.5 ~= 11863283 (0x00B504F3). */
limit = DTLS_AEAD_AES_CCM_FAIL_LIMIT;
ExpectIntEQ(w64GetHigh32(limit), 0);
ExpectIntEQ(w64GetLow32(limit), 0x00B504F3);
/* Key-update threshold is half the fail limit: 5931641 (0x005A8279). */
limit = DTLS_AEAD_AES_CCM_FAIL_KU_LIMIT;
ExpectIntEQ(w64GetHigh32(limit), 0);
ExpectIntEQ(w64GetLow32(limit), 0x005A8279);
#endif
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
(defined(BUILD_TLS_AES_128_GCM_SHA256) || \
defined(BUILD_TLS_AES_256_GCM_SHA384) || \
defined(BUILD_TLS_AES_128_CCM_SHA256) || \
defined(BUILD_TLS_AES_128_CCM_8_SHA256))
/* Drive the client's encrypt sequence number towards the spec limit for
* `suite` and verify CheckTLS13AEADSendLimit's KeyUpdate trigger fires at
* exactly the right boundary.
*
* Two writes are exercised:
* 1. Counter set to limit - 2. After the write the counter must read
* limit - 1 (record incremented it by 1) and no KeyUpdate must have
* been emitted. CheckTLS13AEADSendLimit uses `seq >= limit`, so neither
* the pre-send check nor the trailing loop check (which runs once more
* after the last record before wolfSSL_write exits) is allowed to fire.
* 2. A second write follows with the counter already sitting at limit - 1
* from the previous record. The user record goes out at seq = limit-1,
* which bumps the counter to limit; the trailing limit check then
* fires SendTls13KeyUpdate. SetKeysSide zeroes the encrypt counter, so
* the post-write counter is 0.
*
* With the previous broken AEAD-limit macros the limit was unreachable, no
* KeyUpdate would ever fire, and the counter would simply advance to
* limit_lo + 1 in the second case instead of being reset.
*
* The AEAD nonce mixes in the record sequence number on both sides, so the
* server's decrypt counter has to be advanced in lockstep with the client's
* encrypt counter or the record fails the integrity check. */
static int test_tls13_AEAD_limit_triggers_KeyUpdate_cs(const char* suite,
word32 limit_hi, word32 limit_lo, int expected_bulk_cipher)
{
EXPECT_DECLS;
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
const char msg[] = "post-limit-record";
char buf[sizeof(msg)];
int written;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
test_ctx.c_ciphers = suite;
test_ctx.s_ciphers = suite;
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
if (EXPECT_SUCCESS() && ssl_c != NULL && ssl_s != NULL) {
/* Sanity check: the negotiated bulk cipher matches what the caller
* intends to exercise. If a build flag combination falls through to
* a different suite, the limit constant would be wrong. */
ExpectIntEQ(ssl_c->specs.bulk_cipher_algorithm, expected_bulk_cipher);
/* Stage the counters two below the limit so the first write stays
* comfortably below the trigger threshold. */
ssl_c->keys.sequence_number_hi = limit_hi;
ssl_c->keys.sequence_number_lo = limit_lo - 2;
ssl_s->keys.peer_sequence_number_hi = limit_hi;
ssl_s->keys.peer_sequence_number_lo = limit_lo - 2;
}
/* First write: below the limit, no KeyUpdate expected. */
written = wolfSSL_write(ssl_c, msg, (int)sizeof(msg));
ExpectIntEQ(written, (int)sizeof(msg));
if (EXPECT_SUCCESS() && ssl_c != NULL) {
/* The record bumped the counter from limit-2 to limit-1. A
* KeyUpdate would have zeroed it via SetKeysSide and bumped to 1. */
ExpectIntEQ((int)ssl_c->keys.sequence_number_hi, (int)limit_hi);
ExpectIntEQ(ssl_c->keys.sequence_number_lo, limit_lo - 1);
}
/* Server consumes the below-limit record with its existing keys. */
XMEMSET(buf, 0, sizeof(buf));
ExpectIntEQ(wolfSSL_read(ssl_s, buf, (int)sizeof(buf)), (int)sizeof(msg));
ExpectIntEQ(XMEMCMP(buf, msg, sizeof(msg)), 0);
/* Second write: the client's counter is now at limit-1. Sending this
* record will push it to limit, at which point the trailing check
* inside SendData's loop fires SendTls13KeyUpdate. No manual counter
* adjustment is needed -- the counter is allowed to "naturally" reach
* the limit through the previous send. */
written = wolfSSL_write(ssl_c, msg, (int)sizeof(msg));
ExpectIntEQ(written, (int)sizeof(msg));
if (EXPECT_SUCCESS() && ssl_c != NULL) {
/* SendTls13KeyUpdate -> DeriveTls13Keys -> SetKeysSide zeroes the
* encrypt sequence number. The user record went out before the
* trigger fired, so no record was sent on the new keys. */
ExpectIntEQ((int)ssl_c->keys.sequence_number_hi, 0);
ExpectIntEQ((int)ssl_c->keys.sequence_number_lo, 0);
}
/* The server reads the user record (sent under the pre-update keys at
* seq = limit - 1) before it sees the KeyUpdate record. The KeyUpdate
* is consumed transparently on a subsequent read; for the test we just
* need to confirm the user data round-trips. */
XMEMSET(buf, 0, sizeof(buf));
{
int r = -1, attempts;
for (attempts = 0; attempts < 5; attempts++) {
r = wolfSSL_read(ssl_s, buf, (int)sizeof(buf));
if (r > 0)
break;
if (wolfSSL_get_error(ssl_s, r) != WOLFSSL_ERROR_WANT_READ)
break;
}
ExpectIntEQ(r, (int)sizeof(msg));
}
ExpectIntEQ(XMEMCMP(buf, msg, sizeof(msg)), 0);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
return EXPECT_RESULT();
}
#endif
int test_tls13_AEAD_limit_KU_aes128_gcm_sha256(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(BUILD_TLS_AES_128_GCM_SHA256)
ExpectIntEQ(test_tls13_AEAD_limit_triggers_KeyUpdate_cs(
"TLS13-AES128-GCM-SHA256", 0, 0x016A09E6, wolfssl_aes_gcm),
TEST_SUCCESS);
#endif
return EXPECT_RESULT();
}
int test_tls13_AEAD_limit_KU_aes256_gcm_sha384(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(BUILD_TLS_AES_256_GCM_SHA384)
ExpectIntEQ(test_tls13_AEAD_limit_triggers_KeyUpdate_cs(
"TLS13-AES256-GCM-SHA384", 0, 0x016A09E6, wolfssl_aes_gcm),
TEST_SUCCESS);
#endif
return EXPECT_RESULT();
}
int test_tls13_AEAD_limit_KU_aes128_ccm_sha256(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(BUILD_TLS_AES_128_CCM_SHA256)
ExpectIntEQ(test_tls13_AEAD_limit_triggers_KeyUpdate_cs(
"TLS13-AES128-CCM-SHA256", 0, 0x016A09E6, wolfssl_aes_ccm),
TEST_SUCCESS);
#endif
return EXPECT_RESULT();
}
int test_tls13_AEAD_limit_KU_aes128_ccm_8_sha256(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(BUILD_TLS_AES_128_CCM_8_SHA256)
ExpectIntEQ(test_tls13_AEAD_limit_triggers_KeyUpdate_cs(
"TLS13-AES128-CCM-8-SHA256", 0, 0x016A09E6, wolfssl_aes_ccm),
TEST_SUCCESS);
#endif
return EXPECT_RESULT();
}
/* RFC 9846 Section 4.7.3: a sending implementation MUST NOT allow its number of
* key updates to exceed 2^48-1. Establish a TLS 1.3 connection and exercise both
* sides of the boundary: one update seeded just below the ceiling must succeed
* and advance the sender count to exactly 2^48-1, and a further update once the
* count has reached the ceiling must be refused with BAD_STATE_E without
* advancing the count. The count is inspected directly because
* SendTls13KeyUpdate enforces the limit before touching the transport. */
int test_tls13_KeyUpdate_sender_limit(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT) && \
!defined(NO_WOLFSSL_SERVER) && \
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;
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);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
if (EXPECT_SUCCESS() && ssl_c != NULL) {
w64wrapper ceiling;
ceiling = w64From32(TLS13_KEY_UPDATE_MAX_HI32, TLS13_KEY_UPDATE_MAX_LO32);
/* One below the ceiling: the update is allowed and must advance the
* sender count by one, reaching exactly 2^48-1. */
ssl_c->keys.keyUpdateCount = w64From32(TLS13_KEY_UPDATE_MAX_HI32,
TLS13_KEY_UPDATE_MAX_LO32 - 1);
ExpectIntEQ(wolfSSL_update_keys(ssl_c), WOLFSSL_SUCCESS);
ExpectTrue(w64Equal(ssl_c->keys.keyUpdateCount, ceiling));
/* At the ceiling: a further update must be refused rather than
* advancing the count past 2^48-1. */
ExpectIntEQ(wolfSSL_update_keys(ssl_c), WC_NO_ERR_TRACE(BAD_STATE_E));
ExpectTrue(w64Equal(ssl_c->keys.keyUpdateCount, ceiling));
}
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_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) && \
defined(HAVE_CERTIFICATE_STATUS_REQUEST) && defined(HAVE_OCSP) && \
defined(KEEP_PEER_CERT) && \
!defined(NO_CERTS) && !defined(NO_RSA) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
/* Mock OCSP I/O callback that yields no response. It lets stapling be enabled
* without contacting a real responder, but may not even be invoked (the test
* certs need not advertise an OCSP responder URL). Either way no staple is
* produced, which is the "no staple available" path this test exercises. */
static int test_pha_ocsp_io_cb(void* ioCtx, const char* url, int urlSz,
unsigned char* req, int reqSz, unsigned char** resp)
{
(void)ioCtx; (void)url; (void)urlSz; (void)req; (void)reqSz;
*resp = NULL;
return 0;
}
static void test_pha_ocsp_resp_free_cb(void* ioCtx, unsigned char* resp)
{
(void)ioCtx; (void)resp;
}
#endif
/* Post-Handshake Authentication combined with OCSP stapling
* (status_request) on the TLS 1.3 CertificateRequest message.
*
* Regression for two related issues:
* 1. The server's PHA CertificateRequest must include the
* status_request extension (with an empty body) when the client
* offered status_request in its ClientHello (RFC 8446 4.2 / 4.3.2).
* Without the fix the extension was suppressed and the size and
* write paths disagreed by 4 bytes, causing the client to send a
* decode_error alert (BUFFER_ERROR / -328).
* 2. The server-side OCSP-status check in ProcessPeerCerts must run
* for the PHA-received client Certificate. The check must also
* tolerate a missing/empty stapled response unless the verifier
* enforces must-staple, per RFC 8446 4.4.2.1 (client OCSP staple
* is MAY) and RFC 7633 (must-staple). Without the fix the server
* either skipped the check entirely or returned
* BAD_CERTIFICATE_STATUS_ERROR (-406) for the no-staple case.
*
* The test exercises a single TLS 1.3 connection: an initial handshake
* without client authentication, followed by a server-initiated PHA
* exchange. The server expects to receive (and verify) the client
* certificate even though no OCSP staple is supplied.
*
* KEEP_PEER_CERT is part of the guard because the check for the received
* client certificate uses wolfSSL_get_peer_certificate(), which is only
* built when that macro is defined.
*/
int test_tls13_pha_status_request(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) && \
defined(HAVE_CERTIFICATE_STATUS_REQUEST) && defined(HAVE_OCSP) && \
defined(KEEP_PEER_CERT) && \
!defined(NO_CERTS) && !defined(NO_RSA) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
WOLFSSL_X509 *peer = NULL;
const char msg[] = "ping";
char buf[8];
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
/* --- Client CTX ------------------------------------------------ */
ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_c, caCertFile, 0),
WOLFSSL_SUCCESS);
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);
/* Must opt in to PHA before wolfSSL_connect to add the
* post_handshake_auth extension to the ClientHello. */
ExpectIntEQ(wolfSSL_CTX_allow_post_handshake_auth(ctx_c), 0);
ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(ctx_c), WOLFSSL_SUCCESS);
wolfSSL_SetIORecv(ctx_c, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_c, test_memio_write_cb);
/* --- Server CTX ------------------------------------------------ */
ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, caCertFile, 0),
WOLFSSL_SUCCESS);
/* Trust the client cert issuer as well, otherwise the PHA
* Certificate verification would fail with ASN_SELF_SIGNED_E. */
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s,
"./certs/client-ca.pem", 0), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(ctx_s), WOLFSSL_SUCCESS);
/* Mock callback: stapling negotiates but the response is empty. */
ExpectIntEQ(wolfSSL_CTX_SetOCSP_Cb(ctx_s, test_pha_ocsp_io_cb,
test_pha_ocsp_resp_free_cb, NULL), WOLFSSL_SUCCESS);
/* Initial handshake: do not request the client certificate yet -
* the server promotes verification only when triggering PHA. */
wolfSSL_CTX_set_verify(ctx_s, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_SetIORecv(ctx_s, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_s, test_memio_write_cb);
/* --- SSL objects ----------------------------------------------- */
ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
/* Causes status_request in the ClientHello so that the server's
* PHA CertificateRequest re-emits the same extension. */
ExpectIntEQ(wolfSSL_UseOCSPStapling(ssl_c, WOLFSSL_CSR_OCSP, 0),
WOLFSSL_SUCCESS);
ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
/* --- Initial handshake (no client cert requested) -------------- */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectNull(wolfSSL_get_peer_certificate(ssl_s));
/* --- Trigger PHA: server now requires the client certificate -- */
if (EXPECT_SUCCESS()) {
wolfSSL_set_verify(ssl_s,
WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT,
NULL);
ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
}
/* The server's wolfSSL_write below carries the PHA
* CertificateRequest record. The client's wolfSSL_read consumes
* the request, transmits Certificate/CertificateVerify/Finished
* and surfaces the application data to us. */
ExpectIntEQ(wolfSSL_write(ssl_s, msg, (int)sizeof(msg) - 1),
(int)sizeof(msg) - 1);
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf) - 1),
(int)sizeof(msg) - 1);
/* The client's reply lets the server's wolfSSL_read drain the
* incoming PHA Certificate flight before the application data. */
ExpectIntEQ(wolfSSL_write(ssl_c, msg, (int)sizeof(msg) - 1),
(int)sizeof(msg) - 1);
ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf) - 1),
(int)sizeof(msg) - 1);
/* PHA succeeded: the server now holds the client certificate.
* Reaching this point also implies the server tolerated the
* empty OCSP staple instead of failing with -406. */
ExpectNotNull(peer = wolfSSL_get_peer_certificate(ssl_s));
wolfSSL_X509_free(peer);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}