diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 5488e9ca3d4..69e7911374e 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -28,7 +28,7 @@ jobs: check_filenames: true check_hidden: true # Add comma separated list of words that occur multiple times that should be ignored (sorted alphabetically, case sensitive) - ignore_words_list: adin,ameba,aNULL,brunch,carryIn,chainG,ciph,cLen,cliKs,cna,dout,FPR,fpr,haveA,inCreated,inOut,inout,larg,LEAPYEAR,Merget,optionA,parm,parms,repid,rIn,userA,ser,siz,te,Te,HSI,failT,toLen,vor,checkin + ignore_words_list: addIn,adin,ameba,aNULL,brunch,carryIn,chainG,ciph,cLen,cliKs,cna,dout,FPR,fpr,haveA,inCreated,inOut,inout,larg,LEAPYEAR,Merget,optionA,parm,parms,repid,rIn,userA,ser,siz,te,Te,HSI,failT,toLen,vor,checkin # The exclude_file contains lines of code that should be ignored. This is useful for individual lines which have non-words that can safely be ignored. exclude_file: '.codespellexcludelines' # To skip files entirely from being processed, add it to the following list: diff --git a/doc/dox_comments/header_files/random.h b/doc/dox_comments/header_files/random.h index 2bcd2a64219..ab8e05e6a68 100644 --- a/doc/dox_comments/header_files/random.h +++ b/doc/dox_comments/header_files/random.h @@ -6,12 +6,12 @@ with wc_FreeRng). This is a blocking operation. One WC_RNG may be shared between threads for generating and reseeding: - wc_RNG_GenerateBlock(), wc_RNG_DRBG_Reseed(), wc_RNG_DRBG_Reseed_Nonce() + wc_RNG_GenerateBlock(), wc_RNG_DRBG_Reseed(), wc_RNG_DRBG_Reseed_AddIn() and wc_RNG_DRBG_Reseed_Now() each hold the instance lock. So do the DRBG - management calls: wc_RNG_DRBG_Stir(), wc_RNG_DRBG_Stir_Nonce() and + management calls: wc_RNG_DRBG_Stir(), wc_RNG_DRBG_Stir_AddIn() and wc_RNG_DRBG_ScheduleReseed(), and in --enable-rng-extras builds wc_RNG_DRBG_NextStirNow(), wc_RNG_DRBG_NextSeedNow() and - wc_RNG_DRBG_NextSeedNow_Nonce(). The generate path calls their internal + wc_RNG_DRBG_NextSeedNow_AddIn(). The generate path calls their internal cores, which already run under the lock. wc_RNG_DRBG_ReseedRBGC() and wc_RNG_DRBG_StirRBGC() are the exception: @@ -1316,7 +1316,7 @@ int wc_RNG_global_fallback_free(void); \endcode \sa wc_InitRngNonce_ex2 - \sa wc_RNG_DRBG_Reseed_Nonce + \sa wc_RNG_DRBG_Reseed_AddIn \sa wc_RNG_TestSeed \sa wc_RNG_DRBG_GetRBGCStratum */ @@ -1417,7 +1417,7 @@ int wc_RNG_DRBG_ScheduleReseed(WC_RNG* rng); \ingroup Random \brief Immediately reseed rng from the module's built-in, registered, or - associated seed source, with an optional nonce as additional input. The + associated seed source, with an optional addIn as additional input. The credited reseed resets the reseed counter. \details For an SP 800-90C chain member (RBGC stratum > 0, in builds with @@ -1432,7 +1432,7 @@ int wc_RNG_DRBG_ScheduleReseed(WC_RNG* rng); \return 0 Success -- or no-op: an instance with no DRBG (RDRAND et al.) reports success without action; wc_RNG_DRBG_Present() disambiguates. - \return BAD_FUNC_ARG rng is null, or nonce is null with nonceSz nonzero. + \return BAD_FUNC_ARG rng is null, or addIn is null with addInSz nonzero. \return OBJECT_NOT_LOCKED_E The instance requires its lock and the caller does not hold it. \return BAD_MUTEX_E The rng's lock could not be taken. @@ -1453,21 +1453,21 @@ int wc_RNG_DRBG_ScheduleReseed(WC_RNG* rng); remains usable until its reseed interval is reached. \param rng The RNG object to reseed. - \param nonce Optional additional input. - \param nonceSz Length of nonce in bytes. + \param addIn Optional additional input. + \param addInSz Length of addIn in bytes. \sa wc_RNG_DRBG_ScheduleReseed - \sa wc_RNG_DRBG_Reseed_Nonce + \sa wc_RNG_DRBG_Reseed_AddIn \sa wc_RNG_DRBG_Present */ -int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* nonce, word32 nonceSz); +int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* addIn, word32 addInSz); /*! \ingroup Random \brief The forced-primary form of wc_RNG_DRBG_Reseed_Now(): reseed rng directly from the module's primary (initial) randomness source, bypassing - the chain fallback ladder, with an optional nonce as additional input. + the chain fallback ladder, with an optional addIn as additional input. This is the SP 800-90A prediction-resistance primitive -- a reseed from a live entropy source immediately ahead of generation -- and is available to SP 800-90C chain members (RBGC stratum > 0) as well: the initial @@ -1501,7 +1501,7 @@ int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* nonce, word32 nonceSz); retryable from a blockable context. \return 0 Success - \return BAD_FUNC_ARG rng is null, or nonce is null with nonceSz nonzero. + \return BAD_FUNC_ARG rng is null, or addIn is null with addInSz nonzero. \return OBJECT_NOT_LOCKED_E The instance requires its lock and the caller does not hold it. \return WRONG_TYPE_OBJECT_E The instance does not assert @@ -1518,8 +1518,8 @@ int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* nonce, word32 nonceSz); \param rng The RNG object to reseed; in builds with instance locking it must assert WC_RNG_LOCK_REQUIRED and be held by the caller. - \param nonce Optional additional input. - \param nonceSz Length of nonce in bytes. + \param addIn Optional additional input. + \param addInSz Length of addIn in bytes. _Example_ \code @@ -1537,14 +1537,14 @@ int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* nonce, word32 nonceSz); \sa wc_RNG_DRBG_Present \sa wc_RNG_DRBG_NextSeedGenerate_Primary */ -int wc_RNG_DRBG_Reseed_Now_Primary(WC_RNG* rng, const byte* nonce, - word32 nonceSz); +int wc_RNG_DRBG_Reseed_Now_Primary(WC_RNG* rng, const byte* addIn, + word32 addInSz); /*! \ingroup Random \brief Reseed rng's DRBG with caller-supplied seed material and an - optional nonce as additional input, folded in a single derivation pass. + optional addIn as additional input, folded in a single derivation pass. The material is credited: the reseed counter resets. \details The single pass is one reseed operation over both inputs, not @@ -1557,7 +1557,7 @@ int wc_RNG_DRBG_Reseed_Now_Primary(WC_RNG* rng, const byte* nonce, \return RNG_FAILURE_E rng is condemned (status DRBG_FAILED): a condemned instance does not accept a credited reseed; recover with wc_FreeRng() then wc_InitRng*(). Also, the reseed itself failed. - \return BAD_FUNC_ARG rng or seed is null, or nonce is null with nonceSz + \return BAD_FUNC_ARG rng or seed is null, or addIn is null with addInSz nonzero. \return OBJECT_NOT_LOCKED_E The instance requires its lock and the caller does not hold it. @@ -1574,15 +1574,15 @@ int wc_RNG_DRBG_Reseed_Now_Primary(WC_RNG* rng, const byte* nonce, \param rng The RNG object to reseed. \param seed Seed material. \param seedSz Length of seed in bytes. - \param nonce Optional additional input. - \param nonceSz Length of nonce in bytes. + \param addIn Optional additional input. + \param addInSz Length of addIn in bytes. \sa wc_RNG_DRBG_Present \sa wc_RNG_DRBG_Reseed - \sa wc_RNG_DRBG_Stir_Nonce + \sa wc_RNG_DRBG_Stir_AddIn */ -int wc_RNG_DRBG_Reseed_Nonce(WC_RNG* rng, const byte* seed, word32 seedSz, - const byte *nonce, word32 nonceSz); +int wc_RNG_DRBG_Reseed_AddIn(WC_RNG* rng, const byte* seed, word32 seedSz, + const byte *addIn, word32 addInSz); /*! \ingroup Random @@ -1618,7 +1618,7 @@ int wc_RNG_DRBG_Reseed_Nonce(WC_RNG* rng, const byte* seed, word32 seedSz, \param seedSz Length of seed in bytes. \sa wc_RNG_DRBG_Reseed - \sa wc_RNG_DRBG_Stir_Nonce + \sa wc_RNG_DRBG_Stir_AddIn \sa wc_RNG_entropy_needs_recovery \sa wc_RNG_DRBG_Present */ @@ -1627,12 +1627,12 @@ int wc_RNG_DRBG_Stir(WC_RNG* rng, const byte* seed, word32 seedSz); /*! \ingroup Random - \brief The nonce-bearing form of wc_RNG_DRBG_Stir(): the nonce is + \brief The addIn-bearing form of wc_RNG_DRBG_Stir(): the addIn is mixed in as a second, separate generate with additional input. \return 0 Success -- or no-op: an instance with no DRBG (RDRAND et al.) reports success without action; wc_RNG_DRBG_Present() disambiguates. - \return BAD_FUNC_ARG rng or seed is null, or nonce is null with nonceSz + \return BAD_FUNC_ARG rng or seed is null, or addIn is null with addInSz nonzero. \return OBJECT_NOT_LOCKED_E, NEEDS_RECOVERY_E, NOT_READY_E, RNG_FAILURE_E, BAD_MUTEX_E As for wc_RNG_DRBG_Stir(). @@ -1640,16 +1640,16 @@ int wc_RNG_DRBG_Stir(WC_RNG* rng, const byte* seed, word32 seedSz); \param rng The RNG object to stir. \param seed Material to mix in. \param seedSz Length of seed in bytes. - \param nonce Optional additional input. - \param nonceSz Length of nonce in bytes. + \param addIn Optional additional input. + \param addInSz Length of addIn in bytes. \sa wc_RNG_DRBG_Stir - \sa wc_RNG_DRBG_Reseed_Nonce + \sa wc_RNG_DRBG_Reseed_AddIn \sa wc_RNG_DRBG_Present */ -int wc_RNG_DRBG_Stir_Nonce(WC_RNG* rng, const byte* seed, - word32 seedSz, const byte *nonce, - word32 nonceSz); +int wc_RNG_DRBG_Stir_AddIn(WC_RNG* rng, const byte* seed, + word32 seedSz, const byte *addIn, + word32 addInSz); /*! \ingroup Random @@ -1748,7 +1748,7 @@ int wc_InitRngNonceRBGC_New(WC_RNG** child, WC_RNG* parent, const byte* nonce, \ingroup Random \brief Reseed rng from root's generate output -- the SP 800-90C chain - reseed -- with an optional nonce as additional input. The reseed is + reseed -- with an optional addIn as additional input. The reseed is credited (the reseed counter resets); rng's stratum is updated to root's stratum + 1, unless built with WC_RNG_RBGC_STRATUM_IMMUTABLE (required for FIPS). The caller must hold exclusive access to both instances. @@ -1779,8 +1779,8 @@ int wc_InitRngNonceRBGC_New(WC_RNG** child, WC_RNG* parent, const byte* nonce, \return 0 Success -- or no-op: an instance with no DRBG (RDRAND et al.) reports success without action; wc_RNG_DRBG_Present() disambiguates. (Refusals below take precedence.) - \return BAD_FUNC_ARG rng or root is null, rng equals root, nonce is - null with nonceSz nonzero, or the no-downgrade rule refuses root as a + \return BAD_FUNC_ARG rng or root is null, rng equals root, addIn is + null with addInSz nonzero, or the no-downgrade rule refuses root as a chain parent (see \details). \return WRONG_TYPE_OBJECT_E rng is primary-class (stratum 0) and the build is WC_RNG_RBGC_STRATUM_IMMUTABLE, or (under FIPS) root is neither @@ -1798,16 +1798,16 @@ int wc_InitRngNonceRBGC_New(WC_RNG** child, WC_RNG* parent, const byte* nonce, \param rng The chain member to reseed. \param root The chain parent to draw seed material from. - \param nonce Optional additional input. - \param nonceSz Length of nonce in bytes. + \param addIn Optional additional input. + \param addInSz Length of addIn in bytes. \sa wc_InitRngRBGC \sa wc_RNG_DRBG_StirRBGC \sa wc_RNG_DRBG_Reseed_Now \sa wc_RNG_DRBG_Present */ -int wc_RNG_DRBG_ReseedRBGC(WC_RNG* rng, WC_RNG* root, const byte* nonce, - word32 nonceSz); +int wc_RNG_DRBG_ReseedRBGC(WC_RNG* rng, WC_RNG* root, const byte* addIn, + word32 addInSz); /*! \ingroup Random @@ -1817,8 +1817,8 @@ int wc_RNG_DRBG_ReseedRBGC(WC_RNG* rng, WC_RNG* root, const byte* nonce, \return 0 Success -- or no-op: an instance with no DRBG (RDRAND et al.) reports success without action; wc_RNG_DRBG_Present() disambiguates. - \return BAD_FUNC_ARG rng or root is null, rng equals root, or nonce is - null with nonceSz nonzero. + \return BAD_FUNC_ARG rng or root is null, rng equals root, or addIn is + null with addInSz nonzero. \return OBJECT_NOT_LOCKED_E rng or root requires its lock and the caller does not hold it. \return NEEDS_RECOVERY_E A recovery obligation stands on rng; see @@ -1828,8 +1828,8 @@ int wc_RNG_DRBG_ReseedRBGC(WC_RNG* rng, WC_RNG* root, const byte* nonce, \param rng The chain member to stir. \param root The chain parent to draw material from. - \param nonce Optional additional input. - \param nonceSz Length of nonce in bytes. + \param addIn Optional additional input. + \param addInSz Length of addIn in bytes. \sa wc_RNG_DRBG_ReseedRBGC \sa wc_RNG_DRBG_Stir @@ -1844,7 +1844,7 @@ int wc_RNG_DRBG_ReseedRBGC(WC_RNG* rng, WC_RNG* root, const byte* nonce, */ int wc_RNG_DRBG_StirRBGC(WC_RNG* rng, WC_RNG* root, - const byte* nonce, word32 nonceSz); + const byte* addIn, word32 addInSz); /*! \ingroup Random @@ -2091,14 +2091,14 @@ int wc_RNG_DRBG_NextSeedCurrent(const WC_RNG* rng, WC_ATOMIC_INT_ARG* n); \endcode \sa wc_RNG_DRBG_NextSeedGenerate - \sa wc_RNG_DRBG_NextSeedNow_Nonce + \sa wc_RNG_DRBG_NextSeedNow_AddIn */ int wc_RNG_DRBG_NextSeedNow(WC_RNG* rng); /*! \ingroup Random - \brief The nonce-bearing form of wc_RNG_DRBG_NextSeedNow(): the nonce is + \brief The addIn-bearing form of wc_RNG_DRBG_NextSeedNow(): the addIn is mixed in as uncredited additional input alongside the banked seed. \return 0 Success @@ -2109,18 +2109,18 @@ int wc_RNG_DRBG_NextSeedNow(WC_RNG* rng); (re-)asserted, and a recovery reseed is scheduled. \return NOT_READY_E No bank is ready, or the reseed failed retryably with reseed runway remaining. - \return BAD_FUNC_ARG rng is null, or nonce is null with nonceSz nonzero. + \return BAD_FUNC_ARG rng is null, or addIn is null with addInSz nonzero. \return WRONG_TYPE_OBJECT_E, OBJECT_NOT_LOCKED_E, BAD_MUTEX_E, RNG_FAILURE_E, DRBG_CONT_FIPS_E As for wc_RNG_DRBG_NextSeedNow(). \param rng The RNG object to reseed. - \param nonce Additional input. - \param nonceSz Length of nonce in bytes. + \param addIn Additional input. + \param addInSz Length of addIn in bytes. \sa wc_RNG_DRBG_NextSeedNow */ -int wc_RNG_DRBG_NextSeedNow_Nonce(WC_RNG* rng, const byte* nonce, - word32 nonceSz); +int wc_RNG_DRBG_NextSeedNow_AddIn(WC_RNG* rng, const byte* addIn, + word32 addInSz); /*! \ingroup Random @@ -2135,18 +2135,18 @@ int wc_RNG_DRBG_NextSeedNow_Nonce(WC_RNG* rng, const byte* nonce, \return 0 Success (an instance with no DRBG accumulates too; the stir that consumes it is then a no-op -- wc_RNG_DRBG_Present() disambiguates). - \return BAD_FUNC_ARG rng or nonce is null, or nonceSz is 0. + \return BAD_FUNC_ARG rng or addIn is null, or addInSz is 0. \param rng The RNG object whose accumulator to feed. - \param nonce Material to bank. - \param nonceSz Length of nonce in bytes. + \param addIn Material to bank. + \param addInSz Length of addIn in bytes. \sa wc_RNG_DRBG_NextStirNow \sa wc_RNG_DRBG_Stir \sa wc_RNG_DRBG_Present */ -int wc_RNG_DRBG_NextStirStore(WC_RNG* rng, const byte *nonce, - word32 nonceSz); +int wc_RNG_DRBG_NextStirStore(WC_RNG* rng, const byte *addIn, + word32 addInSz); /*! \ingroup Random @@ -2787,16 +2787,21 @@ int wc_rng_debug_stats_sum(struct wc_rng_debug_stats_snapshot *s, call. The pending event is delivered into each instance -- purging its banked and pooled pre-event material via wc_RNG_invalidate_entropy() -- at the instance's next detection point: a generate, a recovery query, a - banked-seed redemption, or a pool extraction. The call is lock-free and - safe from any context that may call the atomic-increment primitive. + banked-seed redemption, or a pool extraction. If an auxiliary + invalidation publisher is registered (see + wc_RNG_entropy_epoch_extra_inv_init()), the fresh epoch is published + through it after the advance is globally visible. The call is lock-free + and safe from any context that may call the atomic-increment primitive + (and, when a publisher is registered, the publisher). \return The new (post-increment) global entropy epoch. \sa wc_RNG_entropy_needs_recovery \sa wc_RNG_invalidate_entropy + \sa wc_RNG_entropy_epoch_extra_inv_init \sa wc_RNG_GenerateBlock */ -WC_ATOMIC_UINT_ARG wc_RNG_global_invalidate_entropy(void); +wc_RNG_entropy_epoch_t wc_RNG_global_invalidate_entropy(void); /*! \ingroup Random @@ -2804,16 +2809,126 @@ WC_ATOMIC_UINT_ARG wc_RNG_global_invalidate_entropy(void); \brief Read the process-global entropy epoch: the count of wc_RNG_global_invalidate_entropy() events so far. An instance whose stamp differs from this value has an undelivered event pending (see - wc_RNG_entropy_needs_recovery(), which delivers it). A relaxed - snapshot, for diagnostics and for callers that want to notice an event - without touching any instance; nothing is propagated. + wc_RNG_entropy_needs_recovery(), which delivers it). + + \details Every epoch read is also a detection point for the auxiliary + pathway: with an external epoch source registered (see + wc_RNG_extra_entropy_epoch_init()), the source is consulted first, and + an external event detected there advances the global epoch before the + read returns -- so a read can itself move the epoch. No per-instance + delivery is performed either way: this is for diagnostics and for + callers that want to notice an event without touching any instance. \return The current global epoch. \sa wc_RNG_global_invalidate_entropy + \sa wc_RNG_extra_entropy_epoch_init + \sa wc_RNG_entropy_needs_recovery +*/ +wc_RNG_entropy_epoch_t wc_RNG_get_global_entropy_epoch(void); + +/*! + \ingroup Random + + \brief Register a publisher for global entropy-epoch advances -- the + sender half of the auxiliary invalidation pathway, carrying + wc_RNG_global_invalidate_entropy() events to consumers outside the + process. + + \details The canonical sender is a kernel module exporting its epoch to + user processes through read-only shared memory: the handler writes each + fresh epoch to the exported word, and user-mode libraries detect the + change through their own registered source (see + wc_RNG_extra_entropy_epoch_init() -- a build registering both is a + relay, receiving events upstream and republishing them downstream). + The "extra" here is an extra invalidation step -- transmission of the + one and only epoch -- not an extra epoch. + + The handler is called after each advance is globally visible, with the + fresh epoch and the registered arg. It must be cheap, nonblocking, and + safe in every context wc_RNG_global_invalidate_entropy() can run in, + and must not call back into wolfCrypt (a call back into the invalidator + is direct recursion). Registration is one-shot for the life of the + process, with no deregistration, by design. + + Publication is only guaranteed for advances after this call returns + success: either defer normal service until registration completes + (natural in module-init contexts), or accept that an advance racing the + registration may go unpublished. + + \return 0 Success: the handler is registered and will receive every + subsequent advance. + \return BAD_FUNC_ARG handler is null. + \return ALREADY_E a publisher is already registered. + \return BUSY_E lost a registration race; nothing was registered by this + call. + + \param handler The publisher callback. + \param arg Opaque argument passed to the callback. + + \sa wc_RNG_global_invalidate_entropy + \sa wc_RNG_extra_entropy_epoch_init +*/ +int wc_RNG_entropy_epoch_extra_inv_init( + wc_RNG_entropy_epoch_extra_inv_handler_t handler, void *arg); + +/*! + \ingroup Random + + \brief Register a getter for an external entropy-epoch word -- the + receiver half of the auxiliary invalidation pathway, folding platform + entropy-invalidation events (a VM fork or resume, a snapshot restore) + into the process-global epoch. + + \details The canonical receiver is a user-mode library polling a + kernel-exported epoch through read-only shared memory. The "extra" + here is a whole extra epoch -- the external one, shadow-tracked + internally so that only its changes are forwarded. Every epoch read + (every invalidation check, in every instance) consults the getter; a + changed value advances the process-global epoch exactly once per change + before the shadow is updated, so an external event is detected at the + first check after it lands, with no thread of control required on the + receiving side. Events between checks coalesce into one advance. + Under concurrency the accounting is best-effort in the safe direction: + racing readers can each advance for the same external change, and a + duplicate advance (with its duplicate publication, when a publisher is + registered) costs at most a spurious recovery cycle. Duplicates are + tolerated by design -- the alternative single-broadcaster protocols + can lose an advance outright, which is never tolerable. + + The getter must be cheap, nonblocking, callable concurrently, and must + not call into wolfCrypt (every wolfCrypt invalidation check would + recurse). It returns the external epoch, or + WC_RNG_ENTROPY_EPOCH_INVALID (0) when no signal is available, which + makes the read inert. + + Registration probes the getter once: a 0 result refuses the + registration and leaves the slot unclaimed. A successful registration + primes the shadow with the probed value, so registering is itself quiet + -- material seeded before registration is trusted. For a conservative + start that distrusts it instead, call + wc_RNG_global_invalidate_entropy() after this call returns. + Registration is one-shot for the life of the process, with no + deregistration, by design. + + \return 0 Success: every subsequent epoch read consults the getter. + \return BAD_FUNC_ARG handler is null, or its probe returned + WC_RNG_ENTROPY_EPOCH_INVALID. + \return ALREADY_E a source is already registered. + \return BUSY_E lost a registration race; nothing was registered by this + call. + + \param handler The getter callback. + \param arg Opaque argument passed to the callback. + + \sa wc_RNG_get_global_entropy_epoch + \sa wc_RNG_global_invalidate_entropy + \sa wc_RNG_entropy_epoch_extra_inv_init \sa wc_RNG_entropy_needs_recovery */ -WC_ATOMIC_UINT_ARG wc_RNG_get_global_entropy_epoch(void); +int wc_RNG_extra_entropy_epoch_init( + wc_RNG_extra_entropy_epoch_get_handler_t handler, + void *arg); /*! \ingroup Random diff --git a/linuxkm/lkcapi_sha_glue.c b/linuxkm/lkcapi_sha_glue.c index c23c5d6cbe9..71056189df8 100644 --- a/linuxkm/lkcapi_sha_glue.c +++ b/linuxkm/lkcapi_sha_glue.c @@ -3568,7 +3568,7 @@ static int wc_linuxkm_entropy_daemon(void *arg) if (ret == 0) { ret = wc_RNG_lock_get_unconditional(global_fallback_rng); if (ret == 0) { - ret = wc_RNG_DRBG_NextSeedNow_Nonce( + ret = wc_RNG_DRBG_NextSeedNow_AddIn( global_fallback_rng, (byte *)&uncredited_nonce, (word32)sizeof uncredited_nonce); @@ -4508,7 +4508,7 @@ static int wc_linuxkm_drbg_generate(struct wc_rng_bank *ctx, ) { unsigned long uncredited_nonce = random_get_entropy(); - ret = wc_RNG_DRBG_NextSeedNow_Nonce(WC_RNG_BANK_INST_TO_RNG(drbg), + ret = wc_RNG_DRBG_NextSeedNow_AddIn(WC_RNG_BANK_INST_TO_RNG(drbg), (byte *)&uncredited_nonce, (word32)sizeof uncredited_nonce); ForceZero(&uncredited_nonce, (word32)sizeof uncredited_nonce); diff --git a/tests/api/test_random.c b/tests/api/test_random.c index e9676986574..c4b2c16afdf 100644 --- a/tests/api/test_random.c +++ b/tests/api/test_random.c @@ -1807,37 +1807,37 @@ int test_wc_DrbgReworkDecisionCoverage(void) XMEMSET(&rng, 0, sizeof(rng)); ExpectIntEQ(wc_InitRng_ex(&rng, HEAP_HINT, INVALID_DEVID), 0); - /* wc_RNG_DRBG_Reseed_Nonce: "nonce == NULL && nonceSz > 0" pair. */ - ExpectIntEQ(wc_RNG_DRBG_Reseed_Nonce(&rng, seed, sizeof(seed), NULL, + /* wc_RNG_DRBG_Reseed_AddIn: "nonce == NULL && nonceSz > 0" pair. */ + ExpectIntEQ(wc_RNG_DRBG_Reseed_AddIn(&rng, seed, sizeof(seed), NULL, sizeof(nonce)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); #if defined(WC_RNG_HAVE_RBGC) && defined(WC_RNG_RBGC_STRATUM_IMMUTABLE) - ExpectIntEQ(wc_RNG_DRBG_Reseed_Nonce(&rng, seed, sizeof(seed), nonce, + ExpectIntEQ(wc_RNG_DRBG_Reseed_AddIn(&rng, seed, sizeof(seed), nonce, sizeof(nonce)), WC_NO_ERR_TRACE(WRONG_TYPE_OBJECT_E)); - ExpectIntEQ(wc_RNG_DRBG_Reseed_Nonce(&rng, seed, sizeof(seed), nonce, 0), + ExpectIntEQ(wc_RNG_DRBG_Reseed_AddIn(&rng, seed, sizeof(seed), nonce, 0), WC_NO_ERR_TRACE(WRONG_TYPE_OBJECT_E)); #else - ExpectIntEQ(wc_RNG_DRBG_Reseed_Nonce(&rng, seed, sizeof(seed), nonce, + ExpectIntEQ(wc_RNG_DRBG_Reseed_AddIn(&rng, seed, sizeof(seed), nonce, sizeof(nonce)), 0); - ExpectIntEQ(wc_RNG_DRBG_Reseed_Nonce(&rng, seed, sizeof(seed), nonce, 0), + ExpectIntEQ(wc_RNG_DRBG_Reseed_AddIn(&rng, seed, sizeof(seed), nonce, 0), 0); #endif - /* wc_RNG_DRBG_Stir_Nonce: rng/seed NULL pair, nonce pair, and the + /* wc_RNG_DRBG_Stir_AddIn: rng/seed NULL pair, nonce pair, and the * second-chunk decision (nonce non-NULL with zero size). */ - ExpectIntEQ(wc_RNG_DRBG_Stir_Nonce(NULL, seed, sizeof(seed), nonce, + ExpectIntEQ(wc_RNG_DRBG_Stir_AddIn(NULL, seed, sizeof(seed), nonce, sizeof(nonce)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_RNG_DRBG_Stir_Nonce(&rng, NULL, sizeof(seed), nonce, + ExpectIntEQ(wc_RNG_DRBG_Stir_AddIn(&rng, NULL, sizeof(seed), nonce, sizeof(nonce)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_RNG_DRBG_Stir_Nonce(&rng, seed, sizeof(seed), NULL, + ExpectIntEQ(wc_RNG_DRBG_Stir_AddIn(&rng, seed, sizeof(seed), NULL, sizeof(nonce)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_RNG_DRBG_Stir_Nonce(&rng, seed, sizeof(seed), nonce, + ExpectIntEQ(wc_RNG_DRBG_Stir_AddIn(&rng, seed, sizeof(seed), nonce, sizeof(nonce)), 0); - ExpectIntEQ(wc_RNG_DRBG_Stir_Nonce(&rng, seed, sizeof(seed), nonce, 0), + ExpectIntEQ(wc_RNG_DRBG_Stir_AddIn(&rng, seed, sizeof(seed), nonce, 0), 0); /* wc_RNG_DRBG_Stir: valid seed only (no nonce chunk). */ @@ -1953,12 +1953,12 @@ int test_wc_RngInitFlagsDecisionCoverage(void) ExpectIntEQ(wc_GenerateSeed(&os, NULL, sizeof(out)), BAD_FUNC_ARG); #endif - /* wc_RNG_DRBG_Stir_Nonce with a valid rng and a NULL seed: the + /* wc_RNG_DRBG_Stir_AddIn with a valid rng and a NULL seed: the * rng-NULL clause's false side. */ XMEMSET(&rng, 0, sizeof(rng)); ExpectIntEQ(wc_InitRng_ex2(&rng, HEAP_HINT, INVALID_DEVID, WC_RNG_INIT_FLAG_NONE), 0); - ExpectIntEQ(wc_RNG_DRBG_Stir_Nonce(&rng, NULL, 0, out, sizeof(out)), + ExpectIntEQ(wc_RNG_DRBG_Stir_AddIn(&rng, NULL, 0, out, sizeof(out)), BAD_FUNC_ARG); ExpectIntEQ(wc_FreeRng(&rng), 0); #endif diff --git a/tests/unit-mcdc/test_random_fault_whitebox.c b/tests/unit-mcdc/test_random_fault_whitebox.c index 96335ec854c..0ed8c5f5edb 100644 --- a/tests/unit-mcdc/test_random_fault_whitebox.c +++ b/tests/unit-mcdc/test_random_fault_whitebox.c @@ -1301,11 +1301,11 @@ static void wb_drbg_reseedctr_type_rows(void) #endif /* -------------------------------------------------------------------------- - * 11. wc_RNG_DRBG_Stir_Nonce() argument guard: + * 11. wc_RNG_DRBG_Stir_AddIn() argument guard: * :2550 (rng == NULL) || (seed == NULL) * * c0 (rng == NULL) is the open operand. c0-T is a structural residual: the - * public wc_RNG_DRBG_Stir_Nonce wrapper guards rng == NULL before calling the + * public wc_RNG_DRBG_Stir_AddIn wrapper guards rng == NULL before calling the * _local function, so the _local guard never sees a NULL rng. The reachable * row is c0-F + c1-T (valid rng, seed == NULL). * ------------------------------------------------------------------------- */ @@ -1320,13 +1320,13 @@ static void wb_stir_nonce_null_rng(void) XMEMSET(nonce, 0xBB, sizeof(nonce)); /* 2550 c0-T: rng == NULL (seed present, so the row is c0's). */ - (void)wc_RNG_DRBG_Stir_Nonce(NULL, seed, sizeof(seed), nonce, + (void)wc_RNG_DRBG_Stir_AddIn(NULL, seed, sizeof(seed), nonce, sizeof(nonce)); /* 2550 c0-F: valid rng, seed == NULL (decision true via the seed arm). */ XMEMSET(&rng, 0, sizeof(rng)); if (wc_InitRng(&rng) == 0) { - (void)wc_RNG_DRBG_Stir_Nonce(&rng, NULL, 0, nonce, sizeof(nonce)); + (void)wc_RNG_DRBG_Stir_AddIn(&rng, NULL, 0, nonce, sizeof(nonce)); (void)wc_FreeRng(&rng); } diff --git a/tests/unit-mcdc/test_random_whitebox.c b/tests/unit-mcdc/test_random_whitebox.c index 40271f61b6d..22046ca24ed 100644 --- a/tests/unit-mcdc/test_random_whitebox.c +++ b/tests/unit-mcdc/test_random_whitebox.c @@ -765,13 +765,13 @@ static void wb_stir_nonce_local(void) } /* :2550 rows: (rng==NULL) and (rng!=NULL, seed==NULL). */ - if (wc_RNG_DRBG_Stir_Nonce_local(NULL, seed, sizeof(seed), + if (wc_RNG_DRBG_Stir_AddIn_local(NULL, seed, sizeof(seed), nonce, sizeof(nonce)) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { WB_NOTE("stir-nonce rng==NULL not rejected"); wb_fail = 1; } - if (wc_RNG_DRBG_Stir_Nonce_local(&rng, NULL, 0, + if (wc_RNG_DRBG_Stir_AddIn_local(&rng, NULL, 0, nonce, sizeof(nonce)) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { WB_NOTE("stir-nonce seed==NULL not rejected"); @@ -779,7 +779,7 @@ static void wb_stir_nonce_local(void) } /* Baseline: all-valid stir, nonce chunk evaluated with ret==0. */ - ret = wc_RNG_DRBG_Stir_Nonce_local(&rng, seed, sizeof(seed), + ret = wc_RNG_DRBG_Stir_AddIn_local(&rng, seed, sizeof(seed), nonce, sizeof(nonce)); if (ret != 0) { WB_NOTE("stir-nonce valid call failed"); @@ -788,13 +788,13 @@ static void wb_stir_nonce_local(void) /* :2566 nonce-operand rows: ret==0 with nonce==NULL and with * nonce!=NULL/nonceSz==0, pairing the nonce-true baseline above. */ - ret = wc_RNG_DRBG_Stir_Nonce_local(&rng, seed, sizeof(seed), + ret = wc_RNG_DRBG_Stir_AddIn_local(&rng, seed, sizeof(seed), NULL, 0); if (ret != 0) { WB_NOTE("stir-nonce no-nonce call failed"); wb_fail = 1; } - ret = wc_RNG_DRBG_Stir_Nonce_local(&rng, seed, sizeof(seed), + ret = wc_RNG_DRBG_Stir_AddIn_local(&rng, seed, sizeof(seed), nonce, 0); if (ret != 0) { WB_NOTE("stir-nonce zero-length-nonce call failed"); @@ -804,7 +804,7 @@ static void wb_stir_nonce_local(void) /* :2566 ret!=0 row: reseed due, live nonce pending. The reseed counter * now belongs to WC_RNG and is shared by both DRBG widths. */ rng.reseedCtr = WC_RESEED_INTERVAL; - ret = wc_RNG_DRBG_Stir_Nonce_local(&rng, seed, sizeof(seed), + ret = wc_RNG_DRBG_Stir_AddIn_local(&rng, seed, sizeof(seed), nonce, sizeof(nonce)); if (ret == 0) { WB_NOTE("stir-nonce with saturated reseed counter succeeded"); diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 65bb0a3a277..38acc77f357 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -179,10 +179,6 @@ This library contains implementation for the random number generator. wc_static_assert(WC_RNG_LOCK_FREE == 0); #endif -#ifdef WC_RNG_HAVE_ENTROPY_EPOCH - static wolfSSL_Atomic_Uint global_entropy_epoch = WOLFSSL_ATOMIC_INITIALIZER(1U); -#endif - #if defined(WOLFSSL_SGX) #include #elif defined(USE_WINDOWS_API) @@ -360,6 +356,173 @@ wc_static_assert(DRBG_SUCCESS == 0); #define DRBG_FAILED WC_DRBG_FAILED #define DRBG_CONT_FAILED WC_DRBG_CONT_FAILED +#ifdef WC_RNG_HAVE_ENTROPY_EPOCH + static struct wc_RNG_entropy_epoch_atomic global_entropy_epoch = + WC_RNG_ENTROPY_EPOCH_ATOMIC_INITIALIZER; + static struct wc_RNG_entropy_epoch_atomic extra_entropy_epoch_local = + WC_RNG_ENTROPY_EPOCH_ATOMIC_INVALID; + static wc_RNG_extra_entropy_epoch_get_handler_t + extra_entropy_epoch_get_handler = NULL; + static byte invalid_arg_sentinel; + static void *extra_entropy_epoch_get_arg = &invalid_arg_sentinel; + + int wc_RNG_extra_entropy_epoch_init( + wc_RNG_extra_entropy_epoch_get_handler_t handler, + void *arg) + { + wc_RNG_extra_entropy_epoch_get_handler_t + cur_extra_entropy_epoch_get_handler = + extra_entropy_epoch_get_handler; + wc_RNG_entropy_epoch_t init_extra_entropy_epoch; + if (handler == NULL) + return BAD_FUNC_ARG; + if (extra_entropy_epoch_get_handler != NULL) + return ALREADY_E; + init_extra_entropy_epoch = handler(arg); + if (init_extra_entropy_epoch == WC_RNG_ENTROPY_EPOCH_INVALID) + return BAD_FUNC_ARG; + if (wolfSSL_Atomic_Func_Ptr_CompareExchange( + &extra_entropy_epoch_get_handler, + &cur_extra_entropy_epoch_get_handler, + handler)) + { + (void)wc_RNG_entropy_epoch_import(WC_RNG_ENTROPY_EPOCH_INVALID, + init_extra_entropy_epoch, + &extra_entropy_epoch_local); + extra_entropy_epoch_get_arg = arg; + return 0; + } + else + return BUSY_E; + } + + /* _TEST_VIS routine to allow swapping of handlers. Minimal safety + * provisions -- only safe to use where no threads need synchronizing, due + * to tearing of handler from arg. */ + int wc_RNG_extra_entropy_epoch_reset( + wc_RNG_extra_entropy_epoch_get_handler_t *handler, + void **arg) + { + wc_RNG_entropy_epoch_t init_extra_entropy_epoch; + if ((handler == NULL) || (arg == NULL)) + return BAD_FUNC_ARG; + *handler = extra_entropy_epoch_get_handler; + if (*handler == NULL) + return BAD_STATE_E; + *arg = extra_entropy_epoch_get_arg; + init_extra_entropy_epoch = + wc_RNG_entropy_epoch_export(&extra_entropy_epoch_local); + if (! wolfSSL_Atomic_Func_Ptr_CompareExchange( + &extra_entropy_epoch_get_handler, + handler, + NULL)) + return BUSY_E; + if (! wc_RNG_entropy_epoch_import(init_extra_entropy_epoch, + WC_RNG_ENTROPY_EPOCH_INVALID, + &extra_entropy_epoch_local)) + { + wc_RNG_extra_entropy_epoch_get_handler_t expected_null = NULL; + (void)wolfSSL_Atomic_Func_Ptr_CompareExchange( + &extra_entropy_epoch_get_handler, + &expected_null, + *handler); + return BUSY_E; + } + extra_entropy_epoch_get_arg = &invalid_arg_sentinel; + return 0; + } + + static WC_INLINE wc_RNG_entropy_epoch_t current_entropy_epoch(void) { + if ((extra_entropy_epoch_get_handler != NULL) && + (extra_entropy_epoch_get_arg != &invalid_arg_sentinel)) + { + wc_RNG_entropy_epoch_t cur_extra_entropy_epoch = + extra_entropy_epoch_get_handler(extra_entropy_epoch_get_arg); + if (cur_extra_entropy_epoch != WC_RNG_ENTROPY_EPOCH_INVALID) { + wc_RNG_entropy_epoch_t cur_extra_entropy_epoch_local = + wc_RNG_entropy_epoch_export(&extra_entropy_epoch_local); + if (cur_extra_entropy_epoch != cur_extra_entropy_epoch_local) { + wc_RNG_global_invalidate_entropy(); + (void)wc_RNG_entropy_epoch_import( + cur_extra_entropy_epoch_local, + cur_extra_entropy_epoch, + &extra_entropy_epoch_local); + } + } + } + return wc_RNG_entropy_epoch_export(&global_entropy_epoch); + } + + wc_RNG_entropy_epoch_t wc_RNG_get_global_entropy_epoch(void) { + return current_entropy_epoch(); + } + + static wc_RNG_entropy_epoch_extra_inv_handler_t + entropy_epoch_extra_inv_handler = NULL; + static void *entropy_epoch_extra_inv_arg = &invalid_arg_sentinel; + int wc_RNG_entropy_epoch_extra_inv_init( + wc_RNG_entropy_epoch_extra_inv_handler_t handler, void *arg) + { + wc_RNG_entropy_epoch_extra_inv_handler_t + cur_entropy_epoch_extra_inv_handler = + entropy_epoch_extra_inv_handler; + if (handler == NULL) + return BAD_FUNC_ARG; + if (cur_entropy_epoch_extra_inv_handler != NULL) + return ALREADY_E; + if (wolfSSL_Atomic_Func_Ptr_CompareExchange( + &entropy_epoch_extra_inv_handler, + &cur_entropy_epoch_extra_inv_handler, + handler)) + { + entropy_epoch_extra_inv_arg = arg; + return 0; + } + else + return BUSY_E; + } + + /* _TEST_VIS routine to allow swapping of handlers. Minimal safety + * provisions -- only safe to use where no threads need synchronizing, due + * to tearing of handler from arg. */ + int wc_RNG_entropy_epoch_extra_inv_reset( + wc_RNG_entropy_epoch_extra_inv_handler_t *handler, void **arg) + { + if ((handler == NULL) || (arg == NULL)) + return BAD_FUNC_ARG; + *handler = entropy_epoch_extra_inv_handler; + if (*handler == NULL) + return BAD_STATE_E; + *arg = entropy_epoch_extra_inv_arg; + if (! wolfSSL_Atomic_Func_Ptr_CompareExchange( + &entropy_epoch_extra_inv_handler, + handler, + NULL)) + return BUSY_E; + entropy_epoch_extra_inv_arg = &invalid_arg_sentinel; + return 0; + } + + wc_RNG_entropy_epoch_t wc_RNG_global_invalidate_entropy(void) { + wc_RNG_entropy_epoch_t new_epoch = + wc_RNG_entropy_epoch_increment_atomic(&global_entropy_epoch); + /* Note that extra invalidation propagation is only guaranteed after + * wc_RNG_entropy_epoch_extra_inv_init() has returned with success -- + * for guaranteed propagation, callers must defer normal service until + * after completion. The handler must not call back into wolfCrypt: + * any epoch read from inside it re-detects the same event and + * recurses. */ + if ((entropy_epoch_extra_inv_handler != NULL) && + (entropy_epoch_extra_inv_arg != &invalid_arg_sentinel)) + { + entropy_epoch_extra_inv_handler( + new_epoch, + entropy_epoch_extra_inv_arg); + } + return new_epoch; + } +#endif /* WC_RNG_HAVE_ENTROPY_EPOCH */ + /* enforcement helper for WC_RNG_LOCK_REQUIRED: instance-consuming public APIs * call this on entry. (WC_RNG_LOCK_ENTROPY_INVALIDATED is deliberately not * enforced here -- see the body.) */ @@ -1060,7 +1223,7 @@ static WARN_UNUSED_RESULT int Hash256_DRBG_Reseed(DRBG_internal* drbg, * (_PRODUCING or _CONSUMING) is repainted _PURGED instead: the holder * still owns the buffer, so it is the holder that wipes and reopens -- * the producer in NextSeedProducerRelease(), the consumer in - * wc_RNG_DRBG_NextSeedNow_Nonce_local()'s failed-release arm. Reopening + * wc_RNG_DRBG_NextSeedNow_AddIn_local()'s failed-release arm. Reopening * EMPTY from under a live holder would let a producer claim and begin a * fill that the holder's own trailing wipe then tears. * The health-test burn arm wipes under its own PRODUCING claim. @@ -1201,7 +1364,7 @@ static WC_MAYBE_UNUSED void NextStirPurge(WC_RNG* rng) #endif /* WC_RNG_HAVE_NEXT_SEED */ /* in_bracketed_consume: nonzero when the caller feeds this reseed from its own - * _CONSUMING claim on the credited aperture (wc_RNG_DRBG_NextSeedNow_Nonce()). + * _CONSUMING claim on the credited aperture (wc_RNG_DRBG_NextSeedNow_AddIn()). * The invalidated-entry purges below must then exempt that aperture: purging * it would steal the caller's claim and defeat its release CAS, converting * the caller's own recovery into a false epoch violation. An external @@ -1211,7 +1374,9 @@ static WARN_UNUSED_RESULT int Hash_DRBG_Reseed(WC_RNG* rng, const byte* seed, word32 seedSz, const byte* additional, word32 additionalSz, int in_bracketed_consume, - WC_ATOMIC_UINT_ARG cur_epoch, +#ifdef WC_RNG_HAVE_ENTROPY_EPOCH + wc_RNG_entropy_epoch_t cur_epoch, +#endif WC_RNG_PID_ARG my_pid) { int ret; @@ -1219,9 +1384,6 @@ static WARN_UNUSED_RESULT int Hash_DRBG_Reseed(WC_RNG* rng, const byte* seed, WC_RNG_lock_arg_t cur_lock; #endif -#ifndef WC_RNG_HAVE_ENTROPY_EPOCH - (void)cur_epoch; -#endif #if !defined(HAVE_GETPID) || defined(WOLFSSL_NO_GETPID) (void)my_pid; #endif @@ -1426,7 +1588,7 @@ static WARN_UNUSED_RESULT int Hash_DRBG_Reseed(WC_RNG* rng, const byte* seed, */ if ((ret == 0) && (cur_lock & WC_RNG_LOCK_ENTROPY_INVALIDATED) #ifdef WC_RNG_HAVE_ENTROPY_EPOCH - && (cur_epoch == WOLFSSL_ATOMIC_LOAD(global_entropy_epoch)) + && (cur_epoch == current_entropy_epoch()) #endif ) { @@ -1487,17 +1649,13 @@ static WARN_UNUSED_RESULT int Hash_DRBG_Reseed(WC_RNG* rng, const byte* seed, return ret; } -int wc_RNG_DRBG_Reseed_Nonce(WC_RNG* rng, const byte* seed, word32 seedSz, - const byte *nonce, word32 nonceSz) +int wc_RNG_DRBG_Reseed_AddIn(WC_RNG* rng, const byte* seed, word32 seedSz, + const byte *addIn, word32 addInSz) { int ret; - WC_ATOMIC_UINT_ARG cur_epoch = #ifdef WC_RNG_HAVE_ENTROPY_EPOCH - WOLFSSL_ATOMIC_LOAD(global_entropy_epoch) -#else - 0 + wc_RNG_entropy_epoch_t cur_epoch = current_entropy_epoch(); #endif - ; WC_RNG_PID_ARG my_pid = WC_RNG_GETPID(); if (rng == NULL || seed == NULL) { return BAD_FUNC_ARG; @@ -1506,7 +1664,7 @@ int wc_RNG_DRBG_Reseed_Nonce(WC_RNG* rng, const byte* seed, word32 seedSz, /* Hash_df() skips a NULL input regardless of its stated length, so * without this the caller's additional input would be dropped and * success reported. Matches _InitRng() and ReseedRBGC(). */ - if ((nonce == NULL) && (nonceSz > 0)) + if ((addIn == NULL) && (addInSz > 0)) return BAD_FUNC_ARG; #if defined(WC_RNG_HAVE_RBGC) && defined(WC_RNG_RBGC_STRATUM_IMMUTABLE) @@ -1545,14 +1703,14 @@ int wc_RNG_DRBG_Reseed_Nonce(WC_RNG* rng, const byte* seed, word32 seedSz, /* Never allow an undersized seed to clear an invalidated state. Note that * the user seed is not evaluated by wc_RNG_TestSeed() -- calling * wc_RNG_TestSeed() is the user's responsibility, and is inapplicable when - * wc_InitRngNonce_UserSeed() and wc_RNG_DRBG_Reseed_Nonce() are called from + * wc_InitRngAddIn_UserSeed() and wc_RNG_DRBG_Reseed_AddIn() are called from * KAT tests, or are seeded by another healthy DRBG. * * Historically, wc_RNG_DRBG_Reseed() has never imposed wc_RNG_TestSeed(), * i.e. it has always succeeded deterministically when passed valid - * arguments. wc_RNG_DRBG_Reseed_Nonce() continues that semantic whether + * arguments. wc_RNG_DRBG_Reseed_AddIn() continues that semantic whether * called directly or via wc_RNG_DRBG_Reseed(). Novel enforcement here is - * frivolous in any case because wc_InitRngNonce_UserSeed() imposes no + * frivolous in any case because wc_InitRngAddIn_UserSeed() imposes no * wc_RNG_TestSeed(). */ { @@ -1568,8 +1726,12 @@ int wc_RNG_DRBG_Reseed_Nonce(WC_RNG* rng, const byte* seed, word32 seedSz, } } - ret = Hash_DRBG_Reseed(rng, seed, seedSz, nonce, nonceSz, - 0 /* in_bracketed_consume */, cur_epoch, my_pid); + ret = Hash_DRBG_Reseed(rng, seed, seedSz, addIn, addInSz, + 0 /* in_bracketed_consume */, +#ifdef WC_RNG_HAVE_ENTROPY_EPOCH + cur_epoch, +#endif + my_pid); if (ret > 0) /* DRBG-internal code: translate at the API */ ret = RNG_FAILURE_E; #if defined(WC_RNG_HAVE_RBGC) && !defined(WC_RNG_RBGC_STRATUM_IMMUTABLE) @@ -1593,7 +1755,7 @@ int wc_RNG_DRBG_Reseed_Nonce(WC_RNG* rng, const byte* seed, word32 seedSz, } int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* seed, word32 seedSz) { - return wc_RNG_DRBG_Reseed_Nonce(rng, seed, seedSz, NULL, 0); + return wc_RNG_DRBG_Reseed_AddIn(rng, seed, seedSz, NULL, 0); } #ifdef WC_RNG_HAVE_RBGC @@ -2843,13 +3005,13 @@ static WARN_UNUSED_RESULT int Hash_DRBG_StirGenerate(WC_RNG* rng, return ret; } -static WARN_UNUSED_RESULT int wc_RNG_DRBG_Stir_Nonce_local(WC_RNG* rng, +static WARN_UNUSED_RESULT int wc_RNG_DRBG_Stir_AddIn_local(WC_RNG* rng, const byte* seed, word32 seedSz, - const byte *nonce, word32 nonceSz) + const byte *addIn, word32 addInSz) { if (rng == NULL || seed == NULL) return BAD_FUNC_ARG; - if ((nonce == NULL) && (nonceSz != 0)) + if ((addIn == NULL) && (addInSz != 0)) return BAD_FUNC_ARG; if (rng->status != WC_DRBG_OK) @@ -2863,18 +3025,18 @@ static WARN_UNUSED_RESULT int wc_RNG_DRBG_Stir_Nonce_local(WC_RNG* rng, { int ret = Hash_DRBG_StirGenerate(rng, seed, seedSz); - if ((ret == 0) && (nonce != NULL) && (nonceSz > 0)) { + if ((ret == 0) && (addIn != NULL) && (addInSz > 0)) { /* Second chunk as its own specified generate: additional * input is per-call, and chunking beats concatenation * scratch. */ - ret = Hash_DRBG_StirGenerate(rng, nonce, nonceSz); + ret = Hash_DRBG_StirGenerate(rng, addIn, addInSz); } return ret; } } -int wc_RNG_DRBG_Stir_Nonce(WC_RNG* rng, const byte* seed, word32 seedSz, - const byte *nonce, word32 nonceSz) +int wc_RNG_DRBG_Stir_AddIn(WC_RNG* rng, const byte* seed, word32 seedSz, + const byte *addIn, word32 addInSz) { int ret; @@ -2883,14 +3045,14 @@ int wc_RNG_DRBG_Stir_Nonce(WC_RNG* rng, const byte* seed, word32 seedSz, ret = RngAutoLockEnter(rng); if (ret != 0) return ret; - ret = wc_RNG_DRBG_Stir_Nonce_local(rng, seed, seedSz, nonce, nonceSz); + ret = wc_RNG_DRBG_Stir_AddIn_local(rng, seed, seedSz, addIn, addInSz); RngAutoLockExit(rng); return ret; } int wc_RNG_DRBG_Stir(WC_RNG* rng, const byte* seed, word32 seedSz) { - return wc_RNG_DRBG_Stir_Nonce(rng, seed, seedSz, NULL, 0); + return wc_RNG_DRBG_Stir_AddIn(rng, seed, seedSz, NULL, 0); } /* SP800-90B 4.4 health tests run over conditioned seed material, which makes @@ -3595,7 +3757,7 @@ static WARN_UNUSED_RESULT int _InitRng(WC_RNG* rng, #ifdef WC_RNG_HAVE_ENTROPY_EPOCH /* note this assignment must precede the later seed operation. */ - rng->entropy_epoch = WOLFSSL_ATOMIC_LOAD(global_entropy_epoch); + rng->entropy_epoch = current_entropy_epoch(); #endif #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) @@ -4682,7 +4844,7 @@ int wc_RNG_lock_get(WC_RNG* rng, WC_RNG_lock_arg_t extra_bits) (wc_RNG_DRBG_NextSeedCurrent(rng, &NextSeedCurrent) == 0) && (NextSeedCurrent == WC_DRBG_NEXT_SEED_READY) #ifdef WC_RNG_HAVE_ENTROPY_EPOCH - && (rng->entropy_epoch == WOLFSSL_ATOMIC_LOAD(global_entropy_epoch)) + && (rng->entropy_epoch == current_entropy_epoch()) #endif #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) && (rng->pid == getpid()) @@ -4922,7 +5084,7 @@ int wc_RNG_lock_put(WC_RNG* rng, WC_RNG_lock_arg_t extra_bits) * the latch carries, delivered lazily: report it here so that a holder * whose last operation straddled the event learns of it at release. The * read is unleased by design (see rng_entropy_event_propagate()). */ - if (rng->entropy_epoch != WOLFSSL_ATOMIC_LOAD(global_entropy_epoch)) + if (rng->entropy_epoch != current_entropy_epoch()) return NEEDS_RECOVERY_E; #endif return 0; @@ -4985,7 +5147,7 @@ int wc_RNG_lock_put_conditional(WC_RNG* rng, return NEEDS_RECOVERY_E; #ifdef WC_RNG_HAVE_ENTROPY_EPOCH /* as in wc_RNG_lock_put() */ - if (rng->entropy_epoch != WOLFSSL_ATOMIC_LOAD(global_entropy_epoch)) + if (rng->entropy_epoch != current_entropy_epoch()) return NEEDS_RECOVERY_E; #endif return 0; @@ -5107,7 +5269,7 @@ WOLFSSL_API int wc_RNG_invalidate_entropy(WC_RNG* rng) { #ifdef WC_RNG_HAVE_ENTROPY_EPOCH /* Load the event epoch before any purge: an increment mid-delivery leaves * the stamp stale, forcing a conservative propagation. */ - WC_ATOMIC_UINT_ARG ev_epoch = WOLFSSL_ATOMIC_LOAD(global_entropy_epoch); + wc_RNG_entropy_epoch_t ev_epoch = current_entropy_epoch(); #endif #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) pid_t my_pid = getpid(); @@ -5196,7 +5358,7 @@ WOLFSSL_API int wc_RNG_invalidate_entropy(WC_RNG* rng) { * post-purge apertures, so a READY it then claims necessarily postdates * this event; a consumer that raced ahead of the latch loses its claim * to the purge above and is refused at its release CAS (see - * wc_RNG_DRBG_NextSeedNow_Nonce()); and an event landing mid-reseed + * wc_RNG_DRBG_NextSeedNow_AddIn()); and an event landing mid-reseed * strips _ENTROPY_RECOVERING here, so the recovery's exit CAS refuses * the clear. No interleaving recovers from pre-event material. */ @@ -5278,7 +5440,7 @@ static WC_MAYBE_UNUSED int rng_entropy_event_propagate(WC_RNG* rng) if (! wc_RNG_DRBG_Present(rng)) return 0; #ifdef WC_RNG_HAVE_ENTROPY_EPOCH - if (rng->entropy_epoch != WOLFSSL_ATOMIC_LOAD(global_entropy_epoch)) + if (rng->entropy_epoch != current_entropy_epoch()) ret = NEEDS_RECOVERY_E; #endif #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) @@ -5316,7 +5478,7 @@ WOLFSSL_API int wc_RNG_entropy_needs_recovery(WC_RNG* rng) { return ret; #else #ifdef WC_RNG_HAVE_ENTROPY_EPOCH - if (rng->entropy_epoch != WOLFSSL_ATOMIC_LOAD(global_entropy_epoch)) + if (rng->entropy_epoch != current_entropy_epoch()) return NEEDS_RECOVERY_E; #endif #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) @@ -5337,16 +5499,6 @@ WOLFSSL_API int wc_RNG_entropy_needs_recovery(WC_RNG* rng) { return 0; } -#ifdef WC_RNG_HAVE_ENTROPY_EPOCH -WOLFSSL_API WC_ATOMIC_UINT_ARG wc_RNG_global_invalidate_entropy(void) { - return wolfSSL_Atomic_Uint_AddFetch(&global_entropy_epoch, 1U); -} - -WC_ATOMIC_UINT_ARG wc_RNG_get_global_entropy_epoch(void) { - return WOLFSSL_ATOMIC_LOAD(global_entropy_epoch); -} -#endif - #ifdef WC_RNG_HAVE_FREE_HOOK /* This routine is used for mitigation of RNG cloning events, particularly by * hypervisors. */ @@ -6063,13 +6215,9 @@ static WARN_UNUSED_RESULT int wc_RNG_DRBG_ReseedRBGC_local( byte seed[SEED_SZ]; #endif int ret; - WC_ATOMIC_UINT_ARG cur_epoch = #ifdef WC_RNG_HAVE_ENTROPY_EPOCH - WOLFSSL_ATOMIC_LOAD(global_entropy_epoch) -#else - 0 + wc_RNG_entropy_epoch_t cur_epoch = current_entropy_epoch(); #endif - ; WC_RNG_PID_ARG my_pid = WC_RNG_GETPID(); if ((rng == NULL) || (root == NULL) || (rng == root) || @@ -6174,7 +6322,10 @@ static WARN_UNUSED_RESULT int wc_RNG_DRBG_ReseedRBGC_local( if (ret == 0) { if (credited) { ret = Hash_DRBG_Reseed(rng, seed, SEED_SZ, nonce, nonceSz, - 0 /* in_bracketed_consume */, cur_epoch, + 0 /* in_bracketed_consume */, +#ifdef WC_RNG_HAVE_ENTROPY_EPOCH + cur_epoch, +#endif my_pid); if (ret > 0) /* DRBG-internal code: translate at the API */ ret = RNG_FAILURE_E; @@ -6188,7 +6339,7 @@ static WARN_UNUSED_RESULT int wc_RNG_DRBG_ReseedRBGC_local( } } else { - ret = wc_RNG_DRBG_Stir_Nonce_local(rng, seed, SEED_SZ, nonce, + ret = wc_RNG_DRBG_Stir_AddIn_local(rng, seed, SEED_SZ, nonce, nonceSz); } } @@ -6226,13 +6377,9 @@ static WARN_UNUSED_RESULT int PollAndReSeed(WC_RNG* rng, const byte* additional, word32 additionalSz) { int ret = WC_NO_ERR_TRACE(DRBG_NEED_RESEED); - WC_ATOMIC_UINT_ARG cur_epoch = #ifdef WC_RNG_HAVE_ENTROPY_EPOCH - WOLFSSL_ATOMIC_LOAD(global_entropy_epoch) -#else - 0 + wc_RNG_entropy_epoch_t cur_epoch = current_entropy_epoch(); #endif - ; WC_RNG_PID_ARG my_pid = WC_RNG_GETPID(); int devId = INVALID_DEVID; #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) @@ -6410,7 +6557,10 @@ static WARN_UNUSED_RESULT int PollAndReSeed(WC_RNG* rng, const byte* additional, if (ret == DRBG_SUCCESS) { ret = Hash_DRBG_Reseed(rng, newSeed + SEED_BLOCK_SZ, SEED_SZ, additional, additionalSz, - 0 /* in_bracketed_consume */, cur_epoch, + 0 /* in_bracketed_consume */, +#ifdef WC_RNG_HAVE_ENTROPY_EPOCH + cur_epoch, +#endif my_pid); #if defined(WC_RNG_HAVE_RBGC) && \ @@ -6450,7 +6600,7 @@ static WARN_UNUSED_RESULT int PollAndReSeed(WC_RNG* rng, const byte* additional, #ifdef WC_RNG_HAVE_ENTROPY_EPOCH if ((ret == 0) && - (cur_epoch != WOLFSSL_ATOMIC_LOAD(global_entropy_epoch))) + (cur_epoch != current_entropy_epoch())) { /* An event landed between the caller's capture and here: the material * reseeded is possibly pre-event. The reseed stands (the state is no @@ -6482,13 +6632,13 @@ static WARN_UNUSED_RESULT int PollAndReSeed(WC_RNG* rng, const byte* additional, * * The caller must hold exclusive access to rng, as for all WC_RNG operations. */ -int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* nonce, word32 nonceSz) +int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* addIn, word32 addInSz) { int ret; if (rng == NULL) return BAD_FUNC_ARG; - if ((nonce == NULL) && (nonceSz > 0)) + if ((addIn == NULL) && (addInSz > 0)) return BAD_FUNC_ARG; ret = rng_lock_required_check(rng); if (ret != 0) @@ -6511,7 +6661,7 @@ int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* nonce, word32 nonceSz) goto out; } - ret = PollAndReSeed(rng, nonce, nonceSz); + ret = PollAndReSeed(rng, addIn, addInSz); if (ret != DRBG_SUCCESS) ret = RngGenerateFailure(rng, ret); @@ -6528,7 +6678,7 @@ int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* nonce, word32 nonceSz) * Multithreaded configurations without _HAVE_LOCK cannot support PR and the flag * RMW it requires. */ int wc_RNG_DRBG_Reseed_Now_Primary(WC_RNG* rng, - const byte* nonce, word32 nonceSz) + const byte* addIn, word32 addInSz) { int ret; if (rng == NULL) @@ -6541,8 +6691,8 @@ int wc_RNG_DRBG_Reseed_Now_Primary(WC_RNG* rng, return WRONG_TYPE_OBJECT_E; #endif #if !defined(WC_RNG_HAVE_LOCK) && !defined(SINGLE_THREADED) - (void)nonce; - (void)nonceSz; + (void)addIn; + (void)addInSz; return NOT_COMPILED_IN; #else /* WC_RNG_HAVE_LOCK || SINGLE_THREADED */ if (rng->flags & WC_RNG_FLAG_NO_PRIMARY_SEED) @@ -6555,7 +6705,7 @@ int wc_RNG_DRBG_Reseed_Now_Primary(WC_RNG* rng, } else restore_flag_bits = 0U; - ret = wc_RNG_DRBG_Reseed_Now(rng, nonce, nonceSz); + ret = wc_RNG_DRBG_Reseed_Now(rng, addIn, addInSz); if (restore_flag_bits) rng->flags &= ~restore_flag_bits; } @@ -6574,11 +6724,11 @@ int wc_RNG_DRBG_Reseed_Now_Primary(WC_RNG* rng, * _NextSeedCurrent() reports the raw aperture value (racy snapshot). * _NextSeedNow() claims a ready bank and performs a source-free * credited reseed with it -- safe in atomic context -- or returns - * NOT_READY_E when no bank is ready; _NextSeedNow_Nonce() is the same - * with a nonce as uncredited additional input. An instance with no + * NOT_READY_E when no bank is ready; _NextSeedNow_AddIn() is the same + * with a addIn as uncredited additional input. An instance with no * DRBG (RDRAND et al.) never opens its seed aperture, and producers * and consumers alike refuse it with WRONG_TYPE_OBJECT_E. The caller - * must own the instance for _NextSeedNow[_Nonce](). */ + * must own the instance for _NextSeedNow[_AddIn](). */ /* Banked-next-seed protocol. * @@ -7076,20 +7226,16 @@ int wc_RNG_DRBG_NextSeedCurrent(const WC_RNG* rng, WC_ATOMIC_INT_ARG* n) * construction); wc_RNG_DRBG_Reseed_Now() remains the live-gather shape. */ /* safe (bounded-at-once) recursion for RBGC reseed. */ /* NOLINTNEXTLINE(misc-no-recursion) */ -static WARN_UNUSED_RESULT int wc_RNG_DRBG_NextSeedNow_Nonce_local( - WC_RNG* rng, const byte* nonce, - word32 nonceSz) +static WARN_UNUSED_RESULT int wc_RNG_DRBG_NextSeedNow_AddIn_local( + WC_RNG* rng, const byte* addIn, + word32 addInSz) { WC_ATOMIC_INT_ARG expected = WC_DRBG_NEXT_SEED_READY; int ret; int devId; - WC_ATOMIC_UINT_ARG cur_epoch = #ifdef WC_RNG_HAVE_ENTROPY_EPOCH - WOLFSSL_ATOMIC_LOAD(global_entropy_epoch) -#else - 0 + wc_RNG_entropy_epoch_t cur_epoch = current_entropy_epoch(); #endif - ; WC_RNG_PID_ARG my_pid = WC_RNG_GETPID(); #ifdef WC_RNG_HAVE_LOCK wc_drbg_reseed_ctr_t baseline_reseedCtr; @@ -7098,7 +7244,7 @@ static WARN_UNUSED_RESULT int wc_RNG_DRBG_NextSeedNow_Nonce_local( if (rng == NULL) return BAD_FUNC_ARG; - if ((nonce == NULL) && (nonceSz != 0)) + if ((addIn == NULL) && (addInSz != 0)) return BAD_FUNC_ARG; ret = rng_lock_required_check(rng); @@ -7158,8 +7304,11 @@ static WARN_UNUSED_RESULT int wc_RNG_DRBG_NextSeedNow_Nonce_local( /* Identical byte accounting to PollAndReSeed(): the SEED_BLOCK_SZ * prefix was consumed by the bank-time health testing. */ ret = Hash_DRBG_Reseed(rng, rng->nextSeed + SEED_BLOCK_SZ, SEED_SZ, - nonce, nonceSz, 1 /* in_bracketed_consume */, - cur_epoch, my_pid); + addIn, addInSz, 1 /* in_bracketed_consume */, +#ifdef WC_RNG_HAVE_ENTROPY_EPOCH + cur_epoch, +#endif + my_pid); /* Use-once: consumed by the attempt, success or not. The scrub must be * visible before the aperture reopens. */ @@ -7319,8 +7468,8 @@ static WARN_UNUSED_RESULT int wc_RNG_DRBG_NextSeedNow_Nonce_local( return ret; } -int wc_RNG_DRBG_NextSeedNow_Nonce(WC_RNG* rng, const byte* nonce, - word32 nonceSz) +int wc_RNG_DRBG_NextSeedNow_AddIn(WC_RNG* rng, const byte* addIn, + word32 addInSz) { int ret; @@ -7329,7 +7478,7 @@ int wc_RNG_DRBG_NextSeedNow_Nonce(WC_RNG* rng, const byte* nonce, ret = RngAutoLockEnter(rng); if (ret != 0) return ret; - ret = wc_RNG_DRBG_NextSeedNow_Nonce_local(rng, nonce, nonceSz); + ret = wc_RNG_DRBG_NextSeedNow_AddIn_local(rng, addIn, addInSz); RngAutoLockExit(rng); return ret; } @@ -7341,12 +7490,12 @@ int wc_RNG_DRBG_NextSeedNow_Nonce(WC_RNG* rng, const byte* nonce, /* safe (bounded-at-once) recursion for RBGC reseed. */ /* NOLINTNEXTLINE(misc-no-recursion) */ static WARN_UNUSED_RESULT int wc_RNG_DRBG_NextSeedNow_local(WC_RNG* rng) { - return wc_RNG_DRBG_NextSeedNow_Nonce_local(rng, NULL, 0); + return wc_RNG_DRBG_NextSeedNow_AddIn_local(rng, NULL, 0); } #endif int wc_RNG_DRBG_NextSeedNow(WC_RNG* rng) { - return wc_RNG_DRBG_NextSeedNow_Nonce(rng, NULL, 0); + return wc_RNG_DRBG_NextSeedNow_AddIn(rng, NULL, 0); } /* Deposit raw uncredited stir material into rng's accumulator. Callable from @@ -7356,11 +7505,11 @@ int wc_RNG_DRBG_NextSeedNow(WC_RNG* rng) { * fragments of compatible provenance are harmless. A full accumulator * publishes WC_DRBG_NEXT_SEED_READY (no health test -- no claim is being made) * and shunts further deposits to xorbuf() until consumed. */ -int wc_RNG_DRBG_NextStirStore(WC_RNG* rng, const byte *nonce, word32 nonceSz) +int wc_RNG_DRBG_NextStirStore(WC_RNG* rng, const byte *addIn, word32 addInSz) { WC_ATOMIC_INT_ARG cur; - if ((rng == NULL) || (nonce == NULL) || (nonceSz == 0)) + if ((rng == NULL) || (addIn == NULL) || (addInSz == 0)) return BAD_FUNC_ARG; /* Note, rng need not be locked -- that's the whole point of the @@ -7372,30 +7521,30 @@ int wc_RNG_DRBG_NextStirStore(WC_RNG* rng, const byte *nonce, word32 nonceSz) if ((cur >= 0) && (cur < (WC_ATOMIC_INT_ARG)sizeof(rng->nextStir))) { word32 fill = (word32)cur; word32 room = (word32)sizeof(rng->nextStir) - fill; - word32 take = (nonceSz < room) ? nonceSz : room; + word32 take = (addInSz < room) ? addInSz : room; - XMEMCPY(rng->nextStir + fill, nonce, take); + XMEMCPY(rng->nextStir + fill, addIn, take); fill += take; if (fill == (word32)sizeof(rng->nextStir)) { WOLFSSL_ATOMIC_STORE(rng->nextStirLen, WC_DRBG_NEXT_SEED_READY); #ifdef WC_RNG_DEBUG_STATS ++rng->_stats_nextstirs_banked; /* racy */ #endif - nonce += take; - nonceSz -= take; /* spillover falls through to the xorbuf() */ + addIn += take; + addInSz -= take; /* spillover falls through to the xorbuf() */ } else { WOLFSSL_ATOMIC_STORE(rng->nextStirLen, cur + (WC_ATOMIC_INT_ARG)take); return 0; } - if (nonceSz == 0) + if (addInSz == 0) return 0; } - if (nonceSz > (word32)sizeof(rng->nextStir)) - nonceSz = (word32)sizeof(rng->nextStir); - xorbuf(rng->nextStir, nonce, nonceSz); + if (addInSz > (word32)sizeof(rng->nextStir)) + addInSz = (word32)sizeof(rng->nextStir); + xorbuf(rng->nextStir, addIn, addInSz); return 0; } @@ -7495,7 +7644,7 @@ static WC_INLINE int RngFailFastVerdict(const WC_RNG* rng) return NEEDS_RECOVERY_E; #endif #ifdef WC_RNG_HAVE_ENTROPY_EPOCH - if (rng->entropy_epoch != WOLFSSL_ATOMIC_LOAD(global_entropy_epoch)) + if (rng->entropy_epoch != current_entropy_epoch()) return NEEDS_RECOVERY_E; #endif #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) @@ -11633,7 +11782,7 @@ int wc_hwrng_generate_block(byte *output, word32 sz) * - request/byte counts in the DRBG arm of wc_RNG_GenerateBlock() * (hardware-offload arms -- RDRAND, Silabs, async, cryptocb, custom -- * are deliberately uncounted: these are DRBG-facility statistics); - * - banked-seed redemption provenance in wc_RNG_DRBG_NextSeedNow_Nonce(); + * - banked-seed redemption provenance in wc_RNG_DRBG_NextSeedNow_AddIn(); * - seed health failures at the two sites that observe them per-instance * (PollAndReSeed(), NextSeedGenerate); * - chain-provenance bytes (RBGC_bytes_produced: output generated while diff --git a/wolfcrypt/src/rng_bank.c b/wolfcrypt/src/rng_bank.c index fdda3d0f1aa..ece5f94a891 100644 --- a/wolfcrypt/src/rng_bank.c +++ b/wolfcrypt/src/rng_bank.c @@ -58,10 +58,10 @@ #define WC_RNG_INIT_FLAG_NONE 0 #endif /* backward-compat shim and helper declarations */ - static int wc_RNG_DRBG_Reseed_Nonce(WC_RNG* rng, const byte* seed, + static int wc_RNG_DRBG_Reseed_AddIn(WC_RNG* rng, const byte* seed, word32 seedSz, const byte *nonce, word32 nonceSz); - static int wc_RNG_DRBG_Stir_Nonce( + static int wc_RNG_DRBG_Stir_AddIn( WC_RNG* rng, const byte* seed, word32 seedSz, const byte *nonce, word32 nonceSz); @@ -2649,27 +2649,27 @@ WOLFSSL_API int wc_rng_bank_seed_range(struct wc_rng_bank *bank, } else { if (flags & WC_RNG_BANK_FLAG_STIR) { - ret = wc_RNG_DRBG_Stir_Nonce( + ret = wc_RNG_DRBG_Stir_AddIn( WC_RNG_BANK_INST_TO_RNG(drbg), seed, seedSz, nonce, nonceSz); #ifdef WC_VERBOSE_RNG if ((ret != 0) && (! (bank->flags & WC_RNG_BANK_FLAG_QUIET))) { WOLFSSL_DEBUG_PRINTF( "WARNING: wc_rng_bank_seed_range(): " - "wc_RNG_DRBG_Stir_Nonce() for inst#%d " + "wc_RNG_DRBG_Stir_AddIn() for inst#%d " "returned %d\n", n, ret); } #endif } else { - ret = wc_RNG_DRBG_Reseed_Nonce( + ret = wc_RNG_DRBG_Reseed_AddIn( WC_RNG_BANK_INST_TO_RNG(drbg), seed, seedSz, nonce, nonceSz); #ifdef WC_VERBOSE_RNG if ((ret != 0) && (! (bank->flags & WC_RNG_BANK_FLAG_QUIET))) { WOLFSSL_DEBUG_PRINTF( "WARNING: wc_rng_bank_seed_range(): " - "wc_RNG_DRBG_Reseed_Nonce() for inst#%d " + "wc_RNG_DRBG_Reseed_AddIn() for inst#%d " "returned %d\n", n, ret); } #endif @@ -3785,7 +3785,7 @@ WOLFSSL_TEST_VIS int wc_RNG_DRBG_Present(const WC_RNG* rng) return (rng != NULL) && (! WC_RNG_BANK_DRBG_NULL(rng)); } -static int wc_RNG_DRBG_Reseed_Nonce( +static int wc_RNG_DRBG_Reseed_AddIn( WC_RNG* rng, const byte* seed, word32 seedSz, const byte *nonce, word32 nonceSz) @@ -3820,7 +3820,7 @@ WOLFSSL_TEST_VIS int wc_RNG_DRBG_ScheduleReseed(WC_RNG* rng) #if FIPS_VERSION3_EQ(5,2,4) -static int wc_RNG_DRBG_Stir_Nonce( +static int wc_RNG_DRBG_Stir_AddIn( WC_RNG* rng, const byte* seed, word32 seedSz, const byte *nonce, word32 nonceSz) { (void)nonce; @@ -3836,7 +3836,7 @@ WOLFSSL_TEST_VIS int wc_RNG_DRBG_Stir( #else /* FIPS_VERSION3_NE(5,2,4) */ -static int wc_RNG_DRBG_Stir_Nonce( +static int wc_RNG_DRBG_Stir_AddIn( WC_RNG* rng, const byte* seed, word32 seedSz, const byte *nonce, word32 nonceSz) { wc_drbg_reseed_ctr_t saved_ctr; @@ -3862,7 +3862,7 @@ static int wc_RNG_DRBG_Stir_Nonce( WOLFSSL_TEST_VIS int wc_RNG_DRBG_Stir( WC_RNG* rng, const byte* seed, word32 seedSz) { - return wc_RNG_DRBG_Stir_Nonce(rng, seed, seedSz, NULL, 0); + return wc_RNG_DRBG_Stir_AddIn(rng, seed, seedSz, NULL, 0); } WOLFSSL_TEST_VIS int wc_RNG_DRBG_Reseed_Now( diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index 0e3bf981338..d3731b338a9 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -2639,6 +2639,12 @@ int wolfSSL_Atomic_Ptr_CompareExchange( #endif /* WOLFSSL_ATOMIC_OPS */ +/* Make sure the pointer size assumptions of + * wolfSSL_Atomic_Func_Ptr_CompareExchange() are met. */ +#ifdef wolfSSL_Atomic_Func_Ptr_CompareExchange + wc_static_assert(sizeof(void (*)(void)) == sizeof(void *)); +#endif + #if !defined(SINGLE_THREADED) void wolfSSL_RefWithMutexInit(wolfSSL_RefWithMutex* ref, int* err) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 9fabf2da026..25a62035b33 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -35945,7 +35945,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_nextseedstest(void) api_ret = wc_RNG_DRBG_NextSeedNow(NULL); if (api_ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out); - api_ret = wc_RNG_DRBG_NextSeedNow_Nonce(NULL, NULL, 0); + api_ret = wc_RNG_DRBG_NextSeedNow_AddIn(NULL, NULL, 0); if (api_ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out); api_ret = wc_RNG_DRBG_NextSeedGenerate_Primary(NULL, 1); @@ -35976,7 +35976,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_nextseedstest(void) api_ret = wc_RNG_DRBG_NextSeedCurrent(root, NULL); if (api_ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out); - api_ret = wc_RNG_DRBG_NextSeedNow_Nonce(root, NULL, 5); + api_ret = wc_RNG_DRBG_NextSeedNow_AddIn(root, NULL, 5); if (api_ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out); @@ -36095,7 +36095,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_nextseedstest(void) if (i >= 64) ERROR_OUT(WC_TEST_RET_ENC_NC, out); RNG_STATS_SNAP(root); - api_ret = wc_RNG_DRBG_NextSeedNow_Nonce(root, matter, + api_ret = wc_RNG_DRBG_NextSeedNow_AddIn(root, matter, sizeof(matter)); if (api_ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out); @@ -36794,6 +36794,8 @@ static int rng_epoch_nomem_seedCb(OS_Seed* os, byte* output, word32 sz) } #endif /* WC_RNG_SEED_CB && WC_RNG_HAVE_LOCK */ +static wc_test_ret_t rng_epoch_extra_test(void); + /* The process-global entropy epoch (wc_RNG_global_invalidate_entropy()): * detection, delivery into the instance's apertures, recovery by one credited * generate, inheritance by spawned chain members, and the capture rule for a @@ -36805,7 +36807,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_epoch_test(void) WC_DECLARE_VAR(rng, WC_RNG, 1, HEAP_HINT); int rng_inited = 0; byte block[32]; - WC_ATOMIC_UINT_ARG epoch_before, epoch_after; + wc_RNG_entropy_epoch_t epoch_before, epoch_after; RNG_STATS_DECLS; @@ -37180,6 +37182,276 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_epoch_test(void) } WC_FREE_VAR(rng, HEAP_HINT); + if (ret == 0) + ret = rng_epoch_extra_test(); + + return ret; +} + +/* Fixtures for rng_epoch_extra_test(): a stand-in "external" epoch word -- + * the observable surface an mmap'd kernel counter presents, minus the + * kernel -- plus a recording publication handler. The fixtures are + * registered afresh each run (any production handlers are displaced via + * the _TEST_VIS resets and restored at exit) and stay quiet for later + * tests: the word only moves when this test moves it. */ +static wolfSSL_Atomic_Uint rng_epoch_extra_ext_word = + WOLFSSL_ATOMIC_INITIALIZER(1U); +static int rng_epoch_extra_get_zero_mode = 0; +static void *rng_epoch_extra_get_arg_seen = NULL; +static int rng_epoch_extra_get_marker = 0; +static int rng_epoch_extra_inv_marker = 0; +static unsigned int rng_epoch_extra_inv_count = 0; +static wc_RNG_entropy_epoch_t rng_epoch_extra_inv_last_epoch = 0; +static void *rng_epoch_extra_inv_arg_seen = NULL; + +static wc_RNG_entropy_epoch_t rng_epoch_extra_getCb(void *arg) +{ + if (rng_epoch_extra_get_zero_mode) { + /* Probe-verification path, single-threaded by construction. The + * normal path stays read-only: the getter remains registered for + * the life of the process, and concurrent epoch reads (e.g. in + * random_thread_test() on a suite rerun) must race on nothing. */ + rng_epoch_extra_get_arg_seen = arg; + return 0; + } + return WOLFSSL_ATOMIC_LOAD(rng_epoch_extra_ext_word); +} + +static void rng_epoch_extra_invCb(wc_RNG_entropy_epoch_t epoch, void *arg) +{ + ++rng_epoch_extra_inv_count; + rng_epoch_extra_inv_last_epoch = epoch; + rng_epoch_extra_inv_arg_seen = arg; +} + +/* The auxiliary invalidation pathway: one-shot registration semantics for + * both handlers, publication of local events to the registered handler + * with the registrant's arg, detection of an external edge at the next + * epoch-reading call (with relay publication), exactly-once accounting + * per edge, and the 0-guard (a signalless getter is inert). */ +static wc_test_ret_t rng_epoch_extra_test(void) +{ + wc_test_ret_t ret = 0; + int api_ret; + WC_DECLARE_VAR(rng, WC_RNG, 1, HEAP_HINT); + int rng_inited = 0; + byte block[32]; + wc_RNG_entropy_epoch_t epoch_before, epoch_after; + unsigned int inv_count_before; + wc_RNG_extra_entropy_epoch_get_handler_t saved_get_handler = NULL; + void *saved_get_arg = NULL; + int saved_get = 0; + wc_RNG_entropy_epoch_extra_inv_handler_t saved_inv_handler = NULL; + void *saved_inv_arg = NULL; + int saved_inv = 0; + + WOLFSSL_ENTER("rng_epoch_extra_test"); + + WC_ALLOC_VAR_EX(rng, WC_RNG, 1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, + return WC_TEST_RET_ENC_EC(MEMORY_E)); + + /* Retrieve-and-reset any installed handlers (e.g. the kernel + * module's own production glue, registered at module init) -- + * restored at out_l. Both slots are then virgin, so every run + * exercises the full registration path. */ + api_ret = wc_RNG_extra_entropy_epoch_reset(&saved_get_handler, + &saved_get_arg); + if (api_ret == 0) + saved_get = 1; + else if (api_ret != WC_NO_ERR_TRACE(BAD_STATE_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + api_ret = wc_RNG_entropy_epoch_extra_inv_reset(&saved_inv_handler, + &saved_inv_arg); + if (api_ret == 0) + saved_inv = 1; + else if (api_ret != WC_NO_ERR_TRACE(BAD_STATE_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + + /* refusals leave the slot unclaimed */ + api_ret = wc_RNG_extra_entropy_epoch_init(NULL, NULL); + if (api_ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + /* a getter with no signal yet is probed and refused -- and the + * probe demonstrably ran, with the caller's arg */ + rng_epoch_extra_get_zero_mode = 1; + rng_epoch_extra_get_arg_seen = NULL; + api_ret = wc_RNG_extra_entropy_epoch_init( + rng_epoch_extra_getCb, &rng_epoch_extra_get_marker); + rng_epoch_extra_get_zero_mode = 0; + if (api_ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + if (rng_epoch_extra_get_arg_seen != (void *)&rng_epoch_extra_get_marker) + ERROR_OUT(WC_TEST_RET_ENC_NC, out_l); + api_ret = wc_RNG_entropy_epoch_extra_inv_init(NULL, NULL); + if (api_ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + /* resetting a virgin slot is a state error, not a crash */ + { + wc_RNG_extra_entropy_epoch_get_handler_t dummy_get_handler = NULL; + void *dummy_arg = NULL; + api_ret = wc_RNG_extra_entropy_epoch_reset(&dummy_get_handler, + &dummy_arg); + if (api_ret != WC_NO_ERR_TRACE(BAD_STATE_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + } + + /* the real registrations */ + api_ret = wc_RNG_extra_entropy_epoch_init( + rng_epoch_extra_getCb, &rng_epoch_extra_get_marker); + if (api_ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + api_ret = wc_RNG_entropy_epoch_extra_inv_init( + rng_epoch_extra_invCb, &rng_epoch_extra_inv_marker); + if (api_ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + + /* one-shot while registered */ + api_ret = wc_RNG_extra_entropy_epoch_init( + rng_epoch_extra_getCb, &rng_epoch_extra_get_marker); + if (api_ret != WC_NO_ERR_TRACE(ALREADY_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + api_ret = wc_RNG_entropy_epoch_extra_inv_init( + rng_epoch_extra_invCb, &rng_epoch_extra_inv_marker); + if (api_ret != WC_NO_ERR_TRACE(ALREADY_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + + /* quiet start: the registration probe primed the shadow word, so a + * read is just a read */ + epoch_before = wc_RNG_get_global_entropy_epoch(); + if (wc_RNG_get_global_entropy_epoch() != epoch_before) + ERROR_OUT(WC_TEST_RET_ENC_NC, out_l); + + /* a local event publishes the fresh epoch to the registered handler, + * with the registrant's arg */ + inv_count_before = rng_epoch_extra_inv_count; + epoch_after = wc_RNG_global_invalidate_entropy(); + if (epoch_after != epoch_before + 1U) + ERROR_OUT(WC_TEST_RET_ENC_I((int)epoch_after), out_l); + if (rng_epoch_extra_inv_count != inv_count_before + 1U) + ERROR_OUT(WC_TEST_RET_ENC_I((int)rng_epoch_extra_inv_count), out_l); + if (rng_epoch_extra_inv_last_epoch != epoch_after) + ERROR_OUT(WC_TEST_RET_ENC_I((int)rng_epoch_extra_inv_last_epoch), + out_l); + if (rng_epoch_extra_inv_arg_seen != (void *)&rng_epoch_extra_inv_marker) + ERROR_OUT(WC_TEST_RET_ENC_NC, out_l); + + /* an instance stamped now is current */ + api_ret = wc_InitRng_ex(rng, HEAP_HINT, RNG_DRBG_DEVID); + if (api_ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + rng_inited = 1; + api_ret = wc_RNG_entropy_needs_recovery(rng); + if (api_ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + + /* the external edge: the instance learns of it at its next + * invalidation check, without anyone calling the invalidator -- the + * check itself is the detecting read, and detection relays through + * the publication handler */ + inv_count_before = rng_epoch_extra_inv_count; + epoch_before = epoch_after; + (void)wolfSSL_Atomic_Uint_AddFetch(&rng_epoch_extra_ext_word, 1U); + api_ret = wc_RNG_entropy_needs_recovery(rng); + if (api_ret != WC_NO_ERR_TRACE(NEEDS_RECOVERY_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + epoch_after = wc_RNG_get_global_entropy_epoch(); + if (epoch_after != epoch_before + 1U) + ERROR_OUT(WC_TEST_RET_ENC_I((int)epoch_after), out_l); + if (rng_epoch_extra_inv_count != inv_count_before + 1U) + ERROR_OUT(WC_TEST_RET_ENC_I((int)rng_epoch_extra_inv_count), out_l); + if (rng_epoch_extra_inv_last_epoch != epoch_after) + ERROR_OUT(WC_TEST_RET_ENC_I((int)rng_epoch_extra_inv_last_epoch), + out_l); + /* exactly-once per edge: more reads are just reads */ + if (wc_RNG_get_global_entropy_epoch() != epoch_after) + ERROR_OUT(WC_TEST_RET_ENC_NC, out_l); + if (rng_epoch_extra_inv_count != inv_count_before + 1U) + ERROR_OUT(WC_TEST_RET_ENC_I((int)rng_epoch_extra_inv_count), out_l); + + /* recovery is rng_epoch_test()'s story; here one credited generate + * (or a reinit where generate is remote) just clears the verdict so + * the 0-guard check below runs against a current instance */ + if (rng_test_generate_is_local(rng)) { + api_ret = wc_RNG_GenerateBlock(rng, block, (word32)sizeof(block)); + if (api_ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + } + else { + api_ret = wc_FreeRng(rng); + rng_inited = 0; + if (api_ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + api_ret = wc_InitRng_ex(rng, HEAP_HINT, RNG_DRBG_DEVID); + if (api_ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + rng_inited = 1; + } + api_ret = wc_RNG_entropy_needs_recovery(rng); + if (api_ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + + /* the 0-guard: a getter with no signal is inert, not an edge */ + inv_count_before = rng_epoch_extra_inv_count; + rng_epoch_extra_get_zero_mode = 1; + api_ret = wc_RNG_entropy_needs_recovery(rng); + rng_epoch_extra_get_zero_mode = 0; + if (api_ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out_l); + if (wc_RNG_get_global_entropy_epoch() != epoch_after) + ERROR_OUT(WC_TEST_RET_ENC_NC, out_l); + if (rng_epoch_extra_inv_count != inv_count_before) + ERROR_OUT(WC_TEST_RET_ENC_I((int)rng_epoch_extra_inv_count), out_l); + +out_l: + + if (rng_inited) { + int cleanup_ret = wc_FreeRng(rng); + if ((cleanup_ret != 0) && (ret == 0)) + ret = WC_TEST_RET_ENC_EC(cleanup_ret); + } + WC_FREE_VAR(rng, HEAP_HINT); + + /* Tear down whichever fixtures are installed (an error path may have + * left either slot vacant), restore any displaced handlers through + * the public inits (whose probes re-prime the shadow), and close + * with one conservative bump to cover events that landed while the + * pathway was ours. */ + { + wc_RNG_extra_entropy_epoch_get_handler_t dummy_get_handler = NULL; + wc_RNG_entropy_epoch_extra_inv_handler_t dummy_inv_handler = NULL; + void *dummy_arg = NULL; + int cleanup_ret = wc_RNG_extra_entropy_epoch_reset( + &dummy_get_handler, &dummy_arg); + if ((cleanup_ret != 0) && + (cleanup_ret != WC_NO_ERR_TRACE(BAD_STATE_E)) && + (ret == 0)) + { + ret = WC_TEST_RET_ENC_EC(cleanup_ret); + } + cleanup_ret = wc_RNG_entropy_epoch_extra_inv_reset( + &dummy_inv_handler, &dummy_arg); + if ((cleanup_ret != 0) && + (cleanup_ret != WC_NO_ERR_TRACE(BAD_STATE_E)) && + (ret == 0)) + { + ret = WC_TEST_RET_ENC_EC(cleanup_ret); + } + if (saved_get) { + cleanup_ret = wc_RNG_extra_entropy_epoch_init(saved_get_handler, + saved_get_arg); + if ((cleanup_ret != 0) && (ret == 0)) + ret = WC_TEST_RET_ENC_EC(cleanup_ret); + } + if (saved_inv) { + cleanup_ret = wc_RNG_entropy_epoch_extra_inv_init( + saved_inv_handler, saved_inv_arg); + if ((cleanup_ret != 0) && (ret == 0)) + ret = WC_TEST_RET_ENC_EC(cleanup_ret); + } + if (saved_get || saved_inv) + (void)wc_RNG_global_invalidate_entropy(); + } + return ret; } #endif /* WC_RNG_HAVE_ENTROPY_EPOCH && HAVE_HASHDRBG && ... */ diff --git a/wolfssl/wolfcrypt/random.h b/wolfssl/wolfcrypt/random.h index 6e91e8706ab..cb6cd3b07e6 100644 --- a/wolfssl/wolfcrypt/random.h +++ b/wolfssl/wolfcrypt/random.h @@ -559,10 +559,15 @@ wc_static_assert(WC_RNG_RBGC_USER_SEED_STRATUM >= 256); #endif #endif -#if ((defined(WOLFSSL_ATOMIC_OPS) && !defined(SINGLE_THREADED)) || \ +#if ((defined(WOLFSSL_ATOMIC_OPS) && !defined(SINGLE_THREADED) && \ + defined(WORD64_AVAILABLE)) || \ defined(WC_RNG_WANT_ENTROPY_EPOCH)) && \ !defined(WC_RNG_NO_ENTROPY_EPOCH) && !defined(WC_NO_RNG) + #if !defined(WOLFSSL_ATOMIC_OPS) || !defined(WORD64_AVAILABLE) + #error WC_RNG_HAVE_ENTROPY_EPOCH requires WOLFSSL_ATOMIC_OPS and WORD64_AVAILABLE. + #endif #define WC_RNG_HAVE_ENTROPY_EPOCH + typedef word64 wc_RNG_entropy_epoch_t; #endif /* RNG context */ @@ -572,7 +577,7 @@ struct WC_RNG { byte status; word32 flags; #ifdef WC_RNG_HAVE_ENTROPY_EPOCH - WC_ATOMIC_UINT_ARG entropy_epoch; + wc_RNG_entropy_epoch_t entropy_epoch; #endif #ifdef WC_RNG_DEBUG_STATS wc_rng_debug_counter_t _stats_total_bytes_requested; @@ -879,9 +884,9 @@ WOLFSSL_API int wc_RNG_GetFlags(const WC_RNG* rng, word32 *flags); #ifdef HAVE_HASHDRBG WOLFSSL_API int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* seed, word32 seedSz); - WOLFSSL_API int wc_RNG_DRBG_Reseed_Nonce(WC_RNG* rng, const byte* seed, - word32 seedSz, const byte *nonce, - word32 nonceSz); + WOLFSSL_API int wc_RNG_DRBG_Reseed_AddIn(WC_RNG* rng, const byte* seed, + word32 seedSz, const byte *addIn, + word32 addInSz); /* Capability markers for code compiled against a random.h of uncertain * vintage (FIPS builds substitute the module's pinned random.[ch] for * the tree's): consumers outside the boundary gate on these rather than @@ -890,14 +895,14 @@ WOLFSSL_API int wc_RNG_GetFlags(const WC_RNG* rng, word32 *flags); WOLFSSL_API int wc_RNG_DRBG_Stir(WC_RNG* rng, const byte* seed, word32 seedSz); - WOLFSSL_API int wc_RNG_DRBG_Stir_Nonce( + WOLFSSL_API int wc_RNG_DRBG_Stir_AddIn( WC_RNG* rng, const byte* seed, word32 seedSz, - const byte *nonce, word32 nonceSz); + const byte *addIn, word32 addInSz); #define WC_RNG_HAVE_RESEED_NOW - WOLFSSL_API int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* nonce, - word32 nonceSz); + WOLFSSL_API int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* addIn, + word32 addInSz); WOLFSSL_API int wc_RNG_DRBG_Reseed_Now_Primary(WC_RNG* rng, - const byte* nonce, word32 nonceSz); + const byte* addIn, word32 addInSz); WOLFSSL_API int wc_RNG_TestSeed(const byte* seed, word32 seedSz); #ifdef WC_RNG_HAVE_RBGC @@ -1034,11 +1039,11 @@ WOLFSSL_API int wc_RNG_GetFlags(const WC_RNG* rng, word32 *flags); word32 flags); #endif /* !WC_NO_CONSTRUCTORS */ WOLFSSL_API int wc_RNG_DRBG_ReseedRBGC(WC_RNG* rng, WC_RNG* root, - const byte* nonce, word32 nonceSz); + const byte* addIn, word32 addInSz); WOLFSSL_API int wc_RNG_DRBG_StirRBGC(WC_RNG* rng, WC_RNG* root, - const byte* nonce, - word32 nonceSz); + const byte* addIn, + word32 addInSz); #endif /* WC_RNG_HAVE_RBGC */ #ifdef WC_RNG_HAVE_NEXT_SEED @@ -1060,12 +1065,12 @@ WOLFSSL_API int wc_RNG_GetFlags(const WC_RNG* rng, word32 *flags); #endif WOLFSSL_API int wc_RNG_DRBG_NextSeedCurrent(const WC_RNG* rng, WC_ATOMIC_INT_ARG* n); - WOLFSSL_API int wc_RNG_DRBG_NextSeedNow_Nonce(WC_RNG* rng, - const byte* nonce, - word32 nonceSz); + WOLFSSL_API int wc_RNG_DRBG_NextSeedNow_AddIn(WC_RNG* rng, + const byte* addIn, + word32 addInSz); WOLFSSL_API int wc_RNG_DRBG_NextSeedNow(WC_RNG* rng); - WOLFSSL_API int wc_RNG_DRBG_NextStirStore(WC_RNG* rng, - const byte *nonce, word32 nonceSz); + WOLFSSL_API int wc_RNG_DRBG_NextStirStore( + WC_RNG* rng, const byte *addIn, word32 addInSz); WOLFSSL_API int wc_RNG_DRBG_NextStirNow(WC_RNG* rng); #endif /* WC_RNG_HAVE_NEXT_SEED */ @@ -1112,8 +1117,90 @@ WOLFSSL_API int wc_RNG_invalidate_entropy(WC_RNG* rng); WOLFSSL_API int wc_RNG_entropy_needs_recovery(WC_RNG* rng); #ifdef WC_RNG_HAVE_ENTROPY_EPOCH - WOLFSSL_API WC_ATOMIC_UINT_ARG wc_RNG_global_invalidate_entropy(void); - WOLFSSL_API WC_ATOMIC_UINT_ARG wc_RNG_get_global_entropy_epoch(void); + struct wc_RNG_entropy_epoch_atomic { + wolfSSL_Atomic_Uint high; + wolfSSL_Atomic_Uint low; + }; + #define WC_RNG_ENTROPY_EPOCH_ATOMIC_INITIALIZER { \ + WOLFSSL_ATOMIC_INITIALIZER(0U), \ + WOLFSSL_ATOMIC_INITIALIZER(1U) \ + } + #define WC_RNG_ENTROPY_EPOCH_ATOMIC_INVALID { \ + WOLFSSL_ATOMIC_INITIALIZER(0U), \ + WOLFSSL_ATOMIC_INITIALIZER(0U) \ + } + #define WC_RNG_ENTROPY_EPOCH_INVALID 0 + static WC_INLINE wc_RNG_entropy_epoch_t wc_RNG_entropy_epoch_export( + struct wc_RNG_entropy_epoch_atomic *epoch) + { + wc_RNG_entropy_epoch_t epoch_export; + epoch_export = WOLFSSL_ATOMIC_LOAD(epoch->low); + /* A tear here will always preserve the epoch mismatch via the low word, + * and at worst have the wrong high word. */ + epoch_export |= + (wc_RNG_entropy_epoch_t)WOLFSSL_ATOMIC_LOAD(epoch->high) << + (wc_RNG_entropy_epoch_t)32; + return epoch_export; + } + static WC_INLINE int wc_RNG_entropy_epoch_import( + wc_RNG_entropy_epoch_t old_epoch, + wc_RNG_entropy_epoch_t new_epoch, + struct wc_RNG_entropy_epoch_atomic *dest) + { + int ret = 1; + WC_ATOMIC_UINT_ARG expected_low = (WC_ATOMIC_UINT_ARG)old_epoch; + WC_ATOMIC_UINT_ARG expected_high = + (WC_ATOMIC_UINT_ARG)(old_epoch >> + (wc_RNG_entropy_epoch_t)32); + if (! wolfSSL_Atomic_Uint_CompareExchange( + &dest->low, + &expected_low, + (WC_ATOMIC_UINT_ARG)new_epoch)) + ret = 0; + if (((new_epoch >> 32) != (old_epoch >> 32)) && + (! wolfSSL_Atomic_Uint_CompareExchange( + &dest->high, + &expected_high, + (WC_ATOMIC_UINT_ARG)(new_epoch >> (wc_RNG_entropy_epoch_t)32)))) + ret = 0; + return ret; + } + static WC_INLINE wc_RNG_entropy_epoch_t wc_RNG_entropy_epoch_increment_atomic( + struct wc_RNG_entropy_epoch_atomic *epoch) + { + wc_RNG_entropy_epoch_t new_epoch = + wolfSSL_Atomic_Uint_AddFetch(&epoch->low, 1U); + if (new_epoch == 0) + new_epoch += + (wc_RNG_entropy_epoch_t)wolfSSL_Atomic_Uint_AddFetch( + &epoch->high, 1U) << + (wc_RNG_entropy_epoch_t)32; + else { + /* Note this is a benign tear between .low and .high here -- worst + * case, the returned value glitches high by 2^32 - 1, resulting in + * an extra cycle of invalidation and recovery. */ + new_epoch += + (wc_RNG_entropy_epoch_t)WOLFSSL_ATOMIC_LOAD(epoch->high) << + (wc_RNG_entropy_epoch_t)32; + } + return new_epoch; + } + WOLFSSL_API wc_RNG_entropy_epoch_t wc_RNG_global_invalidate_entropy(void); + WOLFSSL_API wc_RNG_entropy_epoch_t wc_RNG_get_global_entropy_epoch(void); + typedef void (*wc_RNG_entropy_epoch_extra_inv_handler_t)( + wc_RNG_entropy_epoch_t epoch, void *arg); + WOLFSSL_API int wc_RNG_entropy_epoch_extra_inv_init( + wc_RNG_entropy_epoch_extra_inv_handler_t handler, void *arg); + WOLFSSL_TEST_VIS int wc_RNG_entropy_epoch_extra_inv_reset( + wc_RNG_entropy_epoch_extra_inv_handler_t *handler, void **arg); + typedef wc_RNG_entropy_epoch_t (*wc_RNG_extra_entropy_epoch_get_handler_t)( + void *arg); + WOLFSSL_API int wc_RNG_extra_entropy_epoch_init( + wc_RNG_extra_entropy_epoch_get_handler_t handler, + void *arg); + WOLFSSL_TEST_VIS int wc_RNG_extra_entropy_epoch_reset( + wc_RNG_extra_entropy_epoch_get_handler_t *handler, + void **arg); #endif #ifdef WC_RNG_HAVE_FREE_HOOK diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index 86f8385e419..ee3051b5d7a 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -831,6 +831,12 @@ } #endif +#define wolfSSL_Atomic_Func_Ptr_CompareExchange(c, expected_ptr, new_ptr) \ + wolfSSL_Atomic_Ptr_CompareExchange( \ + (void * volatile *)(c), \ + (void **)(expected_ptr), \ + (void *)(wc_ptr_t)(new_ptr)) + /*** Macro abstractions for compare-and-exchange retry loops, allowing ***/ /*** platform-specific instrumentation and failure paths. ***/