Index: asp3_tinet_ecnl_arm/trunk/wolfssl-3.12.2/src/tls.c
===================================================================
--- asp3_tinet_ecnl_arm/trunk/wolfssl-3.12.2/src/tls.c	(revision 352)
+++ asp3_tinet_ecnl_arm/trunk/wolfssl-3.12.2/src/tls.c	(revision 372)
@@ -49,4 +49,5 @@
     #include <wolfssl/wolfcrypt/random.h>
 #endif
+
 #ifdef HAVE_QSH
     static int TLSX_AddQSHKey(QSHKey** list, QSHKey* key);
@@ -57,4 +58,19 @@
 #endif /* HAVE_QSH */
 
+#if (!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
+        !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \
+    (defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES))
+static int TLSX_KeyShare_IsSupported(int namedGroup);
+#endif
+
+#if (!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
+        !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \
+    (defined(WOLFSSL_TLS13) && !defined(HAVE_ECC) && \
+        !defined(HAVE_CURVE25519) && defined(HAVE_SUPPORTED_CURVES)) || \
+    ((defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+        defined(HAVE_SUPPORTED_CURVES))
+static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions);
+#endif
+
 
 #ifndef NO_TLS
@@ -72,4 +88,24 @@
 #endif
 
+#ifdef WOLFSSL_TLS13
+    #if !defined(NO_DH) && \
+        !defined(HAVE_FFDHE_2048) && !defined(HAVE_FFDHE_3072) && \
+        !defined(HAVE_FFDHE_4096) && !defined(HAVE_FFDHE_6144) && \
+        !defined(HAVE_FFDHE_8192)
+        #error Please configure your TLS 1.3 DH key size using either: HAVE_FFDHE_2048, HAVE_FFDHE_3072, HAVE_FFDHE_4096, HAVE_FFDHE_6144 or HAVE_FFDHE_8192
+    #endif
+    #if !defined(NO_RSA) && !defined(WC_RSA_PSS)
+        #error The build option WC_RSA_PSS is required for TLS 1.3 with RSA
+    #endif
+#endif
+
+/* Optional Pre-Master-Secret logging for Wireshark */
+#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SSLKEYLOGFILE)
+#ifndef WOLFSSL_SSLKEYLOGFILE_OUTPUT
+    #define WOLFSSL_SSLKEYLOGFILE_OUTPUT "sslkeylog.log"
+#endif
+#endif
+
+#ifndef WOLFSSL_NO_TLS12
 
 #ifdef WOLFSSL_SHA384
@@ -78,5 +114,4 @@
     #define P_HASH_MAX_SIZE WC_SHA256_DIGEST_SIZE
 #endif
-
 
 /* compute p_hash for MD5, SHA-1, SHA-256, or SHA-384 for TLSv1 PRF */
@@ -207,9 +242,11 @@
 #undef P_HASH_MAX_SIZE
 
+#endif /* !WOLFSSL_NO_TLS12 */
+
 
 #ifndef NO_OLD_TLS
 
 /* calculate XOR for TLSv1 PRF */
-static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
+static WC_INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
 {
     word32 i;
@@ -231,5 +268,4 @@
     byte* md5_half;
     byte* sha_half;
-    byte* labelSeed;
     byte* md5_result;
     byte* sha_result;
@@ -237,30 +273,40 @@
     byte  md5_half[MAX_PRF_HALF];     /* half is real size */
     byte  sha_half[MAX_PRF_HALF];     /* half is real size */
-    byte  labelSeed[MAX_PRF_LABSEED]; /* labLen + seedLen is real size */
     byte  md5_result[MAX_PRF_DIG];    /* digLen is real size */
     byte  sha_result[MAX_PRF_DIG];    /* digLen is real size */
 #endif
-
-    if (half > MAX_PRF_HALF)
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    DECLARE_VAR(labelSeed, byte, MAX_PRF_LABSEED, heap);
+    if (labelSeed == NULL)
+        return MEMORY_E;
+#else
+    byte labelSeed[MAX_PRF_LABSEED];
+#endif
+
+    if (half > MAX_PRF_HALF ||
+        labLen + seedLen > MAX_PRF_LABSEED ||
+        digLen > MAX_PRF_DIG)
+    {
+    #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+        FREE_VAR(labelSeed, heap);
+    #endif
         return BUFFER_E;
-    if (labLen + seedLen > MAX_PRF_LABSEED)
-        return BUFFER_E;
-    if (digLen > MAX_PRF_DIG)
-        return BUFFER_E;
+    }
 
 #ifdef WOLFSSL_SMALL_STACK
     md5_half   = (byte*)XMALLOC(MAX_PRF_HALF,    heap, DYNAMIC_TYPE_DIGEST);
     sha_half   = (byte*)XMALLOC(MAX_PRF_HALF,    heap, DYNAMIC_TYPE_DIGEST);
-    labelSeed  = (byte*)XMALLOC(MAX_PRF_LABSEED, heap, DYNAMIC_TYPE_SEED);
     md5_result = (byte*)XMALLOC(MAX_PRF_DIG,     heap, DYNAMIC_TYPE_DIGEST);
     sha_result = (byte*)XMALLOC(MAX_PRF_DIG,     heap, DYNAMIC_TYPE_DIGEST);
 
-    if (md5_half == NULL || sha_half == NULL || labelSeed == NULL ||
-                                     md5_result == NULL || sha_result == NULL) {
+    if (md5_half == NULL || sha_half == NULL || md5_result == NULL ||
+                                                           sha_result == NULL) {
         if (md5_half)   XFREE(md5_half,   heap, DYNAMIC_TYPE_DIGEST);
         if (sha_half)   XFREE(sha_half,   heap, DYNAMIC_TYPE_DIGEST);
-        if (labelSeed)  XFREE(labelSeed,  heap, DYNAMIC_TYPE_SEED);
         if (md5_result) XFREE(md5_result, heap, DYNAMIC_TYPE_DIGEST);
         if (sha_result) XFREE(sha_result, heap, DYNAMIC_TYPE_DIGEST);
+    #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+        FREE_VAR(labelSeed, heap);
+    #endif
 
         return MEMORY_E;
@@ -288,9 +334,12 @@
     XFREE(md5_half,   heap, DYNAMIC_TYPE_DIGEST);
     XFREE(sha_half,   heap, DYNAMIC_TYPE_DIGEST);
-    XFREE(labelSeed,  heap, DYNAMIC_TYPE_SEED);
     XFREE(md5_result, heap, DYNAMIC_TYPE_DIGEST);
     XFREE(sha_result, heap, DYNAMIC_TYPE_DIGEST);
 #endif
 
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    FREE_VAR(labelSeed, heap);
+#endif
+
     return ret;
 }
@@ -298,4 +347,6 @@
 #endif
 
+
+#ifndef WOLFSSL_NO_TLS12
 
 /* Wrapper to call straight thru to p_hash in TSL 1.2 cases to remove stack
@@ -308,18 +359,14 @@
 
     if (useAtLeastSha256) {
-#ifdef WOLFSSL_SMALL_STACK
-        byte* labelSeed;
+    #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+        DECLARE_VAR(labelSeed, byte, MAX_PRF_LABSEED, heap);
+        if (labelSeed == NULL)
+            return MEMORY_E;
 #else
-        byte labelSeed[MAX_PRF_LABSEED]; /* labLen + seedLen is real size */
+        byte labelSeed[MAX_PRF_LABSEED];
 #endif
 
         if (labLen + seedLen > MAX_PRF_LABSEED)
             return BUFFER_E;
-
-#ifdef WOLFSSL_SMALL_STACK
-        labelSeed = (byte*)XMALLOC(MAX_PRF_LABSEED, heap, DYNAMIC_TYPE_SEED);
-        if (labelSeed == NULL)
-           return MEMORY_E;
-#endif
 
         XMEMCPY(labelSeed, label, labLen);
@@ -333,6 +380,6 @@
                      labLen + seedLen, hash_type, heap, devId);
 
-#ifdef WOLFSSL_SMALL_STACK
-        XFREE(labelSeed, heap, DYNAMIC_TYPE_SEED);
+    #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+        FREE_VAR(labelSeed, heap);
 #endif
     }
@@ -356,4 +403,5 @@
 int BuildTlsHandshakeHash(WOLFSSL* ssl, byte* hash, word32* hashLen)
 {
+    int ret = 0;
     word32 hashSz = FINISHED_SZ;
 
@@ -361,7 +409,8 @@
         return BAD_FUNC_ARG;
 
+    /* for constant timing perform these even if error */
 #ifndef NO_OLD_TLS
-    wc_Md5GetHash(&ssl->hsHashes->hashMd5, hash);
-    wc_ShaGetHash(&ssl->hsHashes->hashSha, &hash[WC_MD5_DIGEST_SIZE]);
+    ret |= wc_Md5GetHash(&ssl->hsHashes->hashMd5, hash);
+    ret |= wc_ShaGetHash(&ssl->hsHashes->hashSha, &hash[WC_MD5_DIGEST_SIZE]);
 #endif
 
@@ -370,9 +419,5 @@
         if (ssl->specs.mac_algorithm <= sha256_mac ||
             ssl->specs.mac_algorithm == blake2b_mac) {
-            int ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash);
-
-            if (ret != 0)
-                return ret;
-
+            ret |= wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash);
             hashSz = WC_SHA256_DIGEST_SIZE;
         }
@@ -380,9 +425,5 @@
 #ifdef WOLFSSL_SHA384
         if (ssl->specs.mac_algorithm == sha384_mac) {
-            int ret = wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash);
-
-            if (ret != 0)
-                return ret;
-
+            ret |= wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash);
             hashSz = WC_SHA384_DIGEST_SIZE;
         }
@@ -392,5 +433,8 @@
     *hashLen = hashSz;
 
-    return 0;
+    if (ret != 0)
+        ret = BUILD_MSG_ERROR;
+
+    return ret;
 }
 
@@ -400,11 +444,12 @@
     int         ret;
     const byte* side;
-    byte*       handshake_hash;
     word32      hashSz = HSHASH_SZ;
-
-    /* using allocate here to allow async hardware to use buffer directly */
-    handshake_hash = (byte*)XMALLOC(hashSz, ssl->heap, DYNAMIC_TYPE_DIGEST);
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    DECLARE_VAR(handshake_hash, byte, HSHASH_SZ, ssl->heap);
     if (handshake_hash == NULL)
         return MEMORY_E;
+#else
+    byte handshake_hash[HSHASH_SZ];
+#endif
 
     ret = BuildTlsHandshakeHash(ssl, handshake_hash, &hashSz);
@@ -421,12 +466,16 @@
     }
 
-    XFREE(handshake_hash, ssl->heap, DYNAMIC_TYPE_DIGEST);
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    FREE_VAR(handshake_hash, ssl->heap);
+#endif
 
     return ret;
 }
 
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #ifndef NO_OLD_TLS
 
+#ifdef WOLFSSL_ALLOW_TLSV10
 ProtocolVersion MakeTLSv1(void)
 {
@@ -437,4 +486,5 @@
     return pv;
 }
+#endif /* WOLFSSL_ALLOW_TLSV10 */
 
 
@@ -448,6 +498,8 @@
 }
 
-#endif
-
+#endif /* !NO_OLD_TLS */
+
+
+#ifndef WOLFSSL_NO_TLS12
 
 ProtocolVersion MakeTLSv1_2(void)
@@ -459,4 +511,6 @@
     return pv;
 }
+
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #ifdef WOLFSSL_TLS13
@@ -475,4 +529,5 @@
 #endif
 
+#ifndef WOLFSSL_NO_TLS12
 
 #ifdef HAVE_EXTENDED_MASTER
@@ -489,11 +544,24 @@
                          void* heap, int devId)
 {
+    int ret;
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    DECLARE_VAR(seed, byte, SEED_LEN, heap);
+    if (seed == NULL)
+        return MEMORY_E;
+#else
     byte  seed[SEED_LEN];
+#endif
 
     XMEMCPY(seed,           sr, RAN_LEN);
     XMEMCPY(seed + RAN_LEN, cr, RAN_LEN);
 
-    return PRF(key_dig, key_dig_len, ms, msLen, key_label, KEY_LABEL_SZ,
+    ret = PRF(key_dig, key_dig_len, ms, msLen, key_label, KEY_LABEL_SZ,
                seed, SEED_LEN, tls1_2, hash_type, heap, devId);
+
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    FREE_VAR(seed, heap);
+#endif
+
+    return ret;
 }
 
@@ -549,11 +617,24 @@
                                void* heap, int devId)
 {
+    int ret;
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    DECLARE_VAR(seed, byte, SEED_LEN, heap);
+    if (seed == NULL)
+        return MEMORY_E;
+#else
     byte  seed[SEED_LEN];
+#endif
 
     XMEMCPY(seed,           cr, RAN_LEN);
     XMEMCPY(seed + RAN_LEN, sr, RAN_LEN);
 
-    return PRF(ms, msLen, pms, pmsLen, master_label, MASTER_LABEL_SZ,
+    ret = PRF(ms, msLen, pms, pmsLen, master_label, MASTER_LABEL_SZ,
                seed, SEED_LEN, tls1_2, hash_type, heap, devId);
+
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    FREE_VAR(seed, heap);
+#endif
+
+    return ret;
 }
 
@@ -597,20 +678,19 @@
 {
     int    ret;
+
 #ifdef HAVE_EXTENDED_MASTER
     if (ssl->options.haveEMS) {
-        byte*  handshake_hash;
         word32 hashSz = HSHASH_SZ;
-
-        handshake_hash = (byte*)XMALLOC(HSHASH_SZ, ssl->heap,
+    #ifdef WOLFSSL_SMALL_STACK
+        byte* handshake_hash = (byte*)XMALLOC(HSHASH_SZ, ssl->heap,
                                         DYNAMIC_TYPE_DIGEST);
         if (handshake_hash == NULL)
             return MEMORY_E;
+    #else
+        byte handshake_hash[HSHASH_SZ];
+    #endif
 
         ret = BuildTlsHandshakeHash(ssl, handshake_hash, &hashSz);
-        if (ret < 0) {
-            XFREE(handshake_hash, ssl->heap, DYNAMIC_TYPE_DIGEST);
-            return ret;
-        }
-
+        if (ret == 0) {
         ret = _MakeTlsExtendedMasterSecret(
                 ssl->arrays->masterSecret, SECRET_LEN,
@@ -619,8 +699,13 @@
                 IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
                 ssl->heap, ssl->devId);
-
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
         XFREE(handshake_hash, ssl->heap, DYNAMIC_TYPE_DIGEST);
-    } else
-#endif
+#endif
+    }
+    else
+#endif /* HAVE_EXTENDED_MASTER */
+    {
     ret = _MakeTlsMasterSecret(ssl->arrays->masterSecret, SECRET_LEN,
               ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz,
@@ -628,14 +713,45 @@
               IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
               ssl->heap, ssl->devId);
-
+    }
     if (ret == 0) {
     #ifdef SHOW_SECRETS
-        int i;
-
-        printf("master secret: ");
-        for (i = 0; i < SECRET_LEN; i++)
-            printf("%02x", ssl->arrays->masterSecret[i]);
-        printf("\n");
-    #endif
+        /* Wireshark Pre-Master-Secret Format:
+         *  CLIENT_RANDOM <clientrandom> <mastersecret>
+         */
+        const char* CLIENT_RANDOM_LABEL = "CLIENT_RANDOM";
+        int i, pmsPos = 0;
+        char pmsBuf[13 + 1 + 64 + 1 + 96 + 1 + 1];
+
+        XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%s ",
+            CLIENT_RANDOM_LABEL);
+        pmsPos += XSTRLEN(CLIENT_RANDOM_LABEL) + 1;
+        for (i = 0; i < RAN_LEN; i++) {
+            XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%02x",
+                ssl->arrays->clientRandom[i]);
+            pmsPos += 2;
+        }
+        XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, " ");
+        pmsPos += 1;
+        for (i = 0; i < SECRET_LEN; i++) {
+            XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%02x",
+                ssl->arrays->masterSecret[i]);
+            pmsPos += 2;
+        }
+        XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "\n");
+        pmsPos += 1;
+
+        /* print master secret */
+        puts(pmsBuf);
+
+        #if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SSLKEYLOGFILE)
+        {
+            FILE* f = XFOPEN(WOLFSSL_SSLKEYLOGFILE_OUTPUT, "a");
+            if (f != XBADFILE) {
+                XFWRITE(pmsBuf, 1, pmsPos, f);
+                XFCLOSE(f);
+            }
+        }
+    #endif
+    #endif /* SHOW_SECRETS */
 
         ret = DeriveTlsKeys(ssl);
