From d1f19e8eccfc4a868dceee2d9e0f38e2303a36bc Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 21 Feb 2018 17:45:13 +1000 Subject: [PATCH 1/3] Fix resumption code around when not available Can't set a ticket if the encryption callback is NULL. If no useable pre-shared key is found then we won't do PSK. --- src/tls.c | 2 +- src/tls13.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tls.c b/src/tls.c index 814099f9e..dbb737f18 100644 --- a/src/tls.c +++ b/src/tls.c @@ -8062,7 +8062,7 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) } #if defined(HAVE_SESSION_TICKET) - if (ssl->options.resuming) { + if (ssl->options.resuming && ssl->ctx->ticketEncCb != NULL) { WOLFSSL_SESSION* sess = &ssl->session; word32 milli; diff --git a/src/tls13.c b/src/tls13.c index d0856efb0..bf16be20a 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -3173,6 +3173,9 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, break; } + if (current == NULL) + return 0; + /* Hash the rest of the ClientHello. */ ret = HashInputRaw(ssl, input + helloSz - bindersLen, bindersLen); if (ret != 0) From dc4edd0cd92a2f076f9b1ded21431225cf403696 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 21 Feb 2018 22:24:42 +1000 Subject: [PATCH 2/3] SNI fix for nginx --- src/tls.c | 2 +- src/tls13.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tls.c b/src/tls.c index dbb737f18..7c97f240b 100644 --- a/src/tls.c +++ b/src/tls.c @@ -8062,7 +8062,7 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) } #if defined(HAVE_SESSION_TICKET) - if (ssl->options.resuming && ssl->ctx->ticketEncCb != NULL) { + if (ssl->options.resuming && ssl->session.ticketLen > 0) { WOLFSSL_SESSION* sess = &ssl->session; word32 milli; diff --git a/src/tls13.c b/src/tls13.c index bf16be20a..58f4ecc22 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -3570,10 +3570,11 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return ret; } -#ifdef HAVE_STUNNEL +#if defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) if ((ret = SNI_Callback(ssl)) != 0) return ret; -#endif /*HAVE_STUNNEL*/ + ssl->options.side = WOLFSSL_SERVER_END; +#endif /* HAVE_STUNNELi || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ if (TLSX_Find(ssl->extensions, TLSX_SUPPORTED_VERSIONS) == NULL) { if (!ssl->options.downgrade) { From da4024b46af6921d3d7f6a1717f1b0726fb51d34 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Thu, 22 Feb 2018 11:05:58 +1000 Subject: [PATCH 3/3] 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. --- examples/client/client.c | 8 +++ examples/server/server.c | 8 +++ scripts/tls13.test | 32 ++++++++++++ src/internal.c | 7 +++ src/tls.c | 7 +++ src/tls13.c | 108 +++++++++++++++++++++++++++------------ wolfssl/internal.h | 1 + wolfssl/test.h | 2 + 8 files changed, 141 insertions(+), 32 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index 51298e37e..3c010a869 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -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 diff --git a/examples/server/server.c b/examples/server/server.c index 058e4dc32..8f20ab8cb 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -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 diff --git a/scripts/tls13.test b/scripts/tls13.test index a04f29835..719515ac0 100755 --- a/scripts/tls13.test +++ b/scripts/tls13.test @@ -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 diff --git a/src/internal.c b/src/internal.c index acd857870..a06abbe41 100644 --- a/src/internal.c +++ b/src/internal.c @@ -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) { diff --git a/src/tls.c b/src/tls.c index 7c97f240b..c6bf6cdc2 100644 --- a/src/tls.c +++ b/src/tls.c @@ -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; diff --git a/src/tls13.c b/src/tls13.c index 58f4ecc22..0b80cd5f9 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -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; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 753330925..c057557ba 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -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); diff --git a/wolfssl/test.h b/wolfssl/test.h index fff6c1b7b..b4f193cb7 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -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