Skip to content

Commit 5e76c66

Browse files
committed
F-5818: don't invalidate the session on an unauthenticated alert
DoAlert evicted the cached session from the fatal-alert handling that runs before the plaintext-under-encryption validation, so a forged TLS 1.3 plaintext alert injected on an established connection evicted the session (forcing a full handshake on reconnect) even though the alert is then rejected as PARSE_ERROR. The unexpected_message teardown sent in response also evicted through the SendAlert hook. Move the receive-side eviction past the validation, into the branch that processes a genuine alert, and have InvalidateSessionOnFatalAlert refuse to evict for a TLS 1.3 plaintext alert received while encryption is on (the current record was not decrypted) - covering both the receive path and the unexpected_message teardown sent in response. RFC 8446 6.2 does not require TLS 1.3 invalidation, so this loses nothing; TLS 1.2 (RFC 5246 7.2.2) is unaffected.
1 parent 2352d73 commit 5e76c66

1 file changed

Lines changed: 17 additions & 9 deletions

File tree

src/internal.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22527,6 +22527,14 @@ static void InvalidateSessionOnFatalAlert(WOLFSSL* ssl)
2252722527
return;
2252822528
if (!ssl->options.handShakeDone && !ssl->options.resuming)
2252922529
return;
22530+
/* Don't evict on an unauthenticated record: a TLS 1.3 plaintext alert
22531+
* received under encryption (current record not decrypted) is rejected (or
22532+
* ignored) by DoAlert, and the teardown alert routes back here. RFC 8446
22533+
* 6.2 doesn't require TLS 1.3 eviction; TLS 1.2 alerts are plaintext so are
22534+
* unaffected. */
22535+
if (IsAtLeastTLSv1_3(ssl->version) && IsEncryptionOn(ssl, 0) &&
22536+
!ssl->keys.decryptedCur)
22537+
return;
2253022538
(void)wolfSSL_SSL_CTX_remove_session(ssl->ctx, ssl->session);
2253122539
}
2253222540
#endif /* !NO_SESSION_CACHE */
@@ -22593,15 +22601,6 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type)
2259322601
code != close_notify && code != user_canceled) {
2259422602
ssl->options.isClosed = 1;
2259522603
}
22596-
#ifndef NO_SESSION_CACHE
22597-
/* A fatal alert immediately terminates the connection; invalidate the
22598-
* session so it cannot be used to establish new connections. In TLS 1.3
22599-
* all error alerts are implicitly fatal (RFC 8446 6.2). */
22600-
if (code != close_notify &&
22601-
(level == alert_fatal ||
22602-
(IsAtLeastTLSv1_3(ssl->version) && code != user_canceled)))
22603-
InvalidateSessionOnFatalAlert(ssl);
22604-
#endif
2260522604
}
2260622605

2260722606
if (++ssl->options.alertCount >= WOLFSSL_ALERT_COUNT_MAX) {
@@ -22646,6 +22645,15 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type)
2264622645
*/
2264722646
WOLFSSL_ERROR(*type);
2264822647
}
22648+
#ifndef NO_SESSION_CACHE
22649+
/* Validated fatal alert: invalidate the session so it can't be resumed
22650+
* (RFC 5246 7.2.2; in TLS 1.3 all error alerts are fatal, RFC 8446
22651+
* 6.2). */
22652+
if (*type != close_notify &&
22653+
(level == alert_fatal ||
22654+
(IsAtLeastTLSv1_3(ssl->version) && *type != user_canceled)))
22655+
InvalidateSessionOnFatalAlert(ssl);
22656+
#endif
2264922657
}
2265022658
return level;
2265122659
}

0 commit comments

Comments
 (0)