@@ -684,5 +800,5 @@
 
 
-static INLINE void GetSEQIncrement(WOLFSSL* ssl, int verify, word32 seq[2])
+static WC_INLINE void GetSEQIncrement(WOLFSSL* ssl, int verify, word32 seq[2])
 {
     if (verify) {
@@ -706,5 +822,5 @@
 
 #ifdef WOLFSSL_DTLS
-static INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2])
+static WC_INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2])
 {
     if (order == PREV_ORDER) {
@@ -728,5 +844,5 @@
 
 
-static INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
+static WC_INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
 {
     word32 seq[2] = {0, 0};
@@ -813,11 +929,403 @@
 
 
-/* TLS type HMAC */
-int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
-              int content, int verify)
-{
-    Hmac hmac;
-    int  ret = 0;
-    byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ];
+#ifndef WOLFSSL_AEAD_ONLY
+#if !defined(WOLFSSL_NO_HASH_RAW) && !defined(HAVE_FIPS) && \
+    !defined(HAVE_SELFTEST)
+
+/* Update the hash in the HMAC.
+ *
+ * hmac  HMAC object.
+ * data  Data to be hashed.
+ * sz    Size of data to hash.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_HashUpdate(Hmac* hmac, const byte* data, word32 sz)
+{
+    int ret = BAD_FUNC_ARG;
+
+    switch (hmac->macType) {
+    #ifndef NO_SHA
+        case WC_SHA:
+            ret = wc_ShaUpdate(&hmac->hash.sha, data, sz);
+            break;
+    #endif /* !NO_SHA */
+
+    #ifndef NO_SHA256
+        case WC_SHA256:
+            ret = wc_Sha256Update(&hmac->hash.sha256, data, sz);
+            break;
+    #endif /* !NO_SHA256 */
+
+    #ifdef WOLFSSL_SHA384
+        case WC_SHA384:
+            ret = wc_Sha384Update(&hmac->hash.sha384, data, sz);
+            break;
+    #endif /* WOLFSSL_SHA384 */
+
+    #ifdef WOLFSSL_SHA512
+        case WC_SHA512:
+            ret = wc_Sha512Update(&hmac->hash.sha512, data, sz);
+            break;
+    #endif /* WOLFSSL_SHA512 */
+    }
+
+    return ret;
+}
+
+/* Finalize the hash but don't put the EOC, padding or length in.
+ *
+ * hmac  HMAC object.
+ * hash  Hash result.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_HashFinalRaw(Hmac* hmac, unsigned char* hash)
+{
+    int ret = BAD_FUNC_ARG;
+
+    switch (hmac->macType) {
+    #ifndef NO_SHA
+        case WC_SHA:
+            ret = wc_ShaFinalRaw(&hmac->hash.sha, hash);
+            break;
+    #endif /* !NO_SHA */
+
+    #ifndef NO_SHA256
+        case WC_SHA256:
+            ret = wc_Sha256FinalRaw(&hmac->hash.sha256, hash);
+            break;
+    #endif /* !NO_SHA256 */
+
+    #ifdef WOLFSSL_SHA384
+        case WC_SHA384:
+            ret = wc_Sha384FinalRaw(&hmac->hash.sha384, hash);
+            break;
+    #endif /* WOLFSSL_SHA384 */
+
+    #ifdef WOLFSSL_SHA512
+        case WC_SHA512:
+            ret = wc_Sha512FinalRaw(&hmac->hash.sha512, hash);
+            break;
+    #endif /* WOLFSSL_SHA512 */
+    }
+
+    return ret;
+}
+
+/* Finalize the HMAC by performing outer hash.
+ *
+ * hmac  HMAC object.
+ * mac   MAC result.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_OuterHash(Hmac* hmac, unsigned char* mac)
+{
+    int ret = BAD_FUNC_ARG;
+    wc_HashAlg hash;
+    enum wc_HashType hashType = (enum wc_HashType)hmac->macType;
+    int digestSz = wc_HashGetDigestSize(hashType);
+    int blockSz = wc_HashGetBlockSize(hashType);
+
+    ret = wc_HashInit(&hash, hashType);
+    if (ret == 0) {
+        ret = wc_HashUpdate(&hash, hashType, (byte*)hmac->opad,
+            blockSz);
+        if (ret == 0)
+            ret = wc_HashUpdate(&hash, hashType, (byte*)hmac->innerHash,
+                digestSz);
+        if (ret == 0)
+            ret = wc_HashFinal(&hash, hashType, mac);
+        wc_HashFree(&hash, hashType);
+    }
+
+    return ret;
+}
+
+/* Calculate the HMAC of the header + message data.
+ * Constant time implementation using wc_Sha*FinalRaw().
+ *
+ * hmac    HMAC object.
+ * digest  MAC result.
+ * in      Message data.
+ * sz      Size of the message data.
+ * header  Constructed record header with length of handshake data.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_UpdateFinal_CT(Hmac* hmac, byte* digest, const byte* in,
+                               word32 sz, byte* header)
+{
+    byte lenBytes[8];
+    int  i, j, k;
+    int  blockBits, blockMask;
+    int  realLen, lastBlockLen, macLen, extraLen, eocIndex;
+    int  blocks, safeBlocks, lenBlock, eocBlock;
+    int  maxLen;
+    int  blockSz, padSz;
+    int  ret;
+    byte extraBlock;
+
+    switch (hmac->macType) {
+    #ifndef NO_SHA
+        case WC_SHA:
+            blockSz = WC_SHA_BLOCK_SIZE;
+            blockBits = 6;
+            macLen = WC_SHA_DIGEST_SIZE;
+            padSz = WC_SHA_BLOCK_SIZE - WC_SHA_PAD_SIZE + 1;
+            break;
+    #endif /* !NO_SHA */
+
+    #ifndef NO_SHA256
+        case WC_SHA256:
+            blockSz = WC_SHA256_BLOCK_SIZE;
+            blockBits = 6;
+            macLen = WC_SHA256_DIGEST_SIZE;
+            padSz = WC_SHA256_BLOCK_SIZE - WC_SHA256_PAD_SIZE + 1;
+            break;
+    #endif /* !NO_SHA256 */
+
+    #ifdef WOLFSSL_SHA384
+        case WC_SHA384:
+            blockSz = WC_SHA384_BLOCK_SIZE;
+            blockBits = 7;
+            macLen = WC_SHA384_DIGEST_SIZE;
+            padSz = WC_SHA384_BLOCK_SIZE - WC_SHA384_PAD_SIZE + 1;
+            break;
+    #endif /* WOLFSSL_SHA384 */
+
+    #ifdef WOLFSSL_SHA512
+        case WC_SHA512:
+            blockSz = WC_SHA512_BLOCK_SIZE;
+            blockBits = 7;
+            macLen = WC_SHA512_DIGEST_SIZE;
+            padSz = WC_SHA512_BLOCK_SIZE - WC_SHA512_PAD_SIZE + 1;
+            break;
+    #endif /* WOLFSSL_SHA512 */
+
+        default:
+            return BAD_FUNC_ARG;
+}
+    blockMask = blockSz - 1;
+
+    /* Size of data to HMAC if padding length byte is zero. */
+    maxLen = WOLFSSL_TLS_HMAC_INNER_SZ + sz - 1 - macLen;
+    /* Complete data (including padding) has block for EOC and/or length. */
+    extraBlock = ctSetLTE((maxLen + padSz) & blockMask, padSz);
+    /* Total number of blocks for data including padding. */
+    blocks = ((maxLen + blockSz - 1) >> blockBits) + extraBlock;
+    /* Up to last 6 blocks can be hashed safely. */
+    safeBlocks = blocks - 6;
+
+    /* Length of message data. */
+    realLen = maxLen - in[sz - 1];
+    /* Number of message bytes in last block. */
+    lastBlockLen = realLen & blockMask;
+    /* Number of padding bytes in last block. */
+    extraLen = ((blockSz * 2 - padSz - lastBlockLen) & blockMask) + 1;
+    /* Number of blocks to create for hash. */
+    lenBlock = (realLen + extraLen) >> blockBits;
+    /* Block containing EOC byte. */
+    eocBlock = realLen >> blockBits;
+    /* Index of EOC byte in block. */
+    eocIndex = realLen & blockMask;
+
+    /* Add length of hmac's ipad to total length. */
+    realLen += blockSz;
+    /* Length as bits - 8 bytes bigendian. */
+    c32toa(realLen >> ((sizeof(word32) * 8) - 3), lenBytes);
+    c32toa(realLen << 3, lenBytes + sizeof(word32));
+
+    ret = Hmac_HashUpdate(hmac, (unsigned char*)hmac->ipad, blockSz);
+    if (ret != 0)
+        return ret;
+
+    XMEMSET(hmac->innerHash, 0, macLen);
+
+    if (safeBlocks > 0) {
+        ret = Hmac_HashUpdate(hmac, header, WOLFSSL_TLS_HMAC_INNER_SZ);
+        if (ret != 0)
+            return ret;
+        ret = Hmac_HashUpdate(hmac, in, safeBlocks * blockSz -
+                                                     WOLFSSL_TLS_HMAC_INNER_SZ);
+        if (ret != 0)
+            return ret;
+    }
+    else
+        safeBlocks = 0;
+
+    XMEMSET(digest, 0, macLen);
+    k = safeBlocks * blockSz;
+    for (i = safeBlocks; i < blocks; i++) {
+        unsigned char hashBlock[WC_MAX_BLOCK_SIZE];
+        unsigned char isEocBlock = ctMaskEq(i, eocBlock);
+        unsigned char isOutBlock = ctMaskEq(i, lenBlock);
+
+        for (j = 0; j < blockSz; j++, k++) {
+            unsigned char atEoc = ctMaskEq(j, eocIndex) & isEocBlock;
+            unsigned char pastEoc = ctMaskGT(j, eocIndex) & isEocBlock;
+            unsigned char b = 0;
+
+            if (k < WOLFSSL_TLS_HMAC_INNER_SZ)
+                b = header[k];
+            else if (k < maxLen)
+                b = in[k - WOLFSSL_TLS_HMAC_INNER_SZ];
+
+            b = ctMaskSel(atEoc, 0x80, b);
+            b &= (unsigned char)~(word32)pastEoc;
+            b &= ((unsigned char)~(word32)isOutBlock) | isEocBlock;
+
+            if (j >= blockSz - 8) {
+                b = ctMaskSel(isOutBlock, lenBytes[j - (blockSz - 8)], b);
+            }
+
+            hashBlock[j] = b;
+        }
+
+        ret = Hmac_HashUpdate(hmac, hashBlock, blockSz);
+        if (ret != 0)
+            return ret;
+        ret = Hmac_HashFinalRaw(hmac, hashBlock);
+        if (ret != 0)
+            return ret;
+        for (j = 0; j < macLen; j++)
+            ((unsigned char*)hmac->innerHash)[j] |= hashBlock[j] & isOutBlock;
+    }
+
+    ret = Hmac_OuterHash(hmac, digest);
+
+    return ret;
+}
+
+#endif
+
+#if defined(WOLFSSL_NO_HASH_RAW) || defined(HAVE_FIPS) || \
+    defined(HAVE_SELFTEST) || defined(HAVE_BLAKE2)
+
+/* Calculate the HMAC of the header + message data.
+ * Constant time implementation using normal hashing operations.
+ * Update-Final need to be constant time.
+ *
+ * hmac    HMAC object.
+ * digest  MAC result.
+ * in      Message data.
+ * sz      Size of the message data.
+ * header  Constructed record header with length of handshake data.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_UpdateFinal(Hmac* hmac, byte* digest, const byte* in,
+                            word32 sz, byte* header)
+{
+    byte       dummy[WC_MAX_BLOCK_SIZE] = {0};
+    int        ret;
+    word32     msgSz, blockSz, macSz, padSz, maxSz, realSz;
+    word32     currSz, offset;
+    int        msgBlocks, blocks, blockBits;
+    int        i;
+
+    switch (hmac->macType) {
+    #ifndef NO_SHA
+        case WC_SHA:
+            blockSz = WC_SHA_BLOCK_SIZE;
+            blockBits = 6;
+            macSz = WC_SHA_DIGEST_SIZE;
+            padSz = WC_SHA_BLOCK_SIZE - WC_SHA_PAD_SIZE + 1;
+            break;
+    #endif /* !NO_SHA */
+
+    #ifndef NO_SHA256
+        case WC_SHA256:
+            blockSz = WC_SHA256_BLOCK_SIZE;
+            blockBits = 6;
+            macSz = WC_SHA256_DIGEST_SIZE;
+            padSz = WC_SHA256_BLOCK_SIZE - WC_SHA256_PAD_SIZE + 1;
+            break;
+    #endif /* !NO_SHA256 */
+
+    #ifdef WOLFSSL_SHA384
+        case WC_SHA384:
+            blockSz = WC_SHA384_BLOCK_SIZE;
+            blockBits = 7;
+            macSz = WC_SHA384_DIGEST_SIZE;
+            padSz = WC_SHA384_BLOCK_SIZE - WC_SHA384_PAD_SIZE + 1;
+            break;
+    #endif /* WOLFSSL_SHA384 */
+
+    #ifdef WOLFSSL_SHA512
+        case WC_SHA512:
+            blockSz = WC_SHA512_BLOCK_SIZE;
+            blockBits = 7;
+            macSz = WC_SHA512_DIGEST_SIZE;
+            padSz = WC_SHA512_BLOCK_SIZE - WC_SHA512_PAD_SIZE + 1;
+            break;
+    #endif /* WOLFSSL_SHA512 */
+
+    #ifdef HAVE_BLAKE2
+        case WC_HASH_TYPE_BLAKE2B:
+            blockSz = BLAKE2B_BLOCKBYTES;
+            blockBits = 7;
+            macSz = BLAKE2B_256;
+            padSz = 0;
+            break;
+    #endif /* HAVE_BLAK2 */
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    msgSz = sz - (1 + in[sz - 1] + macSz);
+    /* Make negative result 0 */
+    msgSz &= ~(0 - (msgSz >> 31));
+    realSz = WOLFSSL_TLS_HMAC_INNER_SZ + msgSz;
+    maxSz = WOLFSSL_TLS_HMAC_INNER_SZ + (sz - 1) - macSz;
+
+    /* Calculate #blocks processed in HMAC for max and real data. */
+    blocks      = maxSz >> blockBits;
+    blocks     += ((maxSz + padSz) % blockSz) < padSz;
+    msgBlocks   = realSz >> blockBits;
+    /* #Extra blocks to process. */
+    blocks -= msgBlocks + (((realSz + padSz) % blockSz) < padSz);
+    /* Calculate whole blocks. */
+    msgBlocks--;
+
+    ret = wc_HmacUpdate(hmac, header, WOLFSSL_TLS_HMAC_INNER_SZ);
+    if (ret == 0) {
+        /* Fill the rest of the block with any available data. */
+        currSz = ctMaskLT(msgSz, blockSz) & msgSz;
+        currSz |= ctMaskGTE(msgSz, blockSz) & blockSz;
+        currSz -= WOLFSSL_TLS_HMAC_INNER_SZ;
+        currSz &= ~(0 - (currSz >> 31));
+        ret = wc_HmacUpdate(hmac, in, currSz);
+        offset = currSz;
+    }
+    if (ret == 0) {
+        /* Do the hash operations on a block basis. */
+        for (i = 0; i < msgBlocks; i++, offset += blockSz) {
+            ret = wc_HmacUpdate(hmac, in + offset, blockSz);
+            if (ret != 0)
+                break;
+        }
+    }
+    if (ret == 0)
+        ret = wc_HmacUpdate(hmac, in + offset, msgSz - offset);
+    if (ret == 0)
+        ret = wc_HmacFinal(hmac, digest);
+    if (ret == 0) {
+        /* Do the dummy hash operations. Do at least one. */
+        for (i = 0; i < blocks + 1; i++) {
+            ret = wc_HmacUpdate(hmac, dummy, blockSz);
+            if (ret != 0)
+                break;
+        }
+    }
+
+    return ret;
+}
+
+#endif
+
+int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz,
+             int content, int verify)
+{
+    Hmac   hmac;
+    byte   myInner[WOLFSSL_TLS_HMAC_INNER_SZ];
+    int    ret = 0;
 
     if (ssl == NULL)
@@ -825,6 +1333,14 @@
 
 #ifdef HAVE_FUZZER
-    if (ssl->fuzzerCb)
-        ssl->fuzzerCb(ssl, in, sz, FUZZ_HMAC, ssl->fuzzerCtx);
+    /* Fuzz "in" buffer with sz to be used in HMAC algorithm */
+    if (ssl->fuzzerCb) {
+        if (verify && padSz >= 0) {
+            ssl->fuzzerCb(ssl, in, sz + ssl->specs.hash_size + padSz + 1,
+                FUZZ_HMAC, ssl->fuzzerCtx);
+        }
+        else {
+            ssl->fuzzerCb(ssl, in, sz, FUZZ_HMAC, ssl->fuzzerCtx);
+        }
+}
 #endif
 
@@ -836,16 +1352,46 @@
 
     ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl),
-                     wolfSSL_GetMacSecret(ssl, verify), ssl->specs.hash_size);
+                                              wolfSSL_GetMacSecret(ssl, verify),
+                                              ssl->specs.hash_size);
     if (ret == 0) {
-        ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner));
-        if (ret == 0)
-            ret = wc_HmacUpdate(&hmac, in, sz);                    /* content */
-        if (ret == 0)
-            ret = wc_HmacFinal(&hmac, digest);
-    }
+        /* Constant time verification required. */
+        if (verify && padSz >= 0) {
+#if !defined(WOLFSSL_NO_HASH_RAW) && !defined(HAVE_FIPS) && \
+    !defined(HAVE_SELFTEST)
+    #ifdef HAVE_BLAKE2
+            if (wolfSSL_GetHmacType(ssl) == WC_HASH_TYPE_BLAKE2B) {
+                ret = Hmac_UpdateFinal(&hmac, digest, in, sz +
+                                               ssl->specs.hash_size + padSz + 1,
+                                               myInner);
+            }
+            else
+#endif
+            {
+                ret = Hmac_UpdateFinal_CT(&hmac, digest, in, sz +
+                                               ssl->specs.hash_size + padSz + 1,
+                                               myInner);
+            }
+#else
+            ret = Hmac_UpdateFinal(&hmac, digest, in, sz +
+                                               ssl->specs.hash_size + padSz + 1,
+                                               myInner);
+#endif
+        }
+        else {
+            ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner));
+            if (ret == 0)
+                ret = wc_HmacUpdate(&hmac, in, sz);                /* content */
+            if (ret == 0)
+                ret = wc_HmacFinal(&hmac, digest);
+        }
+    }
+
     wc_HmacFree(&hmac);
 
     return ret;
 }
+#endif /* WOLFSSL_AEAD_ONLY */
+
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #ifdef HAVE_TLS_EXTENSIONS
@@ -878,5 +1424,5 @@
  *   'remapped' extension type.
  */
-static INLINE word16 TLSX_ToSemaphore(word16 type)
+static WC_INLINE word16 TLSX_ToSemaphore(word16 type)
 {
     switch (type) {
@@ -918,4 +1464,6 @@
     TLSX* extension = (TLSX*)XMALLOC(sizeof(TLSX), heap, DYNAMIC_TYPE_TLSX);
 
+    (void)heap;
+
     if (extension) {
         extension->type = type;
@@ -953,6 +1501,7 @@
             TLSX_FreeAll(next, heap);
 
-            /* there is no way to occur more than */
-            /* two extensions of the same type.   */
+            /* there is no way to occur more than
+             * two extensions of the same type.
+             */
             break;
         }
@@ -962,5 +1511,32 @@
 }
 
-#ifndef NO_WOLFSSL_SERVER
+#ifndef NO_WOLFSSL_CLIENT
+
+int TLSX_CheckUnsupportedExtension(WOLFSSL* ssl, TLSX_Type type);
+
+int TLSX_CheckUnsupportedExtension(WOLFSSL* ssl, TLSX_Type type)
+{
+    TLSX *extension = TLSX_Find(ssl->extensions, type);
+
+    if (!extension)
+        extension = TLSX_Find(ssl->ctx->extensions, type);
+
+    return extension == NULL;
+}
+
+int TLSX_HandleUnsupportedExtension(WOLFSSL* ssl);
+
+int TLSX_HandleUnsupportedExtension(WOLFSSL* ssl)
+{
+    SendAlert(ssl, alert_fatal, unsupported_extension);
+    return UNSUPPORTED_EXTENSION;
+}
+
+#else
+
+#define TLSX_CheckUnsupportedExtension(ssl, type) 0
+#define TLSX_HandleUnsupportedExtension(ssl) 0
+
+#endif
 
 /** Mark an extension to be sent back to the client. */
@@ -969,11 +1545,9 @@
 void TLSX_SetResponse(WOLFSSL* ssl, TLSX_Type type)
 {
-    TLSX *ext = TLSX_Find(ssl->extensions, type);
-
-    if (ext)
-        ext->resp = 1;
-}
-
-#endif
+    TLSX *extension = TLSX_Find(ssl->extensions, type);
+
+    if (extension)
+        extension->resp = 1;
+}
 
 /******************************************************************************/
@@ -1153,5 +1727,5 @@
                                                TLSX_APPLICATION_LAYER_PROTOCOL);
 
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
     if (ssl->alpnSelect != NULL) {
         const byte* out;
@@ -1173,7 +1747,6 @@
 
     if (extension == NULL || extension->data == NULL) {
-        WOLFSSL_MSG("No ALPN extensions not used or bad");
-        return isRequest ? 0             /* not using ALPN */
-                         : BUFFER_ERROR; /* unexpected ALPN response */
+        return isRequest ? 0
+                         : TLSX_HandleUnsupportedExtension(ssl);
     }
 
@@ -1382,5 +1955,5 @@
                 if (sni->data.host_name) {
                     XSTRNCPY(sni->data.host_name, (const char*)data, size);
-                    sni->data.host_name[size] = 0;
+                    sni->data.host_name[size] = '\0';
                 } else {
                     XFREE(sni, heap, DYNAMIC_TYPE_TLSX);
@@ -1476,6 +2049,4 @@
 }
 
-#ifndef NO_WOLFSSL_SERVER
-
 /** Finds a SNI object in the provided list. */
 static SNI* TLSX_SNI_Find(SNI *list, byte type)
@@ -1489,5 +2060,4 @@
 }
 
-
 /** Sets the status of a SNI object. */
 static void TLSX_SNI_SetStatus(TLSX* extensions, byte type, byte status)
@@ -1511,6 +2081,4 @@
     return 0;
 }
-
-#endif /* NO_WOLFSSL_SERVER */
 
 /** Parses a buffer of SNI extensions. */
@@ -1529,25 +2097,42 @@
         extension = TLSX_Find(ssl->ctx->extensions, TLSX_SERVER_NAME);
 
-    (void)isRequest;
-    (void)input;
-
+    if (!isRequest) {
+        #ifndef NO_WOLFSSL_CLIENT
+            if (!extension || !extension->data)
+                return TLSX_HandleUnsupportedExtension(ssl);
+
+            if (length > 0)
+                return BUFFER_ERROR; /* SNI response MUST be empty. */
+
+            /* This call enables wolfSSL_SNI_GetRequest() to be called in the
+             * client side to fetch the used SNI. It will only work if the SNI
+             * was set at the SSL object level. Right now we only support one
+             * name type, WOLFSSL_SNI_HOST_NAME, but in the future, the
+             * inclusion of other name types will turn this method inaccurate,
+             * as the extension response doesn't contains information of which
+             * name was accepted.
+             */
+            TLSX_SNI_SetStatus(ssl->extensions, WOLFSSL_SNI_HOST_NAME,
+                                                        WOLFSSL_SNI_REAL_MATCH);
+
+            return 0;
+        #endif
+    }
+
+#ifndef NO_WOLFSSL_SERVER
     if (!extension || !extension->data) {
 #if defined(WOLFSSL_ALWAYS_KEEP_SNI) && !defined(NO_WOLFSSL_SERVER)
         /* This will keep SNI even though TLSX_UseSNI has not been called.
          * Enable it so that the received sni is available to functions
-         * that use a custom callback when SNI is received */
+            * that use a custom callback when SNI is received.
+            */
+
         cacheOnly = 1;
         WOLFSSL_MSG("Forcing SSL object to store SNI parameter");
 #else
-        return isRequest ? 0             /* not using SNI.           */
-                         : BUFFER_ERROR; /* unexpected SNI response. */
-#endif
-    }
-
-    if (!isRequest)
-        return length ? BUFFER_ERROR /* SNI response MUST be empty. */
-                      : 0;           /* nothing else to do.         */
-
-#ifndef NO_WOLFSSL_SERVER
+            /* Skipping, SNI not enabled at server side. */
+            return 0;
+#endif
+    }
 
     if (OPAQUE16_LEN > length)
@@ -1580,4 +2165,6 @@
             case WOLFSSL_SNI_HOST_NAME: {
                 int matchStat;
+                byte matched;
+
 #ifdef WOLFSSL_TLS13
                 /* Don't process the second ClientHello SNI extension if there
@@ -1587,7 +2174,7 @@
                     break;
 #endif
-                byte matched = cacheOnly ||
-                            ((XSTRLEN(sni->data.host_name) == size)
-                            && (XSTRNCMP(sni->data.host_name,
+                matched = cacheOnly ||
+                    ((XSTRLEN(sni->data.host_name) == size) &&
+                    (XSTRNCMP(sni->data.host_name,
                                        (const char*)input + offset, size) == 0));
 
@@ -1610,5 +2197,5 @@
                     }
 
-                    TLSX_SNI_SetStatus(ssl->extensions, type, matchStat);
+                    TLSX_SNI_SetStatus(ssl->extensions, type, (byte)matchStat);
 
                     if(!cacheOnly)
@@ -1624,5 +2211,6 @@
         }
     }
-
+#else
+    (void)input;
 #endif
 
@@ -1690,4 +2278,5 @@
     if (!extension) {
         int ret = TLSX_Push(extensions, TLSX_SERVER_NAME, (void*)sni, heap);
+
         if (ret != 0) {
             TLSX_SNI_Free(sni, heap);
@@ -1708,6 +2297,7 @@
                 TLSX_SNI_Free(next, heap);
 
-                /* there is no way to occur more than */
-                /* two SNIs of the same type.         */
+                /* there is no way to occur more than
+                 * two SNIs of the same type.
+                 */
                 break;
             }
