mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 16:40:49 +02:00
Merge pull request #10304 from JeremiahM37/fenrir-2
Zero DH keys, tighten SSL APIs, harden TLS extensions
This commit is contained in:
@@ -8669,6 +8669,9 @@ void FreeKeyExchange(WOLFSSL* ssl)
|
||||
{
|
||||
/* Cleanup signature buffer */
|
||||
if (ssl->buffers.sig.buffer) {
|
||||
/* May transiently hold the client's DH private exponent in the
|
||||
* TLS 1.2 diffie_hellman_kea / dhe_psk_kea paths. */
|
||||
ForceZero(ssl->buffers.sig.buffer, ssl->buffers.sig.length);
|
||||
XFREE(ssl->buffers.sig.buffer, ssl->heap, DYNAMIC_TYPE_SIGNATURE);
|
||||
ssl->buffers.sig.buffer = NULL;
|
||||
ssl->buffers.sig.length = 0;
|
||||
|
||||
@@ -4743,6 +4743,7 @@ int wolfSSL_DH_generate_key(WOLFSSL_DH* dh)
|
||||
int ret = 1;
|
||||
word32 pubSz = 0;
|
||||
word32 privSz = 0;
|
||||
word32 privAllocSz = 0;
|
||||
int localRng = 0;
|
||||
WC_RNG* rng = NULL;
|
||||
WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0);
|
||||
@@ -4792,9 +4793,12 @@ int wolfSSL_DH_generate_key(WOLFSSL_DH* dh)
|
||||
else {
|
||||
privSz = pubSz;
|
||||
}
|
||||
/* Allocate public and private key arrays. */
|
||||
/* Allocate public and private key arrays. Preserve the allocation
|
||||
* size because wc_DhGenerateKeyPair updates privSz in-place. */
|
||||
privAllocSz = privSz;
|
||||
pub = (unsigned char*)XMALLOC(pubSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
|
||||
priv = (unsigned char*)XMALLOC(privSz, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
|
||||
priv = (unsigned char*)XMALLOC(privAllocSz, NULL,
|
||||
DYNAMIC_TYPE_PRIVATE_KEY);
|
||||
if (pub == NULL || priv == NULL) {
|
||||
WOLFSSL_ERROR_MSG("Unable to malloc memory");
|
||||
ret = 0;
|
||||
@@ -4846,7 +4850,10 @@ int wolfSSL_DH_generate_key(WOLFSSL_DH* dh)
|
||||
}
|
||||
/* Dispose of allocated data. */
|
||||
XFREE(pub, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
|
||||
XFREE(priv, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
|
||||
if (priv != NULL) {
|
||||
ForceZero(priv, privAllocSz);
|
||||
XFREE(priv, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+6
-2
@@ -2459,11 +2459,15 @@ static void FreeSetupKeysArgs(WOLFSSL* ssl, void* pArgs)
|
||||
args->key->type = WC_PK_TYPE_NONE;
|
||||
args->key->initPriv = 0; args->key->initPub = 0;
|
||||
|
||||
/* Scrub the raw DH private exponent (and any other key material
|
||||
* embedded in the union) before release. wc_FreeDhKey above only
|
||||
* clears the mp_int DhKey, not the separate privKey byte array.
|
||||
* Use ForceZero (rather than XMEMSET) so the wipe cannot be
|
||||
* elided by the optimizer. */
|
||||
ForceZero(args->key, sizeof(*args->key));
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
XFREE(args->key, NULL, DYNAMIC_TYPE_SNIFFER_KEY);
|
||||
args->key = NULL;
|
||||
#else
|
||||
XMEMSET(args->key, 0, sizeof(args->key));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -10152,11 +10152,21 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
|
||||
#ifdef WOLFSSL_DTLS
|
||||
ssl->options.dtlsStateful = 0;
|
||||
#endif
|
||||
#ifdef WOLFSSL_TLS13
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
ssl->options.noPskDheKe = 0;
|
||||
#ifdef HAVE_SUPPORTED_CURVES
|
||||
ssl->options.onlyPskDheKe = 0;
|
||||
#endif
|
||||
if (ssl->ctx != NULL) {
|
||||
ssl->options.noPskDheKe = ssl->ctx->noPskDheKe;
|
||||
#ifdef HAVE_SUPPORTED_CURVES
|
||||
ssl->options.onlyPskDheKe = ssl->ctx->onlyPskDheKe;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
ssl->options.noPskDheKe = 0;
|
||||
#ifdef HAVE_SUPPORTED_CURVES
|
||||
ssl->options.onlyPskDheKe = 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
#ifdef WOLFSSL_TLS13
|
||||
|
||||
+10
-2
@@ -2722,11 +2722,19 @@ void wolfSSL_DES_ncbc_encrypt(const unsigned char* input, unsigned char* output,
|
||||
int enc)
|
||||
{
|
||||
unsigned char tmp[DES_IV_SIZE];
|
||||
/* Calculate length to a multiple of block size. */
|
||||
size_t offset = (size_t)length;
|
||||
size_t offset;
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_DES_ncbc_encrypt");
|
||||
|
||||
/* Zero/negative length: no block to derive an IV from. The offset math
|
||||
* below would underflow for length == 0, yielding a wild-pointer read. */
|
||||
if (length <= 0) {
|
||||
WOLFSSL_LEAVE("wolfSSL_DES_ncbc_encrypt", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calculate length to a multiple of block size. */
|
||||
offset = (size_t)length;
|
||||
offset = (offset + DES_BLOCK_SIZE - 1) / DES_BLOCK_SIZE;
|
||||
offset *= DES_BLOCK_SIZE;
|
||||
offset -= DES_BLOCK_SIZE;
|
||||
|
||||
+7
-4
@@ -5513,10 +5513,13 @@ int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx)
|
||||
ret = 1;
|
||||
}
|
||||
#else
|
||||
/* OpenSSL's implementation of this API does not require loading the
|
||||
* system CA cert directory. Allow skipping this without erroring out.
|
||||
*/
|
||||
ret = 1;
|
||||
/* No source available: SSL_CERT_DIR/SSL_CERT_FILE not set and
|
||||
* WOLFSSL_SYS_CA_CERTS not compiled in. Returning success would be
|
||||
* fail-open since no trust anchors were loaded. */
|
||||
WOLFSSL_MSG("wolfSSL_CTX_set_default_verify_paths: no CA source "
|
||||
"available (build without WOLFSSL_SYS_CA_CERTS and no "
|
||||
"SSL_CERT_DIR/SSL_CERT_FILE env)");
|
||||
ret = WOLFSSL_FAILURE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1598,8 +1598,12 @@ int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session)
|
||||
#if !defined(OPENSSL_EXTRA) || !defined(WOLFSSL_ERROR_CODE_OPENSSL)
|
||||
return WOLFSSL_FAILURE; /* session timed out */
|
||||
#else /* defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL) */
|
||||
/* Return success for OpenSSL compatibility but do not carry the
|
||||
* expired session's version/cipher into ssl state, which would
|
||||
* otherwise pin the ClientHello to stale values. */
|
||||
WOLFSSL_MSG("Session is expired but return success for "
|
||||
"OpenSSL compatibility");
|
||||
return WOLFSSL_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
ssl->options.resuming = 1;
|
||||
|
||||
@@ -9063,6 +9063,9 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap)
|
||||
if (WOLFSSL_NAMED_GROUP_IS_FFDHE(current->group)) {
|
||||
#ifndef NO_DH
|
||||
wc_FreeDhKey((DhKey*)current->key);
|
||||
if (current->privKey != NULL && current->privKeyLen > 0) {
|
||||
ForceZero(current->privKey, current->privKeyLen);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (current->group == WOLFSSL_ECC_X25519) {
|
||||
@@ -17369,8 +17372,8 @@ static word16 TLSX_GetMinSize_Server(const word16 *type)
|
||||
|
||||
|
||||
/** Parses a buffer of TLS extensions. */
|
||||
int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
|
||||
Suites *suites)
|
||||
WOLFSSL_TEST_VIS int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
||||
byte msgType, Suites *suites)
|
||||
{
|
||||
int ret = 0;
|
||||
word16 offset = 0;
|
||||
@@ -17992,6 +17995,20 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
|
||||
#ifdef WOLFSSL_SRTP
|
||||
case TLSX_USE_SRTP:
|
||||
WOLFSSL_MSG("Use SRTP extension received");
|
||||
|
||||
#if defined(WOLFSSL_TLS13)
|
||||
if (IsAtLeastTLSv1_3(ssl->version)) {
|
||||
if (msgType != client_hello &&
|
||||
msgType != encrypted_extensions)
|
||||
return EXT_NOT_ALLOWED;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (msgType != client_hello &&
|
||||
msgType != server_hello)
|
||||
return EXT_NOT_ALLOWED;
|
||||
}
|
||||
ret = SRTP_PARSE(ssl, input + offset, size, isRequest);
|
||||
break;
|
||||
#endif
|
||||
@@ -18086,6 +18103,15 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
case TLSX_ECH:
|
||||
WOLFSSL_MSG("ECH extension received");
|
||||
if (!IsAtLeastTLSv1_3(ssl->version))
|
||||
break;
|
||||
|
||||
if (msgType != client_hello &&
|
||||
msgType != encrypted_extensions &&
|
||||
msgType != hello_retry_request) {
|
||||
return EXT_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
ret = ECH_PARSE(ssl, input + offset, size, msgType);
|
||||
break;
|
||||
case TLSXT_ECH_OUTER_EXTENSIONS:
|
||||
|
||||
@@ -39707,6 +39707,8 @@ TEST_CASE testCases[] = {
|
||||
TEST_DECL(test_certificate_authorities_client_hello),
|
||||
TEST_DECL(test_TLSX_TCA_Find),
|
||||
TEST_DECL(test_TLSX_SNI_GetSize_overflow),
|
||||
TEST_DECL(test_TLSX_ECH_msg_type_validation),
|
||||
TEST_DECL(test_TLSX_SRTP_msg_type_validation),
|
||||
TEST_DECL(test_wolfSSL_wolfSSL_UseSecureRenegotiation),
|
||||
TEST_DECL(test_wolfSSL_clear_secure_renegotiation),
|
||||
TEST_DECL(test_wolfSSL_SCR_Reconnect),
|
||||
|
||||
@@ -203,6 +203,34 @@ int test_wolfSSL_DES_ncbc(void)
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
int test_wolfSSL_DES_ncbc_zero_length(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_DES3)
|
||||
const_DES_cblock myDes;
|
||||
DES_cblock iv;
|
||||
DES_cblock ivSaved;
|
||||
DES_key_schedule key = {0};
|
||||
unsigned char msg[DES_BLOCK_SIZE] = {0};
|
||||
unsigned char out[DES_BLOCK_SIZE] = {0};
|
||||
|
||||
DES_set_key(&key, &myDes);
|
||||
|
||||
/* length == 0 must no-op: the offset math would otherwise underflow
|
||||
* size_t and read from a wild pointer. */
|
||||
XMEMSET((byte*)&iv, 0xAB, DES_BLOCK_SIZE);
|
||||
XMEMCPY(&ivSaved, &iv, DES_BLOCK_SIZE);
|
||||
DES_ncbc_encrypt(msg, out, 0, &myDes, &iv, DES_ENCRYPT);
|
||||
ExpectIntEQ(XMEMCMP(&iv, &ivSaved, DES_BLOCK_SIZE), 0);
|
||||
|
||||
XMEMSET((byte*)&iv, 0xAB, DES_BLOCK_SIZE);
|
||||
XMEMCPY(&ivSaved, &iv, DES_BLOCK_SIZE);
|
||||
DES_ncbc_encrypt(msg, out, 0, &myDes, &iv, DES_DECRYPT);
|
||||
ExpectIntEQ(XMEMCMP(&iv, &ivSaved, DES_BLOCK_SIZE), 0);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
int test_wolfSSL_DES_ecb_encrypt(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
int test_wolfSSL_DES(void);
|
||||
int test_wolfSSL_DES_ncbc(void);
|
||||
int test_wolfSSL_DES_ncbc_zero_length(void);
|
||||
int test_wolfSSL_DES_ecb_encrypt(void);
|
||||
int test_wolfSSL_DES_ede3_cbc_encrypt(void);
|
||||
int test_wolfSSL_AES_encrypt(void);
|
||||
@@ -38,6 +39,7 @@ int test_wolfSSL_RC4(void);
|
||||
#define TEST_OSSL_CIPHER_DECLS \
|
||||
TEST_DECL_GROUP("ossl_cipher", test_wolfSSL_DES), \
|
||||
TEST_DECL_GROUP("ossl_cipher", test_wolfSSL_DES_ncbc), \
|
||||
TEST_DECL_GROUP("ossl_cipher", test_wolfSSL_DES_ncbc_zero_length), \
|
||||
TEST_DECL_GROUP("ossl_cipher", test_wolfSSL_DES_ecb_encrypt), \
|
||||
TEST_DECL_GROUP("ossl_cipher", test_wolfSSL_DES_ede3_cbc_encrypt), \
|
||||
TEST_DECL_GROUP("ossl_cipher", test_wolfSSL_AES_encrypt), \
|
||||
|
||||
@@ -5847,3 +5847,29 @@ int test_tls13_ticket_peer_cert_reverify(void)
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
int test_tls13_clear_preserves_psk_dhe(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) && \
|
||||
defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES) && \
|
||||
(defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \
|
||||
!defined(NO_WOLFSSL_CLIENT)
|
||||
WOLFSSL_CTX* ctx = NULL;
|
||||
WOLFSSL* ssl = NULL;
|
||||
|
||||
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
|
||||
ExpectIntEQ(wolfSSL_CTX_no_dhe_psk(ctx), 0);
|
||||
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
||||
ExpectIntEQ(ssl->options.noPskDheKe, 1);
|
||||
|
||||
/* SSL reuse must preserve the CTX-level noPskDheKe; resetting to 0
|
||||
* would silently re-enable psk_dhe_ke for the next handshake. */
|
||||
ExpectIntEQ(wolfSSL_clear(ssl), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(ssl->options.noPskDheKe, 1);
|
||||
|
||||
wolfSSL_free(ssl);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ int test_tls13_cert_with_extern_psk_rejects_resumption(void);
|
||||
int test_tls13_cert_with_extern_psk_sh_missing_key_share(void);
|
||||
int test_tls13_cert_with_extern_psk_sh_confirms_resumption(void);
|
||||
int test_tls13_ticket_peer_cert_reverify(void);
|
||||
int test_tls13_clear_preserves_psk_dhe(void);
|
||||
|
||||
#define TEST_TLS13_DECLS \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_apis), \
|
||||
@@ -111,6 +112,7 @@ int test_tls13_ticket_peer_cert_reverify(void);
|
||||
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_rejects_resumption), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_sh_missing_key_share), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_sh_confirms_resumption), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_ticket_peer_cert_reverify)
|
||||
TEST_DECL_GROUP("tls13", test_tls13_ticket_peer_cert_reverify), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_clear_preserves_psk_dhe)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_TLS13_H */
|
||||
|
||||
@@ -982,3 +982,54 @@ int test_TLSX_SNI_GetSize_overflow(void)
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* ECH is only valid in ClientHello, EncryptedExtensions, or
|
||||
* HelloRetryRequest per RFC 9460. Feeding it in a Finished message must
|
||||
* be rejected with EXT_NOT_ALLOWED rather than being silently accepted. */
|
||||
int test_TLSX_ECH_msg_type_validation(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) && \
|
||||
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS)
|
||||
WOLFSSL_CTX* ctx = NULL;
|
||||
WOLFSSL* ssl = NULL;
|
||||
/* type = TLSX_ECH (0xfe0d), size = 0x0000 */
|
||||
const byte extBytes[] = { 0xfe, 0x0d, 0x00, 0x00 };
|
||||
|
||||
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
|
||||
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
||||
|
||||
ExpectIntEQ(TLSX_Parse(ssl, extBytes, (word16)sizeof(extBytes),
|
||||
finished, NULL),
|
||||
WC_NO_ERR_TRACE(EXT_NOT_ALLOWED));
|
||||
|
||||
wolfSSL_free(ssl);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* use_srtp is only valid in ClientHello/ServerHello (pre-TLS 1.3) or
|
||||
* ClientHello/EncryptedExtensions (TLS 1.3) per RFC 5764. Feeding it in a
|
||||
* Finished message must be rejected with EXT_NOT_ALLOWED. */
|
||||
int test_TLSX_SRTP_msg_type_validation(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SRTP) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS)
|
||||
WOLFSSL_CTX* ctx = NULL;
|
||||
WOLFSSL* ssl = NULL;
|
||||
/* type = TLSX_USE_SRTP (0x000e), size = 0x0000 */
|
||||
const byte extBytes[] = { 0x00, 0x0e, 0x00, 0x00 };
|
||||
|
||||
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
|
||||
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
||||
|
||||
ExpectIntEQ(TLSX_Parse(ssl, extBytes, (word16)sizeof(extBytes),
|
||||
finished, NULL),
|
||||
WC_NO_ERR_TRACE(EXT_NOT_ALLOWED));
|
||||
|
||||
wolfSSL_free(ssl);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
@@ -34,5 +34,7 @@ int test_certificate_authorities_certificate_request(void);
|
||||
int test_certificate_authorities_client_hello(void);
|
||||
int test_TLSX_TCA_Find(void);
|
||||
int test_TLSX_SNI_GetSize_overflow(void);
|
||||
int test_TLSX_ECH_msg_type_validation(void);
|
||||
int test_TLSX_SRTP_msg_type_validation(void);
|
||||
|
||||
#endif /* TESTS_API_TEST_TLS_EMS_H */
|
||||
|
||||
+4
-1
@@ -3232,7 +3232,10 @@ WOLFSSL_LOCAL int TLSX_ParseVersion(WOLFSSL* ssl, const byte* input,
|
||||
WOLFSSL_LOCAL int TLSX_SupportedVersions_Parse(const WOLFSSL* ssl,
|
||||
const byte* input, word16 length, byte msgType, ProtocolVersion* pv,
|
||||
Options* opts, TLSX** exts);
|
||||
WOLFSSL_LOCAL int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
||||
#ifdef WOLFSSL_API_PREFIX_MAP
|
||||
#define TLSX_Parse wolfSSL_TLSX_Parse
|
||||
#endif
|
||||
WOLFSSL_TEST_VIS int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
||||
byte msgType, Suites *suites);
|
||||
WOLFSSL_LOCAL int TLSX_Push(TLSX** list, TLSX_Type type,
|
||||
const void* data, void* heap);
|
||||
|
||||
Reference in New Issue
Block a user