Merge pull request #5276 from rizlik/dtls13_client_downgrade

Dtls: improve version negotiation
pull/5330/head
David Garske 2022-07-06 11:57:53 -07:00 committed by GitHub
commit b2d1bf96ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 514 additions and 55 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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");

View File

@ -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;

View File

@ -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 \

View File

@ -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]));

View File

@ -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

View File

@ -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

View File

@ -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