@@ -1934,10 +2524,17 @@
                                                                  byte isRequest)
 {
-    (void)isRequest;
-
     if (length != ENUM_LEN)
         return BUFFER_ERROR;
 
+#ifdef WOLFSSL_OLD_UNSUPPORTED_EXTENSION
+    (void) isRequest;
+#else
+    if (!isRequest)
+        if (TLSX_CheckUnsupportedExtension(ssl, TLSX_MAX_FRAGMENT_LENGTH))
+            return TLSX_HandleUnsupportedExtension(ssl);
+#endif
+
     switch (*input) {
+        case WOLFSSL_MFL_2_8 : ssl->max_fragment =  256; break;
         case WOLFSSL_MFL_2_9 : ssl->max_fragment =  512; break;
         case WOLFSSL_MFL_2_10: ssl->max_fragment = 1024; break;
@@ -1954,7 +2551,8 @@
 #ifndef NO_WOLFSSL_SERVER
     if (isRequest) {
-        int r = TLSX_UseMaxFragment(&ssl->extensions, *input, ssl->heap);
-
-        if (r != WOLFSSL_SUCCESS) return r; /* throw error */
+        int ret = TLSX_UseMaxFragment(&ssl->extensions, *input, ssl->heap);
+
+        if (ret != WOLFSSL_SUCCESS)
+            return ret; /* throw error */
 
         TLSX_SetResponse(ssl, TLSX_MAX_FRAGMENT_LENGTH);
@@ -1970,18 +2568,15 @@
     int   ret  = 0;
 
-    if (extensions == NULL)
+    if (extensions == NULL || mfl < WOLFSSL_MFL_MIN || mfl > WOLFSSL_MFL_MAX)
         return BAD_FUNC_ARG;
 
-    if (mfl < WOLFSSL_MFL_2_9 || WOLFSSL_MFL_2_13 < mfl)
-        return BAD_FUNC_ARG;
-
-    if ((data = (byte*)XMALLOC(ENUM_LEN, heap, DYNAMIC_TYPE_TLSX)) == NULL)
+    data = (byte*)XMALLOC(ENUM_LEN, heap, DYNAMIC_TYPE_TLSX);
+    if (data == NULL)
         return MEMORY_E;
 
     data[0] = mfl;
 
-    /* push new MFL extension. */
-    if ((ret = TLSX_Push(extensions, TLSX_MAX_FRAGMENT_LENGTH, data, heap))
-                                                                         != 0) {
+    ret = TLSX_Push(extensions, TLSX_MAX_FRAGMENT_LENGTH, data, heap);
+    if (ret != 0) {
         XFREE(data, heap, DYNAMIC_TYPE_TLSX);
         return ret;
@@ -2015,19 +2610,23 @@
                                                                  byte isRequest)
 {
-    (void)isRequest;
-
     if (length != 0 || input == NULL)
         return BUFFER_ERROR;
 
+    if (!isRequest) {
+    #ifndef WOLFSSL_OLD_UNSUPPORTED_EXTENSION
+        if (TLSX_CheckUnsupportedExtension(ssl, TLSX_TRUNCATED_HMAC))
+            return TLSX_HandleUnsupportedExtension(ssl);
+    #endif
+    }
+    else {
 #ifndef NO_WOLFSSL_SERVER
-    if (isRequest) {
-        int r = TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap);
-
-        if (r != WOLFSSL_SUCCESS)
-            return r; /* throw error */
+            int ret = TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap);
+
+            if (ret != WOLFSSL_SUCCESS)
+                return ret; /* throw error */
 
         TLSX_SetResponse(ssl, TLSX_TRUNCATED_HMAC);
-    }
-#endif
+#endif
+    }
 
     ssl->truncated_hmac = 1;
@@ -2043,5 +2642,6 @@
         return BAD_FUNC_ARG;
 
-    if ((ret = TLSX_Push(extensions, TLSX_TRUNCATED_HMAC, NULL, heap)) != 0)
+    ret = TLSX_Push(extensions, TLSX_TRUNCATED_HMAC, NULL, heap);
+    if (ret != 0)
         return ret;
 
@@ -2092,4 +2692,15 @@
             break;
         }
+    }
+#endif
+#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+    if (!isRequest && csr->ssl->options.tls1_3) {
+        if (csr->response.buffer == NULL) {
+            OcspRequest* request = &csr->request.ocsp;
+            int ret = CreateOcspResponse(csr->ssl, &request, &csr->response);
+            if (ret < 0)
+                return ret;
+        }
+        return OPAQUE8_LEN + OPAQUE24_LEN + csr->response.length;
     }
 #endif
@@ -2134,4 +2745,15 @@
     }
 #endif
+#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+    if (!isRequest && csr->ssl->options.tls1_3) {
+        word16 offset = 0;
+        output[offset++] = csr->status_type;
+        c32to24(csr->response.length, output + offset);
+        offset += OPAQUE24_LEN;
+        XMEMCPY(output + offset, csr->response.buffer, csr->response.length);
+        offset += csr->response.length;
+        return offset;
+    }
+#endif
 
     return 0;
@@ -2157,11 +2779,11 @@
             csr = extension ? (CertificateStatusRequest*)extension->data : NULL;
 
-            if (!csr)
-                return BUFFER_ERROR; /* unexpected extension */
+            if (!csr) /* unexpected extension */
+                return TLSX_HandleUnsupportedExtension(ssl);
 
             /* enable extension at ssl level */
             ret = TLSX_UseCertificateStatusRequest(&ssl->extensions,
-                                     csr->status_type, csr->options, ssl->heap,
-                                     ssl->devId);
+                                     csr->status_type, csr->options, ssl,
+                                     ssl->heap, ssl->devId);
             if (ret != WOLFSSL_SUCCESS)
                 return ret;
@@ -2186,5 +2808,32 @@
         ssl->status_request = 1;
 
-        return length ? BUFFER_ERROR : 0; /* extension_data MUST be empty. */
+    #ifdef WOLFSSL_TLS13
+        if (ssl->options.tls1_3) {
+            word32       resp_length;
+            word32       offset = 0;
+            ret = 0;
+            if (OPAQUE8_LEN + OPAQUE24_LEN > length)
+                ret = BUFFER_ERROR;
+            if (ret == 0 && input[offset++] != WOLFSSL_CSR_OCSP)
+                ret = BAD_CERTIFICATE_STATUS_ERROR;
+            if (ret == 0) {
+                c24to32(input + offset, &resp_length);
+                offset += OPAQUE24_LEN;
+                if (offset + resp_length != length)
+                    ret = BUFFER_ERROR;
+            }
+            if (ret == 0) {
+                csr->response.buffer = input + offset;
+                csr->response.length = resp_length;
+            }
+
+            return ret;
+        }
+        else
+    #endif
+        {
+            /* extension_data MUST be empty. */
+            return length ? BUFFER_ERROR : 0;
+        }
 #endif
     }
@@ -2239,5 +2888,5 @@
         /* accept the first good status_type and return */
         ret = TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type,
-                                                      0, ssl->heap, ssl->devId);
+                                                 0, ssl, ssl->heap, ssl->devId);
         if (ret != WOLFSSL_SUCCESS)
             return ret; /* throw error */
@@ -2245,5 +2894,4 @@
         TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST);
         ssl->status_request = status_type;
-
 #endif
     }
@@ -2323,5 +2971,6 @@
 
 int TLSX_UseCertificateStatusRequest(TLSX** extensions, byte status_type,
-                                           byte options, void* heap, int devId)
+                                         byte options, WOLFSSL* ssl, void* heap,
+                                                                      int devId)
 {
     CertificateStatusRequest* csr = NULL;
@@ -2340,4 +2989,5 @@
     csr->status_type = status_type;
     csr->options     = options;
+    csr->ssl         = ssl;
 
     switch (csr->status_type) {
@@ -2519,11 +3169,12 @@
                         (CertificateStatusRequestItemV2*)extension->data : NULL;
 
-            if (!csr2)
-                return BUFFER_ERROR; /* unexpected extension */
+            if (!csr2) /* unexpected extension */
+                return TLSX_HandleUnsupportedExtension(ssl);
 
             /* enable extension at ssl level */
             for (; csr2; csr2 = csr2->next) {
                 ret = TLSX_UseCertificateStatusRequestV2(&ssl->extensions,
-                       csr2->status_type, csr2->options, ssl->heap, ssl->devId);
+                                    csr2->status_type, csr2->options, ssl->heap,
+                                                                    ssl->devId);
                 if (ret != WOLFSSL_SUCCESS)
                     return ret;
@@ -2566,4 +3217,8 @@
 
         /* list size */
+        if (offset + OPAQUE16_LEN >= length) {
+            return BUFFER_E;
+        }
+
         ato16(input + offset, &request_length);
         offset += OPAQUE16_LEN;
@@ -2819,5 +3474,5 @@
 #ifdef HAVE_SUPPORTED_CURVES
 
-#ifndef HAVE_ECC
+#if !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) && !defined(WOLFSSL_TLS13)
 #error Elliptic Curves Extension requires Elliptic Curve Cryptography. \
        Use --enable-ecc in the configure script or define HAVE_ECC.
@@ -2829,4 +3484,6 @@
     if (curve == NULL)
         return BAD_FUNC_ARG;
+
+    (void)heap;
 
     *curve = (SupportedCurve*)XMALLOC(sizeof(SupportedCurve), heap,
@@ -2846,4 +3503,6 @@
         return BAD_FUNC_ARG;
 
+    (void)heap;
+
     *point = (PointFormat*)XMALLOC(sizeof(PointFormat), heap,
                                                              DYNAMIC_TYPE_TLSX);
@@ -2882,39 +3541,45 @@
                                                                      void* heap)
 {
-    if (list == NULL)
-        return BAD_FUNC_ARG;
-
-    while (1) {
-        if (list->name == name)
-            return 0; /* curve alreay in use */
-
-        if (list->next == NULL)
-            return TLSX_SupportedCurve_New(&list->next, name, heap);
+    int ret = BAD_FUNC_ARG;
+
+    while (list) {
+        if (list->name == name) {
+            ret = 0; /* curve alreay in use */
+            break;
+        }
+
+        if (list->next == NULL) {
+            ret = TLSX_SupportedCurve_New(&list->next, name, heap);
+            break;
+        }
 
         list = list->next;
     }
 
-    return 0;
+    return ret;
 }
 
 static int TLSX_PointFormat_Append(PointFormat* list, byte format, void* heap)
 {
-    if (list == NULL)
-        return BAD_FUNC_ARG;
-
-    while (1) {
-        if (list->format == format)
-            return 0; /* format already in use */
-
-        if (list->next == NULL)
-            return TLSX_PointFormat_New(&list->next, format, heap);
+    int ret = BAD_FUNC_ARG;
+
+    while (list) {
+        if (list->format == format) {
+            ret = 0; /* format already in use */
+            break;
+        }
+
+        if (list->next == NULL) {
+            ret = TLSX_PointFormat_New(&list->next, format, heap);
+            break;
+        }
 
         list = list->next;
     }
 
-    return 0;
-}
-
-#ifndef NO_WOLFSSL_CLIENT
+    return ret;
+}
+
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
 
 static void TLSX_SupportedCurve_ValidateRequest(WOLFSSL* ssl, byte* semaphore)
@@ -2947,4 +3612,5 @@
 
 #endif
+
 #ifndef NO_WOLFSSL_SERVER
 
@@ -3019,10 +3685,11 @@
     }
 
-    output[0] = offset - ENUM_LEN;
+    output[0] = (byte)(offset - ENUM_LEN);
 
     return offset;
 }
 
-#ifndef NO_WOLFSSL_SERVER
+#if !defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \
+                                         !defined(WOLFSSL_NO_SERVER_GROUPS_EXT))
 
 static int TLSX_SupportedCurve_Parse(WOLFSSL* ssl, byte* input, word16 length,
@@ -3033,5 +3700,11 @@
     int ret;
 
-    (void) isRequest; /* shut up compiler! */
+    if(!isRequest && !IsAtLeastTLSv1_3(ssl->version)) {
+#ifdef WOLFSSL_ALLOW_SERVER_SC_EXT
+        return 0;
+#else
+        return BUFFER_ERROR; /* servers doesn't send this extension. */
+#endif
+    }
 
     if (OPAQUE16_LEN > length || length % OPAQUE16_LEN)
@@ -3044,9 +3717,35 @@
         return BUFFER_ERROR;
 
-    for (offset = OPAQUE16_LEN; offset < length; offset += OPAQUE16_LEN) {
+    offset = OPAQUE16_LEN;
+    if (offset == length)
+        return 0;
+
+#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)
+    if (!isRequest) {
+        TLSX* extension;
+        SupportedCurve* curve;
+
+        extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
+        if (extension != NULL) {
+            /* Replace client list with server list of supported groups. */
+            curve = (SupportedCurve*)extension->data;
+            extension->data = NULL;
+            TLSX_SupportedCurve_FreeAll(curve, ssl->heap);
+
         ato16(input + offset, &name);
+            offset += OPAQUE16_LEN;
+
+            ret = TLSX_SupportedCurve_New(&curve, name, ssl->heap);
+            if (ret != 0)
+                return ret; /* throw error */
+            extension->data = (void*)curve;
+        }
+    }
+#endif
+
+    for (; offset < length; offset += OPAQUE16_LEN) {
+        ato16(input + offset, &name);
 
         ret = TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap);
-
         if (ret != WOLFSSL_SUCCESS)
             return ret; /* throw error */
@@ -3055,4 +3754,90 @@
     return 0;
 }
+
+#endif
+
+#if !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
+                                          !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)
+
+/* Checks the priority of the groups on the server and set the supported groups
+ * response if there is a group not advertised by the client that is preferred.
+ *
+ * ssl  SSL/TLS object.
+ * returns 0 on success, otherwise an error.
+ */
+int TLSX_SupportedCurve_CheckPriority(WOLFSSL* ssl)
+{
+    int ret;
+    TLSX* extension;
+    TLSX* priority = NULL;
+    TLSX* ext = NULL;
+    word16 name;
+    SupportedCurve* curve;
+
+    extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
+    /* May be doing PSK with no key exchange. */
+    if (extension == NULL)
+        return 0;
+
+    if ((ret = TLSX_PopulateSupportedGroups(ssl, &priority)) != WOLFSSL_SUCCESS)
+        return ret;
+
+    ext = TLSX_Find(priority, TLSX_SUPPORTED_GROUPS);
+    curve = (SupportedCurve*)ext->data;
+    name = curve->name;
+
+    curve = (SupportedCurve*)extension->data;
+    while (curve != NULL) {
+        if (curve->name == name)
+            break;
+        curve = curve->next;
+    }
+
+    if (curve == NULL) {
+        /* Couldn't find the preferred group in client list. */
+        extension->resp = 1;
+
+        /* Send server list back and free client list. */
+        curve = (SupportedCurve*)extension->data;
+        extension->data = ext->data;
+        ext->data = curve;
+    }
+
+    TLSX_FreeAll(priority, ssl->heap);
+
+    return 0;
+}
+
+#endif
+
+#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)
+/* Return the preferred group.
+ *
+ * ssl             SSL/TLS object.
+ * checkSupported  Whether to check for the first supported group.
+ * returns BAD_FUNC_ARG if no group found, otherwise the group.
+ */
+int TLSX_SupportedCurve_Preferred(WOLFSSL* ssl, int checkSupported)
+{
+    TLSX* extension;
+    SupportedCurve* curve;
+
+    extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
+    if (extension == NULL)
+        return BAD_FUNC_ARG;
+
+    curve = (SupportedCurve*)extension->data;
+    while (curve != NULL) {
+        if (!checkSupported || TLSX_KeyShare_IsSupported(curve->name))
+            return curve->name;
+        curve = curve->next;
+    }
+
+    return BAD_FUNC_ARG;
+}
+
+#endif
+
+#ifndef NO_WOLFSSL_SERVER
 
 static int TLSX_PointFormat_Parse(WOLFSSL* ssl, byte* input, word16 length,
@@ -3078,4 +3863,5 @@
 }
 
+#if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
 int TLSX_ValidateSupportedCurves(WOLFSSL* ssl, byte first, byte second) {
     TLSX*          extension = (first == ECC_BYTE || first == CHACHA_BYTE)
@@ -3111,4 +3897,5 @@
         /* find supported curve */
         switch (curve->name) {
+#ifdef HAVE_ECC
     #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)
         #ifndef NO_ECC_SECP
@@ -3166,4 +3953,6 @@
                 break;
         #endif /* !NO_ECC_SECP */
+    #endif /* !NO_ECC256 || HAVE_ALL_CURVES */
+#endif
         #ifdef HAVE_CURVE25519
             case WOLFSSL_ECC_X25519:
@@ -3177,4 +3966,6 @@
                 break;
         #endif /* HAVE_CURVE25519 */
+#ifdef HAVE_ECC
+    #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
         #ifdef HAVE_ECC_KOBLITZ
             case WOLFSSL_ECC_SECP256K1:
@@ -3220,7 +4011,9 @@
         #endif /* !NO_ECC_SECP */
     #endif
+#endif
             default: continue; /* unsupported curve */
         }
 
+    #ifdef HAVE_ECC
         /* Set default Oid */
         if (defOid == 0 && ssl->eccTempKeySz <= octets && defSz > octets) {
@@ -3229,4 +4022,5 @@
         }
 
+        /* The eccTempKeySz is the preferred ephemeral key size */
         if (currOid == 0 && ssl->eccTempKeySz == octets)
             currOid = oid;
@@ -3235,4 +4029,17 @@
             nextSz  = octets;
         }
+    #else
+        if (defOid == 0 && defSz > octets) {
+            defOid = oid;
+            defSz = octets;
+        }
+
+        if (currOid == 0)
+            currOid = oid;
+        if (nextOid == 0 || nextSz > octets) {
+            nextOid = oid;
+            nextSz  = octets;
+        }
+    #endif
 
         if (first == ECC_BYTE) {
@@ -3346,5 +4153,10 @@
 
     /* Choose the default if it is at the required strength. */
-    if (ssl->ecdhCurveOID == 0 && defSz == ssl->eccTempKeySz) {
+#ifdef HAVE_ECC
+    if (ssl->ecdhCurveOID == 0 && defSz == ssl->eccTempKeySz)
+#else
+    if (ssl->ecdhCurveOID == 0)
+#endif
+    {
         key = 1;
         ssl->ecdhCurveOID = defOid;
@@ -3367,4 +4179,5 @@
     return sig && key;
 }
+#endif
 
 #endif /* NO_WOLFSSL_SERVER */
@@ -3374,5 +4187,5 @@
     TLSX* extension = NULL;
     SupportedCurve* curve = NULL;
-    int ret = 0;
+    int ret;
 
     if (extensions == NULL)
@@ -3399,7 +4212,5 @@
     }
 
-    return (TLSX_Find(*extensions, TLSX_EC_POINT_FORMATS) == NULL)
-        ? TLSX_UsePointFormat(extensions, WOLFSSL_EC_PF_UNCOMPRESSED, heap)
-        : WOLFSSL_SUCCESS;
+    return WOLFSSL_SUCCESS;
 }
 
@@ -3447,5 +4258,6 @@
 #endif
 
-#ifndef NO_WOLFSSL_SERVER
+#if !defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \
+                                         !defined(WOLFSSL_NO_SERVER_GROUPS_EXT))
 #define EC_PARSE TLSX_SupportedCurve_Parse
 #else
@@ -3496,5 +4308,5 @@
 
     /* data will be NULL for HAVE_SERVER_RENEGOTIATION_INFO only */
