Skip to content

Commit 7bcc613

Browse files
authored
Merge pull request #10478 from embhorn/zd21821
Fixes in SP int and DH
2 parents 70f8bd9 + dc6db15 commit 7bcc613

3 files changed

Lines changed: 61 additions & 14 deletions

File tree

wolfcrypt/src/dh.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1122,13 +1122,24 @@ static int GeneratePrivateDh186(DhKey* key, WC_RNG* rng, byte* priv,
11221122
byte cBuf[DH_MAX_SIZE + 64 / WOLFSSL_BIT_SIZE];
11231123
#endif
11241124

1125-
/* Parameters validated in calling functions. */
1125+
/* Pointer parameters validated by the public entry wc_DhGenerateKeyPair. */
11261126

11271127
if (mp_iszero(&key->q) == MP_YES) {
11281128
WOLFSSL_MSG("DH q parameter needed for FIPS 186-4 key generation");
11291129
return BAD_FUNC_ARG;
11301130
}
11311131

1132+
/* Bound *privSz so cSz (= *privSz + 8) cannot exceed the cBuf capacity.
1133+
* Note: DH_MAX_SIZE is documented as a bit count, but the cBuf declaration
1134+
* above uses it directly as a byte count (cBuf is DH_MAX_SIZE + 8 bytes).
1135+
* This check matches that convention so *privSz (in bytes) is bounded by
1136+
* the actual byte capacity of cBuf. The same bound is applied to the
1137+
* WOLFSSL_SMALL_STACK path to avoid unbounded heap allocation. */
1138+
if (*privSz > DH_MAX_SIZE) {
1139+
WOLFSSL_MSG("DH private key size exceeds DH_MAX_SIZE");
1140+
return BAD_FUNC_ARG;
1141+
}
1142+
11321143
qSz = (word32)mp_unsigned_bin_size(&key->q);
11331144
pSz = (word32)mp_unsigned_bin_size(&key->p);
11341145

wolfcrypt/src/sp_int.c

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6140,8 +6140,10 @@ int sp_leading_bit(const sp_int* a)
61406140
int sp_set_bit(sp_int* a, int i)
61416141
{
61426142
int err = MP_OKAY;
6143-
/* Get index of word to set. */
6144-
sp_size_t w = (sp_size_t)(i >> SP_WORD_SHIFT);
6143+
/* Compute word index in full int width so that bit indices large enough
6144+
* to make the word index overflow sp_size_t are caught by the bounds
6145+
* check below rather than wrapping. */
6146+
int wi = (i < 0) ? 0 : (i >> SP_WORD_SHIFT);
61456147

61466148
#if SP_INT_DIGITS < (65536 / SP_WORD_SIZEOF)
61476149
/* Check bit index isn't bigger than maximum allowed. */
@@ -6151,10 +6153,11 @@ int sp_set_bit(sp_int* a, int i)
61516153
else
61526154
#endif
61536155
/* Check for valid number and space for bit. */
6154-
if ((a == NULL) || (i < 0) || (w >= a->size)) {
6156+
if ((a == NULL) || (i < 0) || (wi >= (int)a->size)) {
61556157
err = MP_VAL;
61566158
}
61576159
if (err == MP_OKAY) {
6160+
sp_size_t w = (sp_size_t)wi;
61586161
/* Amount to shift up to set bit in word. */
61596162
unsigned int s = (unsigned int)(i & (SP_WORD_SIZE - 1));
61606163
unsigned int j;
@@ -8627,15 +8630,16 @@ void sp_rshd(sp_int* a, int c)
86278630
{
86288631
/* Do shift if we have an SP int. */
86298632
if ((a != NULL) && (c > 0)) {
8630-
/* Make zero if shift removes all digits. */
8631-
if ((sp_size_t)c >= a->used) {
8633+
/* Compare c in int width to avoid narrowing to sp_size_t (which can
8634+
* be word16) before the bounds check. */
8635+
if (c >= (int)a->used) {
86328636
_sp_zero(a);
86338637
}
86348638
else {
86358639
sp_size_t i;
86368640

86378641
/* Update used digits count. */
8638-
a->used = (sp_size_t)(a->used - c);
8642+
a->used = (sp_size_t)((int)a->used - c);
86398643
/* Move digits down. */
86408644
for (i = 0; i < a->used; i++, c++) {
86418645
a->dp[i] = a->dp[c];
@@ -8657,21 +8661,23 @@ void sp_rshd(sp_int* a, int c)
86578661
int sp_rshb(const sp_int* a, int n, sp_int* r)
86588662
{
86598663
int err = MP_OKAY;
8660-
/* Number of digits to shift down. */
8661-
sp_size_t i;
8664+
/* Compute the digit-shift count in full int width to avoid wrapping
8665+
* when n is large enough that the count would exceed sp_size_t range. */
8666+
int ni = (n < 0) ? 0 : (n >> SP_WORD_SHIFT);
86628667

86638668
if ((a == NULL) || (n < 0)) {
86648669
err = MP_VAL;
86658670
}
86668671
/* Handle case where shifting out all digits. */
8667-
else if ((i = (sp_size_t)(n >> SP_WORD_SHIFT)) >= a->used) {
8672+
else if (ni >= (int)a->used) {
86688673
_sp_zero(r);
86698674
}
86708675
/* Change callers when more error cases returned. */
8671-
else if ((err == MP_OKAY) && (a->used - i > r->size)) {
8676+
else if ((err == MP_OKAY) && ((int)a->used - ni > (int)r->size)) {
86728677
err = MP_VAL;
86738678
}
86748679
else if (err == MP_OKAY) {
8680+
sp_size_t i = (sp_size_t)ni;
86758681
sp_size_t j;
86768682

86778683
/* Number of bits to shift in digits. */
@@ -14920,16 +14926,25 @@ int sp_div_2d(const sp_int* a, int e, sp_int* r, sp_int* rem)
1492014926
int sp_mod_2d(const sp_int* a, int e, sp_int* r)
1492114927
{
1492214928
int err = MP_OKAY;
14923-
sp_size_t digits = (sp_size_t)((e + SP_WORD_SIZE - 1) >> SP_WORD_SHIFT);
14929+
/* Compute digit count in full int width. Decompose to avoid signed
14930+
* overflow if e is near INT_MAX: (e + SP_WORD_SIZE - 1) >> SHIFT is
14931+
* equivalent to (e >> SHIFT) + (e has remainder ? 1 : 0). */
14932+
int digits_full = 0;
14933+
sp_size_t digits = 0;
1492414934

1492514935
if ((a == NULL) || (r == NULL) || (e < 0)) {
1492614936
err = MP_VAL;
1492714937
}
14928-
if ((err == MP_OKAY) && (digits > r->size)) {
14929-
err = MP_VAL;
14938+
if (err == MP_OKAY) {
14939+
digits_full = (e >> SP_WORD_SHIFT) +
14940+
(((e & (SP_WORD_SIZE - 1)) != 0) ? 1 : 0);
14941+
if (digits_full > (int)r->size) {
14942+
err = MP_VAL;
14943+
}
1493014944
}
1493114945

1493214946
if (err == MP_OKAY) {
14947+
digits = (sp_size_t)digits_full;
1493314948
/* Copy a into r if not same pointer. */
1493414949
if (a != r) {
1493514950
sp_size_t cnt = (a->used < digits) ? a->used : digits;

wolfcrypt/test/test.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29702,6 +29702,27 @@ static wc_test_ret_t dh_fips_generate_test(WC_RNG *rng)
2970229702
if (ret != 0)
2970329703
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_gen_test);
2970429704

29705+
#if !defined(WOLFSSL_NO_DH186) && !defined(HAVE_SELFTEST) && \
29706+
!defined(HAVE_FIPS)
29707+
/* Regression: an oversized *privSz must be rejected before
29708+
* GeneratePrivateDh186 writes (*privSz + 8) bytes of RNG output into the
29709+
* stack-allocated cBuf (sized DH_MAX_SIZE + 8 in non-WOLFSSL_SMALL_STACK
29710+
* builds). The key still has q set here, so the call dispatches through
29711+
* GeneratePrivateDh186. Only exercised when the local src/dh.c bound
29712+
* check is in play (not HAVE_SELFTEST / HAVE_FIPS builds, which use
29713+
* separate validated modules). */
29714+
{
29715+
word32 hugePrivSz = (word32)DH_MAX_SIZE + 1;
29716+
word32 outPubSz = sizeof(pub);
29717+
ret = wc_DhGenerateKeyPair(key, rng, priv, &hugePrivSz, pub, &outPubSz);
29718+
#if defined(WOLFSSL_ASYNC_CRYPT)
29719+
ret = wc_AsyncWait(ret, &key->asyncDev, WC_ASYNC_FLAG_NONE);
29720+
#endif
29721+
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
29722+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_gen_test);
29723+
}
29724+
#endif /* !WOLFSSL_NO_DH186 && !HAVE_SELFTEST && !HAVE_FIPS */
29725+
2970529726
wc_FreeDhKey(key);
2970629727
ret = wc_InitDhKey_ex(key, HEAP_HINT, devId);
2970729728
if (ret != 0)

0 commit comments

Comments
 (0)