Skip to content

Commit 841da4a

Browse files
committed
TLSv1.3 PSK binders: always use id protection
Removed WOLFSSL_PSK_ID_PROTECTION from use as it is now on by default. Always check whether the server has a certificate (not a CA chain). If there is a certificate then continue, otherwise, report a binder error. Added test to ensure binder error returned and alert sent when no NO_CERT. test_tls13_bad_psk_binder already tested no certificate. Allowed memio test harness to be built when NO_CERT is defined.
1 parent 91f3e7e commit 841da4a

5 files changed

Lines changed: 148 additions & 16 deletions

File tree

src/tls13.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
* WOLFSSL_PSK_ONE_ID: Single PSK identity per connect default: off
5858
* WOLFSSL_PSK_MULTI_ID_PER_CS: Multiple PSK IDs per cipher suite default: off
5959
* WOLFSSL_PRIORITIZE_PSK: Prioritize PSK over ciphersuite order default: off
60-
* WOLFSSL_PSK_ID_PROTECTION: Enable PSK identity protection default: off
6160
*
6261
* TLS 1.3 Session Tickets:
6362
* WOLFSSL_TICKET_HAVE_ID: Session tickets include ID default: off
@@ -6527,20 +6526,19 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 inputSz,
65276526
}
65286527

65296528
if (current == NULL) {
6530-
#ifdef WOLFSSL_PSK_ID_PROTECTION
65316529
#ifndef NO_CERTS
6532-
if (ssl->buffers.certChainCnt != 0) {
6530+
if (ssl->buffers.certificate != NULL
6531+
#ifdef WOLFSSL_CERT_SETUP_CB
6532+
|| ssl->ctx->certSetupCb != NULL
6533+
#endif
6534+
) {
65336535
ret = 0;
65346536
goto cleanup;
65356537
}
65366538
#endif
65376539
WOLFSSL_ERROR_VERBOSE(BAD_BINDER);
65386540
ret = BAD_BINDER;
65396541
goto cleanup;
6540-
#else
6541-
ret = 0;
6542-
goto cleanup;
6543-
#endif
65446542
}
65456543

65466544
*first = (current == ext->data);
@@ -6817,14 +6815,16 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
68176815
TLSX_Remove(&ssl->extensions, TLSX_CERT_WITH_EXTERN_PSK, ssl->heap);
68186816
ssl->options.certWithExternPsk = 0;
68196817
#endif
6820-
#ifdef WOLFSSL_PSK_ID_PROTECTION
68216818
#ifndef NO_CERTS
6822-
if (ssl->buffers.certChainCnt != 0)
6819+
if (ssl->buffers.certificate != NULL
6820+
#ifdef WOLFSSL_CERT_SETUP_CB
6821+
|| ssl->ctx->certSetupCb != NULL
6822+
#endif
6823+
)
68236824
return 0;
68246825
#endif
68256826
WOLFSSL_ERROR_VERBOSE(BAD_BINDER);
68266827
return BAD_BINDER;
6827-
#endif
68286828
}
68296829

68306830
WOLFSSL_LEAVE("CheckPreSharedKeys", ret);

tests/api/test_tls13.c

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,6 +1775,123 @@ int test_tls13_bad_psk_binder(void)
17751775
}
17761776

17771777