-    if (data && data->enabled) {
+    if (data && data->enabled && data->verifySet) {
         /* client sends client_verify_data only */
         length += TLS_FINISHED_SZ;
@@ -3512,6 +4324,5 @@
 {
     word16 offset = OPAQUE8_LEN; /* RenegotiationInfo length */
-
-    if (data && data->enabled) {
+    if (data && data->enabled && data->verifySet) {
         /* client sends client_verify_data only */
         XMEMCPY(output + offset, data->client_verify_data, TLS_FINISHED_SZ);
@@ -3536,37 +4347,37 @@
 
     if (length >= OPAQUE8_LEN) {
-        if (ssl->secure_renegotiation == NULL) {
+        if (isRequest) {
         #ifndef NO_WOLFSSL_SERVER
-            if (isRequest && *input == 0) {
-            #ifdef HAVE_SERVER_RENEGOTIATION_INFO
-                if (length == OPAQUE8_LEN) {
-                    if (TLSX_Find(ssl->extensions,
-                                  TLSX_RENEGOTIATION_INFO) == NULL) {
-                        ret = TLSX_AddEmptyRenegotiationInfo(&ssl->extensions,
-                                                             ssl->heap);
-                        if (ret == WOLFSSL_SUCCESS)
-                            ret = 0;
-
-                    } else {
+            if (ssl->secure_renegotiation == NULL) {
+                /* already in error state */
+                WOLFSSL_MSG("server SCR not available");
+            }
+            else if (!ssl->secure_renegotiation->enabled) {
+                if (*input == 0) {
+                    input++; /* get past size */
+
+                    ssl->secure_renegotiation->enabled = 1;
+                    TLSX_SetResponse(ssl, TLSX_RENEGOTIATION_INFO);
                         ret = 0;
                     }
+                else {
+                    /* already in error state */
+                    WOLFSSL_MSG("SCR client verify data present");
                 }
-            #else
-                ret = 0;  /* don't reply, user didn't enable */
-            #endif /* HAVE_SERVER_RENEGOTIATION_INFO */
             }
-            #ifdef HAVE_SERVER_RENEGOTIATION_INFO
-            else if (!isRequest) {
-                /* don't do anything on client side */
-                ret = 0;
-            }
-            #endif
-        #endif
-        }
-        else if (isRequest) {
-        #ifndef NO_WOLFSSL_SERVER
-            if (*input == TLS_FINISHED_SZ) {
-                /* TODO compare client_verify_data */
-                ret = 0;
+            else if (*input == TLS_FINISHED_SZ) {
+                input++; /* get past size */
+
+                /* validate client verify data */
+                if (XMEMCMP(input,
+                            ssl->secure_renegotiation->client_verify_data,
+                            TLS_FINISHED_SZ) == 0) {
+                    WOLFSSL_MSG("SCR client verify data match");
+                    TLSX_SetResponse(ssl, TLSX_RENEGOTIATION_INFO);
+                    ret = 0;  /* verified */
+                } else {
+                    /* already in error state */
+                    WOLFSSL_MSG("SCR client verify data Failure");
+        }
             }
         #endif
@@ -3632,12 +4443,6 @@
 #ifdef HAVE_SERVER_RENEGOTIATION_INFO
 
-int TLSX_AddEmptyRenegotiationInfo(TLSX** extensions, void* heap)
-{
-    int ret;
-
-    ret = TLSX_Push(extensions, TLSX_RENEGOTIATION_INFO, NULL, heap);
-    if (ret != 0)
-        return ret;
-
+int TLSX_AddEmptyRenegotiationInfo(TLSX** extensions)
+{
     /* send empty renegotiation_info extension */
     TLSX* ext = TLSX_Find(*extensions, TLSX_RENEGOTIATION_INFO);
@@ -3671,5 +4476,5 @@
 #ifdef HAVE_SESSION_TICKET
 
-#ifndef NO_WOLFSSL_CLIENT
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
 static void TLSX_SessionTicket_ValidateRequest(WOLFSSL* ssl)
 {
@@ -3686,5 +4491,5 @@
     }
 }
-#endif /* NO_WOLFSSL_CLIENT */
+#endif /* WLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */
 
 
@@ -3717,5 +4522,7 @@
 
     if (!isRequest) {
-        /* client side */
+        if (TLSX_CheckUnsupportedExtension(ssl, TLSX_SESSION_TICKET))
+            return TLSX_HandleUnsupportedExtension(ssl);
+
         if (length != 0)
             return BUFFER_ERROR;
@@ -4441,16 +5248,22 @@
  *
  * data       The SSL/TLS object.
+ * msgType The type of the message this extension is being written into.
  * returns the length of data that will be in the extension.
  */
-static word16 TLSX_SupportedVersions_GetSize(void* data)
+static int TLSX_SupportedVersions_GetSize(void* data, byte msgType, word16* pSz)
 {
     WOLFSSL* ssl = (WOLFSSL*)data;
 
+    if (msgType == client_hello) {
     /* TLS v1.2 and TLS v1.3  */
     int cnt = 2;
 
 #ifndef NO_OLD_TLS
-    /* TLS v1 and TLS v1.1  */
-    cnt += 2;
+        /* TLS v1.1  */
+        cnt++;
+    #ifdef WOLFSSL_ALLOW_TLSV10
+        /* TLS v1.0  */
+        cnt++;
+    #endif
 #endif
 
@@ -4458,5 +5271,14 @@
        cnt = 1;
 
-    return OPAQUE8_LEN + cnt * OPAQUE16_LEN;
+        *pSz += (word16)(OPAQUE8_LEN + cnt * OPAQUE16_LEN);
+    }
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    else if (msgType == server_hello || msgType == hello_retry_request)
+        *pSz += OPAQUE16_LEN;
+#endif
+    else
+        return SANITY_MSG_E;
+
+    return 0;
 }
 
@@ -4465,17 +5287,27 @@
  * data    The SSL/TLS object.
  * output  The buffer to write the extension into.
+ * msgType The type of the message this extension is being written into.
  * returns the length of data that was written.
  */
-static word16 TLSX_SupportedVersions_Write(void* data, byte* output)
+static int TLSX_SupportedVersions_Write(void* data, byte* output,
+                                           byte msgType, word16* pSz)
 {
     WOLFSSL* ssl = (WOLFSSL*)data;
-    ProtocolVersion pv = ssl->ctx->method->version;
+    ProtocolVersion pv;
     int i;
+    int cnt;
+
+    if (msgType == client_hello) {
+        pv = ssl->ctx->method->version;
     /* TLS v1.2 and TLS v1.3  */
-    int cnt = 2;
+        cnt = 2;
 
 #ifndef NO_OLD_TLS
-    /* TLS v1 and TLS v1.1  */
-    cnt += 2;
+        /* TLS v1.1  */
+        cnt++;
+    #ifdef WOLFSSL_ALLOW_TLSV10
+        /* TLS v1.0  */
+        cnt++;
+    #endif
 #endif
 
@@ -4483,7 +5315,7 @@
        cnt = 1;
 
-    *(output++) = cnt * OPAQUE16_LEN;
+        *(output++) = (byte)(cnt * OPAQUE16_LEN);
     for (i = 0; i < cnt; i++) {
-        /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */
+#ifdef WOLFSSL_TLS13_DRAFT
         if (pv.minor - i == TLSv1_3_MINOR) {
             /* The TLS draft major number. */
@@ -4493,10 +5325,34 @@
             continue;
         }
+#endif
 
         *(output++) = pv.major;
-        *(output++) = pv.minor - i;
-    }
-
-    return OPAQUE8_LEN + cnt * OPAQUE16_LEN;
+            *(output++) = (byte)(pv.minor - i);
+        }
+
+        *pSz += (word16)(OPAQUE8_LEN + cnt * OPAQUE16_LEN);
+    }
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    else if (msgType == server_hello || msgType == hello_retry_request) {
+    #ifdef WOLFSSL_TLS13_DRAFT
+        if (ssl->version.major == SSLv3_MAJOR &&
+                                          ssl->version.minor == TLSv1_3_MINOR) {
+            output[0] = TLS_DRAFT_MAJOR;
+            output[1] = TLS_DRAFT_MINOR;
+        }
+        else
+    #endif
+        {
+            output[0] = ssl->version.major;
+            output[1] = ssl->version.minor;
+        }
+
+        *pSz += OPAQUE16_LEN;
+    }
+#endif
+    else
+        return SANITY_MSG_E;
+
+    return 0;
 }
 
@@ -4506,15 +5362,17 @@
  * input   The buffer with the extension data.
  * length  The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
  * returns 0 on success, otherwise failure.
  */
 static int TLSX_SupportedVersions_Parse(WOLFSSL *ssl, byte* input,
-                                        word16 length)
+                                        word16 length, byte msgType)
 {
     ProtocolVersion pv = ssl->ctx->method->version;
     int i;
-    int ret = VERSION_ERROR;
     int len;
     byte major, minor;
-
+    int newMinor = 0;
+
+    if (msgType == client_hello) {
     /* Must contain a length and at least one version. */
     if (length < OPAQUE8_LEN + OPAQUE16_LEN || (length & 1) != 1)
@@ -4534,9 +5392,10 @@
         minor = input[i + OPAQUE8_LEN];
 
-        /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */
+#ifdef WOLFSSL_TLS13_DRAFT
         if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) {
             major = SSLv3_MAJOR;
             minor = TLSv1_3_MINOR;
         }
+#endif
 
         if (major != pv.major)
@@ -4544,29 +5403,88 @@
 
         /* No upgrade allowed. */
-        if (ssl->version.minor > minor)
+            if (minor > ssl->version.minor)
                 continue;
         /* Check downgrade. */
-        if (ssl->version.minor < minor) {
+            if (minor < ssl->version.minor) {
             if (!ssl->options.downgrade)
                 continue;
 
-#ifdef NO_OLD_TLS
-            if (minor < TLSv1_2_MINOR)
+                if (minor < ssl->options.minDowngrade)
                 continue;
-#endif
+
+                if (newMinor == 0 && minor > ssl->options.oldMinor) {
             /* Downgrade the version. */
             ssl->version.minor = minor;
         }
+            }
 
         if (minor >= TLSv1_3_MINOR) {
+                if (!ssl->options.tls1_3) {
             ssl->options.tls1_3 = 1;
-            TLSX_Push(&ssl->extensions, TLSX_SUPPORTED_VERSIONS, input,
+                    TLSX_Push(&ssl->extensions, TLSX_SUPPORTED_VERSIONS, ssl,
                       ssl->heap);
-        }
-        ret = 0;
-        break;
-    }
-
-    return ret;
+#ifndef WOLFSSL_TLS13_DRAFT_18
+                    TLSX_SetResponse(ssl, TLSX_SUPPORTED_VERSIONS);
+#endif
+        }
+                if (minor > newMinor) {
+                    ssl->version.minor = minor;
+                    newMinor = minor;
+                }
+            }
+            else if (minor > ssl->options.oldMinor)
+                ssl->options.oldMinor = minor;
+        }
+    }
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    else if (msgType == server_hello || msgType == hello_retry_request) {
+        /* Must contain one version. */
+        if (length != OPAQUE16_LEN)
+            return BUFFER_ERROR;
+
+        major = input[0];
+        minor = input[OPAQUE8_LEN];
+
+    #ifdef WOLFSSL_TLS13_DRAFT
+        if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) {
+            major = SSLv3_MAJOR;
+            minor = TLSv1_3_MINOR;
+        }
+    #endif
+
+        if (major != pv.major)
+            return VERSION_ERROR;
+
+        /* Can't downgrade with this extension below TLS v1.3. */
+        if (minor < TLSv1_3_MINOR)
+            return VERSION_ERROR;
+
+        /* Version is TLS v1.2 to handle downgrading from TLS v1.3+. */
+        if (ssl->options.downgrade && ssl->version.minor == TLSv1_2_MINOR) {
+            /* Set minor version back to TLS v1.3+ */
+            ssl->version.minor = ssl->ctx->method->version.minor;
+    }
+
+        /* No upgrade allowed. */
+        if (ssl->version.minor < minor)
+            return VERSION_ERROR;
+
+        /* Check downgrade. */
+        if (ssl->version.minor > minor) {
+            if (!ssl->options.downgrade)
+                return VERSION_ERROR;
+
+            if (minor < ssl->options.minDowngrade)
+                return VERSION_ERROR;
+
+            /* Downgrade the version. */
+            ssl->version.minor = minor;
+        }
+    }
+#endif
+    else
+        return SANITY_MSG_E;
+
+    return 0;
 }
 
@@ -4593,7 +5511,7 @@
 #else
 
-#define SV_GET_SIZE(a)       0
-#define SV_WRITE(a, b)       0
-#define SV_PARSE(a, b, c)    0
+#define SV_GET_SIZE(a, b, c) 0
+#define SV_WRITE(a, b, c, d) 0
+#define SV_PARSE(a, b, c, d) 0
 
 #endif /* WOLFSSL_TLS13 */
@@ -4625,10 +5543,11 @@
  * returns the number of bytes of the encoded Cookie extension.
  */
-static word16 TLSX_Cookie_GetSize(Cookie* cookie, byte msgType)
+static int TLSX_Cookie_GetSize(Cookie* cookie, byte msgType, word16* pSz)
 {
     if (msgType == client_hello || msgType == hello_retry_request)
-        return OPAQUE16_LEN + cookie->len;
-
+        *pSz += OPAQUE16_LEN + cookie->len;
+    else
     return SANITY_MSG_E;
+    return 0;
 }
 
@@ -4642,5 +5561,5 @@
  * returns the number of bytes written into the buffer.
  */
-static word16 TLSX_Cookie_Write(Cookie* cookie, byte* output, byte msgType)
+static int TLSX_Cookie_Write(Cookie* cookie, byte* output, byte msgType, word16* pSz)
 {
     if (msgType == client_hello || msgType == hello_retry_request) {
@@ -4648,8 +5567,9 @@
         output += OPAQUE16_LEN;
         XMEMCPY(output, &cookie->data, cookie->len);
-        return OPAQUE16_LEN + cookie->len;
-    }
-
+        *pSz += OPAQUE16_LEN + cookie->len;
+    }
+    else
     return SANITY_MSG_E;
+    return 0;
 }
 
@@ -4744,5 +5664,5 @@
 
     extension->data = (void*)cookie;
-    extension->resp = resp;
+    extension->resp = (byte)resp;
 
     return 0;
@@ -4757,6 +5677,6 @@
 
 #define CKE_FREE_ALL(a, b)    0
-#define CKE_GET_SIZE(a, b)    0
-#define CKE_WRITE(a, b, c)    0
+#define CKE_GET_SIZE(a, b, c) 0
+#define CKE_WRITE(a, b, c, d) 0
 #define CKE_PARSE(a, b, c, d) 0
 
@@ -4764,5 +5684,5 @@
 
 /******************************************************************************/
-/* Sugnature Algorithms                                                       */
+/* Signature Algorithms                                                       */
 /******************************************************************************/
 
@@ -4790,5 +5710,5 @@
  */
 static int TLSX_SignatureAlgorithms_MapPss(WOLFSSL *ssl, byte* input,
-                                           word16 length)
+                                                                  word16 length)
 {
     word16 i;
@@ -4834,9 +5754,10 @@
  */
 static int TLSX_SignatureAlgorithms_Parse(WOLFSSL *ssl, byte* input,
-                                          word16 length, Suites* suites)
+                                  word16 length, byte isRequest, Suites* suites)
 {
     word16 len;
 
-    (void)ssl;
+    if (!isRequest)
+        return BUFFER_ERROR;
 
     /* Must contain a length and at least algorithm. */
@@ -4851,11 +5772,16 @@
         return BUFFER_ERROR;
 
-    XMEMCPY(suites->hashSigAlgo, input, len);
+    /* truncate hashSigAlgo list if too long */
     suites->hashSigAlgoSz = len;
+    if (suites->hashSigAlgoSz > WOLFSSL_MAX_SIGALGO) {
+        WOLFSSL_MSG("TLSX SigAlgo list exceeds max, truncating");
+        suites->hashSigAlgoSz = WOLFSSL_MAX_SIGALGO;
+    }
+    XMEMCPY(suites->hashSigAlgo, input, suites->hashSigAlgoSz);
 
     return TLSX_SignatureAlgorithms_MapPss(ssl, input, len);
 }
 
-/* Sets a new SupportedVersions extension into the extension list.
+/* Sets a new SignatureAlgorithms extension into the extension list.
  *
  * extensions  The list of extensions.
@@ -4877,4 +5803,99 @@
 #define SA_PARSE     TLSX_SignatureAlgorithms_Parse
 
+/******************************************************************************/
+/* Signature Algorithms Certificate                                           */
+/******************************************************************************/
+
+#ifdef WOLFSSL_TLS13
+#if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+/* Return the size of the SignatureAlgorithms extension's data.
+ *
+ * data  Unused
+ * returns the length of data that will be in the extension.
+ */
+static word16 TLSX_SignatureAlgorithmsCert_GetSize(void* data)
+{
+    WOLFSSL* ssl = (WOLFSSL*)data;
+
+    return OPAQUE16_LEN + ssl->certHashSigAlgoSz;
+}
+
+/* Writes the SignatureAlgorithmsCert extension into the buffer.
+ *
+ * data    Unused
+ * output  The buffer to write the extension into.
+ * returns the length of data that was written.
+ */
+static word16 TLSX_SignatureAlgorithmsCert_Write(void* data, byte* output)
+{
+    WOLFSSL* ssl = (WOLFSSL*)data;
+
+    c16toa(ssl->certHashSigAlgoSz, output);
+    XMEMCPY(output + OPAQUE16_LEN, ssl->certHashSigAlgo,
+            ssl->certHashSigAlgoSz);
+
+    return OPAQUE16_LEN + ssl->certHashSigAlgoSz;
+}
+
+/* Parse the SignatureAlgorithmsCert extension.
+ *
+ * ssl     The SSL/TLS object.
+ * input   The buffer with the extension data.
+ * length  The length of the extension data.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_SignatureAlgorithmsCert_Parse(WOLFSSL *ssl, byte* input,
+                                              word16 length, byte isRequest)
+{
+    word16 len;
+
+    if (!isRequest)
+        return BUFFER_ERROR;
+
+    /* Must contain a length and at least algorithm. */
+    if (length < OPAQUE16_LEN + OPAQUE16_LEN || (length & 1) != 0)
+        return BUFFER_ERROR;
+
+    ato16(input, &len);
+    input += OPAQUE16_LEN;
+
+    /* Algorithm array must fill rest of data. */
+    if (length != OPAQUE16_LEN + len)
+        return BUFFER_ERROR;
+
+    /* truncate hashSigAlgo list if too long */
+    ssl->certHashSigAlgoSz = len;
+    if (ssl->certHashSigAlgoSz > WOLFSSL_MAX_SIGALGO) {
+        WOLFSSL_MSG("TLSX SigAlgo list exceeds max, truncating");
+        ssl->certHashSigAlgoSz = WOLFSSL_MAX_SIGALGO;
+    }
+    XMEMCPY(ssl->certHashSigAlgo, input, ssl->certHashSigAlgoSz);
+
+    return 0;
+}
+
+/* Sets a new SignatureAlgorithmsCert extension into the extension list.
+ *
+ * extensions  The list of extensions.
+ * data        The extensions specific data.
+ * heap        The heap used for allocation.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_SetSignatureAlgorithmsCert(TLSX** extensions, const void* data,
+                                       void* heap)
+{
+    if (extensions == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_Push(extensions, TLSX_SIGNATURE_ALGORITHMS_CERT, (void *)data,
+                                                                          heap);
+}
+
+#define SAC_GET_SIZE  TLSX_SignatureAlgorithmsCert_GetSize
+#define SAC_WRITE     TLSX_SignatureAlgorithmsCert_Write
+#define SAC_PARSE     TLSX_SignatureAlgorithmsCert_Parse
+#endif /* !WOLFSSL_TLS13_DRAFT_18 && !WOLFSSL_TLS13_DRAFT_22 */
+#endif /* WOLFSSL_TLS13 */
+
 
 /******************************************************************************/
@@ -4883,5 +5904,4 @@
 
 #ifdef WOLFSSL_TLS13
-#ifndef NO_DH
 /* Create a key share entry using named Diffie-Hellman parameters group.
  * Generates a key pair.
@@ -4894,4 +5914,5 @@
 {
     int             ret;
+#ifndef NO_DH
     byte*           keyData;
     void*           key = NULL;
@@ -4899,5 +5920,9 @@
     word32          dataSz;
     const DhParams* params;
-    DhKey dhKey;
+#ifdef WOLFSSL_SMALL_STACK
+    DhKey*          dhKey = NULL;
+#else
+    DhKey           dhKey[1];
+#endif
 
     /* TODO: [TLS13] The key size should come from wolfcrypt. */
@@ -4938,7 +5963,17 @@
     }
 
-    ret = wc_InitDhKey_ex(&dhKey, ssl->heap, ssl->devId);
-    if (ret != 0)
+#ifdef WOLFSSL_SMALL_STACK
+    dhKey = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap, DYNAMIC_TYPE_DH);
+    if (dhKey == NULL)
+        return MEMORY_E;
+#endif
+
+    ret = wc_InitDhKey_ex(dhKey, ssl->heap, ssl->devId);
+    if (ret != 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+    #endif
         return ret;
+    }
 
     /* Allocate space for the public key. */
@@ -4957,5 +5992,5 @@
 
     /* Set key */
-    ret = wc_DhSetKey(&dhKey,
+    ret = wc_DhSetKey(dhKey,
         (byte*)params->p, params->p_len,
         (byte*)params->g, params->g_len);
@@ -4964,10 +5999,10 @@
 
     /* Generate a new key pair. */
-    ret = wc_DhGenerateKeyPair(&dhKey, ssl->rng, (byte*)key, &keySz, keyData,
+    ret = wc_DhGenerateKeyPair(dhKey, ssl->rng, (byte*)key, &keySz, keyData,
                                &dataSz);
 #ifdef WOLFSSL_ASYNC_CRYPT
     /* TODO: Make this function non-blocking */
     if (ret == WC_PENDING_E) {
-        ret = wc_AsyncWait(ret, &dhKey.asyncDev, WC_ASYNC_FLAG_NONE);
+        ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
     }
 #endif
@@ -4981,6 +6016,6 @@
     }
 
-    kse->ke = keyData;
-    kse->keLen = params->p_len;
+    kse->pubKey = keyData;
+    kse->pubKeyLen = params->p_len;
     kse->key = key;
     kse->keyLen = keySz;
@@ -4993,5 +6028,8 @@
 end:
 
-    wc_FreeDhKey(&dhKey);
+    wc_FreeDhKey(dhKey);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+#endif
 
     if (ret != 0) {
@@ -5002,10 +6040,88 @@
             XFREE(key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
     }
+#else
+    (void)ssl;
+    (void)kse;
+
+    ret = NOT_COMPILED_IN;
+#endif
 
     return ret;
 }
-#endif
-
-#ifdef HAVE_ECC
+
+/* Create a key share entry using X25519 parameters group.
+ * Generates a key pair.
+ *
+ * ssl   The SSL/TLS object.
+ * kse   The key share entry object.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_KeyShare_GenX25519Key(WOLFSSL *ssl, KeyShareEntry* kse)
+{
+    int      ret;
+    #ifdef HAVE_CURVE25519
+    byte*           keyData = NULL;
+    word32          dataSize = CURVE25519_KEYSIZE;
+                curve25519_key* key;
+
+                /* Allocate an ECC key to hold private key. */
+                key = (curve25519_key*)XMALLOC(sizeof(curve25519_key),
+                                           ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+                if (key == NULL) {
+                    WOLFSSL_MSG("EccTempKey Memory error");
+                    return MEMORY_E;
+                }
+
+                /* Make an ECC key. */
+                ret = wc_curve25519_init(key);
+                if (ret != 0)
+                    goto end;
+    ret = wc_curve25519_make_key(ssl->rng, CURVE25519_KEYSIZE, key);
+                if (ret != 0)
+                    goto end;
+
+                /* Allocate space for the public key. */
+    keyData = (byte*)XMALLOC(CURVE25519_KEYSIZE, ssl->heap,
+                                         DYNAMIC_TYPE_PUBLIC_KEY);
+                if (keyData == NULL) {
+                    WOLFSSL_MSG("Key data Memory error");
+                    ret = MEMORY_E;
+                    goto end;
+                }
+
+                /* Export public key. */
+                if (wc_curve25519_export_public_ex(key, keyData, &dataSize,
+                                                  EC25519_LITTLE_ENDIAN) != 0) {
+                    ret = ECC_EXPORT_ERROR;
+                    goto end;
+                }
+
+    kse->pubKey = keyData;
+    kse->pubKeyLen = CURVE25519_KEYSIZE;
+                kse->key = key;
+
+#ifdef WOLFSSL_DEBUG_TLS
+                WOLFSSL_MSG("Public Curve25519 Key");
+                WOLFSSL_BUFFER(keyData, dataSize);
+#endif
+
+end:
+    if (ret != 0) {
+        /* Data owned by key share entry otherwise. */
+        if (keyData != NULL)
+            XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+        wc_curve25519_free(key);
+        XFREE(key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+    }
+#else
+    (void)ssl;
+    (void)kse;
+
+    ret = NOT_COMPILED_IN;
+#endif /* HAVE_CURVE25519 */
+
+    return ret;
+            }
+
 /* Create a key share entry using named elliptic curve parameters group.
  * Generates a key pair.
@@ -5018,8 +6134,10 @@
 {
     int      ret;
+#ifdef HAVE_ECC
     byte*    keyData = NULL;
     word32   dataSize;
+    byte*    keyPtr = NULL;
     word32   keySize;
-    ecc_key* eccKey = NULL;
+    ecc_key* eccKey;
     word16   curveId;
 
@@ -5054,54 +6172,4 @@
         #endif /* !NO_ECC_SECP */
     #endif
-    #ifdef HAVE_CURVE25519
-        case WOLFSSL_ECC_X25519:
-            {
-                curve25519_key* key;
-                /* Allocate an ECC key to hold private key. */
-                key = (curve25519_key*)XMALLOC(sizeof(curve25519_key),
-                                           ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
-                if (key == NULL) {
-                    WOLFSSL_MSG("EccTempKey Memory error");
-                    return MEMORY_E;
-                }
-
-                dataSize = keySize = 32;
-
-                /* Make an ECC key. */
-                ret = wc_curve25519_init(key);
-                if (ret != 0)
-                    goto end;
-                ret = wc_curve25519_make_key(ssl->rng, keySize, key);
-                if (ret != 0)
-                    goto end;
-
-                /* Allocate space for the public key. */
-                keyData = (byte*)XMALLOC(dataSize, ssl->heap,
-                                         DYNAMIC_TYPE_PUBLIC_KEY);
-                if (keyData == NULL) {
-                    WOLFSSL_MSG("Key data Memory error");
-                    ret = MEMORY_E;
-                    goto end;
-                }
-
-                /* Export public key. */
-                if (wc_curve25519_export_public_ex(key, keyData, &dataSize,
-                                                  EC25519_LITTLE_ENDIAN) != 0) {
-                    ret = ECC_EXPORT_ERROR;
-                    goto end;
-                }
-
-                kse->ke = keyData;
-                kse->keLen = dataSize;
-                kse->key = key;
-
-#ifdef WOLFSSL_DEBUG_TLS
-                WOLFSSL_MSG("Public Curve25519 Key");
-                WOLFSSL_BUFFER(keyData, dataSize);
-#endif
-
-                goto end;
-            }
-    #endif
     #ifdef HAVE_X448
         case WOLFSSL_ECC_X448:
@@ -5115,10 +6183,11 @@
 
     /* Allocate an ECC key to hold private key. */
-    eccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), ssl->heap,
+    keyPtr = (byte*)XMALLOC(sizeof(ecc_key), ssl->heap,
                                DYNAMIC_TYPE_PRIVATE_KEY);
-    if (eccKey == NULL) {
+    if (keyPtr == NULL) {
         WOLFSSL_MSG("EccTempKey Memory error");
         return MEMORY_E;
     }
+    eccKey = (ecc_key*)keyPtr;
 
     /* Make an ECC key. */
@@ -5150,7 +6219,7 @@
     }
 
-    kse->ke = keyData;
-    kse->keLen = dataSize;
-    kse->key = eccKey;
+    kse->pubKey = keyData;
+    kse->pubKeyLen = dataSize;
+    kse->key = keyPtr;
 
 #ifdef WOLFSSL_DEBUG_TLS
@@ -5162,12 +6231,18 @@
     if (ret != 0) {
         /* Data owned by key share entry otherwise. */
-        if (eccKey != NULL)
-            XFREE(eccKey, ssl->heap, DYNAMIC_TYPE_TLSX);
+        if (keyPtr != NULL)
+            XFREE(keyPtr, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
         if (keyData != NULL)
-            XFREE(keyData, ssl->heap, DYNAMIC_TYPE_TLSX);
-    }
+            XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    }
+#else
+    (void)ssl;
+    (void)kse;
+
+    ret = NOT_COMPILED_IN;
+#endif /* HAVE_ECC */
+
     return ret;
 }
-#endif /* HAVE_ECC */
 
 /* Generate a secret/key using the key share entry.
@@ -5178,14 +6253,10 @@
 static int TLSX_KeyShare_GenKey(WOLFSSL *ssl, KeyShareEntry *kse)
 {
-#ifndef NO_DH
     /* Named FFHE groups have a bit set to identify them. */
     if ((kse->group & NAMED_DH_MASK) == NAMED_DH_MASK)
         return TLSX_KeyShare_GenDhKey(ssl, kse);
-#endif
-#ifdef HAVE_ECC
+    if (kse->group == WOLFSSL_ECC_X25519)
+        return TLSX_KeyShare_GenX25519Key(ssl, kse);
     return TLSX_KeyShare_GenEccKey(ssl, kse);
-#else
-    return NOT_COMPILED_IN;
-#endif
 }
 
@@ -5204,5 +6275,5 @@
             if (current->group == WOLFSSL_ECC_X25519) {
 #ifdef HAVE_CURVE25519
-
+                wc_curve25519_free((curve25519_key*)current->key);
 #endif
             }
@@ -5213,5 +6284,7 @@
             }
         }
+        if (current->key != NULL)
         XFREE(current->key, heap, DYNAMIC_TYPE_PRIVATE_KEY);
+        XFREE(current->pubKey, heap, DYNAMIC_TYPE_PUBLIC_KEY);
         XFREE(current->ke, heap, DYNAMIC_TYPE_PUBLIC_KEY);
         XFREE(current, heap, DYNAMIC_TYPE_TLSX);
@@ -5246,8 +6319,8 @@
             continue;
 
-        len += OPAQUE16_LEN + OPAQUE16_LEN + current->keLen;
-    }
-
-    return len;
+        len += (int)(KE_GROUP_LEN + OPAQUE16_LEN + current->pubKeyLen);
+    }
+
+    return (word16)len;
 }
 
