From 5f14de33e7ad5b0c76354529b76cf346e2c291fe Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Mon, 20 Nov 2017 11:07:32 +1000 Subject: [PATCH] Changes for TLS v1.3 Draft 22 Middlebox compatibility available too. --- configure.ac | 2 +- src/internal.c | 52 +++++- src/ssl.c | 23 +-- src/tls.c | 214 ++++++++++++++++------- src/tls13.c | 411 ++++++++++++++++++++++++++++++++++++++------- wolfssl/internal.h | 12 +- 6 files changed, 563 insertions(+), 151 deletions(-) diff --git a/configure.ac b/configure.ac index 6a6edefe4..e0470d826 100644 --- a/configure.ac +++ b/configure.ac @@ -329,7 +329,7 @@ then fi -# Post-handshake Authentication +# Hello Retry Request Cookie AC_ARG_ENABLE([hrrcookie], [AS_HELP_STRING([--enable-hrrcookie],[Enable the server to send Cookie Extension in HRR with state (default: disabled)])], [ ENABLED_SEND_HRR_COOKIE=$enableval ], diff --git a/src/internal.c b/src/internal.c index a6989c419..1177e5337 100644 --- a/src/internal.c +++ b/src/internal.c @@ -5980,8 +5980,13 @@ static void AddRecordHeader(byte* output, word32 length, byte type, WOLFSSL* ssl rl->type = type; rl->pvMajor = ssl->version.major; /* type and version same in each */ #ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version)) + if (IsAtLeastTLSv1_3(ssl->version)) { +#ifdef WOLFSSL_TLS13_DRAFT_18 rl->pvMinor = TLSv1_MINOR; +#else + rl->pvMinor = TLSv1_2_MINOR; +#endif + } else #endif rl->pvMinor = ssl->version.minor; @@ -6462,7 +6467,12 @@ static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #else if (rh->pvMajor != ssl->version.major || (rh->pvMinor != ssl->version.minor && - (!IsAtLeastTLSv1_3(ssl->version) || rh->pvMinor != TLSv1_MINOR))) +#ifdef WOLFSSL_TLS13_DRAFT_18 + (!IsAtLeastTLSv1_3(ssl->version) || rh->pvMinor != TLSv1_MINOR) +#else + (!IsAtLeastTLSv1_3(ssl->version) || rh->pvMinor != TLSv1_2_MINOR) +#endif + )) #endif { if (ssl->options.side == WOLFSSL_SERVER_END && @@ -11854,7 +11864,14 @@ int ProcessReply(WOLFSSL* ssl) /* decrypt message */ case decryptMessage: - if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0) { +#if !defined(WOLFSSL_TLS13) || defined(WOLFSSL_TLS13_DRAFT_18) + if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0) +#else + if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0 && + (!IsAtLeastTLSv1_3(ssl->version) || + ssl->curRL.type != change_cipher_spec)) +#endif + { bufferStatic* in = &ssl->buffers.inputBuffer; ret = SanityCheckCipherText(ssl, ssl->curSize); @@ -11941,7 +11958,14 @@ int ProcessReply(WOLFSSL* ssl) /* verify digest of message */ case verifyMessage: - if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0) { +#if !defined(WOLFSSL_TLS13) || defined(WOLFSSL_TLS13_DRAFT_18) + if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0) +#else + if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0 && + (!IsAtLeastTLSv1_3(ssl->version) || + ssl->curRL.type != change_cipher_spec)) +#endif + { if (!atomicUser) { ret = VerifyMac(ssl, ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, @@ -12059,6 +12083,26 @@ int ProcessReply(WOLFSSL* ssl) } #endif +#ifdef WOLFSSL_TLS13 + #ifdef WOLFSSL_TLS13_DRAFT_18 + if (IsAtLeastTLSv1_3(ssl->version)) { + SendAlert(ssl, alert_fatal, illegal_parameter); + return UNKNOWN_RECORD_TYPE; + } + #else + if (IsAtLeastTLSv1_3(ssl->version)) { + word32 i = ssl->buffers.inputBuffer.idx; + if (ssl->curSize != 1 || + ssl->buffers.inputBuffer.buffer[i] != 1) { + SendAlert(ssl, alert_fatal, illegal_parameter); + return UNKNOWN_RECORD_TYPE; + } + ssl->buffers.inputBuffer.idx++; + break; + } + #endif +#endif + ret = SanityCheckMsgReceived(ssl, change_cipher_hs); if (ret != 0) { if (!ssl->options.dtls) { diff --git a/src/ssl.c b/src/ssl.c index 435f01b52..16baafee5 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -9213,22 +9213,8 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, FALL_THROUGH; case ACCEPT_CLIENT_HELLO_DONE : - if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { - if ((ssl->error = SendTls13HelloRetryRequest(ssl)) != 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - } - ssl->options.acceptState = ACCEPT_HELLO_RETRY_REQUEST_DONE; - WOLFSSL_MSG("accept state ACCEPT_HELLO_RETRY_REQUEST_DONE"); - FALL_THROUGH; - - case ACCEPT_HELLO_RETRY_REQUEST_DONE : - if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { - if ( (ssl->error = ProcessReply(ssl)) < 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } + if (ssl->options.tls1_3) { + return wolfSSL_accept_TLSv13(ssl); } #endif ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE; @@ -9236,11 +9222,6 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, FALL_THROUGH; case ACCEPT_FIRST_REPLY_DONE : - #ifdef WOLFSSL_TLS13 - if (ssl->options.tls1_3) { - return wolfSSL_accept_TLSv13(ssl); - } - #endif if ( (ssl->error = SendServerHello(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; diff --git a/src/tls.c b/src/tls.c index fcd408e0b..58eab78d1 100644 --- a/src/tls.c +++ b/src/tls.c @@ -4505,64 +4505,90 @@ int TLSX_UseQSHScheme(TLSX** extensions, word16 name, byte* pKey, word16 pkeySz, /* Return the size of the SupportedVersions extension's data. * * data The SSL/TLS object. + * msgType The type of the message this extension is being written into. * returns the length of data that will be in the extension. */ -static word16 TLSX_SupportedVersions_GetSize(void* data) +static word16 TLSX_SupportedVersions_GetSize(void* data, byte msgType) { WOLFSSL* ssl = (WOLFSSL*)data; - /* TLS v1.2 and TLS v1.3 */ - int cnt = 2; + if (msgType == client_hello) { + /* TLS v1.2 and TLS v1.3 */ + int cnt = 2; #ifndef NO_OLD_TLS - /* TLS v1 and TLS v1.1 */ - cnt += 2; + /* TLS v1 and TLS v1.1 */ + cnt += 2; #endif - if (!ssl->options.downgrade) - cnt = 1; + if (!ssl->options.downgrade) + cnt = 1; - return (word16)(OPAQUE8_LEN + cnt * OPAQUE16_LEN); + return (word16)(OPAQUE8_LEN + cnt * OPAQUE16_LEN); + } +#ifndef WOLFSSL_TLS13_DRAFT_18 + else if (msgType == server_hello || msgType == hello_retry_request) + return OPAQUE16_LEN; +#endif + else + return SANITY_MSG_E; } /* Writes the SupportedVersions extension into the buffer. * * data The SSL/TLS object. * output The buffer to write the extension into. + * msgType The type of the message this extension is being written into. * returns the length of data that was written. */ -static word16 TLSX_SupportedVersions_Write(void* data, byte* output) +static word16 TLSX_SupportedVersions_Write(void* data, byte* output, + byte msgType) { WOLFSSL* ssl = (WOLFSSL*)data; - ProtocolVersion pv = ssl->ctx->method->version; + ProtocolVersion pv; int i; - /* TLS v1.2 and TLS v1.3 */ - int cnt = 2; + int cnt; + + if (msgType == client_hello) { + pv = ssl->ctx->method->version; + /* TLS v1.2 and TLS v1.3 */ + cnt = 2; #ifndef NO_OLD_TLS - /* TLS v1 and TLS v1.1 */ - cnt += 2; + /* TLS v1 and TLS v1.1 */ + cnt += 2; #endif - if (!ssl->options.downgrade) - cnt = 1; + if (!ssl->options.downgrade) + cnt = 1; - *(output++) = (byte)(cnt * OPAQUE16_LEN); - for (i = 0; i < cnt; i++) { - /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */ - if (pv.minor - i == TLSv1_3_MINOR) { - /* The TLS draft major number. */ - *(output++) = TLS_DRAFT_MAJOR; - /* Version of draft supported. */ - *(output++) = TLS_DRAFT_MINOR; - continue; + *(output++) = (byte)(cnt * OPAQUE16_LEN); + for (i = 0; i < cnt; i++) { + /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */ + if (pv.minor - i == TLSv1_3_MINOR) { + /* The TLS draft major number. */ + *(output++) = TLS_DRAFT_MAJOR; + /* Version of draft supported. */ + *(output++) = TLS_DRAFT_MINOR; + continue; + } + + *(output++) = pv.major; + *(output++) = pv.minor - i; } - *(output++) = pv.major; - *(output++) = (byte)(pv.minor - i); + return (word16)(OPAQUE8_LEN + cnt * OPAQUE16_LEN); } +#ifndef WOLFSSL_TLS13_DRAFT_18 + else if (msgType == server_hello || msgType == hello_retry_request) { + output[0] = ssl->version.major; + output[1] = ssl->version.minor; - return (word16)(OPAQUE8_LEN + cnt * OPAQUE16_LEN); + return OPAQUE16_LEN; + } +#endif + else + return SANITY_MSG_E; } /* Parse the SupportedVersions extension. @@ -4570,10 +4596,11 @@ static word16 TLSX_SupportedVersions_Write(void* data, byte* output) * ssl The SSL/TLS object. * input The buffer with the extension data. * length The length of the extension data. + * msgType The type of the message this extension is being parsed from. * returns 0 on success, otherwise failure. */ static int TLSX_SupportedVersions_Parse(WOLFSSL *ssl, byte* input, - word16 length) + word16 length, byte msgType) { ProtocolVersion pv = ssl->ctx->method->version; int i; @@ -4581,22 +4608,69 @@ static int TLSX_SupportedVersions_Parse(WOLFSSL *ssl, byte* input, int len; byte major, minor; - /* Must contain a length and at least one version. */ - if (length < OPAQUE8_LEN + OPAQUE16_LEN || (length & 1) != 1) - return BUFFER_ERROR; + if (msgType == client_hello) { + /* Must contain a length and at least one version. */ + if (length < OPAQUE8_LEN + OPAQUE16_LEN || (length & 1) != 1) + return BUFFER_ERROR; - len = *input; + len = *input; - /* Protocol version array must fill rest of data. */ - if (length != OPAQUE8_LEN + len) - return BUFFER_ERROR; + /* Protocol version array must fill rest of data. */ + if (length != OPAQUE8_LEN + len) + return BUFFER_ERROR; - input++; + input++; - /* Find first match. */ - for (i = 0; i < len; i += OPAQUE16_LEN) { - major = input[i]; - minor = input[i + OPAQUE8_LEN]; + /* Find first match. */ + for (i = 0; i < len; i += OPAQUE16_LEN) { + major = input[i]; + minor = input[i + OPAQUE8_LEN]; + + /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */ + if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) { + major = SSLv3_MAJOR; + minor = TLSv1_3_MINOR; + } + + if (major != pv.major) + continue; + + /* No upgrade allowed. */ + if (ssl->version.minor > minor) + continue; + /* Check downgrade. */ + if (ssl->version.minor < minor) { + if (!ssl->options.downgrade) + continue; + +#ifdef NO_OLD_TLS + if (minor < TLSv1_2_MINOR) + continue; +#endif + /* Downgrade the version. */ + ssl->version.minor = minor; + } + + if (minor >= TLSv1_3_MINOR) { + ssl->options.tls1_3 = 1; + TLSX_Push(&ssl->extensions, TLSX_SUPPORTED_VERSIONS, ssl, + ssl->heap); +#ifndef WOLFSSL_TLS13_DRAFT_18 + TLSX_SetResponse(ssl, TLSX_SUPPORTED_VERSIONS); +#endif + } + ret = 0; + break; + } + } +#ifndef WOLFSSL_TLS13_DRAFT_18 + else if (msgType == server_hello || msgType == hello_retry_request) { + /* Must contain one version. */ + if (length != OPAQUE16_LEN) + return BUFFER_ERROR; + + major = input[0]; + minor = input[OPAQUE8_LEN]; /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */ if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) { @@ -4605,32 +4679,30 @@ static int TLSX_SupportedVersions_Parse(WOLFSSL *ssl, byte* input, } if (major != pv.major) - continue; + return VERSION_ERROR; /* No upgrade allowed. */ - if (ssl->version.minor > minor) - continue; + if (ssl->version.minor < minor) + return VERSION_ERROR; + /* Check downgrade. */ - if (ssl->version.minor < minor) { + if (ssl->version.minor > minor) { if (!ssl->options.downgrade) - continue; + return VERSION_ERROR; #ifdef NO_OLD_TLS if (minor < TLSv1_2_MINOR) - continue; + return VERSION_ERROR; #endif /* Downgrade the version. */ ssl->version.minor = minor; } - if (minor >= TLSv1_3_MINOR) { - ssl->options.tls1_3 = 1; - TLSX_Push(&ssl->extensions, TLSX_SUPPORTED_VERSIONS, input, - ssl->heap); - } ret = 0; - break; } +#endif + else + return SANITY_MSG_E; return ret; } @@ -4657,9 +4729,9 @@ static int TLSX_SetSupportedVersions(TLSX** extensions, const void* data, #else -#define SV_GET_SIZE(a) 0 -#define SV_WRITE(a, b) 0 -#define SV_PARSE(a, b, c) 0 +#define SV_GET_SIZE(a, b) 0 +#define SV_WRITE(a, b, c) 0 +#define SV_PARSE(a, b, c, d) 0 #endif /* WOLFSSL_TLS13 */ @@ -7195,7 +7267,7 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType) #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: - length += SV_GET_SIZE(extension->data); + length += SV_GET_SIZE(extension->data, msgType); break; case TLSX_COOKIE: @@ -7342,7 +7414,7 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: WOLFSSL_MSG("Supported Versions extension to write"); - offset += SV_WRITE(extension->data, output + offset); + offset += SV_WRITE(extension->data, output + offset, msgType); break; case TLSX_COOKIE: @@ -8150,6 +8222,10 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType) #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) { XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); +#ifndef WOLFSSL_TLS13_DRAFT_18 + TURN_OFF(semaphore, + TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); +#endif TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); @@ -8166,6 +8242,9 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType) #ifdef WOLFSSL_TLS13 case hello_retry_request: XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); +#ifndef WOLFSSL_TLS13_DRAFT_18 + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); +#endif TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE)); break; @@ -8173,6 +8252,7 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType) #ifdef WOLFSSL_TLS13 case encrypted_extensions: TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) @@ -8238,6 +8318,10 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType) #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) { XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); +#ifndef WOLFSSL_TLS13_DRAFT_18 + TURN_OFF(semaphore, + TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); +#endif TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); @@ -8254,12 +8338,16 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType) #ifdef WOLFSSL_TLS13 case hello_retry_request: XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); +#ifndef WOLFSSL_TLS13_DRAFT_18 + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); +#endif TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); break; #endif #ifdef WOLFSSL_TLS13 case encrypted_extensions: TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) @@ -8519,10 +8607,16 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, WOLFSSL_MSG("Supported Versions extension received"); if (IsAtLeastTLSv1_3(ssl->version) && - msgType != client_hello) { +#ifdef WOLFSSL_TLS13_DRAFT_18 + msgType != client_hello +#else + msgType != client_hello && msgType != server_hello && + msgType != hello_retry_request +#endif + ) { return EXT_NOT_ALLOWED; } - ret = SV_PARSE(ssl, input + offset, size); + ret = SV_PARSE(ssl, input + offset, size, msgType); break; case TLSX_COOKIE: diff --git a/src/tls13.c b/src/tls13.c index cd07c9d4d..40422f8f3 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -1367,7 +1367,11 @@ static void AddTls13RecordHeader(byte* output, word32 length, byte type, rl = (RecordLayerHeader*)output; rl->type = type; rl->pvMajor = ssl->version.major; +#ifdef WOLFSSL_TLS13_DRAFT_18 rl->pvMinor = TLSv1_MINOR; +#else + rl->pvMinor = TLSv1_2_MINOR; +#endif c16toa((word16)length, rl->length); } @@ -2263,9 +2267,17 @@ int SendTls13ClientHello(WOLFSSL* ssl) return SUITES_ERROR; } - /* Version | Random | Session Id | Cipher Suites | Compression | Ext */ + /* Version | Random | Session Id | Cipher Suites | Compression */ length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->suites->suiteSz + SUITE_LEN + COMP_LEN + ENUM_LEN; +#ifndef WOLFSSL_TLS13_DRAFT_18 + #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + length += ID_LEN; + #else + if (ssl->session.sessionIDSz > 0) + length += ssl->session.sessionIDSz; + #endif +#endif /* Auto populate extensions supported unless user defined. */ if ((ret = TLSX_PopulateExtensions(ssl, 0)) != 0) @@ -2319,8 +2331,25 @@ int SendTls13ClientHello(WOLFSSL* ssl) XMEMCPY(output + idx, ssl->arrays->clientRandom, RAN_LEN); idx += RAN_LEN; +#ifdef WOLFSSL_TLS13_DRAFT_18 /* TLS v1.3 does not use session id - 0 length. */ output[idx++] = 0; +#else + if (ssl->session.sessionIDSz > 0) { + output[idx++] = ID_LEN; + XMEMCPY(output + idx, ssl->session.sessionID, ssl->session.sessionIDSz); + idx += ID_LEN; + } + else { + #ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT + output[idx++] = ID_LEN; + XMEMCPY(output + idx, ssl->arrays->clientRandom, ID_LEN); + idx += ID_LEN; + #else + output[idx++] = 0; + #endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */ + } +#endif /* WOLFSSL_TLS13_DRAFT_18 */ /* Cipher suites */ c16toa(ssl->suites->suiteSz, output + idx); @@ -2477,6 +2506,7 @@ static int RestartHandshakeHash(WOLFSSL* ssl) } #endif +#ifdef WOLFSSL_TLS13_DRAFT_18 /* Parse and handle a HelloRetryRequest message. * Only a client will receive this message. * @@ -2515,16 +2545,6 @@ static int DoTls13HelloRetryRequest(WOLFSSL* ssl, const byte* input, if (ret != 0) return ret; -#ifndef WOLFSSL_TLS13_DRAFT_18 - /* Set the cipher suite from the message. */ - ssl->options.cipherSuite0 = input[i++]; - ssl->options.cipherSuite = input[i++]; - - ret = SetCipherSpecs(ssl); - if (ret != 0) - return ret; -#endif - /* Length of extension data. */ ato16(&input[i], &totalExtSz); i += OPAQUE16_LEN; @@ -2547,14 +2567,24 @@ static int DoTls13HelloRetryRequest(WOLFSSL* ssl, const byte* input, ssl->options.tls1_3 = 1; ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST; -#ifndef WOLFSSL_TLS13_DRAFT_18 - ret = RestartHandshakeHash(ssl); -#endif - WOLFSSL_LEAVE("DoTls13HelloRetryRequest", ret); return ret; } +#endif + + +#ifndef WOLFSSL_TLS13_DRAFT_18 +/* The value in the random field of a ServerHello to indicate + * HelloRetryRequest. + */ +static byte helloRetryRequestRandom[] = { + 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, + 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, + 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, + 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C +}; +#endif /* Handle the ServerHello message from the server. * Only a client will receive this message. @@ -2573,11 +2603,16 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 i = *inOutIdx; word32 begin = i; int ret; +#ifndef WOLFSSL_TLS13_DRAFT_18 + byte sessIdSz; + byte b; +#endif word16 totalExtSz; #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TLSX* ext; PreSharedKey* psk = NULL; #endif + byte extMsgType = server_hello; WOLFSSL_ENTER("DoTls13ServerHello"); @@ -2593,6 +2628,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* Protocol version */ XMEMCPY(&pv, input + i, OPAQUE16_LEN); i += OPAQUE16_LEN; +#ifdef WOLFSSL_TLS13_DRAFT_18 ret = CheckVersion(ssl, pv); if (ret != 0) return ret; @@ -2605,19 +2641,77 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, WOLFSSL_MSG("CLient using higher version, fatal error"); return VERSION_ERROR; } +#else + if (pv.major != ssl->version.major || pv.minor != TLSv1_2_MINOR) + return VERSION_ERROR; +#endif - /* Random, cipher suite and extensions length check. */ - if ((i - begin) + RAN_LEN + OPAQUE16_LEN + OPAQUE16_LEN > helloSz) +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* Random length check */ + if ((i - begin) + RAN_LEN > helloSz) return BUFFER_ERROR; +#else + /* Random and session id length check */ + if ((i - begin) + RAN_LEN + ENUM_LEN > helloSz) + return BUFFER_ERROR; + + if (XMEMCMP(input + i, helloRetryRequestRandom, RAN_LEN) == 0) + extMsgType = hello_retry_request; +#endif /* Server random - keep for debugging. */ XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN); i += RAN_LEN; +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Session id */ + 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 */ + i += sessIdSz; +#endif /* WOLFSSL_TLS13_DRAFT_18 */ + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* Ciphersuite and extensions length 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) + return BUFFER_ERROR; +#endif + /* Set the cipher suite from the message. */ ssl->options.cipherSuite0 = input[i++]; ssl->options.cipherSuite = input[i++]; +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Compression */ + b = input[i++]; + if (b != 0) { + WOLFSSL_MSG("Must be no compression types in list"); + return INVALID_PARAMETER; + } +#endif + /* Get extension length and length check. */ ato16(&input[i], &totalExtSz); i += OPAQUE16_LEN; @@ -2625,7 +2719,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return BUFFER_ERROR; /* Parse and handle extensions. */ - ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, server_hello, NULL); + ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, extMsgType, NULL); if (ret != 0) return ret; @@ -2649,21 +2743,37 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return ret; #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) - ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); - if (ext != NULL) - psk = (PreSharedKey*)ext->data; - while (psk != NULL && !psk->chosen) - psk = psk->next; - if (psk == NULL) { - ssl->options.resuming = 0; - ssl->arrays->psk_keySz = 0; - XMEMSET(ssl->arrays->psk_key, 0, MAX_PSK_KEY_LEN); +#ifndef WOLFSSL_TLS13_DRAFT_18 + if (extMsgType == server_hello) +#endif + { + ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (ext != NULL) + psk = (PreSharedKey*)ext->data; + while (psk != NULL && !psk->chosen) + psk = psk->next; + if (psk == NULL) { + ssl->options.resuming = 0; + ssl->arrays->psk_keySz = 0; + XMEMSET(ssl->arrays->psk_key, 0, MAX_PSK_KEY_LEN); + } + else if ((ret = SetupPskKey(ssl, psk)) != 0) + return ret; } - else if ((ret = SetupPskKey(ssl, psk)) != 0) - return ret; #endif +#ifdef WOLFSSL_TLS13_DRAFT_18 ssl->keys.encryptionOn = 1; +#else + if (extMsgType == server_hello) + ssl->keys.encryptionOn = 1; + else { + ssl->options.tls1_3 = 1; + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST; + + ret = RestartHandshakeHash(ssl); + } +#endif WOLFSSL_LEAVE("DoTls13ServerHello", ret); @@ -3166,15 +3276,30 @@ static int CheckCookie(WOLFSSL* ssl, byte* cookie, byte cookieSz) /* Length of the KeyShare Extension */ #define HRR_KEY_SHARE_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) +/* Length of the Supported Vresions Extension */ +#define HRR_VERSIONS_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) /* Length of the Cookie Extension excluding cookie data */ #define HRR_COOKIE_HDR_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) +#ifdef WOLFSSL_TLS13_DRAFT_18 /* PV | CipherSuite | Ext Len */ #define HRR_BODY_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) /* HH | PV | CipherSuite | Ext Len | Key Share | Cookie */ -#define MAX_HRR_SZ (HANDSHAKE_HEADER_SZ + \ - HRR_BODY_SZ + \ - HRR_KEY_SHARE_SZ + \ +#define MAX_HRR_SZ (HANDSHAKE_HEADER_SZ + \ + HRR_BODY_SZ + \ + HRR_KEY_SHARE_SZ + \ HRR_COOKIE_HDR_SZ) +#else +/* PV | Random | Session Id | CipherSuite | Compression | Ext Len */ +#define HRR_BODY_SZ (VERSION_SZ + RAN_LEN + ENUM_LEN + ID_LEN + \ + SUITE_LEN + COMP_LEN + OPAQUE16_LEN) +/* HH | PV | CipherSuite | Ext Len | Key Share | Supported Version | Cookie */ +#define MAX_HRR_SZ (HANDSHAKE_HEADER_SZ + \ + HRR_BODY_SZ + \ + HRR_KEY_SHARE_SZ + \ + HRR_VERSIONS_SZ + \ + HRR_COOKIE_HDR_SZ) +#endif + /* Restart the Hanshake hash from the cookie value. * * ssl SSL/TLS object. @@ -3211,11 +3336,18 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie) return ret; /* Reconstruct the HelloRetryMessage for handshake hash. */ +#ifdef WOLFSSL_TLS13_DRAFT_18 length = HRR_BODY_SZ + HRR_COOKIE_HDR_SZ + cookie->len; +#else + length = HRR_BODY_SZ - ID_LEN + ssl->session.sessionIDSz + + HRR_COOKIE_HDR_SZ + cookie->len; + length += HRR_VERSIONS_SZ; +#endif if (cookieDataSz > hashSz + OPAQUE16_LEN) { keyShareExt = 1; length += HRR_KEY_SHARE_SZ; } +#ifdef WOLFSSL_TLS13_DRAFT_18 AddTls13HandShakeHeader(hrr, length, 0, 0, hello_retry_request, ssl); idx += hashSz; @@ -3238,6 +3370,39 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie) length -= HRR_BODY_SZ; c16toa(length, hrr + hrrIdx); hrrIdx += 2; +#else + AddTls13HandShakeHeader(hrr, length, 0, 0, server_hello, ssl); + + idx += hashSz; + hrrIdx = HANDSHAKE_HEADER_SZ; + + /* The negotiated protocol version. */ + hrr[hrrIdx++] = ssl->version.major; + hrr[hrrIdx++] = TLSv1_2_MINOR; + + /* HelloRetryRequest message has fixed value for random. */ + XMEMCPY(hrr + hrrIdx, helloRetryRequestRandom, RAN_LEN); + hrrIdx += RAN_LEN; + + hrr[hrrIdx++] = ssl->session.sessionIDSz; + if (ssl->session.sessionIDSz > 0) { + XMEMCPY(hrr + hrrIdx, ssl->session.sessionID, ssl->session.sessionIDSz); + hrrIdx += ssl->session.sessionIDSz; + } + + /* Cipher Suite */ + hrr[hrrIdx++] = cookieData[idx++]; + hrr[hrrIdx++] = cookieData[idx++]; + + /* Compression not supported in TLS v1.3. */ + hrr[hrrIdx++] = 0; + + /* Extensions' length */ + length -= HRR_BODY_SZ - ID_LEN + ssl->session.sessionIDSz; + c16toa(length, hrr + hrrIdx); + hrrIdx += 2; + +#endif /* Optional KeyShare Extension */ if (keyShareExt) { c16toa(TLSX_KEY_SHARE, hrr + hrrIdx); @@ -3247,6 +3412,14 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie) hrr[hrrIdx++] = cookieData[idx++]; hrr[hrrIdx++] = cookieData[idx++]; } +#ifndef WOLFSSL_TLS13_DRAFT_18 + c16toa(TLSX_SUPPORTED_VERSIONS, hrr + hrrIdx); + hrrIdx += 2; + c16toa(OPAQUE16_LEN, hrr + hrrIdx); + hrrIdx += 2; + hrr[hrrIdx++] = ssl->version.major; + hrr[hrrIdx++] = ssl->version.minor; +#endif /* Mandatory Cookie Extension */ c16toa(TLSX_COOKIE, hrr + hrrIdx); hrrIdx += 2; @@ -3322,12 +3495,23 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, WOLFSSL_BUFFER(ssl->arrays->clientRandom, RAN_LEN); #endif +#ifdef WOLFSSL_TLS13_DRAFT_18 /* Session id - empty in TLS v1.3 */ sessIdSz = input[i++]; if (sessIdSz > 0) { WOLFSSL_MSG("Client sent session id - not supported"); return BUFFER_ERROR; } +#else + sessIdSz = input[i++]; + if (sessIdSz != ID_LEN && sessIdSz != 0) + return INVALID_PARAMETER; + ssl->session.sessionIDSz = sessIdSz; + if (sessIdSz == ID_LEN) { + XMEMCPY(ssl->session.sessionID, input + i, sessIdSz); + i += ID_LEN; + } +#endif /* Cipher suites */ if ((i - begin) + OPAQUE16_LEN > helloSz) @@ -3457,6 +3641,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return ret; } +#ifdef WOLFSSL_TLS13_DRAFT_18 /* Send the HelloRetryRequest message to indicate the negotiated protocol * version and security parameters the server is willing to use. * Only a server will send this message. @@ -3475,24 +3660,14 @@ int SendTls13HelloRetryRequest(WOLFSSL* ssl) WOLFSSL_ENTER("SendTls13HelloRetryRequest"); -#ifndef WOLFSSL_TLS13_DRAFT_18 - if ((ret = RestartHandshakeHash(ssl)) < 0) - return ret; -#endif - /* Get the length of the extensions that will be written. */ len = TLSX_GetResponseSize(ssl, hello_retry_request); /* There must be extensions sent to indicate what client needs to do. */ if (len == 0) return MISSING_HANDSHAKE_DATA; -#ifndef WOLFSSL_TLS13_DRAFT_18 - /* Protocol version + CipherSuite + Extensions */ - length = OPAQUE16_LEN + OPAQUE16_LEN + len; -#else /* Protocol version + Extensions */ length = OPAQUE16_LEN + len; -#endif sendSz = idx + length; /* Check buffers are big enough and grow if needed. */ @@ -3516,12 +3691,6 @@ int SendTls13HelloRetryRequest(WOLFSSL* ssl) output[idx++] = TLS_DRAFT_MAJOR; output[idx++] = TLS_DRAFT_MINOR; -#ifndef WOLFSSL_TLS13_DRAFT_18 - /* Chosen cipher suite */ - output[idx++] = ssl->options.cipherSuite0; - output[idx++] = ssl->options.cipherSuite; -#endif - /* Add TLS extensions. */ TLSX_WriteResponse(ssl, output + idx, hello_retry_request); idx += len; @@ -3534,7 +3703,6 @@ int SendTls13HelloRetryRequest(WOLFSSL* ssl) ssl->heap); } #endif - if ((ret = HashOutput(ssl, output, idx, 0)) != 0) return ret; @@ -3547,6 +3715,7 @@ int SendTls13HelloRetryRequest(WOLFSSL* ssl) return ret; } +#endif /* WOLFSSL_TLS13_DRAFT_18 */ /* Send TLS v1.3 ServerHello message to client. * Only a server will send this message. @@ -3554,7 +3723,10 @@ int SendTls13HelloRetryRequest(WOLFSSL* ssl) * ssl The SSL/TLS object. * returns 0 on success, otherwise failure. */ -static int SendTls13ServerHello(WOLFSSL* ssl) +#ifdef WOLFSSL_TLS13_DRAFT_18 +static +#endif +int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) { byte* output; word32 length; @@ -3564,9 +3736,24 @@ static int SendTls13ServerHello(WOLFSSL* ssl) WOLFSSL_ENTER("SendTls13ServerHello"); +#ifndef WOLFSSL_TLS13_DRAFT_18 + if (extMsgType == hello_retry_request) { + if ((ret = RestartHandshakeHash(ssl)) < 0) + return ret; + } +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 /* Protocol version, server random, cipher suite and extensions. */ length = VERSION_SZ + RAN_LEN + SUITE_LEN + TLSX_GetResponseSize(ssl, server_hello); +#else + /* Protocol version, server random, session id, cipher suite, compression + * and extensions. + */ + length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->session.sessionIDSz + + SUITE_LEN + COMP_LEN + TLSX_GetResponseSize(ssl, extMsgType); +#endif sendSz = idx + length; /* Check buffers are big enough and grow if needed. */ @@ -3580,6 +3767,7 @@ static int SendTls13ServerHello(WOLFSSL* ssl) /* Put the record and handshake headers on. */ AddTls13Headers(output, length, server_hello, ssl); +#ifdef WOLFSSL_TLS13_DRAFT_18 /* TODO: [TLS13] Replace existing code with code in comment. * Use the TLS v1.3 draft version for now. * @@ -3590,10 +3778,23 @@ static int SendTls13ServerHello(WOLFSSL* ssl) /* The negotiated protocol version. */ output[idx++] = TLS_DRAFT_MAJOR; output[idx++] = TLS_DRAFT_MINOR; +#else + /* The protocol version must be TLS v1.2 for middleboxes. */ + output[idx++] = ssl->version.major; + output[idx++] = TLSv1_2_MINOR; +#endif - /* Generate server random. */ - if ((ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN)) != 0) - return ret; + if (extMsgType == server_hello) { + /* Generate server random. */ + if ((ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN)) != 0) + return ret; + } +#ifndef WOLFSSL_TLS13_DRAFT_18 + else { + /* HelloRetryRequest message has fixed value for random. */ + XMEMCPY(output + idx, helloRetryRequestRandom, RAN_LEN); + } +#endif /* Store in SSL for debugging. */ XMEMCPY(ssl->arrays->serverRandom, output + idx, RAN_LEN); idx += RAN_LEN; @@ -3603,12 +3804,25 @@ static int SendTls13ServerHello(WOLFSSL* ssl) WOLFSSL_BUFFER(ssl->arrays->serverRandom, RAN_LEN); #endif +#ifndef WOLFSSL_TLS13_DRAFT_18 + output[idx++] = ssl->session.sessionIDSz; + if (ssl->session.sessionIDSz > 0) { + XMEMCPY(output + idx, ssl->session.sessionID, ssl->session.sessionIDSz); + idx += ssl->session.sessionIDSz; + } +#endif + /* Chosen cipher suite */ output[idx++] = ssl->options.cipherSuite0; output[idx++] = ssl->options.cipherSuite; +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Compression not supported in TLS v1.3. */ + output[idx++] = 0; +#endif + /* Extensions */ - TLSX_WriteResponse(ssl, output + idx, server_hello); + TLSX_WriteResponse(ssl, output + idx, extMsgType); ssl->buffers.outputBuffer.length += sendSz; @@ -3624,7 +3838,12 @@ static int SendTls13ServerHello(WOLFSSL* ssl) } #endif +#ifdef WOLFSSL_TLS13_DRAFT_18 ssl->options.serverState = SERVER_HELLO_COMPLETE; +#else + if (extMsgType == server_hello) + ssl->options.serverState = SERVER_HELLO_COMPLETE; +#endif if (!ssl->options.groupMessages) ret = SendBuffered(ssl); @@ -5647,8 +5866,6 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, if ((*inOutIdx - begin) + 1 > size) return BUFFER_ERROR; nonceLength = input[*inOutIdx]; - if (nonceLength == 0) - return INVALID_PARAMETER; if (nonceLength > MAX_TICKET_NONCE_SZ) { WOLFSSL_MSG("Nonce length not supported"); return INVALID_PARAMETER; @@ -5687,7 +5904,8 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, #endif #ifndef WOLFSSL_TLS13_DRAFT_18 ssl->session.ticketNonce.len = nonceLength; - XMEMCPY(&ssl->session.ticketNonce.data, nonce, nonceLength); + if (nonceLength > 0) + XMEMCPY(&ssl->session.ticketNonce.data, nonce, nonceLength); #endif if ((*inOutIdx - begin) + EXTS_SZ > size) @@ -5967,11 +6185,19 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) #ifndef NO_WOLFSSL_CLIENT case server_hello: +#ifdef WOLFSSL_TLS13_DRAFT_18 if (ssl->msgsReceived.got_server_hello) { WOLFSSL_MSG("Duplicate ServerHello received"); return DUPLICATE_MSG_E; } ssl->msgsReceived.got_server_hello = 1; +#else + if (ssl->msgsReceived.got_server_hello == 2) { + WOLFSSL_MSG("Duplicate ServerHello received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_server_hello++; +#endif break; #endif @@ -6171,10 +6397,12 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, switch (type) { #ifndef NO_WOLFSSL_CLIENT +#ifdef WOLFSSL_TLS13_DRAFT_18 case hello_retry_request: WOLFSSL_MSG("processing hello rety request"); ret = DoTls13HelloRetryRequest(ssl, input, inOutIdx, size); break; +#endif case server_hello: WOLFSSL_MSG("processing server hello"); @@ -6498,6 +6726,14 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT"); #ifdef WOLFSSL_EARLY_DATA if (ssl->earlyData) { + #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ + defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + #endif ssl->options.handShakeState = CLIENT_HELLO_COMPLETE; return WOLFSSL_SUCCESS; } @@ -6538,6 +6774,16 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { ssl->options.serverState = NULL_STATE; + #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ + defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + if (!ssl->options.sentChangeCipher) { + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + } + #endif /* Try again with different security parameters. */ if ((ssl->error = SendTls13ClientHello(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); @@ -6589,6 +6835,16 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) FALL_THROUGH; case FIRST_REPLY_FIRST: + #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ + defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + if (!ssl->options.sentChangeCipher) { + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + } + #endif #ifndef NO_CERTS if (!ssl->options.resuming && ssl->options.sendVerify) { ssl->error = SendTls13Certificate(ssl); @@ -7012,32 +7268,53 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) case ACCEPT_BEGIN : /* get response */ - while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) + while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { if ((ssl->error = ProcessReply(ssl)) < 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } + } ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE; WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE"); FALL_THROUGH; case ACCEPT_CLIENT_HELLO_DONE : +#ifdef WOLFSSL_TLS13_DRAFT_18 if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { if ((ssl->error = SendTls13HelloRetryRequest(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } } +#else + if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { + if ((ssl->error = SendTls13ServerHello(ssl, + hello_retry_request)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + #ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + #endif + } +#endif ssl->options.acceptState = ACCEPT_HELLO_RETRY_REQUEST_DONE; WOLFSSL_MSG("accept state ACCEPT_HELLO_RETRY_REQUEST_DONE"); FALL_THROUGH; case ACCEPT_HELLO_RETRY_REQUEST_DONE : if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { - if ( (ssl->error = ProcessReply(ssl)) < 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; + ssl->options.clientState = NULL_STATE; + while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + if ((ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } } } ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE; @@ -7045,10 +7322,20 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) FALL_THROUGH; case ACCEPT_FIRST_REPLY_DONE : - if ((ssl->error = SendTls13ServerHello(ssl)) != 0) { + if ((ssl->error = SendTls13ServerHello(ssl, server_hello)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } + #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ + defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + if (!ssl->options.sentChangeCipher) { + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + } + #endif ssl->options.acceptState = SERVER_HELLO_SENT; WOLFSSL_MSG("accept state SERVER_HELLO_SENT"); FALL_THROUGH; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 9c77120a1..f0d35a44c 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -955,7 +955,7 @@ enum Misc { #ifdef WOLFSSL_TLS13_DRAFT_18 TLS_DRAFT_MINOR = 0x12, /* Minor version number of TLS draft */ #else - TLS_DRAFT_MINOR = 0x15, /* Minor version number of TLS draft */ + TLS_DRAFT_MINOR = 0x16, /* Minor version number of TLS draft */ #endif OLD_HELLO_ID = 0x01, /* SSLv2 Client Hello Indicator */ INVALID_BYTE = 0xff, /* Used to initialize cipher specs values */ @@ -2933,6 +2933,9 @@ typedef struct Options { #ifdef WOLFSSL_ALT_CERT_CHAINS word16 usingAltCertChain:1;/* Alternate cert chain was used */ #endif +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + word16 sentChangeCipher:1; /* Change Cipher Spec sent */ +#endif /* need full byte values for this section */ byte processReply; /* nonblocking resume */ @@ -2967,7 +2970,6 @@ typedef struct Options { #ifdef WOLFSSL_EARLY_DATA word32 maxEarlyDataSz; #endif - } Options; typedef struct Arrays { @@ -3179,7 +3181,7 @@ typedef struct DtlsMsg { typedef struct MsgsReceived { word16 got_hello_request:1; word16 got_client_hello:2; - word16 got_server_hello:1; + word16 got_server_hello:2; word16 got_hello_verify_request:1; word16 got_session_ticket:1; word16 got_end_of_early_data:1; @@ -3654,7 +3656,11 @@ WOLFSSL_LOCAL int SendTicket(WOLFSSL*); WOLFSSL_LOCAL int DoClientTicket(WOLFSSL*, const byte*, word32); WOLFSSL_LOCAL int SendData(WOLFSSL*, const void*, int); #ifdef WOLFSSL_TLS13 +#ifdef WOLFSSL_TLS13_DRAFT_18 WOLFSSL_LOCAL int SendTls13HelloRetryRequest(WOLFSSL*); +#else +WOLFSSL_LOCAL int SendTls13ServerHello(WOLFSSL*, byte); +#endif #endif WOLFSSL_LOCAL int SendCertificate(WOLFSSL*); WOLFSSL_LOCAL int SendCertificateRequest(WOLFSSL*);