F-5813: fail TLS 1.2 record send before the sequence number wraps

GetSEQIncrement silently rolled the 64-bit write sequence counter from 2^64-1
back to 0, reusing sequence number 0 with the same keys. Per RFC 5246 Section
6.1 sequence numbers MUST NOT wrap. BuildMessage now refuses to emit a TLS 1.2
record once the write sequence number has reached its maximum, returning the
new SEQUENCE_NUMBER_E error so the caller renegotiates or closes instead.
This commit is contained in:
Juliusz Sosinowicz
2026-06-03 00:27:25 +02:00
parent a3a2609b18
commit 0ec0db9357
2 changed files with 19 additions and 1 deletions
+16
View File
@@ -24662,6 +24662,19 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input,
#endif
#ifndef WOLFSSL_NO_TLS12
/* RFC 5246 6.1: record sequence numbers MUST NOT wrap. Refuse to emit a
* record once the write sequence number has reached its maximum value
* (2^64-1); reusing sequence number 0 with the same keys would break the
* record protection. The caller must renegotiate or close the connection
* instead. DTLS sequence numbers are epoch-scoped and handled elsewhere. */
if (!sizeOnly && !ssl->options.dtls &&
ssl->keys.sequence_number_hi == 0xFFFFFFFFU &&
ssl->keys.sequence_number_lo == 0xFFFFFFFFU) {
WOLFSSL_MSG("TLS write sequence number would wrap");
WOLFSSL_ERROR_VERBOSE(SEQUENCE_NUMBER_E);
return SEQUENCE_NUMBER_E;
}
#ifdef WOLFSSL_ASYNC_CRYPT
ret = WC_NO_PENDING_E;
if (asyncOkay) {
@@ -28108,6 +28121,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e)
case ECH_REQUIRED_E:
return "ECH offered but rejected by server";
case SEQUENCE_NUMBER_E:
return "Record sequence number would wrap";
}
return "unknown error number";
+3 -1
View File
@@ -244,7 +244,9 @@ enum wolfSSL_ErrorCodes {
ECH_REQUIRED_E = -519, /* ECH offered but rejected by server */
WOLFSSL_LAST_E = -519
SEQUENCE_NUMBER_E = -520, /* Record sequence number would wrap */
WOLFSSL_LAST_E = -520
/* codes -1000 to -1999 are reserved for wolfCrypt. */
};