@@ -5285,8 +6358,8 @@
         c16toa(current->group, &output[i]);
         i += KE_GROUP_LEN;
-        c16toa(current->keLen, &output[i]);
+        c16toa((word16)(current->pubKeyLen), &output[i]);
         i += OPAQUE16_LEN;
-        XMEMCPY(&output[i], current->ke, current->keLen);
-        i += current->keLen;
+        XMEMCPY(&output[i], current->pubKey, current->pubKeyLen);
+        i += (word16)current->pubKeyLen;
     }
     /* Write the length of the list if required. */
@@ -5308,7 +6381,9 @@
     int             ret;
     const DhParams* params;
-    word16          i;
-    byte            b;
-    DhKey           dhKey;
+#ifdef WOLFSSL_SMALL_STACK
+    DhKey*          dhKey = NULL;
+#else
+    DhKey           dhKey[1];
+#endif
 
     switch (keyShareEntry->group) {
@@ -5347,42 +6422,40 @@
 #endif
 
-    if (params->p_len != keyShareEntry->keLen)
-        return BUFFER_ERROR;
-    ssl->options.dhKeySz = params->p_len;
-
-    /* TODO: [TLS13] move this check down into wolfcrypt. */
-    /* Check that public DH key is not 0 or 1. */
-    b = 0;
-    for (i = 0; i < params->p_len - 1; i++)
-        b |= keyShareEntry->ke[i];
-    if (b == 0 && (keyShareEntry->ke[i] == 0x00 ||
-                   keyShareEntry->ke[i] == 0x01)) {
+#ifdef WOLFSSL_SMALL_STACK
+    dhKey = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap, DYNAMIC_TYPE_DH);
+    if (dhKey == NULL)
+        return MEMORY_E;
+#endif
+
+    ret = wc_InitDhKey_ex(dhKey, ssl->heap, ssl->devId);
+    if (ret != 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+    #endif
+        return ret;
+    }
+
+    /* Set key */
+    ret = wc_DhSetKey(dhKey, (byte*)params->p, params->p_len, (byte*)params->g,
+                                                                 params->g_len);
+    if (ret != 0) {
+        wc_FreeDhKey(dhKey);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+    #endif
+        return ret;
+    }
+
+    ret = wc_DhCheckPubKey(dhKey, keyShareEntry->ke, keyShareEntry->keLen);
+    if (ret != 0) {
+        wc_FreeDhKey(dhKey);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+    #endif
         return PEER_KEY_ERROR;
     }
-    /* Check that public DH key is not mod, mod + 1 or mod - 1. */
-    b = 0;
-    for (i = 0; i < params->p_len - 1; i++)
-        b |= params->p[i] ^ keyShareEntry->ke[i];
-    if (b == 0 && (params->p[i]     == keyShareEntry->ke[i] ||
-                   params->p[i] - 1 == keyShareEntry->ke[i] ||
-                   params->p[i] + 1 == keyShareEntry->ke[i])) {
-        return PEER_KEY_ERROR;
-    }
-
-    ret = wc_InitDhKey_ex(&dhKey, ssl->heap, ssl->devId);
-    if (ret != 0)
-        return ret;
-
-    /* Set key */
-    ret = wc_DhSetKey(&dhKey,
-        (byte*)params->p, params->p_len,
-        (byte*)params->g, params->g_len);
-    if (ret != 0) {
-        wc_FreeDhKey(&dhKey);
-        return ret;
-    }
 
     /* Derive secret from private key and peer's public key. */
-    ret = wc_DhAgree(&dhKey,
+    ret = wc_DhAgree(dhKey,
         ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz,
         (const byte*)keyShareEntry->key, keyShareEntry->keyLen,
@@ -5391,9 +6464,30 @@
     /* TODO: Make this function non-blocking */
     if (ret == WC_PENDING_E) {
-        ret = wc_AsyncWait(ret, &dhKey.asyncDev, WC_ASYNC_FLAG_NONE);
-    }
-#endif
-
-    wc_FreeDhKey(&dhKey);
+        ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
+    }
+#endif
+    /* RFC 8446 Section 7.4.1:
+     *     ... left-padded with zeros up to the size of the prime. ...
+     */
+    if (params->p_len > ssl->arrays->preMasterSz) {
+        word32 diff = params->p_len - ssl->arrays->preMasterSz;
+        XMEMMOVE(ssl->arrays->preMasterSecret + diff,
+                        ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz);
+        XMEMSET(ssl->arrays->preMasterSecret, 0, diff);
+        ssl->arrays->preMasterSz = params->p_len;
+    }
+
+    wc_FreeDhKey(dhKey);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+#endif
+    if (keyShareEntry->key != NULL) {
+        XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+        keyShareEntry->key = NULL;
+    }
+    XFREE(keyShareEntry->pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    keyShareEntry->pubKey = NULL;
+    XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    keyShareEntry->ke = NULL;
 
     return ret;
@@ -5403,4 +6497,76 @@
     return PEER_KEY_ERROR;
 #endif
+}
+
+/* Process the X25519 key share extension on the client side.
+ *
+ * ssl            The SSL/TLS object.
+ * keyShareEntry  The key share entry object to use to calculate shared secret.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_KeyShare_ProcessX25519(WOLFSSL* ssl,
+                                       KeyShareEntry* keyShareEntry)
+{
+    int ret;
+
+#ifdef HAVE_CURVE25519
+    curve25519_key* key = (curve25519_key*)keyShareEntry->key;
+    curve25519_key* peerX25519Key;
+
+#ifdef HAVE_ECC
+    if (ssl->peerEccKey != NULL) {
+        wc_ecc_free(ssl->peerEccKey);
+        ssl->peerEccKey = NULL;
+    }
+#endif
+
+    peerX25519Key = (curve25519_key*)XMALLOC(sizeof(curve25519_key), ssl->heap,
+                                                             DYNAMIC_TYPE_TLSX);
+    if (peerX25519Key == NULL) {
+        WOLFSSL_MSG("PeerEccKey Memory error");
+        return MEMORY_ERROR;
+    }
+    ret = wc_curve25519_init(peerX25519Key);
+    if (ret != 0) {
+        XFREE(peerX25519Key, ssl->heap, DYNAMIC_TYPE_TLSX);
+        return ret;
+    }
+#ifdef WOLFSSL_DEBUG_TLS
+    WOLFSSL_MSG("Peer Curve25519 Key");
+    WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
+#endif
+
+    /* Point is validated by import function. */
+    if (wc_curve25519_import_public_ex(keyShareEntry->ke, keyShareEntry->keLen,
+                                                  peerX25519Key,
+                                                  EC25519_LITTLE_ENDIAN) != 0) {
+        ret = ECC_PEERKEY_ERROR;
+    }
+
+    if (ret == 0) {
+        ssl->arrays->preMasterSz = ENCRYPT_LEN;
+        ssl->ecdhCurveOID = ECC_X25519_OID;
+
+        ret = wc_curve25519_shared_secret_ex(key, peerX25519Key,
+                                                   ssl->arrays->preMasterSecret,
+                                                   &ssl->arrays->preMasterSz,
+                                                   EC25519_LITTLE_ENDIAN);
+    }
+
+    wc_curve25519_free(peerX25519Key);
+    XFREE(peerX25519Key, ssl->heap, DYNAMIC_TYPE_TLSX);
+    wc_curve25519_free((curve25519_key*)keyShareEntry->key);
+    if (keyShareEntry->key != NULL) {
+        XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+        keyShareEntry->key = NULL;
+    }
+#else
+    (void)ssl;
+    (void)keyShareEntry;
+
+    ret = PEER_KEY_ERROR;
+#endif /* HAVE_CURVE25519 */
+
+    return ret;
 }
 
@@ -5455,44 +6621,4 @@
         #endif /* !NO_ECC_SECP */
     #endif
-    #ifdef HAVE_CURVE25519
-        case WOLFSSL_ECC_X25519:
-            {
-                curve25519_key* key = (curve25519_key*)keyShareEntry->key;
-                curve25519_key* peerEccKey;
-
-                if (ssl->peerEccKey != NULL)
-                    wc_ecc_free(ssl->peerEccKey);
-
-                peerEccKey = (curve25519_key*)XMALLOC(sizeof(curve25519_key),
-                                                  ssl->heap, DYNAMIC_TYPE_TLSX);
-                if (peerEccKey == NULL) {
-                    WOLFSSL_MSG("PeerEccKey Memory error");
-                    return MEMORY_ERROR;
-                }
-                ret = wc_curve25519_init(peerEccKey);
-                if (ret != 0)
-                    return ret;
-#ifdef WOLFSSL_DEBUG_TLS
-                WOLFSSL_MSG("Peer Curve25519 Key");
-                WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
-#endif
-
-                /* Point is validated by import function. */
-                if (wc_curve25519_import_public_ex(keyShareEntry->ke,
-                                               keyShareEntry->keLen, peerEccKey,
-                                               EC25519_LITTLE_ENDIAN) != 0) {
-                    return ECC_PEERKEY_ERROR;
-                }
-
-                ssl->arrays->preMasterSz = ENCRYPT_LEN;
-                ret = wc_curve25519_shared_secret_ex(key, peerEccKey,
-                    ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz,
-                    EC25519_LITTLE_ENDIAN);
-                wc_curve25519_free(peerEccKey);
-                XFREE(peerEccKey, ssl->heap, DYNAMIC_TYPE_TLSX);
-                ssl->ecdhCurveOID = ECC_X25519_OID;
-                return ret;
-            }
-    #endif
     #ifdef HAVE_X448
         case WOLFSSL_ECC_X448:
@@ -5532,13 +6658,16 @@
         keyShareEntry->ke, &keyShareEntry->keLen,
         ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz,
-        ssl->options.side,
-    #ifdef HAVE_PK_CALLBACKS
-        ssl->EccSharedSecretCtx
-    #else
-        NULL
-    #endif
+        ssl->options.side
     );
 #endif
 
+    wc_ecc_free(ssl->peerEccKey);
+    XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC);
+    ssl->peerEccKey = NULL;
+    wc_ecc_free((ecc_key*)(keyShareEntry->key));
+    if (keyShareEntry->key != NULL) {
+        XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+        keyShareEntry->key = NULL;
+    }
 
 #else
@@ -5563,9 +6692,11 @@
 
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
-    ssl->session.namedGroup = keyShareEntry->group;
+    ssl->session.namedGroup = (byte)keyShareEntry->group;
 #endif
     /* Use Key Share Data from server. */
     if (keyShareEntry->group & NAMED_DH_MASK)
         ret = TLSX_KeyShare_ProcessDh(ssl, keyShareEntry);
+    else if (keyShareEntry->group == WOLFSSL_ECC_X25519)
+        ret = TLSX_KeyShare_ProcessX25519(ssl, keyShareEntry);
     else
         ret = TLSX_KeyShare_ProcessEcc(ssl, keyShareEntry);
@@ -5627,6 +6758,6 @@
 /* Searches the groups sent for the specified named group.
  *
- * ssl   The SSL/TLS object.
- * name  The group name to match.
+ * ssl    SSL/TLS object.
+ * name   Group name to match.
  * returns 1 when the extension has the group name and 0 otherwise.
  */
@@ -5637,12 +6768,14 @@
 
     extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+    if (extension == NULL) {
+        extension = TLSX_Find(ssl->ctx->extensions, TLSX_KEY_SHARE);
     if (extension == NULL)
         return 0;
+    }
 
     list = (KeyShareEntry*)extension->data;
     while (list != NULL) {
-        if (list->group == group) {
+        if (list->group == group)
             return 1;
-        }
         list = list->next;
     }
@@ -5664,6 +6797,11 @@
     SupportedCurve* curve = NULL;
 
