Files
wolfssl/tests/api/test_tls13.c
T

6874 lines
260 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_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);
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx_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 8773bis 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);
#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);
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx_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();
}
#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 */
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;
}
}
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;
}
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);
(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);
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);
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();
}
#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();
}
/* 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();
}
/* 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. */
{
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();
}
/* 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 to force the server to
* encode an over-limit lifetime onto the wire and confirm 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);
/* 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();
}
/* 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 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();
}