From cea9fd792fa2eb4b62059837637c6940933290e4 Mon Sep 17 00:00:00 2001 From: Mark Atwood Date: Mon, 16 Mar 2026 11:13:29 -0700 Subject: [PATCH 1/2] ecc: reject compressed points with incorrect length wc_ecc_import_point_der_ex accepted a single byte 0x02 or 0x03 as a valid compressed EC point, treating the missing X coordinate bytes as zeros. This could allow ECDH with a crafted peer public key. Add length validation: compressed points must be exactly 1 + field_element_size bytes. Reject anything shorter or longer. Co-Authored-By: Claude Opus 4.6 (1M context) --- wolfcrypt/src/ecc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 1376cff2a03..c938538c684 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -9470,6 +9470,10 @@ int wc_ecc_import_point_der_ex(const byte* in, word32 inLen, if (pointType == ECC_POINT_COMP_EVEN || pointType == ECC_POINT_COMP_ODD) { #ifdef HAVE_COMP_KEY compressed = 1; + /* compressed points must be exactly 1 + field_element_size bytes */ + if (inLen != 1 + (word32)ecc_sets[curve_idx].size) { + err = ECC_BAD_ARG_E; + } #else err = NOT_COMPILED_IN; #endif From cedc3c8eb608bb853315b9fb0347a80eca64b7c0 Mon Sep 17 00:00:00 2001 From: Mark Atwood Date: Mon, 16 Mar 2026 11:16:16 -0700 Subject: [PATCH 2/2] ecc: fix double-free in wc_ecc_import_point_der_ex on invalid format byte wc_ecc_import_point_der_ex crashed (double-free/SIGABRT) when given a full-length EC point blob with an invalid first byte (0x01, 0x05, 0xFF, etc.). The function fell through to code paths that partially initialized state, then the cleanup path freed already-freed memory. Add early validation of the format byte and fix cleanup paths to prevent double-free on error. Co-Authored-By: Claude Opus 4.6 (1M context) --- wolfcrypt/src/ecc.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index c938538c684..f68cd26feea 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -9439,6 +9439,14 @@ int wc_ecc_import_point_der_ex(const byte* in, word32 inLen, return ECC_BAD_ARG_E; } + /* validate point format byte before any memory operations */ + pointType = in[0]; + if (pointType != ECC_POINT_UNCOMP && + pointType != ECC_POINT_COMP_EVEN && + pointType != ECC_POINT_COMP_ODD) { + return ASN_PARSE_E; + } + /* clear if previously allocated */ mp_clear(point->x); mp_clear(point->y); @@ -9460,13 +9468,7 @@ int wc_ecc_import_point_der_ex(const byte* in, word32 inLen, SAVE_VECTOR_REGISTERS(return _svr_ret;); - /* check for point type (4, 2, or 3) */ - pointType = in[0]; - if (pointType != ECC_POINT_UNCOMP && pointType != ECC_POINT_COMP_EVEN && - pointType != ECC_POINT_COMP_ODD) { - err = ASN_PARSE_E; - } - + /* pointType already validated above; check for compressed format */ if (pointType == ECC_POINT_COMP_EVEN || pointType == ECC_POINT_COMP_ODD) { #ifdef HAVE_COMP_KEY compressed = 1;