diff --git a/src/dtls13.c b/src/dtls13.c index 2f30c98db..0eab6d442 100644 --- a/src/dtls13.c +++ b/src/dtls13.c @@ -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 diff --git a/src/internal.c b/src/internal.c index 9f94b300b..a3d568782 100644 --- a/src/internal.c +++ b/src/internal.c @@ -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 diff --git a/src/tls13.c b/src/tls13.c index 85d1ca674..23901be61 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -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 */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 1ea0bf43c..a8f37fe57 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -4659,6 +4659,8 @@ struct WOLFSSL { word32 dtls13FragOffset; byte dtls13FragHandshakeType; Dtls13Rtx dtls13Rtx; + byte *dtls13ClientHello; + word16 dtls13ClientHelloSz; #endif /* WOLFSSL_DTLS13 */ #endif /* WOLFSSL_DTLS */