diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 49353bc671..355cc8c4bd 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -790,6 +790,7 @@ WOLFSSL_MONT_RED_CT WOLFSSL_MP_COND_COPY WOLFSSL_MP_INVMOD_CONSTANT_TIME WOLFSSL_MULTICIRCULATE_ALTNAMELIST +WOLFSSL_NEW_PRIME_CHECK WOLFSSL_NONBLOCK_OCSP WOLFSSL_NOSHA3_384 WOLFSSL_NOT_WINDOWS_API diff --git a/configure.ac b/configure.ac index 9fd7732c49..70bc42b18d 100644 --- a/configure.ac +++ b/configure.ac @@ -1428,6 +1428,7 @@ then test "$enable_md5" = "" && enable_md5=yes test "$enable_anon" = "" && enable_anon=yes test "$enable_ssh" = "" && test "$enable_hmac" != "no" && enable_ssh=yes + test "$enable_rng_bank" = "" && enable_rng_bank=yes # the compiler optimizer generates a weird out-of-bounds bss reference for # find_hole() in the FP_ECC implementation. @@ -2208,6 +2209,19 @@ then AM_CFLAGS="$AM_CFLAGS -DWC_NO_RNG" fi +AC_ARG_ENABLE([rng-bank], + [AS_HELP_STRING([--enable-rng-bank],[Enable compiling and using RNG banks (default: disabled)])], + [ ENABLED_RNG_BANK=$enableval ], + [ ENABLED_RNG_BANK=$KERNEL_MODE_DEFAULTS ] + ) + +if test "$ENABLED_RNG_BANK" = "yes" +then + AS_IF([test "$ENABLED_RNG" = "no"], + AC_MSG_ERROR([--enable-rng-bank requires --enable-rng])) + AM_CFLAGS="$AM_CFLAGS -DWC_RNG_BANK_SUPPORT" +fi + # DTLS-SCTP AC_ARG_ENABLE([sctp], @@ -3984,12 +3998,17 @@ then fi # AMD RDSEED -AC_ARG_ENABLE([amdrand], - [AS_HELP_STRING([--enable-amdrand],[Enable AMD rdseed as preferred RNG seeding source (default: disabled)])], +AC_ARG_ENABLE([amdrdseed], + [AS_HELP_STRING([--enable-amdrdseed],[Enable AMD rdseed as preferred RNG seeding source (default: disabled)])], [ ENABLED_AMDRDSEED=$enableval ], [ ENABLED_AMDRDSEED=no ] ) +AC_ARG_ENABLE([amdrand], + [AS_HELP_STRING([--enable-amdrand],[Enable AMD rdseed as preferred RNG seeding source (default: disabled)])], + [ ENABLED_AMDRDSEED=$enableval ] + ) + if test "$ENABLED_AMDRDSEED" = "yes" then AM_CFLAGS="$AM_CFLAGS -DHAVE_AMD_RDSEED" @@ -11079,6 +11098,7 @@ AM_CONDITIONAL([BUILD_ECCSI],[test "x$ENABLED_ECCSI" = "xyes" || test "x$ENABLED AM_CONDITIONAL([BUILD_SAKKE],[test "x$ENABLED_SAKKE" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_MEMORY],[test "x$ENABLED_MEMORY" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_MEMUSE],[test "x$ENABLED_ENTROPY_MEMUSE" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) +AM_CONDITIONAL([BUILD_RNG_BANK],[test "$ENABLED_RNG_BANK" = "yes" || test "$ENABLED_USERSETTINGS" = "yes"]) AM_CONDITIONAL([BUILD_RSA],[test "x$ENABLED_RSA" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_DH],[test "x$ENABLED_DH" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_ASN],[test "x$ENABLED_ASN" != "xno" || test "x$ENABLED_RSA" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) diff --git a/linuxkm/linuxkm_wc_port.h b/linuxkm/linuxkm_wc_port.h index 51bc3f26ab..bb9dd03a76 100644 --- a/linuxkm/linuxkm_wc_port.h +++ b/linuxkm/linuxkm_wc_port.h @@ -937,7 +937,9 @@ typeof(kfree) *kfree; typeof(ksize) *ksize; +#ifndef LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT typeof(get_random_bytes) *get_random_bytes; +#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) typeof(getnstimeofday) *getnstimeofday; #elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0) @@ -1072,9 +1074,7 @@ #endif /* !WOLFCRYPT_ONLY && !NO_CERTS */ - #ifdef WOLFSSL_DEBUG_BACKTRACE_ERROR_CODES typeof(dump_stack) *dump_stack; - #endif #ifdef CONFIG_ARM64 #ifndef CONFIG_ARCH_TEGRA @@ -1269,7 +1269,9 @@ #endif #define ksize WC_PIE_INDIRECT_SYM(ksize) +#ifndef LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT #define get_random_bytes WC_PIE_INDIRECT_SYM(get_random_bytes) +#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) #define getnstimeofday WC_PIE_INDIRECT_SYM(getnstimeofday) #elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0) @@ -1345,9 +1347,7 @@ #endif /* !WOLFCRYPT_ONLY && !NO_CERTS */ - #ifdef WOLFSSL_DEBUG_BACKTRACE_ERROR_CODES #define dump_stack WC_PIE_INDIRECT_SYM(dump_stack) - #endif #undef preempt_count /* just in case -- not a macro on x86. */ #define preempt_count WC_PIE_INDIRECT_SYM(preempt_count) @@ -1729,4 +1729,13 @@ #error unexpected BITS_PER_LONG value. #endif +/* WC_DUMP_BACKTRACE_NONDEBUG is intended to dump a backtrace only if it hasn't + * already been dumped by the called function. + */ +#if defined(WOLFSSL_DEBUG_TRACE_ERROR_CODES) && defined(WOLFSSL_DEBUG_BACKTRACE_ERROR_CODES) + #define WC_DUMP_BACKTRACE_NONDEBUG WC_DO_NOTHING +#else + #define WC_DUMP_BACKTRACE_NONDEBUG dump_stack() +#endif + #endif /* LINUXKM_WC_PORT_H */ diff --git a/linuxkm/lkcapi_dh_glue.c b/linuxkm/lkcapi_dh_glue.c index dc419865e4..a598307f53 100644 --- a/linuxkm/lkcapi_dh_glue.c +++ b/linuxkm/lkcapi_dh_glue.c @@ -749,10 +749,7 @@ static int km_ffdhe_init(struct crypto_kpp *tfm, int name, word32 nbits) ctx->name = name; ctx->nbits = nbits; - if (WOLFSSL_ATOMIC_LOAD(linuxkm_lkcapi_registering_now)) - err = LKCAPI_INITRNG_FOR_SELFTEST(&ctx->rng); - else - err = wc_InitRng(&ctx->rng); + err = LKCAPI_INITRNG(&ctx->rng); if (err) { #ifdef WOLFKM_DEBUG_DH pr_err("%s: init rng returned: %d\n", WOLFKM_DH_DRIVER, err); diff --git a/linuxkm/lkcapi_ecdh_glue.c b/linuxkm/lkcapi_ecdh_glue.c index 5a57bc0ead..1086bbf988 100644 --- a/linuxkm/lkcapi_ecdh_glue.c +++ b/linuxkm/lkcapi_ecdh_glue.c @@ -387,10 +387,7 @@ static int km_ecdh_init(struct crypto_kpp *tfm, int curve_id) ctx->curve_len = (word32) ret; } - if (WOLFSSL_ATOMIC_LOAD(linuxkm_lkcapi_registering_now)) - ret = LKCAPI_INITRNG_FOR_SELFTEST(&ctx->rng); - else - ret = wc_InitRng(&ctx->rng); + ret = LKCAPI_INITRNG(&ctx->rng); if (ret) { #ifdef WOLFKM_DEBUG_ECDH pr_err("%s: init rng returned: %d\n", WOLFKM_ECDH_DRIVER, ret); diff --git a/linuxkm/lkcapi_rsa_glue.c b/linuxkm/lkcapi_rsa_glue.c index c91e63b8be..3872ecd898 100644 --- a/linuxkm/lkcapi_rsa_glue.c +++ b/linuxkm/lkcapi_rsa_glue.c @@ -634,14 +634,13 @@ static int km_rsa_ctx_init(struct km_rsa_ctx * ctx, int hash_oid) static inline int km_rsa_ctx_init_rng(struct km_rsa_ctx * ctx) { switch (ctx->rng.status) { case WC_DRBG_OK: +#ifdef WC_RNG_BANK_SUPPORT + case WC_DRBG_BANKREF: +#endif return 0; case WC_DRBG_NOT_INIT: { - int err; - if (WOLFSSL_ATOMIC_LOAD(linuxkm_lkcapi_registering_now)) - err = LKCAPI_INITRNG_FOR_SELFTEST(&ctx->rng); - else - err = wc_InitRng(&ctx->rng); + int err = LKCAPI_INITRNG(&ctx->rng); if (err) { pr_err("%s: init rng returned: %d\n", WOLFKM_RSA_DRIVER, err); if (err == WC_NO_ERR_TRACE(MEMORY_E)) @@ -2105,7 +2104,7 @@ static int linuxkm_test_rsa_driver(const char * driver, int nbits) memset(&rng, 0, sizeof(rng)); memset(key, 0, sizeof(RsaKey)); - ret = LKCAPI_INITRNG_FOR_SELFTEST(&rng); + ret = LKCAPI_INITRNG(&rng); if (ret) { pr_err("error: init rng returned: %d\n", ret); @@ -2483,7 +2482,7 @@ static int linuxkm_test_pkcs1pad_driver(const char * driver, int nbits, memset(&rng, 0, sizeof(rng)); memset(key, 0, sizeof(RsaKey)); - ret = LKCAPI_INITRNG_FOR_SELFTEST(&rng); + ret = LKCAPI_INITRNG(&rng); if (ret) { pr_err("error: init rng returned: %d\n", ret); goto test_pkcs1_end; @@ -3007,7 +3006,7 @@ static int linuxkm_test_pkcs1_driver(const char * driver, int nbits, memset(&rng, 0, sizeof(rng)); memset(key, 0, sizeof(RsaKey)); - ret = LKCAPI_INITRNG_FOR_SELFTEST(&rng); + ret = LKCAPI_INITRNG(&rng); if (ret) { pr_err("error: init rng returned: %d\n", ret); goto test_pkcs1_end; diff --git a/linuxkm/lkcapi_sha_glue.c b/linuxkm/lkcapi_sha_glue.c index e08d1a9aed..1bdc56a8ac 100644 --- a/linuxkm/lkcapi_sha_glue.c +++ b/linuxkm/lkcapi_sha_glue.c @@ -955,104 +955,79 @@ struct wc_swallow_the_semicolon #include #endif #include +#include -struct wc_linuxkm_drbg_ctx { - size_t n_rngs; - struct wc_rng_inst { - wolfSSL_Atomic_Int lock; - WC_RNG rng; - } *rngs; /* one per CPU ID */ -}; +static volatile int wc_linuxkm_drbg_init_tfm_disable_vector_registers = 0; -static inline void wc_linuxkm_drbg_ctx_clear(struct wc_linuxkm_drbg_ctx * ctx) -{ - unsigned int i; - - if (ctx->rngs) { - for (i = 0; i < ctx->n_rngs; ++i) { - if (ctx->rngs[i].lock != 0) { - /* better to leak than to crash. */ - pr_err("BUG: wc_linuxkm_drbg_ctx_clear called with DRBG #%d still locked.", i); - ctx->rngs = NULL; - ctx->n_rngs = 0; - return; - } - else - wc_FreeRng(&ctx->rngs[i].rng); - } - free(ctx->rngs); - ctx->rngs = NULL; - ctx->n_rngs = 0; - } +#ifndef WC_LINUXKM_INITRNG_TIMEOUT_SEC + #define WC_LINUXKM_INITRNG_TIMEOUT_SEC 30 +#endif - return; +static int linuxkm_affinity_lock(void *arg) { + (void)arg; + if (preempt_count() != 0) + return ALREADY_E; +#if defined(CONFIG_SMP) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + migrate_disable(); /* this actually makes irq_count() nonzero, so that + * DISABLE_VECTOR_REGISTERS() is superfluous, but + * don't depend on that. + */ +#endif + local_bh_disable(); + return 0; } -static volatile int wc_linuxkm_drbg_init_tfm_disable_vector_registers = 0; +static int linuxkm_affinity_get_id(void *arg, int *id) { + (void)arg; + *id = raw_smp_processor_id(); + return 0; +} -#ifndef WC_LINUXKM_INITRNG_TIMEOUT_SEC - #define WC_LINUXKM_INITRNG_TIMEOUT_SEC 30 +static int linuxkm_affinity_unlock(void *arg) { + (void)arg; + local_bh_enable(); +#if defined(CONFIG_SMP) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + migrate_enable(); #endif + return 0; +} static int wc_linuxkm_drbg_init_tfm(struct crypto_tfm *tfm) { - struct wc_linuxkm_drbg_ctx *ctx = (struct wc_linuxkm_drbg_ctx *)crypto_tfm_ctx(tfm); - unsigned int i; + struct wc_rng_bank *ctx = (struct wc_rng_bank *)crypto_tfm_ctx(tfm); int ret; - int need_reenable_vec = 0; - int can_sleep = (preempt_count() == 0); + word32 flags = WC_RNG_BANK_FLAG_CAN_WAIT; - ctx->n_rngs = nr_cpu_ids + 4; - ctx->rngs = (struct wc_rng_inst *)malloc(sizeof(*ctx->rngs) * ctx->n_rngs); - if (! ctx->rngs) { - ctx->n_rngs = 0; - return -ENOMEM; - } - XMEMSET(ctx->rngs, 0, sizeof(*ctx->rngs) * ctx->n_rngs); + if (wc_linuxkm_drbg_init_tfm_disable_vector_registers) + flags |= WC_RNG_BANK_FLAG_NO_VECTOR_OPS; - for (i = 0; i < ctx->n_rngs; ++i) { - int nretries = 0; - u64 ts1 = ktime_get_ns(); - for (;;) { - u64 ts2; - if (wc_linuxkm_drbg_init_tfm_disable_vector_registers) - need_reenable_vec = (DISABLE_VECTOR_REGISTERS() == 0); - ret = wc_InitRng(&ctx->rngs[i].rng); - if (need_reenable_vec) - REENABLE_VECTOR_REGISTERS(); - if (can_sleep) { - /* if we're allowed to sleep, relax the loop between each inner - * iteration even on success, assuring relaxation of the outer - * iterations. - */ - cond_resched(); - } - if (ret == 0) - break; - if (can_sleep) { - /* Allow interrupt only if we're stuck spinning retries -- i.e., - * don't allow an untimely user signal to derail an - * initialization that is proceeding expeditiously. - */ - if (WC_CHECK_FOR_INTR_SIGNALS() == WC_NO_ERR_TRACE(INTERRUPTED_E)) { - ret = -EINTR; - break; - } - } - ts2 = ktime_get_ns(); - if (ts2 - ts1 > 1000000000L * WC_LINUXKM_INITRNG_TIMEOUT_SEC) - break; - ++nretries; - } + ret = wc_rng_bank_init( + ctx, nr_cpu_ids + 4, flags, WC_LINUXKM_INITRNG_TIMEOUT_SEC, + NULL /* heap */, INVALID_DEVID); + + if (ret == 0) { + ret = wc_rng_bank_set_affinity_handlers( + ctx, + linuxkm_affinity_lock, + linuxkm_affinity_get_id, + linuxkm_affinity_unlock, + NULL); if (ret != 0) { - pr_warn("WARNING: wc_InitRng returned %d after %d retries.\n", ret, nretries); - ret = -EINVAL; - break; + (void)wc_rng_bank_fini(ctx); + pr_err("ERROR: wc_rng_bank_set_affinity_handlers() in wc_linuxkm_drbg_init_tfm() returned err %d\n", ret); + WC_DUMP_BACKTRACE_NONDEBUG; } } - - if (ret != 0) { - wc_linuxkm_drbg_ctx_clear(ctx); + else { + pr_err("ERROR: wc_rng_bank_init() in wc_linuxkm_drbg_init_tfm() returned err %d\n", ret); + if (ret == WC_NO_ERR_TRACE(MEMORY_E)) + ret = -ENOMEM; + else if (ret == WC_NO_ERR_TRACE(WC_TIMEOUT_E)) + ret = -ETIMEDOUT; + else if (ret == WC_NO_ERR_TRACE(INTERRUPTED_E)) + ret = -EINTR; + else + ret = -EINVAL; } return ret; @@ -1060,101 +1035,54 @@ static int wc_linuxkm_drbg_init_tfm(struct crypto_tfm *tfm) static void wc_linuxkm_drbg_exit_tfm(struct crypto_tfm *tfm) { - struct wc_linuxkm_drbg_ctx *ctx = (struct wc_linuxkm_drbg_ctx *)crypto_tfm_ctx(tfm); + struct wc_rng_bank *ctx = (struct wc_rng_bank *)crypto_tfm_ctx(tfm); + int ret = wc_rng_bank_fini(ctx); - wc_linuxkm_drbg_ctx_clear(ctx); + if (ret != 0) + pr_err("ERROR: wc_rng_bank_fini() in wc_linuxkm_drbg_exit_tfm() returned err %d\n", ret); return; } static int wc_linuxkm_drbg_default_instance_registered = 0; -/* get_drbg() uses atomic operations to get exclusive ownership of a DRBG - * without delay. It expects to be called in uninterruptible context, though - * works fine in any context. It starts by trying the DRBG matching the current - * CPU ID, and if that doesn't immediately succeed, it iterates upward until one - * succeeds. The first attempt will always succeed, even under intense load, - * unless there is or has recently been a reseed or mix-in operation competing - * with generators. - * - * Note that wc_linuxkm_drbg_init_tfm() allocates at least 4 DRBGs, regardless - * of nominal core count, to avoid stalling generators on unicore targets. - */ - -static inline struct wc_rng_inst *get_drbg(struct crypto_rng *tfm) { - struct wc_linuxkm_drbg_ctx *ctx = (struct wc_linuxkm_drbg_ctx *)crypto_rng_ctx(tfm); - int n, new_lock_value; - - /* check for mismatched handler or missing instance array. */ - if ((tfm->base.__crt_alg->cra_init != wc_linuxkm_drbg_init_tfm) || - (ctx->rngs == NULL)) - { +static struct wc_rng_bank_inst *linuxkm_get_drbg(struct crypto_rng *tfm) { + struct wc_rng_bank *ctx = (struct wc_rng_bank *)crypto_rng_ctx(tfm); + int err; + struct wc_rng_bank_inst *ret; + word32 flags = + WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST | + WC_RNG_BANK_FLAG_CAN_WAIT | + WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST; + + /* check for mismatched handler. */ + if (tfm->base.__crt_alg->cra_init != wc_linuxkm_drbg_init_tfm) { + pr_err("BUG: linuxkm_get_drbg() called on foreign tfm.\n"); return NULL; } - if ((tfm == crypto_default_rng) && (preempt_count() == 0)) { - #if defined(CONFIG_SMP) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) - migrate_disable(); /* this actually makes irq_count() nonzero, so that - * DISABLE_VECTOR_REGISTERS() is superfluous, but - * don't depend on that. - */ - #endif - local_bh_disable(); - new_lock_value = 2; - } + if (preempt_count() == 0) + flags |= WC_RNG_BANK_FLAG_AFFINITY_LOCK; else - { - new_lock_value = 1; - } + flags |= WC_RNG_BANK_FLAG_NO_VECTOR_OPS; - n = raw_smp_processor_id(); + err = wc_rng_bank_checkout(ctx, &ret, 0, WC_LINUXKM_INITRNG_TIMEOUT_SEC, flags); - for (;;) { - int expected = 0; - if (likely(__atomic_compare_exchange_n(&ctx->rngs[n].lock, &expected, new_lock_value, 0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE))) - return &ctx->rngs[n]; - ++n; - if (n >= (int)ctx->n_rngs) - n = 0; - cpu_relax(); - } - - __builtin_unreachable(); -} - -/* get_drbg_n() is used by bulk seed, mix-in, and reseed operations. It expects - * the caller to be able to wait until the requested DRBG is available. If the - * caller can't sleep and the requested DRBG is busy, it returns immediately -- - * this avoids priority inversions and deadlocks. - */ -static inline struct wc_rng_inst *get_drbg_n(struct wc_linuxkm_drbg_ctx *ctx, int n, int can_spin) { - int can_sleep = (preempt_count() == 0); - - for (;;) { - int expected = 0; - if (likely(__atomic_compare_exchange_n(&ctx->rngs[n].lock, &expected, 1, 0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE))) - return &ctx->rngs[n]; - if (can_sleep && can_spin) { - if (signal_pending(current)) - return NULL; - cond_resched(); - } - else - return NULL; + if (err != 0) { + pr_err("ERROR: wc_rng_bank_checkout() in linuxkm_get_drbg() returned err %d.\n", err); + WC_DUMP_BACKTRACE_NONDEBUG; + return NULL; } - __builtin_unreachable(); + return ret; } -static inline void put_drbg(struct wc_rng_inst *drbg) { - int migration_disabled = (drbg->lock == 2); - __atomic_store_n(&(drbg->lock),0,__ATOMIC_RELEASE); - - if (migration_disabled) { - local_bh_enable(); - #if defined(CONFIG_SMP) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) - migrate_enable(); - #endif +static void linuxkm_put_drbg(struct crypto_rng *tfm, struct wc_rng_bank_inst **drbg) { + struct wc_rng_bank *ctx = (struct wc_rng_bank *)crypto_rng_ctx(tfm); + int ret = wc_rng_bank_checkin(ctx, drbg); + if (ret != 0) { + pr_err("ERROR: wc_rng_bank_checkin() in linuxkm_put_drbg() returned err %d.\n", ret); + WC_DUMP_BACKTRACE_NONDEBUG; } } @@ -1188,196 +1116,43 @@ static inline struct crypto_rng *get_crypto_default_rng(void) { return current_crypto_default_rng; } -static int drbg_init_from(WC_RNG *source_rng, struct DRBG_internal* dest_drbg) { - int ret; - int need_vec_reenable; - - XMEMSET(dest_drbg, 0, sizeof(struct DRBG_internal)); - - need_vec_reenable = (DISABLE_VECTOR_REGISTERS() == 0); - - /* Don't copy out the low level DRBG itself -- it contains sensitive secret - * state. Instead, use it to generate fresh V and C values in a - * non-intrusive way. - */ - ret = wc_RNG_GenerateBlock(source_rng, dest_drbg->V, sizeof dest_drbg->V); - if (ret != 0) { - pr_err("drbg_init_from: wc_RNG_GenerateBlock for V returned %d\n", ret); - goto out; - } - ret = wc_RNG_GenerateBlock(source_rng, dest_drbg->C, sizeof dest_drbg->C); - if (ret != 0) { - pr_err("drbg_init_from: wc_RNG_GenerateBlock for C returned %d\n", ret); - goto out; - } - - dest_drbg->heap = source_rng->heap; -#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) - dest_drbg->devId = source_rng->devId; -#endif - - ret = wc_InitSha256_ex(&dest_drbg->sha256, dest_drbg->heap, -#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) - source_rng->dev_id -#else - INVALID_DEVID +#ifndef WC_DRBG_BANKREF + #error LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT requires WC_DRBG_BANKREF support. #endif - ); - if (ret != 0) - goto out; - - dest_drbg->reseedCtr = 1; - - ret = 0; - -out: - - if (need_vec_reenable) - REENABLE_VECTOR_REGISTERS(); - return ret; -} - -/* fork_default_rng() is a non-FIPS-compliant helper function to initialize an - * RNG for glue layer POSTs. Direct replacement for wc_InitRng(), and secure in - * principle, but not permissible to use as such in FIPS runtimes. - */ -static WC_MAYBE_UNUSED int fork_default_rng(WC_RNG *forked_rng) { - struct crypto_rng *current_crypto_default_rng; - struct wc_rng_inst *rng = NULL; - struct DRBG_internal *drbg = NULL; - struct DRBG_internal *drbg_scratch = NULL; - byte *health_check_scratch = NULL; - byte *newSeed_buf = NULL; +WC_MAYBE_UNUSED static int linuxkm_InitRng_DefaultRef(WC_RNG* rng) { int ret; - - if (forked_rng == NULL) - return BAD_FUNC_ARG; - - XMEMSET(forked_rng, 0, sizeof *forked_rng); - - health_check_scratch = - (byte *)XMALLOC(RNG_HEALTH_TEST_CHECK_SIZE, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (health_check_scratch == NULL) { - ret = MEMORY_E; - goto out; - } - - newSeed_buf = (byte*)XMALLOC(WC_DRBG_SEED_SZ + - WC_DRBG_SEED_BLOCK_SZ, - NULL, - DYNAMIC_TYPE_SEED); - if (newSeed_buf == NULL) { - ret = MEMORY_E; - goto out; - } - - drbg = (struct DRBG_internal *)XMALLOC(sizeof *drbg, NULL, - DYNAMIC_TYPE_RNG); - if (drbg == NULL) { - ret = MEMORY_E; - goto out; - } - - drbg_scratch = - (struct DRBG_internal *)XMALLOC(sizeof *drbg_scratch, NULL, - DYNAMIC_TYPE_RNG); - if (drbg_scratch == NULL) { - ret = MEMORY_E; - goto out; - } - - current_crypto_default_rng = get_crypto_default_rng(); + struct crypto_rng *current_crypto_default_rng = get_crypto_default_rng(); if (current_crypto_default_rng == NULL) { - ret = BAD_STATE_E; - goto out; - } - - rng = get_drbg(current_crypto_default_rng); - if (rng == NULL) { - ret = BAD_STATE_E; - goto out; - } - - if (rng->rng.status != WC_DRBG_OK) { - pr_err("fork_default_rng: rng->rng.status = %d\n", rng->rng.status); - ret = RNG_FAILURE_E; - goto out; + pr_warn_once("WARNING: get_crypto_default_rng() failed in linuxkm_InitRng_DefaultRef(); falling through to wc_InitRng().\n"); + return wc_InitRng(rng); } - - XMEMCPY(forked_rng, &rng->rng, sizeof *forked_rng); - forked_rng->drbg = (struct DRBG *)drbg; - forked_rng->drbg_scratch = drbg_scratch; - forked_rng->health_check_scratch = health_check_scratch; - forked_rng->newSeed_buf = newSeed_buf; - - ret = drbg_init_from(&rng->rng, (struct DRBG_internal*)forked_rng->drbg); - if (ret != 0) - goto out; - - ret = drbg_init_from(&rng->rng, (struct DRBG_internal*)forked_rng->drbg_scratch); - if (ret != 0) - goto out; - - put_drbg(rng); - rng = NULL; - - { - byte scratch[4]; - ret = wc_RNG_GenerateBlock(forked_rng, scratch, sizeof scratch); - if (ret != 0) - goto out; - } - - ret = 0; - -out: - - if (ret == 0) - return ret; else { - if (rng) - put_drbg(rng); - XFREE(drbg, rng->rng.heap, DYNAMIC_TYPE_RNG); - XFREE(drbg_scratch, rng->rng.heap, DYNAMIC_TYPE_RNG); - XFREE(health_check_scratch, rng->rng.heap, DYNAMIC_TYPE_RNG); - XFREE(newSeed_buf, rng->rng.heap, DYNAMIC_TYPE_RNG); - pr_warn("WARNING: fork_default_rng: ret=%d; falling through to wc_InitRng()\n", ret); - return wc_InitRng(forked_rng); + struct wc_rng_bank *default_bank = (struct wc_rng_bank *)crypto_rng_ctx(current_crypto_default_rng); + ret = wc_InitRng_BankRef(default_bank, rng); + return ret; } -} - -#define LKCAPI_INITRNG_FOR_SELFTEST(rng) fork_default_rng(rng) - -#else /* !LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT || !HAVE_HASHDRBG */ -#define LKCAPI_INITRNG_FOR_SELFTEST(rng) wc_InitRng(rng) + __builtin_unreachable(); +} +#define LKCAPI_INITRNG(rng) linuxkm_InitRng_DefaultRef(rng) -#endif /* !LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT || !HAVE_HASHDRBG */ +#endif /* LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT && HAVE_HASHDRBG */ static int wc_linuxkm_drbg_generate(struct crypto_rng *tfm, const u8 *src, unsigned int slen, u8 *dst, unsigned int dlen) { int ret, retried = 0; - int need_fpu_restore; - struct wc_rng_inst *drbg = get_drbg(tfm); + struct wc_rng_bank_inst *drbg = linuxkm_get_drbg(tfm); if (! drbg) { - pr_err_once("BUG: get_drbg() failed."); + pr_err_once("BUG: linuxkm_get_drbg() failed."); return -EFAULT; } - /* for the default RNG, make sure we don't cache an underlying SHA256 - * method that uses vector insns (forbidden from irq handlers). - */ - need_fpu_restore = (tfm == crypto_default_rng) ? (DISABLE_VECTOR_REGISTERS() == 0) : 0; - -retry: - if (slen > 0) { - ret = wc_RNG_DRBG_Reseed(&drbg->rng, src, slen); + ret = wc_RNG_DRBG_Reseed(WC_RNG_BANK_INST_TO_RNG(drbg), src, slen); if (ret != 0) { pr_warn_once("WARNING: wc_RNG_DRBG_Reseed returned %d\n",ret); ret = -EINVAL; @@ -1388,7 +1163,7 @@ static int wc_linuxkm_drbg_generate(struct crypto_rng *tfm, for (;;) { #define RNG_MAX_BLOCK_LEN_ROUNDED (RNG_MAX_BLOCK_LEN & ~0xfU) if (dlen > RNG_MAX_BLOCK_LEN_ROUNDED) { - ret = wc_RNG_GenerateBlock(&drbg->rng, dst, RNG_MAX_BLOCK_LEN_ROUNDED); + ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(drbg), dst, RNG_MAX_BLOCK_LEN_ROUNDED); if (ret == 0) { dlen -= RNG_MAX_BLOCK_LEN_ROUNDED; dst += RNG_MAX_BLOCK_LEN_ROUNDED; @@ -1396,38 +1171,48 @@ static int wc_linuxkm_drbg_generate(struct crypto_rng *tfm, } #undef RNG_MAX_BLOCK_LEN_ROUNDED else { - ret = wc_RNG_GenerateBlock(&drbg->rng, dst, dlen); - dlen -= dlen; + ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(drbg), dst, dlen); + if (ret == 0) + dlen = 0; } + if (dlen == 0) + break; + + if (ret == 0) + continue; + if (unlikely(ret == WC_NO_ERR_TRACE(RNG_FAILURE_E)) && (! retried)) { + if (slen > 0) + break; + retried = 1; - wc_FreeRng(&drbg->rng); - ret = wc_InitRng(&drbg->rng); + + ret = wc_rng_bank_inst_reinit((struct wc_rng_bank *)crypto_rng_ctx(tfm), + drbg, + WC_LINUXKM_INITRNG_TIMEOUT_SEC, + WC_RNG_BANK_FLAG_CAN_WAIT); + if (ret == 0) { - pr_warn("WARNING: reinitialized DRBG #%d after RNG_FAILURE_E.", raw_smp_processor_id()); - goto retry; + pr_warn("WARNING: reinitialized DRBG #%d after RNG_FAILURE_E from wc_RNG_GenerateBlock().", raw_smp_processor_id()); + continue; } else { pr_warn_once("ERROR: reinitialization of DRBG #%d after RNG_FAILURE_E failed with ret %d.", raw_smp_processor_id(), ret); ret = -EINVAL; + break; } } - else if (ret != 0) { - pr_warn_once("WARNING: wc_RNG_GenerateBlock returned %d\n",ret); + else { + pr_warn_once("ERROR: wc_linuxkm_drbg_generate() wc_RNG_GenerateBlock returned %d.\n",ret); ret = -EINVAL; break; } - - if (! dlen) - break; } out: - if (need_fpu_restore) - REENABLE_VECTOR_REGISTERS(); - put_drbg(drbg); + linuxkm_put_drbg(tfm, &drbg); return ret; } @@ -1435,13 +1220,10 @@ static int wc_linuxkm_drbg_generate(struct crypto_rng *tfm, static int wc_linuxkm_drbg_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) { - struct wc_linuxkm_drbg_ctx *ctx = (struct wc_linuxkm_drbg_ctx *)crypto_rng_ctx(tfm); - u8 *seed_copy = NULL; - int ret = 0; - int n; + struct wc_rng_bank *ctx = (struct wc_rng_bank *)crypto_rng_ctx(tfm); + int ret; - if ((tfm->base.__crt_alg->cra_init != wc_linuxkm_drbg_init_tfm) || - (ctx->rngs == NULL)) + if (tfm->base.__crt_alg->cra_init != wc_linuxkm_drbg_init_tfm) { pr_err_once("BUG: mismatched tfm."); return -EFAULT; @@ -1450,51 +1232,12 @@ static int wc_linuxkm_drbg_seed(struct crypto_rng *tfm, if (slen == 0) return 0; - seed_copy = (u8 *)malloc(slen + 2); - if (! seed_copy) - return -ENOMEM; - XMEMCPY(seed_copy + 2, seed, slen); - - /* this iteration counts down, whereas the iteration in get_drbg() counts - * up, to assure they can't possibly phase-lock to each other. - */ - for (n = ctx->n_rngs - 1; n >= 0; --n) { - struct wc_rng_inst *drbg = get_drbg_n(ctx, n, 1); - - if (! drbg) { - ret = -EINTR; - break; - } - - /* perturb the seed with the CPU ID, so that no DRBG has the exact same - * seed. - */ - seed_copy[0] = (u8)(n >> 8); - seed_copy[1] = (u8)n; - - { - /* for the default RNG, make sure we don't cache an underlying SHA256 - * method that uses vector insns (forbidden from irq handlers). - */ - int need_fpu_restore = (tfm == crypto_default_rng) ? (DISABLE_VECTOR_REGISTERS() == 0) : 0; - ret = wc_RNG_DRBG_Reseed(&drbg->rng, seed_copy, slen + 2); - if (need_fpu_restore) - REENABLE_VECTOR_REGISTERS(); - } - - if (ret != 0) { - pr_warn_once("WARNING: wc_RNG_DRBG_Reseed returned %d\n",ret); - ret = -EINVAL; - } - - put_drbg(drbg); - - if (ret != 0) - break; + ret = wc_rng_bank_seed(ctx, seed, slen, WC_LINUXKM_INITRNG_TIMEOUT_SEC, WC_RNG_BANK_FLAG_CAN_WAIT); + if (ret != 0) { + pr_err("wc_rng_bank_seed() in wc_linuxkm_drbg_seed() returned err %d.\n", ret); + ret = -EINVAL; } - free(seed_copy); - return ret; } @@ -1506,7 +1249,7 @@ static struct rng_alg wc_linuxkm_drbg = { .cra_name = WOLFKM_STDRNG_NAME, .cra_driver_name = WOLFKM_STDRNG_DRIVER, .cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, - .cra_ctxsize = sizeof(struct wc_linuxkm_drbg_ctx), + .cra_ctxsize = sizeof(struct wc_rng_bank), .cra_init = wc_linuxkm_drbg_init_tfm, .cra_exit = wc_linuxkm_drbg_exit_tfm, .cra_module = THIS_MODULE @@ -1549,9 +1292,9 @@ static int wc_linuxkm_drbg_loaded = 0; #ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS -static inline struct wc_linuxkm_drbg_ctx *get_default_drbg_ctx(void) { +static inline struct wc_rng_bank *get_default_drbg_ctx(void) { struct crypto_rng *current_crypto_default_rng = get_crypto_default_rng(); - struct wc_linuxkm_drbg_ctx *ctx = (current_crypto_default_rng ? (struct wc_linuxkm_drbg_ctx *)crypto_rng_ctx(current_crypto_default_rng) : NULL); + struct wc_rng_bank *ctx = (current_crypto_default_rng ? (struct wc_rng_bank *)crypto_rng_ctx(current_crypto_default_rng) : NULL); if (ctx && (! ctx->rngs)) { pr_err_once("BUG: get_default_drbg_ctx() found null ctx->rngs."); return NULL; @@ -1681,7 +1424,7 @@ static ssize_t wc_extract_crng_user(void __user *buf, size_t nbytes) { } static int wc_mix_pool_bytes(const void *buf, size_t len) { - struct wc_linuxkm_drbg_ctx *ctx; + struct wc_rng_bank *ctx; size_t i; int n; int can_sleep = (preempt_count() == 0); @@ -1693,19 +1436,20 @@ static int wc_mix_pool_bytes(const void *buf, size_t len) { return -EFAULT; for (n = ctx->n_rngs - 1; n >= 0; --n) { - struct wc_rng_inst *drbg = get_drbg_n(ctx, n, 0); + struct wc_rng_bank_inst *drbg; + int V_offset; - if (! drbg) + if (wc_rng_bank_checkout(ctx, &drbg, n, 0, WC_RNG_BANK_FLAG_NONE) != 0) continue; for (i = 0, V_offset = 0; i < len; ++i) { - ((struct DRBG_internal *)drbg->rng.drbg)->V[V_offset++] += ((byte *)buf)[i]; - if (V_offset == (int)sizeof ((struct DRBG_internal *)drbg->rng.drbg)->V) + ((struct DRBG_internal *)WC_RNG_BANK_INST_TO_RNG(drbg)->drbg)->V[V_offset++] += ((byte *)buf)[i]; + if (V_offset == (int)sizeof ((struct DRBG_internal *)WC_RNG_BANK_INST_TO_RNG(drbg)->drbg)->V) V_offset = 0; } - put_drbg(drbg); + wc_rng_bank_checkin(ctx, &drbg); if (can_sleep) { if (signal_pending(current)) return -EINTR; @@ -1717,40 +1461,23 @@ static int wc_mix_pool_bytes(const void *buf, size_t len) { } static int wc_crng_reseed(void) { - struct wc_linuxkm_drbg_ctx *ctx = get_default_drbg_ctx(); - int n; + struct wc_rng_bank *ctx = get_default_drbg_ctx(); int can_sleep = (preempt_count() == 0); + int ret; - if (! ctx) - return -EFAULT; - - for (n = ctx->n_rngs - 1; n >= 0; --n) { - struct wc_rng_inst *drbg = get_drbg_n(ctx, n, 1); - - if (! drbg) - return -EINTR; - - ((struct DRBG_internal *)drbg->rng.drbg)->reseedCtr = WC_RESEED_INTERVAL; - - if (can_sleep) { - byte scratch[4]; - int need_reenable_vec = (DISABLE_VECTOR_REGISTERS() == 0); - int ret = wc_RNG_GenerateBlock(&drbg->rng, scratch, (word32)sizeof(scratch)); - if (need_reenable_vec) - REENABLE_VECTOR_REGISTERS(); - if (ret != 0) - pr_err("ERROR: wc_crng_reseed() wc_RNG_GenerateBlock() for DRBG #%d returned %d.", n, ret); - put_drbg(drbg); - if (signal_pending(current)) - return -EINTR; - cond_resched(); - } - else { - put_drbg(drbg); - } + ret = wc_rng_bank_reseed(ctx, WC_LINUXKM_INITRNG_TIMEOUT_SEC, + can_sleep + ? + WC_RNG_BANK_FLAG_CAN_WAIT + : + WC_RNG_BANK_FLAG_NONE); + if (ret != 0) { + pr_err("ERROR: wc_rng_bank_reseed() returned err %d.\n", ret); + return -EINVAL; + } + else { + return 0; } - - return 0; } struct wolfssl_linuxkm_random_bytes_handlers random_bytes_handlers = { @@ -2266,4 +1993,8 @@ static int wc_linuxkm_drbg_cleanup(void) { #endif /* LINUXKM_LKCAPI_REGISTER_HASH_DRBG */ +#ifndef LKCAPI_INITRNG + #define LKCAPI_INITRNG(rng) wc_InitRng(rng) +#endif + #endif /* !WC_SKIP_INCLUDED_C_FILES */ diff --git a/linuxkm/module_exports.c.template b/linuxkm/module_exports.c.template index 2784041f8b..6af571d94a 100644 --- a/linuxkm/module_exports.c.template +++ b/linuxkm/module_exports.c.template @@ -66,6 +66,9 @@ #include #endif #include + #ifdef WC_RNG_BANK_SUPPORT + #include + #endif #endif #include #include diff --git a/linuxkm/module_hooks.c b/linuxkm/module_hooks.c index c92074b0a7..df7dad3201 100644 --- a/linuxkm/module_hooks.c +++ b/linuxkm/module_hooks.c @@ -297,8 +297,10 @@ void wc_linuxkm_relax_long_loop(void) { */ } #endif + return; } #endif + cpu_relax(); } #if defined(WC_LINUXKM_WOLFENTROPY_IN_GLUE_LAYER) @@ -1286,7 +1288,9 @@ static int set_up_wolfssl_linuxkm_pie_redirect_table(void) { wolfssl_linuxkm_pie_redirect_table.kvfree = kvfree; #endif +#ifndef LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT wolfssl_linuxkm_pie_redirect_table.get_random_bytes = get_random_bytes; +#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) wolfssl_linuxkm_pie_redirect_table.getnstimeofday = getnstimeofday; @@ -1475,9 +1479,7 @@ static int set_up_wolfssl_linuxkm_pie_redirect_table(void) { #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #endif /* !WOLFCRYPT_ONLY && !NO_CERTS */ -#ifdef WOLFSSL_DEBUG_BACKTRACE_ERROR_CODES wolfssl_linuxkm_pie_redirect_table.dump_stack = dump_stack; -#endif wolfssl_linuxkm_pie_redirect_table.preempt_count = my_preempt_count; #ifndef _raw_spin_lock_irqsave diff --git a/linuxkm/x86_vector_register_glue.c b/linuxkm/x86_vector_register_glue.c index 4e1e47ba27..c7bd83eaef 100644 --- a/linuxkm/x86_vector_register_glue.c +++ b/linuxkm/x86_vector_register_glue.c @@ -332,7 +332,8 @@ WARN_UNUSED_RESULT int wc_save_vector_registers_x86(enum wc_svr_flags flags) * a second look at preempt_count(). */ if (((preempt_count() & (NMI_MASK | HARDIRQ_MASK)) != 0) || (task_pid_nr(current) == 0)) { - VRG_PR_WARN_X("WARNING: wc_save_vector_registers_x86 called with preempt_count 0x%x and pid %d on CPU %d.\n", preempt_count(), task_pid_nr(current), raw_smp_processor_id()); + if (! (flags & WC_SVR_FLAG_INHIBIT)) + VRG_PR_WARN_X("WARNING: wc_save_vector_registers_x86(0x%x) called with preempt_count 0x%x and pid %d on CPU %d.\n", (unsigned)flags, preempt_count(), task_pid_nr(current), raw_smp_processor_id()); return WC_ACCEL_INHIBIT_E; } diff --git a/src/include.am b/src/include.am index 2b4c5faf66..fe97320637 100644 --- a/src/include.am +++ b/src/include.am @@ -185,6 +185,10 @@ if BUILD_MEMUSE src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfentropy.c endif +if BUILD_RNG_BANK +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/rng_bank.c +endif + src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/kdf.c if BUILD_RSA @@ -434,6 +438,10 @@ if BUILD_MEMUSE src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfentropy.c endif +if BUILD_RNG_BANK +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/rng_bank.c +endif + src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/kdf.c if BUILD_RSA @@ -789,6 +797,9 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/random.c if BUILD_MEMUSE src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfentropy.c endif +if BUILD_RNG_BANK +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/rng_bank.c +endif endif endif !BUILD_FIPS_V2_PLUS diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index b24a7710d3..9e24d9aa47 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -659,6 +659,12 @@ const char* wc_GetErrorString(int error) case MLKEM_PUB_HASH_E: return "ML-KEM priv key's stored hash doesn't match encoded pub key"; + case BUSY_E: + return "Object is busy"; + + case ALREADY_E: + return "Operation was redundant or preempted"; + case MAX_CODE_E: case WC_SPAN1_MIN_CODE_E: case MIN_CODE_E: diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index ba526958ca..4a50de6cbb 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -68,6 +68,9 @@ This library contains implementation for the random number generator. #include +#ifdef WC_RNG_BANK_SUPPORT + #include +#endif #include #ifndef WC_NO_RNG /* if not FIPS and RNG is disabled then do not compile */ @@ -371,7 +374,8 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type, #ifdef WC_VERBOSE_RNG if (ret != 0) - WOLFSSL_DEBUG_PRINTF("%s failed with err = %d", __FUNCTION__, ret); + WOLFSSL_DEBUG_PRINTF("ERROR: %s failed with err = %d", __FUNCTION__, + ret); #endif return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; @@ -414,7 +418,8 @@ static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz #ifdef WC_VERBOSE_RNG if (ret != 0) - WOLFSSL_DEBUG_PRINTF("Hash_DRBG_Reseed failed with err %d.", ret); + WOLFSSL_DEBUG_PRINTF("ERROR: Hash_DRBG_Reseed failed with err %d.", + ret); #endif return ret; @@ -545,7 +550,7 @@ static int Hash_gen(DRBG_internal* drbg, byte* out, word32 outSz, const byte* V) * and (2) the caller will actually see the DRBG_FAILURE code, and is * free to (and probably will) log it itself. */ - WOLFSSL_DEBUG_PRINTF("Hash_gen failed with err %d.", ret); + WOLFSSL_DEBUG_PRINTF("ERROR: Hash_gen failed with err %d.", ret); } #endif @@ -662,7 +667,8 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz) #ifdef WC_VERBOSE_RNG if ((ret != DRBG_SUCCESS) && (ret != DRBG_FAILURE)) { /* see note above regarding log spam reduction */ - WOLFSSL_DEBUG_PRINTF("Hash_DRBG_Generate failed with err %d.", ret); + WOLFSSL_DEBUG_PRINTF("ERROR: Hash_DRBG_Generate failed with err %d.", + ret); } #endif @@ -962,7 +968,9 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, ret = seedCb(&rng->seed, seed, seedSz); if (ret != 0) { #ifdef WC_VERBOSE_RNG - WOLFSSL_DEBUG_PRINTF("seedCb in _InitRng() failed with err = %d", ret); + WOLFSSL_DEBUG_PRINTF( + "ERROR: seedCb in _InitRng() failed with err = %d", + ret); #endif ret = DRBG_FAILURE; } @@ -974,7 +982,9 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG_EX("Seed generation failed... %d", ret); #elif defined(WC_VERBOSE_RNG) - WOLFSSL_DEBUG_PRINTF("wc_GenerateSeed() in _InitRng() failed with err %d", ret); + WOLFSSL_DEBUG_PRINTF( + "ERROR: wc_GenerateSeed() in _InitRng() failed with err %d", + ret); #endif ret = DRBG_FAILURE; rng->status = DRBG_FAILED; @@ -988,7 +998,9 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, } #elif defined(WC_VERBOSE_RNG) if (ret != DRBG_SUCCESS) { - WOLFSSL_DEBUG_PRINTF("wc_RNG_TestSeed() in _InitRng() returned err %d.", ret); + WOLFSSL_DEBUG_PRINTF( + "ERROR: wc_RNG_TestSeed() in _InitRng() returned err %d.", + ret); } #endif @@ -1166,7 +1178,8 @@ static int PollAndReSeed(WC_RNG* rng) ret = seedCb(&rng->seed, newSeed, SEED_SZ + SEED_BLOCK_SZ); if (ret != 0) { #ifdef WC_VERBOSE_RNG - WOLFSSL_DEBUG_PRINTF("seedCb() in PollAndReSeed() failed with err %d", ret); + WOLFSSL_DEBUG_PRINTF("ERROR: seedCb() in PollAndReSeed() " + "failed with err %d", ret); #endif ret = DRBG_FAILURE; } @@ -1176,7 +1189,9 @@ static int PollAndReSeed(WC_RNG* rng) SEED_SZ + SEED_BLOCK_SZ); if (ret != 0) { #ifdef WC_VERBOSE_RNG - WOLFSSL_DEBUG_PRINTF("wc_GenerateSeed() in PollAndReSeed() failed with err %d", ret); + WOLFSSL_DEBUG_PRINTF( + "ERROR: wc_GenerateSeed() in PollAndReSeed() failed with " + "err %d", ret); #endif ret = DRBG_FAILURE; } @@ -1186,7 +1201,9 @@ static int PollAndReSeed(WC_RNG* rng) ret = wc_RNG_TestSeed(newSeed, SEED_SZ + SEED_BLOCK_SZ); #ifdef WC_VERBOSE_RNG if (ret != DRBG_SUCCESS) - WOLFSSL_DEBUG_PRINTF("wc_RNG_TestSeed() in PollAndReSeed() returned err %d.", ret); + WOLFSSL_DEBUG_PRINTF( + "ERROR: wc_RNG_TestSeed() in PollAndReSeed() returned " + "err %d.", ret); #endif } if (ret == DRBG_SUCCESS) @@ -1210,8 +1227,12 @@ static int PollAndReSeed(WC_RNG* rng) #endif /* place a generated block in output */ +#ifdef WC_RNG_BANK_SUPPORT +static int wc_local_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) +#else WOLFSSL_ABI int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) +#endif { int ret; @@ -1260,7 +1281,8 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) ret = (int)CUSTOM_RAND_GENERATE_BLOCK(output, sz); #ifdef WC_VERBOSE_RNG if (ret != 0) - WOLFSSL_DEBUG_PRINTF("CUSTOM_RAND_GENERATE_BLOCK failed with err %d.", ret); + WOLFSSL_DEBUG_PRINTF( + "ERROR: CUSTOM_RAND_GENERATE_BLOCK failed with err %d.", ret); #endif #else @@ -1311,6 +1333,42 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) return ret; } +#ifdef WC_RNG_BANK_SUPPORT +WOLFSSL_ABI +int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) +{ + if (rng == NULL) + return BAD_FUNC_ARG; + + if (rng->status == WC_DRBG_BANKREF) { + int ret; + struct wc_rng_bank_inst *bank_inst = NULL; + + ret = wc_local_rng_bank_checkout_for_bankref(rng->bankref, &bank_inst); + if (ret != 0) + return ret; + if (bank_inst == NULL) + return BAD_STATE_E; + ret = wc_local_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(bank_inst), + output, sz); + { + int checkin_ret = wc_rng_bank_checkin(rng->bankref, &bank_inst); + if (checkin_ret != 0) { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "ERROR: wc_RNG_GenerateBlock() wc_rng_bank_checkin() " + "failed with err %d.", checkin_ret); +#endif + if (ret == 0) + ret = checkin_ret; + } + } + return ret; + } + else + return wc_local_RNG_GenerateBlock(rng, output, sz); +} +#endif int wc_RNG_GenerateByte(WC_RNG* rng, byte* b) { @@ -1325,6 +1383,11 @@ int wc_FreeRng(WC_RNG* rng) if (rng == NULL) return BAD_FUNC_ARG; +#ifdef WC_RNG_BANK_SUPPORT + if (rng->status == WC_DRBG_BANKREF) + return wc_BankRef_Release(rng); +#endif /* WC_RNG_BANK_SUPPORT */ + #if defined(WOLFSSL_ASYNC_CRYPT) wolfAsync_DevCtxFree(&rng->asyncDev, WOLFSSL_ASYNC_MARKER_RNG); #endif @@ -3071,32 +3134,10 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #elif defined(WOLFSSL_LINUXKM) - /* When registering the kernel default DRBG with a native/intrinsic entropy - * source, fallback to get_random_bytes() isn't allowed because we replace - * it with our DRBG. - */ - - #if defined(HAVE_ENTROPY_MEMUSE) && \ - defined(LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) - - int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) - { - (void)os; - return wc_Entropy_Get(MAX_ENTROPY_BITS, output, sz); - } - - #elif (defined(HAVE_INTEL_RDSEED) || defined(HAVE_AMD_RDSEED)) && \ - defined(LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) - - int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) - { - (void)os; - return wc_GenerateSeed_IntelRD(NULL, output, sz); - } - - #else /* !((HAVE_ENTROPY_MEMUSE || HAVE_*_RDSEED) && LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) */ + #ifndef LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT + #include + #endif - #include int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) { (void)os; @@ -3104,11 +3145,9 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #ifdef HAVE_ENTROPY_MEMUSE ret = wc_Entropy_Get(MAX_ENTROPY_BITS, output, sz); - if (ret == 0) { + if (ret == 0) return 0; - } #ifdef ENTROPY_MEMUSE_FORCE_FAILURE - /* Don't fallback to /dev/urandom. */ return ret; #endif #endif @@ -3116,23 +3155,30 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #if defined(HAVE_INTEL_RDSEED) || defined(HAVE_AMD_RDSEED) if (IS_INTEL_RDSEED(intel_flags)) { ret = wc_GenerateSeed_IntelRD(NULL, output, sz); - #ifndef FORCE_FAILURE_RDSEED if (ret == 0) - #endif - { - return ret; - } + return 0; + #ifdef FORCE_FAILURE_RDSEED + return ret; + #endif } #endif /* HAVE_INTEL_RDSEED || HAVE_AMD_RDSEED */ + #ifdef LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT + #if !defined(HAVE_ENTROPY_MEMUSE) && \ + !defined(HAVE_INTEL_RDSEED) && \ + !defined(HAVE_AMD_RDSEED) + #error LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT requires an intrinsic entropy source. + #else + return ret; + #endif + #else (void)ret; get_random_bytes(output, sz); return 0; + #endif } - #endif /* !(HAVE_*_RDSEED && LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) */ - #elif defined(WOLFSSL_BSDKM) #include int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) diff --git a/wolfcrypt/src/rng_bank.c b/wolfcrypt/src/rng_bank.c new file mode 100644 index 0000000000..f23c805846 --- /dev/null +++ b/wolfcrypt/src/rng_bank.c @@ -0,0 +1,723 @@ +/* rng_bank.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include + +#ifdef WC_RNG_BANK_SUPPORT + +#include +#include + +WOLFSSL_API int wc_rng_bank_init( + struct wc_rng_bank *ctx, + int n_rngs, + word32 flags, + int timeout_secs, + void *heap, + int devId) +{ + int i; + int ret; + int need_reenable_vec = 0; + + if ((ctx == NULL) || (n_rngs <= 0)) + return BAD_FUNC_ARG; + + XMEMSET(ctx, 0, sizeof(*ctx)); + + wolfSSL_RefInit(&ctx->refcount, &ret); + if (ret != 0) + return ret; + + ctx->flags = flags | WC_RNG_BANK_FLAG_INITED; + ctx->heap = heap; + + ctx->rngs = (struct wc_rng_bank_inst *) + XMALLOC(sizeof(*ctx->rngs) * (size_t)n_rngs, + heap, DYNAMIC_TYPE_RNG); + if (! ctx->rngs) + ret = MEMORY_E; + + if (ret == 0) { + XMEMSET(ctx->rngs, 0, sizeof(*ctx->rngs) * (size_t)n_rngs); + ctx->n_rngs = n_rngs; + + for (i = 0; i < n_rngs; ++i) { +#ifdef WC_VERBOSE_RNG + int nretries = 0; +#endif + time_t ts1 = XTIME(0); + for (;;) { + time_t ts2; + + if (flags & WC_RNG_BANK_FLAG_NO_VECTOR_OPS) + need_reenable_vec = (DISABLE_VECTOR_REGISTERS() == 0); + ret = wc_InitRngNonce_ex( + WC_RNG_BANK_INST_TO_RNG(ctx->rngs + i), + (byte *)&ctx->rngs[i], sizeof(byte *), heap, devId); + + if (need_reenable_vec) + REENABLE_VECTOR_REGISTERS(); + /* if we're allowed to sleep, relax the loop between each inner + * iteration even on success, assuring relaxation of the outer + * iterations. + */ + WC_RELAX_LONG_LOOP(); + if (ret == 0) + break; + /* Allow interrupt only if we're stuck spinning retries -- i.e., + * don't allow an untimely user signal to derail an + * initialization that is proceeding expeditiously. + */ + ret = WC_CHECK_FOR_INTR_SIGNALS(); + if (ret == WC_NO_ERR_TRACE(INTERRUPTED_E)) + break; + ts2 = XTIME(0); + if (ts2 - ts1 > timeout_secs) { + ret = WC_TIMEOUT_E; + break; + } +#ifdef WC_VERBOSE_RNG + ++nretries; +#endif + } + if (ret != 0) { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "ERROR: wc_InitRng returned %d after %d retries.\n", ret, + nretries); +#endif + break; + } + } + } + + if (ret != 0) + (void)wc_rng_bank_fini(ctx); + + return ret; +} + +WOLFSSL_API int wc_rng_bank_new( + struct wc_rng_bank **ctx, + int n_rngs, + word32 flags, + int timeout_secs, + void *heap, + int devId) +{ + int ret; + + if ((ctx == NULL) || (n_rngs <= 0)) + return BAD_FUNC_ARG; + + *ctx = (struct wc_rng_bank *)XMALLOC(sizeof(struct wc_rng_bank), heap, DYNAMIC_TYPE_RNG); + if (*ctx == NULL) + return MEMORY_E; + + ret = wc_rng_bank_init(*ctx, n_rngs, flags, timeout_secs, heap, devId); + + if (ret != 0) { + XFREE(*ctx, heap, DYNAMIC_TYPE_RNG); + *ctx = NULL; + } + + return ret; +} + +WOLFSSL_API 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) +{ + if ((ctx == NULL) || + (! (ctx->flags & WC_RNG_BANK_FLAG_INITED))) + { + return BAD_FUNC_ARG; + } + if ((affinity_lock_cb == NULL) ^ (affinity_unlock_cb == NULL)) + return BAD_FUNC_ARG; + if (wolfSSL_RefCur(ctx->refcount) != 1) + return BUSY_E; + ctx->affinity_lock_cb = affinity_lock_cb; + ctx->affinity_get_id_cb = affinity_get_id_cb; + ctx->affinity_unlock_cb = affinity_unlock_cb; + ctx->cb_arg = cb_arg; + return 0; +} + +WOLFSSL_API int wc_rng_bank_fini(struct wc_rng_bank *ctx) { + int i; + + if (ctx == NULL) + return BAD_FUNC_ARG; + + if (ctx->flags == WC_RNG_BANK_FLAG_NONE) + return 0; + + if (! (ctx->flags & WC_RNG_BANK_FLAG_INITED)) + return BAD_FUNC_ARG; + + if (wolfSSL_RefCur(ctx->refcount) > 1) + return BUSY_E; + + if (ctx->rngs) { + for (i = 0; i < ctx->n_rngs; ++i) { + if (ctx->rngs[i].lock != 0) { + /* better to leak than to crash. */ +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "BUG: wc_rng_bank_fini() called with RNG #%d still " + "locked.\n", i); +#endif + return BUSY_E; + } + } + + for (i = 0; i < ctx->n_rngs; ++i) { + wc_FreeRng(&ctx->rngs[i].rng); + } + + XFREE(ctx->rngs, ctx->heap, DYNAMIC_TYPE_RNG); + ctx->rngs = NULL; + ctx->n_rngs = 0; + } + + wolfSSL_RefFree(&ctx->refcount); + + ctx->flags = WC_RNG_BANK_FLAG_NONE; + ctx->cb_arg = NULL; + + return 0; +} + +WOLFSSL_API int wc_rng_bank_free(struct wc_rng_bank **ctx) { + int ret; + void *heap; + + if (ctx == NULL) + return BAD_FUNC_ARG; + + if (*ctx == NULL) + return 0; + + heap = (*ctx)->heap; + + ret = wc_rng_bank_fini(*ctx); + + if (ret == 0) { + XFREE(*ctx, heap, DYNAMIC_TYPE_RNG); + *ctx = NULL; + } + + return ret; +} + +/* wc_rng_bank_checkout() uses atomic operations to get exclusive ownership of a + * DRBG without delay. It expects to be called in uninterruptible context, + * though works fine in any context. When _PREFER_AFFINITY_INST, it starts by + * trying the DRBG matching the local DRBG (usually the current CPU ID, returned + * by bank->affinity_get_id_cb()), and if that doesn't immediately succeed, and + * _CAN_FAIL_OVER_INST, it iterates upward until one succeeds. The first + * attempt will always succeed, even under intense load, unless there is or has + * recently been a reseed or mix-in operation competing with generators. + */ +WOLFSSL_API 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) +{ + int new_lock_value = WC_RNG_BANK_INST_LOCK_HELD; + int ret = 0; + time_t ts1, ts2; + int n_rngs_tried = 0; + + if ((bank == NULL) || + (! (bank->flags & WC_RNG_BANK_FLAG_INITED)) || + (rng_inst == NULL)) + { + return BAD_FUNC_ARG; + } + + if ((flags & WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST) && + (bank->affinity_get_id_cb == NULL)) + { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "BUG: wc_rng_bank_checkout() called with _PREFER_AFFINITY_INST but " + "no _get_id_cb.\n"); +#endif + return BAD_FUNC_ARG; + } + + if (flags & WC_RNG_BANK_FLAG_AFFINITY_LOCK) { + if ((bank->affinity_lock_cb == NULL) || + (bank->affinity_unlock_cb == NULL)) + { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "BUG: wc_rng_bank_checkout() called with _AFFINITY_LOCK but " + "missing _lock_cb.\n"); +#endif + return BAD_FUNC_ARG; + } + ret = bank->affinity_lock_cb(bank->cb_arg); + if (ret == 0) + new_lock_value |= WC_RNG_BANK_INST_LOCK_AFFINITY_LOCKED; + else if (ret != WC_NO_ERR_TRACE(ALREADY_E)) + return ret; + } + + if (flags & WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST) { + preferred_inst_offset = -1; + ret = bank->affinity_get_id_cb(bank->cb_arg, &preferred_inst_offset); + if (ret != 0) { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "BUG: bank->affinity_get_id_cb() returned err %d.\n", ret); +#endif + } + else if (((preferred_inst_offset < 0) || + (preferred_inst_offset >= bank->n_rngs))) + { + ret = BAD_INDEX_E; + } + } + else { + if ((preferred_inst_offset < 0) || + (preferred_inst_offset >= bank->n_rngs)) + { + ret = BAD_INDEX_E; + } + } + + if ((timeout_secs > 0) && (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) + ts1 = XTIME(0); + else + ts1 = 0; /* mollify -Wmaybe-uninitialized... */ + + for (; ret == 0;) { + int expected = 0; + + if (wolfSSL_Atomic_Int_CompareExchange( + &bank->rngs[preferred_inst_offset].lock, + &expected, + new_lock_value)) + { + *rng_inst = &bank->rngs[preferred_inst_offset]; + + if ((! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) && + (((struct DRBG_internal *)(*rng_inst)->rng.drbg)->reseedCtr >= + WC_RESEED_INTERVAL) && + (flags & WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST) && + (n_rngs_tried < bank->n_rngs)) + { + WOLFSSL_ATOMIC_STORE((*rng_inst)->lock, WC_RNG_BANK_INST_LOCK_FREE); + } + else { +#ifdef WC_VERBOSE_RNG + if ((! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) && + (((struct DRBG_internal *)(*rng_inst)->rng.drbg)->reseedCtr >= + WC_RESEED_INTERVAL)) + { + WOLFSSL_DEBUG_PRINTF( + "WARNING: wc_rng_bank_checkout() returning RNG ID %d, " + "currently marked for reseed, to !_CAN_WAIT caller.\n", + preferred_inst_offset); + } + + /* Note that a caller can still encounter a PollAndReSeed() via + * wc_RNG_GenerateBlock() if a call bumps reseedCtr up to + * WC_RESEED_INTERVAL. In kernel mode, the default interval is + * the SP 800-90A max of 2.81E+14, which is unlikely to be + * reached in practice. + */ +#endif + + if ((flags | bank->flags) & WC_RNG_BANK_FLAG_NO_VECTOR_OPS) { + if (DISABLE_VECTOR_REGISTERS() == 0) + WOLFSSL_ATOMIC_STORE((*rng_inst)->lock, new_lock_value | + WC_RNG_BANK_INST_LOCK_VEC_OPS_INH); + } + + return 0; /* Short-circuit return, holding onto RNG and affinity + * locks and vector register inhibition. + */ + } + } + + if (flags & WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST) { + if ((! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) && + (n_rngs_tried >= bank->n_rngs)) + { + ret = BUSY_E; + break; /* jump to cleanup. */ + } + ++preferred_inst_offset; + if (preferred_inst_offset >= bank->n_rngs) + preferred_inst_offset = 0; + ++n_rngs_tried; + } + else { + if (! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) { + ret = BUSY_E; + break; /* jump to cleanup. */ + } + } + + if (flags & WC_RNG_BANK_FLAG_AFFINITY_LOCK) + (void)bank->affinity_unlock_cb(bank->cb_arg); + + ret = WC_CHECK_FOR_INTR_SIGNALS(); + if (ret == WC_NO_ERR_TRACE(INTERRUPTED_E)) + return ret; /* immediate return -- no locks held */ + + if (timeout_secs > 0) { + ts2 = XTIME(0); + if (ts2 - ts1 >= timeout_secs) + return WC_TIMEOUT_E; /* immediate return -- no locks held */ + } + WC_RELAX_LONG_LOOP(); + + if (flags & WC_RNG_BANK_FLAG_AFFINITY_LOCK) { + ret = bank->affinity_lock_cb(bank->cb_arg); + if (ret) + return ret; /* immediate return -- no locks held */ + } + + /* Note that we may have been migrated at this point, but it doesn't + * matter -- we only reach this point if we have to retry/iterate. + */ + } + + if (flags & WC_RNG_BANK_FLAG_AFFINITY_LOCK) + (void)bank->affinity_unlock_cb(bank->cb_arg); + + return ret; +} + +#ifdef WC_DRBG_BANKREF +WOLFSSL_LOCAL int wc_local_rng_bank_checkout_for_bankref( + struct wc_rng_bank *bank, + struct wc_rng_bank_inst **rng_inst) +{ + return wc_rng_bank_checkout( + bank, rng_inst, 0, 0, + WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST | + WC_RNG_BANK_FLAG_CAN_WAIT | + ((bank->affinity_get_id_cb != NULL) ? WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST : 0) | + ((bank->affinity_lock_cb != NULL) ? WC_RNG_BANK_FLAG_AFFINITY_LOCK : 0)); +} +#endif /* WC_DRBG_BANKREF */ + +WOLFSSL_API int wc_rng_bank_checkin( + struct wc_rng_bank *bank, + struct wc_rng_bank_inst **rng_inst) +{ + int lockval; + + if ((bank == NULL) || (rng_inst == NULL) || (*rng_inst == NULL)) + return BAD_FUNC_ARG; + + lockval = (int)WOLFSSL_ATOMIC_LOAD((*rng_inst)->lock); + + WOLFSSL_ATOMIC_STORE((*rng_inst)->lock, WC_RNG_BANK_INST_LOCK_FREE); + + *rng_inst = NULL; + + if (lockval & WC_RNG_BANK_INST_LOCK_VEC_OPS_INH) + REENABLE_VECTOR_REGISTERS(); + + if (lockval & WC_RNG_BANK_INST_LOCK_AFFINITY_LOCKED) + return bank->affinity_unlock_cb(bank->cb_arg); + else + return 0; +} + +/* note the rng_inst passed to wc_rng_bank_inst_reinit() must have been obtained + * via wc_rng_bank_checkout() to assure that the caller holds the proper locks. + */ +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) +{ + int ret; + time_t ts1 = 0; + int devId; + + if ((rng_inst == NULL) || + (rng_inst->rng.drbg == NULL)) + { + return BAD_FUNC_ARG; + } + + if ((timeout_secs > 0) && (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) + ts1 = XTIME(0); + +#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + devId = rng_inst->rng.devId; +#else + devId = INVALID_DEVID; +#endif + + wc_FreeRng(&rng_inst->rng); + + for (;;) { + ret = wc_InitRngNonce_ex(WC_RNG_BANK_INST_TO_RNG(rng_inst), + (byte *)&rng_inst, sizeof(byte *), + bank->heap, devId); + if (ret == 0) + break; + if (! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "WARNING: wc_rng_bank_inst_reinit() returning err %d.\n", ret); +#endif + break; + } + + if (timeout_secs > 0) { + time_t ts2 = XTIME(0); + if (ts2 - ts1 >= timeout_secs) { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "WARNING: wc_rng_bank_inst_reinit() timed out, err %d.\n", + ret); +#endif + break; + } + } + } + + return ret; +} + +WOLFSSL_API int wc_rng_bank_seed(struct wc_rng_bank *bank, + const byte* seed, word32 seedSz, + int timeout_secs, + word32 flags) +{ + int ret = 0; + int n; + + if ((bank == NULL) || + (! (bank->flags & WC_RNG_BANK_FLAG_INITED))) + { + return BAD_FUNC_ARG; + } + + if (seedSz == 0) + return 0; + + /* this iteration counts down, whereas the iteration in get_drbg() counts + * up, to assure they can't possibly phase-lock to each other. + */ + for (n = bank->n_rngs - 1; n >= 0; --n) { + struct wc_rng_bank_inst *drbg; + ret = wc_rng_bank_checkout(bank, &drbg, n, timeout_secs, flags); + if (ret != 0) { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "WARNING: wc_rng_bank_seed(): wc_rng_bank_checkout() for " + "inst#%d returned err %d.\n", n, ret); +#endif + break; + } + else if (drbg->rng.drbg == NULL) { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "WARNING: wc_rng_bank_seed(): inst#%d has null .drbg.\n", n); +#endif + ret = BAD_STATE_E; + } + else if ((ret = wc_RNG_DRBG_Reseed(WC_RNG_BANK_INST_TO_RNG(drbg), seed, + seedSz)) != 0) + { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "WARNING: wc_rng_bank_seed(): Hash_DRBG_Reseed() for inst#%d " + "returned %d\n", n, ret); +#endif + } + + (void)wc_rng_bank_checkin(bank, &drbg); + + if (ret != 0) + break; + } + + return ret; +} + +WOLFSSL_API int wc_rng_bank_reseed(struct wc_rng_bank *bank, + int timeout_secs, + word32 flags) +{ + int n; + int ret; + time_t ts1 = 0; + + if (! bank) + return BAD_FUNC_ARG; + + if (flags & (WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST | + WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST)) + return BAD_FUNC_ARG; + + if ((timeout_secs > 0) && (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) + ts1 = XTIME(0); + + for (n = bank->n_rngs - 1; n >= 0; --n) { + struct wc_rng_bank_inst *drbg; + + ret = wc_rng_bank_checkout(bank, &drbg, n, timeout_secs, flags); + if (ret != 0) + return ret; + + ((struct DRBG_internal *)drbg->rng.drbg)->reseedCtr = + WC_RESEED_INTERVAL; + + if (flags & WC_RNG_BANK_FLAG_CAN_WAIT) { + byte scratch[4]; + for (;;) { + time_t ts2; + ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(drbg), scratch, + (word32)sizeof(scratch)); + if (ret == 0) + break; + if ((timeout_secs <= 0) || + (! (flags & WC_RNG_BANK_FLAG_CAN_WAIT))) + { + break; + } + ts2 = XTIME(0); + if (ts2 - ts1 > timeout_secs) { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "ERROR: timeout after attempted reseed by " + "wc_RNG_GenerateBlock() for DRBG #%d, err %d.", n, ret); +#endif + ret = WC_TIMEOUT_E; + break; + } + } +#ifdef WC_VERBOSE_RNG + if ((ret != 0) && (ret != WC_NO_ERR_TRACE(WC_TIMEOUT_E))) + WOLFSSL_DEBUG_PRINTF( + "ERROR: wc_crng_reseed() wc_RNG_GenerateBlock() " + "for DRBG #%d returned %d.", n, ret); +#endif + wc_rng_bank_checkin(bank, &drbg); + if (ret == WC_NO_ERR_TRACE(WC_TIMEOUT_E)) + return ret; + ret = WC_CHECK_FOR_INTR_SIGNALS(); + if (ret == WC_NO_ERR_TRACE(INTERRUPTED_E)) + return ret; + WC_RELAX_LONG_LOOP(); + } + else { + wc_rng_bank_checkin(bank, &drbg); + } + } + + return 0; +} + +#ifdef WC_DRBG_BANKREF + +WOLFSSL_API int wc_InitRng_BankRef(struct wc_rng_bank *bank, WC_RNG *rng) +{ + int ret; + + if ((bank == NULL) || + (! (bank->flags & WC_RNG_BANK_FLAG_INITED)) || + (rng == NULL)) + { + return BAD_FUNC_ARG; + } + + XMEMSET(rng, 0, sizeof(*rng)); + + wolfSSL_RefInc(&bank->refcount, &ret); + + if (ret != 0) + return ret; + + rng->heap = bank->heap; + rng->status = WC_DRBG_BANKREF; + rng->bankref = bank; + + return 0; +} + +WOLFSSL_API int wc_BankRef_Release(WC_RNG *rng) +{ + int isZero = 0; + int ret = 0; + if (rng->bankref == NULL) + return BAD_FUNC_ARG; + wolfSSL_RefDec(&rng->bankref->refcount, &isZero, &ret); +#ifdef WC_VERBOSE_RNG + if (isZero) + WOLFSSL_DEBUG_PRINTF( + "BUG: wc_BankRef_Release() popped refcount to zero.\n"); +#else + (void)isZero; +#endif + rng->heap = NULL; + rng->status = WC_DRBG_NOT_INIT; + rng->bankref = NULL; + return ret; +} + +WOLFSSL_API int wc_rng_new_bankref(struct wc_rng_bank *bank, WC_RNG **rng) { + int ret; + + if ((bank == NULL) || + (! (bank->flags & WC_RNG_BANK_FLAG_INITED)) || + (rng == NULL)) + { + return BAD_FUNC_ARG; + } + + *rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), bank->heap, DYNAMIC_TYPE_RNG); + if (*rng == NULL) { + return MEMORY_E; + } + + ret = wc_InitRng_BankRef(bank, *rng); + if (ret != 0) { + XFREE(*rng, bank->heap, DYNAMIC_TYPE_RNG); + *rng = NULL; + } + + return ret; +} + +#endif /* WC_DRBG_BANKREF */ + +#endif /* WC_RNG_BANK_SUPPORT */ diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index 462e85a6ca..3b376e0935 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -1698,6 +1698,7 @@ void wolfSSL_RefWithMutexFree(wolfSSL_RefWithMutex* ref) if (wc_FreeMutex(&ref->mutex) != 0) { WOLFSSL_MSG("Failed to free mutex of reference counting!"); } + ref->count = 0; } void wolfSSL_RefWithMutexInc(wolfSSL_RefWithMutex* ref, int* err) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 69176ad82f..286c6348e6 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -325,6 +325,9 @@ static const byte const_byte_array[] = "A+Gd\0\0\0"; #include #if !defined(WC_NO_RNG) #include + #ifdef WC_RNG_BANK_SUPPORT + #include + #endif #endif #include #include @@ -687,6 +690,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dsa_test(void); WOLFSSL_TEST_SUBROUTINE wc_test_ret_t srp_test(void); #ifndef WC_NO_RNG WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void); +#ifdef WC_RNG_BANK_SUPPORT +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void); +#endif #endif /* WC_NO_RNG */ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pwdbased_test(void); #if defined(USE_CERT_BUFFERS_2048) && \ @@ -2133,6 +2139,12 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ TEST_FAIL("RANDOM test failed!\n", ret); else TEST_PASS("RANDOM test passed!\n"); +#ifdef WC_RNG_BANK_SUPPORT + if ((ret = random_bank_test()) != 0) + TEST_FAIL("RNGBANK test failed!\n", ret); + else + TEST_PASS("RNGBANK test passed!\n"); +#endif #endif /* WC_NO_RNG */ #ifdef WOLFSSL_SHAKE128 @@ -20133,7 +20145,338 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void) } #endif /* !HAVE_HASHDRBG || CUSTOM_RAND_GENERATE_BLOCK || HAVE_INTEL_RDRAND */ -#endif /* WC_NO_RNG */ + +#ifdef WC_RNG_BANK_SUPPORT + +static char *rng_bank_affinity_lock_lock; +static int rng_bank_affinity_lock(void *arg) { + rng_bank_affinity_lock_lock = (char *)arg; + return 0; +} + +static int rng_bank_affinity_get_id_id; +static int rng_bank_affinity_get_id(void *arg, int *id) { + if (rng_bank_affinity_lock_lock != (char *)arg) + return BAD_STATE_E; + rng_bank_affinity_lock_lock = (char *)arg + 1; + *id = rng_bank_affinity_get_id_id; + return 0; +} + +static int rng_bank_affinity_unlock(void *arg) { + rng_bank_affinity_lock_lock = (char *)arg + 2; + return 0; +} + +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) +{ + + int ret; + WC_DECLARE_VAR(bank, struct wc_rng_bank, 1, HEAP_HINT); + struct wc_rng_bank_inst *rng_inst = NULL; + struct wc_rng_bank *bank2 = NULL; + struct wc_rng_bank_inst *rng_inst2 = NULL; +#ifdef WC_DRBG_BANKREF + WC_RNG *rng = NULL, *rng2 = NULL; +#endif + static const char bank_arg[] = "hi"; + byte outbuf1[16], outbuf2[16]; + int i; + + WC_ALLOC_VAR_EX(bank, struct wc_rng_bank, 1, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER, + return WC_TEST_RET_ENC_EC(MEMORY_E)); + XMEMSET(bank, 0, sizeof(*bank)); + + ret = wc_rng_bank_init(NULL, 4, WC_RNG_BANK_FLAG_CAN_WAIT, 10, HEAP_HINT, INVALID_DEVID); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_rng_bank_init(bank, 4, WC_RNG_BANK_FLAG_CAN_WAIT, 10, HEAP_HINT, INVALID_DEVID); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_rng_bank_set_affinity_handlers( + bank, + rng_bank_affinity_lock, + rng_bank_affinity_get_id, + rng_bank_affinity_unlock, + (char *)bank_arg); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_rng_bank_new(&bank2, 4, WC_RNG_BANK_FLAG_NO_VECTOR_OPS, 10, HEAP_HINT, INVALID_DEVID); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_rng_bank_set_affinity_handlers( + bank2, + rng_bank_affinity_lock, + rng_bank_affinity_get_id, + rng_bank_affinity_unlock, + (char *)bank_arg); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + rng_bank_affinity_get_id_id = 4; + ret = wc_rng_bank_checkout(bank2, &rng_inst2, -1, 10, WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST | WC_RNG_BANK_FLAG_AFFINITY_LOCK); + if (ret != WC_NO_ERR_TRACE(BAD_INDEX_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + rng_bank_affinity_get_id_id = 2; + ret = wc_rng_bank_checkout(bank2, &rng_inst2, -1, 10, WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST | WC_RNG_BANK_FLAG_AFFINITY_LOCK); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + if (rng_inst2 != bank2->rngs + 2) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + if (rng_bank_affinity_lock_lock != bank_arg + 1) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + + /* if we can, confirm that WC_RNG_BANK_FLAG_NO_VECTOR_OPS worked. */ +#if defined(WC_HAVE_VECTOR_SPEEDUPS) && \ + defined(WOLFSSL_KERNEL_MODE) && \ + defined(WC_C_DYNAMIC_FALLBACK) && \ + defined(HAVE_HASHDRBG) && \ + defined(WC_NO_INTERNAL_FUNCTION_POINTERS) + if (((struct DRBG_internal *)rng_inst2->rng.drbg)->sha256.sha_method != 7 /* SHA256_C */) + ERROR_OUT(WC_TEST_RET_ENC_I(((struct DRBG_internal *)rng_inst2->rng.drbg)->sha256.sha_method), out); +#endif + + ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(rng_inst2), outbuf1, sizeof(outbuf1)); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_rng_bank_checkin(bank2, &rng_inst2); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + if (rng_inst2 != NULL) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + if (rng_bank_affinity_lock_lock != bank_arg + 2) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + + ret = wc_rng_bank_checkout(bank2, &rng_inst2, 3, 10, WC_RNG_BANK_FLAG_NONE); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + if (rng_inst2 != bank2->rngs + 3) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + ret = wc_rng_bank_checkin(bank2, &rng_inst2); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + rng_bank_affinity_get_id_id = 3; + ret = wc_rng_bank_checkout(bank2, &rng_inst2, -1, 10, WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST | WC_RNG_BANK_FLAG_AFFINITY_LOCK); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + if (rng_inst2 != bank2->rngs + 3) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + + ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(rng_inst2), outbuf2, sizeof(outbuf2)); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_rng_bank_checkin(bank2, &rng_inst2); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + if (rng_inst2 != NULL) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + + if (XMEMCMP(outbuf1, outbuf2, sizeof(outbuf1)) == 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + +#ifdef WC_DRBG_BANKREF + ret = wc_rng_new_bankref(bank2, &rng2); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + rng_bank_affinity_get_id_id = 1; + ret = wc_RNG_GenerateBlock(rng2, outbuf1, sizeof(outbuf1)); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + if (XMEMCMP(outbuf1, outbuf2, sizeof(outbuf1)) == 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); +#endif + + ret = wc_rng_bank_reseed(bank2, 10, WC_RNG_BANK_FLAG_NONE); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + for (i = 0; i < bank2->n_rngs; ++i) { + if (((struct DRBG_internal *)bank2->rngs[i].rng.drbg) + ->reseedCtr != WC_RESEED_INTERVAL) + { + ERROR_OUT(WC_TEST_RET_ENC_I(i), out); + } + } + + rng_bank_affinity_get_id_id = 0; + /* WC_RNG_BANK_FLAG_CAN_WAIT needed to avoiding warning message that the + * instance needs reseed. + */ + ret = wc_rng_bank_checkout(bank2, &rng_inst2, -1, 10, WC_RNG_BANK_FLAG_CAN_WAIT | WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST | WC_RNG_BANK_FLAG_AFFINITY_LOCK); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(rng_inst2), outbuf1, sizeof(outbuf1)); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + ret = wc_rng_bank_checkin(bank2, &rng_inst2); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + rng_bank_affinity_get_id_id = 1; + ret = wc_rng_bank_checkout(bank2, &rng_inst2, -1, 10, WC_RNG_BANK_FLAG_CAN_WAIT | WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST | WC_RNG_BANK_FLAG_AFFINITY_LOCK); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(rng_inst2), outbuf2, sizeof(outbuf2)); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + ret = wc_rng_bank_checkin(bank2, &rng_inst2); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + if (XMEMCMP(outbuf1, outbuf2, sizeof(outbuf1)) == 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + +#ifdef WC_DRBG_BANKREF + if (wolfSSL_RefCur(bank2->refcount) != 2) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + + ret = wc_rng_bank_free(&bank2); + if (ret != WC_NO_ERR_TRACE(BUSY_E)) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + + wc_rng_free(rng2); + rng2 = NULL; + + if (wolfSSL_RefCur(bank2->refcount) != 1) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); +#endif + + ret = wc_rng_bank_free(&bank2); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + if (bank2 != NULL) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + + rng_bank_affinity_get_id_id = 0; + + ret = wc_rng_bank_checkout(bank, &rng_inst, -1, 10, WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST | WC_RNG_BANK_FLAG_AFFINITY_LOCK); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(rng_inst), outbuf1, sizeof(outbuf1)); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + /* can't wc_rng_bank_seed() with _FLAG_CAN_WAIT while holding an inst -- + * deadlocks then times out. + */ + ret = wc_rng_bank_checkin(bank, &rng_inst); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_rng_bank_seed(bank, (byte *)bank_arg, (word32)sizeof(bank_arg), 10, WC_RNG_BANK_FLAG_CAN_WAIT); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_rng_bank_checkout(bank, &rng_inst, -1, 10, WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST | WC_RNG_BANK_FLAG_AFFINITY_LOCK); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(rng_inst), outbuf2, sizeof(outbuf2)); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + if (XMEMCMP(outbuf1, outbuf2, sizeof(outbuf1)) == 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + + ret = wc_rng_bank_checkin(bank, &rng_inst); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_rng_bank_seed(bank, (byte *)bank_arg, (word32)sizeof(bank_arg), 10, WC_RNG_BANK_FLAG_CAN_WAIT); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_rng_bank_checkout(bank, &rng_inst, -1, 10, WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST | WC_RNG_BANK_FLAG_AFFINITY_LOCK); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(rng_inst), outbuf1, sizeof(outbuf1)); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + /* even though we passed in the same seed, the state is different, because + * Hash_DRBG_Reseed() chains in the previous state, and also churns in the + * "type" only on reseed. + */ + if (XMEMCMP(outbuf1, outbuf2, sizeof(outbuf1)) == 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + + ret = wc_rng_bank_inst_reinit(bank, rng_inst, 10, WC_RNG_BANK_FLAG_CAN_WAIT); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(rng_inst), outbuf1, sizeof(outbuf1)); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + + if (XMEMCMP(outbuf1, outbuf2, sizeof(outbuf1)) == 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + + ret = wc_rng_bank_checkin(bank, &rng_inst); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + +out: + + { + int cleanup_ret; + +#ifdef WC_DRBG_BANKREF + if (rng) { + cleanup_ret = wc_FreeRng(rng); + if ((cleanup_ret != 0) && (ret == 0)) + ret = WC_TEST_RET_ENC_EC(cleanup_ret); + } + if (rng2) { + cleanup_ret = wc_FreeRng(rng2); + if ((cleanup_ret != 0) && (ret == 0)) + ret = WC_TEST_RET_ENC_EC(cleanup_ret); + } +#endif + + if (rng_inst) { + cleanup_ret = wc_rng_bank_checkin(bank, &rng_inst); + if ((cleanup_ret != 0) && (ret == 0)) + ret = WC_TEST_RET_ENC_EC(cleanup_ret); + if ((rng_inst != NULL) && (ret == 0)) + ret = WC_TEST_RET_ENC_NC; + } + if (rng_inst2) { + cleanup_ret = wc_rng_bank_checkin(bank2, &rng_inst2); + if ((cleanup_ret != 0) && (ret == 0)) + ret = WC_TEST_RET_ENC_EC(cleanup_ret); + if ((rng_inst2 != NULL) && (ret == 0)) + ret = WC_TEST_RET_ENC_NC; + } + cleanup_ret = wc_rng_bank_fini(bank); + if ((cleanup_ret != 0) && (ret == 0)) + ret = WC_TEST_RET_ENC_EC(cleanup_ret); + WC_FREE_VAR_EX(bank, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + cleanup_ret = wc_rng_bank_free(&bank2); + if ((cleanup_ret != 0) && (ret == 0)) + ret = WC_TEST_RET_ENC_EC(cleanup_ret); + if ((bank2 != NULL) && (ret == 0)) + ret = WC_TEST_RET_ENC_NC; + } + + return ret; +} + +#endif /* WC_RNG_BANK_SUPPORT */ + +#endif /* !WC_NO_RNG */ #ifndef MEM_TEST_SZ #define MEM_TEST_SZ 1024 @@ -31983,7 +32326,7 @@ static wc_test_ret_t ecc_test_deterministic_k(WC_RNG* rng) #endif WC_ALLOC_VAR_EX(key, ecc_key, 1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, - return MEMORY_E); + return WC_TEST_RET_ENC_EC(MEMORY_E)); ret = wc_ecc_init_ex(key, HEAP_HINT, devId); if (ret != 0) diff --git a/wolfssl/wolfcrypt/async.h b/wolfssl/wolfcrypt/async.h index 8eac4aa9c7..d6ab016a4f 100644 --- a/wolfssl/wolfcrypt/async.h +++ b/wolfssl/wolfcrypt/async.h @@ -186,7 +186,7 @@ struct WC_ASYNC_DEV; typedef struct WC_ASYNC_SW { void* ctx; - #if HAVE_ANONYMOUS_INLINE_AGGREGATES + #ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES union { #endif #ifdef HAVE_ECC @@ -211,7 +211,7 @@ struct WC_ASYNC_DEV; #ifndef NO_DES3 struct AsyncCryptSwDes des; #endif /* !NO_DES3 */ - #if HAVE_ANONYMOUS_INLINE_AGGREGATES + #ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES }; /* union */ #endif byte type; /* enum WC_ASYNC_SW_TYPE */ diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index 0e7d21cfbc..e4db03cd65 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -309,9 +309,11 @@ enum wolfCrypt_ErrorCodes { INTERRUPTED_E = -1004, /* Process interrupted */ MLKEM_PUB_HASH_E = -1005, /* Encoded public key in decapsulation key does * not match stored hash*/ + BUSY_E = -1006, /* Object is busy */ + ALREADY_E = -1007, /* Operation was redundant or preempted */ - WC_SPAN2_LAST_E = -1005, /* Update to indicate last used error code */ - WC_LAST_E = -1005, /* the last code used either here or in + WC_SPAN2_LAST_E = -1007, /* Update to indicate last used error code */ + WC_LAST_E = -1007, /* the last code used either here or in * error-ssl.h */ WC_SPAN2_MIN_CODE_E = -1999, /* Last usable code in span 2 */ diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index ff1dc50cae..fd23791b91 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -48,6 +48,7 @@ nobase_include_HEADERS+= \ wolfssl/wolfcrypt/chacha20_poly1305.h \ wolfssl/wolfcrypt/random.h \ wolfssl/wolfcrypt/wolfentropy.h \ + wolfssl/wolfcrypt/rng_bank.h \ wolfssl/wolfcrypt/ripemd.h \ wolfssl/wolfcrypt/rsa.h \ wolfssl/wolfcrypt/rc2.h \ diff --git a/wolfssl/wolfcrypt/random.h b/wolfssl/wolfcrypt/random.h index c9f54d924f..3a337ece49 100644 --- a/wolfssl/wolfcrypt/random.h +++ b/wolfssl/wolfcrypt/random.h @@ -247,12 +247,6 @@ struct OS_Seed { #define RNG_HEALTH_TEST_CHECK_SIZE (WC_SHA256_DIGEST_SIZE * 4) -/* RNG health states */ -#define WC_DRBG_NOT_INIT 0 -#define WC_DRBG_OK 1 -#define WC_DRBG_FAILED 2 -#define WC_DRBG_CONT_FAILED 3 - struct DRBG_internal { #ifdef WORD64_AVAILABLE word64 reseedCtr; @@ -271,26 +265,57 @@ struct DRBG_internal { byte digest_scratch[WC_SHA256_DIGEST_SIZE]; #endif }; +#endif /* HAVE_HASHDRBG */ + +/* RNG health states */ +#define WC_DRBG_NOT_INIT 0 +#define WC_DRBG_OK 1 +#define WC_DRBG_FAILED 2 +#define WC_DRBG_CONT_FAILED 3 +#ifdef WC_RNG_BANK_SUPPORT + #define WC_DRBG_BANKREF 4 /* Marks the WC_RNG as a ref to a wc_rng_bank, + * with no usable DRBG of its own. + */ #endif /* RNG context */ struct WC_RNG { struct OS_Seed seed; void* heap; -#ifdef HAVE_HASHDRBG - /* Hash-based Deterministic Random Bit Generator */ - struct DRBG* drbg; -#if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) - struct DRBG_internal drbg_data; + byte status; + +#ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES + union { #endif -#ifdef WOLFSSL_SMALL_STACK_CACHE - /* Scratch buffer slots -- everything is preallocated by _InitRng(). */ - struct DRBG_internal *drbg_scratch; - byte *health_check_scratch; - byte *newSeed_buf; + + #ifdef WC_RNG_BANK_SUPPORT + struct wc_rng_bank *bankref; + #endif + + #ifdef HAVE_HASHDRBG + #ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES + struct { + #endif + /* Hash-based Deterministic Random Bit Generator */ + struct DRBG* drbg; + #if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) + struct DRBG_internal drbg_data; + #endif + #ifdef WOLFSSL_SMALL_STACK_CACHE + /* Scratch buffers -- all preallocated by _InitRng(). */ + struct DRBG_internal *drbg_scratch; + byte *health_check_scratch; + byte *newSeed_buf; + #endif + #ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES + }; + #endif + #endif /* HAVE_HASHDRBG */ + +#ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES + }; #endif - byte status; -#endif /* HAVE_HASHDRBG */ + #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) pid_t pid; #endif diff --git a/wolfssl/wolfcrypt/rng_bank.h b/wolfssl/wolfcrypt/rng_bank.h new file mode 100644 index 0000000000..205c1e5e32 --- /dev/null +++ b/wolfssl/wolfcrypt/rng_bank.h @@ -0,0 +1,145 @@ +/* rng_bank.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/*! + \file wolfssl/wolfcrypt/rng_bank.h +*/ + +/* This facility allocates and manages a bank of persistent RNGs with thread + * safety and provisions for automatic affinity. It is typically used in kernel + * applications. + */ + +#ifndef WOLF_CRYPT_RNG_BANK_H +#define WOLF_CRYPT_RNG_BANK_H + +#include + +#ifdef WC_RNG_BANK_SUPPORT + +#ifdef WC_NO_RNG + #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) + +#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) + +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_inst { + wolfSSL_Atomic_Int lock; + WC_RNG rng; +}; + +struct wc_rng_bank { + wolfSSL_Ref refcount; + void *heap; + word32 flags; + 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; + struct wc_rng_bank_inst *rngs; /* typically one per CPU ID, plus a few */ +}; + +WOLFSSL_API int wc_rng_bank_new( + struct wc_rng_bank **ctx, + int n_rngs, + word32 flags, + int timeout_secs, + void *heap, + int devId); + +WOLFSSL_API int wc_rng_bank_init( + struct wc_rng_bank *ctx, + int n_rngs, + word32 flags, + int timeout_secs, + void *heap, + int devId); + +WOLFSSL_API 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); + +WOLFSSL_API int wc_rng_bank_fini(struct wc_rng_bank *ctx); + +WOLFSSL_API int wc_rng_bank_free(struct wc_rng_bank **ctx); + +WOLFSSL_API 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); + +WOLFSSL_LOCAL int wc_local_rng_bank_checkout_for_bankref( + struct wc_rng_bank *bank, + struct wc_rng_bank_inst **rng_inst); + +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_reinit( + struct wc_rng_bank *bank, + struct wc_rng_bank_inst *rng_inst, + int timeout_secs, + word32 flags); + +WOLFSSL_API int wc_rng_bank_seed(struct wc_rng_bank *bank, + const byte* seed, word32 seedSz, + int timeout_secs, + word32 flags); + +WOLFSSL_API int wc_rng_bank_reseed(struct wc_rng_bank *bank, + int timeout_secs, + word32 flags); + +#ifdef WC_DRBG_BANKREF +WOLFSSL_API int wc_InitRng_BankRef(struct wc_rng_bank *bank, WC_RNG *rng); + +WOLFSSL_API int wc_BankRef_Release(WC_RNG *rng); + +WOLFSSL_API int wc_rng_new_bankref(struct wc_rng_bank *bank, WC_RNG **rng); +#endif /* WC_DRBG_BANKREF */ + +#define WC_RNG_BANK_INST_TO_RNG(rng_inst) (&(rng_inst)->rng) + +#endif /* WC_RNG_BANK_SUPPORT */ + +#endif /* WOLF_CRYPT_RNG_BANK_H */ diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 2397557d12..bf3029791c 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -431,6 +431,8 @@ (WOLFSSL_FIPS_VERSION2_CODE >= WOLFSSL_MAKE_FIPS_VERSION(major,minor)) #define FIPS_VERSION_GT(major,minor) \ (WOLFSSL_FIPS_VERSION2_CODE > WOLFSSL_MAKE_FIPS_VERSION(major,minor)) +#define FIPS_VERSION_NE(major,minor) \ + (WOLFSSL_FIPS_VERSION2_CODE != WOLFSSL_MAKE_FIPS_VERSION(major,minor)) #define FIPS_VERSION3_LT(major,minor,patch) \ (WOLFSSL_FIPS_VERSION_CODE < WOLFSSL_MAKE_FIPS_VERSION3(major,minor,patch)) @@ -3680,9 +3682,6 @@ extern void uITRON4_free(void *p) ; #ifndef WOLFSSL_KERNEL_MODE #define WOLFSSL_KERNEL_MODE #endif - #ifndef WOLFSSL_API_PREFIX_MAP - #define WOLFSSL_API_PREFIX_MAP - #endif #if defined(WOLFSSL_LINUXKM_VERBOSE_DEBUG) && \ !defined(WOLFSSL_KERNEL_VERBOSE_DEBUG) #define WOLFSSL_KERNEL_VERBOSE_DEBUG @@ -3715,21 +3714,11 @@ extern void uITRON4_free(void *p) ; #ifndef USE_WOLF_STRTOK #define USE_WOLF_STRTOK #endif - #ifndef WOLFSSL_OLD_PRIME_CHECK - #define WOLFSSL_OLD_PRIME_CHECK - #endif #ifdef LINUXKM_LKCAPI_REGISTER #ifndef WC_TEST_EXPORT_SUBTESTS #define WC_TEST_EXPORT_SUBTESTS #endif #endif - #ifndef WOLFSSL_TEST_SUBROUTINE - #ifdef WC_TEST_EXPORT_SUBTESTS - #define WOLFSSL_TEST_SUBROUTINE - #else - #define WOLFSSL_TEST_SUBROUTINE static - #endif - #endif #undef HAVE_PTHREAD /* linuxkm uses linux/string.h, included by linuxkm_wc_port.h. */ #undef HAVE_STRINGS_H @@ -3790,21 +3779,6 @@ extern void uITRON4_free(void *p) ; #undef HAVE_PUBLIC_FFDHE #endif - #ifndef NO_OLD_WC_NAMES - #define NO_OLD_WC_NAMES - #endif - #ifndef NO_OLD_SHA_NAMES - #define NO_OLD_SHA_NAMES - #endif - #ifndef NO_OLD_MD5_NAME - #define NO_OLD_MD5_NAME - #endif - #ifndef OPENSSL_COEXIST - #define OPENSSL_COEXIST - #endif - #ifndef NO_OLD_SSL_NAMES - #define NO_OLD_SSL_NAMES - #endif #undef WOLFSSL_MIN_AUTH_TAG_SZ #define WOLFSSL_MIN_AUTH_TAG_SZ 4 @@ -3814,22 +3788,10 @@ extern void uITRON4_free(void *p) ; */ #define WOLFSSL_ASN_INT_LEAD_0_ANY #endif - - #if !defined(WC_RESEED_INTERVAL) && defined(LINUXKM_LKCAPI_REGISTER) - /* If installing handlers, use the maximum reseed interval allowed by - * NIST SP 800-90A Rev. 1, to avoid unnecessary delays in DRBG - * generation. - */ - #if defined(HAVE_FIPS) && FIPS_VERSION_LT(6,0) - #define WC_RESEED_INTERVAL UINT_MAX - #else - #define WC_RESEED_INTERVAL (((word64)1UL)<<48UL) - #endif - #endif #if defined(__aarch64__) && !defined(WOLFSSL_AARCH64_PRIVILEGE_MODE) #define WOLFSSL_AARCH64_PRIVILEGE_MODE #endif -#endif +#endif /* WOLFSSL_LINUXKM */ /* FreeBSD Kernel Module */ #ifdef WOLFSSL_BSDKM @@ -3869,16 +3831,6 @@ extern void uITRON4_free(void *p) ; #ifndef USE_WOLF_STRTOK #define USE_WOLF_STRTOK #endif - #ifndef WOLFSSL_OLD_PRIME_CHECK - #define WOLFSSL_OLD_PRIME_CHECK - #endif - #ifndef WOLFSSL_TEST_SUBROUTINE - #ifndef NO_CRYPT_TEST - #define WOLFSSL_TEST_SUBROUTINE - #else - #define WOLFSSL_TEST_SUBROUTINE static - #endif - #endif /* bsdkm uses kernel headers, included in bsdkm_wc_port.h. */ #undef HAVE_PTHREAD #undef HAVE_STRINGS_H @@ -3909,6 +3861,19 @@ extern void uITRON4_free(void *p) ; #define WOLFSSL_SP_DIV_WORD_HALF #endif + /* FreeBSD kernel defines its own min, max functions in sys/libkern.h */ + #undef WOLFSSL_HAVE_MIN + #define WOLFSSL_HAVE_MIN + + #undef WOLFSSL_HAVE_MAX + #define WOLFSSL_HAVE_MAX +#endif /* WOLFSSL_BSDKM */ + +/* Common setup for kernel mode builds */ +#ifdef WOLFSSL_KERNEL_MODE + #ifndef WOLFSSL_API_PREFIX_MAP + #define WOLFSSL_API_PREFIX_MAP + #endif #ifndef NO_OLD_WC_NAMES #define NO_OLD_WC_NAMES #endif @@ -3925,18 +3890,36 @@ extern void uITRON4_free(void *p) ; #define NO_OLD_SSL_NAMES #endif - /* FreeBSD kernel defines its own min, max functions in sys/libkern.h */ - #undef WOLFSSL_HAVE_MIN - #define WOLFSSL_HAVE_MIN + #ifndef WOLFSSL_TEST_SUBROUTINE + #ifdef WC_TEST_EXPORT_SUBTESTS + #define WOLFSSL_TEST_SUBROUTINE + #else + #define WOLFSSL_TEST_SUBROUTINE static + #endif + #endif - #undef WOLFSSL_HAVE_MAX - #define WOLFSSL_HAVE_MAX -#endif + #if !defined(WOLFSSL_OLD_PRIME_CHECK) && \ + !defined(WOLFSSL_NEW_PRIME_CHECK) && !defined(HAVE_FIPS) + #define WOLFSSL_OLD_PRIME_CHECK + #endif -#if defined(WOLFSSL_KERNEL_MODE) && !defined(WC_NO_VERBOSE_RNG) && \ - !defined(WC_VERBOSE_RNG) - #define WC_VERBOSE_RNG -#endif + #ifndef WC_RESEED_INTERVAL + /* In kernel mode, use the maximum reseed interval 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 + #else + #define WC_RESEED_INTERVAL (((word64)1UL)<<48UL) + #endif + #endif + + #if !defined(WC_NO_VERBOSE_RNG) && !defined(WC_VERBOSE_RNG) + #define WC_VERBOSE_RNG + #endif +#endif /* WOLFSSL_KERNEL_MODE */ #if defined(WC_SYM_RELOC_TABLES) && defined(HAVE_FIPS) && \ !defined(WC_PIE_RELOC_TABLES) diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index feded367eb..951a87e5b3 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -125,7 +125,7 @@ typedef const char wcchar[]; /* if a version is available, pivot on the version, otherwise guess it's * disallowed, subject to override. */ - #if !defined(WOLF_C89) && (!defined(__STDC__) \ + #if !defined(WOLF_C89) && !defined(_MSC_VER) && (!defined(__STDC__) \ || (!defined(__STDC_VERSION__) && !defined(__cplusplus)) \ || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201101L)) \ || (defined(__cplusplus) && (__cplusplus >= 201103L))) diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index 5e631e0123..875511d72e 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -694,13 +694,15 @@ typedef struct wolfSSL_RefWithMutex { #endif int count; } wolfSSL_RefWithMutex; - +#define wolfSSL_RefWithMutexCur(ref) ((ref).count) #if defined(WOLFSSL_ATOMIC_OPS) && !defined(SINGLE_THREADED) typedef struct wolfSSL_Ref { wolfSSL_Atomic_Int count; } wolfSSL_Ref; +#define wolfSSL_RefCur(ref) WOLFSSL_ATOMIC_LOAD((ref).count) #else typedef struct wolfSSL_RefWithMutex wolfSSL_Ref; +#define wolfSSL_RefCur(ref) wolfSSL_RefWithMutexCur(ref) #endif #if defined(SINGLE_THREADED) || defined(WOLFSSL_ATOMIC_OPS) @@ -710,7 +712,10 @@ typedef struct wolfSSL_RefWithMutex wolfSSL_Ref; wolfSSL_Atomic_Int_Init(&(ref)->count, 1); \ *(err) = 0; \ } while(0) -#define wolfSSL_RefFree(ref) WC_DO_NOTHING +#define wolfSSL_RefFree(ref) \ + do { \ + wolfSSL_Atomic_Int_Init(&(ref)->count, 0); \ + } while(0) #define wolfSSL_RefInc(ref, err) \ do { \ (void)wolfSSL_Atomic_Int_FetchAdd(&(ref)->count, 1); \