Fork of wolfSSL by wolf SSL

Revision:
12:0217a9463bc3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tls13.c	Tue May 30 06:15:48 2017 +0000
@@ -0,0 +1,5428 @@
+/* tls13.c
+ *
+ * Copyright (C) 2006-2016 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
+ */
+
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef WOLFSSL_TLS13
+#if defined(HAVE_SESSION_TICKET)
+#include <sys/time.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#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
+
+#if defined(DEBUG_WOLFSSL) || defined(WOLFSSL_DEBUG) || \
+    defined(CHACHA_AEAD_TEST) || defined(WOLFSSL_SESSION_EXPORT_DEBUG)
+    #if defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX)
+        #if MQX_USE_IO_OLD
+            #include <fio.h>
+        #else
+            #include <nio.h>
+        #endif
+    #else
+        #include <stdio.h>
+    #endif
+#endif
+
+#ifdef __sun
+    #include <sys/filio.h>
+#endif
+
+#ifndef TRUE
+    #define TRUE  1
+#endif
+#ifndef FALSE
+    #define FALSE 0
+#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; }
+
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+/* Return the minimum of the two values.
+ *
+ * a  First value.
+ * b  Second value.
+ * returns the minimum of a and b.
+ */
+static INLINE word32 min(word32 a, word32 b)
+{
+    return a > b ? b : a;
+}
+#endif /* WOLFSSL_HAVE_MIN */
+
+/* Convert 16-bit integer to opaque data.
+ *
+ * u16  Unsigned 16-bit value.
+ * c    The buffer to write to.
+ */
+static INLINE void c16toa(word16 u16, byte* c)
+{
+    c[0] = (u16 >> 8) & 0xff;
+    c[1] =  u16 & 0xff;
+}
+
+/* Convert 32-bit integer to opaque data.
+ *
+ * u32  Unsigned 32-bit value.
+ * c    The buffer to write to.
+ */
+static INLINE void c32toa(word32 u32, byte* c)
+{
+    c[0] = (u32 >> 24) & 0xff;
+    c[1] = (u32 >> 16) & 0xff;
+    c[2] = (u32 >>  8) & 0xff;
+    c[3] =  u32 & 0xff;
+}
+
+
+/* Convert 24-bit opaque data into a 32-bit value.
+ *
+ * u24  The opaque data holding a 24-bit integer.
+ * u32  Unsigned 32-bit value.
+ */
+static INLINE void c24to32(const word24 u24, word32* u32)
+{
+    *u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2];
+}
+
+
+/* Convert opaque data into a 16-bit value.
+ *
+ * c    The opaque data.
+ * u16  Unsigned 16-bit value.
+ */
+static INLINE void ato16(const byte* c, word16* u16)
+{
+    *u16 = (word16) ((c[0] << 8) | (c[1]));
+}
+
+#ifndef NO_WOLFSSL_CLIENT
+#ifdef HAVE_SESSION_TICKET
+/* Convert opaque data into a 32-bit value.
+ *
+ * c    The opaque data.
+ * u32  Unsigned 32-bit value.
+ */
+static INLINE void ato32(const byte* c, word32* u32)
+{
+    *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
+}
+#endif
+#endif
+
+/* 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;
+    int len;
+
+    switch (mac) {
+        #ifndef NO_SHA256
+        case sha256_mac:
+            hash = SHA256;
+            len = SHA256_DIGEST_SIZE;
+            break;
+        #endif
+
+        #ifdef WOLFSSL_SHA384
+        case sha384_mac:
+            hash = SHA384;
+            len = SHA384_DIGEST_SIZE;
+            break;
+        #endif
+
+        #ifdef WOLFSSL_SHA512
+        case sha512_mac:
+            hash = SHA512;
+            len = SHA512_DIGEST_SIZE;
+            break;
+        #endif
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    /* 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.
+ * 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++] = okmLen >> 8;
+    data[idx++] = okmLen;
+    /* Length of protocol | label. */
+    data[idx++] = 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++] = 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;
+}
+
+/* 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, ";
+
+/* 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[MAX_DIGEST_SIZE];
+    Digest      digest;
+    word32      hashSz = 0;
+    const byte* protocol;
+    word32      protocolLen;
+    int         digestAlg;
+
+    switch (hashAlgo) {
+#ifndef NO_WOLFSSL_SHA256
+        case sha256_mac:
+            wc_InitSha256(&digest.sha256);
+            wc_Sha256Update(&digest.sha256, msg, msgLen);
+            wc_Sha256Final(&digest.sha256, hash);
+            wc_Sha256Free(&digest.sha256);
+            hashSz = SHA256_DIGEST_SIZE;
+            digestAlg = SHA256;
+            break;
+#endif
+#ifdef WOLFSSL_SHA384
+        case sha384_mac:
+            wc_InitSha384(&digest.sha384);
+            wc_Sha384Update(&digest.sha384, msg, msgLen);
+            wc_Sha384Final(&digest.sha384, hash);
+            wc_Sha384Free(&digest.sha384);
+            hashSz = SHA384_DIGEST_SIZE;
+            digestAlg = SHA384;
+            break;
+#endif
+#ifdef WOLFSSL_SHA512
+        case sha512_mac:
+            wc_InitSha512(&digest.sha512);
+            wc_Sha512Update(&digest.sha512, msg, msgLen);
+            wc_Sha512Final(&digest.sha512, hash);
+            wc_Sha512Free(&digest.sha512);
+            hashSz = SHA512_DIGEST_SIZE;
+            digestAlg = SHA512;
+            break;
+#endif
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    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);
+}
+
+/* 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[MAX_DIGEST_SIZE];
+    word32      hashSz = 0;
+    word32      hashOutSz = 0;
+    const byte* protocol;
+    word32      protocolLen;
+    int         digestAlg;
+
+    switch (hashAlgo) {
+        #ifndef NO_SHA256
+            case sha256_mac:
+                hashSz    = SHA256_DIGEST_SIZE;
+                digestAlg = SHA256;
+                if (includeMsgs)
+                    ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash);
+            break;
+        #endif
+
+        #ifdef WOLFSSL_SHA384
+            case sha384_mac:
+                hashSz    = SHA384_DIGEST_SIZE;
+                digestAlg = SHA384;
+                if (includeMsgs)
+                    ret = wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash);
+            break;
+        #endif
+
+        #ifdef WOLFSSL_SHA512
+            case sha512_mac:
+                hashSz    = SHA512_DIGEST_SIZE;
+                digestAlg = SHA512;
+                if (includeMsgs)
+                    ret = wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash);
+            break;
+        #endif
+
+        default:
+            ret = BAD_FUNC_ARG;
+            break;
+    }
+    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);
+}
+
+
+#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK)
+/* 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";
+/* 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);
+}
+
+/* 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";
+/* 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
+
+#ifdef TLS13_SUPPORTS_0RTT
+/* 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";
+/* 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)
+{
+    WOLFSSL_MSG("Derive Early Traffic Secret");
+    return DeriveKey(ssl, key, -1, ssl->arrays->secret,
+                     earlyTrafficLabel, EARLY_TRAFFIC_LABEL_SZ,
+                     ssl->specs.mac_algorithm, 1);
+}
+
+    #ifdef TLS13_SUPPORTS_EXPORTERS
+/* 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";
+/* 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)
+{
+    WOLFSSL_MSG("Derive Early Exporter Secret");
+    return DeriveKey(ssl, key, -1, ssl->arrays->secret,
+                     earlyExporterLabel, EARLY_EXPORTER_LABEL_SZ,
+                     ssl->specs.mac_algorithm, 1);
+}
+    #endif
+#endif
+
+/* The length of the client hanshake label. */
+#define CLIENT_HANDSHAKE_LABEL_SZ   31
+/* The client hanshake label. */
+static const byte clientHandshakeLabel[CLIENT_HANDSHAKE_LABEL_SZ + 1] =
+    "client handshake traffic secret";
+/* 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)
+{
+    WOLFSSL_MSG("Derive Client Handshake Secret");
+    return DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret,
+                     clientHandshakeLabel, CLIENT_HANDSHAKE_LABEL_SZ,
+                     ssl->specs.mac_algorithm, 1);
+}
+
+/* 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";
+/* 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)
+{
+    WOLFSSL_MSG("Derive Server Handshake Secret");
+    return DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret,
+                     serverHandshakeLabel, SERVER_HANDSHAKE_LABEL_SZ,
+                     ssl->specs.mac_algorithm, 1);
+}
+
+/* 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";
+/* 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)
+{
+    WOLFSSL_MSG("Derive Client Traffic Secret");
+    return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret,
+                     clientAppLabel, CLIENT_APP_LABEL_SZ,
+                     ssl->specs.mac_algorithm, 1);
+}
+
+/* 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";
+/* 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)
+{
+    WOLFSSL_MSG("Derive Server Traffic Secret");
+    return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret,
+                     serverAppLabel, SERVER_APP_LABEL_SZ,
+                     ssl->specs.mac_algorithm, 1);
+}
+
+#ifdef TLS13_SUPPORTS_EXPORTERS
+/* 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";
+/* 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)
+{
+    WOLFSSL_MSG("Derive Exporter Secret");
+    return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret,
+                     exporterMasterLabel, EXPORTER_MASTER_LABEL_SZ,
+                     ssl->specs.mac_algorithm, 1);
+}
+#endif
+
+#ifndef NO_PSK
+/* 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";
+/* 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);
+}
+
+/* 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";
+/* 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 DeriveKeyMsg(ssl, secret, -1, secret,
+                        appTrafficLabel, APP_TRAFFIC_LABEL_SZ,
+                        NULL, 0, ssl->specs.mac_algorithm);
+}
+
+/* Derive the early secret using HKDF Extract.
+ *
+ * ssl  The SSL/TLS object.
+ */
+static int DeriveEarlySecret(WOLFSSL* ssl)
+{
+    WOLFSSL_MSG("Derive Early Secret");
+#ifndef 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
+}
+
+/* Derive the handshake secret using HKDF Extract.
+ *
+ * ssl  The SSL/TLS object.
+ */
+static int DeriveHandshakeSecret(WOLFSSL* ssl)
+{
+    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);
+}
+
+/* Derive the master secret using HKDF Extract.
+ *
+ * ssl  The SSL/TLS object.
+ */
+static int DeriveMasterSecret(WOLFSSL* ssl)
+{
+    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);
+}
+
+/* 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)
+{
+    Hmac verifyHmac;
+    int  hashType = SHA256;
+    int  hashSz = SHA256_DIGEST_SIZE;
+
+    /* Get the hash of the previous handshake messages. */
+    switch (ssl->specs.mac_algorithm) {
+    #ifndef NO_SHA256
+        case sha256_mac:
+            hashType = SHA256;
+            hashSz = SHA256_DIGEST_SIZE;
+            wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash);
+            break;
+    #endif /* !NO_SHA256 */
+    #ifdef WOLFSSL_SHA384
+        case sha384_mac:
+            hashType = SHA384;
+            hashSz = SHA384_DIGEST_SIZE;
+            wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash);
+            break;
+    #endif /* WOLFSSL_SHA384 */
+    #ifdef WOLFSSL_SHA512
+        case sha512_mac:
+            hashType = SHA512;
+            hashSz = SHA512_DIGEST_SIZE;
+            wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash);
+            break;
+    #endif /* WOLFSSL_SHA512 */
+    }
+
+    /* Calculate the verify data. */
+    wc_HmacSetKey(&verifyHmac, hashType, key, ssl->specs.hash_size);
+    wc_HmacUpdate(&verifyHmac, hash, hashSz);
+    wc_HmacFinal(&verifyHmac, hash);
+
+    return hashSz;
+}
+
+/* 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  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.
+ * returns 0 on success, otherwise failure.
+ */
+static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side)
+{
+    int   ret;
+    int   i = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* key_data;
+#else
+    byte  key_data[MAX_PRF_DIG];
+#endif
+    int   deriveClient = 0;
+    int   deriveServer = 0;
+
+#ifdef WOLFSSL_SMALL_STACK
+    key_data = (byte*)XMALLOC(MAX_PRF_DIG, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (key_data == NULL)
+        return MEMORY_E;
+#endif
+
+    if (side == ENCRYPT_AND_DECRYPT_SIDE) {
+        deriveClient = 1;
+        deriveServer = 1;
+    }
+    else {
+        deriveClient = (ssl->options.side != WOLFSSL_CLIENT_END) ^
+                       (side == ENCRYPT_SIDE_ONLY);
+        deriveServer = !deriveClient;
+    }
+
+    /* Derive the appropriate secret to use in the HKDF. */
+    switch (secret) {
+        case handshake_key:
+            if (deriveClient) {
+                ret = DeriveClientHandshakeSecret(ssl,
+                                                  ssl->arrays->clientSecret);
+                if (ret != 0)
+                    goto end;
+            }
+            if (deriveServer) {
+                ret = DeriveServerHandshakeSecret(ssl,
+                                                  ssl->arrays->serverSecret);
+                if (ret != 0)
+                    goto end;
+            }
+            break;
+
+        case traffic_key:
+            if (deriveClient) {
+                ret = DeriveClientTrafficSecret(ssl, ssl->arrays->clientSecret);
+                if (ret != 0)
+                    goto end;
+            }
+            if (deriveServer) {
+                ret = DeriveServerTrafficSecret(ssl, ssl->arrays->serverSecret);
+                if (ret != 0)
+                    goto end;
+            }
+            break;
+
+        case update_traffic_key:
+            if (deriveClient) {
+                ret = DeriveTrafficSecret(ssl, ssl->arrays->clientSecret);
+                if (ret != 0)
+                    goto end;
+            }
+            if (deriveServer) {
+                ret = DeriveTrafficSecret(ssl, ssl->arrays->serverSecret);
+                if (ret != 0)
+                    goto end;
+            }
+            break;
+    }
+
+    /* Key data = client key | server key | client IV | server IV */
+
+    /* Derive the client key.  */
+    WOLFSSL_MSG("Derive Client Key");
+    ret = DeriveKey(ssl, &key_data[i], ssl->specs.key_size,
+                    ssl->arrays->clientSecret, writeKeyLabel,
+                    WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0);
+    if (ret != 0)
+        goto end;
+    i += ssl->specs.key_size;
+
+    /* Derive the server key.  */
+    WOLFSSL_MSG("Derive Server Key");
+    ret = DeriveKey(ssl, &key_data[i], ssl->specs.key_size,
+                    ssl->arrays->serverSecret, writeKeyLabel,
+                    WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0);
+    if (ret != 0)
+        goto end;
+    i += ssl->specs.key_size;
+
+    /* Derive the client IV.  */
+    WOLFSSL_MSG("Derive Client IV");
+    ret = DeriveKey(ssl, &key_data[i], ssl->specs.iv_size,
+                    ssl->arrays->clientSecret, writeIVLabel, WRITE_IV_LABEL_SZ,
+                    ssl->specs.mac_algorithm, 0);
+    if (ret != 0)
+        goto end;
+    i += ssl->specs.iv_size;
+
+    /* Derive the server IV.  */
+    WOLFSSL_MSG("Derive Server IV");
+    ret = DeriveKey(ssl, &key_data[i], ssl->specs.iv_size,
+                    ssl->arrays->serverSecret, writeIVLabel, WRITE_IV_LABEL_SZ,
+                    ssl->specs.mac_algorithm, 0);
+    if (ret != 0)
+        goto end;
+
+    /* Store keys and IVs but don't activate them. */
+    ret = StoreKeys(ssl, key_data);
+
+end:
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(key_data, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+#if defined(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(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(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)
+    {
+        NET_SECURE_OS_TICK  clk = 0;
+
+        #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+            clk = NetSecure_OS_TimeGet();
+        #endif
+        return (word32)clk * 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 */
+
+
+#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 = 0;
+
+#ifndef NO_OLD_TLS
+#ifndef NO_SHA
+    wc_ShaUpdate(&ssl->hsHashes->hashSha, input, sz);
+#endif
+#ifndef NO_MD5
+    wc_Md5Update(&ssl->hsHashes->hashMd5, input, sz);
+#endif
+#endif
+
+#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_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 hanshake 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;
+    rl->pvMinor = TLSv1_MINOR;
+    c16toa((word16)length, rl->length);
+}
+
+/* Add handshake header to message.
+ *
+ * output      The buffer to write the hanshake 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 fragement 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 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 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];
+}
+
+/* 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.
+ * 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,
+                                    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;
+    /* 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, NULL, 0, output, sz, tag,
+                          POLY1305_AUTH_SZ);
+
+    return ret;
+}
+
+/* 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 data to encrypt.
+ * sz      The number of bytes to encrypt.
+ * returns 0 on success, otherwise failure.
+ */
+static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input,
+                        word16 sz)
+{
+    int    ret    = 0;
+    word16 dataSz = sz - ssl->specs.aead_mac_size;
+    word16 macSz  = ssl->specs.aead_mac_size;
+    byte   nonce[AEAD_NONCE_SZ];
+
+    (void)output;
+    (void)input;
+    (void)sz;
+    (void)dataSz;
+    (void)macSz;
+
+#ifdef WOLFSSL_DEBUG_TLS
+    WOLFSSL_MSG("Data to encrypt");
+    WOLFSSL_BUFFER(input, dataSz);
+#endif
+
+    BuildTls13Nonce(ssl, nonce, ssl->keys.aead_enc_imp_IV, CUR_ORDER);
+
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_AESGCM
+        case wolfssl_aes_gcm:
+            ret = wc_AesGcmEncrypt(ssl->encrypt.aes, output, input, dataSz,
+                nonce, AESGCM_NONCE_SZ, output + dataSz, macSz, NULL, 0);
+            break;
+        #endif
+
+        #ifdef HAVE_AESCCM
+        case wolfssl_aes_ccm:
+            ret = wc_AesCcmEncrypt(ssl->encrypt.aes, output, input, dataSz,
+                nonce, AESCCM_NONCE_SZ, output + dataSz, macSz, NULL, 0);
+            break;
+        #endif
+
+        #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+        case wolfssl_chacha:
+            ret = ChaCha20Poly1305_Encrypt(ssl, output, input, dataSz, nonce,
+                output + dataSz);
+            break;
+        #endif
+
+        default:
+            WOLFSSL_MSG("wolfSSL Encrypt programming error");
+            return ENCRYPT_ERROR;
+    }
+
+    ForceZero(nonce, AEAD_NONCE_SZ);
+
+#ifdef WOLFSSL_DEBUG_TLS
+    WOLFSSL_MSG("Encrypted data");
+    WOLFSSL_BUFFER(output, dataSz);
+    WOLFSSL_MSG("Authentication Tag");
+    WOLFSSL_BUFFER(output + dataSz, macSz);
+#endif
+
+    return ret;
+}
+
+/* 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.
+ * 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* 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;
+
+    /* 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, NULL, 0, (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;
+}
+
+/* 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 encrypt and authentication tag.
+ * sz      The length of the encrypted data plus authentication tag.
+ * returns 0 on success, otherwise failure.
+ */
+int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz)
+{
+    int    ret    = 0;
+    word16 dataSz = sz - ssl->specs.aead_mac_size;
+    word16 macSz  = ssl->specs.aead_mac_size;
+    byte   nonce[AEAD_NONCE_SZ];
+
+    (void)output;
+    (void)input;
+    (void)sz;
+    (void)dataSz;
+    (void)macSz;
+
+#ifdef WOLFSSL_DEBUG_TLS
+    WOLFSSL_MSG("Data to decrypt");
+    WOLFSSL_BUFFER(input, dataSz);
+    WOLFSSL_MSG("Authentication tag");
+    WOLFSSL_BUFFER(input + dataSz, macSz);
+#endif
+
+    BuildTls13Nonce(ssl, nonce, ssl->keys.aead_dec_imp_IV, PEER_ORDER);
+
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_AESGCM
+        case wolfssl_aes_gcm:
+            ret = wc_AesGcmDecrypt(ssl->decrypt.aes, output, input, dataSz,
+                nonce, AESGCM_NONCE_SZ, input + dataSz, macSz, NULL, 0);
+            break;
+        #endif
+
+        #ifdef HAVE_AESCCM
+        case wolfssl_aes_ccm:
+            ret = wc_AesCcmDecrypt(ssl->decrypt.aes, output, input, dataSz,
+                nonce, AESCCM_NONCE_SZ, input + dataSz, macSz, NULL, 0);
+            break;
+        #endif
+
+        #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+        case wolfssl_chacha:
+            ret = ChaCha20Poly1305_Decrypt(ssl, output, input, dataSz, nonce,
+                input + dataSz);
+            break;
+        #endif
+
+        default:
+            WOLFSSL_MSG("wolfSSL Decrypt programming error");
+            return DECRYPT_ERROR;
+    }
+
+    ForceZero(nonce, AEAD_NONCE_SZ);
+    if (ret < 0 && !ssl->options.dtls) {
+        SendAlert(ssl, alert_fatal, bad_record_mac);
+        ret = VERIFY_MAC_ERROR;
+    }
+
+#ifdef WOLFSSL_DEBUG_TLS
+    WOLFSSL_MSG("Decrypted data");
+    WOLFSSL_BUFFER(output, dataSz);
+#endif
+
+    return ret;
+}
+
+/* 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.
+ * 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)
+{
+    word32 sz = RECORD_HEADER_SZ + inSz;
+    word32 idx  = RECORD_HEADER_SZ;
+    word32 headerSz = RECORD_HEADER_SZ;
+    word16 size;
+    int ret        = 0;
+    int atomicUser = 0;
+
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+    if (!sizeOnly && (output == NULL || input == NULL))
+        return BAD_FUNC_ARG;
+    /* catch mistaken sizeOnly parameter */
+    if (sizeOnly && (output || input)) {
+        WOLFSSL_MSG("BuildMessage with sizeOnly doesn't need input or output");
+        return BAD_FUNC_ARG;
+    }
+
+    /* Record layer content type at the end of record data. */
+    sz++;
+    /* Authentication data at the end. */
+    sz += ssl->specs.aead_mac_size;
+
+    if (sizeOnly)
+        return sz;
+
+    if (sz > (word32)outSz) {
+        WOLFSSL_MSG("Oops, want to write past output buffer size");
+        return BUFFER_E;
+    }
+
+    /* Record data length. */
+    size = (word16)(sz - 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, size, application_data, ssl);
+
+    /* TLS v1.3 can do in place encryption. */
+    if (input != output + idx)
+        XMEMCPY(output + idx, input, inSz);
+    idx += inSz;
+
+    if (hashOutput) {
+        ret = HashOutput(ssl, output, headerSz + inSz, 0);
+        if (ret != 0)
+            return ret;
+    }
+
+    /* The real record content type goes at the end of the data. */
+    output[idx++] = type;
+
+#ifdef ATOMIC_USER
+    if (ssl->ctx->MacEncryptCb)
+        atomicUser = 1;
+#endif
+
+    if (atomicUser) {   /* User Record Layer Callback handling */
+#ifdef ATOMIC_USER
+        byte* mac = output + idx;
+        output += headerSz;
+
+        if ((ret = ssl->ctx->MacEncryptCb(ssl, mac, output, inSz, type, 0,
+                output, output, size, ssl->MacEncryptCtx)) != 0) {
+            return ret;
+        }
+#endif
+    }
+    else {
+        output += headerSz;
+        if ((ret = EncryptTls13(ssl, output, output, size)) != 0)
+            return ret;
+    }
+
+    return sz;
+}
+
+#ifndef NO_WOLFSSL_CLIENT
+#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK)
+/* Get the size of the message hash.
+ *
+ * ssl   The SSL/TLS object.
+ * returns the length of the hash.
+ */
+static int GetMsgHashSize(WOLFSSL *ssl)
+{
+    switch (ssl->specs.mac_algorithm) {
+    #ifndef NO_SHA256
+        case sha256_mac:
+            return SHA256_DIGEST_SIZE;
+    #endif /* !NO_SHA256 */
+    #ifdef WOLFSSL_SHA384
+        case sha384_mac:
+            return SHA384_DIGEST_SIZE;
+    #endif /* WOLFSSL_SHA384 */
+    #ifdef WOLFSSL_SHA512
+        case sha512_mac:
+            return SHA512_DIGEST_SIZE;
+    #endif /* WOLFSSL_SHA512 */
+    }
+    return 0;
+}
+
+/* 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[MAX_DIGEST_SIZE];
+    word16        len;
+
+    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. */
+    idx -= TLSX_PreSharedKey_GetSizeBinders(ext->data, client_hello);
+
+    /* Hash truncated ClientHello - up to binders. */
+    ret = HashOutput(ssl, output, idx, 0);
+    if (ret != 0)
+        return ret;
+
+    current = ext->data;
+    /* Calculate the binder for each identity based on previous handshake data.
+     */
+    while (current != NULL) {
+        if (current->resumption) {
+            /* Set the HMAC to use based on the one for the session (set into
+             * the extension data at the start of this function based on the
+             * cipher suite in the session information.
+             */
+            ssl->specs.mac_algorithm = current->hmac;
+
+            /* Resumption PSK is master secret. */
+            ssl->arrays->psk_keySz = GetMsgHashSize(ssl);
+            XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret,
+                    ssl->arrays->psk_keySz);
+            /* Derive the early secret using the PSK. */
+            DeriveEarlySecret(ssl);
+            /* Derive the binder key to use to with HMAC. */
+            DeriveBinderKeyResume(ssl, binderKey);
+        }
+        else {
+            /* TODO: [TLS13] Support non-ticket PSK. */
+            /* Get the pre-shared key. */
+            ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl,
+                    (char *)current->identity, ssl->arrays->client_identity,
+                    MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN);
+            /* Derive the early secret using the PSK. */
+            DeriveEarlySecret(ssl);
+            /* Derive the binder key to use to with HMAC. */
+            DeriveBinderKey(ssl, binderKey);
+        }
+
+        /* Derive the Finished message secret. */
+        DeriveFinishedSecret(ssl, binderKey, ssl->keys.client_write_MAC_secret);
+        /* Build the HMAC of the handshake message data = binder. */
+        current->binderLen = BuildTls13HandshakeHmac(ssl,
+            ssl->keys.client_write_MAC_secret, current->binder);
+
+        current = current->next;
+    }
+
+    /* Data entered into extension, now write to message. */
+    len = TLSX_PreSharedKey_WriteBinders(ext->data, output + idx, client_hello);
+
+    /* Hash binders to complete the hash of the ClientHello. */
+    return HashOutputRaw(ssl, output + idx, len);
+}
+#endif
+
+/* 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;
+    word32 length;
+    word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+    int    sendSz;
+    int    ret;
+
+#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && !defined(NO_PSK)
+    if (ssl->options.resuming &&
+            (ssl->session.version.major != ssl->version.major ||
+             ssl->session.version.minor != ssl->version.minor)) {
+        ssl->version.major = ssl->session.version.major;
+        ssl->version.minor = ssl->session.version.minor;
+        return SendClientHello(ssl);
+    }
+#endif
+
+    if (ssl->suites == NULL) {
+        WOLFSSL_MSG("Bad suites pointer in SendTls13ClientHello");
+        return SUITES_ERROR;
+    }
+
+    /* Version | Random | Session Id | Cipher Suites | Compression | Ext  */
+    length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->suites->suiteSz +
+             SUITE_LEN + COMP_LEN + ENUM_LEN;
+
+    /* Auto populate extensions supported unless user defined. */
+    if ((ret = TLSX_PopulateExtensions(ssl, 0)) != 0)
+        return ret;
+#ifdef HAVE_QSH
+    if (QSH_Init(ssl) != 0)
+        return MEMORY_E;
+#endif
+    /* Include length of TLS extensions. */
+    length += TLSX_GetRequestSize(ssl);
+
+    /* 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. */
+    output[idx++] = SSLv3_MAJOR;
+    output[idx++] = TLSv1_2_MINOR;
+    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;
+
+    /* TLS v1.3 does not use session id - 0 length. */
+    output[idx++] = 0;
+
+    /* 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. */
+    idx += TLSX_WriteRequest(ssl, output + idx);
+
+#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK)
+    /* Resumption has a specific set of extensions and binder is calculated
+     * for each identity.
+     */
+    if (ssl->options.resuming)
+        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("ClientHello", &ssl->handShakeInfo);
+    if (ssl->toInfoOn)
+        AddPacketInfo("ClientHello", &ssl->timeoutInfo, output, sendSz,
+                      ssl->heap);
+#endif
+
+    ssl->buffers.outputBuffer.length += sendSz;
+
+    return SendBuffered(ssl);
+}
+
+/* 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;
+
+#ifdef WOLFSSL_CALLBACKS
+    if (ssl->hsInfoOn) AddPacketName("HelloRetryRequest", &ssl->handShakeInfo);
+    if (ssl->toInfoOn) AddLateName("HelloRetryRequest", &ssl->timeoutInfo);
+#endif
+
+    /* Version info and length field of extension data. */
+    if (totalSz < i - begin + 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)))
+        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;
+
+    return 0;
+}
+
+/* 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)
+{
+    ProtocolVersion pv;
+    word32          i = *inOutIdx;
+    word32          begin = i;
+    int             ret;
+    word16          totalExtSz;
+
+#ifdef WOLFSSL_CALLBACKS
+    if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo);
+    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;
+    ret = CheckVersion(ssl, pv);
+    if (ret != 0)
+        return ret;
+    if (!IsAtLeastTLSv1_3(pv) && pv.major != TLS_DRAFT_MAJOR) {
+        ssl->version = pv;
+        return DoServerHello(ssl, input, inOutIdx, helloSz);
+    }
+
+    /* Random, cipher suite and extensions length check. */
+    if ((i - begin) + RAN_LEN + OPAQUE16_LEN + OPAQUE16_LEN > helloSz)
+        return BUFFER_ERROR;
+
+    /* Server random - keep for debugging. */
+    XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN);
+    i += RAN_LEN;
+    /* TODO: [TLS13] Check last 8 bytes. */
+
+    /* Set the cipher suite from the message. */
+    ssl->options.cipherSuite0 = input[i++];
+    ssl->options.cipherSuite  = input[i++];
+
+    /* Get extension length and length check. */
+    ato16(&input[i], &totalExtSz);
+    i += OPAQUE16_LEN;
+    if ((i - begin) + totalExtSz > helloSz)
+        return BUFFER_ERROR;
+
+    /* Parse and handle extensions. */
+    ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, server_hello, 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;
+        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 */
+
+    ret = SetCipherSpecs(ssl);
+    if (ret != 0)
+        return ret;
+
+#ifndef NO_PSK
+    if (ssl->options.resuming) {
+        PreSharedKey *psk = NULL;
+        TLSX* ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
+        if (ext != NULL)
+            psk = (PreSharedKey*)ext->data;
+        while (psk != NULL && !psk->chosen)
+            psk = psk->next;
+        if (psk == NULL) {
+            ssl->options.resuming = 0;
+            ssl->arrays->psk_keySz = ssl->specs.hash_size;
+            XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz);
+        }
+    }
+#endif
+
+    ssl->keys.encryptionOn = 1;
+
+    return ret;
+}
+
+/* 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;
+
+#ifdef WOLFSSL_CALLBACKS
+    if (ssl->hsInfoOn) AddPacketName("EncryptedExtensions",
+                                     &ssl->handShakeInfo);
+    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;
+
+    return 0;
+}
+
+/* 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;
+
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("CertificateRequest",
+                                         &ssl->handShakeInfo);
+        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;
+
+    /* Request context parsed here. */
+    /* TODO: [TLS13] Request context for post-handshake auth.
+     * Store the value and return it in Certificate message.
+     * Must be unique in the scope of the connection.
+     */
+    *inOutIdx += len;
+
+    /* Signature and hash algorithms. */
+    if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+        return BUFFER_ERROR;
+    ato16(input + *inOutIdx, &len);
+    *inOutIdx += OPAQUE16_LEN;
+    if ((*inOutIdx - begin) + len > size)
+        return BUFFER_ERROR;
+    PickHashSigAlgo(ssl, input + *inOutIdx, len);
+    *inOutIdx += len;
+
+    /* Length of certificate authority data. */
+    if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+        return BUFFER_ERROR;
+    ato16(input + *inOutIdx, &len);
+    *inOutIdx += OPAQUE16_LEN;
+    if ((*inOutIdx - begin) + len > size)
+        return BUFFER_ERROR;
+
+    /* Certificate authorities. */
+    while (len) {
+        word16 dnSz;
+
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &dnSz);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + dnSz > size)
+            return BUFFER_ERROR;
+
+        *inOutIdx += dnSz;
+        len -= OPAQUE16_LEN + dnSz;
+    }
+
+    /* TODO: [TLS13] Add extension handling. */
+    /* 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;
+    /* Skip over extensions for now. */
+    *inOutIdx += len;
+
+    ssl->options.sendVerify = SEND_CERT;
+
+    /* This message is always encrypted so add encryption padding. */
+    *inOutIdx += ssl->keys.padSz;
+
+    return 0;
+}
+
+#endif /* !NO_WOLFSSL_CLIENT */
+
+#ifndef NO_WOLFSSL_SERVER
+#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK)
+/* 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[MAX_DIGEST_SIZE];
+    byte          binder[MAX_DIGEST_SIZE];
+    word16        binderLen;
+    word16        modes;
+
+    ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
+    if (ext == NULL)
+        return 0;
+
+    /* 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.
+     */
+    bindersLen = TLSX_PreSharedKey_GetSizeBinders(ext->data, client_hello);
+
+    /* 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) {
+        /* TODO: [TLS13] Support non-ticket PSK. */
+        /* Decode the identity. */
+        ret = DoClientTicket(ssl, current->identity, current->identityLen);
+        if (ret != WOLFSSL_TICKET_RET_OK)
+            continue;
+
+        if (current->resumption) {
+            /* Check the ticket isn't too old or new. */
+            int diff = TimeNowInMilliseconds() - ssl->session.ticketSeen;
+            diff -= current->ticketAge - ssl->session.ticketAdd;
+            /* TODO: [TLS13] What should the value be? Configurable? */
+            if (diff < -1000 || diff > 1000) {
+                /* Invalid difference, fallback to full handshake. */
+                ssl->options.resuming = 0;
+                break;
+            }
+
+            /* 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;
+            XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret,
+                    ssl->specs.hash_size);
+            /* Derive the early secret using the PSK. */
+            DeriveEarlySecret(ssl);
+            /* Derive the binder key to use to with HMAC. */
+            DeriveBinderKeyResume(ssl, binderKey);
+        }
+        else {
+            /* PSK age is always zero. */
+            if (current->ticketAge != ssl->session.ticketAdd)
+                return PSK_KEY_ERROR;
+
+            /* Get the pre-shared key. */
+            ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl,
+                    (char*)current->identity, ssl->arrays->client_identity,
+                    MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN);
+            /* Derive the early secret using the PSK. */
+            DeriveEarlySecret(ssl);
+            /* Derive the binder key to use to with HMAC. */
+            DeriveBinderKey(ssl, binderKey);
+        }
+
+        /* Derive the Finished message secret. */
+        DeriveFinishedSecret(ssl, binderKey, ssl->keys.client_write_MAC_secret);
+        /* Derive the binder and compare with the one in the extension. */
+        binderLen = BuildTls13HandshakeHmac(ssl,
+                ssl->keys.client_write_MAC_secret, binder);
+        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;
+
+    /* 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 (ext != NULL && (modes & (1 << PSK_DHE_KE)) != 0 &&
+            !ssl->options.noPskDheKe) {
+        /* Only use named group used in last session. */
+        ssl->namedGroup = ssl->session.namedGroup;
+
+        /* Try to establish a new secret. */
+        ret = TLSX_KeyShare_Establish(ssl);
+        if (ret == KEY_SHARE_ERROR)
+            return PSK_KEY_ERROR;
+        else if (ret > 0)
+            ret = 0;
+
+        /* Send new public key to client. */
+        ext->resp = 1;
+    }
+    else if ((modes & (1 << PSK_KE)) != 0) {
+        /* Don't send a key share extension back. */
+        if (ext != NULL)
+            ext->resp = 0;
+    }
+    else
+        return PSK_KEY_ERROR;
+
+    *usingPSK = 1;
+
+    return ret;
+}
+#endif
+
+/* 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.
+ */
+static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
+                              word32 helloSz)
+{
+    int             ret;
+    byte            b;
+    ProtocolVersion pv;
+    Suites          clSuites;
+    word32          i = *inOutIdx;
+    word32          begin = i;
+    word16          totalExtSz;
+    int             usingPSK = 0;
+
+#ifdef WOLFSSL_CALLBACKS
+    if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
+    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 ((ssl->version.major == SSLv3_MAJOR &&
+         ssl->version.minor < TLSv1_3_MINOR) || ssl->options.dtls) {
+        return DoClientHello(ssl, input, inOutIdx, helloSz);
+    }
+
+    /* 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
+
+
+    /* Session id - empty in TLS v1.3 */
+    b = input[i++];
+    if (b != 0) {
+        WOLFSSL_MSG("Client sent session id - not supported");
+        return BUFFER_ERROR;
+    }
+
+    /* 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;
+
+    /* 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;
+    }
+
+    /* TLS v1.3 ClientHello messages will have extensions. */
+    if ((i - begin) >= helloSz) {
+        WOLFSSL_MSG("ClientHello must have extensions in TLS v1.3");
+        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;
+
+#ifdef HAVE_QSH
+    QSH_Init(ssl);
+#endif
+
+    /* 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;
+    }
+
+#ifdef HAVE_STUNNEL
+    if ((ret = SNI_Callback(ssl)) != 0)
+        return ret;
+#endif /*HAVE_STUNNEL*/
+
+    if (TLSX_Find(ssl->extensions, TLSX_SUPPORTED_VERSIONS) == NULL)
+        ssl->version.minor = pv.minor;
+
+#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK)
+    /* Process the Pre-Shared Key extension if present. */
+    ret = DoPreSharedKeys(ssl, input + begin, helloSz, &usingPSK);
+    if (ret != 0)
+        return ret;
+#endif
+
+    if (!usingPSK) {
+        ret = MatchSuite(ssl, &clSuites);
+        if (ret < 0) {
+            WOLFSSL_MSG("Unsupported cipher suite, ClientHello");
+            return ret;
+        }
+
+#ifndef NO_PSK
+        if (ssl->options.resuming) {
+            ssl->options.resuming = 0;
+            XMEMSET(ssl->arrays->psk_key, 0, ssl->specs.hash_size);
+            /* May or may not have done any hashing. */
+            ret = InitHandshakeHashes(ssl);
+            if (ret != 0)
+                return ret;
+        }
+#endif
+
+        ret = HashInput(ssl, input + begin,  helloSz);
+        if (ret != 0)
+            return ret;
+    }
+
+    i += totalExtSz;
+    *inOutIdx = i;
+
+    ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+
+    return 0;
+}
+
+/* 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;
+    word32 len;
+    word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+    int    sendSz;
+
+    /* Get the length of the extensions that will be written. */
+    len = TLSX_GetResponseSize(ssl, hello_retry_request);
+    /* There must be extensions sent to indicate what client needs to do. */
+    if (len == 0)
+        return MISSING_HANDSHAKE_DATA;
+
+    /* Protocol version + Extensions */
+    length = OPAQUE16_LEN + len;
+    sendSz = idx + length;
+
+    /* 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;
+    /* Add record and hanshake headers. */
+    AddTls13Headers(output, length, hello_retry_request, ssl);
+
+    /* TODO: [TLS13] Replace existing code with code in comment.
+     * Use the TLS v1.3 draft version for now.
+     *
+     * Change to:
+     * output[idx++] = ssl->version.major;
+     * output[idx++] = ssl->version.minor;
+     */
+    /* The negotiated protocol version. */
+    output[idx++] = TLS_DRAFT_MAJOR;
+    output[idx++] = TLS_DRAFT_MINOR;
+
+    /* Add TLS extensions. */
+    TLSX_WriteResponse(ssl, output + idx, hello_retry_request);
+    idx += len;
+
+#ifdef WOLFSSL_CALLBACKS
+    if (ssl->hsInfoOn)
+        AddPacketName("HelloRetryRequest", &ssl->handShakeInfo);
+    if (ssl->toInfoOn)
+        AddPacketInfo("HelloRetryRequest", &ssl->timeoutInfo, output, sendSz,
+                      ssl->heap);
+#endif
+
+    ret = HashOutput(ssl, output, idx, 0);
+    if (ret != 0)
+        return ret;
+
+    ssl->buffers.outputBuffer.length += sendSz;
+
+    if (ssl->options.groupMessages)
+        return 0;
+    else
+        return SendBuffered(ssl);
+}
+
+/* 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.
+ */
+int SendTls13ServerHello(WOLFSSL* ssl)
+{
+    byte*  output;
+    word32 length;
+    word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+    int    sendSz;
+    int    ret;
+
+    /* Protocol version, server random, cipher suite and extensions. */
+    length = VERSION_SZ + RAN_LEN + SUITE_LEN +
+             TLSX_GetResponseSize(ssl, server_hello);
+    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);
+
+    /* TODO: [TLS13] Replace existing code with code in comment.
+     * Use the TLS v1.3 draft version for now.
+     *
+     * Change to:
+     * output[idx++] = ssl->version.major;
+     * output[idx++] = ssl->version.minor;
+     */
+    /* The negotiated protocol version. */
+    output[idx++] = TLS_DRAFT_MAJOR;
+    output[idx++] = TLS_DRAFT_MINOR;
+
+    /* TODO: [TLS13] Last 8 bytes have special meaning. */
+    /* Generate server random. */
+    ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN);
+    if (ret != 0)
+        return ret;
+    /* 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
+
+    /* Chosen cipher suite */
+    output[idx++] = ssl->options.cipherSuite0;
+    output[idx++] = ssl->options.cipherSuite;
+
+    /* Extensions */
+    TLSX_WriteResponse(ssl, output + idx, server_hello);
+
+    ssl->buffers.outputBuffer.length += sendSz;
+
+    ret = HashOutput(ssl, output, sendSz, 0);
+    if (ret != 0)
+        return ret;
+
+    #ifdef WOLFSSL_CALLBACKS
+    if (ssl->hsInfoOn)
+        AddPacketName("ServerHello", &ssl->handShakeInfo);
+    if (ssl->toInfoOn)
+        AddPacketInfo("ServerHello", &ssl->timeoutInfo, output, sendSz,
+                      ssl->heap);
+    #endif
+
+    ssl->options.serverState = SERVER_HELLO_COMPLETE;
+
+    if (ssl->options.groupMessages)
+        return 0;
+    else
+        return SendBuffered(ssl);
+}
+
+/* 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.
+ */
+int SendTls13EncryptedExtensions(WOLFSSL *ssl)
+{
+    int    ret;
+    byte*  output;
+    word32 length;
+    word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+    int    sendSz;
+
+    ssl->keys.encryptionOn = 1;
+
+    /* Derive early secret for handshake secret. */
+    if ((ret = DeriveEarlySecret(ssl)) != 0)
+        return ret;
+    /* 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)) != 0)
+        return ret;
+
+    /* Setup encrypt/decrypt keys for following messages. */
+    if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0)
+        return ret;
+
+    length = TLSX_GetResponseSize(ssl, encrypted_extensions);
+    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);
+
+    TLSX_WriteResponse(ssl, output + idx, encrypted_extensions);
+    idx += length;
+
+#ifdef WOLFSSL_CALLBACKS
+    if (ssl->hsInfoOn)
+        AddPacketName("EncryptedExtensions", &ssl->handShakeInfo);
+    if (ssl->toInfoOn)
+        AddPacketInfo("EncryptedExtensions", &ssl->timeoutInfo, output,
+                      sendSz, 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);
+    if (sendSz < 0)
+        return sendSz;
+
+    ssl->buffers.outputBuffer.length += sendSz;
+
+    ssl->options.serverState = SERVER_ENCRYPTED_EXTENSIONS_COMPLETE;
+
+    if (ssl->options.groupMessages)
+        return 0;
+    else
+        return SendBuffered(ssl);
+}
+
+#ifndef NO_CERTS
+/* Send the TLS v1.3 CertificateRequest message.
+ * 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.
+ */
+int SendTls13CertificateRequest(WOLFSSL* ssl)
+{
+    byte   *output;
+    int    ret;
+    int    sendSz;
+    int    reqCtxLen = 0;
+    word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+
+    int  reqSz = OPAQUE8_LEN + reqCtxLen + REQ_HEADER_SZ + REQ_HEADER_SZ;
+
+    reqSz += LENGTH_SZ + ssl->suites->hashSigAlgoSz;
+
+    if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher)
+        return 0;  /* not needed */
+
+    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. */
+    /* TODO: [TLS13] Request context for post-handshake auth.
+     * Must be unique in the scope of the connection.
+     */
+    output[i++] = reqCtxLen;
+
+    /* supported hash/sig */
+    c16toa(ssl->suites->hashSigAlgoSz, &output[i]);
+    i += LENGTH_SZ;
+
+    XMEMCPY(&output[i], ssl->suites->hashSigAlgo, ssl->suites->hashSigAlgoSz);
+    i += ssl->suites->hashSigAlgoSz;
+
+    /* Certificate authorities not supported yet - empty buffer. */
+    c16toa(0, &output[i]);
+    i += REQ_HEADER_SZ;
+
+    /* Certificate extensions. */
+    /* TODO: [TLS13] Add extension handling. */
+    c16toa(0, &output[i]);  /* auth's */
+    i += REQ_HEADER_SZ;
+
+    /* Always encrypted. */
+    sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ,
+                               i - RECORD_HEADER_SZ, handshake, 1, 0);
+    if (sendSz < 0)
+        return sendSz;
+
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("CertificateRequest", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("CertificateRequest", &ssl->timeoutInfo, output,
+                          sendSz, ssl->heap);
+    #endif
+
+    ssl->buffers.outputBuffer.length += sendSz;
+    if (!ssl->options.groupMessages)
+        return SendBuffered(ssl);
+    return 0;
+}
+#endif /* NO_CERTS */
+#endif /* NO_WOLFSSL_SERVER */
+
+#ifndef NO_CERTS
+#if !defined(NO_RSA) || defined(HAVE_ECC)
+/* Encode the signature algorithm into buffer.
+ *
+ * hashalgo  The hash algorithm.
+ * hsType   The signature type.
+ * output    The buffer to encode into.
+ */
+static INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output)
+{
+    switch (hsType) {
+#ifdef HAVE_ECC
+        case DYNAMIC_TYPE_ECC:
+            output[0] = hashAlgo;
+            output[1] = ecc_dsa_sa_algo;
+            break;
+#endif
+#ifndef NO_RSA
+        case DYNAMIC_TYPE_RSA:
+            output[0] = hashAlgo;
+            output[1] = rsa_sa_algo;
+            break;
+#endif
+        /* PSS signatures: 0x080[4-6] */
+        /* ED25519: 0x0807 */
+        /* ED448: 0x0808 */
+    }
+}
+
+/* Decode the signature algorithm.
+ *
+ * input     The encoded signature algorithm.
+ * hashalgo  The hash algorithm.
+ * hsType   The signature type.
+ */
+static INLINE void DecodeSigAlg(byte* input, byte* hashAlgo, byte* hsType)
+{
+    switch (input[0]) {
+        case 0x08:
+           /* PSS signatures: 0x080[4-6] */
+           if (input[1] <= 0x06) {
+               *hsType   = input[0];
+               *hashAlgo = input[1];
+           }
+           break;
+        /* ED25519: 0x0807 */
+        /* ED448: 0x0808 */
+        default:
+            *hashAlgo = input[0];
+            *hsType   = input[1];
+            break;
+    }
+}
+
+/* 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 INLINE int GetMsgHash(WOLFSSL *ssl, byte* hash)
+{
+    switch (ssl->specs.mac_algorithm) {
+    #ifndef NO_SHA256
+        case sha256_mac:
+            wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash);
+            return SHA256_DIGEST_SIZE;
+    #endif /* !NO_SHA256 */
+    #ifdef WOLFSSL_SHA384
+        case sha384_mac:
+            wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash);
+            return SHA384_DIGEST_SIZE;
+    #endif /* WOLFSSL_SHA384 */
+    #ifdef WOLFSSL_SHA512
+        case sha512_mac:
+            wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash);
+            return SHA512_DIGEST_SIZE;
+    #endif /* WOLFSSL_SHA512 */
+    }
+    return 0;
+}
+
+/* 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      + \
+                                    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 void CreateSigData(WOLFSSL* ssl, byte* sigData, word16* sigDataSz,
+                          int check)
+{
+    word16 idx;
+    int side = ssl->options.side;
+
+    /* Signature Data = Prefix | Label | Handshake Hash */
+    XMEMSET(sigData, SIGNING_DATA_PREFIX_BYTE, SIGNING_DATA_PREFIX_SZ);
+    idx = SIGNING_DATA_PREFIX_SZ;
+
+    #ifndef NO_WOLFSSL_SERVER
+    if ((side == WOLFSSL_SERVER_END && check) ||
+        (side == WOLFSSL_CLIENT_END && !check)) {
+        XMEMCPY(&sigData[idx], clientCertVfyLabel, CERT_VFY_LABEL_SZ);
+    }
+    #endif
+    #ifndef NO_WOLFSSL_CLIENT
+    if ((side == WOLFSSL_CLIENT_END && check) ||
+        (side == WOLFSSL_SERVER_END && !check)) {
+        XMEMCPY(&sigData[idx], serverCertVfyLabel, CERT_VFY_LABEL_SZ);
+    }
+    #endif
+    idx += CERT_VFY_LABEL_SZ;
+
+    *sigDataSz = idx + GetMsgHash(ssl, &sigData[idx]);
+}
+
+#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 hashAlgo)
+{
+    Digest digest;
+    int    hashSz = 0;
+    int    hashOid = 0;
+
+    /* Digest the signature data. */
+    switch (hashAlgo) {
+#ifndef NO_WOLFSSL_SHA256
+        case sha256_mac:
+            wc_InitSha256(&digest.sha256);
+            wc_Sha256Update(&digest.sha256, sigData, sigDataSz);
+            wc_Sha256Final(&digest.sha256, sigData);
+            wc_Sha256Free(&digest.sha256);
+            hashSz = SHA256_DIGEST_SIZE;
+            hashOid = SHA256h;
+            break;
+#endif
+#ifdef WOLFSSL_SHA384
+        case sha384_mac:
+            wc_InitSha384(&digest.sha384);
+            wc_Sha384Update(&digest.sha384, sigData, sigDataSz);
+            wc_Sha384Final(&digest.sha384, sigData);
+            wc_Sha384Free(&digest.sha384);
+            hashSz = SHA384_DIGEST_SIZE;
+            hashOid = SHA384h;
+            break;
+#endif
+#ifdef WOLFSSL_SHA512
+        case sha512_mac:
+            wc_InitSha512(&digest.sha512);
+            wc_Sha512Update(&digest.sha512, sigData, sigDataSz);
+            wc_Sha512Final(&digest.sha512, sigData);
+            wc_Sha512Free(&digest.sha512);
+            hashSz = SHA512_DIGEST_SIZE;
+            hashOid = SHA512h;
+            break;
+#endif
+    }
+
+    /* Encode the signature data as per PKCS #1.5 */
+    return wc_EncodeSignature(sig, sigData, hashSz, hashOid);
+}
+
+#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;
+
+    /* Digest the signature data. */
+    switch (hashAlgo) {
+#ifndef NO_WOLFSSL_SHA256
+        case sha256_mac:
+            wc_InitSha256(&digest.sha256);
+            wc_Sha256Update(&digest.sha256, sigData, sigDataSz);
+            wc_Sha256Final(&digest.sha256, sigData);
+            wc_Sha256Free(&digest.sha256);
+            hashSz = SHA256_DIGEST_SIZE;
+            break;
+#endif
+#ifdef WOLFSSL_SHA384
+        case sha384_mac:
+            wc_InitSha384(&digest.sha384);
+            wc_Sha384Update(&digest.sha384, sigData, sigDataSz);
+            wc_Sha384Final(&digest.sha384, sigData);
+            wc_Sha384Free(&digest.sha384);
+            hashSz = SHA384_DIGEST_SIZE;
+            break;
+#endif
+#ifdef WOLFSSL_SHA512
+        case sha512_mac:
+            wc_InitSha512(&digest.sha512);
+            wc_Sha512Update(&digest.sha512, sigData, sigDataSz);
+            wc_Sha512Final(&digest.sha512, sigData);
+            wc_Sha512Free(&digest.sha512);
+            hashSz = SHA512_DIGEST_SIZE;
+            break;
+#endif
+    }
+
+    return hashSz;
+}
+#endif
+
+
+/* Check that the decrypted signature matches the encoded signature
+ * based on the digest of the signature data.
+ *
+ * ssl       The SSL/TLS object.
+ * hashAlgo  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;
+#ifdef WOLFSSL_SMALL_STACK
+    byte*  encodedSig = NULL;
+#else
+    byte   encodedSig[MAX_ENCODED_SIG_SZ];
+#endif
+    word32 sigSz;
+
+    if (sigAlgo == rsa_sa_algo) {
+#ifdef WOLFSSL_SMALL_STACK
+        encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, ssl->heap,
+                                    DYNAMIC_TYPE_TMP_BUFFER);
+        if (encodedSig == NULL) {
+            ret = MEMORY_E;
+            goto end;
+        }
+#endif
+
+        CreateSigData(ssl, sigData, &sigDataSz, 1);
+        sigSz = CreateRSAEncodedSig(encodedSig, sigData, sigDataSz, hashAlgo);
+        /* Check the encoded and decrypted signature data match. */
+        if (decSigSz != sigSz || decSig == NULL ||
+                XMEMCMP(decSig, encodedSig, sigSz) != 0) {
+            ret = VERIFY_CERT_ERROR;
+        }
+    }
+    else {
+        CreateSigData(ssl, sigData, &sigDataSz, 1);
+        sigSz = CreateECCEncodedSig(sigData, sigDataSz, hashAlgo);
+        if (decSigSz != sigSz || decSig == NULL)
+            ret = VERIFY_CERT_ERROR;
+        else {
+            decSig -= 2 * decSigSz;
+            XMEMCPY(decSig, sigData, decSigSz);
+            decSig -= 8;
+            XMEMSET(decSig, 0, 8);
+            CreateECCEncodedSig(decSig, 8 + decSigSz * 2, hashAlgo);
+            if (XMEMCMP(decSig, decSig + 8 + decSigSz * 2, decSigSz) != 0)
+                ret = VERIFY_CERT_ERROR;
+        }
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+end:
+    if (encodedSig != NULL)
+        XFREE(encodedSig, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    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.
+ *
+ * cert    The certificate data to write out.
+ * len     The length of the certificate data.
+ * 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(byte* cert, word32 len, 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 + OPAQUE16_LEN <= fragSz) {
+        /* Empty extension */
+        output[i++] = 0;
+        output[i++] = 0;
+    }
+
+    return i;
+}
+
+/* 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.
+ */
+int SendTls13Certificate(WOLFSSL* ssl)
+{
+    int    ret = 0;
+    word32 certSz, certChainSz, headerSz, listSz, payloadSz;
+    word32 length, maxFragment;
+    word32 len = 0;
+    word32 idx = 0;
+    word32 offset = OPAQUE16_LEN;
+    byte*  p = NULL;
+
+
+    /* TODO: [TLS13] Request context for post-handshake auth.
+     * Taken from request if post-handshake.
+     */
+
+    if (ssl->options.sendVerify == SEND_BLANK_CERT) {
+        certSz = 0;
+        certChainSz = 0;
+        headerSz = CERT_HEADER_SZ;
+        length = CERT_HEADER_SZ;
+        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 List Len | Cert Data Len */
+        headerSz = OPAQUE8_LEN + CERT_HEADER_SZ + CERT_HEADER_SZ;
+        /* Length of message data with one certificate and empty extensions. */
+        length = headerSz + certSz + OPAQUE16_LEN;
+        /* Length of list data with one certificate and empty extensions. */
+        listSz = CERT_HEADER_SZ + certSz + OPAQUE16_LEN;
+
+        /* Send rest of chain if sending cert (chain has leading size/s). */
+        if (certSz > 0 && ssl->buffers.certChainCnt > 0) {
+            /* The pointer to the current spot in the cert chain buffer. */
+            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 = MAX_RECORD_SIZE;
+
+    #ifdef HAVE_MAX_FRAGMENT
+    if (ssl->max_fragment != 0 && maxFragment >= ssl->max_fragment)
+        maxFragment = ssl->max_fragment;
+    #endif /* HAVE_MAX_FRAGMENT */
+
+    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 + OPAQUE16_LEN + certChainSz <=
+                maxFragment - HANDSHAKE_HEADER_SZ) {
+
+                fragSz = headerSz + certSz + OPAQUE16_LEN + 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++] = 0;
+            length -= 1;
+            fragSz -= 1;
+            /* 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);
+
+        /* TODO: [TLS13] Test with fragments and multiple CA certs */
+        if (certSz > 0 && ssl->fragOffset < certSz + OPAQUE16_LEN) {
+            /* Put in the leaf certificate and empty extension. */
+            word32 copySz = AddCertExt(ssl->buffers.certificate->buffer, certSz,
+                                       ssl->fragOffset, fragSz, output + i);
+
+            i += copySz;
+            ssl->fragOffset += copySz;
+            length -= copySz;
+            fragSz -= copySz;
+        }
+        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;
+                    len = NextCert(ssl->buffers.certChain->buffer,
+                                   ssl->buffers.certChain->length, &idx);
+                    if (len == 0)
+                        break;
+                }
+
+                /* Write out certificate and empty extension. */
+                l = AddCertExt(p, 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);
+        if (sendSz < 0)
+            return sendSz;
+
+        #ifdef WOLFSSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("Certificate", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz,
+                               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;
+    }
+
+    return ret;
+}
+
+typedef struct Scv13Args {
+    byte*  output; /* not allocated */
+#ifndef NO_RSA
+    byte*  verifySig;
+#endif
+    byte*  verify; /* not allocated */
+    byte*  input;
+    word32 idx;
+    word32 sigLen;
+    int    sendSz;
+    word16 length;
+
+    byte*  sigData;
+    word16 sigDataSz;
+} Scv13Args;
+
+static void FreeScv13Args(WOLFSSL* ssl, void* pArgs)
+{
+    Scv13Args* args = (Scv13Args*)pArgs;
+
+    (void)ssl;
+
+#ifndef NO_RSA
+    if (args->verifySig) {
+        XFREE(args->verifySig, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        args->verifySig = NULL;
+    }
+#endif
+    if (args->sigData) {
+        XFREE(args->sigData, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        args->sigData = NULL;
+    }
+    if (args->input) {
+        XFREE(args->input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        args->input = NULL;
+    }
+}
+
+/* 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.
+ */
+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_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;
+            /* 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 */
+
+        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];
+
+            ret = DecodePrivateKey(ssl, &args->length);
+            if (ret != 0)
+                goto exit_scv;
+
+            /* Add signature algorithm. */
+            EncodeSigAlg(ssl->suites->hashAlgo, ssl->hsType, args->verify);
+
+            /* Create the data to be signed. */
+            args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap,
+                                                    DYNAMIC_TYPE_TMP_BUFFER);
+            if (args->sigData == NULL) {
+                ERROR_OUT(MEMORY_E, exit_scv);
+            }
+
+            CreateSigData(ssl, args->sigData, &args->sigDataSz, 0);
+
+        #ifndef NO_RSA
+            if (ssl->hsType == DYNAMIC_TYPE_RSA) {
+                /* build encoded signature buffer */
+                sig->length = MAX_ENCODED_SIG_SZ;
+                sig->buffer = (byte*)XMALLOC(sig->length, ssl->heap,
+                                                    DYNAMIC_TYPE_TMP_BUFFER);
+                if (sig->buffer == NULL)
+                    return MEMORY_E;
+
+                /* Digest the signature data and encode. Used in verify too. */
+                sig->length = CreateRSAEncodedSig(sig->buffer, args->sigData,
+                    args->sigDataSz, ssl->suites->hashAlgo);
+                if (ret != 0)
+                    goto exit_scv;
+
+                /* 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;
+                args->sigDataSz = CreateECCEncodedSig(args->sigData,
+                    args->sigDataSz, ssl->suites->hashAlgo);
+            }
+        #endif /* HAVE_ECC */
+
+            /* Advance state and proceed */
+            ssl->options.asyncState = TLS_ASYNC_DO;
+        } /* case TLS_ASYNC_BUILD */
+
+        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,
+                    &sig->length, (ecc_key*)ssl->hsKey,
+            #if defined(HAVE_PK_CALLBACKS)
+                    ssl->buffers.key->buffer, ssl->buffers.key->length,
+                    ssl->EccSignCtx
+            #else
+                    NULL, 0, NULL
+            #endif
+                );
+                args->length = sig->length;
+            }
+        #endif /* HAVE_ECC */
+        #ifndef NO_RSA
+            if (ssl->hsType == DYNAMIC_TYPE_RSA) {
+                /* restore verify pointer */
+                args->verify = &args->output[args->idx];
+
+                ret = RsaSign(ssl, sig->buffer, sig->length,
+                    args->verify + HASH_SIG_SIZE + VERIFY_HEADER, &args->sigLen,
+                    (RsaKey*)ssl->hsKey,
+                    ssl->buffers.key->buffer, ssl->buffers.key->length,
+                #ifdef HAVE_PK_CALLBACKS
+                    ssl->RsaSignCtx
+                #else
+                    NULL
+                #endif
+                );
+                args->length = 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 */
+
+        case TLS_ASYNC_VERIFY:
+        {
+            /* restore verify pointer */
+            args->verify = &args->output[args->idx];
+
+        #ifndef NO_RSA
+            if (ssl->hsType == DYNAMIC_TYPE_RSA) {
+                if (args->verifySig == NULL) {
+                    args->verifySig = (byte*)XMALLOC(args->sigLen, ssl->heap,
+                                                   DYNAMIC_TYPE_TMP_BUFFER);
+                    if (args->verifySig == NULL) {
+                        ERROR_OUT(MEMORY_E, exit_scv);
+                    }
+                    XMEMCPY(args->verifySig,
+                        args->verify + HASH_SIG_SIZE + VERIFY_HEADER,
+                        args->sigLen);
+                }
+
+                /* check for signature faults */
+                ret = VerifyRsaSign(ssl, args->verifySig, args->sigLen,
+                    sig->buffer, sig->length, (RsaKey*)ssl->hsKey);
+            }
+        #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 */
+
+        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;
+
+            /* This message is always encrypted. */
+            args->sendSz = BuildTls13Message(ssl, args->output,
+                                       MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA,
+                                       args->output + RECORD_HEADER_SZ,
+                                       args->sendSz - RECORD_HEADER_SZ, handshake,
+                                       1, 0);
+            if (args->sendSz < 0) {
+                ret = args->sendSz;
+                goto exit_scv;
+            }
+
+            /* Advance state and proceed */
+            ssl->options.asyncState = TLS_ASYNC_END;
+        } /* case TLS_ASYNC_FINALIZE */
+
+        case TLS_ASYNC_END:
+        {
+        #ifdef WOLFSSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("CertificateVerify", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddPacketInfo("CertificateVerify", &ssl->timeoutInfo,
+                              args->output, args->sendSz, 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);
+
+#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;
+}
+
+
+/* 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)
+{
+    return ProcessPeerCerts(ssl, input, inOutIdx, totalSz);
+}
+
+#if !defined(NO_RSA) || defined(HAVE_ECC)
+
+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) {
+        XFREE(args->sigData, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        args->sigData = NULL;
+    }
+
+    (void)ssl;
+}
+
+/* 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_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("CertificateVerify",
+                                             &ssl->handShakeInfo);
+            if (ssl->toInfoOn) AddLateName("CertificateVerify",
+                                           &ssl->timeoutInfo);
+        #endif
+
+            /* Advance state and proceed */
+            ssl->options.asyncState = TLS_ASYNC_BUILD;
+        } /* case TLS_ASYNC_BEGIN */
+
+        case TLS_ASYNC_BUILD:
+        {
+            /* Signature algorithm. */
+            if ((args->idx - args->begin) + ENUM_LEN + ENUM_LEN > totalSz) {
+                ERROR_OUT(BUFFER_ERROR, exit_dcv);
+            }
+            DecodeSigAlg(input + args->idx, &args->hashAlgo, &args->sigAlgo);
+            args->idx += OPAQUE16_LEN;
+            /* TODO: [TLS13] was it in SignatureAlgorithms extension? */
+
+            /* 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. */
+            if (args->sigAlgo == ecc_dsa_sa_algo &&
+                                                   !ssl->peerEccDsaKeyPresent) {
+                WOLFSSL_MSG("Oops, peer sent ECC key but not in verify");
+            }
+            if ((args->sigAlgo == rsa_sa_algo ||
+                 args->sigAlgo == rsa_pss_sa_algo) &&
+                         (ssl->peerRsaKey == NULL || !ssl->peerRsaKeyPresent)) {
+                WOLFSSL_MSG("Oops, peer sent RSA key but not in verify");
+            }
+
+            sig->buffer = XMALLOC(args->sz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            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_TMP_BUFFER);
+                if (args->sigData == NULL) {
+                    ERROR_OUT(MEMORY_E, exit_dcv);
+                }
+
+                CreateSigData(ssl, args->sigData, &args->sigDataSz, 1);
+                args->sigDataSz = CreateECCEncodedSig(args->sigData,
+                    args->sigDataSz, args->hashAlgo);
+            }
+        #endif
+
+            /* Advance state and proceed */
+            ssl->options.asyncState = TLS_ASYNC_DO;
+        } /* case TLS_ASYNC_BUILD */
+
+        case TLS_ASYNC_DO:
+        {
+        #ifndef NO_RSA
+            if (args->sigAlgo ==  rsa_sa_algo ||
+                                             args->sigAlgo == rsa_pss_sa_algo) {
+                WOLFSSL_MSG("Doing RSA peer cert verify");
+
+                ret = RsaVerify(ssl, sig->buffer, sig->length, &args->output,
+                    args->sigAlgo, args->hashAlgo, ssl->peerRsaKey,
+                #ifdef HAVE_PK_CALLBACKS
+                    ssl->buffers.peerRsaKey.buffer,
+                    ssl->buffers.peerRsaKey.length,
+                    ssl->RsaVerifyCtx
+                #else
+                    NULL, 0, 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.buffer,
+                    ssl->buffers.peerEccDsaKey.length,
+                    ssl->EccVerifyCtx
+                #else
+                    NULL, 0, NULL
+                #endif
+                );
+            }
+        #endif /* HAVE_ECC */
+
+            /* Check for error */
+            if (ret != 0) {
+                goto exit_dcv;
+            }
+
+            /* Advance state and proceed */
+            ssl->options.asyncState = TLS_ASYNC_VERIFY;
+        } /* case TLS_ASYNC_DO */
+
+        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;
+            }
+        #endif /* !NO_RSA */
+
+            /* Advance state and proceed */
+            ssl->options.asyncState = TLS_ASYNC_FINALIZE;
+        } /* case TLS_ASYNC_VERIFY */
+
+        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);
+
+#ifdef WOLFSSL_ASYNC_CRYPT
+    /* Handle async operation */
+    if (ret == WC_PENDING_E) {
+        /* Mark message as not recevied so it can process again */
+        ssl->msgsReceived.got_certificate_verify = 0;
+
+        return ret;
+    }
+#endif /* WOLFSSL_ASYNC_CRYPT */
+
+    /* 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[MAX_DIGEST_SIZE];
+
+    /* check against totalSz */
+    if (*inOutIdx + size + ssl->keys.padSz > totalSz)
+        return BUFFER_E;
+
+    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->arrays->clientSecret,
+                                   ssl->keys.client_write_MAC_secret);
+        if (ret != 0)
+            return ret;
+
+        ret = DeriveFinishedSecret(ssl, ssl->arrays->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;
+    finishedSz = BuildTls13HandshakeHmac(ssl, secret, mac);
+    if (size != finishedSz)
+        return BUFFER_ERROR;
+
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
+        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");
+            return VERIFY_FINISHED_ERROR;
+        }
+    }
+
+    /* Force input exhaustion at ProcessReply by consuming padSz. */
+    *inOutIdx += size + ssl->keys.padSz;
+
+    if (ssl->options.side == WOLFSSL_SERVER_END) {
+        /* Setup keys for application data messages from client. */
+        if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0)
+            return ret;
+    }
+
+#ifndef NO_WOLFSSL_SERVER
+    if (ssl->options.side == WOLFSSL_CLIENT_END) {
+        ssl->options.serverState = SERVER_FINISHED_COMPLETE;
+        if (!ssl->options.resuming) {
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+            ssl->options.handShakeDone  = 1;
+        }
+    }
+#endif
+#ifndef NO_WOLFSSL_CLIENT
+    if (ssl->options.side == WOLFSSL_SERVER_END) {
+        ssl->options.clientState = CLIENT_FINISHED_COMPLETE;
+        ssl->options.handShakeState = HANDSHAKE_DONE;
+        ssl->options.handShakeDone  = 1;
+    }
+#endif
+
+    return 0;
+}
+#endif /* NO_CERTS */
+
+/* Send the TLS v1.3 Finished message.
+ *
+ * ssl  The SSL/TLS object.
+ * returns 0 on success, otherwise failure.
+ */
+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;
+
+    outputSz = 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.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->arrays->clientSecret,
+                                   ssl->keys.client_write_MAC_secret);
+        if (ret != 0)
+            return ret;
+
+        ret = DeriveFinishedSecret(ssl, ssl->arrays->serverSecret,
+                                   ssl->keys.server_write_MAC_secret);
+        if (ret != 0)
+            return ret;
+
+        secret = ssl->keys.server_write_MAC_secret;
+    }
+    BuildTls13HandshakeHmac(ssl, secret, &input[headerSz]);
+
+    /* This message is always encrypted. */
+    sendSz = BuildTls13Message(ssl, output, outputSz, input,
+                               headerSz + finishedSz, handshake, 1, 0);
+    if (sendSz < 0)
+        return BUILD_MSG_ERROR;
+
+    if (!ssl->options.resuming) {
+#ifndef NO_SESSION_CACHE
+        AddSession(ssl);    /* just try */
+#endif
+    }
+    else {
+        if (ssl->options.side == WOLFSSL_CLIENT_END) {
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+            ssl->options.handShakeDone  = 1;
+        }
+    }
+
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("Finished", &ssl->timeoutInfo, output, sendSz,
+                          ssl->heap);
+    #endif
+
+    ssl->buffers.outputBuffer.length += sendSz;
+
+    ret = SendBuffered(ssl);
+    if (ret != 0)
+        return ret;
+
+    if (ssl->options.side == WOLFSSL_SERVER_END) {
+        /* Can send application data now. */
+        if ((ret = DeriveMasterSecret(ssl)) != 0)
+            return ret;
+        if ((ret = DeriveTls13Keys(ssl, traffic_key,
+                                   ENCRYPT_AND_DECRYPT_SIDE)) != 0)
+            return ret;
+        if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
+            return ret;
+    }
+
+    if (ssl->options.side == WOLFSSL_CLIENT_END) {
+        /* Setup keys for application data messages. */
+        if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0)
+            return ret;
+
+#ifndef NO_PSK
+        ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret);
+#endif
+    }
+
+    return ret;
+}
+
+/* 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;
+
+    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);
+    if (sendSz < 0)
+        return BUILD_MSG_ERROR;
+
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("KeyUpdate", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("KeyUpdate", &ssl->timeoutInfo, output, sendSz,
+                          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))
+                                                                           != 0)
+        return ret;
+    if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
+        return ret;
+
+    return ret;
+}
+
+/* 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;
+
+    /* check against totalSz */
+    if (OPAQUE8_LEN != totalSz)
+        return BUFFER_E;
+
+    switch (input[i]) {
+        case update_not_requested:
+            /* This message in response to any oustanding 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;
+            break;
+    }
+
+    /* 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)) != 0)
+        return ret;
+    if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0)
+        return ret;
+
+    if (ssl->keys.keyUpdateRespond)
+        return SendTls13KeyUpdate(ssl);
+    return 0;
+}
+
+#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.
+ * retuns 0 on success, otherwise failure.
+ */
+static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input,
+                                   word32* inOutIdx, word32 size)
+{
+#ifdef HAVE_SESSION_TICKET
+    word32  begin = *inOutIdx;
+    word32  lifetime;
+    word32  ageAdd;
+    word16  length;
+
+    /* 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;
+
+    /* 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;
+
+    /* Free old dynamic ticket if we already had one. */
+    if (ssl->session.isDynamic) {
+        XFREE(ssl->session.ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK);
+        /* Reset back to static by default. */
+        ssl->session.ticket = NULL;
+        ssl->session.isDynamic = 0;
+        ssl->session.ticket = ssl->session.staticTicket;
+    }
+    /* Use dynamic ticket if required.*/
+    if (length > sizeof(ssl->session.staticTicket)) {
+        ssl->session.ticket = (byte*)XMALLOC(length, ssl->heap,
+                                             DYNAMIC_TYPE_SESSION_TICK);
+        if (ssl->session.ticket == NULL)
+            return MEMORY_E;
+        ssl->session.isDynamic = 1;
+    }
+
+    /* Copy in ticket data (server identity). */
+    XMEMCPY(ssl->session.ticket, input + *inOutIdx, length);
+    *inOutIdx += length;
+    ssl->timeout = lifetime;
+    ssl->session.ticketLen = length;
+    ssl->session.timeout = lifetime;
+    ssl->session.ticketAdd = ageAdd;
+    ssl->session.ticketSeen = TimeNowInMilliseconds();
+    if (ssl->session_ticket_cb != NULL) {
+        ssl->session_ticket_cb(ssl, ssl->session.ticket,
+                               ssl->session.ticketLen,
+                               ssl->session_ticket_ctx);
+    }
+    ssl->options.haveSessionId = 1;
+    XMEMCPY(ssl->arrays->sessionID, ssl->session.ticket + length - ID_LEN,
+            ID_LEN);
+    ssl->session.cipherSuite0 = ssl->options.cipherSuite0;
+    ssl->session.cipherSuite = ssl->options.cipherSuite;
+    #ifndef NO_SESSION_CACHE
+    AddSession(ssl);
+    #endif
+
+    /* No extension support - skip over extensions. */
+    if ((*inOutIdx - begin) + EXTS_SZ > size)
+        return BUFFER_ERROR;
+    ato16(input + *inOutIdx, &length);
+    *inOutIdx += EXTS_SZ;
+    if ((*inOutIdx - begin) + length != size)
+        return BUFFER_ERROR;
+    *inOutIdx += length;
+
+    /* Always encrypted. */
+    *inOutIdx += ssl->keys.padSz;
+
+    ssl->expect_session_ticket = 0;
+#else
+    (void)ssl;
+    (void)input;
+    *inOutIdx += size + ssl->keys.padSz;
+#endif /* HAVE_SESSION_TICKET */
+
+    return 0;
+}
+#endif /* NO_WOLFSSL_CLIENT */
+
+#ifndef NO_WOLFSSL_SERVER
+    #ifdef HAVE_SESSION_TICKET
+/* Send New Session Ticket handshake message.
+ * Message contains the information required to perform resumption.
+ *
+ * ssl  The SSL/TLS object.
+ * retuns 0 on success, otherwise failure.
+ */
+int SendTls13NewSessionTicket(WOLFSSL* ssl)
+{
+    byte*  output;
+    int    ret;
+    int    sendSz;
+    word32 length;
+    word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+
+    if (!ssl->options.noTicketTls13) {
+        ret = CreateTicket(ssl);
+        if (ret != 0) return ret;
+    }
+
+    /* Lifetime | Age Add | Ticket | Extensions */
+    length = SESSION_HINT_SZ + SESSION_ADD_SZ + LENGTH_SZ +
+             ssl->session.ticketLen + EXTS_SZ;
+    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;
+
+    /* length */
+    c16toa(ssl->session.ticketLen, output + idx);
+    idx += LENGTH_SZ;
+    /* ticket */
+    XMEMCPY(output + idx, ssl->session.ticket, ssl->session.ticketLen);
+    idx += ssl->session.ticketLen;
+
+    /* No extension support - empty extensions. */
+    c16toa(0, output + idx);
+    idx += EXTS_SZ;
+
+    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);
+    if (sendSz < 0)
+        return sendSz;
+
+    ssl->buffers.outputBuffer.length += sendSz;
+
+    return SendBuffered(ssl);
+}
+    #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:
+            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:
+            if (ssl->msgsReceived.got_server_hello) {
+                WOLFSSL_MSG("Duplicate ServerHello received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_server_hello = 1;
+
+            break;
+#endif
+
+#ifndef NO_WOLFSSL_CLIENT
+        case session_ticket:
+            if (ssl->msgsReceived.got_session_ticket) {
+                WOLFSSL_MSG("Duplicate SessionTicket received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_session_ticket = 1;
+
+            break;
+#endif
+
+#ifndef NO_WOLFSSL_CLIENT
+        case hello_retry_request:
+            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
+
+#ifndef NO_WOLFSSL_CLIENT
+        case encrypted_extensions:
+            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:
+            if (ssl->msgsReceived.got_certificate) {
+                WOLFSSL_MSG("Duplicate Certificate received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_certificate = 1;
+
+#ifndef NO_WOLFSSL_CLIENT
+            if (ssl->options.side == WOLFSSL_CLIENT_END) {
+                if ( ssl->msgsReceived.got_server_hello == 0) {
+                    WOLFSSL_MSG("No ServerHello before Cert");
+                    return OUT_OF_ORDER_E;
+                }
+            }
+#endif
+#ifndef NO_WOLFSSL_SERVER
+            if (ssl->options.side == WOLFSSL_SERVER_END) {
+                if ( ssl->msgsReceived.got_client_hello == 0) {
+                    WOLFSSL_MSG("No ClientHello before Cert");
+                    return OUT_OF_ORDER_E;
+                }
+            }
+#endif
+            break;
+
+#ifndef NO_WOLFSSL_CLIENT
+        case certificate_request:
+            if (ssl->msgsReceived.got_certificate_request) {
+                WOLFSSL_MSG("Duplicate CertificateRequest received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_certificate_request = 1;
+
+            break;
+#endif
+
+        case certificate_verify:
+            if (ssl->msgsReceived.got_certificate_verify) {
+                WOLFSSL_MSG("Duplicate CertificateVerify received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_certificate_verify = 1;
+
+            if (ssl->msgsReceived.got_certificate == 0) {
+                WOLFSSL_MSG("No Cert before CertVerify");
+                return OUT_OF_ORDER_E;
+            }
+            break;
+
+        case finished:
+            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;
+    (void)totalSz;
+    word32 inIdx = *inOutIdx;
+
+    WOLFSSL_ENTER("DoTls13HandShakeMsgType");
+
+    /* make sure 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");
+        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(0, &ssl->timeoutInfo, input + *inOutIdx - add,
+                      size + add, ssl->heap);
+        AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo);
+    }
+#endif
+
+    if (ssl->options.handShakeState == HANDSHAKE_DONE &&
+            type != session_ticket && type != certificate_request &&
+            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.dtls &&
+               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_CLIENT_END && ssl->options.dtls &&
+            type == server_hello_done &&
+            ssl->options.serverState < SERVER_HELLO_COMPLETE) {
+        WOLFSSL_MSG("Server hello done received before server hello in DTLS");
+        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
+    case hello_retry_request:
+        WOLFSSL_MSG("processing hello rety request");
+        ret = DoTls13HelloRetryRequest(ssl, input, inOutIdx, size);
+        break;
+
+    case server_hello:
+        WOLFSSL_MSG("processing server hello");
+        ret = DoTls13ServerHello(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;
+
+    case encrypted_extensions:
+        WOLFSSL_MSG("processing encrypted extensions");
+        ret = DoTls13EncryptedExtensions(ssl, input, inOutIdx, size);
+        break;
+#endif /* !NO_WOLFSSL_CLIENT */
+
+#ifndef NO_CERTS
+    case certificate:
+        WOLFSSL_MSG("processing certificate");
+        ret = DoTls13Certificate(ssl, input, inOutIdx, size);
+        break;
+#endif
+
+#if !defined(NO_RSA) || defined(HAVE_ECC)
+    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;
+
+#ifndef NO_WOLFSSL_SERVER
+    case client_hello:
+        WOLFSSL_MSG("processing client hello");
+        ret = DoTls13ClientHello(ssl, input, inOutIdx, size);
+        break;
+#endif /* !NO_WOLFSSL_SERVER */
+
+    default:
+        WOLFSSL_MSG("Unknown handshake message type");
+        ret = UNKNOWN_HANDSHAKE_TYPE;
+        break;
+    }
+
+    if (ret == 0 && type != client_hello && type != session_ticket &&
+        type != key_update && ssl->error != WC_PENDING_E) {
+        ret = HashInput(ssl, input + inIdx, size);
+    }
+
+    if (ret == BUFFER_ERROR || ret == MISSING_HANDSHAKE_DATA)
+        SendAlert(ssl, alert_fatal, decode_error);
+
+    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 (ssl->options.tls1_3) {
+        if (type == server_hello && ssl->options.side == WOLFSSL_CLIENT_END) {
+            if ((ret = DeriveEarlySecret(ssl)) != 0)
+                return ret;
+            if ((ret = DeriveHandshakeSecret(ssl)) != 0)
+                return ret;
+            if ((ret = DeriveTls13Keys(ssl, handshake_key,
+                                       ENCRYPT_AND_DECRYPT_SIDE)) != 0)
+                return ret;
+
+            /* setup decrypt keys for following messages */
+            if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0)
+                return ret;
+            if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
+                return ret;
+        }
+
+        if (type == finished && ssl->options.side == WOLFSSL_CLIENT_END) {
+            if ((ret = DeriveMasterSecret(ssl)) != 0)
+                return ret;
+            if ((ret = DeriveTls13Keys(ssl, traffic_key,
+                                       ENCRYPT_AND_DECRYPT_SIDE)) != 0)
+                return ret;
+        }
+
+#ifndef NO_PSK
+        if (type == finished && ssl->options.side == WOLFSSL_SERVER_END)
+            DeriveResumptionSecret(ssl, ssl->session.masterSecret);
+#endif
+    }
+
+#ifdef WOLFSSL_ASYNC_CRYPT
+    /* if async, offset index so this msg will be processed again */
+    if (ret == WC_PENDING_E) {
+        *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)
+            return PARSE_ERROR;
+
+        return DoTls13HandShakeMsgType(ssl, input, inOutIdx, type, size,
+                                       totalSz);
+    }
+
+    inputLength = ssl->buffers.inputBuffer.length - *inOutIdx;
+
+    /* 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 - HANDSHAKE_HEADER_SZ;
+            return 0;
+        }
+
+        ret = DoTls13HandShakeMsgType(ssl, input, inOutIdx, type, size,
+                                      totalSz);
+    }
+    else {
+        if (inputLength + ssl->arrays->pendingMsgOffset >
+                ssl->arrays->pendingMsgSz) {
+            return BUFFER_ERROR;
+        }
+
+        XMEMCPY(ssl->arrays->pendingMsg + ssl->arrays->pendingMsgOffset,
+                input + *inOutIdx, inputLength);
+        ssl->arrays->pendingMsgOffset += inputLength;
+        *inOutIdx += inputLength;
+
+        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);
+            XFREE(ssl->arrays->pendingMsg, ssl->heap, DYNAMIC_TYPE_ARRAYS);
+            ssl->arrays->pendingMsg = NULL;
+            ssl->arrays->pendingMsgSz = 0;
+        }
+    }
+
+    WOLFSSL_LEAVE("DoTls13HandShakeMsg()", ret);
+    return ret;
+}
+
+/* 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 SSL_SUCCESS on successful handshake, SSL_FATAL_ERROR when
+ * unrecoverable error occurs and 0 otherwise.
+ * For more error information use wolfSSL_get_error().
+ */
+int wolfSSL_connect_TLSv13(WOLFSSL* ssl)
+{
+    int neededState;
+
+    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 SSL_FATAL_ERROR;
+    }
+
+    if (ssl->buffers.outputBuffer.length > 0) {
+        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 SSL_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 SSL_FATAL_ERROR;
+            }
+
+            ssl->options.connectState = CLIENT_HELLO_SENT;
+            WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT");
+
+        case CLIENT_HELLO_SENT:
+            neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE :
+                                                  SERVER_HELLODONE_COMPLETE;
+            /* Get the response/s from the server. */
+            while (ssl->options.serverState < neededState) {
+                if ((ssl->error = ProcessReply(ssl)) < 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+                /* if resumption failed, reset needed state. */
+                if (neededState == SERVER_FINISHED_COMPLETE &&
+                        !ssl->options.resuming) {
+                    neededState = SERVER_HELLODONE_COMPLETE;
+                }
+            }
+
+            ssl->options.connectState = HELLO_AGAIN;
+            WOLFSSL_MSG("connect state: HELLO_AGAIN");
+        case HELLO_AGAIN:
+            if (ssl->options.certOnly)
+                return SSL_SUCCESS;
+
+            if (!ssl->options.tls1_3)
+                return wolfSSL_connect(ssl);
+
+            if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) {
+                ssl->options.serverState = NULL_STATE;
+                /* Try again with different security parameters. */
+                if ((ssl->error = SendTls13ClientHello(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            }
+
+            ssl->options.connectState = HELLO_AGAIN_REPLY;
+            WOLFSSL_MSG("connect state: HELLO_AGAIN_REPLY");
+
+        case HELLO_AGAIN_REPLY:
+            if (ssl->options.serverState == NULL_STATE) {
+                neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE :
+                                                      SERVER_HELLODONE_COMPLETE;
+
+                /* Get the response/s from the server. */
+                while (ssl->options.serverState < neededState) {
+                    if ((ssl->error = ProcessReply(ssl)) < 0) {
+                            WOLFSSL_ERROR(ssl->error);
+                            return SSL_FATAL_ERROR;
+                    }
+                    /* if resumption failed, reset needed state */
+                    else if (neededState == SERVER_FINISHED_COMPLETE) {
+                        if (!ssl->options.resuming)
+                            neededState = SERVER_HELLODONE_COMPLETE;
+                    }
+                }
+            }
+
+            ssl->options.connectState = FIRST_REPLY_DONE;
+            WOLFSSL_MSG("connect state: FIRST_REPLY_DONE");
+
+        case FIRST_REPLY_DONE:
+            #ifndef NO_CERTS
+            if (!ssl->options.resuming && ssl->options.sendVerify) {
+                ssl->error = SendTls13Certificate(ssl);
+                if (ssl->error != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+                WOLFSSL_MSG("sent: certificate");
+            }
+            #endif
+
+            ssl->options.connectState = FIRST_REPLY_FIRST;
+            WOLFSSL_MSG("connect state: FIRST_REPLY_FIRST");
+
+        case FIRST_REPLY_FIRST:
+            #ifndef NO_CERTS
+            if (!ssl->options.resuming && ssl->options.sendVerify) {
+                ssl->error = SendTls13CertificateVerify(ssl);
+                if (ssl->error != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+                WOLFSSL_MSG("sent: certificate verify");
+            }
+            #endif
+
+            ssl->options.connectState = FIRST_REPLY_SECOND;
+            WOLFSSL_MSG("connect state: FIRST_REPLY_SECOND");
+
+        case FIRST_REPLY_SECOND:
+            if ((ssl->error = SendTls13Finished(ssl)) != 0) {
+                WOLFSSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            WOLFSSL_MSG("sent: finished");
+
+            ssl->options.connectState = FINISHED_DONE;
+            WOLFSSL_MSG("connect state: FINISHED_DONE");
+
+        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 SSL_FATAL_ERROR;
+                }
+            }
+#endif /* NO_HANDSHAKE_DONE_CB */
+
+            WOLFSSL_LEAVE("SSL_connect()", SSL_SUCCESS);
+            return SSL_SUCCESS;
+
+        default:
+            WOLFSSL_MSG("Unknown connect state ERROR");
+            return SSL_FATAL_ERROR; /* unknown connect state */
+    }
+}
+
+/* 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 = BAD_FUNC_ARG;
+
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL);
+    if (ret != 0)
+        return ret;
+
+    return SSL_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 = BAD_FUNC_ARG;
+
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    ret = TLSX_KeyShare_Empty(ssl);
+    if (ret != 0)
+        return ret;
+
+    return SSL_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)
+        return BAD_FUNC_ARG;
+
+#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) ||
+            ssl->options.side == WOLFSSL_CLIENT_END)
+        return BAD_FUNC_ARG;
+
+#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)
+        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 SSL_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,
+ * SSL_ERROR_WANT_WRITE when non-blocking I/O is not ready to write,
+ * SSL_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 = SSL_ERROR_WANT_WRITE;
+    else if (ret == 0)
+        ret = SSL_SUCCESS;
+    return ret;
+}
+
+/* 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 SSL_SUCCESS on successful handshake, SSL_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;
+    word16 haveAnon = 0;
+    WOLFSSL_ENTER("SSL_accept_TLSv13()");
+
+#ifdef HAVE_ERRNO_H
+    errno = 0;
+#endif
+
+#ifndef NO_PSK
+    havePSK = ssl->options.havePSK;
+#endif
+    (void)havePSK;
+
+#ifdef HAVE_ANON
+    haveAnon = ssl->options.haveAnon;
+#endif
+    (void)haveAnon;
+
+    if (ssl->options.side != WOLFSSL_SERVER_END) {
+        WOLFSSL_ERROR(ssl->error = SIDE_ERROR);
+        return SSL_FATAL_ERROR;
+    }
+
+#ifndef NO_CERTS
+    /* in case used set_accept_state after init */
+    if (!havePSK && !haveAnon &&
+        (!ssl->buffers.certificate ||
+         !ssl->buffers.certificate->buffer ||
+         !ssl->buffers.key ||
+         !ssl->buffers.key->buffer)) {
+        WOLFSSL_MSG("accept error: don't have server cert and key");
+        ssl->error = NO_PRIVATE_KEY;
+        WOLFSSL_ERROR(ssl->error);
+        return SSL_FATAL_ERROR;
+    }
+#endif
+#ifdef WOLFSSL_DTLS
+    if (ssl->version.major == DTLS_MAJOR) {
+        ssl->options.dtls   = 1;
+        ssl->options.tls    = 1;
+        ssl->options.tls1_1 = 1;
+    }
+#endif
+
+    if (ssl->buffers.outputBuffer.length > 0) {
+        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 SSL_FATAL_ERROR;
+        }
+    }
+
+    switch (ssl->options.acceptState) {
+
+        case ACCEPT_BEGIN :
+            /* get response */
+            while (ssl->options.clientState < CLIENT_HELLO_COMPLETE)
+                if ((ssl->error = ProcessReply(ssl)) < 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+
+            ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE");
+
+        case ACCEPT_CLIENT_HELLO_DONE :
+            if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) {
+                if ((ssl->error = SendTls13HelloRetryRequest(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            }
+            ssl->options.acceptState = ACCEPT_HELLO_RETRY_REQUEST_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_HELLO_RETRY_REQUEST_DONE");
+
+        case ACCEPT_HELLO_RETRY_REQUEST_DONE :
+            if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) {
+                if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            }
+            ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE");
+
+        case ACCEPT_FIRST_REPLY_DONE :
+            if ((ssl->error = SendTls13ServerHello(ssl)) != 0) {
+                WOLFSSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.acceptState = SERVER_HELLO_SENT;
+            WOLFSSL_MSG("accept state SERVER_HELLO_SENT");
+
+        case SERVER_HELLO_SENT :
+            if ((ssl->error = SendTls13EncryptedExtensions(ssl)) != 0) {
+                WOLFSSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.acceptState = SERVER_EXTENSIONS_SENT;
+            WOLFSSL_MSG("accept state SERVER_EXTENSIONS_SENT");
+        case SERVER_EXTENSIONS_SENT :
+#ifndef NO_CERTS
+            if (!ssl->options.resuming)
+                if (ssl->options.verifyPeer)
+                    ssl->error = SendTls13CertificateRequest(ssl);
+                    if (ssl->error != 0) {
+                        WOLFSSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+#endif
+            ssl->options.acceptState = CERT_REQ_SENT;
+            WOLFSSL_MSG("accept state CERT_REQ_SENT");
+
+        case CERT_REQ_SENT :
+            ssl->options.acceptState = KEY_EXCHANGE_SENT;
+#ifndef NO_CERTS
+            if (!ssl->options.resuming) {
+                if ((ssl->error = SendTls13Certificate(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            }
+#endif
+            ssl->options.acceptState = CERT_SENT;
+            WOLFSSL_MSG("accept state CERT_SENT");
+
+        case CERT_SENT :
+#ifndef NO_CERTS
+            if (!ssl->options.resuming) {
+                if ((ssl->error = SendTls13CertificateVerify(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            }
+#endif
+            ssl->options.acceptState = CERT_STATUS_SENT;
+            WOLFSSL_MSG("accept state CERT_STATUS_SENT");
+
+        case CERT_VERIFY_SENT :
+            if ((ssl->error = SendTls13Finished(ssl)) != 0) {
+                WOLFSSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+
+            ssl->options.acceptState = ACCEPT_FINISHED_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_FINISHED_DONE");
+
+        case ACCEPT_FINISHED_DONE :
+#ifdef HAVE_SESSION_TICKET
+            /* TODO: [TLS13] Section 4.5.1 Note.  */
+            if (!ssl->options.resuming && !ssl->options.verifyPeer &&
+                !ssl->options.noTicketTls13 && ssl->ctx->ticketEncCb != NULL) {
+                if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            }
+#endif /* HAVE_SESSION_TICKET */
+            ssl->options.acceptState = TICKET_SENT;
+            WOLFSSL_MSG("accept state  TICKET_SENT");
+
+        case TICKET_SENT:
+            while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE)
+                if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+
+            ssl->options.acceptState = ACCEPT_SECOND_REPLY_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE");
+        case ACCEPT_SECOND_REPLY_DONE :
+#ifdef HAVE_SESSION_TICKET
+            if (!ssl->options.resuming && ssl->options.verifyPeer &&
+                !ssl->options.noTicketTls13 && ssl->ctx->ticketEncCb != NULL) {
+                if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            }
+#endif /* HAVE_SESSION_TICKET */
+            ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE");
+
+        case ACCEPT_THIRD_REPLY_DONE:
+#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 SSL_FATAL_ERROR;
+                }
+            }
+#endif /* NO_HANDSHAKE_DONE_CB */
+
+#ifdef WOLFSSL_SESSION_EXPORT
+            if (ssl->dtls_export) {
+                if ((ssl->error = wolfSSL_send_session(ssl)) != 0) {
+                    WOLFSSL_MSG("Export DTLS session error");
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            }
+#endif
+
+            WOLFSSL_LEAVE("SSL_accept()", SSL_SUCCESS);
+            return SSL_SUCCESS;
+
+        default :
+            WOLFSSL_MSG("Unknown accept state ERROR");
+            return SSL_FATAL_ERROR;
+    }
+}
+
+
+#undef ERROR_OUT
+
+#endif /* WOLFCRYPT_ONLY */
+
+#endif /* WOLFSSL_TLS13 */
+