-    if ((extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS)) == NULL)
+    if ((extension = TLSX_Find(ssl->extensions,
+                                              TLSX_SUPPORTED_GROUPS)) == NULL) {
+        if ((extension = TLSX_Find(ssl->ctx->extensions,
+                                              TLSX_SUPPORTED_GROUPS)) == NULL) {
         return 0;
+        }
+    }
 
     for (curve = (SupportedCurve*)extension->data; curve; curve = curve->next) {
@@ -5693,9 +6831,20 @@
 {
     int ret;
-    KeyShareEntry *keyShareEntry;
+    KeyShareEntry *keyShareEntry = NULL;
+    word16 group;
 
     if (msgType == client_hello) {
         int offset = 0;
         word16 len;
+        TLSX*  extension;
+
+        /* Add a KeyShare extension if it doesn't exist. */
+        extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+        if (extension == NULL) {
+            /* Push new KeyShare extension. */
+            ret = TLSX_Push(&ssl->extensions, TLSX_KEY_SHARE, NULL, ssl->heap);
+            if (ret != 0)
+                return ret;
+        }
 
         if (length < OPAQUE16_LEN)
@@ -5722,4 +6871,18 @@
         int len;
 
+        if (length < OPAQUE16_LEN)
+            return BUFFER_ERROR;
+
+        /* The data is the named group the server wants to use. */
+        ato16(input, &group);
+
+        /* Check the selected group was supported by ClientHello extensions. */
+        if (!TLSX_SupportedGroups_Find(ssl, group))
+            return BAD_KEY_SHARE_DATA;
+
+        /* Check if the group was sent. */
+        if (!TLSX_KeyShare_Find(ssl, group))
+            return BAD_KEY_SHARE_DATA;
+
         /* ServerHello contains one key share entry. */
         len = TLSX_KeyShareEntry_Parse(ssl, input, length, &keyShareEntry);
@@ -5728,13 +6891,13 @@
 
         /* Not in list sent if there isn't a private key. */
-        if (keyShareEntry->key == NULL)
+        if (keyShareEntry == NULL || keyShareEntry->key == NULL)
             return BAD_KEY_SHARE_DATA;
 
         /* Process the entry to calculate the secret. */
         ret = TLSX_KeyShare_Process(ssl, keyShareEntry);
+        if (ret == 0)
+            ssl->session.namedGroup = ssl->namedGroup = group;
     }
     else if (msgType == hello_retry_request) {
-        word16 group;
-
         if (length != OPAQUE16_LEN)
             return BUFFER_ERROR;
@@ -5750,4 +6913,9 @@
         if (TLSX_KeyShare_Find(ssl, group))
             return BAD_KEY_SHARE_DATA;
+
+        /* Clear out unusable key shares. */
+        ret = TLSX_KeyShare_Empty(ssl);
+        if (ret != 0)
+            return ret;
 
         /* Try to use the server's group. */
@@ -5781,5 +6949,5 @@
 
     XMEMSET(kse, 0, sizeof(*kse));
-    kse->group = group;
+    kse->group = (word16)group;
 
     /* Add it to the back and maintain the links. */
@@ -5788,4 +6956,6 @@
     *list = kse;
     *keyShareEntry = kse;
+
+    (void)heap;
 
     return 0;
@@ -5839,7 +7009,4 @@
 
     if (data != NULL) {
-        /* Keep the public key data and free when finished. */
-        if (keyShareEntry->ke != NULL)
-            XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
         keyShareEntry->ke = data;
         keyShareEntry->keLen = len;
@@ -5941,4 +7108,66 @@
 
     return 1;
+}
+
+/* Examines the application specified group ranking and returns the rank of the
+ * group.
+ * If no group ranking set then all groups are rank 0 (highest).
+ *
+ * ssl    The SSL/TLS object.
+ * group  The group to check ranking for.
+ * returns ranking from 0 to MAX_GROUP_COUNT-1 or -1 when group not in list.
+ */
+static int TLSX_KeyShare_GroupRank(WOLFSSL* ssl, int group)
+{
+    byte i;
+
+    if (ssl->numGroups == 0) {
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+    #if !defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)
+        #ifndef NO_ECC_SECP
+            ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP256R1;
+        #endif
+    #endif
+#endif
+    #ifndef HAVE_FIPS
+        #if defined(HAVE_CURVE25519)
+            ssl->group[ssl->numGroups++] = WOLFSSL_ECC_X25519;
+        #endif
+    #endif
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+    #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+        #ifndef NO_ECC_SECP
+            ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP384R1;
+        #endif
+    #endif
+    #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+        #ifndef NO_ECC_SECP
+            ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP521R1;
+        #endif
+    #endif
+#endif
+            /* Add FFDHE supported groups. */
+        #ifdef HAVE_FFDHE_2048
+            ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_2048;
+        #endif
+        #ifdef HAVE_FFDHE_3072
+            ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_3072;
+        #endif
+        #ifdef HAVE_FFDHE_4096
+            ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_4096;
+        #endif
+        #ifdef HAVE_FFDHE_6144
+            ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_6144;
+        #endif
+        #ifdef HAVE_FFDHE_8192
+            ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_8192;
+        #endif
+    }
+
+    for (i = 0; i < ssl->numGroups; i++)
+        if (ssl->group[i] == group)
+            return i;
+
+    return -1;
 }
 
@@ -5955,15 +7184,26 @@
     TLSX*          extension;
     SupportedCurve* curve = NULL;
-
-    /* Use SupportedGroup's order. */
+    SupportedCurve* preferredCurve = NULL;
+    int             preferredRank = WOLFSSL_MAX_GROUP_COUNT;
+    int             rank;
+
     extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
     if (extension != NULL)
         curve = (SupportedCurve*)extension->data;
+    /* Use server's preference order. */
     for (; curve != NULL; curve = curve->next) {
-        if (TLSX_KeyShare_IsSupported(curve->name) &&
-                !TLSX_KeyShare_Find(ssl, curve->name)) {
-            break;
-        }
-    }
+        if (!TLSX_KeyShare_IsSupported(curve->name))
+            continue;
+
+        rank = TLSX_KeyShare_GroupRank(ssl, curve->name);
+        if (rank == -1)
+            continue;
+        if (rank < preferredRank) {
+            preferredCurve = curve;
+            preferredRank = rank;
+        }
+    }
+    curve = preferredCurve;
+
     if (curve == NULL)
         return BAD_KEY_SHARE_DATA;
@@ -5993,5 +7233,5 @@
 }
 
-/* Establish the secret based on the key shares received from the client.
+/* Ensure there is a key pair that can be used for key exchange.
  *
  * ssl  The SSL/TLS object.
@@ -6005,6 +7245,7 @@
     KeyShareEntry* serverKSE;
     KeyShareEntry* list = NULL;
-    byte*          ke;
-    word16         keLen;
+    KeyShareEntry* preferredKSE = NULL;
+    int preferredRank = WOLFSSL_MAX_GROUP_COUNT;
+    int rank;
 
     /* Find the KeyShare extension if it exists. */
@@ -6016,7 +7257,9 @@
         return 0;
 
-    /* TODO: [TLS13] Server's preference and sending back SupportedGroups */
-    /* Use client's preference. */
+    /* Use server's preference order. */
     for (clientKSE = list; clientKSE != NULL; clientKSE = clientKSE->next) {
+        if (clientKSE->ke == NULL)
+            continue;
+
         /* Check consistency now - extensions in any order. */
         if (!TLSX_SupportedGroups_Find(ssl, clientKSE->group))
@@ -6024,11 +7267,23 @@
 
     #ifdef OPENSSL_EXTRA
+        if ((clientKSE->group & NAMED_DH_MASK) == 0) {
         /* Check if server supports group. */
         if (ssl->ctx->disabledCurves & (1 << clientKSE->group))
             continue;
-    #endif
-        if (TLSX_KeyShare_IsSupported(clientKSE->group))
-            break;
-    }
+        }
+    #endif
+        if (!TLSX_KeyShare_IsSupported(clientKSE->group))
+            continue;
+
+        rank = TLSX_KeyShare_GroupRank(ssl, clientKSE->group);
+        if (rank == -1)
+            continue;
+        if (rank < preferredRank) {
+            preferredKSE = clientKSE;
+            preferredRank = rank;
+    }
+    }
+    clientKSE = preferredKSE;
+
     /* No supported group found - send HelloRetryRequest. */
     if (clientKSE == NULL) {
@@ -6045,34 +7300,56 @@
     if (ret != 0)
         return ret;
-    ret = TLSX_KeyShare_GenKey(ssl, serverKSE);
+
+    if (clientKSE->key == NULL) {
+        ret = TLSX_KeyShare_GenKey(ssl, serverKSE);
     if (ret != 0)
         return ret;
-
-    /* Move private key to client entry. */
-    if (clientKSE->key != NULL)
-        XFREE(clientKSE->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
-    clientKSE->key = serverKSE->key;
-    serverKSE->key = NULL;
-    clientKSE->keyLen = serverKSE->keyLen;
+    }
+    else {
+        serverKSE->key = clientKSE->key;
+        serverKSE->keyLen = clientKSE->keyLen;
+        serverKSE->pubKey = clientKSE->pubKey;
+        serverKSE->pubKeyLen = clientKSE->pubKeyLen;
+        clientKSE->key = NULL;
+        clientKSE->pubKey = NULL;
+    }
+    serverKSE->ke = clientKSE->ke;
+    serverKSE->keLen = clientKSE->keLen;
+    clientKSE->ke = NULL;
+    clientKSE->keLen = 0;
+
+    TLSX_KeyShare_FreeAll((KeyShareEntry*)extension->data, ssl->heap);
+    extension->data = (void *)serverKSE;
+
+    extension->resp = 1;
+
+    return 0;
+}
+
+/* Derive the shared secret of the key exchange.
+ *
+ * ssl  The SSL/TLS object.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_KeyShare_DeriveSecret(WOLFSSL *ssl)
+{
+    int            ret;
+    TLSX*          extension;
+    KeyShareEntry* list = NULL;
+
+    /* Find the KeyShare extension if it exists. */
+    extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+    if (extension != NULL)
+        list = (KeyShareEntry*)extension->data;
+
+    if (list == NULL)
+        return KEY_SHARE_ERROR;
 
     /* Calculate secret. */
-    ret = TLSX_KeyShare_Process(ssl, clientKSE);
+    ret = TLSX_KeyShare_Process(ssl, list);
     if (ret != 0)
         return ret;
 
-    /* Swap public keys for sending to client. */
-    ke = serverKSE->ke;
-    keLen = serverKSE->keLen;
-    serverKSE->ke = clientKSE->ke;
-    serverKSE->keLen = clientKSE->keLen;
-    clientKSE->ke = ke;
-    clientKSE->keLen = keLen;
-
-    extension->resp = 1;
-
-    /* Dispose of temporary server extension. */
-    TLSX_KeyShare_FreeAll(list, ssl->heap);
-
-    return 0;
+    return ret;
 }
 
@@ -6291,4 +7568,6 @@
         word16 idx = 0;
 
+        TLSX_Remove(&ssl->extensions, TLSX_PRE_SHARED_KEY, ssl->heap);
+
         /* Length of identities and of binders. */
         if (length - idx < OPAQUE16_LEN + OPAQUE16_LEN)
@@ -6348,5 +7627,5 @@
             list->binderLen = input[idx++];
             if (list->binderLen < WC_SHA256_DIGEST_SIZE ||
-                    list->binderLen > MAX_DIGEST_SIZE)
+                    list->binderLen > WC_MAX_DIGEST_SIZE)
                 return BUFFER_E;
             if (len < OPAQUE8_LEN + list->binderLen)
@@ -6376,4 +7655,8 @@
             return BUFFER_E;
         ato16(input, &idx);
+
+    #ifdef WOLFSSL_EARLY_DATA
+        ssl->options.pskIdIndex = idx + 1;
+    #endif
 
         /* Find the list of identities sent to server. */
@@ -6395,14 +7678,10 @@
            if (ssl->options.cipherSuite0  != ssl->session.cipherSuite0 ||
                ssl->options.cipherSuite   != ssl->session.cipherSuite  ||
-               ssl->session.version.major != ssl->version.major        ||
-               ssl->session.version.minor != ssl->version.minor        ) {
+               ssl->session.version.major != ssl->ctx->method->version.major ||
+               ssl->session.version.minor != ssl->ctx->method->version.minor) {
                return PSK_KEY_ERROR;
            }
         }
     #endif
-        /* TODO: [TLS13] More checks of consistency.
-         * the "key_share", and "signature_algorithms" extensions are
-         * consistent with the indicated ke_modes and auth_modes values
-         */
 
         return 0;
@@ -6450,5 +7729,5 @@
 }
 
-static INLINE byte GetHmacLength(int hmac)
+static WC_INLINE byte GetHmacLength(int hmac)
 {
     switch (hmac) {
@@ -6457,9 +7736,9 @@
             return WC_SHA256_DIGEST_SIZE;
     #endif
-    #ifndef NO_SHA384
+    #ifdef WOLFSSL_SHA384
         case sha384_mac:
             return WC_SHA384_DIGEST_SIZE;
     #endif
-    #ifndef NO_SHA512
+    #ifdef WOLFSSL_SHA512
         case sha512_mac:
             return WC_SHA512_DIGEST_SIZE;
@@ -6713,5 +7992,5 @@
 {
     if (msgType == client_hello)
-        return OPAQUE8_LEN;
+        return 0;
 
     return SANITY_MSG_E;
@@ -6728,8 +8007,8 @@
 static word16 TLSX_PostHandAuth_Write(byte* output, byte msgType)
 {
-    if (msgType == client_hello) {
-        *output = 0;
-        return OPAQUE8_LEN;
-    }
+    (void)output;
+
+    if (msgType == client_hello)
+        return 0;
 
     return SANITY_MSG_E;
@@ -6748,13 +8027,9 @@
                                  byte msgType)
 {
-    byte len;
+    (void)input;
 
     if (msgType == client_hello) {
-        /* Ensure length byte exists. */
-        if (length < OPAQUE8_LEN)
-            return BUFFER_E;
-
-        len = input[0];
-        if (length - OPAQUE8_LEN != len || len != 0)
+        /* Ensure extension is empty. */
+        if (length != 0)
             return BUFFER_E;
 
@@ -6866,4 +8141,10 @@
             return BUFFER_E;
 
+        /* Ensure the index of PSK identity chosen by server is 0.
+         * Index is plus one to handle 'not set' value of 0.
+         */
+        if (ssl->options.pskIdIndex != 1)
+            return PSK_KEY_ERROR;
+
         return TLSX_EarlyData_Use(ssl, 1);
     }
@@ -6939,4 +8220,22 @@
 }
 
+/** Remove an extension. */
+void TLSX_Remove(TLSX** list, TLSX_Type type, void* heap)
+{
+    TLSX* extension = *list;
+    TLSX** next = list;
+
+    while (extension && extension->type != type) {
+        next = &extension->next;
+        extension = extension->next;
+    }
+
+    if (extension) {
+        *next = extension->next;
+        extension->next = NULL;
+        TLSX_FreeAll(extension, heap);
+    }
+}
+
 /** Releases all extensions in the provided list. */
 void TLSX_FreeAll(TLSX* list, void* heap)
@@ -7005,8 +8304,4 @@
                 break;
 
-            case TLSX_KEY_SHARE:
-                KS_FREE_ALL((KeyShareEntry*)extension->data, heap);
-                break;
-
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
             case TLSX_PRE_SHARED_KEY:
@@ -7027,4 +8322,13 @@
                 break;
     #endif
+
+    #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+            case TLSX_SIGNATURE_ALGORITHMS_CERT:
+                break;
+    #endif
+
+            case TLSX_KEY_SHARE:
+                KS_FREE_ALL((KeyShareEntry*)extension->data, heap);
+                break;
 #endif
         }
@@ -7042,6 +8346,7 @@
 
 /** Tells the buffered size of the extensions in a list. */
-static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType)
-{
+static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, word16* pLength)
+{
+    int    ret = 0;
     TLSX*  extension;
     word16 length = 0;
@@ -7123,13 +8428,9 @@
 #ifdef WOLFSSL_TLS13
             case TLSX_SUPPORTED_VERSIONS:
-                length += SV_GET_SIZE(extension->data);
+                ret = SV_GET_SIZE(extension->data, msgType, &length);
                 break;
 
             case TLSX_COOKIE:
-                length += CKE_GET_SIZE((Cookie*)extension->data, msgType);
-                break;
-
-            case TLSX_KEY_SHARE:
-                length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType);
+                ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &length);
                 break;
 
@@ -7155,4 +8456,14 @@
                 break;
     #endif
+
+    #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+            case TLSX_SIGNATURE_ALGORITHMS_CERT:
+                length += SAC_GET_SIZE(extension->data);
+                break;
+    #endif
+
+            case TLSX_KEY_SHARE:
+                length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType);
+                break;
 #endif
         }
@@ -7163,11 +8474,14 @@
     }
 
-    return length;
+    *pLength += length;
+
+    return ret;
 }
 
 /** Writes the extensions of a list in a buffer. */
-static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
-                         byte msgType)
-{
+static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
+                         byte msgType, word16* pOffset)
+{
+    int    ret = 0;
     TLSX* extension;
     word16 offset = 0;
@@ -7212,5 +8526,5 @@
 
             case TLSX_SUPPORTED_GROUPS:
-                WOLFSSL_MSG("Elliptic Curves extension to write");
+                WOLFSSL_MSG("Supported Groups extension to write");
                 offset += EC_WRITE((SupportedCurve*)extension->data,
                                     output + offset);
@@ -7270,17 +8584,11 @@
             case TLSX_SUPPORTED_VERSIONS:
                 WOLFSSL_MSG("Supported Versions extension to write");
-                offset += SV_WRITE(extension->data, output + offset);
+                ret = SV_WRITE(extension->data, output + offset, msgType, &offset);
                 break;
 
             case TLSX_COOKIE:
                 WOLFSSL_MSG("Cookie extension to write");
-                offset += CKE_WRITE((Cookie*)extension->data, output + offset,
-                                    msgType);
-                break;
-
-            case TLSX_KEY_SHARE:
-                WOLFSSL_MSG("Key Share extension to write");
-                offset += KS_WRITE((KeyShareEntry*)extension->data,
-                                   output + offset, msgType);
+                ret = CKE_WRITE((Cookie*)extension->data, output + offset,
+                                msgType, &offset);
                 break;
 
@@ -7311,4 +8619,17 @@
                 break;
     #endif
+
+    #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+            case TLSX_SIGNATURE_ALGORITHMS_CERT:
+                WOLFSSL_MSG("Signature Algorithms extension to write");
+                offset += SAC_WRITE(extension->data, output + offset);
+                break;
+    #endif
+
+            case TLSX_KEY_SHARE:
+                WOLFSSL_MSG("Key Share extension to write");
+                offset += KS_WRITE((KeyShareEntry*)extension->data,
+                                   output + offset, msgType);
+                break;
 #endif
         }
@@ -7322,5 +8643,7 @@
     }
 
-    return offset;
+    *pOffset += offset;
+
+    return ret;
 }
 
@@ -7516,4 +8839,181 @@
 #endif /* HAVE_QSH */
 
+#if (!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
+        !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \
+    (defined(WOLFSSL_TLS13) && !defined(HAVE_ECC) && \
+        !defined(HAVE_CURVE25519) && defined(HAVE_SUPPORTED_CURVES)) || \
+    ((defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+        defined(HAVE_SUPPORTED_CURVES))
+
+/* Populates the default supported groups / curves */
+static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions)
+{
+    int ret = WOLFSSL_SUCCESS;
+#ifdef WOLFSSL_TLS13
+    int i;
+
+#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+    if (ssl->options.resuming && ssl->session.namedGroup != 0) {
+        return TLSX_UseSupportedCurve(extensions, ssl->session.namedGroup,
+                                                                     ssl->heap);
+        }
+#endif
+
+    if (ssl->numGroups != 0) {
+        for (i = 0; i < ssl->numGroups; i++) {
+            ret = TLSX_UseSupportedCurve(extensions, ssl->group[i], ssl->heap);
+            if (ret != WOLFSSL_SUCCESS)
+                        return ret;
+            }
+        return WOLFSSL_SUCCESS;
+        }
+#endif /* WOLFSSL_TLS13 */
+
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+        /* list in order by strength, since not all servers choose by strength */
+        #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP521R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+        #endif
+        #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)
+            #ifdef HAVE_ECC_BRAINPOOL
+                ret = TLSX_UseSupportedCurve(extensions,
+                                        WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+        #endif
+        #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP384R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_BRAINPOOL
+                ret = TLSX_UseSupportedCurve(extensions,
+                                        WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+        #endif
+        #endif
+        #if !defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP256R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_KOBLITZ
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP256K1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_BRAINPOOL
+                ret = TLSX_UseSupportedCurve(extensions,
+                                        WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+        #endif
+#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */
+
+        #ifndef HAVE_FIPS
+            #if defined(HAVE_CURVE25519)
+                ret = TLSX_UseSupportedCurve(extensions,
+                                                 WOLFSSL_ECC_X25519, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+    #endif
+        #endif /* HAVE_FIPS */
+
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+        #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP224R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_KOBLITZ
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP224K1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+        #endif
+
+    #ifndef HAVE_FIPS
+        #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP192R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_KOBLITZ
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP192K1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+        #endif
+        #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP160R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_SECPR2
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP160R2, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_KOBLITZ
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP160K1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+        #endif
+    #endif /* HAVE_FIPS */
+#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */
+
+    #ifdef WOLFSSL_TLS13
+        if (IsAtLeastTLSv1_3(ssl->version)) {
+                /* Add FFDHE supported groups. */
+        #ifdef HAVE_FFDHE_8192
+                ret = TLSX_UseSupportedCurve(extensions,
+                                             WOLFSSL_FFDHE_8192, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS)
+                    return ret;
+        #endif
+        #ifdef HAVE_FFDHE_6144
+                ret = TLSX_UseSupportedCurve(extensions,
+                                             WOLFSSL_FFDHE_6144, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS)
+                    return ret;
+        #endif
+        #ifdef HAVE_FFDHE_4096
+                ret = TLSX_UseSupportedCurve(extensions,
+                                             WOLFSSL_FFDHE_4096, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS)
+                    return ret;
+        #endif
+        #ifdef HAVE_FFDHE_3072
+                ret = TLSX_UseSupportedCurve(extensions,
+                                             WOLFSSL_FFDHE_3072, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS)
+                    return ret;
+        #endif
+        #ifdef HAVE_FFDHE_2048
+                ret = TLSX_UseSupportedCurve(extensions,
+                                             WOLFSSL_FFDHE_2048, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS)
+                    return ret;
+        #endif
+        }
+    #endif /* WOLFSSL_TLS13 */
+
+    (void)ssl;
+    (void)extensions;
+
+    return ret;
+}
+
+#endif
+
 int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
 {
@@ -7531,5 +9031,5 @@
     /* add supported QSHSchemes */
     WOLFSSL_MSG("Adding supported QSH Schemes");
-#endif
+            #endif
 
     /* server will add extension depending on whats parsed from client */
@@ -7605,103 +9105,25 @@
             }
         }
-#endif
-
-#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
-        if (!ssl->options.userCurves && !ssl->ctx->userCurves &&
-               TLSX_Find(ssl->ctx->extensions, TLSX_SUPPORTED_GROUPS) == NULL) {
-
-    #ifndef HAVE_FIPS
-        #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)
-            #ifndef NO_ECC_SECP
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP160R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_SECPR2
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP160R2, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_KOBLITZ
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP160K1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
         #endif
-        #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)
-            #ifndef NO_ECC_SECP
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP192R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_KOBLITZ
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP192K1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-        #endif
-    #endif
-        #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)
-            #ifndef NO_ECC_SECP
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP224R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_KOBLITZ
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP224K1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-        #endif
-        #if !defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)
-            #ifndef NO_ECC_SECP
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP256R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #if defined(HAVE_CURVE25519)
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                                 WOLFSSL_ECC_X25519, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_KOBLITZ
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP256K1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_BRAINPOOL
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                        WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-        #endif
-        #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
-            #ifndef NO_ECC_SECP
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP384R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_BRAINPOOL
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                        WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-        #endif
-        #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)
-            #ifdef HAVE_ECC_BRAINPOOL
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                        WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-        #endif
-        #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
-            #ifndef NO_ECC_SECP
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP521R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-        #endif
-        }
-#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */
+
+#if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                  defined(HAVE_SUPPORTED_CURVES)
+        if (!ssl->options.userCurves && !ssl->ctx->userCurves) {
+            if (TLSX_Find(ssl->ctx->extensions,
+                                               TLSX_SUPPORTED_GROUPS) == NULL) {
+                ret = TLSX_PopulateSupportedGroups(ssl, &ssl->extensions);
+                if (ret != WOLFSSL_SUCCESS)
+                    return ret;
+        }
+        }
+        if ((!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade) &&
+               TLSX_Find(ssl->ctx->extensions, TLSX_EC_POINT_FORMATS) == NULL &&
+               TLSX_Find(ssl->extensions, TLSX_EC_POINT_FORMATS) == NULL) {
+             ret = TLSX_UsePointFormat(&ssl->extensions,
+                                         WOLFSSL_EC_PF_UNCOMPRESSED, ssl->heap);
+             if (ret != WOLFSSL_SUCCESS)
+                 return ret;
+        }
+#endif /* (HAVE_ECC || HAVE_CURVE25519) && HAVE_SUPPORTED_CURVES */
     } /* is not server */
 
@@ -7717,80 +9139,73 @@
             WOLFSSL_MSG("Adding supported versions extension");
             if ((ret = TLSX_SetSupportedVersions(&ssl->extensions, ssl,
-                                                 ssl->heap)) != 0)
+                                                             ssl->heap)) != 0) {
                 return ret;
-
-#ifdef HAVE_SUPPORTED_CURVES
-            if (!ssl->options.userCurves && !ssl->ctx->userCurves &&
-                TLSX_Find(ssl->ctx->extensions, TLSX_SUPPORTED_GROUPS)
-                                                                      == NULL) {
-                /* Add FFDHE supported groups. */
-        #ifdef HAVE_FFDHE_2048
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                             WOLFSSL_FFDHE_2048, ssl->heap);
+            }
+
+    #if !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) && \
+                                                  defined(HAVE_SUPPORTED_CURVES)
+        if (TLSX_Find(ssl->ctx->extensions, TLSX_SUPPORTED_GROUPS) == NULL) {
+            /* Put in DH groups for TLS 1.3 only. */
+            ret = TLSX_PopulateSupportedGroups(ssl, &ssl->extensions);
                 if (ret != WOLFSSL_SUCCESS)
                     return ret;
-        #endif
-        #ifdef HAVE_FFDHE_3072
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                             WOLFSSL_FFDHE_3072, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS)
-                    return ret;
-        #endif
-        #ifdef HAVE_FFDHE_4096
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                             WOLFSSL_FFDHE_4096, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS)
-                    return ret;
-        #endif
-        #ifdef HAVE_FFDHE_6144
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                             WOLFSSL_FFDHE_6144, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS)
-                    return ret;
-        #endif
-        #ifdef HAVE_FFDHE_8192
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                             WOLFSSL_FFDHE_8192, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS)
-                    return ret;
-        #endif
                 ret = 0;
             }
