From 5d74c49ecbef4abd97a8b0c2e3e57784eb92543a Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Wed, 22 Jun 2022 15:12:36 +0200 Subject: [PATCH 1/6] 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 From 8fe3f51ecb3d075196f114e800123361f8724b94 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Wed, 22 Jun 2022 15:15:16 +0200 Subject: [PATCH 2/6] dtls13: client: recompute transcript hash on downgrade If a lower version is negotiated, the transcript hash must be recomputed using the <= v1.2 rules. --- src/dtls13.c | 32 +++++++++++++++++++++++++++++++ src/internal.c | 30 +++++++++++++++++++++++------ src/tls13.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ wolfssl/internal.h | 2 ++ 4 files changed, 105 insertions(+), 6 deletions(-) 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 */ From df7e81d18754ffa37f6868a6af03889d6769b8f0 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Mon, 4 Jul 2022 17:07:39 +0200 Subject: [PATCH 3/6] dtls: support version negotiation --- src/internal.c | 73 ++++++++++++++++++++++++++++++---------------- src/ssl.c | 4 ++- src/tls13.c | 10 +++++++ wolfssl/internal.h | 1 + 4 files changed, 62 insertions(+), 26 deletions(-) diff --git a/src/internal.c b/src/internal.c index a3d568782..b8eaa4240 100644 --- a/src/internal.c +++ b/src/internal.c @@ -10015,7 +10015,7 @@ int GetDtlsHandShakeHeader(WOLFSSL* ssl, const byte* input, (!IsAtLeastTLSv1_3(ssl->version) && ssl->curRL.pvMinor != ssl->version.minor) || (IsAtLeastTLSv1_3(ssl->version) && ssl->curRL.pvMinor != DTLSv1_2_MINOR) ) { - if (*type != client_hello && *type != hello_verify_request) { + if (*type != client_hello && *type != hello_verify_request && *type != server_hello) { WOLFSSL_ERROR(VERSION_ERROR); return VERSION_ERROR; } @@ -24669,6 +24669,7 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType, */ int CheckVersion(WOLFSSL *ssl, ProtocolVersion pv) { + byte lowerVersion, higherVersion; #ifdef WOLFSSL_TLS13_DRAFT if (pv.major == TLS_DRAFT_MAJOR) { pv.major = SSLv3_MAJOR; @@ -24682,11 +24683,24 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType, } #endif - if (pv.minor > ssl->version.minor) { + if (ssl->options.dtls) { + if (pv.major != DTLS_MAJOR || pv.minor == DTLS_BOGUS_MINOR) + return VERSION_ERROR; + lowerVersion = pv.minor > ssl->version.minor; + higherVersion = pv.minor < ssl->version.minor; + } + else { + if (pv.major != SSLv3_MAJOR) + return VERSION_ERROR; + lowerVersion = pv.minor < ssl->version.minor; + higherVersion = pv.minor > ssl->version.minor; + } + + if (higherVersion) { WOLFSSL_MSG("Server using higher version, fatal error"); return VERSION_ERROR; } - if (pv.minor < ssl->version.minor) { + if (lowerVersion) { WOLFSSL_MSG("server using lower version"); /* Check for downgrade attack. */ @@ -24694,7 +24708,8 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType, WOLFSSL_MSG("\tno downgrade allowed, fatal error"); return VERSION_ERROR; } - if (pv.minor < ssl->options.minDowngrade) { + if ((!ssl->options.dtls && pv.minor < ssl->options.minDowngrade) || + (ssl->options.dtls && pv.minor > ssl->options.minDowngrade)) { WOLFSSL_MSG("\tversion below minimum allowed, fatal error"); return VERSION_ERROR; } @@ -24709,27 +24724,35 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType, #endif /* Checks made - OK to downgrade. */ - if (pv.minor == SSLv3_MINOR) { - /* turn off tls */ - WOLFSSL_MSG("\tdowngrading to SSLv3"); - ssl->options.tls = 0; - ssl->options.tls1_1 = 0; - ssl->version.minor = SSLv3_MINOR; - } - else if (pv.minor == TLSv1_MINOR) { - /* turn off tls 1.1+ */ - WOLFSSL_MSG("\tdowngrading to TLSv1"); - ssl->options.tls1_1 = 0; - ssl->version.minor = TLSv1_MINOR; - } - else if (pv.minor == TLSv1_1_MINOR) { - WOLFSSL_MSG("\tdowngrading to TLSv1.1"); - ssl->version.minor = TLSv1_1_MINOR; - } - else if (pv.minor == TLSv1_2_MINOR) { - WOLFSSL_MSG(" downgrading to TLSv1.2"); - ssl->version.minor = TLSv1_2_MINOR; - } + ssl->version.minor = pv.minor; + switch(pv.minor) { + case SSLv3_MINOR: + /* turn off tls */ + WOLFSSL_MSG("\tdowngrading to SSLv3"); + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + break; + case TLSv1_MINOR: + /* turn off tls 1.1+ */ + WOLFSSL_MSG("\tdowngrading to TLSv1"); + ssl->options.tls1_1 = 0; + break; + case TLSv1_1_MINOR: + WOLFSSL_MSG("\tdowngrading to TLSv1.1"); + break; + case DTLS_MINOR: + WOLFSSL_MSG("\tdowngrading to DTLSv1.1"); + break; + case TLSv1_2_MINOR: + WOLFSSL_MSG("\tdowngrading to TLSv1.2"); + break; + case DTLSv1_2_MINOR: + WOLFSSL_MSG("\tdowngrading to DTLSv1.2"); + break; + default: + WOLFSSL_MSG("\tbad minor version"); + return VERSION_ERROR; + } } #ifdef OPENSSL_EXTRA diff --git a/src/ssl.c b/src/ssl.c index 3f19647b9..ff37f8028 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -4516,17 +4516,19 @@ static int SetMinVersionHelper(byte* minVersion, int version) break; #endif -#ifdef WOLFSSL_DTLS13 +#ifdef WOLFSSL_DTLS case WOLFSSL_DTLSV1: *minVersion = DTLS_MINOR; break; case WOLFSSL_DTLSV1_2: *minVersion = DTLSv1_2_MINOR; break; +#ifdef WOLFSSL_DTLS13 case WOLFSSL_DTLSV1_3: *minVersion = DTLSv1_3_MINOR; break; #endif /* WOLFSSL_DTLS13 */ +#endif /* WOLFSSL_DTLS */ default: WOLFSSL_MSG("Bad function argument"); diff --git a/src/tls13.c b/src/tls13.c index 23901be61..d5d3e939d 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -3659,6 +3659,10 @@ static int Dtls13DoDowngrade(WOLFSSL* ssl) XFREE(ssl->dtls13ClientHello, ssl->heap, DYNAMIC_TYPE_DTLS_MSG); ssl->dtls13ClientHello = NULL; ssl->dtls13ClientHelloSz = 0; + ssl->keys.dtls_sequence_number_hi = + w64GetHigh32(ssl->dtls13EncryptEpoch->nextSeqNumber); + ssl->keys.dtls_sequence_number_lo = + w64GetLow32(ssl->dtls13EncryptEpoch->nextSeqNumber); return ret; } #endif /* WOLFSSL_DTLS13 && !WOLFSSL_NO_CLIENT*/ @@ -3762,6 +3766,12 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, XMEMCPY(&args->pv, input + args->idx, OPAQUE16_LEN); args->idx += OPAQUE16_LEN; +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls && + (args->pv.major != DTLS_MAJOR || args->pv.minor == DTLS_BOGUS_MINOR)) + return VERSION_ERROR; +#endif /* WOLFSSL_DTLS */ + #ifndef WOLFSSL_NO_TLS12 { byte wantDowngrade; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index a8f37fe57..2822eef1a 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1205,6 +1205,7 @@ enum Misc { DTLS_MAJOR = 0xfe, /* DTLS major version number */ DTLS_MINOR = 0xff, /* DTLS minor version number */ + DTLS_BOGUS_MINOR = 0xfe, /* DTLS 0xfe was skipped, see RFC6347 Sec. 1 */ DTLSv1_2_MINOR = 0xfd, /* DTLS minor version number */ DTLSv1_3_MINOR = 0xfc, /* DTLS minor version number */ SSLv3_MAJOR = 3, /* SSLv3 and TLSv1+ major version number */ From fd4836772bd263a7b6576aab9bcd2dd140b5ac65 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Mon, 4 Jul 2022 17:00:15 +0200 Subject: [PATCH 4/6] examples: support DTLS version downgrading --- examples/client/client.c | 36 +++++++++++++++++++++++++++++++++--- examples/server/server.c | 11 +++++++---- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index c39e6ba1d..c88dde320 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -2802,7 +2802,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) err_sys("Bad DTLS version"); #endif /* WOLFSSL_DTLS13 */ } - else + else if (version == 2) version = -1; } } @@ -2859,7 +2859,16 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif case CLIENT_DOWNGRADE_VERSION: - method = wolfSSLv23_client_method_ex; + if (!doDTLS) { + method = wolfSSLv23_client_method_ex; + } + else { +#ifdef WOLFSSL_DTLS + method = wolfDTLS_client_method_ex; +#else + err_sys("version not supported"); +#endif /* WOLFSSL_DTLS */ + } break; #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) case EITHER_DOWNGRADE_VERSION: @@ -2934,7 +2943,28 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) } #endif if (minVersion != CLIENT_INVALID_VERSION) { - wolfSSL_CTX_SetMinVersion(ctx, minVersion); +#ifdef WOLFSSL_DTLS + if (doDTLS) { + switch (minVersion) { + case 4: +#ifdef WOLFSSL_DTLS13 + minVersion = WOLFSSL_DTLSV1_3; + break; +#else + err_sys("invalid minimum downgrade version"); + break; +#endif /* WOLFSSL_DTLS13 */ + case 3: + minVersion = WOLFSSL_DTLSV1_2; + break; + case 2: + minVersion = WOLFSSL_DTLSV1; + break; + } + } +#endif /* WOLFSSL_DTLS */ + if (wolfSSL_CTX_SetMinVersion(ctx, minVersion) != WOLFSSL_SUCCESS) + err_sys("can't set minimum downgrade version"); } if (simulateWantWrite) { #ifdef USE_WOLFSSL_IO diff --git a/examples/server/server.c b/examples/server/server.c index 864228a99..f3ff44469 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -2265,11 +2265,11 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) method = wolfSSLv23_server_method_ex; } else { -#ifdef WOLFSSL_DTLS13 +#ifdef WOLFSSL_DTLS method = wolfDTLS_server_method_ex; #else err_sys_ex(runWithErrors, "version not supported"); -#endif /* WOLFSSL_DTLS13 */ +#endif /* WOLFSSL_DTLS */ } break; #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) @@ -2341,12 +2341,14 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) err_sys_ex(catastrophic, "unable to get ctx"); if (minVersion != SERVER_INVALID_VERSION) { -#ifdef WOLFSSL_DTLS13 +#ifdef WOLFSSL_DTLS if (doDTLS) { switch (minVersion) { +#ifdef WOLFSSL_DTLS13 case 4: minVersion = WOLFSSL_DTLSV1_3; break; +#endif /* WOLFSSL_DTLS13 */ case 3: minVersion = WOLFSSL_DTLSV1_2; break; @@ -2356,7 +2358,8 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) } } #endif /* WOLFSSL_DTLS13 */ - wolfSSL_CTX_SetMinVersion(ctx, minVersion); + if (wolfSSL_CTX_SetMinVersion(ctx, minVersion) != WOLFSSL_SUCCESS) + err_sys_ex(catastrophic, "can't set minimum downgrade version"); } #ifdef OPENSSL_COMPATIBLE_DEFAULTS From 683adb59176ff99fc0926e9692ad3427eb3a51f0 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Tue, 5 Jul 2022 10:37:12 +0200 Subject: [PATCH 5/6] tests: add dtls downgrade tests --- tests/include.am | 1 + tests/suites.c | 11 +++++++++ tests/test-dtls-downgrade.conf | 21 ++++++++++++++++ tests/test-dtls13-downgrade.conf | 42 ++++++++++++++++++++++++++++---- 4 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 tests/test-dtls-downgrade.conf diff --git a/tests/include.am b/tests/include.am index c4b6b7af4..b4a0aef15 100644 --- a/tests/include.am +++ b/tests/include.am @@ -30,6 +30,7 @@ EXTRA_DIST += tests/unit.h \ tests/test-psk-no-id.conf \ tests/test-psk-no-id-sha2.conf \ tests/test-dtls.conf \ + tests/test-dtls-downgrade.conf \ tests/test-dtls-fails.conf \ tests/test-dtls-fails-cipher.conf \ tests/test-dtls-group.conf \ diff --git a/tests/suites.c b/tests/suites.c index 5f1a1fb62..b7f2c18a2 100644 --- a/tests/suites.c +++ b/tests/suites.c @@ -1023,6 +1023,17 @@ int SuiteTest(int argc, char** argv) goto exit; } #endif + + /* Add dtls downgrade test */ + XSTRLCPY(argv0[1], "tests/test-dtls-downgrade.conf", sizeof(argv0[1])); + printf("starting dtls downgrade tests\n"); + test_harness(&args); + if (args.return_code != 0) { + printf("error from script %d\n", args.return_code); + args.return_code = EXIT_FAILURE; + goto exit; + } + #ifdef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES /* add dtls extra suites */ XSTRLCPY(argv0[1], "tests/test-dtls-sha2.conf", sizeof(argv0[1])); diff --git a/tests/test-dtls-downgrade.conf b/tests/test-dtls-downgrade.conf new file mode 100644 index 000000000..067ff47a6 --- /dev/null +++ b/tests/test-dtls-downgrade.conf @@ -0,0 +1,21 @@ +# server DTLS multiversion allow downgrading +-vd +-7 2 +-u +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + +# client DTLSv1.0 +-v 2 +-u +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + +# server DTLSv1.0 +-v 2 +-u +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + +# client DTLS multiversion allow downgrading +-vd +-7 2 +-u +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA diff --git a/tests/test-dtls13-downgrade.conf b/tests/test-dtls13-downgrade.conf index 4bde3259f..bda26666c 100644 --- a/tests/test-dtls13-downgrade.conf +++ b/tests/test-dtls13-downgrade.conf @@ -1,11 +1,43 @@ -# server DTLSv1.3 allow downgrading +# server DTLS multiversion allow downgrade -vd -7 2 -u --l TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA -# client TLSv1.2 group message +# client DTLSv1.2 -v 3 -u --l TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 --f +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + +# server DTLS multiversion allow downgrade +-vd +-7 2 +-u +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + +# client DTLSv1.0 +-v 2 +-u +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + +# server DTLSv1.0 +-v 2 +-u +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + +# client DTLS multiversion, allow downgrade +-vd +-7 2 +-u +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + +# server DTLSv1.2 +-v 3 +-u +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + +# client DTLS multiversion, allow downgrade +-vd +-7 2 +-u +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA From 3abffc3a3c2ee39f996648e23c430e26be96edfc Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Tue, 5 Jul 2022 11:52:14 +0200 Subject: [PATCH 6/6] doc: add documentation for wolfDTLS[v1_3]_*_method() --- doc/dox_comments/header_files/ssl.h | 156 ++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index 203fd15c2..29b8abf3a 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -475,7 +475,163 @@ WOLFSSL_METHOD *wolfDTLSv1_client_method(void); \sa wolfSSL_CTX_new */ WOLFSSL_METHOD *wolfDTLSv1_server_method(void); +/*! + \ingroup Setup + \brief The wolfDTLSv1_3_server_method() function is used to indicate that + the application is a server and will only support the DTLS 1.3 + protocol. This function allocates memory for and initializes a new + wolfSSL_METHOD structure to be used when creating the SSL/TLS context with + wolfSSL_CTX_new(). This function is only available when wolfSSL has been + compiled with DTLSv1.3 support (--enable-dtls13, or by defining + wolfSSL_DTLS13). + + \return * If successful, the call will return a pointer to the newly + created WOLFSSL_METHOD structure. + \return FAIL If memory allocation fails when calling XMALLOC, the failure + value of the underlying malloc() implementation will be returned + (typically NULL with errno will be set to ENOMEM). + + \param none No parameters. + + _Example_ + \code + WOLFSSL_METHOD* method; + WOLFSSL_CTX* ctx; + + method = wolfDTLSv1_3_server_method(); + if (method == NULL) { + // unable to get method + } + + ctx = wolfSSL_CTX_new(method); + ... + \endcode + + + \sa wolfDTLSv1_3_client_method +*/ + +WOLFSSL_METHOD *wolfDTLSv1_3_server_method(void); +/*! + \ingroup Setup + + \brief The wolfDTLSv1_3_client_method() function is used to indicate that + the application is a client and will only support the DTLS 1.3 + protocol. This function allocates memory for and initializes a new + wolfSSL_METHOD structure to be used when creating the SSL/TLS context with + wolfSSL_CTX_new(). This function is only available when wolfSSL has been + compiled with DTLSv1.3 support (--enable-dtls13, or by defining + wolfSSL_DTLS13). + + \return * If successful, the call will return a pointer to the newly + created WOLFSSL_METHOD structure. + \return FAIL If memory allocation fails when calling XMALLOC, the failure + value of the underlying malloc() implementation will be returned + (typically NULL with errno will be set to ENOMEM). + + \param none No parameters. + + _Example_ + \code + WOLFSSL_METHOD* method; + WOLFSSL_CTX* ctx; + + method = wolfDTLSv1_3_client_method(); + if (method == NULL) { + // unable to get method + } + + ctx = wolfSSL_CTX_new(method); + ... + \endcode + + + \sa wolfDTLSv1_3_server_method +*/ +WOLFSSL_METHOD* wolfDTLSv1_3_client_method(void); +/*! + \ingroup Setup + + \brief The wolfDTLS_server_method() function is used to indicate that the + application is a server and will support the highest version of DTLS + available and all the version up to the minimum version allowed. The + default minimum version allowed is based on the define + WOLFSSL_MIN_DTLS_DOWNGRADE and can be changed at runtime using + wolfSSL_SetMinVersion(). This function allocates memory for and initializes + a new wolfSSL_METHOD structure to be used when creating the SSL/TLS context + with wolfSSL_CTX_new(). This function is only available when wolfSSL has + been compiled with DTLS support (--enable-dtls, or by defining + wolfSSL_DTLS). + + \return * If successful, the call will return a pointer to the newly + created WOLFSSL_METHOD structure. + \return FAIL If memory allocation fails when calling XMALLOC, the failure + value of the underlying malloc() implementation will be returned + (typically NULL with errno will be set to ENOMEM). + + \param none No parameters. + + _Example_ + \code + WOLFSSL_METHOD* method; + WOLFSSL_CTX* ctx; + + method = wolfDTLS_server_method(); + if (method == NULL) { + // unable to get method + } + + ctx = wolfSSL_CTX_new(method); + ... + \endcode + + + \sa wolfDTLS_client_method + \sa wolfSSL_SetMinVersion +*/ +WOLFSSL_METHOD *wolfDTLS_server_method(void); +/*! + \ingroup Setup + + \brief The wolfDTLS_client_method() function is used to indicate that the + application is a client and will support the highest version of DTLS + available and all the version up to the minimum version allowed. The + default minimum version allowed is based on the define + WOLFSSL_MIN_DTLS_DOWNGRADE and can be changed at runtime using + wolfSSL_SetMinVersion(). This function allocates memory for and initializes + a new wolfSSL_METHOD structure to be used when creating the SSL/TLS context + with wolfSSL_CTX_new(). This function is only available when wolfSSL has + been compiled with DTLS support (--enable-dtls, or by defining + wolfSSL_DTLS). + + \return * If successful, the call will return a pointer to the newly + created WOLFSSL_METHOD structure. + \return FAIL If memory allocation fails when calling XMALLOC, the failure + value of the underlying malloc() implementation will be returned + (typically NULL with errno will be set to ENOMEM). + + \param none No parameters. + + _Example_ + \code + WOLFSSL_METHOD* method; + WOLFSSL_CTX* ctx; + + method = wolfDTLS_client_method(); + if (method == NULL) { + // unable to get method + } + + ctx = wolfSSL_CTX_new(method); + ... + \endcode + + + \sa wolfDTLS_server_method + \sa wolfSSL_SetMinVersion +*/ +WOLFSSL_METHOD *wolfDTLS_client_method(void); /*! \brief This function creates and initializes a WOLFSSL_METHOD for the server side.