Skip to content

Commit b10a8cf

Browse files
committed
RFC 8446 6.2 / RFC 5246 7.2.2 - no writes after fatal alert
1 parent 9a19265 commit b10a8cf

4 files changed

Lines changed: 65 additions & 0 deletions

File tree

src/internal.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16005,6 +16005,7 @@ void DoCertFatalAlert(WOLFSSL* ssl, int ret)
1600516005
(void)alertWhy;
1600616006
#endif
1600716007
ssl->options.isClosed = 1;
16008+
ssl->options.sentOrRcvdFatalAlert = 1;
1600816009
}
1600916010

1601016011
int SetupStoreCtxCallback(WOLFSSL_X509_STORE_CTX** store_pt,
@@ -24115,12 +24116,14 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type)
2411524116
if (level == alert_fatal &&
2411624117
!AlertIsExemptUserCanceled(ssl, code)) {
2411724118
ssl->options.isClosed = 1; /* Don't send close_notify */
24119+
ssl->options.sentOrRcvdFatalAlert = 1;
2411824120
}
2411924121
/* RFC 9846 Section 6.2: In TLS 1.3, all error alerts are implicitly
2412024122
* fatal regardless of the AlertLevel byte. */
2412124123
if (IsAtLeastTLSv1_3(ssl->version) &&
2412224124
code != close_notify && code != user_canceled) {
2412324125
ssl->options.isClosed = 1;
24126+
ssl->options.sentOrRcvdFatalAlert = 1;
2412424127
}
2412524128
}
2412624129

@@ -29020,6 +29023,13 @@ int SendData(WOLFSSL* ssl, const void* data, size_t sz)
2902029023
return WOLFSSL_FATAL_ERROR;
2902129024
}
2902229025

29026+
/* after fatal alert, no more data writes (RFC 8446 section 6.2) */
29027+
if (ssl->options.sentOrRcvdFatalAlert) {
29028+
WOLFSSL_MSG("fatal alert already sent/received, no more writes");
29029+
ssl->error = SOCKET_PEER_CLOSED_E;
29030+
return WOLFSSL_FATAL_ERROR;
29031+
}
29032+
2902329033
#ifdef WOLFSSL_THREADED_CRYPT
2902429034
ret = SendAsyncData(ssl);
2902529035
if (ret != 0) {
@@ -29591,7 +29601,10 @@ static int SendAlert_ex(WOLFSSL* ssl, int severity, int type)
2959129601
/* Mark as closed in dtls only once we enter stateful mode. */
2959229602
if (!ssl->options.dtls || ssl->options.dtlsStateful)
2959329603
#endif
29604+
{
2959429605
ssl->options.isClosed = 1; /* Don't send close_notify */
29606+
ssl->options.sentOrRcvdFatalAlert = 1;
29607+
}
2959529608
}
2959629609

2959729610
/* send encrypted alert if encryption is on - can be a rehandshake over

tests/api/test_ssl_rw.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,55 @@ int test_wolfSSL_SendUserCanceled_paths(void)
10621062
return EXPECT_RESULT();
10631063
}
10641064

1065+
/* Test that a fatal alert closure stops later application writes.
1066+
*
1067+
* RFC 8446 section 6.2 / RFC 5246 7.2.2: Once a fatal alert has been sent or
1068+
* received, no further application data may be sent. This is flagged by
1069+
* sentOrRcvdFatalAlert. Subsequent writes should fail to queue.
1070+
*
1071+
* @return TEST_SUCCESS on success.
1072+
*/
1073+
int test_wolfSSL_write_after_fatal_alert(void)
1074+
{
1075+
EXPECT_DECLS;
1076+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(NO_TLS) && \
1077+
!defined(WOLFSSL_NO_TLS12)
1078+
WOLFSSL_CTX* ctx_c = NULL;
1079+
WOLFSSL_CTX* ctx_s = NULL;
1080+
WOLFSSL* ssl_c = NULL;
1081+
WOLFSSL* ssl_s = NULL;
1082+
struct test_memio_ctx test_ctx;
1083+
const char msg[] = "must not be sent";
1084+
1085+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
1086+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
1087+
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
1088+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
1089+
1090+
/* A fatal alert was sent (or received); no close_notify follows a fatal
1091+
* alert. */
1092+
if (ssl_c != NULL) {
1093+
ssl_c->options.isClosed = 1;
1094+
ssl_c->options.sentOrRcvdFatalAlert = 1;
1095+
ssl_c->error = WOLFSSL_ERROR_NONE;
1096+
1097+
ExpectIntEQ(wolfSSL_write(ssl_c, msg, (int)sizeof(msg)),
1098+
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
1099+
/* Check the recorded error rather than the value reported, which
1100+
* wolfSSL_get_error() translates for OpenSSL compatibility. */
1101+
ExpectIntEQ(ssl_c->error, WC_NO_ERR_TRACE(SOCKET_PEER_CLOSED_E));
1102+
/* No record was queued for the peer. */
1103+
ExpectIntEQ(ssl_c->buffers.outputBuffer.length, 0);
1104+
}
1105+
1106+
wolfSSL_free(ssl_c);
1107+
wolfSSL_free(ssl_s);
1108+
wolfSSL_CTX_free(ctx_c);
1109+
wolfSSL_CTX_free(ctx_s);
1110+
#endif
1111+
return EXPECT_RESULT();
1112+
}
1113+
10651114
/* Test that an error the read side recorded is the one the write reports.
10661115
*
10671116
* With a write duplicate in use the read side hands errors over through

tests/api/test_ssl_rw.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ int test_wolfSSL_shutdown_repeat_after_done(void);
3838
int test_wolfSSL_shutdown_flush_no_notify(void);
3939
int test_wolfSSL_shutdown_quic_alert_refused(void);
4040
int test_wolfSSL_SendUserCanceled_paths(void);
41+
int test_wolfSSL_write_after_fatal_alert(void);
4142
int test_wolfSSL_write_dup_err(void);
4243

4344
#define TEST_SSL_RW_DECLS \
@@ -56,6 +57,7 @@ int test_wolfSSL_write_dup_err(void);
5657
TEST_DECL_GROUP("ssl_rw", test_wolfSSL_shutdown_flush_no_notify), \
5758
TEST_DECL_GROUP("ssl_rw", test_wolfSSL_shutdown_quic_alert_refused), \
5859
TEST_DECL_GROUP("ssl_rw", test_wolfSSL_SendUserCanceled_paths), \
60+
TEST_DECL_GROUP("ssl_rw", test_wolfSSL_write_after_fatal_alert), \
5961
TEST_DECL_GROUP("ssl_rw", test_wolfSSL_write_dup_err)
6062

6163
#endif /* TESTS_API_SSL_RW_H */

wolfssl/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5461,6 +5461,7 @@ struct Options {
54615461
word16 isClosed:1; /* if we consider conn closed */
54625462
word16 closeNotify:1; /* we've received a close notify */
54635463
word16 sentNotify:1; /* we've sent a close notify */
5464+
word16 sentOrRcvdFatalAlert:1; /* a fatal alert occurred */
54645465
word16 usingCompression:1; /* are we using compression */
54655466
word16 haveRSA:1; /* RSA available */
54665467
word16 haveECC:1; /* ECC available */

0 commit comments

Comments
 (0)