FIPS builds at v5.2 or older force WOLFSSL_NO_SHAKE128/256 on in
settings.h, which blocks ML-DSA and ML-KEM's internal SHAKE hashing
under --enable-fips=v5. Adds a CFLAGS opt-in, V523_NONFIPS_SHAKE,
that restores SHAKE128/256 for exactly the cert4718 (5.2.1) build.
- configure.ac, src/include.am, wolfssl/wolfcrypt/include.am: build
and install the paired shake.c/shake.h from the internal fips repo
overlay only when the opt-in and FIPS version match, validating
both files exist first
- hash.c, asn.c, wc_mldsa.c/.h, benchmark.c, test.c, test_sha3.c:
include shake.h ahead of their first sha3.h/asn.h include, since
asn.h can reach sha3.h unguarded via ed448.h/wc_lms.h/wc_xmss.h
first
- wc_mlkem.h: the one exception - its override must come after its
sha3.h include, since sha3.h processes first there with SHAKE off,
and shake.h's own fallback typedef and prototypes are what actually
declare wc_Shake
- every override site uses the same
defined(WOLFSSL_SHA3) && defined(V523_NONFIPS_SHAKE) guard
- registers V523_NONFIPS_SHAKE in .wolfssl_known_macro_extras, which
check-source-text otherwise flags as unrecognized
wc_rng_bank_root_rng_init() now refuses WC_RNG_INIT_FLAG_USE_FULL_MUTEX
with BAD_FUNC_ARG. The bank operates its root through lock-word
operations alone -- the daemon's claims, reinit-in-place
(wc_rng_bank_reinit_rng()), the invalidation walk -- none of which take
the outer mutex, so a full-mutex root was bypassed by every one of them,
and its reinit's teardown (wc_FreeRng_PreLocked() under a lock-word-only
lease) released and destroyed a mutex the bank never took, under any
getter holding it. wc_rng_bank_reinit_rng() gets a matching tripwire
(WRONG_TYPE_OBJECT_E on a WC_RNG_FLAG_FULL_MUTEX instance, before any
mutation), unreachable through the bank's own constructors.
doc/dox_comments/header_files/rng_bank.h: wc_rng_bank_root_rng_init()
documents the refusal (and the existing ALREADY_E).
wolfcrypt/test/test.c: rng_lifecycle_test() tries the flag on a vacated
root (refused, root still vacant), then instantiates and reinstantiates
the root without it. WC_RNG_HAVE_LOCK_FULL_MUTEX builds only; no CI
scenario sets WC_RNG_WANT_LOCK_FULL_MUTEX, so verified locally with
--enable-rng-extras --enable-rng-bank CFLAGS=-DWC_RNG_WANT_LOCK_FULL_MUTEX.
* wc_rng_bank_checkout(): without the lock facility the prediction-
resistance reseed is wc_RNG_DRBG_Reseed_Now(), as before this branch.
wc_RNG_DRBG_Reseed_Now_Primary() refuses a multithreaded lock-less
build with NOT_COMPILED_IN because a bare instance there has no
exclusion to make reseed-then-draw atomic, so every prediction-
resistant checkout in such a bank (--enable-rng-bank without
--enable-rng-extras) had come to fail. The bank's lease is that
exclusion, and without the lock facility an instance retains no chain
parent for a reseed to defer to, so the plain reseed is the primary
reseed and the _Primary() flag override has nothing to override.
* wc_rng_bank_reseed_range(): the _CAN_WAIT retry loop now stops on a
non-transient code, as wc_rng_bank_inst_reinit()'s does. A verdict --
WRONG_TYPE_OBJECT_E for a chain reseed of a stratum-0 member under
WC_RNG_RBGC_STRATUM_IMMUTABLE, RNG_FAILURE_E for a condemned instance
-- does not change with waiting; the loop retried it until timeout,
reporting WC_TIMEOUT_E in its place, or forever with no timeout, the
member's lease held throughout. The walk now records it and moves on
to the remaining instances.
wolfcrypt/test/test.c: the prediction-resistance checkout tests in
random_bank_test() are no longer gated to lock or single-threaded
builds; rng_lifecycle_test() gains the chain-reseed-of-a-plain-bank
walk under immutable strata (prompt WRONG_TYPE_OBJECT_E, members
untouched, a primary walk then succeeds).
The reinit holds the inst-op gate for the duration, and the root's
recovery (wc_rng_bank_root_rng_reinit()) needs that same gate, so a
WC_RNG_BANK_FLAG_CAN_WAIT caller waited for an event its own hold
foreclosed -- until timeout, or forever with none (and the daemon's root
recovery behind it, forever too). The root's verdict is now returned at
once in that arm, gate released, member out of service and retryable.
With the lock facility the root's recovery rides the root's lock, not
the gate, and the wait stands.
wolfcrypt/test/test.c: rng_lifecycle_test() gains the scenario: a
lock-less RBG-chain member reinit against a torn-down root returns
NOT_READY_E well inside its timeout, and succeeds -- the member a chain
child again -- once the root is recovered. Fails against the previous
rng_bank.c by timing out.
wolfcrypt/src/rng_bank.c:
* wc_rng_bank_fini(): a root pinned by an external (caller-spawned)
child, or held, is now refused before commitment, with the bank fully
intact -- STILL_REFERENCED_E / BUSY_E, as for a member. Previously a
root free failure was only tallied, the bank's refcount and flags were
destroyed, and the retry of wc_rng_bank_free() deallocated the bank
under the child's RBGC_parent. The pre-commit check counts member
pins (released by the member frees) and refuses on any pin beyond
them, regardless of the root's status: a root torn down by a failed
reinit is NOT_INIT with its lock word live and its pins outstanding,
and was previously skipped. The post-commit root free now restores
the refcount and returns on BUSY_E / STILL_REFERENCED_E, as the member
loop does, so a child that arrives after the pre-commit check still
leaves a retryable bank.
* wc_rng_bank_reinit_rng(): WC_RNG_INIT_FLAG_PRESERVE_LOCK is added
only when WC_RNG_HAVE_LOCK, as wc_rng_bank_inst_reinit() already does.
_InitRng() refuses the flag with NOT_COMPILED_IN otherwise, so in a
bank built without the lock facility wc_rng_bank_root_rng_reinit()
tore the root down and could not reinstantiate it; the inst-op gate is
the exclusion in that arm.
wolfcrypt/src/random.c:
* _InitRng(): on an RDRAND-capable CPU with HAVE_INTEL_RDRAND, the DRBG
bypass now refuses caller-supplied seed material with
WRONG_TYPE_OBJECT_E, the instance left uninstantiated. Previously
wc_InitRngNonce_UserSeed() and wc_RNG_global_fallback_init_user_seed()
returned success with the seed silently dropped and the instance
relabeled stratum 0, generating from RDRAND -- a primary-class
instance under a user-seeded name. Instantiating the DRBG anyway is
not an option: wc_RNG_GenerateBlock() reads RDRAND whenever the CPU
has it, DRBG or not. wc_InitRngFixedSeed()'s post-hoc backstop
(which stays, for CUSTOM_RAND_GENERATE_BLOCK) returns the same code.
doc/dox_comments/header_files/random.h: wc_InitRngNonce_UserSeed()
documents the refusal; the previous text described a bypass
"HAVE_INTEL_RDRAND without HAVE_HASHDRBG", which cannot reach the
function (WC_RNG_HAVE_RBGC requires HAVE_HASHDRBG), while the reachable
case went undocumented.
wolfcrypt/test/test.c: rng_lifecycle_test() gains the bank-teardown
scenario (external child of the root; refused fini leaves the bank
generating; held root; torn-down pinned root; convergence once the child
is released) and a lock-less bank root reinit. The latter fails against
the previous rng_bank.c.
linuxkm/module_hooks.c: in the pre-3.17 NMI-context time accessors, read
jiffies after the calibration latch rather than at entry: a calibration
published by another CPU between the two can carry a later tick, and
the unsigned difference wrapped.
linuxkm/linuxkm_wc_port.h: in_task() shim for kernels before 4.10, where
it first appears (include/linux/preempt.h); wc_linuxkm_can_long_loop()
used it unconditionally.
- Source comments: msg may be NULL if msgSz is 0 for the sign and
verify functions, and Sign(), Verify() and slhdsakey_sign_external()
reject a NULL msg only when msgSz is greater than 0.
- Doxygen: note on the msg parameter, and SignDeterministic() returns
BAD_LENGTH_E for a too-small signature buffer.
- test.c: SignDeterministic() with (NULL, 0) must match the signature
for a non-NULL message of length 0.
- test_slhdsa.c: SignWithRandom() with (NULL, 0) and a full-size
signature buffer signs successfully.
wc_SlhDsaKey_SignWithRandom() rejected msg == NULL for any length, so it
and wc_SlhDsaKey_SignDeterministic() returned BAD_FUNC_ARG for an empty
message passed as (NULL, 0), unlike wc_SlhDsaKey_Sign() and Verify().
Use the same check as Sign() and, like Sign(), replace a NULL message
with a one-byte static stand-in before the crypto callback dispatch.
Update the doxygen and source comments, and add tests for the (NULL, 0)
case.
WC_RNG_RBGC_STRATUM_IMMUTABLE campaign):
* RNG state-invalidation delivery by entropy epoch
* Fork safety for the WC_RNG lock word
* RBGC lineage persistence with a global fallback source
* A uniform "transient vs. verdict" error taxonomy
* Lifecycle hardening that makes WC_RNG safe to reinstantiate under lease-free
observers.
Protocol-level changes (random.[ch]):
* Entropy epoch (WC_RNG_HAVE_ENTROPY_EPOCH, on by default with atomics in
multithreaded builds; WC_RNG_WANT_/WC_RNG_NO_ENTROPY_EPOCH override): a
global event counter, wc_RNG_global_invalidate_entropy(), replaces the
per-instance walk as the primary delivery mechanism for state-invalidation
events (VM fork/resume, hibernation). Each WC_RNG carries a stamp; every
seeding operation captures the epoch (and PID) before acquiring material
and stamps at completion, so an event that lands mid-operation leaves a
stale stamp. rng_entropy_event_propagate() converts {stale stamp,
unlatched} to {latched, swept} lazily, at the instance's next aperture:
"detection is also delivery," and every aperture consulted after a nonzero
wc_RNG_entropy_needs_recovery() is post-purge. wc_RNG_lock_put() reports
an unpropagated increment as NEEDS_RECOVERY_E, so a holder whose last
operation straddled the event learns of it at release. The latch is
cleared by a recovery only when the recovering caller's capture is still
current.
* wc_RNG_entropy_needs_recovery() is the single authoritative verdict on a
standing recovery obligation (latch, stale epoch, PID change, exhausted
reseed budget), and the generate path, the stir path, the pool reader and
the banked-seed consumer all key on it. rng_pid_change_check() is retired
into it: a fork() is an epoch event. The reseed counter is thereby
returned to its SP 800-90A meaning (budget only); invalidation never
spends runway and is never enforced by counter saturation in lock builds.
* Fork safety for the lock word: WC_RNG_LOCK_ORPHANED (error-crypt.h:
OBJECT_ORPHANED_E, -1036; HWPUF_* codes shift down by one). A _HELD word
stamped with another process's PID was held across a fork() by a holder
absent in this process; the first post-fork contender marks it _ORPHANED
(RngLockOrphanCheck(), from every lock getter), applies the invalidation
once as CAS winner, and reports OBJECT_ORPHANED_E. The verdict licenses
nothing to the contender: the owner adopts the lease by
wc_FreeRng_PreLocked() then wc_InitRng_ex2() with the new
WC_RNG_INIT_FLAG_PRESERVE_LOCK (which clears _ORPHANED with the latch); a
live holder's release or completed recovery also clears it.
* RBGC lineage persistence (WC_RNG_HAVE_LOCK && WC_RNG_HAVE_RBGC): a chain
child retains RBGC_parent and pins it by RBGC_refcount (both live for as
long as the lock word, preserved across _PRESERVE_LOCK reinits).
wc_FreeRng() on a pinned parent wipes sensitive state and returns the new
STILL_REFERENCED_E (error-crypt.h) -- the shell must outlive its
children; wc_rng_free() leaks rather than freeing referenced memory.
WC_RNG_FLAG_NO_RBGC_PARENT opts an instance out of being retained
(wc_rng_new*() and *_New() constructors set it, since the void
wc_rng_free() cannot report). HAVE_FIPS forces lock-required parents and
WC_RNG_RBGC_STRATUM_IMMUTABLE, and random.h refuses HAVE_FIPS with RBGC
but without the lock facility.
* Global fallback RBGC source (WC_RNG_HAVE_GLOBAL_FALLBACK_RNG):
wc_RNG_global_fallback_init[_user_seed]() / _get() / _free(), a static
lock-required WC_RNG, freed by wolfCrypt_Cleanup(). PollAndReSeed() and
wc_RNG_DRBG_NextSeedGenerate() climb a ladder for a chain-backed
instance: the retained parent, then the global fallback (under FIPS only
when it qualifies as "a sibling of the parent, an ancestor, or the initial
randomness source" per SP 800-90C), then -- unless the instance is
WC_RNG_FLAG_NO_PRIMARY_SEED -- the primary source. A ladder rung whose
release reports NEEDS_RECOVERY_E voids the reseed (DRBG_NEED_RESEED) or
purges the bank just filled. SP 800-90C qualification of a supplied root
against the retained parent is enforced in wc_RNG_DRBG_ReseedRBGC() and
wc_RNG_DRBG_NextSeedGenerate_RBGC() under FIPS.
* Runtime policy flags: wc_RNG_SetFlags() / wc_RNG_ClearFlags() /
wc_RNG_GetFlags(), limited to WC_RNG_FLAGS_SETTABLE / _CLEARABLE
(FAIL_FAST, ONLY_PRIMARY_SEED, NO_PRIMARY_SEED) and to exclusive
ownership. WC_RNG_FLAG_FAIL_FAST (WC_RNG_INIT_FLAG_FAIL_FAST at birth):
a generate that would otherwise reseed in-line reports instead --
NOT_READY_E for the budget, NEEDS_RECOVERY_E for a latched or stale
instance (RngFailFastVerdict()) -- leaving the DRBG uncondemned;
wc_RNG_Pool_Collect2() sets it transiently on its source so the ring claim
is held for one bounded generate. WC_RNG_FLAG_NO_PRIMARY_SEED /
WC_RNG_INIT_FLAG_NO_PRIMARY_SEED forbids the primary source after
instantiation (chain members that must stay chain-fed; MISSING_RNG_E on an
instance with no chain parent); WC_RNG_FLAG_ONLY_PRIMARY_SEED is the
converse, set transiently by the new wc_RNG_DRBG_Reseed_Now_Primary() for
prediction-resistant constructions on chain-backed instances.
WC_RNG_{INIT_,}FLAG_RECOVER_AND_PROMOTE_FROM_NEXT_SEED is renamed
_UPGRADE_FROM_NEXT_SEED (rng_bank.h: WC_RNG_BANK_FLAG_AUTO_UPGRADE_FROM_
NEXT_SEED). WC_RNG_INIT_FLAG_* retain their shipped values, with the
new flags appended; WC_RNG_FLAG_* are renumbered alongside.
* Transient-vs-verdict taxonomy: WC_RNG_ERR_IS_TRANSIENT() (random.h, with
a mirror in rng_bank.h for boundaries that predate it) names the codes
that mean "not now" -- BUSY_E, NOT_READY_E, NEEDS_RECOVERY_E, RAN_BLOCK_E,
ENTROPY_RT_E, ENTROPY_APT_E. wc_InitRng*() passes them through from the
seed source verbatim (ReseedSourceFailure(), shared by instantiate and
reseed) rather than folding them into RNG_FAILURE_E; rng_bank.c keys its
retry loops on the same set. BUSY_E and MEMORY_E -- a resource that
requires waiting, in a context that can't -- never condemn, even with no
reseed runway (RngGenerateFailure(), now also the single outcome mapping
for wc_RNG_DRBG_Reseed_Now()). wc_RNG_Status() precomputes the code for
a status (NOT_READY_E / RNG_FAILURE_E / DRBG_CONT_FIPS_E) and replaces
the ad hoc status checks throughout. wc_GenerateSeed() with
HAVE_ENTROPY_MEMUSE returns BUSY_E from a context that cannot run the
wolfEntropy source rather than silently substituting a backup source.
* WC_RNG_INIT_FLAG_TEST_USER_SEED: caller-supplied seed material is
health-tested and laid out exactly as module-gathered material (leading
SEED_BLOCK_SZ bytes are the test block, excluded from DRBG input in FIPS
and non-FULL_SEED builds); wc_InitRngFixedSeed() uses it, restoring its
master behavior. Without the flag the user seed is copied at the
instantiate offset, so no supplied byte is discarded and no health test
runs. The strength floors live at the public entry points
(UserSeedSzFloor(): WC_DRBG_SEED_SZ, plus a block under the flag where the
block is excluded; zero refused); _InitRng() keeps only the one-block
backstop. wc_InitRngNonce_UserSeed() refuses without WC_RNG_HAVE_RBGC
(provenance marking lives there) and validates its shape arguments.
Lifecycle hardening (random.[ch]):
* WC_RNG members shared by both DRBG cores -- drbgType, reseedCtr, the
banked-next-seed aperture (nextSeed, nextSeedLen, nextSeedRBGCStratum) --
move from DRBG_internal / DRBG_SHA512_internal into WC_RNG, for safe
lock-free access by lease-free observers; the per-core structs keep the
SMALL_STACK_CACHE newSeed_buf. WC_DRBG_SEED_BUF_SIZE names the gathered
seed length; the generic DRBG functions take the reseed counter by
pointer. NextSeedPtrs() and the per-core duplication it served are gone.
* _InitRng() zeroization (RngInitWipe()) skips the atomic words that can
have lease-free concurrent observers (lock, RBGC_refcount, poolHead/Tail,
nextStirLen, nextSeedLen), which are instead atomically (re)initialized;
the apertures are painted _TORNDOWN at entry and reopened as the last act
before publication, and rng->status becomes DRBG_OK only at the very end.
WC_RNG_INIT_FLAG_PRESERVE_LOCK leaves the lock word and refcount exactly
as found (refusing _LOCK_INITIALLY and _USE_FULL_MUTEX, and insisting the
_REQUIRED bits agree), and discharges an inherited latch by CAS at entry
rather than erasing it. WC_RNG_STATIC_INITIALIZER is provided.
* Pool lifecycle: poolHead carries a 2-bit state above the epoch (UNALLOC,
LIVE, CLAIMED, TORNDOWN). wc_RNG_Pool_Alloc() allocates unclaimed and
publishes by CAS; a writer claims by one CAS at entry and releases by CAS
at every exit; wc_FreeRng() takes LIVE -> TORNDOWN by one CAS before any
irreversible step and returns BUSY_E (nothing mutated) when a claim is
held, never spinning; TORNDOWN refuses re-equipment until the next
_InitRng(). Likewise the credited seed aperture gains
WC_DRBG_NEXT_SEED_TORNDOWN, every ownership transition is a CAS, and a
purge repaints a live claim _PURGED for its holder to unwind rather than
reopening it from under the holder. wc_FreeRng() frees the DRBG after
nulling the pointer at every site, and uninstantiates only the core
matching drbgType.
* wc_FreeRng() in lock builds takes the lease itself (unconditionally, so a
standing latch or condemnation does not block teardown) and refuses a
held instance with BUSY_E; wc_FreeRng_PreLocked() is the form for a
caller already holding the lease, which it retains. The WC_RNG_LOCK_
REQUIRED-but-unheld case is OBJECT_NOT_LOCKED_E. wc_RNG_lock_get_
unconditional() / _put_unconditional() are the internal trivial forms.
* wc_RNG_DRBG_GetReseedCtr() becomes WOLFSSL_LOCAL (the counter is
potentially sensitive internal state); wc_RNG_DRBG_NextSeedGenerate_
Primary() is added; wc_RNG_DRBG_NextSeedCurrent(), wc_RNG_Pool_Current()
and wc_RNG_lock_read() take const. 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 (was MISSING_RNG_E, which nothing on
that path returned). A stir refuses with the needs-recovery verdict
(NEEDS_RECOVERY_E) when the instance is quarantined, due, or stale, and
NOT_READY_E only when the interval trips within the call.
* WC_VERBOSE_RNG logging follows the taxonomy: transient codes are never
logged as errors.
rng_bank.c / rng_bank.h:
* struct wc_rng_bank_inst now places its WC_RNG at offset 0, so
WC_RNG_BANK_INST_TO_RNG() is a cast; wc_rng_bank_reinit_rng() (LOCAL)
retires and reinstantiates any bank-owned rng, protected by WC_RNG.lock
under _PRESERVE_LOCK where available (a held root yields BUSY_E) and by
the inst-op gate otherwise; wc_rng_bank_inst_reinit() and
wc_rng_bank_root_rng_reinit() are built on it. A member is reborn only
as a chain child of its root -- a root that cannot serve right now is a
reason to retry, never to substitute a primary reseed.
* wc_rng_bank_reseed_range(): the RBGC arm takes the root's lease for the
chain draw; the walk carries on past a per-instance failure (marking the
instance due) and returns the first such failure, with a code that
aborted the walk (WC_TIMEOUT_E, INTERRUPTED_E, a checkout failure)
outranking it; wc_rng_bank_next_seed_generate_local() purges the member
when the root's release reports an event under its hold, as
wc_RNG_DRBG_NextSeedGenerate()'s chain arm does.
* wc_rng_bank_fini(): a member refusing to free (BUSY_E /
STILL_REFERENCED_E) restores the bank refcount so the caller can and must
retry; the root is freed after the members, so member pins are released
before the root's refcount is judged. The invalidation walk's root arm is
unconditional (a root mid-reinit is NOT_INIT with its lock word live).
Init retry loops key on WC_RNG_ERR_IS_TRANSIENT().
* rng_bank.h: WC_RNG_LOCK_ORPHANED / WC_RNG_LOCK_EXTRA_SHIFT 5 mirrored in
the no-lock compat arm; for the WCv5.2.4 boundary, which carries the
backported RNG services, WC_RNG_HAVE_STIR / WC_RNG_HAVE_RESEED_NOW
capability markers and a wc_InitRngNonceRBGC() perso-argument shim, so
consumers outside the boundary (src/ssl.c, src/ssl_crypto.c) gate on the
markers rather than on FIPS version arithmetic.
linuxkm/lkcapi_sha_glue.c:
* wc_linuxkm_rng_state_invalidate(): with the entropy epoch, bumps the
epoch and materializes only the bank root's latch synchronously
(rng_invalidation_pre_check() keys on it), leaving members to lazy
delivery so a consumer is admitted to a still-unlatched member and
recovers it under its own lease rather than waiting out a quarantine;
without the epoch, the synchronous walk as before. The daemon-less bank
path treats a transient member code from wc_rng_bank_reseed_range() as a
deferred recovery, not a failure.
* Entropy daemon: a transient failure of the last-ditch root reinit is
retried next pass rather than ending the daemon (which had made root
recovery and next-seed feeding end for good on ordinary contention);
the vmgenid poller's immediate root reseed takes the root's lease (it was
OBJECT_NOT_LOCKED_E and void-cast); the kernel-log rule throughout --
transient codes are one pass away and not errors, the SP 800-90B health
verdicts are warnings (WC_LKM_RNG_ERR_IS_HEALTH()), anything else is an
error -- at the recovery, banking, bonus-reseed and reinit arms; the
banking pass's no-DRBG case is WRONG_TYPE_OBJECT_E; busy instances are
counted in the recovery sweep's tally.
* wc_linuxkm_drbg_generate(): the kernel-facing language is two-valued --
-EIO for a verdict (non-transient, or ENTROPY_RT_E / ENTROPY_APT_E),
-EBUSY for every "not now" code; only BUSY_E outside the invalidation
window (every instance held at once: an undersized bank) is logged as an
error. The pooling pass (re)equips any instance it finds poolless each
turn, so no up-front allocation and no special case after a
reinstantiation. Bank sizing rationale documented.
* The _get_random_bytes() callback contract is best-effort, not
unconditional success: a refusal from atomic context immediately after a
global invalidation falls through silently to the native generator.
linuxkm/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-7v3.patch: drop the
WARN_ONCE on callback failure, and drop the routing of the batched
get_random_{u8,u16,u32,u64}() through the callback (not FIPS-controlled
consumers; get_random_bytes_user() and getrandom() remain fully covered).
Tests:
* wolfcrypt/test/test.c: flags_test() (WCFLAGS) replaces rng_flag_abi_test():
pairwise-disjointness of every bit-flag namespace in the wolfcrypt headers
at compile time and of the hand-numbered registries at run time, against
the symbols rather than literal values; rng_epoch_test() (RNGEPOCH: epoch
propagation on every aperture, mid-gather increments, busy and
out-of-memory seed sources never condemn); rng_lifecycle_test() (RNGLIFE:
RBGC parent pinning and STILL_REFERENCED_E, the destruction latch,
wc_FreeRng_PreLocked() and the _PRESERVE_* reinit, the bank-walk mirror
arm); rng_lock_fork_test() (RNGLKFRK: the orphaned-lease verdict and
adoption across a real fork()); rng_init_flags_test() (contradictory and
not-compiled-in init flags refused) and rng_seed_verdict_test() (transient
codes from the seed source survive wc_InitRng*() verbatim; FIPS v7+ only,
the pinned legacy random.c folds them); rng_seed_test() reactivated (dead
since the seed-size defaults moved into random.h) and steered to SHA-256
in SHA-512-preferring builds; WC_RNG_INIT_FLAG_TEST_USER_SEED arms in the
wc_InitRngNonce_UserSeed() strict-contract block; leak fixes and
goto-teardown in the RBGC-lifetime and pool tests; per-subtest in-kernel
stack high-water marks (WC_LINUXKM_STACK_DEBUG_PER_TEST); WC_RNG moved to
the heap in pkcs7authenveloped_run_vectors().
* tests/api/test_random.c, tests/unit-mcdc/test_random_*whitebox.c: follow
the reseed counter to WC_RNG; forced seed failures use a nonsense code so
the WC_VERBOSE_RNG line stays quiet; condemnation-on-reseed-failure arms
saturate the counter explicitly, since invalidation no longer does.
* doc/dox_comments: every new API and flag; the instantiation-input and
user-seed contracts; reseed/reseed_range return semantics; the next-seed
return taxonomy.