diff --git a/configure.ac b/configure.ac index 9cc58e412..fe8ebb80a 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 ], @@ -2327,6 +2361,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_TLS13_EARLY_DATA=$enableval ], + [ ENABLED_TLS13_EARLY_DATA=no ] + ) +if test "$ENABLED_TLS13_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)])], @@ -3741,6 +3795,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 " * 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 d8e5c9266..f26834d72 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); @@ -1928,6 +1941,10 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) ClientRead(ssl, reply, sizeof(reply)-1, 1); +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (postHandAuth) + ClientWrite(ssl, msg, msgSz); +#endif if (sendGET) { /* get html */ ClientRead(ssl, reply, sizeof(reply)-1, 0); } @@ -2027,6 +2044,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/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 bbc818ec4..64626f0eb 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; @@ -3783,6 +3787,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; @@ -7473,7 +7481,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 @@ -10899,6 +10908,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); @@ -10919,6 +10933,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) { @@ -11376,6 +11399,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. */ @@ -11462,6 +11498,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 @@ -13154,6 +13201,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"); @@ -13306,6 +13362,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"); @@ -22484,6 +22545,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; @@ -22515,6 +22579,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); @@ -22639,6 +22707,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 8e297c4eb..a54f524a4 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; @@ -8279,6 +8286,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 : @@ -9228,11 +9240,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) { @@ -9459,9 +9474,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..7943a9cfa 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 @@ -298,6 +314,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. @@ -363,9 +381,6 @@ static int DeriveKeyMsg(WOLFSSL* ssl, byte* output, int outputLen, digestAlg = SHA512; break; #endif - - default: - return BAD_FUNC_ARG; } if (ret != 0) @@ -387,6 +402,7 @@ static int DeriveKeyMsg(WOLFSSL* ssl, byte* output, int outputLen, protocol, protocolLen, label, labelLen, hash, hashSz, digestAlg); } +#endif /* Derive a key. * @@ -520,7 +536,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 @@ -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 @@ -944,7 +960,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 +971,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 +984,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 +993,32 @@ 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: + ret = DeriveEarlyTrafficSecret(ssl, ssl->arrays->clientSecret); + 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 +1027,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 +1040,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 +1053,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 @@ -1329,6 +1366,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. @@ -1350,19 +1391,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 @@ -1374,8 +1415,9 @@ 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 /* Extract the handshake header information. @@ -1709,9 +1751,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 +1760,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 +1955,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,19 +1962,24 @@ 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; } -/* Persistable BuildMessage arguments */ +/* Persistable BuildTls13Message arguments */ typedef struct BuildMsg13Args { word32 sz; word32 idx; @@ -1981,10 +2025,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) { @@ -2018,11 +2058,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; } @@ -2116,33 +2157,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. * @@ -2176,56 +2236,23 @@ 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) { - /* 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; + if ((ret = SetupPskKey(ssl, current)) != 0) + return ret; - /* Resumption PSK is master secret. */ - ssl->arrays->psk_keySz = GetMsgHashSize(ssl); - XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, - ssl->arrays->psk_keySz); - /* Derive the early secret using the PSK. */ - ret = DeriveEarlySecret(ssl); - if (ret != 0) - return ret; - /* Derive the binder key to use to with HMAC. */ + #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: Forcing cipher suite to use SHA256 with PSK. */ - /* Default to SHA-256 if cb doesn't specify. */ - ssl->specs.mac_algorithm = sha256_mac; - /* Derive the early secret using the PSK. */ - ret = DeriveEarlySecret(ssl); - if (ret != 0) - return ret; - /* Derive the binder key to use to with HMAC. */ + if (!current->resumption) ret = DeriveBinderKey(ssl, binderKey); - if (ret != 0) - return ret; - } - else #endif - { - current = current->next; - continue; - } + if (ret != 0) + return ret; /* 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 +2270,24 @@ 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) { + if ((ret = SetupPskKey(ssl, (PreSharedKey*)ext->data)) != 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,10 +2309,12 @@ 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)) { + /* 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); @@ -2287,6 +2333,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; @@ -2358,14 +2414,19 @@ 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; - return SendBuffered(ssl); + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13ClientHello", ret); + + return ret; } /* Parse and handle a HelloRetryRequest message. @@ -2406,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) @@ -2426,7 +2489,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. */ @@ -2436,7 +2499,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. @@ -2457,6 +2526,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"); @@ -2522,24 +2595,25 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ret != 0) return ret; -#ifdef HAVE_SESSION_TICKET - 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); - } +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (ext != NULL) + psk = (PreSharedKey*)ext->data; + while (psk != NULL && !psk->chosen) + psk = psk->next; + if (psk == NULL) { + ssl->options.resuming = 0; + ssl->arrays->psk_keySz = 0; + XMEMSET(ssl->arrays->psk_key, 0, MAX_PSK_KEY_LEN); } + else if ((ret = SetupPskKey(ssl, psk)) != 0) + return ret; #endif ssl->keys.encryptionOn = 1; + WOLFSSL_LEAVE("DoTls13ServerHello", ret); + return ret; } @@ -2590,6 +2664,16 @@ 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 + + WOLFSSL_LEAVE("DoTls13EncryptedExtensions", ret); + return ret; } @@ -2609,8 +2693,10 @@ 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; +#endif #ifdef WOLFSSL_POST_HANDSHAKE_AUTH CertReqCtx* certReqCtx; #endif @@ -2633,8 +2719,12 @@ 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 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; @@ -2644,6 +2734,51 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, #endif *inOutIdx += len; +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* 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; +#else /* TODO: Add support for more extensions: * signed_certificate_timestamp, certificate_authorities, oid_filters. */ @@ -2662,6 +2797,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) @@ -2682,6 +2818,8 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, } #endif + WOLFSSL_LEAVE("DoTls13CertificateRequest", ret); + return ret; } @@ -2710,10 +2848,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 +2882,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); @@ -2744,23 +2894,32 @@ 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; + 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. * 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; @@ -2769,6 +2928,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) @@ -2781,7 +2941,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 +2954,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 +2982,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 +3007,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) @@ -2850,8 +3035,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; @@ -2859,18 +3044,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; @@ -2991,7 +3171,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; } @@ -3012,28 +3192,23 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return ret; #endif - if (!usingPSK || !ssl->options.resuming) { - ret = MatchSuite(ssl, &clSuites); - if (ret < 0) { + if (!usingPSK) { + if ((ret = MatchSuite(ssl, &clSuites)) < 0) { WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); return ret; } - } - if (!usingPSK) { #ifdef HAVE_SESSION_TICKET if (ssl->options.resuming) { 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. */ @@ -3046,6 +3221,8 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ssl->options.clientState = CLIENT_HELLO_COMPLETE; + WOLFSSL_LEAVE("DoTls13ClientHello", ret); + return ret; } @@ -3078,8 +3255,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. */ @@ -3099,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); @@ -3110,25 +3288,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. @@ -3137,7 +3318,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; @@ -3175,8 +3356,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); @@ -3196,24 +3376,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. @@ -3223,7 +3405,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; @@ -3241,12 +3423,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; @@ -3271,9 +3462,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. */ @@ -3286,10 +3478,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 @@ -3302,7 +3496,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; @@ -3312,9 +3507,48 @@ 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 + 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; + if (reqCtxLen != 0) { + XMEMCPY(output + i, reqCtx, reqCtxLen); + 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); @@ -3343,6 +3577,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, @@ -3353,15 +3588,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 */ @@ -3823,7 +4062,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; @@ -3847,8 +4086,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 { @@ -4002,9 +4241,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; @@ -4027,6 +4267,8 @@ int SendTls13Certificate(WOLFSSL* ssl) } #endif + WOLFSSL_LEAVE("SendTls13Certificate", ret); + return ret; } @@ -4073,7 +4315,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; @@ -4153,8 +4395,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. */ @@ -4342,9 +4586,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; @@ -4390,12 +4635,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; @@ -4404,7 +4649,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) @@ -4788,6 +5035,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; @@ -4816,7 +5069,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; @@ -4878,30 +5131,50 @@ 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) { /* 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; @@ -4978,9 +5251,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; @@ -4990,7 +5264,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 +5317,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 +5332,92 @@ 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; + + WOLFSSL_ENTER("SendTls13EndOfEarlyData"); + + 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; + + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13EndOfEarlyData", ret); + + return ret; +} +#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) +{ + int ret; + word32 begin = *inOutIdx; + + (void)input; + + WOLFSSL_ENTER("DoTls13EndOfEarlyData"); + + if ((*inOutIdx - begin) != size) + return BUFFER_ERROR; + + /* Always encrypted. */ + *inOutIdx += ssl->keys.padSz; + + ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY); + + WOLFSSL_LEAVE("SendTls13EndOfEarlyData", ret); + + return ret; +} +#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,10 +5433,16 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size) { #ifdef HAVE_SESSION_TICKET - word32 begin = *inOutIdx; - word32 lifetime; - word32 ageAdd; - word16 length; + #ifdef WOLFSSL_EARLY_DATA + int ret; + #endif + word32 begin = *inOutIdx; + word32 lifetime; + word32 ageAdd; + word16 length; + word32 now; + + WOLFSSL_ENTER("DoTls13NewSessionTicket"); /* Lifetime hint. */ if ((*inOutIdx - begin) + SESSION_HINT_SZ > size) @@ -5115,37 +5483,51 @@ 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 = now; + 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; @@ -5153,37 +5535,156 @@ 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 */ #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. * * ssl The SSL/TLS object. * retuns 0 on success, otherwise failure. */ -int SendTls13NewSessionTicket(WOLFSSL* ssl) +static int SendTls13NewSessionTicket(WOLFSSL* ssl) { byte* output; int ret; int sendSz; + word32 extSz; word32 length; word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - if (!ssl->options.noTicketTls13) { - ret = CreateTicket(ssl); - if (ret != 0) return ret; + 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; + } + +#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 +5712,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; @@ -5229,7 +5734,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 */ @@ -5278,6 +5788,19 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) break; #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"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_end_of_early_data++; + + break; + #endif +#endif + #ifndef NO_WOLFSSL_CLIENT case hello_retry_request: if (ssl->msgsReceived.got_hello_retry_request) { @@ -5499,6 +6022,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,28 +6079,52 @@ 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) - 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 } @@ -5738,6 +6294,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 +6367,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 +6391,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 +6408,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 +6426,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 +6435,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; @@ -6028,7 +6606,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; @@ -6057,8 +6634,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 +6837,17 @@ 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 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) { @@ -6272,6 +6855,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 +6874,12 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) case ACCEPT_SECOND_REPLY_DONE : #ifdef HAVE_SESSION_TICKET - if (!ssl->options.resuming && ssl->options.verifyPeer && + #ifdef WOLFSSL_TLS13_TICKET_BEFORE_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 +6922,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 5b1708063..81a2b38f1 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 @@ -2227,6 +2245,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 */ @@ -2558,6 +2579,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]; @@ -2808,6 +2832,9 @@ typedef struct Options { #if defined(HAVE_ECC) || defined(HAVE_ED25519) short minEccKeySz; /* minimum ECC key size */ #endif +#ifdef WOLFSSL_EARLY_DATA + word32 maxEarlyDataSz; +#endif } Options; @@ -3019,6 +3046,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; @@ -3332,6 +3360,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 }; @@ -3432,27 +3464,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 }; @@ -3470,26 +3509,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*); @@ -3498,7 +3525,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); @@ -3595,13 +3622,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 */ 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*);