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 ) {
0 commit comments