Merge pull request #10632 from Frauschi/fenrir

Fenrir fixes
This commit is contained in:
David Garske
2026-06-10 08:14:30 -07:00
committed by GitHub
24 changed files with 563 additions and 48 deletions
+4 -1
View File
@@ -7,7 +7,10 @@
Before this method may be called, one must first initialize the ARC4
structure using wc_Arc4SetKey.
\return none
\return 0 Returned upon successfully processing the message.
\return BAD_FUNC_ARG If arc4, out, or in is NULL.
\return MISSING_KEY If no key has been set on the ARC4 structure with
wc_Arc4SetKey.
\param arc4 pointer to the ARC4 structure used to process the message
\param out pointer to the output buffer in which to store the
+8
View File
@@ -273,6 +273,10 @@ int wc_Des3_SetIV(Des3* des, const byte* iv);
with cipher block chaining (CBC) mode.
\return 0 Returned upon successfully encrypting the given input message
\return BAD_FUNC_ARG If des, out, or in is NULL.
\return BAD_LENGTH_E If sz is not a multiple of DES_BLOCK_SIZE.
\return MISSING_KEY If no key has been set on the Des3 structure with
wc_Des3_SetKey.
\param des pointer to the Des3 structure to use for encryption
\param out pointer to the buffer in which to store the encrypted ciphertext
@@ -306,6 +310,10 @@ int wc_Des3_CbcEncrypt(Des3* des, byte* out,
encryption with cipher block chaining (CBC) mode.
\return 0 Returned upon successfully decrypting the given ciphertext
\return BAD_FUNC_ARG If des, out, or in is NULL.
\return BAD_LENGTH_E If sz is not a multiple of DES_BLOCK_SIZE.
\return MISSING_KEY If no key has been set on the Des3 structure with
wc_Des3_SetKey.
\param des pointer to the Des3 structure to use for decryption
\param out pointer to the buffer in which to store the decrypted plaintext
+27
View File
@@ -38861,6 +38861,14 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
*inOutIdx = i;
#if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_SUPPORTED_CURVES)
/* Reset per-ClientHello extension state before (re)parsing so a stale
* value from an earlier handshake on this object (e.g. secure
* renegotiation, where Options is not zeroed) cannot trigger a spurious
* RFC 8422 abort below. */
ssl->options.peerNoUncompPF = 0;
#endif
/* tls extensions */
if ((i - begin) < helloSz) {
#ifdef HAVE_TLS_EXTENSIONS
@@ -39073,6 +39081,25 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
if (ret == 0)
ret = MatchSuite(ssl, ssl->clSuites);
#if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_SUPPORTED_CURVES)
/* RFC 8422 Section 5.1.2: abort only when an ECC suite was actually
* negotiated and the client's ec_point_formats omitted the uncompressed
* (0) format (peerNoUncompPF, set in TLSX_PointFormat_Parse). Checked
* after MatchSuite so it keys off the chosen suite, not advertised
* groups. */
if (ret == 0 && ssl->options.peerNoUncompPF &&
(ssl->specs.kea == ecc_diffie_hellman_kea ||
ssl->specs.kea == ecc_static_diffie_hellman_kea ||
ssl->specs.kea == ecdhe_psk_kea)) {
WOLFSSL_MSG("Client ec_point_formats extension missing "
"uncompressed format for negotiated ECC suite");
SendAlert(ssl, alert_fatal, illegal_parameter);
ret = INVALID_PARAMETER;
WOLFSSL_ERROR_VERBOSE(ret);
goto out;
}
#endif
#if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_ENCRYPT_THEN_MAC) && \
!defined(WOLFSSL_AEAD_ONLY)
if (ret == 0 && ssl->options.encThenMac &&
+35 -2
View File
@@ -5232,8 +5232,13 @@ int TLSX_SupportedCurve_Parse(const WOLFSSL* ssl, const byte* input,
if (length != OPAQUE16_LEN + offset)
return BUFFER_ERROR;
offset = OPAQUE16_LEN;
if (offset == length)
return 0;
if (offset == length) {
/* An empty named group list is malformed (named_group_list<2..2^16-1>,
* RFC 8422 / RFC 8446). BUFFER_ERROR yields a decode_error alert (see
* TranslateErrorToAlert()). Accepting it would also make an explicit
* empty extension look absent and impose no group restriction. */
return BUFFER_ERROR;
}
extension = TLSX_Find(*extensions, TLSX_SUPPORTED_GROUPS);
if (extension == NULL) {
@@ -5250,6 +5255,14 @@ int TLSX_SupportedCurve_Parse(const WOLFSSL* ssl, const byte* input,
break;
ret = 0;
}
/* All advertised groups are unsupported, so no node was added above.
* Record an empty node so suite selection still sees the restriction
* (e.g. ECC/ECDHE must not be chosen) instead of treating the
* extension as absent. */
if (ret == 0 && isRequest &&
TLSX_Find(*extensions, TLSX_SUPPORTED_GROUPS) == NULL) {
ret = TLSX_Push(extensions, TLSX_SUPPORTED_GROUPS, NULL, ssl->heap);
}
}
else {
/* Find the intersection with what the user has set */
@@ -5654,6 +5667,26 @@ static int TLSX_PointFormat_Parse(WOLFSSL* ssl, const byte* input,
return BUFFER_ERROR;
if (isRequest) {
#if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_SUPPORTED_CURVES)
/* RFC 8422 Section 5.1.2: a client that sends the ec_point_formats
* extension MUST include the uncompressed (0) format. Record whether
* it is missing so DoClientHello() can abort with an illegal_parameter
* alert if the client also advertised ECC named groups. The decision
* is deferred to after all extensions are parsed so it does not depend
* on the relative order of the supported_groups and ec_point_formats
* extensions in the ClientHello. */
word16 i;
int found = 0;
for (i = 0; i < input[0]; i++) {
if (input[ENUM_LEN + i] == WOLFSSL_EC_PF_UNCOMPRESSED) {
found = 1;
break;
}
}
ssl->options.peerNoUncompPF = (found == 0);
#endif
/* adding uncompressed point format to response */
ret = TLSX_UsePointFormat(&ssl->extensions, WOLFSSL_EC_PF_UNCOMPRESSED,
ssl->heap);
+2
View File
@@ -35141,6 +35141,8 @@ TEST_CASE testCases[] = {
TEST_DECL(test_TLSX_ECH_msg_type_validation),
TEST_DECL(test_TLSX_SRTP_msg_type_validation),
TEST_DECL(test_TLSX_ALPN_server_response_count),
TEST_DECL(test_TLSX_SupportedCurve_empty_or_unsupported),
TEST_DECL(test_TLSX_PointFormat_uncompressed_required),
TEST_DECL(test_wolfSSL_wolfSSL_UseSecureRenegotiation),
TEST_DECL(test_wolfSSL_clear_secure_renegotiation),
TEST_DECL(test_wolfSSL_SCR_Reconnect),
+37
View File
@@ -104,6 +104,43 @@ int test_wc_Arc4Process(void)
} /* END test_wc_Arc4Process */
/*
* Regression test for issue 5378: wc_Arc4Process must refuse to run unless a
* key has been configured with wc_Arc4SetKey(), both before SetKey and after
* Free. Otherwise the keystream is all-zero and ARC4 silently copies the
* plaintext into the ciphertext.
*/
int test_wc_Arc4Process_no_key(void)
{
EXPECT_DECLS;
#ifndef NO_RC4
Arc4 arc4;
const char* key = "\x01\x23\x45\x67\x89\xab\xcd\xef";
int keyLen = 8;
const char* input = "\x01\x23\x45\x67\x89\xab\xcd\xef";
byte cipher[8];
XMEMSET(&arc4, 0, sizeof(arc4));
XMEMSET(cipher, 0, sizeof(cipher));
/* Processing without a key after init must fail, not silently copy. */
ExpectIntEQ(wc_Arc4Init(&arc4, NULL, INVALID_DEVID), 0);
ExpectIntEQ(wc_Arc4Process(&arc4, cipher, (byte*)input, (word32)keyLen),
WC_NO_ERR_TRACE(MISSING_KEY));
/* After a key is set, processing succeeds. */
ExpectIntEQ(wc_Arc4SetKey(&arc4, (byte*)key, (word32)keyLen), 0);
ExpectIntEQ(wc_Arc4Process(&arc4, cipher, (byte*)input, (word32)keyLen), 0);
/* After free, the keyed state is cleared and processing must fail again. */
wc_Arc4Free(&arc4);
ExpectIntEQ(wc_Arc4Process(&arc4, cipher, (byte*)input, (word32)keyLen),
WC_NO_ERR_TRACE(MISSING_KEY));
#endif
return EXPECT_RESULT();
} /* END test_wc_Arc4Process_no_key */
#include <wolfssl/wolfcrypt/random.h>
+2
View File
@@ -26,11 +26,13 @@
int test_wc_Arc4SetKey(void);
int test_wc_Arc4Process(void);
int test_wc_Arc4Process_no_key(void);
int test_wc_Arc4_MonteCarlo(void);
#define TEST_ARC4_DECLS \
TEST_DECL_GROUP("arc4", test_wc_Arc4SetKey), \
TEST_DECL_GROUP("arc4", test_wc_Arc4Process), \
TEST_DECL_GROUP("arc4", test_wc_Arc4Process_no_key), \
TEST_DECL_GROUP("arc4", test_wc_Arc4_MonteCarlo)
#endif /* WOLFCRYPT_TEST_ARC4_H */
+61
View File
@@ -181,6 +181,67 @@ int test_wc_Des3_CbcEncryptDecrypt(void)
} /* END wc_Des3_CbcEncrypt */
/*
* Regression test for issue 5379: wc_Des3_CbcEncrypt/Decrypt must refuse to
* run unless a key has been configured with wc_Des3_SetKey(), both before
* SetKey and after Free. Otherwise the operation would silently run with
* uninitialized or zeroed key material and return success.
*
* FIPS builds use the FIPS-certified DES3 implementation which does not track
* key state, so skip the test for FIPS.
*/
int test_wc_Des3_CbcEncryptDecrypt_no_key(void)
{
EXPECT_DECLS;
#if !defined(NO_DES3) && !defined(HAVE_FIPS)
Des3 des;
byte cipher[24];
byte plain[24];
const byte key[] = {
0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
0xfe,0xde,0xba,0x98,0x76,0x54,0x32,0x10,
0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67
};
const byte iv[] = {
0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x11,0x21,0x31,0x41,0x51,0x61,0x71,0x81
};
const byte vector[] = { /* "Now is the time for all " w/o trailing 0 */
0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74,
0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20,
0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20
};
XMEMSET(&des, 0, sizeof(Des3));
XMEMSET(cipher, 0, sizeof(cipher));
XMEMSET(plain, 0, sizeof(plain));
/* Encrypt/decrypt without a key after init must fail, not silently run. */
ExpectIntEQ(wc_Des3Init(&des, NULL, INVALID_DEVID), 0);
ExpectIntEQ(wc_Des3_CbcEncrypt(&des, cipher, vector, 24),
WC_NO_ERR_TRACE(MISSING_KEY));
ExpectIntEQ(wc_Des3_CbcDecrypt(&des, plain, vector, 24),
WC_NO_ERR_TRACE(MISSING_KEY));
/* After a key is set, the operations succeed. */
ExpectIntEQ(wc_Des3_SetKey(&des, key, iv, DES_ENCRYPTION), 0);
ExpectIntEQ(wc_Des3_CbcEncrypt(&des, cipher, vector, 24), 0);
ExpectIntEQ(wc_Des3_SetKey(&des, key, iv, DES_DECRYPTION), 0);
ExpectIntEQ(wc_Des3_CbcDecrypt(&des, plain, cipher, 24), 0);
ExpectIntEQ(XMEMCMP(plain, vector, 24), 0);
/* After free, the keyed state is cleared and operations must fail again. */
wc_Des3Free(&des);
ExpectIntEQ(wc_Des3_CbcEncrypt(&des, cipher, vector, 24),
WC_NO_ERR_TRACE(MISSING_KEY));
ExpectIntEQ(wc_Des3_CbcDecrypt(&des, plain, vector, 24),
WC_NO_ERR_TRACE(MISSING_KEY));
#endif
return EXPECT_RESULT();
} /* END test_wc_Des3_CbcEncryptDecrypt_no_key */
/*
* Unit test for wc_Des3_EcbEncrypt
*/
+7 -5
View File
@@ -27,14 +27,16 @@
int test_wc_Des3_SetIV(void);
int test_wc_Des3_SetKey(void);
int test_wc_Des3_CbcEncryptDecrypt(void);
int test_wc_Des3_CbcEncryptDecrypt_no_key(void);
int test_wc_Des3_EcbEncrypt(void);
int test_wc_Des3Cbc_MonteCarlo(void);
#define TEST_DES3_DECLS \
TEST_DECL_GROUP("des3", test_wc_Des3_SetIV), \
TEST_DECL_GROUP("des3", test_wc_Des3_SetKey), \
TEST_DECL_GROUP("des3", test_wc_Des3_CbcEncryptDecrypt), \
TEST_DECL_GROUP("des3", test_wc_Des3_EcbEncrypt), \
#define TEST_DES3_DECLS \
TEST_DECL_GROUP("des3", test_wc_Des3_SetIV), \
TEST_DECL_GROUP("des3", test_wc_Des3_SetKey), \
TEST_DECL_GROUP("des3", test_wc_Des3_CbcEncryptDecrypt), \
TEST_DECL_GROUP("des3", test_wc_Des3_CbcEncryptDecrypt_no_key), \
TEST_DECL_GROUP("des3", test_wc_Des3_EcbEncrypt), \
TEST_DECL_GROUP("des3", test_wc_Des3Cbc_MonteCarlo)
#endif /* WOLFCRYPT_TEST_DES3_H */
+3 -1
View File
@@ -965,7 +965,9 @@ int test_wolfSSL_RC4(void)
wolfSSL_RC4(NULL, 0, data, enc);
ExpectIntEQ(1, 1);
for (i = 0; EXPECT_SUCCESS() && (i <= sizeof(key)); i++) {
/* Start at a key length of 1: a zero-length key is invalid and leaves the
* Arc4 object without a key set, so encrypt/decrypt is a no-op. */
for (i = 1; EXPECT_SUCCESS() && (i <= sizeof(key)); i++) {
for (j = 0; EXPECT_SUCCESS() && (j <= sizeof(data)); j++) {
XMEMSET(enc, 0, sizeof(enc));
XMEMSET(dec, 0, sizeof(dec));
+103
View File
@@ -885,6 +885,109 @@ int test_tls12_no_null_compression(void)
return EXPECT_RESULT();
}
/* RFC 8422 Section 5.1.2: a client that sends an ec_point_formats extension
* omitting the uncompressed (0) format while negotiating an ECC suite must be
* rejected by the server with a fatal illegal_parameter alert. This drives a
* real handshake all the way through DoClientHello so the abort path (not just
* the parse-time detection) is exercised.
*
* Rather than hand-craft a ClientHello (which would pin the cipher suite, named
* group and exact byte offsets, making the test fragile as extension handling
* evolves), the client builds its own ClientHello and we only suppress the
* uncompressed point format: TLSX_PopulateExtensions() adds the default
* uncompressed format only when no ec_point_formats extension already exists,
* so pre-seeding the client with a compressed-only list makes it advertise
* exactly that. The curve is negotiated normally, so the test is independent of
* which named groups are enabled. */
int test_tls12_ec_point_formats_no_uncompressed(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) \
&& defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) \
&& defined(BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
/* Pin an ECDHE (ECC) suite so the server negotiates an ECC key exchange;
* gating on the BUILD_ macro skips the test in builds where the suite is
* unavailable (e.g. --disable-aescbc) instead of failing with
* MATCH_SUITE_ERROR. */
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, "ECDHE-RSA-AES128-SHA"),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, "ECDHE-RSA-AES128-SHA"),
WOLFSSL_SUCCESS);
/* Make the client advertise only the compressed point format (1 ==
* ansiX962_compressed_prime), i.e. omit the uncompressed (0) format. */
ExpectIntEQ(TLSX_UsePointFormat(&ssl_c->extensions, 1, ssl_c->heap),
WOLFSSL_SUCCESS);
/* The server must reject the handshake with a fatal illegal_parameter
* alert (surfaced as INVALID_PARAMETER), not complete it. */
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(INVALID_PARAMETER));
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* RFC 8422 Section 5.1.2 ties the missing-uncompressed-format abort to the
* server actually negotiating an ECC cipher suite. A client that omits the
* uncompressed point format but negotiates a NON-ECC suite (here DHE_RSA) must
* NOT be rejected - the handshake completes. This is the complement of
* test_tls12_ec_point_formats_no_uncompressed and guards against regressing
* back to an advertised-groups (parse-time) abort.
*
* As in that test the client builds a real ClientHello and we only suppress the
* uncompressed point format (see the comment there); the suite is pinned to a
* DHE (non-ECC) suite. */
int test_tls12_ec_point_formats_no_uncompressed_non_ecc(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) \
&& defined(HAVE_SUPPORTED_CURVES) && !defined(NO_DH) && defined(HAVE_FFDHE) \
&& !defined(NO_RSA) && defined(BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA)
/* The negotiated suite must be non-ECC for the missing format to be
* irrelevant. RFC 9325 / WOLFSSL_HARDEN_TLS disables all TLS_DHE_* suites
* (NO_TLS_DH); gating on the BUILD_ macro skips the test there rather than
* failing with MATCH_SUITE_ERROR. */
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, "DHE-RSA-AES128-SHA"),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, "DHE-RSA-AES128-SHA"),
WOLFSSL_SUCCESS);
/* Make the client advertise only the compressed point format (1 ==
* ansiX962_compressed_prime), i.e. omit the uncompressed (0) format. */
ExpectIntEQ(TLSX_UsePointFormat(&ssl_c->extensions, 1, ssl_c->heap),
WOLFSSL_SUCCESS);
/* The handshake must complete: the missing uncompressed format is
* irrelevant for a non-ECC (DHE) suite. */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Sanity: the server really did observe a point-format list without the
* uncompressed format, yet proceeded. */
ExpectIntEQ(ssl_s->options.peerNoUncompPF, 1);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* Test that set_curves_list correctly resolves ECC curve names that fall
* through the kNistCurves table and reach the wc_ecc_get_curve_idx_from_name
* fallback path. The kNistCurves lookup uses a case-sensitive XSTRNCMP, so
+5
View File
@@ -32,6 +32,8 @@ int test_tls_certreq_order(void);
int test_tls12_certreq_odd_sigalgs(void);
int test_tls12_bad_cv_sig_alg(void);
int test_tls12_no_null_compression(void);
int test_tls12_ec_point_formats_no_uncompressed(void);
int test_tls12_ec_point_formats_no_uncompressed_non_ecc(void);
int test_tls12_etm_failed_resumption(void);
int test_tls_set_session_min_downgrade(void);
int test_tls12_session_id_resumption_sni_mismatch(void);
@@ -61,6 +63,9 @@ int test_wolfSSL_get_shared_ciphers(void);
TEST_DECL_GROUP("tls", test_tls12_certreq_odd_sigalgs), \
TEST_DECL_GROUP("tls", test_tls12_bad_cv_sig_alg), \
TEST_DECL_GROUP("tls", test_tls12_no_null_compression), \
TEST_DECL_GROUP("tls", test_tls12_ec_point_formats_no_uncompressed), \
TEST_DECL_GROUP("tls", \
test_tls12_ec_point_formats_no_uncompressed_non_ecc), \
TEST_DECL_GROUP("tls", test_tls12_etm_failed_resumption), \
TEST_DECL_GROUP("tls", test_tls_set_session_min_downgrade), \
TEST_DECL_GROUP("tls", test_tls12_session_id_resumption_sni_mismatch), \
+169
View File
@@ -1071,3 +1071,172 @@ int test_TLSX_ALPN_server_response_count(void)
#endif
return EXPECT_RESULT();
}
/* Regression test for the supported_groups (a.k.a. supported curves) parsing.
*
* A client that explicitly sends a supported_groups extension restricts the
* groups the server may use. An empty list, or a list that contains only
* groups the server does not support, must NOT be silently treated as if the
* extension was absent (which would impose no restriction and let the server
* pick an ECDHE suite/curve the client never advertised).
*
* - An empty named group list is malformed and must be rejected.
* - A list of only-unsupported groups must still leave a supported_groups
* node behind so suite selection sees the restriction.
*/
int test_TLSX_SupportedCurve_empty_or_unsupported(void)
{
EXPECT_DECLS;
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) && \
defined(HAVE_SUPPORTED_CURVES) && !defined(WOLFSSL_NO_TLS12) && \
(!defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \
!defined(WOLFSSL_NO_SERVER_GROUPS_EXT)))
/* This exercises the server's parsing of a received ClientHello: the
* relevant code path (TLSX_SupportedCurve_Parse) is selected by the
* message type passed to TLSX_Parse (client_hello => isRequest), not by
* the side of the WOLFSSL object. A client-side WOLFSSL is used purely as
* the parse vehicle because creating a server-side WOLFSSL would require a
* certificate to be loaded first (NO_PRIVATE_KEY otherwise). */
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
Suites* suites = NULL;
/* supported_groups (0x000a), ext len 0x0002, named_group_list len 0x0000 */
const byte emptyList[] = { 0x00, 0x0a, 0x00, 0x02, 0x00, 0x00 };
/* supported_groups (0x000a), ext len 0x0004, list len 0x0002,
* group 0xeeee (private-use value we do not support) */
const byte unsupportedOnly[] = { 0x00, 0x0a, 0x00, 0x04, 0x00, 0x02,
0xee, 0xee };
/* An empty named group list is malformed and must be rejected. */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
ExpectNotNull(ssl = wolfSSL_new(ctx));
if (ssl != NULL)
suites = (Suites*)WOLFSSL_SUITES(ssl);
ExpectIntEQ(TLSX_Parse(ssl, emptyList, (word16)sizeof(emptyList),
client_hello, suites),
WC_NO_ERR_TRACE(BUFFER_ERROR));
wolfSSL_free(ssl);
ssl = NULL;
/* A list with only unsupported groups must still record a supported_groups
* node so that ECC/ECDHE suite selection sees the (now empty) restriction
* instead of treating the extension as absent. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
if (ssl != NULL)
suites = (Suites*)WOLFSSL_SUITES(ssl);
/* Precondition: server has not preconfigured supported groups. */
ExpectNull(TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS));
ExpectIntEQ(TLSX_Parse(ssl, unsupportedOnly, (word16)sizeof(unsupportedOnly),
client_hello, suites), 0);
/* The fix records an (empty) supported_groups node. */
ExpectNotNull(TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS));
wolfSSL_free(ssl);
ssl = NULL;
wolfSSL_CTX_free(ctx);
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT)
/* An empty named group list is equally malformed in a TLS 1.3
* EncryptedExtensions message (named_group_list<2..2^16-1>) and must be
* rejected with the same decode_error (BUFFER_ERROR), not silently
* accepted as the server advertising no groups. */
{
WOLFSSL_CTX* ctx13 = NULL;
WOLFSSL* ssl13 = NULL;
const byte emptyListEE[] = { 0x00, 0x0a, 0x00, 0x02, 0x00, 0x00 };
ExpectNotNull(ctx13 = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
ExpectNotNull(ssl13 = wolfSSL_new(ctx13));
/* Ensure the connection is treated as TLS 1.3 so EncryptedExtensions
* is a valid context for the extension. */
if (ssl13 != NULL) {
ssl13->version.major = SSLv3_MAJOR;
ssl13->version.minor = TLSv1_3_MINOR;
}
ExpectIntEQ(TLSX_Parse(ssl13, emptyListEE, (word16)sizeof(emptyListEE),
encrypted_extensions, NULL),
WC_NO_ERR_TRACE(BUFFER_ERROR));
wolfSSL_free(ssl13);
wolfSSL_CTX_free(ctx13);
}
#endif
#endif
return EXPECT_RESULT();
}
/* RFC 8422 Section 5.1.2: a client that sends the ec_point_formats extension
* MUST include the uncompressed (0) point format. When the uncompressed format
* is omitted the server records this (ssl->options.peerNoUncompPF) during
* parsing so the handshake can be aborted with an illegal_parameter alert if
* the client also advertised ECC named groups.
*
* - A list that contains the uncompressed format must clear the flag.
* - A list that omits the uncompressed format must set the flag.
*/
int test_TLSX_PointFormat_uncompressed_required(void)
{
EXPECT_DECLS;
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_TLS) && defined(HAVE_SUPPORTED_CURVES) && \
defined(HAVE_TLS_EXTENSIONS) && !defined(WOLFSSL_NO_TLS12)
/* This exercises the server's parsing of a received ClientHello: the
* relevant code path (TLSX_PointFormat_Parse) is selected by the message
* type passed to TLSX_Parse (client_hello => isRequest), not by the side
* of the WOLFSSL object. A client-side WOLFSSL is used purely as the parse
* vehicle because creating a server-side WOLFSSL would require a
* certificate to be loaded first (NO_PRIVATE_KEY otherwise). The server
* build is required because TLSX_PointFormat_Parse (the PF_PARSE dispatch
* macro) is compiled to a no-op when NO_WOLFSSL_SERVER is defined. */
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
Suites* suites = NULL;
/* ec_point_formats (0x000b), ext len 0x0002, list len 0x01,
* format 0x00 (uncompressed) */
const byte withUncomp[] = { 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00 };
/* ec_point_formats (0x000b), ext len 0x0002, list len 0x01,
* format 0x01 (ansiX962_compressed_prime, uncompressed omitted) */
const byte noUncomp[] = { 0x00, 0x0b, 0x00, 0x02, 0x01, 0x01 };
/* As above but with two compressed formats and no uncompressed. */
const byte noUncomp2[] = { 0x00, 0x0b, 0x00, 0x03, 0x02, 0x01, 0x02 };
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
/* A list containing the uncompressed format leaves the flag clear and
* still adds the uncompressed format to the response. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
if (ssl != NULL)
suites = (Suites*)WOLFSSL_SUITES(ssl);
ExpectIntEQ(TLSX_Parse(ssl, withUncomp, (word16)sizeof(withUncomp),
client_hello, suites), 0);
if (ssl != NULL)
ExpectIntEQ(ssl->options.peerNoUncompPF, 0);
ExpectNotNull(TLSX_Find(ssl->extensions, TLSX_EC_POINT_FORMATS));
wolfSSL_free(ssl);
ssl = NULL;
/* A single-entry list that omits the uncompressed format sets the flag. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
if (ssl != NULL)
suites = (Suites*)WOLFSSL_SUITES(ssl);
ExpectIntEQ(TLSX_Parse(ssl, noUncomp, (word16)sizeof(noUncomp),
client_hello, suites), 0);
if (ssl != NULL)
ExpectIntEQ(ssl->options.peerNoUncompPF, 1);
wolfSSL_free(ssl);
ssl = NULL;
/* A multi-entry list that omits the uncompressed format sets the flag. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
if (ssl != NULL)
suites = (Suites*)WOLFSSL_SUITES(ssl);
ExpectIntEQ(TLSX_Parse(ssl, noUncomp2, (word16)sizeof(noUncomp2),
client_hello, suites), 0);
if (ssl != NULL)
ExpectIntEQ(ssl->options.peerNoUncompPF, 1);
wolfSSL_free(ssl);
ssl = NULL;
wolfSSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
+2
View File
@@ -37,5 +37,7 @@ int test_TLSX_SNI_GetSize_overflow(void);
int test_TLSX_ECH_msg_type_validation(void);
int test_TLSX_SRTP_msg_type_validation(void);
int test_TLSX_ALPN_server_response_count(void);
int test_TLSX_SupportedCurve_empty_or_unsupported(void);
int test_TLSX_PointFormat_uncompressed_required(void);
#endif /* TESTS_API_TEST_TLS_EMS_H */
+8
View File
@@ -67,6 +67,8 @@ int wc_Arc4SetKey(Arc4* arc4, const byte* key, word32 length)
keyIndex = 0;
}
arc4->keySet = 1;
return ret;
}
@@ -102,6 +104,10 @@ int wc_Arc4Process(Arc4* arc4, byte* out, const byte* in, word32 length)
}
#endif
if (!arc4->keySet) {
return MISSING_KEY;
}
x = arc4->x;
y = arc4->y;
@@ -123,6 +129,7 @@ int wc_Arc4Init(Arc4* arc4, void* heap, int devId)
return BAD_FUNC_ARG;
arc4->heap = heap;
arc4->keySet = 0;
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ARC4)
ret = wolfAsync_DevCtxInit(&arc4->asyncDev, WOLFSSL_ASYNC_MARKER_ARC4,
@@ -148,6 +155,7 @@ void wc_Arc4Free(Arc4* arc4)
ForceZero(arc4->state, sizeof(arc4->state));
arc4->x = 0;
arc4->y = 0;
arc4->keySet = 0;
}
#endif /* NO_RC4 */
+13 -22
View File
@@ -31973,10 +31973,7 @@ static int eccToPKCS8(ecc_key* key, byte* output, word32* outLen,
ret = wc_BuildEccKeyDer(key, tmpDer, &sz, includePublic, 0);
if (ret < 0) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret;
goto exit;
}
tmpDerSz = (word32)ret;
@@ -31984,42 +31981,36 @@ static int eccToPKCS8(ecc_key* key, byte* output, word32* outLen,
ret = wc_CreatePKCS8Key(NULL, &pkcs8Sz, tmpDer, tmpDerSz, algoID,
curveOID, oidSz);
if (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret;
goto exit;
}
if (output == NULL) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
*outLen = pkcs8Sz;
return WC_NO_ERR_TRACE(LENGTH_ONLY_E);
ret = WC_NO_ERR_TRACE(LENGTH_ONLY_E);
goto exit;
}
else if (*outLen < pkcs8Sz) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
WOLFSSL_MSG("Input buffer too small for ECC PKCS#8 key");
return BUFFER_E;
ret = BUFFER_E;
goto exit;
}
ret = wc_CreatePKCS8Key(output, &pkcs8Sz, tmpDer, tmpDerSz,
algoID, curveOID, oidSz);
if (ret < 0) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret;
goto exit;
}
*outLen = (word32)ret;
exit:
/* tmpDer holds a plaintext copy of the ECC private key - always zeroize
* it before releasing (or before the stack buffer goes out of scope). */
ForceZero(tmpDer, ECC_BUFSIZE);
#ifndef WOLFSSL_NO_MALLOC
XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
*outLen = (word32)ret;
return ret;
}
+11
View File
@@ -1649,6 +1649,8 @@
if (ret != 0)
return ret;
des->keySet = 1;
return wc_Des3_SetIV(des, iv);
}
@@ -1793,6 +1795,10 @@
return BAD_LENGTH_E;
}
if (!des->keySet) {
return MISSING_KEY;
}
#ifdef WOLF_CRYPTO_CB
if (des->devId != INVALID_DEVID) {
int ret = wc_CryptoCb_Des3Encrypt(des, out, in, sz);
@@ -1848,6 +1854,10 @@
return BAD_LENGTH_E;
}
if (!des->keySet) {
return MISSING_KEY;
}
#ifdef WOLF_CRYPTO_CB
if (des->devId != INVALID_DEVID) {
int ret = wc_CryptoCb_Des3Decrypt(des, out, in, sz);
@@ -1969,6 +1979,7 @@ int wc_Des3Init(Des3* des3, void* heap, int devId)
return BAD_FUNC_ARG;
des3->heap = heap;
des3->keySet = 0;
#ifdef WOLF_CRYPTO_CB
des3->devId = devId;
+18 -10
View File
@@ -230,7 +230,7 @@ int NitroxCheckRequests(WC_ASYNC_DEV* dev,
word32 buf_size = sizeof(req_stat_buf->req);
ret = CspGetAllResults(req_stat_buf->req, buf_size, &res_count,
dev->nitrox.devId);
multi_req->count = res_count;
req_stat_buf->count = res_count;
#endif
return NitroxTranslateResponseCode(ret);
@@ -324,6 +324,10 @@ int NitroxRsaPrivateDecrypt(const byte* in, word32 inLen, byte* out,
word32* outLen, RsaKey* key)
{
int ret;
/* The Csp call writes a 16-bit length; use a dedicated Uint16 rather than
* casting the word32* outLen, which would place the bytes in the wrong half
* of the word on a big-endian host before the ntohs() below. */
Uint16 localOutLen = 0;
if (key == NULL || in == NULL || out == NULL ||
inLen != (word32)key->n.raw.len) {
@@ -337,17 +341,17 @@ int NitroxRsaPrivateDecrypt(const byte* in, word32 inLen, byte* out,
ret = CspPkcs1v15CrtDec(key->asyncDev.nitrox.devId, CAVIUM_REQ_MODE,
CAVIUM_SSL_GRP, CAVIUM_DPORT, BT2, key->n.raw.len, key->q.raw.buf,
key->dQ.raw.buf, key->p.raw.buf, key->dP.raw.buf, key->u.raw.buf,
(byte*)in, (Uint16*)outLen, out, &key->asyncDev.nitrox.reqId);
(byte*)in, &localOutLen, out, &key->asyncDev.nitrox.reqId);
#else
ret = CspPkcs1v15CrtDec(CAVIUM_REQ_MODE, BT2, key->n.raw.len,
key->q.raw.buf, key->dQ.raw.buf, key->p.raw.buf, key->dP.raw.buf,
key->u.raw.buf, (byte*)in, &outLen, out, &key->asyncDev.nitrox.reqId,
key->asyncDev.nitrox.devId);
key->u.raw.buf, (byte*)in, &localOutLen, out,
&key->asyncDev.nitrox.reqId, key->asyncDev.nitrox.devId);
#endif
#ifdef WOLFSSL_NITROX_DEBUG
printf("NitroxRsaPrivateDecrypt: ret %x, req %lx in %p (%d), out %p (%d)\n",
ret, key->asyncDev.nitrox.reqId, in, inLen, out, *outLen);
ret, key->asyncDev.nitrox.reqId, in, inLen, out, localOutLen);
#endif
ret = NitroxTranslateResponseCode(ret);
@@ -355,7 +359,7 @@ int NitroxRsaPrivateDecrypt(const byte* in, word32 inLen, byte* out,
return ret;
}
*outLen = ntohs(*outLen);
*outLen = ntohs(localOutLen);
return *outLen;
}
@@ -404,6 +408,10 @@ int NitroxRsaSSL_Verify(const byte* in, word32 inLen, byte* out,
word32* outLen, RsaKey* key)
{
int ret;
/* The Csp call writes a 16-bit length; use a dedicated Uint16 rather than
* casting the word32* outLen, which would place the bytes in the wrong half
* of the word on a big-endian host before the ntohs() below. */
Uint16 localOutLen = 0;
if (key == NULL || in == NULL || out == NULL ||
inLen != (word32)key->n.raw.len) {
@@ -416,17 +424,17 @@ int NitroxRsaSSL_Verify(const byte* in, word32 inLen, byte* out,
#ifdef HAVE_CAVIUM_V
ret = CspPkcs1v15Dec(key->asyncDev.nitrox.devId, CAVIUM_REQ_MODE,
CAVIUM_SSL_GRP, CAVIUM_DPORT, BT1, key->n.raw.len, key->e.raw.len,
key->n.raw.buf, key->e.raw.buf, (byte*)in, (Uint16*)outLen, out,
key->n.raw.buf, key->e.raw.buf, (byte*)in, &localOutLen, out,
&key->asyncDev.nitrox.reqId);
#else
ret = CspPkcs1v15Dec(CAVIUM_REQ_MODE, BT1, key->n.raw.len, key->e.raw.len,
key->n.raw.buf, key->e.raw.buf, (byte*)in, &outLen, out,
key->n.raw.buf, key->e.raw.buf, (byte*)in, &localOutLen, out,
&key->asyncDev.nitrox.reqId, key->asyncDev.nitrox.devId);
#endif
#ifdef WOLFSSL_NITROX_DEBUG
printf("NitroxRsaSSL_Verify: ret %x, req %lx in %p (%d), out %p (%d)\n",
ret, key->asyncDev.nitrox.reqId, in, inLen, out, *outLen);
ret, key->asyncDev.nitrox.reqId, in, inLen, out, localOutLen);
#endif
ret = NitroxTranslateResponseCode(ret);
@@ -434,7 +442,7 @@ int NitroxRsaSSL_Verify(const byte* in, word32 inLen, byte* out,
return ret;
}
*outLen = ntohs(*outLen);
*outLen = ntohs(localOutLen);
return *outLen;
}
+12 -1
View File
@@ -49,7 +49,14 @@ static void wolfSSL_liboqsGetRandomData(uint8_t* buffer, size_t numOfBytes)
while (numOfBytes > 0) {
numOfBytes_word32 = (word32)numOfBytes;
numOfBytes -= numOfBytes_word32;
/* On platforms where size_t is wider than word32, the cast above can
* truncate. If numOfBytes does not fit into a word32 (including the
* case where it is an exact multiple of 2^32 and truncates to 0),
* generate the largest chunk that fits to guarantee forward progress
* and avoid an infinite loop. */
if ((size_t)numOfBytes_word32 != numOfBytes) {
numOfBytes_word32 = 0xFFFFFFFFU;
}
ret = wc_RNG_GenerateBlock(liboqsCurrentRNG, buffer,
numOfBytes_word32);
if (ret != 0) {
@@ -62,6 +69,10 @@ static void wolfSSL_liboqsGetRandomData(uint8_t* buffer, size_t numOfBytes)
);
abort();
}
/* Advance the buffer so subsequent iterations append rather than
* overwrite the previously generated bytes. */
buffer += numOfBytes_word32;
numOfBytes -= numOfBytes_word32;
}
}
+24 -3
View File
@@ -7927,6 +7927,12 @@ static int mldsa_make_key_from_seed(wc_MlDsaKey* key, const byte* seed)
}
#ifndef WC_MLDSA_CACHE_PRIV_VECTORS
/* Zeroize the private vectors s1, s2 and t before freeing. These occupy
* the front of the buffer; any matrix A that follows is public (expanded
* from the public seed) and need not be cleared. */
if (s1 != NULL) {
ForceZero(s1, (word32)params->s1Sz + 2U * (word32)params->s2Sz);
}
XFREE(s1, key->heap, DYNAMIC_TYPE_MLDSA);
#endif
return ret;
@@ -7945,6 +7951,7 @@ static int mldsa_make_key_from_seed(wc_MlDsaKey* key, const byte* seed)
unsigned int r;
unsigned int s;
byte kl[2];
unsigned int allocSz = 0;
#ifdef WOLFSSL_MLDSA_DYNAMIC_KEYS
ret = mldsa_alloc_priv_buf(key);
@@ -7959,8 +7966,6 @@ static int mldsa_make_key_from_seed(wc_MlDsaKey* key, const byte* seed)
/* Allocate memory for large intermediates. */
if (ret == 0) {
unsigned int allocSz;
/* s1-l, s2-k, t-k, a-1 */
allocSz = (unsigned int)params->s1Sz + params->s2Sz + params->s2Sz +
(unsigned int)MLDSA_REJ_NTT_POLY_H_SIZE +
@@ -8158,6 +8163,15 @@ static int mldsa_make_key_from_seed(wc_MlDsaKey* key, const byte* seed)
key->pubKeySet = 1;
}
/* Zeroize the whole buffer before freeing. It holds the private vectors
* s1, s2 and t at the front; the rejection-sampling / matrix A region in
* the middle is public, but the trailing t64 accumulator (POLY64 builds)
* holds A o NTT(s1) - from which s1 is recoverable - so it must be
* cleared too. As the secret material is not contiguous, zeroize the
* entire allocation rather than a sub-range. */
if (s1 != NULL) {
ForceZero(s1, allocSz);
}
XFREE(s1, key->heap, DYNAMIC_TYPE_MLDSA);
return ret;
#endif
@@ -8584,7 +8598,14 @@ static int mldsa_sign_with_seed_mu(wc_MlDsaKey* key,
ForceZero(priv_rand_seed, sizeof(priv_rand_seed));
if (y != NULL) {
ForceZero(y, allocSz);
word32 zeroSz = allocSz;
#ifndef WC_MLDSA_CACHE_MATRIX_A
/* The public matrix A is appended at the end of the buffer and is
* expanded from the public seed - it need not be zeroized. The
* preceding vectors (y, w0, s1, s2, t0, ...) are secret dependent. */
zeroSz -= (word32)params->aSz;
#endif
ForceZero(y, zeroSz);
}
XFREE(y, key->heap, DYNAMIC_TYPE_MLDSA);
return ret;
+8 -1
View File
@@ -3466,7 +3466,12 @@ WOLFSSL_LOCAL int TLSX_SupportedCurve_Copy(TLSX* src, TLSX** dst, void* heap);
WOLFSSL_LOCAL int TLSX_UseSupportedCurve(TLSX** extensions, word16 name,
void* heap, int side);
WOLFSSL_LOCAL int TLSX_UsePointFormat(TLSX** extensions, byte point,
#ifdef WOLFSSL_API_PREFIX_MAP
#define TLSX_UsePointFormat wolfSSL_TLSX_UsePointFormat
#endif
/* WOLFSSL_TEST_VIS so the API tests can seed a client's ec_point_formats
* extension (the point-format negotiation has no public API). */
WOLFSSL_TEST_VIS int TLSX_UsePointFormat(TLSX** extensions, byte point,
void* heap);
WOLFSSL_LOCAL int TLSX_IsGroupSupported(int namedGroup, int side);
@@ -5197,6 +5202,8 @@ struct Options {
#endif /* WOLFSSL_DTLS */
#if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_SUPPORTED_CURVES)
word16 userCurves:1; /* indicates user called wolfSSL_UseSupportedCurve */
word16 peerNoUncompPF:1; /* peer sent ec_point_formats without
* the uncompressed (0) format */
#endif
word16 keepResources:1; /* Keep resources after handshake */
word16 useClientOrder:1; /* Use client's cipher order */
+2 -2
View File
@@ -40,9 +40,9 @@
typedef struct WOLFSSL_RC4_KEY {
/* big enough for Arc4 from wolfssl/wolfcrypt/arc4.h */
#ifdef WC_NO_PTR_INT_CAST
void* holder[(288 + WC_ASYNC_DEV_SIZE) / sizeof(void*)];
void* holder[(296 + WC_ASYNC_DEV_SIZE) / sizeof(void*)];
#else
void* holder[(272 + WC_ASYNC_DEV_SIZE) / sizeof(void*)];
void* holder[(280 + WC_ASYNC_DEV_SIZE) / sizeof(void*)];
#endif
} WOLFSSL_RC4_KEY;
+1
View File
@@ -51,6 +51,7 @@ typedef struct Arc4 {
WC_ASYNC_DEV asyncDev;
#endif
void* heap;
WC_BITFIELD keySet:1; /* set to 1 once a key has been configured */
} Arc4;
WOLFSSL_API int wc_Arc4Process(Arc4* arc4, byte* out, const byte* in,
+1
View File
@@ -113,6 +113,7 @@ struct Des3 {
void* devCtx;
#endif
void* heap;
WC_BITFIELD keySet:1; /* set to 1 once a key has been configured */
};
#ifndef WC_DES3_TYPE_DEFINED