dtls13: client: recompute transcript hash on downgrade

If a lower version is negotiated, the transcript hash must be recomputed using
the <= v1.2 rules.
This commit is contained in:
Marco Oliverio
2022-06-22 15:15:16 +02:00
parent 5d74c49ecb
commit 8fe3f51ecb
4 changed files with 105 additions and 6 deletions

View File

@@ -716,6 +716,35 @@ static void Dtls13RtxRemoveCurAck(WOLFSSL* ssl)
}
}
static void Dtls13MaybeSaveClientHello(WOLFSSL* ssl)
{
Dtls13RtxRecord *r, **prev_next;
r = ssl->dtls13Rtx.rtxRecords;
prev_next = &ssl->dtls13Rtx.rtxRecords;
if (ssl->options.side == WOLFSSL_CLIENT_END &&
ssl->options.connectState >= CLIENT_HELLO_SENT &&
ssl->options.connectState <= HELLO_AGAIN_REPLY &&
ssl->options.downgrade && ssl->options.minDowngrade >= DTLSv1_2_MINOR) {
while (r != NULL) {
if (r->handshakeType == client_hello) {
Dtls13RtxRecordUnlink(ssl, prev_next, r);
if (ssl->dtls13ClientHello != NULL)
XFREE(ssl->dtls13ClientHello, ssl->heap,
DYNAMIC_TYPE_DTLS_MSG);
ssl->dtls13ClientHello = r->data;
ssl->dtls13ClientHelloSz = r->length;
r->data = NULL;
Dtls13FreeRtxBufferRecord(ssl, r);
return;
}
prev_next = &r->next;
r = r->next;
}
}
}
static int Dtls13RtxMsgRecvd(WOLFSSL* ssl, enum HandShakeType hs,
word32 fragOffset)
{
@@ -725,6 +754,9 @@ static int Dtls13RtxMsgRecvd(WOLFSSL* ssl, enum HandShakeType hs,
ssl->keys.dtls_peer_handshake_number >=
ssl->keys.dtls_expected_peer_handshake_number) {
if (hs == server_hello)
Dtls13MaybeSaveClientHello(ssl);
/* In the handshake, receiving part of the next flight, acknowledge the
sent flight. The only exception is, on the server side, receiving the
last client flight does not ACK any sent new_session_ticket

View File

@@ -7284,6 +7284,15 @@ void SSL_ResourceFree(WOLFSSL* ssl)
XFREE(ssl->buffers.dtlsCookieSecret.buffer, ssl->heap,
DYNAMIC_TYPE_COOKIE_PWD);
#endif
#ifdef WOLFSSL_DTLS13
if (ssl->dtls13ClientHello != NULL) {
XFREE(ssl->dtls13ClientHello, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
ssl->dtls13ClientHello = NULL;
ssl->dtls13ClientHelloSz = 0;
}
#endif /* WOLFSSL_DTLS13 */
#endif /* WOLFSSL_DTLS */
#ifdef OPENSSL_EXTRA
#ifndef NO_BIO
@@ -7503,12 +7512,21 @@ void FreeHandshakeResources(WOLFSSL* ssl)
WOLFSSL_ENTER("FreeHandshakeResources");
#ifdef WOLFSSL_DTLS
/* DTLS_POOL (DTLSv1.3 flushes the queue autonomously) */
if (ssl->options.dtls && !IsAtLeastTLSv1_3(ssl->version)) {
DtlsMsgPoolReset(ssl);
DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap);
ssl->dtls_rx_msg_list = NULL;
ssl->dtls_rx_msg_list_sz = 0;
if (ssl->options.dtls) {
/* DTLS_POOL (DTLSv1.3 flushes the queue autonomously) */
if(!IsAtLeastTLSv1_3(ssl->version)) {
DtlsMsgPoolReset(ssl);
DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap);
ssl->dtls_rx_msg_list = NULL;
ssl->dtls_rx_msg_list_sz = 0;
}
#ifdef WOLFSSL_DTLS13
if (ssl->dtls13ClientHello != NULL) {
XFREE(ssl->dtls13ClientHello, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
ssl->dtls13ClientHello = NULL;
ssl->dtls13ClientHelloSz = 0;
}
#endif /* WOLFSSL_DTLS13 */
}
#endif

View File

@@ -3641,6 +3641,28 @@ int SendTls13ClientHello(WOLFSSL* ssl)
return ret;
}
#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_NO_CLIENT)
static int Dtls13DoDowngrade(WOLFSSL* ssl)
{
int ret;
if (ssl->dtls13ClientHello == NULL)
return BAD_STATE_E;
/* v1.3 and v1.2 hash messages to compute the transcript hash. When we are
* using DTLSv1.3 we hash the first clientHello following v1.3 but the
* server can negotiate a lower version. So we need to re-hash the
* clientHello to adhere to DTLS <= v1.2 rules. */
ret = InitHandshakeHashes(ssl);
if (ret != 0)
return ret;
ret = HashRaw(ssl, ssl->dtls13ClientHello, ssl->dtls13ClientHelloSz);
XFREE(ssl->dtls13ClientHello, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
ssl->dtls13ClientHello = NULL;
ssl->dtls13ClientHelloSz = 0;
return ret;
}
#endif /* WOLFSSL_DTLS13 && !WOLFSSL_NO_CLIENT*/
/* handle processing of TLS 1.3 server_hello (2) and hello_retry_request (6) */
/* Handle the ServerHello message from the server.
* Only a client will receive this message.
@@ -3762,6 +3784,9 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
if (ssl->options.dtls) {
ssl->chVersion.minor = DTLSv1_2_MINOR;
ssl->version.minor = DTLSv1_2_MINOR;
ret = Dtls13DoDowngrade(ssl);
if (ret != 0)
return ret;
}
#endif /* WOLFSSL_DTLS13 */
@@ -3839,6 +3864,9 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
if (ssl->options.dtls) {
ssl->chVersion.minor = DTLSv1_2_MINOR;
ssl->version.minor = DTLSv1_2_MINOR;
ret = Dtls13DoDowngrade(ssl);
if (ret != 0)
return ret;
}
#endif /* WOLFSSL_DTLS13 */
@@ -3893,9 +3921,28 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
return VERSION_ERROR;
ssl->version.minor = args->pv.minor;
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls) {
ret = Dtls13DoDowngrade(ssl);
if (ret != 0)
return ret;
}
#endif /* WOLFSSL_DTLS13 */
}
}
#ifdef WOLFSSL_DTLS13
/* we are sure that version is >= v1.3 now, we can get rid of buffered
* ClientHello that was buffered to re-compute the hash in case of
* downgrade */
if (ssl->options.dtls && ssl->dtls13ClientHello != NULL) {
XFREE(ssl->dtls13ClientHello, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
ssl->dtls13ClientHello = NULL;
ssl->dtls13ClientHelloSz = 0;
}
#endif /* WOLFSSL_DTLS13 */
/* Advance state and proceed */
ssl->options.asyncState = TLS_ASYNC_BUILD;
} /* case TLS_ASYNC_BEGIN */

View File

@@ -4659,6 +4659,8 @@ struct WOLFSSL {
word32 dtls13FragOffset;
byte dtls13FragHandshakeType;
Dtls13Rtx dtls13Rtx;
byte *dtls13ClientHello;
word16 dtls13ClientHelloSz;
#endif /* WOLFSSL_DTLS13 */
#endif /* WOLFSSL_DTLS */