Fix downgrading from TLS v1.3 to TLS v1.2

Fix handling of ServerHello in TLS v1.3 to support TLS v1.2 when
downgrading.
Added support in client and server examples for using downgrade method:
wolfSSLv23_client_method_ex() or wolfSSLv23_server_method_ex().
Add tests, using downgrade version, of client or server downgrading from
TLS v1.3 to TLS v1.2.
This commit is contained in:
Sean Parkinson 2018-02-22 11:05:58 +10:00
parent dc4edd0cd9
commit da4024b46a
8 changed files with 141 additions and 32 deletions

View File

@ -1027,6 +1027,10 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
break;
case 'v' :
if (myoptarg[0] == 'd') {
version = CLIENT_DOWNGRADE_VERSION;
break;
}
version = atoi(myoptarg);
if (version < 0 || version > 4) {
Usage();
@ -1414,6 +1418,10 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
method = wolfTLSv1_3_client_method_ex;
break;
#endif
case CLIENT_DOWNGRADE_VERSION:
method = wolfSSLv23_client_method_ex;
break;
#endif /* NO_TLS */
#ifdef WOLFSSL_DTLS

View File

@ -643,6 +643,10 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
break;
case 'v' :
if (myoptarg[0] == 'd') {
version = SERVER_DOWNGRADE_VERSION;
break;
}
version = atoi(myoptarg);
if (version < 0 || version > 4) {
Usage();
@ -893,6 +897,10 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
method = wolfTLSv1_3_server_method_ex;
break;
#endif
case SERVER_DOWNGRADE_VERSION:
method = wolfSSLv23_server_method_ex;
break;
#endif /* NO_TLS */
#ifdef CYASSL_DTLS

View File

@ -373,6 +373,22 @@ if [ $RESULT -eq 0 ]; then
fi
echo ""
# TLS Downgrade server / TLS 1.2 client.
echo -e "\n\nTLS server downgrading to TLS v1.2"
port=0
./examples/server/server -v d -R $ready_file -p $port &
server_pid=$!
create_port
./examples/client/client -v 3 -p $port
RESULT=$?
remove_ready_file
if [ $RESULT -ne 0 ]; then
echo -e "\n\nIssue with TLS server downgrading to TLS v1.2"
do_cleanup
exit 1
fi
echo ""
# TLS 1.2 server / TLS 1.3 client.
echo -e "\n\nTLS v1.3 client upgrading server to TLS v1.3"
port=0
@ -389,6 +405,22 @@ if [ $RESULT -eq 0 ]; then
fi
echo ""
# TLS 1.2 server / TLS downgrade client.
echo -e "\n\nTLS client downgrading to TLS v1.2"
port=0
./examples/server/server -v 3 -R $ready_file -p $port &
server_pid=$!
create_port
./examples/client/client -v d -p $port
RESULT=$?
remove_ready_file
if [ $RESULT -ne 0 ]; then
echo -e "\n\nIssue with TLS client downgrading to TLS v1.2"
do_cleanup
exit 1
fi
echo ""
# TLS 1.3 server / TLS 1.3 client send KeyUpdate before sending app data.
echo -e "\n\nTLS v1.3 KeyUpdate"
port=0

View File

@ -17431,6 +17431,13 @@ void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo,
}
#endif /* HAVE_SECRET_CALLBACK */
return CompleteServerHello(ssl);
}
int CompleteServerHello(WOLFSSL* ssl)
{
int ret;
if (ssl->options.resuming) {
if (DSH_CheckSessionId(ssl)) {
if (SetCipherSpecs(ssl) == 0) {

View File

@ -4679,6 +4679,13 @@ static int TLSX_SupportedVersions_Parse(WOLFSSL *ssl, byte* input,
if (major != pv.major)
return VERSION_ERROR;
/* Version is TLS v1.2 to handle downgrading from TLS v1.3+. */
if (ssl->options.downgrade && ssl->version.minor == TLSv1_2_MINOR &&
minor >= TLSv1_3_MINOR) {
/* Set minor version back to TLS v1.3+ */
ssl->version.minor = ssl->ctx->method->version.minor;
}
/* No upgrade allowed. */
if (ssl->version.minor < minor)
return VERSION_ERROR;

View File

@ -2605,6 +2605,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
int ret;
#ifndef WOLFSSL_TLS13_DRAFT_18
byte sessIdSz;
const byte* sessId;
byte b;
#endif
word16 totalExtSz;
@ -2668,35 +2669,18 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
sessIdSz = input[i++];
if ((i - begin) + sessIdSz > helloSz)
return BUFFER_ERROR;
#ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
if (sessIdSz == 0)
return INVALID_PARAMETER;
if (ssl->session.sessionIDSz != 0) {
if (ssl->session.sessionIDSz != sessIdSz ||
XMEMCMP(ssl->session.sessionID, input + i, sessIdSz) != 0) {
return INVALID_PARAMETER;
}
}
else if (XMEMCMP(ssl->arrays->clientRandom, input + i, sessIdSz) != 0)
return INVALID_PARAMETER;
#else
if (sessIdSz != ssl->session.sessionIDSz || (sessIdSz > 0 &&
XMEMCMP(ssl->session.sessionID, input + i, sessIdSz) != 0)) {
WOLFSSL_MSG("Server sent different session id");
return INVALID_PARAMETER;
}
#endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */
sessId = input + i;
i += sessIdSz;
ssl->options.haveSessionId = 1;
#endif /* WOLFSSL_TLS13_DRAFT_18 */
ssl->options.haveSessionId = 1;
#ifdef WOLFSSL_TLS13_DRAFT_18
/* Ciphersuite and extensions length check */
/* Ciphersuite check */
if ((i - begin) + OPAQUE16_LEN + OPAQUE16_LEN > helloSz)
return BUFFER_ERROR;
#else
/* Ciphersuite, compression and extensions length check */
if ((i - begin) + OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN > helloSz)
/* Ciphersuite and compression check */
if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz)
return BUFFER_ERROR;
#endif
@ -2713,18 +2697,33 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
}
#endif
/* Get extension length and length check. */
ato16(&input[i], &totalExtSz);
i += OPAQUE16_LEN;
if ((i - begin) + totalExtSz > helloSz)
return BUFFER_ERROR;
#ifndef WOLFSSL_TLS13_DRAFT_18
if ((i - begin) + OPAQUE16_LEN > helloSz) {
if (!ssl->options.downgrade)
return BUFFER_ERROR;
ssl->version.minor = TLSv1_2_MINOR;
ssl->options.haveEMS = 0;
}
if ((i - begin) < helloSz)
#endif
{
/* Get extension length and length check. */
ato16(&input[i], &totalExtSz);
i += OPAQUE16_LEN;
if ((i - begin) + totalExtSz > helloSz)
return BUFFER_ERROR;
/* Parse and handle extensions. */
ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, extMsgType, NULL);
if (ret != 0)
return ret;
#ifndef WOLFSSL_TLS13_DRAFT_18
if (ssl->options.downgrade)
ssl->version.minor = TLSv1_2_MINOR;
#endif
/* Parse and handle extensions. */
ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, extMsgType, NULL);
if (ret != 0)
return ret;
i += totalExtSz;
i += totalExtSz;
}
*inOutIdx = i;
ssl->options.serverState = SERVER_HELLO_COMPLETE;
@ -2739,6 +2738,51 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
}
#endif /* HAVE_SECRET_CALLBACK */
#ifndef WOLFSSL_TLS13_DRAFT_18
/* Version only negotiated in extensions for TLS v1.3.
* Only now do we know how to deal with session id.
*/
if (!IsAtLeastTLSv1_3(ssl->version)) {
ssl->arrays->sessionIDSz = sessIdSz;
if (ssl->arrays->sessionIDSz > ID_LEN) {
WOLFSSL_MSG("Invalid session ID size");
ssl->arrays->sessionIDSz = 0;
return BUFFER_ERROR;
}
else if (ssl->arrays->sessionIDSz) {
XMEMCPY(ssl->arrays->sessionID, sessId, ssl->arrays->sessionIDSz);
ssl->options.haveSessionId = 1;
}
/* Complete TLS v1.2 processing of ServerHello. */
ret = CompleteServerHello(ssl);
WOLFSSL_LEAVE("DoTls13ServerHello", ret);
return ret;
}
#ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
if (sessIdSz == 0)
return INVALID_PARAMETER;
if (ssl->session.sessionIDSz != 0) {
if (ssl->session.sessionIDSz != sessIdSz ||
XMEMCMP(ssl->session.sessionID, sessId, sessIdSz) != 0) {
return INVALID_PARAMETER;
}
}
else if (XMEMCMP(ssl->arrays->clientRandom, sessId, sessIdSz) != 0)
return INVALID_PARAMETER;
#else
if (sessIdSz != ssl->session.sessionIDSz || (sessIdSz > 0 &&
XMEMCMP(ssl->session.sessionID, sessId, sessIdSz) != 0)) {
WOLFSSL_MSG("Server sent different session id");
return INVALID_PARAMETER;
}
#endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */
#endif
ret = SetCipherSpecs(ssl);
if (ret != 0)
return ret;

View File

@ -1481,6 +1481,7 @@ WOLFSSL_LOCAL int DoTls13ClientHello(WOLFSSL* ssl, const byte* input,
#endif
WOLFSSL_LOCAL int DoServerHello(WOLFSSL* ssl, const byte* input, word32*,
word32);
WOLFSSL_LOCAL int CompleteServerHello(WOLFSSL *ssl);
WOLFSSL_LOCAL int CheckVersion(WOLFSSL *ssl, ProtocolVersion pv);
WOLFSSL_LOCAL void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo,
word32 hashSigAlgoSz);

View File

@ -234,9 +234,11 @@
#define SERVER_DEFAULT_VERSION 3
#define SERVER_DTLS_DEFAULT_VERSION (-2)
#define SERVER_INVALID_VERSION (-99)
#define SERVER_DOWNGRADE_VERSION (-98)
#define CLIENT_DEFAULT_VERSION 3
#define CLIENT_DTLS_DEFAULT_VERSION (-2)
#define CLIENT_INVALID_VERSION (-99)
#define CLIENT_DOWNGRADE_VERSION (-98)
#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_MAX_STRENGTH)
#define DEFAULT_MIN_DHKEY_BITS 2048
#else