From cb8e28446466c0702d6dea28a3b6158c0fdd54a3 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 15 Nov 2017 14:34:25 +1000 Subject: [PATCH] Update code to support Draft 21 of TLS v1.3 --- src/internal.c | 11 +++++ src/ssl.c | 8 +++ src/tls.c | 4 +- src/tls13.c | 118 ++++++++++++++++++++++++++++++++++++++++++++- wolfssl/internal.h | 18 ++++++- 5 files changed, 156 insertions(+), 3 deletions(-) diff --git a/src/internal.c b/src/internal.c index 540376aa9..622fa58ed 100644 --- a/src/internal.c +++ b/src/internal.c @@ -23264,6 +23264,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef WOLFSSL_TLS13 word32 ageAdd; /* Obfuscation of age */ byte namedGroup; /* Named group used */ + #ifndef WOLFSSL_TLS13_DRAFT_18 + TicketNonce ticketNonce; /* Ticket nonce */ + #endif #ifdef WOLFSSL_EARLY_DATA word32 maxEarlyDataSz; /* Max size of early data */ #endif @@ -23319,6 +23322,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, it.timestamp = TimeNowInMilliseconds(); /* Resumption master secret. */ XMEMCPY(it.msecret, ssl->session.masterSecret, SECRET_LEN); + #ifndef WOLFSSL_TLS13_DRAFT_18 + XMEMCPY(&it.ticketNonce, &ssl->session.ticketNonce, + sizeof(TicketNonce)); + #endif #endif } @@ -23431,6 +23438,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif /* Resumption master secret. */ XMEMCPY(ssl->session.masterSecret, it->msecret, SECRET_LEN); + #ifndef WOLFSSL_TLS13_DRAFT_18 + XMEMCPY(&ssl->session.ticketNonce, &it->ticketNonce, + sizeof(TicketNonce)); + #endif ssl->session.namedGroup = it->namedGroup; #endif } diff --git a/src/ssl.c b/src/ssl.c index 72e90abcd..f061cf3e6 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -9787,6 +9787,10 @@ static int GetDeepCopySession(WOLFSSL* ssl, WOLFSSL_SESSION* copyFrom) copyInto->namedGroup = copyFrom->namedGroup; copyInto->ticketSeen = copyFrom->ticketSeen; copyInto->ticketAdd = copyFrom->ticketAdd; +#ifndef WOLFSSL_TLS13_DRAFT_18 + XMEMCPY(©Into->ticketNonce, ©From->ticketNonce, + sizeof(TicketNonce)); +#endif #ifdef WOLFSSL_EARLY_DATA copyInto->maxEarlyDataSz = copyFrom->maxEarlyDataSz; #endif @@ -10019,6 +10023,10 @@ int AddSession(WOLFSSL* ssl) session->namedGroup = ssl->session.namedGroup; session->ticketSeen = ssl->session.ticketSeen; session->ticketAdd = ssl->session.ticketAdd; +#ifndef WOLFSSL_TLS13_DRAFT_18 + XMEMCPY(&session->ticketNonce, &ssl->session.ticketNonce, + sizeof(TicketNonce)); +#endif #ifdef WOLFSSL_EARLY_DATA session->maxEarlyDataSz = ssl->session.maxEarlyDataSz; #endif diff --git a/src/tls.c b/src/tls.c index e8495bd41..c543f2481 100644 --- a/src/tls.c +++ b/src/tls.c @@ -3083,7 +3083,7 @@ static int TLSX_SupportedCurve_Parse(WOLFSSL* ssl, byte* input, word16 length, word16 name; int ret; - if(!isRequest) + if(!isRequest && !IsAtLeastTLSv1_3(ssl->version)) return BUFFER_ERROR; /* servers doesn't send this extension. */ if (OPAQUE16_LEN > length || length % OPAQUE16_LEN) @@ -8157,6 +8157,7 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType) #endif #ifdef WOLFSSL_TLS13 case encrypted_extensions: + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) @@ -8243,6 +8244,7 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType) #endif #ifdef WOLFSSL_TLS13 case encrypted_extensions: + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) diff --git a/src/tls13.c b/src/tls13.c index 408528e59..47fa538a9 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -169,6 +169,7 @@ static int Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen, * TLS v1.3 defines this function. * * okm The generated pseudorandom key - output key material. + * okmLen The length of generated pseudorandom key - output key material. * prk The salt - pseudo-random key. * prkLen The length of the salt - pseudo-random key. * protocol The TLS protocol label. @@ -808,6 +809,62 @@ static int DeriveMasterSecret(WOLFSSL* ssl) #endif } +#ifndef WOLFSSL_TLS13_DRAFT_18 +#if defined(HAVE_SESSION_TICKET) +/* Length of the resumption label. */ +#define RESUMPTION_LABEL_SZ 10 +/* Resumption label for generating PSK assocated with the ticket. */ +static const byte resumptionLabel[RESUMPTION_LABEL_SZ+1] = "resumption"; +/* Derive the PSK assocated with the ticket. + * + * ssl The SSL/TLS object. + * nonce The nonce to derive with. + * nonceLen The length of the nonce to derive with. + * secret The derived secret. + * returns 0 on success, otherwise failure. + */ +static int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, + byte* secret) +{ + int digestAlg; + /* Only one protocol version defined at this time. */ + const byte* protocol = tls13ProtocolLabel; + word32 protocolLen = TLS13_PROTOCOL_LABEL_SZ; + + WOLFSSL_MSG("Derive Resumption PSK"); + + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + digestAlg = WC_SHA256; + break; + #endif + + #ifdef WOLFSSL_SHA384 + case sha384_mac: + digestAlg = WC_SHA256; + break; + #endif + + #ifdef WOLFSSL_TLS13_TLS13_SHA512 + case sha512_mac: + digestAlg = WC_SHA256; + break; + #endif + + default: + return BAD_FUNC_ARG; + } + + return HKDF_Expand_Label(secret, ssl->specs.hash_size, + ssl->session.masterSecret, ssl->specs.hash_size, + protocol, protocolLen, resumptionLabel, + RESUMPTION_LABEL_SZ, nonce, nonceLen, digestAlg); +} +#endif /* HAVE_SESSION_TICKET */ +#endif /* WOLFSSL_TLS13_DRAFT_18 */ + + /* Calculate the HMAC of message data to this point. * * ssl The SSL/TLS object. @@ -2055,8 +2112,15 @@ static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk) #endif /* Resumption PSK is master secret. */ ssl->arrays->psk_keySz = ssl->specs.hash_size; +#ifdef WOLFSSL_TLS13_DRAFT_18 XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, ssl->arrays->psk_keySz); +#else + if ((ret = DeriveResumptionPSK(ssl, ssl->session.ticketNonce.data, + ssl->session.ticketNonce.len, ssl->arrays->psk_key)) != 0) { + return ret; + } +#endif } #endif #ifndef NO_PSK @@ -2916,8 +2980,15 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, /* Resumption PSK is resumption master secret. */ ssl->arrays->psk_keySz = ssl->specs.hash_size; +#ifdef WOLFSSL_TLS13_DRAFT_18 XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, - ssl->specs.hash_size); + ssl->arrays->psk_keySz); +#else + if ((ret = DeriveResumptionPSK(ssl, ssl->session.ticketNonce.data, + ssl->session.ticketNonce.len, ssl->arrays->psk_key)) != 0) { + return ret; + } +#endif /* Derive the early secret using the PSK. */ ret = DeriveEarlySecret(ssl); @@ -5550,6 +5621,10 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, word32 ageAdd; word16 length; word32 now; +#ifndef WOLFSSL_TLS13_DRAFT_18 + const byte* nonce; + byte nonceLength; +#endif WOLFSSL_ENTER("DoTls13NewSessionTicket"); @@ -5567,6 +5642,24 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, ato32(input + *inOutIdx, &ageAdd); *inOutIdx += SESSION_ADD_SZ; +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Ticket nonce. */ + 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; + } + *inOutIdx += 1; + if ((*inOutIdx - begin) + nonceLength > size) + return BUFFER_ERROR; + nonce = input + *inOutIdx; + *inOutIdx += 1; +#endif + /* Ticket length. */ if ((*inOutIdx - begin) + LENGTH_SZ > size) return BUFFER_ERROR; @@ -5592,6 +5685,10 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, #ifdef WOLFSSL_EARLY_DATA ssl->session.maxEarlyDataSz = ssl->options.maxEarlyDataSz; #endif +#ifndef WOLFSSL_TLS13_DRAFT_18 + ssl->session.ticketNonce.len = nonceLength; + XMEMCPY(&ssl->session.ticketNonce.data, nonce, nonceLength); +#endif if ((*inOutIdx - begin) + EXTS_SZ > size) return BUFFER_ERROR; @@ -5751,6 +5848,16 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl) } #endif +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Start ticket nonce at 0 and go up to 255. */ + if (ssl->session.ticketNonce.len == 0) { + ssl->session.ticketNonce.len = DEF_TICKET_NONCE_SZ; + ssl->session.ticketNonce.data[0] = 0; + } + else + ssl->session.ticketNonce.data[0]++; +#endif + if (!ssl->options.noTicketTls13) { if ((ret = CreateTicket(ssl)) != 0) return ret; @@ -5768,6 +5875,10 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl) /* Lifetime | Age Add | Ticket | Extensions */ length = SESSION_HINT_SZ + SESSION_ADD_SZ + LENGTH_SZ + ssl->session.ticketLen + extSz; +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Nonce */ + length += TICKET_NONCE_LEN_SZ + DEF_TICKET_NONCE_SZ; +#endif sendSz = idx + length + MAX_MSG_EXTRA; /* Check buffers are big enough and grow if needed. */ @@ -5788,6 +5899,11 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl) c32toa(ssl->session.ticketAdd, output + idx); idx += SESSION_ADD_SZ; +#ifndef WOLFSSL_TLS13_DRAFT_18 + output[idx++] = ssl->session.ticketNonce.len; + output[idx++] = ssl->session.ticketNonce.data[0]; +#endif + /* length */ c16toa(ssl->session.ticketLen, output + idx); idx += LENGTH_SZ; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 4dc29fe2c..a62bf2c22 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 = 0x14, /* Minor version number of TLS draft */ + TLS_DRAFT_MINOR = 0x15, /* Minor version number of TLS draft */ #endif OLD_HELLO_ID = 0x01, /* SSLv2 Client Hello Indicator */ INVALID_BYTE = 0xff, /* Used to initialize cipher specs values */ @@ -1003,6 +1003,9 @@ enum Misc { NAMED_DH_MASK = 0x100, /* Named group mask for DH parameters */ SESSION_HINT_SZ = 4, /* session timeout hint */ SESSION_ADD_SZ = 4, /* session age add */ + TICKET_NONCE_LEN_SZ = 1, /* Ticket nonce length size */ + DEF_TICKET_NONCE_SZ = 1, /* Default ticket nonce size */ + MAX_TICKET_NONCE_SZ = 4, /* maximum ticket nonce size */ MAX_LIFETIME = 604800, /* maximum ticket lifetime */ MAX_EARLY_DATA_SZ = 4096, /* maximum early data size */ @@ -2150,6 +2153,16 @@ WOLFSSL_LOCAL int TLSX_KeyShare_Establish(WOLFSSL* ssl); #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +#ifndef WOLFSSL_TLS13_DRAFT_18 +/* Ticket nonce - for deriving PSK. + * Length allowed to be: 1..255. Only support 4 bytes. + */ +typedef struct TicketNonce { + byte len; + byte data[MAX_TICKET_NONCE_SZ]; +} TicketNonce; +#endif + /* The PreSharedKey extension information - entry in a linked list. */ typedef struct PreSharedKey { word16 identityLen; /* Length of identity */ @@ -2670,6 +2683,9 @@ struct WOLFSSL_SESSION { byte namedGroup; word32 ticketSeen; /* Time ticket seen (ms) */ word32 ticketAdd; /* Added by client */ + #ifndef WOLFSSL_TLS13_DRAFT_18 + TicketNonce ticketNonce; /* Nonce used to derive PSK */ + #endif #endif #ifdef WOLFSSL_EARLY_DATA word32 maxEarlyDataSz;