wolfcrypt/src/random.c, wolfssl/wolfcrypt/random.h, wolfcrypt/src/rng_bank.c, wolfssl/wolfcrypt/rng_bank.h, wolfcrypt/test/test.c: generalize SP 800-90C RBG chains from a leaf tag to strata:

* 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.
pull/11435/head
Daniel Pouzzner 2026-09-09 05:03:21 +00:00
parent 2237e5e1c1
commit 7bca2d66f6
7 changed files with 931 additions and 329 deletions

View File

@ -806,6 +806,7 @@ WC_RNG_BLOCKING
WC_RNG_NO_LOCK
WC_RNG_NO_LOCK_FULL_MUTEX
WC_RNG_NO_NEXT_SEED
WC_RNG_NO_RBGC
WC_RSA_NONBLOCK_TIME
WC_RSA_NO_FERMAT_CHECK
WC_RTL8735B_NO_DERIVE_CACHE

View File

@ -839,6 +839,10 @@ int wc_RNG_DRBG_Reseed_Nonce(WC_RNG* rng, const byte* seed, word32 seedSz,
return ret;
ret = Hash_DRBG_Reseed(rng, seed, seedSz, nonce, nonceSz, 1 /* credited */);
#ifdef WC_RNG_HAVE_RBGC
if (ret == 0)
rng->RBGCStratum = 0;
#endif
return ret;
}
@ -847,16 +851,53 @@ int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* seed, word32 seedSz) {
return wc_RNG_DRBG_Reseed_Nonce(rng, seed, seedSz, NULL, 0);
}
#ifdef WC_RNG_HAVE_RBGC
/* Returns 1 if rng was seeded from another DRBG's output (an SP 800-90C
* chain leaf, via wc_InitRng*RBGC() or wc_RNG_DRBG_ReseedRBGC()), else 0.
* The tag is sticky for the instance's lifetime; a leaf is never usable as
* a chain root. */
int wc_RNG_DRBG_IsRBGCLeaf(const WC_RNG* rng)
int wc_RNG_DRBG_GetRBGCStratum(const WC_RNG* rng)
{
return (rng != NULL) && rng->isRbgcLeaf;
if (rng)
return rng->RBGCStratum;
else
return BAD_FUNC_ARG;
}
#ifdef WC_RNG_HAVE_NEXT_SEED
int wc_RNG_DRBG_GetNextSeedRBGCStratum(const WC_RNG* rng)
{
if (rng == NULL)
return BAD_FUNC_ARG;
/* Race-free via the NextSeed aperture protocol. If called with rng locked,
* and ->nextSeedLen == WC_DRBG_NEXT_SEED_READY, then competing producers
* and consumers are all excluded, unambiguously marking ->nextSeedRBGCStratum
* as strictly reliable and stable. nextSeedLen functions as the
* synchronizer -- the producer writes ->nextSeedRBGCStratum before publishing
* WC_DRBG_NEXT_SEED_READY to nextSeedLen with release semantics.
*/
#ifndef NO_SHA256
if ((rng->drbgType == WC_DRBG_SHA256) && (rng->drbg != NULL)) {
if (WOLFSSL_ATOMIC_LOAD(((const DRBG_internal*)rng->drbg)->nextSeedLen) != WC_DRBG_NEXT_SEED_READY)
return NOT_READY_E;
else
return ((const DRBG_internal *)rng->drbg)->nextSeedRBGCStratum;
}
#endif
#ifdef WOLFSSL_DRBG_SHA512
if ((rng->drbgType == WC_DRBG_SHA512) && (rng->drbg512 != NULL)) {
if (WOLFSSL_ATOMIC_LOAD(((const DRBG_SHA512_internal*)rng->drbg512)->nextSeedLen) != WC_DRBG_NEXT_SEED_READY)
return NOT_READY_E;
else
return ((const DRBG_SHA512_internal *)rng->drbg512)->nextSeedRBGCStratum;
}
#endif
return BAD_FUNC_ARG;
}
#endif /* WC_RNG_HAVE_NEXT_SEED */
#endif /* WC_RNG_HAVE_RBGC */
/* Read-only accessor for the DRBG reseed counter. When no DRBG is
* instantiated (see wc_RNG_DRBG_Present()) there is no counter; *reseedCtr
* is set to 0 -- never due for reseed -- and 0 is returned. */
@ -2167,9 +2208,17 @@ static int _InitRng(WC_RNG* rng, const byte* nonce, word32 nonceSz,
#endif /* WC_RNG_HAVE_LOCK */
{
XMEMSET(rng, 0, sizeof(*rng));
rng->isRbgcLeaf = (seedRng != NULL);
}
#ifdef WC_RNG_HAVE_RBGC
if (seedRng == NULL)
rng->RBGCStratum = 0;
else {
if (seedRng->RBGCStratum >= WC_MAX_SINT_OF(int))
return SEQ_OVERFLOW_E;
rng->RBGCStratum = seedRng->RBGCStratum + 1;
}
#endif
#ifdef WOLFSSL_HEAP_TEST
rng->heap = (void*)WOLFSSL_HEAP_TEST;
@ -2980,106 +3029,175 @@ int wc_RNG_lock_clear_extra(WC_RNG* rng, WC_RNG_lock_arg_t extra_bits)
#endif /* WC_RNG_HAVE_LOCK */
#ifdef WC_RNG_HAVE_RBGC
#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK)
/* Unified mechanics for the four wc_InitRng*RBGC() APIs: instantiate a leaf
* DRBG subordinate to root in an SP 800-90C RBG chain, drawing its seed
* material from root's generate function in place of the module's seed
* source; every other aspect of instantiation -- seed byte accounting,
* health testing, nonce handling, failure disposition -- is _InitRng()'s,
* identically to wc_InitRngNonce_ex().
/* Unified mechanics for the four wc_InitRng*RBGC() APIs: instantiate a child
* DRBG subordinate to parent in an SP 800-90C RBG chain, drawing its seed
* material from parent's generate function in place of the module's seed
* source; every other aspect of instantiation -- seed byte accounting, nonce
* handling, failure disposition -- is _InitRng()'s, identically to
* wc_InitRngNonce_ex() with the omission of health testing, which is
* superfluous when a healthy DRBG generates the seed data.
*
* Exactly one of new_leaf_stack (caller-provided WC_RNG, uninitialized) and
* new_leaf_heap (callee-allocated from root's heap, to be released with
* SP 800-90C accounting: the child's claimable security strength is capped by
* the parent's, and the child has no formal prediction resistance. The child's
* own reseeds default to the module's seed source (the reseed-interval
* backstop, wc_RNG_DRBG_Reseed_Now()); wc_RNG_DRBG_ReseedRBGC() reseeds it from
* a supplied root instead. In configurations with no DRBG (RDRAND et al.), the
* child comes up as _InitRng() dictates for such configurations and the parent
* is not consulted.
*
* Exactly one of new_child_stack (caller-provided WC_RNG, uninitialized) and
* new_child_heap (callee-allocated from parent's heap, to be released with
* wc_rng_free()) must be non-NULL. The caller must hold exclusive access
* to root for the duration of the call, as for all WC_RNG operations; the
* spawn debits root's reseed counter by one generate.
*
* SP 800-90C accounting: the leaf's claimable security strength is capped
* by root's, and the leaf has no prediction resistance. The leaf's own
* reseeds default to the module's seed source (the reseed-interval
* backstop, wc_RNG_DRBG_Reseed_Now()); wc_RNG_DRBG_ReseedRBGC() reseeds it
* from root instead. Chains are depth-one BY POLICY, with programmatic
* enforcement: a leaf is tagged (WC_RNG.isRbgcLeaf, sticky for the
* instance's lifetime even across source reseeds) and is rejected as a
* root by every RBGC API. In configurations with no DRBG (RDRAND et al.),
* the leaf comes up as _InitRng() dictates for such configurations and
* root is not consulted. */
static int SpawnRngRBGC(WC_RNG* new_leaf_stack, WC_RNG** new_leaf_heap,
WC_RNG* root, byte* nonce, word32 nonceSz)
* to parent for the duration of the call, as for all WC_RNG operations; the
* spawn debits parent's reseed counter by one generate.
*/
static int SpawnRngRBGC(WC_RNG* new_child_stack, WC_RNG** new_child_heap,
WC_RNG* parent, const byte* nonce, word32 nonceSz,
word32 flags)
{
WC_RNG* leaf = new_leaf_stack;
WC_RNG* child = new_child_stack;
int ret;
#ifdef WC_USE_DEVID
int devId = WC_USE_DEVID;
#else
int devId = INVALID_DEVID;
#endif
if ((root == NULL) ||
((new_leaf_stack == NULL) == (new_leaf_heap == NULL)) ||
(new_leaf_stack == root))
{
return BAD_FUNC_ARG;
}
/* Depth-one chains only, by policy: a leaf is never a root. */
if (root->isRbgcLeaf)
if (parent == NULL)
return BAD_FUNC_ARG;
if (new_leaf_heap != NULL) {
leaf = (WC_RNG*)XMALLOC(sizeof(WC_RNG), root->heap, DYNAMIC_TYPE_RNG);
if (leaf == NULL)
if ((new_child_stack == NULL) == (new_child_heap == NULL))
return BAD_FUNC_ARG;
if (new_child_stack == parent)
return BAD_FUNC_ARG;
if ((nonce == NULL) && (nonceSz > 0))
return BAD_FUNC_ARG;
if (new_child_heap != NULL) {
*new_child_heap = (WC_RNG*)XMALLOC(sizeof(WC_RNG), parent->heap, DYNAMIC_TYPE_RNG);
if (*new_child_heap == NULL)
return MEMORY_E;
child = *new_child_heap;
}
ret = _InitRng(leaf, nonce, nonceSz, root->heap, devId, root,
WC_RNG_INIT_FLAGS_NONE);
ret = _InitRng(child, nonce, nonceSz, parent->heap,
#if defined(WOLF_CRYPTO_CB)
parent->devId,
#else
INVALID_DEVID,
#endif
parent, flags);
if (new_leaf_heap != NULL) {
if (new_child_heap != NULL) {
if (ret != 0) {
XFREE(leaf, root->heap, DYNAMIC_TYPE_RNG);
leaf = NULL;
XFREE(child, parent->heap, DYNAMIC_TYPE_RNG);
*new_child_heap = child = NULL;
}
*new_leaf_heap = leaf;
}
return ret;
}
int wc_InitRngRBGC(WC_RNG* leaf, WC_RNG* root)
int wc_InitRngRBGC(WC_RNG* child, WC_RNG* parent, word32 flags)
{
return SpawnRngRBGC(leaf, NULL, root, NULL, 0);
return SpawnRngRBGC(child, NULL, parent, NULL, 0, flags);
}
int wc_InitRngNonceRBGC(WC_RNG* leaf, WC_RNG* root, byte* nonce,
word32 nonceSz)
int wc_InitRngNonceRBGC(WC_RNG* child, WC_RNG* parent, const byte* nonce,
word32 nonceSz, word32 flags)
{
return SpawnRngRBGC(leaf, NULL, root, nonce, nonceSz);
return SpawnRngRBGC(child, NULL, parent, nonce, nonceSz, flags);
}
#ifndef WC_NO_CONSTRUCTORS
int wc_InitRngRBGC_New(WC_RNG** leaf, WC_RNG* root)
int wc_InitRngRBGC_New(WC_RNG** child, WC_RNG* parent, word32 flags)
{
return SpawnRngRBGC(NULL, leaf, root, NULL, 0);
return SpawnRngRBGC(NULL, child, parent, NULL, 0, flags);
}
int wc_InitRngNonceRBGC_New(WC_RNG** leaf, WC_RNG* root, byte* nonce,
word32 nonceSz)
int wc_InitRngNonceRBGC_New(WC_RNG** child, WC_RNG* parent, const byte* nonce,
word32 nonceSz, word32 flags)
{
return SpawnRngRBGC(NULL, leaf, root, nonce, nonceSz);
return SpawnRngRBGC(NULL, child, parent, nonce, nonceSz, flags);
}
#endif /* !WC_NO_CONSTRUCTORS */
/* PollAndReSeed() and wc_RNG_GenerateBlock() form a single-cycle recursion when
* a seedRng is passed to PollAndReSeed() by the RBGC chain APIs.
* wc_RNG_GenerateBlock() itself never passes a seedRng, ending the cycle
* immediately.
/* Immediately reseed rng from root's generate output -- the reseed counterpart
* of the wc_InitRng*RBGC() spawn. The reseed counter is reset iff the reseed
* succeeds and credited. The nonce, if any, rides the same reseed derivation
* as (uncredited) additional input. The caller must hold exclusive access to
* BOTH rng and root. On credited success, rng is (or remains) a chain RNG:
* its current seed period is chain-backed, so RBGCStratum is set, and it is not
* usable as a reseed root.
*/
/* NOLINTNEXTLINE(misc-no-recursion) */
static int wc_RNG_DRBG_ReseedRBGC_local(WC_RNG* rng, WC_RNG* root, const byte* nonce,
word32 nonceSz, int credited)
{
#ifdef WOLFSSL_SMALL_STACK_CACHE
byte *seed;
#else
byte seed[SEED_SZ];
#endif
int ret;
if ((rng == NULL) || (root == NULL) || (rng == root) ||
((nonce == NULL) && (nonceSz > 0)))
{
return BAD_FUNC_ARG;
}
ret = rng_lock_required_check(rng);
if (ret != 0)
return ret;
#ifdef WOLFSSL_SMALL_STACK_CACHE
seed = rng->newSeed_buf;
#endif
/* Reseed from root only, by policy. */
if (root->RBGCStratum > 0)
return BAD_FUNC_ARG;
if (rng->status != DRBG_OK)
return RNG_FAILURE_E;
if (! wc_RNG_DRBG_Present(rng)) {
return 0;
}
ret = wc_RNG_GenerateBlock(root, seed, SEED_SZ);
if (ret == 0) {
if (credited) {
ret = wc_RNG_DRBG_Reseed_Nonce(rng, seed, SEED_SZ, nonce, nonceSz);
if (ret == 0) {
rng->RBGCStratum = root->RBGCStratum + 1;
}
}
else {
ret = wc_RNG_DRBG_Reseed_Nonce_Uncredited(rng, seed, SEED_SZ, nonce, nonceSz);
}
}
ForceZero(seed, SEED_SZ);
return ret;
}
int wc_RNG_DRBG_ReseedRBGC(WC_RNG* rng, WC_RNG* root, const byte* nonce,
word32 nonceSz)
{
return wc_RNG_DRBG_ReseedRBGC_local(rng, root, nonce, nonceSz, 1);
}
int wc_RNG_DRBG_ReseedRBGC_Uncredited(WC_RNG* rng, WC_RNG* root, const byte* nonce,
word32 nonceSz)
{
return wc_RNG_DRBG_ReseedRBGC_local(rng, root, nonce, nonceSz, 0);
}
#endif /* WC_RNG_HAVE_RBGC */
#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK)
static int PollAndReSeed(WC_RNG* rng, const byte* additional,
word32 additionalSz, WC_RNG* seedRng)
word32 additionalSz)
{
int ret = WC_NO_ERR_TRACE(DRBG_NEED_RESEED);
int devId = INVALID_DEVID;
@ -3099,17 +3217,6 @@ static int PollAndReSeed(WC_RNG* rng, const byte* additional,
ret = DRBG_SUCCESS;
#endif
if (ret == DRBG_SUCCESS) {
if (seedRng != NULL) {
/* RBGC reseed (wc_RNG_DRBG_ReseedRBGC()): draw the seed
* material from the parent DRBG's generate function in place
* of the module's seed source; all subsequent handling is
* identical to the seed-source path. */
ret = wc_RNG_GenerateBlock(seedRng, newSeed,
SEED_SZ + SEED_BLOCK_SZ);
if (ret != 0)
ret = DRBG_FAILURE;
}
else {
#ifdef WC_RNG_SEED_CB
if (seedCb == NULL) {
ret = DRBG_NO_SEED_CB;
@ -3136,7 +3243,6 @@ static int PollAndReSeed(WC_RNG* rng, const byte* additional,
ret = DRBG_FAILURE;
}
#endif
}
}
if (ret == DRBG_SUCCESS) {
ret = wc_RNG_TestSeed(newSeed, SEED_SZ + SEED_BLOCK_SZ);
@ -3150,6 +3256,11 @@ static 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, 1 /* credited */);
#ifdef WC_RNG_HAVE_RBGC
if (ret == 0)
rng->RBGCStratum = 0;
#endif
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE)
if (newSeed != NULL) {
@ -3208,7 +3319,7 @@ int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* nonce, word32 nonceSz)
return 0;
}
ret = PollAndReSeed(rng, nonce, nonceSz, NULL);
ret = PollAndReSeed(rng, nonce, nonceSz);
/* Identical outcome mapping to the generate-path reseed. */
if (ret == DRBG_SUCCESS) {
@ -3226,62 +3337,6 @@ int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* nonce, word32 nonceSz)
return ret;
}
/* Immediately reseed leaf from root's generate output -- the reseed
* counterpart of the wc_InitRng*RBGC() spawn, with identical semantics to
* wc_RNG_DRBG_Reseed_Now() except for the seed source: the drawn material is
* health-tested and applied by the module's own reseed function, the reseed
* counter is reset iff the reseed succeeds, and a nonce rides the same
* reseed derivation as (uncredited) additional input. The caller must hold
* exclusive access to BOTH leaf and root. On success leaf is (or remains) a
* chain leaf: its current seed period is chain-backed, so isRbgcLeaf is set
* and it is not usable as a root. Depth-one policy applies: root must not
* itself be a leaf. */
int wc_RNG_DRBG_ReseedRBGC(WC_RNG* leaf, WC_RNG* root, const byte* nonce,
word32 nonceSz)
{
int ret;
if ((leaf == NULL) || (root == NULL) || (leaf == root) ||
((nonce == NULL) && (nonceSz > 0)))
{
return BAD_FUNC_ARG;
}
ret = rng_lock_required_check(leaf);
if (ret != 0)
return ret;
/* Depth-one chains only, by policy: a leaf is never a root. */
if (root->isRbgcLeaf)
return BAD_FUNC_ARG;
/* Mirror wc_RNG_GenerateBlock(): only an in-service DRBG may reseed. */
if (leaf->status != DRBG_OK)
return RNG_FAILURE_E;
if (! wc_RNG_DRBG_Present(leaf)) {
/* No DRBG instantiated -- nothing to reseed (RDRAND et al.). */
return 0;
}
ret = PollAndReSeed(leaf, nonce, nonceSz, root);
/* Identical outcome mapping to the generate-path reseed. */
if (ret == DRBG_SUCCESS) {
leaf->isRbgcLeaf = 1;
ret = 0;
}
else if (ret == WC_NO_ERR_TRACE(DRBG_CONT_FAILURE)) {
ret = DRBG_CONT_FIPS_E;
leaf->status = DRBG_CONT_FAILED;
}
else {
ret = RNG_FAILURE_E;
leaf->status = DRBG_FAILED;
}
return ret;
}
#ifdef WC_RNG_HAVE_NEXT_SEED
/* Banked-next-seed services. _NextSeedGenerate() banks up to n more
@ -3324,26 +3379,42 @@ int wc_RNG_DRBG_ReseedRBGC(WC_RNG* leaf, WC_RNG* root, const byte* nonce,
/* Locate the aperture members for rng's live DRBG. Returns nonzero when no
* DRBG is instantiated (RDRAND et al.). */
static int NextSeedPtrs(WC_RNG* rng, byte** seed, wolfSSL_Atomic_Int** len)
static WC_INLINE int NextSeedPtrs(WC_RNG* rng, byte** seed, word32 *nextSeedSz, wolfSSL_Atomic_Int** len, int **nextSeedRBGCStratum)
{
#ifndef NO_SHA256
if ((rng->drbgType == WC_DRBG_SHA256) && (rng->drbg != NULL)) {
*seed = ((DRBG_internal*)rng->drbg)->nextSeed;
*nextSeedSz = (word32)sizeof(((DRBG_internal*)rng->drbg)->nextSeed);
*len = &((DRBG_internal*)rng->drbg)->nextSeedLen;
if (nextSeedRBGCStratum) {
#ifdef WC_RNG_HAVE_RBGC
*nextSeedRBGCStratum = &((DRBG_internal*)rng->drbg)->nextSeedRBGCStratum;
#else
*nextSeedRBGCStratum = NULL;
#endif
}
return 0;
}
#endif
#ifdef WOLFSSL_DRBG_SHA512
if ((rng->drbgType == WC_DRBG_SHA512) && (rng->drbg512 != NULL)) {
*seed = ((DRBG_SHA512_internal*)rng->drbg512)->nextSeed;
*nextSeedSz = (word32)sizeof(((DRBG_SHA512_internal*)rng->drbg512)->nextSeed);
*len = &((DRBG_SHA512_internal*)rng->drbg512)->nextSeedLen;
if (nextSeedRBGCStratum) {
#ifdef WC_RNG_HAVE_RBGC
*nextSeedRBGCStratum = &((DRBG_SHA512_internal*)rng->drbg512)->nextSeedRBGCStratum;
#else
*nextSeedRBGCStratum = NULL;
#endif
}
return 0;
}
#endif
return MISSING_RNG_E;
}
/* Bank up to n more bytes of seed material from the module's seed source into
/* Bank up to n more bytes of seed material from a supplied root RNG into
* rng's next-seed bank. Callable without owning the instance (the scheduling
* daemon's entry point); deliberately independent of rng->status so that
* banking can proceed for any instantiated DRBG. n is clamped to the space
@ -3352,67 +3423,138 @@ static int NextSeedPtrs(WC_RNG* rng, byte** seed, wolfSSL_Atomic_Int** len)
* published; a failed test consumes the material (use-once) and returns the
* test's error, leaving an empty bank for the next cycle. A gather failure
* leaves the partial bank intact for retry. */
int wc_RNG_DRBG_NextSeedGenerate(WC_RNG* rng, word32 n)
static int wc_RNG_DRBG_NextSeedGenerate_local(WC_RNG* rng, WC_RNG *root, word32 n)
{
byte* seed;
wolfSSL_Atomic_Int* lenp;
int *nextSeedRBGCStratum_p = NULL;
WC_ATOMIC_INT_ARG cur;
word32 nextSeedSz;
int ret;
if ((rng == NULL) || (n == 0))
return BAD_FUNC_ARG;
if (NextSeedPtrs(rng, &seed, &lenp) != 0) {
/* Note, rng need not be locked -- that's the whole point of the
* banked-next-seed aperture protocol.
*/
if (root) {
#ifdef WC_RNG_HAVE_RBGC
if (root->RBGCStratum > 0)
return BAD_FUNC_ARG;
ret = rng_lock_required_check(root);
if (ret != 0)
return ret;
#else
return NOT_COMPILED_IN;
#endif
}
ret = NextSeedPtrs(rng, &seed, &nextSeedSz, &lenp, &nextSeedRBGCStratum_p);
if (ret != 0) {
/* No DRBG instantiated -- nothing to bank (RDRAND et al.). */
return BAD_FUNC_ARG;
return ret;
}
cur = *lenp;
if ((cur < 0) || (cur >= (WC_ATOMIC_INT_ARG)WC_DRBG_NEXT_SEED_LEN)) {
if (cur != (WC_ATOMIC_INT_ARG)WC_DRBG_NEXT_SEED_LEN) {
if ((cur < 0) || (cur >= (WC_ATOMIC_INT_ARG)nextSeedSz)) {
if (cur != (WC_ATOMIC_INT_ARG)nextSeedSz) {
/* Ready, consuming, or other sentinel -- nothing to do. */
return ALREADY_E;
return WC_NO_ERR_TRACE(ALREADY_E); /* not an error */
}
/* Complete but unpublished (interrupted between fill completion and
* publication): retry the health test and publication below. */
n = 0;
}
else if (n > WC_DRBG_NEXT_SEED_LEN - (word32)cur) {
n = WC_DRBG_NEXT_SEED_LEN - (word32)cur;
}
if (n > 0) {
/* wc_GenerateSeed() must be called completely independent of rng, aside
* from the memory aperture itself. For safety, we pass a dummy
* OS_Seed, which will be ignored by the wc_GenerateSeed() typically
* used in conjunction with WC_RNG_HAVE_NEXT_SEED.
*/
struct OS_Seed os;
#ifdef WC_RNG_HAVE_RBGC
if (root) {
/* If primary seed bytes were carried forward, reset now to avoid
* wc_RNG_TestSeed() at completion. */
if ((cur > 0) && (*nextSeedRBGCStratum_p == 0)) {
cur = 0;
WOLFSSL_ATOMIC_STORE(*lenp, cur);
}
/* Named-member init: layout-proof against OS_Seed growing or
* reordering members under its several config axes. */
XMEMSET(&os, 0, sizeof(os));
if (n > nextSeedSz - (word32)cur)
n = nextSeedSz - (word32)cur;
ret = wc_RNG_GenerateBlock(root, seed + cur, n);
if (ret != 0) {
/* Partial bank preserved -- retry on a later cycle. */
return ret;
}
/* If RBGC seed bytes were carried forward, make sure we're
* pessimistic about the RBGC stratum. */
if ((cur == 0) || (*nextSeedRBGCStratum_p < root->RBGCStratum + 1))
*nextSeedRBGCStratum_p = root->RBGCStratum + 1;
}
else
#endif /* WC_RNG_HAVE_RBGC */
{
/* wc_GenerateSeed() must be called completely independent of rng, aside
* from the memory aperture itself. For safety, we pass a dummy
* OS_Seed, which will be ignored by the wc_GenerateSeed() typically
* used in conjunction with WC_RNG_HAVE_NEXT_SEED.
*/
struct OS_Seed os;
/* Named-member init: layout-proof against OS_Seed growing or
* reordering members under its several config axes. */
XMEMSET(&os, 0, sizeof(os));
#ifndef USE_WINDOWS_API
os.fd = -1;
os.fd = -1;
#endif
#ifdef WOLF_CRYPTO_CB
os.devId = INVALID_DEVID;
os.devId = INVALID_DEVID;
#endif
ret = wc_GenerateSeed(&os, seed + cur, n);
if (ret != 0) {
/* Partial bank preserved -- retry on a later cycle. */
return ret;
#ifdef WC_RNG_HAVE_RBGC
/* If RBGC seed bytes were carried forward, reset now to avoid
* intermixture and force wc_RNG_TestSeed() at completion. */
if ((cur > 0) && (*nextSeedRBGCStratum_p > 0)) {
cur = 0;
WOLFSSL_ATOMIC_STORE(*lenp, cur);
}
#endif
if (n > nextSeedSz - (word32)cur)
n = nextSeedSz - (word32)cur;
ret = wc_GenerateSeed(&os, seed + cur, n);
if (ret != 0) {
/* Partial bank preserved -- retry on a later cycle. */
return ret;
}
#ifdef WC_RNG_HAVE_RBGC
*nextSeedRBGCStratum_p = 0;
#endif
}
cur = wolfSSL_Atomic_Int_AddFetch(lenp, (WC_ATOMIC_INT_ARG)n);
cur += (int)n;
WOLFSSL_ATOMIC_STORE(*lenp, cur);
}
if (cur == (WC_ATOMIC_INT_ARG)WC_DRBG_NEXT_SEED_LEN) {
if (cur == (WC_ATOMIC_INT_ARG)nextSeedSz) {
#ifdef WC_RNG_HAVE_RBGC
/* If RBGC bytes were used for the reseed, then we can skip
* wc_RNG_TestSeed(). */
if (*nextSeedRBGCStratum_p > 0) {
WOLFSSL_ATOMIC_STORE(*lenp, WC_DRBG_NEXT_SEED_READY);
return 0;
}
#endif
/* Bank complete: health-test now, in advance of consumption, so
* that wc_RNG_DRBG_NextSeedNow() is pure computation. */
ret = wc_RNG_TestSeed(seed, WC_DRBG_NEXT_SEED_LEN);
ret = wc_RNG_TestSeed(seed, nextSeedSz);
if (ret == 0) {
WOLFSSL_ATOMIC_STORE(*lenp, WC_DRBG_NEXT_SEED_READY);
return 0;
}
else if (ret == WC_NO_ERR_TRACE(MEMORY_E)) {
/* wc_RNG_TestSeed() did nothing with the data -- not
@ -3425,7 +3567,7 @@ int wc_RNG_DRBG_NextSeedGenerate(WC_RNG* rng, word32 n)
/* Use-once: a failed test consumes the material. Release
* store: the ForceZero() must be visible before the empty
* aperture is. */
ForceZero(seed, WC_DRBG_NEXT_SEED_LEN);
ForceZero(seed, nextSeedSz);
WOLFSSL_ATOMIC_STORE(*lenp, WC_DRBG_NEXT_SEED_EMPTY);
return ret;
}
@ -3438,6 +3580,18 @@ int wc_RNG_DRBG_NextSeedGenerate(WC_RNG* rng, word32 n)
return 0;
}
#ifdef WC_RNG_HAVE_RBGC
int wc_RNG_DRBG_NextSeedGenerate_RBGC(WC_RNG* rng, WC_RNG *root, word32 n) {
if (root == NULL)
return BAD_FUNC_ARG;
return wc_RNG_DRBG_NextSeedGenerate_local(rng, root, n);
}
#endif
int wc_RNG_DRBG_NextSeedGenerate(WC_RNG* rng, word32 n) {
return wc_RNG_DRBG_NextSeedGenerate_local(rng, NULL, n);
}
/* Report the raw aperture value: a racy snapshot by design. Values in [0, bank
* length) count banked bytes; WC_DRBG_NEXT_SEED_READY and
* WC_DRBG_NEXT_SEED_CONSUMING indicate a ready or in-consumption bank,
@ -3446,11 +3600,12 @@ int wc_RNG_DRBG_NextSeedCurrent(WC_RNG* rng, WC_ATOMIC_INT_ARG* n)
{
byte* seed;
wolfSSL_Atomic_Int* lenp;
word32 nextSeedSz;
if ((rng == NULL) || (n == NULL))
return BAD_FUNC_ARG;
if (NextSeedPtrs(rng, &seed, &lenp) != 0) {
if (NextSeedPtrs(rng, &seed, &nextSeedSz, &lenp, NULL) != 0) {
*n = WC_DRBG_NEXT_SEED_EMPTY;
return 0;
}
@ -3459,25 +3614,26 @@ int wc_RNG_DRBG_NextSeedCurrent(WC_RNG* rng, WC_ATOMIC_INT_ARG* n)
return 0;
}
/* Consume a ready next-seed bank in an immediate credited reseed. The
* caller must own the instance. Source-free by construction -- the
* material was gathered from the module's seed source and health-tested at
* bank time -- so consumption is pure computation and safe in atomic
* context: the one credited reseed shape with that property. Distinct
* protocol results: NOT_READY_E when no bank is ready (nothing consumed),
* MISSING_RNG_E when the instance has no DRBG (RDRAND et al.) -- both
* deliberately loud, so a direct caller must demonstrate it understands
* the instance it holds. (The WC_RNG_BANK_FLAG_CONSUME_NEXT_SEED
* checkout arm is return-agnostic by construction and needs neither.)
* Use-once: the bank is consumed by the attempt, success or failure. Note
* that a banked reseed can never provide SP 800-90 prediction resistance
* (the material predates the request by construction);
* wc_RNG_DRBG_Reseed_Now() remains the live-gather shape. */
/* Consume a ready next-seed bank in an immediate credited reseed. The caller
* must own the instance. Source-free by construction -- the material was
* gathered from the module's seed source and health-tested at bank time -- so
* consumption is pure computation and safe in atomic context: the one credited
* primary reseed shape with that property. Distinct protocol results:
* NOT_READY_E when no bank is ready (nothing consumed), MISSING_RNG_E when the
* instance has no DRBG (RDRAND et al.) -- both deliberately loud, so a direct
* caller must demonstrate it understands the instance it holds. (The
* WC_RNG_BANK_FLAG_CONSUME_NEXT_SEED checkout arm is return-agnostic by
* construction and needs neither.) Use-once: the bank is consumed by the
* attempt, success or failure. Note that a banked reseed can never provide SP
* 800-90 prediction resistance (the material predates the request by
* construction); wc_RNG_DRBG_Reseed_Now() remains the live-gather shape. */
int wc_RNG_DRBG_NextSeedNow_Nonce(WC_RNG* rng, const byte* nonce,
word32 nonceSz)
{
byte* seed;
wolfSSL_Atomic_Int* lenp;
word32 nextSeedSz;
int *nextSeedRBGCStratum_p;
WC_ATOMIC_INT_ARG expected = WC_DRBG_NEXT_SEED_READY;
int ret;
@ -3495,7 +3651,7 @@ int wc_RNG_DRBG_NextSeedNow_Nonce(WC_RNG* rng, const byte* nonce,
if (rng->status != DRBG_OK)
return RNG_FAILURE_E;
ret = NextSeedPtrs(rng, &seed, &lenp);
ret = NextSeedPtrs(rng, &seed, &nextSeedSz, &lenp, &nextSeedRBGCStratum_p);
if (ret != 0) {
/* No DRBG instantiated -- nothing to reseed (RDRAND et al.). */
return ret;
@ -3513,6 +3669,14 @@ int wc_RNG_DRBG_NextSeedNow_Nonce(WC_RNG* rng, const byte* nonce,
ret = Hash_DRBG_Reseed(rng, seed + SEED_BLOCK_SZ, SEED_SZ,
nonce, nonceSz, 1 /* credited */);
#ifdef WC_RNG_HAVE_RBGC
if (ret == 0) {
rng->RBGCStratum = *nextSeedRBGCStratum_p;
*nextSeedRBGCStratum_p = 0;
}
#endif
/* Use-once: consumed by the attempt, success or not. Release store:
* the ForceZero() must be visible before the empty aperture is. */
ForceZero(seed, WC_DRBG_NEXT_SEED_LEN);
@ -3617,7 +3781,7 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz)
#if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID)
if (rng->pid != getpid()) {
rng->pid = getpid();
ret = PollAndReSeed(rng, NULL, 0, NULL);
ret = PollAndReSeed(rng, NULL, 0);
if (ret != DRBG_SUCCESS) {
rng->status = DRBG_FAILED;
return RNG_FAILURE_E;
@ -3630,7 +3794,7 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz)
ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz,
NULL, 0);
if (ret == WC_NO_ERR_TRACE(DRBG_NEED_RESEED)) {
ret = PollAndReSeed(rng, NULL, 0, NULL);
ret = PollAndReSeed(rng, NULL, 0);
if (ret == DRBG_SUCCESS)
ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output,
sz, NULL, 0);
@ -3643,7 +3807,7 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz)
ret = Hash512_DRBG_Generate((DRBG_SHA512_internal *)rng->drbg512,
output, sz, NULL, 0);
if (ret == WC_NO_ERR_TRACE(DRBG_NEED_RESEED)) {
ret = PollAndReSeed(rng, NULL, 0, NULL);
ret = PollAndReSeed(rng, NULL, 0);
if (ret == DRBG_SUCCESS)
ret = Hash512_DRBG_Generate(
(DRBG_SHA512_internal *)rng->drbg512, output, sz,

View File

@ -49,6 +49,10 @@ WOLFSSL_API int wc_rng_bank_init_nonce(
int i;
int ret;
int need_reenable_vec = 0;
#ifdef WC_RNG_HAVE_RBGC
WC_RNG root;
int root_inited = 0;
#endif
if ((ctx == NULL) || (n_rngs <= 0))
return BAD_FUNC_ARG;
@ -77,8 +81,16 @@ WOLFSSL_API int wc_rng_bank_init_nonce(
ret = MEMORY_E;
#endif
#ifdef WC_RNG_HAVE_RBGC
if ((ret == 0) && (flags & WC_RNG_BANK_FLAG_INIT_RBGC)) {
ret = wc_InitRngNonce_ex(&root, nonce, nonceSz, heap, devId);
if (ret == 0)
root_inited = 1;
}
#else
(void)nonce;
(void)nonceSz;
#endif
if (ret == 0) {
XMEMSET(ctx->rngs, 0, sizeof(*ctx->rngs) * (size_t)n_rngs);
@ -98,6 +110,21 @@ WOLFSSL_API int wc_rng_bank_init_nonce(
if (flags & WC_RNG_BANK_FLAG_NO_VECTOR_OPS)
need_reenable_vec = (DISABLE_VECTOR_REGISTERS() == 0);
#ifdef WC_RNG_HAVE_RBGC
if (flags & WC_RNG_BANK_FLAG_INIT_RBGC) {
ret = wc_InitRngNonceRBGC(
WC_RNG_BANK_INST_TO_RNG(rng_inst),
&root,
(byte *)&rng_inst, sizeof(byte *)
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
, WC_RNG_INIT_FLAGS_LOCK_REQUIRED
#else
, WC_RNG_INIT_FLAGS_NONE
#endif
);
}
else
#endif
{
#ifdef WC_RNG_INIT_FLAGS_LOCK_REQUIRED
ret = wc_InitRngNonce_ex2(
@ -174,6 +201,10 @@ out:
if (ret != 0)
(void)wc_rng_bank_fini(ctx);
#ifdef WC_RNG_HAVE_RBGC
if (root_inited)
wc_FreeRng(&root);
#endif
return ret;
}
@ -1136,19 +1167,28 @@ WOLFSSL_API int wc_rng_bank_inst_checkin(
#define WC_RNG_BANK_INST_OP_DAEMON ((WC_ATOMIC_INT_ARG)1)
#define WC_RNG_BANK_INST_OP_REINIT ((WC_ATOMIC_INT_ARG)2)
WOLFSSL_API int wc_rng_bank_next_seed_generate(
static int wc_rng_bank_next_seed_generate_local(
struct wc_rng_bank *bank,
int inst_offset,
word32 n)
word32 n,
WC_RNG *root)
{
int ret;
WC_ATOMIC_INT_ARG expected = 0;
if ((bank == NULL) || (! (bank->flags & WC_RNG_BANK_FLAG_INITED)) ||
(inst_offset < 0) || (inst_offset >= bank->n_rngs))
{
if (bank == NULL)
return BAD_FUNC_ARG;
}
if (! (bank->flags & WC_RNG_BANK_FLAG_INITED))
return BAD_FUNC_ARG;
if (inst_offset < 0)
return BAD_FUNC_ARG;
if (inst_offset >= bank->n_rngs)
return BAD_FUNC_ARG;
#ifndef WC_RNG_HAVE_RBGC
if (root != NULL)
return NOT_COMPILED_IN;
#endif
if (! wolfSSL_Atomic_Int_CompareExchange(&bank->inst_op_gate, &expected,
WC_RNG_BANK_INST_OP_DAEMON))
@ -1158,14 +1198,42 @@ WOLFSSL_API int wc_rng_bank_next_seed_generate(
return BUSY_E;
}
ret = wc_RNG_DRBG_NextSeedGenerate(
WC_RNG_BANK_INST_TO_RNG(&bank->rngs[inst_offset]), n);
#ifdef WC_RNG_HAVE_RBGC
if (root != NULL) {
ret = wc_RNG_DRBG_NextSeedGenerate_RBGC(
WC_RNG_BANK_INST_TO_RNG(&bank->rngs[inst_offset]), root, n);
}
else
#endif
{
ret = wc_RNG_DRBG_NextSeedGenerate(
WC_RNG_BANK_INST_TO_RNG(&bank->rngs[inst_offset]), n);
}
WOLFSSL_ATOMIC_STORE(bank->inst_op_gate, 0);
return ret;
}
WOLFSSL_API int wc_rng_bank_next_seed_generate_rbgc(
struct wc_rng_bank *bank,
int inst_offset,
word32 n,
WC_RNG *root)
{
if (root == NULL)
return BAD_FUNC_ARG;
return wc_rng_bank_next_seed_generate_local(bank, inst_offset, n, root);
}
WOLFSSL_API int wc_rng_bank_next_seed_generate(
struct wc_rng_bank *bank,
int inst_offset,
word32 n)
{
return wc_rng_bank_next_seed_generate_local(bank, inst_offset, n, NULL);
}
#endif /* WC_RNG_HAVE_NEXT_SEED */
/* note the rng_inst passed to wc_rng_bank_inst_reinit() must have been obtained
@ -1382,9 +1450,7 @@ WOLFSSL_API int wc_rng_bank_recover_inst(
return ret;
}
#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) && \
(!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
#ifdef WC_RNG_HAVE_RBGC
/* Unified mechanics for wc_rng_bank_spawn() and wc_rng_bank_spawn_new():
* check out -> wc_InitRngNonceRBGC[_New]() -> check in, following the
* exactly-one-destination convention of random.c's SpawnRngRBGC(). All
@ -1427,22 +1493,28 @@ static int rng_bank_spawn(
if (ret != 0)
return ret;
{
word32 child_init_flags = WC_RNG_INIT_FLAGS_NONE;
if (leaf_stack != NULL) {
ret = wc_InitRngNonceRBGC(leaf_stack,
WC_RNG_BANK_INST_TO_RNG(rng_inst),
nonce, nonceSz);
nonce, nonceSz,
child_init_flags
);
}
else {
#ifndef WC_NO_CONSTRUCTORS
ret = wc_InitRngNonceRBGC_New(leaf_heap,
WC_RNG_BANK_INST_TO_RNG(rng_inst),
nonce, nonceSz);
nonce, nonceSz,
child_init_flags);
#else
/* Unreachable: wc_rng_bank_spawn_new() is absent under
* WC_NO_CONSTRUCTORS, so leaf_heap is always null here. */
ret = BAD_FUNC_ARG;
#endif
}
}
checkin_ret = wc_rng_bank_inst_checkin(&rng_inst);
if ((checkin_ret != 0) && (ret == 0)) {
@ -1491,8 +1563,7 @@ WOLFSSL_API int wc_rng_bank_spawn_new(
preferred_inst_offset, timeout_secs, flags);
}
#endif /* !WC_NO_CONSTRUCTORS */
#endif /* HAVE_HASHDRBG && !CUSTOM_RAND_GENERATE_BLOCK &&
* (!HAVE_FIPS || FIPS_VERSION3_GE(7,0,0)) */
#endif /* WC_RNG_HAVE_RBGC */
WOLFSSL_API int wc_rng_bank_seed(struct wc_rng_bank *bank,
const byte* seed, word32 seedSz,

View File

@ -943,6 +943,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t noisesrc_test(void);
#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) && \
(!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_svc_test(void);
#endif
#ifdef WC_RNG_HAVE_RBGC
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_rbgc_test(void);
#endif
#ifdef WC_RNG_HAVE_NEXT_SEED
@ -2617,6 +2619,8 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\
TEST_FAIL("RNGSVC test failed!\n", ret);
else
TEST_PASS("RNGSVC test passed!\n");
#endif
#ifdef WC_RNG_HAVE_RBGC
if ((ret = rng_drbg_rbgc_test()) != 0)
TEST_FAIL("RNGRBGC test failed!\n", ret);
else
@ -27927,8 +27931,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void)
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
int svc_present = 0;
#endif
#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) && \
(!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
#ifdef WC_RNG_HAVE_RBGC
#ifndef WC_NO_CONSTRUCTORS
WC_RNG *spawned_rng = NULL;
#endif
@ -27946,8 +27949,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void)
ERROR_OUT(WC_TEST_RET_ENC_EC(MEMORY_E), out));
XMEMSET(rng, 0, sizeof(*rng));
#endif
#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) && \
(!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
#ifdef WC_RNG_HAVE_RBGC
WC_ALLOC_VAR_EX(leaf_rng, WC_RNG, 1, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER,
ERROR_OUT(WC_TEST_RET_ENC_EC(MEMORY_E), out));
@ -28655,25 +28657,22 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void)
}
#endif /* WC_RNG_HAVE_NEXT_SEED */
#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) && \
(!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
#ifdef WC_RNG_HAVE_RBGC
/* RBGC spawn: argument and flag contracts */
if (wc_rng_bank_spawn(bank, NULL, NULL, 0, 0, 0, 0) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
ret = wc_rng_bank_spawn(bank, NULL, NULL, 0, 0, 0, 0);
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
#ifndef WC_NO_CONSTRUCTORS
if (wc_rng_bank_spawn_new(bank, NULL, NULL, 0, 0, 0, 0) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
ret = wc_rng_bank_spawn_new(bank, NULL, NULL, 0, 0, 0, 0);
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
#endif
if (wc_rng_bank_spawn(bank, leaf_rng, NULL, 0, 0, 0,
WC_RNG_BANK_FLAG_SEED_UNCREDITED) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (wc_rng_bank_spawn(bank, leaf_rng, NULL, 0, 0, 0,
WC_RNG_BANK_FLAG_FOR_RECOVERY) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
ret = wc_rng_bank_spawn(bank, leaf_rng, NULL, 0, 0, 0, WC_RNG_BANK_FLAG_SEED_UNCREDITED);
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
ret = wc_rng_bank_spawn(bank, leaf_rng, NULL, 0, 0, 0, WC_RNG_BANK_FLAG_FOR_RECOVERY);
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
/* nonce-bearing stack spawn: the leaf is a tagged chain leaf,
* generates, and is torn down independently of the bank */
@ -28682,8 +28681,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void)
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
leaf_rng_inited = 1;
if (wc_RNG_DRBG_IsRBGCLeaf(leaf_rng) != 1)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
ret = wc_RNG_DRBG_GetRBGCStratum(leaf_rng);
if (ret != 1)
ERROR_OUT(WC_TEST_RET_ENC_I(ret), out);
#endif
ret = wc_RNG_GenerateBlock(leaf_rng, outbuf1, sizeof(outbuf1));
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
@ -28697,16 +28699,59 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void)
ret = wc_rng_bank_spawn_new(bank, &spawned_rng, NULL, 0, 1, 0, 0);
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
if ((spawned_rng == NULL) || (wc_RNG_DRBG_IsRBGCLeaf(spawned_rng) != 1))
if (spawned_rng == NULL)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
ret = wc_RNG_DRBG_GetRBGCStratum(spawned_rng);
if (ret != 1)
ERROR_OUT(WC_TEST_RET_ENC_I(ret), out);
#endif
ret = wc_RNG_GenerateBlock(spawned_rng, outbuf1, sizeof(outbuf1));
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
wc_rng_free(spawned_rng);
spawned_rng = NULL;
#endif /* !WC_NO_CONSTRUCTORS */
#endif /* HAVE_HASHDRBG && !CUSTOM_RAND_GENERATE_BLOCK &&
* (!HAVE_FIPS || FIPS_VERSION3_GE(7,0,0)) */
/* PR spawn: a fresh credited primary reseed of the parent instance
* immediately before the child's seed draw (the SP 800-90C Sec. 4.1.1
* pattern). The child is stratum 1; the parent instance's counter
* shows reseed-then-one-draw. */
ret = wc_rng_bank_spawn(bank, leaf_rng, NULL, 0, 0, 10,
WC_RNG_BANK_FLAG_PREDICTION_RESISTANCE |
WC_RNG_BANK_FLAG_CAN_WAIT);
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
leaf_rng_inited = 1;
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
ret = wc_RNG_DRBG_GetRBGCStratum(leaf_rng);
if (ret != 1)
ERROR_OUT(WC_TEST_RET_ENC_I(ret), out);
#endif
ret = wc_RNG_GenerateBlock(leaf_rng, outbuf1, sizeof(outbuf1));
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
ret = wc_FreeRng(leaf_rng);
leaf_rng_inited = 0;
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
if (svc_present) {
wc_drbg_reseed_ctr_t ns_ctr;
ret = wc_rng_bank_checkout(bank, &rng_inst, 0, 10,
WC_RNG_BANK_FLAG_NONE);
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
ret = wc_RNG_DRBG_GetReseedCtr(
WC_RNG_BANK_INST_TO_RNG(rng_inst), &ns_ctr);
if ((ret != 0) || (ns_ctr != 2))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
ret = wc_rng_bank_inst_checkin(&rng_inst);
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
#endif /* !HAVE_FIPS || FIPS_VERSION3_GE(7,0,0) */
#endif /* WC_RNG_HAVE_RBGC */
/* WC_RNG_BANK_FLAG_PREDICTION_RESISTANCE checkout contracts.
* Per-call PR demands CAN_WAIT (the fresh gather may block) and
@ -28883,8 +28928,7 @@ out:
ret = WC_TEST_RET_ENC_NC;
#endif /* !WC_RNG_BANK_STATIC */
#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) && \
(!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
#ifdef WC_RNG_HAVE_RBGC
#ifndef WC_NO_CONSTRUCTORS
if (spawned_rng != NULL)
wc_rng_free(spawned_rng);
@ -28895,8 +28939,7 @@ out:
ret = WC_TEST_RET_ENC_EC(cleanup_ret);
}
WC_FREE_VAR_EX(leaf_rng, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
#endif /* HAVE_HASHDRBG && !CUSTOM_RAND_GENERATE_BLOCK &&
* (!HAVE_FIPS || FIPS_VERSION3_GE(7,0,0)) */
#endif /* WC_RNG_HAVE_RBGC */
}
return ret;
@ -28938,8 +28981,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_svc_test(void)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (wc_RNG_DRBG_Present(NULL) != 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (wc_RNG_DRBG_IsRBGCLeaf(NULL) != 0)
#ifdef WC_RNG_HAVE_RBGC
if (wc_RNG_DRBG_GetRBGCStratum(NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
#endif
if (wc_RNG_DRBG_GetReseedCtr(NULL, &c1) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
@ -28953,8 +28998,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_svc_test(void)
if (wc_RNG_DRBG_GetReseedCtr(root, NULL) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (wc_RNG_DRBG_IsRBGCLeaf(root) != 0)
#ifdef WC_RNG_HAVE_RBGC
if (wc_RNG_DRBG_GetRBGCStratum(root) != 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
#endif
present = wc_RNG_DRBG_Present(root);
@ -29141,8 +29188,15 @@ out:
return ret;
}
#endif /* HAVE_HASHDRBG && !CUSTOM_RAND_GENERATE_BLOCK && */
/* (!HAVE_FIPS || FIPS_VERSION3_GE(7,0,0)) */
#ifdef WC_RNG_HAVE_RBGC
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
/* Coverage for the SP 800-90C RBGC (RBG chain) APIs: spawn, reseed-from-
* root, the leaf tag and accessor, and the sticky depth-one enforcement.
* root, the leaf tag and accessor, and the sticky stratum-one enforcement.
* DRBG-internal observations are gated at runtime on wc_RNG_DRBG_Present(),
* so the test also passes on RDRAND-shaped instantiations, where the RBGC
* APIs are exercised in their degenerate arms. */
@ -29175,15 +29229,19 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_rbgc_test(void)
present = wc_RNG_DRBG_Present(&root);
/* spawn argument contracts */
if (wc_InitRngRBGC(NULL, &root) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (wc_InitRngRBGC(&leaf, NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (wc_InitRngRBGC(&root, &root) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
api_ret = wc_InitRngRBGC(NULL, &root, WC_RNG_INIT_FLAGS_NONE);
if (api_ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
api_ret = wc_InitRngRBGC(&leaf, NULL, WC_RNG_INIT_FLAGS_NONE);
if (api_ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
api_ret = wc_InitRngRBGC(&root, &root, WC_RNG_INIT_FLAGS_NONE);
if (api_ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
#ifndef WC_NO_CONSTRUCTORS
if (wc_InitRngRBGC_New(NULL, &root) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
api_ret = wc_InitRngRBGC_New(NULL, &root, WC_RNG_INIT_FLAGS_NONE);
if (api_ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
#endif
/* spawn a leaf; the spawn debits root's counter; the leaf is tagged */
@ -29192,7 +29250,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_rbgc_test(void)
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
}
api_ret = wc_InitRngRBGC(&leaf, &root);
api_ret = wc_InitRngRBGC(&leaf, &root, WC_RNG_INIT_FLAGS_NONE);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
leaf_inited = 1;
@ -29200,27 +29258,25 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_rbgc_test(void)
api_ret = wc_RNG_DRBG_GetReseedCtr(&root, &c2);
if ((api_ret != 0) || (c2 <= c1))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
/* the spawn draw is one fully-served generate on the parent */
}
if (wc_RNG_DRBG_IsRBGCLeaf(&leaf) != 1)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (wc_RNG_DRBG_IsRBGCLeaf(&root) != 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
api_ret = wc_RNG_DRBG_GetRBGCStratum(&leaf);
if (api_ret != 1)
ERROR_OUT(WC_TEST_RET_ENC_I(api_ret), out);
api_ret = wc_RNG_DRBG_GetRBGCStratum(&root);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_I(api_ret), out);
api_ret = wc_RNG_GenerateBlock(&leaf, buf, sizeof(buf));
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
if (present) {
/* chain-provenance accounting: bytes generated at stratum 1 count
* in both the total and the RBGC ledgers */
}
/* depth-one enforcement: a leaf is never a root */
if (wc_InitRngRBGC(&extra, &leaf) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
#ifndef WC_NO_CONSTRUCTORS
if (wc_InitRngRBGC_New(&pleaf, &leaf) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (pleaf != NULL)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
#endif
if (wc_RNG_DRBG_ReseedRBGC(&root, &leaf, NULL, 0) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
api_ret = wc_RNG_DRBG_ReseedRBGC(&root, &leaf, NULL, 0);
if (api_ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
/* reseed-from-root, without and with a nonce; counter resets */
api_ret = wc_RNG_DRBG_ReseedRBGC(&leaf, &root, NULL, 0);
@ -29233,26 +29289,33 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_rbgc_test(void)
api_ret = wc_RNG_DRBG_GetReseedCtr(&leaf, &c1);
if ((api_ret != 0) || (c1 != 1))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
/* target: two credited chain reseeds; source: two fully-served
* seed draws */
}
if (wc_RNG_DRBG_ReseedRBGC(&leaf, &leaf, NULL, 0) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (wc_RNG_DRBG_ReseedRBGC(NULL, &root, NULL, 0) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (wc_RNG_DRBG_ReseedRBGC(&leaf, &root, NULL, 7) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
api_ret = wc_RNG_DRBG_ReseedRBGC(&leaf, &leaf, 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_ReseedRBGC(NULL, &root, 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_ReseedRBGC(&leaf, &root, NULL, 7);
if (api_ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
/* the leaf tag is sticky across a source reseed */
/* The RBGC stratum is reset to zero by a primary source reseed. */
api_ret = wc_RNG_DRBG_ScheduleReseed(&leaf);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
api_ret = wc_RNG_GenerateBlock(&leaf, buf, sizeof(buf));
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
if (wc_RNG_DRBG_IsRBGCLeaf(&leaf) != 1)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
ret = wc_RNG_DRBG_GetRBGCStratum(&leaf);
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_I(ret), out);
if (present) {
/* the primary reseed precedes the byte production, so the served
* bytes are not chain-provenance */
}
#if !defined(WC_NO_CONSTRUCTORS)
/* chain-reseeding a source-born instance demotes it, one-way */
@ -29260,34 +29323,42 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_rbgc_test(void)
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
extra_inited = 1;
if (wc_RNG_DRBG_IsRBGCLeaf(&extra) != 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
api_ret = wc_RNG_DRBG_GetRBGCStratum(&extra);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_I(api_ret), out);
if (present) {
api_ret = wc_RNG_DRBG_ReseedRBGC(&extra, &root, NULL, 0);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
if (wc_RNG_DRBG_IsRBGCLeaf(&extra) != 1)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (wc_InitRngRBGC_New(&pleaf, &extra) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
api_ret = wc_RNG_DRBG_GetRBGCStratum(&extra);
if (api_ret != 1)
ERROR_OUT(WC_TEST_RET_ENC_I(api_ret), out);
/* long-chained init is allowed, only chained reseed is forbidden. */
ret = wc_InitRngRBGC_New(&pleaf, &extra, WC_RNG_INIT_FLAGS_NONE);
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
if ((pleaf == NULL) || (wc_RNG_DRBG_GetRBGCStratum(pleaf) != 2))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
wc_rng_free(pleaf);
pleaf = NULL;
}
/* heap-allocated leaves, without and with a nonce */
api_ret = wc_InitRngRBGC_New(&pleaf, &root);
api_ret = wc_InitRngRBGC_New(&pleaf, &root, WC_RNG_INIT_FLAGS_NONE);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
if ((pleaf == NULL) || (wc_RNG_DRBG_IsRBGCLeaf(pleaf) != 1))
if ((pleaf == NULL) || (wc_RNG_DRBG_GetRBGCStratum(pleaf) != 1))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
api_ret = wc_RNG_GenerateBlock(pleaf, buf, sizeof(buf));
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
wc_rng_free(pleaf);
pleaf = NULL;
api_ret = wc_InitRngNonceRBGC_New(&pleaf, &root, matter, 16);
api_ret = wc_InitRngNonceRBGC_New(&pleaf, &root, matter, 16,
WC_RNG_INIT_FLAGS_NONE);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
if ((pleaf == NULL) || (wc_RNG_DRBG_IsRBGCLeaf(pleaf) != 1))
if ((pleaf == NULL) || (wc_RNG_DRBG_GetRBGCStratum(pleaf) != 1))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
wc_rng_free(pleaf);
pleaf = NULL;
@ -29298,12 +29369,14 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_rbgc_test(void)
leaf_inited = 0;
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
api_ret = wc_InitRngNonceRBGC(&leaf, &root, matter, 16);
api_ret = wc_InitRngNonceRBGC(&leaf, &root, matter, 16,
WC_RNG_INIT_FLAGS_NONE);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
leaf_inited = 1;
if (wc_RNG_DRBG_IsRBGCLeaf(&leaf) != 1)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
api_ret = wc_RNG_DRBG_GetRBGCStratum(&leaf);
if (api_ret != 1)
ERROR_OUT(WC_TEST_RET_ENC_I(api_ret), out);
out:
@ -29330,8 +29403,193 @@ out:
return ret;
}
#endif /* HAVE_HASHDRBG && !CUSTOM_RAND_GENERATE_BLOCK &&
* (!HAVE_FIPS || FIPS_VERSION3_GE(7,0,0)) */
#else /* HAVE_FIPS && FIPS_VERSION3_LT(7,0,0) */
#ifndef WC_RNG_BANK_SUPPORT
/* needed for compat setup */
#define WC_RNG_BANK_SUPPORT
#include <wolfssl/wolfcrypt/rng_bank.h>
#undef WC_RNG_BANK_SUPPORT
#endif
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_rbgc_test(void)
{
wc_test_ret_t ret = 0;
int api_ret;
int present;
int root_inited = 0;
int leaf_inited = 0;
int extra_inited = 0;
WC_RNG root;
WC_RNG leaf;
WC_RNG extra;
WC_RNG* pleaf = NULL;
wc_drbg_reseed_ctr_t c1 = 0;
wc_drbg_reseed_ctr_t c2 = 0;
byte buf[32];
byte matter[32];
WOLFSSL_ENTER("rng_drbg_rbgc_test");
XMEMSET(matter, 0xa5, sizeof(matter));
api_ret = wc_InitRng(&root);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
root_inited = 1;
present = wc_RNG_DRBG_Present(&root);
/* spawn argument contracts */
if (wc_InitRngRBGC(NULL, &root, WC_RNG_INIT_FLAGS_NONE) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (wc_InitRngRBGC(&leaf, NULL, WC_RNG_INIT_FLAGS_NONE) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (wc_InitRngRBGC(&root, &root, WC_RNG_INIT_FLAGS_NONE) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
#ifndef WC_NO_CONSTRUCTORS
if (wc_InitRngRBGC_New(NULL, &root, WC_RNG_INIT_FLAGS_NONE) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
#endif
/* spawn a leaf; the spawn debits root's counter; the leaf is tagged */
if (present) {
api_ret = wc_RNG_DRBG_GetReseedCtr(&root, &c1);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
}
api_ret = wc_InitRngRBGC(&leaf, &root, WC_RNG_INIT_FLAGS_NONE);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
leaf_inited = 1;
if (present) {
api_ret = wc_RNG_DRBG_GetReseedCtr(&root, &c2);
if ((api_ret != 0) || (c2 <= c1))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
}
api_ret = wc_RNG_GenerateBlock(&leaf, buf, sizeof(buf));
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
if (wc_RNG_DRBG_ReseedRBGC(&root, &leaf) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
#endif
/* reseed-from-root, without and with a nonce; counter resets */
api_ret = wc_RNG_DRBG_ReseedRBGC(&leaf, &root);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
api_ret = wc_RNG_DRBG_ReseedRBGC(&leaf, &root);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
if (present) {
api_ret = wc_RNG_DRBG_GetReseedCtr(&leaf, &c1);
if ((api_ret != 0) || (c1 != 1))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
}
if (wc_RNG_DRBG_ReseedRBGC(&leaf, &leaf) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
if (wc_RNG_DRBG_ReseedRBGC(NULL, &root) !=
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
/* The RGBC stratum is reset to zero by a primary source reseed. */
api_ret = wc_RNG_DRBG_ScheduleReseed(&leaf);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
api_ret = wc_RNG_GenerateBlock(&leaf, buf, sizeof(buf));
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
#if !defined(WC_NO_CONSTRUCTORS)
/* chain-reseeding a source-born instance demotes it, one-way */
api_ret = wc_InitRng(&extra);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
extra_inited = 1;
if (present) {
api_ret = wc_RNG_DRBG_ReseedRBGC(&extra, &root);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
/* long-chained init is allowed, only chained reseed is forbidden. */
ret = wc_InitRngRBGC_New(&pleaf, &extra, WC_RNG_INIT_FLAGS_NONE);
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
if (pleaf == NULL)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
wc_rng_free(pleaf);
pleaf = NULL;
}
/* heap-allocated leaves, without and with a nonce */
api_ret = wc_InitRngRBGC_New(&pleaf, &root, WC_RNG_INIT_FLAGS_NONE);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
if (pleaf == NULL)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
api_ret = wc_RNG_GenerateBlock(pleaf, buf, sizeof(buf));
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
wc_rng_free(pleaf);
pleaf = NULL;
api_ret = wc_InitRngNonceRBGC_New(&pleaf, &root, matter, 16,
WC_RNG_INIT_FLAGS_NONE);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
if (pleaf == NULL)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
wc_rng_free(pleaf);
pleaf = NULL;
#endif /* !WC_NO_CONSTRUCTORS */
/* nonce-bearing stack spawn */
api_ret = wc_FreeRng(&leaf);
leaf_inited = 0;
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
api_ret = wc_InitRngNonceRBGC(&leaf, &root, matter, 16,
WC_RNG_INIT_FLAGS_NONE);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);
leaf_inited = 1;
out:
{
int cleanup_ret;
if (pleaf != NULL)
wc_rng_free(pleaf);
if (leaf_inited) {
cleanup_ret = wc_FreeRng(&leaf);
if ((cleanup_ret != 0) && (ret == 0))
ret = WC_TEST_RET_ENC_EC(cleanup_ret);
}
if (extra_inited) {
cleanup_ret = wc_FreeRng(&extra);
if ((cleanup_ret != 0) && (ret == 0))
ret = WC_TEST_RET_ENC_EC(cleanup_ret);
}
if (root_inited) {
cleanup_ret = wc_FreeRng(&root);
if ((cleanup_ret != 0) && (ret == 0))
ret = WC_TEST_RET_ENC_EC(cleanup_ret);
}
}
return ret;
}
#endif /* HAVE_FIPS && FIPS_VERSION3_LT(7,0,0) */
#endif /* WC_RNG_HAVE_RBGC */
#ifdef WC_RNG_HAVE_NEXT_SEED
/* Coverage for the banked-next-seed facility: the aperture protocol
@ -29471,6 +29729,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_nextseed_test(void)
api_ret = wc_RNG_DRBG_GetReseedCtr(root, &c1);
if ((api_ret != 0) || (c1 != 1))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
/* redemption of a primary-provenance bank: credited, counted as a
* primary redemption */
#ifdef WC_RNG_HAVE_RBGC
#endif
api_ret = wc_RNG_DRBG_NextSeedCurrent(root, &cur);
if (api_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(api_ret), out);

View File

@ -262,9 +262,9 @@ extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void);
#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) && \
(!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_svc_test(void);
#endif
extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_rbgc_test(void);
extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_nextseed_test(void);
#endif
#endif /* WC_NO_RNG */
extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pwdbased_test(void);
#if defined(USE_CERT_BUFFERS_2048) && \

View File

@ -43,6 +43,16 @@
WOLFSSL_LOCAL int wolfCrypt_FIPS_DRBG_sanity(void);
#endif
#ifndef WC_RNG_NO_RBGC
#if !defined(WC_RNG_HAVE_RBGC) && \
defined(HAVE_HASHDRBG) && \
!defined(CUSTOM_RAND_GENERATE_BLOCK)
#define WC_RNG_HAVE_RBGC
#endif
#else
#undef WC_RNG_HAVE_RBGC
#endif
/* _FULL_MUTEX is opt-in, and depends on WC_RNG_HAVE_LOCK. */
#ifdef WC_RNG_NO_LOCK_FULL_MUTEX
#undef WC_RNG_HAVE_LOCK_FULL_MUTEX
@ -356,6 +366,9 @@ struct DRBG_internal {
#ifdef WC_RNG_HAVE_NEXT_SEED
byte nextSeed[WC_DRBG_NEXT_SEED_LEN];
WC_DRBG_nextSeedLen_t nextSeedLen;
#ifdef WC_RNG_HAVE_RBGC
int nextSeedRBGCStratum;
#endif
#endif
void* heap;
#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
@ -381,6 +394,9 @@ struct DRBG_SHA512_internal {
#ifdef WC_RNG_HAVE_NEXT_SEED
byte nextSeed[WC_DRBG_NEXT_SEED_LEN];
WC_DRBG_nextSeedLen_t nextSeedLen;
#ifdef WC_RNG_HAVE_RBGC
int nextSeedRBGCStratum;
#endif
#endif
void* heap;
#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
@ -412,6 +428,7 @@ enum wc_RngHealthState {
};
#define WC_RNG_FLAG_NONE 0
#define WC_RNG_FLAG_RBGC_NEXT_SEED (1U << 0)
#define WC_RNG_FLAG_FULL_MUTEX (1U << 1)
#define WC_RNG_FLAG_BANKREF (1U << 2)
@ -422,11 +439,9 @@ struct WC_RNG {
void* heap;
byte status;
word32 flags;
/* Set when this instance was seeded from another DRBG's output
* (wc_InitRng*RBGC(), wc_RNG_DRBG_ReseedRBGC()) -- an SP 800-90C chain
* leaf. Sticky by policy: a leaf is never usable as a chain root, even
* after a subsequent reseed from the module's seed source. */
byte isRbgcLeaf;
#ifdef WC_RNG_HAVE_RBGC
int RBGCStratum;
#endif
#ifdef WC_RNG_HAVE_LOCK
WC_RNG_lock_t lock;
#ifdef WC_RNG_HAVE_LOCK_FULL_MUTEX
@ -700,7 +715,12 @@ WOLFSSL_API int wc_RNG_DRBG_Present(const WC_RNG* rng);
#endif
#endif
WOLFSSL_API int wc_RNG_DRBG_IsRBGCLeaf(const WC_RNG* rng);
#ifdef WC_RNG_HAVE_RBGC
WOLFSSL_API int wc_RNG_DRBG_GetRBGCStratum(const WC_RNG* rng);
#ifdef WC_RNG_HAVE_NEXT_SEED
WOLFSSL_API int wc_RNG_DRBG_GetNextSeedRBGCStratum(const WC_RNG* rng);
#endif
#endif /* WC_RNG_HAVE_RBGC */
WOLFSSL_API int wc_RNG_DRBG_GetReseedCtr(const WC_RNG* rng,
wc_drbg_reseed_ctr_t* reseedCtr);
WOLFSSL_API int wc_RNG_DRBG_ScheduleReseed(WC_RNG* rng);
@ -813,21 +833,33 @@ WOLFSSL_API int wc_RNG_DRBG_Present(const WC_RNG* rng);
#endif /* HAVE_HASHDRBG */
#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK)
/* SP 800-90C RBG-chain spawn: instantiate leaf as a subordinate DRBG
* seeded from root's generate output. The _New variants allocate the
* leaf from root's heap; release those with wc_rng_free(). */
WOLFSSL_API int wc_InitRngRBGC(WC_RNG* leaf, WC_RNG* root);
WOLFSSL_API int wc_InitRngNonceRBGC(WC_RNG* leaf, WC_RNG* root,
byte* nonce, word32 nonceSz);
#ifndef WC_NO_CONSTRUCTORS
WOLFSSL_API int wc_InitRngRBGC_New(WC_RNG** leaf, WC_RNG* root);
WOLFSSL_API int wc_InitRngNonceRBGC_New(WC_RNG** leaf, WC_RNG* root,
byte* nonce, word32 nonceSz);
#endif /* !WC_NO_CONSTRUCTORS */
WOLFSSL_API int wc_RNG_DRBG_ReseedRBGC(WC_RNG* leaf, WC_RNG* root,
#ifdef WC_RNG_HAVE_RBGC
/* SP 800-90C RBG-chain spawn: instantiate child as a subordinate DRBG
* seeded from parent's generate output. The _New variants allocate the
* child from parent's heap; release them with ordinary wc_rng_free(). */
WOLFSSL_API int wc_InitRngRBGC(WC_RNG* child, WC_RNG* parent, word32 flags);
WOLFSSL_API int wc_InitRngNonceRBGC(WC_RNG* child, WC_RNG* parent,
const byte* nonce, word32 nonceSz,
word32 flags);
#ifndef WC_NO_CONSTRUCTORS
/* flags are per-object (WC_RNG_INIT_FLAGS_*), deliberately NOT
* inherited from the parent: a child's lock policy is its own. */
WOLFSSL_API int wc_InitRngRBGC_New(WC_RNG** child, WC_RNG* parent,
word32 flags);
WOLFSSL_API int wc_InitRngNonceRBGC_New(WC_RNG** child, WC_RNG* parent,
const byte* nonce, word32 nonceSz,
word32 flags);
#endif /* !WC_NO_CONSTRUCTORS */
/* Note, only a root RNG -- stratum 0, i.e. primary-seeded -- is permitted
* to generate reseed bytes (wolfCrypt policy; stricter than SP 800-90C
* 7.1.2.2, which also permits parent reseed). */
WOLFSSL_API int wc_RNG_DRBG_ReseedRBGC(WC_RNG* rng, WC_RNG* root,
const byte* nonce, word32 nonceSz);
#endif /* HAVE_HASHDRBG && !CUSTOM_RAND_GENERATE_BLOCK */
WOLFSSL_API int wc_RNG_DRBG_ReseedRBGC_Uncredited(WC_RNG* rng,
WC_RNG* root,
const byte* nonce,
word32 nonceSz);
#endif /* WC_RNG_HAVE_RBGC */
#ifdef WC_RNG_HAVE_NEXT_SEED
#define WC_DRBG_NEXT_SEED_EMPTY 0
@ -837,6 +869,11 @@ WOLFSSL_API int wc_RNG_DRBG_Present(const WC_RNG* rng);
#define WC_DRBG_NEXT_SEED_CONSUMING ((WC_ATOMIC_INT_ARG)(-1))
WOLFSSL_API int wc_RNG_DRBG_NextSeedGenerate(WC_RNG* rng, word32 n);
#ifdef WC_RNG_HAVE_RBGC
WOLFSSL_API int wc_RNG_DRBG_NextSeedGenerate_RBGC(WC_RNG* rng,
WC_RNG *root,
word32 n);
#endif
WOLFSSL_API int wc_RNG_DRBG_NextSeedCurrent(WC_RNG* rng,
WC_ATOMIC_INT_ARG* n);
WOLFSSL_API int wc_RNG_DRBG_NextSeedNow_Nonce(WC_RNG* rng,

View File

@ -106,6 +106,7 @@
* a use-after-free instead of BUSY_E -- only containers whose teardown
* provably quiesces consumers first may set it. */
#define WC_RNG_BANK_FLAG_NO_CHECKOUT_REFCOUNTING (1U << 11)
#define WC_RNG_BANK_FLAG_INIT_RBGC (1U << 12)
#define WC_RNG_BANK_FLAG_PREDICTION_RESISTANCE (1U << 14)
/* base lock states are WC_RNG_LOCK_FREE / WC_RNG_LOCK_HELD in random.h;
@ -290,6 +291,11 @@ WOLFSSL_API int wc_rng_bank_next_seed_generate(
struct wc_rng_bank *bank,
int inst_offset,
word32 n);
WOLFSSL_API int wc_rng_bank_next_seed_generate_rbgc(
struct wc_rng_bank *bank,
int inst_offset,
word32 n,
WC_RNG *root);
#endif
WOLFSSL_API int wc_rng_bank_inst_reinit(
@ -313,26 +319,25 @@ WOLFSSL_API int wc_rng_bank_recover_inst(
int timeout_secs,
word32 flags);
#ifdef WC_RNG_HAVE_RBGC
#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) && \
(!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
/* Spawn an SP 800-90C chain leaf from a bank instance: check out an
/* Spawn an SP 800-90C chain RNG from a bank instance: check out a parent
* instance (honoring the usual selection flags), wc_InitRngNonceRBGC() /
* wc_InitRngNonceRBGC_New() the leaf from it, and check the instance back
* in. The leaf's lifetime is thereafter decoupled from the bank: it is
* lock-free for its owner and is released with wc_FreeRng() (stack form)
* or wc_rng_free() (heap form). nonce/nonceSz may be NULL/0 for a plain
* spawn; per the bank's distinctness convention, passing the address of
* the leaf's owning object or request is recommended. bank == NULL uses
* the default bank where support is compiled in.
* WC_RNG_BANK_FLAG_CONSUME_NEXT_SEED composes (banked reseed before the
* spawn draw); WC_RNG_BANK_FLAG_SEED_UNCREDITED and
* WC_RNG_BANK_FLAG_FOR_RECOVERY are rejected.
* WC_RNG_BANK_FLAG_ERROR_ON_RNG_FAILED is implied: the root is guaranteed
* in-service, or an error is returned with no lease and no leaf. */
* wc_InitRngNonceRBGC_New() the child from it, and check the parent instance
* back in. The child's lifetime is thereafter decoupled from the parent and
* its bank: it is lock-free for its owner and is released with wc_FreeRng()
* (stack form) or wc_rng_free() (heap form). The child's RBGC stratum is one
* plus the parent's stratum at time of instantiation. nonce/nonceSz may be
* NULL/0 for a plain spawn; an example of a recommended nonce is Linux kernel
* random_get_entropy() (which is typically a racy read of a high-resolution
* timer). bank == NULL uses the default bank where support is compiled in.
* WC_RNG_BANK_FLAG_CONSUME_NEXT_SEED composes (banked reseed before the spawn
* draw); WC_RNG_BANK_FLAG_SEED_UNCREDITED and WC_RNG_BANK_FLAG_FOR_RECOVERY are
* rejected. WC_RNG_BANK_FLAG_ERROR_ON_RNG_FAILED is implied: the parent is
* guaranteed in-service, or an error is returned with no lease and no child. */
WOLFSSL_API int wc_rng_bank_spawn(
struct wc_rng_bank *bank,
WC_RNG *leaf_rng,
WC_RNG *child_rng,
byte *nonce,
word32 nonceSz,
int preferred_inst_offset,
@ -342,15 +347,15 @@ WOLFSSL_API int wc_rng_bank_spawn(
#ifndef WC_NO_CONSTRUCTORS
WOLFSSL_API int wc_rng_bank_spawn_new(
struct wc_rng_bank *bank,
WC_RNG **leaf_rng,
WC_RNG **child_rng,
byte *nonce,
word32 nonceSz,
int preferred_inst_offset,
int timeout_secs,
word32 flags);
#endif /* !WC_NO_CONSTRUCTORS */
#endif /* HAVE_HASHDRBG && !CUSTOM_RAND_GENERATE_BLOCK &&
* (!HAVE_FIPS || FIPS_VERSION3_GE(7,0,0)) */
#endif /* WC_RNG_HAVE_RBGC */
WOLFSSL_API int wc_rng_bank_seed(struct wc_rng_bank *bank,
const byte* seed, word32 seedSz,
@ -689,6 +694,35 @@ static WC_INLINE WC_MAYBE_UNUSED int wc_rng_bank_inst_lock_clear_extra(struct wc
wc_static_assert((WC_RESEED_INTERVAL) <= 0xFFFFFFFFUL);
#endif
#ifdef WC_RNG_HAVE_RBGC
#define wc_InitRngRBGC(leaf, root, flags) \
wc_InitRngNonceRBGC(leaf, root, NULL, 0, flags)
WC_MAYBE_UNUSED static WC_INLINE int wc_InitRngRBGC_New(WC_RNG** leaf, WC_RNG* root, word32 flags) {
if ((leaf == NULL) || (root == NULL))
return BAD_FUNC_ARG;
*leaf = (WC_RNG*)XMALLOC(sizeof(WC_RNG), root->heap, DYNAMIC_TYPE_RNG);
if (*leaf == NULL)
return MEMORY_E;
else
return wc_InitRngNonceRBGC(*leaf, root, NULL, 0, flags);
}
WC_MAYBE_UNUSED static WC_INLINE int wc_InitRngNonceRBGC_New(WC_RNG** leaf, WC_RNG* root,
const byte* nonce, word32 nonceSz,
word32 flags)
{
if ((leaf == NULL) || (root == NULL))
return BAD_FUNC_ARG;
*leaf = (WC_RNG*)XMALLOC(sizeof(WC_RNG), root->heap, DYNAMIC_TYPE_RNG);
if (*leaf == NULL)
return MEMORY_E;
else
return wc_InitRngNonceRBGC(*leaf, root, nonce, nonceSz, flags);
}
#endif /* WC_RNG_HAVE_RBGC */
WC_MAYBE_UNUSED static WC_INLINE int wc_RNG_GetStatus(const WC_RNG* rng)
{
@ -811,6 +845,17 @@ static WC_INLINE WC_MAYBE_UNUSED int wc_rng_bank_inst_reseed_now(
return wc_RNG_DRBG_Reseed_Now(WC_RNG_BANK_INST_TO_RNG(inst),
nonce, nonceSz);
}
#ifdef WC_RNG_HAVE_RBGC
static WC_INLINE WC_MAYBE_UNUSED int wc_rng_bank_inst_reseed_rbgc(
struct wc_rng_bank_inst *inst, WC_RNG* root, const byte* nonce,
word32 nonceSz)
{
if (inst == NULL)
return BAD_FUNC_ARG;
return wc_RNG_DRBG_ReseedRBGC(WC_RNG_BANK_INST_TO_RNG(inst), root,
nonce, nonceSz);
}
#endif /* WC_RNG_HAVE_RBGC */
#else /* !WC_RNG_HAVE_LOCK */
@ -825,6 +870,28 @@ static WC_INLINE WC_MAYBE_UNUSED int wc_rng_bank_inst_reseed_now(
return ret;
}
#ifdef WC_RNG_HAVE_RBGC
static WC_INLINE WC_MAYBE_UNUSED int wc_rng_bank_inst_reseed_rbgc(
struct wc_rng_bank_inst *inst, WC_RNG* root, const byte* nonce,
word32 nonceSz)
{
int ret;
if (inst == NULL)
return BAD_FUNC_ARG;
#if defined(HAVE_FIPS) && FIPS_VERSION3_LT(7,0,0)
/* the pre-v7 boundary's wc_RNG_DRBG_ReseedRBGC() predates the nonce
* parameters; honest rejection, as with the boundary's Reseed_Now(). */
if (nonceSz > 0)
return NOT_COMPILED_IN;
(void)nonce;
ret = wc_RNG_DRBG_ReseedRBGC(WC_RNG_BANK_INST_TO_RNG(inst), root);
#else
ret = wc_RNG_DRBG_ReseedRBGC(WC_RNG_BANK_INST_TO_RNG(inst), root,
nonce, nonceSz);
#endif
return ret;
}
#endif /* WC_RNG_HAVE_RBGC */
#endif /* !WC_RNG_HAVE_LOCK */