Skip to content

Commit 08bd5b1

Browse files
authored
Merge pull request #408 from ColtonWilley/fix-drbg-reseed-fips-version-gate
wp_drbg: gate wc_RNG_DRBG_Reseed on FIPS version
2 parents e3e19e9 + 05f28c3 commit 08bd5b1

5 files changed

Lines changed: 229 additions & 38 deletions

File tree

include/wolfprovider/settings.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,20 @@
2828
#include <wolfssl/version.h>
2929
#include <wolfssl/wolfcrypt/settings.h>
3030

31+
/* wc_RNG_DRBG_Reseed is only reliably exported in non-FIPS >= 5.7.2 and FIPS
32+
* v6+. FIPS v5.x bundles are inconsistent (some keep it WOLFSSL_LOCAL), so use
33+
* the native reseed only where it's exported, else fall back to DRBG
34+
* re-instantiation. WP_NO_DRBG_RESEED forces the fallback. */
35+
#if defined(WP_NO_DRBG_RESEED)
36+
/* caller forced the re-instantiation fallback */
37+
#elif !defined(HAVE_FIPS)
38+
#if LIBWOLFSSL_VERSION_HEX >= 0x05007002
39+
#define WP_HAVE_DRBG_RESEED
40+
#endif
41+
#elif defined(HAVE_FIPS_VERSION_MAJOR) && HAVE_FIPS_VERSION_MAJOR >= 6
42+
#define WP_HAVE_DRBG_RESEED
43+
#endif
44+
3145
#define WP_HAVE_DIGEST
3246
#if !defined(NO_MD5)
3347
#define WP_HAVE_MD5

scripts/utils-wolfssl.sh

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,16 @@ install_wolfssl() {
179179
# Determine configure option from tag
180180
local fips_configure_arg=""
181181
case "$fips_tag" in
182+
v5.2.4|linuxv5.2.4)
183+
# Distinct module (SP math, PATCH 4) — not the v5/cert4718 base
184+
fips_configure_arg="v5.2.4"
185+
;;
186+
v5.2.3|linuxv5.2.3)
187+
# Distinct module (PATCH 3) — not the v5/cert4718 base
188+
fips_configure_arg="v5.2.3"
189+
;;
182190
v5.2.*|v5.3.*|v5.4.*|v5.5.*|linuxv5.*)
191+
# v5.2.1/cert4718 and other v5.x map to the base v5 module
183192
fips_configure_arg="v5"
184193
;;
185194
v6.*|linuxv6.*)
@@ -320,7 +329,12 @@ install_wolfssl() {
320329
do_cleanup
321330
exit 1
322331
fi
323-
cd ..
332+
# Only the clone path descended into XXX-fips-test; bundles build in
333+
# wolfssl-source directly. Must mirror the descent guard, else the
334+
# bundle path pops one level too far.
335+
if [ -z "$WOLFSSL_FIPS_BUNDLE" ]; then
336+
cd ..
337+
fi
324338
printf "Done.\n"
325339
fi
326340
fi

src/wp_drbg.c

Lines changed: 161 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <openssl/evp.h>
2828
#include <openssl/hmac.h>
2929

30+
#include <wolfprovider/settings.h>
3031
#include <wolfprovider/alg_funcs.h>
3132
#include <wolfprovider/internal.h>
3233

@@ -61,6 +62,10 @@ typedef struct wp_DrbgCtx {
6162
OSSL_FUNC_rand_get_seed_fn* parentGetSeed;
6263
/** Parent's clear_seed function. */
6364
OSSL_FUNC_rand_clear_seed_fn* parentClearSeed;
65+
#ifndef WP_HAVE_DRBG_RESEED
66+
/** Set when a failed reseed re-instantiation left ctx->rng de-instantiated. */
67+
int rngError;
68+
#endif
6469
} wp_DrbgCtx;
6570

6671

@@ -143,6 +148,8 @@ static void wp_drbg_free(wp_DrbgCtx* ctx)
143148
}
144149
}
145150

