Skip to content

Commit c84f7d8

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 c84f7d8

5 files changed

Lines changed: 138 additions & 16 deletions

File tree

src/tls13.c

Lines changed: 2 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,15 @@ 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) {
65336531
ret = 0;
65346532
goto cleanup;
65356533
}
65366534
#endif
65376535
WOLFSSL_ERROR_VERBOSE(BAD_BINDER);
65386536
ret = BAD_BINDER;
65396537
goto cleanup;
6540-
#else
6541-
ret = 0;
6542-
goto cleanup;
6543-
#endif
65446538
}
65456539

65466540
*first = (current == ext->data);
@@ -6817,14 +6811,12 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
68176811
TLSX_Remove(&ssl->extensions, TLSX_CERT_WITH_EXTERN_PSK, ssl->heap);
68186812
ssl->options.certWithExternPsk = 0;
68196813
#endif
6820-
#ifdef WOLFSSL_PSK_ID_PROTECTION
68216814
#ifndef NO_CERTS
6822-
if (ssl->buffers.certChainCnt != 0)
6815+
if (ssl->buffers.certificate != NULL)
68236816
return 0;
68246817
#endif
68256818
WOLFSSL_ERROR_VERBOSE(BAD_BINDER);
68266819
return BAD_BINDER;
6827-
#endif
68286820
}
68296821

68306822
WOLFSSL_LEAVE("CheckPreSharedKeys", ret);

tests/api/test_tls13.c

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

17771777

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

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)