-#endif
+    #endif /* !HAVE_ECC && !HAVE_CURVE25519 && HAVE_SUPPORTED_CURVES */
+
+        #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+            if (ssl->certHashSigAlgoSz > 0) {
+                WOLFSSL_MSG("Adding signature algorithms cert extension");
+                if ((ret = TLSX_SetSignatureAlgorithmsCert(&ssl->extensions,
+                                                        ssl, ssl->heap)) != 0) {
+                    return ret;
+                }
+            }
+        #endif /* !WOLFSSL_TLS13_DRAFT_18 && !WOLFSSL_TLS13_DRAFT_22 */
 
             if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) {
-        #if (!defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)) && \
-            !defined(NO_ECC_SECP)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP256R1, 0, NULL,
-                                        NULL);
+                word16 namedGroup;
+
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+                if (ssl->options.resuming && ssl->session.namedGroup != 0)
+                    namedGroup = ssl->session.namedGroup;
+                else
+        #endif
+                {
+        #if defined(HAVE_ECC) && (!defined(NO_ECC256) || \
+                              defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP)
+                    namedGroup = WOLFSSL_ECC_SECP256R1;
         #elif defined(HAVE_CURVE25519)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_X25519, 0, NULL, NULL);
-        #elif (!defined(NO_ECC384)  || defined(HAVE_ALL_CURVES)) && \
-              !defined(NO_ECC_SECP)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP384R1, 0, NULL,
-                                        NULL);
-        #elif (!defined(NO_ECC521)  || defined(HAVE_ALL_CURVES)) && \
-              !defined(NO_ECC_SECP)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP521R1, 0, NULL,
-                                        NULL);
+                    namedGroup = WOLFSSL_ECC_X25519;
+        #elif defined(HAVE_ECC) && (!defined(NO_ECC384) || \
+                              defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP)
+                    namedGroup = WOLFSSL_ECC_SECP384R1;
+        #elif defined(HAVE_ECC) && (!defined(NO_ECC521) || \
+                              defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP)
+                    namedGroup = WOLFSSL_ECC_SECP521R1;
         #elif defined(HAVE_FFDHE_2048)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_2048, 0, NULL, NULL);
+                    namedGroup = WOLFSSL_FFDHE_2048;
         #elif defined(HAVE_FFDHE_3072)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_3072, 0, NULL, NULL);
+                    namedGroup = WOLFSSL_FFDHE_3072;
         #elif defined(HAVE_FFDHE_4096)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_4096, 0, NULL, NULL);
+                    namedGroup = WOLFSSL_FFDHE_4096;
         #elif defined(HAVE_FFDHE_6144)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_6144, 0, NULL, NULL);
+                    namedGroup = WOLFSSL_FFDHE_6144;
         #elif defined(HAVE_FFDHE_8192)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_8192, 0, NULL, NULL);
+                    namedGroup = WOLFSSL_FFDHE_8192;
         #else
-                ret = KEY_SHARE_ERROR;
+                    return KEY_SHARE_ERROR;
         #endif
+                }
+                ret = TLSX_KeyShare_Use(ssl, namedGroup, 0, NULL, NULL);
                 if (ret != 0)
                     return ret;
             }
 
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+            TLSX_Remove(&ssl->extensions, TLSX_PRE_SHARED_KEY, ssl->heap);
+        #endif
         #if defined(HAVE_SESSION_TICKET)
-            if (ssl->options.resuming) {
+            if (ssl->options.resuming && ssl->session.ticketLen > 0) {
                 WOLFSSL_SESSION* sess = &ssl->session;
                 word32           milli;
@@ -7839,5 +9254,5 @@
                 ret = TLSX_PreSharedKey_Use(ssl,
                                           (byte*)ssl->arrays->client_identity,
-                                          XSTRLEN(ssl->arrays->client_identity),
+                                  (word16)XSTRLEN(ssl->arrays->client_identity),
                                           0, ssl->specs.mac_algorithm,
                                           cipherSuite0, cipherSuite, 0,
@@ -7855,5 +9270,5 @@
                 /* Pre-shared key modes: mandatory extension for resumption. */
                 modes = 1 << PSK_KE;
-            #if !defined(NO_DH) || defined(HAVE_ECC)
+            #if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_CURVE25519)
                 if (!ssl->options.noPskDheKe)
                     modes |= 1 << PSK_DHE_KE;
@@ -7880,16 +9295,14 @@
     (void)ssl;
 
-    if (ret == WOLFSSL_SUCCESS)
-        ret = 0;
-
     return ret;
 }
 
 
-#ifndef NO_WOLFSSL_CLIENT
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
 
 /** Tells the buffered size of extensions to be sent into the client hello. */
-word16 TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType)
-{
+int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word16* pLength)
+{
+    int ret = 0;
     word16 length = 0;
     byte semaphore[SEMAPHORE_SIZE] = {0};
@@ -7921,4 +9334,16 @@
     #endif
         }
+    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+        if (IsAtLeastTLSv1_3(ssl->version) && ssl->options.noPskDheKe) {
+        #if !defined(NO_PSK)
+            if (ssl->options.havePSK)
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #endif
+        #if defined(HAVE_SESSION_TICKET)
+            if (ssl->options.resuming)
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #endif
+        }
+    #endif
 #endif
     #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
@@ -7936,7 +9361,7 @@
         XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
-        TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
         /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
          *       TLSX_CERTIFICATE_AUTHORITIES, OID_FILTERS
+         *       TLSX_STATUS_REQUEST
          */
     }
@@ -7945,11 +9370,11 @@
 
     if (ssl->extensions)
-        length += TLSX_GetSize(ssl->extensions, semaphore, msgType);
+        ret = TLSX_GetSize(ssl->extensions, semaphore, msgType, &length);
     if (ssl->ctx && ssl->ctx->extensions)
-        length += TLSX_GetSize(ssl->ctx->extensions, semaphore, msgType);
+        ret = TLSX_GetSize(ssl->ctx->extensions, semaphore, msgType, &length);
 
 #ifdef HAVE_EXTENDED_MASTER
     if (msgType == client_hello && ssl->options.haveEMS &&
-                                              !IsAtLeastTLSv1_3(ssl->version)) {
+                  (!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade)) {
         length += HELLO_EXT_SZ;
     }
@@ -7959,10 +9384,13 @@
         length += OPAQUE16_LEN; /* for total length storage. */
 
-    return length;
+    *pLength += length;
+
+    return ret;
 }
 
 /** Writes the extensions to be sent into the client hello. */
-word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType)
-{
+int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word16* pOffset)
+{
+    int ret = 0;
     word16 offset = 0;
     byte semaphore[SEMAPHORE_SIZE] = {0};
@@ -7997,4 +9425,16 @@
         }
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+        if (IsAtLeastTLSv1_3(ssl->version) && ssl->options.noPskDheKe) {
+        #if !defined(NO_PSK)
+            if (ssl->options.havePSK)
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #endif
+        #if defined(HAVE_SESSION_TICKET)
+            if (ssl->options.resuming)
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #endif
+        }
+    #endif
+    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
         /* Must write Pre-shared Key extension at the end in TLS v1.3.
          * Must not write out Pre-shared Key extension in earlier versions of
@@ -8018,7 +9458,7 @@
         XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
-        TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
         /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
          *       TLSX_CERTIFICATE_AUTHORITIES, TLSX_OID_FILTERS
+         *       TLSX_STATUS_REQUEST
          */
     }
@@ -8027,15 +9467,16 @@
 
     if (ssl->extensions) {
-        offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
-                             msgType);
+        ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+                         msgType, &offset);
     }
     if (ssl->ctx && ssl->ctx->extensions) {
-        offset += TLSX_Write(ssl->ctx->extensions, output + offset, semaphore,
-                             msgType);
+        ret = TLSX_Write(ssl->ctx->extensions, output + offset, semaphore,
+                         msgType, &offset);
     }
 
 #ifdef HAVE_EXTENDED_MASTER
     if (msgType == client_hello && ssl->options.haveEMS &&
-                                              !IsAtLeastTLSv1_3(ssl->version)) {
+                  (!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade)) {
+        WOLFSSL_MSG("EMS extension to write");
         c16toa(HELLO_EXT_EXTMS, output + offset);
         offset += HELLO_EXT_TYPE_SZ;
@@ -8050,6 +9491,6 @@
         /* Write out what we can of Pre-shared key extension.  */
         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
-        offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
-                             client_hello);
+        ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+                         client_hello, &offset);
     }
     #endif
@@ -8059,18 +9500,22 @@
         c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
 
-    return offset;
-}
-
-#endif /* NO_WOLFSSL_CLIENT */
-
-#ifndef NO_WOLFSSL_SERVER
+     *pOffset += offset;
+
+    return ret;
+}
+
+#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */
+
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_SERVER)
 
 /** Tells the buffered size of extensions to be sent into the server hello. */
-word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType)
-{
+int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength)
+{
+    int ret = 0;
     word16 length = 0;
     byte semaphore[SEMAPHORE_SIZE] = {0};
 
     switch (msgType) {
+#ifndef NO_WOLFSSL_SERVER
         case server_hello:
             PF_VALIDATE_RESPONSE(ssl, semaphore);
@@ -8078,4 +9523,9 @@
                 if (ssl->options.tls1_3) {
                     XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+        #ifndef WOLFSSL_TLS13_DRAFT_18
+                    TURN_OFF(semaphore,
+                                     TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+        #endif
+                    if (!ssl->options.noPskDheKe)
                     TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
@@ -8083,15 +9533,29 @@
     #endif
                 }
+                else {
+                    TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+                    TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+        #endif
+                }
 #endif
             break;
+
 #ifdef WOLFSSL_TLS13
         case hello_retry_request:
             XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+        #ifndef WOLFSSL_TLS13_DRAFT_18
+                TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+        #endif
+            if (!ssl->options.noPskDheKe)
             TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
             TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
-#endif
             break;
+    #endif
+
 #ifdef WOLFSSL_TLS13
         case encrypted_extensions:
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
@@ -8099,5 +9563,9 @@
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
     #endif
+        #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+        #endif
             break;
+
     #ifdef WOLFSSL_EARLY_DATA
         case session_ticket:
@@ -8108,4 +9576,8 @@
             break;
     #endif
+    #endif
+#endif
+
+#ifdef WOLFSSL_TLS13
     #ifndef NO_CERT
         case certificate:
@@ -8130,10 +9602,12 @@
 
 #ifdef HAVE_EXTENDED_MASTER
-    if (ssl->options.haveEMS && msgType == server_hello)
+    if (ssl->options.haveEMS && msgType == server_hello &&
+                                              !IsAtLeastTLSv1_3(ssl->version)) {
         length += HELLO_EXT_SZ;
+    }
 #endif
 
     if (TLSX_SupportExtensions(ssl))
-        length += TLSX_GetSize(ssl->extensions, semaphore, msgType);
+        ret = TLSX_GetSize(ssl->extensions, semaphore, msgType, &length);
 
     /* All the response data is set at the ssl object only, so no ctx here. */
@@ -8142,10 +9616,13 @@
         length += OPAQUE16_LEN; /* for total length storage. */
 
-    return length;
+    *pLength += length;
+
+    return ret;
 }
 
 /** Writes the server hello extensions into a buffer. */
-word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType)
-{
+int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset)
+{
+    int ret = 0;
     word16 offset = 0;
 
@@ -8154,4 +9631,5 @@
 
         switch (msgType) {
+#ifndef NO_WOLFSSL_SERVER
             case server_hello:
                 PF_VALIDATE_RESPONSE(ssl, semaphore);
@@ -8159,4 +9637,9 @@
                 if (ssl->options.tls1_3) {
                     XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+        #ifndef WOLFSSL_TLS13_DRAFT_18
+                    TURN_OFF(semaphore,
+                                     TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+        #endif
+                    if (!ssl->options.noPskDheKe)
                     TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
@@ -8164,14 +9647,29 @@
     #endif
                 }
-#endif
-                break;
+                else {
+                    TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+                    TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+        #endif
+                }
+#endif
+                break;
+
 #ifdef WOLFSSL_TLS13
             case hello_retry_request:
                 XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-                TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
-#endif
-                break;
+        #ifndef WOLFSSL_TLS13_DRAFT_18
+                TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+#endif
+                if (!ssl->options.noPskDheKe)
+                    TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+                /* Cookie is written below as last extension. */
+                break;
+    #endif
+
 #ifdef WOLFSSL_TLS13
             case encrypted_extensions:
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
@@ -8179,5 +9677,21 @@
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
     #endif
-                break;
+        #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+        #endif
+                break;
+
+        #ifdef WOLFSSL_EARLY_DATA
+            case session_ticket:
+                if (ssl->options.tls1_3) {
+                    XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+                    TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
+                }
+                break;
+        #endif
+    #endif
+#endif
+
+    #ifdef WOLFSSL_TLS13
     #ifndef NO_CERTS
             case certificate:
@@ -8189,12 +9703,4 @@
                 break;
     #endif
-    #ifdef WOLFSSL_EARLY_DATA
-            case session_ticket:
-                if (ssl->options.tls1_3) {
-                    XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-                    TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
-                }
-                break;
-    #endif
 #endif
         }
@@ -8202,6 +9708,6 @@
         offset += OPAQUE16_LEN; /* extensions length */
 
-        offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
-                             msgType);
+        ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+                         msgType, &offset);
 
 #ifdef WOLFSSL_TLS13
@@ -8209,11 +9715,13 @@
             XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
             TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
-            offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
-                                 msgType);
+            ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+                             msgType, &offset);
         }
 #endif
 
 #ifdef HAVE_EXTENDED_MASTER
-        if (ssl->options.haveEMS && msgType == server_hello) {
+        if (ssl->options.haveEMS && msgType == server_hello &&
+                                              !IsAtLeastTLSv1_3(ssl->version)) {
+            WOLFSSL_MSG("EMS extension to write");
             c16toa(HELLO_EXT_EXTMS, output + offset);
             offset += HELLO_EXT_TYPE_SZ;
@@ -8227,8 +9735,11 @@
     }
 
-    return offset;
-}
-
-#endif /* NO_WOLFSSL_SERVER */
+    if (pOffset)
+        *pOffset += offset;
+
+    return ret;
+}
+
+#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_SERVER */
 
 /** Parses a buffer of TLS extensions. */
@@ -8240,6 +9751,10 @@
     byte isRequest = (msgType == client_hello ||
                       msgType == certificate_request);
+
 #ifdef HAVE_EXTENDED_MASTER
     byte pendingEMS = 0;
+#endif
+#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK))
+    int pskDone = 0;
 #endif
 
@@ -8251,4 +9766,9 @@
         word16 size;
 
+#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK))
+        if (msgType == client_hello && pskDone)
+            return PSK_KEY_ERROR;
+#endif
+
         if (length - offset < HELLO_EXT_TYPE_SZ + OPAQUE16_LEN)
             return BUFFER_ERROR;
@@ -8268,9 +9788,13 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
                         msgType != client_hello &&
                         msgType != encrypted_extensions) {
                     return EXT_NOT_ALLOWED;
                 }
+                else if (!IsAtLeastTLSv1_3(ssl->version) &&
+                         msgType == encrypted_extensions) {
+                    return EXT_NOT_ALLOWED;
+                }
 #endif
                 ret = SNI_PARSE(ssl, input + offset, size, isRequest);
@@ -8281,9 +9805,13 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
                         msgType != client_hello &&
                         msgType != encrypted_extensions) {
                     return EXT_NOT_ALLOWED;
                 }
+                else if (!IsAtLeastTLSv1_3(ssl->version) &&
+                         msgType == encrypted_extensions) {
+                    return EXT_NOT_ALLOWED;
+                }
 #endif
                 ret = MFL_PARSE(ssl, input + offset, size, isRequest);
@@ -8294,6 +9822,8 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version))
-                    return EXT_NOT_ALLOWED;
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
+                        !ssl->options.downgrade) {
+                    break;
+                }
 #endif
                 ret = THM_PARSE(ssl, input + offset, size, isRequest);
@@ -8301,12 +9831,16 @@
 
             case TLSX_SUPPORTED_GROUPS:
-                WOLFSSL_MSG("Elliptic Curves extension received");
+                WOLFSSL_MSG("Supported Groups extension received");
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
                         msgType != client_hello &&
                         msgType != encrypted_extensions) {
                     return EXT_NOT_ALLOWED;
                 }
+                else if (!IsAtLeastTLSv1_3(ssl->version) &&
+                         msgType == encrypted_extensions) {
+                    return EXT_NOT_ALLOWED;
+                }
 #endif
                 ret = EC_PARSE(ssl, input + offset, size, isRequest);
@@ -8317,8 +9851,7 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello &&
-                        msgType != encrypted_extensions) {
-                    return EXT_NOT_ALLOWED;
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
+                        !ssl->options.downgrade) {
+                    break;
                 }
 #endif
@@ -8330,8 +9863,7 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello &&
-                        msgType != encrypted_extensions) {
-                    return EXT_NOT_ALLOWED;
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
+                        !ssl->options.downgrade) {
+                    break;
                 }
 #endif
@@ -8343,7 +9875,8 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
                         msgType != client_hello &&
-                        msgType != encrypted_extensions) {
+                        msgType != certificate_request &&
+                        msgType != certificate) {
                     return EXT_NOT_ALLOWED;
                 }
@@ -8355,4 +9888,33 @@
             case HELLO_EXT_EXTMS:
                 WOLFSSL_MSG("Extended Master Secret extension received");
+
+#ifdef WOLFSSL_TLS13
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
+                        !ssl->options.downgrade) {
+                    break;
+                }
+#endif
+#ifndef NO_WOLFSSL_SERVER
+                if (isRequest)
+                    ssl->options.haveEMS = 1;
+#endif
+                pendingEMS = 1;
+                break;
+#endif
+
+            case TLSX_RENEGOTIATION_INFO:
+                WOLFSSL_MSG("Secure Renegotiation extension received");
+
+#ifdef WOLFSSL_TLS13
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
+                        !ssl->options.downgrade) {
+                    break;
+                }
+#endif
+                ret = SCR_PARSE(ssl, input + offset, size, isRequest);
+                break;
+
+            case TLSX_SESSION_TICKET:
+                WOLFSSL_MSG("Session Ticket extension received");
 
 #ifdef WOLFSSL_TLS13
@@ -8362,27 +9924,4 @@
                 }
 #endif
-#ifndef NO_WOLFSSL_SERVER
-                if (isRequest && !IsAtLeastTLSv1_3(ssl->version))
-                    ssl->options.haveEMS = 1;
-#endif
-                pendingEMS = 1;
-                break;
-#endif
-
-            case TLSX_RENEGOTIATION_INFO:
-                WOLFSSL_MSG("Secure Renegotiation extension received");
-
-                ret = SCR_PARSE(ssl, input + offset, size, isRequest);
-                break;
-
-            case TLSX_SESSION_TICKET:
-                WOLFSSL_MSG("Session Ticket extension received");
-
-#ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello) {
-                    return EXT_NOT_ALLOWED;
-                }
-#endif
                 ret = WOLF_STK_PARSE(ssl, input + offset, size, isRequest);
                 break;
@@ -8392,6 +9931,8 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version))
-                    return EXT_NOT_ALLOWED;
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
+                        !ssl->options.downgrade) {
+                    break;
+                }
 #endif
                 ret = QSH_PARSE(ssl, input + offset, size, isRequest);