151+
static int wp_drbg_uninstantiate(wp_DrbgCtx* ctx);
152+
146153
/**
147154
* Instantiate a new DRBG.
148155
*
@@ -171,6 +178,11 @@ static int wp_drbg_instantiate(wp_DrbgCtx* ctx, unsigned int strength,
171178
ok = 0;
172179
}
173180

181+
/* Free any existing DRBG before re-allocating to avoid a leak. */
182+
if (ok && ctx->rng != NULL) {
183+
wp_drbg_uninstantiate(ctx);
184+
}
185+
174186
if (ok && ctx->parentGetSeed != NULL) {
175187
/* Get entropy from parent DRBG (no file I/O needed) */
176188
WOLFPROV_MSG_DEBUG(WP_LOG_COMP_RNG,
@@ -189,7 +201,9 @@ static int wp_drbg_instantiate(wp_DrbgCtx* ctx, unsigned int strength,
189201
}
190202

191203
if (ok) {
192-
/* Initialize wolfCrypt RNG with parent-provided seed */
204+
/* Route DRBG instantiation through the FIPS-validated
205+
* wc_InitRngNonce entry (not wc_rng_new), so it works on every
206+
* pinned FIPS bundle vintage. */
193207
ctx->rng = OPENSSL_zalloc(sizeof(*ctx->rng));
194208
if (ctx->rng == NULL) {
195209
ok = 0;
@@ -201,7 +215,7 @@ static int wp_drbg_instantiate(wp_DrbgCtx* ctx, unsigned int strength,
201215
if (rc != 0) {
202216
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_COMP_RNG,
203217
"wc_InitRngNonce", rc);
204-
OPENSSL_free(ctx->rng);
218+
OPENSSL_clear_free(ctx->rng, sizeof(*ctx->rng));
205219
ctx->rng = NULL;
206220
ok = 0;
207221
}
@@ -242,6 +256,13 @@ static int wp_drbg_instantiate(wp_DrbgCtx* ctx, unsigned int strength,
242256
#endif
243257
}
244258

259+
#ifndef WP_HAVE_DRBG_RESEED
260+
if (ok) {
261+
/* Clear any prior reseed error state. */
262+
ctx->rngError = 0;
263+
}
264+
#endif
265+
245266
WOLFPROV_LEAVE(WP_LOG_COMP_RNG, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);
246267
return ok;
247268
}
@@ -262,6 +283,9 @@ static int wp_drbg_uninstantiate(wp_DrbgCtx* ctx)
262283
OPENSSL_clear_free(ctx->rng, sizeof(*ctx->rng));
263284
#endif
264285
ctx->rng = NULL;
286+
#ifndef WP_HAVE_DRBG_RESEED
287+
ctx->rngError = 0;
288+
#endif
265289
WOLFPROV_LEAVE(WP_LOG_COMP_RNG, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), 1);
266290
return 1;
267291
}
@@ -292,6 +316,16 @@ static int wp_drbg_generate(wp_DrbgCtx* ctx, unsigned char* out,
292316
if (strength > WP_DRBG_STRENGTH) {
293317
ok = 0;
294318
}
319+
if (ok && ctx->rng == NULL) {
320+
WOLFPROV_MSG_DEBUG(WP_LOG_COMP_RNG, "DRBG not instantiated");
321+
ok = 0;
322+
}
323+
#ifndef WP_HAVE_DRBG_RESEED
324+
if (ok && ctx->rngError) {
325+
WOLFPROV_MSG_DEBUG(WP_LOG_COMP_RNG, "DRBG in error state");
326+
ok = 0;
327+
}
328+
#endif
295329
#if 0
296330
if (ok && (addInLen > 0)) {
297331
rc = wc_RNG_DRBG_Reseed(ctx->rng, addIn, addInLen);
@@ -318,10 +352,12 @@ static int wp_drbg_generate(wp_DrbgCtx* ctx, unsigned char* out,
318352
return ok;
319353
}
320354

321-
/* No usage of EVP_RAND_reseed seen in OpenSSL library. */
322355
/**
323356
* Reseed DRBG.
324357
*
358+
* Without WP_HAVE_DRBG_RESEED, re-instantiates instead of reseeding: @p entropy
359+
* and @p addIn become the nonce, not DRBG entropy_input.
360+
*
325361
* @param [in, out] ctx DRBG context object.
326362
* @param [in] predResist Prediction resistance required.
327363
* @param [in] entropy Entropy data to reseed with.
@@ -338,52 +374,124 @@ static int wp_drbg_reseed(wp_DrbgCtx* ctx, int predResist,
338374
{
339375
int ok = 1;
340376
int rc;
341-
unsigned char *seed = NULL;
342-
size_t seedLen = 0;
343377

344378
WOLFPROV_ENTER(WP_LOG_COMP_RNG, "wp_drbg_reseed");
345379

346-
/* If no entropy provided, get fresh entropy from the OS source. */
347-
if (entropy == NULL || entropyLen == 0) {
348-
seedLen = 48;
349-
seed = OPENSSL_malloc(seedLen);
350-
if (seed == NULL) {
351-
ok = 0;
352-
}
353-
if (ok) {
354-
OS_Seed osSeed;
355-
rc = wc_GenerateSeed(&osSeed, seed, (word32)seedLen);
356-
if (rc != 0) {
380+
/* Reseed requires an instantiated DRBG. */
381+
if (ctx->rng == NULL) {
382+
ok = 0;
383+
}
384+
385+
/* wolfCrypt RNG APIs take word32 lengths; reject oversized inputs. */
386+
if (ok && entropy != NULL && entropyLen > 0xFFFFFFFFU) {
387+
ok = 0;
388+
}
389+
if (ok && addIn != NULL && addInLen > 0xFFFFFFFFU) {
390+
ok = 0;
391+
}
392+
393+
#ifdef WP_HAVE_DRBG_RESEED
394+
{
395+
unsigned char* seed = NULL;
396+
size_t seedLen = 0;
397+
398+
/* No caller entropy: with SEED-SRC, draw from the cached /dev/urandom
399+
* fd (survives a seccomp sandbox); else wc_GenerateSeed(). */
400+
if (ok && (entropy == NULL || entropyLen == 0)) {
401+
seedLen = 48;
402+
seed = OPENSSL_malloc(seedLen);
403+
if (seed == NULL) {
357404
ok = 0;
358405
}
359-
else {
406+
if (ok) {
407+
#if defined(WP_HAVE_SEED_SRC) && defined(WP_HAVE_RANDOM)
408+
if (wp_urandom_read(seed, seedLen) != (int)seedLen) {
409+
ok = 0;
410+
}
411+
#else
412+
OS_Seed osSeed;
413+
if (wc_GenerateSeed(&osSeed, seed, (word32)seedLen) != 0) {
414+
ok = 0;
415+
}
416+
#endif
417+
}
418+
if (ok) {
360419
entropy = seed;
361420
entropyLen = seedLen;
362421
}
363422
}
364-
}
365423

366-
if (ok && entropy != NULL && entropyLen > 0) {
367-
rc = wc_RNG_DRBG_Reseed(ctx->rng, entropy, (word32)entropyLen);
368-
if (rc != 0) {
369-
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_COMP_RNG,
370-
"wc_RNG_DRBG_Reseed", rc);
371-
ok = 0;
424+
/* In-place SP 800-90A reseed via wolfCrypt's public DRBG API. */
425+
if (ok && entropy != NULL && entropyLen > 0) {
426+
rc = wc_RNG_DRBG_Reseed(ctx->rng, entropy, (word32)entropyLen);
427+
if (rc != 0) {
428+
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_COMP_RNG,
429+
"wc_RNG_DRBG_Reseed", rc);
430+
ok = 0;
431+
}
372432
}
373-
}
374-
if (ok && (addInLen > 0) && (addIn != NULL)) {
375-
rc = wc_RNG_DRBG_Reseed(ctx->rng, addIn, (word32)addInLen);
376-
if (rc != 0) {
377-
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_COMP_RNG,
378-
"wc_RNG_DRBG_Reseed", rc);
379-
ok = 0;
433+
if (ok && (addInLen > 0) && (addIn != NULL)) {
434+
rc = wc_RNG_DRBG_Reseed(ctx->rng, addIn, (word32)addInLen);
435+
if (rc != 0) {
436+
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_COMP_RNG,
437+
"wc_RNG_DRBG_Reseed", rc);
438+
ok = 0;
439+
}
440+
}
441+
442+
if (seed != NULL) {
443+
OPENSSL_clear_free(seed, seedLen);
380444
}
381445
}
446+
#else
447+
/* No exported wc_RNG_DRBG_Reseed (e.g. cert4718): re-instantiate in place
448+
* via wc_FreeRng() + wc_InitRngNonce(), which self-seeds fresh entropy
449+
* (sandbox-safe when built with SEED-SRC). Caller entropy/addIn become
450+
* only the nonce. A failed re-init sets rngError. */
451+
if (ok) {
452+
unsigned char* nonce = NULL;
453+
word32 nonceLen = 0;
454+
word32 eLen = (entropy != NULL) ? (word32)entropyLen : 0;
455+
word32 aLen = (addIn != NULL) ? (word32)addInLen : 0;
382456

383-
/* Securely clear and free locally allocated seed buffer. */
384-
if (seed != NULL) {
385-
OPENSSL_clear_free(seed, seedLen);
457+
/* Build nonce = entropy || addIn (either may be absent). */
458+
if (aLen > (0xFFFFFFFFU - eLen)) {
459+
ok = 0;
460+
}
461+
if (ok && (eLen + aLen) > 0) {
462+
nonceLen = eLen + aLen;
463+
nonce = OPENSSL_malloc(nonceLen);
464+
if (nonce == NULL) {
465+
ok = 0;
466+
}
467+
else {
468+
if (eLen > 0) {
469+
XMEMCPY(nonce, entropy, eLen);
470+
}
471+
if (aLen > 0) {
472+
XMEMCPY(nonce + eLen, addIn, aLen);
473+
}
474+
}
475+
}
476+
if (ok) {
477+
wc_FreeRng(ctx->rng);
478+
rc = wc_InitRngNonce(ctx->rng, nonce, nonceLen);
479+
if (rc != 0) {
480+
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_COMP_RNG,
481+
"wc_InitRngNonce", rc);
482+
ctx->rngError = 1;
483+
ok = 0;
484+
}
485+
else {
486+
/* Recovered: clear any prior reseed error. */
487+
ctx->rngError = 0;
488+
}
489+
}
490+
if (nonce != NULL) {
491+
OPENSSL_clear_free(nonce, nonceLen);
492+
}
386493
}
494+
#endif /* WP_HAVE_DRBG_RESEED */
387495

388496
(void)predResist;
389497

@@ -512,15 +620,25 @@ static int wp_drbg_get_ctx_params(wp_DrbgCtx* ctx, OSSL_PARAM params[])
512620

513621
WOLFPROV_ENTER(WP_LOG_COMP_RNG, "wp_drbg_get_ctx_params");
514622

515-
(void)ctx;
516-
517623
p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST);
518624
if ((p != NULL) && (!OSSL_PARAM_set_size_t(p, WP_DRBG_MAX_REQUESTS))) {
519625
ok = 0;
520626
}
521627
if (ok) {
628+
int state = EVP_RAND_STATE_READY;
629+
630+
if (ctx->rng == NULL) {
631+
state = EVP_RAND_STATE_UNINITIALISED;
632+
}
633+
#ifndef WP_HAVE_DRBG_RESEED
634+
/* Failed reseed re-instantiation left the DRBG de-instantiated. */
635+
else if (ctx->rngError) {
636+
state = EVP_RAND_STATE_ERROR;
637+
}
638+
#endif
639+
522640
p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE);
523-
if ((p != NULL) && (!OSSL_PARAM_set_int(p, EVP_RAND_STATE_READY))) {
641+
if ((p != NULL) && (!OSSL_PARAM_set_int(p, state))) {
524642
ok = 0;
525643
}
526644
}
@@ -622,6 +740,12 @@ static size_t wp_drbg_get_seed(wp_DrbgCtx* ctx, unsigned char** pSeed,
622740
"DRBG not instantiated");
623741
goto end;
624742
}
743+
#ifndef WP_HAVE_DRBG_RESEED
744+
if (ctx->rngError) {
745+
WOLFPROV_MSG_DEBUG(WP_LOG_COMP_RNG, "DRBG in error state");
746+
goto end;
747+
}
748+
#endif
625749

626750
buffer = OPENSSL_secure_malloc(minLen);
627751
if (buffer == NULL) {

test/test_rand_seed.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,25 @@ static int test_drbg_reseed_helper(OSSL_LIB_CTX *libCtx, const char *propq)
680680
}
681681
PRINT_MSG("Pre/post-reseed outputs differ as expected");
682682

683+
/* Reseed with explicit entropy + addIn. */
684+
{
685+
unsigned char ent[32], add[16];
686+
memset(ent, 0xA5, sizeof(ent));
687+
memset(add, 0x5A, sizeof(add));
688+
if (EVP_RAND_reseed(drbg_ctx, 0, ent, sizeof(ent),
689+
add, sizeof(add)) != 1) {
690+
PRINT_ERR_MSG("Reseed with entropy/addIn failed");
691+
err = 1;
692+
goto cleanup;
693+
}
694+
if (EVP_RAND_generate(drbg_ctx, buf1, sizeof(buf1), 256, 0, NULL, 0)
695+
!= 1 || memcmp(buf1, buf2, sizeof(buf1)) == 0) {
696+
PRINT_ERR_MSG("Generate after entropy reseed failed/unchanged");
697+
err = 1;
698+
goto cleanup;
699+
}
700+
}
701+
683702
/* Uninstantiate and verify zeroization (exercises fix #170). */
684703
if (EVP_RAND_uninstantiate(drbg_ctx) != 1) {
685704
PRINT_ERR_MSG("EVP_RAND_uninstantiate failed");

0 commit comments

Comments
 (0)