104104 * WOLFSSL_TLS13_NO_PEEK_HANDSHAKE_DONE:
105105 * Disable peek returning WANT_READ for tickets default: off
106106 * WOLFSSL_TLS13_IGNORE_AEAD_LIMITS:
107- * Ignore AEAD message limits from RFC 8446 default: off
107+ * Ignore AEAD message limits from RFC 9846 5.5, which
108+ * makes observing them a MUST default: off
108109 * WOLFSSL_DTLS13_SEND_MOREACK_DEFAULT:
109110 * Send more ACKs by default in DTLS 1.3 default: off
110111 *
@@ -23994,10 +23995,41 @@ static void LogAlert(int type)
2399423995#endif /* DEBUG_WOLFSSL */
2399523996}
2399623997
23998+ /* RFC 9846 Section 6.1 exempts "user_canceled" from tearing the connection
23999+ * down whatever AlertLevel the peer used, because the level byte carries no
24000+ * meaning in TLS 1.3.
24001+ *
24002+ * The exemption needs a connection that is demonstrably running TLS 1.3, and
24003+ * neither obvious flag is enough on its own. ssl->version holds the highest
24004+ * version this side offered until the peer's choice is known, and
24005+ * options.tls1_3 is set from the session by wolfSSL_set_session() before any
24006+ * ServerHello, so a downgrade-capable client resuming a TLS 1.3 session has
24007+ * both set while the peer may still pick TLS 1.2. Exempting on either would
24008+ * swallow a pre-1.3 peer's fatal alert and leave the caller waiting for a
24009+ * handshake that is never coming.
24010+ *
24011+ * Requiring the record to have been decrypted settles it: in TLS 1.3 every
24012+ * record after the ServerHello is encrypted, so a decrypted alert can only
24013+ * have arrived on a connection whose version is already agreed - which is the
24014+ * only situation RFC 9846 Section 6.1 is describing. keys.decryptedCur is a
24015+ * property of the record in hand, not a latch: GetRecordHeader() clears it for
24016+ * each new record and only a successful decrypt sets it, so an earlier
24017+ * encrypted record cannot lend its status to a later plaintext alert.
24018+ *
24019+ * ssl The SSL/TLS object.
24020+ * code Alert description received.
24021+ * returns 1 when the alert must be ignored rather than acted on.
24022+ */
24023+ static int AlertIsExemptUserCanceled(const WOLFSSL* ssl, int code)
24024+ {
24025+ return ssl->options.tls1_3 && ssl->keys.decryptedCur &&
24026+ (code == user_canceled);
24027+ }
24028+
2399724029/* process alert, return level */
2399824030#ifndef NO_SESSION_CACHE
2399924031/* RFC 5246 Section 7.2.2: a TLS 1.2 session whose connection is terminated by a
24000- * fatal alert MUST be invalidated so it cannot be resumed. (TLS 1.3 RFC 8446
24032+ * fatal alert MUST be invalidated so it cannot be resumed. (TLS 1.3 RFC 9846
2400124033 * Section 6.2 only requires closing the connection, but evicting here too is
2400224034 * sound defense-in-depth.) Evict the cached session (which also drops any
2400324035 * associated ticket). Acts on an established connection or an in-progress
@@ -24011,7 +24043,7 @@ static void InvalidateSessionOnFatalAlert(WOLFSSL* ssl)
2401124043 return;
2401224044 /* Don't evict on an unauthenticated record: a TLS 1.3 plaintext alert
2401324045 * received under encryption (current record not decrypted) is rejected (or
24014- * ignored) by DoAlert, and the teardown alert routes back here. RFC 8446
24046+ * ignored) by DoAlert, and the teardown alert routes back here. RFC 9846
2401524047 * 6.2 doesn't require TLS 1.3 eviction; TLS 1.2 alerts are plaintext so are
2401624048 * unaffected. */
2401724049 if (IsAtLeastTLSv1_3(ssl->version) && IsEncryptionOn(ssl, 0) &&
@@ -24075,10 +24107,16 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type)
2407524107 {
2407624108 ssl->alert_history.last_rx.code = code;
2407724109 ssl->alert_history.last_rx.level = level;
24078- if (level == alert_fatal) {
24110+ /* RFC 9846 Section 6.1: "user_canceled" only "generally" has
24111+ * AlertLevel=warning, and a receiver SHOULD keep reading until
24112+ * "close_notify" arrives. The level byte is meaningless in TLS 1.3,
24113+ * so do not let a peer that sends the alert at fatal level tear the
24114+ * connection down. */
24115+ if (level == alert_fatal &&
24116+ !AlertIsExemptUserCanceled(ssl, code)) {
2407924117 ssl->options.isClosed = 1; /* Don't send close_notify */
2408024118 }
24081- /* RFC 8446 Section 6.2: In TLS 1.3, all error alerts are implicitly
24119+ /* RFC 9846 Section 6.2: In TLS 1.3, all error alerts are implicitly
2408224120 * fatal regardless of the AlertLevel byte. */
2408324121 if (IsAtLeastTLSv1_3(ssl->version) &&
2408424122 code != close_notify && code != user_canceled) {
@@ -24130,12 +24168,17 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type)
2413024168 }
2413124169#ifndef NO_SESSION_CACHE
2413224170 /* Validated fatal alert: invalidate the session so it can't be resumed
24133- * (RFC 5246 7.2.2; in TLS 1.3 all error alerts are fatal, RFC 8446
24134- * 6.2). */
24135- if (*type != close_notify &&
24136- (level == alert_fatal ||
24137- (IsAtLeastTLSv1_3(ssl->version) && *type != user_canceled)))
24171+ * (RFC 5246 7.2.2; in TLS 1.3 all error alerts are fatal, RFC 9846
24172+ * 6.2). "close_notify" is not an error, and "user_canceled" is exempt
24173+ * in TLS 1.3 at any AlertLevel (RFC 9846 6.1). */
24174+ if (IsAtLeastTLSv1_3(ssl->version)) {
24175+ if (*type != close_notify &&
24176+ !AlertIsExemptUserCanceled(ssl, *type))
24177+ InvalidateSessionOnFatalAlert(ssl);
24178+ }
24179+ else if (level == alert_fatal && *type != close_notify) {
2413824180 InvalidateSessionOnFatalAlert(ssl);
24181+ }
2413924182#endif
2414024183 }
2414124184 return level;
@@ -24985,7 +25028,9 @@ static int DoProcessAlertRecord(WOLFSSL* ssl)
2498525028 WOLFSSL_MSG("got ALERT!");
2498625029 ret = DoAlert(ssl, ssl->buffers.inputBuffer.buffer,
2498725030 &ssl->buffers.inputBuffer.idx, &type);
24988- if (ret == alert_fatal)
25031+ /* RFC 9846 Section 6.1: keep reading past a TLS 1.3 "user_canceled" until
25032+ * "close_notify" arrives, whatever AlertLevel the peer used. */
25033+ if (ret == alert_fatal && !AlertIsExemptUserCanceled(ssl, type))
2498925034 return FATAL_ERROR;
2499025035 else if (ret < 0)
2499125036 return ret;
@@ -25001,7 +25046,7 @@ static int DoProcessAlertRecord(WOLFSSL* ssl)
2500125046 if (type == decrypt_error)
2500225047 return FATAL_ERROR;
2500325048
25004- /* RFC 8446 Section 6.2: In TLS 1.3, all error alerts MUST
25049+ /* RFC 9846 Section 6.2: In TLS 1.3, all error alerts MUST
2500525050 * be treated as fatal regardless of the AlertLevel byte.
2500625051 * Only close_notify (handled above) and user_canceled
2500725052 * are exempt. */
@@ -28634,7 +28679,7 @@ int IsSCR(WOLFSSL* ssl)
2863428679 !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS)
2863528680/*
2863628681 * Enforce limits specified in
28637- * https://www.rfc-editor.org/rfc/rfc8446 #section-5.5
28682+ * https://www.rfc-editor.org/rfc/rfc9846 #section-5.5
2863828683 */
2863928684static int CheckTLS13AEADSendLimit(WOLFSSL* ssl)
2864028685{
@@ -28701,6 +28746,44 @@ static int CheckTLS13AEADSendLimit(WOLFSSL* ssl)
2870128746 ssl->keys.sequence_number_lo);
2870228747 }
2870328748
28749+ #ifdef WOLFSSL_EARLY_DATA
28750+ /* RFC 9846 Section 5.5: a KeyUpdate cannot be performed for early data, so
28751+ * a sender MUST NOT exceed the limits while sending it. There is no way to
28752+ * rekey here - the handshake has not finished, so a KeyUpdate would be out
28753+ * of order - and the write has to fail instead.
28754+ *
28755+ * Stop one record early. If the server accepts the early data the client
28756+ * still owes it an EndOfEarlyData, and Section 2.3 has that message go out
28757+ * under the same 0-RTT traffic keys. Spending the last record on
28758+ * application data would leave that message to overrun the limit.
28759+ *
28760+ * seq is the number the next record will use, so it also counts the
28761+ * records already sent under this key. Refusing once seq + 1 reaches the
28762+ * limit stops application data at seq == limit - 2 and keeps the final
28763+ * slot, seq == limit - 1, free for the EndOfEarlyData. */
28764+ if (ssl->options.side == WOLFSSL_CLIENT_END &&
28765+ ssl->earlyData != no_early_data &&
28766+ ssl->earlyData != done_early_data) {
28767+ w64wrapper afterThis = seq;
28768+
28769+ w64Increment(&afterThis);
28770+ /* cppcheck-suppress uninitvar
28771+ * (false positive from cppcheck-2.13.0: every switch arm above either
28772+ * sets limit or returns) */
28773+ if (w64GTE(afterThis, limit)) {
28774+ WOLFSSL_MSG("AEAD limit reached while sending early data");
28775+ /* Deliberately not recorded here. The caller decides whether this
28776+ * is an error: a write whose last record took the final slot has
28777+ * completed and returns success, and recording it now would leave
28778+ * TOO_MUCH_EARLY_DATA in the OpenSSL-compatibility error queue for
28779+ * a call that reported no failure. SendData() records it on the
28780+ * path that does fail. */
28781+ return TOO_MUCH_EARLY_DATA;
28782+ }
28783+ return 0;
28784+ }
28785+ #endif
28786+
2870428787 if (w64GTE(seq, limit)) { /* cppcheck-suppress uninitvar
2870528788 * (false positive from cppcheck-2.13.0)
2870628789 */
@@ -28966,6 +29049,27 @@ int SendData(WOLFSSL* ssl, const void* data, size_t sz)
2896629049#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS)
2896729050 if (IsAtLeastTLSv1_3(ssl->version)) {
2896829051 ret = CheckTLS13AEADSendLimit(ssl);
29052+ #ifdef WOLFSSL_EARLY_DATA
29053+ /* This check runs at the top of every iteration, including the
29054+ * one after the last record, so it also fires when the write is
29055+ * already complete and its final record happened to reach the
29056+ * limit. Nothing is left to send, so report the success: without
29057+ * this the caller would see WOLFSSL_FATAL_ERROR for a write that
29058+ * fully landed.
29059+ *
29060+ * A write stopped part way through is a failure, not a short
29061+ * return. Short returns here are gated on partialWrite, and
29062+ * wolfSSL_get_error(ssl, ret) reports nothing for a positive ret,
29063+ * so a short count would be indistinguishable from a complete one
29064+ * to a caller following the documented contract. */
29065+ if (ret == WC_NO_ERR_TRACE(TOO_MUCH_EARLY_DATA)) {
29066+ if (sent == (word32)sz) {
29067+ break;
29068+ }
29069+ /* Failing for real, so now it is worth recording. */
29070+ WOLFSSL_ERROR_VERBOSE(ret);
29071+ }
29072+ #endif
2896929073 if (ret != 0) {
2897029074 ssl->error = ret;
2897129075 return WOLFSSL_FATAL_ERROR;
@@ -38414,7 +38518,14 @@ const byte* MaskCurve25519PeerKey(const byte* pub, word32 pubSz,
3841438518 int TranslateErrorToAlert(int err)
3841538519 {
3841638520 switch (err) {
38521+ /* RFC 9846 Section 4.3 requires a "decode_error" alert when an
38522+ * extension has data left over after its structure is parsed, and
38523+ * Section 6.2 defines the alert for any field out of range or
38524+ * message of incorrect length. The extension parsers report those
38525+ * as either BUFFER_ERROR or the wolfCrypt BUFFER_E; both must map
38526+ * here, or the handshake aborts silently with no alert sent. */
3841738527 case WC_NO_ERR_TRACE(BUFFER_ERROR):
38528+ case WC_NO_ERR_TRACE(BUFFER_E):
3841838529 return decode_error;
3841938530 case WC_NO_ERR_TRACE(EXT_NOT_ALLOWED):
3842038531 case WC_NO_ERR_TRACE(PEER_KEY_ERROR):
0 commit comments