From 350ce5fcef19f6240c4376226598dc62e290bf75 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Mon, 19 Jun 2017 11:37:10 +1000 Subject: [PATCH 1/5] TLS v1.3 0-RTT --- configure.ac | 21 ++ examples/client/client.c | 68 +++- examples/server/server.c | 38 +- src/internal.c | 70 ++++ src/keys.c | 65 +++- src/ssl.c | 36 +- src/tls.c | 232 +++++++++++- src/tls13.c | 765 +++++++++++++++++++++++++++++++------- tests/test-psk-no-id.conf | 40 ++ tests/test-tls13.conf | 34 ++ wolfssl/internal.h | 83 +++-- wolfssl/ssl.h | 13 +- 12 files changed, 1271 insertions(+), 194 deletions(-) diff --git a/configure.ac b/configure.ac index d9b17709c..c08723d25 100644 --- a/configure.ac +++ b/configure.ac @@ -2326,6 +2326,26 @@ then AM_CFLAGS="$AM_CFLAGS -DHAVE_SUPPORTED_CURVES"]) fi +# Early Data handshake in TLS v1.3 and above +AC_ARG_ENABLE([earlydata], + [AS_HELP_STRING([--enable-earlydata],[Enable Early Data handshake with wolfSSL TLS v1.3 (default: disabled)])], + [ ENABLED_EARLY_DATA=$enableval ], + [ ENABLED_EARLY_DATA=no ] + ) +if test "$ENABLED_EARLY_DATA" = "yes" +then + if test "x$ENABLED_TLS13" = "xno" + then + AC_MSG_ERROR([cannot enable earlydata without enabling tls13.]) + fi + if test "x$ENABLED_SESSION_TICKET" = "xno" && test "x$ENABLED_PSK" = "xno" + then + AC_MSG_ERROR([cannot enable earlydata without enabling session tickets and/or PSK.]) + fi + AM_CFLAGS="-DWOLFSSL_EARLY_DATA $AM_CFLAGS" +fi + + # PKCS7 AC_ARG_ENABLE([pkcs7], [AS_HELP_STRING([--enable-pkcs7],[Enable PKCS7 (default: disabled)])], @@ -3740,6 +3760,7 @@ echo " * SCTP: $ENABLED_SCTP" echo " * Old TLS Versions: $ENABLED_OLD_TLS" echo " * SSL version 3.0: $ENABLED_SSLV3" echo " * TLS v1.3: $ENABLED_TLS13" +echo " * Early Data: $ENABLED_EARLY_DATA" echo " * OCSP: $ENABLED_OCSP" echo " * OCSP Stapling: $ENABLED_CERTIFICATE_STATUS_REQUEST" echo " * OCSP Stapling v2: $ENABLED_CERTIFICATE_STATUS_REQUEST_V2" diff --git a/examples/client/client.c b/examples/client/client.c index eab3d10ce..0ce953a52 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -716,6 +716,9 @@ static void Usage(void) #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) printf("-Q Support requesting certificate post-handshake\n"); #endif +#ifdef WOLFSSL_EARLY_DATA + printf("-0 Early data sent to server (0-RTT handshake)\n"); +#endif } THREAD_RETURN WOLFSSL_THREAD client_test(void* args) @@ -817,6 +820,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif #endif int updateKeysIVs = 0; +#ifdef WOLFSSL_EARLY_DATA + int earlyData = 0; +#endif #ifdef HAVE_OCSP int useOcsp = 0; @@ -864,7 +870,8 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) /* Not used: All used */ while ((ch = mygetopt(argc, argv, "?" "ab:c:defgh:ijk:l:mnop:q:rstuv:wxyz" - "A:B:CDE:F:GHIJKL:M:NO:PQRS:TUVW:XYZ:")) != -1) { + "A:B:CDE:F:GHIJKL:M:NO:PQRS:TUVW:XYZ:" + "0")) != -1) { switch (ch) { case '?' : Usage(); @@ -1184,6 +1191,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif break; + case '0' : + #ifdef WOLFSSL_EARLY_DATA + earlyData = 1; + #endif + break; + default: Usage(); exit(MY_EX_USAGE); @@ -2027,6 +2040,59 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) ret = NonBlockingSSL_Connect(sslResume); } else { + #ifdef WOLFSSL_EARLY_DATA + #ifndef HAVE_SESSION_TICKET + if (!usePsk) { + } + else + #endif + if (earlyData) { + do { + err = 0; /* reset error */ + ret = wolfSSL_write_early_data(sslResume, msg, msgSz, + &msgSz); + if (ret <= 0) { + err = wolfSSL_get_error(sslResume, 0); + #ifdef WOLFSSL_ASYNC_CRYPT + if (err == WC_PENDING_E) { + ret = wolfSSL_AsyncPoll(sslResume, + WOLF_POLL_FLAG_CHECK_HW); + if (ret < 0) break; + } + #endif + } + } while (err == WC_PENDING_E); + if (ret != msgSz) { + printf("SSL_write_early_data msg error %d, %s\n", err, + wolfSSL_ERR_error_string(err, buffer)); + wolfSSL_free(sslResume); + wolfSSL_CTX_free(ctx); + err_sys("SSL_write_early_data failed"); + } + do { + err = 0; /* reset error */ + ret = wolfSSL_write_early_data(sslResume, msg, msgSz, + &msgSz); + if (ret <= 0) { + err = wolfSSL_get_error(sslResume, 0); + #ifdef WOLFSSL_ASYNC_CRYPT + if (err == WC_PENDING_E) { + ret = wolfSSL_AsyncPoll(sslResume, + WOLF_POLL_FLAG_CHECK_HW); + if (ret < 0) break; + } + #endif + } + } while (err == WC_PENDING_E); + if (ret != msgSz) { + printf("SSL_write_early_data msg error %d, %s\n", err, + wolfSSL_ERR_error_string(err, buffer)); + wolfSSL_free(sslResume); + wolfSSL_CTX_free(ctx); + err_sys("SSL_write_early_data failed"); + } + } + #endif do { err = 0; /* reset error */ ret = wolfSSL_connect(sslResume); diff --git a/examples/server/server.c b/examples/server/server.c index 28d527a55..974e9f353 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -368,6 +368,9 @@ static void Usage(void) printf("-Q Request certificate from client post-handshake\n"); #endif #endif +#ifdef WOLFSSL_EARLY_DATA + printf("-0 Early data read from client (0-RTT handshake)\n"); +#endif } THREAD_RETURN CYASSL_THREAD server_test(void* args) @@ -456,6 +459,9 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) int postHandAuth = 0; #endif +#ifdef WOLFSSL_EARLY_DATA + int earlyData = 0; +#endif #ifdef WOLFSSL_STATIC_MEMORY #if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) \ @@ -503,7 +509,8 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) /* Not Used: h, m, t, x, y, z, F, J, M, T, V, W, X, Y */ while ((ch = mygetopt(argc, argv, "?" "abc:defgijk:l:nop:q:rsuv:w" - "A:B:C:D:E:GHIKL:NO:PQR:S:UYZ:")) != -1) { + "A:B:C:D:E:GHIKL:NO:PQR:S:UYZ:" + "0")) != -1) { switch (ch) { case '?' : Usage(); @@ -724,6 +731,12 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) #endif break; + case '0' : + #ifdef WOLFSSL_EARLY_DATA + earlyData = 1; + #endif + break; + default: Usage(); exit(MY_EX_USAGE); @@ -1167,6 +1180,29 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) ret = NonBlockingSSL_Accept(ssl); } else { + #ifdef WOLFSSL_EARLY_DATA + if (earlyData) { + do { + int len; + err = 0; /* reset error */ + ret = wolfSSL_read_early_data(ssl, input, sizeof(input)-1, + &len); + if (ret != SSL_SUCCESS) { + err = SSL_get_error(ssl, 0); + #ifdef WOLFSSL_ASYNC_CRYPT + if (err == WC_PENDING_E) { + ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW); + if (ret < 0) break; + } + #endif + } + if (ret > 0) { + input[ret] = 0; /* null terminate message */ + printf("Early Data Client message: %s\n", input); + } + } while (err == WC_PENDING_E || ret > 0); + } + #endif do { err = 0; /* reset error */ ret = SSL_accept(ssl); diff --git a/src/internal.c b/src/internal.c index 7de85c1c0..d8230a893 100755 --- a/src/internal.c +++ b/src/internal.c @@ -1433,6 +1433,10 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method, void* heap) ret = wolfEventQueue_Init(&ctx->event_queue); #endif /* HAVE_WOLF_EVENT */ +#ifdef WOLFSSL_EARLY_DATA + ctx->maxEarlyDataSz = MAX_EARLY_DATA_SZ; +#endif + ctx->heap = heap; /* wolfSSL_CTX_load_static_memory sets */ return ret; @@ -3782,6 +3786,10 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) ssl->options.client_psk_cb = ctx->client_psk_cb; ssl->options.server_psk_cb = ctx->server_psk_cb; #endif /* NO_PSK */ +#ifdef WOLFSSL_EARLY_DATA + if (ssl->options.side == WOLFSSL_SERVER_END) + ssl->options.maxEarlyDataSz = ctx->maxEarlyDataSz; +#endif #ifdef HAVE_ANON ssl->options.haveAnon = ctx->haveAnon; @@ -10898,6 +10906,11 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx) byte decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; #endif +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData) { + } + else +#endif if (ssl->options.handShakeDone == 0) { WOLFSSL_MSG("Received App data before a handshake completed"); SendAlert(ssl, alert_fatal, unexpected_message); @@ -10918,6 +10931,15 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx) WOLFSSL_MSG("App data buffer error, malicious input?"); return BUFFER_ERROR; } +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData) { + if (ssl->earlyDataSz + dataSz > ssl->options.maxEarlyDataSz) { + SendAlert(ssl, alert_fatal, unexpected_message); + return SSL_FATAL_ERROR; + } + ssl->earlyDataSz += dataSz; + } +#endif /* read data */ if (dataSz) { @@ -11375,6 +11397,19 @@ int ProcessReply(WOLFSSL* ssl) else { WOLFSSL_MSG("Decrypt failed"); WOLFSSL_ERROR(ret); + #ifdef WOLFSSL_EARLY_DATA + if (ssl->options.tls1_3) { + ssl->earlyDataSz += ssl->curSize; + if (ssl->earlyDataSz <= ssl->options.maxEarlyDataSz) { + if (ssl->keys.peer_sequence_number_lo-- == 0) + ssl->keys.peer_sequence_number_hi--; + ssl->options.processReply = doProcessInit; + ssl->buffers.inputBuffer.idx = + ssl->buffers.inputBuffer.length; + return 0; + } + } + #endif #ifdef WOLFSSL_DTLS /* If in DTLS mode, if the decrypt fails for any * reason, pretend the datagram never happened. */ @@ -11461,6 +11496,17 @@ int ProcessReply(WOLFSSL* ssl) ssl->buffers.inputBuffer.buffer, &ssl->buffers.inputBuffer.idx, ssl->buffers.inputBuffer.length); + #ifdef WOLFSSL_EARLY_DATA + if (ret != 0) + return ret; + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->earlyData && + ssl->options.handShakeState == HANDSHAKE_DONE) { + ssl->earlyData = 0; + ssl->options.processReply = doProcessInit; + return ZERO_RETURN; + } + #endif #else ret = BUFFER_ERROR; #endif @@ -13153,6 +13199,15 @@ int SendData(WOLFSSL* ssl, const void* data, int sz) if (ssl->error == WANT_WRITE || ssl->error == WC_PENDING_E) ssl->error = 0; +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData) { + if (ssl->options.handShakeState == HANDSHAKE_DONE) { + WOLFSSL_MSG("handshake complete, trying to send early data"); + return BUILD_MSG_ERROR; + } + } + else +#endif if (ssl->options.handShakeState != HANDSHAKE_DONE) { int err; WOLFSSL_MSG("handshake not complete, trying to finish"); @@ -13305,6 +13360,11 @@ int ReceiveData(WOLFSSL* ssl, byte* output, int sz, int peek) return ssl->error; } +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData) { + } + else +#endif if (ssl->options.handShakeState != HANDSHAKE_DONE) { int err; WOLFSSL_MSG("Handshake not complete, trying to finish"); @@ -22472,6 +22532,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef WOLFSSL_TLS13 word32 ageAdd; /* Obfuscation of age */ byte namedGroup; /* Named group used */ + #ifdef WOLFSSL_EARLY_DATA + word32 maxEarlyDataSz; /* Max size of early data */ + #endif #endif } InternalTicket; @@ -22503,6 +22566,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, it.suite[0] = ssl->options.cipherSuite0; it.suite[1] = ssl->options.cipherSuite; + #ifdef WOLFSSL_EARLY_DATA + it.maxEarlyDataSz = ssl->options.maxEarlyDataSz; + #endif + if (!ssl->options.tls1_3) { XMEMCPY(it.msecret, ssl->arrays->masterSecret, SECRET_LEN); c32toa(LowResTimer(), (byte*)&it.timestamp); @@ -22627,6 +22694,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ssl->session.ticketAdd = it->ageAdd; ssl->session.cipherSuite0 = it->suite[0]; ssl->session.cipherSuite = it->suite[1]; + #ifdef WOLFSSL_EARLY_DATA + ssl->session.maxEarlyDataSz = it->maxEarlyDataSz; + #endif /* Resumption master secret. */ XMEMCPY(ssl->session.masterSecret, it->msecret, SECRET_LEN); ssl->session.namedGroup = it->namedGroup; diff --git a/src/keys.c b/src/keys.c index 3a22073b0..8239b0ff6 100644 --- a/src/keys.c +++ b/src/keys.c @@ -2900,14 +2900,42 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side) switch (side) { case ENCRYPT_SIDE_ONLY: + WOLFSSL_MSG("Provisioning ENCRYPT key"); + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_BUFFER(ssl->keys.client_write_key, AES_256_KEY_SIZE); + } + else { + WOLFSSL_BUFFER(ssl->keys.server_write_key, AES_256_KEY_SIZE); + } wc_encrypt = &ssl->encrypt; break; case DECRYPT_SIDE_ONLY: + WOLFSSL_MSG("Provisioning DECRYPT key"); + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_BUFFER(ssl->keys.server_write_key, AES_256_KEY_SIZE); + } + else { + WOLFSSL_BUFFER(ssl->keys.client_write_key, AES_256_KEY_SIZE); + } wc_decrypt = &ssl->decrypt; break; case ENCRYPT_AND_DECRYPT_SIDE: + WOLFSSL_MSG("Provisioning ENCRYPT key"); + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_BUFFER(ssl->keys.client_write_key, AES_256_KEY_SIZE); + } + else { + WOLFSSL_BUFFER(ssl->keys.server_write_key, AES_256_KEY_SIZE); + } + WOLFSSL_MSG("Provisioning DECRYPT key"); + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_BUFFER(ssl->keys.server_write_key, AES_256_KEY_SIZE); + } + else { + WOLFSSL_BUFFER(ssl->keys.client_write_key, AES_256_KEY_SIZE); + } wc_encrypt = &ssl->encrypt; wc_decrypt = &ssl->decrypt; break; @@ -2996,7 +3024,7 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side) /* TLS can call too */ -int StoreKeys(WOLFSSL* ssl, const byte* keyData) +int StoreKeys(WOLFSSL* ssl, const byte* keyData, int side) { int sz, i = 0; Keys* keys = &ssl->keys; @@ -3011,21 +3039,32 @@ int StoreKeys(WOLFSSL* ssl, const byte* keyData) if (ssl->specs.cipher_type != aead) { sz = ssl->specs.hash_size; - XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz); - i += sz; - XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz); - i += sz; + if (side & PROVISION_CLIENT) { + XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz); + i += sz; + } + if (side & PROVISION_SERVER) { + XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz); + i += sz; + } } sz = ssl->specs.key_size; - XMEMCPY(keys->client_write_key, &keyData[i], sz); - i += sz; - XMEMCPY(keys->server_write_key, &keyData[i], sz); - i += sz; + if (side & PROVISION_CLIENT) { + XMEMCPY(keys->client_write_key, &keyData[i], sz); + i += sz; + } + if (side & PROVISION_SERVER) { + XMEMCPY(keys->server_write_key, &keyData[i], sz); + i += sz; + } sz = ssl->specs.iv_size; - XMEMCPY(keys->client_write_IV, &keyData[i], sz); - i += sz; - XMEMCPY(keys->server_write_IV, &keyData[i], sz); + if (side & PROVISION_CLIENT) { + XMEMCPY(keys->client_write_IV, &keyData[i], sz); + i += sz; + } + if (side & PROVISION_SERVER) + XMEMCPY(keys->server_write_IV, &keyData[i], sz); #ifdef HAVE_AEAD if (ssl->specs.cipher_type == aead) { @@ -3126,7 +3165,7 @@ int DeriveKeys(WOLFSSL* ssl) } if (ret == 0) - ret = StoreKeys(ssl, keyData); + ret = StoreKeys(ssl, keyData, PROVISION_CLIENT_SERVER); } #ifdef WOLFSSL_SMALL_STACK diff --git a/src/ssl.c b/src/ssl.c index bcbbbf5a2..1866ed4e3 100755 --- a/src/ssl.c +++ b/src/ssl.c @@ -1313,6 +1313,14 @@ int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) if (ssl == NULL || data == NULL || sz < 0) return BAD_FUNC_ARG; +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData && (ret = wolfSSL_negotiate(ssl)) < 0) { + ssl->error = ret; + return SSL_FATAL_ERROR; + } + ssl->earlyData = 0; +#endif + #ifdef HAVE_WRITE_DUP { /* local variable scope */ int dupErr = 0; /* local copy */ @@ -1357,7 +1365,6 @@ int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) return ret; } - static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek) { int ret; @@ -8273,6 +8280,11 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, } } +#ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); +#endif + switch (ssl->options.connectState) { case CONNECT_BEGIN : @@ -9222,11 +9234,14 @@ static int GetDeepCopySession(WOLFSSL* ssl, WOLFSSL_SESSION* copyFrom) return BAD_MUTEX_E; } - copyInto->cipherSuite0 = copyFrom->cipherSuite0; - copyInto->cipherSuite = copyFrom->cipherSuite; - copyInto->namedGroup = copyFrom->namedGroup; - copyInto->ticketSeen = copyFrom->ticketSeen; - copyInto->ticketAdd = copyFrom->ticketAdd; + copyInto->cipherSuite0 = copyFrom->cipherSuite0; + copyInto->cipherSuite = copyFrom->cipherSuite; + copyInto->namedGroup = copyFrom->namedGroup; + copyInto->ticketSeen = copyFrom->ticketSeen; + copyInto->ticketAdd = copyFrom->ticketAdd; +#ifdef WOLFSSL_EARLY_DATA + copyInto->maxEarlyDataSz = copyFrom->maxEarlyDataSz; +#endif XMEMCPY(copyInto->masterSecret, copyFrom->masterSecret, SECRET_LEN); if (wc_UnLockMutex(&session_mutex) != 0) { @@ -9453,9 +9468,12 @@ int AddSession(WOLFSSL* ssl) #endif /* SESSION_CERTS || (WOLFSSL_TLS13 & HAVE_SESSION_TICKET) */ #if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) if (error == 0) { - session->namedGroup = ssl->session.namedGroup; - session->ticketSeen = ssl->session.ticketSeen; - session->ticketAdd = ssl->session.ticketAdd; + session->namedGroup = ssl->session.namedGroup; + session->ticketSeen = ssl->session.ticketSeen; + session->ticketAdd = ssl->session.ticketAdd; + #ifdef WOLFSSL_EARLY_DATA + session->maxEarlyDataSz = ssl->session.maxEarlyDataSz; + #endif } #endif /* WOLFSSL_TLS13 && HAVE_SESSION_TICKET */ #ifdef HAVE_EXT_CACHE diff --git a/src/tls.c b/src/tls.c index c976e6980..76a83f914 100755 --- a/src/tls.c +++ b/src/tls.c @@ -533,7 +533,7 @@ int DeriveTlsKeys(WOLFSSL* ssl) IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, ssl->heap, ssl->devId); if (ret == 0) - ret = StoreKeys(ssl, key_dig); + ret = StoreKeys(ssl, key_dig, PROVISION_CLIENT_SERVER); #ifdef WOLFSSL_SMALL_STACK XFREE(key_dig, ssl->heap, DYNAMIC_TYPE_DIGEST); @@ -5992,7 +5992,7 @@ static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, byte* input, word16 length, idx += OPAQUE32_LEN; ret = TLSX_PreSharedKey_Use(ssl, identity, identityLen, age, no_mac, - 1, NULL); + 0, 0, 1, NULL); if (ret != 0) return ret; @@ -6145,12 +6145,15 @@ static INLINE byte GetHmacLength(int hmac) * len The length of the identity data. * age The age of the identity. * hmac The HMAC algorithm. + * ciphersuite0 The first byte of the ciphersuite to use. + * ciphersuite The second byte of the ciphersuite to use. * resumption The PSK is for resumption of a session. * preSharedKey The new pre-shared key object. * returns 0 on success and other values indicate failure. */ int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity, word16 len, word32 age, - byte hmac, byte resumption, + byte hmac, byte cipherSuite0, + byte cipherSuite, byte resumption, PreSharedKey **preSharedKey) { int ret = 0; @@ -6189,10 +6192,12 @@ int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity, word16 len, word32 age, } /* Update/set age and HMAC algorithm. */ - psk->ticketAge = age; - psk->hmac = hmac; - psk->resumption = resumption; - psk->binderLen = GetHmacLength(psk->hmac); + psk->ticketAge = age; + psk->hmac = hmac; + psk->cipherSuite0 = cipherSuite0; + psk->cipherSuite = cipherSuite; + psk->resumption = resumption; + psk->binderLen = GetHmacLength(psk->hmac); if (preSharedKey != NULL) *preSharedKey = psk; @@ -6224,7 +6229,7 @@ int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity, word16 len, word32 age, * * modes The PSK KE mode bit string. * msgType The type of the message this extension is being written into. - * returns the number of bytes of the encoded key share extension. + * returns the number of bytes of the encoded PSK KE mode extension. */ static word16 TLSX_PskKeModes_GetSize(byte modes, byte msgType) { @@ -6436,8 +6441,8 @@ static int TLSX_PostHandAuth_Parse(WOLFSSL* ssl, byte* input, word16 length, */ static int TLSX_PostHandAuth_Use(WOLFSSL* ssl) { - int ret = 0; - TLSX* extension; + int ret = 0; + TLSX* extension; /* Find the PSK key exchange modes extension if it exists. */ extension = TLSX_Find(ssl->extensions, TLSX_POST_HANDSHAKE_AUTH); @@ -6464,6 +6469,129 @@ static int TLSX_PostHandAuth_Use(WOLFSSL* ssl) #endif +/******************************************************************************/ +/* Early Data Indication */ +/******************************************************************************/ + +#ifdef WOLFSSL_EARLY_DATA +/* Get the size of the encoded Early Data Indication extension. + * In messages: ClientHello, EncryptedExtensions and NewSessionTicket. + * + * msgType The type of the message this extension is being written into. + * returns the number of bytes of the encoded key share extension. + */ +static word16 TLSX_EarlyData_GetSize(byte msgType) +{ + if (msgType == client_hello || msgType == encrypted_extensions) + return 0; + if (msgType == session_ticket) + return OPAQUE32_LEN; + + return SANITY_MSG_E; +} + +/* Writes the Early Data Indicator extension into the output buffer. + * Assumes that the the output buffer is big enough to hold data. + * In messages: ClientHello, EncryptedExtensions and NewSessionTicket. + * + * max The maximum early data size. + * output The buffer to write into. + * msgType The type of the message this extension is being written into. + * returns the number of bytes written into the buffer. + */ +static word16 TLSX_EarlyData_Write(word32 max, byte* output, byte msgType) +{ + if (msgType == client_hello || msgType == encrypted_extensions) { + return 0; + } + if (msgType == session_ticket) { + c32toa(max, output); + return OPAQUE32_LEN; + } + + return SANITY_MSG_E; +} + +/* Parse the Early Data Indicator extension. + * In messages: ClientHello, EncryptedExtensions and NewSessionTicket. + * + * ssl The SSL/TLS object. + * input 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 and other values indicate failure. + */ +static int TLSX_EarlyData_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType) +{ + if (msgType == client_hello) { + if (length != 0) + return BUFFER_E; + + return TLSX_EarlyData_Use(ssl, 0); + } + if (msgType == encrypted_extensions) { + if (length != 0) + return BUFFER_E; + + return TLSX_EarlyData_Use(ssl, 1); + } + if (msgType == session_ticket) { + word32 max; + + if (length != OPAQUE32_LEN) + return BUFFER_E; + ato32(input, &max); + + ssl->session.maxEarlyDataSz = max; + return 0; + } + + return SANITY_MSG_E; +} + +/* Use the data to create a new Early Data object in the extensions. + * + * ssl The SSL/TLS object. + * max The maximum early data size. + * returns 0 on success and other values indicate failure. + */ +int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 max) +{ + int ret = 0; + TLSX* extension; + + /* Find the early extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); + if (extension == NULL) { + /* Push new early extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_EARLY_DATA, NULL, ssl->heap); + if (ret != 0) + return ret; + + extension = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); + if (extension == NULL) + return MEMORY_E; + } + + extension->resp = 1; + extension->val = max; + + return 0; +} + +#define EDI_GET_SIZE TLSX_EarlyData_GetSize +#define EDI_WRITE TLSX_EarlyData_Write +#define EDI_PARSE TLSX_EarlyData_Parse + +#else + +#define EDI_GET_SIZE(a) 0 +#define EDI_WRITE(a, b, c) 0 +#define EDI_PARSE(a, b, c, d) 0 + +#endif + /******************************************************************************/ /* TLS Extensions Framework */ /******************************************************************************/ @@ -6550,6 +6678,11 @@ void TLSX_FreeAll(TLSX* list, void* heap) break; #endif + #ifdef WOLFSSL_EARLY_DATA + case TLSX_EARLY_DATA: + break; + #endif + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH case TLSX_POST_HANDSHAKE_AUTH: break; @@ -6662,6 +6795,13 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType) length += PKM_GET_SIZE(extension->val, msgType); break; #endif + + #ifdef WOLFSSL_EARLY_DATA + case TLSX_EARLY_DATA: + length += EDI_GET_SIZE(msgType); + break; + #endif + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH case TLSX_POST_HANDSHAKE_AUTH: length += PHA_GET_SIZE(msgType); @@ -6797,6 +6937,14 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, offset += PKM_WRITE(extension->val, output + offset, msgType); break; #endif + + #ifdef WOLFSSL_EARLY_DATA + case TLSX_EARLY_DATA: + WOLFSSL_MSG("Early Data extension to write"); + offset += EDI_WRITE(extension->val, output + offset, msgType); + break; + #endif + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH case TLSX_POST_HANDSHAKE_AUTH: WOLFSSL_MSG("Post-Handshake Authentication extension to write"); @@ -7292,12 +7440,16 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) /* Determine the MAC algorithm for the cipher suite used. */ ssl->options.cipherSuite0 = sess->cipherSuite0; ssl->options.cipherSuite = sess->cipherSuite; - SetCipherSpecs(ssl); + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; milli = TimeNowInMilliseconds() - sess->ticketSeen + sess->ticketAdd; /* Pre-shared key is mandatory extension for resumption. */ ret = TLSX_PreSharedKey_Use(ssl, sess->ticket, sess->ticketLen, - milli, ssl->specs.mac_algorithm, 1, + milli, ssl->specs.mac_algorithm, + ssl->options.cipherSuite0, + ssl->options.cipherSuite, 1, NULL); if (ret != 0) return ret; @@ -7307,7 +7459,9 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) #endif #ifndef NO_PSK if (ssl->options.client_psk_cb != NULL) { - byte mac = sha256_mac; + /* Default ciphersuite. */ + byte cipherSuite0 = TLS13_BYTE; + byte cipherSuite = WOLFSSL_DEF_PSK_CIPHER; ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, ssl->arrays->server_hint, ssl->arrays->client_identity, @@ -7317,12 +7471,19 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) return PSK_KEY_ERROR; } ssl->arrays->client_identity[MAX_PSK_ID_LEN] = '\0'; - /* Hash algorithm defaults to SHA-256 unless cb specifies. */ + /* TODO: Callback should be able to change ciphersuite. */ + ssl->options.cipherSuite0 = cipherSuite0; + ssl->options.cipherSuite = cipherSuite; + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; ret = TLSX_PreSharedKey_Use(ssl, (byte*)ssl->arrays->client_identity, XSTRLEN(ssl->arrays->client_identity), - 0, mac, 0, NULL); + 0, ssl->specs.mac_algorithm, + cipherSuite0, cipherSuite, 0, + NULL); if (ret != 0) return ret; @@ -7500,7 +7661,9 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType) TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); #endif } +#endif break; +#ifdef WOLFSSL_TLS13 case encrypted_extensions: TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); @@ -7512,9 +7675,17 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType) case certificate_request: XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); + break; + #endif + #ifdef WOLFSSL_EARLY_DATA + case session_ticket: + if (ssl->options.tls1_3) { + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA)); + } + break; #endif #endif - break; } #ifdef HAVE_QSH @@ -7561,7 +7732,9 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType) TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); #endif } +#endif break; +#ifdef WOLFSSL_TLS13 case encrypted_extensions: TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); @@ -7574,9 +7747,17 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType) XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); + break; + #endif + #ifdef WOLFSSL_EARLY_DATA + case session_ticket: + if (ssl->options.tls1_3) { + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA)); + } + break; #endif #endif - break; } offset += OPAQUE16_LEN; /* extensions length */ @@ -7837,6 +8018,23 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, ret = PKM_PARSE(ssl, input + offset, size, msgType); break; #endif + + #ifdef WOLFSSL_EARLY_DATA + case TLSX_EARLY_DATA: + WOLFSSL_MSG("Early Data extension received"); + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && msgType != session_ticket && + msgType != encrypted_extensions) { + return EXT_NOT_ALLOWED; + } + ret = EDI_PARSE(ssl, input + offset, size, msgType); + break; + #endif + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH case TLSX_POST_HANDSHAKE_AUTH: WOLFSSL_MSG("PSK Key Exchange Modes extension received"); diff --git a/src/tls13.c b/src/tls13.c index f9fde02ed..8be4e91f0 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -520,7 +520,7 @@ static int DeriveBinderKeyResume(WOLFSSL* ssl, byte* key) } #endif /* HAVE_SESSION_TICKET */ -#ifdef TLS13_SUPPORTS_0RTT +#ifdef WOLFSSL_EARLY_DATA #ifdef WOLFSSL_TLS13_DRAFT_18 /* The length of the early traffic label. */ #define EARLY_TRAFFIC_LABEL_SZ 27 @@ -944,7 +944,9 @@ static const byte writeIVLabel[WRITE_IV_LABEL_SZ+1] = "iv"; /* Derive the keys and IVs for TLS v1.3. * * ssl The SSL/TLS object. - * sercret handshake_key when deriving keys and IVs for encrypting handshake + * sercret early_data_key when deriving the key and IV for encrypting early + * data application data and end_of_early_data messages. + * handshake_key when deriving keys and IVs for encrypting handshake * messages. * traffic_key when deriving first keys and IVs for encrypting * traffic messages. @@ -953,9 +955,11 @@ static const byte writeIVLabel[WRITE_IV_LABEL_SZ+1] = "iv"; * side ENCRYPT_SIDE_ONLY when only encryption secret needs to be derived. * DECRYPT_SIDE_ONLY when only decryption secret needs to be derived. * ENCRYPT_AND_DECRYPT_SIDE when both secret needs to be derived. + * store 1 indicates to derive the keys and IVs from derived secret and + * store ready for provisioning. * returns 0 on success, otherwise failure. */ -static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side) +static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) { int ret; int i = 0; @@ -964,8 +968,7 @@ static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side) #else byte key_dig[MAX_PRF_DIG]; #endif - int deriveClient = 0; - int deriveServer = 0; + int provision; #ifdef WOLFSSL_SMALL_STACK key_dig = (byte*)XMALLOC(MAX_PRF_DIG, ssl->heap, DYNAMIC_TYPE_DIGEST); @@ -974,25 +977,39 @@ static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side) #endif if (side == ENCRYPT_AND_DECRYPT_SIDE) { - deriveClient = 1; - deriveServer = 1; + provision = PROVISION_CLIENT_SERVER; } else { - deriveClient = (ssl->options.side != WOLFSSL_CLIENT_END) ^ - (side == ENCRYPT_SIDE_ONLY); - deriveServer = !deriveClient; + provision = ((ssl->options.side != WOLFSSL_CLIENT_END) ^ + (side == ENCRYPT_SIDE_ONLY)) ? PROVISION_CLIENT : + PROVISION_SERVER; } /* Derive the appropriate secret to use in the HKDF. */ switch (secret) { +#ifdef WOLFSSL_EARLY_DATA + case early_data_key: + if (provision & PROVISION_CLIENT) { + ret = DeriveEarlyTrafficSecret(ssl, ssl->arrays->clientSecret); + if (ret != 0) + goto end; + } + if (provision & PROVISION_SERVER) { + ret = DeriveEarlyTrafficSecret(ssl, ssl->arrays->serverSecret); + if (ret != 0) + goto end; + } + break; +#endif + case handshake_key: - if (deriveClient) { + if (provision & PROVISION_CLIENT) { ret = DeriveClientHandshakeSecret(ssl, ssl->arrays->clientSecret); if (ret != 0) goto end; } - if (deriveServer) { + if (provision & PROVISION_SERVER) { ret = DeriveServerHandshakeSecret(ssl, ssl->arrays->serverSecret); if (ret != 0) @@ -1001,12 +1018,12 @@ static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side) break; case traffic_key: - if (deriveClient) { + if (provision & PROVISION_CLIENT) { ret = DeriveClientTrafficSecret(ssl, ssl->arrays->clientSecret); if (ret != 0) goto end; } - if (deriveServer) { + if (provision & PROVISION_SERVER) { ret = DeriveServerTrafficSecret(ssl, ssl->arrays->serverSecret); if (ret != 0) goto end; @@ -1014,12 +1031,12 @@ static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side) break; case update_traffic_key: - if (deriveClient) { + if (provision & PROVISION_CLIENT) { ret = DeriveTrafficSecret(ssl, ssl->arrays->clientSecret); if (ret != 0) goto end; } - if (deriveServer) { + if (provision & PROVISION_SERVER) { ret = DeriveTrafficSecret(ssl, ssl->arrays->serverSecret); if (ret != 0) goto end; @@ -1027,45 +1044,56 @@ static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side) break; } + if (!store) + goto end; + /* Key data = client key | server key | client IV | server IV */ - /* Derive the client key. */ - WOLFSSL_MSG("Derive Client Key"); - ret = DeriveKey(ssl, &key_dig[i], ssl->specs.key_size, - ssl->arrays->clientSecret, writeKeyLabel, - WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0); - if (ret != 0) - goto end; - i += ssl->specs.key_size; + if (provision & PROVISION_CLIENT) { + /* Derive the client key. */ + WOLFSSL_MSG("Derive Client Key"); + ret = DeriveKey(ssl, &key_dig[i], ssl->specs.key_size, + ssl->arrays->clientSecret, writeKeyLabel, + WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0); + if (ret != 0) + goto end; + i += ssl->specs.key_size; + } - /* Derive the server key. */ - WOLFSSL_MSG("Derive Server Key"); - ret = DeriveKey(ssl, &key_dig[i], ssl->specs.key_size, - ssl->arrays->serverSecret, writeKeyLabel, - WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0); - if (ret != 0) - goto end; - i += ssl->specs.key_size; + if (provision & PROVISION_SERVER) { + /* Derive the server key. */ + WOLFSSL_MSG("Derive Server Key"); + ret = DeriveKey(ssl, &key_dig[i], ssl->specs.key_size, + ssl->arrays->serverSecret, writeKeyLabel, + WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0); + if (ret != 0) + goto end; + i += ssl->specs.key_size; + } - /* Derive the client IV. */ - WOLFSSL_MSG("Derive Client IV"); - ret = DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, - ssl->arrays->clientSecret, writeIVLabel, WRITE_IV_LABEL_SZ, - ssl->specs.mac_algorithm, 0); - if (ret != 0) - goto end; - i += ssl->specs.iv_size; + if (provision & PROVISION_CLIENT) { + /* Derive the client IV. */ + WOLFSSL_MSG("Derive Client IV"); + ret = DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, + ssl->arrays->clientSecret, writeIVLabel, + WRITE_IV_LABEL_SZ, ssl->specs.mac_algorithm, 0); + if (ret != 0) + goto end; + i += ssl->specs.iv_size; + } - /* Derive the server IV. */ - WOLFSSL_MSG("Derive Server IV"); - ret = DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, - ssl->arrays->serverSecret, writeIVLabel, WRITE_IV_LABEL_SZ, - ssl->specs.mac_algorithm, 0); - if (ret != 0) - goto end; + if (provision & PROVISION_SERVER) { + /* Derive the server IV. */ + WOLFSSL_MSG("Derive Server IV"); + ret = DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, + ssl->arrays->serverSecret, writeIVLabel, + WRITE_IV_LABEL_SZ, ssl->specs.mac_algorithm, 0); + if (ret != 0) + goto end; + } /* Store keys and IVs but don't activate them. */ - ret = StoreKeys(ssl, key_dig); + ret = StoreKeys(ssl, key_dig, provision); end: #ifdef WOLFSSL_SMALL_STACK @@ -1709,9 +1737,6 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, case CIPHER_STATE_END: { - if (ssl->encrypt.nonce) - ForceZero(ssl->encrypt.nonce, AEAD_NONCE_SZ); - #ifdef WOLFSSL_DEBUG_TLS WOLFSSL_MSG("Nonce"); WOLFSSL_BUFFER(ssl->encrypt.nonce, ssl->specs.iv_size); @@ -1721,7 +1746,10 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, WOLFSSL_BUFFER(output + dataSz, macSz); #endif - break; + if (ssl->encrypt.nonce) + ForceZero(ssl->encrypt.nonce, AEAD_NONCE_SZ); + + break; } } @@ -1913,9 +1941,6 @@ int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz) case CIPHER_STATE_END: { - if (ssl->decrypt.nonce) - ForceZero(ssl->decrypt.nonce, AEAD_NONCE_SZ); - #ifdef WOLFSSL_DEBUG_TLS WOLFSSL_MSG("Nonce"); WOLFSSL_BUFFER(ssl->decrypt.nonce, ssl->specs.iv_size); @@ -1923,14 +1948,19 @@ int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz) WOLFSSL_BUFFER(output, dataSz); #endif + if (ssl->decrypt.nonce) + ForceZero(ssl->decrypt.nonce, AEAD_NONCE_SZ); + break; } } +#ifndef WOLFSSL_EARLY_DATA if (ret < 0 && !ssl->options.dtls) { SendAlert(ssl, alert_fatal, bad_record_mac); ret = VERIFY_MAC_ERROR; } +#endif return ret; } @@ -2158,6 +2188,13 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) PreSharedKey* current; byte binderKey[MAX_DIGEST_SIZE]; word16 len; + #ifdef WOLFSSL_EARLY_DATA + byte pskKey[MAX_DIGEST_SIZE]; + int pskKeySz = 0; + int seenPsk = 0; + byte cipherSuite0 = 0; + byte cipherSuite = 0; + #endif ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); if (ext == NULL) @@ -2178,21 +2215,25 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) while (current != NULL) { #ifdef HAVE_SESSION_TICKET if (current->resumption) { - /* Set the HMAC to use based on the one for the session (set into - * the extension data at the start of this function based on the - * cipher suite in the session information. - */ ssl->specs.mac_algorithm = current->hmac; + #ifdef WOLFSSL_EARLY_DATA + if (ssl->session.maxEarlyDataSz == 0) + ssl->earlyData = 0; + #endif /* Resumption PSK is master secret. */ ssl->arrays->psk_keySz = GetMsgHashSize(ssl); XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, ssl->arrays->psk_keySz); + ssl->options.cipherSuite0 = current->cipherSuite0; + ssl->options.cipherSuite = current->cipherSuite; + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; /* Derive the early secret using the PSK. */ ret = DeriveEarlySecret(ssl); if (ret != 0) return ret; - /* Derive the binder key to use to with HMAC. */ ret = DeriveBinderKeyResume(ssl, binderKey); if (ret != 0) return ret; @@ -2205,14 +2246,16 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, (char *)current->identity, ssl->arrays->client_identity, MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); - /* TODO: Forcing cipher suite to use SHA256 with PSK. */ - /* Default to SHA-256 if cb doesn't specify. */ - ssl->specs.mac_algorithm = sha256_mac; + /* TODO: Callback should be able to change ciphersuite. */ + ssl->options.cipherSuite0 = current->cipherSuite0; + ssl->options.cipherSuite = current->cipherSuite; + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; /* Derive the early secret using the PSK. */ ret = DeriveEarlySecret(ssl); if (ret != 0) return ret; - /* Derive the binder key to use to with HMAC. */ ret = DeriveBinderKey(ssl, binderKey); if (ret != 0) return ret; @@ -2224,8 +2267,19 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) continue; } + #ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData && !seenPsk) { + pskKeySz = ssl->arrays->psk_keySz; + XMEMCPY(pskKey, ssl->arrays->psk_key, pskKeySz); + cipherSuite0 = ssl->options.cipherSuite0; + cipherSuite = ssl->options.cipherSuite; + seenPsk = 1; + } + #endif + /* Derive the Finished message secret. */ - ret = DeriveFinishedSecret(ssl, binderKey, ssl->keys.client_write_MAC_secret); + ret = DeriveFinishedSecret(ssl, binderKey, + ssl->keys.client_write_MAC_secret); if (ret != 0) return ret; @@ -2243,7 +2297,34 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) client_hello); /* Hash binders to complete the hash of the ClientHello. */ - return HashOutputRaw(ssl, output + idx, len); + ret = HashOutputRaw(ssl, output + idx, len); + if (ret < 0) + return ret; + + #ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData && seenPsk) { + XMEMCPY(ssl->arrays->psk_key, pskKey, pskKeySz); + ssl->arrays->psk_keySz = pskKeySz; + + ssl->options.cipherSuite0 = cipherSuite0; + ssl->options.cipherSuite = cipherSuite; + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; + + /* Derive the early secret using the PSK. */ + ret = DeriveEarlySecret(ssl); + if (ret != 0) + return ret; + /* Derive early data encryption key. */ + ret = DeriveTls13Keys(ssl, early_data_key, ENCRYPT_SIDE_ONLY, 1); + if (ret != 0) + return ret; + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + } + #endif + return ret; } #endif @@ -2265,7 +2346,7 @@ int SendTls13ClientHello(WOLFSSL* ssl) WOLFSSL_ENTER("SendTls13ClientHello"); -#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) +#ifdef HAVE_SESSION_TICKET if (ssl->options.resuming && (ssl->session.version.major != ssl->version.major || ssl->session.version.minor != ssl->version.minor)) { @@ -2287,6 +2368,16 @@ int SendTls13ClientHello(WOLFSSL* ssl) /* Auto populate extensions supported unless user defined. */ if ((ret = TLSX_PopulateExtensions(ssl, 0)) != 0) return ret; +#ifdef WOLFSSL_EARLY_DATA + #ifndef NO_PSK + if (!ssl->options.resuming && ssl->options.client_psk_cb == NULL) + #else + if (!ssl->options.resuming) + #endif + ssl->earlyData = 0; + if (ssl->earlyData && (ret = TLSX_EarlyData_Use(ssl, 0)) < 0) + return ret; +#endif #ifdef HAVE_QSH if (QSH_Init(ssl) != 0) return MEMORY_E; @@ -2365,7 +2456,11 @@ int SendTls13ClientHello(WOLFSSL* ssl) ssl->buffers.outputBuffer.length += sendSz; - return SendBuffered(ssl); + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13ClientHello", ret); + + return ret; } /* Parse and handle a HelloRetryRequest message. @@ -2522,7 +2617,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ret != 0) return ret; -#ifdef HAVE_SESSION_TICKET +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) if (ssl->options.resuming) { PreSharedKey* psk = NULL; TLSX* ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); @@ -2535,6 +2630,27 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ssl->arrays->psk_keySz = ssl->specs.hash_size; XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz); } + #ifdef HAVE_SESSION_TICKET + else if (psk->resumption) { + ssl->arrays->psk_keySz = ssl->specs.hash_size; + XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, + ssl->specs.hash_size); + } + #endif + #ifndef NO_PSK + else if (!psk->resumption) { + /* Get the pre-shared key. */ + ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, + (char *)psk->identity, ssl->arrays->client_identity, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + /* TODO: Callback should be able to change ciphersuite. */ + ssl->options.cipherSuite0 = psk->cipherSuite0; + ssl->options.cipherSuite = psk->cipherSuite; + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; + } + #endif } #endif @@ -2590,6 +2706,14 @@ static int DoTls13EncryptedExtensions(WOLFSSL* ssl, const byte* input, /* Always encrypted. */ *inOutIdx += ssl->keys.padSz; +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData) { + TLSX* ext = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); + if (ext == NULL || !ext->val) + ssl->earlyData = 0; + } +#endif + return ret; } @@ -2633,8 +2757,8 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, return BUFFER_ERROR; #ifdef WOLFSSL_POST_HANDSHAKE_AUTH - certReqCtx = XMALLOC(sizeof(CertReqCtx) + len - 1, ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); + certReqCtx = (CertReqCtx*)XMALLOC(sizeof(CertReqCtx) + len - 1, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); if (certReqCtx == NULL) return MEMORY_E; certReqCtx->next = ssl->certReqCtx; @@ -2710,10 +2834,18 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, byte binder[MAX_DIGEST_SIZE]; word32 binderLen; word16 modes; +#ifdef WOLFSSL_EARLY_DATA + int pskCnt = 0; + TLSX* extEarlyData; +#endif ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); - if (ext == NULL) + if (ext == NULL) { +#ifdef WOLFSSL_EARLY_DATA + ssl->earlyData = 0; +#endif return 0; + } /* Extensions pushed on stack/list and PSK must be last. */ if (ssl->extensions != ext) @@ -2736,6 +2868,10 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, /* Look through all client's pre-shared keys for a match. */ current = (PreSharedKey*)ext->data; while (current != NULL) { + #ifdef WOLFSSL_EARLY_DATA + pskCnt++; + #endif + #ifndef NO_PSK XMEMCPY(ssl->arrays->client_identity, current->identity, current->identityLen); @@ -2745,22 +2881,28 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, #ifdef HAVE_SESSION_TICKET /* Decode the identity. */ if ((ret = DoClientTicket(ssl, current->identity, current->identityLen)) == WOLFSSL_TICKET_RET_OK) { - word32 now = TimeNowInMilliseconds(); - int diff = now - ssl->session.ticketSeen; + word32 now; + int diff; + + now = TimeNowInMilliseconds(); + diff = now - ssl->session.ticketSeen; diff -= current->ticketAge - ssl->session.ticketAdd; /* Check session and ticket age timeout. * Allow +/- 1000 milliseconds on ticket age. */ - if ((ssl->session.bornOn + ssl->session.timeout) * 1000 >= now || - diff < -1000 || diff - MAX_TICKET_AGE_SECS * 1000 > 1000) { + if (diff > (int)ssl->timeout * 1000 || diff < -1000 || + diff - MAX_TICKET_AGE_SECS * 1000 > 1000) { /* Invalid difference, fallback to full handshake. */ ssl->options.resuming = 0; break; } + #ifdef WOLFSSL_EARLY_DATA + ssl->options.maxEarlyDataSz = ssl->session.maxEarlyDataSz; + #endif /* Use the same cipher suite as before and set up for use. */ - ssl->options.cipherSuite0 = ssl->session.cipherSuite0; - ssl->options.cipherSuite = ssl->session.cipherSuite; + ssl->options.cipherSuite0 = ssl->session.cipherSuite0; + ssl->options.cipherSuite = ssl->session.cipherSuite; ret = SetCipherSpecs(ssl); if (ret != 0) return ret; @@ -2781,7 +2923,8 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, else #endif #ifndef NO_PSK - if ((ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, + if (ssl->options.server_psk_cb != NULL && + (ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, ssl->arrays->client_identity, ssl->arrays->psk_key, MAX_PSK_KEY_LEN)) != 0) { if (ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) @@ -2793,9 +2936,13 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, if (current->ticketAge != ssl->session.ticketAdd) return PSK_KEY_ERROR; - /* TODO: Forcing cipher suite to use SHA256 with PSK. */ - /* Default to SHA-256 if cb doesn't specify. */ - ssl->specs.mac_algorithm = sha256_mac; + /* TODO: Callback should be able to change ciphersuite. */ + /* Default to ciphersuite if cb doesn't specify. */ + ssl->options.cipherSuite0 = TLS13_BYTE; + ssl->options.cipherSuite = WOLFSSL_DEF_PSK_CIPHER; + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; /* Derive the early secret using the PSK. */ ret = DeriveEarlySecret(ssl); @@ -2817,17 +2964,17 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, /* Derive the Finished message secret. */ ret = DeriveFinishedSecret(ssl, binderKey, - ssl->keys.client_write_MAC_secret); + ssl->keys.client_write_MAC_secret); if (ret != 0) return ret; /* Derive the binder and compare with the one in the extension. */ ret = BuildTls13HandshakeHmac(ssl, - ssl->keys.client_write_MAC_secret, binder, &binderLen); + ssl->keys.client_write_MAC_secret, binder, &binderLen); if (ret != 0) return ret; if (binderLen != current->binderLen || - XMEMCMP(binder, current->binder, binderLen) != 0) { + XMEMCMP(binder, current->binder, binderLen) != 0) { return BAD_BINDER; } @@ -2842,6 +2989,26 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, if (ret != 0) return ret; +#ifdef WOLFSSL_EARLY_DATA + extEarlyData = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); + if (extEarlyData != NULL) { + if (ssl->earlyData && current == ext->data) { + extEarlyData->resp = 1; + + /* Derive early data decryption key. */ + ret = DeriveTls13Keys(ssl, early_data_key, DECRYPT_SIDE_ONLY, 1); + if (ret != 0) + return ret; + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + + ssl->earlyData = 2; + } + else + extEarlyData->resp = 0; + } +#endif + /* Get the PSK key exchange modes the client wants to negotiate. */ ext = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES); if (ext == NULL) @@ -3012,15 +3179,13 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return ret; #endif - if (!usingPSK || !ssl->options.resuming) { + if (!usingPSK) { ret = MatchSuite(ssl, &clSuites); if (ret < 0) { WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); return ret; } - } - if (!usingPSK) { #ifdef HAVE_SESSION_TICKET if (ssl->options.resuming) { ssl->options.resuming = 0; @@ -3241,12 +3406,21 @@ int SendTls13EncryptedExtensions(WOLFSSL* ssl) if ((ret = DeriveHandshakeSecret(ssl)) != 0) return ret; if ((ret = DeriveTls13Keys(ssl, handshake_key, - ENCRYPT_AND_DECRYPT_SIDE)) != 0) + ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) return ret; /* Setup encrypt/decrypt keys for following messages. */ +#ifdef WOLFSSL_EARLY_DATA + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + if (ssl->earlyData != 2) { + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + } +#else if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) return ret; +#endif length = TLSX_GetResponseSize(ssl, encrypted_extensions); sendSz = idx + length; @@ -4788,6 +4962,12 @@ static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ssl->options.side == WOLFSSL_SERVER_END && !ssl->options.handShakeDone) { +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData) { + if ((ret = DeriveTls13Keys(ssl, no_key, DECRYPT_SIDE_ONLY, 1)) != 0) + return ret; + } +#endif /* Setup keys for application data messages from client. */ if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) return ret; @@ -4893,15 +5073,35 @@ int SendTls13Finished(WOLFSSL* ssl) /* Can send application data now. */ if ((ret = DeriveMasterSecret(ssl)) != 0) return ret; - if ((ret = DeriveTls13Keys(ssl, traffic_key, - ENCRYPT_AND_DECRYPT_SIDE)) != 0) +#ifdef WOLFSSL_EARLY_DATA + if ((ret = DeriveTls13Keys(ssl, traffic_key, ENCRYPT_SIDE_ONLY, 1)) + != 0) { return ret; + } + if ((ret = DeriveTls13Keys(ssl, traffic_key, DECRYPT_SIDE_ONLY, + !ssl->earlyData)) != 0) { + return ret; + } +#else + if ((ret = DeriveTls13Keys(ssl, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, + 1)) != 0) { + return ret; + } +#endif if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) return ret; } if (ssl->options.side == WOLFSSL_CLIENT_END && !ssl->options.handShakeDone) { +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData) { + if ((ret = DeriveTls13Keys(ssl, no_key, ENCRYPT_AND_DECRYPT_SIDE, + 1)) != 0) { + return ret; + } + } +#endif /* Setup keys for application data messages. */ if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) return ret; @@ -4990,7 +5190,7 @@ static int SendTls13KeyUpdate(WOLFSSL* ssl) return ret; /* Future traffic uses new encryption keys. */ - if ((ret = DeriveTls13Keys(ssl, update_traffic_key, ENCRYPT_SIDE_ONLY)) + if ((ret = DeriveTls13Keys(ssl, update_traffic_key, ENCRYPT_SIDE_ONLY, 1)) != 0) return ret; if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) @@ -5043,8 +5243,10 @@ static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx, *inOutIdx += ssl->keys.padSz; /* Future traffic uses new decryption keys. */ - if ((ret = DeriveTls13Keys(ssl, update_traffic_key, DECRYPT_SIDE_ONLY)) != 0) + if ((ret = DeriveTls13Keys(ssl, update_traffic_key, DECRYPT_SIDE_ONLY, 1)) + != 0) { return ret; + } if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) return ret; @@ -5056,6 +5258,79 @@ static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return 0; } +#ifdef WOLFSSL_EARLY_DATA +#ifndef NO_WOLFSSL_CLIENT +/* Send the TLS v1.3 EndOfEarlyData message to indicate that there will be no + * more early application data. + * The encryption key now changes to the pre-calculated handshake key. + * + * ssl The SSL/TLS object. + * returns 0 on success and otherwise failure. + */ +static int SendTls13EndOfEarlyData(WOLFSSL* ssl) +{ + byte* output; + int ret; + int sendSz; + word32 length; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + length = 0; + sendSz = idx + length + MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, length, end_of_early_data, ssl); + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, + idx - RECORD_HEADER_SZ, handshake, 1, 0, 0); + if (sendSz < 0) + return sendSz; + + ssl->buffers.outputBuffer.length += sendSz; + + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + + return SendBuffered(ssl); +} +#endif /* !NO_WOLFSSL_CLIENT */ + +#ifndef NO_WOLFSSL_SERVER +/* Parse the TLS v1.3 EndOfEarlyData message that indicates that there will be + * no more early application data. + * The decryption key now changes to the pre-calculated handshake key. + * + * ssl The SSL/TLS object. + * returns 0 on success and otherwise failure. + */ +static int DoTls13EndOfEarlyData(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 size) +{ + word32 begin = *inOutIdx; + + (void)input; + + if ((*inOutIdx - begin) != size) + return BUFFER_ERROR; + + /* Always encrypted. */ + *inOutIdx += ssl->keys.padSz; + + return SetKeysSide(ssl, DECRYPT_SIDE_ONLY); + +} +#endif /* !NO_WOLFSSL_SERVER */ +#endif /* WOLFSSL_EARLY_DATA */ + #ifndef NO_WOLFSSL_CLIENT /* Handle a New Session Ticket handshake message. * Message contains the information required to perform resumption. @@ -5071,6 +5346,9 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size) { #ifdef HAVE_SESSION_TICKET + #ifdef WOLFSSL_EARLY_DATA + int ret; + #endif word32 begin = *inOutIdx; word32 lifetime; word32 ageAdd; @@ -5116,36 +5394,47 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, } /* Copy in ticket data (server identity). */ + ssl->timeout = lifetime; + ssl->session.timeout = lifetime; + ssl->session.cipherSuite0 = ssl->options.cipherSuite0; + ssl->session.cipherSuite = ssl->options.cipherSuite; + ssl->session.ticketSeen = TimeNowInMilliseconds(); + ssl->session.ticketAdd = ageAdd; + #ifdef WOLFSSL_EARLY_DATA + ssl->session.maxEarlyDataSz = ssl->options.maxEarlyDataSz; + #endif XMEMCPY(ssl->session.ticket, input + *inOutIdx, length); *inOutIdx += length; - ssl->timeout = lifetime; - ssl->session.ticketLen = length; - ssl->session.timeout = lifetime; - ssl->session.ticketAdd = ageAdd; - ssl->session.ticketSeen = TimeNowInMilliseconds(); + ssl->session.ticketLen = length; + if (ssl->session_ticket_cb != NULL) { ssl->session_ticket_cb(ssl, ssl->session.ticket, ssl->session.ticketLen, ssl->session_ticket_ctx); } + ssl->options.haveSessionId = 1; XMEMCPY(ssl->arrays->sessionID, ssl->session.ticket + length - ID_LEN, ID_LEN); - ssl->session.cipherSuite0 = ssl->options.cipherSuite0; - ssl->session.cipherSuite = ssl->options.cipherSuite; - #ifndef NO_SESSION_CACHE - AddSession(ssl); - #endif - /* No extension support - skip over extensions. */ if ((*inOutIdx - begin) + EXTS_SZ > size) return BUFFER_ERROR; ato16(input + *inOutIdx, &length); *inOutIdx += EXTS_SZ; if ((*inOutIdx - begin) + length != size) return BUFFER_ERROR; + #ifdef WOLFSSL_EARLY_DATA + ret = TLSX_Parse(ssl, (byte *)input + (*inOutIdx), length, session_ticket, + NULL); + if (ret != 0) + return ret; + #endif *inOutIdx += length; + #ifndef NO_SESSION_CACHE + AddSession(ssl); + #endif + /* Always encrypted. */ *inOutIdx += ssl->keys.padSz; @@ -5173,6 +5462,7 @@ int SendTls13NewSessionTicket(WOLFSSL* ssl) byte* output; int ret; int sendSz; + word32 extSz; word32 length; word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; @@ -5181,9 +5471,18 @@ int SendTls13NewSessionTicket(WOLFSSL* ssl) if (ret != 0) return ret; } +#ifdef WOLFSSL_EARLY_DATA + ssl->session.maxEarlyDataSz = ssl->options.maxEarlyDataSz; + if (ssl->session.maxEarlyDataSz > 0) + TLSX_EarlyData_Use(ssl, ssl->session.maxEarlyDataSz); + extSz = TLSX_GetResponseSize(ssl, session_ticket); +#else + extSz = EXTS_SZ; +#endif + /* Lifetime | Age Add | Ticket | Extensions */ length = SESSION_HINT_SZ + SESSION_ADD_SZ + LENGTH_SZ + - ssl->session.ticketLen + EXTS_SZ; + ssl->session.ticketLen + extSz; sendSz = idx + length + MAX_MSG_EXTRA; /* Check buffers are big enough and grow if needed. */ @@ -5211,9 +5510,13 @@ int SendTls13NewSessionTicket(WOLFSSL* ssl) XMEMCPY(output + idx, ssl->session.ticket, ssl->session.ticketLen); idx += ssl->session.ticketLen; +#ifdef WOLFSSL_EARLY_DATA + idx += TLSX_WriteResponse(ssl, output + idx, session_ticket); +#else /* No extension support - empty extensions. */ c16toa(0, output + idx); idx += EXTS_SZ; +#endif ssl->options.haveSessionId = 1; @@ -5278,6 +5581,17 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) break; #endif +#ifndef NO_WOLFSSL_SERVER + case end_of_early_data: + if (ssl->msgsReceived.got_end_of_early_data == 1) { + WOLFSSL_MSG("Too many EndOfEarlyData received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_end_of_early_data++; + + break; +#endif + #ifndef NO_WOLFSSL_CLIENT case hello_retry_request: if (ssl->msgsReceived.got_hello_retry_request) { @@ -5499,6 +5813,15 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, break; #endif /* !NO_RSA || HAVE_ECC */ +#ifdef WOLFSSL_EARLY_DATA + #ifndef NO_WOLFSSL_SERVER + case end_of_early_data: + WOLFSSL_MSG("processing end of early data"); + ret = DoTls13EndOfEarlyData(ssl, input, inOutIdx, size); + break; + #endif +#endif + case finished: WOLFSSL_MSG("processing finished"); ret = DoTls13Finished(ssl, input, inOutIdx, size, totalSz, NO_SNIFF); @@ -5547,23 +5870,44 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, return ret; if ((ret = DeriveHandshakeSecret(ssl)) != 0) return ret; - if ((ret = DeriveTls13Keys(ssl, handshake_key, - ENCRYPT_AND_DECRYPT_SIDE)) != 0) - return ret; - /* setup decrypt keys for following messages */ + if ((ret = DeriveTls13Keys(ssl, handshake_key, + ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) { + return ret; + } +#ifdef WOLFSSL_EARLY_DATA if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) return ret; - if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) +#else + if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) return ret; +#endif } +#ifdef WOLFSSL_EARLY_DATA + if (type == encrypted_extensions && + ssl->options.side == WOLFSSL_CLIENT_END) { + if (!ssl->earlyData) + { + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + } + } +#endif if (type == finished && ssl->options.side == WOLFSSL_CLIENT_END) { if ((ret = DeriveMasterSecret(ssl)) != 0) return ret; +#ifdef WOLFSSL_EARLY_DATA if ((ret = DeriveTls13Keys(ssl, traffic_key, - ENCRYPT_AND_DECRYPT_SIDE)) != 0) + ENCRYPT_AND_DECRYPT_SIDE, !ssl->earlyData)) != 0) { return ret; + } +#else + if ((ret = DeriveTls13Keys(ssl, traffic_key, + ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) { + return ret; + } +#endif } #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) @@ -5738,6 +6082,12 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) ssl->options.connectState = CLIENT_HELLO_SENT; WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT"); + #ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData) { + ssl->options.handShakeState = CLIENT_HELLO_COMPLETE; + return SSL_SUCCESS; + } + #endif FALL_THROUGH; case CLIENT_HELLO_SENT: @@ -5805,7 +6155,22 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) FALL_THROUGH; case FIRST_REPLY_DONE: - #ifndef NO_CERTS + #ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData) { + if ((ssl->error = SendTls13EndOfEarlyData(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: end_of_early_data"); + } + #endif + + ssl->options.connectState = FIRST_REPLY_FIRST; + WOLFSSL_MSG("connect state: FIRST_REPLY_FIRST"); + FALL_THROUGH; + + case FIRST_REPLY_FIRST: + #ifndef NO_CERTS if (!ssl->options.resuming && ssl->options.sendVerify) { ssl->error = SendTls13Certificate(ssl); if (ssl->error != 0) { @@ -5814,14 +6179,15 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) } WOLFSSL_MSG("sent: certificate"); } - #endif + #endif - ssl->options.connectState = FIRST_REPLY_FIRST; - WOLFSSL_MSG("connect state: FIRST_REPLY_FIRST"); + ssl->options.connectState = FIRST_REPLY_SECOND; + WOLFSSL_MSG("connect state: FIRST_REPLY_SECOND"); FALL_THROUGH; - case FIRST_REPLY_FIRST: - #ifndef NO_CERTS + case FIRST_REPLY_SECOND: + + #ifndef NO_CERTS if (!ssl->options.resuming && ssl->options.sendVerify) { ssl->error = SendTls13CertificateVerify(ssl); if (ssl->error != 0) { @@ -5830,13 +6196,13 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) } WOLFSSL_MSG("sent: certificate verify"); } - #endif + #endif - ssl->options.connectState = FIRST_REPLY_SECOND; - WOLFSSL_MSG("connect state: FIRST_REPLY_SECOND"); + ssl->options.connectState = FIRST_REPLY_THIRD; + WOLFSSL_MSG("connect state: FIRST_REPLY_THIRD"); FALL_THROUGH; - case FIRST_REPLY_SECOND: + case FIRST_REPLY_THIRD: if ((ssl->error = SendTls13Finished(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return SSL_FATAL_ERROR; @@ -5848,7 +6214,7 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) FALL_THROUGH; case FINISHED_DONE: -#ifndef NO_HANDSHAKE_DONE_CB + #ifndef NO_HANDSHAKE_DONE_CB if (ssl->hsDoneCb != NULL) { int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); if (cbret < 0) { @@ -5857,7 +6223,7 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) return SSL_FATAL_ERROR; } } -#endif /* NO_HANDSHAKE_DONE_CB */ + #endif /* NO_HANDSHAKE_DONE_CB */ WOLFSSL_LEAVE("wolfSSL_connect_TLSv13()", SSL_SUCCESS); return SSL_SUCCESS; @@ -6057,8 +6423,8 @@ int wolfSSL_request_certificate(WOLFSSL* ssl) if (!ssl->options.postHandshakeAuth) return POST_HAND_AUTH_ERROR; - certReqCtx = XMALLOC(sizeof(CertReqCtx), ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); + certReqCtx = (CertReqCtx*)XMALLOC(sizeof(CertReqCtx), ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); if (certReqCtx == NULL) return MEMORY_E; XMEMSET(certReqCtx, 0, sizeof(CertReqCtx)); @@ -6260,11 +6626,18 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) ssl->options.acceptState = ACCEPT_FINISHED_DONE; WOLFSSL_MSG("accept state ACCEPT_FINISHED_DONE"); +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData) { + ssl->options.handShakeState = SERVER_FINISHED_COMPLETE; + return SSL_SUCCESS; + } +#endif FALL_THROUGH; case ACCEPT_FINISHED_DONE : #ifdef HAVE_SESSION_TICKET - /* TODO: [TLS13] Section 4.5.1 Note. */ +#ifdef RESUMPTION_SECRET_CALCULATED_WITHOUT_CLIENT_FINISHED + /* TODO: [TLS13] Section 4.6.1 Note. */ if (!ssl->options.resuming && !ssl->options.verifyPeer && !ssl->options.noTicketTls13 && ssl->ctx->ticketEncCb != NULL) { if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) { @@ -6272,6 +6645,7 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) return SSL_FATAL_ERROR; } } +#endif #endif /* HAVE_SESSION_TICKET */ ssl->options.acceptState = TICKET_SENT; WOLFSSL_MSG("accept state TICKET_SENT"); @@ -6290,7 +6664,12 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) case ACCEPT_SECOND_REPLY_DONE : #ifdef HAVE_SESSION_TICKET - if (!ssl->options.resuming && ssl->options.verifyPeer && +#ifdef RESUMPTION_SECRET_CALCULATED_WITHOUT_CLIENT_FINISHED + if (!ssl->options.verifyPeer) { + } + else +#endif + if (!ssl->options.resuming && !ssl->options.noTicketTls13 && ssl->ctx->ticketEncCb != NULL) { if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); @@ -6333,9 +6712,139 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) } } +#ifdef WOLFSSL_EARLY_DATA +/* Sets the maximum amount of early data that can be seen by server when using + * session tickets for resumption. + * A value of zero indicates no early data is to be sent by client using session + * tickets. + * + * ctx The SSL/TLS CTX object. + * sz Maximum size of the early data. + * returns BAD_FUNC_ARG when ctx is NULL, SIDE_ERROR when not a server and + * 0 on success. + */ +int wolfSSL_CTX_set_max_early_data(WOLFSSL_CTX* ctx, unsigned int sz) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + if (ctx->method->side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ctx->maxEarlyDataSz = sz; + + return 0; +} + +/* Sets the maximum amount of early data that can be seen by server when using + * session tickets for resumption. + * A value of zero indicates no early data is to be sent by client using session + * tickets. + * + * ssl The SSL/TLS object. + * sz Maximum size of the early data. + * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3, + * SIDE_ERROR when not a server and 0 on success. + */ +int wolfSSL_set_max_early_data(WOLFSSL* ssl, unsigned int sz) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + if (ssl->options.side != WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ssl->options.maxEarlyDataSz = sz; + + return 0; +} + +/* Write early data to the server. + * + * ssl The SSL/TLS object. + * data Early data to write + * sz The size of the eary data in bytes. + * outSz The number of early data bytes written. + * returns BAD_FUNC_ARG when ssl, data or outSz is NULL or when sz is negative; + * SIDE ERROR when not a client; or the number of early data bytes written. + */ +int wolfSSL_write_early_data(WOLFSSL* ssl, const void* data, int sz, int* outSz) +{ + int ret = 0; + + WOLFSSL_ENTER("SSL_write_early_data()"); + + if (ssl == NULL || data == NULL || sz < 0 || outSz == NULL) + return BAD_FUNC_ARG; + + if (ssl->options.side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + + if (ssl->options.handShakeState == NULL_STATE) { + ssl->earlyData = 1; + ret = wolfSSL_connect_TLSv13(ssl); + if (ret <= 0) + return SSL_FATAL_ERROR; + } + if (ssl->options.handShakeState == CLIENT_HELLO_COMPLETE) { + ret = SendData(ssl, data, sz); + if (ret > 0) + *outSz = ret; + } + + WOLFSSL_LEAVE("SSL_write_early_data()", ret); + + if (ret < 0) + ret = SSL_FATAL_ERROR; + return ret; +} + +/* Read the any early data from the client. + * + * ssl The SSL/TLS object. + * data Buffer to put the early data into. + * sz The size of the buffer in bytes. + * outSz The number of early data bytes read. + * returns BAD_FUNC_ARG when ssl, data or outSz is NULL or when sz is negative; + * SIDE ERROR when not a server; or the number of early data bytes read. + */ +int wolfSSL_read_early_data(WOLFSSL* ssl, void* data, int sz, int* outSz) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_read_early_data()"); + + + if (ssl == NULL || data == NULL || sz < 0 || outSz == NULL) + return BAD_FUNC_ARG; + + if (ssl->options.side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + + if (ssl->options.handShakeState == NULL_STATE) { + ssl->earlyData = 1; + ret = wolfSSL_accept_TLSv13(ssl); + if (ret <= 0) + return SSL_FATAL_ERROR; + } + if (ssl->options.handShakeState == SERVER_FINISHED_COMPLETE) { + ret = ReceiveData(ssl, (byte*)data, sz, FALSE); + if (ret > 0) + *outSz = ret; + if (ssl->error == ZERO_RETURN) + ssl->error = SSL_ERROR_NONE; + } + else + ret = 0; + + WOLFSSL_LEAVE("wolfSSL_read_early_data()", ret); + + if (ret < 0) + ret = SSL_FATAL_ERROR; + return ret; +} +#endif #undef ERROR_OUT -#endif /* WOLFCRYPT_ONLY */ +#endif /* !WOLFCRYPT_ONLY */ #endif /* WOLFSSL_TLS13 */ diff --git a/tests/test-psk-no-id.conf b/tests/test-psk-no-id.conf index f3a997e25..c5c0a190e 100644 --- a/tests/test-psk-no-id.conf +++ b/tests/test-psk-no-id.conf @@ -261,3 +261,43 @@ -v 4 -l TLS13-AES128-GCM-SHA256 +# server TLSv1.3 accepting EarlyData using PSK +-v 4 +-l TLS13-AES128-GCM-SHA256 +-r +-s +-0 + +# client TLSv1.3 sending EarlyData using PSK +-v 4 +-l TLS13-AES128-GCM-SHA256 +-r +-s +-0 + +# server TLSv1.3 not accepting EarlyData using PSK +-v 4 +-l TLS13-AES128-GCM-SHA256 +-r +-s + +# client TLSv1.3 sending EarlyData using PSK +-v 4 +-l TLS13-AES128-GCM-SHA256 +-r +-s +-0 + +# server TLSv1.3 accepting EarlyData using PSK +-v 4 +-l TLS13-AES128-GCM-SHA256 +-r +-s +-0 + +# client TLSv1.3 not sending EarlyData using PSK +-v 4 +-l TLS13-AES128-GCM-SHA256 +-r +-s + diff --git a/tests/test-tls13.conf b/tests/test-tls13.conf index b0c2aa92f..4f2c30eea 100644 --- a/tests/test-tls13.conf +++ b/tests/test-tls13.conf @@ -105,3 +105,37 @@ -A ./certs/server-ecc.pem -t +# server TLSv1.3 accepting EarlyData +-v 4 +-l TLS13-AES128-GCM-SHA256 +-r +-0 + +# client TLSv1.3 sending EarlyData +-v 4 +-l TLS13-AES128-GCM-SHA256 +-r +-0 + +# server TLSv1.3 not accepting EarlyData +-v 4 +-l TLS13-AES128-GCM-SHA256 +-r + +# client TLSv1.3 sending EarlyData +-v 4 +-l TLS13-AES128-GCM-SHA256 +-r +-0 + +# server TLSv1.3 accepting EarlyData +-v 4 +-l TLS13-AES128-GCM-SHA256 +-r +-0 + +# client TLSv1.3 not sending EarlyData +-v 4 +-l TLS13-AES128-GCM-SHA256 +-r + diff --git a/wolfssl/internal.h b/wolfssl/internal.h index c35b7b2e7..56e349398 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -978,6 +978,7 @@ enum Misc { SESSION_HINT_SZ = 4, /* session timeout hint */ SESSION_ADD_SZ = 4, /* session age add */ MAX_LIFETIME = 604800, /* maximum ticket lifetime */ + MAX_EARLY_DATA_SZ = 4096, /* maximum early data size */ RAN_LEN = 32, /* random length */ SEED_LEN = RAN_LEN * 2, /* tls prf seed length */ @@ -1784,6 +1785,9 @@ typedef enum { #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TLSX_PRE_SHARED_KEY = 0x0029, #endif + #ifdef WOLFSSL_EARLY_DATA + TLSX_EARLY_DATA = 0x002a, + #endif TLSX_SUPPORTED_VERSIONS = 0x002b, #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TLSX_PSK_KEY_EXCHANGE_MODES = 0x002d, @@ -2082,6 +2086,8 @@ typedef struct PreSharedKey { word16 identityLen; /* Length of identity */ byte* identity; /* PSK identity */ word32 ticketAge; /* Age of the ticket */ + byte cipherSuite0; /* Cipher Suite */ + byte cipherSuite; /* Cipher Suite */ word32 binderLen; /* Length of HMAC */ byte binder[MAX_DIGEST_SIZE]; /* HMAC of hanshake */ byte hmac; /* HMAC algorithm */ @@ -2096,6 +2102,7 @@ WOLFSSL_LOCAL word16 TLSX_PreSharedKey_GetSizeBinders(PreSharedKey* list, byte msgType); WOLFSSL_LOCAL int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity, word16 len, word32 age, byte hmac, + byte cipherSuite0, byte cipherSuite, byte resumption, PreSharedKey **preSharedKey); @@ -2104,11 +2111,22 @@ enum PskKeyExchangeMode { PSK_DHE_KE }; +/* User can define this. */ +#ifndef WOLFSSL_DEF_PSK_CIPHER +#define WOLFSSL_DEF_PSK_CIPHER TLS_AES_128_GCM_SHA256 +#endif + WOLFSSL_LOCAL int TLSX_PskKeModes_Use(WOLFSSL* ssl, byte modes); + +#ifdef WOLFSSL_EARLY_DATA +WOLFSSL_LOCAL int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 max); +#endif #endif /* HAVE_SESSION_TICKET || !NO_PSK */ /* The types of keys to derive for. */ enum DeriveKeyType { + no_key, + early_data_key, handshake_key, traffic_key, update_traffic_key @@ -2225,6 +2243,9 @@ struct WOLFSSL_CTX { wc_psk_server_callback server_psk_cb; /* server callback */ char server_hint[MAX_PSK_ID_LEN + NULL_TERM_LEN]; #endif /* HAVE_SESSION_TICKET || !NO_PSK */ +#ifdef WOLFSSL_EARLY_DATA + word32 maxEarlyDataSz; +#endif #ifdef HAVE_ANON byte haveAnon; /* User wants to allow Anon suites */ #endif /* HAVE_ANON */ @@ -2556,6 +2577,9 @@ struct WOLFSSL_SESSION { word32 ticketSeen; /* Time ticket seen (ms) */ word32 ticketAdd; /* Added by client */ #endif + #ifdef WOLFSSL_EARLY_DATA + word32 maxEarlyDataSz; + #endif byte* ticket; word16 ticketLen; byte staticTicket[SESSION_TICKET_LEN]; @@ -2806,6 +2830,9 @@ typedef struct Options { #ifdef HAVE_ECC short minEccKeySz; /* minimum ECC key size */ #endif +#ifdef WOLFSSL_EARLY_DATA + word32 maxEarlyDataSz; +#endif } Options; @@ -3017,6 +3044,7 @@ typedef struct MsgsReceived { word16 got_server_hello:1; word16 got_hello_verify_request:1; word16 got_session_ticket:1; + word16 got_end_of_early_data:1; word16 got_hello_retry_request:1; word16 got_encrypted_extensions:1; word16 got_certificate:1; @@ -3326,6 +3354,10 @@ struct WOLFSSL { #ifdef WOLFSSL_JNI void* jObjectRef; /* reference to WolfSSLSession in JNI wrapper */ #endif /* WOLFSSL_JNI */ +#ifdef WOLFSSL_EARLY_DATA + int earlyData; + word32 earlyDataSz; +#endif }; @@ -3426,27 +3458,34 @@ typedef struct DtlsHandShakeHeader { enum HandShakeType { - hello_request = 0, - client_hello = 1, - server_hello = 2, - hello_verify_request = 3, /* DTLS addition */ - session_ticket = 4, - hello_retry_request = 6, - encrypted_extensions = 8, - certificate = 11, - server_key_exchange = 12, - certificate_request = 13, - server_hello_done = 14, - certificate_verify = 15, - client_key_exchange = 16, - finished = 20, - certificate_status = 22, - key_update = 24, - change_cipher_hs = 55, /* simulate unique handshake type for sanity - checks. record layer change_cipher - conflicts with handshake finished */ - message_hash = 254, /* synthetic message type for TLS v1.3 */ - no_shake = 255 /* used to initialize the DtlsMsg record */ + hello_request = 0, + client_hello = 1, + server_hello = 2, + hello_verify_request = 3, /* DTLS addition */ + session_ticket = 4, + end_of_early_data = 5, + hello_retry_request = 6, + encrypted_extensions = 8, + certificate = 11, + server_key_exchange = 12, + certificate_request = 13, + server_hello_done = 14, + certificate_verify = 15, + client_key_exchange = 16, + finished = 20, + certificate_status = 22, + key_update = 24, + change_cipher_hs = 55, /* simulate unique handshake type for sanity + checks. record layer change_cipher + conflicts with handshake finished */ + message_hash = 254, /* synthetic message type for TLS v1.3 */ + no_shake = 255 /* used to initialize the DtlsMsg record */ +}; + +enum ProvisionSide { + PROVISION_CLIENT = 1, + PROVISION_SERVER = 2, + PROVISION_CLIENT_SERVER = 3 }; @@ -3492,7 +3531,7 @@ WOLFSSL_LOCAL int MakeMasterSecret(WOLFSSL*); WOLFSSL_LOCAL int AddSession(WOLFSSL*); WOLFSSL_LOCAL int DeriveKeys(WOLFSSL* ssl); -WOLFSSL_LOCAL int StoreKeys(WOLFSSL* ssl, const byte* keyData); +WOLFSSL_LOCAL int StoreKeys(WOLFSSL* ssl, const byte* keyData, int side); WOLFSSL_LOCAL int IsTLS(const WOLFSSL* ssl); WOLFSSL_LOCAL int IsAtLeastTLSv1_2(const WOLFSSL* ssl); diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 813733241..d93d500b7 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -399,9 +399,6 @@ WOLFSSL_API void wolfSSL_set_using_nonblock(WOLFSSL*, int); WOLFSSL_API int wolfSSL_get_using_nonblock(WOLFSSL*); /* please see note at top of README if you get an error from connect */ WOLFSSL_API int wolfSSL_connect(WOLFSSL*); -#ifdef WOLFSSL_TLS13 -WOLFSSL_API int wolfSSL_connect_TLSv13(WOLFSSL*); -#endif WOLFSSL_API int wolfSSL_write(WOLFSSL*, const void*, int); WOLFSSL_API int wolfSSL_read(WOLFSSL*, void*, int); WOLFSSL_API int wolfSSL_peek(WOLFSSL*, void*, int); @@ -415,7 +412,17 @@ WOLFSSL_API int wolfSSL_update_keys(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_CTX_allow_post_handshake_auth(WOLFSSL_CTX* ctx); WOLFSSL_API int wolfSSL_allow_post_handshake_auth(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_request_certificate(WOLFSSL* ssl); + +WOLFSSL_API int wolfSSL_connect_TLSv13(WOLFSSL*); WOLFSSL_API int wolfSSL_accept_TLSv13(WOLFSSL*); + +#ifdef WOLFSSL_EARLY_DATA +WOLFSSL_API int wolfSSL_CTX_set_max_early_data(WOLFSSL_CTX* ctx, + unsigned int sz); +WOLFSSL_API int wolfSSL_set_max_early_data(WOLFSSL* ssl, unsigned int sz); +WOLFSSL_API int wolfSSL_write_early_data(WOLFSSL*, const void*, int, int*); +WOLFSSL_API int wolfSSL_read_early_data(WOLFSSL*, void*, int, int*); +#endif #endif WOLFSSL_API void wolfSSL_CTX_free(WOLFSSL_CTX*); WOLFSSL_API void wolfSSL_free(WOLFSSL*); From 1549a60aa536ed422719aca2077135b97ea8ad56 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Tue, 20 Jun 2017 11:03:14 +1000 Subject: [PATCH 2/5] Put back Draft 18 code --- src/tls13.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/src/tls13.c b/src/tls13.c index 8be4e91f0..2c1bdc3e8 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -298,6 +298,8 @@ static const byte tls13ProtocolLabel[TLS13_PROTOCOL_LABEL_SZ + 1] = "TLS 1.3, "; static const byte tls13ProtocolLabel[TLS13_PROTOCOL_LABEL_SZ + 1] = "tls13 "; #endif +#if !defined(WOLFSSL_TLS13_DRAFT_18) || defined(HAVE_SESSION_TICKET) || \ + !defined(NO_PSK) /* Derive a key from a message. * * ssl The SSL/TLS object. @@ -387,6 +389,7 @@ static int DeriveKeyMsg(WOLFSSL* ssl, byte* output, int outputLen, protocol, protocolLen, label, labelLen, hash, hashSz, digestAlg); } +#endif /* Derive a key. * @@ -2733,10 +2736,12 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, { word16 len; word32 begin = *inOutIdx; - int ret; + int ret = 0; +#ifndef WOLFSSL_TLS13_DRAFT_18 Suites peerSuites; #ifdef WOLFSSL_POST_HANDSHAKE_AUTH CertReqCtx* certReqCtx; +#endif #endif WOLFSSL_ENTER("DoTls13CertificateRequest"); @@ -2756,6 +2761,57 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, if (ssl->options.connectState < FINISHED_DONE && len > 0) return BUFFER_ERROR; +#ifdef WOLFSSL_TLS13_DRAFT_18 + *inOutIdx += len; + + /* Signature and hash algorithms. */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + PickHashSigAlgo(ssl, input + *inOutIdx, len); + *inOutIdx += len; + + /* Length of certificate authority data. */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + + /* Certificate authorities. */ + while (len) { + word16 dnSz; + + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &dnSz); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + dnSz > size) + return BUFFER_ERROR; + + *inOutIdx += dnSz; + len -= OPAQUE16_LEN + dnSz; + } + + /* Certificate extensions */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + *inOutIdx += len; + ssl->options.sendVerify = SEND_CERT; + + /* This message is always encrypted so add encryption padding. */ + *inOutIdx += ssl->keys.padSz; +#else #ifdef WOLFSSL_POST_HANDSHAKE_AUTH certReqCtx = (CertReqCtx*)XMALLOC(sizeof(CertReqCtx) + len - 1, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -2795,6 +2851,7 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, /* This message is always encrypted so add encryption padding. */ *inOutIdx += ssl->keys.padSz; +#endif #if !defined(NO_WOLFSSL_CLIENT) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) if (ssl->options.side == WOLFSSL_CLIENT_END && @@ -3489,6 +3546,46 @@ int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, int reqCtxLen) if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher) return 0; /* not needed */ +#ifdef WOLFSSL_TLS13_DRAFT_18 + (void)reqCtx; + + i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + reqSz = OPAQUE8_LEN + reqCtxLen + REQ_HEADER_SZ + REQ_HEADER_SZ; + reqSz += LENGTH_SZ + ssl->suites->hashSigAlgoSz; + + sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz; + /* Always encrypted and make room for padding. */ + sendSz += MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, reqSz, certificate_request, ssl); + + /* Certificate request context. */ + output[i++] = reqCtxLen; + + /* supported hash/sig */ + c16toa(ssl->suites->hashSigAlgoSz, &output[i]); + i += LENGTH_SZ; + + XMEMCPY(&output[i], ssl->suites->hashSigAlgo, ssl->suites->hashSigAlgoSz); + i += ssl->suites->hashSigAlgoSz; + + /* Certificate authorities not supported yet - empty buffer. */ + c16toa(0, &output[i]); + i += REQ_HEADER_SZ; + + /* Certificate extensions. */ + c16toa(0, &output[i]); /* auth's */ + i += REQ_HEADER_SZ; +#else i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; reqSz = OPAQUE8_LEN + reqCtxLen + TLSX_GetResponseSize(ssl, certificate_request); @@ -3517,6 +3614,7 @@ int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, int reqCtxLen) /* Certificate extensions. */ i += TLSX_WriteResponse(ssl, output + i, certificate_request); +#endif /* Always encrypted. */ sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, From decdf7ae8beaaddb77225aec35c081f01fc3b737 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 21 Jun 2017 16:56:51 +1000 Subject: [PATCH 3/5] Cleanup --- examples/client/client.c | 4 + scripts/tls13.test | 80 +++++++ src/internal.c | 5 +- src/tls13.c | 471 +++++++++++++++++++-------------------- wolfssl/internal.h | 17 -- 5 files changed, 315 insertions(+), 262 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index 0ce953a52..389269458 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -1941,6 +1941,10 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) ClientRead(ssl, reply, sizeof(reply)-1, 1); +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + if (postHandAuth) + ClientWrite(ssl, msg, msgSz); +#endif if (sendGET) { /* get html */ ClientRead(ssl, reply, sizeof(reply)-1, 0); } diff --git a/scripts/tls13.test b/scripts/tls13.test index 27a891f58..95c7044ca 100755 --- a/scripts/tls13.test +++ b/scripts/tls13.test @@ -95,6 +95,22 @@ if [ $RESULT -ne 0 ]; then fi echo "" +# Use HelloRetryRequest with TLS v1.3 server / TLS v1.3 client - SHA384. +echo -e "\n\nTLS v1.3 HelloRetryRequest - SHA384" +port=0 +./examples/server/server -v 4 -l TLS13-AES256-GCM-SHA384 -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 4 -J -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nTLS v1.3 HelloRetryRequest with SHA384 not working" + do_cleanup + exit 1 +fi +echo "" + # Resumption TLS v1.3 server / TLS v1.3 client. echo -e "\n\nTLS v1.3 resumption" port=0 @@ -111,6 +127,22 @@ if [ $RESULT -ne 0 ]; then fi echo "" +# Resumption TLS v1.3 server / TLS v1.3 client - SHA384 +echo -e "\n\nTLS v1.3 resumption - SHA384" +port=0 +./examples/server/server -v 4 -l TLS13-AES256-GCM-SHA384 -r -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 4 -l TLS13-AES256-GCM-SHA384 -r -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nTLS v1.3 resumption with SHA384 not working" + do_cleanup + exit 1 +fi +echo "" + # Usual TLS v1.3 server / TLS v1.3 client and ECC certificates. echo -e "\n\nTLS v1.3 server with TLS v1.3 client - ECC certificates" port=0 @@ -127,6 +159,22 @@ if [ $RESULT -ne 0 ]; then fi echo "" +# Usual TLS v1.3 server / TLS v1.3 client and no client certificate. +echo -e "\n\nTLS v1.3 server with TLS v1.3 client - no client cretificate" +port=0 +./examples/server/server -v 4 -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 4 -x -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nTLS v1.3 and no client certificate not working" + do_cleanup + exit 1 +fi +echo "" + # Usual TLS v1.3 server / TLS v1.3 client and DH Key. echo -e "\n\nTLS v1.3 server with TLS v1.3 client - DH Key Exchange" port=0 @@ -306,6 +354,38 @@ if [ $RESULT -ne 0 ]; then fi echo "" +# TLS 1.3 server / TLS 1.3 client don't use (EC)DHE with PSK. +echo -e "\n\nTLS v1.3 KeyUpdate" +port=0 +./examples/server/server -v 4 -r -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 4 -r -K -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS v1.3 KeyUpdate" + do_cleanup + exit 1 +fi +echo "" + +# TLS 1.3 server / TLS 1.3 client and Post-Handshake Authentication. +echo -e "\n\nTLS v1.3 Post-Handshake Authentication" +port=0 +./examples/server/server -v 4 -Q -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 4 -Q -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS v1.3 Post-Handshake Auth" + do_cleanup + exit 1 +fi +echo "" + echo -e "\nALL Tests Passed" exit 0 diff --git a/src/internal.c b/src/internal.c index d8230a893..a4ff376b9 100755 --- a/src/internal.c +++ b/src/internal.c @@ -7480,7 +7480,8 @@ static void FreeProcPeerCertArgs(WOLFSSL* ssl, void* pArgs) } } -int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 totalSz) +int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) { int ret = 0; #ifdef WOLFSSL_ASYNC_CRYPT @@ -13067,7 +13068,7 @@ int SendCertificateStatus(WOLFSSL* ssl) #ifdef WOLFSSL_SMALL_STACK cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap, - DYNAMIC_TYPE_TMP_DCERT); + DYNAMIC_TYPE_DCERT); if (cert == NULL) return MEMORY_E; #endif diff --git a/src/tls13.c b/src/tls13.c index 2c1bdc3e8..522e34f15 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -365,9 +365,6 @@ static int DeriveKeyMsg(WOLFSSL* ssl, byte* output, int outputLen, digestAlg = SHA512; break; #endif - - default: - return BAD_FUNC_ARG; } if (ret != 0) @@ -992,16 +989,9 @@ static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) switch (secret) { #ifdef WOLFSSL_EARLY_DATA case early_data_key: - if (provision & PROVISION_CLIENT) { - ret = DeriveEarlyTrafficSecret(ssl, ssl->arrays->clientSecret); - if (ret != 0) - goto end; - } - if (provision & PROVISION_SERVER) { - ret = DeriveEarlyTrafficSecret(ssl, ssl->arrays->serverSecret); - if (ret != 0) - goto end; - } + ret = DeriveEarlyTrafficSecret(ssl, ssl->arrays->clientSecret); + if (ret != 0) + goto end; break; #endif @@ -1360,6 +1350,10 @@ static int HashInputRaw(WOLFSSL* ssl, const byte* input, int sz) } #endif +#ifndef WOLFSSL_TLS13_DRAFT_18 +/* The offset into MessageHash of the low byte of the length field. */ +#define MSG_HASH_LEN_OFFSET 3 + /* Restart the Hanshake hash with a hash of the previous messages. * * ssl The SSL/TLS object. @@ -1381,19 +1375,19 @@ static int RestartHandshakeHash(WOLFSSL* ssl) switch (ssl->specs.mac_algorithm) { #ifndef NO_SHA256 case sha256_mac: - header[3] = SHA256_DIGEST_SIZE; + header[MSG_HASH_LEN_OFFSET] = SHA256_DIGEST_SIZE; hash = hashes.sha256; break; #endif #ifdef WOLFSSL_SHA384 case sha384_mac: - header[3] = SHA384_DIGEST_SIZE; + header[MSG_HASH_LEN_OFFSET] = SHA384_DIGEST_SIZE; hash = hashes.sha384; break; #endif #ifdef WOLFSSL_SHA512 case sha512_mac: - header[3] = SHA512_DIGEST_SIZE; + header[MSG_HASH_LEN_OFFSET] = SHA512_DIGEST_SIZE; hash = hashes.sha512; break; #endif @@ -1407,6 +1401,7 @@ static int RestartHandshakeHash(WOLFSSL* ssl) return ret; return HashOutputRaw(ssl, hash, header[3]); } +#endif /* Extract the handshake header information. @@ -1968,7 +1963,7 @@ int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz) return ret; } -/* Persistable BuildMessage arguments */ +/* Persistable BuildTls13Message arguments */ typedef struct BuildMsg13Args { word32 sz; word32 idx; @@ -2014,10 +2009,6 @@ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, WOLFSSL_ENTER("BuildTls13Message"); - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - ret = WC_NOT_PENDING_E; #ifdef WOLFSSL_ASYNC_CRYPT if (asyncOkay) { @@ -2051,11 +2042,12 @@ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, switch (ssl->options.buildMsgState) { case BUILD_MSG_BEGIN: { - if (!sizeOnly && (output == NULL || input == NULL)) + if (output == NULL || input == NULL) return BAD_FUNC_ARG; /* catch mistaken sizeOnly parameter */ if (sizeOnly && (output || input)) { - WOLFSSL_MSG("BuildMessage with sizeOnly doesn't need input or output"); + WOLFSSL_MSG("BuildTls13Message with sizeOnly doesn't need " + "input or output"); return BAD_FUNC_ARG; } @@ -2149,33 +2141,52 @@ exit_buildmsg: } #ifndef NO_WOLFSSL_CLIENT -#ifdef HAVE_SESSION_TICKET -/* Get the size of the message hash. +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +/* Setup pre-shared key based on the details in the extension data. * - * ssl The SSL/TLS object. - * returns the length of the hash. + * ssl SSL/TLS object. + * psk Pre-shared key extension data. + * returns 0 on success, PSK_KEY_ERROR when the client PSK callback fails and + * other negative value on failure. */ -static int GetMsgHashSize(WOLFSSL* ssl) +static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk) { - switch (ssl->specs.mac_algorithm) { - #ifndef NO_SHA256 - case sha256_mac: - return SHA256_DIGEST_SIZE; - #endif /* !NO_SHA256 */ - #ifdef WOLFSSL_SHA384 - case sha384_mac: - return SHA384_DIGEST_SIZE; - #endif /* WOLFSSL_SHA384 */ - #ifdef WOLFSSL_SHA512 - case sha512_mac: - return SHA512_DIGEST_SIZE; - #endif /* WOLFSSL_SHA512 */ + int ret; + + ssl->options.cipherSuite0 = psk->cipherSuite0; + ssl->options.cipherSuite = psk->cipherSuite; + if ((ret = SetCipherSpecs(ssl)) != 0) + return ret; + +#ifdef HAVE_SESSION_TICKET + if (psk->resumption) { + #ifdef WOLFSSL_EARLY_DATA + if (ssl->session.maxEarlyDataSz == 0) + ssl->earlyData = 0; + #endif + /* Resumption PSK is master secret. */ + ssl->arrays->psk_keySz = ssl->specs.hash_size; + XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, + ssl->arrays->psk_keySz); + } +#endif +#ifndef NO_PSK + if (!psk->resumption) { + /* Get the pre-shared key. */ + ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, + (char *)psk->identity, ssl->arrays->client_identity, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + return PSK_KEY_ERROR; + } } - return 0; -} #endif -#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* Derive the early secret using the PSK. */ + return DeriveEarlySecret(ssl); +} + /* Derive and write the binders into the ClientHello in space left when * writing the Pre-Shared Key extension. * @@ -2191,13 +2202,6 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) PreSharedKey* current; byte binderKey[MAX_DIGEST_SIZE]; word16 len; - #ifdef WOLFSSL_EARLY_DATA - byte pskKey[MAX_DIGEST_SIZE]; - int pskKeySz = 0; - int seenPsk = 0; - byte cipherSuite0 = 0; - byte cipherSuite = 0; - #endif ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); if (ext == NULL) @@ -2216,69 +2220,19 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) /* Calculate the binder for each identity based on previous handshake data. */ while (current != NULL) { - #ifdef HAVE_SESSION_TICKET - if (current->resumption) { - ssl->specs.mac_algorithm = current->hmac; + if ((ret = SetupPskKey(ssl, current)) != 0) + return ret; - #ifdef WOLFSSL_EARLY_DATA - if (ssl->session.maxEarlyDataSz == 0) - ssl->earlyData = 0; - #endif - /* Resumption PSK is master secret. */ - ssl->arrays->psk_keySz = GetMsgHashSize(ssl); - XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, - ssl->arrays->psk_keySz); - ssl->options.cipherSuite0 = current->cipherSuite0; - ssl->options.cipherSuite = current->cipherSuite; - ret = SetCipherSpecs(ssl); - if (ret != 0) - return ret; - /* Derive the early secret using the PSK. */ - ret = DeriveEarlySecret(ssl); - if (ret != 0) - return ret; + #ifdef HAVE_SESSION_TICKET + if (current->resumption) ret = DeriveBinderKeyResume(ssl, binderKey); - if (ret != 0) - return ret; - } - else #endif #ifndef NO_PSK - if (!current->resumption) { - /* Get the pre-shared key. */ - ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, - (char *)current->identity, ssl->arrays->client_identity, - MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); - /* TODO: Callback should be able to change ciphersuite. */ - ssl->options.cipherSuite0 = current->cipherSuite0; - ssl->options.cipherSuite = current->cipherSuite; - ret = SetCipherSpecs(ssl); - if (ret != 0) - return ret; - /* Derive the early secret using the PSK. */ - ret = DeriveEarlySecret(ssl); - if (ret != 0) - return ret; + if (!current->resumption) ret = DeriveBinderKey(ssl, binderKey); - if (ret != 0) - return ret; - } - else - #endif - { - current = current->next; - continue; - } - - #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData && !seenPsk) { - pskKeySz = ssl->arrays->psk_keySz; - XMEMCPY(pskKey, ssl->arrays->psk_key, pskKeySz); - cipherSuite0 = ssl->options.cipherSuite0; - cipherSuite = ssl->options.cipherSuite; - seenPsk = 1; - } #endif + if (ret != 0) + return ret; /* Derive the Finished message secret. */ ret = DeriveFinishedSecret(ssl, binderKey, @@ -2305,20 +2259,10 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) return ret; #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData && seenPsk) { - XMEMCPY(ssl->arrays->psk_key, pskKey, pskKeySz); - ssl->arrays->psk_keySz = pskKeySz; - - ssl->options.cipherSuite0 = cipherSuite0; - ssl->options.cipherSuite = cipherSuite; - ret = SetCipherSpecs(ssl); - if (ret != 0) + if (ssl->earlyData) { + if ((ret = SetupPskKey(ssl, (PreSharedKey*)ext->data)) != 0) return ret; - /* Derive the early secret using the PSK. */ - ret = DeriveEarlySecret(ssl); - if (ret != 0) - return ret; /* Derive early data encryption key. */ ret = DeriveTls13Keys(ssl, early_data_key, ENCRYPT_SIDE_ONLY, 1); if (ret != 0) @@ -2353,6 +2297,8 @@ int SendTls13ClientHello(WOLFSSL* ssl) if (ssl->options.resuming && (ssl->session.version.major != ssl->version.major || ssl->session.version.minor != ssl->version.minor)) { + /* Cannot resume with a different protocol version - new handshake. */ + ssl->options.resuming = 0; ssl->version.major = ssl->session.version.major; ssl->version.minor = ssl->session.version.minor; return SendClientHello(ssl); @@ -2452,9 +2398,10 @@ int SendTls13ClientHello(WOLFSSL* ssl) #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo); - if (ssl->toInfoOn) + if (ssl->toInfoOn) { AddPacketInfo("ClientHello", &ssl->timeoutInfo, output, sendSz, ssl->heap); + } #endif ssl->buffers.outputBuffer.length += sendSz; @@ -2524,7 +2471,7 @@ static int DoTls13HelloRetryRequest(WOLFSSL* ssl, const byte* input, if (i - begin + totalExtSz > totalSz) return BUFFER_ERROR; if ((ret = TLSX_Parse(ssl, (byte *)(input + i), totalExtSz, - hello_retry_request, NULL))) + hello_retry_request, NULL)) != 0) return ret; /* The KeyShare extension parsing fails when not valid. */ @@ -2534,7 +2481,13 @@ static int DoTls13HelloRetryRequest(WOLFSSL* ssl, const byte* input, ssl->options.tls1_3 = 1; ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST; - return RestartHandshakeHash(ssl); +#ifndef WOLFSSL_TLS13_DRAFT_18 + ret = RestartHandshakeHash(ssl); +#endif + + WOLFSSL_LEAVE("DoTls13HelloRetryRequest", ret); + + return ret; } /* Handle the ServerHello message from the server. @@ -2555,6 +2508,10 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 begin = i; int ret; word16 totalExtSz; +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + TLSX* ext; + PreSharedKey* psk = NULL; +#endif WOLFSSL_ENTER("DoTls13ServerHello"); @@ -2621,44 +2578,24 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return ret; #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) - if (ssl->options.resuming) { - PreSharedKey* psk = NULL; - TLSX* 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 = ssl->specs.hash_size; - XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz); - } - #ifdef HAVE_SESSION_TICKET - else if (psk->resumption) { - ssl->arrays->psk_keySz = ssl->specs.hash_size; - XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, - ssl->specs.hash_size); - } - #endif - #ifndef NO_PSK - else if (!psk->resumption) { - /* Get the pre-shared key. */ - ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, - (char *)psk->identity, ssl->arrays->client_identity, - MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); - /* TODO: Callback should be able to change ciphersuite. */ - ssl->options.cipherSuite0 = psk->cipherSuite0; - ssl->options.cipherSuite = psk->cipherSuite; - ret = SetCipherSpecs(ssl); - if (ret != 0) - return ret; - } - #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; #endif ssl->keys.encryptionOn = 1; + WOLFSSL_LEAVE("DoTls13ServerHello", ret); + return ret; } @@ -2717,6 +2654,8 @@ static int DoTls13EncryptedExtensions(WOLFSSL* ssl, const byte* input, } #endif + WOLFSSL_LEAVE("DoTls13EncryptedExtensions", ret); + return ret; } @@ -2807,10 +2746,6 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, if ((*inOutIdx - begin) + len > size) return BUFFER_ERROR; *inOutIdx += len; - ssl->options.sendVerify = SEND_CERT; - - /* This message is always encrypted so add encryption padding. */ - *inOutIdx += ssl->keys.padSz; #else #ifdef WOLFSSL_POST_HANDSHAKE_AUTH certReqCtx = (CertReqCtx*)XMALLOC(sizeof(CertReqCtx) + len - 1, ssl->heap, @@ -2842,6 +2777,7 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, *inOutIdx += len; PickHashSigAlgo(ssl, peerSuites.hashSigAlgo, peerSuites.hashSigAlgoSz); +#endif if (ssl->buffers.certificate && ssl->buffers.certificate->buffer && ssl->buffers.key && ssl->buffers.key->buffer) @@ -2851,7 +2787,6 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, /* This message is always encrypted so add encryption padding. */ *inOutIdx += ssl->keys.padSz; -#endif #if !defined(NO_WOLFSSL_CLIENT) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) if (ssl->options.side == WOLFSSL_CLIENT_END && @@ -2863,6 +2798,8 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, } #endif + WOLFSSL_LEAVE("DoTls13CertificateRequest", ret); + return ret; } @@ -2937,11 +2874,14 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, #ifdef HAVE_SESSION_TICKET /* Decode the identity. */ - if ((ret = DoClientTicket(ssl, current->identity, current->identityLen)) == WOLFSSL_TICKET_RET_OK) { + if ((ret = DoClientTicket(ssl, current->identity, current->identityLen)) + == WOLFSSL_TICKET_RET_OK) { word32 now; int diff; now = TimeNowInMilliseconds(); + if (now == (word32)GETTIME_ERROR) + return now; diff = now - ssl->session.ticketSeen; diff -= current->ticketAge - ssl->session.ticketAdd; /* Check session and ticket age timeout. @@ -2968,6 +2908,7 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, ssl->arrays->psk_keySz = ssl->specs.hash_size; XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, ssl->specs.hash_size); + /* Derive the early secret using the PSK. */ ret = DeriveEarlySecret(ssl); if (ret != 0) @@ -2995,8 +2936,8 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, /* TODO: Callback should be able to change ciphersuite. */ /* Default to ciphersuite if cb doesn't specify. */ - ssl->options.cipherSuite0 = TLS13_BYTE; - ssl->options.cipherSuite = WOLFSSL_DEF_PSK_CIPHER; + ssl->options.cipherSuite0 = TLS13_BYTE; + ssl->options.cipherSuite = WOLFSSL_DEF_PSK_CIPHER; ret = SetCipherSpecs(ssl); if (ret != 0) return ret; @@ -3074,8 +3015,8 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, ext = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); /* Use (EC)DHE for forward-security if possible. */ - if (ext != NULL && (modes & (1 << PSK_DHE_KE)) != 0 && - !ssl->options.noPskDheKe) { + if ((modes & (1 << PSK_DHE_KE)) != 0 && !ssl->options.noPskDheKe && + ext != NULL) { /* Only use named group used in last session. */ ssl->namedGroup = ssl->session.namedGroup; @@ -3083,18 +3024,13 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, ret = TLSX_KeyShare_Establish(ssl); if (ret == KEY_SHARE_ERROR) return PSK_KEY_ERROR; - else if (ret > 0) - ret = 0; + else if (ret < 0) + return ret; /* Send new public key to client. */ ext->resp = 1; } - else if ((modes & (1 << PSK_KE)) != 0) { - /* Don't send a key share extension back. */ - if (ext != NULL) - ext->resp = 0; - } - else + else if ((modes & (1 << PSK_KE)) == 0) return PSK_KEY_ERROR; *usingPSK = 1; @@ -3215,7 +3151,7 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* Parse extensions */ if ((ret = TLSX_Parse(ssl, (byte*)input + i, totalExtSz, client_hello, - &clSuites))) { + &clSuites))) { return ret; } @@ -3237,8 +3173,7 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif if (!usingPSK) { - ret = MatchSuite(ssl, &clSuites); - if (ret < 0) { + if ((ret = MatchSuite(ssl, &clSuites)) < 0) { WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); return ret; } @@ -3248,14 +3183,12 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ssl->options.resuming = 0; XMEMSET(ssl->arrays->psk_key, 0, ssl->specs.hash_size); /* May or may not have done any hashing. */ - ret = InitHandshakeHashes(ssl); - if (ret != 0) + if ((ret = InitHandshakeHashes(ssl)) != 0) return ret; } #endif - ret = HashInput(ssl, input + begin, helloSz); - if (ret != 0) + if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) return ret; /* Derive early secret for handshake secret. */ @@ -3268,6 +3201,8 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ssl->options.clientState = CLIENT_HELLO_COMPLETE; + WOLFSSL_LEAVE("DoTls13ClientHello", ret); + return ret; } @@ -3300,8 +3235,7 @@ int SendTls13HelloRetryRequest(WOLFSSL* ssl) sendSz = idx + length; /* Check buffers are big enough and grow if needed. */ - ret = CheckAvailableSize(ssl, sendSz); - if (ret != 0) + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) return ret; /* Get position in output buffer to write new message to. */ @@ -3332,25 +3266,28 @@ int SendTls13HelloRetryRequest(WOLFSSL* ssl) #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("HelloRetryRequest", &ssl->handShakeInfo); - if (ssl->toInfoOn) + if (ssl->toInfoOn) { AddPacketInfo("HelloRetryRequest", &ssl->timeoutInfo, output, sendSz, ssl->heap); + } #endif - ret = RestartHandshakeHash(ssl); - if (ret < 0) +#ifndef WOLFSSL_TLS13_DRAFT_18 + if ((ret = RestartHandshakeHash(ssl)) < 0) return ret; +#endif - ret = HashOutput(ssl, output, idx, 0); - if (ret != 0) + if ((ret = HashOutput(ssl, output, idx, 0)) != 0) return ret; ssl->buffers.outputBuffer.length += sendSz; - if (ssl->options.groupMessages) - return 0; - else - return SendBuffered(ssl); + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13HelloRetryRequest", ret); + + return ret; } /* Send TLS v1.3 ServerHello message to client. @@ -3359,7 +3296,7 @@ int SendTls13HelloRetryRequest(WOLFSSL* ssl) * ssl The SSL/TLS object. * returns 0 on success, otherwise failure. */ -int SendTls13ServerHello(WOLFSSL* ssl) +static int SendTls13ServerHello(WOLFSSL* ssl) { byte* output; word32 length; @@ -3397,8 +3334,7 @@ int SendTls13ServerHello(WOLFSSL* ssl) output[idx++] = TLS_DRAFT_MINOR; /* Generate server random. */ - ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN); - if (ret != 0) + if ((ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN)) != 0) return ret; /* Store in SSL for debugging. */ XMEMCPY(ssl->arrays->serverRandom, output + idx, RAN_LEN); @@ -3418,24 +3354,26 @@ int SendTls13ServerHello(WOLFSSL* ssl) ssl->buffers.outputBuffer.length += sendSz; - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) + if ((ret = HashOutput(ssl, output, sendSz, 0)) != 0) return ret; #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo); - if (ssl->toInfoOn) + if (ssl->toInfoOn) { AddPacketInfo("ServerHello", &ssl->timeoutInfo, output, sendSz, ssl->heap); + } #endif ssl->options.serverState = SERVER_HELLO_COMPLETE; - if (ssl->options.groupMessages) - return 0; - else - return SendBuffered(ssl); + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13ServerHello", ret); + + return ret; } /* Send the rest of the extensions encrypted under the handshake key. @@ -3445,7 +3383,7 @@ int SendTls13ServerHello(WOLFSSL* ssl) * ssl The SSL/TLS object. * returns 0 on success, otherwise failure. */ -int SendTls13EncryptedExtensions(WOLFSSL* ssl) +static int SendTls13EncryptedExtensions(WOLFSSL* ssl) { int ret; byte* output; @@ -3502,9 +3440,10 @@ int SendTls13EncryptedExtensions(WOLFSSL* ssl) #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("EncryptedExtensions", &ssl->handShakeInfo); - if (ssl->toInfoOn) + if (ssl->toInfoOn) { AddPacketInfo("EncryptedExtensions", &ssl->timeoutInfo, output, sendSz, ssl->heap); + } #endif /* This handshake message is always encrypted. */ @@ -3517,10 +3456,12 @@ int SendTls13EncryptedExtensions(WOLFSSL* ssl) ssl->options.serverState = SERVER_ENCRYPTED_EXTENSIONS_COMPLETE; - if (ssl->options.groupMessages) - return 0; - else - return SendBuffered(ssl); + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13EncryptedExtensions", ret); + + return ret; } #ifndef NO_CERTS @@ -3533,7 +3474,8 @@ int SendTls13EncryptedExtensions(WOLFSSL* ssl) * reqCtxLen Length of context. 0 when sending as part of handshake. * returns 0 on success, otherwise failure. */ -int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, int reqCtxLen) +static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, + int reqCtxLen) { byte* output; int ret; @@ -3543,9 +3485,6 @@ int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, int reqCtxLen) WOLFSSL_ENTER("SendTls13CertificateRequest"); - if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher) - return 0; /* not needed */ - #ifdef WOLFSSL_TLS13_DRAFT_18 (void)reqCtx; @@ -3625,15 +3564,19 @@ int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, int reqCtxLen) #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("CertificateRequest", &ssl->handShakeInfo); - if (ssl->toInfoOn) + if (ssl->toInfoOn) { AddPacketInfo("CertificateRequest", &ssl->timeoutInfo, output, sendSz, ssl->heap); + } #endif ssl->buffers.outputBuffer.length += sendSz; if (!ssl->options.groupMessages) - return SendBuffered(ssl); - return 0; + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13CertificateRequest", ret); + + return ret; } #endif /* NO_CERTS */ #endif /* NO_WOLFSSL_SERVER */ @@ -4095,7 +4038,7 @@ static word32 AddCertExt(byte* cert, word32 len, word32 idx, word32 fragSz, * ssl The SSL/TLS object. * returns 0 on success, otherwise failure. */ -int SendTls13Certificate(WOLFSSL* ssl) +static int SendTls13Certificate(WOLFSSL* ssl) { int ret = 0; word32 certSz, certChainSz, headerSz, listSz, payloadSz; @@ -4119,8 +4062,8 @@ int SendTls13Certificate(WOLFSSL* ssl) if (ssl->options.sendVerify == SEND_BLANK_CERT) { certSz = 0; certChainSz = 0; - headerSz = CERT_HEADER_SZ; - length = CERT_HEADER_SZ; + headerSz = OPAQUE8_LEN + certReqCtxLen + CERT_HEADER_SZ; + length = headerSz; listSz = 0; } else { @@ -4274,9 +4217,10 @@ int SendTls13Certificate(WOLFSSL* ssl) #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo); - if (ssl->toInfoOn) + if (ssl->toInfoOn) { AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz, ssl->heap); + } #endif ssl->buffers.outputBuffer.length += sendSz; @@ -4299,6 +4243,8 @@ int SendTls13Certificate(WOLFSSL* ssl) } #endif + WOLFSSL_LEAVE("SendTls13Certificate", ret); + return ret; } @@ -4345,7 +4291,7 @@ static void FreeScv13Args(WOLFSSL* ssl, void* pArgs) * ssl The SSL/TLS object. * returns 0 on success, otherwise failure. */ -int SendTls13CertificateVerify(WOLFSSL* ssl) +static int SendTls13CertificateVerify(WOLFSSL* ssl) { int ret = 0; buffer* sig = &ssl->buffers.sig; @@ -4425,8 +4371,10 @@ int SendTls13CertificateVerify(WOLFSSL* ssl) } else if (ssl->hsType == DYNAMIC_TYPE_ECC) args->sigAlgo = ecc_dsa_sa_algo; + #ifdef HAVE_ED25519 else if (ssl->hsType == DYNAMIC_TYPE_ED25519) args->sigAlgo = ed25519_sa_algo; + #endif EncodeSigAlg(ssl->suites->hashAlgo, args->sigAlgo, args->verify); /* Create the data to be signed. */ @@ -4614,9 +4562,10 @@ int SendTls13CertificateVerify(WOLFSSL* ssl) #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("CertificateVerify", &ssl->handShakeInfo); - if (ssl->toInfoOn) + if (ssl->toInfoOn) { AddPacketInfo("CertificateVerify", &ssl->timeoutInfo, args->output, args->sendSz, ssl->heap); + } #endif ssl->buffers.outputBuffer.length += args->sendSz; @@ -4662,12 +4611,12 @@ static int DoTls13Certificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, { int ret; + WOLFSSL_ENTER("DoTls13Certificate"); + ret = ProcessPeerCerts(ssl, input, inOutIdx, totalSz); - if (ret != 0) - return ret; #if !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - if (ssl->options.side == WOLFSSL_SERVER_END && + if (ret == 0 && ssl->options.side == WOLFSSL_SERVER_END && ssl->options.handShakeState == HANDSHAKE_DONE) { /* reset handshake states */ ssl->options.serverState = SERVER_FINISHED_COMPLETE; @@ -4676,7 +4625,9 @@ static int DoTls13Certificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, } #endif - return 0; + WOLFSSL_LEAVE("DoTls13Certificate", ret); + + return ret; } #if !defined(NO_RSA) || defined(HAVE_ECC) @@ -5094,7 +5045,7 @@ static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, * ssl The SSL/TLS object. * returns 0 on success, otherwise failure. */ -int SendTls13Finished(WOLFSSL* ssl) +static int SendTls13Finished(WOLFSSL* ssl) { int sendSz; int finishedSz = ssl->specs.hash_size; @@ -5156,15 +5107,15 @@ int SendTls13Finished(WOLFSSL* ssl) #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo); - if (ssl->toInfoOn) + if (ssl->toInfoOn) { AddPacketInfo("Finished", &ssl->timeoutInfo, output, sendSz, ssl->heap); + } #endif ssl->buffers.outputBuffer.length += sendSz; - ret = SendBuffered(ssl); - if (ret != 0) + if ((ret = SendBuffered(ssl)) != 0) return ret; if (ssl->options.side == WOLFSSL_SERVER_END) { @@ -5276,9 +5227,10 @@ static int SendTls13KeyUpdate(WOLFSSL* ssl) #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("KeyUpdate", &ssl->handShakeInfo); - if (ssl->toInfoOn) + if (ssl->toInfoOn) { AddPacketInfo("KeyUpdate", &ssl->timeoutInfo, output, sendSz, ssl->heap); + } #endif ssl->buffers.outputBuffer.length += sendSz; @@ -5373,6 +5325,8 @@ static int SendTls13EndOfEarlyData(WOLFSSL* ssl) word32 length; word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + WOLFSSL_ENTER("SendTls13EndOfEarlyData"); + length = 0; sendSz = idx + length + MAX_MSG_EXTRA; @@ -5398,7 +5352,12 @@ static int SendTls13EndOfEarlyData(WOLFSSL* ssl) if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) return ret; - return SendBuffered(ssl); + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13EndOfEarlyData", ret); + + return ret; } #endif /* !NO_WOLFSSL_CLIENT */ @@ -5413,18 +5372,24 @@ static int SendTls13EndOfEarlyData(WOLFSSL* ssl) static int DoTls13EndOfEarlyData(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size) { - word32 begin = *inOutIdx; + int ret; + word32 begin = *inOutIdx; (void)input; + WOLFSSL_ENTER("DoTls13EndOfEarlyData"); + if ((*inOutIdx - begin) != size) return BUFFER_ERROR; /* Always encrypted. */ *inOutIdx += ssl->keys.padSz; - return SetKeysSide(ssl, DECRYPT_SIDE_ONLY); + ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY); + WOLFSSL_LEAVE("SendTls13EndOfEarlyData", ret); + + return ret; } #endif /* !NO_WOLFSSL_SERVER */ #endif /* WOLFSSL_EARLY_DATA */ @@ -5445,12 +5410,15 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, { #ifdef HAVE_SESSION_TICKET #ifdef WOLFSSL_EARLY_DATA - int ret; + int ret; #endif - word32 begin = *inOutIdx; - word32 lifetime; - word32 ageAdd; - word16 length; + word32 begin = *inOutIdx; + word32 lifetime; + word32 ageAdd; + word16 length; + word32 now; + + WOLFSSL_ENTER("DoTls13NewSessionTicket"); /* Lifetime hint. */ if ((*inOutIdx - begin) + SESSION_HINT_SZ > size) @@ -5491,12 +5459,15 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, ssl->session.isDynamic = 1; } + now = TimeNowInMilliseconds(); + if (now == (word32)GETTIME_ERROR) + return now; /* Copy in ticket data (server identity). */ ssl->timeout = lifetime; ssl->session.timeout = lifetime; ssl->session.cipherSuite0 = ssl->options.cipherSuite0; ssl->session.cipherSuite = ssl->options.cipherSuite; - ssl->session.ticketSeen = TimeNowInMilliseconds(); + ssl->session.ticketSeen = now; ssl->session.ticketAdd = ageAdd; #ifdef WOLFSSL_EARLY_DATA ssl->session.maxEarlyDataSz = ssl->options.maxEarlyDataSz; @@ -5540,9 +5511,14 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, #else (void)ssl; (void)input; + + WOLFSSL_ENTER("DoTls13NewSessionTicket"); + *inOutIdx += size + ssl->keys.padSz; #endif /* HAVE_SESSION_TICKET */ + WOLFSSL_LEAVE("DoTls13NewSessionTicket", 0); + return 0; } #endif /* NO_WOLFSSL_CLIENT */ @@ -5555,7 +5531,7 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, * ssl The SSL/TLS object. * retuns 0 on success, otherwise failure. */ -int SendTls13NewSessionTicket(WOLFSSL* ssl) +static int SendTls13NewSessionTicket(WOLFSSL* ssl) { byte* output; int ret; @@ -5564,9 +5540,11 @@ int SendTls13NewSessionTicket(WOLFSSL* ssl) word32 length; word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + WOLFSSL_ENTER("SendTls13NewSessionTicket"); + if (!ssl->options.noTicketTls13) { - ret = CreateTicket(ssl); - if (ret != 0) return ret; + if ((ret = CreateTicket(ssl)) != 0) + return ret; } #ifdef WOLFSSL_EARLY_DATA @@ -5630,7 +5608,12 @@ int SendTls13NewSessionTicket(WOLFSSL* ssl) ssl->buffers.outputBuffer.length += sendSz; - return SendBuffered(ssl); + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13NewSessionTicket", 0); + + return ret; } #endif /* HAVE_SESSION_TICKET */ #endif /* NO_WOLFSSL_SERVER */ @@ -5680,6 +5663,7 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) #endif #ifndef NO_WOLFSSL_SERVER + #ifdef WOLFSSL_EARLY_DATA case end_of_early_data: if (ssl->msgsReceived.got_end_of_early_data == 1) { WOLFSSL_MSG("Too many EndOfEarlyData received"); @@ -5688,6 +5672,7 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) ssl->msgsReceived.got_end_of_early_data++; break; + #endif #endif #ifndef NO_WOLFSSL_CLIENT diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 56e349398..939b79d11 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3503,26 +3503,14 @@ WOLFSSL_LOCAL int DoClientTicket(WOLFSSL*, const byte*, word32); WOLFSSL_LOCAL int SendData(WOLFSSL*, const void*, int); #ifdef WOLFSSL_TLS13 WOLFSSL_LOCAL int SendTls13HelloRetryRequest(WOLFSSL*); -WOLFSSL_LOCAL int SendTls13EncryptedExtensions(WOLFSSL*); #endif WOLFSSL_LOCAL int SendCertificate(WOLFSSL*); -#ifdef WOLFSSL_TLS13 -WOLFSSL_LOCAL int SendTls13Certificate(WOLFSSL*); -#endif WOLFSSL_LOCAL int SendCertificateRequest(WOLFSSL*); -#ifdef WOLFSSL_TLS13 -WOLFSSL_LOCAL int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, - int reqCtxLen); -#endif WOLFSSL_LOCAL int SendCertificateStatus(WOLFSSL*); WOLFSSL_LOCAL int SendServerKeyExchange(WOLFSSL*); WOLFSSL_LOCAL int SendBuffered(WOLFSSL*); WOLFSSL_LOCAL int ReceiveData(WOLFSSL*, byte*, int, int); WOLFSSL_LOCAL int SendFinished(WOLFSSL*); -#ifdef WOLFSSL_TLS13 -WOLFSSL_LOCAL int SendTls13Finished(WOLFSSL*); -WOLFSSL_LOCAL int SendTls13NewSessionTicket(WOLFSSL*); -#endif WOLFSSL_LOCAL int SendAlert(WOLFSSL*, int, int); WOLFSSL_LOCAL int ProcessReply(WOLFSSL*); @@ -3628,13 +3616,8 @@ WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength); WOLFSSL_LOCAL int SendCertificateVerify(WOLFSSL*); #endif /* NO_WOLFSSL_CLIENT */ - WOLFSSL_LOCAL int SendTls13CertificateVerify(WOLFSSL*); - #ifndef NO_WOLFSSL_SERVER WOLFSSL_LOCAL int SendServerHello(WOLFSSL*); - #ifdef WOLFSSL_TLS13 - WOLFSSL_LOCAL int SendTls13ServerHello(WOLFSSL*); - #endif WOLFSSL_LOCAL int SendServerHelloDone(WOLFSSL*); #endif /* NO_WOLFSSL_SERVER */ From 08a0b98f521553fae34c56d92d382e3113f89413 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Thu, 22 Jun 2017 12:40:41 +1000 Subject: [PATCH 4/5] Updates from code review --- configure.ac | 46 ++++++++-- examples/client/client.c | 2 +- src/tls13.c | 189 ++++++++++++++++++++++++++++++++------- 3 files changed, 198 insertions(+), 39 deletions(-) diff --git a/configure.ac b/configure.ac index c08723d25..6c1639283 100644 --- a/configure.ac +++ b/configure.ac @@ -248,21 +248,55 @@ then fi +# TLS v1.3 Draft 18 +AC_ARG_ENABLE([tls13-draft18], + [AS_HELP_STRING([--enable-tls13-draft18],[Enable wolfSSL TLS v1.3 Draft 18 (default: disabled)])], + [ ENABLED_TLS13_DRAFT18=$enableval ], + [ ENABLED_TLS13_DRAFT18=no ] + ) +if test "$ENABLED_TLS13_DRAFT18" = "yes" +then + AM_CFLAGS="-DWOLFSSL_TLS13_DRAFT18 $AM_CFLAGS" +fi + + # TLS v1.3 AC_ARG_ENABLE([tls13], [AS_HELP_STRING([--enable-tls13],[Enable wolfSSL TLS v1.3 (default: disabled)])], [ ENABLED_TLS13=$enableval ], [ ENABLED_TLS13=no ] ) + +if test "$ENABLED_TLS13_DRAFT18" = "yes" +then + ENABLED_TLS13="yes" +fi + if test "$ENABLED_TLS13" = "yes" then - AM_CFLAGS="-DWOLFSSL_TLS13 -DHAVE_TLS_EXTENSIONS -DHAVE_FFDHE_2048 $AM_CFLAGS" + AM_CFLAGS="-DWOLFSSL_TLS13 -DHAVE_TLS_EXTENSIONS -DHAVE_FFDHE_2048 $AM_CFLAGS" fi # check if TLS v1.3 was enabled for conditionally running tls13.test script AM_CONDITIONAL([BUILD_TLS13], [test "x$ENABLED_TLS13" = "xyes"]) +# Post-handshake Authentication +AC_ARG_ENABLE([postauth], + [AS_HELP_STRING([--enable-postauth],[Enable wolfSSL Post-handshake Authentication (default: disabled)])], + [ ENABLED_TLS13_POST_AUTH=$enableval ], + [ ENABLED_TLS13_POST_AUTH=no ] + ) +if test "$ENABLED_TLS13_POST_AUTH" = "yes" +then + if test "x$ENABLED_TLS13" = "xno" + then + AC_MSG_ERROR([cannot enable postauth without enabling tls13.]) + fi + AM_CFLAGS="-DWOLFSSL_POST_HANDSHAKE_AUTH $AM_CFLAGS" +fi + + AC_ARG_ENABLE([rng], [AS_HELP_STRING([--enable-rng],[Enable compiling and using RNG (default: enabled)])], [ ENABLED_RNG=$enableval ], @@ -2329,10 +2363,10 @@ fi # Early Data handshake in TLS v1.3 and above AC_ARG_ENABLE([earlydata], [AS_HELP_STRING([--enable-earlydata],[Enable Early Data handshake with wolfSSL TLS v1.3 (default: disabled)])], - [ ENABLED_EARLY_DATA=$enableval ], - [ ENABLED_EARLY_DATA=no ] + [ ENABLED_TLS13_EARLY_DATA=$enableval ], + [ ENABLED_TLS13_EARLY_DATA=no ] ) -if test "$ENABLED_EARLY_DATA" = "yes" +if test "$ENABLED_TLS13_EARLY_DATA" = "yes" then if test "x$ENABLED_TLS13" = "xno" then @@ -3760,7 +3794,9 @@ echo " * SCTP: $ENABLED_SCTP" echo " * Old TLS Versions: $ENABLED_OLD_TLS" echo " * SSL version 3.0: $ENABLED_SSLV3" echo " * TLS v1.3: $ENABLED_TLS13" -echo " * Early Data: $ENABLED_EARLY_DATA" +echo " * TLS v1.3 Draft 18: $ENABLED_TLS13_DRAFT18" +echo " * Post-handshake Auth: $ENABLED_TLS13_POST_AUTH" +echo " * Early Data: $ENABLED_TLS13_EARLY_DATA" echo " * OCSP: $ENABLED_OCSP" echo " * OCSP Stapling: $ENABLED_CERTIFICATE_STATUS_REQUEST" echo " * OCSP Stapling v2: $ENABLED_CERTIFICATE_STATUS_REQUEST_V2" diff --git a/examples/client/client.c b/examples/client/client.c index 389269458..907ab8c91 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -1941,7 +1941,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) ClientRead(ssl, reply, sizeof(reply)-1, 1); -#ifdef WOLFSSL_POST_HANDSHAKE_AUTH +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) if (postHandAuth) ClientWrite(ssl, msg, msgSz); #endif diff --git a/src/tls13.c b/src/tls13.c index 522e34f15..d12d4ff47 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -20,6 +20,22 @@ */ +/* + * WOLFSSL_TLS13_DRAFT_18 + * Conform with Draft 18 of the TLS v1.3 specification. + * WOLFSSL_EARLY_DATA + * Allow 0-RTT Handshake using Early Data extensions and handshake message + * WOLFSSL_POST_HANDSHAKE_AUTH + * Allow TLS v1.3 code to perform post-handshake authentication of the + * client. + * WOLFSSL_TLS13_TICKET_BEFORE_FINISHED + * Allow a NewSessionTicket message to be sent by server before Client's + * Finished message. + * See TLS v.13 specification, Section 4.6.1, Paragraph 4 (Note). + * TLS13_SUPPORTS_EXPORTERS + * Gaurd to compile out any code for exporter keys. + * Feature not supported yet. + */ #ifdef HAVE_CONFIG_H #include @@ -210,16 +226,16 @@ static int Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen, } #ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Salt"); + WOLFSSL_MSG(" Salt"); WOLFSSL_BUFFER(salt, saltLen); - WOLFSSL_MSG("IKM"); + WOLFSSL_MSG(" IKM"); WOLFSSL_BUFFER(ikm, ikmLen); #endif ret = wc_HKDF_Extract(hash, salt, saltLen, ikm, ikmLen, prk); #ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("PRK"); + WOLFSSL_MSG(" PRK"); WOLFSSL_BUFFER(prk, len); #endif @@ -268,16 +284,16 @@ static int HKDF_Expand_Label(byte* okm, word32 okmLen, idx += infoLen; #ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("PRK"); + WOLFSSL_MSG(" PRK"); WOLFSSL_BUFFER(prk, prkLen); - WOLFSSL_MSG("Info"); + WOLFSSL_MSG(" Info"); WOLFSSL_BUFFER(data, idx); #endif ret = wc_HKDF_Expand(digest, prk, prkLen, data, idx, okm, okmLen); #ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("OKM"); + WOLFSSL_MSG(" OKM"); WOLFSSL_BUFFER(okm, okmLen); #endif @@ -548,7 +564,7 @@ static int DeriveEarlyTrafficSecret(WOLFSSL* ssl, byte* key) ssl->specs.mac_algorithm, 1); } - #ifdef TLS13_SUPPORTS_EXPORTERS +#ifdef TLS13_SUPPORTS_EXPORTERS #ifdef WOLFSSL_TLS13_DRAFT_18 /* The length of the early exporter label. */ #define EARLY_EXPORTER_LABEL_SZ 28 @@ -575,7 +591,7 @@ static int DeriveEarlyExporterSecret(WOLFSSL* ssl, byte* key) earlyExporterLabel, EARLY_EXPORTER_LABEL_SZ, ssl->specs.mac_algorithm, 1); } - #endif +#endif #endif #ifdef WOLFSSL_TLS13_DRAFT_18 @@ -1399,7 +1415,7 @@ static int RestartHandshakeHash(WOLFSSL* ssl) ret = HashOutputRaw(ssl, header, sizeof(header)); if (ret != 0) return ret; - return HashOutputRaw(ssl, hash, header[3]); + return HashOutputRaw(ssl, hash, header[MSG_HASH_LEN_OFFSET]); } #endif @@ -2678,9 +2694,9 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, int ret = 0; #ifndef WOLFSSL_TLS13_DRAFT_18 Suites peerSuites; +#endif #ifdef WOLFSSL_POST_HANDSHAKE_AUTH CertReqCtx* certReqCtx; -#endif #endif WOLFSSL_ENTER("DoTls13CertificateRequest"); @@ -2700,9 +2716,23 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, if (ssl->options.connectState < FINISHED_DONE && len > 0) return BUFFER_ERROR; -#ifdef WOLFSSL_TLS13_DRAFT_18 +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + /* CertReqCtx has one byte at end for context value. + * Increase size to handle other implementations sending more than one byte. + * That is, allocate extra space, over one byte, to hold the context value. + */ + certReqCtx = (CertReqCtx*)XMALLOC(sizeof(CertReqCtx) + len - 1, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (certReqCtx == NULL) + return MEMORY_E; + certReqCtx->next = ssl->certReqCtx; + certReqCtx->len = len; + XMEMCPY(&certReqCtx->ctx, input + *inOutIdx, len); + ssl->certReqCtx = certReqCtx; +#endif *inOutIdx += len; +#ifdef WOLFSSL_TLS13_DRAFT_18 /* Signature and hash algorithms. */ if ((*inOutIdx - begin) + OPAQUE16_LEN > size) return BUFFER_ERROR; @@ -2747,18 +2777,6 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, return BUFFER_ERROR; *inOutIdx += len; #else -#ifdef WOLFSSL_POST_HANDSHAKE_AUTH - certReqCtx = (CertReqCtx*)XMALLOC(sizeof(CertReqCtx) + len - 1, ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (certReqCtx == NULL) - return MEMORY_E; - certReqCtx->next = ssl->certReqCtx; - certReqCtx->len = len; - XMEMCPY(&certReqCtx->ctx, input + *inOutIdx, len); - ssl->certReqCtx = certReqCtx; -#endif - *inOutIdx += len; - /* TODO: Add support for more extensions: * signed_certificate_timestamp, certificate_authorities, oid_filters. */ @@ -3486,8 +3504,6 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, WOLFSSL_ENTER("SendTls13CertificateRequest"); #ifdef WOLFSSL_TLS13_DRAFT_18 - (void)reqCtx; - i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; reqSz = OPAQUE8_LEN + reqCtxLen + REQ_HEADER_SZ + REQ_HEADER_SZ; reqSz += LENGTH_SZ + ssl->suites->hashSigAlgoSz; @@ -3509,6 +3525,10 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, /* Certificate request context. */ output[i++] = reqCtxLen; + if (reqCtxLen != 0) { + XMEMCPY(output + i, reqCtx, reqCtxLen); + i += reqCtxLen; + } /* supported hash/sig */ c16toa(ssl->suites->hashSigAlgoSz, &output[i]); @@ -5525,6 +5545,101 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, #ifndef NO_WOLFSSL_SERVER #ifdef HAVE_SESSION_TICKET + +#ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED +/* Offset of the MAC size in the finished message. */ +#define FINISHED_MSG_SIZE_OFFSET 3 + +/* Calculate the resumption secret which includes the unseen client finished + * message. + * + * ssl The SSL/TLS object. + * retuns 0 on success, otherwise failure. + */ +static int ExpectedResumptionSecret(WOLFSSL* ssl) +{ + int ret; + word32 finishedSz = 0; + byte mac[MAX_DIGEST_SIZE]; + Digest digest; + static byte header[] = { 0x14, 0x00, 0x00, 0x00 }; + + /* Copy the running hash so we cna restore it after. */ + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + ret = wc_Sha256Copy(&ssl->hsHashes->hashSha256, &digest.sha256); + if (ret != 0) + return ret; + break; + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + ret = wc_Sha384Copy(&ssl->hsHashes->hashSha384, &digest.sha384); + if (ret != 0) + return ret; + break; + #endif + #ifdef WOLFSSL_SHA512 + case sha512_mac: + ret = wc_Sha512Copy(&ssl->hsHashes->hashSha512, &digest.sha512); + if (ret != 0) + return ret; + break; + #endif + } + + /* Generate the Client's Finished message and hash it. */ + ret = BuildTls13HandshakeHmac(ssl, ssl->keys.client_write_MAC_secret, mac, + &finishedSz); + if (ret != 0) + return ret; + header[FINISHED_MSG_SIZE_OFFSET] = finishedSz; +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData) { + static byte endOfEarlyData[] = { 0x05, 0x00, 0x00, 0x00 }; + ret = HashInputRaw(ssl, endOfEarlyData, sizeof(endOfEarlyData)); + if (ret != 0) + return ret; + } +#endif + if ((ret = HashInputRaw(ssl, header, sizeof(header))) != 0) + return ret; + if ((ret = HashInputRaw(ssl, mac, finishedSz)) != 0) + return ret; + + if ((ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret)) != 0) + return ret; + + /* Restore the hash inline with currently seen messages. */ + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + ret = wc_Sha256Copy(&digest.sha256, &ssl->hsHashes->hashSha256); + if (ret != 0) + return ret; + break; + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + ret = wc_Sha384Copy(&digest.sha384, &ssl->hsHashes->hashSha384); + if (ret != 0) + return ret; + break; + #endif + #ifdef WOLFSSL_SHA512 + case sha512_mac: + ret = wc_Sha512Copy(&digest.sha512, &ssl->hsHashes->hashSha384); + if (ret != 0) + return ret; + break; + #endif + } + + return ret; +} +#endif + /* Send New Session Ticket handshake message. * Message contains the information required to perform resumption. * @@ -5542,6 +5657,13 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl) WOLFSSL_ENTER("SendTls13NewSessionTicket"); +#ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED + if (!ssl->msgsReceived.got_finished) { + if ((ret = ExpectedResumptionSecret(ssl)) != 0) + return ret; + } +#endif + if (!ssl->options.noTicketTls13) { if ((ret = CreateTicket(ssl)) != 0) return ret; @@ -5994,8 +6116,11 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, } #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) - if (type == finished && ssl->options.side == WOLFSSL_SERVER_END) - DeriveResumptionSecret(ssl, ssl->session.masterSecret); + if (type == finished && ssl->options.side == WOLFSSL_SERVER_END) { + ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret); + if (ret != 0) + return ret; + } #endif } @@ -6477,7 +6602,6 @@ int wolfSSL_allow_post_handshake_auth(WOLFSSL* ssl) { if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) return BAD_FUNC_ARG; - return BAD_FUNC_ARG; if (ssl->options.side == WOLFSSL_SERVER_END) return SIDE_ERROR; @@ -6719,8 +6843,7 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) case ACCEPT_FINISHED_DONE : #ifdef HAVE_SESSION_TICKET -#ifdef RESUMPTION_SECRET_CALCULATED_WITHOUT_CLIENT_FINISHED - /* TODO: [TLS13] Section 4.6.1 Note. */ + #ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED if (!ssl->options.resuming && !ssl->options.verifyPeer && !ssl->options.noTicketTls13 && ssl->ctx->ticketEncCb != NULL) { if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) { @@ -6728,7 +6851,7 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) return SSL_FATAL_ERROR; } } -#endif + #endif #endif /* HAVE_SESSION_TICKET */ ssl->options.acceptState = TICKET_SENT; WOLFSSL_MSG("accept state TICKET_SENT"); @@ -6747,11 +6870,11 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) case ACCEPT_SECOND_REPLY_DONE : #ifdef HAVE_SESSION_TICKET -#ifdef RESUMPTION_SECRET_CALCULATED_WITHOUT_CLIENT_FINISHED + #ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED if (!ssl->options.verifyPeer) { } else -#endif + #endif if (!ssl->options.resuming && !ssl->options.noTicketTls13 && ssl->ctx->ticketEncCb != NULL) { if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) { From 207b275d24250147a1a6803d286ea6d577f36727 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Thu, 22 Jun 2017 14:40:09 +1000 Subject: [PATCH 5/5] Fix HelloRetryRequest for Draft 18 --- src/tls13.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tls13.c b/src/tls13.c index d12d4ff47..7943a9cfa 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -2467,9 +2467,11 @@ 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++]; +#endif ret = SetCipherSpecs(ssl); if (ret != 0) @@ -3273,9 +3275,11 @@ 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);