1778+
#if defined(WOLFSSL_TLS13) && \
1779+
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_NO_CERTS) && \
1780+
!defined(NO_PSK) && defined(NO_CERTS)
1781+
static unsigned int test_tls13_psk_no_cert_client_cb(WOLFSSL* ssl,
1782+
const char* hint, char* identity, unsigned int id_max_len,
1783+
unsigned char* key, unsigned int key_max_len)
1784+
{
1785+
(void)ssl;
1786+
(void)hint;
1787+
(void)key_max_len;
1788+
1789+
/* Offer a PSK so the client sends a pre_shared_key extension. */
1790+
XSTRNCPY(identity, "Client_identity", id_max_len);
1791+
key[0] = 0x20;
1792+
return 1;
1793+
}
1794+
1795+
static unsigned int test_tls13_psk_no_cert_server_cb(WOLFSSL* ssl,
1796+
const char* id, unsigned char* key, unsigned int key_max_len)
1797+
{
1798+
(void)ssl;
1799+
(void)id;
1800+
(void)key;
1801+
(void)key_max_len;
1802+
1803+
/* Reject every identity so the server finds no matching PSK. */
1804+
return 0;
1805+
}
1806+
#endif
1807+
1808+
/* When no offered PSK matches and the server has no certificate to fall back
1809+
* to, the server must abort the handshake with BAD_BINDER rather than silently
1810+
* continuing. This covers both cases:
1811+
* - NO_CERTS defined: the certificate fall-back branch is compiled out.
1812+
* - certificates compiled in but none loaded: ssl->buffers.certificate is
1813+
* NULL, so the same branch is taken at runtime.
1814+
* It uses the cert-less memio harness so it builds and runs in either
1815+
* configuration. */
1816+
int test_tls13_psk_no_cert_bad_binder(void)
1817+
{
1818+
EXPECT_DECLS;
1819+
#if defined(WOLFSSL_TLS13) && \
1820+
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_NO_CERTS) && \
1821+
!defined(NO_PSK) && defined(NO_CERTS)
1822+
WOLFSSL_CTX *ctx_c = NULL;
1823+
WOLFSSL_CTX *ctx_s = NULL;
1824+
WOLFSSL *ssl_c = NULL;
1825+
WOLFSSL *ssl_s = NULL;
1826+
struct test_memio_ctx test_ctx;
1827+
WOLFSSL_ALERT_HISTORY h;
1828+
1829+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
1830+
1831+
/* Don't use test_memio_setup(): it loads a default server certificate,
1832+
* which would let the server fall back to a certificate handshake. Build
1833+
* the contexts by hand so the server has no certificate loaded. */
1834+
ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
1835+
ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
1836+
if (ctx_c != NULL) {
1837+
wolfSSL_SetIORecv(ctx_c, test_memio_read_cb);
1838+
wolfSSL_SetIOSend(ctx_c, test_memio_write_cb);
1839+
}
1840+
if (ctx_s != NULL) {
1841+
wolfSSL_SetIORecv(ctx_s, test_memio_read_cb);
1842+
wolfSSL_SetIOSend(ctx_s, test_memio_write_cb);
1843+
}
1844+
1845+
ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
1846+
ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
1847+
if (ssl_c != NULL) {
1848+
wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
1849+
wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
1850+
}
1851+
if (ssl_s != NULL) {
1852+
wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
1853+
wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
1854+
}
1855+
1856+
wolfSSL_set_psk_client_callback(ssl_c, test_tls13_psk_no_cert_client_cb);
1857+
wolfSSL_set_psk_server_callback(ssl_s, test_tls13_psk_no_cert_server_cb);
1858+
1859+
/* Confirm the precondition: the server really has no certificate. */
1860+
#ifndef NO_CERTS
1861+
if (ssl_s != NULL) {
1862+
ExpectNull(ssl_s->buffers.certificate);
1863+
}
1864+
#endif
1865+
1866+
/* Client sends ClientHello (with PSK) and waits for the response. */
1867+
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
1868+
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
1869+
WOLFSSL_ERROR_WANT_READ);
1870+
1871+
/* Server processes ClientHello: no PSK matches and no certificate is
1872+
* available, so it must abort with BAD_BINDER. */
1873+
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
1874+
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
1875+
WC_NO_ERR_TRACE(BAD_BINDER));
1876+
1877+
/* Client reads the server's alert: BAD_BINDER maps to a fatal
1878+
* illegal_parameter alert (see TranslateErrorToAlert). */
1879+
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
1880+
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
1881+
WC_NO_ERR_TRACE(FATAL_ERROR));
1882+
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
1883+
ExpectIntEQ(h.last_rx.code, illegal_parameter);
1884+
ExpectIntEQ(h.last_rx.level, alert_fatal);
1885+
1886+
wolfSSL_free(ssl_c);
1887+
wolfSSL_CTX_free(ctx_c);
1888+
wolfSSL_free(ssl_s);
1889+
wolfSSL_CTX_free(ctx_s);
1890+
#endif
1891+
return EXPECT_RESULT();
1892+
}
1893+
1894+
17781895
#if defined(HAVE_RPK) && !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) && \
17791896
!defined(NO_WOLFSSL_SERVER)
17801897