@@ -8402,9 +9943,14 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
                         msgType != client_hello &&
+                        msgType != server_hello &&
                         msgType != encrypted_extensions) {
                     return EXT_NOT_ALLOWED;
                 }
+                else if (!IsAtLeastTLSv1_3(ssl->version) &&
+                         msgType == encrypted_extensions) {
+                    return EXT_NOT_ALLOWED;
+                }
 #endif
                 ret = ALPN_PARSE(ssl, input + offset, size, isRequest);
@@ -8417,10 +9963,12 @@
                     break;
 
-                if (IsAtLeastTLSv1_3(ssl->version) &&
+#ifdef WOLFSSL_TLS13
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
                         msgType != client_hello &&
                         msgType != certificate_request) {
                     return EXT_NOT_ALLOWED;
                 }
-                ret = SA_PARSE(ssl, input + offset, size, suites);
+#endif
+                ret = SA_PARSE(ssl, input + offset, size, isRequest, suites);
                 break;
 
@@ -8429,9 +9977,19 @@
                 WOLFSSL_MSG("Supported Versions extension received");
 
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello) {
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
+                    break;
+
+                if (
+    #ifdef WOLFSSL_TLS13_DRAFT_18
+                        msgType != client_hello
+    #else
+                        msgType != client_hello &&
+                        msgType != server_hello &&
+                        msgType != hello_retry_request
+    #endif
+                   ) {
                     return EXT_NOT_ALLOWED;
                 }
-                ret = SV_PARSE(ssl, input + offset, size);
+                ret = SV_PARSE(ssl, input + offset, size, msgType);
                 break;
 
@@ -8439,23 +9997,103 @@
                 WOLFSSL_MSG("Cookie extension received");
 
-                if (!IsAtLeastTLSv1_3(ssl->version))
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
                     break;
 
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello &&
+                if (msgType != client_hello &&
                         msgType != hello_retry_request) {
                     return EXT_NOT_ALLOWED;
                 }
+
                 ret = CKE_PARSE(ssl, input + offset, size, msgType);
                 break;
+
+    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+            case TLSX_PRE_SHARED_KEY:
+                WOLFSSL_MSG("Pre-Shared Key extension received");
+
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
+                    break;
+
+                if (msgType != client_hello && msgType != server_hello)
+                    return EXT_NOT_ALLOWED;
+
+                ret = PSK_PARSE(ssl, input + offset, size, msgType);
+                pskDone = 1;
+                break;
+
+            case TLSX_PSK_KEY_EXCHANGE_MODES:
+                WOLFSSL_MSG("PSK Key Exchange Modes extension received");
+
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
+                    break;
+
+                if (msgType != client_hello)
+                    return EXT_NOT_ALLOWED;
+
+                ret = PKM_PARSE(ssl, input + offset, size, msgType);
+                break;
+    #endif
+
+    #ifdef WOLFSSL_EARLY_DATA
+            case TLSX_EARLY_DATA:
+                WOLFSSL_MSG("Early Data extension received");
+
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
+                    break;
+
+                if (msgType != client_hello && msgType != session_ticket &&
+                         msgType != encrypted_extensions) {
+                    return EXT_NOT_ALLOWED;
+                }
+                if (!IsAtLeastTLSv1_3(ssl->version) &&
+                        (msgType == session_ticket ||
+                         msgType == encrypted_extensions)) {
+                    return EXT_NOT_ALLOWED;
+                }
+                ret = EDI_PARSE(ssl, input + offset, size, msgType);
+                break;
+    #endif
+
+    #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+            case TLSX_POST_HANDSHAKE_AUTH:
+                WOLFSSL_MSG("Post Handshake Authentication extension received");
+
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
+                    break;
+
+                if (msgType != client_hello)
+                    return EXT_NOT_ALLOWED;
+
+                ret = PHA_PARSE(ssl, input + offset, size, msgType);
+                break;
+    #endif
+
+    #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+            case TLSX_SIGNATURE_ALGORITHMS_CERT:
+                WOLFSSL_MSG("Signature Algorithms extension received");
+
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
+                    break;
+
+                if (msgType != client_hello &&
+                        msgType != certificate_request) {
+                    return EXT_NOT_ALLOWED;
+                }
+                if (!IsAtLeastTLSv1_3(ssl->version) &&
+                        msgType == certificate_request) {
+                    return EXT_NOT_ALLOWED;
+                }
+
+                ret = SAC_PARSE(ssl, input + offset, size, isRequest);
+                break;
+    #endif
 
             case TLSX_KEY_SHARE:
                 WOLFSSL_MSG("Key Share extension received");
 
-                if (!IsAtLeastTLSv1_3(ssl->version))
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
                     break;
 
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello && msgType != server_hello &&
+                if (msgType != client_hello && msgType != server_hello &&
                         msgType != hello_retry_request) {
                     return EXT_NOT_ALLOWED;
@@ -8463,63 +10101,4 @@
                 ret = KS_PARSE(ssl, input + offset, size, msgType);
                 break;
-
-    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
-            case TLSX_PRE_SHARED_KEY:
-                WOLFSSL_MSG("Pre-Shared Key extension received");
-
-                if (!IsAtLeastTLSv1_3(ssl->version))
-                    break;
-
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello && msgType != server_hello) {
-                    return EXT_NOT_ALLOWED;
-                }
-                ret = PSK_PARSE(ssl, input + offset, size, msgType);
-                break;
-
-            case TLSX_PSK_KEY_EXCHANGE_MODES:
-                WOLFSSL_MSG("PSK Key Exchange Modes extension received");
-
-                if (!IsAtLeastTLSv1_3(ssl->version))
-                    break;
-
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello) {
-                    return EXT_NOT_ALLOWED;
-                }
-                ret = PKM_PARSE(ssl, input + offset, size, msgType);
-                break;
-    #endif
-
-    #ifdef WOLFSSL_EARLY_DATA
-            case TLSX_EARLY_DATA:
-                WOLFSSL_MSG("Early Data extension received");
-
-                if (!IsAtLeastTLSv1_3(ssl->version))
-                    break;
-
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                         msgType != client_hello && msgType != session_ticket &&
-                         msgType != encrypted_extensions) {
-                    return EXT_NOT_ALLOWED;
-                }
-                ret = EDI_PARSE(ssl, input + offset, size, msgType);
-                break;
-    #endif
-
-    #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
-            case TLSX_POST_HANDSHAKE_AUTH:
-                WOLFSSL_MSG("PSK Key Exchange Modes extension received");
-
-                if (!IsAtLeastTLSv1_3(ssl->version))
-                    break;
-
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello) {
-                    return EXT_NOT_ALLOWED;
-                }
-                ret = PHA_PARSE(ssl, input + offset, size, msgType);
-                break;
-    #endif
 #endif
         }
@@ -8550,16 +10129,9 @@
 
 #ifndef NO_OLD_TLS
-
+    #ifdef WOLFSSL_ALLOW_TLSV10
     WOLFSSL_METHOD* wolfTLSv1_client_method(void)
     {
         return wolfTLSv1_client_method_ex(NULL);
     }
-
-
-    WOLFSSL_METHOD* wolfTLSv1_1_client_method(void)
-    {
-        return wolfTLSv1_1_client_method_ex(NULL);
-    }
-
     WOLFSSL_METHOD* wolfTLSv1_client_method_ex(void* heap)
     {
@@ -8567,10 +10139,16 @@
                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
                                                      heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("TLSv1_client_method_ex");
         if (method)
             InitSSL_Method(method, MakeTLSv1());
         return method;
     }
-
-
+    #endif /* WOLFSSL_ALLOW_TLSV10 */
+
+    WOLFSSL_METHOD* wolfTLSv1_1_client_method(void)
+    {
+        return wolfTLSv1_1_client_method_ex(NULL);
+    }
     WOLFSSL_METHOD* wolfTLSv1_1_client_method_ex(void* heap)
     {
@@ -8578,17 +10156,17 @@
                               (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
                                                      heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("TLSv1_1_client_method_ex");
         if (method)
             InitSSL_Method(method, MakeTLSv1_1());
         return method;
     }
-
 #endif /* !NO_OLD_TLS */
 
-
+#ifndef WOLFSSL_NO_TLS12
     WOLFSSL_METHOD* wolfTLSv1_2_client_method(void)
     {
         return wolfTLSv1_2_client_method_ex(NULL);
     }
-
     WOLFSSL_METHOD* wolfTLSv1_2_client_method_ex(void* heap)
     {
@@ -8597,8 +10175,10 @@
                                                      heap, DYNAMIC_TYPE_METHOD);
         (void)heap;
+        WOLFSSL_ENTER("TLSv1_2_client_method_ex");
         if (method)
             InitSSL_Method(method, MakeTLSv1_2());
         return method;
     }
+#endif /* WOLFSSL_NO_TLS12 */
 
 #ifdef WOLFSSL_TLS13
@@ -8623,4 +10203,5 @@
                                          DYNAMIC_TYPE_METHOD);
         (void)heap;
+        WOLFSSL_ENTER("TLSv1_3_client_method_ex");
         if (method)
             InitSSL_Method(method, MakeTLSv1_3());
@@ -8629,12 +10210,11 @@
 #endif /* WOLFSSL_TLS13 */
 
-
-    WOLFSSL_METHOD* wolfSSLv23_client_method(void)
+#ifdef WOLFSSL_DTLS
+
+    WOLFSSL_METHOD* wolfDTLS_client_method(void)
     {
-        return wolfSSLv23_client_method_ex(NULL);
-    }
-
-
-    WOLFSSL_METHOD* wolfSSLv23_client_method_ex(void* heap)
+        return wolfDTLS_client_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLS_client_method_ex(void* heap)
     {
         WOLFSSL_METHOD* method =
@@ -8642,25 +10222,201 @@
                                                      heap, DYNAMIC_TYPE_METHOD);
         (void)heap;
+        WOLFSSL_ENTER("DTLS_client_method_ex");
         if (method) {
-#if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)
-#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NGINX)
-            InitSSL_Method(method, MakeTLSv1_3());
+        #if !defined(WOLFSSL_NO_TLS12)
+            InitSSL_Method(method, MakeDTLSv1_2());
+        #elif !defined(NO_OLD_TLS)
+            InitSSL_Method(method, MakeDTLSv1());
 #else
-            InitSSL_Method(method, MakeTLSv1_2());
-#endif
-#else
+            #error No DTLS version enabled!
+    #endif
+
+            method->downgrade = 1;
+            method->side      = WOLFSSL_CLIENT_END;
+        }
+        return method;
+    }
+
     #ifndef NO_OLD_TLS
-            InitSSL_Method(method, MakeTLSv1_1());
-    #endif
-#endif
+    WOLFSSL_METHOD* wolfDTLSv1_client_method(void)
+    {
+        return wolfDTLSv1_client_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLSv1_client_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* method =
+                          (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+                                                 heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("DTLSv1_client_method_ex");
+        if (method)
+            InitSSL_Method(method, MakeDTLSv1());
+        return method;
+    }
+    #endif  /* NO_OLD_TLS */
+
+    #ifndef WOLFSSL_NO_TLS12
+    WOLFSSL_METHOD* wolfDTLSv1_2_client_method(void)
+    {
+        return wolfDTLSv1_2_client_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLSv1_2_client_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* method =
+                          (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+                                                 heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("DTLSv1_2_client_method_ex");
+        if (method)
+            InitSSL_Method(method, MakeDTLSv1_2());
+        (void)heap;
+        return method;
+    }
+    #endif /* !WOLFSSL_NO_TLS12 */
+#endif /* WOLFSSL_DTLS */
+
+#endif /* NO_WOLFSSL_CLIENT */
+
+
+/* EITHER SIDE METHODS */
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
 #ifndef NO_OLD_TLS
-            method->downgrade = 1;
-#endif
-        }
-        return method;
-    }
-
-#endif /* NO_WOLFSSL_CLIENT */
-
+    #ifdef WOLFSSL_ALLOW_TLSV10
+    /* Gets a WOLFSL_METHOD type that is not set as client or server
+     *
+     * Returns a pointer to a WOLFSSL_METHOD struct
+     */
+    WOLFSSL_METHOD* wolfTLSv1_method(void)
+    {
+        return wolfTLSv1_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfTLSv1_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* m;
+        WOLFSSL_ENTER("TLSv1_method");
+    #ifndef NO_WOLFSSL_CLIENT
+        m = wolfTLSv1_client_method_ex(heap);
+    #else
+        m = wolfTLSv1_server_method_ex(heap);
+    #endif
+        if (m != NULL) {
+            m->side = WOLFSSL_NEITHER_END;
+        }
+
+        return m;
+    }
+    #endif /* WOLFSSL_ALLOW_TLSV10 */
+
+    /* Gets a WOLFSL_METHOD type that is not set as client or server
+     *
+     * Returns a pointer to a WOLFSSL_METHOD struct
+     */
+    WOLFSSL_METHOD* wolfTLSv1_1_method(void)
+    {
+        return wolfTLSv1_1_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfTLSv1_1_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* m;
+        WOLFSSL_ENTER("TLSv1_1_method");
+    #ifndef NO_WOLFSSL_CLIENT
+        m = wolfTLSv1_1_client_method_ex(heap);
+    #else
+        m = wolfTLSv1_1_server_method_ex(heap);
+    #endif
+        if (m != NULL) {
+            m->side = WOLFSSL_NEITHER_END;
+        }
+        return m;
+    }
+    #endif /* !NO_OLD_TLS */
+
+    #ifndef WOLFSSL_NO_TLS12
+    /* Gets a WOLFSL_METHOD type that is not set as client or server
+     *
+     * Returns a pointer to a WOLFSSL_METHOD struct
+     */
+    WOLFSSL_METHOD* wolfTLSv1_2_method(void)
+    {
+        return wolfTLSv1_2_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfTLSv1_2_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* m;
+        WOLFSSL_ENTER("TLSv1_2_method");
+    #ifndef NO_WOLFSSL_CLIENT
+        m = wolfTLSv1_2_client_method_ex(heap);
+    #else
+        m = wolfTLSv1_2_server_method_ex(heap);
+    #endif
+        if (m != NULL) {
+            m->side = WOLFSSL_NEITHER_END;
+    }
+        return m;
+    }
+    #endif /* !WOLFSSL_NO_TLS12 */
+
+#ifdef WOLFSSL_DTLS
+    WOLFSSL_METHOD* wolfDTLS_method(void)
+    {
+        return wolfDTLS_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLS_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* m;
+        WOLFSSL_ENTER("DTLS_method_ex");
+    #ifndef NO_WOLFSSL_CLIENT
+        m = wolfDTLS_client_method_ex(heap);
+    #else
+        m = wolfDTLS_server_method_ex(heap);
+    #endif
+        if (m != NULL) {
+            m->side = WOLFSSL_NEITHER_END;
+        }
+        return m;
+    }
+
+    #ifndef NO_OLD_TLS
+    WOLFSSL_METHOD* wolfDTLSv1_method(void)
+    {
+        return wolfDTLSv1_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLSv1_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* m;
+        WOLFSSL_ENTER("DTLSv1_method_ex");
+    #ifndef NO_WOLFSSL_CLIENT
+        m = wolfDTLSv1_client_method_ex(heap);
+    #else
+        m = wolfDTLSv1_server_method_ex(heap);
+    #endif
+        if (m != NULL) {
+            m->side = WOLFSSL_NEITHER_END;
+        }
+        return m;
+    }
+    #endif /* !NO_OLD_TLS */
+    #ifndef WOLFSSL_NO_TLS12
+    WOLFSSL_METHOD* wolfDTLSv1_2_method(void)
+    {
+        return wolfDTLSv1_2_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLSv1_2_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* m;
+        WOLFSSL_ENTER("DTLSv1_2_method");
+    #ifndef NO_WOLFSSL_CLIENT
+        m = wolfDTLSv1_2_client_method_ex(heap);
+    #else
+        m = wolfDTLSv1_2_server_method_ex(heap);
+    #endif
+        if (m != NULL) {
+            m->side = WOLFSSL_NEITHER_END;
+        }
+        return m;
+    }
+    #endif /* !WOLFSSL_NO_TLS12 */
+#endif /* WOLFSSL_DTLS */
+#endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */
 
 
@@ -8668,16 +10424,9 @@
 
 #ifndef NO_OLD_TLS
-
+    #ifdef WOLFSSL_ALLOW_TLSV10
     WOLFSSL_METHOD* wolfTLSv1_server_method(void)
     {
         return wolfTLSv1_server_method_ex(NULL);
     }
-
-
-    WOLFSSL_METHOD* wolfTLSv1_1_server_method(void)
-    {
-        return wolfTLSv1_1_server_method_ex(NULL);
-    }
-
     WOLFSSL_METHOD* wolfTLSv1_server_method_ex(void* heap)
     {
@@ -8685,4 +10434,6 @@
                               (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
                                                      heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("TLSv1_server_method_ex");
         if (method) {
             InitSSL_Method(method, MakeTLSv1());
@@ -8691,6 +10442,10 @@
         return method;
     }
-
-
+    #endif /* WOLFSSL_ALLOW_TLSV10 */
+
+    WOLFSSL_METHOD* wolfTLSv1_1_server_method(void)
+    {
+        return wolfTLSv1_1_server_method_ex(NULL);
+    }
     WOLFSSL_METHOD* wolfTLSv1_1_server_method_ex(void* heap)
     {
@@ -8698,4 +10453,6 @@
                               (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
                                                      heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("TLSv1_1_server_method_ex");
         if (method) {
             InitSSL_Method(method, MakeTLSv1_1());
@@ -8707,9 +10464,9 @@
 
 
+#ifndef WOLFSSL_NO_TLS12
     WOLFSSL_METHOD* wolfTLSv1_2_server_method(void)
     {
         return wolfTLSv1_2_server_method_ex(NULL);
     }
-
     WOLFSSL_METHOD* wolfTLSv1_2_server_method_ex(void* heap)
     {
@@ -8718,4 +10475,5 @@
                                                      heap, DYNAMIC_TYPE_METHOD);
         (void)heap;
+        WOLFSSL_ENTER("TLSv1_2_server_method_ex");
         if (method) {
             InitSSL_Method(method, MakeTLSv1_2());
@@ -8724,4 +10482,5 @@
         return method;
     }
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #ifdef WOLFSSL_TLS13
@@ -8746,4 +10505,5 @@
                                                      heap, DYNAMIC_TYPE_METHOD);
         (void)heap;
+        WOLFSSL_ENTER("TLSv1_3_server_method_ex");
         if (method) {
             InitSSL_Method(method, MakeTLSv1_3());
@@ -8754,10 +10514,10 @@
 #endif /* WOLFSSL_TLS13 */
 
-    WOLFSSL_METHOD* wolfSSLv23_server_method(void)
+#ifdef WOLFSSL_DTLS
+    WOLFSSL_METHOD* wolfDTLS_server_method(void)
     {
-        return wolfSSLv23_server_method_ex(NULL);
-    }
-
-    WOLFSSL_METHOD* wolfSSLv23_server_method_ex(void* heap)
+        return wolfDTLS_server_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLS_server_method_ex(void* heap)
     {
         WOLFSSL_METHOD* method =
@@ -8765,28 +10525,64 @@
                                                      heap, DYNAMIC_TYPE_METHOD);
         (void)heap;
+        WOLFSSL_ENTER("DTLS_server_method_ex");
         if (method) {
-#if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)
-#ifdef WOLFSSL_TLS13
-            InitSSL_Method(method, MakeTLSv1_3());
-#else
-            InitSSL_Method(method, MakeTLSv1_2());
-#endif
-#else
+        #if !defined(WOLFSSL_NO_TLS12)
+            InitSSL_Method(method, MakeDTLSv1_2());
+        #elif !defined(NO_OLD_TLS)
+            InitSSL_Method(method, MakeDTLSv1());
+    #else
+            #error No DTLS version enabled!
+    #endif
+
+            method->downgrade = 1;
+            method->side      = WOLFSSL_SERVER_END;
+        }
+        return method;
+    }
+
     #ifndef NO_OLD_TLS
-            InitSSL_Method(method, MakeTLSv1_1());
-    #else
-            #error Must have SHA256, SHA384 or SHA512 enabled for TLS 1.2
-    #endif
-#endif
-#ifndef NO_OLD_TLS
-            method->downgrade = 1;
-#endif
-            method->side      = WOLFSSL_SERVER_END;
+    WOLFSSL_METHOD* wolfDTLSv1_server_method(void)
+    {
+        return wolfDTLSv1_server_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLSv1_server_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* method =
+                          (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+                                                 heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("DTLSv1_server_method_ex");
+        if (method) {
+            InitSSL_Method(method, MakeDTLSv1());
+            method->side = WOLFSSL_SERVER_END;
         }
         return method;
     }
-
+    #endif /* !NO_OLD_TLS */
+
+    #ifndef WOLFSSL_NO_TLS12
+    WOLFSSL_METHOD* wolfDTLSv1_2_server_method(void)
+    {
+        return wolfDTLSv1_2_server_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLSv1_2_server_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* method =
+                          (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+                                                 heap, DYNAMIC_TYPE_METHOD);
+        WOLFSSL_ENTER("DTLSv1_2_server_method_ex");
+        (void)heap;
+        if (method) {
+            InitSSL_Method(method, MakeDTLSv1_2());
+            method->side = WOLFSSL_SERVER_END;
+        }
+        (void)heap;
+        return method;
+    }
+    #endif /* !WOLFSSL_NO_TLS12 */
+#endif /* WOLFSSL_DTLS */
 
 #endif /* NO_WOLFSSL_SERVER */
+
 #endif /* NO_TLS */
 #endif /* WOLFCRYPT_ONLY */
