diff --git a/configure.ac b/configure.ac index 03c16b05b..91868887d 100644 --- a/configure.ac +++ b/configure.ac @@ -195,6 +195,7 @@ then else AC_MSG_ERROR([Invalid value for --enable-harden-tls]) fi + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_EXTRA_ALERTS -DWOLFSSL_CHECK_ALERT_ON_ERR" fi # Support for forcing 32-bit mode diff --git a/src/internal.c b/src/internal.c index 8bca1bbd3..5e30694b4 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7127,11 +7127,13 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) } #endif -#ifdef HAVE_SECURE_RENEGOTIATION +#if defined(HAVE_SECURE_RENEGOTIATION) || \ + defined(HAVE_SERVER_RENEGOTIATION_INFO) if (ssl->options.side == WOLFSSL_CLIENT_END) { int useSecureReneg = ssl->ctx->useSecureReneg; /* use secure renegotiation by default (not recommend) */ - #ifdef WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT + #if defined(WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT) || \ + (defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_NO_TLS12)) useSecureReneg = 1; #endif if (useSecureReneg) { @@ -26988,6 +26990,18 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType, } #endif +#ifdef WOLFSSL_HARDEN_TLS + if (ssl->secure_renegotiation == NULL || + !ssl->secure_renegotiation->enabled) { + /* If the server does not acknowledge the extension, the client + * MUST generate a fatal handshake_failure alert prior to + * terminating the connection. + * https://www.rfc-editor.org/rfc/rfc9325#name-renegotiation-in-tls-12 */ + WOLFSSL_MSG("ServerHello did not contain SCR extension"); + return SECURE_RENEGOTIATION_E; + } +#endif + ssl->options.serverState = SERVER_HELLO_COMPLETE; if (IsEncryptionOn(ssl, 0)) { diff --git a/src/ssl.c b/src/ssl.c index 57a3b48d2..73c391893 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -13959,6 +13959,9 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, case ACCEPT_FIRST_REPLY_DONE : if ( (ssl->error = SendServerHello(ssl)) != 0) { + #ifdef WOLFSSL_CHECK_ALERT_ON_ERR + ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ + #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } @@ -13975,6 +13978,9 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #ifndef NO_CERTS if (!ssl->options.resuming) if ( (ssl->error = SendCertificate(ssl)) != 0) { + #ifdef WOLFSSL_CHECK_ALERT_ON_ERR + ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ + #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } @@ -13987,6 +13993,9 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #ifndef NO_CERTS if (!ssl->options.resuming) if ( (ssl->error = SendCertificateStatus(ssl)) != 0) { + #ifdef WOLFSSL_CHECK_ALERT_ON_ERR + ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ + #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } @@ -14003,6 +14012,9 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #endif if (!ssl->options.resuming) if ( (ssl->error = SendServerKeyExchange(ssl)) != 0) { + #ifdef WOLFSSL_CHECK_ALERT_ON_ERR + ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ + #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } @@ -14015,6 +14027,9 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, if (!ssl->options.resuming) { if (ssl->options.verifyPeer) { if ( (ssl->error = SendCertificateRequest(ssl)) != 0) { + #ifdef WOLFSSL_CHECK_ALERT_ON_ERR + ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ + #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } @@ -14032,6 +14047,9 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, case CERT_REQ_SENT : if (!ssl->options.resuming) if ( (ssl->error = SendServerHelloDone(ssl)) != 0) { + #ifdef WOLFSSL_CHECK_ALERT_ON_ERR + ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ + #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } @@ -14070,6 +14088,9 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #ifdef HAVE_SESSION_TICKET if (ssl->options.createTicket && !ssl->options.noTicketTls12) { if ( (ssl->error = SendTicket(ssl)) != 0) { + #ifdef WOLFSSL_CHECK_ALERT_ON_ERR + ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ + #endif WOLFSSL_MSG("Thought we need ticket but failed"); WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; @@ -14088,6 +14109,9 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, } if ( (ssl->error = SendChangeCipher(ssl)) != 0) { + #ifdef WOLFSSL_CHECK_ALERT_ON_ERR + ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ + #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } @@ -14097,6 +14121,9 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, case CHANGE_CIPHER_SENT : if ( (ssl->error = SendFinished(ssl)) != 0) { + #ifdef WOLFSSL_CHECK_ALERT_ON_ERR + ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ + #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } diff --git a/tests/api.c b/tests/api.c index f29e35983..40f197a09 100644 --- a/tests/api.c +++ b/tests/api.c @@ -63519,6 +63519,77 @@ static int test_extra_alerts_bad_psk(void) return TEST_SKIPPED; } #endif + +#if defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_NO_TLS12) && \ + defined(HAVE_IO_TESTS_DEPENDENCIES) +static int test_harden_no_secure_renegotiation_io_cb(WOLFSSL *ssl, char *buf, + int sz, void *ctx) +{ + static int sentServerHello = FALSE; + + if (!sentServerHello) { + byte renegExt[] = { 0xFF, 0x01, 0x00, 0x01, 0x00 }; + size_t i; + + if (sz < (int)sizeof(renegExt)) + return WOLFSSL_CBIO_ERR_GENERAL; + + /* Remove SCR from ServerHello */ + for (i = 0; i < sz - sizeof(renegExt); i++) { + if (XMEMCMP(buf + i, renegExt, sizeof(renegExt)) == 0) { + /* Found the extension. Change it to something unrecognized. */ + buf[i+1] = 0x11; + break; + } + } + sentServerHello = TRUE; + } + + return EmbedSend(ssl, buf, sz, ctx); +} + +static void test_harden_no_secure_renegotiation_ssl_ready(WOLFSSL* ssl) +{ + wolfSSL_SSLSetIOSend(ssl, test_harden_no_secure_renegotiation_io_cb); +} + +static void test_harden_no_secure_renegotiation_on_cleanup(WOLFSSL* ssl) +{ + WOLFSSL_ALERT_HISTORY h; + AssertIntEQ(wolfSSL_get_alert_history(ssl, &h), WOLFSSL_SUCCESS); + AssertIntEQ(h.last_rx.code, handshake_failure); + AssertIntEQ(h.last_rx.level, alert_fatal); +} + +static int test_harden_no_secure_renegotiation(void) +{ + callback_functions client_cbs, server_cbs; + + XMEMSET(&client_cbs, 0, sizeof(client_cbs)); + XMEMSET(&server_cbs, 0, sizeof(server_cbs)); + + client_cbs.method = wolfTLSv1_2_client_method; + server_cbs.method = wolfTLSv1_2_server_method; + + server_cbs.ssl_ready = test_harden_no_secure_renegotiation_ssl_ready; + server_cbs.on_cleanup = test_harden_no_secure_renegotiation_on_cleanup; + test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs); + + AssertIntEQ(client_cbs.return_code, TEST_FAIL); + AssertIntEQ(client_cbs.last_err, SECURE_RENEGOTIATION_E); + AssertIntEQ(server_cbs.return_code, TEST_FAIL); + AssertIntEQ(server_cbs.last_err, SOCKET_ERROR_E); + + return TEST_RES_CHECK(1); +} +#else +static int test_harden_no_secure_renegotiation(void) +{ + return TEST_SKIPPED; +} +#endif + + /*----------------------------------------------------------------------------* | Main *----------------------------------------------------------------------------*/ @@ -64539,6 +64610,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_extra_alerts_wrong_cs), TEST_DECL(test_extra_alerts_skip_hs), TEST_DECL(test_extra_alerts_bad_psk), + TEST_DECL(test_harden_no_secure_renegotiation), /* If at some point a stub get implemented this test should fail indicating * a need to implement a new test case */ diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index cf9e01bbb..9156bad71 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -2995,6 +2995,13 @@ extern void uITRON4_free(void *p) ; #ifndef NO_OLD_TLS #error "TLS < 1.2 protocol versions not allowed https://www.rfc-editor.org/rfc/rfc9325#section-3.1.1" #endif + #if !defined(WOLFSSL_NO_TLS12) && !defined(HAVE_SECURE_RENEGOTIATION) && \ + !defined(HAVE_SERVER_RENEGOTIATION_INFO) + #error "TLS 1.2 requires at least HAVE_SERVER_RENEGOTIATION_INFO to send the secure renegotiation extension https://www.rfc-editor.org/rfc/rfc9325#section-3.5" + #endif + #if !defined(WOLFSSL_EXTRA_ALERTS) || !defined(WOLFSSL_CHECK_ALERT_ON_ERR) + #error "RFC9325 requires some additional alerts to be sent" + #endif /* Ciphersuite check done in internal.h */ #endif