Enable support for mandatory PSKs

Add a new option to require that an external Pre-Shared Key is negotiated
for a handshake to succeed, configured via the new APIs
wolfSSL_CTX_require_psk()/wolfSSL_require_psk(). When set, a handshake
that completes without negotiating an external PSK is aborted with
PSK_MISSING_ERROR instead of falling back to a certificate handshake, so
the PSK acts as an additional security factor.

This is a TLS 1.3 / DTLS 1.3 feature. In (D)TLS 1.2 the use of a PSK is
determined by the negotiated cipher suite, so a mandatory PSK is instead
configured there by restricting the cipher suite list to PSK suites; the
new APIs therefore reject non-TLS-1.3 contexts with BAD_FUNC_ARG.

To keep the requirement fail-closed, the APIs also disable version
downgrade on the object so a downgrade-capable context (e.g. one created
from a v23 method) cannot silently fall back to (D)TLS 1.2 and complete
without a PSK; a peer that does not support (D)TLS 1.3 fails to connect.

The requirement applies to external PSKs only (not session tickets):
session-ticket resumption is exempt. To preserve forward secrecy a
mandatory external PSK must also use an (EC)DHE key exchange; a pure
psk_ke handshake is rejected with PSK_KEY_ERROR. When used with
WOLFSSL_CERT_WITH_EXTERN_PSK, it also ensures that peers are properly
authenticated with both the PSK and via certificates.

The new APIs live alongside the existing wolfSSL_[CTX_]no_dhe_psk()/
only_dhe_psk() PSK options and do not depend on certificate support, so
the feature is usable in NO_CERTS (PSK-only) builds.

