mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-10 12:30:52 +02:00
DTLS 1.3 and TLS 1.3 focused fixes
dtls13.c: - Fix wrong return value in Dtls13SendFragmentedInternal error path (return outputSz instead of recordLength) - Fix incomplete bounds check in Dtls13SendFragmented to account for DTLS_HANDSHAKE_HEADER_SZ - Fix wrong WOLFSSL_ENTER trace string in Dtls13EpochCopyKeys tls13.c: - Remove wrong (byte) cast on cookie->len passed to TlsCheckCookie - Add missing bounds check on PSK identityLen in SetupPskKey before copying to client_identity - Fix data race on static header array in ExpectedResumptionSecret - Add defensive underflow check in EncryptTls13 for consistency with DecryptTls13 - Fix wrong return variable in DTLS 1.3 Finished send error path (return dtlsRet instead of ret) - Add missing SM3 case and default in Tls13_Exporter hash switch to prevent NULL dereference - Initialize *outSz to 0 in wolfSSL_write_early_data to match wolfSSL_read_early_data - Add bounds check for bindersLen against helloSz in CheckPreSharedKeys - Fix resource leak and hash state corruption in ExpectedResumptionSecret error paths - Fix memory leak of rsaSigBuf in dual-alg RSA+RSA CertificateVerify - Guard against word32 underflow in inputLength - HANDSHAKE_HEADER_SZ in DoTls13HandShakeMsg - Fix swapped side parameter in DeriveFinishedSecret for server-side Finished processing - Fix no_mac fall-through in ssl_handshake_md to return NULL instead of wrong digest - Fix strict aliasing violation in FindPsk PSK key size check - Remove duplicate !ssl->options.dtls check in TLS 1.3 middlebox compat condition tests: - Add regression tests for wolfSSL_write_early_data outSz initialization and DTLS 1.3 Finished send error propagation
This commit is contained in:
+3
-3
@@ -1040,7 +1040,7 @@ static int Dtls13SendFragmentedInternal(WOLFSSL* ssl)
|
||||
fragLength + DTLS_HANDSHAKE_HEADER_SZ, isEncrypted);
|
||||
if (outputSz < 0) {
|
||||
Dtls13FreeFragmentsBuffer(ssl);
|
||||
return recordLength;
|
||||
return outputSz;
|
||||
}
|
||||
|
||||
ret = CheckAvailableSize(ssl, outputSz);
|
||||
@@ -1102,7 +1102,7 @@ static int Dtls13SendFragmented(WOLFSSL* ssl, byte* message, word16 length,
|
||||
isEncrypted = Dtls13TypeIsEncrypted(handshake_type);
|
||||
rlHeaderLength = Dtls13GetRlHeaderLength(ssl, isEncrypted);
|
||||
|
||||
if (length < rlHeaderLength)
|
||||
if (length < rlHeaderLength + DTLS_HANDSHAKE_HEADER_SZ)
|
||||
return INCOMPLETE_DATA;
|
||||
|
||||
/* DTLSv1.3 do not consider fragmentation for hash transcript. Build the
|
||||
@@ -2212,7 +2212,7 @@ static void Dtls13EpochCopyKeys(WOLFSSL* ssl, Dtls13Epoch* e, Keys* k, int side)
|
||||
byte clientWrite, serverWrite;
|
||||
byte enc, dec;
|
||||
|
||||
WOLFSSL_ENTER("Dtls13SetEpochKeys");
|
||||
WOLFSSL_ENTER("Dtls13EpochCopyKeys");
|
||||
|
||||
clientWrite = serverWrite = 0;
|
||||
enc = dec = 0;
|
||||
|
||||
+44
-13
@@ -948,6 +948,13 @@ static const byte emptySHA512Hash[] = {
|
||||
0xF9, 0x27, 0xDA, 0x3E
|
||||
};
|
||||
#endif
|
||||
#ifdef WOLFSSL_SM3
|
||||
static const byte emptySM3Hash[] = {
|
||||
0x1A, 0xB2, 0x1D, 0x83, 0x55, 0xCF, 0xA1, 0x7F, 0x8E, 0x61, 0x19, 0x48,
|
||||
0x31, 0xE8, 0x1A, 0x8F, 0x22, 0xBE, 0xC8, 0xC7, 0x28, 0xFE, 0xFB, 0x74,
|
||||
0x7E, 0xD0, 0x35, 0xEB, 0x50, 0x82, 0xAA, 0x2B
|
||||
};
|
||||
#endif
|
||||
/**
|
||||
* Implement section 7.5 of RFC 8446
|
||||
* @return 0 on success
|
||||
@@ -1003,6 +1010,17 @@ int Tls13_Exporter(WOLFSSL* ssl, unsigned char *out, size_t outLen,
|
||||
emptyHash = emptySHA512Hash;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_SM3
|
||||
case sm3_mac:
|
||||
hashType = WC_HASH_TYPE_SM3;
|
||||
hashLen = WC_SM3_DIGEST_SIZE;
|
||||
emptyHash = emptySM3Hash;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* Derive-Secret(Secret, label, "") */
|
||||
@@ -2572,7 +2590,7 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input,
|
||||
word16 sz, const byte* aad, word16 aadSz, int asyncOkay)
|
||||
{
|
||||
int ret = 0;
|
||||
word16 dataSz = sz - ssl->specs.aead_mac_size;
|
||||
word16 dataSz;
|
||||
word16 macSz = ssl->specs.aead_mac_size;
|
||||
word32 nonceSz = 0;
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
@@ -2581,6 +2599,9 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input,
|
||||
#endif
|
||||
|
||||
WOLFSSL_ENTER("EncryptTls13");
|
||||
if (sz < ssl->specs.aead_mac_size)
|
||||
return BUFFER_E;
|
||||
dataSz = sz - ssl->specs.aead_mac_size;
|
||||
|
||||
(void)output;
|
||||
(void)input;
|
||||
@@ -4054,6 +4075,7 @@ static const WOLFSSL_EVP_MD* ssl_handshake_md(const byte mac_alg)
|
||||
{
|
||||
switch(mac_alg) {
|
||||
case no_mac:
|
||||
return NULL;
|
||||
#ifndef NO_MD5
|
||||
case md5_mac:
|
||||
return wolfSSL_EVP_md5();
|
||||
@@ -4161,6 +4183,8 @@ static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk, int clientHello)
|
||||
#endif
|
||||
|
||||
/* Set the client identity to use. */
|
||||
if (psk->identityLen > MAX_PSK_ID_LEN)
|
||||
return PSK_KEY_ERROR;
|
||||
XMEMSET(ssl->arrays->client_identity, 0,
|
||||
sizeof(ssl->arrays->client_identity));
|
||||
XMEMCPY(ssl->arrays->client_identity, psk->identity, psk->identityLen);
|
||||
@@ -5982,7 +6006,7 @@ int FindPskSuite(const WOLFSSL* ssl, PreSharedKey* psk, byte* psk_key,
|
||||
}
|
||||
if (*found) {
|
||||
if (*psk_keySz > MAX_PSK_KEY_LEN &&
|
||||
*((int*)psk_keySz) != WC_NO_ERR_TRACE(USE_HW_PSK)) {
|
||||
(int)*psk_keySz != WC_NO_ERR_TRACE(USE_HW_PSK)) {
|
||||
WOLFSSL_MSG("Key len too long in FindPsk()");
|
||||
ret = PSK_KEY_ERROR;
|
||||
WOLFSSL_ERROR_VERBOSE(ret);
|
||||
@@ -6322,6 +6346,8 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
|
||||
client_hello, &bindersLen);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (bindersLen > helloSz)
|
||||
return BUFFER_ERROR;
|
||||
|
||||
/* Refine list for PSK processing. */
|
||||
sslRefineSuites(ssl, clSuites);
|
||||
@@ -6564,7 +6590,7 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
|
||||
int keyShareExt = 0;
|
||||
int ret;
|
||||
|
||||
ret = TlsCheckCookie(ssl, cookie->data, (byte)cookie->len);
|
||||
ret = TlsCheckCookie(ssl, cookie->data, cookie->len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cookieDataSz = (word16)ret;
|
||||
@@ -9741,6 +9767,7 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl)
|
||||
#ifndef NO_RSA
|
||||
if (ssl->hsAltType == DYNAMIC_TYPE_RSA) {
|
||||
/* build encoded signature buffer */
|
||||
XFREE(rsaSigBuf->buffer, ssl->heap, DYNAMIC_TYPE_SIGNATURE);
|
||||
rsaSigBuf->length = WC_MAX_DIGEST_SIZE;
|
||||
rsaSigBuf->buffer = (byte*)XMALLOC(rsaSigBuf->length,
|
||||
ssl->heap,
|
||||
@@ -11488,13 +11515,13 @@ static int SendTls13Finished(WOLFSSL* ssl)
|
||||
*/
|
||||
ret = DeriveFinishedSecret(ssl, ssl->clientSecret,
|
||||
ssl->keys.client_write_MAC_secret,
|
||||
WOLFSSL_SERVER_END);
|
||||
WOLFSSL_CLIENT_END);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = DeriveFinishedSecret(ssl, ssl->serverSecret,
|
||||
ssl->keys.server_write_MAC_secret,
|
||||
WOLFSSL_CLIENT_END);
|
||||
WOLFSSL_SERVER_END);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
@@ -11520,7 +11547,7 @@ static int SendTls13Finished(WOLFSSL* ssl)
|
||||
(word16)(Dtls13GetRlHeaderLength(ssl, 1) + headerSz + finishedSz), finished,
|
||||
1);
|
||||
if (dtlsRet != 0 && dtlsRet != WC_NO_ERR_TRACE(WANT_WRITE))
|
||||
return ret;
|
||||
return dtlsRet;
|
||||
|
||||
} else
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
@@ -12166,7 +12193,7 @@ static int ExpectedResumptionSecret(WOLFSSL* ssl)
|
||||
word32 finishedSz = 0;
|
||||
byte mac[WC_MAX_DIGEST_SIZE];
|
||||
Digest digest;
|
||||
static byte header[] = { 0x14, 0x00, 0x00, 0x00 };
|
||||
byte header[] = { 0x14, 0x00, 0x00, 0x00 };
|
||||
|
||||
XMEMSET(&digest, 0, sizeof(Digest));
|
||||
|
||||
@@ -12206,25 +12233,26 @@ static int ExpectedResumptionSecret(WOLFSSL* ssl)
|
||||
ret = BuildTls13HandshakeHmac(ssl, ssl->keys.client_write_MAC_secret, mac,
|
||||
&finishedSz);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
goto restore;
|
||||
header[FINISHED_MSG_SIZE_OFFSET] = finishedSz;
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
if (ssl->earlyData != no_early_data) {
|
||||
static byte endOfEarlyData[] = { 0x05, 0x00, 0x00, 0x00 };
|
||||
ret = HashRaw(ssl, endOfEarlyData, sizeof(endOfEarlyData));
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
goto restore;
|
||||
}
|
||||
#endif
|
||||
if ((ret = HashRaw(ssl, header, sizeof(header))) != 0)
|
||||
return ret;
|
||||
goto restore;
|
||||
if ((ret = HashRaw(ssl, mac, finishedSz)) != 0)
|
||||
return ret;
|
||||
goto restore;
|
||||
|
||||
if ((ret = DeriveResumptionSecret(ssl, ssl->session->masterSecret)) != 0)
|
||||
return ret;
|
||||
goto restore;
|
||||
|
||||
/* Restore the hash inline with currently seen messages. */
|
||||
restore:
|
||||
switch (ssl->specs.mac_algorithm) {
|
||||
#ifndef NO_SHA256
|
||||
case sha256_mac:
|
||||
@@ -13460,7 +13488,8 @@ int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
}
|
||||
|
||||
ret = EarlySanityCheckMsgReceived(ssl, type,
|
||||
min(inputLength - HANDSHAKE_HEADER_SZ, size));
|
||||
(inputLength > HANDSHAKE_HEADER_SZ) ?
|
||||
min(inputLength - HANDSHAKE_HEADER_SZ, size) : 0);
|
||||
if (ret != 0) {
|
||||
WOLFSSL_ERROR(ret);
|
||||
return ret;
|
||||
@@ -15308,6 +15337,8 @@ int wolfSSL_write_early_data(WOLFSSL* ssl, const void* data, int sz, int* outSz)
|
||||
if (!IsAtLeastTLSv1_3(ssl->version))
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
*outSz = 0;
|
||||
|
||||
#ifndef NO_WOLFSSL_CLIENT
|
||||
if (ssl->options.side == WOLFSSL_SERVER_END)
|
||||
return SIDE_ERROR;
|
||||
|
||||
+41
@@ -33050,6 +33050,46 @@ static int test_dtls13_missing_finished_server(void)
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
static int test_dtls13_finished_send_error_propagation(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
|
||||
WOLFSSL_CTX *ctx_c = NULL;
|
||||
WOLFSSL_CTX *ctx_s = NULL;
|
||||
WOLFSSL *ssl_c = NULL;
|
||||
WOLFSSL *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,
|
||||
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
|
||||
|
||||
/* CH1 */
|
||||
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
|
||||
/* HRR */
|
||||
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
|
||||
/* CH2 */
|
||||
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
|
||||
/* Server first flight with finished */
|
||||
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
|
||||
/* Client second flight with finished — block sends to force error */
|
||||
test_ctx.s_len = TEST_MEMIO_BUF_SZ;
|
||||
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
|
||||
/* Verify the error is propagated, not silently swallowed as success */
|
||||
ExpectIntNE(wolfSSL_get_error(ssl_c, -1), 0);
|
||||
|
||||
wolfSSL_free(ssl_c);
|
||||
wolfSSL_free(ssl_s);
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
wolfSSL_CTX_free(ctx_s);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
|
||||
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
|
||||
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
|
||||
@@ -35393,6 +35433,7 @@ TEST_CASE testCases[] = {
|
||||
TEST_DECL(test_dtls12_missing_finished),
|
||||
TEST_DECL(test_dtls13_missing_finished_client),
|
||||
TEST_DECL(test_dtls13_missing_finished_server),
|
||||
TEST_DECL(test_dtls13_finished_send_error_propagation),
|
||||
TEST_DTLS_DECLS,
|
||||
TEST_DECL(test_tls_multi_handshakes_one_record),
|
||||
TEST_DECL(test_write_dup),
|
||||
|
||||
@@ -808,6 +808,11 @@ int test_tls13_apis(void)
|
||||
/* invoking without session or psk cbs */
|
||||
ExpectIntEQ(wolfSSL_write_early_data(clientSsl, earlyData,
|
||||
sizeof(earlyData), &outSz), WC_NO_ERR_TRACE(BAD_STATE_E));
|
||||
/* verify *outSz is initialized to 0 even on non-success paths */
|
||||
outSz = 42;
|
||||
ExpectIntEQ(wolfSSL_write_early_data(clientSsl, earlyData,
|
||||
sizeof(earlyData), &outSz), WC_NO_ERR_TRACE(BAD_STATE_E));
|
||||
ExpectIntEQ(outSz, 0);
|
||||
#endif
|
||||
|
||||
ExpectIntEQ(wolfSSL_read_early_data(NULL, earlyDataBuffer,
|
||||
|
||||
Reference in New Issue
Block a user