tests/api/test_tls13.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ int test_tls13_hrr_bad_cookie(void);
6161
int test_tls13_zero_inner_content_type(void);
6262
int test_tls13_downgrade_sentinel(void);
6363
int test_tls13_serverhello_bad_cipher_suites(void);
64+
int test_tls13_psk_no_cert_bad_binder(void);
6465
int test_tls13_cert_with_extern_psk_apis(void);
6566
int test_tls13_cert_with_extern_psk_handshake(void);
6667
int test_tls13_cert_with_extern_psk_requires_key_share(void);
@@ -113,6 +114,7 @@ int test_tls13_cipher_fuzz_aes128_ccm_8_sha256(void);
113114
TEST_DECL_GROUP("tls13", test_tls13_zero_inner_content_type), \
114115
TEST_DECL_GROUP("tls13", test_tls13_downgrade_sentinel), \
115116
TEST_DECL_GROUP("tls13", test_tls13_serverhello_bad_cipher_suites), \
117+
TEST_DECL_GROUP("tls13", test_tls13_psk_no_cert_bad_binder), \
116118
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_apis), \
117119
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_handshake), \
118120
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_requires_key_share), \

tests/utils.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#include <tests/utils.h>
2424
#include <wolfssl/wolfcrypt/error-crypt.h>
2525

26-
#ifdef HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES
26+
#ifdef HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD
2727

2828
/* This set of memio functions allows for more fine tuned control of the TLS
2929
* connection operations. For new tests, try to use ssl_memio first. */
@@ -784,7 +784,7 @@ int test_memio_setup(struct test_memio_ctx *ctx,
784784
method_s, NULL, 0, NULL, 0, NULL, 0);
785785
}
786786

787-
#endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES */
787+
#endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD */
788788

789789
#if !defined(NO_FILESYSTEM) && defined(OPENSSL_EXTRA) && \
790790
defined(DEBUG_UNIT_TEST_CERTS)

tests/utils.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,24 @@ extern char tmpDirName[16];
3232
extern const char* currentTestName;
3333
#endif
3434

35-
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
36-
(!defined(NO_RSA) || defined(HAVE_RPK)) && \
37-
!defined(NO_WOLFSSL_SERVER) && !defined(NO_WOLFSSL_CLIENT) && \
35+
/* Base dependencies for the manual memio test harness. The harness itself does
36+
* not require certificate support, so cert-less tests (e.g. PSK-only) can use
37+
* it through this narrower macro. */
38+
#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_WOLFSSL_CLIENT) && \
3839
(!defined(WOLFSSL_NO_TLS12) || defined(WOLFSSL_TLS13))
40+
#define HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_NO_CERTS
41+
#define HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD
42+
#endif
43+
44+
/* Full dependencies: the base harness plus certificate support. Most memio
45+
* tests set up a certificate-based handshake and must use this macro. */
46+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_NO_CERTS) && \
47+
!defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
48+
(!defined(NO_RSA) || defined(HAVE_RPK))
3949
#define HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES
50+
#endif
51+
52+
#ifdef HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD
4053
#define TEST_MEMIO_BUF_SZ (64 * 1024)
4154
#define TEST_MEMIO_MAX_MSGS 32
4255

@@ -85,7 +98,7 @@ int test_memio_move_message(struct test_memio_ctx *ctx, int client,
8598
int test_memio_drop_message(struct test_memio_ctx *ctx, int client, int msg_pos);
8699
int test_memio_modify_message_len(struct test_memio_ctx *ctx, int client, int msg_pos, int new_len);
87100
int test_memio_remove_from_buffer(struct test_memio_ctx *ctx, int client, int off, int sz);
88-
#endif
101+
#endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD */
89102

90103
#if !defined(NO_FILESYSTEM) && defined(OPENSSL_EXTRA) && \
91104
defined(DEBUG_UNIT_TEST_CERTS)

0 commit comments

Comments
 (0)