diff --git a/doc/dox_comments/header_files-ja/chacha.h b/doc/dox_comments/header_files-ja/chacha.h index 968827018d7..d1e587472ab 100644 --- a/doc/dox_comments/header_files-ja/chacha.h +++ b/doc/dox_comments/header_files-ja/chacha.h @@ -33,6 +33,7 @@ int wc_Chacha_SetIV(ChaCha* ctx, const byte* inIv, word32 counter); \return 0 入力の暗号化または復号に成功した場合に返されます \return BAD_FUNC_ARG ctx入力引数の処理中にエラーが発生した場合に返されます + \return MISSING_KEY 処理前にwc_Chacha_SetKeyでキーが設定されていない場合に返されます \param ctx ivを設定するChaCha構造体へのポインタ \param output 出力暗号文または復号された平文を格納するバッファへのポインタ diff --git a/doc/dox_comments/header_files/chacha.h b/doc/dox_comments/header_files/chacha.h index 890b8270208..499c7ffd5cc 100644 --- a/doc/dox_comments/header_files/chacha.h +++ b/doc/dox_comments/header_files/chacha.h @@ -41,6 +41,8 @@ int wc_Chacha_SetIV(ChaCha* ctx, const byte* inIv, word32 counter); \return 0 Returned upon successfully encrypting or decrypting the input \return BAD_FUNC_ARG returned if there is an error processing the ctx input argument + \return MISSING_KEY returned if wc_Chacha_SetKey was not called to set a + key before processing \param ctx pointer to the ChaCha structure on which to set the iv \param output pointer to a buffer in which to store the output ciphertext diff --git a/doc/dox_comments/header_files/ecc.h b/doc/dox_comments/header_files/ecc.h index c754d19c9a4..25f48c11782 100644 --- a/doc/dox_comments/header_files/ecc.h +++ b/doc/dox_comments/header_files/ecc.h @@ -316,6 +316,8 @@ void wc_ecc_key_free(ecc_key* key); shared key \return MP_MEM may be returned if there is an error while computing the shared key + \return ECC_INF_E returned when the computed shared secret is the point at + infinity \param private_key pointer to the ecc_key structure containing the local private key diff --git a/tests/api/test_chacha.c b/tests/api/test_chacha.c index 46c2beba7fd..80a8758c384 100644 --- a/tests/api/test_chacha.c +++ b/tests/api/test_chacha.c @@ -703,3 +703,28 @@ int test_wc_Chacha_XChachaSetKey(void) #endif return EXPECT_RESULT(); } /* END test_wc_Chacha_XChachaSetKey */ + +/* + * A zero-initialized context that only receives a nonce, with the key setup + * omitted, must not silently encrypt with an all-zero key. wc_Chacha_Process + * has to reject the missing key instead of returning success. + */ +int test_wc_Chacha_MissingKey(void) +{ + EXPECT_DECLS; +#ifdef HAVE_CHACHA + ChaCha ctx; + const byte iv[CHACHA_IV_BYTES] = { 0 }; + const byte input[32] = { 0 }; + byte cipher[32]; + + XMEMSET(&ctx, 0, sizeof(ctx)); + XMEMSET(cipher, 0, sizeof(cipher)); + + /* Nonce set, but wc_Chacha_SetKey() deliberately skipped. */ + ExpectIntEQ(wc_Chacha_SetIV(&ctx, iv, 0), 0); + ExpectIntEQ(wc_Chacha_Process(&ctx, cipher, input, sizeof(input)), + WC_NO_ERR_TRACE(MISSING_KEY)); +#endif + return EXPECT_RESULT(); +} /* END test_wc_Chacha_MissingKey */ diff --git a/tests/api/test_chacha.h b/tests/api/test_chacha.h index 57246b79486..7ef8c8fa502 100644 --- a/tests/api/test_chacha.h +++ b/tests/api/test_chacha.h @@ -32,6 +32,7 @@ int test_wc_Chacha_CounterOverflow(void); int test_wc_Chacha_InPlace(void); int test_wc_Chacha_UnalignedBuffers(void); int test_wc_Chacha_XChachaSetKey(void); +int test_wc_Chacha_MissingKey(void); #define TEST_CHACHA_DECLS \ TEST_DECL_GROUP("chacha", test_wc_Chacha_SetKey), \ @@ -41,6 +42,7 @@ int test_wc_Chacha_XChachaSetKey(void); TEST_DECL_GROUP("chacha", test_wc_Chacha_CounterOverflow), \ TEST_DECL_GROUP("chacha", test_wc_Chacha_InPlace), \ TEST_DECL_GROUP("chacha", test_wc_Chacha_UnalignedBuffers), \ - TEST_DECL_GROUP("chacha", test_wc_Chacha_XChachaSetKey) + TEST_DECL_GROUP("chacha", test_wc_Chacha_XChachaSetKey), \ + TEST_DECL_GROUP("chacha", test_wc_Chacha_MissingKey) #endif /* WOLFCRYPT_TEST_CHACHA_H */ diff --git a/tests/api/test_dh.c b/tests/api/test_dh.c index 30a4c8b575b..e42601da52d 100644 --- a/tests/api/test_dh.c +++ b/tests/api/test_dh.c @@ -316,6 +316,37 @@ int test_wc_DhSetKey(void) return EXPECT_RESULT(); } +/* + * wc_DhSetKey_ex validates untrusted parameters, so it must reject a composite + * modulus even when that composite is a strong pseudoprime to the fixed + * small-prime Miller-Rabin bases. n = 341550071728321 = 10670053 * 32010157 is + * a strong pseudoprime to bases 2, 3, 5, 7, 11, 13, 17 and 19, which the + * deterministic fixed-base test wrongly accepts as prime. Random-witness + * testing rejects it. As with the library's own primality check, rejection is + * probabilistic: eight random Miller-Rabin rounds leave a negligible + * (well under 1e-4) chance of accepting the composite, so a one-off failure + * here is statistical, not a regression. + */ +int test_wc_DhSetKey_ex_pseudoprime(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) && \ + !defined(WC_NO_RNG) + DhKey key; + /* n = 341550071728321, big-endian. */ + byte p[] = { 0x01, 0x36, 0xA3, 0x52, 0xB2, 0xC8, 0xC1 }; + byte g[] = { 0x02 }; + + XMEMSET(&key, 0, sizeof(key)); + + ExpectIntEQ(wc_InitDhKey(&key), 0); + ExpectIntEQ(wc_DhSetKey_ex(&key, p, sizeof(p), g, sizeof(g), NULL, 0), + WC_NO_ERR_TRACE(DH_CHECK_PUB_E)); + wc_FreeDhKey(&key); +#endif + return EXPECT_RESULT(); +} + /* * Testing wc_DhSetNamedKey(), wc_DhGetNamedKeyParamSize(), * wc_DhCopyNamedKey() and wc_DhCmpNamedKey(). diff --git a/tests/api/test_dh.h b/tests/api/test_dh.h index 23a4a0bb265..3aa50855eeb 100644 --- a/tests/api/test_dh.h +++ b/tests/api/test_dh.h @@ -27,6 +27,7 @@ int test_wc_DhPublicKeyDecode(void); int test_wc_DhAgree_subgroup_check(void); int test_wc_DhSetKey(void); +int test_wc_DhSetKey_ex_pseudoprime(void); int test_wc_DhSetNamedKey_and_helpers(void); int test_wc_DhGenerateKeyPair_bad_args(void); int test_wc_DhGenerateKeyPair_and_Agree(void); @@ -42,6 +43,7 @@ int test_wc_DhGenerateKeyPair_CheckDhLN(void); TEST_DECL_GROUP("dh", test_wc_DhPublicKeyDecode), \ TEST_DECL_GROUP("dh", test_wc_DhAgree_subgroup_check), \ TEST_DECL_GROUP("dh", test_wc_DhSetKey), \ + TEST_DECL_GROUP("dh", test_wc_DhSetKey_ex_pseudoprime), \ TEST_DECL_GROUP("dh", test_wc_DhSetNamedKey_and_helpers), \ TEST_DECL_GROUP("dh", test_wc_DhGenerateKeyPair_bad_args), \ TEST_DECL_GROUP("dh", test_wc_DhGenerateKeyPair_and_Agree), \ diff --git a/tests/api/test_ecc.c b/tests/api/test_ecc.c index 732c0df513d..86b82307be2 100644 --- a/tests/api/test_ecc.c +++ b/tests/api/test_ecc.c @@ -295,6 +295,66 @@ int test_wc_ecc_check_key(void) return EXPECT_RESULT(); } /* END test_wc_ecc_check_key */ +/* + * Negative coverage for the public-key checks in wc_ecc_check_key. A point off + * the curve must be rejected with IS_POINT_E, and a coordinate outside + * [0, p-1] with ECC_OUT_OF_RANGE_E. Uses secp224r1, which is not single + * precision accelerated, so the software validation path runs even in SP + * builds that offload P-256. + */ +int test_wc_ecc_check_key_invalid_pubkey(void) +{ + EXPECT_DECLS; + /* Older FIPS-certified modules ship a frozen source tree where these + * imports and checks behave differently, so restrict to non-FIPS or + * FIPS v7 and later, and skip the CAVP selftest build. */ +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && \ + defined(HAVE_ECC) && defined(HAVE_ECC_KEY_IMPORT) && \ + !defined(NO_ECC_CHECK_PUBKEY_ORDER) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \ + (defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)) && \ + (ECC_MIN_KEY_SZ <= 224) && \ + !defined(WOLFSSL_VALIDATE_ECC_IMPORT) && !defined(WOLFSSL_SP_MATH) && \ + !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \ + !defined(WOLFSSL_MICROCHIP_TA100) && !defined(WOLFSSL_CRYPTOCELL) && \ + !defined(WOLFSSL_SILABS_SE_ACCEL) && !defined(WOLFSSL_SE050) && \ + !defined(WOLFSSL_STM32_PKA) && !defined(WOLFSSL_KCAPI_ECC) + ecc_key key; + const char* qx = + "b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21"; + const char* qy = + "bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"; + /* Qy with its low bit flipped: still less than p, but not on the curve. */ + const char* qyOffCurve = + "bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e35"; + /* p, the SECP224R1 field prime, used as an out-of-range coordinate. */ + const char* pModulus = + "ffffffffffffffffffffffffffffffff000000000000000000000001"; + + /* Point not on the curve: rejected by the on-curve check. */ + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_ecc_init(&key), 0); + ExpectIntEQ(wc_ecc_import_raw(&key, qx, qyOffCurve, NULL, "SECP224R1"), 0); + ExpectIntEQ(wc_ecc_check_key(&key), WC_NO_ERR_TRACE(IS_POINT_E)); + wc_ecc_free(&key); + + /* Qx == p: rejected by the coordinate-range check. */ + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_ecc_init(&key), 0); + ExpectIntEQ(wc_ecc_import_raw(&key, pModulus, qy, NULL, "SECP224R1"), 0); + ExpectIntEQ(wc_ecc_check_key(&key), WC_NO_ERR_TRACE(ECC_OUT_OF_RANGE_E)); + wc_ecc_free(&key); + + /* Qy == p: rejected by the coordinate-range check. */ + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_ecc_init(&key), 0); + ExpectIntEQ(wc_ecc_import_raw(&key, qx, pModulus, NULL, "SECP224R1"), 0); + ExpectIntEQ(wc_ecc_check_key(&key), WC_NO_ERR_TRACE(ECC_OUT_OF_RANGE_E)); + wc_ecc_free(&key); +#endif + return EXPECT_RESULT(); +} /* END test_wc_ecc_check_key_invalid_pubkey */ + /* * Testing wc_ecc_get_generator() */ @@ -578,6 +638,77 @@ int test_wc_ecc_shared_secret(void) return EXPECT_RESULT(); } /* END tests_wc_ecc_shared_secret */ +/* + * A shared secret that computes to the point at infinity must be rejected + * (SP 800-56Ar3 5.7.1.2), not returned as an all-zero secret. Setting the + * private scalar to the curve order makes k times the peer point the identity + * for any peer point. Uses secp224r1, which is not single precision + * accelerated, so the non-SP ECDH path runs even in SP builds that offload + * P-256. + */ +int test_wc_ecc_shared_secret_at_infinity(void) +{ + EXPECT_DECLS; + /* ECC_INF_E rejection is not present in the frozen ecc.c of older + * FIPS-certified modules, so restrict to non-FIPS or FIPS v7 and later, + * and skip the CAVP selftest build. */ +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && \ + defined(HAVE_ECC) && defined(HAVE_ECC_DHE) && !defined(WC_NO_RNG) && \ + (defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)) && \ + (ECC_MIN_KEY_SZ <= 224) && \ + !defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_VALIDATE_ECC_IMPORT) && \ + !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \ + !defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_SE050) && \ + !defined(WOLFSSL_KCAPI_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) + ecc_key key; + ecc_key pubKey; + WC_RNG rng; + byte out[MAX_ECC_BYTES]; + word32 outlen = (word32)sizeof(out); + /* A valid SECP224R1 public point. */ + const char* qx = + "b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21"; + const char* qy = + "bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"; + /* Order n of SECP224R1. Every valid point has order n on this curve, so + * a private scalar equal to n makes n times the peer point the identity. */ + const char* order = + "ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d"; + + XMEMSET(&key, 0, sizeof(key)); + XMEMSET(&pubKey, 0, sizeof(pubKey)); + XMEMSET(&rng, 0, sizeof(rng)); + + PRIVATE_KEY_UNLOCK(); + + ExpectIntEQ(wc_ecc_init(&key), 0); + ExpectIntEQ(wc_ecc_init(&pubKey), 0); + ExpectIntEQ(wc_InitRng(&rng), 0); + + ExpectIntEQ(wc_ecc_import_raw(&key, qx, qy, order, "SECP224R1"), 0); + ExpectIntEQ(wc_ecc_import_raw(&pubKey, qx, qy, NULL, "SECP224R1"), 0); + +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \ + !defined(HAVE_SELFTEST) + ExpectIntEQ(wc_ecc_set_rng(&key, &rng), 0); +#endif + + ExpectIntEQ(wc_ecc_shared_secret(&key, &pubKey, out, &outlen), + WC_NO_ERR_TRACE(ECC_INF_E)); + + DoExpectIntEQ(wc_FreeRng(&rng), 0); + wc_ecc_free(&pubKey); + wc_ecc_free(&key); +#ifdef FP_ECC + wc_ecc_fp_free(); +#endif + PRIVATE_KEY_LOCK(); +#endif + return EXPECT_RESULT(); +} /* END test_wc_ecc_shared_secret_at_infinity */ + #if defined(HAVE_ECC) && defined(HAVE_ECC_DHE) && !defined(WC_NO_RNG) && \ (defined(HAVE_ECC384) || defined(HAVE_ECC521) || \ defined(HAVE_ALL_CURVES)) && \ diff --git a/tests/api/test_ecc.h b/tests/api/test_ecc.h index b99f29ae2df..405773af0dc 100644 --- a/tests/api/test_ecc.h +++ b/tests/api/test_ecc.h @@ -31,11 +31,13 @@ int test_wc_ecc_get_curve_id_from_dp_params(void); int test_wc_ecc_make_key(void); int test_wc_ecc_init(void); int test_wc_ecc_check_key(void); +int test_wc_ecc_check_key_invalid_pubkey(void); int test_wc_ecc_get_generator(void); int test_wc_ecc_size(void); int test_wc_ecc_params(void); int test_wc_ecc_signVerify_hash(void); int test_wc_ecc_shared_secret(void); +int test_wc_ecc_shared_secret_at_infinity(void); int test_wc_ecc_shared_secret_size_bounds(void); int test_wc_ecc_export_x963(void); int test_wc_ecc_export_x963_ex(void); @@ -74,11 +76,13 @@ int test_wc_EccDecisionCoverage4(void); TEST_DECL_GROUP("ecc", test_wc_ecc_make_key), \ TEST_DECL_GROUP("ecc", test_wc_ecc_init), \ TEST_DECL_GROUP("ecc", test_wc_ecc_check_key), \ + TEST_DECL_GROUP("ecc", test_wc_ecc_check_key_invalid_pubkey), \ TEST_DECL_GROUP("ecc", test_wc_ecc_get_generator), \ TEST_DECL_GROUP("ecc", test_wc_ecc_size), \ TEST_DECL_GROUP("ecc", test_wc_ecc_params), \ TEST_DECL_GROUP("ecc", test_wc_ecc_signVerify_hash), \ TEST_DECL_GROUP("ecc", test_wc_ecc_shared_secret), \ + TEST_DECL_GROUP("ecc", test_wc_ecc_shared_secret_at_infinity), \ TEST_DECL_GROUP("ecc", test_wc_ecc_shared_secret_size_bounds), \ TEST_DECL_GROUP("ecc", test_wc_ecc_export_x963), \ TEST_DECL_GROUP("ecc", test_wc_ecc_export_x963_ex), \ diff --git a/tests/api/test_ed448.c b/tests/api/test_ed448.c index 2fe404b9c9a..e3b7a464028 100644 --- a/tests/api/test_ed448.c +++ b/tests/api/test_ed448.c @@ -177,6 +177,115 @@ int test_wc_ed448_sign_msg(void) return EXPECT_RESULT(); } /* END test_wc_ed448_sign_msg */ +/* + * RFC 8032 requires the Ed448 signature scalar S to be canonical (S < L). + * Because L times the base point is the identity, a malleated signature with + * S' = S + L recomputes the same R, so the S-range check is the only guard + * against it. Confirm a signature with S >= L (including the malleability case + * S + L) is rejected with BAD_FUNC_ARG, while an in-range but wrong S fails + * verification with SIG_VERIFY_E. + */ +int test_wc_ed448_verify_sig_S_range(void) +{ + EXPECT_DECLS; + /* The S-range rejection may be absent in the frozen ed448.c of older + * FIPS-certified modules, so restrict to non-FIPS or FIPS v7 and later. */ +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + defined(HAVE_ED448) && defined(HAVE_ED448_SIGN) && \ + defined(HAVE_ED448_VERIFY) + ed448_key key; + WC_RNG rng; + byte msg[] = "Everybody gets Friday off.\n"; + byte sig[ED448_SIG_SIZE]; + byte badSig[ED448_SIG_SIZE]; + word32 msglen = sizeof(msg); + word32 siglen = sizeof(sig); + int verify_ok = 0; + int i; + int carry; + int sum; + /* Ed448 group order L, little-endian, 57 bytes. */ + static const byte order[] = { + 0xf3, 0x44, 0x58, 0xab, 0x92, 0xc2, 0x78, 0x23, + 0x55, 0x8f, 0xc5, 0x8d, 0x72, 0xc2, 0x6c, 0x21, + 0x90, 0x36, 0xd6, 0xae, 0x49, 0xdb, 0x4e, 0xc4, + 0xe9, 0x23, 0xca, 0x7c, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, + 0x00 + }; + + XMEMSET(&key, 0, sizeof(key)); + XMEMSET(&rng, 0, sizeof(rng)); + XMEMSET(sig, 0, sizeof(sig)); + + ExpectIntEQ(wc_ed448_init(&key), 0); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0); + + /* Produce a valid signature and confirm it verifies. */ + ExpectIntEQ(wc_ed448_sign_msg(msg, msglen, sig, &siglen, &key, NULL, 0), 0); + ExpectIntEQ(siglen, ED448_SIG_SIZE); + ExpectIntEQ(wc_ed448_verify_msg(sig, siglen, msg, msglen, &verify_ok, &key, + NULL, 0), 0); + ExpectIntEQ(verify_ok, 1); + + /* Malleability: S' = S + L. The same R is recomputed, so only the S-range + * check can reject it. */ + XMEMCPY(badSig, sig, ED448_SIG_SIZE); + carry = 0; + for (i = 0; i < (int)sizeof(order); i++) { + sum = (int)badSig[ED448_SIG_SIZE / 2 + i] + (int)order[i] + carry; + badSig[ED448_SIG_SIZE / 2 + i] = (byte)(sum & 0xff); + carry = sum >> 8; + } + verify_ok = 1; + ExpectIntEQ(wc_ed448_verify_msg(badSig, ED448_SIG_SIZE, msg, msglen, + &verify_ok, &key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(verify_ok, 0); + + /* S exactly equal to L. */ + XMEMCPY(badSig, sig, ED448_SIG_SIZE); + XMEMCPY(badSig + ED448_SIG_SIZE / 2, order, sizeof(order)); + verify_ok = 1; + ExpectIntEQ(wc_ed448_verify_msg(badSig, ED448_SIG_SIZE, msg, msglen, + &verify_ok, &key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(verify_ok, 0); + + /* S greater than L in a high byte. */ + XMEMCPY(badSig, sig, ED448_SIG_SIZE); + XMEMCPY(badSig + ED448_SIG_SIZE / 2, order, sizeof(order)); + badSig[ED448_SIG_SIZE / 2 + 55] = 0x40; + verify_ok = 1; + ExpectIntEQ(wc_ed448_verify_msg(badSig, ED448_SIG_SIZE, msg, msglen, + &verify_ok, &key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(verify_ok, 0); + + /* S greater than L in a low byte. */ + XMEMCPY(badSig, sig, ED448_SIG_SIZE); + XMEMCPY(badSig + ED448_SIG_SIZE / 2, order, sizeof(order)); + badSig[ED448_SIG_SIZE / 2 + 0] = 0xf4; + verify_ok = 1; + ExpectIntEQ(wc_ed448_verify_msg(badSig, ED448_SIG_SIZE, msg, msglen, + &verify_ok, &key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(verify_ok, 0); + + /* S below L: passes the range check, fails verification instead. */ + XMEMCPY(badSig, sig, ED448_SIG_SIZE); + XMEMCPY(badSig + ED448_SIG_SIZE / 2, order, sizeof(order)); + badSig[ED448_SIG_SIZE / 2 + 0] = 0xf2; + verify_ok = 1; + ExpectIntEQ(wc_ed448_verify_msg(badSig, ED448_SIG_SIZE, msg, msglen, + &verify_ok, &key, NULL, 0), WC_NO_ERR_TRACE(SIG_VERIFY_E)); + ExpectIntEQ(verify_ok, 0); + + DoExpectIntEQ(wc_FreeRng(&rng), 0); + wc_ed448_free(&key); +#endif + return EXPECT_RESULT(); +} /* END test_wc_ed448_verify_sig_S_range */ + /* * Test that wc_ed448_sign_msg() rejects a public-key-only key object. * A key with pubKeySet=1 but privKeySet=0 must not silently sign. diff --git a/tests/api/test_ed448.h b/tests/api/test_ed448.h index 169c88a39ce..53209b21651 100644 --- a/tests/api/test_ed448.h +++ b/tests/api/test_ed448.h @@ -27,6 +27,7 @@ int test_wc_ed448_make_key(void); int test_wc_ed448_init(void); int test_wc_ed448_sign_msg(void); +int test_wc_ed448_verify_sig_S_range(void); int test_wc_ed448_sign_msg_pubonly_fails(void); int test_wc_ed448_import_public(void); int test_wc_ed448_import_private_key(void); @@ -47,6 +48,7 @@ int test_wc_ed448_check_key_decisions(void); TEST_DECL_GROUP("ed448", test_wc_ed448_make_key), \ TEST_DECL_GROUP("ed448", test_wc_ed448_init), \ TEST_DECL_GROUP("ed448", test_wc_ed448_sign_msg), \ + TEST_DECL_GROUP("ed448", test_wc_ed448_verify_sig_S_range), \ TEST_DECL_GROUP("ed448", test_wc_ed448_sign_msg_pubonly_fails), \ TEST_DECL_GROUP("ed448", test_wc_ed448_import_public), \ TEST_DECL_GROUP("ed448", test_wc_ed448_import_private_key), \ diff --git a/wolfcrypt/src/chacha.c b/wolfcrypt/src/chacha.c index bc4ec134ecf..0d9e0ad7750 100644 --- a/wolfcrypt/src/chacha.c +++ b/wolfcrypt/src/chacha.c @@ -257,6 +257,7 @@ int wc_Chacha_SetKey(ChaCha* ctx, const byte* key, word32 keySz) #endif ctx->left = 0; /* resets state */ + ctx->keySet = 1; return 0; } @@ -370,6 +371,9 @@ int wc_Chacha_Process(ChaCha* ctx, byte* output, const byte* input, if (ctx == NULL || input == NULL || output == NULL) return BAD_FUNC_ARG; + if (!ctx->keySet) + return MISSING_KEY; + #ifdef USE_INTEL_CHACHA_SPEEDUP /* handle left overs */ if (msglen > 0 && ctx->left > 0) { diff --git a/wolfcrypt/src/dh.c b/wolfcrypt/src/dh.c index 5a6daa98531..75f9b3f5801 100644 --- a/wolfcrypt/src/dh.c +++ b/wolfcrypt/src/dh.c @@ -2670,10 +2670,39 @@ static int _DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, else #endif { - if (rng != NULL) - ret = mp_prime_is_prime_ex(keyP, 8, &isPrime, rng); +#ifndef WC_NO_RNG + WC_RNG* checkRng = rng; + WC_RNG* tmpRng = NULL; + + /* A fixed-base Miller-Rabin test can be fooled by a crafted + * composite, so use random witnesses when an RNG is available. + * Create a temporary RNG when the caller did not supply one. */ + if (checkRng == NULL) { + tmpRng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), key->heap, + DYNAMIC_TYPE_RNG); + if ((tmpRng != NULL) && + (wc_InitRng_ex(tmpRng, key->heap, INVALID_DEVID) == 0)) { + checkRng = tmpRng; + } + } + + /* Fall back to the deterministic test when no RNG could be + * obtained rather than failing the parameter load. */ + if (checkRng != NULL) + ret = mp_prime_is_prime_ex(keyP, 8, &isPrime, checkRng); else ret = mp_prime_is_prime(keyP, 8, &isPrime); + + if (tmpRng != NULL) { + /* wc_FreeRng is safe on a partially-constructed RNG and + * releases any resources a failed wc_InitRng_ex left behind. */ + wc_FreeRng(tmpRng); + XFREE(tmpRng, key->heap, DYNAMIC_TYPE_RNG); + } +#else + (void)rng; + ret = mp_prime_is_prime(keyP, 8, &isPrime); +#endif } if (ret == 0 && isPrime == 0) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 117adfd5ae5..8f780e609dc 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -5043,6 +5043,15 @@ int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point, /* Use constant time map if compiled in */ err = ecc_map_ex(result, curve->prime, mp, 1); } + if (err == MP_OKAY) { + /* SP 800-56Ar3 5.7.1.2: a real scalar must not produce a shared + * secret at the point at infinity. A zero scalar (e.g. a key whose + * private value is held in secure hardware) is not a computed + * secret, so leave that case to the offload path. */ + if (!mp_iszero(k) && wc_ecc_point_is_at_infinity(result)) { + err = ECC_INF_E; + } + } if (err == MP_OKAY) { x = mp_unsigned_bin_size(curve->prime); if (*outlen < (word32)x || x < mp_unsigned_bin_size(result->x)) { diff --git a/wolfcrypt/src/port/Espressif/esp32_mp.c b/wolfcrypt/src/port/Espressif/esp32_mp.c index 9ca4d90b3e9..124d3d23584 100644 --- a/wolfcrypt/src/port/Espressif/esp32_mp.c +++ b/wolfcrypt/src/port/Espressif/esp32_mp.c @@ -567,12 +567,10 @@ static int esp_mp_hw_unlock(void) * This releases the RSA Accelerator from reset.*/ portENTER_CRITICAL_SAFE(&wc_rsa_reg_lock); { - DPORT_REG_CLR_BIT( - (volatile void *)(DR_REG_RSA_BASE + SYSTEM_CRYPTO_RSA_CLK_EN), - SYSTEM_PERIP_CLK_EN1_REG); - DPORT_REG_SET_BIT( - (volatile void *)(DR_REG_RSA_BASE + SYSTEM_RSA_MEM_PD), - SYSTEM_RSA_PD_CTRL_REG); + DPORT_REG_CLR_BIT((volatile void *)(SYSTEM_PERIP_CLK_EN1_REG), + SYSTEM_CRYPTO_RSA_CLK_EN); + DPORT_REG_SET_BIT((volatile void *)(SYSTEM_RSA_PD_CTRL_REG), + SYSTEM_RSA_MEM_PD); } portEXIT_CRITICAL_SAFE(&wc_rsa_reg_lock); #elif defined(CONFIG_IDF_TARGET_ESP32C6) diff --git a/wolfcrypt/src/port/cypress/psoc6_crypto.c b/wolfcrypt/src/port/cypress/psoc6_crypto.c index 655e4c2be4e..5dd818bee87 100644 --- a/wolfcrypt/src/port/cypress/psoc6_crypto.c +++ b/wolfcrypt/src/port/cypress/psoc6_crypto.c @@ -2107,6 +2107,11 @@ int psoc6_ecc_verify_hash_ex(MATH_INT_T* r, MATH_INT_T* s, const byte* hash, if (keySz > MAX_ECC_KEYSIZE) return -BAD_FUNC_ARG; + /* Reject r or s values that would overflow their keySz slot in + * signature_buf when serialized. */ + if (rSz > keySz || sSz > keySz) + return -BAD_FUNC_ARG; + /* Prepare ECC key */ ecc_key.type = PK_PUBLIC; ecc_key.curveID = psoc6_get_curve_id(keySz); diff --git a/wolfcrypt/src/port/intel/quickassist_sync.c b/wolfcrypt/src/port/intel/quickassist_sync.c index 91cb76ae8b2..f9f0309a131 100644 --- a/wolfcrypt/src/port/intel/quickassist_sync.c +++ b/wolfcrypt/src/port/intel/quickassist_sync.c @@ -1085,10 +1085,13 @@ static int IntelQaSymCipher(IntelQaDev* dev, byte* out, const byte* in, status = cpaCySymPerformOp(dev->handle, dev, opData, bufferList, bufferList, &verifyResult); - if (symOperation == CPA_CY_SYM_OP_ALGORITHM_CHAINING && - cipherAlgorithm == CPA_CY_SYM_CIPHER_AES_GCM && - cipherDirection == CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT && - hashAlgorithm == CPA_CY_SYM_HASH_AES_GCM) { + if (status != CPA_STATUS_SUCCESS) { + ret = ASYNC_OP_E; + } + else if (symOperation == CPA_CY_SYM_OP_ALGORITHM_CHAINING && + cipherAlgorithm == CPA_CY_SYM_CIPHER_AES_GCM && + cipherDirection == CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT && + hashAlgorithm == CPA_CY_SYM_HASH_AES_GCM) { if (verifyResult == CPA_FALSE) { ret = AES_GCM_AUTH_E; } diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 096c0e50e21..0f72614a8e8 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -387,8 +387,8 @@ int wc_InitRsaKey_Id(RsaKey* key, unsigned char* id, int len, void* heap, { int ret = 0; #if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_RSA) - /* SE050 TLS users store a word32 at id, need to cast back */ - word32* keyPtr = NULL; + /* SE050 TLS users store a word32 at id, need to read it back */ + word32 keyId = 0; #endif if (key == NULL) @@ -403,8 +403,8 @@ int wc_InitRsaKey_Id(RsaKey* key, unsigned char* id, int len, void* heap, #if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_RSA) /* Set SE050 ID from word32, populate RsaKey with public from SE050 */ if (len == (int)sizeof(word32)) { - keyPtr = (word32*)key->id; - ret = wc_RsaUseKeyId(key, *keyPtr, 0); + keyId = readUnalignedWord32(key->id); + ret = wc_RsaUseKeyId(key, keyId, 0); } #endif } diff --git a/wolfcrypt/src/wc_mlkem_poly.c b/wolfcrypt/src/wc_mlkem_poly.c index 2ab7299cfe1..31cace546a3 100644 --- a/wolfcrypt/src/wc_mlkem_poly.c +++ b/wolfcrypt/src/wc_mlkem_poly.c @@ -3957,12 +3957,14 @@ static void mlkem_cbd_eta3(sword16* p, const byte* r) #else /* Calculate eight integer coefficients at a time. */ for (i = 0; i < MLKEM_N; i += 16) { - const word32* r32 = (const word32*)r; + word32 r0 = readUnalignedWord32(r); + word32 r1 = readUnalignedWord32(r + 4); + word32 r2 = readUnalignedWord32(r + 8); /* Take the next 12 bytes, little endian, as 24 bit values. */ - word32 t0 = r32[0] & 0xffffff; - word32 t1 = ((r32[0] >> 24) | (r32[1] << 8)) & 0xffffff; - word32 t2 = ((r32[1] >> 16) | (r32[2] << 16)) & 0xffffff; - word32 t3 = r32[2] >> 8 ; + word32 t0 = r0 & 0xffffff; + word32 t1 = ((r0 >> 24) | (r1 << 8)) & 0xffffff; + word32 t2 = ((r1 >> 16) | (r2 << 16)) & 0xffffff; + word32 t3 = r2 >> 8 ; word32 d0; word32 d1; word32 d2; @@ -5071,18 +5073,22 @@ static void mlkem_vec_compress_10_c(byte* r, sword16* v, unsigned int k) sword16 t14 = TO_COMP_WORD_10(v, i, j, 14); sword16 t15 = TO_COMP_WORD_10(v, i, j, 15); - word32* r32 = (word32*)r; /* Pack sixteen 10-bit values into byte array. */ - r32[0] = (word32)t0 | ((word32)t1 << 10) | - ((word32)t2 << 20) | ((word32)t3 << 30); - r32[1] = ((word32)t3 >> 2) | ((word32)t4 << 8) | - ((word32)t5 << 18) | ((word32)t6 << 28); - r32[2] = ((word32)t6 >> 4) | ((word32)t7 << 6) | - ((word32)t8 << 16) | ((word32)t9 << 26); - r32[3] = ((word32)t9 >> 6) | ((word32)t10 << 4) | - ((word32)t11 << 14) | ((word32)t12 << 24); - r32[4] = ((word32)t12 >> 8) | ((word32)t13 << 2) | - ((word32)t14 << 12) | ((word32)t15 << 22); + writeUnalignedWord32(r + 0, + (word32)t0 | ((word32)t1 << 10) | + ((word32)t2 << 20) | ((word32)t3 << 30)); + writeUnalignedWord32(r + 4, + ((word32)t3 >> 2) | ((word32)t4 << 8) | + ((word32)t5 << 18) | ((word32)t6 << 28)); + writeUnalignedWord32(r + 8, + ((word32)t6 >> 4) | ((word32)t7 << 6) | + ((word32)t8 << 16) | ((word32)t9 << 26)); + writeUnalignedWord32(r + 12, + ((word32)t9 >> 6) | ((word32)t10 << 4) | + ((word32)t11 << 14) | ((word32)t12 << 24)); + writeUnalignedWord32(r + 16, + ((word32)t12 >> 8) | ((word32)t13 << 2) | + ((word32)t14 << 12) | ((word32)t15 << 22)); /* Move over set bytes. */ r += 20; diff --git a/wolfssl/wolfcrypt/chacha.h b/wolfssl/wolfcrypt/chacha.h index b7b15e7dff5..8528ee925d7 100644 --- a/wolfssl/wolfcrypt/chacha.h +++ b/wolfssl/wolfcrypt/chacha.h @@ -95,6 +95,7 @@ typedef struct ChaCha { #elif defined(USE_RISCV_CHACHA_SPEEDUP) ALIGN8 word32 over[CHACHA_CHUNK_WORDS]; #endif + WC_BITFIELD keySet:1; /* set to 1 once a key is set */ } ChaCha; /**