@@ -1775,6 +1775,162 @@ int test_tls13_bad_psk_binder(void)
17751775}
17761776
17771777
1778+ #if defined(WOLFSSL_TLS13 ) && \
1779+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD ) && \
1780+ !defined(NO_PSK )
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 configurations:
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 runtime check takes the same abort path.
1814+ * The contexts are built by hand (no certificate loaded) so the test exercises
1815+ * whichever branch the build provides.
1816+ * When certificates are compiled in, a second connection sets a certificate
1817+ * and key against the server context and verifies the opposite branch: the
1818+ * non-matching PSK is ignored and the handshake falls back to a full
1819+ * certificate handshake instead of aborting. */
1820+ int test_tls13_psk_no_cert_bad_binder (void )
1821+ {
1822+ EXPECT_DECLS ;
1823+ #if defined(WOLFSSL_TLS13 ) && \
1824+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD ) && \
1825+ !defined(NO_PSK )
1826+ WOLFSSL_CTX * ctx_c = NULL ;
1827+ WOLFSSL_CTX * ctx_s = NULL ;
1828+ WOLFSSL * ssl_c = NULL ;
1829+ WOLFSSL * ssl_s = NULL ;
1830+ struct test_memio_ctx test_ctx ;
1831+ WOLFSSL_ALERT_HISTORY h ;
1832+
1833+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
1834+
1835+ /* Don't use test_memio_setup(): it loads a default server certificate,
1836+ * which would let the server fall back to a certificate handshake. Build
1837+ * the contexts by hand so the server has no certificate loaded. */
1838+ ExpectNotNull (ctx_c = wolfSSL_CTX_new (wolfTLSv1_3_client_method ()));
1839+ ExpectNotNull (ctx_s = wolfSSL_CTX_new (wolfTLSv1_3_server_method ()));
1840+ if (ctx_c != NULL ) {
1841+ wolfSSL_SetIORecv (ctx_c , test_memio_read_cb );
1842+ wolfSSL_SetIOSend (ctx_c , test_memio_write_cb );
1843+ }
1844+ if (ctx_s != NULL ) {
1845+ wolfSSL_SetIORecv (ctx_s , test_memio_read_cb );
1846+ wolfSSL_SetIOSend (ctx_s , test_memio_write_cb );
1847+ }
1848+
1849+ /* Set the PSK callbacks on the contexts, not the SSL objects: with
1850+ * certificates compiled in, creating a server-side SSL object without a
1851+ * certificate and key fails (NO_PRIVATE_KEY) unless ctx->havePSK is
1852+ * already set when wolfSSL_new() is called. */
1853+ wolfSSL_CTX_set_psk_client_callback (ctx_c ,
1854+ test_tls13_psk_no_cert_client_cb );
1855+ wolfSSL_CTX_set_psk_server_callback (ctx_s ,
1856+ test_tls13_psk_no_cert_server_cb );
1857+
1858+ ExpectNotNull (ssl_c = wolfSSL_new (ctx_c ));
1859+ ExpectNotNull (ssl_s = wolfSSL_new (ctx_s ));
1860+ if (ssl_c != NULL ) {
1861+ wolfSSL_SetIOWriteCtx (ssl_c , & test_ctx );
1862+ wolfSSL_SetIOReadCtx (ssl_c , & test_ctx );
1863+ }
1864+ if (ssl_s != NULL ) {
1865+ wolfSSL_SetIOWriteCtx (ssl_s , & test_ctx );
1866+ wolfSSL_SetIOReadCtx (ssl_s , & test_ctx );
1867+ }
1868+
1869+ /* Confirm the precondition: the server really has no certificate. */
1870+ #ifndef NO_CERTS
1871+ if (ssl_s != NULL ) {
1872+ ExpectNull (ssl_s -> buffers .certificate );
1873+ }
1874+ #endif
1875+
1876+ /* Client sends ClientHello (with PSK) and waits for the response. */
1877+ ExpectIntNE (wolfSSL_connect (ssl_c ), WOLFSSL_SUCCESS );
1878+ ExpectIntEQ (wolfSSL_get_error (ssl_c , WC_NO_ERR_TRACE (WOLFSSL_FATAL_ERROR )),
1879+ WOLFSSL_ERROR_WANT_READ );
1880+
1881+ /* Server processes ClientHello: no PSK matches and no certificate is
1882+ * available, so it must abort with BAD_BINDER. */
1883+ ExpectIntNE (wolfSSL_accept (ssl_s ), WOLFSSL_SUCCESS );
1884+ ExpectIntEQ (wolfSSL_get_error (ssl_s , WC_NO_ERR_TRACE (WOLFSSL_FATAL_ERROR )),
1885+ WC_NO_ERR_TRACE (BAD_BINDER ));
1886+
1887+ /* Client reads the server's alert: BAD_BINDER maps to a fatal
1888+ * illegal_parameter alert (see TranslateErrorToAlert). */
1889+ ExpectIntNE (wolfSSL_connect (ssl_c ), WOLFSSL_SUCCESS );
1890+ ExpectIntEQ (wolfSSL_get_error (ssl_c , WC_NO_ERR_TRACE (WOLFSSL_FATAL_ERROR )),
1891+ WC_NO_ERR_TRACE (FATAL_ERROR ));
1892+ ExpectIntEQ (wolfSSL_get_alert_history (ssl_c , & h ), WOLFSSL_SUCCESS );
1893+ ExpectIntEQ (h .last_rx .code , illegal_parameter );
1894+ ExpectIntEQ (h .last_rx .level , alert_fatal );
1895+
1896+ wolfSSL_free (ssl_c );
1897+ ssl_c = NULL ;
1898+ wolfSSL_CTX_free (ctx_c );
1899+ ctx_c = NULL ;
1900+ wolfSSL_free (ssl_s );
1901+ ssl_s = NULL ;
1902+ wolfSSL_CTX_free (ctx_s );
1903+ ctx_s = NULL ;
1904+
1905+ #ifndef NO_CERTS
1906+ /* Conversely, with a certificate and key set against the server context,
1907+ * a non-matching PSK must not leak the mismatch: the server ignores the
1908+ * PSK and falls back to a full certificate handshake. test_memio_setup()
1909+ * loads the default CA, server certificate and key. */
1910+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
1911+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
1912+ wolfTLSv1_3_client_method , wolfTLSv1_3_server_method ), 0 );
1913+
1914+ wolfSSL_set_psk_client_callback (ssl_c , test_tls13_psk_no_cert_client_cb );
1915+ wolfSSL_set_psk_server_callback (ssl_s , test_tls13_psk_no_cert_server_cb );
1916+
1917+ /* Confirm the precondition: the server has a certificate this time. */
1918+ if (ssl_s != NULL ) {
1919+ ExpectNotNull (ssl_s -> buffers .certificate );
1920+ }
1921+
1922+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
1923+
1924+ wolfSSL_free (ssl_c );
1925+ wolfSSL_CTX_free (ctx_c );
1926+ wolfSSL_free (ssl_s );
1927+ wolfSSL_CTX_free (ctx_s );
1928+ #endif /* !NO_CERTS */
1929+ #endif
1930+ return EXPECT_RESULT ();
1931+ }
1932+
1933+
17781934#if defined(HAVE_RPK ) && !defined(NO_TLS ) && !defined(NO_WOLFSSL_CLIENT ) && \
17791935 !defined(NO_WOLFSSL_SERVER )
17801936
0 commit comments