diff options
Diffstat (limited to 'FreeRTOS-Plus/Source/WolfSSL/src/tls13.c')
-rw-r--r-- | FreeRTOS-Plus/Source/WolfSSL/src/tls13.c | 9048 |
1 files changed, 9048 insertions, 0 deletions
diff --git a/FreeRTOS-Plus/Source/WolfSSL/src/tls13.c b/FreeRTOS-Plus/Source/WolfSSL/src/tls13.c new file mode 100644 index 000000000..9b9b1d1b9 --- /dev/null +++ b/FreeRTOS-Plus/Source/WolfSSL/src/tls13.c @@ -0,0 +1,9048 @@ +/* tls13.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +/* + * BUILD_GCM + * Enables AES-GCM ciphersuites. + * HAVE_AESCCM + * Enables AES-CCM ciphersuites. + * HAVE_SESSION_TICKET + * Enables session tickets - required for TLS 1.3 resumption. + * NO_PSK + * Do not enable Pre-Shared Keys. + * TLS13_SUPPORTS_EXPORTERS + * Guard to compile out any code for exporter keys. + * Feature not supported yet. + * WOLFSSL_ASYNC_CRYPT + * Enables the use of asynchronous cryptographic operations. + * This is available for ciphers and certificates. + * HAVE_CHACHA && HAVE_POLY1305 + * Enables use of CHACHA20-POLY1305 ciphersuites. + * WOLFSSL_DEBUG_TLS + * Writes out details of TLS 1.3 protocol including handshake message buffers + * and key generation input and output. + * WOLFSSL_EARLY_DATA + * Allow 0-RTT Handshake using Early Data extensions and handshake message + * WOLFSSL_EARLY_DATA_GROUP + * Group EarlyData message with ClientHello when sending + * WOLFSSL_NO_SERVER_GROUPS_EXT + * Do not send the server's groups in an extension when the server's top + * preference is not in client's list. + * WOLFSSL_POST_HANDSHAKE_AUTH + * Allow TLS v1.3 code to perform post-handshake authentication of the + * client. + * WOLFSSL_SEND_HRR_COOKIE + * Send a cookie in hello_retry_request message to enable stateless tracking + * of ClientHello replies. + * WOLFSSL_TLS13 + * Enable TLS 1.3 protocol implementation. + * WOLFSSL_TLS13_DRAFT_18 + * Conform with Draft 18 of the TLS v1.3 specification. + * WOLFSSL_TLS13_DRAFT_22 + * Conform with Draft 22 of the TLS v1.3 specification. + * WOLFSSL_TLS13_DRAFT_23 + * Conform with Draft 23 of the TLS v1.3 specification. + * WOLFSSL_TLS13_MIDDLEBOX_COMPAT + * Enable middlebox compatibility in the TLS 1.3 handshake. + * This includes sending ChangeCipherSpec before encrypted messages and + * including a session id. + * WOLFSSL_TLS13_SHA512 + * Allow generation of SHA-512 digests in handshake - no ciphersuite + * requires SHA-512 at this time. + * WOLFSSL_TLS13_TICKET_BEFORE_FINISHED + * Allow a NewSessionTicket message to be sent by server before Client's + * Finished message. + * See TLS v1.3 specification, Section 4.6.1, Paragraph 4 (Note). + */ + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <wolfssl/wolfcrypt/settings.h> + +#ifdef WOLFSSL_TLS13 +#ifdef HAVE_SESSION_TICKET + #include <wolfssl/wolfcrypt/wc_port.h> +#endif + +#ifndef WOLFCRYPT_ONLY + +#ifdef HAVE_ERRNO_H + #include <errno.h> +#endif + +#include <wolfssl/internal.h> +#include <wolfssl/error-ssl.h> +#include <wolfssl/wolfcrypt/asn.h> +#include <wolfssl/wolfcrypt/dh.h> +#ifdef NO_INLINE + #include <wolfssl/wolfcrypt/misc.h> +#else + #define WOLFSSL_MISC_INCLUDED + #include <wolfcrypt/src/misc.c> +#endif + +#ifdef HAVE_NTRU + #include "libntruencrypt/ntru_crypto.h" +#endif + +#ifdef __sun + #include <sys/filio.h> +#endif + +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + +#ifndef HAVE_HKDF + #error The build option HAVE_HKDF is required for TLS 1.3 +#endif + +#ifndef HAVE_TLS_EXTENSIONS + #ifndef _MSC_VER + #error "The build option HAVE_TLS_EXTENSIONS is required for TLS 1.3" + #else + #pragma message("error: The build option HAVE_TLS_EXTENSIONS is required for TLS 1.3") + #endif +#endif + + +/* Set ret to error value and jump to label. + * + * err The error value to set. + * eLabel The label to jump to. + */ +#define ERROR_OUT(err, eLabel) { ret = (err); goto eLabel; } + + +/* Extract data using HMAC, salt and input. + * RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function (HKDF) + * + * prk The generated pseudorandom key. + * salt The salt. + * saltLen The length of the salt. + * ikm The input keying material. + * ikmLen The length of the input keying material. + * mac The type of digest to use. + * returns 0 on success, otherwise failure. + */ +static int Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen, + byte* ikm, int ikmLen, int mac) +{ + int ret; + int hash = 0; + int len = 0; + + switch (mac) { + #ifndef NO_SHA256 + case sha256_mac: + hash = WC_SHA256; + len = WC_SHA256_DIGEST_SIZE; + break; + #endif + + #ifdef WOLFSSL_SHA384 + case sha384_mac: + hash = WC_SHA384; + len = WC_SHA384_DIGEST_SIZE; + break; + #endif + + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + hash = WC_SHA512; + len = WC_SHA512_DIGEST_SIZE; + break; + #endif + } + + /* When length is 0 then use zeroed data of digest length. */ + if (ikmLen == 0) { + ikmLen = len; + XMEMSET(ikm, 0, len); + } + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" Salt"); + WOLFSSL_BUFFER(salt, saltLen); + 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_BUFFER(prk, len); +#endif + + return ret; +} + +/* Expand data using HMAC, salt and label and info. + * TLS v1.3 defines this function. + * + * okm The generated pseudorandom key - output key material. + * okmLen The length of generated pseudorandom key - output key material. + * prk The salt - pseudo-random key. + * prkLen The length of the salt - pseudo-random key. + * protocol The TLS protocol label. + * protocolLen The length of the TLS protocol label. + * info The information to expand. + * infoLen The length of the information. + * digest The type of digest to use. + * returns 0 on success, otherwise failure. + */ +static int HKDF_Expand_Label(byte* okm, word32 okmLen, + const byte* prk, word32 prkLen, + const byte* protocol, word32 protocolLen, + const byte* label, word32 labelLen, + const byte* info, word32 infoLen, + int digest) +{ + int ret = 0; + int idx = 0; + byte data[MAX_HKDF_LABEL_SZ]; + + /* Output length. */ + data[idx++] = (byte)(okmLen >> 8); + data[idx++] = (byte)okmLen; + /* Length of protocol | label. */ + data[idx++] = (byte)(protocolLen + labelLen); + /* Protocol */ + XMEMCPY(&data[idx], protocol, protocolLen); + idx += protocolLen; + /* Label */ + XMEMCPY(&data[idx], label, labelLen); + idx += labelLen; + /* Length of hash of messages */ + data[idx++] = (byte)infoLen; + /* Hash of messages */ + XMEMCPY(&data[idx], info, infoLen); + idx += infoLen; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" PRK"); + WOLFSSL_BUFFER(prk, prkLen); + 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_BUFFER(okm, okmLen); +#endif + + ForceZero(data, idx); + + return ret; +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* Size of the TLS v1.3 label use when deriving keys. */ +#define TLS13_PROTOCOL_LABEL_SZ 9 +/* The protocol label for TLS v1.3. */ +static const byte tls13ProtocolLabel[TLS13_PROTOCOL_LABEL_SZ + 1] = "TLS 1.3, "; +#else +/* Size of the TLS v1.3 label use when deriving keys. */ +#define TLS13_PROTOCOL_LABEL_SZ 6 +/* The protocol label for TLS v1.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. + * output The buffer to hold the derived key. + * outputLen The length of the derived key. + * secret The secret used to derive the key (HMAC secret). + * label The label used to distinguish the context. + * labelLen The length of the label. + * msg The message data to derive key from. + * msgLen The length of the message data to derive key from. + * hashAlgo The hash algorithm to use in the HMAC. + * returns 0 on success, otherwise failure. + */ +static int DeriveKeyMsg(WOLFSSL* ssl, byte* output, int outputLen, + const byte* secret, const byte* label, word32 labelLen, + byte* msg, int msgLen, int hashAlgo) +{ + byte hash[WC_MAX_DIGEST_SIZE]; + Digest digest; + word32 hashSz = 0; + const byte* protocol; + word32 protocolLen; + int digestAlg = -1; + int ret = BAD_FUNC_ARG; + + switch (hashAlgo) { +#ifndef NO_WOLFSSL_SHA256 + case sha256_mac: + ret = wc_InitSha256_ex(&digest.sha256, ssl->heap, INVALID_DEVID); + if (ret == 0) { + ret = wc_Sha256Update(&digest.sha256, msg, msgLen); + if (ret == 0) + ret = wc_Sha256Final(&digest.sha256, hash); + wc_Sha256Free(&digest.sha256); + } + hashSz = WC_SHA256_DIGEST_SIZE; + digestAlg = WC_SHA256; + break; +#endif +#ifdef WOLFSSL_SHA384 + case sha384_mac: + ret = wc_InitSha384_ex(&digest.sha384, ssl->heap, INVALID_DEVID); + if (ret == 0) { + ret = wc_Sha384Update(&digest.sha384, msg, msgLen); + if (ret == 0) + ret = wc_Sha384Final(&digest.sha384, hash); + wc_Sha384Free(&digest.sha384); + } + hashSz = WC_SHA384_DIGEST_SIZE; + digestAlg = WC_SHA384; + break; +#endif +#ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + ret = wc_InitSha512_ex(&digest.sha512, ssl->heap, INVALID_DEVID); + if (ret == 0) { + ret = wc_Sha512Update(&digest.sha512, msg, msgLen); + if (ret == 0) + ret = wc_Sha512Final(&digest.sha512, hash); + wc_Sha512Free(&digest.sha512); + } + hashSz = WC_SHA512_DIGEST_SIZE; + digestAlg = WC_SHA512; + break; +#endif + default: + digestAlg = -1; + break; + } + + if (digestAlg < 0) + return HASH_TYPE_E; + + if (ret != 0) + return ret; + + switch (ssl->version.minor) { + case TLSv1_3_MINOR: + protocol = tls13ProtocolLabel; + protocolLen = TLS13_PROTOCOL_LABEL_SZ; + break; + + default: + return VERSION_ERROR; + } + if (outputLen == -1) + outputLen = hashSz; + + return HKDF_Expand_Label(output, outputLen, secret, hashSz, + protocol, protocolLen, label, labelLen, + hash, hashSz, digestAlg); +} +#endif + +/* Derive a key. + * + * ssl The SSL/TLS object. + * output The buffer to hold the derived key. + * outputLen The length of the derived key. + * secret The secret used to derive the key (HMAC secret). + * label The label used to distinguish the context. + * labelLen The length of the label. + * hashAlgo The hash algorithm to use in the HMAC. + * includeMsgs Whether to include a hash of the handshake messages so far. + * returns 0 on success, otherwise failure. + */ +static int DeriveKey(WOLFSSL* ssl, byte* output, int outputLen, + const byte* secret, const byte* label, word32 labelLen, + int hashAlgo, int includeMsgs) +{ + int ret = 0; + byte hash[WC_MAX_DIGEST_SIZE]; + word32 hashSz = 0; + word32 hashOutSz = 0; + const byte* protocol; + word32 protocolLen; + int digestAlg = 0; + + switch (hashAlgo) { + #ifndef NO_SHA256 + case sha256_mac: + hashSz = WC_SHA256_DIGEST_SIZE; + digestAlg = WC_SHA256; + if (includeMsgs) + ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash); + break; + #endif + + #ifdef WOLFSSL_SHA384 + case sha384_mac: + hashSz = WC_SHA384_DIGEST_SIZE; + digestAlg = WC_SHA384; + if (includeMsgs) + ret = wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash); + break; + #endif + + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + hashSz = WC_SHA512_DIGEST_SIZE; + digestAlg = WC_SHA512; + if (includeMsgs) + ret = wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash); + break; + #endif + } + if (ret != 0) + return ret; + + /* Only one protocol version defined at this time. */ + protocol = tls13ProtocolLabel; + protocolLen = TLS13_PROTOCOL_LABEL_SZ; + + if (outputLen == -1) + outputLen = hashSz; + if (includeMsgs) + hashOutSz = hashSz; + + return HKDF_Expand_Label(output, outputLen, secret, hashSz, + protocol, protocolLen, label, labelLen, + hash, hashOutSz, digestAlg); +} + +#ifndef NO_PSK +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the binder key label. */ +#define BINDER_KEY_LABEL_SZ 23 +/* The binder key label. */ +static const byte binderKeyLabel[BINDER_KEY_LABEL_SZ + 1] = + "external psk binder key"; +#else +/* The length of the binder key label. */ +#define BINDER_KEY_LABEL_SZ 10 +/* The binder key label. */ +static const byte binderKeyLabel[BINDER_KEY_LABEL_SZ + 1] = + "ext binder"; +#endif +/* Derive the binder key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveBinderKey(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Binder Key"); + return DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret, + binderKeyLabel, BINDER_KEY_LABEL_SZ, + NULL, 0, ssl->specs.mac_algorithm); +} +#endif /* !NO_PSK */ + +#ifdef HAVE_SESSION_TICKET +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the binder key resume label. */ +#define BINDER_KEY_RESUME_LABEL_SZ 25 +/* The binder key resume label. */ +static const byte binderKeyResumeLabel[BINDER_KEY_RESUME_LABEL_SZ + 1] = + "resumption psk binder key"; +#else +/* The length of the binder key resume label. */ +#define BINDER_KEY_RESUME_LABEL_SZ 10 +/* The binder key resume label. */ +static const byte binderKeyResumeLabel[BINDER_KEY_RESUME_LABEL_SZ + 1] = + "res binder"; +#endif +/* Derive the binder resumption key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveBinderKeyResume(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Binder Key - Resumption"); + return DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret, + binderKeyResumeLabel, BINDER_KEY_RESUME_LABEL_SZ, + NULL, 0, ssl->specs.mac_algorithm); +} +#endif /* HAVE_SESSION_TICKET */ + +#ifdef WOLFSSL_EARLY_DATA +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the early traffic label. */ +#define EARLY_TRAFFIC_LABEL_SZ 27 +/* The early traffic label. */ +static const byte earlyTrafficLabel[EARLY_TRAFFIC_LABEL_SZ + 1] = + "client early traffic secret"; +#else +/* The length of the early traffic label. */ +#define EARLY_TRAFFIC_LABEL_SZ 11 +/* The early traffic label. */ +static const byte earlyTrafficLabel[EARLY_TRAFFIC_LABEL_SZ + 1] = + "c e traffic"; +#endif +/* Derive the early traffic key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveEarlyTrafficSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Early Traffic Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->secret, + earlyTrafficLabel, EARLY_TRAFFIC_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, CLIENT_EARLY_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} + +#ifdef TLS13_SUPPORTS_EXPORTERS +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the early exporter label. */ +#define EARLY_EXPORTER_LABEL_SZ 28 +/* The early exporter label. */ +static const byte earlyExporterLabel[EARLY_EXPORTER_LABEL_SZ + 1] = + "early exporter master secret"; +#else +/* The length of the early exporter label. */ +#define EARLY_EXPORTER_LABEL_SZ 12 +/* The early exporter label. */ +static const byte earlyExporterLabel[EARLY_EXPORTER_LABEL_SZ + 1] = + "e exp master"; +#endif +/* Derive the early exporter key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveEarlyExporterSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Early Exporter Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->secret, + earlyExporterLabel, EARLY_EXPORTER_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, EARLY_EXPORTER_SECRET, key + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} +#endif +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the client handshake label. */ +#define CLIENT_HANDSHAKE_LABEL_SZ 31 +/* The client handshake label. */ +static const byte clientHandshakeLabel[CLIENT_HANDSHAKE_LABEL_SZ + 1] = + "client handshake traffic secret"; +#else +/* The length of the client handshake label. */ +#define CLIENT_HANDSHAKE_LABEL_SZ 12 +/* The client handshake label. */ +static const byte clientHandshakeLabel[CLIENT_HANDSHAKE_LABEL_SZ + 1] = + "c hs traffic"; +#endif +/* Derive the client handshake key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveClientHandshakeSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Client Handshake Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret, + clientHandshakeLabel, CLIENT_HANDSHAKE_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, CLIENT_HANDSHAKE_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the server handshake label. */ +#define SERVER_HANDSHAKE_LABEL_SZ 31 +/* The server handshake label. */ +static const byte serverHandshakeLabel[SERVER_HANDSHAKE_LABEL_SZ + 1] = + "server handshake traffic secret"; +#else +/* The length of the server handshake label. */ +#define SERVER_HANDSHAKE_LABEL_SZ 12 +/* The server handshake label. */ +static const byte serverHandshakeLabel[SERVER_HANDSHAKE_LABEL_SZ + 1] = + "s hs traffic"; +#endif +/* Derive the server handshake key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveServerHandshakeSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Server Handshake Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret, + serverHandshakeLabel, SERVER_HANDSHAKE_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, SERVER_HANDSHAKE_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the client application traffic label. */ +#define CLIENT_APP_LABEL_SZ 33 +/* The client application traffic label. */ +static const byte clientAppLabel[CLIENT_APP_LABEL_SZ + 1] = + "client application traffic secret"; +#else +/* The length of the client application traffic label. */ +#define CLIENT_APP_LABEL_SZ 12 +/* The client application traffic label. */ +static const byte clientAppLabel[CLIENT_APP_LABEL_SZ + 1] = + "c ap traffic"; +#endif +/* Derive the client application traffic key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveClientTrafficSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Client Traffic Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + clientAppLabel, CLIENT_APP_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, CLIENT_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the server application traffic label. */ +#define SERVER_APP_LABEL_SZ 33 +/* The server application traffic label. */ +static const byte serverAppLabel[SERVER_APP_LABEL_SZ + 1] = + "server application traffic secret"; +#else +/* The length of the server application traffic label. */ +#define SERVER_APP_LABEL_SZ 12 +/* The server application traffic label. */ +static const byte serverAppLabel[SERVER_APP_LABEL_SZ + 1] = + "s ap traffic"; +#endif +/* Derive the server application traffic key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveServerTrafficSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Server Traffic Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + serverAppLabel, SERVER_APP_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, SERVER_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} + +#ifdef TLS13_SUPPORTS_EXPORTERS +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the exporter master secret label. */ +#define EXPORTER_MASTER_LABEL_SZ 22 +/* The exporter master secret label. */ +static const byte exporterMasterLabel[EXPORTER_MASTER_LABEL_SZ + 1] = + "exporter master secret"; +#else +/* The length of the exporter master secret label. */ +#define EXPORTER_MASTER_LABEL_SZ 10 +/* The exporter master secret label. */ +static const byte exporterMasterLabel[EXPORTER_MASTER_LABEL_SZ + 1] = + "exp master"; +#endif +/* Derive the exporter secret. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveExporterSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Exporter Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + exporterMasterLabel, EXPORTER_MASTER_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, EXPORTER_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} +#endif + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the resumption master secret label. */ +#define RESUME_MASTER_LABEL_SZ 24 +/* The resumption master secret label. */ +static const byte resumeMasterLabel[RESUME_MASTER_LABEL_SZ + 1] = + "resumption master secret"; +#else +/* The length of the resumption master secret label. */ +#define RESUME_MASTER_LABEL_SZ 10 +/* The resumption master secret label. */ +static const byte resumeMasterLabel[RESUME_MASTER_LABEL_SZ + 1] = + "res master"; +#endif +/* Derive the resumption secret. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveResumptionSecret(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Resumption Secret"); + return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + resumeMasterLabel, RESUME_MASTER_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +} +#endif + +/* Length of the finished label. */ +#define FINISHED_LABEL_SZ 8 +/* Finished label for generating finished key. */ +static const byte finishedLabel[FINISHED_LABEL_SZ+1] = "finished"; +/* Derive the finished secret. + * + * ssl The SSL/TLS object. + * key The key to use with the HMAC. + * secret The derived secret. + * returns 0 on success, otherwise failure. + */ +static int DeriveFinishedSecret(WOLFSSL* ssl, byte* key, byte* secret) +{ + WOLFSSL_MSG("Derive Finished Secret"); + return DeriveKey(ssl, secret, -1, key, finishedLabel, FINISHED_LABEL_SZ, + ssl->specs.mac_algorithm, 0); +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the application traffic label. */ +#define APP_TRAFFIC_LABEL_SZ 26 +/* The application traffic label. */ +static const byte appTrafficLabel[APP_TRAFFIC_LABEL_SZ + 1] = + "application traffic secret"; +#else +/* The length of the application traffic label. */ +#define APP_TRAFFIC_LABEL_SZ 11 +/* The application traffic label. */ +static const byte appTrafficLabel[APP_TRAFFIC_LABEL_SZ + 1] = + "traffic upd"; +#endif +/* Update the traffic secret. + * + * ssl The SSL/TLS object. + * secret The previous secret and derived secret. + * returns 0 on success, otherwise failure. + */ +static int DeriveTrafficSecret(WOLFSSL* ssl, byte* secret) +{ + WOLFSSL_MSG("Derive New Application Traffic Secret"); + return DeriveKey(ssl, secret, -1, secret, + appTrafficLabel, APP_TRAFFIC_LABEL_SZ, + ssl->specs.mac_algorithm, 0); +} + +/* Derive the early secret using HKDF Extract. + * + * ssl The SSL/TLS object. + */ +static int DeriveEarlySecret(WOLFSSL* ssl) +{ + WOLFSSL_MSG("Derive Early Secret"); +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + return Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0, + ssl->arrays->psk_key, ssl->arrays->psk_keySz, + ssl->specs.mac_algorithm); +#else + return Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0, + ssl->arrays->masterSecret, 0, ssl->specs.mac_algorithm); +#endif +} + +#ifndef WOLFSSL_TLS13_DRAFT_18 +/* The length of the derived label. */ +#define DERIVED_LABEL_SZ 7 +/* The derived label. */ +static const byte derivedLabel[DERIVED_LABEL_SZ + 1] = + "derived"; +#endif +/* Derive the handshake secret using HKDF Extract. + * + * ssl The SSL/TLS object. + */ +static int DeriveHandshakeSecret(WOLFSSL* ssl) +{ +#ifdef WOLFSSL_TLS13_DRAFT_18 + WOLFSSL_MSG("Derive Handshake Secret"); + return Tls13_HKDF_Extract(ssl->arrays->preMasterSecret, + ssl->arrays->secret, ssl->specs.hash_size, + ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz, + ssl->specs.mac_algorithm); +#else + byte key[WC_MAX_DIGEST_SIZE]; + int ret; + + WOLFSSL_MSG("Derive Handshake Secret"); + + ret = DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret, + derivedLabel, DERIVED_LABEL_SZ, + NULL, 0, ssl->specs.mac_algorithm); + if (ret != 0) + return ret; + + return Tls13_HKDF_Extract(ssl->arrays->preMasterSecret, + key, ssl->specs.hash_size, + ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz, + ssl->specs.mac_algorithm); +#endif +} + +/* Derive the master secret using HKDF Extract. + * + * ssl The SSL/TLS object. + */ +static int DeriveMasterSecret(WOLFSSL* ssl) +{ +#ifdef WOLFSSL_TLS13_DRAFT_18 + WOLFSSL_MSG("Derive Master Secret"); + return Tls13_HKDF_Extract(ssl->arrays->masterSecret, + ssl->arrays->preMasterSecret, ssl->specs.hash_size, + ssl->arrays->masterSecret, 0, ssl->specs.mac_algorithm); +#else + byte key[WC_MAX_DIGEST_SIZE]; + int ret; + + WOLFSSL_MSG("Derive Master Secret"); + + ret = DeriveKeyMsg(ssl, key, -1, ssl->arrays->preMasterSecret, + derivedLabel, DERIVED_LABEL_SZ, + NULL, 0, ssl->specs.mac_algorithm); + if (ret != 0) + return ret; + + return Tls13_HKDF_Extract(ssl->arrays->masterSecret, + key, ssl->specs.hash_size, + ssl->arrays->masterSecret, 0, ssl->specs.mac_algorithm); +#endif +} + +#ifndef WOLFSSL_TLS13_DRAFT_18 +#if defined(HAVE_SESSION_TICKET) +/* Length of the resumption label. */ +#define RESUMPTION_LABEL_SZ 10 +/* Resumption label for generating PSK associated with the ticket. */ +static const byte resumptionLabel[RESUMPTION_LABEL_SZ+1] = "resumption"; +/* Derive the PSK associated with the ticket. + * + * ssl The SSL/TLS object. + * nonce The nonce to derive with. + * nonceLen The length of the nonce to derive with. + * secret The derived secret. + * returns 0 on success, otherwise failure. + */ +static int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, + byte* secret) +{ + int digestAlg; + /* Only one protocol version defined at this time. */ + const byte* protocol = tls13ProtocolLabel; + word32 protocolLen = TLS13_PROTOCOL_LABEL_SZ; + + WOLFSSL_MSG("Derive Resumption PSK"); + + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + digestAlg = WC_SHA256; + break; + #endif + + #ifdef WOLFSSL_SHA384 + case sha384_mac: + digestAlg = WC_SHA384; + break; + #endif + + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + digestAlg = WC_SHA512; + break; + #endif + + default: + return BAD_FUNC_ARG; + } + + return HKDF_Expand_Label(secret, ssl->specs.hash_size, + ssl->session.masterSecret, ssl->specs.hash_size, + protocol, protocolLen, resumptionLabel, + RESUMPTION_LABEL_SZ, nonce, nonceLen, digestAlg); +} +#endif /* HAVE_SESSION_TICKET */ +#endif /* WOLFSSL_TLS13_DRAFT_18 */ + + +/* Calculate the HMAC of message data to this point. + * + * ssl The SSL/TLS object. + * key The HMAC key. + * hash The hash result - verify data. + * returns length of verify data generated. + */ +static int BuildTls13HandshakeHmac(WOLFSSL* ssl, byte* key, byte* hash, + word32* pHashSz) +{ + Hmac verifyHmac; + int hashType = WC_SHA256; + int hashSz = WC_SHA256_DIGEST_SIZE; + int ret = BAD_FUNC_ARG; + + /* Get the hash of the previous handshake messages. */ + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + hashType = WC_SHA256; + hashSz = WC_SHA256_DIGEST_SIZE; + ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash); + break; + #endif /* !NO_SHA256 */ + #ifdef WOLFSSL_SHA384 + case sha384_mac: + hashType = WC_SHA384; + hashSz = WC_SHA384_DIGEST_SIZE; + ret = wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash); + break; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + hashType = WC_SHA512; + hashSz = WC_SHA512_DIGEST_SIZE; + ret = wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash); + break; + #endif /* WOLFSSL_TLS13_SHA512 */ + } + if (ret != 0) + return ret; + + /* Calculate the verify data. */ + ret = wc_HmacInit(&verifyHmac, ssl->heap, ssl->devId); + if (ret == 0) { + ret = wc_HmacSetKey(&verifyHmac, hashType, key, ssl->specs.hash_size); + if (ret == 0) + ret = wc_HmacUpdate(&verifyHmac, hash, hashSz); + if (ret == 0) + ret = wc_HmacFinal(&verifyHmac, hash); + wc_HmacFree(&verifyHmac); + } + + if (pHashSz) + *pHashSz = hashSz; + + return ret; +} + +/* The length of the label to use when deriving keys. */ +#define WRITE_KEY_LABEL_SZ 3 +/* The length of the label to use when deriving IVs. */ +#define WRITE_IV_LABEL_SZ 2 +/* The label to use when deriving keys. */ +static const byte writeKeyLabel[WRITE_KEY_LABEL_SZ+1] = "key"; +/* The label to use when deriving IVs. */ +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 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. + * update_traffic_key when deriving next keys and IVs for encrypting + * traffic messages. + * 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, int store) +{ + int ret = BAD_FUNC_ARG; /* Assume failure */ + int i = 0; +#ifdef WOLFSSL_SMALL_STACK + byte* key_dig; +#else + byte key_dig[MAX_PRF_DIG]; +#endif + int provision; + +#ifdef WOLFSSL_SMALL_STACK + key_dig = (byte*)XMALLOC(MAX_PRF_DIG, ssl->heap, DYNAMIC_TYPE_DIGEST); + if (key_dig == NULL) + return MEMORY_E; +#endif + + if (side == ENCRYPT_AND_DECRYPT_SIDE) { + provision = PROVISION_CLIENT_SERVER; + } + else { + 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->clientSecret); + if (ret != 0) + goto end; + break; +#endif + + case handshake_key: + if (provision & PROVISION_CLIENT) { + ret = DeriveClientHandshakeSecret(ssl, + ssl->clientSecret); + if (ret != 0) + goto end; + } + if (provision & PROVISION_SERVER) { + ret = DeriveServerHandshakeSecret(ssl, + ssl->serverSecret); + if (ret != 0) + goto end; + } + break; + + case traffic_key: + if (provision & PROVISION_CLIENT) { + ret = DeriveClientTrafficSecret(ssl, ssl->clientSecret); + if (ret != 0) + goto end; + } + if (provision & PROVISION_SERVER) { + ret = DeriveServerTrafficSecret(ssl, ssl->serverSecret); + if (ret != 0) + goto end; + } + break; + + case update_traffic_key: + if (provision & PROVISION_CLIENT) { + ret = DeriveTrafficSecret(ssl, ssl->clientSecret); + if (ret != 0) + goto end; + } + if (provision & PROVISION_SERVER) { + ret = DeriveTrafficSecret(ssl, ssl->serverSecret); + if (ret != 0) + goto end; + } + break; + } + + if (!store) + goto end; + + /* Key data = client key | server key | client IV | server IV */ + + if (provision & PROVISION_CLIENT) { + /* Derive the client key. */ + WOLFSSL_MSG("Derive Client Key"); + ret = DeriveKey(ssl, &key_dig[i], ssl->specs.key_size, + ssl->clientSecret, 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->serverSecret, 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 IV. */ + WOLFSSL_MSG("Derive Client IV"); + ret = DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, + ssl->clientSecret, writeIVLabel, + WRITE_IV_LABEL_SZ, ssl->specs.mac_algorithm, 0); + if (ret != 0) + goto end; + i += ssl->specs.iv_size; + } + + if (provision & PROVISION_SERVER) { + /* Derive the server IV. */ + WOLFSSL_MSG("Derive Server IV"); + ret = DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, + ssl->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, provision); + +end: +#ifdef WOLFSSL_SMALL_STACK + XFREE(key_dig, ssl->heap, DYNAMIC_TYPE_DIGEST); +#endif + + return ret; +} + +#ifdef HAVE_SESSION_TICKET +#if defined(USER_TICKS) +#if 0 + word32 TimeNowInMilliseconds(void) + { + /* + write your own clock tick function if don't want gettimeofday() + needs millisecond accuracy but doesn't have to correlated to EPOCH + */ + } +#endif + +#elif defined(TIME_OVERRIDES) + #ifndef HAVE_TIME_T_TYPE + typedef long time_t; + #endif + extern time_t XTIME(time_t * timer); + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32) XTIME(0) * 1000; + } + +#elif defined(XTIME_MS) + word32 TimeNowInMilliseconds(void) + { + return (word32)XTIME_MS(0); + } + +#elif defined(USE_WINDOWS_API) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + static int init = 0; + static LARGE_INTEGER freq; + LARGE_INTEGER count; + + if (!init) { + QueryPerformanceFrequency(&freq); + init = 1; + } + + QueryPerformanceCounter(&count); + + return (word32)(count.QuadPart / (freq.QuadPart / 1000)); + } + +#elif defined(HAVE_RTP_SYS) + #include "rtptime.h" + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32)rtp_get_system_sec() * 1000; + } +#elif defined(WOLFSSL_DEOS) + word32 TimeNowInMilliseconds(void) + { + const uint32_t systemTickTimeInHz = 1000000 / systemTickInMicroseconds(); + uint32_t *systemTickPtr = systemTickPointer(); + + return (word32) (*systemTickPtr/systemTickTimeInHz) * 1000; + } +#elif defined(MICRIUM) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + OS_TICK ticks = 0; + OS_ERR err; + + ticks = OSTimeGet(&err); + + return (word32) (ticks / OSCfg_TickRate_Hz) * 1000; + } +#elif defined(MICROCHIP_TCPIP_V5) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32) (TickGet() / (TICKS_PER_SECOND / 1000)); + } +#elif defined(MICROCHIP_TCPIP) + #if defined(MICROCHIP_MPLAB_HARMONY) + #include <system/tmr/sys_tmr.h> + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32)(SYS_TMR_TickCountGet() / + (SYS_TMR_TickCounterFrequencyGet() / 1000)); + } + #else + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32)(SYS_TICK_Get() / (SYS_TICK_TicksPerSecondGet() / 1000)); + } + + #endif + +#elif defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + TIME_STRUCT mqxTime; + + _time_get_elapsed(&mqxTime); + + return (word32) mqxTime.SECONDS * 1000; + } +#elif defined(FREESCALE_FREE_RTOS) || defined(FREESCALE_KSDK_FREERTOS) + #include "include/task.h" + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (unsigned int)(((float)xTaskGetTickCount()) / + (configTICK_RATE_HZ / 1000)); + } +#elif defined(FREESCALE_KSDK_BM) + #include "lwip/sys.h" /* lwIP */ + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return sys_now(); + } +#elif defined(WOLFSSL_TIRTOS) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32) Seconds_get() * 1000; + } +#elif defined(WOLFSSL_UTASKER) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32)(uTaskerSystemTick / (TICK_RESOLUTION / 1000)); + } +#else + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + struct timeval now; + + if (gettimeofday(&now, 0) < 0) + return GETTIME_ERROR; + /* Convert to milliseconds number. */ + return (word32)(now.tv_sec * 1000 + now.tv_usec / 1000); + } +#endif +#endif /* HAVE_SESSION_TICKET || !NO_PSK */ + + +#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_SESSION_TICKET) || \ + !defined(NO_PSK)) +/* Add input to all handshake hashes. + * + * ssl The SSL/TLS object. + * input The data to hash. + * sz The size of the data to hash. + * returns 0 on success, otherwise failure. + */ +static int HashInputRaw(WOLFSSL* ssl, const byte* input, int sz) +{ + int ret = BAD_FUNC_ARG; + +#ifndef NO_SHA256 + ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, input, sz); + if (ret != 0) + return ret; +#endif +#ifdef WOLFSSL_SHA384 + ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, input, sz); + if (ret != 0) + return ret; +#endif +#ifdef WOLFSSL_TLS13_SHA512 + ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, input, sz); + if (ret != 0) + return ret; +#endif + + return ret; +} +#endif + +/* Extract the handshake header information. + * + * ssl The SSL/TLS object. + * input The buffer holding the message data. + * inOutIdx On entry, the index into the buffer of the handshake data. + * On exit, the start of the handshake data. + * type Type of handshake message. + * size The length of the handshake message data. + * totalSz The total size of data in the buffer. + * returns BUFFER_E if there is not enough input data and 0 on success. + */ +static int GetHandshakeHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + byte* type, word32* size, word32 totalSz) +{ + const byte* ptr = input + *inOutIdx; + (void)ssl; + + *inOutIdx += HANDSHAKE_HEADER_SZ; + if (*inOutIdx > totalSz) + return BUFFER_E; + + *type = ptr[0]; + c24to32(&ptr[1], size); + + return 0; +} + +/* Add record layer header to message. + * + * output The buffer to write the record layer header into. + * length The length of the record data. + * type The type of record message. + * ssl The SSL/TLS object. + */ +static void AddTls13RecordHeader(byte* output, word32 length, byte type, + WOLFSSL* ssl) +{ + RecordLayerHeader* rl; + + rl = (RecordLayerHeader*)output; + rl->type = type; + rl->pvMajor = ssl->version.major; +#ifdef WOLFSSL_TLS13_DRAFT_18 + rl->pvMinor = TLSv1_MINOR; +#else + /* NOTE: May be TLSv1_MINOR when sending first ClientHello. */ + rl->pvMinor = TLSv1_2_MINOR; +#endif + c16toa((word16)length, rl->length); +} + +/* Add handshake header to message. + * + * output The buffer to write the handshake header into. + * length The length of the handshake data. + * fragOffset The offset of the fragment data. (DTLS) + * fragLength The length of the fragment data. (DTLS) + * type The type of handshake message. + * ssl The SSL/TLS object. (DTLS) + */ +static void AddTls13HandShakeHeader(byte* output, word32 length, + word32 fragOffset, word32 fragLength, + byte type, WOLFSSL* ssl) +{ + HandShakeHeader* hs; + (void)fragOffset; + (void)fragLength; + (void)ssl; + + /* handshake header */ + hs = (HandShakeHeader*)output; + hs->type = type; + c32to24(length, hs->length); +} + + +/* Add both record layer and handshake header to message. + * + * output The buffer to write the headers into. + * length The length of the handshake data. + * type The type of record layer message. + * ssl The SSL/TLS object. (DTLS) + */ +static void AddTls13Headers(byte* output, word32 length, byte type, + WOLFSSL* ssl) +{ + word32 lengthAdj = HANDSHAKE_HEADER_SZ; + word32 outputAdj = RECORD_HEADER_SZ; + + AddTls13RecordHeader(output, length + lengthAdj, handshake, ssl); + AddTls13HandShakeHeader(output + outputAdj, length, 0, length, type, ssl); +} + + +#ifndef NO_CERTS +/* Add both record layer and fragment handshake header to message. + * + * output The buffer to write the headers into. + * fragOffset The offset of the fragment data. (DTLS) + * fragLength The length of the fragment data. (DTLS) + * length The length of the handshake data. + * type The type of record layer message. + * ssl The SSL/TLS object. (DTLS) + */ +static void AddTls13FragHeaders(byte* output, word32 fragSz, word32 fragOffset, + word32 length, byte type, WOLFSSL* ssl) +{ + word32 lengthAdj = HANDSHAKE_HEADER_SZ; + word32 outputAdj = RECORD_HEADER_SZ; + (void)fragSz; + + AddTls13RecordHeader(output, fragSz + lengthAdj, handshake, ssl); + AddTls13HandShakeHeader(output + outputAdj, length, fragOffset, fragSz, + type, ssl); +} +#endif /* NO_CERTS */ + +/* Write the sequence number into the buffer. + * No DTLS v1.3 support. + * + * ssl The SSL/TLS object. + * verifyOrder Which set of sequence numbers to use. + * out The buffer to write into. + */ +static WC_INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out) +{ + word32 seq[2] = {0, 0}; + + if (verifyOrder) { + seq[0] = ssl->keys.peer_sequence_number_hi; + seq[1] = ssl->keys.peer_sequence_number_lo++; + /* handle rollover */ + if (seq[1] > ssl->keys.peer_sequence_number_lo) + ssl->keys.peer_sequence_number_hi++; + } + else { + seq[0] = ssl->keys.sequence_number_hi; + seq[1] = ssl->keys.sequence_number_lo++; + /* handle rollover */ + if (seq[1] > ssl->keys.sequence_number_lo) + ssl->keys.sequence_number_hi++; + } + + c32toa(seq[0], out); + c32toa(seq[1], out + OPAQUE32_LEN); +} + +/* Build the nonce for TLS v1.3 encryption and decryption. + * + * ssl The SSL/TLS object. + * nonce The nonce data to use when encrypting or decrypting. + * iv The derived IV. + * order The side on which the message is to be or was sent. + */ +static WC_INLINE void BuildTls13Nonce(WOLFSSL* ssl, byte* nonce, const byte* iv, + int order) +{ + int i; + + /* The nonce is the IV with the sequence XORed into the last bytes. */ + WriteSEQ(ssl, order, nonce + AEAD_NONCE_SZ - SEQ_SZ); + for (i = 0; i < AEAD_NONCE_SZ - SEQ_SZ; i++) + nonce[i] = iv[i]; + for (; i < AEAD_NONCE_SZ; i++) + nonce[i] ^= iv[i]; +} + +#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) +/* Encrypt with ChaCha20 and create authenication tag with Poly1305. + * + * ssl The SSL/TLS object. + * output The buffer to write encrypted data and authentication tag into. + * May be the same pointer as input. + * input The data to encrypt. + * sz The number of bytes to encrypt. + * nonce The nonce to use with ChaCha20. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * tag The authentication tag buffer. + * returns 0 on success, otherwise failure. + */ +static int ChaCha20Poly1305_Encrypt(WOLFSSL* ssl, byte* output, + const byte* input, word16 sz, byte* nonce, + const byte* aad, word16 aadSz, byte* tag) +{ + int ret = 0; + byte poly[CHACHA20_256_KEY_SIZE]; + + /* Poly1305 key is 256 bits of zero encrypted with ChaCha20. */ + XMEMSET(poly, 0, sizeof(poly)); + + /* Set the nonce for ChaCha and get Poly1305 key. */ + ret = wc_Chacha_SetIV(ssl->encrypt.chacha, nonce, 0); + if (ret != 0) + return ret; + /* Create Poly1305 key using ChaCha20 keystream. */ + ret = wc_Chacha_Process(ssl->encrypt.chacha, poly, poly, sizeof(poly)); + if (ret != 0) + return ret; + ret = wc_Chacha_SetIV(ssl->encrypt.chacha, nonce, 1); + if (ret != 0) + return ret; + /* Encrypt the plain text. */ + ret = wc_Chacha_Process(ssl->encrypt.chacha, output, input, sz); + if (ret != 0) { + ForceZero(poly, sizeof(poly)); + return ret; + } + + /* Set key for Poly1305. */ + ret = wc_Poly1305SetKey(ssl->auth.poly1305, poly, sizeof(poly)); + ForceZero(poly, sizeof(poly)); /* done with poly1305 key, clear it */ + if (ret != 0) + return ret; + /* Add authentication code of encrypted data to end. */ + ret = wc_Poly1305_MAC(ssl->auth.poly1305, (byte*)aad, aadSz, output, sz, + tag, POLY1305_AUTH_SZ); + + return ret; +} +#endif + +#ifdef HAVE_NULL_CIPHER +/* Create authenication tag and copy data over input. + * + * ssl The SSL/TLS object. + * output The buffer to copy data into. + * May be the same pointer as input. + * input The data. + * sz The number of bytes of data. + * nonce The nonce to use with authentication. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * tag The authentication tag buffer. + * returns 0 on success, otherwise failure. + */ +static int Tls13IntegrityOnly_Encrypt(WOLFSSL* ssl, byte* output, + const byte* input, word16 sz, + const byte* nonce, + const byte* aad, word16 aadSz, byte* tag) +{ + int ret; + + /* HMAC: nonce | aad | input */ + ret = wc_HmacUpdate(ssl->encrypt.hmac, nonce, HMAC_NONCE_SZ); + if (ret == 0) + ret = wc_HmacUpdate(ssl->encrypt.hmac, aad, aadSz); + if (ret == 0) + ret = wc_HmacUpdate(ssl->encrypt.hmac, input, sz); + if (ret == 0) + ret = wc_HmacFinal(ssl->encrypt.hmac, tag); + /* Copy the input to output if not the same buffer */ + if (ret == 0 && output != input) + XMEMCPY(output, input, sz); + + return ret; +} +#endif + +/* Encrypt data for TLS v1.3. + * + * ssl The SSL/TLS object. + * output The buffer to write encrypted data and authentication tag into. + * May be the same pointer as input. + * input The record header and data to encrypt. + * sz The number of bytes to encrypt. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * asyncOkay If non-zero can return WC_PENDING_E, otherwise blocks on crypto + * returns 0 on success, otherwise failure. + */ +static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, + word16 sz, const byte* aad, word16 aadSz, int asyncOkay) +{ + int ret = 0; + word16 dataSz = sz - ssl->specs.aead_mac_size; + word16 macSz = ssl->specs.aead_mac_size; + word32 nonceSz = 0; +#ifdef WOLFSSL_ASYNC_CRYPT + WC_ASYNC_DEV* asyncDev = NULL; + word32 event_flags = WC_ASYNC_FLAG_CALL_AGAIN; +#endif + + WOLFSSL_ENTER("EncryptTls13"); + + (void)output; + (void)input; + (void)sz; + (void)dataSz; + (void)macSz; + (void)asyncOkay; + (void)nonceSz; + +#ifdef WOLFSSL_ASYNC_CRYPT + if (ssl->error == WC_PENDING_E) { + ssl->error = 0; /* clear async */ + } +#endif + + switch (ssl->encrypt.state) { + case CIPHER_STATE_BEGIN: + { + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Data to encrypt"); + WOLFSSL_BUFFER(input, dataSz); +#if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) && \ + !defined(WOLFSSL_TLS13_DRAFT_23) + WOLFSSL_MSG("Additional Authentication Data"); + WOLFSSL_BUFFER(aad, aadSz); +#endif + #endif + + #ifdef CIPHER_NONCE + if (ssl->encrypt.nonce == NULL) + ssl->encrypt.nonce = (byte*)XMALLOC(AEAD_NONCE_SZ, + ssl->heap, DYNAMIC_TYPE_AES_BUFFER); + if (ssl->encrypt.nonce == NULL) + return MEMORY_E; + + BuildTls13Nonce(ssl, ssl->encrypt.nonce, ssl->keys.aead_enc_imp_IV, + CUR_ORDER); + #endif + + /* Advance state and proceed */ + ssl->encrypt.state = CIPHER_STATE_DO; + } + FALL_THROUGH; + + case CIPHER_STATE_DO: + { + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_AESGCM + case wolfssl_aes_gcm: + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + asyncDev = &ssl->encrypt.aes->asyncDev; + ret = wolfSSL_AsyncInit(ssl, asyncDev, event_flags); + if (ret != 0) + break; + #endif + + nonceSz = AESGCM_NONCE_SZ; + #if ((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) + ret = wc_AesGcmEncrypt(ssl->encrypt.aes, output, input, + dataSz, ssl->encrypt.nonce, nonceSz, + output + dataSz, macSz, aad, aadSz); + #else + ret = wc_AesGcmSetExtIV(ssl->encrypt.aes, + ssl->encrypt.nonce, nonceSz); + if (ret == 0) { + ret = wc_AesGcmEncrypt_ex(ssl->encrypt.aes, output, + input, dataSz, ssl->encrypt.nonce, nonceSz, + output + dataSz, macSz, aad, aadSz); + } + #endif + break; + #endif + + #ifdef HAVE_AESCCM + case wolfssl_aes_ccm: + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + asyncDev = &ssl->encrypt.aes->asyncDev; + ret = wolfSSL_AsyncInit(ssl, asyncDev, event_flags); + if (ret != 0) + break; + #endif + + nonceSz = AESCCM_NONCE_SZ; + #if ((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) + ret = wc_AesCcmEncrypt(ssl->encrypt.aes, output, input, + dataSz, ssl->encrypt.nonce, nonceSz, + output + dataSz, macSz, aad, aadSz); + #else + ret = wc_AesCcmSetNonce(ssl->encrypt.aes, + ssl->encrypt.nonce, nonceSz); + if (ret == 0) { + ret = wc_AesCcmEncrypt_ex(ssl->encrypt.aes, output, + input, dataSz, ssl->encrypt.nonce, nonceSz, + output + dataSz, macSz, aad, aadSz); + } + #endif + break; + #endif + + #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + case wolfssl_chacha: + ret = ChaCha20Poly1305_Encrypt(ssl, output, input, dataSz, + ssl->encrypt.nonce, aad, aadSz, output + dataSz); + break; + #endif + + #ifdef HAVE_NULL_CIPHER + case wolfssl_cipher_null: + ret = Tls13IntegrityOnly_Encrypt(ssl, output, input, dataSz, + ssl->encrypt.nonce, aad, aadSz, output + dataSz); + break; + #endif + + default: + WOLFSSL_MSG("wolfSSL Encrypt programming error"); + return ENCRYPT_ERROR; + } + + /* Advance state */ + ssl->encrypt.state = CIPHER_STATE_END; + + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + /* if async is not okay, then block */ + if (!asyncOkay) { + ret = wc_AsyncWait(ret, asyncDev, event_flags); + } + else { + /* If pending, then leave and return will resume below */ + return wolfSSL_AsyncPush(ssl, asyncDev); + } + } + #endif + } + FALL_THROUGH; + + case CIPHER_STATE_END: + { + #ifdef WOLFSSL_DEBUG_TLS + #ifdef CIPHER_NONCE + WOLFSSL_MSG("Nonce"); + WOLFSSL_BUFFER(ssl->encrypt.nonce, ssl->specs.iv_size); + #endif + WOLFSSL_MSG("Encrypted data"); + WOLFSSL_BUFFER(output, dataSz); + WOLFSSL_MSG("Authentication Tag"); + WOLFSSL_BUFFER(output + dataSz, macSz); + #endif + + #ifdef CIPHER_NONCE + ForceZero(ssl->encrypt.nonce, AEAD_NONCE_SZ); + #endif + + break; + } + } + + /* Reset state */ + ssl->encrypt.state = CIPHER_STATE_BEGIN; + + return ret; +} + +#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) +/* Decrypt with ChaCha20 and check authenication tag with Poly1305. + * + * ssl The SSL/TLS object. + * output The buffer to write decrypted data into. + * May be the same pointer as input. + * input The data to decrypt. + * sz The number of bytes to decrypt. + * nonce The nonce to use with ChaCha20. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * tagIn The authentication tag data from packet. + * returns 0 on success, otherwise failure. + */ +static int ChaCha20Poly1305_Decrypt(WOLFSSL* ssl, byte* output, + const byte* input, word16 sz, byte* nonce, + const byte* aad, word16 aadSz, + const byte* tagIn) +{ + int ret; + byte tag[POLY1305_AUTH_SZ]; + byte poly[CHACHA20_256_KEY_SIZE]; /* generated key for mac */ + + /* Poly1305 key is 256 bits of zero encrypted with ChaCha20. */ + XMEMSET(poly, 0, sizeof(poly)); + + /* Set nonce and get Poly1305 key. */ + ret = wc_Chacha_SetIV(ssl->decrypt.chacha, nonce, 0); + if (ret != 0) + return ret; + /* Use ChaCha20 keystream to get Poly1305 key for tag. */ + ret = wc_Chacha_Process(ssl->decrypt.chacha, poly, poly, sizeof(poly)); + if (ret != 0) + return ret; + ret = wc_Chacha_SetIV(ssl->decrypt.chacha, nonce, 1); + if (ret != 0) + return ret; + + /* Set key for Poly1305. */ + ret = wc_Poly1305SetKey(ssl->auth.poly1305, poly, sizeof(poly)); + ForceZero(poly, sizeof(poly)); /* done with poly1305 key, clear it */ + if (ret != 0) + return ret; + /* Generate authentication tag for encrypted data. */ + if ((ret = wc_Poly1305_MAC(ssl->auth.poly1305, (byte*)aad, aadSz, + (byte*)input, sz, tag, sizeof(tag))) != 0) { + return ret; + } + + /* Check tag sent along with packet. */ + if (ConstantCompare(tagIn, tag, POLY1305_AUTH_SZ) != 0) { + WOLFSSL_MSG("MAC did not match"); + return VERIFY_MAC_ERROR; + } + + /* If the tag was good decrypt message. */ + ret = wc_Chacha_Process(ssl->decrypt.chacha, output, input, sz); + + return ret; +} +#endif + +#ifdef HAVE_NULL_CIPHER +/* Check HMAC tag and copy over input. + * + * ssl The SSL/TLS object. + * output The buffer to copy data into. + * May be the same pointer as input. + * input The data. + * sz The number of bytes of data. + * nonce The nonce to use with authentication. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * tagIn The authentication tag data from packet. + * returns 0 on success, otherwise failure. + */ +static int Tls13IntegrityOnly_Decrypt(WOLFSSL* ssl, byte* output, + const byte* input, word16 sz, + const byte* nonce, + const byte* aad, word16 aadSz, + const byte* tagIn) +{ + int ret; + byte hmac[WC_MAX_DIGEST_SIZE]; + + /* HMAC: nonce | aad | input */ + ret = wc_HmacUpdate(ssl->decrypt.hmac, nonce, HMAC_NONCE_SZ); + if (ret == 0) + ret = wc_HmacUpdate(ssl->decrypt.hmac, aad, aadSz); + if (ret == 0) + ret = wc_HmacUpdate(ssl->decrypt.hmac, input, sz); + if (ret == 0) + ret = wc_HmacFinal(ssl->decrypt.hmac, hmac); + /* Check authentication tag matches */ + if (ret == 0 && ConstantCompare(tagIn, hmac, ssl->specs.hash_size) != 0) + ret = DECRYPT_ERROR; + /* Copy the input to output if not the same buffer */ + if (ret == 0 && output != input) + XMEMCPY(output, input, sz); + + return ret; +} +#endif + +/* Decrypt data for TLS v1.3. + * + * ssl The SSL/TLS object. + * output The buffer to write decrypted data into. + * May be the same pointer as input. + * input The data to decrypt and authentication tag. + * sz The length of the encrypted data plus authentication tag. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * returns 0 on success, otherwise failure. + */ +int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz, + const byte* aad, word16 aadSz) +{ + int ret = 0; + word16 dataSz = sz - ssl->specs.aead_mac_size; + word16 macSz = ssl->specs.aead_mac_size; + word32 nonceSz = 0; + + WOLFSSL_ENTER("DecryptTls13"); + +#ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->decrypt.state); + if (ret != WC_NOT_PENDING_E) { + /* check for still pending */ + if (ret == WC_PENDING_E) + return ret; + + ssl->error = 0; /* clear async */ + + /* let failures through so CIPHER_STATE_END logic is run */ + } + else +#endif + { + /* Reset state */ + ret = 0; + ssl->decrypt.state = CIPHER_STATE_BEGIN; + } + + (void)output; + (void)input; + (void)sz; + (void)dataSz; + (void)macSz; + (void)nonceSz; + + switch (ssl->decrypt.state) { + case CIPHER_STATE_BEGIN: + { + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Data to decrypt"); + WOLFSSL_BUFFER(input, dataSz); +#if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) && \ + !defined(WOLFSSL_TLS13_DRAFT_23) + WOLFSSL_MSG("Additional Authentication Data"); + WOLFSSL_BUFFER(aad, aadSz); +#endif + WOLFSSL_MSG("Authentication tag"); + WOLFSSL_BUFFER(input + dataSz, macSz); + #endif + + #ifdef CIPHER_NONCE + if (ssl->decrypt.nonce == NULL) + ssl->decrypt.nonce = (byte*)XMALLOC(AEAD_NONCE_SZ, + ssl->heap, DYNAMIC_TYPE_AES_BUFFER); + if (ssl->decrypt.nonce == NULL) + return MEMORY_E; + + BuildTls13Nonce(ssl, ssl->decrypt.nonce, ssl->keys.aead_dec_imp_IV, + PEER_ORDER); + #endif + + /* Advance state and proceed */ + ssl->decrypt.state = CIPHER_STATE_DO; + } + FALL_THROUGH; + + case CIPHER_STATE_DO: + { + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_AESGCM + case wolfssl_aes_gcm: + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &ssl->decrypt.aes->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + break; + #endif + + nonceSz = AESGCM_NONCE_SZ; + ret = wc_AesGcmDecrypt(ssl->decrypt.aes, output, input, + dataSz, ssl->decrypt.nonce, nonceSz, + input + dataSz, macSz, aad, aadSz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, + &ssl->decrypt.aes->asyncDev); + } + #endif + break; + #endif + + #ifdef HAVE_AESCCM + case wolfssl_aes_ccm: + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &ssl->decrypt.aes->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + break; + #endif + + nonceSz = AESCCM_NONCE_SZ; + ret = wc_AesCcmDecrypt(ssl->decrypt.aes, output, input, + dataSz, ssl->decrypt.nonce, nonceSz, + input + dataSz, macSz, aad, aadSz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, + &ssl->decrypt.aes->asyncDev); + } + #endif + break; + #endif + + #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + case wolfssl_chacha: + ret = ChaCha20Poly1305_Decrypt(ssl, output, input, dataSz, + ssl->decrypt.nonce, aad, aadSz, input + dataSz); + break; + #endif + + #ifdef HAVE_NULL_CIPHER + case wolfssl_cipher_null: + ret = Tls13IntegrityOnly_Decrypt(ssl, output, input, dataSz, + ssl->decrypt.nonce, aad, aadSz, input + dataSz); + break; + #endif + default: + WOLFSSL_MSG("wolfSSL Decrypt programming error"); + return DECRYPT_ERROR; + } + + /* Advance state */ + ssl->decrypt.state = CIPHER_STATE_END; + + #ifdef WOLFSSL_ASYNC_CRYPT + /* If pending, leave now */ + if (ret == WC_PENDING_E) { + return ret; + } + #endif + } + FALL_THROUGH; + + case CIPHER_STATE_END: + { + #ifdef WOLFSSL_DEBUG_TLS + #ifdef CIPHER_NONCE + WOLFSSL_MSG("Nonce"); + WOLFSSL_BUFFER(ssl->decrypt.nonce, ssl->specs.iv_size); + #endif + WOLFSSL_MSG("Decrypted data"); + WOLFSSL_BUFFER(output, dataSz); + #endif + + #ifdef CIPHER_NONCE + ForceZero(ssl->decrypt.nonce, AEAD_NONCE_SZ); + #endif + + break; + } + } + +#ifndef WOLFSSL_EARLY_DATA + if (ret < 0) { + SendAlert(ssl, alert_fatal, bad_record_mac); + ret = VERIFY_MAC_ERROR; + } +#endif + + return ret; +} + +/* Persistable BuildTls13Message arguments */ +typedef struct BuildMsg13Args { + word32 sz; + word32 idx; + word32 headerSz; + word16 size; +} BuildMsg13Args; + +static void FreeBuildMsg13Args(WOLFSSL* ssl, void* pArgs) +{ + BuildMsg13Args* args = (BuildMsg13Args*)pArgs; + + (void)ssl; + (void)args; + + /* no allocations in BuildTls13Message */ +} + +/* Build SSL Message, encrypted. + * TLS v1.3 encryption is AEAD only. + * + * ssl The SSL/TLS object. + * output The buffer to write record message to. + * outSz Size of the buffer being written into. + * input The record data to encrypt (excluding record header). + * inSz The size of the record data. + * type The recorder header content type. + * hashOutput Whether to hash the unencrypted record data. + * sizeOnly Only want the size of the record message. + * asyncOkay If non-zero can return WC_PENDING_E, otherwise blocks on crypto + * returns the size of the encrypted record message or negative value on error. + */ +int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, + int inSz, int type, int hashOutput, int sizeOnly, int asyncOkay) +{ + int ret = 0; + BuildMsg13Args* args; + BuildMsg13Args lcl_args; +#ifdef WOLFSSL_ASYNC_CRYPT + args = (BuildMsg13Args*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); +#endif + + WOLFSSL_ENTER("BuildTls13Message"); + + ret = WC_NOT_PENDING_E; +#ifdef WOLFSSL_ASYNC_CRYPT + if (asyncOkay) { + ret = wolfSSL_AsyncPop(ssl, &ssl->options.buildMsgState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_buildmsg; + } + } + else +#endif + { + args = &lcl_args; + } + + /* Reset state */ + if (ret == WC_NOT_PENDING_E) { + ret = 0; + ssl->options.buildMsgState = BUILD_MSG_BEGIN; + XMEMSET(args, 0, sizeof(BuildMsg13Args)); + + args->sz = RECORD_HEADER_SZ + inSz; + args->idx = RECORD_HEADER_SZ; + args->headerSz = RECORD_HEADER_SZ; + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeBuildMsg13Args; + #endif + } + + switch (ssl->options.buildMsgState) { + case BUILD_MSG_BEGIN: + { + /* catch mistaken sizeOnly parameter */ + if (sizeOnly) { + if (output || input) { + WOLFSSL_MSG("BuildTls13Message with sizeOnly " + "doesn't need input or output"); + return BAD_FUNC_ARG; + } + } + else if (output == NULL || input == NULL) { + return BAD_FUNC_ARG; + } + + /* Record layer content type at the end of record data. */ + args->sz++; + /* Authentication data at the end. */ + args->sz += ssl->specs.aead_mac_size; + + if (sizeOnly) + return args->sz; + + if (args->sz > (word32)outSz) { + WOLFSSL_MSG("Oops, want to write past output buffer size"); + return BUFFER_E; + } + + /* Record data length. */ + args->size = (word16)(args->sz - args->headerSz); + /* Write/update the record header with the new size. + * Always have the content type as application data for encrypted + * messages in TLS v1.3. + */ + AddTls13RecordHeader(output, args->size, application_data, ssl); + + /* TLS v1.3 can do in place encryption. */ + if (input != output + args->idx) + XMEMCPY(output + args->idx, input, inSz); + args->idx += inSz; + + ssl->options.buildMsgState = BUILD_MSG_HASH; + } + FALL_THROUGH; + + case BUILD_MSG_HASH: + { + if (hashOutput) { + ret = HashOutput(ssl, output, args->headerSz + inSz, 0); + if (ret != 0) + goto exit_buildmsg; + } + + /* The real record content type goes at the end of the data. */ + output[args->idx++] = (byte)type; + + ssl->options.buildMsgState = BUILD_MSG_ENCRYPT; + } + FALL_THROUGH; + + case BUILD_MSG_ENCRYPT: + { + #ifdef ATOMIC_USER + if (ssl->ctx->MacEncryptCb) { + /* User Record Layer Callback handling */ + byte* mac = output + args->idx; + output += args->headerSz; + + ret = ssl->ctx->MacEncryptCb(ssl, mac, output, inSz, type, 0, + output, output, args->size, ssl->MacEncryptCtx); + } + else + #endif + { +#if defined(WOLFSSL_TLS13_DRAFT_18) || defined(WOLFSSL_TLS13_DRAFT_22) || \ + defined(WOLFSSL_TLS13_DRAFT_23) + output += args->headerSz; + ret = EncryptTls13(ssl, output, output, args->size, NULL, 0, + asyncOkay); +#else + const byte* aad = output; + output += args->headerSz; + ret = EncryptTls13(ssl, output, output, args->size, aad, + RECORD_HEADER_SZ, asyncOkay); +#endif + } + break; + } + } + +exit_buildmsg: + + WOLFSSL_LEAVE("BuildTls13Message", ret); + +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + return ret; + } +#endif + + /* make sure build message state is reset */ + ssl->options.buildMsgState = BUILD_MSG_BEGIN; + + /* return sz on success */ + if (ret == 0) + ret = args->sz; + + /* Final cleanup */ + FreeBuildMsg13Args(ssl, args); +#ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = NULL; +#endif + + return ret; +} + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +/* Find the cipher suite in the suites set in the SSL. + * + * ssl SSL/TLS object. + * suite Cipher suite to look for. + * returns 1 when suite is found in SSL/TLS object's list and 0 otherwise. + */ +static int FindSuiteSSL(WOLFSSL* ssl, byte* suite) +{ + word16 i; + + for (i = 0; i < ssl->suites->suiteSz; i += 2) { + if (ssl->suites->suites[i+0] == suite[0] && + ssl->suites->suites[i+1] == suite[1]) { + return 1; + } + } + + return 0; +} +#endif + +#ifndef WOLFSSL_TLS13_DRAFT_18 +#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER) +/* Create Cookie extension using the hash of the first ClientHello. + * + * ssl SSL/TLS object. + * hash The hash data. + * hashSz The size of the hash data in bytes. + * returns 0 on success, otherwise failure. + */ +static int CreateCookie(WOLFSSL* ssl, byte* hash, byte hashSz) +{ + int ret; + byte mac[WC_MAX_DIGEST_SIZE] = {0}; + Hmac cookieHmac; + byte cookieType = 0; + byte macSz = 0; + +#if !defined(NO_SHA) && defined(NO_SHA256) + cookieType = SHA; + macSz = WC_SHA_DIGEST_SIZE; +#endif /* NO_SHA */ +#ifndef NO_SHA256 + cookieType = WC_SHA256; + macSz = WC_SHA256_DIGEST_SIZE; +#endif /* NO_SHA256 */ + XMEMSET(&cookieHmac, 0, sizeof(Hmac)); + + ret = wc_HmacSetKey(&cookieHmac, cookieType, + ssl->buffers.tls13CookieSecret.buffer, + ssl->buffers.tls13CookieSecret.length); + if (ret != 0) + return ret; + if ((ret = wc_HmacUpdate(&cookieHmac, hash, hashSz)) != 0) + return ret; + if ((ret = wc_HmacFinal(&cookieHmac, mac)) != 0) + return ret; + + /* The cookie data is the hash and the integrity check. */ + return TLSX_Cookie_Use(ssl, hash, hashSz, mac, macSz, 1); +} +#endif + +/* Restart the handshake hash with a hash of the previous messages. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int RestartHandshakeHash(WOLFSSL* ssl) +{ + int ret; + Hashes hashes; + byte header[HANDSHAKE_HEADER_SZ] = {0}; + byte* hash = NULL; + byte hashSz = 0; + + ret = BuildCertHashes(ssl, &hashes); + if (ret != 0) + return ret; + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + hash = hashes.sha256; + break; + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + hash = hashes.sha384; + break; + #endif + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + hash = hashes.sha512; + break; + #endif + } + hashSz = ssl->specs.hash_size; + + /* check hash */ + if (hash == NULL && hashSz > 0) + return BAD_FUNC_ARG; + + AddTls13HandShakeHeader(header, hashSz, 0, 0, message_hash, ssl); + + WOLFSSL_MSG("Restart Hash"); + WOLFSSL_BUFFER(hash, hashSz); + +#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER) + if (ssl->options.sendCookie) { + byte cookie[OPAQUE8_LEN + WC_MAX_DIGEST_SIZE + OPAQUE16_LEN * 2]; + TLSX* ext; + word32 idx = 0; + + /* Cookie Data = Hash Len | Hash | CS | KeyShare Group */ + cookie[idx++] = hashSz; + if (hash) + XMEMCPY(cookie + idx, hash, hashSz); + idx += hashSz; + cookie[idx++] = ssl->options.cipherSuite0; + cookie[idx++] = ssl->options.cipherSuite; + if ((ext = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE)) != NULL) { + KeyShareEntry* kse = (KeyShareEntry*)ext->data; + c16toa(kse->group, cookie + idx); + idx += OPAQUE16_LEN; + } + return CreateCookie(ssl, cookie, idx); + } +#endif + + ret = InitHandshakeHashes(ssl); + if (ret != 0) + return ret; + ret = HashOutputRaw(ssl, header, sizeof(header)); + if (ret != 0) + return ret; + return HashOutputRaw(ssl, hash, hashSz); +} + +/* The value in the random field of a ServerHello to indicate + * HelloRetryRequest. + */ +static byte helloRetryRequestRandom[] = { + 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, + 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, + 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, + 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C +}; +#endif /* WOLFSSL_TLS13_DRAFT_18 */ + +#ifndef NO_WOLFSSL_CLIENT +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +/* Setup pre-shared key based on the details in the extension data. + * + * 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 SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk) +{ + int ret; + byte suite[2]; + + if (psk == NULL) + return BAD_FUNC_ARG; + + suite[0] = psk->cipherSuite0; + suite[1] = psk->cipherSuite; + if (!FindSuiteSSL(ssl, suite)) + return PSK_KEY_ERROR; + + 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 = no_early_data; + #endif + /* Resumption PSK is master secret. */ + ssl->arrays->psk_keySz = ssl->specs.hash_size; +#ifdef WOLFSSL_TLS13_DRAFT_18 + XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, + ssl->arrays->psk_keySz); +#else + if ((ret = DeriveResumptionPSK(ssl, ssl->session.ticketNonce.data, + ssl->session.ticketNonce.len, ssl->arrays->psk_key)) != 0) { + return ret; + } +#endif + } +#endif +#ifndef NO_PSK + if (!psk->resumption) { + #ifndef WOLFSSL_PSK_ONE_ID + const char* cipherName = NULL; + byte cipherSuite0 = TLS13_BYTE, cipherSuite = WOLFSSL_DEF_PSK_CIPHER; + + /* Get the pre-shared key. */ + if (ssl->options.client_psk_tls13_cb != NULL) { + ssl->arrays->psk_keySz = ssl->options.client_psk_tls13_cb(ssl, + (char *)psk->identity, ssl->arrays->client_identity, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN, + &cipherName); + if (GetCipherSuiteFromName(cipherName, &cipherSuite0, + &cipherSuite) != 0) { + return PSK_KEY_ERROR; + } + } + else { + 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; + } + + if (psk->cipherSuite0 != cipherSuite0 || + psk->cipherSuite != cipherSuite) { + return PSK_KEY_ERROR; + } + #else + /* PSK information loaded during setting of default TLS extensions. */ + #endif + } +#endif + + if (ssl->options.noPskDheKe) + ssl->arrays->preMasterSz = 0; + + /* 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. + * + * ssl The SSL/TLS object. + * output The buffer containing the ClientHello. + * idx The index at the end of the completed ClientHello. + * returns 0 on success and otherwise failure. + */ +static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) +{ + int ret; + TLSX* ext; + PreSharedKey* current; + byte binderKey[WC_MAX_DIGEST_SIZE]; + word16 len; + + WOLFSSL_ENTER("WritePSKBinders"); + + ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (ext == NULL) + return SANITY_MSG_E; + + /* Get the size of the binders to determine where to write binders. */ + ret = TLSX_PreSharedKey_GetSizeBinders((PreSharedKey*)ext->data, + client_hello, &len); + if (ret < 0) + return ret; + idx -= len; + + /* Hash truncated ClientHello - up to binders. */ + ret = HashOutput(ssl, output, idx, 0); + if (ret != 0) + return ret; + + current = (PreSharedKey*)ext->data; + /* Calculate the binder for each identity based on previous handshake data. + */ + while (current != NULL) { + if ((ret = SetupPskKey(ssl, current)) != 0) + return ret; + + #ifdef HAVE_SESSION_TICKET + if (current->resumption) + ret = DeriveBinderKeyResume(ssl, binderKey); + #endif + #ifndef NO_PSK + if (!current->resumption) + ret = DeriveBinderKey(ssl, binderKey); + #endif + if (ret != 0) + return ret; + + /* Derive the Finished message secret. */ + ret = DeriveFinishedSecret(ssl, binderKey, + ssl->keys.client_write_MAC_secret); + if (ret != 0) + return ret; + + /* Build the HMAC of the handshake message data = binder. */ + ret = BuildTls13HandshakeHmac(ssl, ssl->keys.client_write_MAC_secret, + current->binder, ¤t->binderLen); + if (ret != 0) + return ret; + + current = current->next; + } + + /* Data entered into extension, now write to message. */ + ret = TLSX_PreSharedKey_WriteBinders((PreSharedKey*)ext->data, output + idx, + client_hello, &len); + if (ret < 0) + return ret; + + /* Hash binders to complete the hash of the ClientHello. */ + ret = HashOutputRaw(ssl, output + idx, len); + if (ret < 0) + return ret; + + #ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + 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 + + WOLFSSL_LEAVE("WritePSKBinders", ret); + + return ret; +} +#endif + +/* handle generation of TLS 1.3 client_hello (1) */ +/* Send a ClientHello message to the server. + * Include the information required to start a handshake with servers using + * protocol versions less than TLS v1.3. + * Only a client will send this message. + * + * ssl The SSL/TLS object. + * returns 0 on success and otherwise failure. + */ +int SendTls13ClientHello(WOLFSSL* ssl) +{ + byte* output; + word16 length; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + int ret; + + WOLFSSL_START(WC_FUNC_CLIENT_HELLO_SEND); + WOLFSSL_ENTER("SendTls13ClientHello"); + +#ifdef HAVE_SESSION_TICKET + if (ssl->options.resuming && + (ssl->session.version.major != ssl->version.major || + ssl->session.version.minor != ssl->version.minor)) { + #ifndef WOLFSSL_NO_TLS12 + if (ssl->session.version.major == ssl->version.major && + ssl->session.version.minor < ssl->version.minor) { + /* Cannot resume with a different protocol version. */ + ssl->options.resuming = 0; + ssl->version.major = ssl->session.version.major; + ssl->version.minor = ssl->session.version.minor; + return SendClientHello(ssl); + } + else + #endif + return VERSION_ERROR; + } +#endif + + if (ssl->suites == NULL) { + WOLFSSL_MSG("Bad suites pointer in SendTls13ClientHello"); + return SUITES_ERROR; + } + + /* Version | Random | Session Id | Cipher Suites | Compression */ + length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->suites->suiteSz + + SUITE_LEN + COMP_LEN + ENUM_LEN; +#ifndef WOLFSSL_TLS13_DRAFT_18 + #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + length += ID_LEN; + #else + if (ssl->session.sessionIDSz > 0) + length += ssl->session.sessionIDSz; + #endif +#endif + + /* Auto populate extensions supported unless user defined. */ + if ((ret = TLSX_PopulateExtensions(ssl, 0)) != 0) + return ret; +#ifdef WOLFSSL_EARLY_DATA + #ifndef NO_PSK + if (!ssl->options.resuming && + ssl->options.client_psk_tls13_cb == NULL && + ssl->options.client_psk_cb == NULL) + #else + if (!ssl->options.resuming) + #endif + ssl->earlyData = no_early_data; + if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) + ssl->earlyData = no_early_data; + if (ssl->earlyData == no_early_data) + TLSX_Remove(&ssl->extensions, TLSX_EARLY_DATA, ssl->heap); + if (ssl->earlyData != no_early_data && + (ret = TLSX_EarlyData_Use(ssl, 0)) < 0) { + return ret; + } +#endif + /* Include length of TLS extensions. */ + ret = TLSX_GetRequestSize(ssl, client_hello, &length); + if (ret != 0) + return ret; + + /* Total message size. */ + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + /* 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, client_hello, ssl); + + /* Protocol version - negotiation now in extension: supported_versions. */ + output[idx++] = SSLv3_MAJOR; + output[idx++] = TLSv1_2_MINOR; + /* Keep for downgrade. */ + ssl->chVersion = ssl->version; + + /* Client Random */ + if (ssl->options.connectState == CONNECT_BEGIN) { + ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN); + if (ret != 0) + return ret; + + /* Store random for possible second ClientHello. */ + XMEMCPY(ssl->arrays->clientRandom, output + idx, RAN_LEN); + } + else + XMEMCPY(output + idx, ssl->arrays->clientRandom, RAN_LEN); + idx += RAN_LEN; + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* TLS v1.3 does not use session id - 0 length. */ + output[idx++] = 0; +#else + if (ssl->session.sessionIDSz > 0) { + /* Session resumption for old versions of protocol. */ + output[idx++] = ID_LEN; + XMEMCPY(output + idx, ssl->session.sessionID, ssl->session.sessionIDSz); + idx += ID_LEN; + } + else { + #ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT + output[idx++] = ID_LEN; + XMEMCPY(output + idx, ssl->arrays->clientRandom, ID_LEN); + idx += ID_LEN; + #else + /* TLS v1.3 does not use session id - 0 length. */ + output[idx++] = 0; + #endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */ + } +#endif /* WOLFSSL_TLS13_DRAFT_18 */ + + /* Cipher suites */ + c16toa(ssl->suites->suiteSz, output + idx); + idx += OPAQUE16_LEN; + XMEMCPY(output + idx, &ssl->suites->suites, ssl->suites->suiteSz); + idx += ssl->suites->suiteSz; + + /* Compression not supported in TLS v1.3. */ + output[idx++] = COMP_LEN; + output[idx++] = NO_COMPRESSION; + + /* Write out extensions for a request. */ + length = 0; + ret = TLSX_WriteRequest(ssl, output + idx, client_hello, &length); + if (ret != 0) + return ret; + idx += length; + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* Resumption has a specific set of extensions and binder is calculated + * for each identity. + */ + if (TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY)) + ret = WritePSKBinders(ssl, output, idx); + else +#endif + ret = HashOutput(ssl, output, idx, 0); + if (ret != 0) + return ret; + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "ClientHello"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "ClientHello", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + } +#endif + + ssl->buffers.outputBuffer.length += sendSz; + +#ifdef WOLFSSL_EARLY_DATA_GROUP + if (ssl->earlyData == no_early_data) +#endif + ret = SendBuffered(ssl); + + + WOLFSSL_LEAVE("SendTls13ClientHello", ret); + WOLFSSL_END(WC_FUNC_CLIENT_HELLO_SEND); + + return ret; +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* handle rocessing of TLS 1.3 hello_retry_request (6) */ +/* Parse and handle a HelloRetryRequest message. + * Only a client will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of + * HelloRetryRequest. + * On exit, the index of byte after the HelloRetryRequest message. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13HelloRetryRequest(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 totalSz) +{ + int ret; + word32 begin = *inOutIdx; + word32 i = begin; + word16 totalExtSz; + ProtocolVersion pv; + + WOLFSSL_ENTER("DoTls13HelloRetryRequest"); + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "HelloRetryRequest"); + if (ssl->toInfoOn) AddLateName("HelloRetryRequest", &ssl->timeoutInfo); +#endif + + /* Version info and length field of extension data. */ + if (totalSz < i - begin + OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) + return BUFFER_ERROR; + + /* Protocol version. */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + i += OPAQUE16_LEN; + ret = CheckVersion(ssl, pv); + if (ret != 0) + return ret; + + /* Length of extension data. */ + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + if (totalExtSz == 0) { + WOLFSSL_MSG("HelloRetryRequest must contain extensions"); + return MISSING_HANDSHAKE_DATA; + } + + /* Extension data. */ + if (i - begin + totalExtSz > totalSz) + return BUFFER_ERROR; + if ((ret = TLSX_Parse(ssl, (byte *)(input + i), totalExtSz, + hello_retry_request, NULL)) != 0) + return ret; + /* The KeyShare extension parsing fails when not valid. */ + + /* Move index to byte after message. */ + *inOutIdx = i + totalExtSz; + + ssl->options.tls1_3 = 1; + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; + + WOLFSSL_LEAVE("DoTls13HelloRetryRequest", ret); + + return ret; +} +#endif + + +/* handle processing of TLS 1.3 server_hello (2) and hello_retry_request (6) */ +/* Handle the ServerHello message from the server. + * Only a client will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of ServerHello. + * On exit, the index of byte after the ServerHello message. + * helloSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz, byte* extMsgType) +{ + ProtocolVersion pv; + word32 i = *inOutIdx; + word32 begin = i; + int ret; +#ifndef WOLFSSL_TLS13_DRAFT_18 + byte sessIdSz; + const byte* sessId; + byte b; + int foundVersion; +#endif + word16 totalExtSz; +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + TLSX* ext; + PreSharedKey* psk = NULL; +#endif + + WOLFSSL_START(WC_FUNC_SERVER_HELLO_DO); + WOLFSSL_ENTER("DoTls13ServerHello"); + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "ServerHello"); + if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo); +#endif + + /* Protocol version length check. */ + if (OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + /* Protocol version */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + i += OPAQUE16_LEN; +#ifdef WOLFSSL_TLS13_DRAFT_18 + ret = CheckVersion(ssl, pv); + if (ret != 0) + return ret; + if (!IsAtLeastTLSv1_3(pv) && pv.major != TLS_DRAFT_MAJOR) { +#ifndef WOLFSSL_NO_TLS12 + if (ssl->options.downgrade) { + ssl->version = pv; + return DoServerHello(ssl, input, inOutIdx, helloSz); + } +#endif + + WOLFSSL_MSG("Client using higher version, fatal error"); + return VERSION_ERROR; + } +#else +#ifndef WOLFSSL_NO_TLS12 + if (pv.major == ssl->version.major && pv.minor < TLSv1_2_MINOR && + ssl->options.downgrade) { + /* Force client hello version 1.2 to work for static RSA. */ + ssl->chVersion.minor = TLSv1_2_MINOR; + ssl->version.minor = TLSv1_2_MINOR; + return DoServerHello(ssl, input, inOutIdx, helloSz); + } +#endif + if (pv.major != ssl->version.major || pv.minor != TLSv1_2_MINOR) + return VERSION_ERROR; +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* Random length check */ + if ((i - begin) + RAN_LEN > helloSz) + return BUFFER_ERROR; +#else + /* Random and session id length check */ + if ((i - begin) + RAN_LEN + ENUM_LEN > helloSz) + return BUFFER_ERROR; + + if (XMEMCMP(input + i, helloRetryRequestRandom, RAN_LEN) == 0) + *extMsgType = hello_retry_request; +#endif + + /* Server random - keep for debugging. */ + XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN); + i += RAN_LEN; + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Session id */ + sessIdSz = input[i++]; + if ((i - begin) + sessIdSz > helloSz) + return BUFFER_ERROR; + sessId = input + i; + i += sessIdSz; +#endif /* WOLFSSL_TLS13_DRAFT_18 */ + ssl->options.haveSessionId = 1; + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* Ciphersuite check */ + if ((i - begin) + OPAQUE16_LEN + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; +#else + /* Ciphersuite and compression check */ + if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; +#endif + + /* Set the cipher suite from the message. */ + ssl->options.cipherSuite0 = input[i++]; + ssl->options.cipherSuite = input[i++]; + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Compression */ + b = input[i++]; + if (b != 0) { + WOLFSSL_MSG("Must be no compression types in list"); + return INVALID_PARAMETER; + } +#endif + +#ifndef WOLFSSL_TLS13_DRAFT_18 + if ((i - begin) + OPAQUE16_LEN > helloSz) { + if (!ssl->options.downgrade) + return BUFFER_ERROR; +#ifndef WOLFSSL_NO_TLS12 + ssl->version.minor = TLSv1_2_MINOR; +#endif + ssl->options.haveEMS = 0; + } + if ((i - begin) < helloSz) +#endif + { + /* Get extension length and length check. */ + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Need to negotiate version first. */ + if ((ret = TLSX_ParseVersion(ssl, (byte*)input + i, totalExtSz, + *extMsgType, &foundVersion))) { + return ret; + } + if (!foundVersion) { + if (!ssl->options.downgrade) { + WOLFSSL_MSG("Server trying to downgrade to version less than " + "TLS v1.3"); + return VERSION_ERROR; + } + + if (pv.minor < ssl->options.minDowngrade) + return VERSION_ERROR; + ssl->version.minor = pv.minor; + } +#endif + + /* Parse and handle extensions. */ + ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, *extMsgType, + NULL); + if (ret != 0) + return ret; + + i += totalExtSz; + } + *inOutIdx = i; + + ssl->options.serverState = SERVER_HELLO_COMPLETE; + +#ifdef HAVE_SECRET_CALLBACK + if (ssl->sessionSecretCb != NULL) { + int secretSz = SECRET_LEN; + ret = ssl->sessionSecretCb(ssl, ssl->session.masterSecret, + &secretSz, ssl->sessionSecretCtx); + if (ret != 0 || secretSz != SECRET_LEN) { + return SESSION_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Version only negotiated in extensions for TLS v1.3. + * Only now do we know how to deal with session id. + */ + if (!IsAtLeastTLSv1_3(ssl->version)) { +#ifndef WOLFSSL_NO_TLS12 + ssl->arrays->sessionIDSz = sessIdSz; + + if (ssl->arrays->sessionIDSz > ID_LEN) { + WOLFSSL_MSG("Invalid session ID size"); + ssl->arrays->sessionIDSz = 0; + return BUFFER_ERROR; + } + else if (ssl->arrays->sessionIDSz) { + XMEMCPY(ssl->arrays->sessionID, sessId, ssl->arrays->sessionIDSz); + ssl->options.haveSessionId = 1; + } + + /* Force client hello version 1.2 to work for static RSA. */ + ssl->chVersion.minor = TLSv1_2_MINOR; + /* Complete TLS v1.2 processing of ServerHello. */ + ret = CompleteServerHello(ssl); +#else + WOLFSSL_MSG("Client using higher version, fatal error"); + ret = VERSION_ERROR; +#endif + + WOLFSSL_LEAVE("DoTls13ServerHello", ret); + + return ret; + } + + #ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT + if (sessIdSz == 0) + return INVALID_PARAMETER; + if (ssl->session.sessionIDSz != 0) { + if (ssl->session.sessionIDSz != sessIdSz || + XMEMCMP(ssl->session.sessionID, sessId, sessIdSz) != 0) { + return INVALID_PARAMETER; + } + } + else if (XMEMCMP(ssl->arrays->clientRandom, sessId, sessIdSz) != 0) + return INVALID_PARAMETER; + #else + if (sessIdSz != ssl->session.sessionIDSz || (sessIdSz > 0 && + XMEMCMP(ssl->session.sessionID, sessId, sessIdSz) != 0)) { + WOLFSSL_MSG("Server sent different session id"); + return INVALID_PARAMETER; + } + #endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */ +#endif + + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; +#ifdef HAVE_NULL_CIPHER + if (ssl->options.cipherSuite0 == ECC_BYTE && + (ssl->options.cipherSuite == TLS_SHA256_SHA256 || + ssl->options.cipherSuite == TLS_SHA384_SHA384)) { + ; + } + else +#endif + /* Check that the negotiated ciphersuite matches protocol version. */ + if (ssl->options.cipherSuite0 != TLS13_BYTE) { + WOLFSSL_MSG("Server sent non-TLS13 cipher suite in TLS 1.3 packet"); + return INVALID_PARAMETER; + } + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +#ifndef WOLFSSL_TLS13_DRAFT_18 + if (*extMsgType == server_hello) +#endif + { + ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (ext != NULL) + psk = (PreSharedKey*)ext->data; + while (psk != NULL && !psk->chosen) + psk = psk->next; + if (psk == NULL) { + ssl->options.resuming = 0; + ssl->arrays->psk_keySz = 0; + XMEMSET(ssl->arrays->psk_key, 0, MAX_PSK_KEY_LEN); + } + else if ((ret = SetupPskKey(ssl, psk)) != 0) + return ret; + } +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 + ssl->keys.encryptionOn = 1; +#else + if (*extMsgType == server_hello) { + ssl->keys.encryptionOn = 1; + ssl->options.serverState = SERVER_HELLO_COMPLETE; + } + else { + ssl->options.tls1_3 = 1; + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; + + ret = RestartHandshakeHash(ssl); + } +#endif + + WOLFSSL_LEAVE("DoTls13ServerHello", ret); + WOLFSSL_END(WC_FUNC_SERVER_HELLO_DO); + + return ret; +} + +/* handle processing TLS 1.3 encrypted_extensions (8) */ +/* Parse and handle an EncryptedExtensions message. + * Only a client will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of + * EncryptedExtensions. + * On exit, the index of byte after the EncryptedExtensions + * message. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13EncryptedExtensions(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 totalSz) +{ + int ret; + word32 begin = *inOutIdx; + word32 i = begin; + word16 totalExtSz; + + WOLFSSL_START(WC_FUNC_ENCRYPTED_EXTENSIONS_DO); + WOLFSSL_ENTER("DoTls13EncryptedExtensions"); + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "EncryptedExtensions"); + if (ssl->toInfoOn) AddLateName("EncryptedExtensions", &ssl->timeoutInfo); +#endif + + /* Length field of extension data. */ + if (totalSz < i - begin + OPAQUE16_LEN) + return BUFFER_ERROR; + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + + /* Extension data. */ + if (i - begin + totalExtSz > totalSz) + return BUFFER_ERROR; + if ((ret = TLSX_Parse(ssl, (byte *)(input + i), totalExtSz, + encrypted_extensions, NULL))) + return ret; + + /* Move index to byte after message. */ + *inOutIdx = i + totalExtSz; + + /* Always encrypted. */ + *inOutIdx += ssl->keys.padSz; + +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + TLSX* ext = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); + if (ext == NULL || !ext->val) + ssl->earlyData = no_early_data; + } +#endif + +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData == no_early_data) { + ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY); + if (ret != 0) + return ret; + } +#endif + + ssl->options.serverState = SERVER_ENCRYPTED_EXTENSIONS_COMPLETE; + + WOLFSSL_LEAVE("DoTls13EncryptedExtensions", ret); + WOLFSSL_END(WC_FUNC_ENCRYPTED_EXTENSIONS_DO); + + return ret; +} + +/* handle processing TLS v1.3 certificate_request (13) */ +/* Handle a TLS v1.3 CertificateRequest message. + * This message is always encrypted. + * Only a client will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of CertificateRequest. + * On exit, the index of byte after the CertificateRequest message. + * size The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 size) +{ + word16 len; + word32 begin = *inOutIdx; + int ret = 0; +#ifndef WOLFSSL_TLS13_DRAFT_18 + Suites peerSuites; +#endif +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + CertReqCtx* certReqCtx; +#endif + + WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_DO); + WOLFSSL_ENTER("DoTls13CertificateRequest"); + +#ifndef WOLFSSL_TLS13_DRAFT_18 + XMEMSET(&peerSuites, 0, sizeof(Suites)); +#endif +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "CertificateRequest"); + if (ssl->toInfoOn) AddLateName("CertificateRequest", &ssl->timeoutInfo); +#endif + + if ((*inOutIdx - begin) + OPAQUE8_LEN > size) + return BUFFER_ERROR; + + /* Length of the request context. */ + len = input[(*inOutIdx)++]; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + if (ssl->options.connectState < FINISHED_DONE && len > 0) + return BUFFER_ERROR; + +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + /* CertReqCtx has one byte at end for context value. + * Increase size to handle other implementations sending more than one byte. + * That is, allocate extra space, over one byte, to hold the context value. + */ + certReqCtx = (CertReqCtx*)XMALLOC(sizeof(CertReqCtx) + len - 1, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (certReqCtx == NULL) + return MEMORY_E; + certReqCtx->next = ssl->certReqCtx; + certReqCtx->len = len; + XMEMCPY(&certReqCtx->ctx, input + *inOutIdx, len); + ssl->certReqCtx = certReqCtx; +#endif + *inOutIdx += len; + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* Signature and hash algorithms. */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + if (PickHashSigAlgo(ssl, input + *inOutIdx, len) != 0 && + ssl->buffers.certificate && ssl->buffers.certificate->buffer && + ssl->buffers.key && ssl->buffers.key->buffer) { + return INVALID_PARAMETER; + } + *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. + */ + /* 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; + if (len == 0) + return INVALID_PARAMETER; + if ((ret = TLSX_Parse(ssl, (byte *)(input + *inOutIdx), len, + certificate_request, &peerSuites))) { + return ret; + } + *inOutIdx += len; +#endif + + if (ssl->buffers.certificate && ssl->buffers.certificate->buffer && + ((ssl->buffers.key && ssl->buffers.key->buffer) + #ifdef HAVE_PK_CALLBACKS + || wolfSSL_CTX_IsPrivatePkSet(ssl->ctx) + #endif + )) { +#ifndef WOLFSSL_TLS13_DRAFT_18 + if (PickHashSigAlgo(ssl, peerSuites.hashSigAlgo, + peerSuites.hashSigAlgoSz) != 0) { + return INVALID_PARAMETER; + } +#endif + ssl->options.sendVerify = SEND_CERT; + } + else { + ssl->options.sendVerify = SEND_BLANK_CERT; + } + + /* This message is always encrypted so add encryption padding. */ + *inOutIdx += ssl->keys.padSz; + + WOLFSSL_LEAVE("DoTls13CertificateRequest", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_DO); + + return ret; +} + +#endif /* !NO_WOLFSSL_CLIENT */ + +#ifndef NO_WOLFSSL_SERVER +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +/* Refine list of supported cipher suites to those common to server and client. + * + * ssl SSL/TLS object. + * peerSuites The peer's advertised list of supported cipher suites. + */ +static void RefineSuites(WOLFSSL* ssl, Suites* peerSuites) +{ + byte suites[WOLFSSL_MAX_SUITE_SZ]; + int suiteSz = 0; + word16 i, j; + + XMEMSET(suites, 0, WOLFSSL_MAX_SUITE_SZ); + + for (i = 0; i < ssl->suites->suiteSz; i += 2) { + for (j = 0; j < peerSuites->suiteSz; j += 2) { + if (ssl->suites->suites[i+0] == peerSuites->suites[j+0] && + ssl->suites->suites[i+1] == peerSuites->suites[j+1]) { + suites[suiteSz++] = peerSuites->suites[j+0]; + suites[suiteSz++] = peerSuites->suites[j+1]; + } + } + } + + ssl->suites->suiteSz = suiteSz; + XMEMCPY(ssl->suites->suites, &suites, sizeof(suites)); +} + +/* Handle any Pre-Shared Key (PSK) extension. + * Must do this in ClientHello as it requires a hash of the truncated message. + * Don't know size of binders until Pre-Shared Key extension has been parsed. + * + * ssl The SSL/TLS object. + * input The ClientHello message. + * helloSz The size of the ClientHello message (including binders if present). + * usingPSK Indicates handshake is using Pre-Shared Keys. + * returns 0 on success and otherwise failure. + */ +static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, + int* usingPSK) +{ + int ret; + TLSX* ext; + word16 bindersLen; + PreSharedKey* current; + byte binderKey[WC_MAX_DIGEST_SIZE]; + byte binder[WC_MAX_DIGEST_SIZE]; + word32 binderLen; + word16 modes; + byte suite[2]; +#ifdef WOLFSSL_EARLY_DATA + int pskCnt = 0; + TLSX* extEarlyData; +#endif +#ifndef NO_PSK + const char* cipherName = NULL; + byte cipherSuite0 = TLS13_BYTE; + byte cipherSuite = WOLFSSL_DEF_PSK_CIPHER; +#endif + + WOLFSSL_ENTER("DoPreSharedKeys"); + + ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (ext == NULL) { + /* Hash data up to binders for deriving binders in PSK extension. */ + ret = HashInput(ssl, input, helloSz); + return ret; + } + + /* Extensions pushed on stack/list and PSK must be last. */ + if (ssl->extensions != ext) + return PSK_KEY_ERROR; + + /* Assume we are going to resume with a pre-shared key. */ + ssl->options.resuming = 1; + + /* Find the pre-shared key extension and calculate hash of truncated + * ClientHello for binders. + */ + ret = TLSX_PreSharedKey_GetSizeBinders((PreSharedKey*)ext->data, + client_hello, &bindersLen); + if (ret < 0) + return ret; + + /* Hash data up to binders for deriving binders in PSK extension. */ + ret = HashInput(ssl, input, helloSz - bindersLen); + if (ret != 0) + return ret; + + /* 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 + if (current->identityLen > MAX_PSK_ID_LEN) { + return BUFFER_ERROR; + } + XMEMCPY(ssl->arrays->client_identity, current->identity, + current->identityLen); + ssl->arrays->client_identity[current->identityLen] = '\0'; + #endif + + #ifdef HAVE_SESSION_TICKET + /* Decode the identity. */ + 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 (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; + } + + /* Check whether resumption is possible based on suites in SSL and + * ciphersuite in ticket. + */ + suite[0] = ssl->session.cipherSuite0; + suite[1] = ssl->session.cipherSuite; + if (!FindSuiteSSL(ssl, suite)) { + current = current->next; + continue; + } + + #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; + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; + + /* Resumption PSK is resumption master secret. */ + ssl->arrays->psk_keySz = ssl->specs.hash_size; + #ifdef WOLFSSL_TLS13_DRAFT_18 + XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, + ssl->arrays->psk_keySz); + #else + if ((ret = DeriveResumptionPSK(ssl, ssl->session.ticketNonce.data, + ssl->session.ticketNonce.len, ssl->arrays->psk_key)) != 0) { + return ret; + } + #endif + + /* Derive the early secret using the PSK. */ + ret = DeriveEarlySecret(ssl); + if (ret != 0) + return ret; + /* Derive the binder key to use to with HMAC. */ + ret = DeriveBinderKeyResume(ssl, binderKey); + if (ret != 0) + return ret; + } + else + #endif + #ifndef NO_PSK + if ((ssl->options.server_psk_tls13_cb != NULL && + (ssl->arrays->psk_keySz = ssl->options.server_psk_tls13_cb(ssl, + ssl->arrays->client_identity, ssl->arrays->psk_key, + MAX_PSK_KEY_LEN, &cipherName)) != 0 && + GetCipherSuiteFromName(cipherName, &cipherSuite0, + &cipherSuite) == 0) || + (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) + return PSK_KEY_ERROR; + + /* Check whether PSK ciphersuite is in SSL. */ + suite[0] = cipherSuite0; + suite[1] = cipherSuite; + if (!FindSuiteSSL(ssl, suite)) { + current = current->next; + continue; + } + + /* Default to ciphersuite if cb doesn't specify. */ + ssl->options.resuming = 0; + + /* PSK age is always zero. */ + if (current->ticketAge != ssl->session.ticketAdd) + return PSK_KEY_ERROR; + + /* Set PSK ciphersuite into SSL. */ + ssl->options.cipherSuite0 = cipherSuite0; + ssl->options.cipherSuite = cipherSuite; + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; + + /* Derive the early secret using the PSK. */ + ret = DeriveEarlySecret(ssl); + if (ret != 0) + return ret; + /* Derive the binder key to use to with HMAC. */ + ret = DeriveBinderKey(ssl, binderKey); + if (ret != 0) + return ret; + } + else + #endif + { + current = current->next; + continue; + } + + ssl->options.sendVerify = 0; + + /* Derive the Finished message secret. */ + ret = DeriveFinishedSecret(ssl, binderKey, + 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); + if (ret != 0) + return ret; + if (binderLen != current->binderLen || + XMEMCMP(binder, current->binder, binderLen) != 0) { + return BAD_BINDER; + } + + /* This PSK works, no need to try any more. */ + current->chosen = 1; + ext->resp = 1; + break; + } + + /* Hash the rest of the ClientHello. */ + ret = HashInputRaw(ssl, input + helloSz - bindersLen, bindersLen); + if (ret != 0) + return ret; + + if (current == NULL) { +#ifdef WOLFSSL_PSK_ID_PROTECTION + #ifndef NO_CERTS + if (ssl->buffers.certChainCnt != 0) + return 0; + #endif + return BAD_BINDER; +#else + return 0; +#endif + } + +#ifdef WOLFSSL_EARLY_DATA + extEarlyData = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); + if (extEarlyData != NULL) { + if (ssl->earlyData != no_early_data && 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 = process_early_data; + } + 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) + return MISSING_HANDSHAKE_DATA; + modes = ext->val; + + ext = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + /* Use (EC)DHE for forward-security if possible. */ + 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; + + /* Pick key share and Generate a new key if not present. */ + ret = TLSX_KeyShare_Establish(ssl); + if (ret == KEY_SHARE_ERROR) { + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; + ret = 0; + } + else if (ret < 0) + return ret; + + /* Send new public key to client. */ + ext->resp = 1; + } + else { + if ((modes & (1 << PSK_KE)) == 0) + return PSK_KEY_ERROR; + ssl->options.noPskDheKe = 1; + ssl->arrays->preMasterSz = 0; + } + + *usingPSK = 1; + + WOLFSSL_LEAVE("DoPreSharedKeys", ret); + + return ret; +} +#endif + +#if !defined(WOLFSSL_TLS13_DRAFT_18) && defined(WOLFSSL_SEND_HRR_COOKIE) +/* Check that the Cookie data's integrity. + * + * ssl SSL/TLS object. + * cookie The cookie data - hash and MAC. + * cookieSz The length of the cookie data in bytes. + * returns Length of the hash on success, otherwise failure. + */ +static int CheckCookie(WOLFSSL* ssl, byte* cookie, byte cookieSz) +{ + int ret; + byte mac[WC_MAX_DIGEST_SIZE] = {0}; + Hmac cookieHmac; + byte cookieType = 0; + byte macSz = 0; + +#if !defined(NO_SHA) && defined(NO_SHA256) + cookieType = SHA; + macSz = WC_SHA_DIGEST_SIZE; +#endif /* NO_SHA */ +#ifndef NO_SHA256 + cookieType = WC_SHA256; + macSz = WC_SHA256_DIGEST_SIZE; +#endif /* NO_SHA256 */ + + if (cookieSz < ssl->specs.hash_size + macSz) + return HRR_COOKIE_ERROR; + cookieSz -= macSz; + XMEMSET(&cookieHmac, 0, sizeof(Hmac)); + + ret = wc_HmacSetKey(&cookieHmac, cookieType, + ssl->buffers.tls13CookieSecret.buffer, + ssl->buffers.tls13CookieSecret.length); + if (ret != 0) + return ret; + if ((ret = wc_HmacUpdate(&cookieHmac, cookie, cookieSz)) != 0) + return ret; + if ((ret = wc_HmacFinal(&cookieHmac, mac)) != 0) + return ret; + + if (ConstantCompare(cookie + cookieSz, mac, macSz) != 0) + return HRR_COOKIE_ERROR; + return cookieSz; +} + +/* Length of the KeyShare Extension */ +#define HRR_KEY_SHARE_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) +/* Length of the Supported Vresions Extension */ +#define HRR_VERSIONS_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) +/* Length of the Cookie Extension excluding cookie data */ +#define HRR_COOKIE_HDR_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* PV | CipherSuite | Ext Len */ +#define HRR_BODY_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) +/* HH | PV | CipherSuite | Ext Len | Key Share | Cookie */ +#define MAX_HRR_SZ (HANDSHAKE_HEADER_SZ + \ + HRR_BODY_SZ + \ + HRR_KEY_SHARE_SZ + \ + HRR_COOKIE_HDR_SZ) +#else +/* PV | Random | Session Id | CipherSuite | Compression | Ext Len */ +#define HRR_BODY_SZ (VERSION_SZ + RAN_LEN + ENUM_LEN + ID_LEN + \ + SUITE_LEN + COMP_LEN + OPAQUE16_LEN) +/* HH | PV | CipherSuite | Ext Len | Key Share | Supported Version | Cookie */ +#define MAX_HRR_SZ (HANDSHAKE_HEADER_SZ + \ + HRR_BODY_SZ + \ + HRR_KEY_SHARE_SZ + \ + HRR_VERSIONS_SZ + \ + HRR_COOKIE_HDR_SZ) +#endif + +/* Restart the handshake hash from the cookie value. + * + * ssl SSL/TLS object. + * cookie Cookie data from client. + * returns 0 on success, otherwise failure. + */ +static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie) +{ + byte header[HANDSHAKE_HEADER_SZ] = {0}; + byte hrr[MAX_HRR_SZ] = {0}; + int hrrIdx; + word32 idx; + byte hashSz; + byte* cookieData; + byte cookieDataSz; + word16 length; + int keyShareExt = 0; + int ret; + + cookieDataSz = ret = CheckCookie(ssl, &cookie->data, cookie->len); + if (ret < 0) + return ret; + hashSz = cookie->data; + cookieData = &cookie->data; + idx = OPAQUE8_LEN; + + /* Restart handshake hash with synthetic message hash. */ + AddTls13HandShakeHeader(header, hashSz, 0, 0, message_hash, ssl); + if ((ret = InitHandshakeHashes(ssl)) != 0) + return ret; + if ((ret = HashOutputRaw(ssl, header, sizeof(header))) != 0) + return ret; + if ((ret = HashOutputRaw(ssl, cookieData + idx, hashSz)) != 0) + return ret; + + /* Reconstruct the HelloRetryMessage for handshake hash. */ +#ifdef WOLFSSL_TLS13_DRAFT_18 + length = HRR_BODY_SZ + HRR_COOKIE_HDR_SZ + cookie->len; +#else + length = HRR_BODY_SZ - ID_LEN + ssl->session.sessionIDSz + + HRR_COOKIE_HDR_SZ + cookie->len; + length += HRR_VERSIONS_SZ; +#endif + if (cookieDataSz > hashSz + OPAQUE16_LEN) { + keyShareExt = 1; + length += HRR_KEY_SHARE_SZ; + } +#ifdef WOLFSSL_TLS13_DRAFT_18 + AddTls13HandShakeHeader(hrr, length, 0, 0, hello_retry_request, ssl); + + idx += hashSz; + hrrIdx = HANDSHAKE_HEADER_SZ; + /* The negotiated protocol version. */ + hrr[hrrIdx++] = TLS_DRAFT_MAJOR; + hrr[hrrIdx++] = TLS_DRAFT_MINOR; + /* Cipher Suite */ + hrr[hrrIdx++] = cookieData[idx++]; + hrr[hrrIdx++] = cookieData[idx++]; + + /* Extensions' length */ + length -= HRR_BODY_SZ; + c16toa(length, hrr + hrrIdx); + hrrIdx += 2; +#else + AddTls13HandShakeHeader(hrr, length, 0, 0, server_hello, ssl); + + idx += hashSz; + hrrIdx = HANDSHAKE_HEADER_SZ; + + /* The negotiated protocol version. */ + hrr[hrrIdx++] = ssl->version.major; + hrr[hrrIdx++] = TLSv1_2_MINOR; + + /* HelloRetryRequest message has fixed value for random. */ + XMEMCPY(hrr + hrrIdx, helloRetryRequestRandom, RAN_LEN); + hrrIdx += RAN_LEN; + + hrr[hrrIdx++] = ssl->session.sessionIDSz; + if (ssl->session.sessionIDSz > 0) { + XMEMCPY(hrr + hrrIdx, ssl->session.sessionID, ssl->session.sessionIDSz); + hrrIdx += ssl->session.sessionIDSz; + } + + /* Cipher Suite */ + hrr[hrrIdx++] = cookieData[idx++]; + hrr[hrrIdx++] = cookieData[idx++]; + + /* Compression not supported in TLS v1.3. */ + hrr[hrrIdx++] = 0; + + /* Extensions' length */ + length -= HRR_BODY_SZ - ID_LEN + ssl->session.sessionIDSz; + c16toa(length, hrr + hrrIdx); + hrrIdx += 2; + +#endif + /* Optional KeyShare Extension */ + if (keyShareExt) { + c16toa(TLSX_KEY_SHARE, hrr + hrrIdx); + hrrIdx += 2; + c16toa(OPAQUE16_LEN, hrr + hrrIdx); + hrrIdx += 2; + hrr[hrrIdx++] = cookieData[idx++]; + hrr[hrrIdx++] = cookieData[idx++]; + } +#ifndef WOLFSSL_TLS13_DRAFT_18 + c16toa(TLSX_SUPPORTED_VERSIONS, hrr + hrrIdx); + hrrIdx += 2; + c16toa(OPAQUE16_LEN, hrr + hrrIdx); + hrrIdx += 2; + #ifdef WOLFSSL_TLS13_DRAFT + hrr[hrrIdx++] = TLS_DRAFT_MAJOR; + hrr[hrrIdx++] = TLS_DRAFT_MINOR; + #else + hrr[hrrIdx++] = ssl->version.major; + hrr[hrrIdx++] = ssl->version.minor; + #endif +#endif + /* Mandatory Cookie Extension */ + c16toa(TLSX_COOKIE, hrr + hrrIdx); + hrrIdx += 2; + c16toa(cookie->len + OPAQUE16_LEN, hrr + hrrIdx); + hrrIdx += 2; + c16toa(cookie->len, hrr + hrrIdx); + hrrIdx += 2; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Reconstucted HelloRetryRequest"); + WOLFSSL_BUFFER(hrr, hrrIdx); + WOLFSSL_MSG("Cookie"); + WOLFSSL_BUFFER(cookieData, cookie->len); +#endif + + if ((ret = HashOutputRaw(ssl, hrr, hrrIdx)) != 0) + return ret; + return HashOutputRaw(ssl, cookieData, cookie->len); +} +#endif + +/* Do SupportedVersion extension for TLS v1.3+ otherwise it is not. + * + * ssl The SSL/TLS object. + * input The message buffer. + * i The index into the message buffer of ClientHello. + * helloSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13SupportedVersions(WOLFSSL* ssl, const byte* input, word32 i, + word32 helloSz, int* wantDowngrade) +{ + int ret; + byte b; + word16 suiteSz; + word16 totalExtSz; + int foundVersion = 0; + + /* Client random */ + i += RAN_LEN; + /* Session id - not used in TLS v1.3 */ + b = input[i++]; + if (i + b > helloSz) { + return BUFFER_ERROR; + } + i += b; + /* Cipher suites */ + if (i + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + ato16(input + i, &suiteSz); + i += OPAQUE16_LEN; + if (i + suiteSz + 1 > helloSz) + return BUFFER_ERROR; + i += suiteSz; + /* Compression */ + b = input[i++]; + if (i + b > helloSz) + return BUFFER_ERROR; + i += b; + + /* TLS 1.3 must have extensions */ + if (i < helloSz) { + if (i + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + if (totalExtSz != helloSz - i) + return BUFFER_ERROR; + + /* Need to negotiate version first. */ + if ((ret = TLSX_ParseVersion(ssl, (byte*)input + i, totalExtSz, + client_hello, &foundVersion))) { + return ret; + } + } + *wantDowngrade = !foundVersion || !IsAtLeastTLSv1_3(ssl->version); + + return 0; +} + +/* Handle a ClientHello handshake message. + * If the protocol version in the message is not TLS v1.3 or higher, use + * DoClientHello() + * Only a server will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of ClientHello. + * On exit, the index of byte after the ClientHello message and + * padding. + * helloSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz) +{ + int ret = VERSION_ERROR; + byte b = 0; + ProtocolVersion pv; + Suites clSuites; + word32 i = *inOutIdx; + word32 begin = i; + word16 totalExtSz = 0; + int usingPSK = 0; + byte sessIdSz = 0; + int wantDowngrade = 0; + + WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO); + WOLFSSL_ENTER("DoTls13ClientHello"); + + XMEMSET(&pv, 0, sizeof(ProtocolVersion)); + XMEMSET(&clSuites, 0, sizeof(Suites)); + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "ClientHello"); + if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo); +#endif + + /* protocol version, random and session id length check */ + if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + /* Protocol version */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + ssl->chVersion = pv; /* store */ + i += OPAQUE16_LEN; + if (pv.major < SSLv3_MAJOR) { + WOLFSSL_MSG("Legacy version field contains unsupported value"); + #ifdef WOLFSSL_MYSQL_COMPATIBLE + SendAlert(ssl, alert_fatal, wc_protocol_version); + #else + SendAlert(ssl, alert_fatal, protocol_version); + #endif + return INVALID_PARAMETER; + } + /* Legacy protocol version cannot negotiate TLS 1.3 or higher. */ + if (pv.major > SSLv3_MAJOR || (pv.major == SSLv3_MAJOR && + pv.minor >= TLSv1_3_MINOR)) { + pv.major = SSLv3_MAJOR; + pv.minor = TLSv1_2_MINOR; + wantDowngrade = 1; + ssl->version.minor = pv.minor; + } + /* Legacy version must be [ SSLv3_MAJOR, TLSv1_2_MINOR ] for TLS v1.3 */ + else if (pv.major == SSLv3_MAJOR && pv.minor < TLSv1_2_MINOR) { + wantDowngrade = 1; + ssl->version.minor = pv.minor; + } + else { + ret = DoTls13SupportedVersions(ssl, input + begin, i - begin, helloSz, + &wantDowngrade); + if (ret < 0) + return ret; + } + if (wantDowngrade) { +#ifndef WOLFSSL_NO_TLS12 + if (!ssl->options.downgrade) { + WOLFSSL_MSG("Client trying to connect with lesser version than " + "TLS v1.3"); + return VERSION_ERROR; + } + + if (pv.minor < ssl->options.minDowngrade) + return VERSION_ERROR; + + if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) + return ret; + return DoClientHello(ssl, input, inOutIdx, helloSz); +#else + WOLFSSL_MSG("Client trying to connect with lesser version than " + "TLS v1.3"); + return VERSION_ERROR; +#endif + } + + /* Client random */ + XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN); + i += RAN_LEN; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("client random"); + WOLFSSL_BUFFER(ssl->arrays->clientRandom, RAN_LEN); +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* Session id - empty in TLS v1.3 */ + sessIdSz = input[i++]; + if (sessIdSz > 0 && !ssl->options.downgrade) { + WOLFSSL_MSG("Client sent session id - not supported"); + return BUFFER_ERROR; + } +#else + sessIdSz = input[i++]; + if (sessIdSz != ID_LEN && sessIdSz != 0) + return INVALID_PARAMETER; +#endif + + if (sessIdSz + i > helloSz) { + return BUFFER_ERROR; + } + + ssl->session.sessionIDSz = sessIdSz; + if (sessIdSz == ID_LEN) { + XMEMCPY(ssl->session.sessionID, input + i, sessIdSz); + i += ID_LEN; + } + + /* Cipher suites */ + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + ato16(&input[i], &clSuites.suiteSz); + i += OPAQUE16_LEN; + /* suites and compression length check */ + if ((i - begin) + clSuites.suiteSz + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + if (clSuites.suiteSz > WOLFSSL_MAX_SUITE_SZ) + return BUFFER_ERROR; + XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz); + i += clSuites.suiteSz; + clSuites.hashSigAlgoSz = 0; + +#ifdef HAVE_SERVER_RENEGOTIATION_INFO + ret = FindSuite(&clSuites, 0, TLS_EMPTY_RENEGOTIATION_INFO_SCSV); + if (ret == SUITES_ERROR) + return BUFFER_ERROR; + if (ret >= 0) { + TLSX* extension; + + /* check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV suite */ + ret = TLSX_AddEmptyRenegotiationInfo(&ssl->extensions, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + + extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO); + if (extension) { + ssl->secure_renegotiation = (SecureRenegotiation*)extension->data; + ssl->secure_renegotiation->enabled = 1; + } + } +#endif /* HAVE_SERVER_RENEGOTIATION_INFO */ + + /* Compression */ + b = input[i++]; + if ((i - begin) + b > helloSz) + return BUFFER_ERROR; + if (b != COMP_LEN) { + WOLFSSL_MSG("Must be one compression type in list"); + return INVALID_PARAMETER; + } + b = input[i++]; + if (b != NO_COMPRESSION) { + WOLFSSL_MSG("Must be no compression type in list"); + return INVALID_PARAMETER; + } + + /* Extensions */ + if ((i - begin) == helloSz) + return BUFFER_ERROR; + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; + + /* Auto populate extensions supported unless user defined. */ + if ((ret = TLSX_PopulateExtensions(ssl, 1)) != 0) + return ret; + + /* Parse extensions */ + if ((ret = TLSX_Parse(ssl, (byte*)input + i, totalExtSz, client_hello, + &clSuites))) { + return ret; + } + +#if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) + if ((ret = SNI_Callback(ssl)) != 0) + return ret; + ssl->options.side = WOLFSSL_SERVER_END; +#endif /* OPENSSL_ALL || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ + + i += totalExtSz; + *inOutIdx = i; + + ssl->options.sendVerify = SEND_CERT; + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + ssl->options.haveSessionId = 1; + +#if !defined(WOLFSSL_TLS13_DRAFT_18) && defined(WOLFSSL_SEND_HRR_COOKIE) + if (ssl->options.sendCookie && + ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + TLSX* ext; + + if ((ext = TLSX_Find(ssl->extensions, TLSX_COOKIE)) == NULL) + return HRR_COOKIE_ERROR; + /* Ensure the cookie came from client and isn't the one in the + * response - HelloRetryRequest. + */ + if (ext->resp == 1) + return HRR_COOKIE_ERROR; + ret = RestartHandshakeHashWithCookie(ssl, (Cookie*)ext->data); + if (ret != 0) + return ret; + } +#endif + +#if (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \ + defined(HAVE_TLS_EXTENSIONS) + if (TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY) != NULL) { + /* Refine list for PSK processing. */ + RefineSuites(ssl, &clSuites); + + /* Process the Pre-Shared Key extension if present. */ + ret = DoPreSharedKeys(ssl, input + begin, helloSz, &usingPSK); + if (ret != 0) + return ret; + } + else +#endif + { +#ifdef WOLFSSL_EARLY_DATA + ssl->earlyData = no_early_data; +#endif + if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) + return ret; + + } + + if (!usingPSK) { + if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) { + WOLFSSL_MSG("Client did not send a KeyShare extension"); + SendAlert(ssl, alert_fatal, missing_extension); + return INCOMPLETE_DATA; + } + if (TLSX_Find(ssl->extensions, TLSX_SIGNATURE_ALGORITHMS) == NULL) { + WOLFSSL_MSG("Client did not send a SignatureAlgorithms extension"); + SendAlert(ssl, alert_fatal, missing_extension); + return INCOMPLETE_DATA; + } + + if ((ret = MatchSuite(ssl, &clSuites)) < 0) { + WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); + SendAlert(ssl, alert_fatal, handshake_failure); + return ret; + } + +#ifdef HAVE_NULL_CIPHER + if (ssl->options.cipherSuite0 == ECC_BYTE && + (ssl->options.cipherSuite == TLS_SHA256_SHA256 || + ssl->options.cipherSuite == TLS_SHA384_SHA384)) { + ; + } + else +#endif + /* Check that the negotiated ciphersuite matches protocol version. */ + if (ssl->options.cipherSuite0 != TLS13_BYTE) { + WOLFSSL_MSG("Negotiated ciphersuite from lesser version than " + "TLS v1.3"); + SendAlert(ssl, alert_fatal, handshake_failure); + return VERSION_ERROR; + } + +#ifdef HAVE_SESSION_TICKET + if (ssl->options.resuming) { + ssl->options.resuming = 0; + XMEMSET(ssl->arrays->psk_key, 0, ssl->specs.hash_size); + } +#endif + + /* Derive early secret for handshake secret. */ + if ((ret = DeriveEarlySecret(ssl)) != 0) + return ret; + } + + WOLFSSL_LEAVE("DoTls13ClientHello", ret); + WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO); + + return ret; +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* handle generation of TLS 1.3 hello_retry_request (6) */ +/* Send the HelloRetryRequest message to indicate the negotiated protocol + * version and security parameters the server is willing to use. + * Only a server will send this message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +int SendTls13HelloRetryRequest(WOLFSSL* ssl) +{ + int ret; + byte* output; + word32 length; + word16 len; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + + WOLFSSL_ENTER("SendTls13HelloRetryRequest"); + + /* Get the length of the extensions that will be written. */ + len = 0; + ret = TLSX_GetResponseSize(ssl, hello_retry_request, &len); + /* There must be extensions sent to indicate what client needs to do. */ + if (ret != 0) + return MISSING_HANDSHAKE_DATA; + + /* Protocol version + Extensions */ + length = OPAQUE16_LEN + len; + sendSz = idx + length; + + /* 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; + /* Add record and handshake headers. */ + AddTls13Headers(output, length, hello_retry_request, ssl); + + /* The negotiated protocol version. */ + output[idx++] = TLS_DRAFT_MAJOR; + output[idx++] = TLS_DRAFT_MINOR; + + /* Add TLS extensions. */ + ret = TLSX_WriteResponse(ssl, output + idx, hello_retry_request, NULL); + if (ret != 0) + return ret; + idx += len; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "HelloRetryRequest"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "HelloRetryRequest", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + } +#endif + if ((ret = HashOutput(ssl, output, idx, 0)) != 0) + return ret; + + ssl->buffers.outputBuffer.length += sendSz; + + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13HelloRetryRequest", ret); + + return ret; +} +#endif /* WOLFSSL_TLS13_DRAFT_18 */ + +/* Send TLS v1.3 ServerHello message to client. + * Only a server will send this message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +#ifdef WOLFSSL_TLS13_DRAFT_18 +static +#endif +/* handle generation of TLS 1.3 server_hello (2) */ +int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) +{ + int ret; + byte* output; + word16 length; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + + WOLFSSL_START(WC_FUNC_SERVER_HELLO_SEND); + WOLFSSL_ENTER("SendTls13ServerHello"); + +#ifndef WOLFSSL_TLS13_DRAFT_18 + if (extMsgType == hello_retry_request) { + WOLFSSL_MSG("wolfSSL Doing HelloRetryRequest"); + if ((ret = RestartHandshakeHash(ssl)) < 0) + return ret; + } +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* Protocol version, server random, cipher suite and extensions. */ + length = VERSION_SZ + RAN_LEN + SUITE_LEN; + ret = TLSX_GetResponseSize(ssl, server_hello, &length); + if (ret != 0) + return ret; +#else + /* Protocol version, server random, session id, cipher suite, compression + * and extensions. + */ + length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->session.sessionIDSz + + SUITE_LEN + COMP_LEN; + ret = TLSX_GetResponseSize(ssl, extMsgType, &length); + if (ret != 0) + return ret; +#endif + sendSz = idx + length; + + /* 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, server_hello, ssl); + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* The negotiated protocol version. */ + output[idx++] = TLS_DRAFT_MAJOR; + output[idx++] = TLS_DRAFT_MINOR; +#else + /* The protocol version must be TLS v1.2 for middleboxes. */ + output[idx++] = ssl->version.major; + output[idx++] = TLSv1_2_MINOR; +#endif + + if (extMsgType == server_hello) { + /* Generate server random. */ + if ((ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN)) != 0) + return ret; + } +#ifndef WOLFSSL_TLS13_DRAFT_18 + else { + /* HelloRetryRequest message has fixed value for random. */ + XMEMCPY(output + idx, helloRetryRequestRandom, RAN_LEN); + } +#endif + /* Store in SSL for debugging. */ + XMEMCPY(ssl->arrays->serverRandom, output + idx, RAN_LEN); + idx += RAN_LEN; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Server random"); + WOLFSSL_BUFFER(ssl->arrays->serverRandom, RAN_LEN); +#endif + +#ifndef WOLFSSL_TLS13_DRAFT_18 + output[idx++] = ssl->session.sessionIDSz; + if (ssl->session.sessionIDSz > 0) { + XMEMCPY(output + idx, ssl->session.sessionID, ssl->session.sessionIDSz); + idx += ssl->session.sessionIDSz; + } +#endif + + /* Chosen cipher suite */ + output[idx++] = ssl->options.cipherSuite0; + output[idx++] = ssl->options.cipherSuite; + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Compression not supported in TLS v1.3. */ + output[idx++] = 0; +#endif + + /* Extensions */ + ret = TLSX_WriteResponse(ssl, output + idx, extMsgType, NULL); + if (ret != 0) + return ret; + + ssl->buffers.outputBuffer.length += sendSz; + + if ((ret = HashOutput(ssl, output, sendSz, 0)) != 0) + return ret; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "ServerHello"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "ServerHello", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + } + #endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 + ssl->options.serverState = SERVER_HELLO_COMPLETE; +#else + if (extMsgType == server_hello) + ssl->options.serverState = SERVER_HELLO_COMPLETE; +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 + if (!ssl->options.groupMessages) +#else + if (!ssl->options.groupMessages || extMsgType != server_hello) +#endif + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13ServerHello", ret); + WOLFSSL_END(WC_FUNC_SERVER_HELLO_SEND); + + return ret; +} + +/* handle generation of TLS 1.3 encrypted_extensions (8) */ +/* Send the rest of the extensions encrypted under the handshake key. + * This message is always encrypted in TLS v1.3. + * Only a server will send this message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int SendTls13EncryptedExtensions(WOLFSSL* ssl) +{ + int ret; + byte* output; + word16 length = 0; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + + WOLFSSL_START(WC_FUNC_ENCRYPTED_EXTENSIONS_SEND); + WOLFSSL_ENTER("SendTls13EncryptedExtensions"); + + ssl->keys.encryptionOn = 1; + +#ifndef WOLFSSL_NO_SERVER_GROUPS_EXT + if ((ret = TLSX_SupportedCurve_CheckPriority(ssl)) != 0) + return ret; +#endif + + /* Derive the handshake secret now that we are at first message to be + * encrypted under the keys. + */ + if ((ret = DeriveHandshakeSecret(ssl)) != 0) + return ret; + if ((ret = DeriveTls13Keys(ssl, handshake_key, + 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 != process_early_data) { + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + } +#else + if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) + return ret; +#endif + + ret = TLSX_GetResponseSize(ssl, encrypted_extensions, &length); + if (ret != 0) + return ret; + + sendSz = idx + length; + /* Encryption always on. */ + sendSz += MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + ret = CheckAvailableSize(ssl, sendSz); + if (ret != 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, encrypted_extensions, ssl); + + ret = TLSX_WriteResponse(ssl, output + idx, encrypted_extensions, NULL); + if (ret != 0) + return ret; + idx += length; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "EncryptedExtensions"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "EncryptedExtensions", handshake, output, + sendSz, WRITE_PROTO, ssl->heap); + } +#endif + + /* This handshake 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; + + ssl->options.serverState = SERVER_ENCRYPTED_EXTENSIONS_COMPLETE; + + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13EncryptedExtensions", ret); + WOLFSSL_END(WC_FUNC_ENCRYPTED_EXTENSIONS_SEND); + + return ret; +} + +#ifndef NO_CERTS +/* handle generation TLS v1.3 certificate_request (13) */ +/* Send the TLS v1.3 CertificateRequest message. + * This message is always encrypted in TLS v1.3. + * Only a server will send this message. + * + * ssl SSL/TLS object. + * reqCtx Request context. + * reqCtxLen Length of context. 0 when sending as part of handshake. + * returns 0 on success, otherwise failure. + */ +static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, + int reqCtxLen) +{ + byte* output; + int ret; + int sendSz; + word32 i; + word16 reqSz; +#ifndef WOLFSSL_TLS13_DRAFT_18 + TLSX* ext; +#endif + + WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_SEND); + WOLFSSL_ENTER("SendTls13CertificateRequest"); + + if (ssl->options.side == WOLFSSL_SERVER_END) + InitSuitesHashSigAlgo(ssl->suites, 1, 1, 0, 1, ssl->buffers.keySz); + +#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 + ext = TLSX_Find(ssl->extensions, TLSX_SIGNATURE_ALGORITHMS); + if (ext == NULL) + return EXT_MISSING; + ext->resp = 0; + + i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + reqSz = (word16)(OPAQUE8_LEN + reqCtxLen); + ret = TLSX_GetRequestSize(ssl, certificate_request, &reqSz); + if (ret != 0) + return ret; + + sendSz = i + 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++] = (byte)reqCtxLen; + if (reqCtxLen != 0) { + XMEMCPY(output + i, reqCtx, reqCtxLen); + i += reqCtxLen; + } + + /* Certificate extensions. */ + reqSz = 0; + ret = TLSX_WriteRequest(ssl, output + i, certificate_request, &reqSz); + if (ret != 0) + return ret; + i += reqSz; +#endif + + /* Always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, + i - RECORD_HEADER_SZ, handshake, 1, 0, 0); + if (sendSz < 0) + return sendSz; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "CertificateRequest"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "CertificateRequest", handshake, output, + sendSz, WRITE_PROTO, ssl->heap); + } + #endif + + ssl->buffers.outputBuffer.length += sendSz; + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13CertificateRequest", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_SEND); + + return ret; +} +#endif /* NO_CERTS */ +#endif /* NO_WOLFSSL_SERVER */ + +#ifndef NO_CERTS +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) +/* Encode the signature algorithm into buffer. + * + * hashalgo The hash algorithm. + * hsType The signature type. + * output The buffer to encode into. + */ +static WC_INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) +{ + switch (hsType) { +#ifdef HAVE_ECC + case ecc_dsa_sa_algo: + output[0] = hashAlgo; + output[1] = ecc_dsa_sa_algo; + break; +#endif +#ifdef HAVE_ED25519 + /* ED25519: 0x0807 */ + case ed25519_sa_algo: + output[0] = ED25519_SA_MAJOR; + output[1] = ED25519_SA_MINOR; + (void)hashAlgo; + break; +#endif +#ifdef HAVE_ED448 + /* ED448: 0x0808 */ + case ed448_sa_algo: + output[0] = ED448_SA_MAJOR; + output[1] = ED448_SA_MINOR; + (void)hashAlgo; + break; +#endif +#ifndef NO_RSA + /* PSS signatures: 0x080[4-6] */ + case rsa_pss_sa_algo: + output[0] = rsa_pss_sa_algo; + output[1] = hashAlgo; + break; +#endif + } +} + +/* Decode the signature algorithm. + * + * input The encoded signature algorithm. + * hashalgo The hash algorithm. + * hsType The signature type. + * returns INVALID_PARAMETER if not recognized and 0 otherwise. + */ +static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, + byte* hsType) +{ + int ret = 0; + + switch (input[0]) { + case NEW_SA_MAJOR: + /* PSS signatures: 0x080[4-6] */ + if (input[1] >= sha256_mac && input[1] <= sha512_mac) { + *hsType = input[0]; + *hashAlgo = input[1]; + } + #ifdef HAVE_ED25519 + /* ED25519: 0x0807 */ + else if (input[1] == ED25519_SA_MINOR) { + *hsType = ed25519_sa_algo; + /* Hash performed as part of sign/verify operation. */ + *hashAlgo = sha512_mac; + } + #endif + #ifdef HAVE_ED448 + /* ED448: 0x0808 */ + else if (input[1] == ED448_SA_MINOR) { + *hsType = ed448_sa_algo; + /* Hash performed as part of sign/verify operation. */ + *hashAlgo = sha512_mac; + } + #endif + else + ret = INVALID_PARAMETER; + break; + default: + *hashAlgo = input[0]; + *hsType = input[1]; + break; + } + + return ret; +} + +/* Get the hash of the messages so far. + * + * ssl The SSL/TLS object. + * hash The buffer to write the hash to. + * returns the length of the hash. + */ +static WC_INLINE int GetMsgHash(WOLFSSL* ssl, byte* hash) +{ + int ret = 0; + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash); + if (ret == 0) + ret = WC_SHA256_DIGEST_SIZE; + break; + #endif /* !NO_SHA256 */ + #ifdef WOLFSSL_SHA384 + case sha384_mac: + ret = wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash); + if (ret == 0) + ret = WC_SHA384_DIGEST_SIZE; + break; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + ret = wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash); + if (ret == 0) + ret = WC_SHA512_DIGEST_SIZE; + break; + #endif /* WOLFSSL_TLS13_SHA512 */ + } + return ret; +} + +/* The length of the certificate verification label - client and server. */ +#define CERT_VFY_LABEL_SZ 34 +/* The server certificate verification label. */ +static const byte serverCertVfyLabel[CERT_VFY_LABEL_SZ] = + "TLS 1.3, server CertificateVerify"; +/* The client certificate verification label. */ +static const byte clientCertVfyLabel[CERT_VFY_LABEL_SZ] = + "TLS 1.3, client CertificateVerify"; + +/* The number of prefix bytes for signature data. */ +#define SIGNING_DATA_PREFIX_SZ 64 +/* The prefix byte in the signature data. */ +#define SIGNING_DATA_PREFIX_BYTE 0x20 +/* Maximum length of the signature data. */ +#define MAX_SIG_DATA_SZ (SIGNING_DATA_PREFIX_SZ + \ + CERT_VFY_LABEL_SZ + \ + WC_MAX_DIGEST_SIZE) + +/* Create the signature data for TLS v1.3 certificate verification. + * + * ssl The SSL/TLS object. + * sigData The signature data. + * sigDataSz The length of the signature data. + * check Indicates this is a check not create. + */ +static int CreateSigData(WOLFSSL* ssl, byte* sigData, word16* sigDataSz, + int check) +{ + word16 idx; + int side = ssl->options.side; + int ret; + + /* Signature Data = Prefix | Label | Handshake Hash */ + XMEMSET(sigData, SIGNING_DATA_PREFIX_BYTE, SIGNING_DATA_PREFIX_SZ); + idx = SIGNING_DATA_PREFIX_SZ; + + if ((side == WOLFSSL_SERVER_END && check) || + (side == WOLFSSL_CLIENT_END && !check)) { + XMEMCPY(&sigData[idx], clientCertVfyLabel, CERT_VFY_LABEL_SZ); + } + if ((side == WOLFSSL_CLIENT_END && check) || + (side == WOLFSSL_SERVER_END && !check)) { + XMEMCPY(&sigData[idx], serverCertVfyLabel, CERT_VFY_LABEL_SZ); + } + idx += CERT_VFY_LABEL_SZ; + + ret = GetMsgHash(ssl, &sigData[idx]); + if (ret < 0) + return ret; + + *sigDataSz = (word16)(idx + ret); + ret = 0; + + return ret; +} + +#ifndef NO_RSA +/* Encode the PKCS #1.5 RSA signature. + * + * sig The buffer to place the encoded signature into. + * sigData The data to be signed. + * sigDataSz The size of the data to be signed. + * hashAlgo The hash algorithm to use when signing. + * returns the length of the encoded signature or negative on error. + */ +static int CreateRSAEncodedSig(byte* sig, byte* sigData, int sigDataSz, + int sigAlgo, int hashAlgo) +{ + Digest digest; + int hashSz = 0; + int ret = BAD_FUNC_ARG; + byte* hash; + + (void)sigAlgo; + + hash = sig; + + /* Digest the signature data. */ + switch (hashAlgo) { +#ifndef NO_WOLFSSL_SHA256 + case sha256_mac: + ret = wc_InitSha256(&digest.sha256); + if (ret == 0) { + ret = wc_Sha256Update(&digest.sha256, sigData, sigDataSz); + if (ret == 0) + ret = wc_Sha256Final(&digest.sha256, hash); + wc_Sha256Free(&digest.sha256); + } + hashSz = WC_SHA256_DIGEST_SIZE; + break; +#endif +#ifdef WOLFSSL_SHA384 + case sha384_mac: + ret = wc_InitSha384(&digest.sha384); + if (ret == 0) { + ret = wc_Sha384Update(&digest.sha384, sigData, sigDataSz); + if (ret == 0) + ret = wc_Sha384Final(&digest.sha384, hash); + wc_Sha384Free(&digest.sha384); + } + hashSz = WC_SHA384_DIGEST_SIZE; + break; +#endif +#ifdef WOLFSSL_SHA512 + case sha512_mac: + ret = wc_InitSha512(&digest.sha512); + if (ret == 0) { + ret = wc_Sha512Update(&digest.sha512, sigData, sigDataSz); + if (ret == 0) + ret = wc_Sha512Final(&digest.sha512, hash); + wc_Sha512Free(&digest.sha512); + } + hashSz = WC_SHA512_DIGEST_SIZE; + break; +#endif + } + + if (ret != 0) + return ret; + + return hashSz; +} +#endif /* !NO_RSA */ + +#ifdef HAVE_ECC +/* Encode the ECC signature. + * + * sigData The data to be signed. + * sigDataSz The size of the data to be signed. + * hashAlgo The hash algorithm to use when signing. + * returns the length of the encoded signature or negative on error. + */ +static int CreateECCEncodedSig(byte* sigData, int sigDataSz, int hashAlgo) +{ + Digest digest; + int hashSz = 0; + int ret = BAD_FUNC_ARG; + + /* Digest the signature data. */ + switch (hashAlgo) { +#ifndef NO_WOLFSSL_SHA256 + case sha256_mac: + ret = wc_InitSha256(&digest.sha256); + if (ret == 0) { + ret = wc_Sha256Update(&digest.sha256, sigData, sigDataSz); + if (ret == 0) + ret = wc_Sha256Final(&digest.sha256, sigData); + wc_Sha256Free(&digest.sha256); + } + hashSz = WC_SHA256_DIGEST_SIZE; + break; +#endif +#ifdef WOLFSSL_SHA384 + case sha384_mac: + ret = wc_InitSha384(&digest.sha384); + if (ret == 0) { + ret = wc_Sha384Update(&digest.sha384, sigData, sigDataSz); + if (ret == 0) + ret = wc_Sha384Final(&digest.sha384, sigData); + wc_Sha384Free(&digest.sha384); + } + hashSz = WC_SHA384_DIGEST_SIZE; + break; +#endif +#ifdef WOLFSSL_SHA512 + case sha512_mac: + ret = wc_InitSha512(&digest.sha512); + if (ret == 0) { + ret = wc_Sha512Update(&digest.sha512, sigData, sigDataSz); + if (ret == 0) + ret = wc_Sha512Final(&digest.sha512, sigData); + wc_Sha512Free(&digest.sha512); + } + hashSz = WC_SHA512_DIGEST_SIZE; + break; +#endif + } + + if (ret != 0) + return ret; + + return hashSz; +} +#endif /* HAVE_ECC */ + +#ifndef NO_RSA +/* Check that the decrypted signature matches the encoded signature + * based on the digest of the signature data. + * + * ssl The SSL/TLS object. + * sigAlgo The signature algorithm used to generate signature. + * hashAlgo The hash algorithm used to generate signature. + * decSig The decrypted signature. + * decSigSz The size of the decrypted signature. + * returns 0 on success, otherwise failure. + */ +static int CheckRSASignature(WOLFSSL* ssl, int sigAlgo, int hashAlgo, + byte* decSig, word32 decSigSz) +{ + int ret = 0; + byte sigData[MAX_SIG_DATA_SZ]; + word16 sigDataSz; + word32 sigSz; + + ret = CreateSigData(ssl, sigData, &sigDataSz, 1); + if (ret != 0) + return ret; + + if (sigAlgo == rsa_pss_sa_algo) { + enum wc_HashType hashType = WC_HASH_TYPE_NONE; + + ret = ConvertHashPss(hashAlgo, &hashType, NULL); + if (ret < 0) + return ret; + + /* PSS signature can be done in-place */ + ret = CreateRSAEncodedSig(sigData, sigData, sigDataSz, + sigAlgo, hashAlgo); + if (ret < 0) + return ret; + sigSz = ret; + + ret = wc_RsaPSS_CheckPadding(sigData, sigSz, decSig, decSigSz, + hashType); + } + + return ret; +} +#endif /* !NO_RSA */ +#endif /* !NO_RSA || HAVE_ECC */ + +/* Get the next certificate from the list for writing into the TLS v1.3 + * Certificate message. + * + * data The certificate list. + * length The length of the certificate data in the list. + * idx The index of the next certificate. + * returns the length of the certificate data. 0 indicates no more certificates + * in the list. + */ +static word32 NextCert(byte* data, word32 length, word32* idx) +{ + word32 len; + + /* Is index at end of list. */ + if (*idx == length) + return 0; + + /* Length of the current ASN.1 encoded certificate. */ + c24to32(data + *idx, &len); + /* Include the length field. */ + len += 3; + + /* Move index to next certificate and return the current certificate's + * length. + */ + *idx += len; + return len; +} + +/* Add certificate data and empty extension to output up to the fragment size. + * + * ssl SSL/TLS object. + * cert The certificate data to write out. + * len The length of the certificate data. + * extSz Length of the extension data with the certificate. + * idx The start of the certificate data to write out. + * fragSz The maximum size of this fragment. + * output The buffer to write to. + * returns the number of bytes written. + */ +static word32 AddCertExt(WOLFSSL* ssl, byte* cert, word32 len, word16 extSz, + word32 idx, word32 fragSz, byte* output) +{ + word32 i = 0; + word32 copySz = min(len - idx, fragSz); + + if (idx < len) { + XMEMCPY(output, cert + idx, copySz); + i = copySz; + if (copySz == fragSz) + return i; + } + copySz = len + extSz - idx - i; + + if (extSz == OPAQUE16_LEN) { + if (copySz <= fragSz) { + /* Empty extension */ + output[i++] = 0; + output[i++] = 0; + } + } + else { + byte* certExts = ssl->buffers.certExts->buffer + idx + i - len; + /* Put out as much of the extensions' data as will fit in fragment. */ + if (copySz > fragSz - i) + copySz = fragSz - i; + XMEMCPY(output + i, certExts, copySz); + i += copySz; + } + + return i; +} + +/* handle generation TLS v1.3 certificate (11) */ +/* Send the certificate for this end and any CAs that help with validation. + * This message is always encrypted in TLS v1.3. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int SendTls13Certificate(WOLFSSL* ssl) +{ + int ret = 0; + word32 certSz, certChainSz, headerSz, listSz, payloadSz; + word16 extSz = 0; + word32 length, maxFragment; + word32 len = 0; + word32 idx = 0; + word32 offset = OPAQUE16_LEN; + byte* p = NULL; + byte certReqCtxLen = 0; + byte* certReqCtx = NULL; + + WOLFSSL_START(WC_FUNC_CERTIFICATE_SEND); + WOLFSSL_ENTER("SendTls13Certificate"); + +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->certReqCtx != NULL) { + certReqCtxLen = ssl->certReqCtx->len; + certReqCtx = &ssl->certReqCtx->ctx; + } +#endif + + if (ssl->options.sendVerify == SEND_BLANK_CERT) { + certSz = 0; + certChainSz = 0; + headerSz = OPAQUE8_LEN + certReqCtxLen + CERT_HEADER_SZ; + length = headerSz; + listSz = 0; + } + else { + if (!ssl->buffers.certificate) { + WOLFSSL_MSG("Send Cert missing certificate buffer"); + return BUFFER_ERROR; + } + /* Certificate Data */ + certSz = ssl->buffers.certificate->length; + /* Cert Req Ctx Len | Cert Req Ctx | Cert List Len | Cert Data Len */ + headerSz = OPAQUE8_LEN + certReqCtxLen + CERT_HEADER_SZ + + CERT_HEADER_SZ; + + ret = TLSX_GetResponseSize(ssl, certificate, &extSz); + if (ret < 0) + return ret; + + /* Create extensions' data if none already present. */ + if (extSz > OPAQUE16_LEN && ssl->buffers.certExts == NULL) { + ret = AllocDer(&ssl->buffers.certExts, extSz, CERT_TYPE, ssl->heap); + if (ret < 0) + return ret; + + extSz = 0; + ret = TLSX_WriteResponse(ssl, ssl->buffers.certExts->buffer, + certificate, &extSz); + if (ret < 0) + return ret; + } + + /* Length of message data with one certificate and extensions. */ + length = headerSz + certSz + extSz; + /* Length of list data with one certificate and extensions. */ + listSz = CERT_HEADER_SZ + certSz + extSz; + + /* Send rest of chain if sending cert (chain has leading size/s). */ + if (certSz > 0 && ssl->buffers.certChainCnt > 0) { + p = ssl->buffers.certChain->buffer; + /* Chain length including extensions. */ + certChainSz = ssl->buffers.certChain->length + + OPAQUE16_LEN * ssl->buffers.certChainCnt; + length += certChainSz; + listSz += certChainSz; + } + else + certChainSz = 0; + } + + payloadSz = length; + + if (ssl->fragOffset != 0) + length -= (ssl->fragOffset + headerSz); + + maxFragment = wolfSSL_GetMaxRecordSize(ssl, MAX_RECORD_SIZE); + + while (length > 0 && ret == 0) { + byte* output = NULL; + word32 fragSz = 0; + word32 i = RECORD_HEADER_SZ; + int sendSz = RECORD_HEADER_SZ; + + if (ssl->fragOffset == 0) { + if (headerSz + certSz + extSz + certChainSz <= + maxFragment - HANDSHAKE_HEADER_SZ) { + fragSz = headerSz + certSz + extSz + certChainSz; + } + else + fragSz = maxFragment - HANDSHAKE_HEADER_SZ; + + sendSz += fragSz + HANDSHAKE_HEADER_SZ; + i += HANDSHAKE_HEADER_SZ; + } + else { + fragSz = min(length, maxFragment); + sendSz += fragSz; + } + + 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; + + if (ssl->fragOffset == 0) { + AddTls13FragHeaders(output, fragSz, 0, payloadSz, certificate, ssl); + + /* Request context. */ + output[i++] = certReqCtxLen; + if (certReqCtxLen > 0) { + XMEMCPY(output + i, certReqCtx, certReqCtxLen); + i += certReqCtxLen; + } + length -= OPAQUE8_LEN + certReqCtxLen; + fragSz -= OPAQUE8_LEN + certReqCtxLen; + /* Certificate list length. */ + c32to24(listSz, output + i); + i += CERT_HEADER_SZ; + length -= CERT_HEADER_SZ; + fragSz -= CERT_HEADER_SZ; + /* Leaf certificate data length. */ + if (certSz > 0) { + c32to24(certSz, output + i); + i += CERT_HEADER_SZ; + length -= CERT_HEADER_SZ; + fragSz -= CERT_HEADER_SZ; + } + } + else + AddTls13RecordHeader(output, fragSz, handshake, ssl); + + if (certSz > 0 && ssl->fragOffset < certSz + extSz) { + /* Put in the leaf certificate with extensions. */ + word32 copySz = AddCertExt(ssl, ssl->buffers.certificate->buffer, + certSz, extSz, ssl->fragOffset, fragSz, output + i); + i += copySz; + ssl->fragOffset += copySz; + length -= copySz; + fragSz -= copySz; + if (ssl->fragOffset == certSz + extSz) + FreeDer(&ssl->buffers.certExts); + } + if (certChainSz > 0 && fragSz > 0) { + /* Put in the CA certificates with empty extensions. */ + while (fragSz > 0) { + word32 l; + + if (offset == len + OPAQUE16_LEN) { + /* Find next CA certificate to write out. */ + offset = 0; + /* Point to the start of current cert in chain buffer. */ + p = ssl->buffers.certChain->buffer + idx; + len = NextCert(ssl->buffers.certChain->buffer, + ssl->buffers.certChain->length, &idx); + if (len == 0) + break; + } + + /* Write out certificate and empty extension. */ + l = AddCertExt(ssl, p, len, OPAQUE16_LEN, offset, fragSz, + output + i); + i += l; + ssl->fragOffset += l; + length -= l; + fragSz -= l; + offset += l; + } + } + + if ((int)i - RECORD_HEADER_SZ < 0) { + WOLFSSL_MSG("Send Cert bad inputSz"); + return BUFFER_E; + } + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, + output + RECORD_HEADER_SZ, + i - RECORD_HEADER_SZ, handshake, 1, 0, 0); + if (sendSz < 0) + return sendSz; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "Certificate"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "Certificate", handshake, output, + sendSz, WRITE_PROTO, ssl->heap); + } + #endif + + ssl->buffers.outputBuffer.length += sendSz; + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + } + + if (ret != WANT_WRITE) { + /* Clean up the fragment offset. */ + ssl->fragOffset = 0; + if (ssl->options.side == WOLFSSL_SERVER_END) + ssl->options.serverState = SERVER_CERT_COMPLETE; + } + +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->certReqCtx != NULL) { + CertReqCtx* ctx = ssl->certReqCtx; + ssl->certReqCtx = ssl->certReqCtx->next; + XFREE(ctx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + + WOLFSSL_LEAVE("SendTls13Certificate", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_SEND); + + return ret; +} + +typedef struct Scv13Args { + byte* output; /* not allocated */ + byte* verify; /* not allocated */ + word32 idx; + word32 sigLen; + int sendSz; + word16 length; + + byte sigAlgo; + byte* sigData; + word16 sigDataSz; +} Scv13Args; + +static void FreeScv13Args(WOLFSSL* ssl, void* pArgs) +{ + Scv13Args* args = (Scv13Args*)pArgs; + + (void)ssl; + + if (args->sigData) { + XFREE(args->sigData, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + args->sigData = NULL; + } +} + +/* handle generation TLS v1.3 certificate_verify (15) */ +/* Send the TLS v1.3 CertificateVerify message. + * A hash of all the message so far is used. + * The signed data is: + * 0x20 * 64 | context string | 0x00 | hash of messages + * This message is always encrypted in TLS v1.3. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int SendTls13CertificateVerify(WOLFSSL* ssl) +{ + int ret = 0; + buffer* sig = &ssl->buffers.sig; +#ifdef WOLFSSL_ASYNC_CRYPT + Scv13Args* args = (Scv13Args*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); +#else + Scv13Args args[1]; +#endif + + WOLFSSL_START(WC_FUNC_CERTIFICATE_VERIFY_SEND); + WOLFSSL_ENTER("SendTls13CertificateVerify"); + +#ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_scv; + } + else +#endif + { + /* Reset state */ + ret = 0; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + XMEMSET(args, 0, sizeof(Scv13Args)); + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeScv13Args; + #endif + } + + switch(ssl->options.asyncState) + { + case TLS_ASYNC_BEGIN: + { + if (ssl->options.sendVerify == SEND_BLANK_CERT) { + return 0; /* sent blank cert, can't verify */ + } + + args->sendSz = MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA; + /* Always encrypted. */ + args->sendSz += MAX_MSG_EXTRA; + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) { + goto exit_scv; + } + + /* get output buffer */ + args->output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_BUILD; + } /* case TLS_ASYNC_BEGIN */ + FALL_THROUGH; + + case TLS_ASYNC_BUILD: + { + /* idx is used to track verify pointer offset to output */ + args->idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + args->verify = + &args->output[RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ]; + + if (ssl->buffers.key == NULL) { + #ifdef HAVE_PK_CALLBACKS + if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) + args->length = GetPrivateKeySigSize(ssl); + else + #endif + ERROR_OUT(NO_PRIVATE_KEY, exit_scv); + } + else { + ret = DecodePrivateKey(ssl, &args->length); + if (ret != 0) + goto exit_scv; + } + + if (args->length <= 0) { + ERROR_OUT(NO_PRIVATE_KEY, exit_scv); + } + + /* Add signature algorithm. */ + if (ssl->hsType == DYNAMIC_TYPE_RSA) + args->sigAlgo = rsa_pss_sa_algo; + 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 + #ifdef HAVE_ED448 + else if (ssl->hsType == DYNAMIC_TYPE_ED448) + args->sigAlgo = ed448_sa_algo; + #endif + EncodeSigAlg(ssl->suites->hashAlgo, args->sigAlgo, args->verify); + + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + int sigLen = MAX_SIG_DATA_SZ; + if (args->length > MAX_SIG_DATA_SZ) + sigLen = args->length; + args->sigData = (byte*)XMALLOC(sigLen, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + } + else { + args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + } + if (args->sigData == NULL) { + ERROR_OUT(MEMORY_E, exit_scv); + } + + /* Create the data to be signed. */ + ret = CreateSigData(ssl, args->sigData, &args->sigDataSz, 0); + if (ret != 0) + goto exit_scv; + + #ifndef NO_RSA + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + /* build encoded signature buffer */ + sig->length = WC_MAX_DIGEST_SIZE; + sig->buffer = (byte*)XMALLOC(sig->length, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (sig->buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_scv); + } + + ret = CreateRSAEncodedSig(sig->buffer, args->sigData, + args->sigDataSz, args->sigAlgo, ssl->suites->hashAlgo); + if (ret < 0) + goto exit_scv; + sig->length = ret; + ret = 0; + + /* Maximum size of RSA Signature. */ + args->sigLen = args->length; + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + if (ssl->hsType == DYNAMIC_TYPE_ECC) { + sig->length = args->sendSz - args->idx - HASH_SIG_SIZE - + VERIFY_HEADER; + ret = CreateECCEncodedSig(args->sigData, + args->sigDataSz, ssl->suites->hashAlgo); + if (ret < 0) + goto exit_scv; + args->sigDataSz = (word16)ret; + ret = 0; + } + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + if (ssl->hsType == DYNAMIC_TYPE_ED25519) { + ret = Ed25519CheckPubKey(ssl); + if (ret < 0) { + ERROR_OUT(ret, exit_scv); + } + sig->length = ED25519_SIG_SIZE; + } + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + if (ssl->hsType == DYNAMIC_TYPE_ED448) { + ret = Ed448CheckPubKey(ssl); + if (ret < 0) { + ERROR_OUT(ret, exit_scv); + } + sig->length = ED448_SIG_SIZE; + } + #endif /* HAVE_ED448 */ + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_DO; + } /* case TLS_ASYNC_BUILD */ + FALL_THROUGH; + + case TLS_ASYNC_DO: + { + #ifdef HAVE_ECC + if (ssl->hsType == DYNAMIC_TYPE_ECC) { + + ret = EccSign(ssl, args->sigData, args->sigDataSz, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, + (word32*)&sig->length, (ecc_key*)ssl->hsKey, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + args->length = (word16)sig->length; + } + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + if (ssl->hsType == DYNAMIC_TYPE_ED25519) { + ret = Ed25519Sign(ssl, args->sigData, args->sigDataSz, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, + (word32*)&sig->length, (ed25519_key*)ssl->hsKey, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + args->length = (word16)sig->length; + } + #endif + #ifdef HAVE_ED448 + if (ssl->hsType == DYNAMIC_TYPE_ED448) { + ret = Ed448Sign(ssl, args->sigData, args->sigDataSz, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, + (word32*)&sig->length, (ed448_key*)ssl->hsKey, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + args->length = (word16)sig->length; + } + #endif + #ifndef NO_RSA + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + ret = RsaSign(ssl, sig->buffer, (word32)sig->length, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, &args->sigLen, + args->sigAlgo, ssl->suites->hashAlgo, + (RsaKey*)ssl->hsKey, + ssl->buffers.key + ); + if (ret == 0) { + args->length = (word16)args->sigLen; + + XMEMCPY(args->sigData, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, + args->sigLen); + } + } + #endif /* !NO_RSA */ + + /* Check for error */ + if (ret != 0) { + goto exit_scv; + } + + /* Add signature length. */ + c16toa(args->length, args->verify + HASH_SIG_SIZE); + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_VERIFY; + } /* case TLS_ASYNC_DO */ + FALL_THROUGH; + + case TLS_ASYNC_VERIFY: + { + #ifndef NO_RSA + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + /* check for signature faults */ + ret = VerifyRsaSign(ssl, args->sigData, args->sigLen, + sig->buffer, (word32)sig->length, args->sigAlgo, + ssl->suites->hashAlgo, (RsaKey*)ssl->hsKey, + ssl->buffers.key + ); + } + #endif /* !NO_RSA */ + + /* Check for error */ + if (ret != 0) { + goto exit_scv; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_FINALIZE; + } /* case TLS_ASYNC_VERIFY */ + FALL_THROUGH; + + case TLS_ASYNC_FINALIZE: + { + /* Put the record and handshake headers on. */ + AddTls13Headers(args->output, args->length + HASH_SIG_SIZE + + VERIFY_HEADER, certificate_verify, ssl); + + args->sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + + args->length + HASH_SIG_SIZE + VERIFY_HEADER; + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_END; + } /* case TLS_ASYNC_FINALIZE */ + FALL_THROUGH; + + case TLS_ASYNC_END: + { + /* This message is always encrypted. */ + ret = BuildTls13Message(ssl, args->output, + MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA, + args->output + RECORD_HEADER_SZ, + args->sendSz - RECORD_HEADER_SZ, handshake, + 1, 0, 0); + + if (ret < 0) { + goto exit_scv; + } + else { + args->sendSz = ret; + ret = 0; + } + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "CertificateVerify"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "CertificateVerify", handshake, + args->output, args->sendSz, WRITE_PROTO, ssl->heap); + } + #endif + + ssl->buffers.outputBuffer.length += args->sendSz; + + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + break; + } + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.asyncState) */ + +exit_scv: + + WOLFSSL_LEAVE("SendTls13CertificateVerify", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_VERIFY_SEND); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* Handle async operation */ + if (ret == WC_PENDING_E) { + return ret; + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + /* Final cleanup */ + FreeScv13Args(ssl, args); + FreeKeyExchange(ssl); + + return ret; +} + +/* handle processing TLS v1.3 certificate (11) */ +/* Parse and handle a TLS v1.3 Certificate message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of Certificate. + * On exit, the index of byte after the Certificate message. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13Certificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + int ret; + + WOLFSSL_START(WC_FUNC_CERTIFICATE_DO); + WOLFSSL_ENTER("DoTls13Certificate"); + + ret = ProcessPeerCerts(ssl, input, inOutIdx, totalSz); + if (ret == 0) { +#if !defined(NO_WOLFSSL_CLIENT) + if (ssl->options.side == WOLFSSL_CLIENT_END) + ssl->options.serverState = SERVER_CERT_COMPLETE; +#endif +#if !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.handShakeState == HANDSHAKE_DONE) { + /* reset handshake states */ + ssl->options.serverState = SERVER_FINISHED_COMPLETE; + ssl->options.acceptState = TICKET_SENT; + ssl->options.handShakeState = SERVER_FINISHED_COMPLETE; + } +#endif + } + + WOLFSSL_LEAVE("DoTls13Certificate", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_DO); + + return ret; +} + +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) + +typedef struct Dcv13Args { + byte* output; /* not allocated */ + word32 sendSz; + word16 sz; + word32 sigSz; + word32 idx; + word32 begin; + byte hashAlgo; + byte sigAlgo; + + byte* sigData; + word16 sigDataSz; +} Dcv13Args; + +static void FreeDcv13Args(WOLFSSL* ssl, void* pArgs) +{ + Dcv13Args* args = (Dcv13Args*)pArgs; + + if (args->sigData != NULL) { + XFREE(args->sigData, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + args->sigData = NULL; + } + + (void)ssl; +} + +/* handle processing TLS v1.3 certificate_verify (15) */ +/* Parse and handle a TLS v1.3 CertificateVerify message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of + * CertificateVerify. + * On exit, the index of byte after the CertificateVerify message. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, + word32* inOutIdx, word32 totalSz) +{ + int ret = 0; + buffer* sig = &ssl->buffers.sig; +#ifdef WOLFSSL_ASYNC_CRYPT + Dcv13Args* args = (Dcv13Args*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); +#else + Dcv13Args args[1]; +#endif + + WOLFSSL_START(WC_FUNC_CERTIFICATE_VERIFY_DO); + WOLFSSL_ENTER("DoTls13CertificateVerify"); + +#ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_dcv; + } + else +#endif + { + /* Reset state */ + ret = 0; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + XMEMSET(args, 0, sizeof(Dcv13Args)); + args->hashAlgo = sha_mac; + args->sigAlgo = anonymous_sa_algo; + args->idx = *inOutIdx; + args->begin = *inOutIdx; + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeDcv13Args; + #endif + } + + switch(ssl->options.asyncState) + { + case TLS_ASYNC_BEGIN: + { + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "CertificateVerify"); + if (ssl->toInfoOn) AddLateName("CertificateVerify", + &ssl->timeoutInfo); + #endif + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_BUILD; + } /* case TLS_ASYNC_BEGIN */ + FALL_THROUGH; + + case TLS_ASYNC_BUILD: + { + /* Signature algorithm. */ + if ((args->idx - args->begin) + ENUM_LEN + ENUM_LEN > totalSz) { + ERROR_OUT(BUFFER_ERROR, exit_dcv); + } + ret = DecodeTls13SigAlg(input + args->idx, &args->hashAlgo, + &args->sigAlgo); + if (ret < 0) + goto exit_dcv; + args->idx += OPAQUE16_LEN; + + /* Signature length. */ + if ((args->idx - args->begin) + OPAQUE16_LEN > totalSz) { + ERROR_OUT(BUFFER_ERROR, exit_dcv); + } + ato16(input + args->idx, &args->sz); + args->idx += OPAQUE16_LEN; + + /* Signature data. */ + if ((args->idx - args->begin) + args->sz > totalSz || + args->sz > ENCRYPT_LEN) { + ERROR_OUT(BUFFER_ERROR, exit_dcv); + } + + /* Check for public key of required type. */ + #ifdef HAVE_ED25519 + if (args->sigAlgo == ed25519_sa_algo && + !ssl->peerEd25519KeyPresent) { + WOLFSSL_MSG("Oops, peer sent ED25519 key but not in verify"); + } + #endif + #ifdef HAVE_ED448 + if (args->sigAlgo == ed448_sa_algo && !ssl->peerEd448KeyPresent) { + WOLFSSL_MSG("Oops, peer sent ED448 key but not in verify"); + } + #endif + #ifdef HAVE_ECC + if (args->sigAlgo == ecc_dsa_sa_algo && + !ssl->peerEccDsaKeyPresent) { + WOLFSSL_MSG("Oops, peer sent ECC key but not in verify"); + } + #endif + #ifndef NO_RSA + if (args->sigAlgo == rsa_sa_algo) { + WOLFSSL_MSG("Oops, peer sent PKCS#1.5 signature"); + ERROR_OUT(INVALID_PARAMETER, exit_dcv); + } + if (args->sigAlgo == rsa_pss_sa_algo && + (ssl->peerRsaKey == NULL || !ssl->peerRsaKeyPresent)) { + WOLFSSL_MSG("Oops, peer sent RSA key but not in verify"); + } + #endif + + sig->buffer = (byte*)XMALLOC(args->sz, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (sig->buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_dcv); + } + sig->length = args->sz; + XMEMCPY(sig->buffer, input + args->idx, args->sz); + + #ifdef HAVE_ECC + if (ssl->peerEccDsaKeyPresent) { + WOLFSSL_MSG("Doing ECC peer cert verify"); + + args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (args->sigData == NULL) { + ERROR_OUT(MEMORY_E, exit_dcv); + } + + ret = CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); + if (ret != 0) + goto exit_dcv; + ret = CreateECCEncodedSig(args->sigData, + args->sigDataSz, args->hashAlgo); + if (ret < 0) + goto exit_dcv; + args->sigDataSz = (word16)ret; + ret = 0; + } + #endif + #ifdef HAVE_ED25519 + if (ssl->peerEd25519KeyPresent) { + WOLFSSL_MSG("Doing ED25519 peer cert verify"); + + args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (args->sigData == NULL) { + ERROR_OUT(MEMORY_E, exit_dcv); + } + + CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); + ret = 0; + } + #endif + #ifdef HAVE_ED448 + if (ssl->peerEd448KeyPresent) { + WOLFSSL_MSG("Doing ED448 peer cert verify"); + + args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (args->sigData == NULL) { + ERROR_OUT(MEMORY_E, exit_dcv); + } + + CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); + ret = 0; + } + #endif + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_DO; + } /* case TLS_ASYNC_BUILD */ + FALL_THROUGH; + + case TLS_ASYNC_DO: + { + #ifndef NO_RSA + if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { + WOLFSSL_MSG("Doing RSA peer cert verify"); + + ret = RsaVerify(ssl, sig->buffer, (word32)sig->length, &args->output, + args->sigAlgo, args->hashAlgo, ssl->peerRsaKey, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerRsaKey + #else + NULL + #endif + ); + if (ret >= 0) { + args->sendSz = ret; + ret = 0; + } + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + if (ssl->peerEccDsaKeyPresent) { + WOLFSSL_MSG("Doing ECC peer cert verify"); + + ret = EccVerify(ssl, input + args->idx, args->sz, + args->sigData, args->sigDataSz, + ssl->peerEccDsaKey, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEccDsaKey + #else + NULL + #endif + ); + + if (ret >= 0) { + FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey); + ssl->peerEccDsaKeyPresent = 0; + } + } + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + if (ssl->peerEd25519KeyPresent) { + WOLFSSL_MSG("Doing ED25519 peer cert verify"); + + ret = Ed25519Verify(ssl, input + args->idx, args->sz, + args->sigData, args->sigDataSz, + ssl->peerEd25519Key, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEd25519Key + #else + NULL + #endif + ); + + if (ret >= 0) { + FreeKey(ssl, DYNAMIC_TYPE_ED25519, + (void**)&ssl->peerEd25519Key); + ssl->peerEd25519KeyPresent = 0; + } + } + #endif + #ifdef HAVE_ED448 + if (ssl->peerEd448KeyPresent) { + WOLFSSL_MSG("Doing ED448 peer cert verify"); + + ret = Ed448Verify(ssl, input + args->idx, args->sz, + args->sigData, args->sigDataSz, + ssl->peerEd448Key, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEd448Key + #else + NULL + #endif + ); + + if (ret >= 0) { + FreeKey(ssl, DYNAMIC_TYPE_ED448, + (void**)&ssl->peerEd448Key); + ssl->peerEd448KeyPresent = 0; + } + } + #endif + + /* Check for error */ + if (ret != 0) { + goto exit_dcv; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_VERIFY; + } /* case TLS_ASYNC_DO */ + FALL_THROUGH; + + case TLS_ASYNC_VERIFY: + { + #ifndef NO_RSA + if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { + ret = CheckRSASignature(ssl, args->sigAlgo, args->hashAlgo, + args->output, args->sendSz); + if (ret != 0) + goto exit_dcv; + + FreeKey(ssl, DYNAMIC_TYPE_RSA, (void**)&ssl->peerRsaKey); + ssl->peerRsaKeyPresent = 0; + } + #endif /* !NO_RSA */ + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_FINALIZE; + } /* case TLS_ASYNC_VERIFY */ + FALL_THROUGH; + + case TLS_ASYNC_FINALIZE: + { + ssl->options.havePeerVerify = 1; + + /* Set final index */ + args->idx += args->sz; + *inOutIdx = args->idx; + + /* Encryption is always on: add padding */ + *inOutIdx += ssl->keys.padSz; + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_END; + } /* case TLS_ASYNC_FINALIZE */ + + case TLS_ASYNC_END: + { + break; + } + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.asyncState) */ + +exit_dcv: + + WOLFSSL_LEAVE("DoTls13CertificateVerify", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_VERIFY_DO); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* Handle async operation */ + if (ret == WC_PENDING_E) { + /* Mark message as not received so it can process again */ + ssl->msgsReceived.got_certificate_verify = 0; + + return ret; + } + else +#endif /* WOLFSSL_ASYNC_CRYPT */ + if (ret != 0 && ret != INVALID_PARAMETER) + SendAlert(ssl, alert_fatal, decrypt_error); + + /* Final cleanup */ + FreeDcv13Args(ssl, args); + FreeKeyExchange(ssl); + + return ret; +} +#endif /* !NO_RSA || HAVE_ECC */ + +/* Parse and handle a TLS v1.3 Finished message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of Finished. + * On exit, the index of byte after the Finished message and padding. + * size Length of message data. + * totalSz Length of remaining data in the message buffer. + * sniff Indicates whether we are sniffing packets. + * returns 0 on success and otherwise failure. + */ +static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 size, word32 totalSz, int sniff) +{ + int ret; + word32 finishedSz = 0; + byte* secret; + byte mac[WC_MAX_DIGEST_SIZE]; + + WOLFSSL_START(WC_FUNC_FINISHED_DO); + WOLFSSL_ENTER("DoTls13Finished"); + + /* check against totalSz */ + if (*inOutIdx + size + ssl->keys.padSz > totalSz) + return BUFFER_E; + + if (ssl->options.handShakeDone) { + ret = DeriveFinishedSecret(ssl, ssl->clientSecret, + ssl->keys.client_write_MAC_secret); + if (ret != 0) + return ret; + + secret = ssl->keys.client_write_MAC_secret; + } + else if (ssl->options.side == WOLFSSL_CLIENT_END) { + /* All the handshake messages have been received to calculate + * client and server finished keys. + */ + ret = DeriveFinishedSecret(ssl, ssl->clientSecret, + ssl->keys.client_write_MAC_secret); + if (ret != 0) + return ret; + + ret = DeriveFinishedSecret(ssl, ssl->serverSecret, + ssl->keys.server_write_MAC_secret); + if (ret != 0) + return ret; + + secret = ssl->keys.server_write_MAC_secret; + } + else + secret = ssl->keys.client_write_MAC_secret; + + ret = BuildTls13HandshakeHmac(ssl, secret, mac, &finishedSz); + if (ret != 0) + return ret; + if (size != finishedSz) + return BUFFER_ERROR; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "Finished"); + if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo); + #endif + + if (sniff == NO_SNIFF) { + /* Actually check verify data. */ + if (XMEMCMP(input + *inOutIdx, mac, size) != 0){ + WOLFSSL_MSG("Verify finished error on hashes"); + SendAlert(ssl, alert_fatal, decrypt_error); + return VERIFY_FINISHED_ERROR; + } + } + + /* Force input exhaustion at ProcessReply by consuming padSz. */ + *inOutIdx += size + ssl->keys.padSz; + + if (ssl->options.side == WOLFSSL_SERVER_END && + !ssl->options.handShakeDone) { +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + 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; + } + +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) + ssl->options.serverState = SERVER_FINISHED_COMPLETE; +#endif +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + ssl->options.clientState = CLIENT_FINISHED_COMPLETE; + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } +#endif + + WOLFSSL_LEAVE("DoTls13Finished", 0); + WOLFSSL_END(WC_FUNC_FINISHED_DO); + + return 0; +} +#endif /* NO_CERTS */ + +/* Send the TLS v1.3 Finished message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int SendTls13Finished(WOLFSSL* ssl) +{ + int sendSz; + int finishedSz = ssl->specs.hash_size; + byte* input; + byte* output; + int ret; + int headerSz = HANDSHAKE_HEADER_SZ; + int outputSz; + byte* secret; + + WOLFSSL_START(WC_FUNC_FINISHED_SEND); + WOLFSSL_ENTER("SendTls13Finished"); + + outputSz = WC_MAX_DIGEST_SIZE + DTLS_HANDSHAKE_HEADER_SZ + MAX_MSG_EXTRA; + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, outputSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + input = output + RECORD_HEADER_SZ; + + AddTls13HandShakeHeader(input, finishedSz, 0, finishedSz, finished, ssl); + + /* make finished hashes */ + if (ssl->options.handShakeDone) { + ret = DeriveFinishedSecret(ssl, ssl->clientSecret, + ssl->keys.client_write_MAC_secret); + if (ret != 0) + return ret; + + secret = ssl->keys.client_write_MAC_secret; + } + else if (ssl->options.side == WOLFSSL_CLIENT_END) + secret = ssl->keys.client_write_MAC_secret; + else { + /* All the handshake messages have been done to calculate client and + * server finished keys. + */ + ret = DeriveFinishedSecret(ssl, ssl->clientSecret, + ssl->keys.client_write_MAC_secret); + if (ret != 0) + return ret; + + ret = DeriveFinishedSecret(ssl, ssl->serverSecret, + ssl->keys.server_write_MAC_secret); + if (ret != 0) + return ret; + + secret = ssl->keys.server_write_MAC_secret; + } + ret = BuildTls13HandshakeHmac(ssl, secret, &input[headerSz], NULL); + if (ret != 0) + return ret; + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, outputSz, input, + headerSz + finishedSz, handshake, 1, 0, 0); + if (sendSz < 0) + return BUILD_MSG_ERROR; + +#ifndef NO_SESSION_CACHE + if (!ssl->options.resuming && (ssl->options.side == WOLFSSL_SERVER_END || + (ssl->options.side == WOLFSSL_SERVER_END && ssl->arrays != NULL))) { + AddSession(ssl); /* just try */ + } +#endif + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "Finished"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "Finished", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + } + #endif + + ssl->buffers.outputBuffer.length += sendSz; + + if (ssl->options.side == WOLFSSL_SERVER_END) { + /* Can send application data now. */ + if ((ret = DeriveMasterSecret(ssl)) != 0) + return ret; +#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 == no_early_data)) != 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 != no_early_data) { + 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; + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret); + if (ret != 0) + return ret; +#endif + } + +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + ssl->options.clientState = CLIENT_FINISHED_COMPLETE; + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } +#endif +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + ssl->options.serverState = SERVER_FINISHED_COMPLETE; + } +#endif + + if ((ret = SendBuffered(ssl)) != 0) + return ret; + + WOLFSSL_LEAVE("SendTls13Finished", ret); + WOLFSSL_END(WC_FUNC_FINISHED_SEND); + + return ret; +} + +/* handle generation TLS v1.3 key_update (24) */ +/* Send the TLS v1.3 KeyUpdate message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int SendTls13KeyUpdate(WOLFSSL* ssl) +{ + int sendSz; + byte* input; + byte* output; + int ret; + int headerSz = HANDSHAKE_HEADER_SZ; + int outputSz; + word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + WOLFSSL_START(WC_FUNC_KEY_UPDATE_SEND); + WOLFSSL_ENTER("SendTls13KeyUpdate"); + + outputSz = OPAQUE8_LEN + MAX_MSG_EXTRA; + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, outputSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + input = output + RECORD_HEADER_SZ; + + AddTls13Headers(output, OPAQUE8_LEN, key_update, ssl); + + /* If: + * 1. I haven't sent a KeyUpdate requesting a response and + * 2. This isn't responding to peer KeyUpdate requiring a response then, + * I want a response. + */ + ssl->keys.updateResponseReq = output[i++] = + !ssl->keys.updateResponseReq && !ssl->keys.keyUpdateRespond; + /* Sent response, no longer need to respond. */ + ssl->keys.keyUpdateRespond = 0; + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, outputSz, input, + headerSz + OPAQUE8_LEN, handshake, 0, 0, 0); + if (sendSz < 0) + return BUILD_MSG_ERROR; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "KeyUpdate"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "KeyUpdate", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + } + #endif + + ssl->buffers.outputBuffer.length += sendSz; + + ret = SendBuffered(ssl); + if (ret != 0 && ret != WANT_WRITE) + return ret; + + /* Future traffic uses new encryption keys. */ + if ((ret = DeriveTls13Keys(ssl, update_traffic_key, ENCRYPT_SIDE_ONLY, 1)) + != 0) + return ret; + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + + WOLFSSL_LEAVE("SendTls13KeyUpdate", ret); + WOLFSSL_END(WC_FUNC_KEY_UPDATE_SEND); + + return ret; +} + +/* handle processing TLS v1.3 key_update (24) */ +/* Parse and handle a TLS v1.3 KeyUpdate message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of Finished. + * On exit, the index of byte after the Finished message and padding. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 totalSz) +{ + int ret; + word32 i = *inOutIdx; + + WOLFSSL_START(WC_FUNC_KEY_UPDATE_DO); + WOLFSSL_ENTER("DoTls13KeyUpdate"); + + /* check against totalSz */ + if (OPAQUE8_LEN != totalSz) + return BUFFER_E; + + switch (input[i]) { + case update_not_requested: + /* This message in response to any outstanding request. */ + ssl->keys.keyUpdateRespond = 0; + ssl->keys.updateResponseReq = 0; + break; + case update_requested: + /* New key update requiring a response. */ + ssl->keys.keyUpdateRespond = 1; + break; + default: + return INVALID_PARAMETER; + } + + /* Move index to byte after message. */ + *inOutIdx += totalSz; + /* Always encrypted. */ + *inOutIdx += ssl->keys.padSz; + + /* Future traffic uses new decryption keys. */ + if ((ret = DeriveTls13Keys(ssl, update_traffic_key, DECRYPT_SIDE_ONLY, 1)) + != 0) { + return ret; + } + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + + if (ssl->keys.keyUpdateRespond) + return SendTls13KeyUpdate(ssl); + + WOLFSSL_LEAVE("DoTls13KeyUpdate", ret); + WOLFSSL_END(WC_FUNC_KEY_UPDATE_DO); + + 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_START(WC_FUNC_END_OF_EARLY_DATA_SEND); + 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); + WOLFSSL_END(WC_FUNC_END_OF_EARLY_DATA_SEND); + + return ret; +} +#endif /* !NO_WOLFSSL_CLIENT */ + +#ifndef NO_WOLFSSL_SERVER +/* handle processing of TLS 1.3 end_of_early_data (5) */ +/* 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_START(WC_FUNC_END_OF_EARLY_DATA_DO); + WOLFSSL_ENTER("DoTls13EndOfEarlyData"); + + if ((*inOutIdx - begin) != size) + return BUFFER_ERROR; + + if (ssl->earlyData == no_early_data) { + WOLFSSL_MSG("EndOfEarlyData received unexpectedly"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + ssl->earlyData = done_early_data; + + /* Always encrypted. */ + *inOutIdx += ssl->keys.padSz; + + ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY); + + WOLFSSL_LEAVE("DoTls13EndOfEarlyData", ret); + WOLFSSL_END(WC_FUNC_END_OF_EARLY_DATA_DO); + + 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. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of Finished. + * On exit, the index of byte after the Finished message and padding. + * size The length of the current handshake message. + * returns 0 on success, otherwise failure. + */ +static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 size) +{ +#ifdef HAVE_SESSION_TICKET + int ret; + word32 begin = *inOutIdx; + word32 lifetime; + word32 ageAdd; + word16 length; + word32 now; +#ifndef WOLFSSL_TLS13_DRAFT_18 + const byte* nonce; + byte nonceLength; +#endif + + WOLFSSL_START(WC_FUNC_NEW_SESSION_TICKET_DO); + WOLFSSL_ENTER("DoTls13NewSessionTicket"); + + /* Lifetime hint. */ + if ((*inOutIdx - begin) + SESSION_HINT_SZ > size) + return BUFFER_ERROR; + ato32(input + *inOutIdx, &lifetime); + *inOutIdx += SESSION_HINT_SZ; + if (lifetime > MAX_LIFETIME) + return SERVER_HINT_ERROR; + + /* Age add. */ + if ((*inOutIdx - begin) + SESSION_ADD_SZ > size) + return BUFFER_ERROR; + ato32(input + *inOutIdx, &ageAdd); + *inOutIdx += SESSION_ADD_SZ; + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Ticket nonce. */ + if ((*inOutIdx - begin) + 1 > size) + return BUFFER_ERROR; + nonceLength = input[*inOutIdx]; + if (nonceLength > MAX_TICKET_NONCE_SZ) { + WOLFSSL_MSG("Nonce length not supported"); + return INVALID_PARAMETER; + } + *inOutIdx += 1; + if ((*inOutIdx - begin) + nonceLength > size) + return BUFFER_ERROR; + nonce = input + *inOutIdx; + *inOutIdx += nonceLength; +#endif + + /* Ticket length. */ + if ((*inOutIdx - begin) + LENGTH_SZ > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &length); + *inOutIdx += LENGTH_SZ; + if ((*inOutIdx - begin) + length > size) + return BUFFER_ERROR; + + if ((ret = SetTicket(ssl, input + *inOutIdx, length)) != 0) + return ret; + *inOutIdx += length; + + 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 +#ifndef WOLFSSL_TLS13_DRAFT_18 + ssl->session.ticketNonce.len = nonceLength; + if (nonceLength > 0) + XMEMCPY(&ssl->session.ticketNonce.data, nonce, nonceLength); +#endif + ssl->session.namedGroup = ssl->namedGroup; + + 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; + + ssl->expect_session_ticket = 0; +#else + (void)ssl; + (void)input; + + WOLFSSL_ENTER("DoTls13NewSessionTicket"); + + *inOutIdx += size + ssl->keys.padSz; +#endif /* HAVE_SESSION_TICKET */ + + WOLFSSL_LEAVE("DoTls13NewSessionTicket", 0); + WOLFSSL_END(WC_FUNC_NEW_SESSION_TICKET_DO); + + 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. + * returns 0 on success, otherwise failure. + */ +static int ExpectedResumptionSecret(WOLFSSL* ssl) +{ + int ret; + word32 finishedSz = 0; + byte mac[WC_MAX_DIGEST_SIZE]; + Digest digest; + static byte header[] = { 0x14, 0x00, 0x00, 0x00 }; + + /* Copy the running hash so we can 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_TLS13_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 != no_early_data) { + 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_TLS13_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. + * returns 0 on success, otherwise failure. + */ +static int SendTls13NewSessionTicket(WOLFSSL* ssl) +{ + byte* output; + int ret; + int sendSz; + word16 extSz; + word32 length; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + WOLFSSL_START(WC_FUNC_NEW_SESSION_TICKET_SEND); + WOLFSSL_ENTER("SendTls13NewSessionTicket"); + +#ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED + if (!ssl->msgsReceived.got_finished) { + if ((ret = ExpectedResumptionSecret(ssl)) != 0) + return ret; + } +#endif + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Start ticket nonce at 0 and go up to 255. */ + if (ssl->session.ticketNonce.len == 0) { + ssl->session.ticketNonce.len = DEF_TICKET_NONCE_SZ; + ssl->session.ticketNonce.data[0] = 0; + } + else + ssl->session.ticketNonce.data[0]++; +#endif + + if (!ssl->options.noTicketTls13) { + if ((ret = CreateTicket(ssl)) != 0) + return ret; + } + +#ifdef WOLFSSL_EARLY_DATA + ssl->session.maxEarlyDataSz = ssl->options.maxEarlyDataSz; + if (ssl->session.maxEarlyDataSz > 0) + TLSX_EarlyData_Use(ssl, ssl->session.maxEarlyDataSz); + extSz = 0; + ret = TLSX_GetResponseSize(ssl, session_ticket, &extSz); + if (ret != 0) + return ret; +#else + extSz = EXTS_SZ; +#endif + + /* Lifetime | Age Add | Ticket | Extensions */ + length = SESSION_HINT_SZ + SESSION_ADD_SZ + LENGTH_SZ + + ssl->session.ticketLen + extSz; +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Nonce */ + length += TICKET_NONCE_LEN_SZ + DEF_TICKET_NONCE_SZ; +#endif + sendSz = idx + length + MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + 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, session_ticket, ssl); + + /* Lifetime hint */ + c32toa(ssl->ctx->ticketHint, output + idx); + idx += SESSION_HINT_SZ; + /* Age add - obfuscator */ + c32toa(ssl->session.ticketAdd, output + idx); + idx += SESSION_ADD_SZ; + +#ifndef WOLFSSL_TLS13_DRAFT_18 + output[idx++] = ssl->session.ticketNonce.len; + output[idx++] = ssl->session.ticketNonce.data[0]; +#endif + + /* length */ + c16toa(ssl->session.ticketLen, output + idx); + idx += LENGTH_SZ; + /* ticket */ + XMEMCPY(output + idx, ssl->session.ticket, ssl->session.ticketLen); + idx += ssl->session.ticketLen; + +#ifdef WOLFSSL_EARLY_DATA + extSz = 0; + ret = TLSX_WriteResponse(ssl, output + idx, session_ticket, &extSz); + if (ret != 0) + return ret; + idx += extSz; +#else + /* No extension support - empty extensions. */ + c16toa(0, output + idx); + idx += EXTS_SZ; +#endif + + ssl->options.haveSessionId = 1; + +#ifndef NO_SESSION_CACHE + AddSession(ssl); +#endif + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, + idx - RECORD_HEADER_SZ, handshake, 0, 0, 0); + if (sendSz < 0) + return sendSz; + + ssl->buffers.outputBuffer.length += sendSz; + + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13NewSessionTicket", 0); + WOLFSSL_END(WC_FUNC_NEW_SESSION_TICKET_SEND); + + return ret; +} + #endif /* HAVE_SESSION_TICKET */ +#endif /* NO_WOLFSSL_SERVER */ + +/* Make sure no duplicates, no fast forward, or other problems + * + * ssl The SSL/TLS object. + * type Type of handshake message received. + * returns 0 on success, otherwise failure. + */ +static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) +{ + /* verify not a duplicate, mark received, check state */ + switch (type) { + +#ifndef NO_WOLFSSL_SERVER + case client_hello: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_MSG("ClientHello received by client"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.clientState >= CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("ClientHello received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->msgsReceived.got_client_hello == 2) { + WOLFSSL_MSG("Too many ClientHello received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_client_hello++; + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case server_hello: + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("ServerHello received by server"); + return OUT_OF_ORDER_E; + } + #endif + #ifdef WOLFSSL_TLS13_DRAFT_18 + if (ssl->msgsReceived.got_server_hello) { + WOLFSSL_MSG("Duplicate ServerHello received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_server_hello = 1; + #else + if (ssl->msgsReceived.got_server_hello == 2) { + WOLFSSL_MSG("Duplicate ServerHello received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_server_hello++; + #endif + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case session_ticket: + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("NewSessionTicket received by server"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) { + WOLFSSL_MSG("NewSessionTicket received out of order"); + return OUT_OF_ORDER_E; + } + ssl->msgsReceived.got_session_ticket = 1; + + break; +#endif + +#ifndef NO_WOLFSSL_SERVER + #ifdef WOLFSSL_EARLY_DATA + case end_of_early_data: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_MSG("EndOfEarlyData received by client"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + WOLFSSL_MSG("EndOfEarlyData received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->options.clientState >= CLIENT_FINISHED_COMPLETE) { + WOLFSSL_MSG("EndOfEarlyData received out of order"); + return OUT_OF_ORDER_E; + } + 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 + +#ifdef WOLFSSL_TLS13_DRAFT_18 + #ifndef NO_WOLFSSL_CLIENT + case hello_retry_request: + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("HelloRetryRequest received by server"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.clientState > CLIENT_FINISHED_COMPLETE) { + WOLFSSL_MSG("HelloRetryRequest received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->msgsReceived.got_hello_retry_request) { + WOLFSSL_MSG("Duplicate HelloRetryRequest received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_hello_retry_request = 1; + + break; + #endif +#endif + +#ifndef NO_WOLFSSL_CLIENT + case encrypted_extensions: + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("EncryptedExtensions received by server"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.serverState != SERVER_HELLO_COMPLETE) { + WOLFSSL_MSG("EncryptedExtensions received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->msgsReceived.got_encrypted_extensions) { + WOLFSSL_MSG("Duplicate EncryptedExtensions received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_encrypted_extensions = 1; + + break; +#endif + + case certificate: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->options.serverState != + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE) { + WOLFSSL_MSG("Certificate received out of order - Client"); + return OUT_OF_ORDER_E; + } + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* Server's authenticating with PSK must not send this. */ + if (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->options.serverState == SERVER_CERT_COMPLETE && + ssl->arrays->psk_keySz != 0) { + WOLFSSL_MSG("Certificate received while using PSK"); + return SANITY_MSG_E; + } + #endif + #endif + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + WOLFSSL_MSG("Certificate received out of order - Server"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->msgsReceived.got_certificate) { + WOLFSSL_MSG("Duplicate Certificate received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_certificate = 1; + + break; + +#ifndef NO_WOLFSSL_CLIENT + case certificate_request: + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("CertificateRequest received by server"); + return OUT_OF_ORDER_E; + } + #endif + #ifndef WOLFSSL_POST_HANDSHAKE_AUTH + if (ssl->options.serverState != + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE) { + WOLFSSL_MSG("CertificateRequest received out of order"); + return OUT_OF_ORDER_E; + } + #else + if (ssl->options.serverState != + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE && + (ssl->options.serverState != SERVER_FINISHED_COMPLETE || + ssl->options.clientState != CLIENT_FINISHED_COMPLETE)) { + WOLFSSL_MSG("CertificateRequest received out of order"); + return OUT_OF_ORDER_E; + } + #endif + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* Server's authenticating with PSK must not send this. */ + if (ssl->options.serverState == + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE && + ssl->arrays->psk_keySz != 0) { + WOLFSSL_MSG("CertificateRequset received while using PSK"); + return SANITY_MSG_E; + } + #endif + #ifndef WOLFSSL_POST_HANDSHAKE_AUTH + if (ssl->msgsReceived.got_certificate_request) { + WOLFSSL_MSG("Duplicate CertificateRequest received"); + return DUPLICATE_MSG_E; + } + #endif + ssl->msgsReceived.got_certificate_request = 1; + + break; +#endif + + case certificate_verify: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (ssl->options.serverState != SERVER_CERT_COMPLETE) { + WOLFSSL_MSG("No Cert before CertVerify"); + return OUT_OF_ORDER_E; + } + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* Server's authenticating with PSK must not send this. */ + if (ssl->options.serverState == SERVER_CERT_COMPLETE && + ssl->arrays->psk_keySz != 0) { + WOLFSSL_MSG("CertificateVerify received while using PSK"); + return SANITY_MSG_E; + } + #endif + } + #endif + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + WOLFSSL_MSG("CertificateVerify received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("CertificateVerify before ClientHello done"); + return OUT_OF_ORDER_E; + } + if (!ssl->msgsReceived.got_certificate) { + WOLFSSL_MSG("No Cert before CertificateVerify"); + return OUT_OF_ORDER_E; + } + } + #endif + if (ssl->msgsReceived.got_certificate_verify) { + WOLFSSL_MSG("Duplicate CertificateVerify received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_certificate_verify = 1; + + break; + + case finished: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("Finished received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->options.serverState < + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE) { + WOLFSSL_MSG("Finished received out of order"); + return OUT_OF_ORDER_E; + } + } + #endif + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + WOLFSSL_MSG("Finished received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("Finished received out of order"); + return OUT_OF_ORDER_E; + } + #ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData == process_early_data) { + return OUT_OF_ORDER_E; + } + #endif + } + #endif + if (ssl->msgsReceived.got_finished) { + WOLFSSL_MSG("Duplicate Finished received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_finished = 1; + + break; + + case key_update: + if (!ssl->msgsReceived.got_finished) { + WOLFSSL_MSG("No KeyUpdate before Finished"); + return OUT_OF_ORDER_E; + } + break; + + default: + WOLFSSL_MSG("Unknown message type"); + return SANITY_MSG_E; + } + + return 0; +} + +/* Handle a type of handshake message that has been received. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the buffer of the current message. + * On exit, the index into the buffer of the next message. + * size The length of the current handshake message. + * totalSz Length of remaining data in the message buffer. + * returns 0 on success and otherwise failure. + */ +int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, + byte type, word32 size, word32 totalSz) +{ + int ret = 0; + word32 inIdx = *inOutIdx; + + (void)totalSz; + + WOLFSSL_ENTER("DoTls13HandShakeMsgType"); + + /* make sure we can read the message */ + if (*inOutIdx + size > totalSz) + return INCOMPLETE_DATA; + + /* sanity check msg received */ + if ((ret = SanityCheckTls13MsgReceived(ssl, type)) != 0) { + WOLFSSL_MSG("Sanity Check on handshake message type received failed"); + SendAlert(ssl, alert_fatal, unexpected_message); + return ret; + } + +#ifdef WOLFSSL_CALLBACKS + /* add name later, add on record and handshake header part back on */ + if (ssl->toInfoOn) { + int add = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + AddPacketInfo(ssl, 0, handshake, input + *inOutIdx - add, + size + add, READ_PROTO, ssl->heap); + AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo); + } +#endif + + if (ssl->options.handShakeState == HANDSHAKE_DONE && + type != session_ticket && type != certificate_request && + type != certificate && type != key_update) { + WOLFSSL_MSG("HandShake message after handshake complete"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->options.serverState == NULL_STATE && + type != server_hello && type != hello_retry_request) { + WOLFSSL_MSG("First server message not server hello"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.clientState == NULL_STATE && type != client_hello) { + WOLFSSL_MSG("First client message not client hello"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + /* above checks handshake state */ + switch (type) { +#ifndef NO_WOLFSSL_CLIENT + /* Messages only received by client. */ + #ifdef WOLFSSL_TLS13_DRAFT_18 + case hello_retry_request: + WOLFSSL_MSG("processing hello retry request"); + ret = DoTls13HelloRetryRequest(ssl, input, inOutIdx, size); + break; + #endif + + case server_hello: + WOLFSSL_MSG("processing server hello"); + ret = DoTls13ServerHello(ssl, input, inOutIdx, size, &type); + #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ + ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ + (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) + if (ssl->options.resuming || !IsAtLeastTLSv1_2(ssl) || + IsAtLeastTLSv1_3(ssl->version)) { + ssl->options.cacheMessages = 0; + if (ssl->hsHashes->messages != NULL) { + XFREE(ssl->hsHashes->messages, ssl->heap, DYNAMIC_TYPE_HASHES); + ssl->hsHashes->messages = NULL; + } + } + #endif + break; + + case encrypted_extensions: + WOLFSSL_MSG("processing encrypted extensions"); + ret = DoTls13EncryptedExtensions(ssl, input, inOutIdx, size); + break; + + #ifndef NO_CERTS + case certificate_request: + WOLFSSL_MSG("processing certificate request"); + ret = DoTls13CertificateRequest(ssl, input, inOutIdx, size); + break; + #endif + + case session_ticket: + WOLFSSL_MSG("processing new session ticket"); + ret = DoTls13NewSessionTicket(ssl, input, inOutIdx, size); + break; +#endif /* !NO_WOLFSSL_CLIENT */ + +#ifndef NO_WOLFSSL_SERVER + /* Messages only received by server. */ + case client_hello: + WOLFSSL_MSG("processing client hello"); + ret = DoTls13ClientHello(ssl, input, inOutIdx, size); + break; + + #ifdef WOLFSSL_EARLY_DATA + case end_of_early_data: + WOLFSSL_MSG("processing end of early data"); + ret = DoTls13EndOfEarlyData(ssl, input, inOutIdx, size); + break; + #endif +#endif /* !NO_WOLFSSL_SERVER */ + + /* Messages received by both client and server. */ +#ifndef NO_CERTS + case certificate: + WOLFSSL_MSG("processing certificate"); + ret = DoTls13Certificate(ssl, input, inOutIdx, size); + break; +#endif + +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) + case certificate_verify: + WOLFSSL_MSG("processing certificate verify"); + ret = DoTls13CertificateVerify(ssl, input, inOutIdx, size); + break; +#endif /* !NO_RSA || HAVE_ECC */ + + case finished: + WOLFSSL_MSG("processing finished"); + ret = DoTls13Finished(ssl, input, inOutIdx, size, totalSz, NO_SNIFF); + break; + + case key_update: + WOLFSSL_MSG("processing finished"); + ret = DoTls13KeyUpdate(ssl, input, inOutIdx, size); + break; + + default: + WOLFSSL_MSG("Unknown handshake message type"); + ret = UNKNOWN_HANDSHAKE_TYPE; + break; + } + + /* reset error */ + if (ret == 0 && ssl->error == WC_PENDING_E) + ssl->error = 0; + + if (ret == 0 && type != client_hello && type != session_ticket && + type != key_update) { + ret = HashInput(ssl, input + inIdx, size); + } + if (ret == 0 && ssl->buffers.inputBuffer.dynamicFlag) { + ShrinkInputBuffer(ssl, NO_FORCED_FREE); + } + + if (ret == BUFFER_ERROR || ret == MISSING_HANDSHAKE_DATA) + SendAlert(ssl, alert_fatal, decode_error); + else if (ret == EXT_NOT_ALLOWED || ret == PEER_KEY_ERROR || + ret == ECC_PEERKEY_ERROR || ret == BAD_KEY_SHARE_DATA || + ret == PSK_KEY_ERROR || ret == INVALID_PARAMETER) { + SendAlert(ssl, alert_fatal, illegal_parameter); + } + + if (ret == 0 && ssl->options.tls1_3) { + /* Need to hash input message before deriving secrets. */ + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (type == server_hello) { + if ((ret = DeriveEarlySecret(ssl)) != 0) + return ret; + if ((ret = DeriveHandshakeSecret(ssl)) != 0) + return ret; + + 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; + #else + if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) + return ret; + #endif + } + + if (type == finished) { + if ((ret = DeriveMasterSecret(ssl)) != 0) + return ret; + #ifdef WOLFSSL_EARLY_DATA + if ((ret = DeriveTls13Keys(ssl, traffic_key, + ENCRYPT_AND_DECRYPT_SIDE, + ssl->earlyData == no_early_data)) != 0) { + return ret; + } + #else + if ((ret = DeriveTls13Keys(ssl, traffic_key, + ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) { + return ret; + } + #endif + } + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + if (type == certificate_request && + ssl->options.handShakeState == HANDSHAKE_DONE) { + /* reset handshake states */ + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + ssl->options.connectState = FIRST_REPLY_DONE; + ssl->options.handShakeState = CLIENT_HELLO_COMPLETE; + + if (wolfSSL_connect_TLSv13(ssl) != SSL_SUCCESS) + ret = POST_HAND_AUTH_ERROR; + } + #endif + } + #endif /* NO_WOLFSSL_CLIENT */ + +#ifndef NO_WOLFSSL_SERVER + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + if (ssl->options.side == WOLFSSL_SERVER_END && type == finished) { + ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret); + if (ret != 0) + return ret; + } + #endif +#endif /* NO_WOLFSSL_SERVER */ + } + +#ifdef WOLFSSL_ASYNC_CRYPT + /* if async, offset index so this msg will be processed again */ + if (ret == WC_PENDING_E && *inOutIdx > 0) { + *inOutIdx -= HANDSHAKE_HEADER_SZ; + } +#endif + + WOLFSSL_LEAVE("DoTls13HandShakeMsgType()", ret); + return ret; +} + + +/* Handle a handshake message that has been received. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the buffer of the current message. + * On exit, the index into the buffer of the next message. + * totalSz Length of remaining data in the message buffer. + * returns 0 on success and otherwise failure. + */ +int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + int ret = 0; + word32 inputLength; + + WOLFSSL_ENTER("DoTls13HandShakeMsg()"); + + if (ssl->arrays == NULL) { + byte type; + word32 size; + + if (GetHandshakeHeader(ssl, input, inOutIdx, &type, &size, + totalSz) != 0) { + SendAlert(ssl, alert_fatal, unexpected_message); + return PARSE_ERROR; + } + + return DoTls13HandShakeMsgType(ssl, input, inOutIdx, type, size, + totalSz); + } + + inputLength = ssl->buffers.inputBuffer.length - *inOutIdx - ssl->keys.padSz; + + /* If there is a pending fragmented handshake message, + * pending message size will be non-zero. */ + if (ssl->arrays->pendingMsgSz == 0) { + byte type; + word32 size; + + if (GetHandshakeHeader(ssl,input, inOutIdx, &type, &size, totalSz) != 0) + return PARSE_ERROR; + + /* Cap the maximum size of a handshake message to something reasonable. + * By default is the maximum size of a certificate message assuming + * nine 2048-bit RSA certificates in the chain. */ + if (size > MAX_HANDSHAKE_SZ) { + WOLFSSL_MSG("Handshake message too large"); + return HANDSHAKE_SIZE_ERROR; + } + + /* size is the size of the certificate message payload */ + if (inputLength - HANDSHAKE_HEADER_SZ < size) { + ssl->arrays->pendingMsgType = type; + ssl->arrays->pendingMsgSz = size + HANDSHAKE_HEADER_SZ; + ssl->arrays->pendingMsg = (byte*)XMALLOC(size + HANDSHAKE_HEADER_SZ, + ssl->heap, + DYNAMIC_TYPE_ARRAYS); + if (ssl->arrays->pendingMsg == NULL) + return MEMORY_E; + XMEMCPY(ssl->arrays->pendingMsg, + input + *inOutIdx - HANDSHAKE_HEADER_SZ, + inputLength); + ssl->arrays->pendingMsgOffset = inputLength; + *inOutIdx += inputLength + ssl->keys.padSz - HANDSHAKE_HEADER_SZ; + return 0; + } + + ret = DoTls13HandShakeMsgType(ssl, input, inOutIdx, type, size, + totalSz); + } + else { + if (inputLength + ssl->arrays->pendingMsgOffset > + ssl->arrays->pendingMsgSz) { + inputLength = ssl->arrays->pendingMsgSz - + ssl->arrays->pendingMsgOffset; + } + XMEMCPY(ssl->arrays->pendingMsg + ssl->arrays->pendingMsgOffset, + input + *inOutIdx, inputLength); + ssl->arrays->pendingMsgOffset += inputLength; + *inOutIdx += inputLength + ssl->keys.padSz; + + if (ssl->arrays->pendingMsgOffset == ssl->arrays->pendingMsgSz) + { + word32 idx = 0; + ret = DoTls13HandShakeMsgType(ssl, + ssl->arrays->pendingMsg + HANDSHAKE_HEADER_SZ, + &idx, ssl->arrays->pendingMsgType, + ssl->arrays->pendingMsgSz - HANDSHAKE_HEADER_SZ, + ssl->arrays->pendingMsgSz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + /* setup to process fragment again */ + ssl->arrays->pendingMsgOffset -= inputLength; + *inOutIdx -= inputLength + ssl->keys.padSz; + } + else + #endif + { + XFREE(ssl->arrays->pendingMsg, ssl->heap, DYNAMIC_TYPE_ARRAYS); + ssl->arrays->pendingMsg = NULL; + ssl->arrays->pendingMsgSz = 0; + } + } + } + + WOLFSSL_LEAVE("DoTls13HandShakeMsg()", ret); + return ret; +} + +#ifndef NO_WOLFSSL_CLIENT + +/* The client connecting to the server. + * The protocol version is expecting to be TLS v1.3. + * If the server downgrades, and older versions of the protocol are compiled + * in, the client will fallback to wolfSSL_connect(). + * Please see note at top of README if you get an error from connect. + * + * ssl The SSL/TLS object. + * returns WOLFSSL_SUCCESS on successful handshake, WOLFSSL_FATAL_ERROR when + * unrecoverable error occurs and 0 otherwise. + * For more error information use wolfSSL_get_error(). + */ +int wolfSSL_connect_TLSv13(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_connect_TLSv13()"); + + #ifdef HAVE_ERRNO_H + errno = 0; + #endif + + if (ssl->options.side != WOLFSSL_CLIENT_END) { + WOLFSSL_ERROR(ssl->error = SIDE_ERROR); + return WOLFSSL_FATAL_ERROR; + } + + if (ssl->buffers.outputBuffer.length > 0 + #ifdef WOLFSSL_ASYNC_CRYPT + /* do not send buffered or advance state if last error was an + async pending operation */ + && ssl->error != WC_PENDING_E + #endif + ) { + if ((ssl->error = SendBuffered(ssl)) == 0) { + /* fragOffset is non-zero when sending fragments. On the last + * fragment, fragOffset is zero again, and the state can be + * advanced. */ + if (ssl->fragOffset == 0) { + ssl->options.connectState++; + WOLFSSL_MSG("connect state: " + "Advanced from last buffered fragment send"); + } + else { + WOLFSSL_MSG("connect state: " + "Not advanced, more fragments to send"); + } + } + else { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + switch (ssl->options.connectState) { + + case CONNECT_BEGIN: + /* Always send client hello first. */ + if ((ssl->error = SendTls13ClientHello(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + ssl->options.connectState = CLIENT_HELLO_SENT; + WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT"); + #ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ + defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + #endif + ssl->options.handShakeState = CLIENT_HELLO_COMPLETE; + return WOLFSSL_SUCCESS; + } + #endif + FALL_THROUGH; + + case CLIENT_HELLO_SENT: + /* Get the response/s from the server. */ + while (ssl->options.serverState < + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + if ((ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + ssl->options.connectState = HELLO_AGAIN; + WOLFSSL_MSG("connect state: HELLO_AGAIN"); + FALL_THROUGH; + + case HELLO_AGAIN: + if (ssl->options.certOnly) + return WOLFSSL_SUCCESS; + + if (!ssl->options.tls1_3) { + #ifndef WOLFSSL_NO_TLS12 + if (ssl->options.downgrade) + return wolfSSL_connect(ssl); + #endif + + WOLFSSL_MSG("Client using higher version, fatal error"); + return VERSION_ERROR; + } + + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ + defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + if (!ssl->options.sentChangeCipher) { + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + } + #endif + /* Try again with different security parameters. */ + if ((ssl->error = SendTls13ClientHello(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + ssl->options.connectState = HELLO_AGAIN_REPLY; + WOLFSSL_MSG("connect state: HELLO_AGAIN_REPLY"); + FALL_THROUGH; + + case HELLO_AGAIN_REPLY: + /* Get the response/s from the server. */ + while (ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + if ((ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + ssl->options.connectState = FIRST_REPLY_DONE; + WOLFSSL_MSG("connect state: FIRST_REPLY_DONE"); + FALL_THROUGH; + + case FIRST_REPLY_DONE: + #ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + if ((ssl->error = SendTls13EndOfEarlyData(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_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: + #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ + defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + if (!ssl->options.sentChangeCipher) { + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + } + #endif + + ssl->options.connectState = FIRST_REPLY_SECOND; + WOLFSSL_MSG("connect state: FIRST_REPLY_SECOND"); + FALL_THROUGH; + + case FIRST_REPLY_SECOND: + #ifndef NO_CERTS + if (!ssl->options.resuming && ssl->options.sendVerify) { + ssl->error = SendTls13Certificate(ssl); + if (ssl->error != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: certificate"); + } + #endif + + ssl->options.connectState = FIRST_REPLY_THIRD; + WOLFSSL_MSG("connect state: FIRST_REPLY_THIRD"); + FALL_THROUGH; + + case FIRST_REPLY_THIRD: + #ifndef NO_CERTS + if (!ssl->options.resuming && ssl->options.sendVerify) { + ssl->error = SendTls13CertificateVerify(ssl); + if (ssl->error != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: certificate verify"); + } + #endif + + ssl->options.connectState = FIRST_REPLY_FOURTH; + WOLFSSL_MSG("connect state: FIRST_REPLY_FOURTH"); + FALL_THROUGH; + + case FIRST_REPLY_FOURTH: + if ((ssl->error = SendTls13Finished(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: finished"); + + ssl->options.connectState = FINISHED_DONE; + WOLFSSL_MSG("connect state: FINISHED_DONE"); + FALL_THROUGH; + + case FINISHED_DONE: + #ifndef NO_HANDSHAKE_DONE_CB + if (ssl->hsDoneCb != NULL) { + int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); + if (cbret < 0) { + ssl->error = cbret; + WOLFSSL_MSG("HandShake Done Cb don't continue error"); + return WOLFSSL_FATAL_ERROR; + } + } + #endif /* NO_HANDSHAKE_DONE_CB */ + + if (!ssl->options.keepResources) { + FreeHandshakeResources(ssl); + } + + WOLFSSL_LEAVE("wolfSSL_connect_TLSv13()", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; + + default: + WOLFSSL_MSG("Unknown connect state ERROR"); + return WOLFSSL_FATAL_ERROR; /* unknown connect state */ + } +} +#endif + +#if defined(WOLFSSL_SEND_HRR_COOKIE) +/* Send a cookie with the HelloRetryRequest to avoid storing state. + * + * ssl SSL/TLS object. + * secret Secret to use when generating integrity check for cookie. + * A value of NULL indicates to generate a new random secret. + * secretSz Size of secret data in bytes. + * Use a value of 0 to indicate use of default size. + * returns BAD_FUNC_ARG when ssl is NULL or not using TLS v1.3, SIDE_ERROR when + * called on a client; WOLFSSL_SUCCESS on success and otherwise failure. + */ +int wolfSSL_send_hrr_cookie(WOLFSSL* ssl, const unsigned char* secret, + unsigned int secretSz) +{ + int ret; + + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + + if (secretSz == 0) { + #if !defined(NO_SHA) && defined(NO_SHA256) + secretSz = WC_SHA_DIGEST_SIZE; + #endif /* NO_SHA */ + #ifndef NO_SHA256 + secretSz = WC_SHA256_DIGEST_SIZE; + #endif /* NO_SHA256 */ + } + + if (secretSz != ssl->buffers.tls13CookieSecret.length) { + byte* newSecret; + + if (ssl->buffers.tls13CookieSecret.buffer != NULL) { + ForceZero(ssl->buffers.tls13CookieSecret.buffer, + ssl->buffers.tls13CookieSecret.length); + XFREE(ssl->buffers.tls13CookieSecret.buffer, + ssl->heap, DYNAMIC_TYPE_COOKIE_PWD); + } + + newSecret = (byte*)XMALLOC(secretSz, ssl->heap, + DYNAMIC_TYPE_COOKIE_PWD); + if (newSecret == NULL) { + ssl->buffers.tls13CookieSecret.buffer = NULL; + ssl->buffers.tls13CookieSecret.length = 0; + WOLFSSL_MSG("couldn't allocate new cookie secret"); + return MEMORY_ERROR; + } + ssl->buffers.tls13CookieSecret.buffer = newSecret; + ssl->buffers.tls13CookieSecret.length = secretSz; + } + + /* If the supplied secret is NULL, randomly generate a new secret. */ + if (secret == NULL) { + ret = wc_RNG_GenerateBlock(ssl->rng, + ssl->buffers.tls13CookieSecret.buffer, secretSz); + if (ret < 0) + return ret; + } + else + XMEMCPY(ssl->buffers.tls13CookieSecret.buffer, secret, secretSz); + + ssl->options.sendCookie = 1; + + ret = WOLFSSL_SUCCESS; +#else + (void)secret; + (void)secretSz; + + ret = SIDE_ERROR; +#endif + + return ret; +} +#endif + +/* Create a key share entry from group. + * Generates a key pair. + * + * ssl The SSL/TLS object. + * group The named group. + * returns 0 on success, otherwise failure. + */ +int wolfSSL_UseKeyShare(WOLFSSL* ssl, word16 group) +{ + int ret; + + if (ssl == NULL) + return BAD_FUNC_ARG; + + ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL); + if (ret != 0) + return ret; + + return WOLFSSL_SUCCESS; +} + +/* Send no key share entries - use HelloRetryRequest to negotiate shared group. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +int wolfSSL_NoKeyShares(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) + return BAD_FUNC_ARG; + if (ssl->options.side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ret = TLSX_KeyShare_Empty(ssl); + if (ret != 0) + return ret; + + return WOLFSSL_SUCCESS; +} + +/* Do not send a ticket after TLS v1.3 handshake for resumption. + * + * ctx The SSL/TLS CTX object. + * returns BAD_FUNC_ARG when ctx is NULL and 0 on success. + */ +int wolfSSL_CTX_no_ticket_TLSv13(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL || !IsAtLeastTLSv1_3(ctx->method->version)) + return BAD_FUNC_ARG; + if (ctx->method->side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + +#ifdef HAVE_SESSION_TICKET + ctx->noTicketTls13 = 1; +#endif + + return 0; +} + +/* Do not send a ticket after TLS v1.3 handshake for resumption. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL, not using TLS v1.3, or called on + * a client and 0 on success. + */ +int wolfSSL_no_ticket_TLSv13(WOLFSSL* ssl) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + if (ssl->options.side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + +#ifdef HAVE_SESSION_TICKET + ssl->options.noTicketTls13 = 1; +#endif + + return 0; +} + +/* Disallow (EC)DHE key exchange when using pre-shared keys. + * + * ctx The SSL/TLS CTX object. + * returns BAD_FUNC_ARG when ctx is NULL and 0 on success. + */ +int wolfSSL_CTX_no_dhe_psk(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL || !IsAtLeastTLSv1_3(ctx->method->version)) + return BAD_FUNC_ARG; + + ctx->noPskDheKe = 1; + + return 0; +} + +/* Disallow (EC)DHE key exchange when using pre-shared keys. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3 and 0 on + * success. + */ +int wolfSSL_no_dhe_psk(WOLFSSL* ssl) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + + ssl->options.noPskDheKe = 1; + + return 0; +} + +/* Update the keys for encryption and decryption. + * If using non-blocking I/O and WOLFSSL_ERROR_WANT_WRITE is returned then + * calling wolfSSL_write() will have the message sent when ready. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3, + * WOLFSSL_ERROR_WANT_WRITE when non-blocking I/O is not ready to write, + * WOLFSSL_SUCCESS on success and otherwise failure. + */ +int wolfSSL_update_keys(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + + ret = SendTls13KeyUpdate(ssl); + if (ret == WANT_WRITE) + ret = WOLFSSL_ERROR_WANT_WRITE; + else if (ret == 0) + ret = WOLFSSL_SUCCESS; + return ret; +} + +#if !defined(NO_CERTS) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) +/* Allow post-handshake authentication in TLS v1.3 connections. + * + * ctx The SSL/TLS CTX object. + * returns BAD_FUNC_ARG when ctx is NULL, SIDE_ERROR when not a client and + * 0 on success. + */ +int wolfSSL_CTX_allow_post_handshake_auth(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL || !IsAtLeastTLSv1_3(ctx->method->version)) + return BAD_FUNC_ARG; + if (ctx->method->side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ctx->postHandshakeAuth = 1; + + return 0; +} + +/* Allow post-handshake authentication in TLS v1.3 connection. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3, + * SIDE_ERROR when not a client and 0 on success. + */ +int wolfSSL_allow_post_handshake_auth(WOLFSSL* ssl) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + if (ssl->options.side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ssl->options.postHandshakeAuth = 1; + + return 0; +} + +/* Request a certificate of the client. + * Can be called any time after handshake completion. + * A maximum of 256 requests can be sent on a connection. + * + * ssl SSL/TLS object. + */ +int wolfSSL_request_certificate(WOLFSSL* ssl) +{ + int ret; +#ifndef NO_WOLFSSL_SERVER + CertReqCtx* certReqCtx; +#endif + + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + if (ssl->options.handShakeState != HANDSHAKE_DONE) + return NOT_READY_ERROR; + if (!ssl->options.postHandshakeAuth) + return POST_HAND_AUTH_ERROR; + + certReqCtx = (CertReqCtx*)XMALLOC(sizeof(CertReqCtx), ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (certReqCtx == NULL) + return MEMORY_E; + XMEMSET(certReqCtx, 0, sizeof(CertReqCtx)); + certReqCtx->next = ssl->certReqCtx; + certReqCtx->len = 1; + if (certReqCtx->next != NULL) + certReqCtx->ctx = certReqCtx->next->ctx + 1; + ssl->certReqCtx = certReqCtx; + + ssl->msgsReceived.got_certificate = 0; + ssl->msgsReceived.got_certificate_verify = 0; + ssl->msgsReceived.got_finished = 0; + + ret = SendTls13CertificateRequest(ssl, &certReqCtx->ctx, certReqCtx->len); + if (ret == WANT_WRITE) + ret = WOLFSSL_ERROR_WANT_WRITE; + else if (ret == 0) + ret = WOLFSSL_SUCCESS; +#else + ret = SIDE_ERROR; +#endif + + return ret; +} +#endif /* !NO_CERTS && WOLFSSL_POST_HANDSHAKE_AUTH */ + +#if !defined(WOLFSSL_NO_SERVER_GROUPS_EXT) +/* Get the preferred key exchange group. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL or not using TLS v1.3, + * SIDE_ERROR when not a client, NOT_READY_ERROR when handshake not complete + * and group number on success. + */ +int wolfSSL_preferred_group(WOLFSSL* ssl) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + if (ssl->options.handShakeState != HANDSHAKE_DONE) + return NOT_READY_ERROR; + + /* Return supported groups only. */ + return TLSX_SupportedCurve_Preferred(ssl, 1); +#else + return SIDE_ERROR; +#endif +} +#endif + +/* Sets the key exchange groups in rank order on a context. + * + * ctx SSL/TLS context object. + * groups Array of groups. + * count Number of groups in array. + * returns BAD_FUNC_ARG when ctx or groups is NULL, not using TLS v1.3 or + * count is greater than WOLFSSL_MAX_GROUP_COUNT and WOLFSSL_SUCCESS on success. + */ +int wolfSSL_CTX_set_groups(WOLFSSL_CTX* ctx, int* groups, int count) +{ + int i; + + if (ctx == NULL || groups == NULL || count > WOLFSSL_MAX_GROUP_COUNT) + return BAD_FUNC_ARG; + if (!IsAtLeastTLSv1_3(ctx->method->version)) + return BAD_FUNC_ARG; + + for (i = 0; i < count; i++) + ctx->group[i] = (word16)groups[i]; + ctx->numGroups = (byte)count; + + return WOLFSSL_SUCCESS; +} + +/* Sets the key exchange groups in rank order. + * + * ssl SSL/TLS object. + * groups Array of groups. + * count Number of groups in array. + * returns BAD_FUNC_ARG when ssl or groups is NULL, not using TLS v1.3 or + * count is greater than WOLFSSL_MAX_GROUP_COUNT and WOLFSSL_SUCCESS on success. + */ +int wolfSSL_set_groups(WOLFSSL* ssl, int* groups, int count) +{ + int i; + + if (ssl == NULL || groups == NULL || count > WOLFSSL_MAX_GROUP_COUNT) + return BAD_FUNC_ARG; + if (!IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + + for (i = 0; i < count; i++) + ssl->group[i] = (word16)groups[i]; + ssl->numGroups = (byte)count; + + return WOLFSSL_SUCCESS; +} + +#ifndef NO_PSK +void wolfSSL_CTX_set_psk_client_tls13_callback(WOLFSSL_CTX* ctx, + wc_psk_client_tls13_callback cb) +{ + WOLFSSL_ENTER("SSL_CTX_set_psk_client_tls13_callback"); + + if (ctx == NULL) + return; + + ctx->havePSK = 1; + ctx->client_psk_tls13_cb = cb; +} + + +void wolfSSL_set_psk_client_tls13_callback(WOLFSSL* ssl, + wc_psk_client_tls13_callback cb) +{ + byte haveRSA = 1; + int keySz = 0; + + WOLFSSL_ENTER("SSL_set_psk_client_tls13_callback"); + + if (ssl == NULL) + return; + + ssl->options.havePSK = 1; + ssl->options.client_psk_tls13_cb = cb; + + #ifdef NO_RSA + haveRSA = 0; + #endif + #ifndef NO_CERTS + keySz = ssl->buffers.keySz; + #endif + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, TRUE, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); +} + + +void wolfSSL_CTX_set_psk_server_tls13_callback(WOLFSSL_CTX* ctx, + wc_psk_server_tls13_callback cb) +{ + WOLFSSL_ENTER("SSL_CTX_set_psk_server_tls13_callback"); + if (ctx == NULL) + return; + ctx->havePSK = 1; + ctx->server_psk_tls13_cb = cb; +} + + +void wolfSSL_set_psk_server_tls13_callback(WOLFSSL* ssl, + wc_psk_server_tls13_callback cb) +{ + byte haveRSA = 1; + int keySz = 0; + + WOLFSSL_ENTER("SSL_set_psk_server_tls13_callback"); + if (ssl == NULL) + return; + + ssl->options.havePSK = 1; + ssl->options.server_psk_tls13_cb = cb; + + #ifdef NO_RSA + haveRSA = 0; + #endif + #ifndef NO_CERTS + keySz = ssl->buffers.keySz; + #endif + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, TRUE, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); +} +#endif + + +#ifndef NO_WOLFSSL_SERVER +/* The server accepting a connection from a client. + * The protocol version is expecting to be TLS v1.3. + * If the client downgrades, and older versions of the protocol are compiled + * in, the server will fallback to wolfSSL_accept(). + * Please see note at top of README if you get an error from accept. + * + * ssl The SSL/TLS object. + * returns WOLFSSL_SUCCESS on successful handshake, WOLFSSL_FATAL_ERROR when + * unrecoverable error occurs and 0 otherwise. + * For more error information use wolfSSL_get_error(). + */ +int wolfSSL_accept_TLSv13(WOLFSSL* ssl) +{ + word16 havePSK = 0; + WOLFSSL_ENTER("SSL_accept_TLSv13()"); + +#ifdef HAVE_ERRNO_H + errno = 0; +#endif + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + havePSK = ssl->options.havePSK; +#endif + (void)havePSK; + + if (ssl->options.side != WOLFSSL_SERVER_END) { + WOLFSSL_ERROR(ssl->error = SIDE_ERROR); + return WOLFSSL_FATAL_ERROR; + } + +#ifndef NO_CERTS + /* allow no private key if using PK callbacks and CB is set */ + if (!havePSK) { + if (!ssl->buffers.certificate || + !ssl->buffers.certificate->buffer) { + + WOLFSSL_MSG("accept error: server cert required"); + WOLFSSL_ERROR(ssl->error = NO_PRIVATE_KEY); + return WOLFSSL_FATAL_ERROR; + } + + #ifdef HAVE_PK_CALLBACKS + if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) { + WOLFSSL_MSG("Using PK for server private key"); + } + else + #endif + if (!ssl->buffers.key || !ssl->buffers.key->buffer) { + WOLFSSL_MSG("accept error: server key required"); + WOLFSSL_ERROR(ssl->error = NO_PRIVATE_KEY); + return WOLFSSL_FATAL_ERROR; + } + } +#endif + + if (ssl->buffers.outputBuffer.length > 0 + #ifdef WOLFSSL_ASYNC_CRYPT + /* do not send buffered or advance state if last error was an + async pending operation */ + && ssl->error != WC_PENDING_E + #endif + ) { + if ((ssl->error = SendBuffered(ssl)) == 0) { + /* fragOffset is non-zero when sending fragments. On the last + * fragment, fragOffset is zero again, and the state can be + * advanced. */ + if (ssl->fragOffset == 0) { + ssl->options.acceptState++; + WOLFSSL_MSG("accept state: " + "Advanced from last buffered fragment send"); + } + else { + WOLFSSL_MSG("accept state: " + "Not advanced, more fragments to send"); + } + } + else { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + switch (ssl->options.acceptState) { + +#ifdef HAVE_SECURE_RENEGOTIATION + case TLS13_ACCEPT_BEGIN_RENEG: +#endif + case TLS13_ACCEPT_BEGIN : + /* get client_hello */ + while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + if ((ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + ssl->options.acceptState = TLS13_ACCEPT_CLIENT_HELLO_DONE; + WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE"); + if (!IsAtLeastTLSv1_3(ssl->version)) + return wolfSSL_accept(ssl); + FALL_THROUGH; + + case TLS13_ACCEPT_CLIENT_HELLO_DONE : +#ifdef WOLFSSL_TLS13_DRAFT_18 + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + if ((ssl->error = SendTls13HelloRetryRequest(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + ssl->options.acceptState = TLS13_ACCEPT_FIRST_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE"); + FALL_THROUGH; + + case TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE : +#else + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + if ((ssl->error = SendTls13ServerHello(ssl, + hello_retry_request)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + ssl->options.acceptState = TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE; + WOLFSSL_MSG("accept state ACCEPT_HELLO_RETRY_REQUEST_DONE"); + FALL_THROUGH; + + case TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE : + #ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; + } + #endif + ssl->options.acceptState = TLS13_ACCEPT_FIRST_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE"); + FALL_THROUGH; +#endif + + case TLS13_ACCEPT_FIRST_REPLY_DONE : + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + ssl->options.clientState = CLIENT_HELLO_RETRY; + while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + if ((ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + } + + ssl->options.acceptState = TLS13_ACCEPT_SECOND_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE"); + FALL_THROUGH; + + case TLS13_ACCEPT_SECOND_REPLY_DONE : + if ((ssl->error = SendTls13ServerHello(ssl, server_hello)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.acceptState = TLS13_SERVER_HELLO_SENT; + WOLFSSL_MSG("accept state SERVER_HELLO_SENT"); + FALL_THROUGH; + + case TLS13_SERVER_HELLO_SENT : + #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ + defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + if (!ssl->options.sentChangeCipher) { + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + } + #endif + + ssl->options.acceptState = TLS13_ACCEPT_THIRD_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE"); + FALL_THROUGH; + + case TLS13_ACCEPT_THIRD_REPLY_DONE : + if (!ssl->options.noPskDheKe) { + ssl->error = TLSX_KeyShare_DeriveSecret(ssl); + if (ssl->error != 0) + return WOLFSSL_FATAL_ERROR; + } + + if ((ssl->error = SendTls13EncryptedExtensions(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.acceptState = TLS13_SERVER_EXTENSIONS_SENT; + WOLFSSL_MSG("accept state SERVER_EXTENSIONS_SENT"); + FALL_THROUGH; + + case TLS13_SERVER_EXTENSIONS_SENT : +#ifndef NO_CERTS + if (!ssl->options.resuming) { + if (ssl->options.verifyPeer) { + ssl->error = SendTls13CertificateRequest(ssl, NULL, 0); + if (ssl->error != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + } +#endif + ssl->options.acceptState = TLS13_CERT_REQ_SENT; + WOLFSSL_MSG("accept state CERT_REQ_SENT"); + FALL_THROUGH; + + case TLS13_CERT_REQ_SENT : +#ifndef NO_CERTS + if (!ssl->options.resuming && ssl->options.sendVerify) { + if ((ssl->error = SendTls13Certificate(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } +#endif + ssl->options.acceptState = TLS13_CERT_SENT; + WOLFSSL_MSG("accept state CERT_SENT"); + FALL_THROUGH; + + case TLS13_CERT_SENT : +#ifndef NO_CERTS + if (!ssl->options.resuming && ssl->options.sendVerify) { + if ((ssl->error = SendTls13CertificateVerify(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } +#endif + ssl->options.acceptState = TLS13_CERT_VERIFY_SENT; + WOLFSSL_MSG("accept state CERT_VERIFY_SENT"); + FALL_THROUGH; + + case TLS13_CERT_VERIFY_SENT : + if ((ssl->error = SendTls13Finished(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + ssl->options.acceptState = TLS13_ACCEPT_FINISHED_SENT; + WOLFSSL_MSG("accept state ACCEPT_FINISHED_SENT"); +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + ssl->options.handShakeState = SERVER_FINISHED_COMPLETE; + return WOLFSSL_SUCCESS; + } +#endif + FALL_THROUGH; + + case TLS13_ACCEPT_FINISHED_SENT : +#ifdef HAVE_SESSION_TICKET + #ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED + if (!ssl->options.verifyPeer && !ssl->options.noTicketTls13 && + ssl->ctx->ticketEncCb != NULL) { + if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + #endif +#endif /* HAVE_SESSION_TICKET */ + ssl->options.acceptState = TLS13_PRE_TICKET_SENT; + WOLFSSL_MSG("accept state TICKET_SENT"); + FALL_THROUGH; + + case TLS13_PRE_TICKET_SENT : + while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + ssl->options.acceptState = TLS13_ACCEPT_FINISHED_DONE; + WOLFSSL_MSG("accept state ACCEPT_FINISHED_DONE"); + FALL_THROUGH; + + case TLS13_ACCEPT_FINISHED_DONE : +#ifdef HAVE_SESSION_TICKET + #ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED + if (!ssl->options.verifyPeer) { + } + else + #endif + if (!ssl->options.noTicketTls13 && ssl->ctx->ticketEncCb != NULL) { + if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* HAVE_SESSION_TICKET */ + ssl->options.acceptState = TLS13_TICKET_SENT; + WOLFSSL_MSG("accept state TICKET_SENT"); + FALL_THROUGH; + + case TLS13_TICKET_SENT : +#ifndef NO_HANDSHAKE_DONE_CB + if (ssl->hsDoneCb) { + int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); + if (cbret < 0) { + ssl->error = cbret; + WOLFSSL_MSG("HandShake Done Cb don't continue error"); + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* NO_HANDSHAKE_DONE_CB */ + + if (!ssl->options.keepResources) { + FreeHandshakeResources(ssl); + } + + WOLFSSL_LEAVE("SSL_accept()", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; + + default : + WOLFSSL_MSG("Unknown accept state ERROR"); + return WOLFSSL_FATAL_ERROR; + } +} +#endif + +#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 || !IsAtLeastTLSv1_3(ctx->method->version)) + return BAD_FUNC_ARG; + if (ctx->method->side == WOLFSSL_CLIENT_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_CLIENT_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; sz is negative; + * or not using TLS v1.3. SIDE ERROR when not a server. Otherwise 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 (!IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + + if (ssl->options.handShakeState == NULL_STATE) { + ssl->earlyData = expecting_early_data; + ret = wolfSSL_connect_TLSv13(ssl); + if (ret != WOLFSSL_SUCCESS) + return WOLFSSL_FATAL_ERROR; + } + if (ssl->options.handShakeState == CLIENT_HELLO_COMPLETE) { + ret = SendData(ssl, data, sz); + if (ret > 0) + *outSz = ret; + } +#else + return SIDE_ERROR; +#endif + + WOLFSSL_LEAVE("SSL_write_early_data()", ret); + + if (ret < 0) + ret = WOLFSSL_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; sz is negative; + * or not using TLS v1.3. SIDE ERROR when not a server. Otherwise the number of + * early data bytes read. + */ +int wolfSSL_read_early_data(WOLFSSL* ssl, void* data, int sz, int* outSz) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_read_early_data()"); + + + if (ssl == NULL || data == NULL || sz < 0 || outSz == NULL) + return BAD_FUNC_ARG; + if (!IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + + if (ssl->options.handShakeState == NULL_STATE) { + ssl->earlyData = expecting_early_data; + ret = wolfSSL_accept_TLSv13(ssl); + if (ret <= 0) + return WOLFSSL_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 = WOLFSSL_ERROR_NONE; + } + else + ret = 0; +#else + return SIDE_ERROR; +#endif + + WOLFSSL_LEAVE("wolfSSL_read_early_data()", ret); + + if (ret < 0) + ret = WOLFSSL_FATAL_ERROR; + return ret; +} +#endif + +#ifdef HAVE_SECRET_CALLBACK +int wolfSSL_set_tls13_secret_cb(WOLFSSL* ssl, Tls13SecretCb cb, void* ctx) +{ + WOLFSSL_ENTER("wolfSSL_set_tls13_secret_cb"); + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + ssl->tls13SecretCb = cb; + ssl->tls13SecretCtx = ctx; + + return WOLFSSL_SUCCESS; +} +#endif + +#undef ERROR_OUT + +#endif /* !WOLFCRYPT_ONLY */ + +#endif /* WOLFSSL_TLS13 */ |