wc_port.h guarded a sys_clock_gettime()/sys_clock_settime() remap with
"#ifndef CLOCK_REALTIME". On Zephyr 4.3 and newer the same header includes
<time.h>, and both picolibc and newlib define CLOCK_REALTIME as 1. The guard was
therefore always false, the whole block was skipped, and z_time() called
clock_gettime() - a symbol Zephyr only defines when the application enables
CONFIG_POSIX_TIMERS, which is itself gated behind CONFIG_POSIX_SYSTEM_INTERFACES.
A build without them failed:
test.c:3657:9: error: implicit declaration of function 'clock_settime';
did you mean 'sys_clock_settime'?
Making the remap unconditional fixes that build but hands every consumer a
library-wide rewrite of two POSIX names. wc_port.h is reached from every
wolfCrypt header, so an application calling clock_gettime() would silently get
sys_clock_gettime(), which reports failure as a negative errno instead of -1
plus errno, and code that stores a function pointer under either name would stop
compiling depending on its include order.
Drop the macros and name the Zephyr API at the three places that need it -
z_time(), the wolfCrypt test's dummy wallclock and the threaded TLS sample -
keeping the POSIX call for Zephyr versions without SYS_CLOCK_REALTIME.
sys_clock_gettime() lives in lib/os/clock.c and is core Zephyr rather than
POSIX, so a Zephyr build no longer has to enable the POSIX layer just to satisfy
wc_port.c.
fe_448.c: small code corner case in reductions
eccsi.c: don't modify ssk field of key on verify
wc_mlkem_poly.c: When compiled for Intel assembly but not AVX2 - no assembly code used - the initialization of the SHAKE is needed in derive secret. Always initialize as it doesn't cost much.
sp_c32.c/sp_c64.c: corner case of div - when r1 is negative is really is going meant to be 0
sp_c32.c: Fix TOOM-3 mul and sqr to handle over large inputs.
ed448.c: check non-canonical keys better
wolfcrypt/test/test.c, wolfssl/wolfcrypt/random.h: fixes for a second batch
of static-analysis findings.
* vmgenid fallback poller: search the ACPI IDs the kernel vmgenid driver
matches -- "VMGENCTR" and "VM_GEN_COUNTER" -- rather than the spec's
mixed-case spellings. ACPICA upcases _HID/_CID strings when building
the namespace and acpi_get_devices() matches by strcmp, so the old walk
found QEMU only by its _HID and missed CID-only devices (Hyper-V, VMware).
* wc_linuxkm_drbg_generate(): in non-vector builds, drop local_bh_disable()
around the blockable CAN_WAIT reseed and reinit operations and retake it
after, mirroring the vector arm's release/reacquire bracket; the
checkout's migrate_disable() persists across the sleep, preserving CPU
pinning preemptibly.
* entropy daemon and sysfs stats dumps: gate the next-stir format fragments
and arguments on WC_RNG_HAVE_NEXT_SEED.
* new WC_LKM_BANK_RBGC_FLAG (WC_RNG_BANK_FLAG_RBGC when WC_RNG_HAVE_RBGC,
else WC_RNG_BANK_FLAG_NONE): keep LKCAPI functional without RBGC support
compiled in.
* wc_rng_bank_init_nonce(): use (size_t)(-1) rather than SIZE_MAX in the
allocation overflow check (C90 and NO_STDINT_H builds).
* wc_rng_bank_fini(): pre-scan all instances for WC_RNG_LOCK_HELD before any
mutation, returning BUSY_E (retryable) with refcount untouched, free hook
unfired, and root intact.
* random.h: #error on WC_RNG_DEBUG_STATS without the RNG lock facility.
* wc_RNG_DRBG_Stir_Nonce(): reject nonce == NULL with nonzero nonceSz
(BAD_FUNC_ARG), matching the other nonce-bearing APIs.
* random_bank_test(): hoist held_inst to function scope and check it in
from the shared teardown path, closing a leak on failing assertions.
* wc_RNG_DRBG_NextSeedGenerate_local(): pointer declaration style cleanup.
wolfssl/wolfcrypt/settings.h: fixes for a batch of static-analysis findings.
* complete the WC_CAS_WITH_RETRY post-loop dispositions in rng_bank.c and the
lock_put()s: aborted releases percolate before the lock word (and, in
wc_RNG_lock_put(), the mutex) is reported free, keeping ownership with the
caller for retry; the inst_lock_*_extra() setters return the CAS result;
wc_rng_bank_inst_invalidate_entropy() latches or condemns, mirroring
wc_RNG_invalidate_entropy().
* wc_RNG_invalidate_entropy(): tolerate WRONG_TYPE_OBJECT_E from
wc_RNG_DRBG_ScheduleReseed() -- a no-DRBG (direct-RDRAND) instance has
nothing to schedule and nothing whose staleness the latch would mark;
don't condemn it.
* wc_rng_bank_reseed_range(): fix undeclared identifier (inst -> drbg) in the
HAVE_FIPS && FIPS_VERSION3_LT(7,0,0) && WC_RNG_HAVE_RBGC branch.
* _InitRng(): free and clear the full mutex when wc_LockMutex() fails after
successful wc_InitMutex() (WC_RNG_INIT_FLAG_LOCK_INITIALLY).
* settings.h: WC_RESEED_INTERVAL (1UL << 48UL) -> (W64LIT(1) << 48) --
unsigned long is 32 bits on LLP64 targets (64-bit MinGW), making the
shift undefined.
* test.c: silence unused i in random_bank_test() when the reseed-interval
check is configured out.
* in struct wc_rng_bank, rename daemon_root to root_rng, and change its gate from WC_RNG_BANK_HAVE_DAEMON_SUPPORT to WC_RNG_HAVE_RBGC || WC_RNG_HAVE_NEXT_SEED || WC_RNG_HAVE_POOL.
* add devId slot to struct wc_rng_bank.
* rename WC_RNG_BANK_FLAG_INIT_RBGC to WC_RNG_BANK_FLAG_RBGC, and support it in wc_rng_bank_reseed_range().
* remove root argument from wc_rng_bank_next_seed_generate_rbgc() (bank->root_rng is now implicit).
* remove wc_rng_bank_daemon_root_set() and wc_rng_bank_daemon_root_get(), and add wc_rng_bank_root_rng_init() and wc_rng_bank_root_rng_get().
* revert wc_rng_bank_inst_lock_get() et al from macros back to inlines, to assure type enforcement, and remove dangerous cast from WC_RNG_BANK_INST_TO_RNG().
* in wc_rng_bank_init_nonce(), use the persistent ctx->root_rng, removing the ephemeral-on-stack "WC_RNG root".
* in wc_rng_bank_fini(), clean up ctx->root_rng.
* in wc_rng_bank_reseed_range(), implement support for WC_RNG_BANK_FLAG_RBGC.
* in wc_rng_bank_invalidate_entropy(), add invalidation of bank->root_rng.
linuxkm/lkcapi_sha_glue.c:
* in wc_linuxkm_rng_state_invalidate(), remove now-obsolete special-case "daemon_root" code, and pass WC_RNG_BANK_FLAG_RBGC to the inline (non-daemon) wc_rng_bank_reseed_range().
* in wc_linuxkm_entropy_daemon(), rename local_root to root_rng, assign it at entry from wc_rng_bank_root_rng_get(bank), and remove the in-daemon cleanup of local_root; move the periodic explicit reseed of the root_rng to precede the pooling pass.
leaf was declared inside the inner block that initializes it, so the
ERROR_OUT() calls between its wc_InitRngNonceRBGC() and its wc_FreeRng()
jumped to a teardown that could neither see it nor free it. Any failed
assertion in that window leaked the DRBG allocation and whatever else the
instance held.
Hoist the declaration to function scope under the same guard, track
initialization, and free it from out: alongside root.
Reported by Fenrir.
The assertion rejected only a decreased reseed counter, which no
implementation would produce, so it could not distinguish a stir from a
credited reseed or from a stir that never ran.
A stir is one SP 800-90A Rev.1 10.1.1.4 generate with the stir material as
additional input, so step 7 advances the counter by exactly one. Require
that: a reset to 1 would mean the stir had masqueraded as a credited reseed,
and no change at all would mean it never executed.
Reported by Fenrir, whose suggested assertion -- that the counter be
unchanged -- does not hold: it fails against the current implementation,
because incrementing is what the generate is required to do.
The banking loop assigned wc_RNG_DRBG_NextSeedGenerate()'s return value to
api_ret and then immediately overwrote it with wc_RNG_DRBG_NextSeedCurrent()'s,
so every check below -- the error classification, the ALREADY_E break, and the
guard on the monotonic-progress assertion -- was reading the query's result,
not the generation's. A hard failure from the generate could not fail the
test.
Keep the two results in separate variables and classify the generate's own
return value.
Reported by Fenrir.
Two related gaps in what callers could supply.
The SP 800-90A personalization string was reachable only as the hardcoded
NULL that _InitRng() passed to Hash_DRBG_Init(). Hash_df() already had
the input; nothing could fill it. Thread it through the instantiate
family -- wc_InitRngNonce_ex2(), wc_InitRngNonceRBGC{,_New}(),
SpawnRngRBGC(), wc_rng_bank_init_nonce() and wc_rng_bank_spawn{,_new}().
Personalization is an instantiate-time input in SP 800-90A, so the reseed
and stir APIs deliberately do not gain it; material of that kind belongs
in their existing additional-input argument.
Separately, the bank-level seed and reseed APIs had no way to pass a nonce
to the per-instance reseed underneath them, so wc_rng_bank_seed{,_range}()
and wc_rng_bank_reseed{,_range}() gain one. The index arguments keep
their positions and the material sits immediately before timeout_secs.
linuxkm uses it to carry a post-event timestamp into the recovery reseeds
issued after a state invalidation, and zeroizes it on every path, matching
the existing uncredited-nonce sites in that file.
RBGCStratum was reset to 0 by any successful reseed, including one
carrying a caller-supplied seed. Stratum 0 means "primary" -- an RNG
seeded from the entropy source -- and it is what
wc_RNG_DRBG_NextSeedGenerate_local() requires of a NextSeed root. So a
single wc_RNG_DRBG_Reseed() call promoted an instance to a provenance it
had not earned.
Reserve a disjoint region of the stratum space for chains rooted in
user-supplied entropy. A user-seeded reseed now sets
WC_RNG_RBGC_USER_SEED_STRATUM rather than 0, and children descend from
there, so unknown provenance is carried rather than erased. Source-
gathered reseeds still promote to 0.
Guards in _InitRng(), wc_RNG_DRBG_ReseedRBGC_local() and
wc_RNG_DRBG_NextSeedGenerate_local() keep a natural chain from growing
into the reserved region, and a static assert keeps the two regions from
overlapping if the constant is overridden.
Consequence worth stating: while an instance carries a user-seed stratum
it cannot serve as a NextSeed root. That is state, not a brand -- a
credited primary reseed promotes it back to 0, and an RBGC reseed places
it one below its root. random_bank_test() covers both directions: a
spawned child at USER_SEED_STRATUM + 1, and a prediction-resistance spawn
whose parent is re-promoted to 0 by a fresh credited primary reseed
immediately before the child's draw.
The RBGC test entry points were gated on WC_RNG_HAVE_RBGC alone, and the
pre-v7 copy of rng_drbg_rbgc_test() pulled rng_bank.h in with
WC_RNG_BANK_SUPPORT defined locally and then undefined again, so that the
RNG-level compat shims were visible only inside that one translation
region.
Gate the tests on the boundary version or on WC_RNG_BANK_SUPPORT actually
being configured, and drop the local define/undef dance in favour of the
real setting. The shims are needed by more than that one test.
FIPS builds force crypto callbacks off, so a test that asserts a callback
took effect is structurally incompatible with any FIPS build, not just
pre-v7 ones. The guard admitted FIPS v7 and later, where the test cannot
pass.
Narrow both the definition guard and the call site to !defined(HAVE_FIPS).
appropriately spelled, for clarity and consistency. Stirring is implemented
by Hash_DRBG_StirGenerate() an an SP 800-90A Rev. 1 10.1.1.4 generate, with
the stir material as additional_input and no output requested.
* implement Hash_DRBG_StirGenerate(), refactor
wc_RNG_DRBG_Reseed_Nonce_Uncredited() and wc_RNG_DRBG_Reseed_Uncredited() atop
it, and revert addition of "credited" arg to Hash256_DRBG_Reseed(),
Hash512_DRBG_Reseed(), and Hash_DRBG_Reseed();
* in _InitRng(), error early on invalid flags, and implement proper catch-all
error path cleanup;
* in wc_RNG_GenerateBlock(), when rng->pid != getpid(), alongside
PollAndReSeeD(), empty the pool and cached seeds, if any;
* also check for WC_RNG_LOCK_ENTROPY_INVALIDATED immediately before calling
Hash*_DRBG_Generate() and if found, recover inline with must-succeed
PollAndReSeed().
configure.ac: add --enable-rng-extras aka -DWC_RNG_EXTRAS, default off unless KERNEL_MODE_DEFAULTS, and add it to enable-all-crypto and FIPS v7 setup.
wolfssl/wolfcrypt/random.h: refactor setup for RNG extras to default off unless defined(WC_RNG_EXTRAS) or the specific WC_RNG_WANT_foo is defined.
wolfcrypt/src/random.c: add missing WC_RNG_HAVE_LOCK gate around NextSeedPurge().
.wolfssl_known_macro_extras: add WC_RNG_WANT_*
wolfcrypt/test/test.c: add !HAVE_SELFTEST gate around rng_drbg_svc_test().
wolfssl/wolfcrypt/types.h: if WOLFSSL_NO_MALLOC and !WOLFSSL_STATIC_MEMORY, make sure WC_NO_CONSTRUCTORS is defined.
* WC_RNG_DEBUG_STATS: global atomic counters across the RNG facilities
-- seeds and reseeds by provenance (source, RBGC, banked next seed,
uncredited stir), generates, pool collects/extracts, bank
checkouts/recoveries -- with wc_rng_debug_stats_snap() /_restore()
/_sum() for snapshot-delta accounting in tests and daemons;
wc_rng_debug_counter_t is word64, word32 where 64-bit is unavailable;
* settings.h: default the knob on for verbose-debug kernel builds
(WC_VERBOSE_RNG && WOLFSSL_KERNEL_VERBOSE_DEBUG), opt-out
WC_RNG_NO_DEBUG_STATS;
* test.c: snapshot-delta assertions verifying the counters advance with
the operations that claim them.
* daemon protocol: wc_rng_bank_daemon_reserve() /_register()
/_unregister() /_release(), a magic-word claim
(WC_RNG_BANK_DAEMON_MAGIC_FREE when unclaimed) admitting exactly one
scheduling daemon per bank, and wc_rng_bank_daemon_root_{set,get}()
binding the daemon's RBGC root; gated
WC_RNG_BANK_HAVE_DAEMON_SUPPORT;
* WC_RNG_BANK_FLAG_DEFAULT_BANK marks the process-default bank;
wc_rng_bank_fini() for symmetric teardown; per-instance flags word
(WC_RNG_BANK_INST_FLAG_*, with _ALREADY_WARNED de-duplicating
degradation warnings);
* test.c random_bank_test(): daemon claim/release contracts, double
claim rejection, root binding, and teardown coverage.
* a second, fixed-size aperture beside the banked next seed:
wc_RNG_DRBG_NextUncreditedSeedStore() banks caller-supplied material
(up to WC_DRBG_NEXT_UNCREDITED_SEED_LEN bytes) and
wc_RNG_DRBG_NextUncreditedSeedNow() stirs it into the DRBG as an
uncredited, source-free, atomic-context-safe reseed -- harvested
entropy improves the instance without claiming credit or resetting
the reseed counter; the hand-off reuses the nextSeedLen aperture
protocol (WC_DRBG_nextSeedLen_t);
* test.c: uncredited-aperture coverage in rng_drbg_nextseed_test():
store/stir protocol, non-resetting counter, coexistence with the
credited bank, and the argument contracts.
* wc_RNG_invalidate_entropy() / wc_rng_bank_invalidate_entropy(): mark
an instance's (or a whole bank's) seed material untrusted -- for VM
fork/resume and similar duplication events -- by latching
WC_RNG_LOCK_ENTROPY_INVALIDATED in the lock word; an invalidated
instance refuses service until recovery-reseeded, and
wc_rng_bank_inst_lock_get_conditional() lets checkout skip
invalidated instances rather than block on them;
* recovery admission: WC_RNG_BANK_FLAG_MAYBE_FOR_RECOVERY tolerates a
not-actually-invalidated instance,
WC_RNG_FLAG_RECOVER_AND_PROMOTE_FROM_NEXT_SEED (and the bank spawn
analog _SPAWN_RECOVER_AND_PROMOTE) admits a banked next seed as the
recovery source; wc_rng_bank_{seed,reseed}_range() (re)seed instance
subsets;
* free hooks: wc_RNG_register_free_hook() /
wc_rng_bank_register_free_hook() -- teardown notification for
external registries (e.g. a kernel-module RNG object registry that
must invalidate on VM resume), gated WC_RNG_HAVE_FREE_HOOK;
* test.c: new rng_drbg_invalidate_test() (RNGINVAL) covering
invalidation latching, refused service, conditional checkout,
recovery admission (including next-seed-sourced), free-hook firing,
and the argument contracts; lock-word read probes in the svc test.
* a caller-sized buffer of pre-generated output attached to a WC_RNG
(wc_RNG_Pool_Alloc()), filled incrementally by wc_RNG_Pool_Collect()
-- or wc_RNG_Pool_Collect2(), drawing from a second instance -- and
drained atomic-context-safely by wc_RNG_Pool_Extract();
wc_RNG_Pool_Current() reports the fill; the collect/extract hand-off
is arbitrated by an aperture word (WC_RNG_pool_state_t, atomic with a
plain-word arm for WOLFSSL_NO_ATOMICS), on the same protocol shape as
the banked next seed;
* gated by WC_RNG_HAVE_POOL (opt-out: WC_RNG_NO_POOL);
* test.c: new rng_drbg_pool_test() (RNGPOOL), covering the collect /
extract protocol, the two-instance collect, exhaustion, and the
argument contracts.
* struct WC_RNG.isRbgcLeaf becomes int RBGCStratum: 0 for a root, n for a
chain member seeded from a stratum-(n-1) parent, sticky for the
instance's lifetime, with SEQ_OVERFLOW_E on stratum overflow;
wc_RNG_DRBG_IsRBGCLeaf() becomes wc_RNG_DRBG_GetRBGCStratum();
SpawnRngRBGC() reworks to parent/child terms with a flags argument,
omitting the seed health test (superfluous when a healthy DRBG
generates the seed data);
* the wc_InitRng*RBGC() constructors gain a flags argument
(WC_RNG_INIT_FLAGS_*); new wc_RNG_DRBG_ReseedRBGC_Uncredited();
* banked next seeds carry provenance: nextSeedRBGCStratum in the DRBG
aperture, WC_RNG_FLAG_RBGC_NEXT_SEED marking a chain-filled bank,
wc_RNG_DRBG_NextSeedGenerate_RBGC() to fill from a parent, and
wc_RNG_DRBG_GetNextSeedRBGCStratum() (race-free via the aperture
protocol) to interrogate it;
* carve the whole facility out under WC_RNG_HAVE_RBGC (opt-out:
WC_RNG_NO_RBGC), derived from HAVE_HASHDRBG &&
!CUSTOM_RAND_GENERATE_BLOCK;
* rng_bank: WC_RNG_BANK_FLAG_INIT_RBGC instantiates bank instances as
chain children of an internal root, on FIPS v7+ boundaries with
_LOCK_REQUIRED;
* test.c: rng_drbg_rbgc_test() reworked for strata (including a pre-v7
compat arm via the rng_bank.h shims), spawn contracts updated for the
flags argument, and stratum probes in the svc and bank tests.
* wc_rng_bank_inst_lock_{get,put,read}() are reimplemented over
wc_RNG_lock_*(): the per-instance lock word is now the instance
WC_RNG's own lock, with the bank-specific bits (affinity-locked,
vec-ops-inherit) carried above WC_RNG_LOCK_EXTRA_SHIFT; instances are
instantiated WC_RNG_INIT_FLAGS_LOCK_REQUIRED on FIPS v7+ boundaries;
stale check-ins now surface OBJECT_NOT_LOCKED_E; optional
WC_RNG_BANK_LOCK_DEBUG instrumentation;
* WC_RNG_BANK_FLAG_PREDICTION_RESISTANCE, per-call or bank-wide: every
sleepable lease is freshly credited-reseeded before the caller's first
draw; demands _CAN_WAIT and contradicts uncredited and recovery
seeding (BAD_FUNC_ARG); atomic callers under a bank-wide posture are
refused; recovery is exempt, and remains the sole restoration path for
a failed instance; PR supersedes _CONSUME_NEXT_SEED, leaving the
banked seed intact for a later consumer;
* new wc_rng_bank_init_nonce(), wc_rng_bank_first_failover_inst_set(),
wc_rng_bank_get_inst_id(); WC_RNG_BANK_FLAG_NO_CHECKOUT_REFCOUNTING;
bank flag literals become unsigned (1U << n);
* test.c random_bank_test(): argument/alignment contracts for the
check-in entry points, PR contract and posture coverage, and probe
modernization -- capture retvals and report them with
WC_TEST_RET_ENC_EC()/_ENC_I() instead of bare _ENC_NC.
* funnel all reseeds through a dual-DRBG-aware rng-level Hash_DRBG_Reseed()
(the SHA-256-internal routine becomes Hash256_DRBG_Reseed()), with an
explicit credited flag: credited reseeds reset the reseed counter,
uncredited ones mix in material without resetting it;
* add wc_RNG_DRBG_Reseed_Nonce() and wc_RNG_DRBG_Reseed_Nonce_Uncredited(),
accepting a nonce as additional input; wc_RNG_DRBG_Reseed() and
wc_RNG_DRBG_Reseed_Uncredited() become thin wrappers around them;
* wc_RNG_DRBG_ScheduleReseed() and the commanded-reseed paths now return
WRONG_TYPE_OBJECT_E, not success, for instances with no DRBG (RDRAND et
al.) -- a commanded reseed that cannot happen is not a success;
* hoist wc_RNG_GetStatus() and wc_RNG_DRBG_Present() above the HASHDRBG
region with hardened gates, and promote them to public API
(WOLFSSL_API prototypes in random.h);
* random.h: regate the service prototypes per-facility (accessors ungated,
RBGC spawn under HAVE_HASHDRBG && !CUSTOM_RAND_GENERATE_BLOCK, banked-
next-seed under WC_RNG_HAVE_NEXT_SEED), migrating the explanatory
comments into random.c beside the implementations.
* integrate the banked-next-seed facility, and add WC_RNG_BANK_FLAG_QUIET.
* add recovery-patrol and leased-spawn support: WC_RNG_BANK_FLAG_FOR_RECOVERY, WC_RNG_BANK_FLAG_ERROR_ON_RNG_FAILED, wc_rng_bank_recover_inst(), wc_rng_bank_spawn(), and wc_rng_bank_spawn_new().
struct wc_rng_bank gains inst_op_gate, a bank-global wolfSSL_Atomic_Int serializing whole-instance operations against the daemon's lockless banking: wc_rng_bank_next_seed_generate() (the daemon entry point) claims it around wc_RNG_DRBG_NextSeedGenerate(), and wc_rng_bank_inst_reinit() claims it around its free/reinstantiate cycle -- non-blocking on both sides (BUSY_E = skip this turn / this attempt). lease-holders never consult the gate; instance-lock exclusion already covers every lease-holder interaction, so the hot path is untouched. the entry point's return taxonomy is daemon policy: ALREADY_E = sleep until consumed; MISSING_RNG_E = retire the instance from the banking rotation; others transient.
WC_RNG_BANK_FLAG_CONSUME_NEXT_SEED: wc_rng_bank_checkout() consumes a ready banked next seed on the locked instance BEFORE the usability evaluation, with the return value deliberately ignored -- every outcome is fully represented in instance state and handled uniformly by the incumbent divert/error/handout machinery: a consumed bank cures a reseed-due instance in place (no divert, no warning); a hard reseed failure marks the instance out of service and flows through the standard paths.
WC_RNG_BANK_FLAG_QUIET (bank-level only, set at wc_rng_bank_init(); no per-call meaning): suppresses the facility's WC_VERBOSE_RNG expected-condition warnings -- reseed-due handout, reinit retry/timeout reports, all-instances-busy, seed-walker out-of-service reports -- so deliberate exercising doesn't spam the log; never suppresses refcount/consistency diagnostics. random_bank_test() sets it at both bank constructions and gains coverage for the daemon entry point's contracts and the consume-at-checkout flow (fill to ALREADY_E, consume lands the reseed counter at 1, empty-bank consume is transparent).
_FOR_RECOVERY declares a recovery-intent checkout of an explicit instance: out-of-service status is expected, the consume-next-seed arm is suppressed, and selection-altering flags are rejected. wc_rng_bank_recover_inst() packages checkout -> reinit-iff-out-of-service -> checkin; healthy instances are success no-ops, so patrols can act on lockless status observations.
_ERROR_ON_RNG_FAILED guarantees checkout returns either a lease on an in-service instance or an error with no lease, closing the two paths that could lease a dead one (targeted checkout; failover after the anti-livelock lap disarm). under _CAN_WAIT a dead instance is retried within the timeout budget -- the window in which a recovery patrol restores it -- and a lap or wait that found only out-of-service instances reports the distinguished BAD_STATE_E.
wc_rng_bank_spawn()/_spawn_new() check out an instance (implying _ERROR_ON_RNG_FAILED), wc_InitRngNonceRBGC[_New]() an SP 800-90C chain leaf from it, and check it back in via wc_rng_bank_inst_checkin(); the leaf's lifetime is thereafter decoupled from the bank and lock-free for its owner. _CONSUME_NEXT_SEED composes for a banked reseed of the root before the spawn draw. the heap form and its supporting arms are gated !WC_NO_CONSTRUCTORS, mirroring wc_InitRngNonceRBGC_New()'s declaration; the stack form remains available under WC_NO_CONSTRUCTORS. random_bank_test() gains coverage for the one-arg checkin roundtrip, the flag contracts and rejected combinations, recovery-patrol no-op semantics, and both spawn forms.
wolfcrypt/src/random.c and wolfssl/wolfcrypt/random.h: add the banked-next-seed facility: wc_RNG_DRBG_NextSeedGenerate(), wc_RNG_DRBG_NextSeedCurrent(), wc_RNG_DRBG_NextSeedNow(), and wc_RNG_DRBG_NextSeedNow_Nonce(), with unit test coverage in new rng_drbg_nextseed_test() ("RNGNXTS").
seed material is banked incrementally, in-boundary, from the module's seed source, and consumed in an immediate credited reseed that touches no seed source -- pure computation, safe in atomic context (the one credited reseed shape with that property). banked reseeds provide no SP 800-90 prediction resistance (the material predates the request by construction); wc_RNG_DRBG_Reseed_Now() remains the live-gather shape.
DRBG_internal and DRBG_SHA512_internal gain nextSeed[] (identical byte accounting to every other source-fed (re)seed) and nextSeedLen, a wolfSSL_Atomic_Int hand-off aperture: non-negative values count banked bytes (filling); negative values are sentinels (WC_DRBG_NEXT_SEED_READY, _CONSUMING). the single-writer daemon fills with AddFetch and publishes _READY with a CAS after health-testing the completed bank (wc_RNG_TestSeed()); a consumer claims with a CAS _READY -> _CONSUMING, reseeds, zeroizes, and release-stores _EMPTY. use-once throughout: delivered, failed, and health-test-rejected material is all zeroized before the aperture reopens.
distinct protocol results, deliberately loud: ALREADY_E (bank ready or consuming), NOT_READY_E (nothing consumable), RETRY_E (health test could not run -- non-dispositive MEMORY_E; leave the bank complete and re-call), MISSING_RNG_E (no DRBG instantiated, e.g. RDRAND bypass -- a direct caller must know what instance it holds). gathering calls wc_GenerateSeed() with a local zero-initialized throwaway OS_Seed, fully independent of rng->seed, so the daemon cannot race an owner's own source reseed; any working seed source suffices (wolfEntropy, RDSEED, et al.). gate: WC_RNG_HAVE_NEXT_SEED = HAVE_HASHDRBG && !CUSTOM_RAND_GENERATE_BLOCK && WOLFSSL_ATOMIC_OPS, opt-out WC_RNG_NO_NEXT_SEED (registered in .wolfssl_known_macro_extras).
RNGNXTS covers the aperture protocol as observed through _NextSeedCurrent() (empty, partial-preserved-across-consume-attempt, monotone fill, ready sentinel, ALREADY_E idempotence, consume -> reseed counter 1 -> empty, refill and _Nonce consume) and the argument contracts, runtime-gated on wc_RNG_DRBG_Present().
wolfcrypt/test/test.c: in random_bank_test(), gate the wc_rng_new_bankref() probes (and the rng2 local and its cleanup) on !WC_NO_CONSTRUCTORS, matching the API's declaration; the wc_InitRng_BankRef() probes are constructor-free and keep the bare WC_HAVE_RNG_BANKREF gate. (fixes an implicit function declaration under WC_NO_CONSTRUCTORS + WC_RNG_BANK_SUPPORT, a configuration with no prior harness coverage. predates the NextSeed work.)
implement by adding a seedRng arg to _InitRng() and PollAndReSeed(): when non-null, seed material is drawn from the parent DRBG's generate function in place of the module's seed source, inheriting all other instantiate/reseed mechanics verbatim (seed byte accounting, wc_RNG_TestSeed(), instantiate/reseed dispatch, failure disposition, RDRAND bypass, SMALL_STACK arms). unified spawn mechanics in static SpawnRngRBGC() with exactly-one-destination arg checking; the four spawn APIs and wc_RNG_DRBG_ReseedRBGC() are minimal stubs.
add WC_RNG.isRbgcLeaf: sticky tag set by spawn and by successful wc_RNG_DRBG_ReseedRBGC() (chain-reseeding a source-born instance demotes it, one-way); every RBGC API rejects a tagged root, enforcing depth-one chains programmatically. the tag survives source reseeds by policy.
annotate the deliberate PollAndReSeed() <-> wc_RNG_GenerateBlock() recursion for clang-tidy misc-no-recursion on each cycle member: the cycle is bounded at one trip lexically -- wc_RNG_GenerateBlock()'s backstop reseed always passes a null seedRng -- independent of chain topology and the depth-one policy.
gate RBGC APIs on !WC_NO_CONSTRUCTORS (the _New variants allocate from the root's heap and release with wc_rng_free()). also neutralize the seed-acquisition failure message attribution in _InitRng() (no longer necessarily wc_GenerateSeed()).
add rng_drbg_svc_test() ("RNGSVC") and rng_drbg_rbgc_test() ("RNGRBGC").
RNGSVC covers the DRBG accessor/reseed services and per-key RNG clear APIs: accessor null contracts, generate advances the reseed counter, wc_RNG_DRBG_Reseed_Uncredited() preserves it, credited wc_RNG_DRBG_Reseed() resets it, wc_RNG_DRBG_ScheduleReseed() lands it exactly at WC_RESEED_INTERVAL and the next generate performs a source reseed, wc_RNG_DRBG_Reseed_Now() with and without nonce, and wc_RsaClearRNG()/wc_ecc_clear_rng()/wc_curve25519_clear_rng() including the preserved wc_RsaSetRNG(key, NULL) rejection.
RNGRBGC covers the RBGC APIs: spawn arg contracts, root reseed-counter debit, leaf tagging and wc_RNG_DRBG_IsRBGCLeaf(), depth-one rejections (spawn-from-leaf in stack and _New forms, ReseedRBGC-with-leaf-as-root), wc_RNG_DRBG_ReseedRBGC() with and without nonce, tag stickiness across a forced source reseed, one-way demotion, and the _New/wc_rng_free() lifecycle.
DRBG-internal observations are gated at runtime on wc_RNG_DRBG_Present() so both tests pass on RDRAND-shaped instantiations, exercising the degenerate arms. key and WC_RNG objects use the WC_*_VAR() macros to respect kernel frame limits.
wc_rng_bank checkin and seed edge cases from the 20260820 review batch:
duplicate (stale-copy) checkin through both wc_rng_bank_checkin() and
wc_rng_bank_inst_checkin(), asserting BAD_STATE_E without bank mutation;
seedSz == 0 no-op success for an explicit inited bank and for the default
form while a default is set; and seedSz == 0 with no default bank set,
asserting NO_DEFAULT_FOUND_E.
* add NO_DEFAULT_FOUND_E "No default object registered for request type".
* add missing #include <wolfssl/wolfcrypt/logging.h> in WOLFSSL_DEBUG_TRACE_ERROR_CODES path.
* add __func__ to __GNUC__ WC_ERR_TRACE().
wolfcrypt/src/rng_bank.c, wolfssl/wolfcrypt/rng_bank.h, wolfcrypt/test/test.c:
* add wc_rng_bank_inst.bank for parent access from the children.
* add wc_rng_bank_inst_checkin().
* improve thread safety, error checking, and default bank support in wc_rng_bank_checkout(), wc_local_rng_bank_checkout_for_bankref(), wc_rng_bank_inst_reinit(), wc_rng_bank_seed(), wc_rng_bank_reseed(), and wc_InitRng_BankRef_local().
* orthogonalize common code in wc_InitRng_BankRef() and wc_rng_new_bankref() into wc_InitRng_BankRef_local().
wolfcrypt/test/test.c:
* fix typo in PRINT_HEAP_CHECKPOINT().
* add wc_rng_bank_inst_checkin() tests to random_bank_test(), update expected failure codes, and remove obsolete test clauses.
* add missing !HAVE_FIPS gates in cryptocb_test().
wolfcrypt/src/random.c:
* in WC_RNG_BANK_SUPPORT variant of wc_RNG_GenerateBlock(), use the new wc_rng_bank_inst_checkin(), not wc_rng_bank_checkin().
* tweaks to WOLFSSL_DEBUG_TRACE_ERROR_CODES code wrappers to mollify clang-tidy and -Wconversion.
* fix a spelling error in _InitRng().
linuxkm/lkcapi_sha_glue.c:
* in wc_linuxkm_drbg_generate(), opportunistically reseed once half way to WC_RESEED_INTERVAL and wc_linuxkm_can_block(). Also properly inhibit the recovery call to wc_rng_bank_inst_reinit() if ! wc_linuxkm_can_block().
* refactor wc_mix_pool_bytes() to use wc_RNG_DRBG_Reseed(), and only on the CPU-local RNG.
wolfcrypt/src/asn.c, wolfcrypt/src/curve25519.c, wolfcrypt/src/evp.c, wolfcrypt/src/pkcs7.c, wolfcrypt/src/pkcs12.c, wolfcrypt/src/srp.c: at each existing wc_InitRng(), attempt wc_InitRng_BankRef() if WC_RNG_BANK_DEFAULT_SUPPORT && WC_HAVE_RNG_BANKREF.
A context starts in software and only wc_ecc_ctx_set_dev_id() sends the ECIES callback and the KDF, AES and HMAC steps to a device; tests, benchmark, docs and the os-check matrix are updated to match.
With WOLFSSL_NO_MALLOC there is no system heap to fall back on, so an
allocation the compatibility layer makes with a NULL heap has to come out
of the static pool the test loads. The test only nominated that pool as
the global heap hint when OPENSSL_EXTRA was off, so in the combination of
the two those allocations had no source at all and openssl_test() failed.
Set the hint in that combination too, and give it a pool sized for the
compatibility layer on top of the algorithm tests. gTestMemory was sized
for the wolfCrypt tests alone and those allocations exhausted it - first in
wolfSSL_CRYPTO_malloc(), then, as the pool was enlarged, further along in
wolfSSL_X509_load_certificate_file(). Every other configuration keeps the
size it had.
The new arm goes ahead of the FrodoKEM and ML-DSA arms rather than after
them, because those fire first for exactly the builds that need the most.
With --enable-mldsa the 576 KB arm won and the RSA test died with -125, and
1 MB only moved the failure to openssl_pkey1_test(), where an exhausted pool
surfaces as a NULL from wolfSSL_X509_get_pubkey() and no error code at all.
FrodoKEM fails the same way on its own 1 MB arm. Both pass at 2 MB, so the
arm asks for 2 MB when either is enabled and 1 MB otherwise.
Claim the hint only when it is unset, and drop it only while it is still
ours. Nothing in tree installs one before wolfcrypt_test() runs, but under
OPENSSL_EXTRA the hint is never handed back, so a program embedding
wolfcrypt_test() as a smoke test would otherwise lose its own pool for the
rest of the process. This is the first-wins rule the examples already use.
The matching teardown stays restricted to !OPENSSL_EXTRA on purpose.
gTestMemory has static storage duration, so the hint cannot dangle, and
testsuite runs the echo server after wolfcrypt_test() returns: the echo
server has no pool of its own, and this is the one that outlives it.
testsuite/testsuite.test now passes with --enable-staticmemory
-DWOLFSSL_NO_MALLOC. scripts/unit.test still fails there, at seven API
tests this change does not address.
BENCH_EMBEDDED gets a #error rather than the enlarged pool. That combination
is self-contradictory - openssl_pkey0_test() is not gated on BENCH_EMBEDDED, so
it still asks for about 1 MB, which is not something to hand a target that has
declared itself embedded. Refusing at build time with the override named beats
either silently reserving a megabyte or failing at run time in RSA_new(), which
is what a 14 KB pool does today. WOLFSSL_STATIC_MEMORY_TEST_SZ remains the
override and is checked first, so such a target can still pick its own size.
The arm is also restricted to !WOLFCRYPT_ONLY. The compatibility layer tests
are gated on !WOLFCRYPT_ONLY themselves, so a crypt-only build never runs
openssl_pkey0_test() and has no reason to reserve a megabyte for it - and
with BENCH_EMBEDDED it met the #error above over a test it does not compile.
Crypt-only keeps the size it had.
Pin the behaviour the asn.c fix restores while it is here: cert_no_malloc_test()
only asserted the in-place layout under WC_ASN_NO_HEAP, so nothing covered the
copy-out side. Add the mirror assertion - pubKeyStored set, publicKey outside
the source DER. It fails on the pre-fix guard and passes after it, and unlike
fill_signer_twice_test() it is not gated on NO_FILESYSTEM, which a real
static-memory target turns off. Carry ParseCert()'s whole predicate rather
than WC_ASN_NO_HEAP alone: the copy-out is also skipped under
NO_WOLFSSL_CM_VERIFY without WOLFSSL_DYN_CERT, and the assertion must not
claim otherwise there.
The same goes for NO_RSA and NO_SHA. Both openssl_pkey0_test() and
openssl_pkey1_test() compile their bodies away without either one, and
openssl_test() alone then fits the sizes the old ladder gives it:
--disable-rsa with BENCH_EMBEDDED passes the whole suite on the 14000-byte
arm, and without BENCH_EMBEDDED it passes on the 160000-byte arm rather
than reserving a megabyte. Excluding the arm reaches both of those;
narrowing only the #error would have left the plain build at 1 MB and
handed the embedded one the same megabyte the #error exists to refuse.