Skip to content

wolfCrypt and TLS 1.3 correctness fixes (F-1376, F-2653, F-1972, F-4593)#10930

Open
julek-wolfssl wants to merge 4 commits into
wolfSSL:masterfrom
julek-wolfssl:fenrir-wolfcrypt-tls-fixes
Open

wolfCrypt and TLS 1.3 correctness fixes (F-1376, F-2653, F-1972, F-4593)#10930
julek-wolfssl wants to merge 4 commits into
wolfSSL:masterfrom
julek-wolfssl:fenrir-wolfcrypt-tls-fixes

Conversation

@julek-wolfssl

Copy link
Copy Markdown
Member

Four independent fixes in wolfCrypt and the TLS 1.3 handshake. Each is self-contained and reviewable on its own commit.

wc_AesCbcEncryptWithKey: validate NULL parameters (F-1376)

The function did not check out/in/key/iv for NULL before calling wc_AesSetKey/wc_AesCbcEncrypt, unlike its counterpart wc_AesCbcDecryptWithKey. A NULL key reaches wc_AesSetKey implementations that XMEMCPY userKey without a NULL guard (e.g. the STM32 path), crashing at the API boundary instead of returning BAD_FUNC_ARG.

Adds the same guard wc_AesCbcDecryptWithKey already uses.

ChaCha20 EVP: fix counter reconstruction shift UB (F-2653)

wolfSSL_EVP_CipherInit rebuilt the 32-bit ChaCha20 counter with (word32)(iv[1] << 8) and friends. The cast applies after the shift, so each unsigned char promotes to int and shifts as a signed value: on 16-bit int platforms iv[1] << 8 is signed-overflow UB and iv[2] << 16/iv[3] << 24 are UB unconditionally (shift >= int width). Even with 32-bit int, iv[3] << 24 with the high bit set is signed overflow.

Casts each byte to word32 before shifting, and uses | rather than + to compose the bytes.

PrintPubKeyDH: fix strict-aliasing violation in length (F-1972)

length was declared word32 but passed as (int*)&length to GetSequence/GetLength, which write through an int*. Where sizeof(int) != sizeof(word32) this updates only part of the object and leaves stale bytes behind.

Declares length as int to match the callee out-parameter type and drops the casts. The values are non-negative ASN.1 lengths, already consumed via (int) casts and pointer arithmetic.

TLS 1.3: send unexpected_message on a duplicate handshake message (F-4593)

When a TLS 1.3 client received a second HelloRetryRequest, DoTls13ServerHello returned DUPLICATE_MSG_E without sending an alert: TranslateErrorToAlert had no mapping for it, so it returned invalid_alert and the dispatch tail skipped SendAlert. The connection aborted silently rather than with the alert RFC 8446 mandates.

Maps DUPLICATE_MSG_E to unexpected_message alongside OUT_OF_ORDER_E, mirroring the sanity-check path and covering any TLS 1.3 handler that returns DUPLICATE_MSG_E to the dispatch loop.


No regression tests here: three of the four only misbehave on platforms where sizeof(int) != sizeof(word32) or int is 16-bit, and the fourth needs a server that replies with a second HelloRetryRequest. Happy to add a unit test for the alert path if reviewers want one.

wc_AesCbcEncryptWithKey did not check out/in/key/iv for NULL before calling
wc_AesSetKey/wc_AesCbcEncrypt, unlike its counterpart wc_AesCbcDecryptWithKey.
A NULL key can reach wc_AesSetKey implementations that XMEMCPY userKey without
a NULL guard (e.g. the STM32 path), causing a crash at the API boundary.

Add the same NULL guard wc_AesCbcDecryptWithKey uses.
wolfSSL_EVP_CipherInit reconstructed the 32-bit ChaCha20 counter with
(word32)(iv[1] << 8) etc., which promotes the unsigned char to int and shifts
before the cast. On 16-bit int platforms iv[1] << 8 is signed-overflow UB and
iv[2] << 16 / iv[3] << 24 are UB unconditionally (shift >= int width). Even on
32-bit int, iv[3] << 24 with the high bit set is signed-overflow UB.

Cast each byte to word32 before shifting so the computation is well-defined.
PrintPubKeyDH declared length as word32 but passed (int*)&length to
GetSequence/GetLength, which write through an int*. On platforms where
sizeof(int) != sizeof(word32) this updates only part of the variable, leaving
stale bytes. Declare length as int (matching the callee out-parameter type)
and drop the (int*) casts; the values are non-negative ASN.1 lengths already
used via (int) casts and pointer arithmetic.
…593)

When a TLS 1.3 client received a second HelloRetryRequest, DoTls13ServerHello
returned DUPLICATE_MSG_E without sending an alert. TranslateErrorToAlert had no
mapping for DUPLICATE_MSG_E, so it returned invalid_alert and the dispatch
tail skipped SendAlert - the connection aborted silently instead of with the
RFC 8446-mandated unexpected_message alert.

Map DUPLICATE_MSG_E to unexpected_message in TranslateErrorToAlert, alongside
OUT_OF_ORDER_E. This mirrors the sanity-check path and covers any TLS 1.3
handler that returns DUPLICATE_MSG_E to the dispatch loop.
Copilot AI review requested due to automatic review settings July 16, 2026 13:23
@julek-wolfssl julek-wolfssl self-assigned this Jul 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR applies four small correctness fixes across wolfCrypt helpers and the TLS 1.3 alert mapping, primarily improving API robustness and standards-compliant error signaling.

Changes:

  • Add NULL-parameter validation to wc_AesCbcEncryptWithKey() to return BAD_FUNC_ARG instead of crashing in lower layers.
  • Fix ChaCha20 EVP counter reconstruction to avoid shift undefined behavior on 16-bit-int (and signed overflow cases) by casting before shifting and composing with |.
  • Fix PrintPubKeyDH() ASN.1 length parsing by using an int length variable to match GetSequence()/GetLength() out-parameter types.
  • Map DUPLICATE_MSG_E to the TLS unexpected_message alert so the TLS 1.3 stack sends an appropriate alert for duplicate handshake messages.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
wolfcrypt/src/wc_encrypt.c Adds NULL argument checks to AES-CBC encrypt-with-key helper to match decrypt counterpart behavior.
wolfcrypt/src/evp.c Fixes ChaCha20 counter byte reconstruction and corrects DH public key parsing length type to avoid aliasing/size issues.
src/internal.c Updates TranslateErrorToAlert() to map DUPLICATE_MSG_E to unexpected_message for proper TLS alerting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@julek-wolfssl
julek-wolfssl marked this pull request as ready for review July 16, 2026 14:29
@github-actions

Copy link
Copy Markdown

retest this please

@github-actions

Copy link
Copy Markdown

MemBrowse Memory Report

gcc-arm-cortex-m3

  • FLASH: .text +8 B (+0.0%, 122,513 B / 262,144 B, total: 47% used)

gcc-arm-cortex-m4-crypto-only

  • FLASH: .text +64 B (+0.0%, 174,632 B / 262,144 B, total: 67% used)

gcc-arm-cortex-m4-pkcs7

  • FLASH: .text +64 B (+0.0%, 212,780 B / 262,144 B, total: 81% used)

gcc-arm-cortex-m4-rsa-only

  • FLASH: .text +64 B (+0.0%, 325,184 B / 1,048,576 B, total: 31% used)

gcc-arm-cortex-m7

  • FLASH: .text +64 B (+0.0%, 200,384 B / 262,144 B, total: 76% used)

gcc-arm-cortex-m7-tls13

@julek-wolfssl

Copy link
Copy Markdown
Member Author

retest this please

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants