Merge pull request #10445 from embhorn/zd21742

Fix in ECC point conversion
This commit is contained in:
Sean Parkinson
2026-05-13 16:09:02 +10:00
committed by GitHub
2 changed files with 97 additions and 4 deletions
+24 -4
View File
@@ -1356,9 +1356,19 @@ WOLFSSL_EC_POINT* wolfSSL_EC_POINT_hex2point(const WOLFSSL_EC_GROUP *group,
}
key_sz = (wolfSSL_EC_GROUP_get_degree(group) + 7) / 8;
if (key_sz <= 0 || (size_t)key_sz > MAX_ECC_BYTES)
goto err;
if (hex[0] == '0' && hex[1] == '4') { /* uncompressed mode */
str_sz = (size_t)key_sz * 2;
/* The uncompressed encoding is exactly 2 + 4*key_sz hex chars
* ("04" prefix plus X and Y as 2*key_sz hex chars each). Reject
* any other length so XMEMCPY/BN_hex2bn cannot read past the end
* of the input and trailing garbage is not silently absorbed. */
if (XSTRLEN(hex + 2) != str_sz * 2)
goto err;
XMEMSET(strGx, 0x0, str_sz + 1);
XMEMCPY(strGx, hex + 2, str_sz);
@@ -1377,10 +1387,20 @@ WOLFSSL_EC_POINT* wolfSSL_EC_POINT_hex2point(const WOLFSSL_EC_GROUP *group,
}
}
else if (hex[0] == '0' && (hex[1] == '2' || hex[1] == '3')) {
size_t sz = XSTRLEN(hex + 2) / 2;
/* compressed mode */
octGx[0] = ECC_POINT_COMP_ODD;
if (hex_to_bytes(hex + 2, octGx + 1, sz) != sz) {
/* The SEC 1 compressed encoding is exactly 1 + key_sz bytes, so
* the hex payload after the "02"/"03" prefix must be exactly
* 2*key_sz hex chars. Compare the input length directly (rather
* than XSTRLEN/2) so that odd-length inputs cannot slip past via
* integer truncation. The exact-match rejects oversized inputs
* (preventing a hex_to_bytes() write past strGx) and undersized
* inputs (preventing wolfSSL_ECPoint_d2i() from reading
* uninitialized stack bytes as the X coordinate). */
if (XSTRLEN(hex + 2) != (size_t)key_sz * 2)
goto err;
octGx[0] = (hex[1] == '2') ? ECC_POINT_COMP_EVEN
: ECC_POINT_COMP_ODD;
if (hex_to_bytes(hex + 2, octGx + 1, (size_t)key_sz)
!= (size_t)key_sz) {
goto err;
}
if (wolfSSL_ECPoint_d2i(octGx, (word32)key_sz + 1, group, p)
+73
View File
@@ -631,6 +631,79 @@ int test_wolfSSL_EC_POINT(void)
#endif
XFREE(hexStr, NULL, DYNAMIC_TYPE_ECC);
EC_POINT_free(get_point);
get_point = NULL;
/* Regression: oversized compressed-point hex must not overflow the stack
* buffer in wolfSSL_EC_POINT_hex2point(). The byte length decoded from
* the hex string must be bounded by the curve's ordinate size. */
{
char tooLongHex[2 + 600 + 1];
size_t i;
tooLongHex[0] = '0';
tooLongHex[1] = '3';
for (i = 2; i < sizeof(tooLongHex) - 1; i++)
tooLongHex[i] = 'A';
tooLongHex[sizeof(tooLongHex) - 1] = '\0';
ExpectNull(EC_POINT_hex2point(group, tooLongHex, NULL, ctx));
/* Same with the "02" (even Y) prefix. */
tooLongHex[1] = '2';
ExpectNull(EC_POINT_hex2point(group, tooLongHex, NULL, ctx));
/* Truncated uncompressed input: prefix "04" with too few hex chars
* to cover the curve's coordinates. Must return NULL without
* reading past the end of the input string. */
ExpectNull(EC_POINT_hex2point(group, "04AB", NULL, ctx));
/* Empty payload after a recognized prefix. */
ExpectNull(EC_POINT_hex2point(group, "03", NULL, ctx));
ExpectNull(EC_POINT_hex2point(group, "04", NULL, ctx));
/* Partially populated compressed input: must be rejected so that
* wolfSSL_ECPoint_d2i() does not consume uninitialized stack
* bytes as the X coordinate. */
ExpectNull(EC_POINT_hex2point(group, "03AB", NULL, ctx));
ExpectNull(EC_POINT_hex2point(group, "02ABCD", NULL, ctx));
/* Odd-length compressed payload: 2*key_sz + 1 hex chars after
* the "03" prefix (P-256: 65 chars). A truncating-divide bound
* (sz = XSTRLEN/2) would round down to key_sz and accept this;
* an exact-length compare must reject it. */
{
char oddLenHex[2 + 65 + 1];
for (i = 2; i < sizeof(oddLenHex) - 1; i++)
oddLenHex[i] = 'A';
oddLenHex[0] = '0';
oddLenHex[1] = '3';
oddLenHex[sizeof(oddLenHex) - 1] = '\0';
ExpectNull(EC_POINT_hex2point(group, oddLenHex, NULL, ctx));
}
}
#if defined(HAVE_COMP_KEY) && !defined(HAVE_SELFTEST)
/* Round-trip a compressed point with even Y ("02" prefix) to verify
* that the prefix-to-parity flag is honored in the compressed branch. */
{
EC_POINT* even_point = NULL;
EC_POINT* round_trip = NULL;
char* even_hex = NULL;
ExpectNotNull(even_point = EC_POINT_dup(Gxy, group));
ExpectIntEQ(EC_POINT_invert(group, even_point, ctx), 1);
ExpectNotNull(even_hex = EC_POINT_point2hex(group, even_point,
POINT_CONVERSION_COMPRESSED, ctx));
/* P-256 G has odd Y; inverting flips Y parity so prefix is "02". */
ExpectIntEQ(even_hex[1], '2');
ExpectNotNull(round_trip = EC_POINT_hex2point(group, even_hex, NULL,
ctx));
ExpectIntEQ(EC_POINT_cmp(group, even_point, round_trip, ctx), 0);
XFREE(even_hex, NULL, DYNAMIC_TYPE_ECC);
EC_POINT_free(round_trip);
EC_POINT_free(even_point);
}
#endif
#ifndef HAVE_SELFTEST
/* Test point to oct */