From 350ce5fcef19f6240c4376226598dc62e290bf75 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Mon, 19 Jun 2017 11:37:10 +1000 Subject: [PATCH] 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*);