Added unit tests for the new APIs and enforcement.
This commit is contained in:
Tobias Frauenschläger
2026-06-22 12:18:05 +02:00
parent 4de819075f
commit 79b30aa268
9 changed files with 964 additions and 11 deletions
+74
View File
@@ -14134,6 +14134,80 @@ int wolfSSL_CTX_no_dhe_psk(WOLFSSL_CTX* ctx);
*/
int wolfSSL_no_dhe_psk(WOLFSSL* ssl);
/*!
\ingroup Setup
\brief This function is called on a TLS v1.3 / DTLS v1.3 context to require
that an external Pre-Shared Key is negotiated for the handshake to succeed.
When set, a handshake that completes without negotiating an external PSK is
aborted with PSK_MISSING_ERROR instead of falling back to a certificate
handshake, so the PSK acts as an additional security factor. The requirement
keys off the external-PSK callback (it has no effect unless one is
registered) and session-ticket resumption is exempt. To preserve forward
secrecy a mandatory external PSK must also use an (EC)DHE key exchange; a
pure psk_ke handshake is rejected with PSK_KEY_ERROR. This applies to TLS 1.3
and DTLS 1.3 only; in (D)TLS 1.2 the use of a PSK is determined by the
negotiated cipher suite, so a mandatory PSK is instead configured by
restricting the cipher suite list to (preferably (EC)DHE-)PSK suites.
\warning Because the requirement can only be enforced for (D)TLS 1.3, this
function also disables version downgrade on the context so it cannot
silently fall back to (D)TLS 1.2 and complete a handshake without a PSK. A
peer that does not support (D)TLS 1.3 will therefore fail to connect.
\note In builds compiled without external-PSK and without session-ticket
support (NO_PSK defined and HAVE_SESSION_TICKET undefined) the requirement
cannot be enforced; the function still returns 0 but has no effect.
\param [in,out] ctx a pointer to a WOLFSSL_CTX structure, created using
wolfSSL_CTX_new().
\return BAD_FUNC_ARG if ctx is NULL or not at least TLS v1.3.
\return 0 if successful.
_Example_
\code
int ret;
WOLFSSL_CTX* ctx;
...
ret = wolfSSL_CTX_require_psk(ctx);
if (ret != 0) {
// failed to make a PSK mandatory
}
\endcode
\sa wolfSSL_require_psk
*/
int wolfSSL_CTX_require_psk(WOLFSSL_CTX* ctx);
/*!
\ingroup Setup
\brief This function is called on a TLS v1.3 / DTLS v1.3 wolfSSL object to
require that an external Pre-Shared Key is negotiated for the handshake to
succeed. See wolfSSL_CTX_require_psk() for the full behaviour.
\param [in,out] ssl a pointer to a WOLFSSL structure, created using
wolfSSL_new().
\return BAD_FUNC_ARG if ssl is NULL or not at least TLS v1.3.
\return 0 if successful.
_Example_
\code
int ret;
WOLFSSL* ssl;
...
ret = wolfSSL_require_psk(ssl);
if (ret != 0) {
// failed to make a PSK mandatory
}
\endcode
\sa wolfSSL_CTX_require_psk
*/
int wolfSSL_require_psk(WOLFSSL* ssl);
/*!
\ingroup IO
+5
View File
@@ -7279,6 +7279,7 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
ssl->options.verifyNone = ctx->verifyNone;
ssl->options.failNoCert = ctx->failNoCert;
ssl->options.failNoCertxPSK = ctx->failNoCertxPSK;
ssl->options.failNoPSK = ctx->failNoPSK;
ssl->options.sendVerify = ctx->sendVerify;
ssl->options.partialWrite = ctx->partialWrite;
@@ -27955,6 +27956,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e)
case DUPE_ENTRY_E:
return "duplicate entry error";
case PSK_MISSING_ERROR:
return "psk missing error";
case GETTIME_ERROR:
return "gettimeofday() error";
@@ -36210,6 +36214,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
return missing_extension;
case WC_NO_ERR_TRACE(MATCH_SUITE_ERROR):
case WC_NO_ERR_TRACE(MISSING_HANDSHAKE_DATA):
case WC_NO_ERR_TRACE(PSK_MISSING_ERROR):
return handshake_failure;
case WC_NO_ERR_TRACE(VERSION_ERROR):
return wolfssl_alert_protocol_version;
+105 -2
View File
@@ -4386,7 +4386,11 @@ static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk, int clientHello)
return PSK_KEY_ERROR;
}
}
else if (ssl->options.onlyPskDheKe) {
else if (ssl->options.onlyPskDheKe ||
(ssl->options.failNoPSK && !psk->resumption)) {
/* A mandatory external PSK (failNoPSK) must be combined with
* (EC)DHE for forward secrecy, so reject a pure psk_ke
* negotiation. Session-ticket resumption is exempt. */
WOLFSSL_ERROR_VERBOSE(PSK_KEY_ERROR);
return PSK_KEY_ERROR;
}
@@ -5907,6 +5911,18 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
while (psk != NULL && !psk->chosen)
psk = psk->next;
if (psk == NULL) {
/* A mandatory PSK is satisfied by any PSK the server chose,
* including a resumption PSK - this matches the server-side
* failNoPSK semantics, where a negotiated PSK (external or
* resumption) is accepted. The error only fires when no PSK was
* chosen at all. havePSK is only set by an external-PSK callback,
* so a peer relying solely on session-ticket resumption is
* unaffected. */
if (ssl->options.havePSK && ssl->options.failNoPSK) {
WOLFSSL_MSG("Server did not negotiate a mandatory PSK");
WOLFSSL_ERROR_VERBOSE(PSK_MISSING_ERROR);
return PSK_MISSING_ERROR;
}
ssl->options.resuming = 0;
ssl->arrays->psk_keySz = 0;
XMEMSET(ssl->arrays->psk_key, 0, MAX_PSK_KEY_LEN);
@@ -6670,6 +6686,16 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
#endif
if (usingPSK)
*usingPSK = 0;
/* No PSK extension at all: if a mandatory external PSK is configured,
* refuse the connection rather than continue without one. havePSK is
* only set by an external-PSK callback, so a peer relying solely on
* session-ticket resumption is unaffected. */
if (ssl->options.havePSK && ssl->options.failNoPSK) {
WOLFSSL_ERROR_VERBOSE(PSK_MISSING_ERROR);
return PSK_MISSING_ERROR;
}
/* Hash data up to binders for deriving binders in PSK extension. */
ret = HashInput(ssl, input, (int)helloSz);
return ret;
@@ -6731,6 +6757,16 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
#endif
if (!*usingPSK) {
/* No suitable PSK was negotiated. When a mandatory external PSK is
* configured, fail with a dedicated error instead of falling back to a
* certificate handshake. This must run before the no-certificate
* BAD_BINDER check below so a PSK-only server (no cert) still reports
* PSK_MISSING_ERROR. havePSK is only set by an external-PSK callback, so
* a peer relying solely on session-ticket resumption is unaffected. */
if (ssl->options.havePSK && ssl->options.failNoPSK) {
WOLFSSL_ERROR_VERBOSE(PSK_MISSING_ERROR);
return PSK_MISSING_ERROR;
}
#ifndef NO_CERTS
if (ssl->buffers.certificate == NULL
#ifdef WOLFSSL_CERT_SETUP_CB
@@ -6892,7 +6928,11 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
ssl->namedGroup = ssl->session->namedGroup;
*usingPSK = 2; /* generate new ephemeral key */
}
else if (ssl->options.onlyPskDheKe) {
else if (ssl->options.onlyPskDheKe ||
(ssl->options.failNoPSK && !ssl->options.resuming)) {
/* A mandatory external PSK (failNoPSK) must be combined with
* (EC)DHE for forward secrecy, so reject a pure psk_ke
* negotiation. Session-ticket resumption is exempt. */
return PSK_KEY_ERROR;
}
else
@@ -6911,6 +6951,8 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
}
else {
#ifdef WOLFSSL_CERT_WITH_EXTERN_PSK
/* If no PSK is found, we remove the extension to make sure it
* is not sent back to the client */
TLSX_Remove(&ssl->extensions, TLSX_CERT_WITH_EXTERN_PSK, ssl->heap);
ssl->options.certWithExternPsk = 0;
#endif
@@ -11852,6 +11894,21 @@ int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
}
#endif
#if !defined(NO_CERTS) && !defined(NO_PSK) && \
defined(WOLFSSL_CERT_WITH_EXTERN_PSK)
/* Verify the server sent a certificate if requested */
if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->options.pskNegotiated &&
ssl->options.failNoCert) {
if ((TLSX_Find(ssl->extensions, TLSX_CERT_WITH_EXTERN_PSK) != NULL) &&
(!ssl->options.havePeerCert || !ssl->options.havePeerVerify)) {
ret = NO_PEER_CERT;
WOLFSSL_MSG("TLS v1.3 server did not present peer cert");
DoCertFatalAlert(ssl, ret);
goto cleanup;
}
}
#endif
/* check against totalSz */
if (*inOutIdx + size > totalSz) {
ret = BUFFER_E;
@@ -14969,6 +15026,52 @@ int wolfSSL_only_dhe_psk(WOLFSSL* ssl)
}
#endif /* HAVE_SUPPORTED_CURVES */
/* Require that an external Pre-Shared Key is negotiated for the handshake to
* succeed. TLS 1.3 / DTLS 1.3 only - in (D)TLS 1.2 the use of a PSK is
* determined by the negotiated cipher suite, so a mandatory PSK is configured
* there by restricting the cipher suite list to PSK suites.
*
* ctx The SSL/TLS CTX object.
* returns BAD_FUNC_ARG when ctx is NULL or not at least TLS v1.3, 0 on success.
*/
int wolfSSL_CTX_require_psk(WOLFSSL_CTX* ctx)
{
if (ctx == NULL || !IsAtLeastTLSv1_3(ctx->method->version))
return BAD_FUNC_ARG;
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
ctx->failNoPSK = 1;
/* The requirement can only be enforced for (D)TLS 1.3, so keep it
* fail-closed by disabling a version downgrade. Otherwise a
* downgrade-capable context (e.g. from a v23 method) could silently fall
* back to (D)TLS 1.2 and complete without any PSK. */
ctx->method->downgrade = 0;
#endif
return 0;
}
/* Require that an external Pre-Shared Key is negotiated for the handshake to
* succeed. See wolfSSL_CTX_require_psk().
*
* ssl The SSL/TLS object.
* returns BAD_FUNC_ARG when ssl is NULL or not at least TLS v1.3, 0 on success.
*/
int wolfSSL_require_psk(WOLFSSL* ssl)
{
if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version))
return BAD_FUNC_ARG;
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
ssl->options.failNoPSK = 1;
/* See wolfSSL_CTX_require_psk() - keep the requirement fail-closed by
* disabling a version downgrade to (D)TLS 1.2. */
ssl->options.downgrade = 0;
#endif
return 0;
}
int Tls13UpdateKeys(WOLFSSL* ssl)
{
if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version))
+1 -1
View File
@@ -28384,7 +28384,7 @@ static int error_test(void)
#endif
{ -9, WC_SPAN1_FIRST_E + 1 },
{ -300, -300 },
{ -335, -336 },
{ -336, -336 },
{ -346, -349 },
{ -356, -356 },
{ -358, -358 },
+746 -8
View File
@@ -1038,6 +1038,49 @@ int test_tls13_cert_with_extern_psk_handshake(void)
return EXPECT_RESULT();
}
int test_tls13_cert_with_extern_psk_client_requires_cert(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
!defined(NO_PSK) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && !defined(NO_CERTS) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
/* The client requests cert_with_extern_psk and mandates a peer certificate
* (WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT). The server negotiates the external
* PSK but does NOT enable cert_with_extern_psk, so it completes a PSK-only
* handshake without sending a Certificate/CertificateVerify. The client
* must therefore reject in DoTls13Finished with NO_PEER_CERT instead of
* accepting a PSK-only handshake. */
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_cwep_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_cwep_server_cb);
/* Only the client requests cert_with_extern_psk. */
ExpectIntEQ(wolfSSL_set_cert_with_extern_psk(ssl_c, 1), WOLFSSL_SUCCESS);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(NO_PEER_CERT));
ExpectIntEQ(ssl_c->options.pskNegotiated, 1);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_cert_with_extern_psk_requires_key_share(void)
{
EXPECT_DECLS;
@@ -1135,15 +1178,19 @@ int test_tls13_cert_with_extern_psk_rejects_resumption(void)
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
/* Load on ssl_s, not ctx_s: ssl_s already exists (test_memio_setup created
* it) and shares the CTX key buffers. Reloading on ctx_s would free those
* buffers, leaving ssl_s with a dangling key that crashes when the server
* decodes it for CertificateVerify. */
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx_s, eccCertFile,
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx_s, eccKeyFile,
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile,
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile,
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#endif
@@ -1328,6 +1375,10 @@ int test_tls13_cert_with_extern_psk_sh_missing_key_share(void)
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
/* Load on ssl_s, not ctx_s: ssl_s already exists (test_memio_setup created
* it) and shares the CTX key buffers. Reloading on ctx_s would free those
* buffers, leaving ssl_s with a dangling key that crashes when the server
* decodes it for CertificateVerify. */
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
@@ -1423,15 +1474,19 @@ int test_tls13_cert_with_extern_psk_sh_confirms_resumption(void)
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
/* Load on ssl_s, not ctx_s: ssl_s already exists (test_memio_setup created
* it) and shares the CTX key buffers. Reloading on ctx_s would free those
* buffers, leaving ssl_s with a dangling key that crashes when the server
* decodes it for CertificateVerify. */
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx_s, eccCertFile,
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx_s, eccKeyFile,
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile,
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile,
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#endif
@@ -1502,6 +1557,689 @@ int test_tls13_cert_with_extern_psk_sh_confirms_resumption(void)
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_api(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT)
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
(void)ctx;
(void)ssl;
/* NULL arguments are rejected. */
ExpectIntEQ(wolfSSL_CTX_require_psk(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_require_psk(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* The failNoPSK bit is only settable when external-PSK or session-ticket
* support is compiled in; mirror the guard used by the API itself. */
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
/* wolfSSL_CTX_require_psk() sets the failNoPSK bit on the CTX, and a new
* SSL object inherits it. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
ExpectIntEQ(wolfSSL_CTX_require_psk(ctx), 0);
ExpectIntEQ(ctx->failNoPSK, 1);
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(ssl->options.failNoPSK, 1);
wolfSSL_free(ssl);
ssl = NULL;
wolfSSL_CTX_free(ctx);
ctx = NULL;
/* wolfSSL_require_psk() sets the option directly on the SSL object. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(ssl->options.failNoPSK, 0);
ExpectIntEQ(wolfSSL_require_psk(ssl), 0);
ExpectIntEQ(ssl->options.failNoPSK, 1);
wolfSSL_free(ssl);
ssl = NULL;
wolfSSL_CTX_free(ctx);
ctx = NULL;
/* The requirement is fail-closed: on a downgrade-capable context (created
* from a v23 method) require_psk() disables version downgrade so the
* handshake cannot silently fall back to (D)TLS 1.2 without a PSK. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
ExpectIntEQ(wolfSSL_CTX_require_psk(ctx), 0);
ExpectIntEQ(ctx->method->downgrade, 0);
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(ssl->options.downgrade, 0);
wolfSSL_free(ssl);
ssl = NULL;
wolfSSL_CTX_free(ctx);
ctx = NULL;
#endif
#ifndef WOLFSSL_NO_TLS12
/* The API is TLS 1.3 only - a TLS 1.2 context is rejected so users are not
* misled into thinking the option applies to TLS 1.2. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
ExpectIntEQ(wolfSSL_CTX_require_psk(ctx), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
wolfSSL_CTX_free(ctx);
ctx = NULL;
#endif
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
/* 32-byte external PSK used by the fail-if-no-PSK test callbacks. */
static const unsigned char test_tls13_fnp_psk[32] = {
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A
};
static unsigned int test_tls13_fnp_client_cb(WOLFSSL* ssl, const char* hint,
char* identity, unsigned int id_max_len, unsigned char* key,
unsigned int key_max_len)
{
(void)ssl;
(void)hint;
if (id_max_len == 0 || key_max_len < sizeof(test_tls13_fnp_psk))
return 0;
XSTRNCPY(identity, "fnp_client", id_max_len);
XMEMCPY(key, test_tls13_fnp_psk, sizeof(test_tls13_fnp_psk));
return (unsigned int)sizeof(test_tls13_fnp_psk);
}
static unsigned int test_tls13_fnp_server_cb(WOLFSSL* ssl, const char* id,
unsigned char* key, unsigned int key_max_len)
{
(void)ssl;
if (key_max_len < sizeof(test_tls13_fnp_psk) || id == NULL)
return 0;
if (XSTRCMP(id, "fnp_client") != 0)
return 0;
XMEMCPY(key, test_tls13_fnp_psk, sizeof(test_tls13_fnp_psk));
return (unsigned int)sizeof(test_tls13_fnp_psk);
}
/* Server PSK callback that finds no PSK for any offered identity (returns 0),
* mirroring an application whose lookup misses. */
static unsigned int test_tls13_fnp_reject_server_cb(WOLFSSL* ssl,
const char* id, unsigned char* key, unsigned int key_max_len)
{
(void)ssl;
(void)id;
(void)key;
(void)key_max_len;
return 0;
}
#endif
int test_tls13_fail_if_no_psk_handshake(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
const char appMsg[] = "fail_if_no_psk test";
char readBuf[sizeof(appMsg)];
int readSz;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
/* Both endpoints require a PSK to be negotiated. */
wolfSSL_require_psk(ssl_c);
wolfSSL_require_psk(ssl_s);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
/* A PSK is configured on both ends, so the handshake completes. */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(ssl_c->options.failNoPSK, 1);
ExpectIntEQ(ssl_s->options.failNoPSK, 1);
ExpectIntEQ(ssl_c->options.pskNegotiated, 1);
ExpectIntEQ(ssl_s->options.pskNegotiated, 1);
/* Application data flows over the PSK-derived keys. */
ExpectIntEQ(wolfSSL_write(ssl_c, appMsg, (int)XSTRLEN(appMsg)),
(int)XSTRLEN(appMsg));
readSz = wolfSSL_read(ssl_s, readBuf, sizeof(readBuf));
ExpectIntEQ(readSz, (int)XSTRLEN(appMsg));
ExpectIntEQ(XMEMCMP(readBuf, appMsg, (size_t)readSz), 0);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_rejects_no_psk(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
(defined(HAVE_ECC) || !defined(NO_RSA))
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
/* The server requires a PSK and has one configured, but the client offers
* none. The server must abort the handshake with PSK_MISSING_ERROR rather
* than fall back to a certificate-only handshake. */
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_require_psk(ssl_s);
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#endif
/* Only the server installs a PSK callback; the client sends no PSK. */
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_MISSING_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_client_no_psk_configured(void)
{
EXPECT_DECLS;
/* WOLFSSL_QT force-enables havePSK on every CTX (see wolfSSL_CTX_new), so the
* "no PSK configured" precondition this test relies on cannot be set up there. */
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && !defined(WOLFSSL_QT) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
(defined(HAVE_ECC) || !defined(NO_RSA))
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
/* The client requires a PSK but configures none. Because failNoPSK is gated
* on havePSK, this must NOT hard-fail: a normal certificate handshake is
* expected to succeed instead of raising PSK_MISSING_ERROR. */
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_PEER, NULL);
wolfSSL_require_psk(ssl_c);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_load_verify_locations(ctx_c, caEccCertFile,
NULL) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_CTX_load_verify_locations(ctx_c, caCertFile,
NULL) == WOLFSSL_SUCCESS);
#endif
ExpectIntEQ(ssl_c->options.failNoPSK, 1);
ExpectIntEQ(ssl_c->options.havePSK, 0);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(ssl_c->options.pskNegotiated, 0);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_client_rejects(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
(defined(HAVE_ECC) || !defined(NO_RSA))
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
/* The client requires a PSK and has one configured, but the server has no
* PSK callback so it never selects one. The client must abort with
* PSK_MISSING_ERROR rather than fall back to a cert-only handshake. */
wolfSSL_require_psk(ssl_c);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#endif
/* Only the client installs a PSK callback. */
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_MISSING_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_requires_dhe(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
/* Baseline: a pure psk_ke handshake (no DHE) succeeds when the PSK is
* optional, confirming the setup itself is valid. */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_c), 0);
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_s), 0);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(ssl_s->options.pskNegotiated, 1);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
ssl_c = NULL; ssl_s = NULL; ctx_c = NULL; ctx_s = NULL;
/* With failNoPSK on the server, the same pure psk_ke negotiation (no
* forward secrecy) must be rejected with PSK_KEY_ERROR. */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_require_psk(ssl_s);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_c), 0);
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_s), 0);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_KEY_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_client_requires_dhe(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
/* Only the client mandates the PSK (failNoPSK). The server does NOT set
* failNoPSK and is configured for pure psk_ke (wolfSSL_no_dhe_psk), so it
* accepts the PSK and replies with a ServerHello that omits a key_share.
* When the client processes that ServerHello in SetupPskKey, the mandatory
* external PSK has no (EC)DHE for forward secrecy, so the client must
* reject it with PSK_KEY_ERROR. This exercises the client-side branch that
* the server-only requires_dhe test cannot reach (there the server rejects
* the pure psk_ke negotiation first). */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
wolfSSL_require_psk(ssl_c);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
/* Force the server to negotiate a pure psk_ke (no (EC)DHE) exchange. */
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_s), 0);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_KEY_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_resumption_exempt_from_dhe(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && defined(HAVE_SESSION_TICKET) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
(defined(HAVE_ECC) || !defined(NO_RSA))
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
WOLFSSL_SESSION *sess = NULL;
struct test_memio_ctx test_ctx;
byte readBuf[16];
/* Step 1: full TLS 1.3 handshake to obtain a session ticket. The server
* cert/key are already loaded by test_memio_setup; the default ticket
* encryption callback lets a fresh server CTX below decrypt the ticket. */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Drain the NewSessionTicket post-handshake message. */
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
wolfSSL_free(ssl_c); ssl_c = NULL;
wolfSSL_free(ssl_s); ssl_s = NULL;
/* Step 2: resume with a pure psk_ke (no (EC)DHE) exchange while the server
* has the mandatory-PSK requirement set. A session-ticket resumption is
* exempt from the mandatory-(EC)DHE rule, so the handshake must succeed
* (an external PSK in the same situation would be rejected). */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_require_psk(ssl_s);
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_c), 0);
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(ssl_c->options.resuming, 1);
ExpectIntEQ(ssl_s->options.resuming, 1);
wolfSSL_SESSION_free(sess);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_server_rejects_offered_psk(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
/* Baseline: the client offers a PSK but the server's callback rejects it
* (returns 0). Without failNoPSK the server (which has a certificate from
* test_memio_setup) falls back to a normal certificate handshake, which
* succeeds and negotiates no PSK. */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_reject_server_cb);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(ssl_s->options.pskNegotiated, 0);
wolfSSL_free(ssl_c); ssl_c = NULL;
wolfSSL_free(ssl_s); ssl_s = NULL;
wolfSSL_CTX_free(ctx_c); ctx_c = NULL;
wolfSSL_CTX_free(ctx_s); ctx_s = NULL;
/* With failNoPSK the same rejected-PSK negotiation must abort with
* PSK_MISSING_ERROR instead of falling back to the certificate handshake. */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_require_psk(ssl_s);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_reject_server_cb);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_MISSING_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_no_cert_server(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
/* Build the CTXs manually so the server has NO certificate configured,
* matching a PSK-only deployment. The client offers a PSK, the server's
* callback rejects it, and failNoPSK is set: the server must report
* PSK_MISSING_ERROR (not BAD_BINDER, and no certificate fallback). */
ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
wolfSSL_SetIORecv(ctx_c, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_c, test_memio_write_cb);
/* PSK callbacks are set on the CTX so PSK cipher suites are available when
* the (cert-less) SSL objects are created. */
wolfSSL_CTX_set_psk_client_callback(ctx_c, test_tls13_fnp_client_cb);
ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
wolfSSL_SetIORecv(ctx_s, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_s, test_memio_write_cb);
wolfSSL_CTX_set_psk_server_callback(ctx_s, test_tls13_fnp_reject_server_cb);
wolfSSL_CTX_require_psk(ctx_s);
ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_MISSING_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_dtls13_handshake(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_DTLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
const char appMsg[] = "fail_if_no_psk dtls13 test";
char readBuf[sizeof(appMsg)];
int readSz;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
/* Both endpoints require a PSK to be negotiated over DTLS 1.3, exercising
* the HRR/cookie flow through DoTls13ServerHello and CheckPreSharedKeys. */
wolfSSL_require_psk(ssl_c);
wolfSSL_require_psk(ssl_s);
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_fnp_client_cb);
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
/* A PSK is configured on both ends, so the handshake completes. */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(ssl_c->options.failNoPSK, 1);
ExpectIntEQ(ssl_s->options.failNoPSK, 1);
ExpectIntEQ(ssl_c->options.pskNegotiated, 1);
ExpectIntEQ(ssl_s->options.pskNegotiated, 1);
/* Application data flows over the PSK-derived keys. */
ExpectIntEQ(wolfSSL_write(ssl_c, appMsg, (int)XSTRLEN(appMsg)),
(int)XSTRLEN(appMsg));
readSz = wolfSSL_read(ssl_s, readBuf, sizeof(readBuf));
ExpectIntEQ(readSz, (int)XSTRLEN(appMsg));
ExpectIntEQ(XMEMCMP(readBuf, appMsg, (size_t)readSz), 0);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_fail_if_no_psk_dtls13_rejects_no_psk(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_DTLS13) && !defined(NO_PSK) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SUPPORTED_CURVES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
(defined(HAVE_ECC) || !defined(NO_RSA))
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
/* The server requires a PSK and has one configured, but the client offers
* none. Over DTLS 1.3 the server must still abort with PSK_MISSING_ERROR
* rather than fall back to a certificate-only handshake. */
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_require_psk(ssl_s);
#if defined(HAVE_ECC)
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, eccCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#else
ExpectTrue(wolfSSL_use_certificate_file(ssl_s, svrCertFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_s, svrKeyFile,
CERT_FILETYPE) == WOLFSSL_SUCCESS);
#endif
/* Only the server installs a PSK callback; the client sends no PSK. */
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_fnp_server_cb);
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(PSK_MISSING_ERROR));
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
!defined(NO_WOLFSSL_SERVER) && defined(HAVE_ECC) && \
defined(BUILD_TLS_AES_128_GCM_SHA256) && \
+26
View File
@@ -69,10 +69,23 @@ int test_tls13_serverhello_bad_cipher_suites(void);
int test_tls13_psk_no_cert_bad_binder(void);
int test_tls13_cert_with_extern_psk_apis(void);
int test_tls13_cert_with_extern_psk_handshake(void);
int test_tls13_cert_with_extern_psk_client_requires_cert(void);
int test_tls13_cert_with_extern_psk_requires_key_share(void);
int test_tls13_cert_with_extern_psk_rejects_resumption(void);
int test_tls13_cert_with_extern_psk_sh_missing_key_share(void);
int test_tls13_cert_with_extern_psk_sh_confirms_resumption(void);
int test_tls13_fail_if_no_psk_api(void);
int test_tls13_fail_if_no_psk_handshake(void);
int test_tls13_fail_if_no_psk_rejects_no_psk(void);
int test_tls13_fail_if_no_psk_client_no_psk_configured(void);
int test_tls13_fail_if_no_psk_client_rejects(void);
int test_tls13_fail_if_no_psk_requires_dhe(void);
int test_tls13_fail_if_no_psk_client_requires_dhe(void);
int test_tls13_fail_if_no_psk_resumption_exempt_from_dhe(void);
int test_tls13_fail_if_no_psk_server_rejects_offered_psk(void);
int test_tls13_fail_if_no_psk_no_cert_server(void);
int test_tls13_fail_if_no_psk_dtls13_handshake(void);
int test_tls13_fail_if_no_psk_dtls13_rejects_no_psk(void);
int test_tls13_ticket_peer_cert_reverify(void);
int test_tls13_clear_preserves_psk_dhe(void);
int test_tls13_cipher_fuzz_aes128_gcm_sha256(void);
@@ -132,10 +145,23 @@ int test_tls13_AEAD_limit_KU_aes128_ccm_8_sha256(void);
TEST_DECL_GROUP("tls13", test_tls13_psk_no_cert_bad_binder), \
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_apis), \
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_handshake), \
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_client_requires_cert), \
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_requires_key_share), \
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_rejects_resumption), \
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_sh_missing_key_share), \
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_sh_confirms_resumption), \
TEST_DECL_GROUP("tls13", test_tls13_fail_if_no_psk_api), \
TEST_DECL_GROUP("tls13", test_tls13_fail_if_no_psk_handshake), \
TEST_DECL_GROUP("tls13", test_tls13_fail_if_no_psk_rejects_no_psk), \
TEST_DECL_GROUP("tls13", test_tls13_fail_if_no_psk_client_no_psk_configured), \
TEST_DECL_GROUP("tls13", test_tls13_fail_if_no_psk_client_rejects), \
TEST_DECL_GROUP("tls13", test_tls13_fail_if_no_psk_requires_dhe), \
TEST_DECL_GROUP("tls13", test_tls13_fail_if_no_psk_client_requires_dhe), \
TEST_DECL_GROUP("tls13", test_tls13_fail_if_no_psk_resumption_exempt_from_dhe), \
TEST_DECL_GROUP("tls13", test_tls13_fail_if_no_psk_server_rejects_offered_psk), \
TEST_DECL_GROUP("tls13", test_tls13_fail_if_no_psk_no_cert_server), \
TEST_DECL_GROUP("tls13", test_tls13_fail_if_no_psk_dtls13_handshake), \
TEST_DECL_GROUP("tls13", test_tls13_fail_if_no_psk_dtls13_rejects_no_psk), \
TEST_DECL_GROUP("tls13", test_tls13_ticket_peer_cert_reverify), \
TEST_DECL_GROUP("tls13", test_tls13_clear_preserves_psk_dhe), \
TEST_DECL_GROUP("tls13", test_tls13_cipher_fuzz_aes128_gcm_sha256), \
+1
View File
@@ -83,6 +83,7 @@ enum wolfSSL_ErrorCodes {
SERVER_HINT_ERROR = -332, /* psk server hint error */
PSK_KEY_ERROR = -333, /* psk key error */
DUPE_ENTRY_E = -334, /* duplicate entry error */
PSK_MISSING_ERROR = -335, /* psk missing */
GETTIME_ERROR = -337, /* gettimeofday failed ??? */
GETITIMER_ERROR = -338, /* getitimer failed ??? */
+2
View File
@@ -3997,6 +3997,7 @@ struct WOLFSSL_CTX {
byte verifyNone:1;
byte failNoCert:1;
byte failNoCertxPSK:1; /* fail if no cert with the exception of PSK*/
byte failNoPSK:1; /* fail if no PSK is negotiated */
byte sessionCacheOff:1;
byte sessionCacheFlushOff:1;
#ifdef HAVE_EXT_CACHE
@@ -5138,6 +5139,7 @@ struct Options {
word16 verifyNone:1;
word16 failNoCert:1;
word16 failNoCertxPSK:1; /* fail for no cert except with PSK */
word16 failNoPSK:1; /* fail if no PSK is negotiated */
word16 downgrade:1; /* allow downgrade of versions */
word16 resuming:1;
#ifdef HAVE_SECURE_RENEGOTIATION
+4
View File
@@ -1499,6 +1499,8 @@ WOLFSSL_API int wolfSSL_CTX_no_dhe_psk(WOLFSSL_CTX* ctx);
WOLFSSL_API int wolfSSL_no_dhe_psk(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_CTX_only_dhe_psk(WOLFSSL_CTX* ctx);
WOLFSSL_API int wolfSSL_only_dhe_psk(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_CTX_require_psk(WOLFSSL_CTX* ctx);
WOLFSSL_API int wolfSSL_require_psk(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_update_keys(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_key_update_response(WOLFSSL* ssl, int* required);
WOLFSSL_API int wolfSSL_CTX_allow_post_handshake_auth(WOLFSSL_CTX* ctx);
@@ -3191,6 +3193,8 @@ enum { /* ssl Constants */
WOLFSSL_VERIFY_CLIENT_ONCE = 1 << 2,
WOLFSSL_VERIFY_POST_HANDSHAKE = 1 << 3,
WOLFSSL_VERIFY_FAIL_EXCEPT_PSK = 1 << 4,
/* 1 << 5 reserved (previously WOLFSSL_VERIFY_FAIL_IF_NO_PSK; a mandatory
* PSK is now requested with wolfSSL_[CTX_]require_psk()). */
WOLFSSL_VERIFY_DEFAULT = 1 << 9,
WOLFSSL_SESS_CACHE_OFF = 0x0000,