mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-10-24 04:09:07 +03:00
Merge pull request #11435 from douzzer/20260907-RNG-extras
20260907-RNG-extras
This commit is contained in:
2
.github/workflows/codespell.yml
vendored
2
.github/workflows/codespell.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
check_filenames: true
|
||||
check_hidden: true
|
||||
# Add comma separated list of words that occur multiple times that should be ignored (sorted alphabetically, case sensitive)
|
||||
ignore_words_list: adin,ameba,aNULL,brunch,carryIn,chainG,ciph,cLen,cliKs,cna,dout,FPR,fpr,haveA,inCreated,inOut,inout,larg,LEAPYEAR,Merget,optionA,parm,parms,repid,rIn,userA,ser,siz,te,Te,HSI,failT,toLen,vor,
|
||||
ignore_words_list: adin,ameba,aNULL,brunch,carryIn,chainG,ciph,cLen,cliKs,cna,dout,FPR,fpr,haveA,inCreated,inOut,inout,larg,LEAPYEAR,Merget,optionA,parm,parms,repid,rIn,userA,ser,siz,te,Te,HSI,failT,toLen,vor,checkin
|
||||
# The exclude_file contains lines of code that should be ignored. This is useful for individual lines which have non-words that can safely be ignored.
|
||||
exclude_file: '.codespellexcludelines'
|
||||
# To skip files entirely from being processed, add it to the following list:
|
||||
|
||||
@@ -63,6 +63,7 @@ CIOCGSESSINFO
|
||||
CLOCK_MONOTONIC
|
||||
CMSIS_OS2_H_
|
||||
COMPONENT_WOLFSSL
|
||||
CONFIG_ACPI
|
||||
CONFIG_ARCH_CHIP_STM32F746ZG
|
||||
CONFIG_ARCH_CHIP_STM32H743ZI
|
||||
CONFIG_ARCH_CHIP_STM32L552ZE
|
||||
@@ -155,6 +156,7 @@ CONFIG_NET_SOCKETS_SOCKOPT_TLS
|
||||
CONFIG_NEWLIB_LIBC
|
||||
CONFIG_NEWLIB_NANO_FORMAT
|
||||
CONFIG_PICOLIBC
|
||||
CONFIG_PM_SLEEP
|
||||
CONFIG_POSIX_API
|
||||
CONFIG_POSIX_THREADS
|
||||
CONFIG_PREEMPT_COUNT
|
||||
@@ -789,6 +791,7 @@ WC_HASH_CUSTOM_MAX_BLOCK_SIZE
|
||||
WC_HASH_CUSTOM_MAX_DIGEST_SIZE
|
||||
WC_HASH_CUSTOM_MIN_DIGEST_SIZE
|
||||
WC_INIT_ERROR_WHEN_CONTENDED
|
||||
WC_LINUXKM_NO_ENTROPY_DAEMON
|
||||
WC_LINUXKM_NO_USE_HEAP_WRAPPERS
|
||||
WC_LINUXKM_SVR_NO_BATCHING
|
||||
WC_MLDSA_NO_ASM
|
||||
@@ -803,8 +806,22 @@ WC_PKCS12_PBKDF_USING_MP_API
|
||||
WC_PROTECT_ENCRYPTED_MEM
|
||||
WC_PUF_HELPER_COMPACT
|
||||
WC_PUF_SHA3
|
||||
WC_RNG_BANK_NO_DAEMON_SUPPORT
|
||||
WC_RNG_BANK_NO_DEFAULT_SUPPORT
|
||||
WC_RNG_BLOCKING
|
||||
WC_RNG_NO_FREE_HOOK
|
||||
WC_RNG_NO_LOCK
|
||||
WC_RNG_NO_LOCK_FULL_MUTEX
|
||||
WC_RNG_NO_NEXT_SEED
|
||||
WC_RNG_NO_POOL
|
||||
WC_RNG_NO_RBGC
|
||||
WC_RNG_NO_RBGC_RESEED
|
||||
WC_RNG_WANT_FREE_HOOK
|
||||
WC_RNG_WANT_LOCK
|
||||
WC_RNG_WANT_LOCK_FULL_MUTEX
|
||||
WC_RNG_WANT_NEXT_SEED
|
||||
WC_RNG_WANT_POOL
|
||||
WC_RNG_WANT_RBGC
|
||||
WC_RSA_NONBLOCK_TIME
|
||||
WC_RSA_NO_FERMAT_CHECK
|
||||
WC_RTL8735B_NO_DERIVE_CACHE
|
||||
|
||||
20
configure.ac
20
configure.ac
@@ -1703,6 +1703,7 @@ then
|
||||
test "$enable_base16" = "" && enable_base16=yes
|
||||
test "$enable_ssh" = "" && test "$enable_hmac" != "no" && enable_ssh=yes
|
||||
test "$enable_rng_bank" = "" && enable_rng_bank=yes
|
||||
test "$enable_rng_extras" = "" && enable_rng_extras=yes
|
||||
test "$enable_dh" = "" && enable_dh=yes
|
||||
test "$enable_defaultdhparams" = "" && enable_defaultdhparams=yes
|
||||
|
||||
@@ -1920,6 +1921,8 @@ then
|
||||
test "$enable_supportedcurves" = "" && enable_supportedcurves=yes
|
||||
fi
|
||||
test "$enable_rng" != "no" && test "$enable_rng_bank" = "" && enable_rng_bank=yes
|
||||
test "$enable_rng" != "no" && test "$enable_rng_extras" = "" && enable_rng_extras=yes
|
||||
|
||||
if test "$ENABLED_FIPS" = "no" || test "$HAVE_FIPS_VERSION" -ge 6
|
||||
then
|
||||
test "$enable_aes" != "no" && test "$enable_aescfb" = "" && enable_aescfb=yes
|
||||
@@ -2791,6 +2794,20 @@ then
|
||||
AM_CFLAGS="$AM_CFLAGS -DWC_NO_RNG"
|
||||
fi
|
||||
|
||||
|
||||
# RNG extras
|
||||
AC_ARG_ENABLE([rng-extras],
|
||||
[AS_HELP_STRING([--enable-rng-extras],[Enable RNG locks, pools, RBGC, and daemon support (default: disabled)])],
|
||||
[ ENABLED_RNG_EXTRAS=$enableval ],
|
||||
[ ENABLED_RNG_EXTRAS=$KERNEL_MODE_DEFAULTS ]
|
||||
)
|
||||
|
||||
if test "$ENABLED_RNG_EXTRAS" = "yes"
|
||||
then
|
||||
AM_CFLAGS="$AM_CFLAGS -DWC_RNG_EXTRAS"
|
||||
fi
|
||||
|
||||
|
||||
AC_ARG_ENABLE([rng-bank],
|
||||
[AS_HELP_STRING([--enable-rng-bank],[Enable compiling and using RNG banks (default: disabled)])],
|
||||
[ ENABLED_RNG_BANK=$enableval ],
|
||||
@@ -7170,7 +7187,8 @@ AS_CASE([$FIPS_VERSION],
|
||||
-DECC_USER_CURVES \
|
||||
-DHAVE_ECC384 \
|
||||
-DHAVE_ECC521 \
|
||||
-DWOLFSSL_VALIDATE_FFC_IMPORT"
|
||||
-DWOLFSSL_VALIDATE_FFC_IMPORT \
|
||||
-DWC_RNG_EXTRAS"
|
||||
|
||||
# KCAPI API does not support custom k for sign, don't force enable ECC key sizes and don't use seed callback
|
||||
AS_IF([test "x$ENABLED_KCAPI_ECC" = "xno"],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
961
doc/dox_comments/header_files/rng_bank.h
Normal file
961
doc/dox_comments/header_files/rng_bank.h
Normal file
@@ -0,0 +1,961 @@
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Allocate and initialize a bank of n_rngs pre-instantiated WC_RNG
|
||||
instances, checked out and back in by consumers (wc_rng_bank_checkout()
|
||||
et al.). The bank is allocated from heap; release with
|
||||
wc_rng_bank_free(). Bank-level flags (WC_RNG_BANK_FLAG_*) fix the
|
||||
bank's posture at initialization: e.g. _CAN_WAIT admits sleeping,
|
||||
_QUIET suppresses seeding-degradation warnings,
|
||||
_NO_CHECKOUT_REFCOUNTING suppresses per-checkout refcount traffic for
|
||||
container-guaranteed lifetimes, _PREDICTION_RESISTANCE imposes a
|
||||
bank-wide fresh-reseed posture on every sleepable lease.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG ctx is null or n_rngs is out of range.
|
||||
\return MEMORY_E Allocation failed.
|
||||
\return RNG_FAILURE_E No instance could be seeded within timeout_secs.
|
||||
|
||||
\param ctx Receives the allocated bank.
|
||||
\param n_rngs Number of instances.
|
||||
\param flags Bitwise-or of WC_RNG_BANK_FLAG_* bank-posture flags.
|
||||
\param timeout_secs Seeding timeout budget.
|
||||
\param heap Heap hint for dynamic allocation.
|
||||
\param devId Device id, or INVALID_DEVID.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
struct wc_rng_bank *bank = NULL;
|
||||
if (wc_rng_bank_new(&bank, 4, WC_RNG_BANK_FLAG_CAN_WAIT, 10,
|
||||
NULL, INVALID_DEVID) == 0) {
|
||||
// ... checkout/checkin traffic ...
|
||||
wc_rng_bank_free(&bank);
|
||||
}
|
||||
\endcode
|
||||
|
||||
\sa wc_rng_bank_init
|
||||
\sa wc_rng_bank_checkout
|
||||
\sa wc_rng_bank_free
|
||||
*/
|
||||
int wc_rng_bank_new(struct wc_rng_bank **ctx, int n_rngs, word32 flags,
|
||||
int timeout_secs, void *heap, int devId);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Initialize a caller-provided bank object. Semantics of
|
||||
wc_rng_bank_new(), without the allocation; release with
|
||||
wc_rng_bank_fini().
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG ctx is null or n_rngs is out of range.
|
||||
\return BAD_LENGTH_E n_rngs exceeds the static capacity
|
||||
(WC_RNG_BANK_STATIC builds).
|
||||
\return RNG_FAILURE_E No instance could be seeded within timeout_secs.
|
||||
|
||||
\param ctx The bank object to initialize.
|
||||
\param n_rngs Number of instances.
|
||||
\param flags Bitwise-or of WC_RNG_BANK_FLAG_* bank-posture flags.
|
||||
\param timeout_secs Seeding timeout budget.
|
||||
\param heap Heap hint for dynamic allocation.
|
||||
\param devId Device id, or INVALID_DEVID.
|
||||
|
||||
\sa wc_rng_bank_new
|
||||
\sa wc_rng_bank_init_nonce
|
||||
\sa wc_rng_bank_fini
|
||||
*/
|
||||
int wc_rng_bank_init(struct wc_rng_bank *ctx, int n_rngs, word32 flags,
|
||||
int timeout_secs, void *heap, int devId);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief The nonce-bearing form of wc_rng_bank_init(): the nonce is used
|
||||
as additional instantiation input for each instance.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG ctx is null, n_rngs is out of range, or nonce is
|
||||
null with nonceSz nonzero.
|
||||
\return RNG_FAILURE_E No instance could be seeded within timeout_secs.
|
||||
\return BAD_LENGTH_E nonceSz exceeds the supported maximum.
|
||||
\return MEMORY_E Allocation failed.
|
||||
\return WC_TIMEOUT_E Instance seeding exceeded timeout_secs.
|
||||
|
||||
\param ctx The bank object to initialize.
|
||||
\param n_rngs Number of instances.
|
||||
\param flags Bitwise-or of WC_RNG_BANK_FLAG_* bank-posture flags.
|
||||
\param timeout_secs Seeding timeout budget.
|
||||
\param heap Heap hint for dynamic allocation.
|
||||
\param devId Device id, or INVALID_DEVID.
|
||||
\param nonce Additional instantiation input.
|
||||
\param nonceSz Length of nonce in bytes.
|
||||
\param perso Optional personalization string (may be null).
|
||||
\param persoSz Length of perso in bytes.
|
||||
|
||||
\sa wc_rng_bank_init
|
||||
*/
|
||||
int wc_rng_bank_init_nonce(struct wc_rng_bank *ctx, int n_rngs,
|
||||
word32 flags, int timeout_secs, void *heap,
|
||||
int devId, const byte *nonce, word32 nonceSz,
|
||||
const byte *perso, word32 persoSz);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Designate the first instance of the failover pool: checkouts
|
||||
without a targeted preference rotate through instances at and above
|
||||
first_failover_inst, reserving the lower offsets for targeted
|
||||
(affinity or daemon) use.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG ctx is null or first_failover_inst is out of range.
|
||||
|
||||
\param ctx The bank to configure.
|
||||
\param first_failover_inst The first failover-eligible instance offset.
|
||||
|
||||
\sa wc_rng_bank_checkout
|
||||
*/
|
||||
int wc_rng_bank_first_failover_inst_set(struct wc_rng_bank *ctx,
|
||||
int first_failover_inst);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Install affinity handlers: callbacks that pin the caller to an
|
||||
execution context (e.g. disable preemption or migration), report its id
|
||||
for instance affinity, and unpin. With handlers installed,
|
||||
WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST checkouts prefer the instance
|
||||
matching the caller's affinity id, and WC_RNG_BANK_FLAG_AFFINITY_LOCK
|
||||
holds the pin across the lease.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG ctx is null.
|
||||
\return BUSY_E The bank is in service; handlers must be set before use.
|
||||
|
||||
\param ctx The bank to configure.
|
||||
\param affinity_lock_cb Pin the caller; may be null.
|
||||
\param affinity_get_id_cb Report the caller's affinity id.
|
||||
\param affinity_unlock_cb Unpin the caller; may be null.
|
||||
\param cb_arg Opaque argument passed to the callbacks.
|
||||
|
||||
\sa wc_rng_bank_checkout
|
||||
*/
|
||||
int wc_rng_bank_set_affinity_handlers(struct wc_rng_bank *ctx,
|
||||
wc_affinity_lock_fn_t affinity_lock_cb,
|
||||
wc_affinity_get_id_fn_t affinity_get_id_cb,
|
||||
wc_affinity_unlock_fn_t affinity_unlock_cb,
|
||||
void *cb_arg);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Tear down a bank initialized with wc_rng_bank_init(): once the
|
||||
refcount and per-instance lease gates pass, fires any registered free
|
||||
hook and frees every instance. Never waits: a referenced or leased
|
||||
bank is refused with BUSY_E, and the caller quiesces its consumers and
|
||||
retries.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG ctx is null.
|
||||
\return BUSY_E The bank is still referenced, or an instance lease is
|
||||
outstanding.
|
||||
\return BAD_STATE_E The refcount is below its initialization baseline
|
||||
(teardown of an uninitialized or corrupted bank).
|
||||
|
||||
\param ctx The bank to tear down.
|
||||
|
||||
\sa wc_rng_bank_init
|
||||
\sa wc_rng_bank_free
|
||||
\sa wc_rng_bank_register_free_hook
|
||||
*/
|
||||
int wc_rng_bank_fini(struct wc_rng_bank *ctx);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Tear down and release a bank allocated with wc_rng_bank_new().
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG ctx or *ctx is null.
|
||||
\return BAD_STATE_E The bank is still referenced.
|
||||
|
||||
\param ctx The bank to release; nulled on success.
|
||||
|
||||
\sa wc_rng_bank_new
|
||||
\sa wc_rng_bank_fini
|
||||
*/
|
||||
int wc_rng_bank_free(struct wc_rng_bank **ctx);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Register bank as the process-default bank, retrievable with
|
||||
wc_rng_bank_default_checkout().
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank is null.
|
||||
\return BAD_STATE_E A default bank is already registered.
|
||||
\return BUSY_E Registration is contended; retry.
|
||||
|
||||
\param bank The bank to register.
|
||||
|
||||
\sa wc_rng_bank_default_checkout
|
||||
\sa wc_rng_bank_default_clear
|
||||
*/
|
||||
int wc_rng_bank_default_set(struct wc_rng_bank *bank);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Take a reference on the process-default bank.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank is null.
|
||||
\return BAD_STATE_E No default bank is registered.
|
||||
\return NO_DEFAULT_FOUND_E No default bank is registered.
|
||||
|
||||
\param bank Receives the default bank.
|
||||
|
||||
\sa wc_rng_bank_default_set
|
||||
\sa wc_rng_bank_default_checkin
|
||||
*/
|
||||
int wc_rng_bank_default_checkout(struct wc_rng_bank **bank);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Release a reference taken with wc_rng_bank_default_checkout().
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank or *bank is null.
|
||||
|
||||
\param bank The reference to release; nulled on success.
|
||||
|
||||
\sa wc_rng_bank_default_checkout
|
||||
*/
|
||||
int wc_rng_bank_default_checkin(struct wc_rng_bank **bank);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Unregister the process-default bank.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank is null or is not the registered default.
|
||||
\return BUSY_E Unregistration is contended; retry.
|
||||
|
||||
\param bank The bank to unregister.
|
||||
|
||||
\sa wc_rng_bank_default_set
|
||||
*/
|
||||
int wc_rng_bank_default_clear(struct wc_rng_bank *bank);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Lease an in-service instance from the bank: either the preferred
|
||||
(or affinity-matched) instance, or -- with
|
||||
WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST -- the first available failover
|
||||
instance. On success the caller owns the instance's lock; access the
|
||||
WC_RNG with WC_RNG_BANK_INST_TO_RNG() and return the lease with
|
||||
wc_rng_bank_inst_checkin(). WC_RNG_BANK_FLAG_CONSUME_NEXT_SEED consumes
|
||||
a ready banked next seed in an immediate source-free credited reseed
|
||||
before returning; WC_RNG_BANK_FLAG_PREDICTION_RESISTANCE (per-call,
|
||||
requires _CAN_WAIT) freshly credited-reseeds the lease before the
|
||||
caller's first draw.
|
||||
|
||||
\details Out-of-service instances: a targeted (non-failover) checkout
|
||||
admits them; failover checkouts divert around them.
|
||||
WC_RNG_BANK_FLAG_FOR_RECOVERY makes the targeted admission explicit and
|
||||
interaction-safe (recovery machinery and patrols): out-of-service
|
||||
status is expected, the _CONSUME_NEXT_SEED arm is suppressed (a consume
|
||||
would fail on exactly the instances recovery targets), and failover and
|
||||
affinity selection are rejected in combination.
|
||||
WC_RNG_BANK_FLAG_ERROR_ON_RNG_FAILED gives the opposite guarantee:
|
||||
either a lease on an in-service instance, or an error with no lease --
|
||||
never a lease on an out-of-service instance; under _CAN_WAIT an
|
||||
out-of-service instance is retried within the timeout budget (allowing
|
||||
a patrol to restore it), and the distinguished error for a lap or wait
|
||||
that found only out-of-service instances is BAD_STATE_E.
|
||||
|
||||
Entropy-invalidated (quarantined) instances refuse ordinary leases with
|
||||
NEEDS_RECOVERY_E, with two admissions. First, when the quarantined
|
||||
instance holds a READY banked next seed, any claimant is admitted and
|
||||
the consume-at-checkout reseed runs unconditionally: the invalidation
|
||||
purge guarantees READY banked material post-dates the invalidation
|
||||
event, so admitting the claimant is completing the recovery. Second,
|
||||
WC_RNG_BANK_FLAG_MAYBE_FOR_RECOVERY admits the caller to a quarantined
|
||||
instance with no banked material, transferring the recovery obligation:
|
||||
checkout then returns NEEDS_RECOVERY_E with the checkout otherwise
|
||||
complete -- *rng_inst set; instance lock, affinity locks, and any
|
||||
vector-inhibit state held. This is the robust-mutex (EOWNERDEAD)
|
||||
pattern: an error return with the acquisition complete and persistent,
|
||||
because "this resource needs consistency recovery" is only safely
|
||||
reportable to a caller that already holds it. The caller must either
|
||||
recover the instance (a credited reseed, e.g. wc_RNG_DRBG_Reseed_Now(),
|
||||
clears the quarantine) or check it back in. Ordinary consumers that
|
||||
cannot complete a recovery must not pass this flag.
|
||||
|
||||
\return 0 Success; *rng_inst holds the lease.
|
||||
\return BAD_FUNC_ARG bank or rng_inst is null, or the flags are
|
||||
contradictory.
|
||||
\return NEEDS_RECOVERY_E Quarantined: refused without a lease
|
||||
(ordinary checkout), or lease held with recovery owed
|
||||
(_MAYBE_FOR_RECOVERY; see \details).
|
||||
\return BAD_STATE_E (_ERROR_ON_RNG_FAILED) only out-of-service
|
||||
instances were found.
|
||||
\return WC_TIMEOUT_E The wait budget expired.
|
||||
\return RNG_FAILURE_E No serviceable instance.
|
||||
\return BAD_INDEX_E preferred_inst_offset is out of range.
|
||||
\return BUSY_E The selected instance is contended (without _CAN_WAIT).
|
||||
|
||||
\param bank The bank to lease from.
|
||||
\param rng_inst Receives the leased instance.
|
||||
\param preferred_inst_offset The preferred instance, or 0.
|
||||
\param timeout_secs Wait budget (with _CAN_WAIT).
|
||||
\param flags Bitwise-or of WC_RNG_BANK_FLAG_* per-call flags.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
struct wc_rng_bank_inst *inst = NULL;
|
||||
if (wc_rng_bank_checkout(bank, &inst, 0, 10,
|
||||
WC_RNG_BANK_FLAG_CAN_WAIT |
|
||||
WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST) == 0) {
|
||||
ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(inst),
|
||||
out, sizeof(out));
|
||||
wc_rng_bank_inst_checkin(&inst);
|
||||
}
|
||||
\endcode
|
||||
|
||||
\sa wc_rng_bank_inst_checkin
|
||||
\sa wc_rng_bank_recover_inst
|
||||
\sa wc_rng_bank_spawn
|
||||
*/
|
||||
int wc_rng_bank_checkout(struct wc_rng_bank *bank,
|
||||
struct wc_rng_bank_inst **rng_inst,
|
||||
int preferred_inst_offset, int timeout_secs,
|
||||
word32 flags);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Return a lease through the bank object, validating that rng_inst
|
||||
belongs to bank. Prefer wc_rng_bank_inst_checkin() when only the
|
||||
instance pointer is at hand.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank or rng_inst is null, or the instance does not
|
||||
belong to bank.
|
||||
\return OBJECT_NOT_LOCKED_E The instance's lease is not held (e.g. a
|
||||
stale duplicate check-in).
|
||||
\return NEEDS_RECOVERY_E Checked in successfully; informational
|
||||
notice that the instance is entropy-invalidated.
|
||||
|
||||
\param bank The bank the instance belongs to.
|
||||
\param rng_inst The lease to return; nulled on success.
|
||||
|
||||
\sa wc_rng_bank_inst_checkin
|
||||
\sa wc_rng_bank_checkout
|
||||
*/
|
||||
int wc_rng_bank_checkin(struct wc_rng_bank *bank,
|
||||
struct wc_rng_bank_inst **rng_inst);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Return a lease by instance pointer alone.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG rng_inst or *rng_inst is null.
|
||||
\return OBJECT_NOT_LOCKED_E The instance's lease is not held.
|
||||
\return NEEDS_RECOVERY_E Checked in successfully; informational
|
||||
notice that the instance is entropy-invalidated.
|
||||
|
||||
\param rng_inst The lease to return; nulled on success.
|
||||
|
||||
\sa wc_rng_bank_checkout
|
||||
\sa wc_rng_bank_checkin
|
||||
*/
|
||||
int wc_rng_bank_inst_checkin(struct wc_rng_bank_inst **rng_inst);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Report the instance's offset within its bank.
|
||||
|
||||
\return n The instance offset, non-negative.
|
||||
\return BAD_FUNC_ARG rng_inst is null.
|
||||
|
||||
\param rng_inst The instance to interrogate.
|
||||
|
||||
\sa wc_rng_bank_checkout
|
||||
*/
|
||||
int wc_rng_bank_get_inst_id(struct wc_rng_bank_inst *rng_inst);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Bank next-seed material for the instance at inst_offset --
|
||||
wc_RNG_DRBG_NextSeedGenerate() through the bank, without taking the
|
||||
instance lock; the daemon-side serialization word arbitrates against
|
||||
concurrent whole-instance reinitialization.
|
||||
|
||||
\return 0 Bytes were banked.
|
||||
\return ALREADY_E The instance's bank is ready or being consumed.
|
||||
\return NOT_READY_E The health test could not run; simply retry.
|
||||
\return BAD_FUNC_ARG bank is null, inst_offset is out of range, or n
|
||||
is 0.
|
||||
|
||||
\param bank The bank.
|
||||
\param inst_offset The instance to bank for.
|
||||
\param n Maximum bytes to bank this call.
|
||||
|
||||
\sa wc_RNG_DRBG_NextSeedGenerate
|
||||
\sa wc_rng_bank_next_seed_generate_rbgc
|
||||
\details The daemon-side serialization word (not the instance lock)
|
||||
excludes a concurrent wc_rng_bank_inst_reinit() from freeing the DRBG
|
||||
out from under the gather; lease-holders never consult it, since
|
||||
instance-lock exclusion already covers every lease-holder interaction.
|
||||
The caller must hold a bank reference (e.g. per the daemon association)
|
||||
for the duration of the call. Return taxonomy for a banking rotation:
|
||||
BUSY_E, the gate is held by a reinit -- skip this turn; ALREADY_E,
|
||||
sleep until the bank is consumed; MISSING_RNG_E, the instance has no
|
||||
DRBG (RDRAND et al.) and can be retired from the rotation permanently;
|
||||
other errors are transient gather or health-test failures -- skip the
|
||||
turn, and alarm if persistent.
|
||||
|
||||
*/
|
||||
int wc_rng_bank_next_seed_generate(struct wc_rng_bank *bank, int inst_offset,
|
||||
word32 n);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief The chain-sourced form of wc_rng_bank_next_seed_generate(): the
|
||||
banked material is drawn from root's generate function and tagged with
|
||||
its provenance.
|
||||
|
||||
\return 0 Bytes were banked.
|
||||
\return ALREADY_E The instance's bank is ready or being consumed.
|
||||
\return NOT_READY_E The health test could not run; simply retry.
|
||||
\return BAD_FUNC_ARG bank or root is null, inst_offset is out of range,
|
||||
or n is 0.
|
||||
|
||||
\param bank The bank.
|
||||
\param inst_offset The instance to bank for.
|
||||
\param n Maximum bytes to bank this call.
|
||||
|
||||
\sa wc_rng_bank_next_seed_generate
|
||||
\sa wc_RNG_DRBG_NextSeedGenerate_RBGC
|
||||
*/
|
||||
int wc_rng_bank_next_seed_generate_rbgc(struct wc_rng_bank *bank,
|
||||
int inst_offset, word32 n);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Free and reinstantiate a leased instance in place. The caller
|
||||
must hold the lease; the daemon-side serialization word excludes
|
||||
concurrent lockless banking during the cycle.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank or rng_inst is null.
|
||||
\return RNG_FAILURE_E Reinstantiation could not be seeded within
|
||||
timeout_secs.
|
||||
\return BUSY_E The whole-instance-operation gate is held (daemon banking in
|
||||
progress); retry.
|
||||
|
||||
\param bank The bank the instance belongs to.
|
||||
\param rng_inst The leased instance to reinitialize.
|
||||
\param timeout_secs Seeding timeout budget.
|
||||
\param flags Bitwise-or of WC_RNG_BANK_FLAG_* flags.
|
||||
|
||||
\sa wc_rng_bank_recover_inst
|
||||
*/
|
||||
int wc_rng_bank_inst_reinit(struct wc_rng_bank *bank,
|
||||
struct wc_rng_bank_inst *rng_inst,
|
||||
int timeout_secs, word32 flags);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Patrol helper: check out the instance at inst_offset with
|
||||
WC_RNG_BANK_FLAG_FOR_RECOVERY, recover it iff it needs recovery, and
|
||||
check it back in. Two recovery arms: an out-of-service instance
|
||||
(wc_RNG_GetStatus() != WC_DRBG_OK) is reinitialized in place; an
|
||||
in-service but entropy-invalidated (quarantined) instance takes one
|
||||
credited reseed, which clears the quarantine while preserving instance
|
||||
identity. A healthy instance is a success no-op, so callers can
|
||||
invoke this unconditionally on state observed locklessly.
|
||||
|
||||
\return 0 Success (recovered, or nothing to recover).
|
||||
\return BAD_FUNC_ARG bank is null, inst_offset is out of range, or the
|
||||
flags are contradictory.
|
||||
\return RNG_FAILURE_E Recovery could not be seeded within timeout_secs.
|
||||
\return BUSY_E The instance lock or whole-instance-operation gate is
|
||||
contended; retry on a later patrol turn.
|
||||
|
||||
\param bank The bank.
|
||||
\param inst_offset The instance to patrol.
|
||||
\param timeout_secs Seeding timeout budget.
|
||||
\param flags Bitwise-or of WC_RNG_BANK_FLAG_* flags.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
// after a VM duplication event has invalidated the bank:
|
||||
for (i = 0; i < n_rngs; i++)
|
||||
(void)wc_rng_bank_recover_inst(bank, i, 10,
|
||||
WC_RNG_BANK_FLAG_CAN_WAIT);
|
||||
\endcode
|
||||
|
||||
\sa wc_rng_bank_invalidate_entropy
|
||||
\sa wc_rng_bank_checkout
|
||||
\details A stale lockless status observation costs one harmless round
|
||||
trip. BUSY_E reports contention on the instance lock or the
|
||||
whole-instance-operation gate: retry on a later patrol turn. flags may
|
||||
include WC_RNG_BANK_FLAG_CAN_WAIT and WC_RNG_BANK_FLAG_AFFINITY_LOCK,
|
||||
which are passed through.
|
||||
|
||||
*/
|
||||
int wc_rng_bank_recover_inst(struct wc_rng_bank *bank, int inst_offset,
|
||||
int timeout_secs, word32 flags);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Spawn an SP 800-90C chain RNG from a bank instance: check out a
|
||||
parent instance (honoring the usual selection flags), instantiate
|
||||
child_rng as its chain child (wc_InitRngNonceRBGC()), and check the
|
||||
parent back in. The child's lifetime is thereafter decoupled from the
|
||||
parent and its bank; release it with wc_FreeRng() (or wc_rng_free() for
|
||||
the heap form, wc_rng_bank_spawn_new()). The child's RBGC stratum is
|
||||
one plus the parent's stratum at instantiation.
|
||||
|
||||
\details A recommended nonce, when available, is a racy read of a
|
||||
high-resolution timer (e.g. Linux kernel random_get_entropy()).
|
||||
WC_RNG_BANK_FLAG_CONSUME_NEXT_SEED composes: a ready banked seed is
|
||||
redeemed on the parent before the spawn draw.
|
||||
WC_RNG_BANK_FLAG_STIR 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.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank or child_rng is null, or the flags are
|
||||
contradictory (uncredited or recovery seeding contradict a spawn).
|
||||
\return RNG_FAILURE_E No serviceable parent within the timeout budget.
|
||||
|
||||
\param bank The bank to spawn from.
|
||||
\param child_rng The caller-provided WC_RNG to instantiate.
|
||||
\param nonce Optional additional instantiation input.
|
||||
\param nonceSz Length of nonce in bytes.
|
||||
\param perso Optional personalization string (may be null).
|
||||
\param persoSz Length of perso in bytes.
|
||||
\param preferred_inst_offset The preferred parent instance, or 0.
|
||||
\param timeout_secs Wait budget (with _CAN_WAIT).
|
||||
\param flags Bitwise-or of WC_RNG_BANK_FLAG_* per-call flags.
|
||||
|
||||
\sa wc_rng_bank_spawn_new
|
||||
\sa wc_InitRngNonceRBGC
|
||||
*/
|
||||
int wc_rng_bank_spawn(struct wc_rng_bank *bank, WC_RNG *child_rng,
|
||||
byte *nonce, word32 nonceSz,
|
||||
const byte *perso, word32 persoSz,
|
||||
int preferred_inst_offset,
|
||||
int timeout_secs, word32 flags);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief The allocating form of wc_rng_bank_spawn(): the child is
|
||||
allocated from the bank's heap and returned through child_rng; release
|
||||
with wc_rng_free().
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank or child_rng is null.
|
||||
\return MEMORY_E Allocation failed.
|
||||
\return RNG_FAILURE_E No serviceable parent within the timeout budget.
|
||||
|
||||
\param bank The bank to spawn from.
|
||||
\param child_rng Receives the allocated, instantiated WC_RNG.
|
||||
\param nonce Optional additional instantiation input.
|
||||
\param nonceSz Length of nonce in bytes.
|
||||
\param perso Optional personalization string (may be null).
|
||||
\param persoSz Length of perso in bytes.
|
||||
\param preferred_inst_offset The preferred parent instance, or 0.
|
||||
\param timeout_secs Wait budget (with _CAN_WAIT).
|
||||
\param flags Bitwise-or of WC_RNG_BANK_FLAG_* per-call flags.
|
||||
|
||||
\sa wc_rng_bank_spawn
|
||||
*/
|
||||
int wc_rng_bank_spawn_new(struct wc_rng_bank *bank, WC_RNG **child_rng,
|
||||
byte *nonce, word32 nonceSz,
|
||||
const byte *perso, word32 persoSz,
|
||||
int preferred_inst_offset, int timeout_secs,
|
||||
word32 flags);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Reseed every instance with caller-supplied seed material.
|
||||
WC_RNG_BANK_FLAG_STIR mixes the material in without
|
||||
crediting it.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank or seed is null.
|
||||
\return RNG_FAILURE_E An instance could not be reseeded within
|
||||
timeout_secs.
|
||||
|
||||
\param bank The bank to seed.
|
||||
\param seed Seed material.
|
||||
\param seedSz Length of seed in bytes.
|
||||
\param nonce Optional per-instance nonce material (may be null).
|
||||
\param nonceSz Length of nonce in bytes.
|
||||
\param timeout_secs Wait budget per instance.
|
||||
\param flags Bitwise-or of WC_RNG_BANK_FLAG_* flags.
|
||||
|
||||
\sa wc_rng_bank_seed_range
|
||||
\sa wc_rng_bank_reseed
|
||||
*/
|
||||
int wc_rng_bank_seed(struct wc_rng_bank *bank, const byte* seed,
|
||||
word32 seedSz, const byte *nonce, word32 nonceSz,
|
||||
int timeout_secs, word32 flags);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief The range form of wc_rng_bank_seed(): seed instances first_inst
|
||||
through last_inst inclusive.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank or seed is null, or the range is out of
|
||||
bounds.
|
||||
\return RNG_FAILURE_E An instance could not be reseeded within
|
||||
timeout_secs.
|
||||
\return BAD_INDEX_E The instance range is invalid.
|
||||
\return BAD_STATE_E The bank is not initialized.
|
||||
\return NO_DEFAULT_FOUND_E bank is null and no default bank is registered.
|
||||
|
||||
\param bank The bank to seed.
|
||||
\param first_inst The first instance offset.
|
||||
\param last_inst The last instance offset.
|
||||
\param seed Seed material.
|
||||
\param seedSz Length of seed in bytes.
|
||||
\param nonce Optional per-instance nonce material (may be null).
|
||||
\param nonceSz Length of nonce in bytes.
|
||||
\param timeout_secs Wait budget per instance.
|
||||
\param flags Bitwise-or of WC_RNG_BANK_FLAG_* flags.
|
||||
|
||||
\sa wc_rng_bank_seed
|
||||
*/
|
||||
int wc_rng_bank_seed_range(struct wc_rng_bank *bank, int first_inst,
|
||||
int last_inst, const byte* seed, word32 seedSz,
|
||||
const byte *nonce, word32 nonceSz,
|
||||
int timeout_secs, word32 flags);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Reseed every instance from the module's seed source.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank is null.
|
||||
\return RNG_FAILURE_E An instance could not be reseeded within
|
||||
timeout_secs.
|
||||
|
||||
\param bank The bank to reseed.
|
||||
\param nonce Optional per-instance nonce material (may be null).
|
||||
\param nonceSz Length of nonce in bytes.
|
||||
\param timeout_secs Wait budget per instance.
|
||||
\param flags Bitwise-or of WC_RNG_BANK_FLAG_* flags.
|
||||
|
||||
\sa wc_rng_bank_reseed_range
|
||||
\sa wc_rng_bank_seed
|
||||
*/
|
||||
int wc_rng_bank_reseed(struct wc_rng_bank *bank,
|
||||
const byte *nonce, word32 nonceSz,
|
||||
int timeout_secs, word32 flags);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief The range form of wc_rng_bank_reseed().
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank is null, or the range is out of bounds.
|
||||
\return RNG_FAILURE_E An instance could not be reseeded within
|
||||
timeout_secs.
|
||||
\return BAD_INDEX_E The instance range is invalid.
|
||||
\return BAD_STATE_E The bank is not initialized.
|
||||
\return WC_TIMEOUT_E The walk exceeded timeout_secs.
|
||||
|
||||
\param bank The bank to reseed.
|
||||
\param nonce Optional per-instance nonce material (may be null).
|
||||
\param nonceSz Length of nonce in bytes.
|
||||
\param first_inst The first instance offset.
|
||||
\param last_inst The last instance offset.
|
||||
\param timeout_secs Wait budget per instance.
|
||||
\param flags Bitwise-or of WC_RNG_BANK_FLAG_* flags.
|
||||
|
||||
\sa wc_rng_bank_reseed
|
||||
*/
|
||||
int wc_rng_bank_reseed_range(struct wc_rng_bank *bank, int first_inst,
|
||||
int last_inst,
|
||||
const byte *nonce, word32 nonceSz,
|
||||
int timeout_secs, word32 flags);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Set the entropy-invalidated latch on every instance (see
|
||||
wc_RNG_invalidate_entropy()): cached entropy products are discarded,
|
||||
and each instance is forced through a credited reseed before its next
|
||||
generate serves output. Lock-free and constant-time per instance; safe
|
||||
from a state-invalidation event context (VM fork/resume).
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank is null.
|
||||
\return BAD_STATE_E The bank is not initialized.
|
||||
|
||||
\param bank The bank to invalidate.
|
||||
\param flags Bitwise-or of WC_RNG_BANK_FLAG_* flags.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
// VM-resume notifier
|
||||
(void)wc_rng_bank_invalidate_entropy(bank, WC_RNG_BANK_FLAG_NONE);
|
||||
// instances recover on next checkout, or by patrol:
|
||||
// wc_rng_bank_recover_inst()
|
||||
\endcode
|
||||
|
||||
\sa wc_RNG_invalidate_entropy
|
||||
\sa wc_rng_bank_recover_inst
|
||||
\details Also purges each instance's banked next-seed apertures: the
|
||||
purge is the provenance guarantee that a READY bank observed after the
|
||||
event holds post-event material (see wc_rng_bank_checkout()'s recovery
|
||||
admissions). Walks every instance even on error, returning the first
|
||||
error. flags must be 0.
|
||||
|
||||
*/
|
||||
int wc_rng_bank_invalidate_entropy(struct wc_rng_bank *bank, word32 flags);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Reserve the bank's daemon slot with a caller-chosen nonzero
|
||||
magic word, admitting exactly one scheduling daemon per bank. The
|
||||
lifecycle is strictly ordered: _reserve, then _register, then
|
||||
_unregister, then _release.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank is null or magic is the free sentinel.
|
||||
\return BUSY_E The slot is claimed, or claiming is contended.
|
||||
|
||||
\param bank The bank to claim.
|
||||
\param magic The daemon's magic word.
|
||||
|
||||
\sa wc_rng_bank_daemon_register
|
||||
\sa wc_rng_bank_daemon_release
|
||||
*/
|
||||
int wc_rng_bank_daemon_reserve(struct wc_rng_bank *bank,
|
||||
WC_ATOMIC_UINT_ARG magic);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Register the daemon object in a slot reserved with the same
|
||||
magic word.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank or daemon is null.
|
||||
\return ALREADY_E The slot is already in the requested state.
|
||||
\return WRONG_TYPE_OBJECT_E magic does not match the claim.
|
||||
\return BUSY_E The slot transition is contended; retry.
|
||||
|
||||
\param bank The bank.
|
||||
\param daemon The daemon object to register.
|
||||
\param magic The daemon's magic word.
|
||||
|
||||
\sa wc_rng_bank_daemon_reserve
|
||||
\sa wc_rng_bank_daemon_unregister
|
||||
*/
|
||||
int wc_rng_bank_daemon_register(struct wc_rng_bank *bank, void *daemon,
|
||||
WC_ATOMIC_UINT_ARG magic);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Unregister the daemon object, returning it through daemon.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank or daemon is null.
|
||||
\return ALREADY_E The slot is already in the requested state.
|
||||
\return WRONG_TYPE_OBJECT_E magic does not match the claim.
|
||||
\return BUSY_E The slot transition is contended; retry.
|
||||
|
||||
\param bank The bank.
|
||||
\param daemon Receives the registered daemon object.
|
||||
\param magic The daemon's magic word.
|
||||
|
||||
\sa wc_rng_bank_daemon_register
|
||||
\sa wc_rng_bank_daemon_release
|
||||
*/
|
||||
int wc_rng_bank_daemon_unregister(struct wc_rng_bank *bank, void **daemon,
|
||||
WC_ATOMIC_UINT_ARG magic);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Release the daemon slot claimed with magic, returning it to the
|
||||
free sentinel.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank is null.
|
||||
\return ALREADY_E The slot is already in the requested state.
|
||||
\return WRONG_TYPE_OBJECT_E magic does not match the claim.
|
||||
\return BUSY_E The slot transition is contended; retry.
|
||||
|
||||
\param bank The bank.
|
||||
\param magic The daemon's magic word.
|
||||
|
||||
\sa wc_rng_bank_daemon_reserve
|
||||
*/
|
||||
int wc_rng_bank_daemon_release(struct wc_rng_bank *bank,
|
||||
WC_ATOMIC_UINT_ARG magic);
|
||||
|
||||
/*!
|
||||
\ingroup RNGBank
|
||||
|
||||
\brief Initialize the bank's root RNG -- the primary-sourced parent
|
||||
that seeds and recovers the bank's instances.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank is null.
|
||||
|
||||
\param bank The bank whose root to initialize.
|
||||
\param nonce Optional instantiation nonce (may be null).
|
||||
\param nonceSz Length of nonce in bytes.
|
||||
\param perso Optional personalization string (may be null).
|
||||
\param persoSz Length of perso in bytes.
|
||||
\param flags Bitwise-or of WC_RNG_INIT_FLAG_* attributes.
|
||||
|
||||
\sa wc_rng_bank_root_rng_get
|
||||
*/
|
||||
int wc_rng_bank_root_rng_init(struct wc_rng_bank *bank,
|
||||
const byte *nonce, word32 nonceSz,
|
||||
const byte *perso, word32 persoSz,
|
||||
word32 flags);
|
||||
|
||||
/*!
|
||||
\ingroup RNGBank
|
||||
|
||||
\brief Report the bank's root RNG.
|
||||
|
||||
\return The root WC_RNG, or null when none is initialized or bank is
|
||||
null.
|
||||
|
||||
\param bank The bank to interrogate.
|
||||
|
||||
\sa wc_rng_bank_root_rng_init
|
||||
*/
|
||||
WC_RNG *wc_rng_bank_root_rng_get(struct wc_rng_bank *bank);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Register a callback fired by wc_rng_bank_fini() once its
|
||||
refcount and leak gates pass -- i.e. once teardown is committed -- for
|
||||
external registries that must drop their reference when the bank dies.
|
||||
One-shot: the hook is cleared before firing. A null free_hook
|
||||
unregisters.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank is null.
|
||||
|
||||
\param bank The bank to hook.
|
||||
\param free_hook The callback.
|
||||
\param arg Opaque argument passed to the callback.
|
||||
|
||||
\sa wc_rng_bank_fini
|
||||
\sa wc_RNG_register_free_hook
|
||||
*/
|
||||
int wc_rng_bank_register_free_hook(struct wc_rng_bank *bank,
|
||||
wc_rng_bank_free_hook_cb_t free_hook,
|
||||
void *arg);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Initialize rng as a bank reference: a WC_RNG with no DRBG of its
|
||||
own, whose wc_RNG_GenerateBlock() transparently checks an instance out
|
||||
of bank, generates, and checks it back in. Release with wc_FreeRng().
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank or rng is null.
|
||||
|
||||
\param bank The bank to reference.
|
||||
\param rng The WC_RNG to initialize as a reference.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
WC_RNG rng;
|
||||
if (wc_InitRng_BankRef(bank, &rng) == 0) {
|
||||
// rng now serves through the bank
|
||||
ret = wc_RNG_GenerateBlock(&rng, out, sizeof(out));
|
||||
wc_FreeRng(&rng);
|
||||
}
|
||||
\endcode
|
||||
|
||||
\sa wc_BankRef_Release
|
||||
\sa wc_rng_new_bankref
|
||||
*/
|
||||
int wc_InitRng_BankRef(struct wc_rng_bank *bank, WC_RNG *rng);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Release a bank reference. wc_FreeRng() calls this
|
||||
automatically for bank references; direct use is rarely needed.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG rng is null or is not a bank reference.
|
||||
|
||||
\param rng The bank reference to release.
|
||||
|
||||
\sa wc_InitRng_BankRef
|
||||
*/
|
||||
int wc_BankRef_Release(WC_RNG *rng);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief The allocating form of wc_InitRng_BankRef(): the reference is
|
||||
allocated from the bank's heap; release with wc_rng_free().
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG bank or rng is null.
|
||||
\return MEMORY_E Allocation failed.
|
||||
|
||||
\param bank The bank to reference.
|
||||
\param rng Receives the allocated bank reference.
|
||||
|
||||
\sa wc_InitRng_BankRef
|
||||
*/
|
||||
int wc_rng_new_bankref(struct wc_rng_bank *bank, WC_RNG **rng);
|
||||
|
||||
/*!
|
||||
\ingroup Random
|
||||
|
||||
\brief Snapshot the RNG debug counters (WC_RNG_DEBUG_STATS) with
|
||||
bank-level context.
|
||||
|
||||
\return 0 Success
|
||||
\return BAD_FUNC_ARG s is null.
|
||||
|
||||
\param s Receives the snapshot.
|
||||
\param bank Optional bank for context, or null.
|
||||
|
||||
\sa wc_rng_debug_stats_snap
|
||||
*/
|
||||
int wc_rng_bank_debug_stats_snap(struct wc_rng_debug_stats_snapshot *s,
|
||||
struct wc_rng_bank *bank);
|
||||
@@ -35,4 +35,5 @@ EXTRA_DIST += m4/ax_linuxkm.m4 \
|
||||
linuxkm/patches/6.1.73/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-6v1v73.patch \
|
||||
linuxkm/patches/6.12/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-6v12.patch \
|
||||
linuxkm/patches/6.15/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-6v15.patch \
|
||||
linuxkm/patches/7.0/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-7v0.patch
|
||||
linuxkm/patches/7.0/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-7v0.patch \
|
||||
linuxkm/patches/7.3/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-7v3.patch
|
||||
|
||||
@@ -795,6 +795,10 @@
|
||||
}
|
||||
#endif
|
||||
#define WC_LKM_REFCOUNT_TO_INT(refcount) wc_lkm_refcount_to_int(&(refcount))
|
||||
#include <linux/notifier.h>
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
#include <linux/suspend.h>
|
||||
#endif
|
||||
#endif /* !WC_CONTAINERIZE_THIS */
|
||||
|
||||
#endif /* LINUXKM_LKCAPI_REGISTER */
|
||||
|
||||
@@ -228,14 +228,14 @@ static int linuxkm_lkcapi_unregister(void);
|
||||
static int enabled_kernel_fips_enabled = 0;
|
||||
#endif
|
||||
|
||||
static ssize_t install_algs_handler(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
static ssize_t install_algs_handler(WC_MODULE_ATTR_CONST struct module_attribute *mattr, struct module_kobject *mk,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int arg;
|
||||
int ret;
|
||||
|
||||
(void)kobj;
|
||||
(void)attr;
|
||||
(void)mattr;
|
||||
(void)mk;
|
||||
|
||||
if (kstrtoint(buf, 10, &arg) || arg != 1)
|
||||
return -EINVAL;
|
||||
@@ -249,14 +249,14 @@ static ssize_t install_algs_handler(struct kobject *kobj, struct kobj_attribute
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t deinstall_algs_handler(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
static ssize_t deinstall_algs_handler(WC_MODULE_ATTR_CONST struct module_attribute *mattr, struct module_kobject *mk,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int arg;
|
||||
int ret;
|
||||
|
||||
(void)kobj;
|
||||
(void)attr;
|
||||
(void)mattr;
|
||||
(void)mk;
|
||||
|
||||
if (kstrtoint(buf, 10, &arg) || arg != 1)
|
||||
return -EINVAL;
|
||||
@@ -279,22 +279,50 @@ static ssize_t deinstall_algs_handler(struct kobject *kobj, struct kobj_attribut
|
||||
|
||||
/* create control channels at /sys/module/libwolfssl/{install_algs,deinstall_algs} */
|
||||
|
||||
static struct kobj_attribute install_algs_attr = __ATTR(install_algs, 0220, NULL, install_algs_handler);
|
||||
static struct kobj_attribute deinstall_algs_attr = __ATTR(deinstall_algs, 0220, NULL, deinstall_algs_handler);
|
||||
static struct module_attribute install_algs_attr = __ATTR(install_algs, 0220, NULL, install_algs_handler);
|
||||
static struct module_attribute deinstall_algs_attr = __ATTR(deinstall_algs, 0220, NULL, deinstall_algs_handler);
|
||||
|
||||
static int installed_sysfs_LKCAPI_files = 0;
|
||||
|
||||
static int linuxkm_lkcapi_sysfs_install(void) {
|
||||
int ret;
|
||||
if (! installed_sysfs_LKCAPI_files) {
|
||||
ret = linuxkm_lkcapi_sysfs_install_node(&install_algs_attr, NULL);
|
||||
ret = linuxkm_sysfs_install_attr(&install_algs_attr.attr, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = linuxkm_lkcapi_sysfs_install_node(&deinstall_algs_attr, NULL);
|
||||
ret = linuxkm_sysfs_install_attr(&deinstall_algs_attr.attr, NULL);
|
||||
if (ret) {
|
||||
(void)linuxkm_lkcapi_sysfs_deinstall_node(&install_algs_attr, NULL);
|
||||
(void)linuxkm_sysfs_deinstall_attr(&install_algs_attr.attr, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef WC_LINUXKM_HAVE_RNG_STATE_INVALIDATE_HANDLER
|
||||
ret = linuxkm_sysfs_install_attr(&wc_linuxkm_rng_state_invalidate_attr.attr,
|
||||
NULL);
|
||||
if (ret) {
|
||||
(void)linuxkm_sysfs_deinstall_attr(&deinstall_algs_attr.attr,
|
||||
NULL);
|
||||
(void)linuxkm_sysfs_deinstall_attr(&install_algs_attr.attr,
|
||||
NULL);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#if defined(LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) && \
|
||||
defined(WC_RNG_DEBUG_STATS)
|
||||
ret = linuxkm_sysfs_install_attr(&wc_linuxkm_rng_stats_attr.attr,
|
||||
NULL);
|
||||
if (ret) {
|
||||
#ifdef WC_LINUXKM_HAVE_RNG_STATE_INVALIDATE_HANDLER
|
||||
(void)linuxkm_sysfs_deinstall_attr(&wc_linuxkm_rng_state_invalidate_attr.attr,
|
||||
NULL);
|
||||
#endif
|
||||
(void)linuxkm_sysfs_deinstall_attr(&deinstall_algs_attr.attr,
|
||||
NULL);
|
||||
(void)linuxkm_sysfs_deinstall_attr(&install_algs_attr.attr,
|
||||
NULL);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
installed_sysfs_LKCAPI_files = 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -302,10 +330,27 @@ static int linuxkm_lkcapi_sysfs_install(void) {
|
||||
|
||||
static int linuxkm_lkcapi_sysfs_deinstall(void) {
|
||||
if (installed_sysfs_LKCAPI_files) {
|
||||
int ret = linuxkm_lkcapi_sysfs_deinstall_node(&install_algs_attr, NULL);
|
||||
int ret;
|
||||
#if defined(LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) && \
|
||||
defined(WC_RNG_DEBUG_STATS)
|
||||
ret = linuxkm_sysfs_deinstall_attr(&wc_linuxkm_rng_stats_attr.attr,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = linuxkm_lkcapi_sysfs_deinstall_node(&deinstall_algs_attr, NULL);
|
||||
#endif
|
||||
#ifdef WC_LINUXKM_HAVE_RNG_STATE_INVALIDATE_HANDLER
|
||||
/* removed first (LIFO), and in any case before RNG teardown can
|
||||
* begin: the store handler walks the registry and reaches the
|
||||
* daemon root. */
|
||||
ret = linuxkm_sysfs_deinstall_attr(&wc_linuxkm_rng_state_invalidate_attr.attr,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
ret = linuxkm_sysfs_deinstall_attr(&install_algs_attr.attr, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = linuxkm_sysfs_deinstall_attr(&deinstall_algs_attr.attr, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
installed_sysfs_LKCAPI_files = 0;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,548 @@
|
||||
--- 7.3/drivers/char/random.c.dist 2026-09-07 15:16:52.000000000 -0500
|
||||
+++ 7.3/drivers/char/random.c 2026-09-08 14:52:24.223216472 -0500
|
||||
@@ -84,6 +84,310 @@ static enum {
|
||||
} crng_init __read_mostly = CRNG_EMPTY;
|
||||
static DEFINE_STATIC_KEY_FALSE(crng_is_ready);
|
||||
#define crng_ready() (static_branch_likely(&crng_is_ready) || crng_init >= CRNG_READY)
|
||||
+
|
||||
+#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS
|
||||
+
|
||||
+#include <linux/percpu-refcount.h>
|
||||
+
|
||||
+static atomic_long_t random_bytes_cb_owner =
|
||||
+ ATOMIC_LONG_INIT((long)NULL);
|
||||
+static struct percpu_ref random_bytes_cb_ref;
|
||||
+static bool random_bytes_cb_live; /* READ_ONCE/WRITE_ONCE only */
|
||||
+static DECLARE_COMPLETION(random_bytes_cb_drained);
|
||||
+static _get_random_bytes_cb_t _get_random_bytes_cb;
|
||||
+static get_random_bytes_user_cb_t get_random_bytes_user_cb;
|
||||
+static crng_ready_cb_t crng_ready_cb;
|
||||
+static mix_pool_bytes_cb_t mix_pool_bytes_cb;
|
||||
+static credit_init_bits_cb_t credit_init_bits_cb;
|
||||
+static crng_reseed_cb_t crng_reseed_cb;
|
||||
+
|
||||
+static void random_bytes_cb_ref_release(struct percpu_ref *ref)
|
||||
+{
|
||||
+ complete(&random_bytes_cb_drained);
|
||||
+}
|
||||
+
|
||||
+/* distinct non-module value marking teardown in progress; guarantees
|
||||
+ * non-collision with any real module pointer. */
|
||||
+static char random_bytes_cb_teardown_sentinel;
|
||||
+#define RANDOM_BYTES_CB_TEARDOWN ((long)&random_bytes_cb_teardown_sentinel)
|
||||
+
|
||||
+int wolfssl_linuxkm_register_random_bytes_handlers(
|
||||
+ struct module *new_random_bytes_cb_owner,
|
||||
+ const struct wolfssl_linuxkm_random_bytes_handlers *handlers)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ if ((new_random_bytes_cb_owner == NULL) ||
|
||||
+ (handlers == NULL) ||
|
||||
+ (handlers->_get_random_bytes == NULL) ||
|
||||
+ (handlers->get_random_bytes_user == NULL))
|
||||
+ {
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* random_bytes_cb_owner is used to enforce serialization of
|
||||
+ * wolfssl_linuxkm_register_random_bytes_handlers() and
|
||||
+ * wolfssl_linuxkm_unregister_random_bytes_handlers(): NULL means
|
||||
+ * unowned, a module pointer means registered (or registration in
|
||||
+ * flight, while random_bytes_cb_live is still false), and
|
||||
+ * RANDOM_BYTES_CB_TEARDOWN means unregistration in flight.
|
||||
+ */
|
||||
+ if (atomic_long_cmpxchg(&random_bytes_cb_owner,
|
||||
+ (long)NULL,
|
||||
+ (long)new_random_bytes_cb_owner)
|
||||
+ != (long)NULL)
|
||||
+ {
|
||||
+ return -EBUSY;
|
||||
+ }
|
||||
+
|
||||
+ if (!try_module_get(new_random_bytes_cb_owner)) {
|
||||
+ atomic_long_set(&random_bytes_cb_owner, (long)NULL);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ /* handlers must be published before the ref goes live. */
|
||||
+ _get_random_bytes_cb = handlers->_get_random_bytes;
|
||||
+ get_random_bytes_user_cb = handlers->get_random_bytes_user;
|
||||
+ crng_ready_cb = handlers->crng_ready;
|
||||
+ mix_pool_bytes_cb = handlers->mix_pool_bytes;
|
||||
+ credit_init_bits_cb = handlers->credit_init_bits;
|
||||
+ crng_reseed_cb = handlers->crng_reseed;
|
||||
+
|
||||
+ reinit_completion(&random_bytes_cb_drained);
|
||||
+ ret = percpu_ref_init(&random_bytes_cb_ref,
|
||||
+ random_bytes_cb_ref_release, 0, GFP_KERNEL);
|
||||
+ if (ret) {
|
||||
+ _get_random_bytes_cb = NULL;
|
||||
+ get_random_bytes_user_cb = NULL;
|
||||
+ crng_ready_cb = NULL;
|
||||
+ mix_pool_bytes_cb = NULL;
|
||||
+ credit_init_bits_cb = NULL;
|
||||
+ crng_reseed_cb = NULL;
|
||||
+ module_put(new_random_bytes_cb_owner);
|
||||
+ /* an unregister call racing this in-flight registration may
|
||||
+ * hold the owner word at RANDOM_BYTES_CB_TEARDOWN for the
|
||||
+ * brief interval before it observes !random_bytes_cb_live
|
||||
+ * and restores our pointer; wait it out rather than
|
||||
+ * clobbering its claim. */
|
||||
+ while (atomic_long_cmpxchg(&random_bytes_cb_owner,
|
||||
+ (long)new_random_bytes_cb_owner,
|
||||
+ (long)NULL)
|
||||
+ != (long)new_random_bytes_cb_owner)
|
||||
+ {
|
||||
+ cpu_relax();
|
||||
+ }
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (IS_ENABLED(CONFIG_VDSO_GETRANDOM)) {
|
||||
+ /* route vDSO getrandom() users to the syscall, hence to the
|
||||
+ * callbacks. */
|
||||
+ WRITE_ONCE(vdso_k_rng_data->is_ready, false);
|
||||
+ }
|
||||
+
|
||||
+ WRITE_ONCE(random_bytes_cb_live, true);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(wolfssl_linuxkm_register_random_bytes_handlers);
|
||||
+
|
||||
+int wolfssl_linuxkm_unregister_random_bytes_handlers(void)
|
||||
+{
|
||||
+ long prev = atomic_long_read(&random_bytes_cb_owner);
|
||||
+ struct module *owner;
|
||||
+
|
||||
+ /* claim teardown ownership: exactly one caller transitions the owner
|
||||
+ * word from a module pointer to RANDOM_BYTES_CB_TEARDOWN; any
|
||||
+ * concurrent or repeated caller is refused.
|
||||
+ */
|
||||
+ for (;;) {
|
||||
+ if ((prev == (long)NULL) || (prev == RANDOM_BYTES_CB_TEARDOWN))
|
||||
+ return -ENODEV;
|
||||
+ if (atomic_long_try_cmpxchg(&random_bytes_cb_owner, &prev,
|
||||
+ RANDOM_BYTES_CB_TEARDOWN))
|
||||
+ break;
|
||||
+ /* prev was refreshed by the failed cmpxchg; loop. */
|
||||
+ }
|
||||
+ owner = (struct module *)prev;
|
||||
+
|
||||
+ if (!READ_ONCE(random_bytes_cb_live)) {
|
||||
+ /* registration still in flight (or failing): hand the owner
|
||||
+ * word back and refuse. */
|
||||
+ atomic_long_set(&random_bytes_cb_owner, prev);
|
||||
+ return -EBUSY;
|
||||
+ }
|
||||
+
|
||||
+ WRITE_ONCE(random_bytes_cb_live, false);
|
||||
+ /* after this, no resolver can be between its liveness check and its
|
||||
+ * tryget. */
|
||||
+ synchronize_rcu();
|
||||
+ percpu_ref_kill(&random_bytes_cb_ref);
|
||||
+ wait_for_completion(&random_bytes_cb_drained);
|
||||
+ percpu_ref_exit(&random_bytes_cb_ref);
|
||||
+
|
||||
+ _get_random_bytes_cb = NULL;
|
||||
+ get_random_bytes_user_cb = NULL;
|
||||
+ crng_ready_cb = NULL;
|
||||
+ mix_pool_bytes_cb = NULL;
|
||||
+ credit_init_bits_cb = NULL;
|
||||
+ crng_reseed_cb = NULL;
|
||||
+
|
||||
+ if (IS_ENABLED(CONFIG_VDSO_GETRANDOM))
|
||||
+ WRITE_ONCE(vdso_k_rng_data->is_ready, crng_ready());
|
||||
+
|
||||
+ module_put(owner);
|
||||
+ atomic_long_set(&random_bytes_cb_owner, (long)NULL);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(wolfssl_linuxkm_unregister_random_bytes_handlers);
|
||||
+
|
||||
+/* Output emitters covered while a generate callback is live:
|
||||
+ * _get_random_bytes (and the batched get_random_uXX fills, which route
|
||||
+ * through it), get_random_bytes_user, and vDSO getrandom (readiness
|
||||
+ * withheld, forcing the syscall path). New crng_make_state callers or
|
||||
+ * vDSO datapage exports need corresponding treatment. */
|
||||
+static __always_inline int reserve_random_bytes_cb(void)
|
||||
+{
|
||||
+ int ret = -ENODEV;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ if (READ_ONCE(random_bytes_cb_live) &&
|
||||
+ percpu_ref_tryget_live(&random_bytes_cb_ref))
|
||||
+ {
|
||||
+ ret = 0;
|
||||
+ }
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static __always_inline void release_random_bytes_cb(void)
|
||||
+{
|
||||
+ percpu_ref_put(&random_bytes_cb_ref);
|
||||
+}
|
||||
+
|
||||
+static inline int call__get_random_bytes_cb(void *buf, size_t len)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ if (_get_random_bytes_cb == NULL)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ ret = reserve_random_bytes_cb();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = _get_random_bytes_cb(buf, len);
|
||||
+
|
||||
+ release_random_bytes_cb();
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static inline ssize_t call_get_random_bytes_user_cb(struct iov_iter *iter)
|
||||
+{
|
||||
+ ssize_t ret;
|
||||
+
|
||||
+ if (get_random_bytes_user_cb == NULL)
|
||||
+ return -ECANCELED;
|
||||
+
|
||||
+ ret = (ssize_t)reserve_random_bytes_cb();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = get_random_bytes_user_cb(iter);
|
||||
+
|
||||
+ release_random_bytes_cb();
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static inline bool call_crng_ready_cb(void)
|
||||
+{
|
||||
+ bool ret;
|
||||
+
|
||||
+ /* Null crng_ready_cb signifies that the DRBG is always ready, i.e. that if
|
||||
+ * called, it will always have or obtain sufficient entropy to fulfill the
|
||||
+ * call.
|
||||
+ */
|
||||
+ if (crng_ready_cb == NULL)
|
||||
+ return 1;
|
||||
+
|
||||
+ if (reserve_random_bytes_cb() != 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = crng_ready_cb();
|
||||
+
|
||||
+ release_random_bytes_cb();
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static inline int call_mix_pool_bytes_cb(const void *buf, size_t len)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ if (mix_pool_bytes_cb == NULL)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ ret = reserve_random_bytes_cb();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = mix_pool_bytes_cb(buf, len);
|
||||
+
|
||||
+ release_random_bytes_cb();
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static inline int call_credit_init_bits_cb(size_t bits)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ if (credit_init_bits_cb == NULL)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ ret = reserve_random_bytes_cb();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = credit_init_bits_cb(bits);
|
||||
+
|
||||
+ release_random_bytes_cb();
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static inline int call_crng_reseed_cb(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ if (crng_reseed_cb == NULL)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ ret = reserve_random_bytes_cb();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = crng_reseed_cb();
|
||||
+
|
||||
+ release_random_bytes_cb();
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+#endif /* WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS */
|
||||
+
|
||||
+#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS
|
||||
+ #define crng_ready_by_cb() (READ_ONCE(random_bytes_cb_live) && call_crng_ready_cb())
|
||||
+ #define crng_ready_maybe_cb() (READ_ONCE(random_bytes_cb_live) ? \
|
||||
+ (call_crng_ready_cb() || crng_ready()) : crng_ready())
|
||||
+#else
|
||||
+ #define crng_ready_maybe_cb() crng_ready()
|
||||
+#endif
|
||||
+
|
||||
/* Various types of waiters for crng_init->CRNG_READY transition. */
|
||||
static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait);
|
||||
static struct fasync_struct *fasync;
|
||||
@@ -107,7 +411,7 @@ MODULE_PARM_DESC(ratelimit_disable, "Dis
|
||||
*/
|
||||
bool rng_is_initialized(void)
|
||||
{
|
||||
- return crng_ready();
|
||||
+ return crng_ready_maybe_cb();
|
||||
}
|
||||
EXPORT_SYMBOL(rng_is_initialized);
|
||||
|
||||
@@ -131,11 +435,11 @@ static void try_to_generate_entropy(void
|
||||
*/
|
||||
int wait_for_random_bytes(void)
|
||||
{
|
||||
- while (!crng_ready()) {
|
||||
+ while (!crng_ready_maybe_cb()) {
|
||||
int ret;
|
||||
|
||||
try_to_generate_entropy();
|
||||
- ret = wait_event_interruptible_timeout(crng_init_wait, crng_ready(), HZ);
|
||||
+ ret = wait_event_interruptible_timeout(crng_init_wait, crng_ready_maybe_cb(), HZ);
|
||||
if (ret)
|
||||
return ret > 0 ? 0 : ret;
|
||||
}
|
||||
@@ -155,7 +459,7 @@ int __cold execute_with_initialized_rng(
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&random_ready_notifier.lock, flags);
|
||||
- if (crng_ready())
|
||||
+ if (crng_ready_maybe_cb())
|
||||
nb->notifier_call(nb, 0, NULL);
|
||||
else
|
||||
ret = raw_notifier_chain_register((struct raw_notifier_head *)&random_ready_notifier.head, nb);
|
||||
@@ -392,6 +696,24 @@ static void _get_random_bytes(void *buf,
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
+#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS
|
||||
+ {
|
||||
+ int cb_ret = call__get_random_bytes_cb(buf, len);
|
||||
+ if (cb_ret == 0)
|
||||
+ return;
|
||||
+ /* Nonzero cb_ret: no handlers installed (-ENODEV), a lost
|
||||
+ * race with deinstallation (also -ENODEV), or a genuine
|
||||
+ * callback failure. Check the sentinel at warn time to
|
||||
+ * distinguish: only a failure with the sentinel still live is
|
||||
+ * a contract violation. Continue regardless; native
|
||||
+ * fallthrough is the only available mechanism to preserve
|
||||
+ * the void contract. */
|
||||
+ WARN_ONCE(READ_ONCE(random_bytes_cb_live),
|
||||
+ "_get_random_bytes callback failed with code %d; "
|
||||
+ "native fallthrough\n", cb_ret);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
first_block_len = min_t(size_t, 32, len);
|
||||
crng_make_state(&chacha_state, buf, first_block_len);
|
||||
len -= first_block_len;
|
||||
@@ -437,6 +759,20 @@ static ssize_t get_random_bytes_user(str
|
||||
if (unlikely(!iov_iter_count(iter)))
|
||||
return 0;
|
||||
|
||||
+#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS
|
||||
+ if (READ_ONCE(random_bytes_cb_live)) {
|
||||
+ ssize_t cb_ret = call_get_random_bytes_user_cb(iter);
|
||||
+ /* -ECANCELED: no iter callback registered; iter is intact.
|
||||
+ * While a generate callback is live, no output bytes come
|
||||
+ * from the native crng: a live handler set must include the
|
||||
+ * iter callback. */
|
||||
+ if (cb_ret != -ECANCELED)
|
||||
+ return cb_ret;
|
||||
+ WARN_ONCE(1, "live random_bytes handler set lacks get_random_bytes_user callback");
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* Immediately overwrite the ChaCha key at index 4 with random
|
||||
* bytes, in case userspace causes copy_to_iter() below to sleep
|
||||
@@ -512,7 +848,7 @@ type get_random_ ##type(void) \
|
||||
struct batch_ ##type *batch; \
|
||||
unsigned long next_gen; \
|
||||
\
|
||||
- if (!crng_ready()) { \
|
||||
+ if (READ_ONCE(random_bytes_cb_live) || !crng_ready()) { \
|
||||
_get_random_bytes(&ret, sizeof(ret)); \
|
||||
return ret; \
|
||||
} \
|
||||
@@ -648,6 +984,11 @@ static void mix_pool_bytes(const void *b
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
+#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS
|
||||
+ (void)call_mix_pool_bytes_cb(buf, len);
|
||||
+ /* continue to mix into native pool too. */
|
||||
+#endif
|
||||
+
|
||||
spin_lock_irqsave(&input_pool.lock, flags);
|
||||
_mix_pool_bytes(buf, len);
|
||||
spin_unlock_irqrestore(&input_pool.lock, flags);
|
||||
@@ -707,7 +1048,13 @@ static void extract_entropy(void *buf, s
|
||||
memzero_explicit(&block, sizeof(block));
|
||||
}
|
||||
|
||||
-#define credit_init_bits(bits) if (!crng_ready()) _credit_init_bits(bits)
|
||||
+#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS
|
||||
+ #define credit_init_bits(bits) do { (void)call_credit_init_bits_cb(bits); \
|
||||
+ if (!crng_ready()) \
|
||||
+ _credit_init_bits(bits); } while (0)
|
||||
+#else
|
||||
+ #define credit_init_bits(bits) do { if (!crng_ready()) _credit_init_bits(bits); } while (0)
|
||||
+#endif
|
||||
|
||||
static void __cold _credit_init_bits(size_t bits)
|
||||
{
|
||||
@@ -731,7 +1078,11 @@ static void __cold _credit_init_bits(siz
|
||||
if (system_dfl_wq)
|
||||
queue_work(system_dfl_wq, &set_ready);
|
||||
atomic_notifier_call_chain(&random_ready_notifier, 0, NULL);
|
||||
- if (IS_ENABLED(CONFIG_VDSO_GETRANDOM))
|
||||
+ if (IS_ENABLED(CONFIG_VDSO_GETRANDOM)
|
||||
+#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS
|
||||
+ && !READ_ONCE(random_bytes_cb_live)
|
||||
+#endif
|
||||
+ )
|
||||
WRITE_ONCE(vdso_k_rng_data->is_ready, true);
|
||||
wake_up_interruptible(&crng_init_wait);
|
||||
kill_fasync(&fasync, SIGIO, POLL_IN);
|
||||
@@ -934,6 +1285,10 @@ void add_device_randomness(const void *b
|
||||
_mix_pool_bytes(&entropy, sizeof(entropy));
|
||||
_mix_pool_bytes(buf, len);
|
||||
spin_unlock_irqrestore(&input_pool.lock, flags);
|
||||
+#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS
|
||||
+ if (READ_ONCE(random_bytes_cb_live))
|
||||
+ (void)call_mix_pool_bytes_cb(buf, len);
|
||||
+#endif
|
||||
}
|
||||
EXPORT_SYMBOL(add_device_randomness);
|
||||
|
||||
@@ -1392,7 +1747,7 @@ SYSCALL_DEFINE3(getrandom, char __user *
|
||||
if ((flags & (GRND_INSECURE | GRND_RANDOM)) == (GRND_INSECURE | GRND_RANDOM))
|
||||
return -EINVAL;
|
||||
|
||||
- if (!crng_ready() && !(flags & GRND_INSECURE)) {
|
||||
+ if (!crng_ready_maybe_cb() && !(flags & GRND_INSECURE)) {
|
||||
if (flags & GRND_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
ret = wait_for_random_bytes();
|
||||
@@ -1408,6 +1763,10 @@ SYSCALL_DEFINE3(getrandom, char __user *
|
||||
|
||||
static __poll_t random_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
+#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS
|
||||
+ if (crng_ready_by_cb())
|
||||
+ return EPOLLIN | EPOLLRDNORM;
|
||||
+#endif
|
||||
poll_wait(file, &crng_init_wait, wait);
|
||||
return crng_ready() ? EPOLLIN | EPOLLRDNORM : EPOLLOUT | EPOLLWRNORM;
|
||||
}
|
||||
@@ -1453,10 +1812,10 @@ static ssize_t urandom_read_iter(struct
|
||||
* Opportunistically attempt to initialize the RNG on platforms that
|
||||
* have fast cycle counters, but don't (for now) require it to succeed.
|
||||
*/
|
||||
- if (!crng_ready())
|
||||
+ if (!crng_ready_maybe_cb())
|
||||
try_to_generate_entropy();
|
||||
|
||||
- if (!crng_ready()) {
|
||||
+ if (!crng_ready_maybe_cb()) {
|
||||
if (!ratelimit_disable && maxwarn <= 0)
|
||||
ratelimit_state_inc_miss(&urandom_warning);
|
||||
else if (ratelimit_disable || __ratelimit(&urandom_warning)) {
|
||||
@@ -1473,7 +1832,7 @@ static ssize_t random_read_iter(struct k
|
||||
{
|
||||
int ret;
|
||||
|
||||
- if (!crng_ready() &&
|
||||
+ if (!crng_ready_by_cb() &&
|
||||
((kiocb->ki_flags & (IOCB_NOWAIT | IOCB_NOIO)) ||
|
||||
(kiocb->ki_filp->f_flags & O_NONBLOCK)))
|
||||
return -EAGAIN;
|
||||
@@ -1538,6 +1897,14 @@ static long random_ioctl(struct file *f,
|
||||
case RNDRESEEDCRNG:
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
+#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS
|
||||
+ /* continue to reseed native crng too. */
|
||||
+ if (call_crng_reseed_cb() == 0) {
|
||||
+ if (crng_ready())
|
||||
+ crng_reseed(NULL);
|
||||
+ return 0;
|
||||
+ }
|
||||
+#endif
|
||||
if (!crng_ready())
|
||||
return -ENODATA;
|
||||
crng_reseed(NULL);
|
||||
--- 7.3/include/linux/random.h.dist 2026-09-07 15:16:52.000000000 -0500
|
||||
+++ 7.3/include/linux/random.h 2026-09-08 14:52:45.063663933 -0500
|
||||
@@ -139,4 +139,37 @@ int random_online_cpu(unsigned int cpu);
|
||||
extern const struct file_operations random_fops, urandom_fops;
|
||||
#endif
|
||||
|
||||
+#ifndef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS
|
||||
+ #define WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS 1
|
||||
+#endif
|
||||
+
|
||||
+typedef int (*_get_random_bytes_cb_t)(void *buf, size_t len);
|
||||
+struct iov_iter;
|
||||
+/* kernels >= 5.17.0 use get_random_bytes_user() */
|
||||
+typedef ssize_t (*get_random_bytes_user_cb_t)(struct iov_iter *iter);
|
||||
+/* kernels < 5.17.0 use extract_crng_user(), though some LTS kernels,
|
||||
+ * e.g. 5.10.236, have the 5.17+ architecture backported.
|
||||
+ */
|
||||
+typedef ssize_t (*extract_crng_user_cb_t)(void __user *buf, size_t nbytes);
|
||||
+typedef bool (*crng_ready_cb_t)(void);
|
||||
+typedef int (*mix_pool_bytes_cb_t)(const void *buf, size_t len);
|
||||
+typedef int (*credit_init_bits_cb_t)(size_t bits);
|
||||
+typedef int (*crng_reseed_cb_t)(void);
|
||||
+
|
||||
+struct wolfssl_linuxkm_random_bytes_handlers {
|
||||
+ _get_random_bytes_cb_t _get_random_bytes;
|
||||
+ get_random_bytes_user_cb_t get_random_bytes_user;
|
||||
+ extract_crng_user_cb_t extract_crng_user;
|
||||
+ crng_ready_cb_t crng_ready;
|
||||
+ mix_pool_bytes_cb_t mix_pool_bytes;
|
||||
+ credit_init_bits_cb_t credit_init_bits;
|
||||
+ crng_reseed_cb_t crng_reseed;
|
||||
+};
|
||||
+
|
||||
+int wolfssl_linuxkm_register_random_bytes_handlers(
|
||||
+ struct module *new_random_bytes_cb_owner,
|
||||
+ const struct wolfssl_linuxkm_random_bytes_handlers *handlers);
|
||||
+
|
||||
+int wolfssl_linuxkm_unregister_random_bytes_handlers(void);
|
||||
+
|
||||
#endif /* _LINUX_RANDOM_H */
|
||||
@@ -204,16 +204,24 @@ static void wb_hash_drbg_init_df_chain(void)
|
||||
/* Vector (F, -): the first Hash_df fails on its very first primitive
|
||||
* call, so the && short-circuits and never calls the second one. */
|
||||
mcdc_fh_arm(1);
|
||||
(void)Hash_DRBG_Instantiate(&drbg, seed, (word32)sizeof(seed),
|
||||
ret = Hash_DRBG_Instantiate(&drbg, seed, (word32)sizeof(seed),
|
||||
nonce, (word32)sizeof(nonce), NULL, 0, NULL, INVALID_DEVID);
|
||||
if (ret == DRBG_SUCCESS) {
|
||||
WB_NOTE("armed Hash_DRBG_Instantiate unexpectedly succeeded");
|
||||
wb_fail = 1;
|
||||
}
|
||||
mcdc_fh_disarm();
|
||||
(void)Hash_DRBG_Uninstantiate(&drbg);
|
||||
|
||||
/* Vector (T, F): the first Hash_df's n1 primitive calls all succeed;
|
||||
* every call from n1+1 on -- the whole second Hash_df -- fails. */
|
||||
mcdc_fh_arm(n1 + 1);
|
||||
(void)Hash_DRBG_Instantiate(&drbg, seed, (word32)sizeof(seed),
|
||||
ret = Hash_DRBG_Instantiate(&drbg, seed, (word32)sizeof(seed),
|
||||
nonce, (word32)sizeof(nonce), NULL, 0, NULL, INVALID_DEVID);
|
||||
if (ret == DRBG_SUCCESS) {
|
||||
WB_NOTE("armed Hash_DRBG_Instantiate unexpectedly succeeded");
|
||||
wb_fail = 1;
|
||||
}
|
||||
mcdc_fh_disarm();
|
||||
(void)Hash_DRBG_Uninstantiate(&drbg);
|
||||
|
||||
@@ -270,15 +278,23 @@ static void wb_hash512_drbg_init_df_chain(void)
|
||||
|
||||
/* Vector (F, -). */
|
||||
mcdc_fh_arm(1);
|
||||
(void)Hash512_DRBG_Instantiate(&drbg, seed, (word32)sizeof(seed),
|
||||
ret = Hash512_DRBG_Instantiate(&drbg, seed, (word32)sizeof(seed),
|
||||
nonce, (word32)sizeof(nonce), NULL, 0, NULL, INVALID_DEVID);
|
||||
if (ret == DRBG_SUCCESS) {
|
||||
WB_NOTE("armed Hash512_DRBG_Instantiate unexpectedly succeeded");
|
||||
wb_fail = 1;
|
||||
}
|
||||
mcdc_fh_disarm();
|
||||
(void)Hash512_DRBG_Uninstantiate(&drbg);
|
||||
|
||||
/* Vector (T, F). */
|
||||
mcdc_fh_arm(n1 + 1);
|
||||
(void)Hash512_DRBG_Instantiate(&drbg, seed, (word32)sizeof(seed),
|
||||
ret = Hash512_DRBG_Instantiate(&drbg, seed, (word32)sizeof(seed),
|
||||
nonce, (word32)sizeof(nonce), NULL, 0, NULL, INVALID_DEVID);
|
||||
if (ret == DRBG_SUCCESS) {
|
||||
WB_NOTE("armed Hash512_DRBG_Instantiate unexpectedly succeeded");
|
||||
wb_fail = 1;
|
||||
}
|
||||
mcdc_fh_disarm();
|
||||
(void)Hash512_DRBG_Uninstantiate(&drbg);
|
||||
|
||||
|
||||
@@ -300,7 +300,7 @@ static void wb_hash_drbg_generate_reseed(void)
|
||||
|
||||
/* False side: reseedCtr below the interval -> generate proceeds. */
|
||||
drbg.reseedCtr = 1;
|
||||
ret = Hash_DRBG_Generate(&drbg, out, (word32)sizeof(out), NULL, 0);
|
||||
ret = Hash_DRBG_Generate(&drbg, out, (word32)sizeof(out), NULL, 0, NULL);
|
||||
if (ret != DRBG_SUCCESS) {
|
||||
WB_NOTE("Hash_DRBG_Generate (below interval) failed");
|
||||
wb_fail = 1;
|
||||
@@ -308,7 +308,7 @@ static void wb_hash_drbg_generate_reseed(void)
|
||||
|
||||
/* True side: reseedCtr at the interval -> early DRBG_NEED_RESEED. */
|
||||
drbg.reseedCtr = WC_RESEED_INTERVAL;
|
||||
ret = Hash_DRBG_Generate(&drbg, out, (word32)sizeof(out), NULL, 0);
|
||||
ret = Hash_DRBG_Generate(&drbg, out, (word32)sizeof(out), NULL, 0, NULL);
|
||||
if (ret != DRBG_NEED_RESEED) {
|
||||
WB_NOTE("Hash_DRBG_Generate did not signal DRBG_NEED_RESEED");
|
||||
wb_fail = 1;
|
||||
@@ -448,14 +448,14 @@ static void wb_hash512_drbg_generate_reseed(void)
|
||||
}
|
||||
|
||||
drbg.reseedCtr = 1; /* false side */
|
||||
ret = Hash512_DRBG_Generate(&drbg, out, (word32)sizeof(out), NULL, 0);
|
||||
ret = Hash512_DRBG_Generate(&drbg, out, (word32)sizeof(out), NULL, 0, NULL);
|
||||
if (ret != DRBG_SUCCESS) {
|
||||
WB_NOTE("Hash512_DRBG_Generate (below interval) failed");
|
||||
wb_fail = 1;
|
||||
}
|
||||
|
||||
drbg.reseedCtr = WC_RESEED_INTERVAL; /* true side */
|
||||
ret = Hash512_DRBG_Generate(&drbg, out, (word32)sizeof(out), NULL, 0);
|
||||
ret = Hash512_DRBG_Generate(&drbg, out, (word32)sizeof(out), NULL, 0, NULL);
|
||||
if (ret != DRBG_NEED_RESEED) {
|
||||
WB_NOTE("Hash512_DRBG_Generate did not signal DRBG_NEED_RESEED");
|
||||
wb_fail = 1;
|
||||
|
||||
@@ -1436,6 +1436,17 @@ int wc_curve25519_set_rng(curve25519_key* key, WC_RNG* rng)
|
||||
key->rng = rng;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Companion to wc_curve25519_set_rng(): detach the key's RNG association.
|
||||
* Subsequent blinded operations then fail in the RNG service (BAD_FUNC_ARG
|
||||
* on the NULL WC_RNG) until a new one is set. */
|
||||
int wc_curve25519_clear_rng(curve25519_key* key)
|
||||
{
|
||||
if (key == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
key->rng = NULL;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* get key size */
|
||||
|
||||
@@ -15101,6 +15101,28 @@ int wc_ecc_set_rng(ecc_key* key, WC_RNG* rng)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Companion to wc_ecc_set_rng(): detach the key's RNG association.
|
||||
* Subsequent operations that require the key's RNG then fail with
|
||||
* MISSING_RNG_E until a new one is set. */
|
||||
int wc_ecc_clear_rng(ecc_key* key)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
#ifdef ECC_TIMING_RESISTANT
|
||||
if (key == NULL) {
|
||||
err = BAD_FUNC_ARG;
|
||||
}
|
||||
else {
|
||||
key->rng = NULL;
|
||||
}
|
||||
#else
|
||||
(void)key;
|
||||
/* report success, not an error if ECC_TIMING_RESISTANT is not defined */
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ECC_ENCRYPT
|
||||
|
||||
|
||||
@@ -15760,6 +15782,9 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
||||
/* Device for the ECIES callback and the KDF/AES/HMAC steps. It comes
|
||||
* only from the context; unset means software, or the CB_FIND finder. */
|
||||
int eciesDevId = INVALID_DEVID;
|
||||
#ifdef ECC_TIMING_RESISTANT
|
||||
int lentRng = 0; /* ctx->rng lent to privKey for this op */
|
||||
#endif
|
||||
|
||||
if (privKey == NULL || pubKey == NULL || msg == NULL || out == NULL ||
|
||||
outSz == NULL)
|
||||
@@ -15848,8 +15873,14 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
||||
return BUFFER_E;
|
||||
|
||||
#ifdef ECC_TIMING_RESISTANT
|
||||
if (ctx->rng != NULL && privKey->rng == NULL)
|
||||
if (ctx->rng != NULL && privKey->rng == NULL) {
|
||||
/* Lend the ctx's RNG to the key for the duration of this operation
|
||||
* only. Restored to NULL before every subsequent return, so no
|
||||
* borrowed pointer survives on the caller's key object after the
|
||||
* call. */
|
||||
privKey->rng = ctx->rng;
|
||||
lentRng = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef WOLFSSL_ECIES_OLD
|
||||
@@ -15859,23 +15890,42 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
||||
#else
|
||||
ret = wc_ecc_make_pub_ex(privKey, NULL, NULL);
|
||||
#endif
|
||||
if (ret != 0)
|
||||
if (ret != 0) {
|
||||
#ifdef ECC_TIMING_RESISTANT
|
||||
if (lentRng)
|
||||
privKey->rng = NULL;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = wc_ecc_export_x963_ex(privKey, out, &pubKeySz, compressed);
|
||||
if (ret != 0)
|
||||
if (ret != 0) {
|
||||
#ifdef ECC_TIMING_RESISTANT
|
||||
if (lentRng)
|
||||
privKey->rng = NULL;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
out += pubKeySz;
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
sharedSecret = (byte*)XMALLOC(sharedSz, ctx->heap, DYNAMIC_TYPE_ECC_BUFFER);
|
||||
if (sharedSecret == NULL)
|
||||
if (sharedSecret == NULL) {
|
||||
#ifdef ECC_TIMING_RESISTANT
|
||||
if (lentRng)
|
||||
privKey->rng = NULL;
|
||||
#endif
|
||||
return MEMORY_E;
|
||||
}
|
||||
|
||||
keys = (byte*)XMALLOC(ECC_BUFSIZE, ctx->heap, DYNAMIC_TYPE_ECC_BUFFER);
|
||||
if (keys == NULL) {
|
||||
XFREE(sharedSecret, ctx->heap, DYNAMIC_TYPE_ECC_BUFFER);
|
||||
#ifdef ECC_TIMING_RESISTANT
|
||||
if (lentRng)
|
||||
privKey->rng = NULL;
|
||||
#endif
|
||||
return MEMORY_E;
|
||||
}
|
||||
#endif
|
||||
@@ -16160,6 +16210,11 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
||||
WC_FREE_VAR_EX(sharedSecret, ctx->heap, DYNAMIC_TYPE_ECC_BUFFER);
|
||||
WC_FREE_VAR_EX(keys, ctx->heap, DYNAMIC_TYPE_ECC_BUFFER);
|
||||
|
||||
#ifdef ECC_TIMING_RESISTANT
|
||||
if (lentRng)
|
||||
privKey->rng = NULL;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -16218,6 +16273,9 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
||||
/* Device for the ECIES callback and the KDF/AES/HMAC steps. It comes
|
||||
* only from the context; unset means software, or the CB_FIND finder. */
|
||||
int eciesDevId = INVALID_DEVID;
|
||||
#ifdef ECC_TIMING_RESISTANT
|
||||
int lentRng = 0; /* ctx->rng lent to privKey for this op */
|
||||
#endif
|
||||
|
||||
|
||||
if (privKey == NULL || msg == NULL || out == NULL || outSz == NULL)
|
||||
@@ -16347,8 +16405,14 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
||||
}
|
||||
|
||||
#ifdef ECC_TIMING_RESISTANT
|
||||
if (ctx->rng != NULL && privKey->rng == NULL)
|
||||
if (ctx->rng != NULL && privKey->rng == NULL) {
|
||||
/* Lend the ctx's RNG to the key for the duration of this operation
|
||||
* only. Restored to NULL before every subsequent return, so no
|
||||
* borrowed pointer survives on the caller's key object after the
|
||||
* call. */
|
||||
privKey->rng = ctx->rng;
|
||||
lentRng = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
@@ -16357,6 +16421,10 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
||||
#ifndef WOLFSSL_ECIES_OLD
|
||||
if (pubKey == peerKey)
|
||||
wc_ecc_free(peerKey);
|
||||
#endif
|
||||
#ifdef ECC_TIMING_RESISTANT
|
||||
if (lentRng)
|
||||
privKey->rng = NULL;
|
||||
#endif
|
||||
return MEMORY_E;
|
||||
}
|
||||
@@ -16367,6 +16435,10 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
||||
#ifndef WOLFSSL_ECIES_OLD
|
||||
if (pubKey == peerKey)
|
||||
wc_ecc_free(peerKey);
|
||||
#endif
|
||||
#ifdef ECC_TIMING_RESISTANT
|
||||
if (lentRng)
|
||||
privKey->rng = NULL;
|
||||
#endif
|
||||
return MEMORY_E;
|
||||
}
|
||||
@@ -16675,6 +16747,11 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
||||
XFREE(keys, ctx->heap, DYNAMIC_TYPE_ECC_BUFFER);
|
||||
#endif
|
||||
|
||||
#ifdef ECC_TIMING_RESISTANT
|
||||
if (lentRng)
|
||||
privKey->rng = NULL;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -760,6 +760,12 @@ const char* wc_GetErrorString(int error)
|
||||
case WRONG_TYPE_OBJECT_E:
|
||||
return "Object is wrong type for requested operation";
|
||||
|
||||
case NEEDS_RECOVERY_E:
|
||||
return "Object needs recovery before use";
|
||||
|
||||
case UNEXPECTED_STATE_E:
|
||||
return "Object has unexpected state";
|
||||
|
||||
case MAX_CODE_E:
|
||||
case WC_SPAN1_MIN_CODE_E:
|
||||
case MIN_CODE_E:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -6171,6 +6171,20 @@ int wc_RsaSetRNG(RsaKey* key, WC_RNG* rng)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Companion to wc_RsaSetRNG(): detach the key's RNG association.
|
||||
* Subsequent operations that require the key's RNG (blinding, pairwise
|
||||
* consistency) then either fail with MISSING_RNG_E or fall back to a
|
||||
* locally instantiated RNG, per operation, until a new RNG is set. */
|
||||
int wc_RsaClearRNG(RsaKey* key)
|
||||
{
|
||||
if (key == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
key->rng = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* !WC_NO_RNG */
|
||||
|
||||
#ifdef WC_RSA_NONBLOCK
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -75,7 +75,7 @@ wc_static_assert(-(long)MIN_CODE_E < 0x7ffL);
|
||||
#define WC_TEST_RET_ENC_NC WC_TEST_RET_ENC(WC_TEST_RET_LN, 0, WC_TEST_RET_TAG_NC)
|
||||
|
||||
/* encode positive integer */
|
||||
#define WC_TEST_RET_ENC_I(i) WC_TEST_RET_ENC(WC_TEST_RET_LN, i, WC_TEST_RET_TAG_I)
|
||||
#define WC_TEST_RET_ENC_I(i) WC_TEST_RET_ENC(WC_TEST_RET_LN, ((i) > 0x7ff) ? 0x7ff : (i), WC_TEST_RET_TAG_I)
|
||||
|
||||
/* encode error code (negative integer) */
|
||||
#define WC_TEST_RET_ENC_EC(ec) WC_TEST_RET_ENC(WC_TEST_RET_LN, -(ec), WC_TEST_RET_TAG_EC)
|
||||
@@ -114,6 +114,10 @@ wc_static_assert(-(long)MIN_CODE_E < 0x7ffL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Note, all macro gates used below must be available with just
|
||||
* wolfcrypt/types.h included, i.e. no macros in alg-specific headers can be
|
||||
* used here.
|
||||
*/
|
||||
extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t macro_test(void);
|
||||
extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t error_test(void);
|
||||
extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t octets_test(void);
|
||||
@@ -255,6 +259,14 @@ extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void);
|
||||
#ifdef WC_RNG_BANK_SUPPORT
|
||||
extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void);
|
||||
#endif
|
||||
#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_entropy_invalidate_test(void);
|
||||
extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_drbg_nextseedstest(void);
|
||||
extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rng_pool_test(void);
|
||||
#endif /* WC_NO_RNG */
|
||||
extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pwdbased_test(void);
|
||||
#if defined(USE_CERT_BUFFERS_2048) && \
|
||||
|
||||
@@ -222,6 +222,8 @@ void wc_curve25519_free(curve25519_key* key);
|
||||
#ifdef WOLFSSL_CURVE25519_BLINDING
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_set_rng(curve25519_key* key, WC_RNG* rng);
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_clear_rng(curve25519_key* key);
|
||||
#endif
|
||||
|
||||
#ifndef WC_NO_CONSTRUCTORS
|
||||
|
||||
@@ -898,6 +898,8 @@ WOLFSSL_API
|
||||
void wc_ecc_fp_init(void);
|
||||
WOLFSSL_API
|
||||
int wc_ecc_set_rng(ecc_key* key, WC_RNG* rng);
|
||||
WOLFSSL_API
|
||||
int wc_ecc_clear_rng(ecc_key* key);
|
||||
|
||||
WOLFSSL_API
|
||||
int wc_ecc_set_curve(ecc_key* key, int keysize, int curve_id);
|
||||
|
||||
@@ -354,9 +354,11 @@ enum wolfCrypt_ErrorCodes {
|
||||
OBJECT_NOT_LOCKED_E = -1031, /* Required lock on object is not held */
|
||||
WRONG_TYPE_OBJECT_E = -1032, /* Object is wrong type for requested */
|
||||
/* operation */
|
||||
NEEDS_RECOVERY_E = -1033, /* Object needs recovery before use */
|
||||
UNEXPECTED_STATE_E = -1034, /* Object has unexpected state */
|
||||
|
||||
WC_SPAN2_LAST_E = -1032, /* Update to indicate last used error code */
|
||||
WC_LAST_E = -1032, /* the last code used either here or in
|
||||
WC_SPAN2_LAST_E = -1034, /* Update to indicate last used error code */
|
||||
WC_LAST_E = -1034, /* the last code used either here or in
|
||||
* error-ssl.h */
|
||||
|
||||
WC_SPAN2_MIN_CODE_E = -1999, /* Last usable code in span 2 */
|
||||
|
||||
@@ -43,6 +43,87 @@
|
||||
WOLFSSL_LOCAL int wolfCrypt_FIPS_DRBG_sanity(void);
|
||||
#endif
|
||||
|
||||
/***** Setup for RNG extra features *****/
|
||||
|
||||
#if (defined(WC_RNG_EXTRAS) || defined(WC_RNG_WANT_LOCK)) && \
|
||||
!defined(WC_RNG_NO_LOCK)
|
||||
#define WC_RNG_HAVE_LOCK
|
||||
#ifdef WOLFSSL_NO_ATOMICS
|
||||
typedef word32 WC_RNG_lock_t;
|
||||
typedef word32 WC_RNG_lock_arg_t;
|
||||
#else
|
||||
typedef wolfSSL_Atomic_Uint WC_RNG_lock_t;
|
||||
typedef WC_ATOMIC_UINT_ARG WC_RNG_lock_arg_t;
|
||||
#endif
|
||||
#else
|
||||
#undef WC_RNG_HAVE_LOCK
|
||||
#endif
|
||||
|
||||
#ifdef WC_RNG_WANT_LOCK_FULL_MUTEX
|
||||
#ifndef WC_RNG_HAVE_LOCK
|
||||
#error FULL_MUTEX depends on WC_RNG_HAVE_LOCK.
|
||||
#endif
|
||||
#define WC_RNG_HAVE_LOCK_FULL_MUTEX
|
||||
#else
|
||||
#undef WC_RNG_HAVE_LOCK_FULL_MUTEX
|
||||
#endif
|
||||
|
||||
#if (defined(WC_RNG_EXTRAS) || defined(WC_RNG_WANT_RBGC)) && \
|
||||
!defined(WC_RNG_NO_RBGC) && defined(HAVE_HASHDRBG) && \
|
||||
!defined(CUSTOM_RAND_GENERATE_BLOCK)
|
||||
#define WC_RNG_HAVE_RBGC
|
||||
#else
|
||||
#undef WC_RNG_HAVE_RBGC
|
||||
#endif
|
||||
|
||||
#if (defined(WC_RNG_EXTRAS) || defined(WC_RNG_WANT_NEXT_SEED)) && \
|
||||
!defined(WC_RNG_NO_NEXT_SEED) && defined(HAVE_HASHDRBG) && \
|
||||
!defined(CUSTOM_RAND_GENERATE_BLOCK)
|
||||
#define WC_RNG_HAVE_NEXT_SEED
|
||||
#ifdef WOLFSSL_NO_ATOMICS
|
||||
typedef sword32 WC_DRBG_nextSeedLen_t;
|
||||
#else
|
||||
typedef wolfSSL_Atomic_Int WC_DRBG_nextSeedLen_t;
|
||||
#endif
|
||||
#else
|
||||
#undef WC_RNG_HAVE_NEXT_SEED
|
||||
#endif
|
||||
#if defined(WC_RNG_HAVE_NEXT_SEED) && !defined(WC_RNG_HAVE_LOCK) && \
|
||||
defined(HAVE_FIPS)
|
||||
/* FIPS builds: pregenerated output requires the full invalidation/purge
|
||||
* protocol, which rides the lock facility. */
|
||||
#error WC_RNG_WANT_NEXT_SEED requires WC_RNG_WANT_LOCK in FIPS builds.
|
||||
#endif
|
||||
|
||||
#if (defined(WC_RNG_EXTRAS) || defined(WC_RNG_WANT_POOL)) && \
|
||||
!defined(WC_RNG_NO_POOL)
|
||||
#define WC_RNG_HAVE_POOL
|
||||
#ifdef WOLFSSL_NO_ATOMICS
|
||||
typedef word32 WC_RNG_pool_pos_t;
|
||||
#else
|
||||
typedef wolfSSL_Atomic_Uint WC_RNG_pool_pos_t;
|
||||
#endif
|
||||
#else
|
||||
#undef WC_RNG_HAVE_POOL
|
||||
#endif
|
||||
#if defined(WC_RNG_HAVE_POOL) && !defined(WC_RNG_HAVE_LOCK) && \
|
||||
defined(HAVE_FIPS)
|
||||
/* FIPS builds: pregenerated output requires the full invalidation/purge
|
||||
* protocol, which rides the lock facility. */
|
||||
#error WC_RNG_WANT_POOL requires WC_RNG_WANT_LOCK in FIPS builds.
|
||||
#endif
|
||||
|
||||
#if (defined(WC_RNG_EXTRAS) || defined(WC_RNG_WANT_FREE_HOOK)) && \
|
||||
!defined(WC_RNG_NO_FREE_HOOK)
|
||||
#define WC_RNG_HAVE_FREE_HOOK
|
||||
struct WC_RNG;
|
||||
typedef int (*wc_RNG_free_hook_cb_t)(const struct WC_RNG *rng, void *arg);
|
||||
#else
|
||||
#undef WC_RNG_HAVE_FREE_HOOK
|
||||
#endif
|
||||
|
||||
/***** End setup for RNG extra features *****/
|
||||
|
||||
/* Maximum generate block length */
|
||||
#ifndef RNG_MAX_BLOCK_LEN
|
||||
#ifdef HAVE_INTEL_QA
|
||||
@@ -73,7 +154,7 @@
|
||||
#undef HAVE_HASHDRBG
|
||||
#define HAVE_HASHDRBG
|
||||
#ifndef WC_RESEED_INTERVAL
|
||||
#define WC_RESEED_INTERVAL (1000000)
|
||||
#define WC_RESEED_INTERVAL 1000000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -295,15 +376,37 @@ struct OS_Seed {
|
||||
#define RNG_HEALTH_TEST_CHECK_SIZE_SHA512 (WC_SHA512_DIGEST_SIZE * 4)
|
||||
#endif
|
||||
|
||||
#ifdef WC_RNG_HAVE_NEXT_SEED
|
||||
/* Length of the banked next seed: identical byte accounting to other
|
||||
* source-fed (re)seeds in the module (gather SEED_SZ + SEED_BLOCK_SZ, apply
|
||||
* the block-offset remainder). */
|
||||
#define WC_DRBG_NEXT_SEED_LEN (WC_DRBG_SEED_SZ + WC_DRBG_SEED_BLOCK_SZ)
|
||||
#define WC_DRBG_NEXT_STIR_LEN 64
|
||||
#endif
|
||||
|
||||
#ifndef WC_DRBG_RESEED_CTR_TYPE_DEFINED
|
||||
#define WC_DRBG_RESEED_CTR_TYPE_DEFINED
|
||||
#ifdef WORD64_AVAILABLE
|
||||
typedef word64 wc_drbg_reseed_ctr_t;
|
||||
#else
|
||||
typedef word32 wc_drbg_reseed_ctr_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NO_SHA256
|
||||
struct DRBG_internal {
|
||||
#ifdef WORD64_AVAILABLE
|
||||
word64 reseedCtr;
|
||||
#else
|
||||
word32 reseedCtr;
|
||||
#endif
|
||||
wc_drbg_reseed_ctr_t reseedCtr;
|
||||
byte V[DRBG_SEED_LEN];
|
||||
byte C[DRBG_SEED_LEN];
|
||||
#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
|
||||
byte nextStir[WC_DRBG_NEXT_STIR_LEN];
|
||||
WC_DRBG_nextSeedLen_t nextStirLen;
|
||||
#endif
|
||||
void* heap;
|
||||
#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
|
||||
int devId;
|
||||
@@ -318,9 +421,18 @@ struct DRBG_internal {
|
||||
|
||||
#ifdef WOLFSSL_DRBG_SHA512
|
||||
struct DRBG_SHA512_internal {
|
||||
word64 reseedCtr;
|
||||
wc_drbg_reseed_ctr_t reseedCtr;
|
||||
byte V[DRBG_SHA512_SEED_LEN];
|
||||
byte C[DRBG_SHA512_SEED_LEN];
|
||||
#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
|
||||
byte nextStir[WC_DRBG_NEXT_STIR_LEN];
|
||||
WC_DRBG_nextSeedLen_t nextStirLen;
|
||||
#endif
|
||||
void* heap;
|
||||
#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
|
||||
int devId;
|
||||
@@ -347,29 +459,100 @@ enum wc_RngHealthState {
|
||||
WC_DRBG_NOT_INIT = 0,
|
||||
WC_DRBG_OK = 1,
|
||||
WC_DRBG_FAILED = 2,
|
||||
WC_DRBG_CONT_FAILED = 3,
|
||||
#ifdef WC_RNG_BANK_SUPPORT
|
||||
WC_DRBG_BANKREF = 4, /* Marks the WC_RNG as a ref to a wc_rng_bank,
|
||||
* with no usable DRBG of its own.
|
||||
*/
|
||||
#define WC_HAVE_RNG_BANKREF
|
||||
#endif
|
||||
WOLF_ENUM_DUMMY_LAST_ELEMENT(wc_RngHealthState)
|
||||
WC_DRBG_CONT_FAILED = 3
|
||||
};
|
||||
|
||||
#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)
|
||||
#define WC_RNG_FLAG_RECOVER_AND_PROMOTE_FROM_NEXT_SEED (1U << 3)
|
||||
|
||||
#ifndef WC_RNG_RBGC_USER_SEED_STRATUM
|
||||
#define WC_RNG_RBGC_USER_SEED_STRATUM 65536
|
||||
#endif
|
||||
wc_static_assert(WC_RNG_RBGC_USER_SEED_STRATUM >= 256);
|
||||
|
||||
#ifdef WC_RNG_WANT_DEBUG_STATS
|
||||
#define WC_RNG_DEBUG_STATS
|
||||
#endif
|
||||
|
||||
#if defined(WC_RNG_DEBUG_STATS) && !defined(WC_RNG_HAVE_LOCK)
|
||||
#error WC_RNG_DEBUG_STATS requires the RNG lock facility (WC_RNG_WANT_LOCK).
|
||||
#endif
|
||||
|
||||
#ifdef WC_RNG_DEBUG_STATS
|
||||
#ifdef WORD64_AVAILABLE
|
||||
typedef word64 wc_rng_debug_counter_t;
|
||||
#else
|
||||
typedef word32 wc_rng_debug_counter_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* RNG context */
|
||||
struct WC_RNG {
|
||||
struct OS_Seed seed;
|
||||
void* heap;
|
||||
byte status;
|
||||
word32 flags;
|
||||
#ifdef WC_RNG_DEBUG_STATS
|
||||
wc_rng_debug_counter_t _stats_total_bytes_requested;
|
||||
wc_rng_debug_counter_t _stats_total_bytes_produced;
|
||||
wc_rng_debug_counter_t _stats_total_requests;
|
||||
wc_rng_debug_counter_t _stats_reseeds;
|
||||
wc_rng_debug_counter_t _stats_stirs;
|
||||
wc_rng_debug_counter_t _stats_seed_failures;
|
||||
#endif
|
||||
#ifdef WC_RNG_HAVE_RBGC
|
||||
int RBGCStratum;
|
||||
#ifdef WC_RNG_DEBUG_STATS
|
||||
wc_rng_debug_counter_t _stats_RBGC_bytes_produced;
|
||||
wc_rng_debug_counter_t _stats_RBGC_reseeds;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef WC_RNG_HAVE_LOCK
|
||||
WC_RNG_lock_t lock;
|
||||
#ifdef WC_RNG_HAVE_LOCK_FULL_MUTEX
|
||||
wolfSSL_Mutex mutex;
|
||||
#endif
|
||||
#ifdef WC_RNG_DEBUG_STATS
|
||||
wc_rng_debug_counter_t _stats_locks_taken;
|
||||
wc_rng_debug_counter_t _stats_locks_released;
|
||||
wc_rng_debug_counter_t _stats_locks_refused; /* racy */
|
||||
#endif
|
||||
#endif
|
||||
#ifdef WC_RNG_HAVE_FREE_HOOK
|
||||
wc_RNG_free_hook_cb_t free_hook;
|
||||
void *free_hook_arg;
|
||||
#endif
|
||||
#ifdef WC_RNG_HAVE_POOL
|
||||
byte* pool;
|
||||
word16 poolSize;
|
||||
WC_RNG_pool_pos_t poolHead; /* written by writer/purger only, CAS */
|
||||
WC_RNG_pool_pos_t poolTail; /* written by reader only, plain. */
|
||||
#ifdef WC_RNG_DEBUG_STATS
|
||||
wc_rng_debug_counter_t _stats_pool_bytes_produced;
|
||||
wc_rng_debug_counter_t _stats_pool_bytes_missed;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(WC_RNG_BANK_SUPPORT) || defined(HAVE_HASHDRBG)
|
||||
#ifdef WC_RNG_DEBUG_STATS
|
||||
#ifdef WC_RNG_HAVE_NEXT_SEED
|
||||
wc_rng_debug_counter_t _stats_nextseedsprimary_redeemed;
|
||||
wc_rng_debug_counter_t _stats_nextseedsRBGC_redeemed;
|
||||
wc_rng_debug_counter_t _stats_nextstirs_redeemed;
|
||||
wc_rng_debug_counter_t _stats_nextseedsbanked;
|
||||
wc_rng_debug_counter_t _stats_nextstirs_banked;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_HASHDRBG) || defined(WC_HAVE_RNG_BANKREF)
|
||||
|
||||
#ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES
|
||||
union {
|
||||
#endif
|
||||
|
||||
#ifdef WC_RNG_BANK_SUPPORT
|
||||
#ifdef WC_HAVE_RNG_BANKREF
|
||||
struct wc_rng_bank *bankref;
|
||||
#endif
|
||||
|
||||
@@ -415,7 +598,7 @@ struct WC_RNG {
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* WC_RNG_BANK_SUPPORT || HAVE_HASHDRBG */
|
||||
#endif /* HAVE_HASHDRBG || WC_HAVE_RNG_BANKREF */
|
||||
|
||||
#if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID)
|
||||
pid_t pid;
|
||||
@@ -554,8 +737,25 @@ WOLFSSL_ABI WOLFSSL_API void wc_rng_free(WC_RNG* rng);
|
||||
#ifndef WC_NO_RNG
|
||||
WOLFSSL_ABI WOLFSSL_API int wc_InitRng(WC_RNG* rng);
|
||||
WOLFSSL_API int wc_InitRng_ex(WC_RNG* rng, void* heap, int devId);
|
||||
WOLFSSL_API int wc_InitRngNonce(WC_RNG* rng, byte* nonce, word32 nonceSz);
|
||||
WOLFSSL_API int wc_InitRngNonce_ex(WC_RNG* rng, byte* nonce, word32 nonceSz,
|
||||
WOLFSSL_API int wc_InitRngNonce(WC_RNG* rng, const byte* nonce, word32 nonceSz);
|
||||
|
||||
#define WC_RNG_INIT_FLAG_NONE 0
|
||||
#define WC_RNG_INIT_FLAG_LOCK_REQUIRED (1U << 0)
|
||||
#define WC_RNG_INIT_FLAG_LOCK_INITIALLY (1U << 1)
|
||||
#define WC_RNG_INIT_FLAG_USE_FULL_MUTEX (1U << 2)
|
||||
/* At each generate, if a banked next seed is READY, consume it when the
|
||||
* instance is flagged _ENTROPY_INVALIDATED (recovery; any provenance), or
|
||||
* when the instance is chain-backed and the banked seed is primary
|
||||
* (promotion). For externally-refreshed long-lived RNGs, e.g. the kernel
|
||||
* module's registered RBGC leaves. */
|
||||
#define WC_RNG_INIT_FLAG_RECOVER_AND_PROMOTE_FROM_NEXT_SEED (1U << 3)
|
||||
|
||||
WOLFSSL_API int wc_InitRng_ex2(WC_RNG* rng, void* heap, int devId,
|
||||
word32 flags);
|
||||
WOLFSSL_API int wc_InitRngNonce_ex2(WC_RNG* rng, const byte* nonce, word32 nonceSz,
|
||||
const byte *perso, word32 persoSz,
|
||||
void* heap, int devId, word32 flags);
|
||||
WOLFSSL_API int wc_InitRngNonce_ex(WC_RNG* rng, const byte* nonce, word32 nonceSz,
|
||||
void* heap, int devId);
|
||||
WOLFSSL_ABI WOLFSSL_API int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz);
|
||||
WOLFSSL_API int wc_RNG_GenerateByte(WC_RNG* rng, byte* b);
|
||||
@@ -566,6 +766,8 @@ WOLFSSL_API int wc_FreeRng(WC_RNG* rng);
|
||||
#define wc_InitRng_ex(rng, h, d) NOT_COMPILED_IN
|
||||
#define wc_InitRngNonce(rng, n, s) NOT_COMPILED_IN
|
||||
#define wc_InitRngNonce_ex(rng, n, s, h, d) NOT_COMPILED_IN
|
||||
#define wc_InitRng_ex2(rng, h, d, f) NOT_COMPILED_IN
|
||||
#define wc_InitRngNonce_ex2(rng, n, s, p, ps, h, d, f) NOT_COMPILED_IN
|
||||
#if defined(__ghs__) || defined(WC_NO_RNG_SIMPLE)
|
||||
/* some older compilers do not like macro function in expression */
|
||||
#define wc_RNG_GenerateBlock(rng, b, s) NOT_COMPILED_IN
|
||||
@@ -585,10 +787,35 @@ WOLFSSL_API int wc_FreeRng(WC_RNG* rng);
|
||||
WOLFSSL_API int wc_SetSeed_Cb(wc_RngSeed_Cb cb);
|
||||
#endif
|
||||
|
||||
WOLFSSL_API int wc_RNG_GetStatus(const WC_RNG* rng);
|
||||
WOLFSSL_API int wc_RNG_DRBG_Present(const WC_RNG* rng);
|
||||
|
||||
#ifdef HAVE_HASHDRBG
|
||||
WOLFSSL_API int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* seed,
|
||||
word32 seedSz);
|
||||
WOLFSSL_API int wc_RNG_DRBG_Reseed_Nonce(WC_RNG* rng, const byte* seed,
|
||||
word32 seedSz, const byte *nonce,
|
||||
word32 nonceSz);
|
||||
WOLFSSL_API int wc_RNG_DRBG_Stir(WC_RNG* rng,
|
||||
const byte* seed,
|
||||
word32 seedSz);
|
||||
WOLFSSL_API int wc_RNG_DRBG_Stir_Nonce(
|
||||
WC_RNG* rng, const byte* seed, word32 seedSz,
|
||||
const byte *nonce, word32 nonceSz);
|
||||
WOLFSSL_API int wc_RNG_DRBG_Reseed_Now(WC_RNG* rng, const byte* nonce,
|
||||
word32 nonceSz);
|
||||
WOLFSSL_API int wc_RNG_TestSeed(const byte* seed, word32 seedSz);
|
||||
|
||||
#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);
|
||||
|
||||
#ifndef NO_SHA256
|
||||
/* SHA-256 Hash_DRBG health test entry points. SHA-512-only builds
|
||||
* (NO_SHA256 + WOLFSSL_DRBG_SHA512) use wc_RNG_HealthTest_SHA512_ex
|
||||
@@ -697,6 +924,146 @@ WOLFSSL_API int wc_FreeRng(WC_RNG* rng);
|
||||
|
||||
#endif /* HAVE_HASHDRBG */
|
||||
|
||||
#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,
|
||||
const byte *perso, word32 persoSz,
|
||||
word32 flags);
|
||||
#ifndef WC_NO_CONSTRUCTORS
|
||||
/* Flags are per-object (WC_RNG_INIT_FLAG_*), 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,
|
||||
const byte *perso, word32 persoSz,
|
||||
word32 flags);
|
||||
#endif /* !WC_NO_CONSTRUCTORS */
|
||||
WOLFSSL_API int wc_RNG_DRBG_ReseedRBGC(WC_RNG* rng, WC_RNG* root,
|
||||
const byte* nonce, word32 nonceSz);
|
||||
WOLFSSL_API int wc_RNG_DRBG_StirRBGC(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
|
||||
/* All sentinel states are negative; non-negative values are banked byte
|
||||
* counts. */
|
||||
#define WC_DRBG_NEXT_SEED_PRODUCING (-1)
|
||||
#define WC_DRBG_NEXT_SEED_READY (-2)
|
||||
#define WC_DRBG_NEXT_SEED_CONSUMING (-3)
|
||||
#define WC_DRBG_NEXT_SEED_PURGED (-4)
|
||||
|
||||
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,
|
||||
const byte* nonce,
|
||||
word32 nonceSz);
|
||||
WOLFSSL_API int wc_RNG_DRBG_NextSeedNow(WC_RNG* rng);
|
||||
WOLFSSL_API int wc_RNG_DRBG_NextStirStore(WC_RNG* rng,
|
||||
const byte *nonce, word32 nonceSz);
|
||||
WOLFSSL_API int wc_RNG_DRBG_NextStirNow(WC_RNG* rng);
|
||||
|
||||
#endif /* WC_RNG_HAVE_NEXT_SEED */
|
||||
|
||||
#ifdef WC_RNG_HAVE_LOCK
|
||||
#define WC_RNG_LOCK_FREE 0
|
||||
#define WC_RNG_LOCK_HELD (1U<<0)
|
||||
#define WC_RNG_LOCK_REQUIRED (1U<<1)
|
||||
#define WC_RNG_LOCK_ENTROPY_INVALIDATED (1U<<2)
|
||||
#define WC_RNG_LOCK_ENTROPY_RECOVERING (1U<<3)
|
||||
/* consumers' annotation bits start here (see e.g. rng_bank.h) */
|
||||
#define WC_RNG_LOCK_EXTRA_SHIFT 4U
|
||||
|
||||
WOLFSSL_API int wc_RNG_lock_get(WC_RNG* rng, WC_RNG_lock_arg_t extra_bits);
|
||||
WOLFSSL_API int wc_RNG_lock_get_conditional(WC_RNG* rng,
|
||||
WC_RNG_lock_arg_t expected_extra_bits,
|
||||
WC_RNG_lock_arg_t want_extra_bits);
|
||||
WOLFSSL_API int wc_RNG_lock_put(WC_RNG* rng, WC_RNG_lock_arg_t extra_bits);
|
||||
WOLFSSL_API int wc_RNG_lock_put_conditional(WC_RNG* rng,
|
||||
WC_RNG_lock_arg_t expected_extra_bits,
|
||||
WC_RNG_lock_arg_t want_extra_bits);
|
||||
WOLFSSL_API int wc_RNG_lock_read(WC_RNG* rng, WC_RNG_lock_arg_t* state);
|
||||
WOLFSSL_API int wc_RNG_lock_set_extra(WC_RNG* rng,
|
||||
WC_RNG_lock_arg_t extra_bits);
|
||||
WOLFSSL_API int wc_RNG_lock_add_extra(WC_RNG* rng,
|
||||
WC_RNG_lock_arg_t extra_bits);
|
||||
WOLFSSL_API int wc_RNG_lock_clear_extra(WC_RNG* rng,
|
||||
WC_RNG_lock_arg_t extra_bits);
|
||||
#ifdef HAVE_HASHDRBG
|
||||
WOLFSSL_API int wc_RNG_invalidate_entropy(WC_RNG* rng);
|
||||
#endif
|
||||
#endif /* WC_RNG_HAVE_LOCK */
|
||||
|
||||
#ifdef WC_RNG_HAVE_FREE_HOOK
|
||||
/* Register a callback fired by wc_FreeRng() immediately before state
|
||||
* destruction, e.g. to unlink the object from an external registry.
|
||||
* One-shot: cleared before firing. A NULL free_hook unregisters.
|
||||
* Reinitialization (wc_InitRng*() on a live object) clears any
|
||||
* registered hook without firing it: hooks are per-lifetime. */
|
||||
WOLFSSL_API int wc_RNG_register_free_hook(WC_RNG* rng,
|
||||
wc_RNG_free_hook_cb_t free_hook,
|
||||
void *arg);
|
||||
#endif
|
||||
|
||||
#ifdef WC_RNG_HAVE_POOL
|
||||
WOLFSSL_API int wc_RNG_Pool_Alloc(WC_RNG* rng, word32 size);
|
||||
WOLFSSL_API int wc_RNG_Pool_Collect(WC_RNG* rng, word32 n);
|
||||
WOLFSSL_API int wc_RNG_Pool_Collect2(WC_RNG* rng_dest, WC_RNG* rng_src,
|
||||
word32 n);
|
||||
WOLFSSL_API int wc_RNG_Pool_Extract(WC_RNG* rng, byte* out, word32* n);
|
||||
WOLFSSL_API int wc_RNG_Pool_Current(WC_RNG* rng, word32* n);
|
||||
#endif /* WC_RNG_HAVE_POOL */
|
||||
|
||||
#ifdef WC_RNG_DEBUG_STATS
|
||||
struct wc_rng_debug_stats_snapshot {
|
||||
wc_rng_debug_counter_t _stats_total_bytes_requested;
|
||||
wc_rng_debug_counter_t _stats_total_bytes_produced;
|
||||
wc_rng_debug_counter_t _stats_total_requests;
|
||||
wc_rng_debug_counter_t _stats_reseeds;
|
||||
wc_rng_debug_counter_t _stats_stirs;
|
||||
wc_rng_debug_counter_t _stats_seed_failures;
|
||||
wc_rng_debug_counter_t _stats_locks_taken;
|
||||
wc_rng_debug_counter_t _stats_locks_released;
|
||||
wc_rng_debug_counter_t _stats_locks_refused;
|
||||
#ifdef WC_RNG_HAVE_RBGC
|
||||
wc_rng_debug_counter_t _stats_RBGC_bytes_produced;
|
||||
wc_rng_debug_counter_t _stats_RBGC_reseeds;
|
||||
#endif
|
||||
#ifdef WC_RNG_HAVE_POOL
|
||||
wc_rng_debug_counter_t _stats_pool_bytes_produced;
|
||||
wc_rng_debug_counter_t _stats_pool_bytes_missed;
|
||||
#endif
|
||||
#ifdef WC_RNG_HAVE_NEXT_SEED
|
||||
wc_rng_debug_counter_t _stats_nextseedsprimary_redeemed;
|
||||
wc_rng_debug_counter_t _stats_nextseedsRBGC_redeemed;
|
||||
wc_rng_debug_counter_t _stats_nextstirs_redeemed;
|
||||
wc_rng_debug_counter_t _stats_nextseedsbanked;
|
||||
wc_rng_debug_counter_t _stats_nextstirs_banked;
|
||||
#endif
|
||||
};
|
||||
|
||||
WOLFSSL_API int wc_rng_debug_stats_snap(struct wc_rng_debug_stats_snapshot *s,
|
||||
const WC_RNG *rng);
|
||||
WOLFSSL_API int wc_rng_debug_stats_restore(
|
||||
const struct wc_rng_debug_stats_snapshot *s,
|
||||
WC_RNG *rng);
|
||||
WOLFSSL_API int wc_rng_debug_stats_sum(struct wc_rng_debug_stats_snapshot *s,
|
||||
const WC_RNG *rng);
|
||||
#endif /* WC_RNG_DEBUG_STATS */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -40,30 +40,81 @@
|
||||
#error WC_RNG_BANK_SUPPORT requires RNG support.
|
||||
#endif
|
||||
|
||||
#define WC_RNG_BANK_FLAG_NONE 0
|
||||
#define WC_RNG_BANK_FLAG_INITED (1<<0)
|
||||
#define WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST (1<<1)
|
||||
#define WC_RNG_BANK_FLAG_CAN_WAIT (1<<2)
|
||||
#define WC_RNG_BANK_FLAG_NO_VECTOR_OPS (1<<3)
|
||||
#define WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST (1<<4)
|
||||
#define WC_RNG_BANK_FLAG_AFFINITY_LOCK (1<<5)
|
||||
#if !defined(WOLFSSL_NO_ATOMICS) && !defined(WC_RNG_BANK_NO_DAEMON_SUPPORT)
|
||||
#define WC_RNG_BANK_HAVE_DAEMON_SUPPORT
|
||||
#define WC_RNG_BANK_DAEMON_MAGIC_FREE 0U
|
||||
#endif
|
||||
|
||||
#define WC_RNG_BANK_INST_LOCK_FREE 0
|
||||
#define WC_RNG_BANK_INST_LOCK_HELD (1<<0)
|
||||
#define WC_RNG_BANK_INST_LOCK_AFFINITY_LOCKED (1<<1)
|
||||
#define WC_RNG_BANK_INST_LOCK_VEC_OPS_INH (1<<2)
|
||||
#define WC_RNG_BANK_FLAG_NONE 0
|
||||
#define WC_RNG_BANK_FLAG_INITED (1U << 0)
|
||||
#define WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST (1U << 1)
|
||||
#define WC_RNG_BANK_FLAG_CAN_WAIT (1U << 2)
|
||||
#define WC_RNG_BANK_FLAG_NO_VECTOR_OPS (1U << 3)
|
||||
#define WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST (1U << 4)
|
||||
#define WC_RNG_BANK_FLAG_AFFINITY_LOCK (1U << 5)
|
||||
#define WC_RNG_BANK_FLAG_STIR (1U << 6)
|
||||
#define WC_RNG_BANK_FLAG_CONSUME_NEXT_SEED (1U << 7)
|
||||
#define WC_RNG_BANK_FLAG_FOR_RECOVERY (1U << 8)
|
||||
#define WC_RNG_BANK_FLAG_MAYBE_FOR_RECOVERY (1U << 9)
|
||||
#define WC_RNG_BANK_FLAG_ERROR_ON_RNG_FAILED (1U << 10)
|
||||
#define WC_RNG_BANK_FLAG_QUIET (1U << 11)
|
||||
#define WC_RNG_BANK_FLAG_NO_CHECKOUT_REFCOUNTING (1U << 12)
|
||||
#define WC_RNG_BANK_FLAG_RBGC (1U << 13)
|
||||
#define WC_RNG_BANK_FLAG_DEFAULT_BANK (1U << 14)
|
||||
#define WC_RNG_BANK_FLAG_PREDICTION_RESISTANCE (1U << 15)
|
||||
#define WC_RNG_BANK_FLAG_AUTO_RECOVER_AND_PROMOTE (1U << 16)
|
||||
|
||||
#ifdef WC_RNG_HAVE_LOCK
|
||||
wc_static_assert(WC_RNG_LOCK_EXTRA_SHIFT == 4U);
|
||||
#else /* !WC_RNG_HAVE_LOCK */
|
||||
/* Definitions for backward-compat / WC_RNG_NO_LOCK */
|
||||
#define WC_RNG_LOCK_FREE 0
|
||||
#define WC_RNG_LOCK_HELD (1U<<0)
|
||||
#define WC_RNG_LOCK_REQUIRED (1U<<1)
|
||||
#define WC_RNG_LOCK_ENTROPY_INVALIDATED (1U<<2)
|
||||
#define WC_RNG_LOCK_ENTROPY_RECOVERING (1U<<3)
|
||||
#define WC_RNG_LOCK_EXTRA_SHIFT 4U
|
||||
#ifdef WOLFSSL_NO_ATOMICS
|
||||
typedef word32 WC_RNG_lock_t;
|
||||
typedef word32 WC_RNG_lock_arg_t;
|
||||
#else
|
||||
typedef wolfSSL_Atomic_Uint WC_RNG_lock_t;
|
||||
typedef WC_ATOMIC_UINT_ARG WC_RNG_lock_arg_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* When WC_RNG_HAVE_LOCK, base lock states are in random.h and the lock word
|
||||
* itself is in WC_RNG.lock; these annotation bits ride above the base bits via
|
||||
* wc_RNG_lock_get() / _set_extra() / _clear_extra(). */
|
||||
#define WC_RNG_BANK_INST_LOCK_AFFINITY_LOCKED (1U<<(WC_RNG_LOCK_EXTRA_SHIFT+0))
|
||||
#define WC_RNG_BANK_INST_LOCK_VEC_OPS_INH (1U<<(WC_RNG_LOCK_EXTRA_SHIFT+1))
|
||||
|
||||
typedef int (*wc_affinity_lock_fn_t)(void *arg);
|
||||
typedef int (*wc_affinity_get_id_fn_t)(void *arg, int *id);
|
||||
typedef int (*wc_affinity_unlock_fn_t)(void *arg);
|
||||
|
||||
struct wc_rng_bank;
|
||||
|
||||
typedef int (*wc_rng_bank_free_hook_cb_t)(const struct wc_rng_bank *bank,
|
||||
void *arg);
|
||||
|
||||
#define WC_RNG_BANK_INST_FLAG_NONE 0
|
||||
#define WC_RNG_BANK_INST_FLAG_ALREADY_WARNED (1U << 0)
|
||||
|
||||
struct wc_rng_bank_inst {
|
||||
#ifdef WOLFSSL_NO_ATOMICS
|
||||
int lock;
|
||||
#else
|
||||
wolfSSL_Atomic_Int lock;
|
||||
#endif
|
||||
#ifdef WC_RNG_HAVE_LOCK
|
||||
/* the exclusivity latch lives in WC_RNG.lock (wc_RNG_lock_*()) --
|
||||
* in-FIPS-boundary, module-enforced. */
|
||||
#else
|
||||
#ifdef WOLFSSL_NO_ATOMICS
|
||||
word32 lock;
|
||||
#else
|
||||
wolfSSL_Atomic_Uint lock;
|
||||
#endif
|
||||
#endif
|
||||
struct wc_rng_bank *bank;
|
||||
WC_RNG rng;
|
||||
volatile word32 flags;
|
||||
};
|
||||
|
||||
#if defined(WOLFSSL_NO_MALLOC) && defined(NO_WOLFSSL_MEMORY) && \
|
||||
@@ -78,16 +129,31 @@ struct wc_rng_bank_inst {
|
||||
struct wc_rng_bank {
|
||||
wolfSSL_Ref refcount;
|
||||
void *heap;
|
||||
int devId;
|
||||
word32 flags;
|
||||
wc_rng_bank_free_hook_cb_t free_hook;
|
||||
void *free_hook_arg;
|
||||
wc_affinity_lock_fn_t affinity_lock_cb;
|
||||
wc_affinity_get_id_fn_t affinity_get_id_cb;
|
||||
wc_affinity_unlock_fn_t affinity_unlock_cb;
|
||||
void *cb_arg; /* if mutable, caller is responsible for thread safety. */
|
||||
int n_rngs;
|
||||
int first_failover_inst;
|
||||
#ifdef WC_RNG_HAVE_NEXT_SEED
|
||||
wolfSSL_Atomic_Int inst_op_gate;
|
||||
#endif
|
||||
#ifdef WC_RNG_BANK_STATIC
|
||||
struct wc_rng_bank_inst rngs[WC_RNG_BANK_STATIC_SIZE];
|
||||
#else
|
||||
struct wc_rng_bank_inst *rngs; /* typically one per CPU ID, plus a few */
|
||||
struct wc_rng_bank_inst *rngs;
|
||||
#endif
|
||||
#ifdef WC_RNG_BANK_HAVE_DAEMON_SUPPORT
|
||||
wolfSSL_Atomic_Uint daemon_magic;
|
||||
void *daemon; /* e.g. a task_struct* for a wc_linuxkm_entropy_daemon() */
|
||||
#endif
|
||||
#if defined(WC_RNG_HAVE_RBGC) || defined(WC_RNG_HAVE_NEXT_SEED) || \
|
||||
defined(WC_RNG_HAVE_POOL)
|
||||
WC_RNG root_rng;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -109,6 +175,20 @@ WOLFSSL_API int wc_rng_bank_init(
|
||||
void *heap,
|
||||
int devId);
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_init_nonce(
|
||||
struct wc_rng_bank *ctx,
|
||||
int n_rngs,
|
||||
word32 flags,
|
||||
int timeout_secs,
|
||||
void *heap,
|
||||
int devId,
|
||||
const byte *nonce, word32 nonceSz,
|
||||
const byte *perso, word32 persoSz);
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_first_failover_inst_set(
|
||||
struct wc_rng_bank *ctx,
|
||||
int first_failover_inst);
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_set_affinity_handlers(
|
||||
struct wc_rng_bank *ctx,
|
||||
wc_affinity_lock_fn_t affinity_lock_cb,
|
||||
@@ -141,34 +221,157 @@ WOLFSSL_API int wc_rng_bank_checkout(
|
||||
int timeout_secs,
|
||||
word32 flags);
|
||||
|
||||
#ifdef WC_RNG_BANK_HAVE_DAEMON_SUPPORT
|
||||
/* Note, these APIs must be called in order, _reserve -> _register ->
|
||||
* _unregister -> _release, for lifecycle hygiene. A registered daemon must be
|
||||
* _unregister()ed, and the bank _release()d, before wc_rng_bank_fini(),
|
||||
* otherwise _fini() will return BUSY_E. */
|
||||
WOLFSSL_API int wc_rng_bank_daemon_reserve(struct wc_rng_bank *bank,
|
||||
WC_ATOMIC_UINT_ARG magic);
|
||||
WOLFSSL_API int wc_rng_bank_daemon_register(struct wc_rng_bank *bank,
|
||||
void *daemon,
|
||||
WC_ATOMIC_UINT_ARG magic);
|
||||
WOLFSSL_API int wc_rng_bank_daemon_unregister(struct wc_rng_bank *bank,
|
||||
void **daemon,
|
||||
WC_ATOMIC_UINT_ARG magic);
|
||||
WOLFSSL_API int wc_rng_bank_daemon_release(struct wc_rng_bank *bank,
|
||||
WC_ATOMIC_UINT_ARG magic);
|
||||
#endif /* WC_RNG_BANK_HAVE_DAEMON_SUPPORT */
|
||||
|
||||
#if defined(WC_DRBG_BANKREF) && !defined(WC_HAVE_RNG_BANKREF)
|
||||
/* forward compat for FIPS v5.2.4 random.h */
|
||||
#define WC_HAVE_RNG_BANKREF
|
||||
#endif
|
||||
|
||||
#ifdef WC_HAVE_RNG_BANKREF
|
||||
WOLFSSL_LOCAL int wc_local_rng_bank_checkout_for_bankref(
|
||||
struct wc_rng_bank *bank,
|
||||
struct wc_rng_bank_inst **rng_inst);
|
||||
#endif
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_get_inst_id(struct wc_rng_bank_inst *rng_inst);
|
||||
|
||||
static WC_INLINE int WC_ARG_NOT_NULL(1) wc_rng_bank_inst_flags_up(
|
||||
struct wc_rng_bank_inst *rng_inst, word32 flags)
|
||||
{
|
||||
if (! (rng_inst->flags & flags)) {
|
||||
rng_inst->flags = rng_inst->flags | flags;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static WC_INLINE int WC_ARG_NOT_NULL(1) wc_rng_bank_inst_flags_down(
|
||||
struct wc_rng_bank_inst *rng_inst, word32 flags)
|
||||
{
|
||||
if (rng_inst->flags & flags) {
|
||||
rng_inst->flags = rng_inst->flags & ~flags;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_checkin(
|
||||
struct wc_rng_bank *bank,
|
||||
struct wc_rng_bank_inst **rng_inst);
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_inst_checkin(
|
||||
struct wc_rng_bank_inst **rng_inst);
|
||||
|
||||
#ifdef WC_RNG_HAVE_NEXT_SEED
|
||||
WOLFSSL_API int wc_rng_bank_next_seed_generate(
|
||||
struct wc_rng_bank *bank,
|
||||
int inst_offset,
|
||||
word32 n);
|
||||
#ifdef WC_RNG_HAVE_RBGC
|
||||
WOLFSSL_API int wc_rng_bank_next_seed_generate_rbgc(
|
||||
struct wc_rng_bank *bank,
|
||||
int inst_offset,
|
||||
word32 n);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_inst_reinit(
|
||||
struct wc_rng_bank *bank,
|
||||
struct wc_rng_bank_inst *rng_inst,
|
||||
int timeout_secs,
|
||||
word32 flags);
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_recover_inst(
|
||||
struct wc_rng_bank *bank,
|
||||
int inst_offset,
|
||||
int timeout_secs,
|
||||
word32 flags);
|
||||
|
||||
#ifdef WC_RNG_HAVE_RBGC
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_spawn(
|
||||
struct wc_rng_bank *bank,
|
||||
WC_RNG *child_rng,
|
||||
byte *nonce, word32 nonceSz,
|
||||
const byte *perso, word32 persoSz,
|
||||
int preferred_inst_offset,
|
||||
int timeout_secs,
|
||||
word32 flags);
|
||||
|
||||
#ifndef WC_NO_CONSTRUCTORS
|
||||
WOLFSSL_API int wc_rng_bank_spawn_new(
|
||||
struct wc_rng_bank *bank,
|
||||
WC_RNG **child_rng,
|
||||
byte *nonce, word32 nonceSz,
|
||||
const byte *perso, word32 persoSz,
|
||||
int preferred_inst_offset,
|
||||
int timeout_secs,
|
||||
word32 flags);
|
||||
#endif /* !WC_NO_CONSTRUCTORS */
|
||||
|
||||
#endif /* WC_RNG_HAVE_RBGC */
|
||||
|
||||
#ifdef HAVE_HASHDRBG
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_seed(struct wc_rng_bank *bank,
|
||||
const byte* seed, word32 seedSz,
|
||||
const byte *nonce, word32 nonceSz,
|
||||
int timeout_secs,
|
||||
word32 flags);
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_seed_range(struct wc_rng_bank *bank,
|
||||
int first_inst, int last_inst,
|
||||
const byte* seed, word32 seedSz,
|
||||
const byte *nonce, word32 nonceSz,
|
||||
int timeout_secs,
|
||||
word32 flags);
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_reseed(struct wc_rng_bank *bank,
|
||||
const byte *nonce, word32 nonceSz,
|
||||
int timeout_secs,
|
||||
word32 flags);
|
||||
|
||||
#if defined(WC_DRBG_BANKREF) && !defined(WC_HAVE_RNG_BANKREF)
|
||||
/* forward compat for FIPS v5.2.4 random.h */
|
||||
#define WC_HAVE_RNG_BANKREF
|
||||
WOLFSSL_API int wc_rng_bank_reseed_range(struct wc_rng_bank *bank,
|
||||
int first_inst, int last_inst,
|
||||
const byte *nonce, word32 nonceSz,
|
||||
int timeout_secs,
|
||||
word32 flags);
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_invalidate_entropy(struct wc_rng_bank *bank,
|
||||
word32 flags);
|
||||
|
||||
#endif /* HAVE_HASHDRBG */
|
||||
|
||||
#if defined(WC_RNG_HAVE_RBGC) || defined(WC_RNG_HAVE_NEXT_SEED) || \
|
||||
defined(WC_RNG_HAVE_POOL)
|
||||
WOLFSSL_API int wc_rng_bank_root_rng_init(struct wc_rng_bank *bank,
|
||||
const byte *nonce, word32 nonceSz,
|
||||
const byte *perso, word32 persoSz,
|
||||
word32 flags);
|
||||
WOLFSSL_API WC_RNG *wc_rng_bank_root_rng_get(struct wc_rng_bank *bank);
|
||||
#endif
|
||||
|
||||
WOLFSSL_API int wc_rng_bank_register_free_hook(struct wc_rng_bank *bank,
|
||||
wc_rng_bank_free_hook_cb_t free_hook, void *arg);
|
||||
|
||||
#ifdef WC_HAVE_RNG_BANKREF
|
||||
WOLFSSL_API int wc_InitRng_BankRef(struct wc_rng_bank *bank, WC_RNG *rng);
|
||||
|
||||
@@ -180,7 +383,133 @@ WOLFSSL_API int wc_rng_new_bankref(struct wc_rng_bank *bank, WC_RNG **rng);
|
||||
#endif
|
||||
#endif /* WC_HAVE_RNG_BANKREF */
|
||||
|
||||
#define WC_RNG_BANK_INST_TO_RNG(rng_inst) (&(rng_inst)->rng)
|
||||
#define WC_RNG_BANK_INST_TO_RNG(rng_inst) \
|
||||
((rng_inst) ? (&(rng_inst)->rng) : NULL)
|
||||
#define WC_RNG_BANK_OFFSET_TO_RNG(bank, n) \
|
||||
((((int)(n) >= 0) && ((int)(n) < (int)(bank)->n_rngs)) ? \
|
||||
WC_RNG_BANK_INST_TO_RNG(&(bank)->rngs[n]) : NULL)
|
||||
|
||||
#ifdef WC_RNG_HAVE_LOCK
|
||||
/* Trivial shims to native lock facility in WC_RNG */
|
||||
static WC_INLINE int wc_rng_bank_inst_lock_get(
|
||||
struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t extra_bits)
|
||||
{
|
||||
return wc_RNG_lock_get(WC_RNG_BANK_INST_TO_RNG(inst), extra_bits);
|
||||
}
|
||||
static WC_INLINE int wc_rng_bank_inst_lock_get_conditional(
|
||||
struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t expected_extra_bits,
|
||||
WC_RNG_lock_arg_t want_extra_bits)
|
||||
{
|
||||
return wc_RNG_lock_get_conditional(
|
||||
WC_RNG_BANK_INST_TO_RNG(inst), expected_extra_bits, want_extra_bits);
|
||||
}
|
||||
static WC_INLINE int wc_rng_bank_inst_lock_put(
|
||||
struct wc_rng_bank_inst *inst)
|
||||
{
|
||||
return wc_RNG_lock_put(WC_RNG_BANK_INST_TO_RNG(inst), 0);
|
||||
}
|
||||
static WC_INLINE int wc_rng_bank_inst_lock_put_conditional(
|
||||
struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t expect_extra_bits)
|
||||
{
|
||||
return wc_RNG_lock_put_conditional(
|
||||
WC_RNG_BANK_INST_TO_RNG(inst), expect_extra_bits, 0);
|
||||
}
|
||||
static WC_INLINE int wc_rng_bank_inst_lock_read(
|
||||
struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t *state)
|
||||
{
|
||||
return wc_RNG_lock_read(WC_RNG_BANK_INST_TO_RNG(inst), state);
|
||||
}
|
||||
static WC_INLINE int wc_rng_bank_inst_lock_set_extra(
|
||||
struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t extra_bits)
|
||||
{
|
||||
return wc_RNG_lock_set_extra(WC_RNG_BANK_INST_TO_RNG(inst), extra_bits);
|
||||
}
|
||||
static WC_INLINE int wc_rng_bank_inst_lock_add_extra(
|
||||
struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t extra_bits)
|
||||
{
|
||||
return wc_RNG_lock_add_extra(WC_RNG_BANK_INST_TO_RNG(inst), extra_bits);
|
||||
}
|
||||
static WC_INLINE int wc_rng_bank_inst_lock_clear_extra(
|
||||
struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t extra_bits)
|
||||
{
|
||||
return wc_RNG_lock_clear_extra(
|
||||
WC_RNG_BANK_INST_TO_RNG(inst), extra_bits);
|
||||
}
|
||||
#ifdef HAVE_HASHDRBG
|
||||
static WC_INLINE int wc_rng_bank_inst_invalidate_entropy(
|
||||
struct wc_rng_bank_inst *inst)
|
||||
{
|
||||
return wc_RNG_invalidate_entropy(WC_RNG_BANK_INST_TO_RNG(inst));
|
||||
}
|
||||
static WC_INLINE int wc_rng_bank_inst_reseed_now(
|
||||
struct wc_rng_bank_inst *inst, const byte *nonce, word32 nonceSz)
|
||||
{
|
||||
return wc_RNG_DRBG_Reseed_Now(
|
||||
WC_RNG_BANK_INST_TO_RNG(inst), nonce, nonceSz);
|
||||
}
|
||||
#ifdef WC_RNG_HAVE_RBGC
|
||||
static WC_INLINE int wc_rng_bank_inst_reseed_rbgc(
|
||||
struct wc_rng_bank_inst *inst, WC_RNG *root,
|
||||
const byte *nonce, word32 nonceSz)
|
||||
{
|
||||
return wc_RNG_DRBG_ReseedRBGC(
|
||||
WC_RNG_BANK_INST_TO_RNG(inst), root, nonce, nonceSz);
|
||||
}
|
||||
#endif /* WC_RNG_HAVE_RBGC */
|
||||
#endif /* HAVE_HASHDRBG */
|
||||
#else /* !WC_RNG_HAVE_LOCK */
|
||||
/* Prototypes for backward compat implementations in rng_bank.c */
|
||||
WOLFSSL_TEST_VIS int wc_rng_bank_inst_lock_get(struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t extra_bits);
|
||||
WOLFSSL_TEST_VIS int wc_rng_bank_inst_lock_get_conditional(
|
||||
struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t expected_extra_bits,
|
||||
WC_RNG_lock_arg_t want_extra_bits);
|
||||
WOLFSSL_TEST_VIS int wc_rng_bank_inst_lock_put(struct wc_rng_bank_inst *inst);
|
||||
WOLFSSL_TEST_VIS int wc_rng_bank_inst_lock_put_conditional(struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t extra_bits);
|
||||
WOLFSSL_TEST_VIS int wc_rng_bank_inst_lock_read(struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t* state);
|
||||
WOLFSSL_TEST_VIS int wc_rng_bank_inst_lock_set_extra(struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t extra_bits);
|
||||
WOLFSSL_TEST_VIS int wc_rng_bank_inst_lock_add_extra(struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t extra_bits);
|
||||
WOLFSSL_TEST_VIS int wc_rng_bank_inst_lock_clear_extra(struct wc_rng_bank_inst *inst, WC_RNG_lock_arg_t extra_bits);
|
||||
#ifdef HAVE_HASHDRBG
|
||||
WOLFSSL_TEST_VIS int wc_rng_bank_inst_invalidate_entropy(
|
||||
struct wc_rng_bank_inst *inst);
|
||||
WOLFSSL_TEST_VIS int wc_rng_bank_inst_reseed_now(
|
||||
struct wc_rng_bank_inst *inst, const byte* nonce, word32 nonceSz);
|
||||
#ifdef WC_RNG_HAVE_RBGC
|
||||
WOLFSSL_TEST_VIS int wc_rng_bank_inst_reseed_rbgc(
|
||||
struct wc_rng_bank_inst *inst, WC_RNG* root, const byte* nonce,
|
||||
word32 nonceSz);
|
||||
#endif /* WC_RNG_HAVE_RBGC */
|
||||
#endif /* HAVE_HASHDRBG */
|
||||
#endif /* !WC_RNG_HAVE_LOCK */
|
||||
|
||||
#if defined(HAVE_FIPS) && FIPS_VERSION3_LT(7,0,0)
|
||||
#ifndef WC_DRBG_RESEED_CTR_TYPE_DEFINED
|
||||
#define WC_DRBG_RESEED_CTR_TYPE_DEFINED
|
||||
#if defined(WORD64_AVAILABLE) && FIPS_VERSION3_GE(5,2,4) && \
|
||||
FIPS_VERSION3_NE(6,0,0)
|
||||
typedef word64 wc_drbg_reseed_ctr_t;
|
||||
#else
|
||||
typedef word32 wc_drbg_reseed_ctr_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define wc_InitRngRBGC(leaf, root, flags) \
|
||||
wc_InitRngNonceRBGC(leaf, root, NULL, 0, flags)
|
||||
WOLFSSL_TEST_VIS int wc_RNG_GetStatus(const WC_RNG* rng);
|
||||
WOLFSSL_TEST_VIS int wc_RNG_DRBG_Stir(WC_RNG* rng, const byte* seed, word32 seedSz);
|
||||
WOLFSSL_TEST_VIS int wc_RNG_DRBG_Present(const WC_RNG* rng);
|
||||
WOLFSSL_TEST_VIS int wc_InitRngNonceRBGC_New(WC_RNG** leaf, WC_RNG* root,
|
||||
const byte* nonce, word32 nonceSz,
|
||||
const byte *perso, word32 persoSz,
|
||||
word32 flags);
|
||||
WOLFSSL_TEST_VIS int wc_InitRngRBGC_New(WC_RNG** leaf, WC_RNG* root, word32 flags);
|
||||
WOLFSSL_TEST_VIS int wc_RNG_DRBG_ScheduleReseed(WC_RNG* rng);
|
||||
#endif /* HAVE_FIPS && FIPS_VERSION3_LT(7,0,0) */
|
||||
|
||||
#ifdef WC_RNG_DEBUG_STATS
|
||||
WOLFSSL_API int wc_rng_bank_debug_stats_snap(struct wc_rng_debug_stats_snapshot *s,
|
||||
struct wc_rng_bank *bank);
|
||||
#endif
|
||||
|
||||
#endif /* WC_RNG_BANK_SUPPORT */
|
||||
|
||||
|
||||
@@ -447,6 +447,7 @@ WOLFSSL_API int wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz,
|
||||
|
||||
#ifndef WC_NO_RNG
|
||||
WOLFSSL_API int wc_RsaSetRNG(RsaKey* key, WC_RNG* rng);
|
||||
WOLFSSL_API int wc_RsaClearRNG(RsaKey* key);
|
||||
#endif
|
||||
#ifdef WC_RSA_NONBLOCK
|
||||
WOLFSSL_API int wc_RsaSetNonBlock(RsaKey* key, RsaNb* nb);
|
||||
|
||||
@@ -1515,7 +1515,7 @@
|
||||
/* user needs to define XTIME to function that provides
|
||||
* seconds since Unix epoch */
|
||||
#ifndef XTIME
|
||||
#error XTIME must be defined in wolfSSL settings.h
|
||||
#error XTIME must be defined in wolfSSL user_settings.h
|
||||
/* #define XTIME fnSecondsSinceEpoch */
|
||||
#endif
|
||||
|
||||
@@ -4628,15 +4628,20 @@
|
||||
#endif
|
||||
|
||||
#ifndef WC_RESEED_INTERVAL
|
||||
/* In kernel mode, use the maximum reseed interval allowed by
|
||||
/* In kernel mode, use the maximum mandatory reseed threshold allowed by
|
||||
* NIST SP 800-90A Rev. 1, to avoid unnecessary delays in DRBG
|
||||
* generation.
|
||||
*/
|
||||
#if defined(HAVE_FIPS) && \
|
||||
FIPS_VERSION_LT(6,0) && FIPS_VERSION3_NE(5,2,4)
|
||||
#define WC_RESEED_INTERVAL UINT_MAX
|
||||
#elif defined(WC_16BIT_CPU) || defined(WC_32BIT_CPU) || defined(NO_64BIT)
|
||||
#define WC_RESEED_INTERVAL UINT_MAX
|
||||
#elif defined(__x86_64__) || defined(__ia64__) || \
|
||||
defined(__aarch64__) || defined(__mips64)
|
||||
#define WC_RESEED_INTERVAL (W64LIT(1) << 48)
|
||||
#else
|
||||
#define WC_RESEED_INTERVAL (((word64)1UL)<<48UL)
|
||||
#define WC_RESEED_INTERVAL UINT_MAX
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -4644,6 +4649,11 @@
|
||||
#define WC_VERBOSE_RNG
|
||||
#endif
|
||||
|
||||
#if defined(WC_VERBOSE_RNG) && defined(WOLFSSL_KERNEL_VERBOSE_DEBUG) && \
|
||||
!defined(WC_RNG_NO_DEBUG_STATS) && !defined(WC_RNG_WANT_DEBUG_STATS)
|
||||
#define WC_RNG_WANT_DEBUG_STATS
|
||||
#endif
|
||||
|
||||
#if WOLFSSL_GENERAL_ALIGNMENT < SIZEOF_LONG
|
||||
#undef WOLFSSL_GENERAL_ALIGNMENT
|
||||
#define WOLFSSL_GENERAL_ALIGNMENT SIZEOF_LONG
|
||||
@@ -5982,10 +5992,6 @@ blinding by defining WC_BLINDING_NO_RNG_ACKNOWLEDGE_WEAKNESS."
|
||||
#error "If TLS is enabled please make sure either client or server is enabled."
|
||||
#endif
|
||||
|
||||
#if defined(WC_RNG_BANK_SUPPORT) && defined(NO_ASN_TIME)
|
||||
#undef WC_RNG_BANK_SUPPORT
|
||||
#endif
|
||||
|
||||
/* The OCSP responder time-stamps every response it generates (producedAt,
|
||||
* thisUpdate and, for revoked certs, revocationDate), so it needs ASN time
|
||||
* support. */
|
||||
|
||||
@@ -926,6 +926,11 @@ enum {
|
||||
#endif /* WOLFSSL_STATIC_MEMORY */
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) && \
|
||||
!defined(WC_NO_CONSTRUCTORS)
|
||||
#define WC_NO_CONSTRUCTORS
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_SMALL_STACK) && defined(WC_NO_CONSTRUCTORS)
|
||||
#error WOLFSSL_SMALL_STACK requires constructors.
|
||||
#endif
|
||||
|
||||
@@ -620,8 +620,11 @@
|
||||
#endif /* !WOLFSSL_NO_ATOMICS */
|
||||
|
||||
#ifdef WOLFSSL_NO_ATOMICS
|
||||
typedef volatile int wolfSSL_Atomic_Int;
|
||||
typedef volatile unsigned int wolfSSL_Atomic_Uint;
|
||||
/* Note, not volatile. _NO_ATOMICS configs promise no concurrent mutation
|
||||
* (single-threaded, or externally serialized); volatile would imply
|
||||
* protection these types do not and cannot provide here. */
|
||||
typedef int wolfSSL_Atomic_Int;
|
||||
typedef unsigned int wolfSSL_Atomic_Uint;
|
||||
#define WOLFSSL_ATOMIC_INITIALIZER(x) (x)
|
||||
#define WOLFSSL_ATOMIC_LOAD(x) (x)
|
||||
#define WOLFSSL_ATOMIC_STORE(x, val) (x) = (val)
|
||||
@@ -787,6 +790,88 @@
|
||||
}
|
||||
#endif
|
||||
|
||||
/*** Macro abstractions for compare-and-exchange retry loops, allowing ***/
|
||||
/*** platform-specific instrumentation and failure paths. ***/
|
||||
|
||||
/* WC_CAS_WITH_RETRY_EXTRA_DECLS allows declaration and initialization of
|
||||
* variables (e.g. a counter) just above the retry loop in
|
||||
* WC_CAS_WITH_RETRY_BEGIN().
|
||||
*/
|
||||
#ifndef WC_CAS_WITH_RETRY_EXTRA_DECLS
|
||||
#define WC_CAS_WITH_RETRY_EXTRA_DECLS \
|
||||
struct wc_cas_with_retry_dummy_struct
|
||||
#endif
|
||||
|
||||
/* Note that freeform code after WC_CAS_WITH_RETRY_BEGIN() and before
|
||||
* WC_CAS_WITH_RETRY_LOOP_UNTIL() sits inside the loop -- continue
|
||||
* in that span omits the refresh of cur_var by the CAS (potentially inducing an
|
||||
* infinite loop), and break in that span without setting result_var leaves it
|
||||
* at WC_FAILURE. return and goto both behave normally in the freeform span.
|
||||
*/
|
||||
#define WC_CAS_WITH_RETRY_BEGIN(targetvar_p, cur_var, result_var) \
|
||||
do { \
|
||||
int WC_CAS_WITH_RETRY_keep_looping = 1; \
|
||||
WC_CAS_WITH_RETRY_EXTRA_DECLS; \
|
||||
\
|
||||
(result_var) = WC_NO_ERR_TRACE(WC_FAILURE); \
|
||||
\
|
||||
while (WC_CAS_WITH_RETRY_keep_looping)
|
||||
|
||||
#define WC_CAS_WITH_RETRY_BEGIN_INIT_CUR(targetvar_p, cur_var, result_var) \
|
||||
do { \
|
||||
int WC_CAS_WITH_RETRY_keep_looping = 1; \
|
||||
WC_CAS_WITH_RETRY_EXTRA_DECLS; \
|
||||
\
|
||||
(cur_var) = WOLFSSL_ATOMIC_LOAD(*(targetvar_p)); \
|
||||
(result_var) = WC_NO_ERR_TRACE(WC_FAILURE); \
|
||||
\
|
||||
while (WC_CAS_WITH_RETRY_keep_looping)
|
||||
|
||||
#ifndef WC_CAS_WITH_RETRY_ITER_CLAUSE
|
||||
#define WC_CAS_WITH_RETRY_ITER_CLAUSE(targetvar_p, cur_var, \
|
||||
want_val, result_var) WC_DO_NOTHING
|
||||
#endif
|
||||
|
||||
/* The "until_clause" should be portable logic of overriding salience, used in
|
||||
* situ by the direct (portable) user code. The _ITER_CLAUSE is for
|
||||
* non-portable logic, such as CPU/scheduler relaxation/yield or deadlock
|
||||
* detection, and is free to set result_var and break as it sees fit.
|
||||
*
|
||||
* Freeform code can appear between WC_CAS_WITH_RETRY_LOOP_UNTIL() and
|
||||
* WC_CAS_WITH_RETRY_END(), and will be evaluated iff the CAS succeeds.
|
||||
*/
|
||||
#define WC_CAS_WITH_RETRY_LOOP_UNTIL(cmpxchg_method, targetvar_p, cur_var, \
|
||||
want_val, result_var, until_clause) \
|
||||
if (! cmpxchg_method(targetvar_p, &(cur_var), want_val)) { \
|
||||
(result_var) = (until_clause); \
|
||||
if ((result_var) != 0) \
|
||||
break; \
|
||||
{ \
|
||||
WC_CAS_WITH_RETRY_ITER_CLAUSE(targetvar_p, cur_var, \
|
||||
want_val, result_var); \
|
||||
} \
|
||||
continue; \
|
||||
} \
|
||||
else { \
|
||||
(result_var) = 0; \
|
||||
WC_CAS_WITH_RETRY_keep_looping = 0; \
|
||||
} \
|
||||
WC_DO_NOTHING
|
||||
|
||||
#ifndef WC_CAS_WITH_RETRY_FOREVER_CLAUSE
|
||||
#define WC_CAS_WITH_RETRY_FOREVER_CLAUSE 0
|
||||
#endif
|
||||
|
||||
#define WC_CAS_WITH_RETRY_LOOP_FOREVER(cmpxchg_method, targetvar_p, \
|
||||
cur_var, want_val, result_var) \
|
||||
WC_CAS_WITH_RETRY_LOOP_UNTIL(cmpxchg_method, targetvar_p, cur_var, \
|
||||
want_val, result_var, \
|
||||
WC_CAS_WITH_RETRY_FOREVER_CLAUSE)
|
||||
|
||||
/* Note, WC_CAS_WITH_RETRY_END() has no side effects -- it's just the success
|
||||
* arm that ends the loop. */
|
||||
#define WC_CAS_WITH_RETRY_END } while (0)
|
||||
|
||||
/* Reference counting. */
|
||||
typedef struct wolfSSL_RefWithMutex {
|
||||
#if !defined(SINGLE_THREADED)
|
||||
@@ -1582,11 +1667,18 @@ WOLFSSL_ABI WOLFSSL_API int wolfCrypt_Cleanup(void);
|
||||
#endif
|
||||
|
||||
#elif defined(TIME_OVERRIDES)
|
||||
/* Override XTIME() and XGMTIME() functionality.
|
||||
Requires user to provide these functions:
|
||||
time_t XTIME(time_t * timer) {}
|
||||
struct tm* XGMTIME(const time_t* timer, struct tm* tmp) {}
|
||||
*/
|
||||
/* User-supplied override XTIME() and XGMTIME() functionality.
|
||||
*
|
||||
* Requires user-supplied macro definitions for XTIME() and XGMTIME(),
|
||||
* mapping to function with signatures time_t time_f(time_t * timer) and
|
||||
* struct tm* gmtime_f(const time_t* timer, struct tm* tmp) respectively.
|
||||
*/
|
||||
#ifndef XTIME
|
||||
#error TIME_OVERRIDES requires a user-supplied XTIME definition.
|
||||
#endif
|
||||
#ifndef XGMTIME
|
||||
#error TIME_OVERRIDES requires a user-supplied XGMTIME definition.
|
||||
#endif
|
||||
#ifndef HAVE_TIME_T_TYPE
|
||||
#define USE_WOLF_TIME_T
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user