diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index 729626be3..f4b867ea0 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. 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 diff --git a/src/dtls13.c b/src/dtls13.c index e46ef3c8e..94245cbef 100644 --- a/src/dtls13.c +++ b/src/dtls13.c @@ -718,6 +718,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) { @@ -727,6 +756,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 59e86cbea..07e1ea094 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 @@ -7286,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 @@ -7505,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 @@ -10022,7 +10038,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; } @@ -24605,8 +24621,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; @@ -24648,7 +24664,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; } @@ -24689,6 +24716,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; @@ -24702,11 +24730,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. */ @@ -24714,7 +24755,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; } @@ -24729,27 +24771,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 1626ef1d6..ccb5d6777 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -4549,17 +4549,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 d1be3696b..dec6d88c4 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -3424,9 +3424,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 */ @@ -3532,9 +3537,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 */ @@ -3639,6 +3654,32 @@ 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; + 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*/ + /* 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. @@ -3738,6 +3779,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; @@ -3760,6 +3807,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 */ @@ -3837,6 +3887,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 */ @@ -3891,9 +3944,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 */ @@ -9178,6 +9250,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"); @@ -9238,7 +9344,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; @@ -9332,6 +9442,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/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 diff --git a/wolfssl/internal.h b/wolfssl/internal.h index c91eb9499..34be9e14e 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 */ @@ -4670,6 +4671,8 @@ struct WOLFSSL { word32 dtls13FragOffset; byte dtls13FragHandshakeType; Dtls13Rtx dtls13Rtx; + byte *dtls13ClientHello; + word16 dtls13ClientHelloSz; #endif /* WOLFSSL_DTLS13 */ #endif /* WOLFSSL_DTLS */ @@ -5186,6 +5189,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