Skip to content

Commit 7134114

Browse files
committed
Fix stack buffer overflow in wc_HpkeLabeledExtract via oversized ECH config
SetEchConfigsEx accepted arbitrarily large ECH configs without bounds checking rawLen. This allowed attacker-controlled data (from DNS HTTPS records or TLS retry_configs) to overflow the fixed 512-byte labeled_ikm stack buffer in wc_HpkeLabeledExtract during ClientHello construction. Add MAX_ECH_CONFIG_RAW_SZ to reject oversized configs at parse time, and add bounds checks in both wc_HpkeLabeledExtract and wc_HpkeLabeledExpand before writing into their fixed-size buffers. Fixes ZD#21309
1 parent b3f08f3 commit 7134114

4 files changed

Lines changed: 35 additions & 0 deletions

File tree

src/ssl_ech.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,13 @@ int SetEchConfigsEx(WOLFSSL_EchConfig** outputConfigs, void* heap,
570570
/* rawLen */
571571
workingConfig->rawLen = length + 4;
572572

573+
/* Reject configs whose raw encoding would overflow the fixed-size
574+
* labeled_ikm buffer in wc_HpkeLabeledExtract */
575+
if (workingConfig->rawLen > MAX_ECH_CONFIG_RAW_SZ) {
576+
ret = BUFFER_E;
577+
break;
578+
}
579+
573580
/* raw body */
574581
workingConfig->raw = (byte*)XMALLOC(workingConfig->rawLen,
575582
heap, DYNAMIC_TYPE_TMP_BUFFER);

src/tls.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9986,6 +9986,10 @@ static int TLSX_KeyShare_ProcessPqcHybridClient(WOLFSSL* ssl,
99869986
ssl->arrays->preMasterSz = ssSzEcc + ssSzPqc;
99879987
}
99889988

9989+
if (ret != 0) {
9990+
ForceZero(ssl->arrays->preMasterSecret, ENCRYPT_LEN);
9991+
}
9992+
99899993
TLSX_KeyShare_FreeAll(ecc_kse, ssl->heap);
99909994
TLSX_KeyShare_FreeAll(pqc_kse, ssl->heap);
99919995

wolfcrypt/src/hpke.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,13 @@ static int wc_HpkeLabeledExtract(Hpke* hpke, byte* suite_id,
473473
WC_ALLOC_VAR_EX(labeled_ikm, byte, MAX_HPKE_LABEL_SZ, hpke->heap,
474474
DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
475475

476+
/* validate total size fits in the labeled_ikm buffer */
477+
if (HPKE_VERSION_STR_LEN + suite_id_len + label_len + ikm_len
478+
> MAX_HPKE_LABEL_SZ) {
479+
WC_FREE_VAR_EX(labeled_ikm, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER);
480+
return BUFFER_E;
481+
}
482+
476483
/* concat the labeled_ikm */
477484
/* version */
478485
XMEMCPY(labeled_ikm, HPKE_VERSION_STR, HPKE_VERSION_STR_LEN);
@@ -520,6 +527,14 @@ static int wc_HpkeLabeledExpand(Hpke* hpke, byte* suite_id, word32 suite_id_len,
520527
WC_ALLOC_VAR_EX(labeled_info, byte, MAX_HPKE_LABEL_SZ, hpke->heap,
521528
DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
522529

530+
/* validate total size fits in the labeled_info buffer
531+
* total = I2OSP length prefix + version + suite_id + label + info */
532+
if (HPKE_I2OSP_LEN_SZ + HPKE_VERSION_STR_LEN + suite_id_len + label_len
533+
+ infoSz > MAX_HPKE_LABEL_SZ) {
534+
WC_FREE_VAR_EX(labeled_info, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER);
535+
return BUFFER_E;
536+
}
537+
523538
/* copy length */
524539
ret = I2OSP((int)L, 2, labeled_info);
525540
labeled_info_p = labeled_info + 2;

wolfssl/wolfcrypt/hpke.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ extern const int hpkeSupportedAead[HPKE_SUPPORTED_AEAD_LEN];
8686
#define MAX_HPKE_LABEL_SZ 512
8787
#endif
8888

89+
/* I2OSP encoded length prefix size in LabeledExpand (RFC 9180 Section 4) */
90+
#define HPKE_I2OSP_LEN_SZ 2
91+
92+
/* Maximum raw ECH config length accepted by SetEchConfigsEx. The raw config
93+
* is concatenated into a MAX_HPKE_LABEL_SZ buffer in wc_HpkeLabeledExtract
94+
* along with version (7) + suite_id (HPKE_SUITE_ID_LEN) + label (~12) +
95+
* TLS info prefix (8) overhead. */
96+
#define MAX_ECH_CONFIG_RAW_SZ (MAX_HPKE_LABEL_SZ - 50)
97+
8998
typedef struct {
9099
void* heap;
91100
word32 kem;

0 commit comments

Comments
 (0)