diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 79cf7f6eaf..31b7d4be79 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -137,6 +137,7 @@ CONFIG_MBEDTLS_CERTIFICATE_BUNDLE CONFIG_MBEDTLS_PSA_CRYPTO_C CONFIG_MIPS CONFIG_MODULE_SIG +CONFIG_MODULE_SIG_SHA1 CONFIG_NET_SOCKETS_SOCKOPT_TLS CONFIG_NEWLIB_LIBC CONFIG_NEWLIB_NANO_FORMAT diff --git a/linuxkm/linuxkm_wc_port.h b/linuxkm/linuxkm_wc_port.h index 8b7b33c1f1..ca4ac90749 100644 --- a/linuxkm/linuxkm_wc_port.h +++ b/linuxkm/linuxkm_wc_port.h @@ -35,28 +35,43 @@ #error Unsupported kernel. #endif - #if defined(HAVE_FIPS) && defined(LINUXKM_LKCAPI_REGISTER_AESXTS) && defined(CONFIG_CRYPTO_MANAGER_EXTRA_TESTS) + #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 16, 0) + #if defined(CONFIG_CRYPTO_MANAGER) && !defined(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) + #define WC_LINUXKM_HAVE_SELFTEST + #endif + #if defined(WC_LINUXKM_HAVE_SELFTEST) && defined(CONFIG_CRYPTO_MANAGER_EXTRA_TESTS) + #define WC_LINUXKM_HAVE_SELFTEST_FULL + #endif + #else + /* see Linux 698de822780f */ + #if defined(CONFIG_CRYPTO_MANAGER) && defined(CONFIG_CRYPTO_SELFTESTS) + #define WC_LINUXKM_HAVE_SELFTEST + #endif + /* see Linux ac90aad0e9 */ + #if defined(WC_LINUXKM_HAVE_SELFTEST) && defined(CONFIG_CRYPTO_SELFTESTS_FULL) + #define WC_LINUXKM_HAVE_SELFTEST_FULL + #endif + #endif + + #if defined(HAVE_FIPS) && defined(LINUXKM_LKCAPI_REGISTER_AESXTS) && defined(WC_LINUXKM_HAVE_SELFTEST_FULL) /* CONFIG_CRYPTO_MANAGER_EXTRA_TESTS expects AES-XTS-384 to work, even when CONFIG_CRYPTO_FIPS, but FIPS 140-3 only allows AES-XTS-256 and AES-XTS-512. */ - #error CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is incompatible with FIPS wolfCrypt AES-XTS -- please reconfigure the target kernel to disable CONFIG_CRYPTO_MANAGER_EXTRA_TESTS. + #error CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is incompatible with FIPS wolfCrypt AES-XTS -- please reconfigure the target kernel to disable CONFIG_CRYPTO_MANAGER_EXTRA_TESTS/CONFIG_CRYPTO_SELFTESTS_FULL. #endif /* The first vector set in /usr/src/linux/crypto/testmgr.h * ecdsa_nist_p192_tv_template[], ecdsa_nist_p256_tv_template[], and * ecdsa_nist_p384_tv_template[] use SHA-1 (even if CONFIG_CRYPTO_SHA1 is * disabled), and kernel module signatures frequently use SHA-1 until quite - * recently (dependent on CONFIG_CRYPTO_SHA1). If either is enabled, force - * downgrade to 186-4. + * recently. */ - #if defined(WC_FIPS_186_5_PLUS) && \ - (defined(CONFIG_CRYPTO_SHA1) || (defined(CONFIG_CRYPTO_MANAGER) && !defined(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS))) && \ - (defined(LINUXKM_LKCAPI_REGISTER_ALL) || defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) || defined(CONFIG_CRYPTO_ECDSA)) - #undef WC_FIPS_186_5_PLUS - #ifdef WC_FIPS_186_5 - #undef WC_FIPS_186_5 - #else - #error Unknown and incompatible FIPS 186 is enabled. - #endif - #define WC_FIPS_186_4 + #if (defined(WC_LINUXKM_HAVE_SELFTEST) || defined(CONFIG_MODULE_SIG_SHA1)) && \ + (((defined(WC_MIN_DIGEST_SIZE_FOR_VERIFY) && (WC_MIN_DIGEST_SIZE_FOR_VERIFY > 20)) || \ + (defined(NO_SHA) && !defined(WC_MIN_DIGEST_SIZE_FOR_VERIFY)))) && \ + defined(HAVE_ECC) && \ + (defined(LINUXKM_LKCAPI_REGISTER_ALL) || \ + defined(LINUXKM_LKCAPI_REGISTER_ECDSA) || \ + (defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_ECDSA))) + #error Target kernel requires SHA-1 signature verification support. #endif #ifdef HAVE_CONFIG_H @@ -427,24 +442,7 @@ #include #include - - #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 16, 0) - #if defined(CONFIG_CRYPTO_MANAGER) && !defined(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) - #define WC_LINUXKM_HAVE_SELFTEST - #endif - #if defined(WC_LINUXKM_HAVE_SELFTEST) && defined(CONFIG_CRYPTO_MANAGER_EXTRA_TESTS) - #define WC_LINUXKM_HAVE_SELFTEST_FULL - #endif - #else - /* see Linux 698de822780f */ - #if defined(CONFIG_CRYPTO_MANAGER) && defined(CONFIG_CRYPTO_SELFTESTS) - #define WC_LINUXKM_HAVE_SELFTEST - #endif - /* see Linux ac90aad0e9 */ - #if defined(WC_LINUXKM_HAVE_SELFTEST) && defined(CONFIG_CRYPTO_SELFTESTS_FULL) - #define WC_LINUXKM_HAVE_SELFTEST_FULL - #endif - #endif + #include /* Kernel non-FIPS self-test ("testmgr") has a KAT with all-zeros keys. */ #if defined(WC_LINUXKM_HAVE_SELFTEST) && !defined(HAVE_FIPS) @@ -655,6 +653,12 @@ #include #endif #include + #ifndef WC_CONTAINERIZE_THIS + /* for struct vm_struct and related -- used by + * wc_linuxkm_malloc_usable_size(). + */ + #include + #endif #include #if __has_include() /* for task_stack_page() */ @@ -823,6 +827,9 @@ #error WOLFSSL_USE_SAVE_VECTOR_REGISTERS is set for an unimplemented architecture. #endif /* WOLFSSL_USE_SAVE_VECTOR_REGISTERS */ + /* This pop must appear here, no later, so that conditional suppressions + * below continue after inclusion. + */ _Pragma("GCC diagnostic pop"); #define PTR_ERR(x) ((int)PTR_ERR(x)) diff --git a/linuxkm/lkcapi_aes_glue.c b/linuxkm/lkcapi_aes_glue.c index 8fea174bf2..d133686429 100644 --- a/linuxkm/lkcapi_aes_glue.c +++ b/linuxkm/lkcapi_aes_glue.c @@ -96,8 +96,16 @@ #define WOLFKM_AESOFB_NAME "ofb(aes)" #define WOLFKM_AESECB_NAME "ecb(aes)" -#if defined(USE_INTEL_SPEEDUP) || defined(USE_INTEL_SPEEDUP_FOR_AES) - #define WOLFKM_AES_DRIVER_ISA_EXT "-aesni-avx" +#if defined(WOLFSSL_X86_64_BUILD) && (defined(USE_INTEL_SPEEDUP) || defined(USE_INTEL_SPEEDUP_FOR_AES)) + #if !defined(NO_AVX512_SUPPORT) + #define WOLFKM_AES_DRIVER_ISA_EXT "-vaes-avx512" + #elif !defined(NO_VAES_SUPPORT) + #define WOLFKM_AES_DRIVER_ISA_EXT "-vaes-avx2" + #elif !defined(NO_AVX2_SUPPORT) + #define WOLFKM_AES_DRIVER_ISA_EXT "-aesni-avx2" + #else + #define WOLFKM_AES_DRIVER_ISA_EXT "-aesni-avx" + #endif #elif defined(WOLFSSL_AESNI) #define WOLFKM_AES_DRIVER_ISA_EXT "-aesni" #else diff --git a/linuxkm/lkcapi_ecdsa_glue.c b/linuxkm/lkcapi_ecdsa_glue.c index c9daf0b000..74cc6eeb7f 100644 --- a/linuxkm/lkcapi_ecdsa_glue.c +++ b/linuxkm/lkcapi_ecdsa_glue.c @@ -48,26 +48,17 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0) /* - * notes: - * - ecdsa supported with linux 6.12 and earlier for now, only. - * - pkcs1pad rsa supported both before and after linux 6.13, but - * without sign/verify after linux 6.13. - * - * In linux 6.13 the sign/verify callbacks were removed from + * note: In linux 6.13 the sign/verify callbacks were removed from * akcipher_alg, and ecdsa changed from a struct akcipher_alg type to * struct sig_alg type. * - * pkcs1pad rsa remained a struct akcipher_alg, but without sign/verify - * functionality. + * The 6.13+ base "ecdsa-nist-pN" sig_alg is verify-only, and takes the + * signature in the kernel's raw format (struct ecdsa_raw_sig -- r and s + * as little endian u64 digit arrays). The X9.62 (ASN.1 DER) and IEEE + * P1363 signature encodings are handled by the kernel's "x962(...)" and + * "p1363(...)" wrapping templates, instantiated around the base alg. */ - #if defined (LINUXKM_LKCAPI_REGISTER_ECDSA) - #undef LINUXKM_LKCAPI_REGISTER_ECDSA - #endif /* LINUXKM_LKCAPI_REGISTER_ECDSA */ - - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_ECDSA) && \ - !defined(LINUXKM_LKCAPI_DONT_REGISTER_ECDSA) - #error Config conflict: missing implementation forces off LINUXKM_LKCAPI_REGISTER_ECDSA. - #endif + #define LINUXKM_ECDSA_SIG_ALG #endif #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && \ @@ -82,6 +73,27 @@ #include #include +#ifdef LINUXKM_ECDSA_SIG_ALG + #define ecdsa_tfm_type crypto_sig + #define ecdsa_tfm_ctx_cb crypto_sig_ctx + + /* Mirror of struct ecdsa_raw_sig from the kernel's + * include/crypto/internal/ecc.h, which can't be included here because its + * struct ecc_point collides with wolfCrypt's. The kernel dimensions the + * digit arrays with ECC_MAX_DIGITS = DIV_ROUND_UP(521, 64) (NIST P521). + * The u64 digits are ordered little endian, with native endianness within + * each digit. + */ + #define KM_ECDSA_MAX_DIGITS ((521 + 63) / 64) + struct km_ecdsa_raw_sig { + u64 r[KM_ECDSA_MAX_DIGITS]; + u64 s[KM_ECDSA_MAX_DIGITS]; + }; +#else + #define ecdsa_tfm_type crypto_akcipher + #define ecdsa_tfm_ctx_cb akcipher_tfm_ctx +#endif /* !LINUXKM_ECDSA_SIG_ALG */ + #if defined(WOLFSSL_SP_X86_64_ASM) && !defined(NO_AVX2_SUPPORT) #define WOLFKM_ECDSA_DRIVER_ISA_EXT "-avx2" #else @@ -123,26 +135,52 @@ struct km_ecdsa_ctx { ecc_key * key; int curve_id; word32 curve_len; +#ifdef LINUXKM_ECDSA_SIG_ALG + word32 curve_nbits; +#endif /* LINUXKM_ECDSA_SIG_ALG */ }; /* shared ecdsa callbacks */ -static void km_ecdsa_exit(struct crypto_akcipher *tfm); -static int km_ecdsa_set_pub(struct crypto_akcipher *tfm, +static void km_ecdsa_exit(struct ecdsa_tfm_type *tfm); +static int km_ecdsa_set_pub(struct ecdsa_tfm_type *tfm, const void *key, unsigned int keylen); +#ifdef LINUXKM_ECDSA_SIG_ALG +static unsigned int km_ecdsa_key_size(struct crypto_sig *tfm); +static unsigned int km_ecdsa_digest_size(struct crypto_sig *tfm); +static int km_ecdsa_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen); +#else static unsigned int km_ecdsa_max_size(struct crypto_akcipher *tfm); static int km_ecdsa_verify(struct akcipher_request *req); +#endif /* !LINUXKM_ECDSA_SIG_ALG */ /* ecdsa_nist_pN callbacks */ #if defined(LINUXKM_ECC192) -static int km_ecdsa_nist_p192_init(struct crypto_akcipher *tfm); +static int km_ecdsa_nist_p192_init(struct ecdsa_tfm_type *tfm); #endif /* LINUXKM_ECC192 */ -static int km_ecdsa_nist_p256_init(struct crypto_akcipher *tfm); -static int km_ecdsa_nist_p384_init(struct crypto_akcipher *tfm); +static int km_ecdsa_nist_p256_init(struct ecdsa_tfm_type *tfm); +static int km_ecdsa_nist_p384_init(struct ecdsa_tfm_type *tfm); #if defined(HAVE_ECC521) -static int km_ecdsa_nist_p521_init(struct crypto_akcipher *tfm); +static int km_ecdsa_nist_p521_init(struct ecdsa_tfm_type *tfm); #endif /* HAVE_ECC521 */ #if defined(LINUXKM_ECC192) +#ifdef LINUXKM_ECDSA_SIG_ALG +static struct sig_alg ecdsa_nist_p192 = { + .base.cra_name = WOLFKM_ECDSA_P192_NAME, + .base.cra_driver_name = WOLFKM_ECDSA_P192_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_ecdsa_ctx), + .verify = km_ecdsa_verify, + .set_pub_key = km_ecdsa_set_pub, + .key_size = km_ecdsa_key_size, + .digest_size = km_ecdsa_digest_size, + .init = km_ecdsa_nist_p192_init, + .exit = km_ecdsa_exit, +}; +#else /* !LINUXKM_ECDSA_SIG_ALG */ static struct akcipher_alg ecdsa_nist_p192 = { .base.cra_name = WOLFKM_ECDSA_P192_NAME, .base.cra_driver_name = WOLFKM_ECDSA_P192_DRIVER, @@ -155,8 +193,24 @@ static struct akcipher_alg ecdsa_nist_p192 = { .init = km_ecdsa_nist_p192_init, .exit = km_ecdsa_exit, }; +#endif /* !LINUXKM_ECDSA_SIG_ALG */ #endif /* LINUXKM_ECC192 */ +#ifdef LINUXKM_ECDSA_SIG_ALG +static struct sig_alg ecdsa_nist_p256 = { + .base.cra_name = WOLFKM_ECDSA_P256_NAME, + .base.cra_driver_name = WOLFKM_ECDSA_P256_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_ecdsa_ctx), + .verify = km_ecdsa_verify, + .set_pub_key = km_ecdsa_set_pub, + .key_size = km_ecdsa_key_size, + .digest_size = km_ecdsa_digest_size, + .init = km_ecdsa_nist_p256_init, + .exit = km_ecdsa_exit, +}; +#else /* !LINUXKM_ECDSA_SIG_ALG */ static struct akcipher_alg ecdsa_nist_p256 = { .base.cra_name = WOLFKM_ECDSA_P256_NAME, .base.cra_driver_name = WOLFKM_ECDSA_P256_DRIVER, @@ -169,7 +223,23 @@ static struct akcipher_alg ecdsa_nist_p256 = { .init = km_ecdsa_nist_p256_init, .exit = km_ecdsa_exit, }; +#endif /* !LINUXKM_ECDSA_SIG_ALG */ +#ifdef LINUXKM_ECDSA_SIG_ALG +static struct sig_alg ecdsa_nist_p384 = { + .base.cra_name = WOLFKM_ECDSA_P384_NAME, + .base.cra_driver_name = WOLFKM_ECDSA_P384_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_ecdsa_ctx), + .verify = km_ecdsa_verify, + .set_pub_key = km_ecdsa_set_pub, + .key_size = km_ecdsa_key_size, + .digest_size = km_ecdsa_digest_size, + .init = km_ecdsa_nist_p384_init, + .exit = km_ecdsa_exit, +}; +#else /* !LINUXKM_ECDSA_SIG_ALG */ static struct akcipher_alg ecdsa_nist_p384 = { .base.cra_name = WOLFKM_ECDSA_P384_NAME, .base.cra_driver_name = WOLFKM_ECDSA_P384_DRIVER, @@ -182,8 +252,24 @@ static struct akcipher_alg ecdsa_nist_p384 = { .init = km_ecdsa_nist_p384_init, .exit = km_ecdsa_exit, }; +#endif /* !LINUXKM_ECDSA_SIG_ALG */ #if defined(HAVE_ECC521) +#ifdef LINUXKM_ECDSA_SIG_ALG +static struct sig_alg ecdsa_nist_p521 = { + .base.cra_name = WOLFKM_ECDSA_P521_NAME, + .base.cra_driver_name = WOLFKM_ECDSA_P521_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_ecdsa_ctx), + .verify = km_ecdsa_verify, + .set_pub_key = km_ecdsa_set_pub, + .key_size = km_ecdsa_key_size, + .digest_size = km_ecdsa_digest_size, + .init = km_ecdsa_nist_p521_init, + .exit = km_ecdsa_exit, +}; +#else /* !LINUXKM_ECDSA_SIG_ALG */ static struct akcipher_alg ecdsa_nist_p521 = { .base.cra_name = WOLFKM_ECDSA_P521_NAME, .base.cra_driver_name = WOLFKM_ECDSA_P521_DRIVER, @@ -196,6 +282,7 @@ static struct akcipher_alg ecdsa_nist_p521 = { .init = km_ecdsa_nist_p521_init, .exit = km_ecdsa_exit, }; +#endif /* !LINUXKM_ECDSA_SIG_ALG */ #endif /* HAVE_ECC521 */ /** @@ -204,18 +291,18 @@ static struct akcipher_alg ecdsa_nist_p521 = { * Kernel crypto ECDSA api expects raw uncompressed format with concatenated * x and y points, with leading 0x04 on pub key. * - * param tfm the crypto_akcipher transform + * param tfm the crypto_akcipher (crypto_sig on linux 6.13+) transform * param key raw uncompressed x, y points, with leading 0x04 * param keylen key length * */ -static int km_ecdsa_set_pub(struct crypto_akcipher *tfm, const void *key, +static int km_ecdsa_set_pub(struct ecdsa_tfm_type *tfm, const void *key, unsigned int keylen) { int err = 0; struct km_ecdsa_ctx * ctx = NULL; const byte * pub = key; - ctx = akcipher_tfm_ctx(tfm); + ctx = ecdsa_tfm_ctx_cb(tfm); switch (ctx->curve_len) { #if defined(LINUXKM_ECC192) @@ -279,23 +366,45 @@ static int km_ecdsa_set_pub(struct crypto_akcipher *tfm, const void *key, return err; } -static unsigned int km_ecdsa_max_size(struct crypto_akcipher *tfm) +#ifdef LINUXKM_ECDSA_SIG_ALG +/* Returns the ECDSA key size (mirrors the kernel's ecdsa_key_size()): + * linux kernel version < 6.15.3: key size in bytes. + * linux kernel version >= 6.15.3: key size in bits. + * */ +static unsigned int km_ecdsa_key_size(struct crypto_sig *tfm) { - struct km_ecdsa_ctx * ctx = NULL; - - ctx = akcipher_tfm_ctx(tfm); - - #ifdef WOLFKM_DEBUG_ECDSA - pr_info("info: exiting km_ecdsa_max_size\n"); - #endif /* WOLFKM_DEBUG_ECDSA */ - return (unsigned int) ctx->curve_len; + struct km_ecdsa_ctx *ctx = crypto_sig_ctx(tfm); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 3) + return ctx->curve_nbits; + #else + return ctx->curve_len; + #endif } -static void km_ecdsa_exit(struct crypto_akcipher *tfm) +/* Mirrors the kernel's ecdsa_digest_size(): ECDSA keys are much smaller than + * RSA keys, and can operate on (hashed) inputs that are larger than the key + * size, e.g. a SHA-384 digest verified with a P-256 key, so advertise the + * largest digest size km_ecdsa_verify() accepts rather than the key size + * that crypto/sig.c would default to. + * */ +static unsigned int km_ecdsa_digest_size(struct crypto_sig *tfm) +{ + (void)tfm; + return WC_MAX_DIGEST_SIZE; +} +#else /* !LINUXKM_ECDSA_SIG_ALG */ +static unsigned int km_ecdsa_max_size(struct crypto_akcipher *tfm) +{ + struct km_ecdsa_ctx *ctx = akcipher_tfm_ctx(tfm); + return ctx->curve_len; +} +#endif /* !LINUXKM_ECDSA_SIG_ALG */ + +static void km_ecdsa_exit(struct ecdsa_tfm_type *tfm) { struct km_ecdsa_ctx * ctx = NULL; - ctx = akcipher_tfm_ctx(tfm); + ctx = ecdsa_tfm_ctx_cb(tfm); if (ctx->key) { wc_ecc_free(ctx->key); @@ -309,12 +418,11 @@ static void km_ecdsa_exit(struct crypto_akcipher *tfm) return; } -static int km_ecdsa_init(struct crypto_akcipher *tfm, int curve_id) +static int km_ecdsa_init(struct ecdsa_tfm_type *tfm, int curve_id) { - struct km_ecdsa_ctx * ctx = NULL; - int ret = 0; + struct km_ecdsa_ctx *ctx = ecdsa_tfm_ctx_cb(tfm); + int ret = 0; - ctx = akcipher_tfm_ctx(tfm); XMEMSET(ctx, 0, sizeof(struct km_ecdsa_ctx)); ctx->curve_id = curve_id; ctx->curve_len = 0; @@ -330,10 +438,17 @@ static int km_ecdsa_init(struct crypto_akcipher *tfm, int curve_id) ctx->curve_len = (word32) ret; + #ifdef LINUXKM_ECDSA_SIG_ALG + /* NIST P-521 is the only supported curve whose bit length isn't a + * multiple of 8 (the kernel's ecdsa_key_size() returns + * curve->nbits). */ + ctx->curve_nbits = (curve_id == ECC_SECP521R1) ? 521 : + (ctx->curve_len * WOLFSSL_BIT_SIZE); + #endif /* LINUXKM_ECDSA_SIG_ALG */ + ctx->key = (ecc_key *)malloc(sizeof(ecc_key)); - if (!ctx->key) { + if (!ctx->key) return -ENOMEM; - } ret = wc_ecc_init(ctx->key); if (ret < 0) { @@ -350,29 +465,182 @@ static int km_ecdsa_init(struct crypto_akcipher *tfm, int curve_id) } #if defined(LINUXKM_ECC192) -static int km_ecdsa_nist_p192_init(struct crypto_akcipher *tfm) +static int km_ecdsa_nist_p192_init(struct ecdsa_tfm_type *tfm) { return km_ecdsa_init(tfm, ECC_SECP192R1); } #endif /* LINUXKM_ECC192 */ -static int km_ecdsa_nist_p256_init(struct crypto_akcipher *tfm) +static int km_ecdsa_nist_p256_init(struct ecdsa_tfm_type *tfm) { return km_ecdsa_init(tfm, ECC_SECP256R1); } -static int km_ecdsa_nist_p384_init(struct crypto_akcipher *tfm) +static int km_ecdsa_nist_p384_init(struct ecdsa_tfm_type *tfm) { return km_ecdsa_init(tfm, ECC_SECP384R1); } #if defined(HAVE_ECC521) -static int km_ecdsa_nist_p521_init(struct crypto_akcipher *tfm) +static int km_ecdsa_nist_p521_init(struct ecdsa_tfm_type *tfm) { return km_ecdsa_init(tfm, ECC_SECP521R1); } #endif /* HAVE_ECC521 */ +#ifdef LINUXKM_ECDSA_SIG_ALG + +/* Convert a little endian u64 digit array (the kernel's raw r/s format) to a + * big endian byte array of out_len bytes. Only the low 8*out_len bits of the + * digit array are read -- digits past DIV_ROUND_UP(out_len, 8) may be + * uninitialized in signatures decoded by the kernel's x962 template, and must + * not be read. + */ +static void km_ecdsa_raw_digits_to_bytes(const u64 *digits, byte *out, + word32 out_len) +{ + word32 i; + + for (i = 0; i < out_len; i++) + out[out_len - 1U - i] = (byte)(digits[i >> 3] >> ((i & 7U) << 3)); +} + +/* + * Verify an ecdsa_nist signature (linux 6.13+ struct sig_alg edition). + * + * src: + * - the signature, formatted as the kernel's struct ecdsa_raw_sig: r then + * s, each an array of ECC_MAX_DIGITS little endian u64 digits. + * - slen must == sizeof(struct ecdsa_raw_sig) (curve-independent). + * + * The kernel's x962 and p1363 templates decode DER and IEEE P1363 + * signature encodings (respectively) to this raw format, zero-filling + * the unused high bytes of the first DIV_ROUND_UP(curve_len, 8) digits + * only. + * + * digest: + * - the hash to be verified. wolfCrypt truncates oversized digests to + * the group order bit length internally (FIPS 186-4 style), matching + * the in-tree implementation. + * + * See kernel (6.13 or later): + * - include/crypto/sig.h + * - crypto/ecdsa.c + */ +static int km_ecdsa_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct km_ecdsa_ctx *ctx = crypto_sig_ctx(tfm); + const struct km_ecdsa_raw_sig + *raw_sig = (const struct km_ecdsa_raw_sig *)src; + byte *work_buffer = NULL; + byte *r_buf = NULL; + byte *s_buf = NULL; + byte *der_sig = NULL; + word32 der_sig_len = 0; + int result = -1; + int err = -1; + + if (src == NULL || digest == NULL) + return -EINVAL; + + if ((ctx->key == NULL) || (ctx->key->type != ECC_PUBLICKEY)) + return -EINVAL; + + if (slen != sizeof(struct km_ecdsa_raw_sig)) + return -EINVAL; + + /* 6 ECDSA (struct sig_testvec) test vectors in crypto/testmgr.h use SHA-1 + * (m_size 20). + */ +#ifdef WC_LINUXKM_HAVE_SELFTEST + wc_static_assert2(WC_MIN_DIGEST_SIZE_FOR_VERIFY <= 20, + "WC_MIN_DIGEST_SIZE_FOR_VERIFY must allow SHA-1-sized digests when " + "native kernel self-test is enabled."); +#endif + + if ((dlen > WC_MAX_DIGEST_SIZE) || + (dlen < WC_MIN_DIGEST_SIZE_FOR_VERIFY)) + { + return -EINVAL; + } + + /* Reject set bits between the curve length and the top of the last + * meaningful digit -- below, only the low 8*curve_len bits of each of r + * and s are converted, and such bits would otherwise be silently masked + * off. (the in-tree implementation rejects them via its r < n, s < n + * checks.) + */ + if (ctx->curve_len & 7U) { + word32 top_i = (ctx->curve_len - 1U) >> 3; + word32 top_shift = (ctx->curve_len & 7U) << 3; + if ((raw_sig->r[top_i] >> top_shift) || + (raw_sig->s[top_i] >> top_shift)) + { + return -EBADMSG; + } + } + + /* work_buffer holds the big endian r and s, followed by the + * DER-encoded signature to be passed to wc_ecc_verify_hash(). */ + work_buffer = (byte *)malloc((2U * ctx->curve_len) + ECC_MAX_SIG_SIZE); + if (unlikely(work_buffer == NULL)) + return -ENOMEM; + + r_buf = work_buffer; + s_buf = work_buffer + ctx->curve_len; + der_sig = work_buffer + (2U * ctx->curve_len); + + km_ecdsa_raw_digits_to_bytes(raw_sig->r, r_buf, ctx->curve_len); + km_ecdsa_raw_digits_to_bytes(raw_sig->s, s_buf, ctx->curve_len); + + der_sig_len = ECC_MAX_SIG_SIZE; + err = wc_ecc_rs_raw_to_sig(r_buf, ctx->curve_len, s_buf, ctx->curve_len, + der_sig, &der_sig_len); + if (err) { + #ifdef WOLFKM_DEBUG_ECDSA + pr_err("error: %s: ecdsa verify: wc_ecc_rs_raw_to_sig returned: %d\n", + WOLFKM_ECDSA_DRIVER, err); + #endif /* WOLFKM_DEBUG_ECDSA */ + err = -EBADMSG; + goto ecdsa_verify_end; + } + + err = wc_ecc_verify_hash(der_sig, der_sig_len, digest, dlen, &result, + ctx->key); + + if (err) { + #ifdef WOLFKM_DEBUG_ECDSA + pr_err("error: %s: ecdsa verify: verify_hash returned: %d\n", + WOLFKM_ECDSA_DRIVER, err); + #endif /* WOLFKM_DEBUG_ECDSA */ + err = -EBADMSG; + goto ecdsa_verify_end; + } + + if (result != 1) { + #ifdef WOLFKM_DEBUG_ECDSA + pr_err("info: %s: ecdsa verify: verify fail: %d\n", + WOLFKM_ECDSA_DRIVER, result); + #endif /* WOLFKM_DEBUG_ECDSA */ + err = -EKEYREJECTED; + goto ecdsa_verify_end; + } + +ecdsa_verify_end: + + free(work_buffer); + + #ifdef WOLFKM_DEBUG_ECDSA + pr_info("info: exiting km_ecdsa_verify dlen %d, slen %d, " + "err %d, result %d\n", dlen, slen, err, result); + #endif /* WOLFKM_DEBUG_ECDSA */ + return err; +} + +#else /* !LINUXKM_ECDSA_SIG_ALG */ + /* * Verify an ecdsa_nist signature. * @@ -405,8 +673,17 @@ static int km_ecdsa_verify(struct akcipher_request *req) sig_len = req->src_len; hash_len = req->dst_len; + /* 6 ECDSA (struct sig_testvec) test vectors in crypto/testmgr.h use SHA-1 + * (m_size 20). + */ +#ifdef WC_LINUXKM_HAVE_SELFTEST + wc_static_assert2(WC_MIN_DIGEST_SIZE_FOR_VERIFY <= 20, + "WC_MIN_DIGEST_SIZE_FOR_VERIFY must allow SHA-1-sized digests when " + "native kernel self-test is enabled."); +#endif + if ((hash_len > WC_MAX_DIGEST_SIZE) || - (hash_len < WC_MIN_DIGEST_SIZE)) + (hash_len < WC_MIN_DIGEST_SIZE_FOR_VERIFY)) { err = -EINVAL; goto ecdsa_verify_end; @@ -456,7 +733,8 @@ static int km_ecdsa_verify(struct akcipher_request *req) } ecdsa_verify_end: - if (sig != NULL) { free(sig); sig = NULL; } + + free(sig); #ifdef WOLFKM_DEBUG_ECDSA pr_info("info: exiting km_ecdsa_verify hash_len %d, sig_len %d, " @@ -465,6 +743,8 @@ ecdsa_verify_end: return err; } +#endif /* !LINUXKM_ECDSA_SIG_ALG */ + #if defined(LINUXKM_ECC192) static int linuxkm_test_ecdsa_nist_p192(void) { @@ -709,6 +989,161 @@ static int linuxkm_test_ecdsa_nist_p521(void) } #endif /* HAVE_ECC521 */ +#ifdef LINUXKM_ECDSA_SIG_ALG + +/* Convert a big endian byte array to the kernel's little endian u64 raw + * digit array format, zero-filling the KM_ECDSA_MAX_DIGITS digits. Inverse + * of km_ecdsa_raw_digits_to_bytes(). + */ +static void km_ecdsa_bytes_to_raw_digits(const byte *in, word32 in_len, + u64 *out) +{ + word32 i; + + XMEMSET(out, 0, KM_ECDSA_MAX_DIGITS * sizeof(u64)); + for (i = 0; i < in_len; i++) + out[i >> 3] |= ((u64)in[in_len - 1U - i]) << ((i & 7U) << 3); +} + +static int linuxkm_test_ecdsa_nist_driver(const char * driver, + const byte * pub, word32 pub_len, + const byte * sig, word32 sig_len, + const byte * hash, word32 hash_len) +{ + int test_rc = WC_NO_ERR_TRACE(WC_FAILURE); + int ret = 0; + struct crypto_sig * tfm = NULL; + struct km_ecdsa_raw_sig * raw_sig = NULL; + byte * r_buf = NULL; + byte * s_buf = NULL; + word32 r_len = 0; + word32 s_len = 0; + word32 curve_len = 0; + + /* infer the curve length from the raw uncompressed pub key: + * 0x04 || x || y. */ + if ((pub_len < 1) || (((pub_len - 1) & 1) != 0)) { + pr_err("error: %s: test pub key has invalid length %u\n", + driver, pub_len); + return BAD_FUNC_ARG; + } + curve_len = (pub_len - 1) >> 1; + + /* allocate the kernel-raw-format signature, followed by buffers for the + * big endian r and s decoded from the DER test signature. */ + raw_sig = (struct km_ecdsa_raw_sig *)malloc( + sizeof(struct km_ecdsa_raw_sig) + (2 * curve_len)); + if (! raw_sig) { + pr_err("error: allocating raw_sig buffer failed.\n"); + test_rc = MEMORY_E; + goto test_ecdsa_nist_end; + } + r_buf = (byte *)raw_sig + sizeof(struct km_ecdsa_raw_sig); + s_buf = r_buf + curve_len; + + /* + * Allocate the sig transform. + */ + tfm = crypto_alloc_sig(driver, 0, 0); + if (IS_ERR(tfm)) { + pr_err("error: allocating sig algorithm %s failed: %d\n", + driver, (int)PTR_ERR(tfm)); + if (PTR_ERR(tfm) == -ENOMEM) + test_rc = MEMORY_E; + else + test_rc = BAD_FUNC_ARG; + tfm = NULL; + goto test_ecdsa_nist_end; + } + + /* now set pub key for verify test. */ + ret = crypto_sig_set_pubkey(tfm, pub, pub_len); + if (ret) { + pr_err("error: crypto_sig_set_pubkey returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_ecdsa_nist_end; + } + + { + /* The behavior of crypto_sig_Xsize (X= max, key, digest) changed + * at linux kernel v6.15.3: + * < 6.15.3: keysize is in bytes. + * >= 6.15.3: keysize is in bits, maxsize and digestsize in + * bytes. */ + unsigned int maxsize = crypto_sig_maxsize(tfm); + unsigned int keysize = crypto_sig_keysize(tfm); + unsigned int digestsize = crypto_sig_digestsize(tfm); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 3) + keysize = ((keysize + WOLFSSL_BIT_SIZE - 1) / WOLFSSL_BIT_SIZE); + #endif /* linux >= 6.15.3 */ + + #ifdef WOLFKM_DEBUG_ECDSA + pr_info("info: crypto_sig_{max, key, digest}size: " + "{%d, %d, %d}\n", + maxsize, keysize, digestsize); + #endif /* WOLFKM_DEBUG_ECDSA */ + + if ((keysize != curve_len) || + (maxsize != curve_len) || + (digestsize != (unsigned int)WC_MAX_DIGEST_SIZE)) + { + pr_err("error: crypto_sig_{max, key, digest}size " + "returned {%u, %u, %u}, expected {%u, %u, %u}\n", + maxsize, keysize, digestsize, + curve_len, curve_len, (unsigned int)WC_MAX_DIGEST_SIZE); + test_rc = BAD_FUNC_ARG; + goto test_ecdsa_nist_end; + } + } + + /* convert the DER test signature to the kernel's raw format. */ + r_len = curve_len; + s_len = curve_len; + ret = wc_ecc_sig_to_rs(sig, sig_len, r_buf, &r_len, s_buf, &s_len); + if (ret) { + pr_err("error: wc_ecc_sig_to_rs returned: %d\n", ret); + test_rc = ret; + goto test_ecdsa_nist_end; + } + + km_ecdsa_bytes_to_raw_digits(r_buf, r_len, raw_sig->r); + km_ecdsa_bytes_to_raw_digits(s_buf, s_len, raw_sig->s); + + ret = crypto_sig_verify(tfm, raw_sig, (unsigned int)sizeof(*raw_sig), + hash, hash_len); + if (ret) { + pr_err("error: crypto_sig_verify returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_ecdsa_nist_end; + } + + /* corrupt the signature -- verify should now fail. */ + raw_sig->r[0] ^= 1U; + + ret = crypto_sig_verify(tfm, raw_sig, (unsigned int)sizeof(*raw_sig), + hash, hash_len); + if ((ret != -EBADMSG) && (ret != -EKEYREJECTED)) { + pr_err("error: crypto_sig_verify returned %d, expected %d or %d\n", + ret, -EBADMSG, -EKEYREJECTED); + test_rc = BAD_FUNC_ARG; + goto test_ecdsa_nist_end; + } + + test_rc = 0; +test_ecdsa_nist_end: + if (tfm) + crypto_free_sig(tfm); + free(raw_sig); + + #ifdef WOLFKM_DEBUG_ECDSA + pr_info("info: %s: self test returned: %d\n", driver, test_rc); + #endif /* WOLFKM_DEBUG_ECDSA */ + return test_rc; +} + +#else /* !LINUXKM_ECDSA_SIG_ALG */ + static int linuxkm_test_ecdsa_nist_driver(const char * driver, const byte * pub, word32 pub_len, const byte * sig, word32 sig_len, @@ -854,6 +1289,8 @@ test_ecdsa_nist_end: return test_rc; } +#endif /* !LINUXKM_ECDSA_SIG_ALG */ + #endif /* LINUXKM_LKCAPI_REGISTER_ECDSA */ #endif /* !WC_SKIP_INCLUDED_C_FILES */ diff --git a/linuxkm/lkcapi_glue.c b/linuxkm/lkcapi_glue.c index a3c0044938..a145770a4f 100644 --- a/linuxkm/lkcapi_glue.c +++ b/linuxkm/lkcapi_glue.c @@ -40,7 +40,6 @@ #if defined(CONFIG_CRYPTO_FIPS) != defined(HAVE_FIPS) #error CONFIG_CRYPTO_MANAGER requires that CONFIG_CRYPTO_FIPS match HAVE_FIPS. #endif - #include #endif /* need misc.c for ForceZero(). */ @@ -553,7 +552,24 @@ static int linuxkm_lkcapi_register(void) #endif #ifdef LINUXKM_LKCAPI_REGISTER_ECDSA - #if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) && \ + #if defined(LINUXKM_ECDSA_SIG_ALG) + /* linux 6.13+: the ecdsa-nist-pN algs are struct sig_alg. */ + #if defined(LINUXKM_ECC192) + REGISTER_ALG(ecdsa_nist_p192, sig, + linuxkm_test_ecdsa_nist_p192); + #endif /* LINUXKM_ECC192 */ + + REGISTER_ALG(ecdsa_nist_p256, sig, + linuxkm_test_ecdsa_nist_p256); + + REGISTER_ALG(ecdsa_nist_p384, sig, + linuxkm_test_ecdsa_nist_p384); + + #if defined(HAVE_ECC521) + REGISTER_ALG(ecdsa_nist_p521, sig, + linuxkm_test_ecdsa_nist_p521); + #endif /* HAVE_ECC521 */ + #elif (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) && \ defined(HAVE_FIPS) && defined(CONFIG_CRYPTO_FIPS) && \ defined(WC_LINUXKM_HAVE_SELFTEST) /* @@ -575,7 +591,7 @@ static int linuxkm_lkcapi_register(void) REGISTER_ALG_OPTIONAL(ecdsa_nist_p521, akcipher, linuxkm_test_ecdsa_nist_p521); #endif /* HAVE_ECC521 */ - #else + #else /* kernel 6.3-6.12 */ #if defined(LINUXKM_ECC192) REGISTER_ALG(ecdsa_nist_p192, akcipher, linuxkm_test_ecdsa_nist_p192); @@ -591,7 +607,7 @@ static int linuxkm_lkcapi_register(void) REGISTER_ALG(ecdsa_nist_p521, akcipher, linuxkm_test_ecdsa_nist_p521); #endif /* HAVE_ECC521 */ - #endif /* if linux < 6.3 && HAVE_FIPS && etc.. */ + #endif /* kernel 6.3-6.12 */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) && \ defined(HAVE_FIPS) && defined(CONFIG_CRYPTO_FIPS) && \ @@ -917,14 +933,26 @@ static int linuxkm_lkcapi_unregister(void) #endif #ifdef LINUXKM_LKCAPI_REGISTER_ECDSA - #if defined(LINUXKM_ECC192) - UNREGISTER_ALG(ecdsa_nist_p192, akcipher); - #endif /* LINUXKM_ECC192 */ - UNREGISTER_ALG(ecdsa_nist_p256, akcipher); - UNREGISTER_ALG(ecdsa_nist_p384, akcipher); - #if defined(HAVE_ECC521) - UNREGISTER_ALG(ecdsa_nist_p521, akcipher); - #endif /* HAVE_ECC521 */ + #if defined(LINUXKM_ECDSA_SIG_ALG) + /* linux 6.13+: the ecdsa-nist-pN algs are struct sig_alg. */ + #if defined(LINUXKM_ECC192) + UNREGISTER_ALG(ecdsa_nist_p192, sig); + #endif /* LINUXKM_ECC192 */ + UNREGISTER_ALG(ecdsa_nist_p256, sig); + UNREGISTER_ALG(ecdsa_nist_p384, sig); + #if defined(HAVE_ECC521) + UNREGISTER_ALG(ecdsa_nist_p521, sig); + #endif /* HAVE_ECC521 */ + #else /* !LINUXKM_ECDSA_SIG_ALG */ + #if defined(LINUXKM_ECC192) + UNREGISTER_ALG(ecdsa_nist_p192, akcipher); + #endif /* LINUXKM_ECC192 */ + UNREGISTER_ALG(ecdsa_nist_p256, akcipher); + UNREGISTER_ALG(ecdsa_nist_p384, akcipher); + #if defined(HAVE_ECC521) + UNREGISTER_ALG(ecdsa_nist_p521, akcipher); + #endif /* HAVE_ECC521 */ + #endif /* !LINUXKM_ECDSA_SIG_ALG */ #endif /* LINUXKM_LKCAPI_REGISTER_ECDSA */ #ifdef LINUXKM_LKCAPI_REGISTER_ECDH diff --git a/linuxkm/lkcapi_sha_glue.c b/linuxkm/lkcapi_sha_glue.c index 33b91048ea..f7b275c4a6 100644 --- a/linuxkm/lkcapi_sha_glue.c +++ b/linuxkm/lkcapi_sha_glue.c @@ -1608,6 +1608,10 @@ static int wc_get_random_bytes_callbacks_installed = 0; #elif defined(WOLFSSL_LINUXKM_USE_GET_RANDOM_KPROBES) +#ifndef WOLFSSL_EXPERIMENTAL_SETTINGS + #error WOLFSSL_LINUXKM_USE_GET_RANDOM_KPROBES requires WOLFSSL_EXPERIMENTAL_SETTINGS. +#endif + #ifndef CONFIG_KPROBES #error WOLFSSL_LINUXKM_USE_GET_RANDOM_KPROBES without CONFIG_KPROBES. #endif diff --git a/linuxkm/module_exports.c.template b/linuxkm/module_exports.c.template index 8209c6277f..f3583184ed 100644 --- a/linuxkm/module_exports.c.template +++ b/linuxkm/module_exports.c.template @@ -32,7 +32,6 @@ #endif #ifndef NO_CRYPT_TEST #include -#include #endif #ifndef EXPORT_SYMBOL_NS diff --git a/linuxkm/module_hooks.c b/linuxkm/module_hooks.c index 55fc70e0a7..52d6fb0d0a 100644 --- a/linuxkm/module_hooks.c +++ b/linuxkm/module_hooks.c @@ -1316,10 +1316,6 @@ void *wc_linuxkm_realloc(void *ptr, size_t newsize) return kvrealloc(ptr, WC_LINUXKM_ROUND_UP_P_OF_2(newsize), (wc_linuxkm_can_block() ? GFP_KERNEL : GFP_ATOMIC)); } -#ifdef CONFIG_HAVE_KPROBES -#include -#endif - size_t wc_linuxkm_malloc_usable_size(void *ptr) { if ((ptr == NULL) || is_vmalloc_addr(ptr)) { diff --git a/src/internal.c b/src/internal.c index 52da452f37..684ff8df84 100644 --- a/src/internal.c +++ b/src/internal.c @@ -5808,7 +5808,7 @@ int EccVerify(WOLFSSL* ssl, const byte* in, word32 inSz, const byte* out, /* Check hash length */ if ((outSz > WC_MAX_DIGEST_SIZE) || - (outSz < WC_MIN_DIGEST_SIZE)) { + (outSz < WC_MIN_DIGEST_SIZE_FOR_VERIFY)) { return BAD_LENGTH_E; } diff --git a/src/pk_ec.c b/src/pk_ec.c index fc22ce163d..d71f0d22d6 100644 --- a/src/pk_ec.c +++ b/src/pk_ec.c @@ -5306,7 +5306,7 @@ int wolfSSL_ECDSA_do_verify(const unsigned char *dgst, int dLen, /* Check hash length */ if ((ret == 1) && ((dLen > WC_MAX_DIGEST_SIZE) || - (dLen < WC_MIN_DIGEST_SIZE))) { + (dLen < WC_MIN_DIGEST_SIZE_FOR_VERIFY))) { WOLFSSL_MSG("wolfSSL_ECDSA_do_verify Bad digest size"); ret = WOLFSSL_FATAL_ERROR; } @@ -5438,7 +5438,7 @@ int wolfSSL_ECDSA_verify(int type, const unsigned char *digest, int digestSz, /* Check hash length */ if ((ret == 1) && ((digestSz > WC_MAX_DIGEST_SIZE) || - (digestSz < WC_MIN_DIGEST_SIZE))) { + (digestSz < WC_MIN_DIGEST_SIZE_FOR_VERIFY))) { WOLFSSL_MSG("wolfSSL_ECDSA_verify Bad digest size"); ret = 0; } diff --git a/tests/api.c b/tests/api.c index 6210e8b926..559ba45f1b 100644 --- a/tests/api.c +++ b/tests/api.c @@ -4282,8 +4282,16 @@ static int test_wolfSSL_CTX_SetTmpDH_file(void) ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_file(ctx, dhParamFile, CERT_FILETYPE)); #if defined(WOLFSSL_WPAS) && !defined(NO_DSA) - ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_file(ctx, dsaParamFile, - CERT_FILETYPE)); + if (EXPECT_SUCCESS()) { + if (ctx->minDhKeySz <= 128 /* bytes */) { + ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_file(ctx, dsaParamFile, + CERT_FILETYPE)); + } + else { + ExpectIntEQ(DH_KEY_SIZE_E, wolfSSL_CTX_SetTmpDH_file(ctx, dsaParamFile, + CERT_FILETYPE)); + } + } #endif wolfSSL_CTX_free(ctx); @@ -4791,8 +4799,16 @@ static int test_wolfSSL_SetTmpDH_file(void) ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetTmpDH_file(ssl, dhX942ParamFile, CERT_FILETYPE)); #if defined(WOLFSSL_WPAS) && !defined(NO_DSA) - ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_file(ctx, dsaParamFile, - CERT_FILETYPE)); + if (EXPECT_SUCCESS()) { + if (ctx->minDhKeySz <= 128 /* bytes */) { + ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetTmpDH_file(ctx, dsaParamFile, + CERT_FILETYPE)); + } + else { + ExpectIntEQ(DH_KEY_SIZE_E, wolfSSL_CTX_SetTmpDH_file(ctx, dsaParamFile, + CERT_FILETYPE)); + } + } #endif wolfSSL_free(ssl); diff --git a/tests/api/api.h b/tests/api/api.h index 2ce8c17d3a..69b1f433e5 100644 --- a/tests/api/api.h +++ b/tests/api/api.h @@ -39,29 +39,35 @@ #include -#if defined(WC_FIPS_186_5_PLUS) +/* Old FIPS headers don't allow comparisons with WC_MIN_DIGEST_SIZE_FOR_SIGN by + * the preprocessor, so we catch those builds with one of the first two + * clauses. + */ +#if defined(WC_FIPS_186_5_PLUS) && \ + defined(HAVE_FIPS) && FIPS_VERSION3_LT(7, 0, 0) #define TEST_STRING "WC_FIPS_186_5_PLUS test test" #define TEST_STRING_SZ 28 -#elif defined(WC_FIPS_186_4_PLUS) || defined(HAVE_SELFTEST) +#elif defined(HAVE_SELFTEST) || (defined(WC_FIPS_186_4_PLUS) && \ + defined(HAVE_FIPS) && FIPS_VERSION3_LT(7, 0, 0)) #define TEST_STRING "WC_FIPS_186_4_PLUS test.." #define TEST_STRING_SZ 25 -#elif WC_MIN_DIGEST_SIZE <= 25 +#elif WC_MIN_DIGEST_SIZE_FOR_SIGN <= 25 #define TEST_STRING "Everyone gets Friday off." #define TEST_STRING_SZ 25 -#elif WC_MIN_DIGEST_SIZE <= 28 +#elif WC_MIN_DIGEST_SIZE_FOR_SIGN <= 28 #define TEST_STRING "Everyone works the weekends." #define TEST_STRING_SZ 28 -#elif WC_MIN_DIGEST_SIZE <= 32 +#elif WC_MIN_DIGEST_SIZE_FOR_SIGN <= 32 #define TEST_STRING "Everyone works through the night" #define TEST_STRING_SZ 32 -#elif WC_MIN_DIGEST_SIZE <= 48 +#elif WC_MIN_DIGEST_SIZE_FOR_SIGN <= 48 #define TEST_STRING "Everyone gets to summer in Tuscany with Chianti." #define TEST_STRING_SZ 48 -#elif WC_MIN_DIGEST_SIZE <= 64 +#elif WC_MIN_DIGEST_SIZE_FOR_SIGN <= 64 #define TEST_STRING "Everyone works from Christmas Eve, clear through New Year's Day." #define TEST_STRING_SZ 64 #else - #error WC_MIN_DIGEST_SIZE value not supported by unit test. + #error WC_MIN_DIGEST_SIZE_FOR_SIGN value not supported by unit test. #endif #ifndef ONEK_BUF diff --git a/tests/api/test_evp_pkey.c b/tests/api/test_evp_pkey.c index 9bdd5b9339..3dc2a51373 100644 --- a/tests/api/test_evp_pkey.c +++ b/tests/api/test_evp_pkey.c @@ -1526,7 +1526,11 @@ static int test_wolfSSL_EVP_PKEY_sign_verify(int keyType) !defined(HAVE_SELFTEST) #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) { +#ifdef HAVE_FIPS + ExpectNotNull(rsa = RSA_generate_key(2048, WC_RSA_EXPONENT, NULL, NULL)); +#else ExpectNotNull(rsa = RSA_generate_key(2048, 3, NULL, NULL)); +#endif ExpectIntEQ(EVP_PKEY_assign_RSA(pkey, rsa), WOLFSSL_SUCCESS); } #endif @@ -2159,7 +2163,11 @@ int test_wolfSSL_EVP_PKEY_encrypt(void) XMEMSET(outDec, 0, rsaKeySz); } +#ifdef HAVE_FIPS + ExpectNotNull(rsa = RSA_generate_key(2048, WC_RSA_EXPONENT, NULL, NULL)); +#else ExpectNotNull(rsa = RSA_generate_key(2048, 3, NULL, NULL)); +#endif ExpectNotNull(pkey = wolfSSL_EVP_PKEY_new()); ExpectIntEQ(EVP_PKEY_assign_RSA(pkey, rsa), WOLFSSL_SUCCESS); if (EXPECT_FAIL()) { diff --git a/tests/api/test_ossl_rsa.c b/tests/api/test_ossl_rsa.c index dc0cee665b..b4ee4a22e5 100644 --- a/tests/api/test_ossl_rsa.c +++ b/tests/api/test_ossl_rsa.c @@ -65,7 +65,11 @@ int test_wolfSSL_RSA(void) RSA_free(rsa); rsa = NULL; +#ifdef HAVE_FIPS + ExpectNotNull(rsa = RSA_generate_key(2048, WC_RSA_EXPONENT, NULL, NULL)); +#else ExpectNotNull(rsa = RSA_generate_key(2048, 3, NULL, NULL)); +#endif ExpectIntEQ(RSA_size(rsa), 256); #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(6,0,0)) && !defined(HAVE_SELFTEST) @@ -306,7 +310,11 @@ int test_wolfSSL_RSA(void) rsa = NULL; #if !defined(USE_FAST_MATH) || (FP_MAX_BITS >= (3072*2)) +#ifdef HAVE_FIPS + ExpectNotNull(rsa = RSA_generate_key(3072, WC_RSA_EXPONENT, NULL, NULL)); +#else ExpectNotNull(rsa = RSA_generate_key(3072, 17, NULL, NULL)); +#endif ExpectIntEQ(RSA_size(rsa), 384); ExpectIntEQ(RSA_bits(rsa), 3072); RSA_free(rsa); @@ -461,7 +469,11 @@ int test_wolfSSL_RSA_print(void) RSA_free(rsa); rsa = NULL; +#ifdef HAVE_FIPS + ExpectNotNull(rsa = RSA_generate_key(2048, WC_RSA_EXPONENT, NULL, NULL)); +#else ExpectNotNull(rsa = RSA_generate_key(2048, 3, NULL, NULL)); +#endif ExpectIntEQ(RSA_print(bio, rsa, 0), 1); ExpectIntEQ(RSA_print(bio, rsa, 4), 1); @@ -644,7 +656,11 @@ int test_wolfSSL_RSA_meth(void) RSA_METHOD *rsa_meth = NULL; #ifdef WOLFSSL_KEY_GEN +#ifdef HAVE_FIPS + ExpectNotNull(rsa = RSA_generate_key(2048, WC_RSA_EXPONENT, NULL, NULL)); +#else ExpectNotNull(rsa = RSA_generate_key(2048, 3, NULL, NULL)); +#endif RSA_free(rsa); rsa = NULL; #else diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 8417e84efa..4c550632ba 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -82,6 +82,9 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits * WOLFSSL_AESNI_BY4: AES-NI 4-block parallel processing default: off * WOLFSSL_AESNI_BY6: AES-NI 6-block parallel processing default: off * USE_INTEL_SPEEDUP: Intel AVX/AVX2 for AES acceleration default: off + * USE_INTEL_SPEEDUP_FOR_AES: + Same as USE_INTEL_SPEEDUP, but scoped + to AES. default: off * WOLFSSL_AES_SMALL_TABLES: Use smaller AES S-box tables default: off * WOLFSSL_AES_NO_UNROLL: Disable AES round loop unrolling default: off * WOLFSSL_AES_TOUCH_LINES: Touch all cache lines for default: off @@ -812,6 +815,10 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits XASM_LINK("AES_256_Key_Expansion_AESNI"); #ifdef WOLFSSL_X86_64_BUILD + #if defined(USE_INTEL_SPEEDUP_FOR_AES) && !defined(USE_INTEL_SPEEDUP) + #define USE_INTEL_SPEEDUP + #endif + /* Wide ECB / CBC / CTR variants for x86_64. They share the AES-NI key * schedule declared above and are selected at runtime from intel_flags. * AES_CBC_decrypt_AESNI is the single max-width path (the by4/by6/by8 diff --git a/wolfcrypt/src/dsa.c b/wolfcrypt/src/dsa.c index 6ae9d0a1ab..3ee03876fe 100644 --- a/wolfcrypt/src/dsa.c +++ b/wolfcrypt/src/dsa.c @@ -755,7 +755,10 @@ int wc_DsaExportKeyRaw(DsaKey* dsa, byte* x, word32* xSz, byte* y, word32* ySz) int wc_DsaSign(const byte* digest, byte* out, DsaKey* key, WC_RNG* rng) { - /* use sha1 by default for backwards compatibility */ + /* Use sha1 by default for backwards compatibility. This API will always + * fail in FIPS 186-5 builds, due to the forbidden SHA-1 sign operation, as + * required. + */ return wc_DsaSign_ex(digest, WC_SHA_DIGEST_SIZE, out, key, rng); } @@ -787,7 +790,7 @@ int wc_DsaSign_ex(const byte* digest, word32 digestSz, byte* out, DsaKey* key, return BAD_FUNC_ARG; if ((digestSz > WC_MAX_DIGEST_SIZE) || - (digestSz < WC_MIN_DIGEST_SIZE)) + (digestSz < WC_MIN_DIGEST_SIZE_FOR_SIGN)) { return BAD_LENGTH_E; } @@ -1121,12 +1124,8 @@ int wc_DsaVerify_ex(const byte* digest, word32 digestSz, const byte* sig, if (digest == NULL || sig == NULL || key == NULL || answer == NULL) return BAD_FUNC_ARG; - /* Note the min allowed digestSz here is WC_SHA_DIGEST_SIZE, not - * WC_MIN_DIGEST_SIZE, to allow verify-only legacy DSA operations, as - * expressly allowed under FIPS 186-5, FIPS 140-3, and SP 800-131A. - */ if ((digestSz > WC_MAX_DIGEST_SIZE) || - (digestSz < WC_SHA_DIGEST_SIZE)) + (digestSz < WC_MIN_DIGEST_SIZE_FOR_VERIFY)) { return BAD_LENGTH_E; } diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 686836c38c..3920d7a0ee 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -6907,7 +6907,7 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, return ECC_BAD_ARG_E; } if ((inlen > WC_MAX_DIGEST_SIZE) || - (inlen < WC_MIN_DIGEST_SIZE)) + (inlen < WC_MIN_DIGEST_SIZE_FOR_SIGN)) { return BAD_LENGTH_E; } @@ -7441,7 +7441,7 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, return ECC_BAD_ARG_E; } if ((inlen > WC_MAX_DIGEST_SIZE) || - (inlen < WC_MIN_DIGEST_SIZE)) + (inlen < WC_MIN_DIGEST_SIZE_FOR_SIGN)) { return BAD_LENGTH_E; } @@ -8755,7 +8755,7 @@ int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash, /* Check hash length */ if ((hashlen > WC_MAX_DIGEST_SIZE) || - (hashlen < WC_MIN_DIGEST_SIZE)) { + (hashlen < WC_MIN_DIGEST_SIZE_FOR_VERIFY)) { return BAD_LENGTH_E; } @@ -9474,7 +9474,7 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, /* Check hash length */ if ((hashlen > WC_MAX_DIGEST_SIZE) || - (hashlen < WC_MIN_DIGEST_SIZE)) { + (hashlen < WC_MIN_DIGEST_SIZE_FOR_VERIFY)) { return BAD_LENGTH_E; } diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 3492977ba0..61035e2fa2 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -4786,7 +4786,7 @@ static int wc_PKCS7_EcdsaVerify(wc_PKCS7* pkcs7, byte* sig, int sigSz, /* Check hash length */ if ((hashSz > WC_MAX_DIGEST_SIZE) || - (hashSz < WC_MIN_DIGEST_SIZE)) { + (hashSz < WC_MIN_DIGEST_SIZE_FOR_VERIFY)) { return BAD_LENGTH_E; } diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 51dc1d6fe7..5ca8ce20a1 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -4915,10 +4915,6 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #elif defined(WOLFSSL_LINUXKM) - #ifndef LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT - #include - #endif - int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) { (void)os; diff --git a/wolfcrypt/src/rng_bank.c b/wolfcrypt/src/rng_bank.c index 3aff7a821e..24d7cdccd3 100644 --- a/wolfcrypt/src/rng_bank.c +++ b/wolfcrypt/src/rng_bank.c @@ -71,6 +71,10 @@ ((rng_ptr)->drbg == NULL) #endif +/* To disable retry looping in wc_rng_bank_init(), pass timeout_secs=0, and to + * retry indefinitely, pass negative timeout_secs -- the flags arg here is only + * used to initialize the flags in the new bank. + */ WOLFSSL_API int wc_rng_bank_init( struct wc_rng_bank *ctx, int n_rngs, @@ -133,6 +137,22 @@ WOLFSSL_API int wc_rng_bank_init( WC_RELAX_LONG_LOOP(); if (ret == 0) break; + + /* Several plausible error codes are non-retryable -- fail early + * for these. + */ + switch (ret) { + case WC_NO_ERR_TRACE(BAD_MUTEX_E): + case WC_NO_ERR_TRACE(BAD_FUNC_ARG): + case WC_NO_ERR_TRACE(MEMORY_E): + case WC_NO_ERR_TRACE(NOT_COMPILED_IN): + case WC_NO_ERR_TRACE(MISSING_RNG_E): + case WC_NO_ERR_TRACE(BUFFER_E): + case WC_NO_ERR_TRACE(OPEN_RAN_E): + case WC_NO_ERR_TRACE(FIPS_NOT_ALLOWED_E): + goto out; + } + /* 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. @@ -141,7 +161,7 @@ WOLFSSL_API int wc_rng_bank_init( if (ret == WC_NO_ERR_TRACE(INTERRUPTED_E)) break; ts2 = XTIME(0); - if (ts2 - ts1 > timeout_secs) { + if ((timeout_secs >= 0) && (ts2 - ts1 > timeout_secs)) { ret = WC_TIMEOUT_E; break; } @@ -160,6 +180,8 @@ WOLFSSL_API int wc_rng_bank_init( } } +out: + if (ret != 0) (void)wc_rng_bank_fini(ctx); @@ -220,6 +242,8 @@ WOLFSSL_API int wc_rng_bank_set_affinity_handlers( WOLFSSL_API int wc_rng_bank_fini(struct wc_rng_bank *ctx) { int i; + int ret; + WC_ATOMIC_INT_ARG new_refcount; if (ctx == NULL) return BAD_FUNC_ARG; @@ -235,6 +259,18 @@ WOLFSSL_API int wc_rng_bank_fini(struct wc_rng_bank *ctx) { else if (wolfSSL_RefCur(ctx->refcount) < 1) return BAD_STATE_E; + wolfSSL_RefDec_IfEquals(&ctx->refcount, 1, &new_refcount, &ret); + if (ret != 0) { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "WARNING: wc_rng_bank_fini() called with refcount %d.", new_refcount); +#endif + if (new_refcount > 1) + return BUSY_E; + else + return ret; + } + #ifndef WC_RNG_BANK_STATIC if (ctx->rngs) #endif @@ -247,7 +283,13 @@ WOLFSSL_API int wc_rng_bank_fini(struct wc_rng_bank *ctx) { "BUG: wc_rng_bank_fini() called with RNG #%d still " "locked.\n", i); #endif - return BUSY_E; + wolfSSL_RefInc2(&ctx->refcount, &new_refcount, &ret); + /* Always return BAD_STATE_E here -- a locked rng with a zero + * refcount on the bank is always a corruption. + */ + (void)new_refcount; + (void)ret; + return BAD_STATE_E; } } @@ -313,22 +355,19 @@ WOLFSSL_API int wc_rng_bank_default_set(struct wc_rng_bank *bank) { if (bank == NULL) return BAD_FUNC_ARG; - if ((! (bank->flags & WC_RNG_BANK_FLAG_INITED)) || - (wolfSSL_RefCur(bank->refcount) < 1)) - { + if (! (bank->flags & WC_RNG_BANK_FLAG_INITED)) return BAD_STATE_E; - } - wolfSSL_RefInc2(&bank->refcount, &new_refcount, &ret); - if (ret != 0) - return ret; + wolfSSL_RefInc_IfAtLeast(&bank->refcount, 1, &new_refcount, &ret); + if (ret != 0) { #ifdef WC_VERBOSE_RNG - if (new_refcount < 2) WOLFSSL_DEBUG_PRINTF( - "BUG: wc_rng_bank_default_set() new_refcount %d.\n", new_refcount); + "BUG: wc_rng_bank_default_set() with refcount %d.\n", new_refcount); #else - (void)new_refcount; + (void)new_refcount; #endif + return ret; + } if (wolfSSL_Atomic_Ptr_CompareExchange((void * volatile *)&default_rng_bank, (void **)&cur_default_rng_bank, bank)) return 0; else { @@ -351,13 +390,19 @@ WOLFSSL_API int wc_rng_bank_default_set(struct wc_rng_bank *bank) { WOLFSSL_API int wc_rng_bank_default_checkout(struct wc_rng_bank **bank) { int ret; struct wc_rng_bank *cur_default_rng_bank = default_rng_bank; + WC_ATOMIC_INT_ARG new_refcount; + if (bank == NULL) return BAD_FUNC_ARG; if (cur_default_rng_bank == NULL) return BAD_STATE_E; - wolfSSL_RefInc(&cur_default_rng_bank->refcount, &ret); - if (ret == 0) - *bank = cur_default_rng_bank; + + wolfSSL_RefInc_IfAtLeast(&cur_default_rng_bank->refcount, 2, &new_refcount, &ret); + if (ret != 0) + return ret; + + *bank = cur_default_rng_bank; + return ret; } @@ -431,6 +476,7 @@ WOLFSSL_API int wc_rng_bank_checkout( int ret = 0; time_t ts1, ts2; int n_rngs_tried = 0; + WC_ATOMIC_INT_ARG new_refcount; #ifdef WC_RNG_BANK_DEFAULT_SUPPORT if (bank == NULL) @@ -460,45 +506,16 @@ WOLFSSL_API int wc_rng_bank_checkout( return BAD_FUNC_ARG; } - if (flags & WC_RNG_BANK_FLAG_AFFINITY_LOCK) { - if ((bank->affinity_lock_cb == NULL) || - (bank->affinity_unlock_cb == NULL)) - { + /* Increment bank->refcount here speculatively, and assert on the resulting + * refcount, to mitigate races with bank deallocation. + */ + wolfSSL_RefInc_IfAtLeast(&bank->refcount, 1, &new_refcount, &ret); + if (ret != 0) { #ifdef WC_VERBOSE_RNG - WOLFSSL_DEBUG_PRINTF( - "BUG: wc_rng_bank_checkout() called with _AFFINITY_LOCK but " - "missing _lock_cb.\n"); + WOLFSSL_DEBUG_PRINTF( + "wc_rng_bank_checkout() called with refcount %d.\n", new_refcount); #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; - } + return ret; } if ((timeout_secs > 0) && (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) @@ -509,6 +526,46 @@ WOLFSSL_API int wc_rng_bank_checkout( for (; ret == 0;) { int expected = 0; + 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 + ret = BAD_FUNC_ARG; + break; + } + 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)) + ret = 0; + else + break; + } + + 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 + break; + } + } + + if ((preferred_inst_offset < 0) || + (preferred_inst_offset >= bank->n_rngs)) + { + ret = BAD_INDEX_E; + break; + } + if (wolfSSL_Atomic_Int_CompareExchange( &bank->rngs[preferred_inst_offset].lock, &expected, @@ -523,6 +580,7 @@ WOLFSSL_API int wc_rng_bank_checkout( (n_rngs_tried < bank->n_rngs)) { WOLFSSL_ATOMIC_STORE((*rng_inst)->lock, WC_RNG_BANK_INST_LOCK_FREE); + *rng_inst = NULL; } else { #ifdef WC_VERBOSE_RNG @@ -544,65 +602,102 @@ WOLFSSL_API int wc_rng_bank_checkout( */ #endif +#ifdef WOLFSSL_USE_SAVE_VECTOR_REGISTERS if ((flags | bank->flags) & WC_RNG_BANK_FLAG_NO_VECTOR_OPS) { - if (DISABLE_VECTOR_REGISTERS() == 0) + ret = DISABLE_VECTOR_REGISTERS(); + if (ret == 0) WOLFSSL_ATOMIC_STORE((*rng_inst)->lock, new_lock_value | WC_RNG_BANK_INST_LOCK_VEC_OPS_INH); + else if (ret == WC_NO_ERR_TRACE(WC_ACCEL_INHIBIT_E)) + ret = 0; + else { + WOLFSSL_ATOMIC_STORE((*rng_inst)->lock, WC_RNG_BANK_INST_LOCK_FREE); + *rng_inst = NULL; + break; + } } +#endif /* WOLFSSL_USE_SAVE_VECTOR_REGISTERS */ - return 0; /* Short-circuit return, holding onto RNG and affinity - * locks and vector register inhibition. + return 0; /* Short-circuit return, holding onto bank refcount, + * RNG lock, affinity locks, and (if applicable) + * 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)) + if ((n_rngs_tried >= bank->n_rngs) && + ((! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) || + (timeout_secs == 0))) { ret = BUSY_E; break; /* jump to cleanup. */ } + /* There's no longer any consistent connection between the CPU ID + * and the instance -- no point getting an affinity lock. + */ + flags &= ~(word32)WC_RNG_BANK_FLAG_AFFINITY_LOCK; + flags &= ~(word32)WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST; + ++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)) { + if ((! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) || + (timeout_secs == 0)) + { ret = BUSY_E; break; /* jump to cleanup. */ } } - if (flags & WC_RNG_BANK_FLAG_AFFINITY_LOCK) + if (new_lock_value & WC_RNG_BANK_INST_LOCK_AFFINITY_LOCKED) { (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 */ + new_lock_value &= ~WC_RNG_BANK_INST_LOCK_AFFINITY_LOCKED; } - /* 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_CAN_WAIT) && (timeout_secs != 0)) { + ret = WC_CHECK_FOR_INTR_SIGNALS(); + if (ret == WC_NO_ERR_TRACE(INTERRUPTED_E)) + break; + + if (timeout_secs > 0) { + ts2 = XTIME(0); + if (ts2 - ts1 >= timeout_secs) { + ret = WC_TIMEOUT_E; + break; + } + } + + WC_RELAX_LONG_LOOP(); + } } - if (flags & WC_RNG_BANK_FLAG_AFFINITY_LOCK) + if (ret == 0) + ret = RNG_FAILURE_E; + + if (new_lock_value & WC_RNG_BANK_INST_LOCK_AFFINITY_LOCKED) (void)bank->affinity_unlock_cb(bank->cb_arg); + /* Decrement the speculative refcount increment. */ + { + int refdec_err; + wolfSSL_RefDec2(&bank->refcount, &new_refcount, &refdec_err); +#ifdef WC_VERBOSE_RNG + if (refdec_err != 0) + WOLFSSL_DEBUG_PRINTF( + "WARNING: wc_rng_bank_checkout() cleanup wolfSSL_RefDec2 returned %d.", refdec_err); + else if (new_refcount <= 0) + WOLFSSL_DEBUG_PRINTF( + "WARNING: wc_rng_bank_checkout() bank refcount after wolfSSL_RefDec2() is %d.", new_refcount); +#else + (void)new_refcount; + (void)refdec_err; +#endif + } + return ret; } @@ -670,9 +765,28 @@ WOLFSSL_API int wc_rng_bank_checkin( REENABLE_VECTOR_REGISTERS(); if (lockval & WC_RNG_BANK_INST_LOCK_AFFINITY_LOCKED) - return bank->affinity_unlock_cb(bank->cb_arg); + ret = bank->affinity_unlock_cb(bank->cb_arg); else - return 0; + ret = 0; + + { + WC_ATOMIC_INT_ARG new_refcount; + int refdec_err; + wolfSSL_RefDec2(&bank->refcount, &new_refcount, &refdec_err); +#ifdef WC_VERBOSE_RNG + if (refdec_err != 0) + WOLFSSL_DEBUG_PRINTF( + "WARNING: wc_rng_bank_checkin() wolfSSL_RefDec2 returned %d.", refdec_err); + else if (new_refcount <= 0) + WOLFSSL_DEBUG_PRINTF( + "WARNING: wc_rng_bank_checkin() bank refcount after wolfSSL_RefDec2() is %d.", new_refcount); +#else + (void)new_refcount; + (void)refdec_err; +#endif + } + + return ret; } /* note the rng_inst passed to wc_rng_bank_inst_reinit() must have been obtained @@ -720,7 +834,7 @@ WOLFSSL_API int wc_rng_bank_inst_reinit( bank->heap, devId); if (ret == 0) break; - if (! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) { + if ((! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) || (timeout_secs == 0)) { #ifdef WC_VERBOSE_RNG WOLFSSL_DEBUG_PRINTF( "WARNING: wc_rng_bank_inst_reinit() returning err %d.\n", ret); @@ -849,21 +963,27 @@ WOLFSSL_API int wc_rng_bank_reseed(struct wc_rng_bank *bank, (word32)sizeof(scratch)); if (ret == 0) break; - if ((timeout_secs <= 0) || + if ((timeout_secs == 0) || (! (flags & WC_RNG_BANK_FLAG_CAN_WAIT))) { break; } - ts2 = XTIME(0); - if (ts2 - ts1 > timeout_secs) { + if (timeout_secs > 0) { + 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); + 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; + ret = WC_TIMEOUT_E; + break; + } } + ret = WC_CHECK_FOR_INTR_SIGNALS(); + if (ret == WC_NO_ERR_TRACE(INTERRUPTED_E)) + break; + WC_RELAX_LONG_LOOP(); } #ifdef WC_VERBOSE_RNG if ((ret != 0) && (ret != WC_NO_ERR_TRACE(WC_TIMEOUT_E))) @@ -872,8 +992,11 @@ WOLFSSL_API int wc_rng_bank_reseed(struct wc_rng_bank *bank, "for DRBG #%d returned %d.", n, ret); #endif (void)wc_rng_bank_checkin(bank, &drbg); - if (ret == WC_NO_ERR_TRACE(WC_TIMEOUT_E)) + if ((ret == WC_NO_ERR_TRACE(WC_TIMEOUT_E)) || + (ret == WC_NO_ERR_TRACE(INTERRUPTED_E))) + { return ret; + } ret = WC_CHECK_FOR_INTR_SIGNALS(); if (ret == WC_NO_ERR_TRACE(INTERRUPTED_E)) return ret; @@ -892,6 +1015,7 @@ WOLFSSL_API int wc_rng_bank_reseed(struct wc_rng_bank *bank, WOLFSSL_API int wc_InitRng_BankRef(struct wc_rng_bank *bank, WC_RNG *rng) { int ret; + WC_ATOMIC_INT_ARG new_refcount; #ifdef WC_RNG_BANK_DEFAULT_SUPPORT if (bank == NULL) @@ -904,19 +1028,15 @@ WOLFSSL_API int wc_InitRng_BankRef(struct wc_rng_bank *bank, WC_RNG *rng) return BAD_FUNC_ARG; } - if ((! (bank->flags & WC_RNG_BANK_FLAG_INITED)) || - (wolfSSL_RefCur(bank->refcount) < 1)) - { + if (! (bank->flags & WC_RNG_BANK_FLAG_INITED)) return BAD_STATE_E; - } - - XMEMSET(rng, 0, sizeof(*rng)); - - wolfSSL_RefInc(&bank->refcount, &ret); + wolfSSL_RefInc_IfAtLeast(&bank->refcount, 1, &new_refcount, &ret); + (void)new_refcount; if (ret != 0) return ret; + XMEMSET(rng, 0, sizeof(*rng)); rng->heap = bank->heap; rng->status = WC_DRBG_BANKREF; rng->bankref = bank; diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index 5a734f5114..be72cb40c8 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -2153,6 +2153,28 @@ void wolfSSL_RefWithMutexInc2(wolfSSL_RefWithMutex* ref, int *new_count, *err = ret; } +void wolfSSL_RefWithMutexInc_IfAtLeast(wolfSSL_RefWithMutex* ref, + int cur_at_least, int *new_count, + int* err) +{ + *err = wc_LockMutex(&ref->mutex); + if (*err != 0) { + WOLFSSL_MSG("Failed to lock mutex for reference increment!"); + *new_count = -1; + } + else { + if (ref->count < cur_at_least) { + *new_count = ref->count; + *err = BAD_STATE_E; + } + else { + *new_count = ++ref->count; + *err = 0; + } + wc_UnLockMutex(&ref->mutex); + } +} + int wolfSSL_RefWithMutexLock(wolfSSL_RefWithMutex* ref) { return wc_LockMutex(&ref->mutex); @@ -2198,6 +2220,29 @@ void wolfSSL_RefWithMutexDec2(wolfSSL_RefWithMutex* ref, int* new_count, } *err = ret; } + +void wolfSSL_RefWithMutexDec_IfEquals(wolfSSL_RefWithMutex* ref, + int current_count, int* new_count, + int* err) +{ + *err = wc_LockMutex(&ref->mutex); + if (*err != 0) { + WOLFSSL_MSG("Failed to lock mutex for reference decrement!"); + *new_count = -1; + } + else { + if (ref->count != current_count) { + *new_count = ref->count; + *err = BAD_STATE_E; + } + else { + *new_count = --ref->count; + *err = 0; + } + wc_UnLockMutex(&ref->mutex); + } +} + #endif /* ! SINGLE_THREADED */ #if WOLFSSL_CRYPT_HW_MUTEX diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 66bcfef391..867e802bc2 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -38112,7 +38112,7 @@ static wc_test_ret_t ecc_test_vector_item(const eccVector* vector) #endif /* !NO_ASN */ #ifdef HAVE_ECC_VERIFY - if (vector->msgLen >= WC_MIN_DIGEST_SIZE) { + if (vector->msgLen >= WC_MIN_DIGEST_SIZE_FOR_VERIFY) { do { #if defined(WOLFSSL_ASYNC_CRYPT) ret = wc_AsyncWait(ret, &userA->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); @@ -43936,10 +43936,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ecc_test_buffers(void) wc_test_ret_t ret; word32 idx = 0; #ifndef WC_NO_RNG - /* 32 bytes: evenly divisible by AES_BLOCK_SZ and meets WC_MIN_DIGEST_SIZE */ + /* 32 bytes: evenly divisible by AES_BLOCK_SZ and meets WC_MIN_DIGEST_SIZE_FOR_SIGN */ byte in[] = "Everyone gets Friday off. ecc p"; - const word32 inLen = sizeof(in); /* includes null terminator */ + wc_static_assert(sizeof(in) >= WC_MIN_DIGEST_SIZE_FOR_SIGN); wc_static_assert2(sizeof(in) == 32, "in[] must be exactly 32 bytes"); + const word32 inLen = sizeof(in); /* includes null terminator */ byte out[256]; byte plain[256]; WOLFSSL_ENTER("ecc_test_buffers"); @@ -75449,16 +75450,26 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) * ecc_test calls to it are not skipped (WC_TEST_SKIP_ECC_CHECK_KEY); the * counter legitimately stays 0 otherwise. CAAM is excluded because the * check-pubkey dispatch in _ecc_validate_public_key is compiled out there - * (CAAM uses software validation failure to detect black keys). */ + * (CAAM uses software validation failure to detect black keys). + * + * The FIPS wrappers force the devId to FIPS_INVALID_DEVID, so we skip + * the check for FIPS. + */ #if !defined(WOLF_CRYPTO_CB_ONLY_ECC) && defined(HAVE_ECC_CHECK_KEY) && \ - !defined(WC_TEST_SKIP_ECC_CHECK_KEY) && !defined(WOLFSSL_CAAM) + !defined(WC_TEST_SKIP_ECC_CHECK_KEY) && !defined(WOLFSSL_CAAM) && \ + !defined(HAVE_FIPS) if (ret == 0 && myCtx.eccCheckPubCount == 0) ret = WC_TEST_RET_ENC_NC; #endif /* Regression: an explicit public point with zero coordinates must cross - * the callback boundary as X9.63 0x04||0||0, not as pubKey = NULL. */ + * the callback boundary as X9.63 0x04||0||0, not as pubKey = NULL. + * + * The FIPS wrappers force the devId to FIPS_INVALID_DEVID, so we skip + * the check for FIPS. + */ #if !defined(WOLFSSL_SWDEV) && defined(HAVE_ECC_CHECK_KEY) && \ - !defined(WOLFSSL_CAAM) && !defined(NO_ECC256) + !defined(WOLFSSL_CAAM) && !defined(NO_ECC256) && \ + !defined(HAVE_FIPS) if (ret == 0) { WC_DECLARE_VAR(zeroKey, ecc_key, 1, HEAP_HINT); int haveZeroKey = 0; @@ -75502,7 +75513,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) !defined(WOLFSSL_SILABS_SE_ACCEL) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \ !defined(NO_ECC_SECP) && !defined(WOLFSSL_NO_MALLOC) && \ !defined(WOLFSSL_CRYPTOCELL) && !defined(NO_ECC256) && \ - defined(HAVE_ECC_KEY_EXPORT) + defined(HAVE_ECC_KEY_EXPORT) && \ + !defined(HAVE_FIPS) if (ret == 0 && myCtx.eccMakePubCount == 0) ret = WC_TEST_RET_ENC_NC; #endif @@ -75519,7 +75531,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) !defined(WOLFSSL_SWDEV) && !defined(NO_ECC_SECP) && \ !defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_CRYPTOCELL) && \ !defined(WOLFSSL_SE050) && \ - !defined(NO_ECC256) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG) + !defined(NO_ECC256) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG) && \ + !defined(HAVE_FIPS) if (ret == 0) { /* generated keypair: private scalar for the negative tests, public * point for the resident-key test */ diff --git a/wolfssl/wolfcrypt/hash.h b/wolfssl/wolfcrypt/hash.h index cd0ec0b9c9..9195bfe0e2 100644 --- a/wolfssl/wolfcrypt/hash.h +++ b/wolfssl/wolfcrypt/hash.h @@ -176,25 +176,31 @@ typedef struct { #define WC_MAX_BLOCK_SIZE WC_HASH_CUSTOM_MAX_BLOCK_SIZE #endif +/* Set up WC_MIN_DIGEST_SIZE. This is the shortest digest supported by any + * fixed-output-size hash algorithm enabled in the library. It is not + * necessarily the shortest digest permitted for signature generation -- that is + * designated by WC_MIN_DIGEST_SIZE_FOR_SIGN, defined below, with additional + * restrictions under FIPS 186-5. + */ #if defined(WC_HASH_CUSTOM_MIN_DIGEST_SIZE) - #if defined(WC_FIPS_186_5_PLUS) && \ - (WC_HASH_CUSTOM_MIN_DIGEST_SIZE < 224 / 8) - #error FIPS 186-5 requires a minimum hash size >= SHA-224. - #elif defined(WC_FIPS_186_4) && \ + /* Note, FIPS 186-5 allows (and we need) SHA-1 in verify-only mode, but + * restricts signing to SHA-224 and larger, enforced below. + */ + #if defined(WC_FIPS_186_4_PLUS) && \ (WC_HASH_CUSTOM_MIN_DIGEST_SIZE < 160 / 8) - #error FIPS 186-4 requires a minimum hash size >= SHA-1. + #error FIPS 186 requires a minimum hash size >= SHA-1. #elif (WC_HASH_CUSTOM_MIN_DIGEST_SIZE < 128 / 8) #error WC_HASH_CUSTOM_MIN_DIGEST_SIZE is too small. #endif /* Let the user override the minimum digest size */ #define WC_MIN_DIGEST_SIZE WC_HASH_CUSTOM_MIN_DIGEST_SIZE -#elif defined(WOLFSSL_MD2) && !defined(WC_FIPS_186_4_PLUS) +#elif defined(WOLFSSL_MD2) #define WC_MIN_DIGEST_SIZE WC_MD2_DIGEST_SIZE /* 16 */ -#elif !defined(NO_MD4) && !defined(WC_FIPS_186_4_PLUS) +#elif !defined(NO_MD4) #define WC_MIN_DIGEST_SIZE WC_MD4_DIGEST_SIZE /* 16 */ -#elif !defined(NO_MD5) && !defined(WC_FIPS_186_4_PLUS) +#elif !defined(NO_MD5) #define WC_MIN_DIGEST_SIZE WC_MD5_DIGEST_SIZE /* 16 */ -#elif !defined(NO_SHA) && !defined(WC_FIPS_186_5_PLUS) +#elif !defined(NO_SHA) #define WC_MIN_DIGEST_SIZE WC_SHA_DIGEST_SIZE /* 20 */ #elif defined(WOLFSSL_SHA224) #define WC_MIN_DIGEST_SIZE WC_SHA224_DIGEST_SIZE @@ -232,6 +238,55 @@ typedef struct { #define WC_MIN_DIGEST_SIZE 64 #endif +/* We can't use preprocessor comparisons for asserts and conditional definitions + * here, because old FIPS uses enums for most of the digest sizes. Moreover we + * can't use WC_SHA_DIGEST_SIZE at all here, because we support SHA-1-sized + * digests even in NO_SHA builds. + */ +#ifdef WC_MIN_DIGEST_SIZE_FOR_SIGN + wc_static_assert2((WC_MIN_DIGEST_SIZE_FOR_SIGN <= WC_MAX_DIGEST_SIZE) && + (WC_MIN_DIGEST_SIZE_FOR_SIGN >= WC_MIN_DIGEST_SIZE), + "Supplied WC_MIN_DIGEST_SIZE_FOR_SIGN is out of range."); + #if defined(WC_FIPS_186_5_PLUS) + wc_static_assert2(WC_MIN_DIGEST_SIZE_FOR_SIGN >= 224 / 8, + "FIPS 186-5 requires a minimum sign-mode hash size >= SHA-224."); + #elif defined(WC_FIPS_186_4) + wc_static_assert2(WC_MIN_DIGEST_SIZE_FOR_SIGN >= 160 / 8, + "FIPS 186-4 requires a minimum sign-mode hash size >= SHA-1."); + #endif +#else + #if defined(WC_FIPS_186_5_PLUS) + #define WC_MIN_DIGEST_SIZE_FOR_SIGN \ + ((WC_MIN_DIGEST_SIZE < 224 / 8) ? (224 / 8) : WC_MIN_DIGEST_SIZE) + #elif defined(WC_FIPS_186_4) + #define WC_MIN_DIGEST_SIZE_FOR_SIGN \ + ((WC_MIN_DIGEST_SIZE < 224 / 8) ? (160 / 8) : WC_MIN_DIGEST_SIZE) + #else + #define WC_MIN_DIGEST_SIZE_FOR_SIGN WC_MIN_DIGEST_SIZE + #endif +#endif + +/* The minimum digest _FOR_VERIFY_under FIPS 186-5, FIPS 140-3, and SP 800-131A, + * is permitted to be shorter, to allow verify-only legacy DSA and ECDSA + * operations. + */ +#ifdef WC_MIN_DIGEST_SIZE_FOR_VERIFY + wc_static_assert2((WC_MIN_DIGEST_SIZE_FOR_VERIFY <= WC_MAX_DIGEST_SIZE) && + (WC_MIN_DIGEST_SIZE_FOR_VERIFY >= 128 / 8), + "Supplied WC_MIN_DIGEST_SIZE_FOR_VERIFY is out of range."); + #if defined(WC_FIPS_186_4_PLUS) + wc_static_assert2(WC_MIN_DIGEST_SIZE_FOR_VERIFY >= 160 / 8, + "FIPS 186 requires a minimum verify-mode hash size >= SHA-1."); + #endif +#else + #if defined(WC_FIPS_186_4_PLUS) + #define WC_MIN_DIGEST_SIZE_FOR_VERIFY \ + ((WC_MIN_DIGEST_SIZE < 160 / 8) ? (160 / 8) : WC_MIN_DIGEST_SIZE) + #else + #define WC_MIN_DIGEST_SIZE_FOR_VERIFY WC_MIN_DIGEST_SIZE + #endif +#endif + #if !defined(NO_ASN) || !defined(NO_DH) || defined(HAVE_ECC) WOLFSSL_API int wc_HashGetOID(enum wc_HashType hash_type); WOLFSSL_API enum wc_HashType wc_OidGetHash(int oid); diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index aeb81cc35e..853ae55f1c 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -517,15 +517,14 @@ #define FIPS_VERSION3_NE(major,minor,patch) \ (WOLFSSL_FIPS_VERSION_CODE != WOLFSSL_MAKE_FIPS_VERSION3(major,minor,patch)) -#if defined(HAVE_FIPS) && !defined(WC_FIPS_186_5) && !defined(WC_FIPS_186_4) - #if FIPS_VERSION3_GE(7,0,0) && !defined(WOLFSSL_FIPS_READY) - #ifndef WC_FIPS_186_5 - #define WC_FIPS_186_5 - #endif +#if (defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ + !defined(WC_FIPS_186_5) && !defined(WC_FIPS_186_4) + #if defined(HAVE_SELFTEST) + #define WC_FIPS_186_4 + #elif FIPS_VERSION3_GE(7,0,0) && !defined(WOLFSSL_FIPS_READY) + #define WC_FIPS_186_5 #else - #ifndef WC_FIPS_186_4 - #define WC_FIPS_186_4 - #endif + #define WC_FIPS_186_4 #endif #endif #if defined(WC_FIPS_186_4) && defined(WC_FIPS_186_5) @@ -4282,6 +4281,23 @@ /* siphash asm produces wrong results in kernel mode. */ #define WC_SIPHASH_NO_ASM #endif + + /* The first vector set in /usr/src/linux/crypto/testmgr.h + * ecdsa_nist_p192_tv_template[], ecdsa_nist_p256_tv_template[], and + * ecdsa_nist_p384_tv_template[] use SHA-1 (even if CONFIG_CRYPTO_SHA1 is + * disabled), and kernel module signatures frequently use SHA-1 until quite + * recently. Force the minimum downward in NO_SHA builds to assure the + * required support is present. + */ + #if defined(NO_SHA) && !defined(WC_MIN_DIGEST_SIZE_FOR_VERIFY) && \ + defined(HAVE_ECC) && \ + (defined(LINUXKM_LKCAPI_REGISTER_ALL) || \ + defined(LINUXKM_LKCAPI_REGISTER_ECDSA) || \ + (defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && \ + defined(CONFIG_CRYPTO_ECDSA))) + #define WC_MIN_DIGEST_SIZE_FOR_VERIFY 20 + #endif + #endif /* WOLFSSL_LINUXKM */ /* FreeBSD Kernel Module */ diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index cdbc989a36..c0bd1401ec 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -2332,14 +2332,14 @@ WOLFSSL_API word32 CheckRunTimeSettings(void); /* DISABLE_VECTOR_REGISTERS() and REENABLE_VECTOR_REGISTERS() are currently only * used by Linux kernel code. If WC_HAVE_VECTOR_SPEEDUPS, we default - * DISABLE_VECTOR_REGISTERS() to -1, to assure calling code is forced to handle - * the failure. But if the build disables vec regs globally, we can return 0 - * harmlessly. The kernel build defines real calls for these in vectorized - * builds, otherwise it uses these fallbacks. + * DISABLE_VECTOR_REGISTERS() to NOT_COMPILED_IN, to assure calling code is + * forced to handle the failure. But if the build disables vec regs globally, + * we can return 0 harmlessly. The kernel build defines real calls for these in + * vectorized builds, otherwise it uses these fallbacks. */ #ifndef DISABLE_VECTOR_REGISTERS #ifdef WC_HAVE_VECTOR_SPEEDUPS - #define DISABLE_VECTOR_REGISTERS() (-1) + #define DISABLE_VECTOR_REGISTERS() NOT_COMPILED_IN #else #define DISABLE_VECTOR_REGISTERS() 0 #endif diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index 07f5829f1e..7bf9fadc24 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -146,8 +146,11 @@ #endif #endif -#if defined(HAVE_FIPS) || defined(HAVE_SELFTEST) +#if (defined(HAVE_FIPS) && FIPS_VERSION3_LT(7,0,0)) || defined(HAVE_SELFTEST) #define INLINE WC_INLINE + #if defined(__GNUC__) || defined(__clang__) + #define __FUNCTION__ __func__ + #endif #endif #ifndef WC_NO_INLINE @@ -811,6 +814,25 @@ typedef struct wolfSSL_RefWithMutex wolfSSL_Ref; *(new_count) = wolfSSL_Atomic_Int_AddFetch(&(ref)->count, 1); \ *(err) = 0; \ } while(0) +#define wolfSSL_RefInc_IfAtLeast(ref, cur_at_least, new_count, err) \ + do { \ + WC_ATOMIC_INT_ARG _expected_count = \ + WOLFSSL_ATOMIC_LOAD((ref)->count); \ + while (_expected_count >= (cur_at_least)) { \ + *(new_count) = _expected_count + 1; \ + if (wolfSSL_Atomic_Int_CompareExchange( \ + &(ref)->count, \ + &_expected_count, \ + *(new_count))) \ + break; \ + } \ + if (_expected_count < (cur_at_least)) { \ + *(new_count) = _expected_count; \ + *(err) = BAD_STATE_E; \ + } \ + else \ + *(err) = 0; \ + } while(0) #define wolfSSL_RefDec(ref, isZero, err) \ do { \ int __prev = wolfSSL_Atomic_Int_FetchSub(&(ref)->count, 1); \ @@ -823,6 +845,25 @@ typedef struct wolfSSL_RefWithMutex wolfSSL_Ref; *(new_count) = wolfSSL_Atomic_Int_SubFetch(&(ref)->count, 1); \ *(err) = 0; \ } while(0) +#define wolfSSL_RefDec_IfEquals(ref, current_count, new_count, err) \ + do { \ + WC_ATOMIC_INT_ARG _expected_count = \ + WOLFSSL_ATOMIC_LOAD((ref)->count); \ + while (_expected_count == (current_count)) {\ + *(new_count) = _expected_count - 1; \ + if (wolfSSL_Atomic_Int_CompareExchange( \ + &(ref)->count, \ + &_expected_count, \ + *(new_count))) \ + break; \ + } \ + if (_expected_count != (current_count)) { \ + *(new_count) = _expected_count; \ + *(err) = BAD_STATE_E; \ + } \ + else \ + *(err) = 0; \ + } while(0) #else @@ -832,8 +873,10 @@ typedef struct wolfSSL_RefWithMutex wolfSSL_Ref; #define wolfSSL_RefFree wolfSSL_RefWithMutexFree #define wolfSSL_RefInc wolfSSL_RefWithMutexInc #define wolfSSL_RefInc2 wolfSSL_RefWithMutexInc2 +#define wolfSSL_RefInc_IfAtLeast wolfSSL_RefWithMutexInc_IfAtLeast #define wolfSSL_RefDec wolfSSL_RefWithMutexDec #define wolfSSL_RefDec2 wolfSSL_RefWithMutexDec2 +#define wolfSSL_RefDec_IfEquals wolfSSL_RefWithMutexDec_IfEquals #endif @@ -843,10 +886,12 @@ typedef struct wolfSSL_RefWithMutex wolfSSL_Ref; #define wolfSSL_RefWithMutexFree wolfSSL_RefFree #define wolfSSL_RefWithMutexInc wolfSSL_RefInc #define wolfSSL_RefWithMutexInc2 wolfSSL_RefInc2 +#define wolfSSL_RefWithMutexInc_IfAtLeast wolfSSL_RefInc_IfAtLeast #define wolfSSL_RefWithMutexLock(ref) 0 #define wolfSSL_RefWithMutexUnlock(ref) 0 #define wolfSSL_RefWithMutexDec wolfSSL_RefDec #define wolfSSL_RefWithMutexDec2 wolfSSL_RefDec2 +#define wolfSSL_RefWithMutexDec_IfEquals wolfSSL_RefDec_IfEquals #else @@ -858,12 +903,19 @@ WOLFSSL_LOCAL void wolfSSL_RefWithMutexInc(wolfSSL_RefWithMutex* ref, WOLFSSL_LOCAL void wolfSSL_RefWithMutexInc2(wolfSSL_RefWithMutex* ref, int *new_count, int* err); +WOLFSSL_LOCAL void wolfSSL_RefWithMutexInc_IfAtLeast(wolfSSL_RefWithMutex* ref, + int cur_at_least, + int *new_count, + int* err); WOLFSSL_LOCAL int wolfSSL_RefWithMutexLock(wolfSSL_RefWithMutex* ref); WOLFSSL_LOCAL int wolfSSL_RefWithMutexUnlock(wolfSSL_RefWithMutex* ref); WOLFSSL_LOCAL void wolfSSL_RefWithMutexDec(wolfSSL_RefWithMutex* ref, int* isZero, int* err); WOLFSSL_LOCAL void wolfSSL_RefWithMutexDec2(wolfSSL_RefWithMutex* ref, int* new_count, int* err); +WOLFSSL_LOCAL void wolfSSL_RefWithMutexDec_IfEquals(wolfSSL_RefWithMutex* ref, + int current_count, + int* new_count, int* err); #endif