From 5d74c49ecbef4abd97a8b0c2e3e57784eb92543a Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Wed, 22 Jun 2022 15:12:36 +0200 Subject: [PATCH] dtls13: allow processing of HelloVerifyRequest to support downgrade HelloVerifyRequest is used in DTLSv1.2 to perform a return routability check, so it can be the legitim reply from a DTLSv1.2 server to a ClientHello. --- src/internal.c | 17 ++++++++--- src/tls13.c | 73 +++++++++++++++++++++++++++++++++++++++++----- wolfssl/internal.h | 2 ++ 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/src/internal.c b/src/internal.c index 98286ba8c..9f94b300b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -147,8 +147,6 @@ WOLFSSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS #ifndef WOLFSSL_NO_TLS12 #ifndef NO_WOLFSSL_CLIENT - static int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input, - word32* inOutIdx, word32 size); static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size); #ifndef NO_CERTS @@ -24562,8 +24560,8 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType, /* handle processing of DTLS hello_verify_request (3) */ - static int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input, - word32* inOutIdx, word32 size) + int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 size) { ProtocolVersion pv; byte cookieSz; @@ -24605,7 +24603,18 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType, *inOutIdx += cookieSz; } +#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_TLS13) + if (IsAtLeastTLSv1_3(ssl->version) && ssl->options.dtls) { + /* we sent a TLSv1.3 ClientHello but received a + * HELLO_VERIFY_REQUEST */ + if (!ssl->options.downgrade || + ssl->options.minDowngrade < pv.minor) + return VERSION_ERROR; + } +#endif /* defined(WOLFSSL_DTLS13) && defined(WOLFSSL_TLS13) */ + ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE; + return 0; } diff --git a/src/tls13.c b/src/tls13.c index 431c2e666..85d1ca674 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -3411,9 +3411,14 @@ int SendTls13ClientHello(WOLFSSL* ssl) #endif #ifdef WOLFSSL_DTLS13 - /* legacy_cookie_id (always 0 length) */ - if (ssl->options.dtls) - args->length += OPAQUE8_LEN; + if (ssl->options.dtls) { + /* legacy_cookie_id len */ + args->length += ENUM_LEN; + + /* server sent us an HelloVerifyRequest and we allow downgrade */ + if (ssl->arrays->cookieSz > 0 && ssl->options.downgrade) + args->length += ssl->arrays->cookieSz; + } #endif /* WOLFSSL_DTLS13 */ /* Advance state and proceed */ @@ -3519,9 +3524,19 @@ int SendTls13ClientHello(WOLFSSL* ssl) } #ifdef WOLFSSL_DTLS13 - /* legacy_cookie_id. always 0 length vector */ - if (ssl->options.dtls) - args->output[args->idx++] = 0; + if (ssl->options.dtls) { + args->output[args->idx++] = ssl->arrays->cookieSz; + + if (ssl->arrays->cookieSz > 0) { + /* We have a cookie saved, so the server sent us an + * HelloVerifyRequest, it means it is a v1.2 server */ + if (!ssl->options.downgrade) + return VERSION_ERROR; + XMEMCPY(args->output + args->idx, ssl->arrays->cookie, + ssl->arrays->cookieSz); + args->idx += ssl->arrays->cookieSz; + } + } #endif /* WOLFSSL_DTLS13 */ /* Cipher suites */ @@ -9111,6 +9126,40 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) } /* Multiple KeyUpdates can be sent. */ break; +#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_NO_TLS12) + case hello_verify_request: + if (!ssl->options.dtls) { + WOLFSSL_MSG("HelloVerifyRequest when not in DTLS"); + return OUT_OF_ORDER_E; + } + if (ssl->msgsReceived.got_hello_verify_request) { + WOLFSSL_MSG("Duplicate HelloVerifyRequest received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_hello_verify_request = 1; + if (ssl->msgsReceived.got_hello_retry_request) { + WOLFSSL_MSG( + "Both HelloVerifyRequest and HelloRetryRequest received"); + return DUPLICATE_MSG_E; + } + if (ssl->options.serverState >= + SERVER_HELLO_RETRY_REQUEST_COMPLETE || + ssl->options.connectState != CLIENT_HELLO_SENT) { + WOLFSSL_MSG("HelloVerifyRequest received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("HelloVerifyRequest recevied on the server"); + return SIDE_ERROR; + } + if (!ssl->options.downgrade || + ssl->options.minDowngrade < DTLSv1_2_MINOR) { + WOLFSSL_MSG( + "HelloVerifyRequest recevied but not DTLSv1.2 allowed"); + return VERSION_ERROR; + } + break; +#endif /* WOLFSSL_DTLS13 && !WOLFSSL_NO_TLS12*/ default: WOLFSSL_MSG("Unknown message type"); @@ -9171,7 +9220,11 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->options.serverState == NULL_STATE && - type != server_hello && type != hello_retry_request) { + type != server_hello && type != hello_retry_request +#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_NO_TLS12) + && (!ssl->options.dtls || type != hello_verify_request) +#endif /* defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_NO_TLS12) */ + ) { WOLFSSL_MSG("First server message not server hello"); SendAlert(ssl, alert_fatal, unexpected_message); return OUT_OF_ORDER_E; @@ -9265,6 +9318,12 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, ret = DoTls13KeyUpdate(ssl, input, inOutIdx, size); break; +#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_NO_TLS12) + case hello_verify_request: + WOLFSSL_MSG("processing hello verify request"); + ret = DoHelloVerifyRequest(ssl, input, inOutIdx, size); + break; +#endif default: WOLFSSL_MSG("Unknown handshake message type"); ret = UNKNOWN_HANDSHAKE_TYPE; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 66d8b1041..1ea0bf43c 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -5175,6 +5175,8 @@ WOLFSSL_LOCAL int cipherExtraData(WOLFSSL* ssl); #ifndef NO_WOLFSSL_CLIENT WOLFSSL_LOCAL int SendClientHello(WOLFSSL* ssl); + WOLFSSL_LOCAL int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 size); #ifdef WOLFSSL_TLS13 WOLFSSL_LOCAL int SendTls13ClientHello(WOLFSSL* ssl); #endif