Merge pull request #10442 from JeremiahM37/zd21783

Fix SAKKE OOB write and correctness gap in sakke_hash_to_range
This commit is contained in:
Sean Parkinson
2026-05-14 19:51:52 +10:00
committed by GitHub
2 changed files with 105 additions and 16 deletions
+38 -16
View File
@@ -6169,20 +6169,28 @@ static int sakke_calc_h_v(SakkeKey* key, enum wc_HashType hashType,
static void sakke_xor_in_v(const byte* v, word32 hashSz, byte* out, word32 idx,
word32 n)
{
int o;
word32 i;
word32 skip;
word32 off;
word32 len;
/* RFC 6508, Section 5.1: output is the low n octets of
* v_1||v_2||...||v_l (the concatenation of l hash outputs taken
* modulo 2^(n*8)). When n is not a multiple of hashSz, drop the
* leading 'skip' high bytes of the first hash output. */
skip = n % hashSz;
skip = (skip == 0) ? 0 : (hashSz - skip);
if (idx == 0) {
i = hashSz - (n % hashSz);
if (i == hashSz) {
i = 0;
}
xorbuf(out, v + skip, hashSz - skip);
}
else {
i = 0;
off = idx - skip;
len = n - off;
if (len > hashSz) {
len = hashSz;
}
xorbuf(out + off, v, len);
}
o = (int)i;
xorbuf(out + idx + i - o, v + i, hashSz - i);
}
/*
@@ -6689,8 +6697,9 @@ static int sakke_compute_point_r(SakkeKey* key, const byte* id, word16 idSz,
* @param [out] auth Authentication data.
* @param [out] authSz Size of authentication data in bytes.
* @return 0 on success.
* @return BAD_FUNC_ARG when key, ssv or encSz is NULL, ssvSz is to big or
* encSz is too small.
* @return BAD_FUNC_ARG when key, ssv or authSz is NULL, ssvSz is 0 or
* larger than the curve modulus byte length, or *authSz is too
* small when encapsulating.
* @return BAD_STATE_E when identity not set.
* @return LENGTH_ONLY_E when auth is NULL. authSz contains required size of
* auth in bytes.
@@ -6706,7 +6715,7 @@ int wc_MakeSakkeEncapsulatedSSV(SakkeKey* key, enum wc_HashType hashType,
word16 outSz = 0;
byte a[WC_MAX_DIGEST_SIZE];
if ((key == NULL) || (ssv == NULL) || (authSz == NULL)) {
if ((key == NULL) || (ssv == NULL) || (authSz == NULL) || (ssvSz == 0)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (key->idSz == 0)) {
@@ -6725,7 +6734,14 @@ int wc_MakeSakkeEncapsulatedSSV(SakkeKey* key, enum wc_HashType hashType,
/* Uncompressed point */
outSz = (word16)(1 + 2 * n);
if ((auth != NULL) && (*authSz < outSz)) {
/* RFC 6508, Section 6.2.1, Step 1 places SSV in 0..2^n-1, so
* ssvSz must be <= n. Enforced on both the encapsulation and
* size-query paths so callers cannot probe authSz with an
* invalid ssvSz. */
if (ssvSz > n) {
err = BAD_FUNC_ARG;
}
else if ((auth != NULL) && (*authSz < outSz)) {
err = BAD_FUNC_ARG;
}
}
@@ -6820,7 +6836,7 @@ int wc_GenerateSakkeSSV(SakkeKey* key, WC_RNG* rng, byte* ssv, word16* ssvSz)
if (err == 0) {
n = (word16)WC_BITS_TO_BYTES(mp_count_bits(&key->params.prime));
if ((ssv != NULL) && (*ssvSz > n)) {
if ((ssv != NULL) && ((*ssvSz == 0) || (*ssvSz > n))) {
err = BAD_FUNC_ARG;
}
}
@@ -6864,7 +6880,8 @@ int wc_GenerateSakkeSSV(SakkeKey* key, WC_RNG* rng, byte* ssv, word16* ssvSz)
* @param [in] auth Authentication data.
* @param [in] authSz Size of authentication data in bytes.
* @return 0 on success.
* @return BAD_FUNC_ARG when key, ssv or auth is NULL.
* @return BAD_FUNC_ARG when key, ssv or auth is NULL, ssvSz is 0 or
* larger than the curve modulus byte length.
* @return BAD_STATE_E when RSK or identity not set.
* @return SAKKE_VERIFY_FAIL_E when calculated R doesn't match the encapsulated
* data's R.
@@ -6883,7 +6900,7 @@ int wc_DeriveSakkeSSV(SakkeKey* key, enum wc_HashType hashType, byte* ssv,
byte* test = NULL;
byte a[WC_MAX_DIGEST_SIZE] = {0};
if ((key == NULL) || (ssv == NULL) || (auth == NULL)) {
if ((key == NULL) || (ssv == NULL) || (auth == NULL) || (ssvSz == 0)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (!key->rsk.set || (key->idSz == 0))) {
@@ -6902,6 +6919,11 @@ int wc_DeriveSakkeSSV(SakkeKey* key, enum wc_HashType hashType, byte* ssv,
if (authSz != 2 * n + 1) {
err = BAD_FUNC_ARG;
}
/* RFC 6508, Section 6.2.1: SSV is in 0..2^n-1, so ssvSz must
* be <= n. */
else if (ssvSz > n) {
err = BAD_FUNC_ARG;
}
}
if (err == 0) {
err = sakke_load_base_point(key);
+67
View File
@@ -61310,6 +61310,73 @@ static wc_test_ret_t sakke_op_test(SakkeKey* priv, SakkeKey* pub, WC_RNG* rng,
authSz);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
{
/* All three SSV entry points reject ssvSz=0 and ssvSz>n. */
word16 zeroSz = 0;
word16 hugeSz = 0xFFFF;
ret = wc_GenerateSakkeSSV(pub, rng, ssv, &zeroSz);
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
zeroSz = 0;
ret = wc_MakeSakkeEncapsulatedSSV(pub, WC_HASH_TYPE_SHA256, ssv, zeroSz,
auth, &authSz);
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
ret = wc_DeriveSakkeSSV(priv, WC_HASH_TYPE_SHA256, ssv, zeroSz, auth,
authSz);
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
ret = wc_GenerateSakkeSSV(pub, rng, ssv, &hugeSz);
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
hugeSz = 0xFFFF;
ret = wc_MakeSakkeEncapsulatedSSV(pub, WC_HASH_TYPE_SHA256, ssv, hugeSz,
auth, &authSz);
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
ret = wc_DeriveSakkeSSV(priv, WC_HASH_TYPE_SHA256, ssv, hugeSz, auth,
authSz);
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
}
{
/* Round-trip encap/derive across ssvSz shapes that exercise the
* multi-iteration paths in sakke_xor_in_v. SHA-256 hashSz=32:
* 48: 2 iterations, partial first block.
* 72: 3 iterations, exercises the len-clamp on the middle iter.
* 64: 2 iterations, exact-multiple (skip==0). */
static const word16 extSzs[3] = { 48, 72, 64 };
byte ssvExt[72];
byte ssvRef[72];
word16 extAuthSz;
int i;
for (i = 0; i < 3; i++) {
word16 extSz = extSzs[i];
ret = wc_RNG_GenerateBlock(rng, ssvRef, extSz);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
XMEMCPY(ssvExt, ssvRef, extSz);
extAuthSz = 257;
ret = wc_MakeSakkeEncapsulatedSSV(pub, WC_HASH_TYPE_SHA256, ssvExt,
extSz, auth, &extAuthSz);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
ret = wc_DeriveSakkeSSV(priv, WC_HASH_TYPE_SHA256, ssvExt, extSz,
auth, extAuthSz);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
if (XMEMCMP(ssvExt, ssvRef, extSz) != 0)
return WC_TEST_RET_ENC_NC;
}
}
return 0;
}