Skip to content

Commit c73f431

Browse files
authored
Merge pull request #10392 from JeremiahM37/fenrir-5
wolfCrypt input validation and side-channel hardening
2 parents c1b2660 + 3f37182 commit c73f431

15 files changed

Lines changed: 247 additions & 26 deletions

tests/api/test_curve25519.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -444,14 +444,17 @@ int test_wc_curve25519_export_private_raw_ex(void)
444444
EXPECT_DECLS;
445445
#if defined(HAVE_CURVE25519)
446446
curve25519_key key;
447+
WC_RNG rng;
447448
byte out[CURVE25519_KEYSIZE];
448449
word32 outLen = sizeof(out);
449450
int endian = EC25519_BIG_ENDIAN;
450451

452+
XMEMSET(&rng, 0, sizeof(WC_RNG));
451453
ExpectIntEQ(wc_curve25519_init(&key), 0);
452454

455+
/* Reject export when private key not set (privSet == 0). */
453456
ExpectIntEQ(wc_curve25519_export_private_raw_ex(&key, out, &outLen, endian),
454-
0);
457+
WC_NO_ERR_TRACE(ECC_BAD_ARG_E));
455458
/* test bad cases */
456459
ExpectIntEQ(wc_curve25519_export_private_raw_ex(NULL, NULL, NULL, endian),
457460
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
@@ -461,12 +464,15 @@ int test_wc_curve25519_export_private_raw_ex(void)
461464
endian), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
462465
ExpectIntEQ(wc_curve25519_export_private_raw_ex(&key, out, NULL, endian),
463466
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
464-
ExpectIntEQ(wc_curve25519_export_private_raw_ex(&key, out, &outLen,
465-
EC25519_LITTLE_ENDIAN), 0);
466-
outLen = outLen - 2;
467+
468+
/* Populate the key, then exercise the buffer-too-small path. */
469+
ExpectIntEQ(wc_InitRng(&rng), 0);
470+
ExpectIntEQ(wc_curve25519_make_key(&rng, CURVE25519_KEYSIZE, &key), 0);
471+
outLen = CURVE25519_KEYSIZE - 1;
467472
ExpectIntEQ(wc_curve25519_export_private_raw_ex(&key, out, &outLen, endian),
468473
WC_NO_ERR_TRACE(ECC_BAD_ARG_E));
469474

475+
DoExpectIntEQ(wc_FreeRng(&rng), 0);
470476
wc_curve25519_free(&key);
471477
#endif
472478
return EXPECT_RESULT();

tests/api/test_curve448.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,16 @@ int test_wc_curve448_export_private_raw_ex(void)
164164
EXPECT_DECLS;
165165
#if defined(HAVE_CURVE448)
166166
curve448_key key;
167+
WC_RNG rng;
167168
byte out[CURVE448_KEY_SIZE];
168169
word32 outLen = sizeof(out);
169170
int endian = EC448_BIG_ENDIAN;
170171

172+
XMEMSET(&rng, 0, sizeof(WC_RNG));
171173
ExpectIntEQ(wc_curve448_init(&key), 0);
174+
/* Reject export when private key not set (privSet == 0). */
172175
ExpectIntEQ(wc_curve448_export_private_raw_ex(&key, out, &outLen, endian),
173-
0);
176+
WC_NO_ERR_TRACE(ECC_BAD_ARG_E));
174177
/* test bad cases */
175178
ExpectIntEQ(wc_curve448_export_private_raw_ex(NULL, NULL, NULL, endian),
176179
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
@@ -180,12 +183,15 @@ int test_wc_curve448_export_private_raw_ex(void)
180183
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
181184
ExpectIntEQ(wc_curve448_export_private_raw_ex(&key, out, NULL, endian),
182185
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
183-
ExpectIntEQ(wc_curve448_export_private_raw_ex(&key, out, &outLen,
184-
EC448_LITTLE_ENDIAN), 0);
185-
outLen = outLen - 2;
186+
187+
/* Populate the key, then exercise the buffer-too-small path. */
188+
ExpectIntEQ(wc_InitRng(&rng), 0);
189+
ExpectIntEQ(wc_curve448_make_key(&rng, CURVE448_KEY_SIZE, &key), 0);
190+
outLen = CURVE448_KEY_SIZE - 1;
186191
ExpectIntEQ(wc_curve448_export_private_raw_ex(&key, out, &outLen, endian),
187192
WC_NO_ERR_TRACE(ECC_BAD_ARG_E));
188193

194+
DoExpectIntEQ(wc_FreeRng(&rng), 0);
189195
wc_curve448_free(&key);
190196
#endif
191197
return EXPECT_RESULT();

tests/api/test_ed25519.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,13 @@ int test_wc_ed25519_export(void)
347347
XMEMSET(&rng, 0, sizeof(WC_RNG));
348348

349349
ExpectIntEQ(wc_ed25519_init(&key), 0);
350+
/* Reject export when private key not set. */
351+
PRIVATE_KEY_UNLOCK();
352+
ExpectIntEQ(wc_ed25519_export_private_only(&key, priv, &privSz),
353+
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
354+
ExpectIntEQ(wc_ed25519_export_private(&key, priv, &privSz),
355+
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
356+
PRIVATE_KEY_LOCK();
350357
ExpectIntEQ(wc_InitRng(&rng), 0);
351358
#ifdef HAVE_ED25519_MAKE_KEY
352359
ExpectIntEQ(wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &key), 0);
@@ -379,6 +386,20 @@ int test_wc_ed25519_export(void)
379386
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
380387
PRIVATE_KEY_LOCK();
381388

389+
#ifdef HAVE_ED25519_KEY_IMPORT
390+
/* Public-only key: re-init and import just the public part; private
391+
* exports must still fail with privKeySet == 0. */
392+
wc_ed25519_free(&key);
393+
ExpectIntEQ(wc_ed25519_init(&key), 0);
394+
ExpectIntEQ(wc_ed25519_import_public(pub, pubSz, &key), 0);
395+
PRIVATE_KEY_UNLOCK();
396+
ExpectIntEQ(wc_ed25519_export_private_only(&key, priv, &privSz),
397+
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
398+
ExpectIntEQ(wc_ed25519_export_private(&key, priv, &privSz),
399+
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
400+
PRIVATE_KEY_LOCK();
401+
#endif
402+
382403
DoExpectIntEQ(wc_FreeRng(&rng), 0);
383404
wc_ed25519_free(&key);
384405
#endif

tests/api/test_ed448.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,13 @@ int test_wc_ed448_export(void)
324324
XMEMSET(&rng, 0, sizeof(WC_RNG));
325325

326326
ExpectIntEQ(wc_ed448_init(&key), 0);
327+
/* Reject export when private key not set. */
328+
PRIVATE_KEY_UNLOCK();
329+
ExpectIntEQ(wc_ed448_export_private_only(&key, priv, &privSz),
330+
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
331+
ExpectIntEQ(wc_ed448_export_private(&key, priv, &privSz),
332+
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
333+
PRIVATE_KEY_LOCK();
327334
ExpectIntEQ(wc_InitRng(&rng), 0);
328335
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
329336

@@ -351,6 +358,20 @@ int test_wc_ed448_export(void)
351358
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
352359
PRIVATE_KEY_LOCK();
353360

361+
#ifdef HAVE_ED448_KEY_IMPORT
362+
/* Public-only key: re-init and import just the public part; private
363+
* exports must still fail with privKeySet == 0. */
364+
wc_ed448_free(&key);
365+
ExpectIntEQ(wc_ed448_init(&key), 0);
366+
ExpectIntEQ(wc_ed448_import_public(pub, pubSz, &key), 0);
367+
PRIVATE_KEY_UNLOCK();
368+
ExpectIntEQ(wc_ed448_export_private_only(&key, priv, &privSz),
369+
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
370+
ExpectIntEQ(wc_ed448_export_private(&key, priv, &privSz),
371+
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
372+
PRIVATE_KEY_LOCK();
373+
#endif
374+
354375
DoExpectIntEQ(wc_FreeRng(&rng), 0);
355376
wc_ed448_free(&key);
356377
#endif

wolfcrypt/src/cmac.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
*/
7272
int wc_CMAC_Grow(Cmac* cmac, const byte* in, int inSz)
7373
{
74+
if ((cmac == NULL) || (in == NULL && inSz != 0))
75+
return BAD_FUNC_ARG;
7476
return _wc_Hash_Grow(&cmac->msg, &cmac->used, &cmac->len, in, inSz, cmac->aes.heap);
7577
}
7678
#endif /* WOLFSSL_HASH_KEEP */

wolfcrypt/src/curve25519.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,9 @@ int wc_curve25519_export_private_raw_ex(curve25519_key* key, byte* out,
975975
if (key == NULL || out == NULL || outLen == NULL)
976976
return BAD_FUNC_ARG;
977977

978+
if (!key->privSet)
979+
return ECC_BAD_ARG_E;
980+
978981
/* check size of outgoing buffer */
979982
if (*outLen < CURVE25519_KEYSIZE) {
980983
*outLen = CURVE25519_KEYSIZE;

wolfcrypt/src/curve448.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,10 @@ int wc_curve448_export_private_raw_ex(curve448_key* key, byte* out,
478478
ret = BAD_FUNC_ARG;
479479
}
480480

481+
if ((ret == 0) && (!key->privSet)) {
482+
ret = ECC_BAD_ARG_E;
483+
}
484+
481485
/* check size of outgoing buffer */
482486
if ((ret == 0) && (*outLen < CURVE448_KEY_SIZE)) {
483487
*outLen = CURVE448_KEY_SIZE;

wolfcrypt/src/ed25519.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1414,7 +1414,7 @@ int wc_ed25519_import_private_key(const byte* priv, word32 privSz,
14141414
int wc_ed25519_export_private_only(const ed25519_key* key, byte* out, word32* outLen)
14151415
{
14161416
/* sanity checks on arguments */
1417-
if (key == NULL || out == NULL || outLen == NULL)
1417+
if (key == NULL || !key->privKeySet || out == NULL || outLen == NULL)
14181418
return BAD_FUNC_ARG;
14191419

14201420
if (*outLen < ED25519_KEY_SIZE) {

wolfcrypt/src/ed448.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,6 +1301,10 @@ int wc_ed448_export_private_only(const ed448_key* key, byte* out, word32* outLen
13011301
ret = BAD_FUNC_ARG;
13021302
}
13031303

1304+
if ((ret == 0) && (!key->privKeySet)) {
1305+
ret = BAD_FUNC_ARG;
1306+
}
1307+
13041308
if ((ret == 0) && (*outLen < ED448_KEY_SIZE)) {
13051309
*outLen = ED448_KEY_SIZE;
13061310
ret = BUFFER_E;
@@ -1333,6 +1337,10 @@ int wc_ed448_export_private(const ed448_key* key, byte* out, word32* outLen)
13331337
ret = BAD_FUNC_ARG;
13341338
}
13351339

1340+
if ((ret == 0) && (!key->privKeySet)) {
1341+
ret = BAD_FUNC_ARG;
1342+
}
1343+
13361344
if ((ret == 0) && (*outLen < ED448_PRV_KEY_SIZE)) {
13371345
*outLen = ED448_PRV_KEY_SIZE;
13381346
ret = BUFFER_E;

wolfcrypt/src/integer.c

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -549,21 +549,48 @@ int mp_exch (mp_int * a, mp_int * b)
549549
return MP_OKAY;
550550
}
551551

552+
/* Constant-time conditional swap: must not branch on m (leaks scalar bit).
553+
* m must be 0 or 1. The t parameter is unused; XOR is performed in place
554+
* with a single-digit stack scratch so callers don't need to clear t->dp. */
552555
int mp_cond_swap_ct_ex (mp_int * a, mp_int * b, int c, int m, mp_int * t)
553556
{
554-
(void)c;
557+
int i;
558+
int err;
559+
int imask;
560+
int idiff;
561+
mp_digit mask;
562+
mp_digit d;
563+
555564
(void)t;
556-
if (m == 1)
557-
mp_exch(a, b);
565+
566+
m &= 1;
567+
imask = -m;
568+
mask = (mp_digit)0 - (mp_digit)m;
569+
570+
if ((err = mp_grow(a, c)) != MP_OKAY)
571+
return err;
572+
if ((err = mp_grow(b, c)) != MP_OKAY)
573+
return err;
574+
575+
idiff = (a->used ^ b->used) & imask;
576+
a->used ^= idiff;
577+
b->used ^= idiff;
578+
idiff = (a->sign ^ b->sign) & imask;
579+
a->sign ^= idiff;
580+
b->sign ^= idiff;
581+
582+
for (i = 0; i < c; i++) {
583+
d = (a->dp[i] ^ b->dp[i]) & mask;
584+
a->dp[i] ^= d;
585+
b->dp[i] ^= d;
586+
}
587+
558588
return MP_OKAY;
559589
}
560590

561591
int mp_cond_swap_ct (mp_int * a, mp_int * b, int c, int m)
562592
{
563-
(void)c;
564-
if (m == 1)
565-
mp_exch(a, b);
566-
return MP_OKAY;
593+
return mp_cond_swap_ct_ex(a, b, c, m, NULL);
567594
}
568595

569596

0 commit comments

Comments
 (0)