summaryrefslogtreecommitdiff
path: root/FreeRTOS-Plus/Source/WolfSSL/src/tls.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS-Plus/Source/WolfSSL/src/tls.c')
-rw-r--r--FreeRTOS-Plus/Source/WolfSSL/src/tls.c11255
1 files changed, 10282 insertions, 973 deletions
diff --git a/FreeRTOS-Plus/Source/WolfSSL/src/tls.c b/FreeRTOS-Plus/Source/WolfSSL/src/tls.c
index f4c76d738..1b9858a75 100644
--- a/FreeRTOS-Plus/Source/WolfSSL/src/tls.c
+++ b/FreeRTOS-Plus/Source/WolfSSL/src/tls.c
@@ -1,8 +1,8 @@
/* tls.c
*
- * Copyright (C) 2006-2015 wolfSSL Inc.
+ * Copyright (C) 2006-2020 wolfSSL Inc.
*
- * This file is part of wolfSSL. (formerly known as CyaSSL)
+ * This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,16 +16,19 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
+#ifndef WOLFCRYPT_ONLY
+
#include <wolfssl/ssl.h>
#include <wolfssl/internal.h>
#include <wolfssl/error-ssl.h>
@@ -33,348 +36,207 @@
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
+ #define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
+#ifdef HAVE_CURVE25519
+ #include <wolfssl/wolfcrypt/curve25519.h>
+#endif
+#ifdef HAVE_CURVE448
+ #include <wolfssl/wolfcrypt/curve448.h>
+#endif
+#ifdef HAVE_NTRU
+ #include "libntruencrypt/ntru_crypto.h"
+ #include <wolfssl/wolfcrypt/random.h>
+#endif
+#ifdef HAVE_QSH
+ static int TLSX_AddQSHKey(QSHKey** list, QSHKey* key);
+ static byte* TLSX_QSHKeyFind_Pub(QSHKey* qsh, word16* pubLen, word16 name);
+#if defined(HAVE_NTRU)
+ static int TLSX_CreateNtruKey(WOLFSSL* ssl, int type);
+#endif
+#endif /* HAVE_QSH */
-#ifndef NO_TLS
-
-
-#ifndef WOLFSSL_HAVE_MIN
-#define WOLFSSL_HAVE_MIN
-
- static INLINE word32 min(word32 a, word32 b)
- {
- return a > b ? b : a;
- }
-
-#endif /* WOLFSSL_HAVE_MIN */
-
-
-#ifdef WOLFSSL_SHA384
- #define P_HASH_MAX_SIZE SHA384_DIGEST_SIZE
-#else
- #define P_HASH_MAX_SIZE SHA256_DIGEST_SIZE
+#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
-/* compute p_hash for MD5, SHA-1, SHA-256, or SHA-384 for TLSv1 PRF */
-static int p_hash(byte* result, word32 resLen, const byte* secret,
- word32 secLen, const byte* seed, word32 seedLen, int hash)
-{
- word32 len = P_HASH_MAX_SIZE;
- word32 times;
- word32 lastLen;
- word32 lastTime;
- word32 i;
- word32 idx = 0;
- int ret = 0;
-#ifdef WOLFSSL_SMALL_STACK
- byte* previous;
- byte* current;
- Hmac* hmac;
-#else
- byte previous[P_HASH_MAX_SIZE]; /* max size */
- byte current[P_HASH_MAX_SIZE]; /* max size */
- Hmac hmac[1];
+#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_CURVE448) && defined(HAVE_SUPPORTED_CURVES)) || \
+ ((defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+ defined(HAVE_CURVE448)) && defined(HAVE_SUPPORTED_CURVES))) && \
+ defined(HAVE_TLS_EXTENSIONS)
+static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions);
#endif
-#ifdef WOLFSSL_SMALL_STACK
- previous = (byte*)XMALLOC(P_HASH_MAX_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- current = (byte*)XMALLOC(P_HASH_MAX_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- hmac = (Hmac*)XMALLOC(sizeof(Hmac), NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (previous == NULL || current == NULL || hmac == NULL) {
- if (previous) XFREE(previous, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (current) XFREE(current, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (hmac) XFREE(hmac, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifndef NO_TLS
- return MEMORY_E;
- }
+/* Digest enable checks */
+#ifdef NO_OLD_TLS /* TLS 1.2 only */
+ #if defined(NO_SHA256) && !defined(WOLFSSL_SHA384) && \
+ !defined(WOLFSSL_SHA512)
+ #error Must have SHA256, SHA384 or SHA512 enabled for TLS 1.2
+ #endif
+#else /* TLS 1.1 or older */
+ #if defined(NO_MD5) && defined(NO_SHA)
+ #error Must have SHA1 and MD5 enabled for old TLS
+ #endif
#endif
- switch (hash) {
- #ifndef NO_MD5
- case md5_mac:
- hash = MD5;
- len = MD5_DIGEST_SIZE;
- break;
- #endif
-
- #ifndef NO_SHA256
- case sha256_mac:
- hash = SHA256;
- len = SHA256_DIGEST_SIZE;
- break;
- #endif
-
- #ifdef WOLFSSL_SHA384
- case sha384_mac:
- hash = SHA384;
- len = SHA384_DIGEST_SIZE;
- break;
+#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
+ #ifndef HAVE_TLS_EXTENSIONS
+ #ifndef _MSC_VER
+ #error "The build option HAVE_TLS_EXTENSIONS is required for TLS 1.3"
+ #else
+ #pragma message("Error: The build option HAVE_TLS_EXTENSIONS is required for TLS 1.3")
#endif
-
- #ifndef NO_SHA
- case sha_mac:
- default:
- hash = SHA;
- len = SHA_DIGEST_SIZE;
- break;
- #endif
- }
-
- times = resLen / len;
- lastLen = resLen % len;
-
- if (lastLen)
- times += 1;
-
- lastTime = times - 1;
-
- if ((ret = wc_HmacSetKey(hmac, hash, secret, secLen)) == 0) {
- if ((ret = wc_HmacUpdate(hmac, seed, seedLen)) == 0) { /* A0 = seed */
- if ((ret = wc_HmacFinal(hmac, previous)) == 0) { /* A1 */
- for (i = 0; i < times; i++) {
- ret = wc_HmacUpdate(hmac, previous, len);
- if (ret != 0)
- break;
- ret = wc_HmacUpdate(hmac, seed, seedLen);
- if (ret != 0)
- break;
- ret = wc_HmacFinal(hmac, current);
- if (ret != 0)
- break;
-
- if ((i == lastTime) && lastLen)
- XMEMCPY(&result[idx], current,
- min(lastLen, P_HASH_MAX_SIZE));
- else {
- XMEMCPY(&result[idx], current, len);
- idx += len;
- ret = wc_HmacUpdate(hmac, previous, len);
- if (ret != 0)
- break;
- ret = wc_HmacFinal(hmac, previous);
- if (ret != 0)
- break;
- }
- }
- }
- }
- }
-
- ForceZero(previous, P_HASH_MAX_SIZE);
- ForceZero(current, P_HASH_MAX_SIZE);
- ForceZero(hmac, sizeof(Hmac));
-
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(previous, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(current, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(hmac, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ #endif
#endif
- return ret;
-}
-
-#undef P_HASH_MAX_SIZE
-
-
-#ifndef NO_OLD_TLS
-
-/* calculate XOR for TLSv1 PRF */
-static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
-{
- word32 i;
-
- for (i = 0; i < digLen; i++)
- digest[i] = md5[i] ^ sha[i];
-}
-
-
-/* compute TLSv1 PRF (pseudo random function using HMAC) */
-static int doPRF(byte* digest, word32 digLen, const byte* secret,word32 secLen,
- const byte* label, word32 labLen, const byte* seed,
- word32 seedLen)
-{
- int ret = 0;
- word32 half = (secLen + 1) / 2;
-
-#ifdef WOLFSSL_SMALL_STACK
- byte* md5_half;
- byte* sha_half;
- byte* labelSeed;
- byte* md5_result;
- byte* sha_result;
-#else
- 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 */
+/* Warn if secrets logging is enabled */
+#if defined(SHOW_SECRETS) || defined(WOLFSSL_SSLKEYLOGFILE)
+ #ifndef _MSC_VER
+ #warning The SHOW_SECRETS and WOLFSSL_SSLKEYLOGFILE options should only be used for debugging and never in a production environment
+ #else
+ #pragma message("Warning: The SHOW_SECRETS and WOLFSSL_SSLKEYLOGFILE options should only be used for debugging and never in a production environment")
+ #endif
#endif
- if (half > MAX_PRF_HALF)
- 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, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- sha_half = (byte*)XMALLOC(MAX_PRF_HALF, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- labelSeed = (byte*)XMALLOC(MAX_PRF_LABSEED, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- md5_result = (byte*)XMALLOC(MAX_PRF_DIG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- sha_result = (byte*)XMALLOC(MAX_PRF_DIG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-
- if (md5_half == NULL || sha_half == NULL || labelSeed == NULL ||
- md5_result == NULL || sha_result == NULL) {
- if (md5_half) XFREE(md5_half, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (sha_half) XFREE(sha_half, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (labelSeed) XFREE(labelSeed, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (md5_result) XFREE(md5_result, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (sha_result) XFREE(sha_result, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-
- return MEMORY_E;
- }
+/* 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
-
- XMEMSET(md5_result, 0, digLen);
- XMEMSET(sha_result, 0, digLen);
-
- XMEMCPY(md5_half, secret, half);
- XMEMCPY(sha_half, secret + half - secLen % 2, half);
-
- XMEMCPY(labelSeed, label, labLen);
- XMEMCPY(labelSeed + labLen, seed, seedLen);
-
- if ((ret = p_hash(md5_result, digLen, md5_half, half, labelSeed,
- labLen + seedLen, md5_mac)) == 0) {
- if ((ret = p_hash(sha_result, digLen, sha_half, half, labelSeed,
- labLen + seedLen, sha_mac)) == 0) {
- get_xor(digest, digLen, md5_result, sha_result);
- }
- }
-
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(md5_half, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(sha_half, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(labelSeed, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(md5_result, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(sha_result, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
- return ret;
-}
+#ifndef WOLFSSL_NO_TLS12
+#ifdef WOLFSSL_SHA384
+ #define HSHASH_SZ WC_SHA384_DIGEST_SIZE
+#else
+ #define HSHASH_SZ FINISHED_SZ
#endif
+#ifdef WOLFSSL_RENESAS_TSIP_TLS
+ int tsip_useable(const WOLFSSL *ssl);
+ int tsip_generateMasterSecret(const byte *pre,
+ const byte *cr,const byte *sr,
+ byte *ms/* out */);
+ int tsip_generateSeesionKey(WOLFSSL *ssl);
+ int tsip_generateVerifyData(const byte *ms, const byte *side,
+ const byte *handshake_hash,
+ byte *hashes /* out */);
+#endif
-/* Wrapper to call straight thru to p_hash in TSL 1.2 cases to remove stack
- use */
-static int PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen,
- const byte* label, word32 labLen, const byte* seed, word32 seedLen,
- int useAtLeastSha256, int hash_type)
+int BuildTlsHandshakeHash(WOLFSSL* ssl, byte* hash, word32* hashLen)
{
int ret = 0;
+ word32 hashSz = FINISHED_SZ;
- if (useAtLeastSha256) {
-#ifdef WOLFSSL_SMALL_STACK
- byte* labelSeed;
-#else
- byte labelSeed[MAX_PRF_LABSEED]; /* labLen + seedLen is real size */
-#endif
-
- if (labLen + seedLen > MAX_PRF_LABSEED)
- return BUFFER_E;
+ if (ssl == NULL || hash == NULL || hashLen == NULL || *hashLen < HSHASH_SZ)
+ return BAD_FUNC_ARG;
-#ifdef WOLFSSL_SMALL_STACK
- labelSeed = (byte*)XMALLOC(MAX_PRF_LABSEED, NULL,
- DYNAMIC_TYPE_TMP_BUFFER);
- if (labelSeed == NULL)
- return MEMORY_E;
+ /* for constant timing perform these even if error */
+#ifndef NO_OLD_TLS
+ ret |= wc_Md5GetHash(&ssl->hsHashes->hashMd5, hash);
+ ret |= wc_ShaGetHash(&ssl->hsHashes->hashSha, &hash[WC_MD5_DIGEST_SIZE]);
#endif
- XMEMCPY(labelSeed, label, labLen);
- XMEMCPY(labelSeed + labLen, seed, seedLen);
-
- /* If a cipher suite wants an algorithm better than sha256, it
- * should use better. */
- if (hash_type < sha256_mac)
- hash_type = sha256_mac;
- ret = p_hash(digest, digLen, secret, secLen, labelSeed,
- labLen + seedLen, hash_type);
-
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(labelSeed, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ if (IsAtLeastTLSv1_2(ssl)) {
+#ifndef NO_SHA256
+ if (ssl->specs.mac_algorithm <= sha256_mac ||
+ ssl->specs.mac_algorithm == blake2b_mac) {
+ ret |= wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash);
+ hashSz = WC_SHA256_DIGEST_SIZE;
+ }
#endif
- }
-#ifndef NO_OLD_TLS
- else {
- ret = doPRF(digest, digLen, secret, secLen, label, labLen, seed,
- seedLen);
- }
+#ifdef WOLFSSL_SHA384
+ if (ssl->specs.mac_algorithm == sha384_mac) {
+ ret |= wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash);
+ hashSz = WC_SHA384_DIGEST_SIZE;
+ }
#endif
+ }
- return ret;
-}
+ *hashLen = hashSz;
+ if (ret != 0)
+ ret = BUILD_MSG_ERROR;
-#ifdef WOLFSSL_SHA384
- #define HSHASH_SZ SHA384_DIGEST_SIZE
-#else
- #define HSHASH_SZ FINISHED_SZ
-#endif
+ return ret;
+}
int BuildTlsFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender)
{
+ int ret;
const byte* side;
- byte handshake_hash[HSHASH_SZ];
- word32 hashSz = FINISHED_SZ;
-
-#ifndef NO_OLD_TLS
- wc_Md5GetHash(&ssl->hsHashes->hashMd5, handshake_hash);
- wc_ShaGetHash(&ssl->hsHashes->hashSha, &handshake_hash[MD5_DIGEST_SIZE]);
+ word32 hashSz = HSHASH_SZ;
+#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
- if (IsAtLeastTLSv1_2(ssl)) {
-#ifndef NO_SHA256
- if (ssl->specs.mac_algorithm <= sha256_mac) {
- int ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256,handshake_hash);
-
- if (ret != 0)
- return ret;
-
- hashSz = SHA256_DIGEST_SIZE;
- }
+ ret = BuildTlsHandshakeHash(ssl, handshake_hash, &hashSz);
+ if (ret == 0) {
+ if (XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0)
+ side = tls_client;
+ else
+ side = tls_server;
+
+#ifdef WOLFSSL_HAVE_PRF
+#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \
+ !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION)
+ if (tsip_useable(ssl)) {
+ ret = tsip_generateVerifyData(ssl->arrays->tsip_masterSecret,
+ side, handshake_hash, (byte*)hashes /* out */);
+ } else
#endif
-#ifdef WOLFSSL_SHA384
- if (ssl->specs.mac_algorithm == sha384_mac) {
- int ret = wc_Sha384Final(&ssl->hsHashes->hashSha384,handshake_hash);
-
- if (ret != 0)
- return ret;
+ ret = wc_PRF_TLS((byte*)hashes, TLS_FINISHED_SZ, ssl->arrays->masterSecret,
+ SECRET_LEN, side, FINISHED_LABEL_SZ, handshake_hash, hashSz,
+ IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
+ ssl->heap, ssl->devId);
+#else
+ /* Pseudo random function must be enabled in the configuration. */
+ ret = PRF_MISSING;
+ WOLFSSL_MSG("Pseudo-random function is not enabled");
- hashSz = SHA384_DIGEST_SIZE;
- }
+ (void)side;
+ (void)hashes;
#endif
}
- if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0)
- side = tls_client;
- else
- side = tls_server;
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+ FREE_VAR(handshake_hash, ssl->heap);
+#endif
- return PRF((byte*)hashes, TLS_FINISHED_SZ, ssl->arrays->masterSecret,
- SECRET_LEN, side, FINISHED_LABEL_SZ, handshake_hash, hashSz,
- IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
+ return ret;
}
+#endif /* !WOLFSSL_NO_TLS12 */
#ifndef NO_OLD_TLS
+#ifdef WOLFSSL_ALLOW_TLSV10
ProtocolVersion MakeTLSv1(void)
{
ProtocolVersion pv;
@@ -383,6 +245,7 @@ ProtocolVersion MakeTLSv1(void)
return pv;
}
+#endif /* WOLFSSL_ALLOW_TLSV10 */
ProtocolVersion MakeTLSv1_1(void)
@@ -394,8 +257,10 @@ ProtocolVersion MakeTLSv1_1(void)
return pv;
}
-#endif
+#endif /* !NO_OLD_TLS */
+
+#ifndef WOLFSSL_NO_TLS12
ProtocolVersion MakeTLSv1_2(void)
{
@@ -406,60 +271,176 @@ ProtocolVersion MakeTLSv1_2(void)
return pv;
}
+#endif /* !WOLFSSL_NO_TLS12 */
+#ifdef WOLFSSL_TLS13
+/* The TLS v1.3 protocol version.
+ *
+ * returns the protocol version data for TLS v1.3.
+ */
+ProtocolVersion MakeTLSv1_3(void)
+{
+ ProtocolVersion pv;
+ pv.major = SSLv3_MAJOR;
+ pv.minor = TLSv1_3_MINOR;
+
+ return pv;
+}
+#endif
+
+#ifndef WOLFSSL_NO_TLS12
+
+#ifdef HAVE_EXTENDED_MASTER
+static const byte ext_master_label[EXT_MASTER_LABEL_SZ + 1] =
+ "extended master secret";
+#endif
static const byte master_label[MASTER_LABEL_SZ + 1] = "master secret";
static const byte key_label [KEY_LABEL_SZ + 1] = "key expansion";
-
-/* External facing wrapper so user can call as well, 0 on success */
-int wolfSSL_DeriveTlsKeys(byte* key_data, word32 keyLen,
+static int _DeriveTlsKeys(byte* key_dig, word32 key_dig_len,
const byte* ms, word32 msLen,
const byte* sr, const byte* cr,
- int tls1_2, int hash_type)
+ int tls1_2, int hash_type,
+ void* heap, int devId)
{
- byte seed[SEED_LEN];
+ 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_data, keyLen, ms, msLen, key_label, KEY_LABEL_SZ,
- seed, SEED_LEN, tls1_2, hash_type);
+#ifdef WOLFSSL_HAVE_PRF
+ ret = wc_PRF_TLS(key_dig, key_dig_len, ms, msLen, key_label, KEY_LABEL_SZ,
+ seed, SEED_LEN, tls1_2, hash_type, heap, devId);
+#else
+ /* Pseudo random function must be enabled in the configuration. */
+ ret = PRF_MISSING;
+ WOLFSSL_MSG("Pseudo-random function is not enabled");
+
+ (void)key_dig;
+ (void)key_dig_len;
+ (void)ms;
+ (void)msLen;
+ (void)tls1_2;
+ (void)hash_type;
+ (void)heap;
+ (void)devId;
+ (void)key_label;
+ (void)master_label;
+#ifdef HAVE_EXTENDED_MASTER
+ (void)ext_master_label;
+#endif
+#endif
+
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+ FREE_VAR(seed, heap);
+#endif
+
+ return ret;
+}
+
+/* External facing wrapper so user can call as well, 0 on success */
+int wolfSSL_DeriveTlsKeys(byte* key_dig, word32 key_dig_len,
+ const byte* ms, word32 msLen,
+ const byte* sr, const byte* cr,
+ int tls1_2, int hash_type)
+{
+ return _DeriveTlsKeys(key_dig, key_dig_len, ms, msLen, sr, cr, tls1_2,
+ hash_type, NULL, INVALID_DEVID);
}
int DeriveTlsKeys(WOLFSSL* ssl)
{
int ret;
- int length = 2 * ssl->specs.hash_size +
- 2 * ssl->specs.key_size +
- 2 * ssl->specs.iv_size;
+ int key_dig_len = 2 * ssl->specs.hash_size +
+ 2 * ssl->specs.key_size +
+ 2 * ssl->specs.iv_size;
#ifdef WOLFSSL_SMALL_STACK
- byte* key_data;
+ byte* key_dig;
#else
- byte key_data[MAX_PRF_DIG];
+ byte key_dig[MAX_PRF_DIG];
#endif
#ifdef WOLFSSL_SMALL_STACK
- key_data = (byte*)XMALLOC(MAX_PRF_DIG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (key_data == NULL) {
+ key_dig = (byte*)XMALLOC(MAX_PRF_DIG, ssl->heap, DYNAMIC_TYPE_DIGEST);
+ if (key_dig == NULL) {
return MEMORY_E;
}
#endif
-
- ret = wolfSSL_DeriveTlsKeys(key_data, length,
- ssl->arrays->masterSecret, SECRET_LEN,
- ssl->arrays->serverRandom, ssl->arrays->clientRandom,
- IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
+#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \
+ !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION)
+ if (tsip_useable(ssl))
+ ret = tsip_generateSeesionKey(ssl);
+ else {
+#endif
+ ret = _DeriveTlsKeys(key_dig, key_dig_len,
+ ssl->arrays->masterSecret, SECRET_LEN,
+ ssl->arrays->serverRandom, ssl->arrays->clientRandom,
+ IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
+ ssl->heap, ssl->devId);
if (ret == 0)
- ret = StoreKeys(ssl, key_data);
+ ret = StoreKeys(ssl, key_dig, PROVISION_CLIENT_SERVER);
+#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \
+ !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION)
+ }
+#endif
#ifdef WOLFSSL_SMALL_STACK
- XFREE(key_data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(key_dig, ssl->heap, DYNAMIC_TYPE_DIGEST);
#endif
return ret;
}
+static int _MakeTlsMasterSecret(byte* ms, word32 msLen,
+ const byte* pms, word32 pmsLen,
+ const byte* cr, const byte* sr,
+ int tls1_2, int hash_type,
+ 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);
+
+#ifdef WOLFSSL_HAVE_PRF
+ ret = wc_PRF_TLS(ms, msLen, pms, pmsLen, master_label, MASTER_LABEL_SZ,
+ seed, SEED_LEN, tls1_2, hash_type, heap, devId);
+#else
+ /* Pseudo random function must be enabled in the configuration. */
+ ret = PRF_MISSING;
+ WOLFSSL_MSG("Pseudo-random function is not enabled");
+
+ (void)ms;
+ (void)msLen;
+ (void)pms;
+ (void)pmsLen;
+ (void)tls1_2;
+ (void)hash_type;
+ (void)heap;
+ (void)devId;
+#endif
+
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+ FREE_VAR(seed, heap);
+#endif
+
+ return ret;
+}
/* External facing wrapper so user can call as well, 0 on success */
int wolfSSL_MakeTlsMasterSecret(byte* ms, word32 msLen,
@@ -467,34 +448,145 @@ int wolfSSL_MakeTlsMasterSecret(byte* ms, word32 msLen,
const byte* cr, const byte* sr,
int tls1_2, int hash_type)
{
- byte seed[SEED_LEN];
+ return _MakeTlsMasterSecret(ms, msLen, pms, pmsLen, cr, sr, tls1_2,
+ hash_type, NULL, INVALID_DEVID);
+}
- XMEMCPY(seed, cr, RAN_LEN);
- XMEMCPY(seed + RAN_LEN, sr, RAN_LEN);
- return PRF(ms, msLen, pms, pmsLen, master_label, MASTER_LABEL_SZ,
- seed, SEED_LEN, tls1_2, hash_type);
+#ifdef HAVE_EXTENDED_MASTER
+
+static int _MakeTlsExtendedMasterSecret(byte* ms, word32 msLen,
+ const byte* pms, word32 pmsLen,
+ const byte* sHash, word32 sHashLen,
+ int tls1_2, int hash_type,
+ void* heap, int devId)
+{
+ int ret;
+
+#ifdef WOLFSSL_HAVE_PRF
+ ret = wc_PRF_TLS(ms, msLen, pms, pmsLen, ext_master_label, EXT_MASTER_LABEL_SZ,
+ sHash, sHashLen, tls1_2, hash_type, heap, devId);
+#else
+ /* Pseudo random function must be enabled in the configuration. */
+ ret = PRF_MISSING;
+ WOLFSSL_MSG("Pseudo-random function is not enabled");
+
+ (void)ms;
+ (void)msLen;
+ (void)pms;
+ (void)pmsLen;
+ (void)sHash;
+ (void)sHashLen;
+ (void)tls1_2;
+ (void)hash_type;
+ (void)heap;
+ (void)devId;
+#endif
+ return ret;
+}
+
+/* External facing wrapper so user can call as well, 0 on success */
+int wolfSSL_MakeTlsExtendedMasterSecret(byte* ms, word32 msLen,
+ const byte* pms, word32 pmsLen,
+ const byte* sHash, word32 sHashLen,
+ int tls1_2, int hash_type)
+{
+ return _MakeTlsExtendedMasterSecret(ms, msLen, pms, pmsLen, sHash, sHashLen,
+ tls1_2, hash_type, NULL, INVALID_DEVID);
}
+#endif /* HAVE_EXTENDED_MASTER */
+
int MakeTlsMasterSecret(WOLFSSL* ssl)
{
- int ret;
+ int ret;
+
+#ifdef HAVE_EXTENDED_MASTER
+ if (ssl->options.haveEMS) {
+ word32 hashSz = HSHASH_SZ;
+ #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) {
+ ret = _MakeTlsExtendedMasterSecret(
+ ssl->arrays->masterSecret, SECRET_LEN,
+ ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz,
+ handshake_hash, hashSz,
+ IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
+ ssl->heap, ssl->devId);
+ }
- ret = wolfSSL_MakeTlsMasterSecret(ssl->arrays->masterSecret, SECRET_LEN,
+ #ifdef WOLFSSL_SMALL_STACK
+ XFREE(handshake_hash, ssl->heap, DYNAMIC_TYPE_DIGEST);
+ #endif
+ }
+ else
+#endif /* HAVE_EXTENDED_MASTER */
+ {
+#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \
+ !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION)
+ if (tsip_useable(ssl)) {
+ ret = tsip_generateMasterSecret(
+ &ssl->arrays->preMasterSecret[VERSION_SZ],
+ ssl->arrays->clientRandom,
+ ssl->arrays->serverRandom,
+ ssl->arrays->tsip_masterSecret);
+ } else
+#endif
+ ret = _MakeTlsMasterSecret(ssl->arrays->masterSecret, SECRET_LEN,
ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz,
ssl->arrays->clientRandom, ssl->arrays->serverRandom,
- IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
-
+ IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
+ ssl->heap, ssl->devId);
+ }
if (ret == 0) {
#ifdef SHOW_SECRETS
- int i;
+ /* 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;
- printf("master secret: ");
- for (i = 0; i < SECRET_LEN; i++)
- printf("%02x", ssl->arrays->masterSecret[i]);
- printf("\n");
- #endif
+ /* 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);
}
@@ -516,7 +608,7 @@ int wolfSSL_make_eap_keys(WOLFSSL* ssl, void* msk, unsigned int len,
#endif
#ifdef WOLFSSL_SMALL_STACK
- seed = (byte*)XMALLOC(SEED_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ seed = (byte*)XMALLOC(SEED_LEN, ssl->heap, DYNAMIC_TYPE_SEED);
if (seed == NULL)
return MEMORY_E;
#endif
@@ -528,82 +620,90 @@ int wolfSSL_make_eap_keys(WOLFSSL* ssl, void* msk, unsigned int len,
XMEMCPY(seed, ssl->arrays->clientRandom, RAN_LEN);
XMEMCPY(seed + RAN_LEN, ssl->arrays->serverRandom, RAN_LEN);
- ret = PRF((byte*)msk, len, ssl->arrays->masterSecret, SECRET_LEN,
- (const byte *)label, (word32)strlen(label), seed, SEED_LEN,
- IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
+#ifdef WOLFSSL_HAVE_PRF
+ ret = wc_PRF_TLS((byte*)msk, len, ssl->arrays->masterSecret, SECRET_LEN,
+ (const byte *)label, (word32)XSTRLEN(label), seed, SEED_LEN,
+ IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
+ ssl->heap, ssl->devId);
+#else
+ /* Pseudo random function must be enabled in the configuration. */
+ ret = PRF_MISSING;
+ WOLFSSL_MSG("Pseudo-random function is not enabled");
+
+ (void)msk;
+ (void)len;
+ (void)label;
+#endif
#ifdef WOLFSSL_SMALL_STACK
- XFREE(seed, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(seed, ssl->heap, DYNAMIC_TYPE_SEED);
#endif
return ret;
}
-/*** next for static INLINE s copied internal.c ***/
-
-/* convert 16 bit integer to opaque */
-static INLINE void c16toa(word16 u16, byte* c)
+static WC_INLINE void GetSEQIncrement(WOLFSSL* ssl, int verify, word32 seq[2])
{
- c[0] = (u16 >> 8) & 0xff;
- c[1] = u16 & 0xff;
-}
-
-#ifdef HAVE_TLS_EXTENSIONS
-/* convert opaque to 16 bit integer */
-static INLINE void ato16(const byte* c, word16* u16)
-{
- *u16 = (c[0] << 8) | (c[1]);
+ if (verify) {
+ seq[0] = ssl->keys.peer_sequence_number_hi;
+ seq[1] = ssl->keys.peer_sequence_number_lo++;
+ if (seq[1] > ssl->keys.peer_sequence_number_lo) {
+ /* handle rollover */
+ ssl->keys.peer_sequence_number_hi++;
+ }
+ }
+ else {
+ seq[0] = ssl->keys.sequence_number_hi;
+ seq[1] = ssl->keys.sequence_number_lo++;
+ if (seq[1] > ssl->keys.sequence_number_lo) {
+ /* handle rollover */
+ ssl->keys.sequence_number_hi++;
+ }
+ }
}
-#ifdef HAVE_SNI
-/* convert a 24 bit integer into a 32 bit one */
-static INLINE void c24to32(const word24 u24, word32* u32)
-{
- *u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2];
-}
-#endif
-#endif
-/* convert 32 bit integer to opaque */
-static INLINE void c32toa(word32 u32, byte* c)
+#ifdef WOLFSSL_DTLS
+static WC_INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2])
{
- c[0] = (u32 >> 24) & 0xff;
- c[1] = (u32 >> 16) & 0xff;
- c[2] = (u32 >> 8) & 0xff;
- c[3] = u32 & 0xff;
+ if (order == PREV_ORDER) {
+ /* Previous epoch case */
+ seq[0] = (((word32)ssl->keys.dtls_epoch - 1) << 16) |
+ (ssl->keys.dtls_prev_sequence_number_hi & 0xFFFF);
+ seq[1] = ssl->keys.dtls_prev_sequence_number_lo;
+ }
+ else if (order == PEER_ORDER) {
+ seq[0] = ((word32)ssl->keys.curEpoch << 16) |
+ (ssl->keys.curSeq_hi & 0xFFFF);
+ seq[1] = ssl->keys.curSeq_lo; /* explicit from peer */
+ }
+ else {
+ seq[0] = ((word32)ssl->keys.dtls_epoch << 16) |
+ (ssl->keys.dtls_sequence_number_hi & 0xFFFF);
+ seq[1] = ssl->keys.dtls_sequence_number_lo;
+ }
}
+#endif /* WOLFSSL_DTLS */
-static INLINE word32 GetSEQIncrement(WOLFSSL* ssl, int verify)
+static WC_INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
{
-#ifdef WOLFSSL_DTLS
- if (ssl->options.dtls) {
- if (verify)
- return ssl->keys.dtls_state.curSeq; /* explicit from peer */
- else
- return ssl->keys.dtls_sequence_number - 1; /* already incremented */
- }
-#endif
- if (verify)
- return ssl->keys.peer_sequence_number++;
- else
- return ssl->keys.sequence_number++;
-}
-
+ word32 seq[2] = {0, 0};
+ if (!ssl->options.dtls) {
+ GetSEQIncrement(ssl, verifyOrder, seq);
+ }
+ else {
#ifdef WOLFSSL_DTLS
+ DtlsGetSEQ(ssl, verifyOrder, seq);
+#endif
+ }
-static INLINE word32 GetEpoch(WOLFSSL* ssl, int verify)
-{
- if (verify)
- return ssl->keys.dtls_state.curEpoch;
- else
- return ssl->keys.dtls_epoch;
+ c32toa(seq[0], out);
+ c32toa(seq[1], out + OPAQUE32_LEN);
}
-#endif /* WOLFSSL_DTLS */
-
/*** end copy ***/
@@ -618,26 +718,26 @@ int wolfSSL_GetHmacType(WOLFSSL* ssl)
#ifndef NO_MD5
case md5_mac:
{
- return MD5;
+ return WC_MD5;
}
#endif
#ifndef NO_SHA256
case sha256_mac:
{
- return SHA256;
+ return WC_SHA256;
}
#endif
#ifdef WOLFSSL_SHA384
case sha384_mac:
{
- return SHA384;
+ return WC_SHA384;
}
#endif
#ifndef NO_SHA
case sha_mac:
{
- return SHA;
+ return WC_SHA;
}
#endif
#ifdef HAVE_BLAKE2
@@ -648,7 +748,7 @@ int wolfSSL_GetHmacType(WOLFSSL* ssl)
#endif
default:
{
- return SSL_FATAL_ERROR;
+ return WOLFSSL_FATAL_ERROR;
}
}
}
@@ -662,11 +762,7 @@ int wolfSSL_SetTlsHmacInner(WOLFSSL* ssl, byte* inner, word32 sz, int content,
XMEMSET(inner, 0, WOLFSSL_TLS_HMAC_INNER_SZ);
-#ifdef WOLFSSL_DTLS
- if (ssl->options.dtls)
- c16toa((word16)GetEpoch(ssl, verify), inner);
-#endif
- c32toa(GetSEQIncrement(ssl, verify), &inner[sizeof(word32)]);
+ WriteSEQ(ssl, verify, inner);
inner[SEQ_SZ] = (byte)content;
inner[SEQ_SZ + ENUM_LEN] = ssl->version.major;
inner[SEQ_SZ + ENUM_LEN + ENUM_LEN] = ssl->version.minor;
@@ -676,52 +772,526 @@ int wolfSSL_SetTlsHmacInner(WOLFSSL* ssl, byte* inner, word32 sz, int content,
}
-/* TLS type HMAC */
-int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
- int content, int verify)
+#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)
{
- Hmac hmac;
+ 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);
+
+ if ((digestSz >= 0) && (blockSz >= 0)) {
+ 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 lastBlockLen, macLen, extraLen, eocIndex;
+ int blocks, safeBlocks, lenBlock, eocBlock;
+ int maxLen;
+ int blockSz, padSz;
int ret;
- byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ];
+ word32 realLen;
+ 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 = 0;
+ 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;
+#ifdef HAVE_TRUNCATED_HMAC
+ word32 hashSz = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ
+ : ssl->specs.hash_size;
+#else
+ word32 hashSz = ssl->specs.hash_size;
+#endif
if (ssl == NULL)
return BAD_FUNC_ARG;
#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 + hashSz + padSz + 1, FUZZ_HMAC,
+ ssl->fuzzerCtx);
+ }
+ else {
+ ssl->fuzzerCb(ssl, in, sz, FUZZ_HMAC, ssl->fuzzerCtx);
+ }
+ }
#endif
wolfSSL_SetTlsHmacInner(ssl, myInner, sz, content, verify);
+#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \
+ !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION)
+ if (tsip_useable(ssl)) {
+ if (ssl->specs.hash_size == WC_SHA_DIGEST_SIZE)
+ ret = tsip_Sha1Hmac(ssl, myInner, WOLFSSL_TLS_HMAC_INNER_SZ,
+ in, sz, digest, verify);
+ else if (ssl->specs.hash_size == WC_SHA256_DIGEST_SIZE)
+ ret = tsip_Sha256Hmac(ssl, myInner, WOLFSSL_TLS_HMAC_INNER_SZ,
+ in, sz, digest, verify);
+ else
+ ret = TSIP_MAC_DIGSZ_E;
- ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl),
- wolfSSL_GetMacSecret(ssl, verify), ssl->specs.hash_size);
- if (ret != 0)
return ret;
- ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner));
- if (ret != 0)
- return ret;
- ret = wc_HmacUpdate(&hmac, in, sz); /* content */
- if (ret != 0)
- return ret;
- ret = wc_HmacFinal(&hmac, digest);
+ }
+#endif
+ ret = wc_HmacInit(&hmac, ssl->heap, ssl->devId);
if (ret != 0)
return ret;
- return 0;
+ ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl),
+ wolfSSL_GetMacSecret(ssl, verify),
+ ssl->specs.hash_size);
+ if (ret == 0) {
+ /* 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 + hashSz + padSz + 1, myInner);
+ }
+ else
+ #endif
+ {
+ ret = Hmac_UpdateFinal_CT(&hmac, digest, in,
+ sz + hashSz + padSz + 1, myInner);
+ }
+#else
+ ret = Hmac_UpdateFinal(&hmac, digest, in, sz + hashSz + 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
+/**
+ * The TLSX semaphore is used to calculate the size of the extensions to be sent
+ * from one peer to another.
+ */
-/** Supports up to 64 flags. Update as needed. */
+/** Supports up to 64 flags. Increase as needed. */
#define SEMAPHORE_SIZE 8
-
-static INLINE word16 TLSX_ToSemaphore(word16 type)
+/**
+ * Converts the extension type (id) to an index in the semaphore.
+ *
+ * Official reference for TLS extension types:
+ * http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xml
+ *
+ * Motivation:
+ * Previously, we used the extension type itself as the index of that
+ * extension in the semaphore as the extension types were declared
+ * sequentially, but maintain a semaphore as big as the number of available
+ * extensions is no longer an option since the release of renegotiation_info.
+ *
+ * How to update:
+ * Assign extension types that extrapolate the number of available semaphores
+ * to the first available index going backwards in the semaphore array.
+ * When adding a new extension type that don't extrapolate the number of
+ * available semaphores, check for a possible collision with with a
+ * 'remapped' extension type.
+ */
+static WC_INLINE word16 TLSX_ToSemaphore(word16 type)
{
switch (type) {
- case SECURE_RENEGOTIATION:
+
+ case TLSX_RENEGOTIATION_INFO: /* 0xFF01 */
return 63;
default:
@@ -732,37 +1302,59 @@ static INLINE word16 TLSX_ToSemaphore(word16 type)
is assigned to be used by another extension.
Use this check value for the new extension and decrement
the check value by one. */
- WOLFSSL_MSG("### TLSX semaphore colision or overflow detected!");
+ WOLFSSL_MSG("### TLSX semaphore collision or overflow detected!");
}
}
return type;
}
-
+/** Checks if a specific light (tls extension) is not set in the semaphore. */
#define IS_OFF(semaphore, light) \
- ((semaphore)[(light) / 8] ^ (byte) (0x01 << ((light) % 8)))
-
+ (!(((semaphore)[(light) / 8] & (byte) (0x01 << ((light) % 8)))))
+/** Turn on a specific light (tls extension) in the semaphore. */
+/* the semaphore marks the extensions already written to the message */
#define TURN_ON(semaphore, light) \
((semaphore)[(light) / 8] |= (byte) (0x01 << ((light) % 8)))
+/** Turn off a specific light (tls extension) in the semaphore. */
+#define TURN_OFF(semaphore, light) \
+ ((semaphore)[(light) / 8] &= (byte) ~(0x01 << ((light) % 8)))
-static int TLSX_Push(TLSX** list, TLSX_Type type, void* data)
+/** Creates a new extension. */
+static TLSX* TLSX_New(TLSX_Type type, void* data, void* heap)
{
- TLSX* extension;
+ TLSX* extension = (TLSX*)XMALLOC(sizeof(TLSX), heap, DYNAMIC_TYPE_TLSX);
+
+ (void)heap;
+
+ if (extension) {
+ extension->type = type;
+ extension->data = data;
+ extension->resp = 0;
+ extension->next = NULL;
+ }
+
+ return extension;
+}
+
+/**
+ * Creates a new extension and pushes it to the provided list.
+ * Checks for duplicate extensions, keeps the newest.
+ */
+static int TLSX_Push(TLSX** list, TLSX_Type type, void* data, void* heap)
+{
+ TLSX* extension = TLSX_New(type, data, heap);
- extension = (TLSX*)XMALLOC(sizeof(TLSX), 0, DYNAMIC_TYPE_TLSX);
if (extension == NULL)
return MEMORY_E;
- extension->type = type;
- extension->data = data;
- extension->resp = 0;
+ /* pushes the new extension on the list. */
extension->next = *list;
*list = extension;
- /* remove duplicated extensions, there should be only one of each type. */
+ /* remove duplicate extensions, there should be only one of each type. */
do {
if (extension->next && extension->next->type == type) {
TLSX *next = extension->next;
@@ -770,10 +1362,11 @@ static int TLSX_Push(TLSX** list, TLSX_Type type, void* data)
extension->next = next->next;
next->next = NULL;
- TLSX_FreeAll(next);
+ 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;
}
} while ((extension = extension->next));
@@ -781,90 +1374,500 @@ static int TLSX_Push(TLSX** list, TLSX_Type type, void* data)
return 0;
}
+#ifndef NO_WOLFSSL_CLIENT
-#ifndef NO_WOLFSSL_SERVER
+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. */
void TLSX_SetResponse(WOLFSSL* ssl, TLSX_Type type);
void TLSX_SetResponse(WOLFSSL* ssl, TLSX_Type type)
{
- TLSX *ext = TLSX_Find(ssl->extensions, type);
+ TLSX *extension = TLSX_Find(ssl->extensions, type);
- if (ext)
- ext->resp = 1;
+ if (extension)
+ extension->resp = 1;
}
-#endif
+/******************************************************************************/
+/* Application-Layer Protocol Negotiation */
+/******************************************************************************/
+
+#ifdef HAVE_ALPN
+/** Creates a new ALPN object, providing protocol name to use. */
+static ALPN* TLSX_ALPN_New(char *protocol_name, word16 protocol_nameSz,
+ void* heap)
+{
+ ALPN *alpn;
-/* SNI - Server Name Indication */
+ WOLFSSL_ENTER("TLSX_ALPN_New");
-#ifdef HAVE_SNI
+ if (protocol_name == NULL ||
+ protocol_nameSz > WOLFSSL_MAX_ALPN_PROTO_NAME_LEN) {
+ WOLFSSL_MSG("Invalid arguments");
+ return NULL;
+ }
+
+ alpn = (ALPN*)XMALLOC(sizeof(ALPN), heap, DYNAMIC_TYPE_TLSX);
+ if (alpn == NULL) {
+ WOLFSSL_MSG("Memory failure");
+ return NULL;
+ }
-static void TLSX_SNI_Free(SNI* sni)
+ alpn->next = NULL;
+ alpn->negotiated = 0;
+ alpn->options = 0;
+
+ alpn->protocol_name = (char*)XMALLOC(protocol_nameSz + 1,
+ heap, DYNAMIC_TYPE_TLSX);
+ if (alpn->protocol_name == NULL) {
+ WOLFSSL_MSG("Memory failure");
+ XFREE(alpn, heap, DYNAMIC_TYPE_TLSX);
+ return NULL;
+ }
+
+ XMEMCPY(alpn->protocol_name, protocol_name, protocol_nameSz);
+ alpn->protocol_name[protocol_nameSz] = 0;
+
+ (void)heap;
+
+ return alpn;
+}
+
+/** Releases an ALPN object. */
+static void TLSX_ALPN_Free(ALPN *alpn, void* heap)
{
- if (sni) {
- switch (sni->type) {
- case WOLFSSL_SNI_HOST_NAME:
- XFREE(sni->data.host_name, 0, DYNAMIC_TYPE_TLSX);
- break;
- }
+ (void)heap;
+
+ if (alpn == NULL)
+ return;
+
+ XFREE(alpn->protocol_name, heap, DYNAMIC_TYPE_TLSX);
+ XFREE(alpn, heap, DYNAMIC_TYPE_TLSX);
+}
- XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
+/** Releases all ALPN objects in the provided list. */
+static void TLSX_ALPN_FreeAll(ALPN *list, void* heap)
+{
+ ALPN* alpn;
+
+ while ((alpn = list)) {
+ list = alpn->next;
+ TLSX_ALPN_Free(alpn, heap);
}
}
-static void TLSX_SNI_FreeAll(SNI* list)
+/** Tells the buffered size of the ALPN objects in a list. */
+static word16 TLSX_ALPN_GetSize(ALPN *list)
{
- SNI* sni;
+ ALPN* alpn;
+ word16 length = OPAQUE16_LEN; /* list length */
- while ((sni = list)) {
- list = sni->next;
- TLSX_SNI_Free(sni);
+ while ((alpn = list)) {
+ list = alpn->next;
+
+ length++; /* protocol name length is on one byte */
+ length += (word16)XSTRLEN(alpn->protocol_name);
}
+
+ return length;
}
-static int TLSX_SNI_Append(SNI** list, byte type, const void* data, word16 size)
+/** Writes the ALPN objects of a list in a buffer. */
+static word16 TLSX_ALPN_Write(ALPN *list, byte *output)
{
- SNI* sni;
+ ALPN* alpn;
+ word16 length = 0;
+ word16 offset = OPAQUE16_LEN; /* list length offset */
- if (list == NULL)
+ while ((alpn = list)) {
+ list = alpn->next;
+
+ length = (word16)XSTRLEN(alpn->protocol_name);
+
+ /* protocol name length */
+ output[offset++] = (byte)length;
+
+ /* protocol name value */
+ XMEMCPY(output + offset, alpn->protocol_name, length);
+
+ offset += length;
+ }
+
+ /* writing list length */
+ c16toa(offset - OPAQUE16_LEN, output);
+
+ return offset;
+}
+
+/** Finds a protocol name in the provided ALPN list */
+static ALPN* TLSX_ALPN_Find(ALPN *list, char *protocol_name, word16 size)
+{
+ ALPN *alpn;
+
+ if (list == NULL || protocol_name == NULL)
+ return NULL;
+
+ alpn = list;
+ while (alpn != NULL && (
+ (word16)XSTRLEN(alpn->protocol_name) != size ||
+ XSTRNCMP(alpn->protocol_name, protocol_name, size)))
+ alpn = alpn->next;
+
+ return alpn;
+}
+
+/** Set the ALPN matching client and server requirements */
+static int TLSX_SetALPN(TLSX** extensions, const void* data, word16 size,
+ void* heap)
+{
+ ALPN *alpn;
+ int ret;
+
+ if (extensions == NULL || data == NULL)
return BAD_FUNC_ARG;
- if ((sni = XMALLOC(sizeof(SNI), 0, DYNAMIC_TYPE_TLSX)) == NULL)
+ alpn = TLSX_ALPN_New((char *)data, size, heap);
+ if (alpn == NULL) {
+ WOLFSSL_MSG("Memory failure");
return MEMORY_E;
+ }
- switch (type) {
- case WOLFSSL_SNI_HOST_NAME: {
- sni->data.host_name = XMALLOC(size + 1, 0, DYNAMIC_TYPE_TLSX);
+ alpn->negotiated = 1;
+
+ ret = TLSX_Push(extensions, TLSX_APPLICATION_LAYER_PROTOCOL, (void*)alpn,
+ heap);
+ if (ret != 0) {
+ TLSX_ALPN_Free(alpn, heap);
+ return ret;
+ }
+
+ return WOLFSSL_SUCCESS;
+}
+
+/** Parses a buffer of ALPN extensions and set the first one matching
+ * client and server requirements */
+static int TLSX_ALPN_ParseAndSet(WOLFSSL *ssl, byte *input, word16 length,
+ byte isRequest)
+{
+ word16 size = 0, offset = 0, idx = 0;
+ int r = BUFFER_ERROR;
+ byte match = 0;
+ TLSX *extension;
+ ALPN *alpn = NULL, *list;
+
+ if (OPAQUE16_LEN > length)
+ return BUFFER_ERROR;
- if (sni->data.host_name) {
- XSTRNCPY(sni->data.host_name, (const char*)data, size);
- sni->data.host_name[size] = 0;
- } else {
- XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
- return MEMORY_E;
+ ato16(input, &size);
+ offset += OPAQUE16_LEN;
+
+ if (size == 0)
+ return BUFFER_ERROR;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL);
+ if (extension == NULL)
+ extension = TLSX_Find(ssl->ctx->extensions,
+ TLSX_APPLICATION_LAYER_PROTOCOL);
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+ if (ssl->alpnSelect != NULL) {
+ const byte* out;
+ unsigned char outLen;
+
+ if (ssl->alpnSelect(ssl, &out, &outLen, input + offset, size,
+ ssl->alpnSelectArg) == 0) {
+ WOLFSSL_MSG("ALPN protocol match");
+ if (TLSX_UseALPN(&ssl->extensions, (char*)out, outLen, 0, ssl->heap)
+ == WOLFSSL_SUCCESS) {
+ if (extension == NULL) {
+ extension = TLSX_Find(ssl->extensions,
+ TLSX_APPLICATION_LAYER_PROTOCOL);
+ }
}
}
- break;
+ }
+#endif
- default: /* invalid type */
- XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
- return BAD_FUNC_ARG;
+ if (extension == NULL || extension->data == NULL) {
+ return isRequest ? 0
+ : TLSX_HandleUnsupportedExtension(ssl);
}
- sni->type = type;
- sni->next = *list;
+ /* validating alpn list length */
+ if (length != OPAQUE16_LEN + size)
+ return BUFFER_ERROR;
+
+ list = (ALPN*)extension->data;
+ /* keep the list sent by client */
+ if (isRequest) {
+ if (ssl->alpn_client_list != NULL)
+ XFREE(ssl->alpn_client_list, ssl->heap, DYNAMIC_TYPE_ALPN);
+
+ ssl->alpn_client_list = (char *)XMALLOC(size, ssl->heap,
+ DYNAMIC_TYPE_ALPN);
+ if (ssl->alpn_client_list == NULL)
+ return MEMORY_ERROR;
+ }
+
+ for (size = 0; offset < length; offset += size) {
+
+ size = input[offset++];
+ if (offset + size > length || size == 0)
+ return BUFFER_ERROR;
+
+ if (isRequest) {
+ XMEMCPY(ssl->alpn_client_list+idx, (char*)input + offset, size);
+ idx += size;
+ ssl->alpn_client_list[idx++] = ',';
+ }
+
+ if (!match) {
+ alpn = TLSX_ALPN_Find(list, (char*)input + offset, size);
+ if (alpn != NULL) {
+ WOLFSSL_MSG("ALPN protocol match");
+ match = 1;
+
+ /* skip reading other values if not required */
+ if (!isRequest)
+ break;
+ }
+ }
+ }
+
+ if (isRequest)
+ ssl->alpn_client_list[idx-1] = 0;
+
+ if (!match) {
+ WOLFSSL_MSG("No ALPN protocol match");
+
+ /* do nothing if no protocol match between client and server and option
+ is set to continue (like OpenSSL) */
+ if (list->options & WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) {
+ WOLFSSL_MSG("Continue on mismatch");
+ return 0;
+ }
+
+ SendAlert(ssl, alert_fatal, no_application_protocol);
+ return UNKNOWN_ALPN_PROTOCOL_NAME_E;
+ }
+
+ /* set the matching negotiated protocol */
+ r = TLSX_SetALPN(&ssl->extensions,
+ alpn->protocol_name,
+ (word16)XSTRLEN(alpn->protocol_name),
+ ssl->heap);
+ if (r != WOLFSSL_SUCCESS) {
+ WOLFSSL_MSG("TLSX_UseALPN failed");
+ return BUFFER_ERROR;
+ }
+
+ /* reply to ALPN extension sent from client */
+ if (isRequest) {
#ifndef NO_WOLFSSL_SERVER
- sni->options = 0;
- sni->status = WOLFSSL_SNI_NO_MATCH;
+ TLSX_SetResponse(ssl, TLSX_APPLICATION_LAYER_PROTOCOL);
#endif
-
- *list = sni;
+ }
return 0;
}
+/** Add a protocol name to the list of accepted usable ones */
+int TLSX_UseALPN(TLSX** extensions, const void* data, word16 size, byte options,
+ void* heap)
+{
+ ALPN *alpn;
+ TLSX *extension;
+ int ret;
+
+ if (extensions == NULL || data == NULL)
+ return BAD_FUNC_ARG;
+
+ alpn = TLSX_ALPN_New((char *)data, size, heap);
+ if (alpn == NULL) {
+ WOLFSSL_MSG("Memory failure");
+ return MEMORY_E;
+ }
+
+ /* Set Options of ALPN */
+ alpn->options = options;
+
+ extension = TLSX_Find(*extensions, TLSX_APPLICATION_LAYER_PROTOCOL);
+ if (extension == NULL) {
+ ret = TLSX_Push(extensions, TLSX_APPLICATION_LAYER_PROTOCOL,
+ (void*)alpn, heap);
+ if (ret != 0) {
+ TLSX_ALPN_Free(alpn, heap);
+ return ret;
+ }
+ }
+ else {
+ /* push new ALPN object to extension data. */
+ alpn->next = (ALPN*)extension->data;
+ extension->data = (void*)alpn;
+ }
+
+ return WOLFSSL_SUCCESS;
+}
+
+/** Get the protocol name set by the server */
+int TLSX_ALPN_GetRequest(TLSX* extensions, void** data, word16 *dataSz)
+{
+ TLSX *extension;
+ ALPN *alpn;
+
+ if (extensions == NULL || data == NULL || dataSz == NULL)
+ return BAD_FUNC_ARG;
+
+ extension = TLSX_Find(extensions, TLSX_APPLICATION_LAYER_PROTOCOL);
+ if (extension == NULL) {
+ WOLFSSL_MSG("TLS extension not found");
+ return WOLFSSL_ALPN_NOT_FOUND;
+ }
+
+ alpn = (ALPN *)extension->data;
+ if (alpn == NULL) {
+ WOLFSSL_MSG("ALPN extension not found");
+ *data = NULL;
+ *dataSz = 0;
+ return WOLFSSL_FATAL_ERROR;
+ }
+
+ if (alpn->negotiated != 1) {
+
+ /* consider as an error */
+ if (alpn->options & WOLFSSL_ALPN_FAILED_ON_MISMATCH) {
+ WOLFSSL_MSG("No protocol match with peer -> Failed");
+ return WOLFSSL_FATAL_ERROR;
+ }
+
+ /* continue without negotiated protocol */
+ WOLFSSL_MSG("No protocol match with peer -> Continue");
+ return WOLFSSL_ALPN_NOT_FOUND;
+ }
+
+ if (alpn->next != NULL) {
+ WOLFSSL_MSG("Only one protocol name must be accepted");
+ return WOLFSSL_FATAL_ERROR;
+ }
+
+ *data = alpn->protocol_name;
+ *dataSz = (word16)XSTRLEN((char*)*data);
+
+ return WOLFSSL_SUCCESS;
+}
+
+#define ALPN_FREE_ALL TLSX_ALPN_FreeAll
+#define ALPN_GET_SIZE TLSX_ALPN_GetSize
+#define ALPN_WRITE TLSX_ALPN_Write
+#define ALPN_PARSE TLSX_ALPN_ParseAndSet
+
+#else /* HAVE_ALPN */
+
+#define ALPN_FREE_ALL(list, heap)
+#define ALPN_GET_SIZE(list) 0
+#define ALPN_WRITE(a, b) 0
+#define ALPN_PARSE(a, b, c, d) 0
+
+#endif /* HAVE_ALPN */
+
+/******************************************************************************/
+/* Server Name Indication */
+/******************************************************************************/
+
+#ifdef HAVE_SNI
+
+/** Creates a new SNI object. */
+static SNI* TLSX_SNI_New(byte type, const void* data, word16 size, void* heap)
+{
+ SNI* sni = (SNI*)XMALLOC(sizeof(SNI), heap, DYNAMIC_TYPE_TLSX);
+
+ (void)heap;
+
+ if (sni) {
+ sni->type = type;
+ sni->next = NULL;
+
+ #ifndef NO_WOLFSSL_SERVER
+ sni->options = 0;
+ sni->status = WOLFSSL_SNI_NO_MATCH;
+ #endif
+
+ switch (sni->type) {
+ case WOLFSSL_SNI_HOST_NAME:
+ sni->data.host_name = (char*)XMALLOC(size + 1, heap,
+ DYNAMIC_TYPE_TLSX);
+ if (sni->data.host_name) {
+ XSTRNCPY(sni->data.host_name, (const char*)data, size);
+ sni->data.host_name[size] = '\0';
+ } else {
+ XFREE(sni, heap, DYNAMIC_TYPE_TLSX);
+ sni = NULL;
+ }
+ break;
+
+ default: /* invalid type */
+ XFREE(sni, heap, DYNAMIC_TYPE_TLSX);
+ sni = NULL;
+ }
+ }
+
+ return sni;
+}
+
+/** Releases a SNI object. */
+static void TLSX_SNI_Free(SNI* sni, void* heap)
+{
+ if (sni) {
+ switch (sni->type) {
+ case WOLFSSL_SNI_HOST_NAME:
+ XFREE(sni->data.host_name, heap, DYNAMIC_TYPE_TLSX);
+ break;
+ }
+
+ XFREE(sni, heap, DYNAMIC_TYPE_TLSX);
+ }
+ (void)heap;
+}
+
+/** Releases all SNI objects in the provided list. */
+static void TLSX_SNI_FreeAll(SNI* list, void* heap)
+{
+ SNI* sni;
+
+ while ((sni = list)) {
+ list = sni->next;
+ TLSX_SNI_Free(sni, heap);
+ }
+}
+
+/** Tells the buffered size of the SNI objects in a list. */
static word16 TLSX_SNI_GetSize(SNI* list)
{
SNI* sni;
@@ -877,7 +1880,7 @@ static word16 TLSX_SNI_GetSize(SNI* list)
switch (sni->type) {
case WOLFSSL_SNI_HOST_NAME:
- length += XSTRLEN((char*)sni->data.host_name);
+ length += (word16)XSTRLEN((char*)sni->data.host_name);
break;
}
}
@@ -885,6 +1888,7 @@ static word16 TLSX_SNI_GetSize(SNI* list)
return length;
}
+/** Writes the SNI objects of a list in a buffer. */
static word16 TLSX_SNI_Write(SNI* list, byte* output)
{
SNI* sni;
@@ -898,7 +1902,7 @@ static word16 TLSX_SNI_Write(SNI* list, byte* output)
switch (sni->type) {
case WOLFSSL_SNI_HOST_NAME:
- length = XSTRLEN((char*)sni->data.host_name);
+ length = (word16)XSTRLEN((char*)sni->data.host_name);
c16toa(length, output + offset); /* sni length */
offset += OPAQUE16_LEN;
@@ -915,9 +1919,10 @@ static word16 TLSX_SNI_Write(SNI* list, byte* output)
return offset;
}
+/** Finds a SNI object in the provided list. */
static SNI* TLSX_SNI_Find(SNI *list, byte type)
{
- SNI *sni = list;
+ SNI* sni = list;
while (sni && sni->type != type)
sni = sni->next;
@@ -925,52 +1930,85 @@ static SNI* TLSX_SNI_Find(SNI *list, byte type)
return sni;
}
-#ifndef NO_WOLFSSL_SERVER
+/** Sets the status of a SNI object. */
static void TLSX_SNI_SetStatus(TLSX* extensions, byte type, byte status)
{
- TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
- SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+ TLSX* extension = TLSX_Find(extensions, TLSX_SERVER_NAME);
+ SNI* sni = TLSX_SNI_Find(extension ? (SNI*)extension->data : NULL, type);
- if (sni) {
+ if (sni)
sni->status = status;
- WOLFSSL_MSG("SNI did match!");
- }
}
+/** Gets the status of a SNI object. */
byte TLSX_SNI_Status(TLSX* extensions, byte type)
{
- TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
- SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+ TLSX* extension = TLSX_Find(extensions, TLSX_SERVER_NAME);
+ SNI* sni = TLSX_SNI_Find(extension ? (SNI*)extension->data : NULL, type);
if (sni)
return sni->status;
return 0;
}
-#endif
+/** Parses a buffer of SNI extensions. */
static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
byte isRequest)
{
#ifndef NO_WOLFSSL_SERVER
word16 size = 0;
word16 offset = 0;
+ int cacheOnly = 0;
+ SNI *sni = NULL;
+ byte type;
+ int matchStat;
+ byte matched;
#endif
- TLSX *extension = TLSX_Find(ssl->extensions, SERVER_NAME_INDICATION);
+ TLSX *extension = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
if (!extension)
- extension = TLSX_Find(ssl->ctx->extensions, SERVER_NAME_INDICATION);
+ extension = TLSX_Find(ssl->ctx->extensions, TLSX_SERVER_NAME);
- if (!extension || !extension->data)
- return isRequest ? 0 : BUFFER_ERROR; /* not using SNI OR unexpected
- SNI response from server. */
+ 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);
- if (!isRequest)
- return length ? BUFFER_ERROR : 0; /* SNI response must be empty!
- Nothing else to do. */
+ 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.
+ */
+
+ cacheOnly = 1;
+ WOLFSSL_MSG("Forcing SSL object to store SNI parameter");
+ #else
+ /* Skipping, SNI not enabled at server side. */
+ return 0;
+ #endif
+ }
if (OPAQUE16_LEN > length)
return BUFFER_ERROR;
@@ -979,74 +2017,135 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
offset += OPAQUE16_LEN;
/* validating sni list length */
- if (length != OPAQUE16_LEN + size)
+ if (length != OPAQUE16_LEN + size || size == 0)
return BUFFER_ERROR;
- for (size = 0; offset < length; offset += size) {
- SNI *sni;
- byte type = input[offset++];
+ /* SNI was badly specified and only one type is now recognized and allowed.
+ * Only one SNI value per type (RFC6066), so, no loop. */
+ type = input[offset++];
+ if (type != WOLFSSL_SNI_HOST_NAME)
+ return BUFFER_ERROR;
- if (offset + OPAQUE16_LEN > length)
- return BUFFER_ERROR;
+ if (offset + OPAQUE16_LEN > length)
+ return BUFFER_ERROR;
+ ato16(input + offset, &size);
+ offset += OPAQUE16_LEN;
- ato16(input + offset, &size);
- offset += OPAQUE16_LEN;
+ if (offset + size != length || size == 0)
+ return BUFFER_ERROR;
- if (offset + size > length)
- return BUFFER_ERROR;
+ if (!cacheOnly && !(sni = TLSX_SNI_Find((SNI*)extension->data, type)))
+ return 0; /* not using this type of SNI. */
- if (!(sni = TLSX_SNI_Find((SNI*)extension->data, type))) {
- continue; /* not using this SNI type */
+#ifdef WOLFSSL_TLS13
+ /* Don't process the second ClientHello SNI extension if there
+ * was problems with the first.
+ */
+ if (!cacheOnly && sni->status != 0)
+ return 0;
+#endif
+ matched = cacheOnly || (XSTRLEN(sni->data.host_name) == size &&
+ XSTRNCMP(sni->data.host_name, (const char*)input + offset, size) == 0);
+
+ if (matched || sni->options & WOLFSSL_SNI_ANSWER_ON_MISMATCH) {
+ int r = TLSX_UseSNI(&ssl->extensions, type, input + offset, size,
+ ssl->heap);
+ if (r != WOLFSSL_SUCCESS)
+ return r; /* throws error. */
+
+ if (cacheOnly) {
+ WOLFSSL_MSG("Forcing storage of SNI, Fake match");
+ matchStat = WOLFSSL_SNI_FORCE_KEEP;
+ }
+ else if (matched) {
+ WOLFSSL_MSG("SNI did match!");
+ matchStat = WOLFSSL_SNI_REAL_MATCH;
+ }
+ else {
+ WOLFSSL_MSG("fake SNI match from ANSWER_ON_MISMATCH");
+ matchStat = WOLFSSL_SNI_FAKE_MATCH;
}
- switch(type) {
- case WOLFSSL_SNI_HOST_NAME: {
- byte matched = (XSTRLEN(sni->data.host_name) == size)
- && (XSTRNCMP(sni->data.host_name,
- (const char*)input + offset, size) == 0);
+ TLSX_SNI_SetStatus(ssl->extensions, type, (byte)matchStat);
- if (matched || sni->options & WOLFSSL_SNI_ANSWER_ON_MISMATCH) {
- int r = TLSX_UseSNI(&ssl->extensions,
- type, input + offset, size);
+ if(!cacheOnly)
+ TLSX_SetResponse(ssl, TLSX_SERVER_NAME);
+ }
+ else if (!(sni->options & WOLFSSL_SNI_CONTINUE_ON_MISMATCH)) {
+ SendAlert(ssl, alert_fatal, unrecognized_name);
- if (r != SSL_SUCCESS) return r; /* throw error */
+ return UNKNOWN_SNI_HOST_NAME_E;
+ }
+#else
+ (void)input;
+#endif
- TLSX_SNI_SetStatus(ssl->extensions, type,
- matched ? WOLFSSL_SNI_REAL_MATCH : WOLFSSL_SNI_FAKE_MATCH);
+ return 0;
+}
- } else if (!(sni->options & WOLFSSL_SNI_CONTINUE_ON_MISMATCH)) {
- SendAlert(ssl, alert_fatal, unrecognized_name);
+static int TLSX_SNI_VerifyParse(WOLFSSL* ssl, byte isRequest)
+{
+ (void)ssl;
- return UNKNOWN_SNI_HOST_NAME_E;
+ if (isRequest) {
+ #ifndef NO_WOLFSSL_SERVER
+ TLSX* ctx_ext = TLSX_Find(ssl->ctx->extensions, TLSX_SERVER_NAME);
+ TLSX* ssl_ext = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
+ SNI* ctx_sni = ctx_ext ? (SNI*)ctx_ext->data : NULL;
+ SNI* ssl_sni = ssl_ext ? (SNI*)ssl_ext->data : NULL;
+ SNI* sni = NULL;
+
+ for (; ctx_sni; ctx_sni = ctx_sni->next) {
+ if (ctx_sni->options & WOLFSSL_SNI_ABORT_ON_ABSENCE) {
+ sni = TLSX_SNI_Find(ssl_sni, ctx_sni->type);
+
+ if (sni) {
+ if (sni->status != WOLFSSL_SNI_NO_MATCH)
+ continue;
+
+ /* if ssl level overrides ctx level, it is ok. */
+ if ((sni->options & WOLFSSL_SNI_ABORT_ON_ABSENCE) == 0)
+ continue;
}
- break;
+
+ SendAlert(ssl, alert_fatal, handshake_failure);
+ return SNI_ABSENT_ERROR;
}
}
- TLSX_SetResponse(ssl, SERVER_NAME_INDICATION);
- }
+ for (; ssl_sni; ssl_sni = ssl_sni->next) {
+ if (ssl_sni->options & WOLFSSL_SNI_ABORT_ON_ABSENCE) {
+ if (ssl_sni->status != WOLFSSL_SNI_NO_MATCH)
+ continue;
-#endif
+ SendAlert(ssl, alert_fatal, handshake_failure);
+ return SNI_ABSENT_ERROR;
+ }
+ }
+ #endif /* NO_WOLFSSL_SERVER */
+ }
return 0;
}
-int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
+int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size,
+ void* heap)
{
- TLSX* extension = TLSX_Find(*extensions, SERVER_NAME_INDICATION);
- SNI* sni = NULL;
- int ret = 0;
+ TLSX* extension;
+ SNI* sni = NULL;
if (extensions == NULL || data == NULL)
return BAD_FUNC_ARG;
- if ((ret = TLSX_SNI_Append(&sni, type, data, size)) != 0)
- return ret;
+ if ((sni = TLSX_SNI_New(type, data, size, heap)) == NULL)
+ return MEMORY_E;
+ extension = TLSX_Find(*extensions, TLSX_SERVER_NAME);
if (!extension) {
- if ((ret = TLSX_Push(extensions, SERVER_NAME_INDICATION, (void*)sni))
- != 0) {
- TLSX_SNI_Free(sni);
+ int ret = TLSX_Push(extensions, TLSX_SERVER_NAME, (void*)sni, heap);
+
+ if (ret != 0) {
+ TLSX_SNI_Free(sni, heap);
return ret;
}
}
@@ -1055,61 +2154,92 @@ int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
sni->next = (SNI*)extension->data;
extension->data = (void*)sni;
- /* look for another server name of the same type to remove */
+ /* remove duplicate SNI, there should be only one of each type. */
do {
if (sni->next && sni->next->type == type) {
- SNI *next = sni->next;
+ SNI* next = sni->next;
sni->next = next->next;
- TLSX_SNI_Free(next);
+ TLSX_SNI_Free(next, heap);
+ /* there is no way to occur more than
+ * two SNIs of the same type.
+ */
break;
}
} while ((sni = sni->next));
}
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
#ifndef NO_WOLFSSL_SERVER
+
+/** Tells the SNI requested by the client. */
word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type, void** data)
{
- TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
- SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+ TLSX* extension = TLSX_Find(extensions, TLSX_SERVER_NAME);
+ SNI* sni = TLSX_SNI_Find(extension ? (SNI*)extension->data : NULL, type);
if (sni && sni->status != WOLFSSL_SNI_NO_MATCH) {
switch (sni->type) {
case WOLFSSL_SNI_HOST_NAME:
- *data = sni->data.host_name;
- return XSTRLEN(*data);
+ if (data) {
+ *data = sni->data.host_name;
+ return (word16)XSTRLEN((char*)*data);
+ }
}
}
return 0;
}
+/** Sets the options for a SNI object. */
void TLSX_SNI_SetOptions(TLSX* extensions, byte type, byte options)
{
- TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
- SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+ TLSX* extension = TLSX_Find(extensions, TLSX_SERVER_NAME);
+ SNI* sni = TLSX_SNI_Find(extension ? (SNI*)extension->data : NULL, type);
if (sni)
sni->options = options;
}
+/** Retrieves a SNI request from a client hello buffer. */
int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
byte type, byte* sni, word32* inOutSz)
{
word32 offset = 0;
- word32 len32 = 0;
- word16 len16 = 0;
+ word32 len32 = 0;
+ word16 len16 = 0;
if (helloSz < RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + CLIENT_HELLO_FIRST)
return INCOMPLETE_DATA;
/* TLS record header */
- if ((enum ContentType) clientHello[offset++] != handshake)
+ if ((enum ContentType) clientHello[offset++] != handshake) {
+
+ /* checking for SSLv2.0 client hello according to: */
+ /* http://tools.ietf.org/html/rfc4346#appendix-E.1 */
+ if ((enum HandShakeType) clientHello[++offset] == client_hello) {
+ offset += ENUM_LEN + VERSION_SZ; /* skip version */
+
+ ato16(clientHello + offset, &len16);
+ offset += OPAQUE16_LEN;
+
+ if (len16 % 3) /* cipher_spec_length must be multiple of 3 */
+ return BUFFER_ERROR;
+
+ ato16(clientHello + offset, &len16);
+ /* Returning SNI_UNSUPPORTED do not increment offset here */
+
+ if (len16 != 0) /* session_id_length must be 0 */
+ return BUFFER_ERROR;
+
+ return SNI_UNSUPPORTED;
+ }
+
return BUFFER_ERROR;
+ }
if (clientHello[offset++] != SSLv3_MAJOR)
return BUFFER_ERROR;
@@ -1185,7 +2315,7 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
if (helloSz < offset + extLen)
return BUFFER_ERROR;
- if (extType != SERVER_NAME_INDICATION) {
+ if (extType != TLSX_SERVER_NAME) {
offset += extLen; /* skip extension */
} else {
word16 listLen;
@@ -1215,7 +2345,7 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
*inOutSz = min(sniLen, *inOutSz);
XMEMCPY(sni, clientHello + offset, *inOutSz);
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
}
@@ -1227,20 +2357,364 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
#endif
-#define SNI_FREE_ALL TLSX_SNI_FreeAll
-#define SNI_GET_SIZE TLSX_SNI_GetSize
-#define SNI_WRITE TLSX_SNI_Write
-#define SNI_PARSE TLSX_SNI_Parse
+#define SNI_FREE_ALL TLSX_SNI_FreeAll
+#define SNI_GET_SIZE TLSX_SNI_GetSize
+#define SNI_WRITE TLSX_SNI_Write
+#define SNI_PARSE TLSX_SNI_Parse
+#define SNI_VERIFY_PARSE TLSX_SNI_VerifyParse
#else
-#define SNI_FREE_ALL(list)
-#define SNI_GET_SIZE(list) 0
-#define SNI_WRITE(a, b) 0
-#define SNI_PARSE(a, b, c, d) 0
+#define SNI_FREE_ALL(list, heap)
+#define SNI_GET_SIZE(list) 0
+#define SNI_WRITE(a, b) 0
+#define SNI_PARSE(a, b, c, d) 0
+#define SNI_VERIFY_PARSE(a, b) 0
#endif /* HAVE_SNI */
+/******************************************************************************/
+/* Trusted CA Key Indication */
+/******************************************************************************/
+
+#ifdef HAVE_TRUSTED_CA
+
+/** Creates a new TCA object. */
+static TCA* TLSX_TCA_New(byte type, const byte* id, word16 idSz, void* heap)
+{
+ TCA* tca = (TCA*)XMALLOC(sizeof(TCA), heap, DYNAMIC_TYPE_TLSX);
+
+ if (tca) {
+ XMEMSET(tca, 0, sizeof(TCA));
+ tca->type = type;
+
+ switch (type) {
+ case WOLFSSL_TRUSTED_CA_PRE_AGREED:
+ break;
+
+ #ifndef NO_SHA
+ case WOLFSSL_TRUSTED_CA_KEY_SHA1:
+ case WOLFSSL_TRUSTED_CA_CERT_SHA1:
+ if (idSz == WC_SHA_DIGEST_SIZE &&
+ (tca->id =
+ (byte*)XMALLOC(idSz, heap, DYNAMIC_TYPE_TLSX))) {
+ XMEMCPY(tca->id, id, idSz);
+ tca->idSz = idSz;
+ }
+ else {
+ XFREE(tca, heap, DYNAMIC_TYPE_TLSX);
+ tca = NULL;
+ }
+ break;
+ #endif
+
+ case WOLFSSL_TRUSTED_CA_X509_NAME:
+ if (idSz > 0 &&
+ (tca->id =
+ (byte*)XMALLOC(idSz, heap, DYNAMIC_TYPE_TLSX))) {
+ XMEMCPY(tca->id, id, idSz);
+ tca->idSz = idSz;
+ }
+ else {
+ XFREE(tca, heap, DYNAMIC_TYPE_TLSX);
+ tca = NULL;
+ }
+ break;
+
+ default: /* invalid type */
+ XFREE(tca, heap, DYNAMIC_TYPE_TLSX);
+ tca = NULL;
+ }
+ }
+
+ (void)heap;
+
+ return tca;
+}
+
+/** Releases a TCA object. */
+static void TLSX_TCA_Free(TCA* tca, void* heap)
+{
+ (void)heap;
+
+ if (tca) {
+ if (tca->id)
+ XFREE(tca->id, heap, DYNAMIC_TYPE_TLSX);
+ XFREE(tca, heap, DYNAMIC_TYPE_TLSX);
+ }
+}
+
+/** Releases all TCA objects in the provided list. */
+static void TLSX_TCA_FreeAll(TCA* list, void* heap)
+{
+ TCA* tca;
+
+ while ((tca = list)) {
+ list = tca->next;
+ TLSX_TCA_Free(tca, heap);
+ }
+}
+
+/** Tells the buffered size of the TCA objects in a list. */
+static word16 TLSX_TCA_GetSize(TCA* list)
+{
+ TCA* tca;
+ word16 length = OPAQUE16_LEN; /* list length */
+
+ while ((tca = list)) {
+ list = tca->next;
+
+ length += ENUM_LEN; /* tca type */
+
+ switch (tca->type) {
+ case WOLFSSL_TRUSTED_CA_PRE_AGREED:
+ break;
+ case WOLFSSL_TRUSTED_CA_KEY_SHA1:
+ case WOLFSSL_TRUSTED_CA_CERT_SHA1:
+ length += tca->idSz;
+ break;
+ case WOLFSSL_TRUSTED_CA_X509_NAME:
+ length += OPAQUE16_LEN + tca->idSz;
+ break;
+ }
+ }
+
+ return length;
+}
+
+/** Writes the TCA objects of a list in a buffer. */
+static word16 TLSX_TCA_Write(TCA* list, byte* output)
+{
+ TCA* tca;
+ word16 offset = OPAQUE16_LEN; /* list length offset */
+
+ while ((tca = list)) {
+ list = tca->next;
+
+ output[offset++] = tca->type; /* tca type */
+
+ switch (tca->type) {
+ case WOLFSSL_TRUSTED_CA_PRE_AGREED:
+ break;
+ #ifndef NO_SHA
+ case WOLFSSL_TRUSTED_CA_KEY_SHA1:
+ case WOLFSSL_TRUSTED_CA_CERT_SHA1:
+ if (tca->id != NULL) {
+ XMEMCPY(output + offset, tca->id, tca->idSz);
+ offset += tca->idSz;
+ }
+ else {
+ /* ID missing. Set to an empty string. */
+ c16toa(0, output + offset);
+ offset += OPAQUE16_LEN;
+ }
+ break;
+ #endif
+ case WOLFSSL_TRUSTED_CA_X509_NAME:
+ if (tca->id != NULL) {
+ c16toa(tca->idSz, output + offset); /* tca length */
+ offset += OPAQUE16_LEN;
+ XMEMCPY(output + offset, tca->id, tca->idSz);
+ offset += tca->idSz;
+ }
+ else {
+ /* ID missing. Set to an empty string. */
+ c16toa(0, output + offset);
+ offset += OPAQUE16_LEN;
+ }
+ break;
+ default:
+ /* ID unknown. Set to an empty string. */
+ c16toa(0, output + offset);
+ offset += OPAQUE16_LEN;
+ }
+ }
+
+ c16toa(offset - OPAQUE16_LEN, output); /* writing list length */
+
+ return offset;
+}
+
+#ifndef NO_WOLFSSL_SERVER
+static TCA* TLSX_TCA_Find(TCA *list, byte type, const byte* id, word16 idSz)
+{
+ TCA* tca = list;
+
+ while (tca && tca->type != type && type != WOLFSSL_TRUSTED_CA_PRE_AGREED &&
+ idSz != tca->idSz && !XMEMCMP(id, tca->id, idSz))
+ tca = tca->next;
+
+ return tca;
+}
+#endif /* NO_WOLFSSL_SERVER */
+
+/** Parses a buffer of TCA extensions. */
+static int TLSX_TCA_Parse(WOLFSSL* ssl, const byte* input, word16 length,
+ byte isRequest)
+{
+#ifndef NO_WOLFSSL_SERVER
+ word16 size = 0;
+ word16 offset = 0;
+#endif
+
+ TLSX *extension = TLSX_Find(ssl->extensions, TLSX_TRUSTED_CA_KEYS);
+
+ if (!extension)
+ extension = TLSX_Find(ssl->ctx->extensions, TLSX_TRUSTED_CA_KEYS);
+
+ if (!isRequest) {
+ #ifndef NO_WOLFSSL_CLIENT
+ if (!extension || !extension->data)
+ return TLSX_HandleUnsupportedExtension(ssl);
+
+ if (length > 0)
+ return BUFFER_ERROR; /* TCA response MUST be empty. */
+
+ /* Set the flag that we're good for keys */
+ TLSX_SetResponse(ssl, TLSX_TRUSTED_CA_KEYS);
+
+ return 0;
+ #endif
+ }
+
+#ifndef NO_WOLFSSL_SERVER
+ if (!extension || !extension->data) {
+ /* Skipping, TCA not enabled at server side. */
+ return 0;
+ }
+
+ if (OPAQUE16_LEN > length)
+ return BUFFER_ERROR;
+
+ ato16(input, &size);
+ offset += OPAQUE16_LEN;
+
+ /* validating tca list length */
+ if (length != OPAQUE16_LEN + size)
+ return BUFFER_ERROR;
+
+ for (size = 0; offset < length; offset += size) {
+ TCA *tca = NULL;
+ byte type;
+ const byte* id = NULL;
+ word16 idSz = 0;
+
+ if (offset + ENUM_LEN > length)
+ return BUFFER_ERROR;
+
+ type = input[offset++];
+
+ switch (type) {
+ case WOLFSSL_TRUSTED_CA_PRE_AGREED:
+ break;
+ #ifndef NO_SHA
+ case WOLFSSL_TRUSTED_CA_KEY_SHA1:
+ case WOLFSSL_TRUSTED_CA_CERT_SHA1:
+ if (offset + WC_SHA_DIGEST_SIZE > length)
+ return BUFFER_ERROR;
+ idSz = WC_SHA_DIGEST_SIZE;
+ id = input + offset;
+ offset += idSz;
+ break;
+ #endif
+ case WOLFSSL_TRUSTED_CA_X509_NAME:
+ if (offset + OPAQUE16_LEN > length)
+ return BUFFER_ERROR;
+ ato16(input + offset, &idSz);
+ offset += OPAQUE16_LEN;
+ if ((offset > length) || (idSz > length - offset))
+ return BUFFER_ERROR;
+ id = input + offset;
+ offset += idSz;
+ break;
+ default:
+ return TCA_INVALID_ID_TYPE;
+ }
+
+ /* Find the type/ID in the TCA list. */
+ tca = TLSX_TCA_Find((TCA*)extension->data, type, id, idSz);
+ if (tca != NULL) {
+ /* Found it. Set the response flag and break out of the loop. */
+ TLSX_SetResponse(ssl, TLSX_TRUSTED_CA_KEYS);
+ break;
+ }
+ }
+#else
+ (void)input;
+#endif
+
+ return 0;
+}
+
+/* Checks to see if the server sent a response for the TCA. */
+static int TLSX_TCA_VerifyParse(WOLFSSL* ssl, byte isRequest)
+{
+ (void)ssl;
+
+ if (!isRequest) {
+ #ifndef NO_WOLFSSL_CLIENT
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_TRUSTED_CA_KEYS);
+
+ if (extension && !extension->resp) {
+ SendAlert(ssl, alert_fatal, handshake_failure);
+ return TCA_ABSENT_ERROR;
+ }
+ #endif /* NO_WOLFSSL_CLIENT */
+ }
+
+ return 0;
+}
+
+int TLSX_UseTrustedCA(TLSX** extensions, byte type,
+ const byte* id, word16 idSz, void* heap)
+{
+ TLSX* extension;
+ TCA* tca = NULL;
+
+ if (extensions == NULL)
+ return BAD_FUNC_ARG;
+
+ if ((tca = TLSX_TCA_New(type, id, idSz, heap)) == NULL)
+ return MEMORY_E;
+
+ extension = TLSX_Find(*extensions, TLSX_TRUSTED_CA_KEYS);
+ if (!extension) {
+ int ret = TLSX_Push(extensions, TLSX_TRUSTED_CA_KEYS, (void*)tca, heap);
+
+ if (ret != 0) {
+ TLSX_TCA_Free(tca, heap);
+ return ret;
+ }
+ }
+ else {
+ /* push new TCA object to extension data. */
+ tca->next = (TCA*)extension->data;
+ extension->data = (void*)tca;
+ }
+
+ return WOLFSSL_SUCCESS;
+}
+
+#define TCA_FREE_ALL TLSX_TCA_FreeAll
+#define TCA_GET_SIZE TLSX_TCA_GetSize
+#define TCA_WRITE TLSX_TCA_Write
+#define TCA_PARSE TLSX_TCA_Parse
+#define TCA_VERIFY_PARSE TLSX_TCA_VerifyParse
+
+#else /* HAVE_TRUSTED_CA */
+
+#define TCA_FREE_ALL(list, heap)
+#define TCA_GET_SIZE(list) 0
+#define TCA_WRITE(a, b) 0
+#define TCA_PARSE(a, b, c, d) 0
+#define TCA_VERIFY_PARSE(a, b) 0
+
+#endif /* HAVE_TRUSTED_CA */
+
+/******************************************************************************/
+/* Max Fragment Length Negotiation */
+/******************************************************************************/
+
#ifdef HAVE_MAX_FRAGMENT
static word16 TLSX_MFL_Write(byte* data, byte* output)
@@ -1256,7 +2730,16 @@ static int TLSX_MFL_Parse(WOLFSSL* ssl, byte* input, word16 length,
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;
case WOLFSSL_MFL_2_11: ssl->max_fragment = 2048; break;
@@ -1271,57 +2754,60 @@ static int TLSX_MFL_Parse(WOLFSSL* ssl, byte* input, word16 length,
#ifndef NO_WOLFSSL_SERVER
if (isRequest) {
- int r = TLSX_UseMaxFragment(&ssl->extensions, *input);
+ int ret = TLSX_UseMaxFragment(&ssl->extensions, *input, ssl->heap);
- if (r != SSL_SUCCESS) return r; /* throw error */
+ if (ret != WOLFSSL_SUCCESS)
+ return ret; /* throw error */
- TLSX_SetResponse(ssl, MAX_FRAGMENT_LENGTH);
+ TLSX_SetResponse(ssl, TLSX_MAX_FRAGMENT_LENGTH);
}
#endif
return 0;
}
-int TLSX_UseMaxFragment(TLSX** extensions, byte mfl)
+int TLSX_UseMaxFragment(TLSX** extensions, byte mfl, void* heap)
{
byte* data = NULL;
- int ret = 0;
-
- if (extensions == NULL)
- return BAD_FUNC_ARG;
+ int ret = 0;
- if (mfl < WOLFSSL_MFL_2_9 || WOLFSSL_MFL_2_13 < mfl)
+ if (extensions == NULL || mfl < WOLFSSL_MFL_MIN || mfl > WOLFSSL_MFL_MAX)
return BAD_FUNC_ARG;
- if ((data = XMALLOC(ENUM_LEN, 0, 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, MAX_FRAGMENT_LENGTH, data)) != 0) {
- XFREE(data, 0, DYNAMIC_TYPE_TLSX);
+ ret = TLSX_Push(extensions, TLSX_MAX_FRAGMENT_LENGTH, data, heap);
+ if (ret != 0) {
+ XFREE(data, heap, DYNAMIC_TYPE_TLSX);
return ret;
}
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
-#define MFL_FREE_ALL(data) XFREE(data, 0, DYNAMIC_TYPE_TLSX)
+#define MFL_FREE_ALL(data, heap) XFREE(data, (heap), DYNAMIC_TYPE_TLSX)
#define MFL_GET_SIZE(data) ENUM_LEN
#define MFL_WRITE TLSX_MFL_Write
#define MFL_PARSE TLSX_MFL_Parse
#else
-#define MFL_FREE_ALL(a)
+#define MFL_FREE_ALL(a, b)
#define MFL_GET_SIZE(a) 0
#define MFL_WRITE(a, b) 0
#define MFL_PARSE(a, b, c, d) 0
#endif /* HAVE_MAX_FRAGMENT */
+/******************************************************************************/
+/* Truncated HMAC */
+/******************************************************************************/
+
#ifdef HAVE_TRUNCATED_HMAC
static int TLSX_THM_Parse(WOLFSSL* ssl, byte* input, word16 length,
@@ -1330,32 +2816,40 @@ static int TLSX_THM_Parse(WOLFSSL* ssl, byte* input, word16 length,
if (length != 0 || input == NULL)
return BUFFER_ERROR;
-#ifndef NO_WOLFSSL_SERVER
- if (isRequest) {
- int r = TLSX_UseTruncatedHMAC(&ssl->extensions);
+ if (!isRequest) {
+ #ifndef WOLFSSL_OLD_UNSUPPORTED_EXTENSION
+ if (TLSX_CheckUnsupportedExtension(ssl, TLSX_TRUNCATED_HMAC))
+ return TLSX_HandleUnsupportedExtension(ssl);
+ #endif
+ }
+ else {
+ #ifndef NO_WOLFSSL_SERVER
+ int ret = TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap);
- if (r != SSL_SUCCESS) return r; /* throw error */
+ if (ret != WOLFSSL_SUCCESS)
+ return ret; /* throw error */
- TLSX_SetResponse(ssl, TRUNCATED_HMAC);
+ TLSX_SetResponse(ssl, TLSX_TRUNCATED_HMAC);
+ #endif
}
-#endif
ssl->truncated_hmac = 1;
return 0;
}
-int TLSX_UseTruncatedHMAC(TLSX** extensions)
+int TLSX_UseTruncatedHMAC(TLSX** extensions, void* heap)
{
int ret = 0;
if (extensions == NULL)
return BAD_FUNC_ARG;
- if ((ret = TLSX_Push(extensions, TRUNCATED_HMAC, NULL)) != 0)
+ ret = TLSX_Push(extensions, TLSX_TRUNCATED_HMAC, NULL, heap);
+ if (ret != 0)
return ret;
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
#define THM_PARSE TLSX_THM_Parse
@@ -1366,58 +2860,1048 @@ int TLSX_UseTruncatedHMAC(TLSX** extensions)
#endif /* HAVE_TRUNCATED_HMAC */
-#ifdef HAVE_SUPPORTED_CURVES
+/******************************************************************************/
+/* Certificate Status Request */
+/******************************************************************************/
-#ifndef HAVE_ECC
-#error Elliptic Curves Extension requires Elliptic Curve Cryptography. \
- Use --enable-ecc in the configure script or define HAVE_ECC.
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+
+static void TLSX_CSR_Free(CertificateStatusRequest* csr, void* heap)
+{
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ FreeOcspRequest(&csr->request.ocsp);
+ break;
+ }
+
+ XFREE(csr, heap, DYNAMIC_TYPE_TLSX);
+ (void)heap;
+}
+
+static word16 TLSX_CSR_GetSize(CertificateStatusRequest* csr, byte isRequest)
+{
+ word16 size = 0;
+
+ /* shut up compiler warnings */
+ (void) csr; (void) isRequest;
+
+#ifndef NO_WOLFSSL_CLIENT
+ if (isRequest) {
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ size += ENUM_LEN + 2 * OPAQUE16_LEN;
+
+ if (csr->request.ocsp.nonceSz)
+ size += OCSP_NONCE_EXT_SZ;
+ break;
+ }
+ }
+#endif
+#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+ if (!isRequest && csr->ssl->options.tls1_3)
+ return OPAQUE8_LEN + OPAQUE24_LEN + csr->response.length;
#endif
-static void TLSX_EllipticCurve_FreeAll(EllipticCurve* list)
+ return size;
+}
+
+static word16 TLSX_CSR_Write(CertificateStatusRequest* csr, byte* output,
+ byte isRequest)
{
- EllipticCurve* curve;
+ /* shut up compiler warnings */
+ (void) csr; (void) output; (void) isRequest;
- while ((curve = list)) {
- list = curve->next;
- XFREE(curve, 0, DYNAMIC_TYPE_TLSX);
+#ifndef NO_WOLFSSL_CLIENT
+ if (isRequest) {
+ word16 offset = 0;
+ word16 length = 0;
+
+ /* type */
+ output[offset++] = csr->status_type;
+
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ /* responder id list */
+ c16toa(0, output + offset);
+ offset += OPAQUE16_LEN;
+
+ /* request extensions */
+ if (csr->request.ocsp.nonceSz)
+ length = (word16)EncodeOcspRequestExtensions(
+ &csr->request.ocsp,
+ output + offset + OPAQUE16_LEN,
+ OCSP_NONCE_EXT_SZ);
+
+ c16toa(length, output + offset);
+ offset += OPAQUE16_LEN + length;
+
+ break;
+ }
+
+ return offset;
+ }
+#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;
}
-static int TLSX_EllipticCurve_Append(EllipticCurve** list, word16 name)
+static int TLSX_CSR_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte isRequest)
{
- EllipticCurve* curve;
+ int ret;
- if (list == NULL)
+ /* shut up compiler warnings */
+ (void) ssl; (void) input;
+
+ if (!isRequest) {
+#ifndef NO_WOLFSSL_CLIENT
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
+ CertificateStatusRequest* csr = extension ?
+ (CertificateStatusRequest*)extension->data : NULL;
+
+ if (!csr) {
+ /* look at context level */
+ extension = TLSX_Find(ssl->ctx->extensions, TLSX_STATUS_REQUEST);
+ csr = extension ? (CertificateStatusRequest*)extension->data : NULL;
+
+ if (!csr) /* unexpected extension */
+ return TLSX_HandleUnsupportedExtension(ssl);
+
+ /* enable extension at ssl level */
+ ret = TLSX_UseCertificateStatusRequest(&ssl->extensions,
+ csr->status_type, csr->options, ssl,
+ ssl->heap, ssl->devId);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ /* propagate nonce */
+ if (csr->request.ocsp.nonceSz) {
+ OcspRequest* request =
+ (OcspRequest*)TLSX_CSR_GetRequest(ssl->extensions);
+
+ if (request) {
+ XMEMCPY(request->nonce, csr->request.ocsp.nonce,
+ csr->request.ocsp.nonceSz);
+ request->nonceSz = csr->request.ocsp.nonceSz;
+ }
+ }
+ break;
+ }
+ }
+
+ ssl->status_request = 1;
+
+ #ifdef WOLFSSL_TLS13
+ if (ssl->options.tls1_3) {
+ word32 resp_length;
+ word32 offset = 0;
+
+ /* Get the new extension potentially created above. */
+ extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
+ csr = extension ? (CertificateStatusRequest*)extension->data : NULL;
+ if (csr == NULL)
+ return MEMORY_ERROR;
+
+ 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 !defined(NO_WOLFSSL_SERVER)
+ if (ret == 0) {
+ csr->response.buffer = input + offset;
+ csr->response.length = resp_length;
+ }
+ #endif
+
+ return ret;
+ }
+ else
+ #endif
+ {
+ /* extension_data MUST be empty. */
+ return length ? BUFFER_ERROR : 0;
+ }
+#endif
+ }
+ else {
+#ifndef NO_WOLFSSL_SERVER
+ byte status_type;
+ word16 offset = 0;
+ word16 size = 0;
+
+ if (length == 0)
+ return 0;
+ if (length < ENUM_LEN)
+ return BUFFER_ERROR;
+
+ status_type = input[offset++];
+
+ switch (status_type) {
+ case WOLFSSL_CSR_OCSP: {
+
+ /* skip responder_id_list */
+ if (length - offset < OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ ato16(input + offset, &size);
+ offset += OPAQUE16_LEN + size;
+
+ /* skip request_extensions */
+ if (length - offset < OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ ato16(input + offset, &size);
+ offset += OPAQUE16_LEN + size;
+
+ if (offset > length)
+ return BUFFER_ERROR;
+
+ /* is able to send OCSP response? */
+ if (ssl->ctx->cm == NULL || !ssl->ctx->cm->ocspStaplingEnabled)
+ return 0;
+ }
+ break;
+
+ /* unknown status type */
+ default:
+ return 0;
+ }
+
+ /* if using status_request and already sending it, skip this one */
+ #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+ if (ssl->status_request_v2)
+ return 0;
+ #endif
+
+ /* accept the first good status_type and return */
+ ret = TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type,
+ 0, ssl, ssl->heap, ssl->devId);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret; /* throw error */
+
+ #if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+ if (ssl->options.tls1_3) {
+ OcspRequest* request;
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
+ CertificateStatusRequest* csr = extension ?
+ (CertificateStatusRequest*)extension->data : NULL;
+ if (csr == NULL)
+ return MEMORY_ERROR;
+
+ request = &csr->request.ocsp;
+ ret = CreateOcspResponse(ssl, &request, &csr->response);
+ if (ret != 0)
+ return ret;
+ if (csr->response.buffer)
+ TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST);
+ }
+ else
+ #endif
+ TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST);
+ ssl->status_request = status_type;
+#endif
+ }
+
+ return 0;
+}
+
+int TLSX_CSR_InitRequest(TLSX* extensions, DecodedCert* cert, void* heap)
+{
+ TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST);
+ CertificateStatusRequest* csr = extension ?
+ (CertificateStatusRequest*)extension->data : NULL;
+ int ret = 0;
+
+ if (csr) {
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP: {
+ byte nonce[MAX_OCSP_NONCE_SZ];
+ int nonceSz = csr->request.ocsp.nonceSz;
+
+ /* preserve nonce */
+ XMEMCPY(nonce, csr->request.ocsp.nonce, nonceSz);
+
+ if ((ret = InitOcspRequest(&csr->request.ocsp, cert, 0, heap))
+ != 0)
+ return ret;
+
+ /* restore nonce */
+ XMEMCPY(csr->request.ocsp.nonce, nonce, nonceSz);
+ csr->request.ocsp.nonceSz = nonceSz;
+ }
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void* TLSX_CSR_GetRequest(TLSX* extensions)
+{
+ TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST);
+ CertificateStatusRequest* csr = extension ?
+ (CertificateStatusRequest*)extension->data : NULL;
+
+ if (csr) {
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ return &csr->request.ocsp;
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+int TLSX_CSR_ForceRequest(WOLFSSL* ssl)
+{
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
+ CertificateStatusRequest* csr = extension ?
+ (CertificateStatusRequest*)extension->data : NULL;
+
+ if (csr) {
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ if (ssl->ctx->cm->ocspEnabled) {
+ csr->request.ocsp.ssl = ssl;
+ return CheckOcspRequest(ssl->ctx->cm->ocsp,
+ &csr->request.ocsp, NULL);
+ }
+ else
+ return OCSP_LOOKUP_FAIL;
+ }
+ }
+
+ return 0;
+}
+
+int TLSX_UseCertificateStatusRequest(TLSX** extensions, byte status_type,
+ byte options, WOLFSSL* ssl, void* heap,
+ int devId)
+{
+ CertificateStatusRequest* csr = NULL;
+ int ret = 0;
+
+ if (!extensions || status_type != WOLFSSL_CSR_OCSP)
return BAD_FUNC_ARG;
- if ((curve = XMALLOC(sizeof(EllipticCurve), 0, DYNAMIC_TYPE_TLSX)) == NULL)
+ csr = (CertificateStatusRequest*)
+ XMALLOC(sizeof(CertificateStatusRequest), heap, DYNAMIC_TYPE_TLSX);
+ if (!csr)
return MEMORY_E;
- curve->name = name;
- curve->next = *list;
+ ForceZero(csr, sizeof(CertificateStatusRequest));
+
+ csr->status_type = status_type;
+ csr->options = options;
+ csr->ssl = ssl;
+
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ if (options & WOLFSSL_CSR_OCSP_USE_NONCE) {
+ WC_RNG rng;
+
+ #ifndef HAVE_FIPS
+ ret = wc_InitRng_ex(&rng, heap, devId);
+ #else
+ ret = wc_InitRng(&rng);
+ (void)devId;
+ #endif
+ if (ret == 0) {
+ if (wc_RNG_GenerateBlock(&rng, csr->request.ocsp.nonce,
+ MAX_OCSP_NONCE_SZ) == 0)
+ csr->request.ocsp.nonceSz = MAX_OCSP_NONCE_SZ;
+
+ wc_FreeRng(&rng);
+ }
+ }
+ break;
+ }
+
+ if ((ret = TLSX_Push(extensions, TLSX_STATUS_REQUEST, csr, heap)) != 0) {
+ XFREE(csr, heap, DYNAMIC_TYPE_TLSX);
+ return ret;
+ }
+
+ return WOLFSSL_SUCCESS;
+}
+
+#define CSR_FREE_ALL TLSX_CSR_Free
+#define CSR_GET_SIZE TLSX_CSR_GetSize
+#define CSR_WRITE TLSX_CSR_Write
+#define CSR_PARSE TLSX_CSR_Parse
+
+#else
+
+#define CSR_FREE_ALL(data, heap)
+#define CSR_GET_SIZE(a, b) 0
+#define CSR_WRITE(a, b, c) 0
+#define CSR_PARSE(a, b, c, d) 0
+
+#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
+
+/******************************************************************************/
+/* Certificate Status Request v2 */
+/******************************************************************************/
+
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+
+static void TLSX_CSR2_FreeAll(CertificateStatusRequestItemV2* csr2, void* heap)
+{
+ CertificateStatusRequestItemV2* next;
+
+ for (; csr2; csr2 = next) {
+ next = csr2->next;
+
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ while(csr2->requests--)
+ FreeOcspRequest(&csr2->request.ocsp[csr2->requests]);
+ break;
+ }
+
+ XFREE(csr2, heap, DYNAMIC_TYPE_TLSX);
+ }
+ (void)heap;
+}
+
+static word16 TLSX_CSR2_GetSize(CertificateStatusRequestItemV2* csr2,
+ byte isRequest)
+{
+ word16 size = 0;
+
+ /* shut up compiler warnings */
+ (void) csr2; (void) isRequest;
+
+#ifndef NO_WOLFSSL_CLIENT
+ if (isRequest) {
+ CertificateStatusRequestItemV2* next;
+
+ for (size = OPAQUE16_LEN; csr2; csr2 = next) {
+ next = csr2->next;
+
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ size += ENUM_LEN + 3 * OPAQUE16_LEN;
+
+ if (csr2->request.ocsp[0].nonceSz)
+ size += OCSP_NONCE_EXT_SZ;
+ break;
+ }
+ }
+ }
+#endif
+
+ return size;
+}
+
+static word16 TLSX_CSR2_Write(CertificateStatusRequestItemV2* csr2,
+ byte* output, byte isRequest)
+{
+ /* shut up compiler warnings */
+ (void) csr2; (void) output; (void) isRequest;
+
+#ifndef NO_WOLFSSL_CLIENT
+ if (isRequest) {
+ word16 offset;
+ word16 length;
+
+ for (offset = OPAQUE16_LEN; csr2 != NULL; csr2 = csr2->next) {
+ /* status_type */
+ output[offset++] = csr2->status_type;
+
+ /* request */
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ /* request_length */
+ length = 2 * OPAQUE16_LEN;
+
+ if (csr2->request.ocsp[0].nonceSz)
+ length += OCSP_NONCE_EXT_SZ;
+
+ c16toa(length, output + offset);
+ offset += OPAQUE16_LEN;
- *list = curve;
+ /* responder id list */
+ c16toa(0, output + offset);
+ offset += OPAQUE16_LEN;
+
+ /* request extensions */
+ length = 0;
+
+ if (csr2->request.ocsp[0].nonceSz)
+ length = (word16)EncodeOcspRequestExtensions(
+ &csr2->request.ocsp[0],
+ output + offset + OPAQUE16_LEN,
+ OCSP_NONCE_EXT_SZ);
+
+ c16toa(length, output + offset);
+ offset += OPAQUE16_LEN + length;
+ break;
+ }
+ }
+
+ /* list size */
+ c16toa(offset - OPAQUE16_LEN, output);
+
+ return offset;
+ }
+#endif
return 0;
}
+static int TLSX_CSR2_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte isRequest)
+{
+ int ret;
+
+ /* shut up compiler warnings */
+ (void) ssl; (void) input;
+
+ if (!isRequest) {
#ifndef NO_WOLFSSL_CLIENT
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST_V2);
+ CertificateStatusRequestItemV2* csr2 = extension ?
+ (CertificateStatusRequestItemV2*)extension->data : NULL;
+
+ if (!csr2) {
+ /* look at context level */
+ extension = TLSX_Find(ssl->ctx->extensions, TLSX_STATUS_REQUEST_V2);
+ csr2 = extension ?
+ (CertificateStatusRequestItemV2*)extension->data : NULL;
+
+ 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);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ /* followed by */
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ /* propagate nonce */
+ if (csr2->request.ocsp[0].nonceSz) {
+ OcspRequest* request =
+ (OcspRequest*)TLSX_CSR2_GetRequest(ssl->extensions,
+ csr2->status_type, 0);
+
+ if (request) {
+ XMEMCPY(request->nonce,
+ csr2->request.ocsp[0].nonce,
+ csr2->request.ocsp[0].nonceSz);
+
+ request->nonceSz =
+ csr2->request.ocsp[0].nonceSz;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ ssl->status_request_v2 = 1;
-static void TLSX_EllipticCurve_ValidateRequest(WOLFSSL* ssl, byte* semaphore)
+ return length ? BUFFER_ERROR : 0; /* extension_data MUST be empty. */
+#endif
+ }
+ else {
+#ifndef NO_WOLFSSL_SERVER
+ byte status_type;
+ word16 request_length;
+ word16 offset = 0;
+ word16 size = 0;
+
+ /* list size */
+ if (offset + OPAQUE16_LEN >= length) {
+ return BUFFER_E;
+ }
+
+ ato16(input + offset, &request_length);
+ offset += OPAQUE16_LEN;
+
+ if (length - OPAQUE16_LEN != request_length)
+ return BUFFER_ERROR;
+
+ while (length > offset) {
+ if (length - offset < ENUM_LEN + OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ status_type = input[offset++];
+
+ ato16(input + offset, &request_length);
+ offset += OPAQUE16_LEN;
+
+ if (length - offset < request_length)
+ return BUFFER_ERROR;
+
+ switch (status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ /* skip responder_id_list */
+ if (length - offset < OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ ato16(input + offset, &size);
+ if (length - offset < size)
+ return BUFFER_ERROR;
+
+ offset += OPAQUE16_LEN + size;
+ /* skip request_extensions */
+ if (length - offset < OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ ato16(input + offset, &size);
+ if (length - offset < size)
+ return BUFFER_ERROR;
+
+ offset += OPAQUE16_LEN + size;
+ if (offset > length)
+ return BUFFER_ERROR;
+
+ /* is able to send OCSP response? */
+ if (ssl->ctx->cm == NULL
+ || !ssl->ctx->cm->ocspStaplingEnabled)
+ continue;
+ break;
+
+ default:
+ /* unknown status type, skipping! */
+ offset += request_length;
+ continue;
+ }
+
+ /* if using status_request and already sending it, skip this one */
+ #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+ if (ssl->status_request)
+ return 0;
+ #endif
+
+ /* accept the first good status_type and return */
+ ret = TLSX_UseCertificateStatusRequestV2(&ssl->extensions,
+ status_type, 0, ssl->heap, ssl->devId);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret; /* throw error */
+
+ TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST_V2);
+ ssl->status_request_v2 = status_type;
+
+ return 0;
+ }
+#endif
+ }
+
+ return 0;
+}
+
+int TLSX_CSR2_InitRequests(TLSX* extensions, DecodedCert* cert, byte isPeer,
+ void* heap)
{
- int i;
+ TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST_V2);
+ CertificateStatusRequestItemV2* csr2 = extension ?
+ (CertificateStatusRequestItemV2*)extension->data : NULL;
+ int ret = 0;
- for (i = 0; i < ssl->suites->suiteSz; i+= 2)
- if (ssl->suites->suites[i] == ECC_BYTE)
+ for (; csr2; csr2 = csr2->next) {
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ if (!isPeer || csr2->requests != 0)
+ break;
+
+ FALL_THROUGH; /* followed by */
+
+ case WOLFSSL_CSR2_OCSP_MULTI: {
+ if (csr2->requests < 1 + MAX_CHAIN_DEPTH) {
+ byte nonce[MAX_OCSP_NONCE_SZ];
+ int nonceSz = csr2->request.ocsp[0].nonceSz;
+
+ /* preserve nonce, replicating nonce of ocsp[0] */
+ XMEMCPY(nonce, csr2->request.ocsp[0].nonce, nonceSz);
+
+ if ((ret = InitOcspRequest(
+ &csr2->request.ocsp[csr2->requests], cert,
+ 0, heap)) != 0)
+ return ret;
+
+ /* restore nonce */
+ XMEMCPY(csr2->request.ocsp[csr2->requests].nonce,
+ nonce, nonceSz);
+ csr2->request.ocsp[csr2->requests].nonceSz = nonceSz;
+ csr2->requests++;
+ }
+ }
+ break;
+ }
+ }
+
+ (void)cert;
+ return ret;
+}
+
+void* TLSX_CSR2_GetRequest(TLSX* extensions, byte status_type, byte idx)
+{
+ TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST_V2);
+ CertificateStatusRequestItemV2* csr2 = extension ?
+ (CertificateStatusRequestItemV2*)extension->data : NULL;
+
+ for (; csr2; csr2 = csr2->next) {
+ if (csr2->status_type == status_type) {
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ /* followed by */
+
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ /* requests are initialized in the reverse order */
+ return idx < csr2->requests
+ ? &csr2->request.ocsp[csr2->requests - idx - 1]
+ : NULL;
+ break;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+int TLSX_CSR2_ForceRequest(WOLFSSL* ssl)
+{
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST_V2);
+ CertificateStatusRequestItemV2* csr2 = extension ?
+ (CertificateStatusRequestItemV2*)extension->data : NULL;
+
+ /* forces only the first one */
+ if (csr2) {
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ /* followed by */
+
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ if (ssl->ctx->cm->ocspEnabled) {
+ csr2->request.ocsp[0].ssl = ssl;
+ return CheckOcspRequest(ssl->ctx->cm->ocsp,
+ &csr2->request.ocsp[0], NULL);
+ }
+ else
+ return OCSP_LOOKUP_FAIL;
+ }
+ }
+
+ return 0;
+}
+
+int TLSX_UseCertificateStatusRequestV2(TLSX** extensions, byte status_type,
+ byte options, void* heap, int devId)
+{
+ TLSX* extension = NULL;
+ CertificateStatusRequestItemV2* csr2 = NULL;
+ int ret = 0;
+
+ if (!extensions)
+ return BAD_FUNC_ARG;
+
+ if (status_type != WOLFSSL_CSR2_OCSP
+ && status_type != WOLFSSL_CSR2_OCSP_MULTI)
+ return BAD_FUNC_ARG;
+
+ csr2 = (CertificateStatusRequestItemV2*)
+ XMALLOC(sizeof(CertificateStatusRequestItemV2), heap, DYNAMIC_TYPE_TLSX);
+ if (!csr2)
+ return MEMORY_E;
+
+ ForceZero(csr2, sizeof(CertificateStatusRequestItemV2));
+
+ csr2->status_type = status_type;
+ csr2->options = options;
+ csr2->next = NULL;
+
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ if (options & WOLFSSL_CSR2_OCSP_USE_NONCE) {
+ WC_RNG rng;
+
+ #ifndef HAVE_FIPS
+ ret = wc_InitRng_ex(&rng, heap, devId);
+ #else
+ ret = wc_InitRng(&rng);
+ (void)devId;
+ #endif
+ if (ret == 0) {
+ if (wc_RNG_GenerateBlock(&rng, csr2->request.ocsp[0].nonce,
+ MAX_OCSP_NONCE_SZ) == 0)
+ csr2->request.ocsp[0].nonceSz = MAX_OCSP_NONCE_SZ;
+
+ wc_FreeRng(&rng);
+ }
+ }
+ break;
+ }
+
+ /* append new item */
+ if ((extension = TLSX_Find(*extensions, TLSX_STATUS_REQUEST_V2))) {
+ CertificateStatusRequestItemV2* last =
+ (CertificateStatusRequestItemV2*)extension->data;
+
+ for (; last->next; last = last->next);
+
+ last->next = csr2;
+ }
+ else if ((ret = TLSX_Push(extensions, TLSX_STATUS_REQUEST_V2, csr2,heap))) {
+ XFREE(csr2, heap, DYNAMIC_TYPE_TLSX);
+ return ret;
+ }
+
+ return WOLFSSL_SUCCESS;
+}
+
+#define CSR2_FREE_ALL TLSX_CSR2_FreeAll
+#define CSR2_GET_SIZE TLSX_CSR2_GetSize
+#define CSR2_WRITE TLSX_CSR2_Write
+#define CSR2_PARSE TLSX_CSR2_Parse
+
+#else
+
+#define CSR2_FREE_ALL(data, heap)
+#define CSR2_GET_SIZE(a, b) 0
+#define CSR2_WRITE(a, b, c) 0
+#define CSR2_PARSE(a, b, c, d) 0
+
+#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
+
+/******************************************************************************/
+/* Supported Elliptic Curves */
+/******************************************************************************/
+
+#ifdef HAVE_SUPPORTED_CURVES
+
+#if !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) && !defined(HAVE_CURVE448) \
+ && !defined(HAVE_FFDHE)
+#error Elliptic Curves Extension requires Elliptic Curve Cryptography. \
+ Use --enable-ecc in the configure script or define HAVE_ECC. \
+ Alternatively use FFDHE for DH ciperhsuites.
+#endif
+
+static int TLSX_SupportedCurve_New(SupportedCurve** curve, word16 name,
+ void* heap)
+{
+ if (curve == NULL)
+ return BAD_FUNC_ARG;
+
+ (void)heap;
+
+ *curve = (SupportedCurve*)XMALLOC(sizeof(SupportedCurve), heap,
+ DYNAMIC_TYPE_TLSX);
+ if (*curve == NULL)
+ return MEMORY_E;
+
+ (*curve)->name = name;
+ (*curve)->next = NULL;
+
+ return 0;
+}
+
+static int TLSX_PointFormat_New(PointFormat** point, byte format, void* heap)
+{
+ if (point == NULL)
+ return BAD_FUNC_ARG;
+
+ (void)heap;
+
+ *point = (PointFormat*)XMALLOC(sizeof(PointFormat), heap,
+ DYNAMIC_TYPE_TLSX);
+ if (*point == NULL)
+ return MEMORY_E;
+
+ (*point)->format = format;
+ (*point)->next = NULL;
+
+ return 0;
+}
+
+static void TLSX_SupportedCurve_FreeAll(SupportedCurve* list, void* heap)
+{
+ SupportedCurve* curve;
+
+ while ((curve = list)) {
+ list = curve->next;
+ XFREE(curve, heap, DYNAMIC_TYPE_TLSX);
+ }
+ (void)heap;
+}
+
+static void TLSX_PointFormat_FreeAll(PointFormat* list, void* heap)
+{
+ PointFormat* point;
+
+ while ((point = list)) {
+ list = point->next;
+ XFREE(point, heap, DYNAMIC_TYPE_TLSX);
+ }
+ (void)heap;
+}
+
+static int TLSX_SupportedCurve_Append(SupportedCurve* list, word16 name,
+ void* heap)
+{
+ int ret = BAD_FUNC_ARG;
+
+ while (list) {
+ if (list->name == name) {
+ ret = 0; /* curve already in use */
+ break;
+ }
+
+ if (list->next == NULL) {
+ ret = TLSX_SupportedCurve_New(&list->next, name, heap);
+ break;
+ }
+
+ list = list->next;
+ }
+
+ return ret;
+}
+
+static int TLSX_PointFormat_Append(PointFormat* list, byte format, void* 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 ret;
+}
+
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
+
+static void TLSX_SupportedCurve_ValidateRequest(WOLFSSL* ssl, byte* semaphore)
+{
+ word16 i;
+
+ for (i = 0; i < ssl->suites->suiteSz; i+= 2) {
+ if (ssl->suites->suites[i] == TLS13_BYTE)
+ return;
+ if (ssl->suites->suites[i] == ECC_BYTE ||
+ ssl->suites->suites[i] == CHACHA_BYTE) {
+ #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+ defined(HAVE_CURVE448)
+ return;
+ #endif
+ }
+ else {
+ #ifdef HAVE_FFDHE
+ return;
+ #endif
+ }
+ }
+
+ /* turns semaphore on to avoid sending this extension. */
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_GROUPS));
+}
+
+static void TLSX_PointFormat_ValidateRequest(WOLFSSL* ssl, byte* semaphore)
+{
+ word16 i;
+
+ for (i = 0; i < ssl->suites->suiteSz; i+= 2) {
+ if (ssl->suites->suites[i] == TLS13_BYTE)
+ return;
+ if (ssl->suites->suites[i] == ECC_BYTE ||
+ ssl->suites->suites[i] == CHACHA_BYTE) {
+ #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+ defined(HAVE_CURVE448)
+ return;
+ #endif
+ }
+ else {
+ #ifdef HAVE_FFDHE
return;
+ #endif
+ }
+ }
+
+ /* turns semaphore on to avoid sending this extension. */
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
+}
+
+#endif
+
+#ifndef NO_WOLFSSL_SERVER
- /* No elliptic curve suite found */
- TURN_ON(semaphore, TLSX_ToSemaphore(ELLIPTIC_CURVES));
+static void TLSX_PointFormat_ValidateResponse(WOLFSSL* ssl, byte* semaphore)
+{
+#if defined(HAVE_FFDHE) || defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+ defined(HAVE_CURVE448)
+ (void)semaphore;
+#endif
+
+ if (ssl->options.cipherSuite0 == TLS13_BYTE)
+ return;
+ if (ssl->options.cipherSuite0 == ECC_BYTE ||
+ ssl->options.cipherSuite0 == CHACHA_BYTE) {
+#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)
+ return;
+#endif
+ }
+ else {
+#ifdef HAVE_FFDHE
+ return;
+#endif
+ }
+
+#if !defined(HAVE_FFDHE) || (!defined(HAVE_ECC) && !defined(HAVE_CURVE25519) \
+ && !defined(HAVE_CURVE448))
+ /* turns semaphore on to avoid sending this extension. */
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
+#endif
}
-static word16 TLSX_EllipticCurve_GetSize(EllipticCurve* list)
+#endif
+#ifndef NO_WOLFSSL_CLIENT
+
+static word16 TLSX_SupportedCurve_GetSize(SupportedCurve* list)
{
- EllipticCurve* curve;
+ SupportedCurve* curve;
word16 length = OPAQUE16_LEN; /* list length */
while ((curve = list)) {
@@ -1428,40 +3912,71 @@ static word16 TLSX_EllipticCurve_GetSize(EllipticCurve* list)
return length;
}
-static word16 TLSX_EllipticCurve_WriteR(EllipticCurve* curve, byte* output);
-static word16 TLSX_EllipticCurve_WriteR(EllipticCurve* curve, byte* output)
+#endif
+
+static word16 TLSX_PointFormat_GetSize(PointFormat* list)
+{
+ PointFormat* point;
+ word16 length = ENUM_LEN; /* list length */
+
+ while ((point = list)) {
+ list = point->next;
+ length += ENUM_LEN; /* format length */
+ }
+
+ return length;
+}
+
+#ifndef NO_WOLFSSL_CLIENT
+
+static word16 TLSX_SupportedCurve_Write(SupportedCurve* list, byte* output)
{
- word16 offset = 0;
+ word16 offset = OPAQUE16_LEN;
- if (!curve)
- return offset;
+ while (list) {
+ c16toa(list->name, output + offset);
+ offset += OPAQUE16_LEN;
+ list = list->next;
+ }
- offset = TLSX_EllipticCurve_WriteR(curve->next, output);
- c16toa(curve->name, output + offset);
+ c16toa(offset - OPAQUE16_LEN, output); /* writing list length */
- return OPAQUE16_LEN + offset;
+ return offset;
}
-static word16 TLSX_EllipticCurve_Write(EllipticCurve* list, byte* output)
+#endif
+
+static word16 TLSX_PointFormat_Write(PointFormat* list, byte* output)
{
- word16 length = TLSX_EllipticCurve_WriteR(list, output + OPAQUE16_LEN);
+ word16 offset = ENUM_LEN;
+
+ while (list) {
+ output[offset++] = list->format;
+ list = list->next;
+ }
- c16toa(length, output); /* writing list length */
+ output[0] = (byte)(offset - ENUM_LEN);
- return OPAQUE16_LEN + length;
+ return offset;
}
-#endif /* NO_WOLFSSL_CLIENT */
-#ifndef NO_WOLFSSL_SERVER
+#if !defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \
+ !defined(WOLFSSL_NO_SERVER_GROUPS_EXT))
-static int TLSX_EllipticCurve_Parse(WOLFSSL* ssl, byte* input, word16 length,
+static int TLSX_SupportedCurve_Parse(WOLFSSL* ssl, byte* input, word16 length,
byte isRequest)
{
word16 offset;
word16 name;
- int r;
+ 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)
return BUFFER_ERROR;
@@ -1472,201 +3987,751 @@ static int TLSX_EllipticCurve_Parse(WOLFSSL* ssl, byte* input, word16 length,
if (length != OPAQUE16_LEN + offset)
return BUFFER_ERROR;
- while (offset) {
+ 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);
- offset -= OPAQUE16_LEN;
- r = TLSX_UseSupportedCurve(&ssl->extensions, name);
+ ret = TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret; /* throw error */
+ }
+
+ return 0;
+}
+
+#endif
+
+#if !defined(NO_WOLFSSL_SERVER)
+
+#if 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(HAVE_FFDHE) && !defined(WOLFSSL_NO_TLS12)
+/* Set the highest priority common FFDHE group on the server as compared to
+ * client extensions.
+ *
+ * ssl SSL/TLS object.
+ * returns 0 on success, otherwise an error.
+ */
+int TLSX_SupportedFFDHE_Set(WOLFSSL* ssl)
+{
+ int ret = 0;
+ TLSX* extension;
+ TLSX* priority = NULL;
+ TLSX* ext = NULL;
+ SupportedCurve* serverGroup;
+ SupportedCurve* clientGroup;
+ SupportedCurve* group;
+ const DhParams* params = NULL;
+ int found = 0;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
+ /* May be doing PSK with no key exchange. */
+ if (extension == NULL)
+ return 0;
+ clientGroup = (SupportedCurve*)extension->data;
+ for (group = clientGroup; group != NULL; group = group->next) {
+ if (group->name >= MIN_FFHDE_GROUP && group->name <= MAX_FFHDE_GROUP) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ return 0;
+
+ if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH) {
+ XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
+ DYNAMIC_TYPE_PUBLIC_KEY);
+ }
+ if (ssl->buffers.serverDH_G.buffer && ssl->buffers.weOwnDH) {
+ XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap,
+ DYNAMIC_TYPE_PUBLIC_KEY);
+ }
+ ssl->buffers.serverDH_P.buffer = NULL;
+ ssl->buffers.serverDH_G.buffer = NULL;
+ ssl->buffers.weOwnDH = 0;
+ ssl->options.haveDH = 0;
+
+
+ if ((ret = TLSX_PopulateSupportedGroups(ssl, &priority)) != WOLFSSL_SUCCESS)
+ return ret;
+ ret = 0;
+
+ ext = TLSX_Find(priority, TLSX_SUPPORTED_GROUPS);
+ serverGroup = (SupportedCurve*)ext->data;
+
+ for (; serverGroup != NULL; serverGroup = serverGroup->next) {
+ if ((serverGroup->name & NAMED_DH_MASK) != NAMED_DH_MASK)
+ continue;
+
+ for (group = clientGroup; group != NULL; group = group->next) {
+ if (serverGroup->name != group->name)
+ continue;
+
+ switch (serverGroup->name) {
+ #ifdef HAVE_FFDHE_2048
+ case WOLFSSL_FFDHE_2048:
+ params = wc_Dh_ffdhe2048_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_3072
+ case WOLFSSL_FFDHE_3072:
+ params = wc_Dh_ffdhe3072_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_4096
+ case WOLFSSL_FFDHE_4096:
+ params = wc_Dh_ffdhe4096_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_6144
+ case WOLFSSL_FFDHE_6144:
+ params = wc_Dh_ffdhe6144_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_8192
+ case WOLFSSL_FFDHE_8192:
+ params = wc_Dh_ffdhe8192_Get();
+ break;
+ #endif
+ }
+ if (params == NULL)
+ return BAD_FUNC_ARG;
+ if (params->p_len >= ssl->options.minDhKeySz &&
+ params->p_len <= ssl->options.maxDhKeySz) {
+ break;
+ }
+ }
+
+ if (group != NULL && serverGroup->name == group->name)
+ break;
+ }
+
+ if (serverGroup) {
+ ssl->buffers.serverDH_P.buffer = (unsigned char *)params->p;
+ ssl->buffers.serverDH_P.length = params->p_len;
+ ssl->buffers.serverDH_G.buffer = (unsigned char *)params->g;
+ ssl->buffers.serverDH_G.length = params->g_len;
+ ssl->namedGroup = serverGroup->name;
+ #if !defined(WOLFSSL_OLD_PRIME_CHECK) && \
+ !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+ ssl->options.dhDoKeyTest = 0;
+ #endif
+ ssl->options.haveDH = 1;
+ }
+
+ TLSX_FreeAll(priority, ssl->heap);
+
+ return ret;
+}
+#endif /* HAVE_FFDHE && !WOLFSSL_NO_TLS12 */
+
+#endif /* !NO_WOLFSSL_SERVER */
+
+#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,
+ byte isRequest)
+{
+ int ret;
+
+ /* validating formats list length */
+ if (ENUM_LEN > length || length != (word16)ENUM_LEN + input[0])
+ return BUFFER_ERROR;
- if (r != SSL_SUCCESS) return r; /* throw error */
+ if (isRequest) {
+ /* adding uncompressed point format to response */
+ ret = TLSX_UsePointFormat(&ssl->extensions, WOLFSSL_EC_PF_UNCOMPRESSED,
+ ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret; /* throw error */
+
+ TLSX_SetResponse(ssl, TLSX_EC_POINT_FORMATS);
}
return 0;
}
-int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) {
- TLSX* extension = (first == ECC_BYTE)
- ? TLSX_Find(ssl->extensions, ELLIPTIC_CURVES)
- : NULL;
- EllipticCurve* curve = NULL;
- word32 oid = 0;
- word16 octets = 0; /* acording to 'ecc_set_type ecc_sets[];' */
- int sig = 0; /* valitade signature */
- int key = 0; /* validate key */
+#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)
+int TLSX_ValidateSupportedCurves(WOLFSSL* ssl, byte first, byte second) {
+ TLSX* extension = NULL;
+ SupportedCurve* curve = NULL;
+ word32 oid = 0;
+ word32 pkOid = 0;
+ word32 defOid = 0;
+ word32 defSz = 80; /* Maximum known curve size is 66. */
+ word32 nextOid = 0;
+ word32 nextSz = 80; /* Maximum known curve size is 66. */
+ word32 currOid = ssl->ecdhCurveOID;
+ int ephmSuite = 0;
+ word16 octets = 0; /* according to 'ecc_set_type ecc_sets[];' */
+ int sig = 0; /* validate signature */
+ int key = 0; /* validate key */
(void)oid;
- (void)octets;
+ if (first == ECC_BYTE || first == CHACHA_BYTE)
+ extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
if (!extension)
return 1; /* no suite restriction */
- for (curve = extension->data; curve && !(sig && key); curve = curve->next) {
+ for (curve = (SupportedCurve*)extension->data;
+ curve && !(sig && key);
+ curve = curve->next) {
+
+ #ifdef OPENSSL_EXTRA
+ /* skip if name is not in supported ECC range */
+ if (curve->name > WOLFSSL_ECC_X448)
+ continue;
+ /* skip if curve is disabled by user */
+ if (ssl->ctx->disabledCurves & (1 << curve->name))
+ continue;
+ #endif
+ /* find supported curve */
switch (curve->name) {
-#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC160)
- case WOLFSSL_ECC_SECP160R1: oid = ECC_160R1; octets = 20; break;
-#endif
-#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC192)
- case WOLFSSL_ECC_SECP192R1: oid = ECC_192R1; octets = 24; break;
-#endif
-#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC224)
- case WOLFSSL_ECC_SECP224R1: oid = ECC_224R1; octets = 28; break;
-#endif
-#if defined(HAVE_ALL_CURVES) || !defined(NO_ECC256)
- case WOLFSSL_ECC_SECP256R1: oid = ECC_256R1; octets = 32; break;
+#ifdef HAVE_ECC
+ #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP160R1:
+ pkOid = oid = ECC_SECP160R1_OID;
+ octets = 20;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #ifdef HAVE_ECC_SECPR2
+ case WOLFSSL_ECC_SECP160R2:
+ pkOid = oid = ECC_SECP160R2_OID;
+ octets = 20;
+ break;
+ #endif /* HAVE_ECC_SECPR2 */
+ #ifdef HAVE_ECC_KOBLITZ
+ case WOLFSSL_ECC_SECP160K1:
+ pkOid = oid = ECC_SECP160K1_OID;
+ octets = 20;
+ break;
+ #endif /* HAVE_ECC_KOBLITZ */
+ #endif
+ #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP192R1:
+ pkOid = oid = ECC_SECP192R1_OID;
+ octets = 24;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #ifdef HAVE_ECC_KOBLITZ
+ case WOLFSSL_ECC_SECP192K1:
+ pkOid = oid = ECC_SECP192K1_OID;
+ octets = 24;
+ break;
+ #endif /* HAVE_ECC_KOBLITZ */
+ #endif
+ #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP224R1:
+ pkOid = oid = ECC_SECP224R1_OID;
+ octets = 28;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #ifdef HAVE_ECC_KOBLITZ
+ case WOLFSSL_ECC_SECP224K1:
+ pkOid = oid = ECC_SECP224K1_OID;
+ octets = 28;
+ break;
+ #endif /* HAVE_ECC_KOBLITZ */
+ #endif
+ #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP256R1:
+ pkOid = oid = ECC_SECP256R1_OID;
+ octets = 32;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif /* !NO_ECC256 || HAVE_ALL_CURVES */
#endif
-#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC384)
- case WOLFSSL_ECC_SECP384R1: oid = ECC_384R1; octets = 48; break;
+ #ifdef HAVE_CURVE25519
+ case WOLFSSL_ECC_X25519:
+ oid = ECC_X25519_OID;
+ #ifdef HAVE_ED25519
+ pkOid = ECC_ED25519_OID;
+ #else
+ pkOid = ECC_X25519_OID;
+ #endif
+ octets = 32;
+ break;
+ #endif /* HAVE_CURVE25519 */
+#ifdef HAVE_ECC
+ #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+ #ifdef HAVE_ECC_KOBLITZ
+ case WOLFSSL_ECC_SECP256K1:
+ pkOid = oid = ECC_SECP256K1_OID;
+ octets = 32;
+ break;
+ #endif /* HAVE_ECC_KOBLITZ */
+ #ifdef HAVE_ECC_BRAINPOOL
+ case WOLFSSL_ECC_BRAINPOOLP256R1:
+ pkOid = oid = ECC_BRAINPOOLP256R1_OID;
+ octets = 32;
+ break;
+ #endif /* HAVE_ECC_BRAINPOOL */
+ #endif
#endif
-#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC521)
- case WOLFSSL_ECC_SECP521R1: oid = ECC_521R1; octets = 66; break;
+ #ifdef HAVE_CURVE448
+ case WOLFSSL_ECC_X448:
+ oid = ECC_X448_OID;
+ #ifdef HAVE_ED448
+ pkOid = ECC_ED448_OID;
+ #else
+ pkOid = ECC_X448_OID;
+ #endif
+ octets = 57;
+ break;
+ #endif /* HAVE_CURVE448 */
+#ifdef HAVE_ECC
+ #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP384R1:
+ pkOid = oid = ECC_SECP384R1_OID;
+ octets = 48;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #ifdef HAVE_ECC_BRAINPOOL
+ case WOLFSSL_ECC_BRAINPOOLP384R1:
+ pkOid = oid = ECC_BRAINPOOLP384R1_OID;
+ octets = 48;
+ break;
+ #endif /* HAVE_ECC_BRAINPOOL */
+ #endif
+ #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)
+ #ifdef HAVE_ECC_BRAINPOOL
+ case WOLFSSL_ECC_BRAINPOOLP512R1:
+ pkOid = oid = ECC_BRAINPOOLP512R1_OID;
+ octets = 64;
+ break;
+ #endif /* HAVE_ECC_BRAINPOOL */
+ #endif
+ #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP521R1:
+ pkOid = oid = ECC_SECP521R1_OID;
+ octets = 66;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
#endif
default: continue; /* unsupported curve */
}
- switch (second) {
-#ifndef NO_DSA
- /* ECDHE_ECDSA */
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
- case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
- case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
- case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
- case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
- case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
- sig |= ssl->pkCurveOID == oid;
- key |= ssl->eccTempKeySz == octets;
- break;
-
- /* ECDH_ECDSA */
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
- case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
- case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
- case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
- case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
- sig |= ssl->pkCurveOID == oid;
- key |= ssl->pkCurveOID == oid;
- break;
+ #ifdef HAVE_ECC
+ /* Set default Oid */
+ if (defOid == 0 && ssl->eccTempKeySz <= octets && defSz > octets) {
+ defOid = oid;
+ defSz = octets;
+ }
+
+ /* The eccTempKeySz is the preferred ephemeral key size */
+ if (currOid == 0 && ssl->eccTempKeySz == octets)
+ currOid = oid;
+ if ((nextOid == 0 || nextSz > octets) && ssl->eccTempKeySz <= octets) {
+ nextOid = oid;
+ 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) {
+ switch (second) {
+ /* ECDHE_ECDSA */
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ sig |= ssl->pkCurveOID == pkOid;
+ key |= ssl->ecdhCurveOID == oid;
+ ephmSuite = 1;
+ break;
+
+#ifdef WOLFSSL_STATIC_DH
+ /* ECDH_ECDSA */
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ if (oid == ECC_X25519_OID && defOid == oid) {
+ defOid = 0;
+ defSz = 80;
+ }
+ if (oid == ECC_X448_OID && defOid == oid) {
+ defOid = 0;
+ defSz = 80;
+ }
+ sig |= ssl->pkCurveOID == pkOid;
+ key |= ssl->pkCurveOID == oid;
+ break;
+#endif /* WOLFSSL_STATIC_DH */
+#ifndef NO_RSA
+ /* ECDHE_RSA */
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ sig = 1;
+ key |= ssl->ecdhCurveOID == oid;
+ ephmSuite = 1;
+ break;
+
+#ifdef WOLFSSL_STATIC_DH
+ /* ECDH_RSA */
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ if (oid == ECC_X25519_OID && defOid == oid) {
+ defOid = 0;
+ defSz = 80;
+ }
+ if (oid == ECC_X448_OID && defOid == oid) {
+ defOid = 0;
+ defSz = 80;
+ }
+ sig = 1;
+ key |= ssl->pkCurveOID == pkOid;
+ break;
+#endif /* WOLFSSL_STATIC_DH */
#endif
+ default:
+ if (oid == ECC_X25519_OID && defOid == oid) {
+ defOid = 0;
+ defSz = 80;
+ }
+ if (oid == ECC_X448_OID && defOid == oid) {
+ defOid = 0;
+ defSz = 80;
+ }
+ if (oid != ECC_X25519_OID && oid != ECC_X448_OID) {
+ sig = 1;
+ }
+ key = 1;
+ break;
+ }
+ }
+
+ /* ChaCha20-Poly1305 ECC cipher suites */
+ if (first == CHACHA_BYTE) {
+ switch (second) {
+ /* ECDHE_ECDSA */
+ case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 :
+ case TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 :
+ sig |= ssl->pkCurveOID == pkOid;
+ key |= ssl->ecdhCurveOID == oid;
+ ephmSuite = 1;
+ break;
#ifndef NO_RSA
- /* ECDHE_RSA */
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
- case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
- case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
- case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
- sig = 1;
- key |= ssl->eccTempKeySz == octets;
- break;
-
- /* ECDH_RSA */
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
- case TLS_ECDH_RSA_WITH_RC4_128_SHA:
- case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
- case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
- case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
- sig = 1;
- key |= ssl->pkCurveOID == oid;
- break;
+ /* ECDHE_RSA */
+ case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 :
+ case TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 :
+ sig = 1;
+ key |= ssl->ecdhCurveOID == oid;
+ ephmSuite = 1;
+ break;
#endif
- default:
- sig = 1;
- key = 1;
- break;
+ default:
+ sig = 1;
+ key = 1;
+ break;
+ }
}
}
+ /* Choose the default if it is at the required strength. */
+#ifdef HAVE_ECC
+ if (ssl->ecdhCurveOID == 0 && defSz == ssl->eccTempKeySz)
+#else
+ if (ssl->ecdhCurveOID == 0)
+#endif
+ {
+ key = 1;
+ ssl->ecdhCurveOID = defOid;
+ }
+ /* Choose any curve at the required strength. */
+ if (ssl->ecdhCurveOID == 0) {
+ key = 1;
+ ssl->ecdhCurveOID = currOid;
+ }
+ /* Choose the default if it is at the next highest strength. */
+ if (ssl->ecdhCurveOID == 0 && defSz == nextSz)
+ ssl->ecdhCurveOID = defOid;
+ /* Choose any curve at the next highest strength. */
+ if (ssl->ecdhCurveOID == 0)
+ ssl->ecdhCurveOID = nextOid;
+ /* No curve and ephemeral ECC suite requires a matching curve. */
+ if (ssl->ecdhCurveOID == 0 && ephmSuite)
+ key = 0;
+
return sig && key;
}
+#endif
#endif /* NO_WOLFSSL_SERVER */
-int TLSX_UseSupportedCurve(TLSX** extensions, word16 name)
+int TLSX_UseSupportedCurve(TLSX** extensions, word16 name, void* heap)
{
- TLSX* extension = TLSX_Find(*extensions, ELLIPTIC_CURVES);
- EllipticCurve* curve = NULL;
- int ret = 0;
+ TLSX* extension = NULL;
+ SupportedCurve* curve = NULL;
+ int ret;
if (extensions == NULL)
return BAD_FUNC_ARG;
- if ((ret = TLSX_EllipticCurve_Append(&curve, name)) != 0)
- return ret;
+ extension = TLSX_Find(*extensions, TLSX_SUPPORTED_GROUPS);
if (!extension) {
- if ((ret = TLSX_Push(extensions, ELLIPTIC_CURVES, curve)) != 0) {
- XFREE(curve, 0, DYNAMIC_TYPE_TLSX);
+ ret = TLSX_SupportedCurve_New(&curve, name, heap);
+ if (ret != 0)
+ return ret;
+
+ ret = TLSX_Push(extensions, TLSX_SUPPORTED_GROUPS, curve, heap);
+ if (ret != 0) {
+ XFREE(curve, heap, DYNAMIC_TYPE_TLSX);
return ret;
}
}
else {
- /* push new EllipticCurve object to extension data. */
- curve->next = (EllipticCurve*)extension->data;
- extension->data = (void*)curve;
+ ret = TLSX_SupportedCurve_Append((SupportedCurve*)extension->data, name,
+ heap);
+ if (ret != 0)
+ return ret;
+ }
- /* look for another curve of the same name to remove (replacement) */
- do {
- if (curve->next && curve->next->name == name) {
- EllipticCurve *next = curve->next;
+ return WOLFSSL_SUCCESS;
+}
- curve->next = next->next;
- XFREE(next, 0, DYNAMIC_TYPE_TLSX);
+int TLSX_UsePointFormat(TLSX** extensions, byte format, void* heap)
+{
+ TLSX* extension = NULL;
+ PointFormat* point = NULL;
+ int ret = 0;
- break;
- }
- } while ((curve = curve->next));
+ if (extensions == NULL)
+ return BAD_FUNC_ARG;
+
+ extension = TLSX_Find(*extensions, TLSX_EC_POINT_FORMATS);
+
+ if (!extension) {
+ ret = TLSX_PointFormat_New(&point, format, heap);
+ if (ret != 0)
+ return ret;
+
+ ret = TLSX_Push(extensions, TLSX_EC_POINT_FORMATS, point, heap);
+ if (ret != 0) {
+ XFREE(point, heap, DYNAMIC_TYPE_TLSX);
+ return ret;
+ }
+ }
+ else {
+ ret = TLSX_PointFormat_Append((PointFormat*)extension->data, format,
+ heap);
+ if (ret != 0)
+ return ret;
}
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
-#define EC_FREE_ALL TLSX_EllipticCurve_FreeAll
-#define EC_VALIDATE_REQUEST TLSX_EllipticCurve_ValidateRequest
+#define EC_FREE_ALL TLSX_SupportedCurve_FreeAll
+#define EC_VALIDATE_REQUEST TLSX_SupportedCurve_ValidateRequest
#ifndef NO_WOLFSSL_CLIENT
-#define EC_GET_SIZE TLSX_EllipticCurve_GetSize
-#define EC_WRITE TLSX_EllipticCurve_Write
+#define EC_GET_SIZE TLSX_SupportedCurve_GetSize
+#define EC_WRITE TLSX_SupportedCurve_Write
#else
#define EC_GET_SIZE(list) 0
#define EC_WRITE(a, b) 0
#endif
-#ifndef NO_WOLFSSL_SERVER
-#define EC_PARSE TLSX_EllipticCurve_Parse
+#if !defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \
+ !defined(WOLFSSL_NO_SERVER_GROUPS_EXT))
+#define EC_PARSE TLSX_SupportedCurve_Parse
#else
#define EC_PARSE(a, b, c, d) 0
#endif
+#define PF_FREE_ALL TLSX_PointFormat_FreeAll
+#define PF_VALIDATE_REQUEST TLSX_PointFormat_ValidateRequest
+#define PF_VALIDATE_RESPONSE TLSX_PointFormat_ValidateResponse
+
+#define PF_GET_SIZE TLSX_PointFormat_GetSize
+#define PF_WRITE TLSX_PointFormat_Write
+
+#ifndef NO_WOLFSSL_SERVER
+#define PF_PARSE TLSX_PointFormat_Parse
#else
+#define PF_PARSE(a, b, c, d) 0
+#endif
-#define EC_FREE_ALL(list)
+#else
+
+#define EC_FREE_ALL(list, heap)
#define EC_GET_SIZE(list) 0
#define EC_WRITE(a, b) 0
#define EC_PARSE(a, b, c, d) 0
#define EC_VALIDATE_REQUEST(a, b)
+#define PF_FREE_ALL(list, heap)
+#define PF_GET_SIZE(list) 0
+#define PF_WRITE(a, b) 0
+#define PF_PARSE(a, b, c, d) 0
+#define PF_VALIDATE_REQUEST(a, b)
+#define PF_VALIDATE_RESPONSE(a, b)
+
#endif /* HAVE_SUPPORTED_CURVES */
-#ifdef HAVE_SECURE_RENEGOTIATION
+/******************************************************************************/
+/* Renegotiation Indication */
+/******************************************************************************/
+
+#if defined(HAVE_SECURE_RENEGOTIATION) \
+ || defined(HAVE_SERVER_RENEGOTIATION_INFO)
static byte TLSX_SecureRenegotiation_GetSize(SecureRenegotiation* data,
int isRequest)
{
byte length = OPAQUE8_LEN; /* empty info length */
- if (data->enabled) {
+ /* data will be NULL for HAVE_SERVER_RENEGOTIATION_INFO only */
+ if (data && data->enabled && data->verifySet) {
/* client sends client_verify_data only */
length += TLS_FINISHED_SZ;
@@ -1682,8 +4747,7 @@ static word16 TLSX_SecureRenegotiation_Write(SecureRenegotiation* data,
byte* output, int isRequest)
{
word16 offset = OPAQUE8_LEN; /* RenegotiationInfo length */
-
- if (data->enabled) {
+ if (data && data->enabled && data->verifySet) {
/* client sends client_verify_data only */
XMEMCPY(output + offset, data->client_verify_data, TLS_FINISHED_SZ);
offset += TLS_FINISHED_SZ;
@@ -1695,7 +4759,7 @@ static word16 TLSX_SecureRenegotiation_Write(SecureRenegotiation* data,
}
}
- output[0] = offset - 1; /* info length - self */
+ output[0] = (byte)(offset - 1); /* info length - self */
return offset;
}
@@ -1706,18 +4770,48 @@ static int TLSX_SecureRenegotiation_Parse(WOLFSSL* ssl, byte* input,
int ret = SECURE_RENEGOTIATION_E;
if (length >= OPAQUE8_LEN) {
- if (ssl->secure_renegotiation == NULL) {
+ if (isRequest) {
#ifndef NO_WOLFSSL_SERVER
- if (isRequest && *input == 0) {
- ret = 0; /* don't reply, user didn't enable */
+ if (ssl->secure_renegotiation == NULL) {
+ ret = wolfSSL_UseSecureRenegotiation(ssl);
+ if (ret == WOLFSSL_SUCCESS)
+ ret = 0;
}
- #endif
- }
- else if (isRequest) {
- #ifndef NO_WOLFSSL_SERVER
- if (*input == TLS_FINISHED_SZ) {
- /* TODO compare client_verify_data */
- ret = 0;
+ if (ret != 0 && ret != SECURE_RENEGOTIATION_E) {
+ }
+ 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 if (*input == TLS_FINISHED_SZ) {
+ if (length < TLS_FINISHED_SZ + 1) {
+ WOLFSSL_MSG("SCR malformed buffer");
+ ret = BUFFER_E;
+ }
+ else {
+ 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
}
@@ -1729,73 +4823,116 @@ static int TLSX_SecureRenegotiation_Parse(WOLFSSL* ssl, byte* input,
ret = 0;
}
}
- else if (*input == 2 * TLS_FINISHED_SZ) {
- /* TODO compare client_verify_data and server_verify_data */
- ret = 0;
+ else if (*input == 2 * TLS_FINISHED_SZ &&
+ length == 2 * TLS_FINISHED_SZ + OPAQUE8_LEN) {
+ input++; /* get past size */
+
+ /* validate client and server verify data */
+ if (XMEMCMP(input,
+ ssl->secure_renegotiation->client_verify_data,
+ TLS_FINISHED_SZ) == 0 &&
+ XMEMCMP(input + TLS_FINISHED_SZ,
+ ssl->secure_renegotiation->server_verify_data,
+ TLS_FINISHED_SZ) == 0) {
+ WOLFSSL_MSG("SCR client and server verify data match");
+ ret = 0; /* verified */
+ } else {
+ /* already in error state */
+ WOLFSSL_MSG("SCR client and server verify data Failure");
+ }
}
#endif
}
}
if (ret != 0) {
- /* TODO: turn on fatal error at ssl level too */
SendAlert(ssl, alert_fatal, handshake_failure);
}
return ret;
}
-int TLSX_UseSecureRenegotiation(TLSX** extensions)
+int TLSX_UseSecureRenegotiation(TLSX** extensions, void* heap)
{
int ret = 0;
- SecureRenegotiation* data = NULL;
+ SecureRenegotiation* data;
- data = (SecureRenegotiation*)XMALLOC(sizeof(SecureRenegotiation), NULL,
+ data = (SecureRenegotiation*)XMALLOC(sizeof(SecureRenegotiation), heap,
DYNAMIC_TYPE_TLSX);
if (data == NULL)
return MEMORY_E;
XMEMSET(data, 0, sizeof(SecureRenegotiation));
- ret = TLSX_Push(extensions, SECURE_RENEGOTIATION, data);
+ ret = TLSX_Push(extensions, TLSX_RENEGOTIATION_INFO, data, heap);
if (ret != 0) {
- XFREE(data, 0, DYNAMIC_TYPE_TLSX);
+ XFREE(data, heap, DYNAMIC_TYPE_TLSX);
return ret;
}
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
+#ifdef HAVE_SERVER_RENEGOTIATION_INFO
+
+int TLSX_AddEmptyRenegotiationInfo(TLSX** extensions, void* heap)
+{
+ int ret;
+
+ /* send empty renegotiation_info extension */
+ TLSX* ext = TLSX_Find(*extensions, TLSX_RENEGOTIATION_INFO);
+ if (ext == NULL) {
+ ret = TLSX_UseSecureRenegotiation(extensions, heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
-#define SCR_FREE_ALL(data) XFREE(data, NULL, DYNAMIC_TYPE_TLSX)
+ ext = TLSX_Find(*extensions, TLSX_RENEGOTIATION_INFO);
+ }
+ if (ext)
+ ext->resp = 1;
+
+ return WOLFSSL_SUCCESS;
+}
+
+#endif /* HAVE_SERVER_RENEGOTIATION_INFO */
+
+
+#define SCR_FREE_ALL(data, heap) XFREE(data, (heap), DYNAMIC_TYPE_TLSX)
#define SCR_GET_SIZE TLSX_SecureRenegotiation_GetSize
#define SCR_WRITE TLSX_SecureRenegotiation_Write
#define SCR_PARSE TLSX_SecureRenegotiation_Parse
#else
-#define SCR_FREE_ALL(a)
+#define SCR_FREE_ALL(a, heap)
#define SCR_GET_SIZE(a, b) 0
#define SCR_WRITE(a, b, c) 0
#define SCR_PARSE(a, b, c, d) 0
#endif /* HAVE_SECURE_RENEGOTIATION */
+/******************************************************************************/
+/* Session Tickets */
+/******************************************************************************/
+
#ifdef HAVE_SESSION_TICKET
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
static void TLSX_SessionTicket_ValidateRequest(WOLFSSL* ssl)
{
- TLSX* extension = TLSX_Find(ssl->extensions, SESSION_TICKET);
- SessionTicket* ticket = extension ? extension->data : NULL;
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_SESSION_TICKET);
+ SessionTicket* ticket = extension ?
+ (SessionTicket*)extension->data : NULL;
if (ticket) {
/* TODO validate ticket timeout here! */
if (ticket->lifetime == 0xfffffff) {
/* send empty ticket on timeout */
- TLSX_UseSessionTicket(&ssl->extensions, NULL);
+ TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap);
}
}
}
+#endif /* WLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */
static word16 TLSX_SessionTicket_GetSize(SessionTicket* ticket, int isRequest)
@@ -1823,12 +4960,18 @@ static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, byte* input, word16 length,
{
int ret = 0;
+ (void) input; /* avoid unused parameter if NO_WOLFSSL_SERVER defined */
+
if (!isRequest) {
- /* client side */
+ if (TLSX_CheckUnsupportedExtension(ssl, TLSX_SESSION_TICKET))
+ return TLSX_HandleUnsupportedExtension(ssl);
+
if (length != 0)
return BUFFER_ERROR;
+#ifndef NO_WOLFSSL_CLIENT
ssl->expect_session_ticket = 1;
+#endif
}
#ifndef NO_WOLFSSL_SERVER
else {
@@ -1840,26 +4983,28 @@ static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, byte* input, word16 length,
if (length == 0) {
/* blank ticket */
- ret = TLSX_UseSessionTicket(&ssl->extensions, NULL);
- if (ret == SSL_SUCCESS) {
+ ret = TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap);
+ if (ret == WOLFSSL_SUCCESS) {
ret = 0;
- TLSX_SetResponse(ssl, SESSION_TICKET); /* send blank ticket */
+ TLSX_SetResponse(ssl, TLSX_SESSION_TICKET); /* send blank ticket */
ssl->options.createTicket = 1; /* will send ticket msg */
ssl->options.useTicket = 1;
+ ssl->options.resuming = 0; /* no standard resumption */
+ ssl->arrays->sessionIDSz = 0; /* no echo on blank ticket */
}
} else {
/* got actual ticket from client */
ret = DoClientTicket(ssl, input, length);
if (ret == WOLFSSL_TICKET_RET_OK) { /* use ticket to resume */
- WOLFSSL_MSG("Using exisitng client ticket");
+ WOLFSSL_MSG("Using existing client ticket");
ssl->options.useTicket = 1;
ssl->options.resuming = 1;
} else if (ret == WOLFSSL_TICKET_RET_CREATE) {
WOLFSSL_MSG("Using existing client ticket, creating new one");
- ret = TLSX_UseSessionTicket(&ssl->extensions, NULL);
- if (ret == SSL_SUCCESS) {
+ ret = TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap);
+ if (ret == WOLFSSL_SUCCESS) {
ret = 0;
- TLSX_SetResponse(ssl, SESSION_TICKET);
+ TLSX_SetResponse(ssl, TLSX_SESSION_TICKET);
/* send blank ticket */
ssl->options.createTicket = 1; /* will send ticket msg */
ssl->options.useTicket = 1;
@@ -1867,6 +5012,7 @@ static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, byte* input, word16 length,
}
} else if (ret == WOLFSSL_TICKET_RET_REJECT) {
WOLFSSL_MSG("Process client ticket rejected, not using");
+ ssl->options.rejectTicket = 1;
ret = 0; /* not fatal */
} else if (ret == WOLFSSL_TICKET_RET_FATAL || ret < 0) {
WOLFSSL_MSG("Process client ticket fatal error, not using");
@@ -1879,14 +5025,14 @@ static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, byte* input, word16 length,
}
WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime,
- byte* data, word16 size)
+ byte* data, word16 size, void* heap)
{
SessionTicket* ticket = (SessionTicket*)XMALLOC(sizeof(SessionTicket),
- NULL, DYNAMIC_TYPE_TLSX);
+ heap, DYNAMIC_TYPE_TLSX);
if (ticket) {
- ticket->data = (byte*)XMALLOC(size, NULL, DYNAMIC_TYPE_TLSX);
+ ticket->data = (byte*)XMALLOC(size, heap, DYNAMIC_TYPE_TLSX);
if (ticket->data == NULL) {
- XFREE(ticket, NULL, DYNAMIC_TYPE_TLSX);
+ XFREE(ticket, heap, DYNAMIC_TYPE_TLSX);
return NULL;
}
@@ -1895,17 +5041,21 @@ WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime,
ticket->lifetime = lifetime;
}
+ (void)heap;
+
return ticket;
}
-WOLFSSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket)
+WOLFSSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket, void* heap)
{
if (ticket) {
- XFREE(ticket->data, NULL, DYNAMIC_TYPE_TLSX);
- XFREE(ticket, NULL, DYNAMIC_TYPE_TLSX);
+ XFREE(ticket->data, heap, DYNAMIC_TYPE_TLSX);
+ XFREE(ticket, heap, DYNAMIC_TYPE_TLSX);
}
+
+ (void)heap;
}
-int TLSX_UseSessionTicket(TLSX** extensions, SessionTicket* ticket)
+int TLSX_UseSessionTicket(TLSX** extensions, SessionTicket* ticket, void* heap)
{
int ret = 0;
@@ -1914,27 +5064,4009 @@ int TLSX_UseSessionTicket(TLSX** extensions, SessionTicket* ticket)
/* If the ticket is NULL, the client will request a new ticket from the
server. Otherwise, the client will use it in the next client hello. */
- if ((ret = TLSX_Push(extensions, SESSION_TICKET, (void*)ticket)) != 0)
+ if ((ret = TLSX_Push(extensions, TLSX_SESSION_TICKET, (void*)ticket, heap))
+ != 0)
return ret;
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
-#define STK_VALIDATE_REQUEST TLSX_SessionTicket_ValidateRequest
-#define STK_GET_SIZE TLSX_SessionTicket_GetSize
-#define STK_WRITE TLSX_SessionTicket_Write
-#define STK_PARSE TLSX_SessionTicket_Parse
+#define WOLF_STK_VALIDATE_REQUEST TLSX_SessionTicket_ValidateRequest
+#define WOLF_STK_GET_SIZE TLSX_SessionTicket_GetSize
+#define WOLF_STK_WRITE TLSX_SessionTicket_Write
+#define WOLF_STK_PARSE TLSX_SessionTicket_Parse
+#define WOLF_STK_FREE(stk, heap) TLSX_SessionTicket_Free((SessionTicket*)stk,(heap))
#else
-#define STK_VALIDATE_REQUEST(a)
-#define STK_GET_SIZE(a, b) 0
-#define STK_WRITE(a, b, c) 0
-#define STK_PARSE(a, b, c, d) 0
+#define WOLF_STK_FREE(a, b)
+#define WOLF_STK_VALIDATE_REQUEST(a)
+#define WOLF_STK_GET_SIZE(a, b) 0
+#define WOLF_STK_WRITE(a, b, c) 0
+#define WOLF_STK_PARSE(a, b, c, d) 0
#endif /* HAVE_SESSION_TICKET */
+/******************************************************************************/
+/* Quantum-Safe-Hybrid */
+/******************************************************************************/
+
+#ifdef HAVE_QSH
+#if defined(HAVE_NTRU)
+static WC_RNG* gRng;
+static wolfSSL_Mutex* gRngMutex;
+#endif
+
+static void TLSX_QSH_FreeAll(QSHScheme* list, void* heap)
+{
+ QSHScheme* current;
+
+ while ((current = list)) {
+ list = current->next;
+ XFREE(current, heap, DYNAMIC_TYPE_TLSX);
+ }
+
+ (void)heap;
+}
+
+static int TLSX_QSH_Append(QSHScheme** list, word16 name, byte* pub,
+ word16 pubLen)
+{
+ QSHScheme* temp;
+
+ if (list == NULL)
+ return BAD_FUNC_ARG;
+
+ if ((temp = (QSHScheme*)XMALLOC(sizeof(QSHScheme), NULL,
+ DYNAMIC_TYPE_TLSX)) == NULL)
+ return MEMORY_E;
+
+ temp->name = name;
+ temp->PK = pub;
+ temp->PKLen = pubLen;
+ temp->next = *list;
+
+ *list = temp;
+
+ return 0;
+}
+
+
+/* request for server's public key : 02 indicates 0-2 requested */
+static byte TLSX_QSH_SerPKReq(byte* output, byte isRequest)
+{
+ if (isRequest) {
+ /* only request one public key from the server */
+ output[0] = 0x01;
+
+ return OPAQUE8_LEN;
+ }
+ else {
+ return 0;
+ }
+}
+
+#ifndef NO_WOLFSSL_CLIENT
+
+/* check for TLS_QSH suite */
+static void TLSX_QSH_ValidateRequest(WOLFSSL* ssl, byte* semaphore)
+{
+ int i;
+
+ for (i = 0; i < ssl->suites->suiteSz; i+= 2)
+ if (ssl->suites->suites[i] == QSH_BYTE)
+ return;
+
+ /* No QSH suite found */
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_QUANTUM_SAFE_HYBRID));
+}
+
+
+/* return the size of the QSH hello extension
+ list the list of QSHScheme structs containing id and key
+ isRequest if 1 then is being sent to the server
+ */
+word16 TLSX_QSH_GetSize(QSHScheme* list, byte isRequest)
+{
+ QSHScheme* temp = list;
+ word16 length = 0;
+
+ /* account for size of scheme list and public key list */
+ if (isRequest)
+ length = OPAQUE16_LEN;
+ length += OPAQUE24_LEN;
+
+ /* for each non null element in list add size */
+ while ((temp)) {
+ /* add public key info Scheme | Key Length | Key */
+ length += OPAQUE16_LEN;
+ length += OPAQUE16_LEN;
+ length += temp->PKLen;
+
+ /* if client add name size for scheme list
+ advance to next QSHScheme struct in list */
+ if (isRequest)
+ length += OPAQUE16_LEN;
+ temp = temp->next;
+ }
+
+ /* add length for request server public keys */
+ if (isRequest)
+ length += OPAQUE8_LEN;
+
+ return length;
+}
+
+
+/* write out a list of QSHScheme IDs */
+static word16 TLSX_QSH_Write(QSHScheme* list, byte* output)
+{
+ QSHScheme* current = list;
+ word16 length = 0;
+
+ length += OPAQUE16_LEN;
+
+ while (current) {
+ c16toa(current->name, output + length);
+ length += OPAQUE16_LEN;
+ current = (QSHScheme*)current->next;
+ }
+
+ c16toa(length - OPAQUE16_LEN, output); /* writing list length */
+
+ return length;
+}
+
+
+/* write public key list in extension */
+static word16 TLSX_QSHPK_WriteR(QSHScheme* format, byte* output)
+{
+ word32 offset = 0;
+ word16 public_len = 0;
+
+ if (!format)
+ return offset;
+
+ /* write scheme ID */
+ c16toa(format->name, output + offset);
+ offset += OPAQUE16_LEN;
+
+ /* write public key matching scheme */
+ public_len = format->PKLen;
+ c16toa(public_len, output + offset);
+ offset += OPAQUE16_LEN;
+ if (format->PK) {
+ XMEMCPY(output+offset, format->PK, public_len);
+ }
+
+ return public_len + offset;
+}
+
+word16 TLSX_QSHPK_Write(QSHScheme* list, byte* output)
+{
+ QSHScheme* current = list;
+ word32 length = 0;
+ word24 toWire;
+
+ length += OPAQUE24_LEN;
+
+ while (current) {
+ length += TLSX_QSHPK_WriteR(current, output + length);
+ current = (QSHScheme*)current->next;
+ }
+ /* length of public keys sent */
+ c32to24(length - OPAQUE24_LEN, toWire);
+ output[0] = toWire[0];
+ output[1] = toWire[1];
+ output[2] = toWire[2];
+
+ return length;
+}
+
+#endif /* NO_WOLFSSL_CLIENT */
+#ifndef NO_WOLFSSL_SERVER
+
+static void TLSX_QSHAgreement(TLSX** extensions, void* heap)
+{
+ TLSX* extension = TLSX_Find(*extensions, TLSX_QUANTUM_SAFE_HYBRID);
+ QSHScheme* format = NULL;
+ QSHScheme* del = NULL;
+ QSHScheme* prev = NULL;
+
+ if (extension == NULL)
+ return;
+
+ format = (QSHScheme*)extension->data;
+ while (format) {
+ if (format->PKLen == 0) {
+ /* case of head */
+ if (format == extension->data) {
+ extension->data = format->next;
+ }
+ if (prev)
+ prev->next = format->next;
+ del = format;
+ format = format->next;
+ XFREE(del, heap, DYNAMIC_TYPE_TMP_BUFFER);
+ del = NULL;
+ } else {
+ prev = format;
+ format = format->next;
+ }
+ }
+
+ (void)heap;
+}
+
+
+/* Parse in hello extension
+ input the byte stream to process
+ length length of total extension found
+ isRequest set to 1 if being sent to the server
+ */
+static int TLSX_QSH_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte isRequest)
+{
+ byte numKeys = 0;
+ word16 offset = 0;
+ word16 schemSz = 0;
+ word16 offset_len = 0;
+ word32 offset_pk = 0;
+ word16 name = 0;
+ word16 PKLen = 0;
+ byte* PK = NULL;
+ int r;
+
+
+ if (OPAQUE16_LEN > length)
+ return BUFFER_ERROR;
+
+ if (isRequest) {
+ ato16(input, &schemSz);
+
+ /* list of public keys available for QSH schemes */
+ offset_len = schemSz + OPAQUE16_LEN;
+ }
+
+ offset_pk = ((input[offset_len] << 16) & 0xFF00000) |
+ (((input[offset_len + 1]) << 8) & 0xFF00) |
+ (input[offset_len + 2] & 0xFF);
+ offset_len += OPAQUE24_LEN;
+
+ /* check buffer size */
+ if (offset_pk > length)
+ return BUFFER_ERROR;
+
+ /* set maximum number of keys the client will accept */
+ if (!isRequest)
+ numKeys = (ssl->maxRequest < 1)? 1 : ssl->maxRequest;
+
+ /* hello extension read list of scheme ids */
+ if (isRequest) {
+
+ /* read in request for public keys */
+ ssl->minRequest = (input[length -1] >> 4) & 0xFF;
+ ssl->maxRequest = input[length -1] & 0x0F;
+
+ /* choose the min between min requested by client and 1 */
+ numKeys = (ssl->minRequest > 1) ? ssl->minRequest : 1;
+
+ if (ssl->minRequest > ssl->maxRequest)
+ return BAD_FUNC_ARG;
+
+ offset += OPAQUE16_LEN;
+ schemSz += offset;
+
+ /* check buffer size */
+ if (schemSz > length)
+ return BUFFER_ERROR;
+
+ while ((offset < schemSz) && numKeys) {
+ /* Scheme ID list */
+ ato16(input + offset, &name);
+ offset += OPAQUE16_LEN;
+
+ /* validate we have scheme id */
+ if (ssl->user_set_QSHSchemes &&
+ !TLSX_ValidateQSHScheme(&ssl->extensions, name)) {
+ continue;
+ }
+
+ /* server create keys on demand */
+ if ((r = TLSX_CreateNtruKey(ssl, name)) != 0) {
+ WOLFSSL_MSG("Error creating ntru keys");
+ return r;
+ }
+
+ /* peer sent an agreed upon scheme */
+ r = TLSX_UseQSHScheme(&ssl->extensions, name, NULL, 0, ssl->heap);
+
+ if (r != WOLFSSL_SUCCESS) return r; /* throw error */
+
+ numKeys--;
+ }
+
+ /* choose the min between min requested by client and 1 */
+ numKeys = (ssl->minRequest > 1) ? ssl->minRequest : 1;
+ }
+
+ /* QSHPK struct */
+ offset_pk += offset_len;
+ while ((offset_len < offset_pk) && numKeys) {
+ QSHKey * temp;
+
+ if ((temp = (QSHKey*)XMALLOC(sizeof(QSHKey), ssl->heap,
+ DYNAMIC_TYPE_TLSX)) == NULL)
+ return MEMORY_E;
+
+ /* initialize */
+ temp->next = NULL;
+ temp->pub.buffer = NULL;
+ temp->pub.length = 0;
+ temp->pri.buffer = NULL;
+ temp->pri.length = 0;
+
+ /* scheme id */
+ ato16(input + offset_len, &(temp->name));
+ offset_len += OPAQUE16_LEN;
+
+ /* public key length */
+ ato16(input + offset_len, &PKLen);
+ temp->pub.length = PKLen;
+ offset_len += OPAQUE16_LEN;
+
+
+ if (isRequest) {
+ /* validate we have scheme id */
+ if (ssl->user_set_QSHSchemes &&
+ (!TLSX_ValidateQSHScheme(&ssl->extensions, temp->name))) {
+ offset_len += PKLen;
+ XFREE(temp, ssl->heap, DYNAMIC_TYPE_TLSX);
+ continue;
+ }
+ }
+
+ /* read in public key */
+ if (PKLen > 0) {
+ temp->pub.buffer = (byte*)XMALLOC(temp->pub.length,
+ ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ XMEMCPY(temp->pub.buffer, input + offset_len, temp->pub.length);
+ offset_len += PKLen;
+ }
+ else {
+ PK = NULL;
+ }
+
+ /* use own key when adding to extensions list for sending reply */
+ PKLen = 0;
+ PK = TLSX_QSHKeyFind_Pub(ssl->QSH_Key, &PKLen, temp->name);
+ r = TLSX_UseQSHScheme(&ssl->extensions, temp->name, PK, PKLen,
+ ssl->heap);
+
+ /* store peers key */
+ ssl->peerQSHKeyPresent = 1;
+ if (TLSX_AddQSHKey(&ssl->peerQSHKey, temp) != 0)
+ return MEMORY_E;
+
+ if (temp->pub.length == 0) {
+ XFREE(temp, ssl->heap, DYNAMIC_TYPE_TLSX);
+ }
+
+ if (r != WOLFSSL_SUCCESS) {return r;} /* throw error */
+
+ numKeys--;
+ }
+
+ /* reply to a QSH extension sent from client */
+ if (isRequest) {
+ TLSX_SetResponse(ssl, TLSX_QUANTUM_SAFE_HYBRID);
+ /* only use schemes we have key generated for -- free the rest */
+ TLSX_QSHAgreement(&ssl->extensions, ssl->heap);
+ }
+
+ return 0;
+}
+
+
+/* Used for parsing in QSHCipher structs on Key Exchange */
+int TLSX_QSHCipher_Parse(WOLFSSL* ssl, const byte* input, word16 length,
+ byte isServer)
+{
+ QSHKey* key;
+ word16 Max_Secret_Len = 48;
+ word16 offset = 0;
+ word16 offset_len = 0;
+ word32 offset_pk = 0;
+ word16 name = 0;
+ word16 secretLen = 0;
+ byte* secret = NULL;
+ word16 buffLen = 0;
+ byte buff[145]; /* size enough for 3 secrets */
+ buffer* buf;
+
+ /* pointer to location where secret should be stored */
+ if (isServer) {
+ buf = ssl->QSH_secret->CliSi;
+ }
+ else {
+ buf = ssl->QSH_secret->SerSi;
+ }
+
+ offset_pk = ((input[offset_len] << 16) & 0xFF0000) |
+ (((input[offset_len + 1]) << 8) & 0xFF00) |
+ (input[offset_len + 2] & 0xFF);
+ offset_len += OPAQUE24_LEN;
+
+ /* validating extension list length -- check if trying to read over edge
+ of buffer */
+ if (length < (offset_pk + OPAQUE24_LEN)) {
+ return BUFFER_ERROR;
+ }
+
+ /* QSHCipherList struct */
+ offset_pk += offset_len;
+ while (offset_len < offset_pk) {
+
+ /* scheme id */
+ ato16(input + offset_len, &name);
+ offset_len += OPAQUE16_LEN;
+
+ /* public key length */
+ ato16(input + offset_len, &secretLen);
+ offset_len += OPAQUE16_LEN;
+
+ /* read in public key */
+ if (secretLen > 0) {
+ secret = (byte*)(input + offset_len);
+ offset_len += secretLen;
+ }
+ else {
+ secret = NULL;
+ }
+
+ /* no secret sent */
+ if (secret == NULL)
+ continue;
+
+ /* find corresponding key */
+ key = ssl->QSH_Key;
+ while (key) {
+ if (key->name == name)
+ break;
+ else
+ key = (QSHKey*)key->next;
+ }
+
+ /* if we do not have the key than there was a big issue negotiation */
+ if (key == NULL) {
+ WOLFSSL_MSG("key was null for decryption!!!\n");
+ return MEMORY_E;
+ }
+
+ /* Decrypt sent secret */
+ buffLen = Max_Secret_Len;
+ QSH_Decrypt(key, secret, secretLen, buff + offset, &buffLen);
+ offset += buffLen;
+ }
+
+ /* allocate memory for buffer */
+ buf->length = offset;
+ buf->buffer = (byte*)XMALLOC(offset, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ if (buf->buffer == NULL)
+ return MEMORY_E;
+
+ /* store secrets */
+ XMEMCPY(buf->buffer, buff, offset);
+ ForceZero(buff, offset);
+
+ return offset_len;
+}
+
+
+/* return 1 on success */
+int TLSX_ValidateQSHScheme(TLSX** extensions, word16 theirs) {
+ TLSX* extension = TLSX_Find(*extensions, TLSX_QUANTUM_SAFE_HYBRID);
+ QSHScheme* format = NULL;
+
+ /* if no extension is sent then do not use QSH */
+ if (!extension) {
+ WOLFSSL_MSG("No QSH Extension");
+ return 0;
+ }
+
+ for (format = (QSHScheme*)extension->data; format; format = format->next) {
+ if (format->name == theirs) {
+ WOLFSSL_MSG("Found Matching QSH Scheme");
+ return 1; /* have QSH */
+ }
+ }
+
+ return 0;
+}
+#endif /* NO_WOLFSSL_SERVER */
+
+/* test if the QSH Scheme is implemented
+ return 1 if yes 0 if no */
+static int TLSX_HaveQSHScheme(word16 name)
+{
+ switch(name) {
+ #ifdef HAVE_NTRU
+ case WOLFSSL_NTRU_EESS439:
+ case WOLFSSL_NTRU_EESS593:
+ case WOLFSSL_NTRU_EESS743:
+ return 1;
+ #endif
+ case WOLFSSL_LWE_XXX:
+ case WOLFSSL_HFE_XXX:
+ return 0; /* not supported yet */
+
+ default:
+ return 0;
+ }
+}
+
+
+/* Add a QSHScheme struct to list of usable ones */
+int TLSX_UseQSHScheme(TLSX** extensions, word16 name, byte* pKey, word16 pkeySz,
+ void* heap)
+{
+ TLSX* extension = NULL;
+ QSHScheme* format = NULL;
+ int ret = 0;
+
+ /* sanity check */
+ if (extensions == NULL || (pKey == NULL && pkeySz != 0))
+ return BAD_FUNC_ARG;
+
+ extension = TLSX_Find(*extensions, TLSX_QUANTUM_SAFE_HYBRID);
+
+ /* if scheme is implemented than add */
+ if (TLSX_HaveQSHScheme(name)) {
+ if ((ret = TLSX_QSH_Append(&format, name, pKey, pkeySz)) != 0)
+ return ret;
+
+ extension = TLSX_Find(*extensions, TLSX_QUANTUM_SAFE_HYBRID);
+ if (!extension) {
+ if ((ret = TLSX_Push(extensions, TLSX_QUANTUM_SAFE_HYBRID, format,
+ heap)) != 0) {
+ XFREE(format, 0, DYNAMIC_TYPE_TLSX);
+ return ret;
+ }
+ }
+ else {
+ /* push new QSH object to extension data. */
+ format->next = (QSHScheme*)extension->data;
+ extension->data = (void*)format;
+
+ /* look for another format of the same name to remove (replacement) */
+ do {
+ if (format->next && (format->next->name == name)) {
+ QSHScheme* next = format->next;
+
+ format->next = next->next;
+ XFREE(next, 0, DYNAMIC_TYPE_TLSX);
+
+ break;
+ }
+ } while ((format = format->next));
+ }
+ }
+ return WOLFSSL_SUCCESS;
+}
+
+#define QSH_FREE_ALL TLSX_QSH_FreeAll
+#define QSH_VALIDATE_REQUEST TLSX_QSH_ValidateRequest
+
+#ifndef NO_WOLFSSL_CLIENT
+#define QSH_GET_SIZE TLSX_QSH_GetSize
+#define QSH_WRITE TLSX_QSH_Write
+#else
+#define QSH_GET_SIZE(list, a) 0
+#define QSH_WRITE(a, b) 0
+#endif
+
+#ifndef NO_WOLFSSL_SERVER
+#define QSH_PARSE TLSX_QSH_Parse
+#else
+#define QSH_PARSE(a, b, c, d) 0
+#endif
+
+#define QSHPK_WRITE TLSX_QSHPK_Write
+#define QSH_SERREQ TLSX_QSH_SerPKReq
+#else
+
+#define QSH_FREE_ALL(list, heap)
+#define QSH_GET_SIZE(list, a) 0
+#define QSH_WRITE(a, b) 0
+#define QSH_PARSE(a, b, c, d) 0
+#define QSHPK_WRITE(a, b) 0
+#define QSH_SERREQ(a, b) 0
+#define QSH_VALIDATE_REQUEST(a, b)
+
+#endif /* HAVE_QSH */
+
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+/******************************************************************************/
+/* Encrypt-then-MAC */
+/******************************************************************************/
+
+#ifndef WOLFSSL_NO_TLS12
+static int TLSX_EncryptThenMac_Use(WOLFSSL* ssl);
+
+/**
+ * Get the size of the Encrypt-Then-MAC extension.
+ *
+ * msgType Type of message to put extension into.
+ * pSz Size of extension data.
+ * return SANITY_MSG_E when the message is not allowed to have extension and
+ * 0 otherwise.
+ */
+static int TLSX_EncryptThenMac_GetSize(byte msgType, word16* pSz)
+{
+ (void)pSz;
+
+ if (msgType != client_hello && msgType != server_hello) {
+ return SANITY_MSG_E;
+ }
+
+ /* Empty extension */
+
+ return 0;
+}
+
+/**
+ * Write the Encrypt-Then-MAC extension.
+ *
+ * data Unused
+ * output Extension data buffer. Unused.
+ * msgType Type of message to put extension into.
+ * pSz Size of extension data.
+ * return SANITY_MSG_E when the message is not allowed to have extension and
+ * 0 otherwise.
+ */
+static int TLSX_EncryptThenMac_Write(void* data, byte* output, byte msgType,
+ word16* pSz)
+{
+ (void)data;
+ (void)output;
+ (void)pSz;
+
+ if (msgType != client_hello && msgType != server_hello) {
+ return SANITY_MSG_E;
+ }
+
+ /* Empty extension */
+
+ return 0;
+}
+
+/**
+ * Parse the Encrypt-Then-MAC extension.
+ *
+ * ssl SSL object
+ * input Extension data buffer.
+ * length Length of this extension's data.
+ * msgType Type of message to extension appeared in.
+ * return SANITY_MSG_E when the message is not allowed to have extension,
+ * BUFFER_ERROR when the extension's data is invalid,
+ * MEMORY_E when unable to allocate memory and
+ * 0 otherwise.
+ */
+static int TLSX_EncryptThenMac_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ int ret;
+
+ (void)input;
+
+ if (msgType != client_hello && msgType != server_hello) {
+ return SANITY_MSG_E;
+ }
+
+ /* Empty extension */
+ if (length != 0)
+ return BUFFER_ERROR;
+
+ if (msgType == client_hello) {
+ /* Check the user hasn't disallowed use of Encrypt-Then-Mac. */
+ if (!ssl->options.disallowEncThenMac) {
+ ssl->options.encThenMac = 1;
+ /* Set the extension reply. */
+ ret = TLSX_EncryptThenMac_Use(ssl);
+ if (ret != 0)
+ return ret;
+ TLSX_SetResponse(ssl, TLSX_ENCRYPT_THEN_MAC);
+ }
+ return 0;
+ }
+
+ /* Server Hello */
+ if (ssl->options.disallowEncThenMac)
+ return SANITY_MSG_E;
+
+ ssl->options.encThenMac = 1;
+ return 0;
+
+}
+
+/**
+ * Add the Encrypt-Then-MAC extension to list.
+ *
+ * ssl SSL object
+ * return MEMORY_E when unable to allocate memory and 0 otherwise.
+ */
+static int TLSX_EncryptThenMac_Use(WOLFSSL* ssl)
+{
+ int ret = 0;
+ TLSX* extension;
+
+ /* Find the Encrypt-Then-Mac extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_ENCRYPT_THEN_MAC);
+ if (extension == NULL) {
+ /* Push new Encrypt-Then-Mac extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_ENCRYPT_THEN_MAC, NULL,
+ ssl->heap);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+#define ETM_GET_SIZE TLSX_EncryptThenMac_GetSize
+#define ETM_WRITE TLSX_EncryptThenMac_Write
+#define ETM_PARSE TLSX_EncryptThenMac_Parse
+
+#else
+
+#define ETM_GET_SIZE(a, b) 0
+#define ETM_WRITE(a, b, c, d) 0
+#define ETM_PARSE(a, b, c, d) 0
+
+#endif /* !WOLFSSL_NO_TLS12 */
+
+#endif /* HAVE_ENCRYPT_THEN_MAC && !WOLFSSL_AEAD_ONLY */
+
+/******************************************************************************/
+/* Supported Versions */
+/******************************************************************************/
+
+#ifdef WOLFSSL_TLS13
+/* Return the size of the SupportedVersions extension's data.
+ *
+ * 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 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 = 0;
+
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1_3) == 0)
+ #endif
+ cnt++;
+
+ if (ssl->options.downgrade) {
+#ifndef WOLFSSL_NO_TLS12
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1_2) == 0)
+ #endif
+ cnt++;
+#endif
+
+#ifndef NO_OLD_TLS
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1_1) == 0)
+ #endif
+ cnt++;
+ #ifdef WOLFSSL_ALLOW_TLSV10
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1) == 0)
+ #endif
+ cnt++;
+ #endif
+#endif
+ }
+
+ *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;
+}
+
+/* Writes the SupportedVersions extension into the buffer.
+ *
+ * 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 int TLSX_SupportedVersions_Write(void* data, byte* output,
+ byte msgType, word16* pSz)
+{
+ WOLFSSL* ssl = (WOLFSSL*)data;
+ byte major;
+ byte* cnt;
+
+ if (msgType == client_hello) {
+ major = ssl->ctx->method->version.major;
+
+
+ cnt = output++;
+ *cnt = 0;
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1_3) == 0)
+ #endif
+ {
+ *cnt += OPAQUE16_LEN;
+#ifdef WOLFSSL_TLS13_DRAFT
+ /* The TLS draft major number. */
+ *(output++) = TLS_DRAFT_MAJOR;
+ /* Version of draft supported. */
+ *(output++) = TLS_DRAFT_MINOR;
+#else
+ *(output++) = major;
+ *(output++) = (byte)TLSv1_3_MINOR;
+#endif
+ }
+ if (ssl->options.downgrade) {
+#ifndef WOLFSSL_NO_TLS12
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1_2) == 0)
+ #endif
+ {
+ *cnt += OPAQUE16_LEN;
+ *(output++) = major;
+ *(output++) = (byte)TLSv1_2_MINOR;
+ }
+#endif
+
+#ifndef NO_OLD_TLS
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1_1) == 0)
+ #endif
+ {
+ *cnt += OPAQUE16_LEN;
+ *(output++) = major;
+ *(output++) = (byte)TLSv1_1_MINOR;
+ }
+ #ifdef WOLFSSL_ALLOW_TLSV10
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1) == 0)
+ #endif
+ {
+ *cnt += OPAQUE16_LEN;
+ *(output++) = major;
+ *(output++) = (byte)TLSv1_MINOR;
+ }
+ #endif
+#endif
+ }
+
+ *pSz += (word16)(OPAQUE8_LEN + *cnt);
+ }
+#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;
+}
+
+/* Parse the SupportedVersions extension.
+ *
+ * ssl The SSL/TLS object.
+ * 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, byte msgType)
+{
+ ProtocolVersion pv = ssl->ctx->method->version;
+ int i;
+ int len;
+ byte major, minor;
+ int newMinor = 0;
+ int set = 0;
+
+ if (msgType == client_hello) {
+ /* Must contain a length and at least one version. */
+ if (length < OPAQUE8_LEN + OPAQUE16_LEN || (length & 1) != 1)
+ return BUFFER_ERROR;
+
+ len = *input;
+
+ /* Protocol version array must fill rest of data. */
+ if (length != (word16)OPAQUE8_LEN + len)
+ return BUFFER_ERROR;
+
+ input++;
+
+ /* Find first match. */
+ for (i = 0; i < len; i += OPAQUE16_LEN) {
+ major = input[i];
+ minor = input[i + OPAQUE8_LEN];
+
+#ifdef WOLFSSL_TLS13_DRAFT
+ if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) {
+ major = SSLv3_MAJOR;
+ minor = TLSv1_3_MINOR;
+ }
+#else
+ if (major == TLS_DRAFT_MAJOR)
+ continue;
+#endif
+
+ if (major != pv.major)
+ continue;
+
+ /* No upgrade allowed. */
+ if (minor > ssl->version.minor)
+ continue;
+ /* Check downgrade. */
+ if (minor < ssl->version.minor) {
+ if (!ssl->options.downgrade)
+ continue;
+
+ if (minor < ssl->options.minDowngrade)
+ continue;
+
+ 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, ssl,
+ ssl->heap);
+#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;
+
+ set = 1;
+ }
+ if (!set) {
+ #ifdef WOLFSSL_MYSQL_COMPATIBLE
+ SendAlert(ssl, alert_fatal, wc_protocol_version);
+ #else
+ SendAlert(ssl, alert_fatal, protocol_version);
+ #endif
+ return VERSION_ERROR;
+ }
+ }
+#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;
+}
+
+/* Sets a new SupportedVersions 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_SetSupportedVersions(TLSX** extensions, const void* data,
+ void* heap)
+{
+ if (extensions == NULL || data == NULL)
+ return BAD_FUNC_ARG;
+
+ return TLSX_Push(extensions, TLSX_SUPPORTED_VERSIONS, (void *)data, heap);
+}
+
+#define SV_GET_SIZE TLSX_SupportedVersions_GetSize
+#define SV_WRITE TLSX_SupportedVersions_Write
+#define SV_PARSE TLSX_SupportedVersions_Parse
+
+#else
+
+#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 */
+
+#if defined(WOLFSSL_TLS13)
+
+/******************************************************************************/
+/* Cookie */
+/******************************************************************************/
+
+/* Free the cookie data.
+ *
+ * cookie Cookie data.
+ * heap The heap used for allocation.
+ */
+static void TLSX_Cookie_FreeAll(Cookie* cookie, void* heap)
+{
+ (void)heap;
+
+ if (cookie != NULL)
+ XFREE(cookie, heap, DYNAMIC_TYPE_TLSX);
+}
+
+/* Get the size of the encoded Cookie extension.
+ * In messages: ClientHello and HelloRetryRequest.
+ *
+ * cookie The cookie to write.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded Cookie extension.
+ */
+static int TLSX_Cookie_GetSize(Cookie* cookie, byte msgType, word16* pSz)
+{
+ if (msgType == client_hello || msgType == hello_retry_request)
+ *pSz += OPAQUE16_LEN + cookie->len;
+ else
+ return SANITY_MSG_E;
+ return 0;
+}
+
+/* Writes the Cookie extension into the output buffer.
+ * Assumes that the the output buffer is big enough to hold data.
+ * In messages: ClientHello and HelloRetryRequest.
+ *
+ * cookie The cookie to write.
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+static int TLSX_Cookie_Write(Cookie* cookie, byte* output, byte msgType,
+ word16* pSz)
+{
+ if (msgType == client_hello || msgType == hello_retry_request) {
+ c16toa(cookie->len, output);
+ output += OPAQUE16_LEN;
+ XMEMCPY(output, &cookie->data, cookie->len);
+ *pSz += OPAQUE16_LEN + cookie->len;
+ }
+ else
+ return SANITY_MSG_E;
+ return 0;
+}
+
+/* Parse the Cookie extension.
+ * In messages: ClientHello and HelloRetryRequest.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_Cookie_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ word16 len;
+ word16 idx = 0;
+ TLSX* extension;
+ Cookie* cookie;
+
+ if (msgType != client_hello && msgType != hello_retry_request)
+ return SANITY_MSG_E;
+
+ /* Message contains length and Cookie which must be at least one byte
+ * in length.
+ */
+ if (length < OPAQUE16_LEN + 1)
+ return BUFFER_E;
+ ato16(input + idx, &len);
+ idx += OPAQUE16_LEN;
+ if (length - idx != len)
+ return BUFFER_E;
+
+ if (msgType == hello_retry_request)
+ return TLSX_Cookie_Use(ssl, input + idx, len, NULL, 0, 0);
+
+ /* client_hello */
+ extension = TLSX_Find(ssl->extensions, TLSX_COOKIE);
+ if (extension == NULL)
+ return HRR_COOKIE_ERROR;
+
+ cookie = (Cookie*)extension->data;
+ if (cookie->len != len || XMEMCMP(&cookie->data, input + idx, len) != 0)
+ return HRR_COOKIE_ERROR;
+
+ /* Request seen. */
+ extension->resp = 0;
+
+ return 0;
+}
+
+/* Use the data to create a new Cookie object in the extensions.
+ *
+ * ssl SSL/TLS object.
+ * data Cookie data.
+ * len Length of cookie data in bytes.
+ * mac MAC data.
+ * macSz Length of MAC data in bytes.
+ * resp Indicates the extension will go into a response (HelloRetryRequest).
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_Cookie_Use(WOLFSSL* ssl, byte* data, word16 len, byte* mac,
+ byte macSz, int resp)
+{
+ int ret = 0;
+ TLSX* extension;
+ Cookie* cookie;
+
+ /* Find the cookie extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_COOKIE);
+ if (extension == NULL) {
+ /* Push new cookie extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_COOKIE, NULL, ssl->heap);
+ if (ret != 0)
+ return ret;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_COOKIE);
+ if (extension == NULL)
+ return MEMORY_E;
+ }
+
+ /* The Cookie structure has one byte for cookie data already. */
+ cookie = (Cookie*)XMALLOC(sizeof(Cookie) + len + macSz - 1, ssl->heap,
+ DYNAMIC_TYPE_TLSX);
+ if (cookie == NULL)
+ return MEMORY_E;
+
+ cookie->len = len + macSz;
+ XMEMCPY(&cookie->data, data, len);
+ if (mac != NULL)
+ XMEMCPY(&cookie->data + len, mac, macSz);
+
+ extension->data = (void*)cookie;
+ extension->resp = (byte)resp;
+
+ return 0;
+}
+
+#define CKE_FREE_ALL TLSX_Cookie_FreeAll
+#define CKE_GET_SIZE TLSX_Cookie_GetSize
+#define CKE_WRITE TLSX_Cookie_Write
+#define CKE_PARSE TLSX_Cookie_Parse
+
+#else
+
+#define CKE_FREE_ALL(a, b) 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
+
+#endif
+#if !defined(WOLFSSL_NO_SIGALG)
+/******************************************************************************/
+/* Signature Algorithms */
+/******************************************************************************/
+
+/* 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_SignatureAlgorithms_GetSize(void* data)
+{
+ WOLFSSL* ssl = (WOLFSSL*)data;
+
+ return OPAQUE16_LEN + ssl->suites->hashSigAlgoSz;
+}
+
+/* Creates a bit string of supported hash algorithms with RSA PSS.
+ * The bit string is used when determining which signature algorithm to use
+ * when creating the CertificateVerify message.
+ * Note: Valid data has an even length as each signature algorithm is two bytes.
+ *
+ * ssl The SSL/TLS object.
+ * input The buffer with the list of supported signature algorithms.
+ * length The length of the list in bytes.
+ * returns 0 on success, BUFFER_ERROR when the length is not even.
+ */
+static int TLSX_SignatureAlgorithms_MapPss(WOLFSSL *ssl, byte* input,
+ word16 length)
+{
+ word16 i;
+
+ if ((length & 1) == 1)
+ return BUFFER_ERROR;
+
+ ssl->pssAlgo = 0;
+ for (i = 0; i < length; i += 2) {
+ if (input[i] == rsa_pss_sa_algo && input[i + 1] <= sha512_mac)
+ ssl->pssAlgo |= 1 << input[i + 1];
+ #ifdef WOLFSSL_TLS13
+ if (input[i] == rsa_pss_sa_algo && input[i + 1] >= pss_sha256 &&
+ input[i + 1] <= pss_sha512) {
+ ssl->pssAlgo |= 1 << input[i + 1];
+ }
+ #endif
+ }
+
+ return 0;
+}
+
+/* Writes the SignatureAlgorithms 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_SignatureAlgorithms_Write(void* data, byte* output)
+{
+ WOLFSSL* ssl = (WOLFSSL*)data;
+
+ c16toa(ssl->suites->hashSigAlgoSz, output);
+ XMEMCPY(output + OPAQUE16_LEN, ssl->suites->hashSigAlgo,
+ ssl->suites->hashSigAlgoSz);
+
+ TLSX_SignatureAlgorithms_MapPss(ssl, output + OPAQUE16_LEN,
+ ssl->suites->hashSigAlgoSz);
+
+ return OPAQUE16_LEN + ssl->suites->hashSigAlgoSz;
+}
+
+/* Parse the SignatureAlgorithms 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_SignatureAlgorithms_Parse(WOLFSSL *ssl, byte* input,
+ word16 length, byte isRequest, Suites* suites)
+{
+ 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 */
+ 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 SignatureAlgorithms 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_SetSignatureAlgorithms(TLSX** extensions, const void* data,
+ void* heap)
+{
+ if (extensions == NULL)
+ return BAD_FUNC_ARG;
+
+ return TLSX_Push(extensions, TLSX_SIGNATURE_ALGORITHMS, (void *)data, heap);
+}
+
+#define SA_GET_SIZE TLSX_SignatureAlgorithms_GetSize
+#define SA_WRITE TLSX_SignatureAlgorithms_Write
+#define SA_PARSE TLSX_SignatureAlgorithms_Parse
+#endif
+/******************************************************************************/
+/* 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 */
+
+
+/******************************************************************************/
+/* Key Share */
+/******************************************************************************/
+
+#ifdef WOLFSSL_TLS13
+/* Create a key share entry using named Diffie-Hellman 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_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse)
+{
+ int ret;
+#ifndef NO_DH
+ byte* keyData;
+ void* key = NULL;
+ word32 keySz;
+ word32 dataSz;
+ const DhParams* params;
+#ifdef WOLFSSL_SMALL_STACK
+ DhKey* dhKey = NULL;
+#else
+ DhKey dhKey[1];
+#endif
+
+ /* TODO: [TLS13] The key size should come from wolfcrypt. */
+ /* Pick the parameters from the named group. */
+ switch (kse->group) {
+ #ifdef HAVE_FFDHE_2048
+ case WOLFSSL_FFDHE_2048:
+ params = wc_Dh_ffdhe2048_Get();
+ keySz = 29;
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_3072
+ case WOLFSSL_FFDHE_3072:
+ params = wc_Dh_ffdhe3072_Get();
+ keySz = 34;
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_4096
+ case WOLFSSL_FFDHE_4096:
+ params = wc_Dh_ffdhe4096_Get();
+ keySz = 39;
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_6144
+ case WOLFSSL_FFDHE_6144:
+ params = wc_Dh_ffdhe6144_Get();
+ keySz = 46;
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_8192
+ case WOLFSSL_FFDHE_8192:
+ params = wc_Dh_ffdhe8192_Get();
+ keySz = 52;
+ break;
+ #endif
+ default:
+ return BAD_FUNC_ARG;
+ }
+
+#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. */
+ dataSz = params->p_len;
+ keyData = (byte*)XMALLOC(dataSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ if (keyData == NULL) {
+ ret = MEMORY_E;
+ goto end;
+ }
+ /* Allocate space for the private key. */
+ key = (byte*)XMALLOC(keySz, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ if (key == NULL) {
+ ret = MEMORY_E;
+ goto end;
+ }
+
+ /* Set key */
+ ret = wc_DhSetKey(dhKey,
+ (byte*)params->p, params->p_len,
+ (byte*)params->g, params->g_len);
+ if (ret != 0)
+ goto end;
+
+ /* Generate a new key pair. */
+ 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);
+ }
+#endif
+ if (ret != 0)
+ goto end;
+
+ if (params->p_len != dataSz) {
+ /* Pad the front of the key data with zeros. */
+ XMEMMOVE(keyData + params->p_len - dataSz, keyData, dataSz);
+ XMEMSET(keyData, 0, params->p_len - dataSz);
+ }
+
+ kse->pubKey = keyData;
+ kse->pubKeyLen = params->p_len;
+ kse->key = key;
+ kse->keyLen = keySz;
+
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Public DH Key");
+ WOLFSSL_BUFFER(keyData, params->p_len);
+#endif
+
+end:
+
+ wc_FreeDhKey(dhKey);
+#ifdef WOLFSSL_SMALL_STACK
+ XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+#endif
+
+ if (ret != 0) {
+ /* Data owned by key share entry otherwise. */
+ if (keyData != NULL)
+ XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ if (key != NULL)
+ XFREE(key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ }
+#else
+ (void)ssl;
+ (void)kse;
+
+ ret = NOT_COMPILED_IN;
+#endif
+
+ return ret;
+}
+
+/* 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 X448 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_GenX448Key(WOLFSSL *ssl, KeyShareEntry* kse)
+{
+ int ret;
+#ifdef HAVE_CURVE448
+ byte* keyData = NULL;
+ word32 dataSize = CURVE448_KEY_SIZE;
+ curve448_key* key;
+
+ /* Allocate an ECC key to hold private key. */
+ key = (curve448_key*)XMALLOC(sizeof(curve448_key), ssl->heap,
+ DYNAMIC_TYPE_PRIVATE_KEY);
+ if (key == NULL) {
+ WOLFSSL_MSG("EccTempKey Memory error");
+ return MEMORY_E;
+ }
+
+ /* Make an ECC key. */
+ ret = wc_curve448_init(key);
+ if (ret != 0)
+ goto end;
+ ret = wc_curve448_make_key(ssl->rng, CURVE448_KEY_SIZE, key);
+ if (ret != 0)
+ goto end;
+
+ /* Allocate space for the public key. */
+ keyData = (byte*)XMALLOC(CURVE448_KEY_SIZE, 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_curve448_export_public_ex(key, keyData, &dataSize,
+ EC448_LITTLE_ENDIAN) != 0) {
+ ret = ECC_EXPORT_ERROR;
+ goto end;
+ }
+
+ kse->pubKey = keyData;
+ kse->pubKeyLen = CURVE448_KEY_SIZE;
+ kse->key = key;
+
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Public Curve448 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_curve448_free(key);
+ XFREE(key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ }
+#else
+ (void)ssl;
+ (void)kse;
+
+ ret = NOT_COMPILED_IN;
+#endif /* HAVE_CURVE448 */
+
+ return ret;
+}
+
+/* Create a key share entry using named elliptic curve 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_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse)
+{
+ int ret;
+#ifdef HAVE_ECC
+ byte* keyData = NULL;
+ word32 dataSize;
+ byte* keyPtr = NULL;
+ word32 keySize;
+ ecc_key* eccKey;
+ word16 curveId;
+
+ /* TODO: [TLS13] The key sizes should come from wolfcrypt. */
+ /* Translate named group to a curve id. */
+ switch (kse->group) {
+ #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP256R1:
+ curveId = ECC_SECP256R1;
+ keySize = 32;
+ dataSize = keySize * 2 + 1;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP384R1:
+ curveId = ECC_SECP384R1;
+ keySize = 48;
+ dataSize = keySize * 2 + 1;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP521R1:
+ curveId = ECC_SECP521R1;
+ keySize = 66;
+ dataSize = keySize * 2 + 1;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #ifdef HAVE_X448
+ case WOLFSSL_ECC_X448:
+ curveId = ECC_X448;
+ dataSize = keySize = 56;
+ break;
+ #endif
+ default:
+ return BAD_FUNC_ARG;
+ }
+
+ /* Allocate an ECC key to hold private key. */
+ keyPtr = (byte*)XMALLOC(sizeof(ecc_key), ssl->heap,
+ DYNAMIC_TYPE_PRIVATE_KEY);
+ if (keyPtr == NULL) {
+ WOLFSSL_MSG("EccTempKey Memory error");
+ return MEMORY_E;
+ }
+ eccKey = (ecc_key*)keyPtr;
+
+ /* Make an ECC key. */
+ ret = wc_ecc_init_ex(eccKey, ssl->heap, ssl->devId);
+ if (ret != 0)
+ goto end;
+ ret = wc_ecc_make_key_ex(ssl->rng, keySize, eccKey, curveId);
+#ifdef WOLFSSL_ASYNC_CRYPT
+ /* TODO: Make this function non-blocking */
+ if (ret == WC_PENDING_E) {
+ ret = wc_AsyncWait(ret, &eccKey->asyncDev, WC_ASYNC_FLAG_NONE);
+ }
+#endif
+ 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_ecc_export_x963(eccKey, keyData, &dataSize) != 0) {
+ ret = ECC_EXPORT_ERROR;
+ goto end;
+ }
+
+ kse->pubKey = keyData;
+ kse->pubKeyLen = dataSize;
+ kse->key = keyPtr;
+
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Public ECC Key");
+ WOLFSSL_BUFFER(keyData, dataSize);
+#endif
+
+end:
+ if (ret != 0) {
+ /* Data owned by key share entry otherwise. */
+ if (keyPtr != NULL)
+ XFREE(keyPtr, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ if (keyData != NULL)
+ XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ }
+#else
+ (void)ssl;
+ (void)kse;
+
+ ret = NOT_COMPILED_IN;
+#endif /* HAVE_ECC */
+
+ return ret;
+}
+
+/* Generate a secret/key using the key share entry.
+ *
+ * ssl The SSL/TLS object.
+ * kse The key share entry holding peer data.
+ */
+static int TLSX_KeyShare_GenKey(WOLFSSL *ssl, KeyShareEntry *kse)
+{
+ /* 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);
+ if (kse->group == WOLFSSL_ECC_X25519)
+ return TLSX_KeyShare_GenX25519Key(ssl, kse);
+ if (kse->group == WOLFSSL_ECC_X448)
+ return TLSX_KeyShare_GenX448Key(ssl, kse);
+ return TLSX_KeyShare_GenEccKey(ssl, kse);
+}
+
+/* Free the key share dynamic data.
+ *
+ * list The linked list of key share entry objects.
+ * heap The heap used for allocation.
+ */
+static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap)
+{
+ KeyShareEntry* current;
+
+ while ((current = list) != NULL) {
+ list = current->next;
+ if ((current->group & NAMED_DH_MASK) == 0) {
+ if (current->group == WOLFSSL_ECC_X25519) {
+#ifdef HAVE_CURVE25519
+ wc_curve25519_free((curve25519_key*)current->key);
+#endif
+ }
+ else if (current->group == WOLFSSL_ECC_X448) {
+#ifdef HAVE_CURVE448
+ wc_curve448_free((curve448_key*)current->key);
+#endif
+ }
+ else {
+#ifdef HAVE_ECC
+ wc_ecc_free((ecc_key*)(current->key));
+#endif
+ }
+ }
+ 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);
+ }
+
+ (void)heap;
+}
+
+/* Get the size of the encoded key share extension.
+ *
+ * list The linked list of key share extensions.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded key share extension.
+ */
+static word16 TLSX_KeyShare_GetSize(KeyShareEntry* list, byte msgType)
+{
+ word16 len = 0;
+ byte isRequest = (msgType == client_hello);
+ KeyShareEntry* current;
+
+ /* The named group the server wants to use. */
+ if (msgType == hello_retry_request)
+ return OPAQUE16_LEN;
+
+ /* List of key exchange groups. */
+ if (isRequest)
+ len += OPAQUE16_LEN;
+ while ((current = list) != NULL) {
+ list = current->next;
+
+ if (!isRequest && current->key == NULL)
+ continue;
+
+ len += KE_GROUP_LEN + OPAQUE16_LEN + current->pubKeyLen;
+ }
+
+ return len;
+}
+
+/* Writes the key share extension into the output buffer.
+ * Assumes that the the output buffer is big enough to hold data.
+ *
+ * list The linked list of key share entries.
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+static word16 TLSX_KeyShare_Write(KeyShareEntry* list, byte* output,
+ byte msgType)
+{
+ word16 i = 0;
+ byte isRequest = (msgType == client_hello);
+ KeyShareEntry* current;
+
+ if (msgType == hello_retry_request) {
+ c16toa(list->group, output);
+ return OPAQUE16_LEN;
+ }
+
+ /* ClientHello has a list but ServerHello is only the chosen. */
+ if (isRequest)
+ i += OPAQUE16_LEN;
+
+ /* Write out all in the list. */
+ while ((current = list) != NULL) {
+ list = current->next;
+
+ if (!isRequest && current->key == NULL)
+ continue;
+
+ c16toa(current->group, &output[i]);
+ i += KE_GROUP_LEN;
+ c16toa((word16)(current->pubKeyLen), &output[i]);
+ i += OPAQUE16_LEN;
+ XMEMCPY(&output[i], current->pubKey, current->pubKeyLen);
+ i += (word16)current->pubKeyLen;
+ }
+ /* Write the length of the list if required. */
+ if (isRequest)
+ c16toa(i - OPAQUE16_LEN, output);
+
+ return i;
+}
+
+/* Process the DH 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_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
+{
+#ifndef NO_DH
+ int ret;
+ const DhParams* params;
+#ifdef WOLFSSL_SMALL_STACK
+ DhKey* dhKey = NULL;
+#else
+ DhKey dhKey[1];
+#endif
+
+ switch (keyShareEntry->group) {
+ #ifdef HAVE_FFDHE_2048
+ case WOLFSSL_FFDHE_2048:
+ params = wc_Dh_ffdhe2048_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_3072
+ case WOLFSSL_FFDHE_3072:
+ params = wc_Dh_ffdhe3072_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_4096
+ case WOLFSSL_FFDHE_4096:
+ params = wc_Dh_ffdhe4096_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_6144
+ case WOLFSSL_FFDHE_6144:
+ params = wc_Dh_ffdhe6144_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_8192
+ case WOLFSSL_FFDHE_8192:
+ params = wc_Dh_ffdhe8192_Get();
+ break;
+ #endif
+ default:
+ return PEER_KEY_ERROR;
+ }
+
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Peer DH Key");
+ WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
+#endif
+
+#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;
+ }
+
+ /* Derive secret from private key and peer's public key. */
+ ret = wc_DhAgree(dhKey,
+ ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz,
+ (const byte*)keyShareEntry->key, keyShareEntry->keyLen,
+ keyShareEntry->ke, keyShareEntry->keLen);
+#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);
+ }
+#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;
+ }
+
+ ssl->options.dhKeySz = 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;
+#else
+ (void)ssl;
+ (void)keyShareEntry;
+ 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
+
+ if (wc_curve25519_check_public(keyShareEntry->ke, keyShareEntry->keLen,
+ EC25519_LITTLE_ENDIAN) != 0) {
+ ret = ECC_PEERKEY_ERROR;
+ }
+
+ if (ret == 0) {
+ if (wc_curve25519_import_public_ex(keyShareEntry->ke,
+ keyShareEntry->keLen, peerX25519Key,
+ EC25519_LITTLE_ENDIAN) != 0) {
+ ret = ECC_PEERKEY_ERROR;
+ }
+ }
+
+ if (ret == 0) {
+ 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;
+}
+
+/* Process the X448 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_ProcessX448(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
+{
+ int ret;
+
+#ifdef HAVE_CURVE448
+ curve448_key* key = (curve448_key*)keyShareEntry->key;
+ curve448_key* peerX448Key;
+
+#ifdef HAVE_ECC
+ if (ssl->peerEccKey != NULL) {
+ wc_ecc_free(ssl->peerEccKey);
+ ssl->peerEccKey = NULL;
+ }
+#endif
+
+ peerX448Key = (curve448_key*)XMALLOC(sizeof(curve448_key), ssl->heap,
+ DYNAMIC_TYPE_TLSX);
+ if (peerX448Key == NULL) {
+ WOLFSSL_MSG("PeerEccKey Memory error");
+ return MEMORY_ERROR;
+ }
+ ret = wc_curve448_init(peerX448Key);
+ if (ret != 0) {
+ XFREE(peerX448Key, ssl->heap, DYNAMIC_TYPE_TLSX);
+ return ret;
+ }
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Peer Curve448 Key");
+ WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
+#endif
+
+ if (wc_curve448_check_public(keyShareEntry->ke, keyShareEntry->keLen,
+ EC448_LITTLE_ENDIAN) != 0) {
+ ret = ECC_PEERKEY_ERROR;
+ }
+
+ if (ret == 0) {
+ if (wc_curve448_import_public_ex(keyShareEntry->ke,
+ keyShareEntry->keLen, peerX448Key,
+ EC448_LITTLE_ENDIAN) != 0) {
+ ret = ECC_PEERKEY_ERROR;
+ }
+ }
+
+ if (ret == 0) {
+ ssl->ecdhCurveOID = ECC_X448_OID;
+
+ ret = wc_curve448_shared_secret_ex(key, peerX448Key,
+ ssl->arrays->preMasterSecret,
+ &ssl->arrays->preMasterSz,
+ EC448_LITTLE_ENDIAN);
+ }
+
+ wc_curve448_free(peerX448Key);
+ XFREE(peerX448Key, ssl->heap, DYNAMIC_TYPE_TLSX);
+ wc_curve448_free((curve448_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_CURVE448 */
+
+ return ret;
+}
+
+/* Process the ECC 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_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
+{
+ int ret;
+
+#ifdef HAVE_ECC
+ int curveId;
+ ecc_key* keyShareKey = (ecc_key*)keyShareEntry->key;
+
+ if (ssl->peerEccKey != NULL)
+ wc_ecc_free(ssl->peerEccKey);
+
+ ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), ssl->heap,
+ DYNAMIC_TYPE_ECC);
+ if (ssl->peerEccKey == NULL) {
+ WOLFSSL_MSG("PeerEccKey Memory error");
+ return MEMORY_ERROR;
+ }
+ ret = wc_ecc_init_ex(ssl->peerEccKey, ssl->heap, ssl->devId);
+ if (ret != 0)
+ return ret;
+
+ /* find supported curve */
+ switch (keyShareEntry->group) {
+ #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP256R1:
+ curveId = ECC_SECP256R1;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP384R1:
+ curveId = ECC_SECP384R1;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP521R1:
+ curveId = ECC_SECP521R1;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #ifdef HAVE_X448
+ case WOLFSSL_ECC_X448:
+ curveId = ECC_X448;
+ break;
+ #endif
+ default:
+ /* unsupported curve */
+ return ECC_PEERKEY_ERROR;
+ }
+
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Peer ECC Key");
+ WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
+#endif
+
+ /* Point is validated by import function. */
+ if (wc_ecc_import_x963_ex(keyShareEntry->ke, keyShareEntry->keLen,
+ ssl->peerEccKey, curveId) != 0) {
+ return ECC_PEERKEY_ERROR;
+ }
+ ssl->ecdhCurveOID = ssl->peerEccKey->dp->oidSum;
+
+ do {
+ #if defined(WOLFSSL_ASYNC_CRYPT)
+ ret = wc_AsyncWait(ret, &keyShareKey->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
+ #endif
+ if (ret >= 0)
+ ret = wc_ecc_shared_secret(keyShareKey, ssl->peerEccKey,
+ ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz);
+ } while (ret == WC_PENDING_E);
+
+#if 0
+ /* TODO: Switch to support async here and use: */
+ ret = EccSharedSecret(ssl, keyShareEntry->key, ssl->peerEccKey,
+ keyShareEntry->ke, &keyShareEntry->keLen,
+ ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz,
+ 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
+ (void)ssl;
+ (void)keyShareEntry;
+
+ ret = PEER_KEY_ERROR;
+#endif /* HAVE_ECC */
+
+ return ret;
+}
+
+/* Process the 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_Process(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
+{
+ int ret;
+
+#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ 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 if (keyShareEntry->group == WOLFSSL_ECC_X448)
+ ret = TLSX_KeyShare_ProcessX448(ssl, keyShareEntry);
+ else
+ ret = TLSX_KeyShare_ProcessEcc(ssl, keyShareEntry);
+
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("KE Secret");
+ WOLFSSL_BUFFER(ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz);
+#endif
+
+ return ret;
+}
+
+/* Parse an entry of the KeyShare extension.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * kse The new key share entry object.
+ * returns a positive number to indicate amount of data parsed and a negative
+ * number on error.
+ */
+static int TLSX_KeyShareEntry_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ KeyShareEntry **kse)
+{
+ int ret;
+ word16 group;
+ word16 keLen;
+ int offset = 0;
+ byte* ke;
+
+ if (length < OPAQUE16_LEN + OPAQUE16_LEN)
+ return BUFFER_ERROR;
+ /* Named group */
+ ato16(&input[offset], &group);
+ offset += OPAQUE16_LEN;
+ /* Key exchange data - public key. */
+ ato16(&input[offset], &keLen);
+ offset += OPAQUE16_LEN;
+ if (keLen == 0)
+ return INVALID_PARAMETER;
+ if (keLen > length - offset)
+ return BUFFER_ERROR;
+
+ /* Store a copy in the key share object. */
+ ke = (byte*)XMALLOC(keLen, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ if (ke == NULL)
+ return MEMORY_E;
+ XMEMCPY(ke, &input[offset], keLen);
+
+ /* Populate a key share object in the extension. */
+ ret = TLSX_KeyShare_Use(ssl, group, keLen, ke, kse);
+ if (ret != 0) {
+ XFREE(ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ return ret;
+ }
+
+ /* Total length of the parsed data. */
+ return offset + keLen;
+}
+
+/* Searches the groups sent for the specified named group.
+ *
+ * ssl SSL/TLS object.
+ * name Group name to match.
+ * returns 1 when the extension has the group name and 0 otherwise.
+ */
+static int TLSX_KeyShare_Find(WOLFSSL* ssl, word16 group)
+{
+ TLSX* extension;
+ KeyShareEntry* list;
+
+ 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)
+ return 1;
+ list = list->next;
+ }
+
+ return 0;
+}
+
+
+/* Searches the supported groups extension for the specified named group.
+ *
+ * ssl The SSL/TLS object.
+ * name The group name to match.
+ * returns 1 when the extension has the group name and 0 otherwise.
+ */
+static int TLSX_SupportedGroups_Find(WOLFSSL* ssl, word16 name)
+{
+#ifdef HAVE_SUPPORTED_CURVES
+ TLSX* extension;
+ SupportedCurve* curve = 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) {
+ if (curve->name == name)
+ return 1;
+ }
+#endif
+
+ (void)ssl;
+ (void)name;
+
+ return 0;
+}
+
+
+/* Parse the KeyShare extension.
+ * Different formats in different messages.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_KeyShare_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ int ret;
+ 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)
+ return BUFFER_ERROR;
+
+ /* ClientHello contains zero or more key share entries. */
+ ato16(input, &len);
+ if (len != length - OPAQUE16_LEN)
+ return BUFFER_ERROR;
+ offset += OPAQUE16_LEN;
+
+ while (offset < (int)length) {
+ ret = TLSX_KeyShareEntry_Parse(ssl, &input[offset], length - offset,
+ &keyShareEntry);
+ if (ret < 0)
+ return ret;
+
+ offset += ret;
+ }
+
+ ret = 0;
+ }
+ else if (msgType == server_hello) {
+ 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);
+ if (len != (int)length)
+ return BUFFER_ERROR;
+
+ /* Not in list sent if there isn't a private key. */
+ 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) {
+ 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;
+
+ /* Clear out unusable key shares. */
+ ret = TLSX_KeyShare_Empty(ssl);
+ if (ret != 0)
+ return ret;
+
+ /* Try to use the server's group. */
+ ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL);
+ }
+ else {
+ /* Not a message type that is allowed to have this extension. */
+ return SANITY_MSG_E;
+ }
+
+ return ret;
+}
+
+/* Create a new key share entry and put it into the list.
+ *
+ * list The linked list of key share entries.
+ * group The named group.
+ * heap The memory to allocate with.
+ * keyShareEntry The new key share entry object.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_KeyShare_New(KeyShareEntry** list, int group, void *heap,
+ KeyShareEntry** keyShareEntry)
+{
+ KeyShareEntry* kse;
+ KeyShareEntry** next;
+
+ kse = (KeyShareEntry*)XMALLOC(sizeof(KeyShareEntry), heap,
+ DYNAMIC_TYPE_TLSX);
+ if (kse == NULL)
+ return MEMORY_E;
+
+ XMEMSET(kse, 0, sizeof(*kse));
+ kse->group = (word16)group;
+
+ /* Add it to the back and maintain the links. */
+ while (*list != NULL) {
+ /* Assign to temporary to work around compiler bug found by customer. */
+ next = &((*list)->next);
+ list = next;
+ }
+ *list = kse;
+ *keyShareEntry = kse;
+
+ (void)heap;
+
+ return 0;
+}
+
+/* Use the data to create a new key share object in the extensions.
+ *
+ * ssl The SSL/TLS object.
+ * group The named group.
+ * len The length of the public key data.
+ * data The public key data.
+ * kse The new key share entry object.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_KeyShare_Use(WOLFSSL* ssl, word16 group, word16 len, byte* data,
+ KeyShareEntry **kse)
+{
+ int ret = 0;
+ TLSX* extension;
+ KeyShareEntry* keyShareEntry = NULL;
+
+ /* Find the KeyShare extension if it exists. */
+ 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;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+ if (extension == NULL)
+ return MEMORY_E;
+ }
+ extension->resp = 0;
+
+ /* Try to find the key share entry with this group. */
+ keyShareEntry = (KeyShareEntry*)extension->data;
+ while (keyShareEntry != NULL) {
+ if (keyShareEntry->group == group)
+ break;
+ keyShareEntry = keyShareEntry->next;
+ }
+
+ /* Create a new key share entry if not found. */
+ if (keyShareEntry == NULL) {
+ ret = TLSX_KeyShare_New((KeyShareEntry**)&extension->data, group,
+ ssl->heap, &keyShareEntry);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (data != NULL) {
+ if (keyShareEntry->ke != NULL) {
+ XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ }
+ keyShareEntry->ke = data;
+ keyShareEntry->keLen = len;
+ }
+ else {
+ /* Generate a key pair. */
+ ret = TLSX_KeyShare_GenKey(ssl, keyShareEntry);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (kse != NULL)
+ *kse = keyShareEntry;
+
+ return 0;
+}
+
+/* Set an empty Key Share extension.
+ *
+ * ssl The SSL/TLS object.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_KeyShare_Empty(WOLFSSL* ssl)
+{
+ int ret = 0;
+ TLSX* extension;
+
+ /* Find the KeyShare extension if it exists. */
+ 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);
+ }
+ else if (extension->data != NULL) {
+ TLSX_KeyShare_FreeAll((KeyShareEntry*)extension->data, ssl->heap);
+ extension->data = NULL;
+ }
+
+ return ret;
+}
+
+/* Returns whether this group is supported.
+ *
+ * namedGroup The named group to check.
+ * returns 1 when supported or 0 otherwise.
+ */
+static int TLSX_KeyShare_IsSupported(int namedGroup)
+{
+ switch (namedGroup) {
+ #ifdef HAVE_FFDHE_2048
+ case WOLFSSL_FFDHE_2048:
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_3072
+ case WOLFSSL_FFDHE_3072:
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_4096
+ case WOLFSSL_FFDHE_4096:
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_6144
+ case WOLFSSL_FFDHE_6144:
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_8192
+ case WOLFSSL_FFDHE_8192:
+ break;
+ #endif
+ #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP256R1:
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #ifdef HAVE_CURVE25519
+ case WOLFSSL_ECC_X25519:
+ break;
+ #endif
+ #ifdef HAVE_CURVE448
+ case WOLFSSL_ECC_X448:
+ break;
+ #endif
+ #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP384R1:
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP521R1:
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ default:
+ return 0;
+ }
+
+ 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
+ #ifndef HAVE_FIPS
+ #if defined(HAVE_CURVE448)
+ ssl->group[ssl->numGroups++] = WOLFSSL_ECC_X448;
+ #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] == (word16)group)
+ return i;
+
+ return -1;
+}
+
+/* Set a key share that is supported by the client into extensions.
+ *
+ * ssl The SSL/TLS object.
+ * returns BAD_KEY_SHARE_DATA if no supported group has a key share,
+ * 0 if a supported group has a key share and other values indicate an error.
+ */
+static int TLSX_KeyShare_SetSupported(WOLFSSL* ssl)
+{
+ int ret;
+#ifdef HAVE_SUPPORTED_CURVES
+ TLSX* extension;
+ SupportedCurve* curve = NULL;
+ 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))
+ 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;
+
+ /* Delete the old key share data list. */
+ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+ if (extension != NULL) {
+ TLSX_KeyShare_FreeAll((KeyShareEntry*)extension->data, ssl->heap);
+ extension->data = NULL;
+ }
+
+ /* Add in the chosen group. */
+ ret = TLSX_KeyShare_Use(ssl, curve->name, 0, NULL, NULL);
+ if (ret != 0)
+ return ret;
+
+ /* Set extension to be in response. */
+ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+ extension->resp = 1;
+#else
+
+ (void)ssl;
+ ret = NOT_COMPILED_IN;
+#endif
+
+ return ret;
+}
+
+/* Ensure there is a key pair that can be used for key exchange.
+ *
+ * ssl The SSL/TLS object.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_KeyShare_Establish(WOLFSSL *ssl)
+{
+ int ret;
+ TLSX* extension;
+ KeyShareEntry* clientKSE = NULL;
+ KeyShareEntry* serverKSE;
+ KeyShareEntry* list = NULL;
+ KeyShareEntry* preferredKSE = NULL;
+ int preferredRank = WOLFSSL_MAX_GROUP_COUNT;
+ int rank;
+
+ /* Find the KeyShare extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+ if (extension != NULL)
+ list = (KeyShareEntry*)extension->data;
+
+ if (extension && extension->resp == 1)
+ return 0;
+
+ /* 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))
+ return BAD_KEY_SHARE_DATA;
+
+ #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))
+ 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) {
+ ret = TLSX_KeyShare_SetSupported(ssl);
+ /* Return KEY_SHARE_ERROR to indicate HelloRetryRequest required. */
+ if (ret == 0)
+ return KEY_SHARE_ERROR;
+ return ret;
+ }
+
+ list = NULL;
+ /* Generate a new key pair. */
+ ret = TLSX_KeyShare_New(&list, clientKSE->group, ssl->heap, &serverKSE);
+ if (ret != 0)
+ return ret;
+
+ if (clientKSE->key == NULL) {
+ ret = TLSX_KeyShare_GenKey(ssl, serverKSE);
+ if (ret != 0)
+ return ret;
+ }
+ 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, list);
+ if (ret != 0)
+ return ret;
+
+ return ret;
+}
+
+#define KS_FREE_ALL TLSX_KeyShare_FreeAll
+#define KS_GET_SIZE TLSX_KeyShare_GetSize
+#define KS_WRITE TLSX_KeyShare_Write
+#define KS_PARSE TLSX_KeyShare_Parse
+
+#else
+
+#define KS_FREE_ALL(a, b)
+#define KS_GET_SIZE(a, b) 0
+#define KS_WRITE(a, b, c) 0
+#define KS_PARSE(a, b, c, d) 0
+
+#endif /* WOLFSSL_TLS13 */
+
+/******************************************************************************/
+/* Pre-Shared Key */
+/******************************************************************************/
+
+#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK))
+/* Free the pre-shared key dynamic data.
+ *
+ * list The linked list of key share entry objects.
+ * heap The heap used for allocation.
+ */
+static void TLSX_PreSharedKey_FreeAll(PreSharedKey* list, void* heap)
+{
+ PreSharedKey* current;
+
+ while ((current = list) != NULL) {
+ list = current->next;
+ XFREE(current->identity, heap, DYNAMIC_TYPE_TLSX);
+ XFREE(current, heap, DYNAMIC_TYPE_TLSX);
+ }
+
+ (void)heap;
+}
+
+/* Get the size of the encoded pre shared key extension.
+ *
+ * list The linked list of pre-shared key extensions.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded pre-shared key extension or
+ * SANITY_MSG_E to indicate invalid message type.
+ */
+static int TLSX_PreSharedKey_GetSize(PreSharedKey* list, byte msgType,
+ word16* pSz)
+{
+ if (msgType == client_hello) {
+ /* Length of identities + Length of binders. */
+ word16 len = OPAQUE16_LEN + OPAQUE16_LEN;
+ while (list != NULL) {
+ /* Each entry has: identity, ticket age and binder. */
+ len += OPAQUE16_LEN + list->identityLen + OPAQUE32_LEN +
+ OPAQUE8_LEN + list->binderLen;
+ list = list->next;
+ }
+ *pSz += len;
+ return 0;
+ }
+
+ if (msgType == server_hello) {
+ *pSz += OPAQUE16_LEN;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* The number of bytes to be written for the binders.
+ *
+ * list The linked list of pre-shared key extensions.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded pre-shared key extension or
+ * SANITY_MSG_E to indicate invalid message type.
+ */
+int TLSX_PreSharedKey_GetSizeBinders(PreSharedKey* list, byte msgType,
+ word16* pSz)
+{
+ word16 len;
+
+ if (msgType != client_hello)
+ return SANITY_MSG_E;
+
+ /* Length of all binders. */
+ len = OPAQUE16_LEN;
+ while (list != NULL) {
+ len += OPAQUE8_LEN + list->binderLen;
+ list = list->next;
+ }
+
+ *pSz = len;
+ return 0;
+}
+
+/* Writes the pre-shared key extension into the output buffer - binders only.
+ * Assumes that the the output buffer is big enough to hold data.
+ *
+ * list The linked list of key share entries.
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+int TLSX_PreSharedKey_WriteBinders(PreSharedKey* list, byte* output,
+ byte msgType, word16* pSz)
+{
+ PreSharedKey* current = list;
+ word16 idx = 0;
+ word16 lenIdx;
+ word16 len;
+
+ if (msgType != client_hello)
+ return SANITY_MSG_E;
+
+ /* Skip length of all binders. */
+ lenIdx = idx;
+ idx += OPAQUE16_LEN;
+ while (current != NULL) {
+ /* Binder data length. */
+ output[idx++] = current->binderLen;
+ /* Binder data. */
+ XMEMCPY(output + idx, current->binder, current->binderLen);
+ idx += current->binderLen;
+
+ current = current->next;
+ }
+ /* Length of the binders. */
+ len = idx - lenIdx - OPAQUE16_LEN;
+ c16toa(len, output + lenIdx);
+
+ *pSz = idx;
+ return 0;
+}
+
+
+/* Writes the pre-shared key extension into the output buffer.
+ * Assumes that the the output buffer is big enough to hold data.
+ *
+ * list The linked list of key share entries.
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+static int TLSX_PreSharedKey_Write(PreSharedKey* list, byte* output,
+ byte msgType, word16* pSz)
+{
+ if (msgType == client_hello) {
+ PreSharedKey* current = list;
+ word16 idx = 0;
+ word16 lenIdx;
+ word16 len;
+ int ret;
+
+ /* Write identites only. Binders after HMACing over this. */
+ lenIdx = idx;
+ idx += OPAQUE16_LEN;
+ while (current != NULL) {
+ /* Identity length */
+ c16toa(current->identityLen, output + idx);
+ idx += OPAQUE16_LEN;
+ /* Identity data */
+ XMEMCPY(output + idx, current->identity, current->identityLen);
+ idx += current->identityLen;
+
+ /* Obfuscated ticket age. */
+ c32toa(current->ticketAge, output + idx);
+ idx += OPAQUE32_LEN;
+
+ current = current->next;
+ }
+ /* Length of the identites. */
+ len = idx - lenIdx - OPAQUE16_LEN;
+ c16toa(len, output + lenIdx);
+
+ /* Don't include binders here.
+ * The binders are based on the hash of all the ClientHello data up to
+ * and include the identities written above.
+ */
+ ret = TLSX_PreSharedKey_GetSizeBinders(list, msgType, &len);
+ if (ret < 0)
+ return ret;
+ *pSz += idx + len;
+ }
+ else if (msgType == server_hello) {
+ word16 i;
+
+ /* Find the index of the chosen identity. */
+ for (i=0; list != NULL && !list->chosen; i++)
+ list = list->next;
+ if (list == NULL)
+ return BUILD_MSG_ERROR;
+
+ /* The index of the identity chosen by the server from the list supplied
+ * by the client.
+ */
+ c16toa(i, output);
+ *pSz += OPAQUE16_LEN;
+ }
+ else
+ return SANITY_MSG_E;
+
+ return 0;
+}
+
+/* Parse the pre-shared key extension.
+ * Different formats in different messages.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ TLSX* extension;
+ PreSharedKey* list;
+
+ if (msgType == client_hello) {
+ int ret;
+ word16 len;
+ 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)
+ return BUFFER_E;
+
+ /* Length of identities. */
+ ato16(input + idx, &len);
+ idx += OPAQUE16_LEN;
+ if (len < MIN_PSK_ID_LEN || length - idx < len)
+ return BUFFER_E;
+
+ /* Create a pre-shared key object for each identity. */
+ while (len > 0) {
+ byte* identity;
+ word16 identityLen;
+ word32 age;
+
+ if (len < OPAQUE16_LEN)
+ return BUFFER_E;
+
+ /* Length of identity. */
+ ato16(input + idx, &identityLen);
+ idx += OPAQUE16_LEN;
+ if (len < OPAQUE16_LEN + identityLen + OPAQUE32_LEN ||
+ identityLen > MAX_PSK_ID_LEN)
+ return BUFFER_E;
+ /* Cache identity pointer. */
+ identity = input + idx;
+ idx += identityLen;
+ /* Ticket age. */
+ ato32(input + idx, &age);
+ idx += OPAQUE32_LEN;
+
+ ret = TLSX_PreSharedKey_Use(ssl, identity, identityLen, age, no_mac,
+ 0, 0, 1, NULL);
+ if (ret != 0)
+ return ret;
+
+ /* Done with this identity. */
+ len -= OPAQUE16_LEN + identityLen + OPAQUE32_LEN;
+ }
+
+ /* Find the list of identities sent to server. */
+ extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
+ if (extension == NULL)
+ return PSK_KEY_ERROR;
+ list = (PreSharedKey*)extension->data;
+
+ /* Length of binders. */
+ if (idx + OPAQUE16_LEN > length)
+ return BUFFER_E;
+ ato16(input + idx, &len);
+ idx += OPAQUE16_LEN;
+ if (len < MIN_PSK_BINDERS_LEN || length - idx < len)
+ return BUFFER_E;
+
+ /* Set binder for each identity. */
+ while (list != NULL && len > 0) {
+ /* Length of binder */
+ list->binderLen = input[idx++];
+ if (list->binderLen < WC_SHA256_DIGEST_SIZE ||
+ list->binderLen > WC_MAX_DIGEST_SIZE)
+ return BUFFER_E;
+ if (len < OPAQUE8_LEN + list->binderLen)
+ return BUFFER_E;
+
+ /* Copy binder into static buffer. */
+ XMEMCPY(list->binder, input + idx, list->binderLen);
+ idx += list->binderLen;
+
+ /* Done with binder entry. */
+ len -= OPAQUE8_LEN + list->binderLen;
+
+ /* Next identity. */
+ list = list->next;
+ }
+ if (list != NULL || len != 0)
+ return BUFFER_E;
+
+ return 0;
+ }
+
+ if (msgType == server_hello) {
+ word16 idx;
+
+ /* Index of identity chosen by server. */
+ if (length != OPAQUE16_LEN)
+ return BUFFER_E;
+ ato16(input, &idx);
+
+ #ifdef WOLFSSL_EARLY_DATA
+ ssl->options.pskIdIndex = idx + 1;
+ #endif
+
+ /* Find the list of identities sent to server. */
+ extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
+ if (extension == NULL)
+ return PSK_KEY_ERROR;
+ list = (PreSharedKey*)extension->data;
+
+ /* Mark the identity as chosen. */
+ for (; list != NULL && idx > 0; idx--)
+ list = list->next;
+ if (list == NULL)
+ return PSK_KEY_ERROR;
+ list->chosen = 1;
+
+ #ifdef HAVE_SESSION_TICKET
+ if (list->resumption) {
+ /* Check that the session's details are the same as the server's. */
+ if (ssl->options.cipherSuite0 != ssl->session.cipherSuite0 ||
+ ssl->options.cipherSuite != ssl->session.cipherSuite ||
+ ssl->session.version.major != ssl->ctx->method->version.major ||
+ ssl->session.version.minor != ssl->ctx->method->version.minor) {
+ return PSK_KEY_ERROR;
+ }
+ }
+ #endif
+
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Create a new pre-shared key and put it into the list.
+ *
+ * list The linked list of pre-shared key.
+ * identity The identity.
+ * len The length of the identity data.
+ * heap The memory to allocate with.
+ * preSharedKey The new pre-shared key object.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_PreSharedKey_New(PreSharedKey** list, byte* identity,
+ word16 len, void *heap,
+ PreSharedKey** preSharedKey)
+{
+ PreSharedKey* psk;
+ PreSharedKey** next;
+
+ psk = (PreSharedKey*)XMALLOC(sizeof(PreSharedKey), heap, DYNAMIC_TYPE_TLSX);
+ if (psk == NULL)
+ return MEMORY_E;
+ XMEMSET(psk, 0, sizeof(*psk));
+
+ /* Make a copy of the identity data. */
+ psk->identity = (byte*)XMALLOC(len, heap, DYNAMIC_TYPE_TLSX);
+ if (psk->identity == NULL) {
+ XFREE(psk, heap, DYNAMIC_TYPE_TLSX);
+ return MEMORY_E;
+ }
+ XMEMCPY(psk->identity, identity, len);
+ psk->identityLen = len;
+
+ /* Add it to the end and maintain the links. */
+ while (*list != NULL) {
+ /* Assign to temporary to work around compiler bug found by customer. */
+ next = &((*list)->next);
+ list = next;
+ }
+ *list = psk;
+ *preSharedKey = psk;
+
+ (void)heap;
+
+ return 0;
+}
+
+static WC_INLINE byte GetHmacLength(int hmac)
+{
+ switch (hmac) {
+ #ifndef NO_SHA256
+ case sha256_mac:
+ return WC_SHA256_DIGEST_SIZE;
+ #endif
+ #ifdef WOLFSSL_SHA384
+ case sha384_mac:
+ return WC_SHA384_DIGEST_SIZE;
+ #endif
+ #ifdef WOLFSSL_SHA512
+ case sha512_mac:
+ return WC_SHA512_DIGEST_SIZE;
+ #endif
+ }
+ return 0;
+}
+
+/* Use the data to create a new pre-shared key object in the extensions.
+ *
+ * ssl The SSL/TLS object.
+ * identity The identity.
+ * len The length of the identity data.
+ * age The age of the identity.
+ * hmac The HMAC algorithm.
+ * ciphersuite0 The first byte of the ciphersuite to use.
+ * ciphersuite The second byte of the ciphersuite to use.
+ * resumption The PSK is for resumption of a session.
+ * preSharedKey The new pre-shared key object.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity, word16 len, word32 age,
+ byte hmac, byte cipherSuite0,
+ byte cipherSuite, byte resumption,
+ PreSharedKey **preSharedKey)
+{
+ int ret = 0;
+ TLSX* extension;
+ PreSharedKey* psk = NULL;
+
+ /* Find the pre-shared key extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
+ if (extension == NULL) {
+ /* Push new pre-shared key extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_PRE_SHARED_KEY, NULL, ssl->heap);
+ if (ret != 0)
+ return ret;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
+ if (extension == NULL)
+ return MEMORY_E;
+ }
+
+ /* Try to find the pre-shared key with this identity. */
+ psk = (PreSharedKey*)extension->data;
+ while (psk != NULL) {
+ if ((psk->identityLen == len) &&
+ (XMEMCMP(psk->identity, identity, len) == 0)) {
+ break;
+ }
+ psk = psk->next;
+ }
+
+ /* Create a new pre-shared key object if not found. */
+ if (psk == NULL) {
+ ret = TLSX_PreSharedKey_New((PreSharedKey**)&extension->data, identity,
+ len, ssl->heap, &psk);
+ if (ret != 0)
+ return ret;
+ }
+
+ /* Update/set age and HMAC algorithm. */
+ psk->ticketAge = age;
+ psk->hmac = hmac;
+ psk->cipherSuite0 = cipherSuite0;
+ psk->cipherSuite = cipherSuite;
+ psk->resumption = resumption;
+ psk->binderLen = GetHmacLength(psk->hmac);
+
+ if (preSharedKey != NULL)
+ *preSharedKey = psk;
+
+ return 0;
+}
+
+#define PSK_FREE_ALL TLSX_PreSharedKey_FreeAll
+#define PSK_GET_SIZE TLSX_PreSharedKey_GetSize
+#define PSK_WRITE TLSX_PreSharedKey_Write
+#define PSK_PARSE TLSX_PreSharedKey_Parse
+
+#else
+
+#define PSK_FREE_ALL(a, b)
+#define PSK_GET_SIZE(a, b, c) 0
+#define PSK_WRITE(a, b, c, d) 0
+#define PSK_PARSE(a, b, c, d) 0
+
+#endif
+
+/******************************************************************************/
+/* PSK Key Exchange Modes */
+/******************************************************************************/
+
+#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK))
+/* Get the size of the encoded PSK KE modes extension.
+ * Only in ClientHello.
+ *
+ * modes The PSK KE mode bit string.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded PSK KE mode extension.
+ */
+static int TLSX_PskKeModes_GetSize(byte modes, byte msgType, word16* pSz)
+{
+ if (msgType == client_hello) {
+ /* Format: Len | Modes* */
+ word16 len = OPAQUE8_LEN;
+ /* Check whether each possible mode is to be written. */
+ if (modes & (1 << PSK_KE))
+ len += OPAQUE8_LEN;
+ if (modes & (1 << PSK_DHE_KE))
+ len += OPAQUE8_LEN;
+ *pSz += len;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Writes the PSK KE modes extension into the output buffer.
+ * Assumes that the the output buffer is big enough to hold data.
+ * Only in ClientHello.
+ *
+ * modes The PSK KE mode bit string.
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+static int TLSX_PskKeModes_Write(byte modes, byte* output, byte msgType,
+ word16* pSz)
+{
+ if (msgType == client_hello) {
+ /* Format: Len | Modes* */
+ int idx = OPAQUE8_LEN;
+
+ /* Write out each possible mode. */
+ if (modes & (1 << PSK_KE))
+ output[idx++] = PSK_KE;
+ if (modes & (1 << PSK_DHE_KE))
+ output[idx++] = PSK_DHE_KE;
+ /* Write out length of mode list. */
+ output[0] = idx - OPAQUE8_LEN;
+
+ *pSz += idx;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Parse the PSK KE modes extension.
+ * Only in ClientHello.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_PskKeModes_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ int ret;
+
+ if (msgType == client_hello) {
+ /* Format: Len | Modes* */
+ int idx = 0;
+ word16 len;
+ byte modes = 0;
+
+ /* Ensure length byte exists. */
+ if (length < OPAQUE8_LEN)
+ return BUFFER_E;
+
+ /* Get length of mode list and ensure that is the only data. */
+ len = input[0];
+ if (length - OPAQUE8_LEN != len)
+ return BUFFER_E;
+
+ idx = OPAQUE8_LEN;
+ /* Set a bit for each recognized modes. */
+ while (len > 0) {
+ /* Ignore unrecognized modes. */
+ if (input[idx] <= PSK_DHE_KE)
+ modes |= 1 << input[idx];
+ idx++;
+ len--;
+ }
+
+ ret = TLSX_PskKeModes_Use(ssl, modes);
+ if (ret != 0)
+ return ret;
+
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Use the data to create a new PSK Key Exchange Modes object in the extensions.
+ *
+ * ssl The SSL/TLS object.
+ * modes The PSK key exchange modes.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_PskKeModes_Use(WOLFSSL* ssl, byte modes)
+{
+ int ret = 0;
+ TLSX* extension;
+
+ /* Find the PSK key exchange modes extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES);
+ if (extension == NULL) {
+ /* Push new PSK key exchange modes extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES, NULL,
+ ssl->heap);
+ if (ret != 0)
+ return ret;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES);
+ if (extension == NULL)
+ return MEMORY_E;
+ }
+
+ extension->val = modes;
+
+ return 0;
+}
+
+#define PKM_GET_SIZE TLSX_PskKeModes_GetSize
+#define PKM_WRITE TLSX_PskKeModes_Write
+#define PKM_PARSE TLSX_PskKeModes_Parse
+
+#else
+
+#define PKM_GET_SIZE(a, b, c) 0
+#define PKM_WRITE(a, b, c, d) 0
+#define PKM_PARSE(a, b, c, d) 0
+
+#endif
+
+/******************************************************************************/
+/* Post-Handshake Authentication */
+/******************************************************************************/
+
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
+/* Get the size of the encoded Post-Handshake Authentication extension.
+ * Only in ClientHello.
+ *
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded Post-Handshake Authentication
+ * extension.
+ */
+static int TLSX_PostHandAuth_GetSize(byte msgType, word16* pSz)
+{
+ if (msgType == client_hello) {
+ *pSz += 0;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Writes the Post-Handshake Authentication extension into the output buffer.
+ * Assumes that the the output buffer is big enough to hold data.
+ * Only in ClientHello.
+ *
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+static int TLSX_PostHandAuth_Write(byte* output, byte msgType, word16* pSz)
+{
+ (void)output;
+
+ if (msgType == client_hello) {
+ *pSz += 0;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Parse the Post-Handshake Authentication extension.
+ * Only in ClientHello.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_PostHandAuth_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ (void)input;
+
+ if (msgType == client_hello) {
+ /* Ensure extension is empty. */
+ if (length != 0)
+ return BUFFER_E;
+
+ ssl->options.postHandshakeAuth = 1;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Create a new Post-handshake authentication object in the extensions.
+ *
+ * ssl The SSL/TLS object.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_PostHandAuth_Use(WOLFSSL* ssl)
+{
+ int ret = 0;
+ TLSX* extension;
+
+ /* Find the PSK key exchange modes extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_POST_HANDSHAKE_AUTH);
+ if (extension == NULL) {
+ /* Push new Post-handshake Authentication extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_POST_HANDSHAKE_AUTH, NULL,
+ ssl->heap);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+#define PHA_GET_SIZE TLSX_PostHandAuth_GetSize
+#define PHA_WRITE TLSX_PostHandAuth_Write
+#define PHA_PARSE TLSX_PostHandAuth_Parse
+
+#else
+
+#define PHA_GET_SIZE(a, b) 0
+#define PHA_WRITE(a, b, c) 0
+#define PHA_PARSE(a, b, c, d) 0
+
+#endif
+
+/******************************************************************************/
+/* Early Data Indication */
+/******************************************************************************/
+
+#ifdef WOLFSSL_EARLY_DATA
+/* Get the size of the encoded Early Data Indication extension.
+ * In messages: ClientHello, EncryptedExtensions and NewSessionTicket.
+ *
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded Early Data Indication extension.
+ */
+static int TLSX_EarlyData_GetSize(byte msgType, word16* pSz)
+{
+ int ret = 0;
+
+ if (msgType == client_hello || msgType == encrypted_extensions)
+ *pSz += 0;
+ else if (msgType == session_ticket)
+ *pSz += OPAQUE32_LEN;
+ else
+ ret = SANITY_MSG_E;
+
+ return ret;
+}
+
+/* Writes the Early Data Indicator extension into the output buffer.
+ * Assumes that the the output buffer is big enough to hold data.
+ * In messages: ClientHello, EncryptedExtensions and NewSessionTicket.
+ *
+ * max The maximum early data size.
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+static int TLSX_EarlyData_Write(word32 max, byte* output, byte msgType,
+ word16* pSz)
+{
+ if (msgType == client_hello || msgType == encrypted_extensions)
+ return 0;
+ else if (msgType == session_ticket) {
+ c32toa(max, output);
+ *pSz += OPAQUE32_LEN;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Parse the Early Data Indicator extension.
+ * In messages: ClientHello, EncryptedExtensions and NewSessionTicket.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_EarlyData_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ if (msgType == client_hello) {
+ if (length != 0)
+ return BUFFER_E;
+
+ if (ssl->earlyData == expecting_early_data)
+ return TLSX_EarlyData_Use(ssl, 0);
+ ssl->earlyData = early_data_ext;
+ return 0;
+ }
+ if (msgType == encrypted_extensions) {
+ if (length != 0)
+ 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);
+ }
+ if (msgType == session_ticket) {
+ word32 maxSz;
+
+ if (length != OPAQUE32_LEN)
+ return BUFFER_E;
+ ato32(input, &maxSz);
+
+ ssl->session.maxEarlyDataSz = maxSz;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Use the data to create a new Early Data object in the extensions.
+ *
+ * ssl The SSL/TLS object.
+ * max The maximum early data size.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 max)
+{
+ int ret = 0;
+ TLSX* extension;
+
+ /* Find the early data extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA);
+ if (extension == NULL) {
+ /* Push new early data extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_EARLY_DATA, NULL, ssl->heap);
+ if (ret != 0)
+ return ret;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA);
+ if (extension == NULL)
+ return MEMORY_E;
+ }
+
+ extension->resp = 1;
+ extension->val = max;
+ return 0;
+}
+
+#define EDI_GET_SIZE TLSX_EarlyData_GetSize
+#define EDI_WRITE TLSX_EarlyData_Write
+#define EDI_PARSE TLSX_EarlyData_Parse
+
+#else
+
+#define EDI_GET_SIZE(a, b) 0
+#define EDI_WRITE(a, b, c, d) 0
+#define EDI_PARSE(a, b, c, d) 0
+
+#endif
+
+/******************************************************************************/
+/* TLS Extensions Framework */
+/******************************************************************************/
+
+/** Finds an extension in the provided list. */
TLSX* TLSX_Find(TLSX* list, TLSX_Type type)
{
TLSX* extension = list;
@@ -1945,7 +9077,26 @@ TLSX* TLSX_Find(TLSX* list, TLSX_Type type)
return extension;
}
-void TLSX_FreeAll(TLSX* list)
+/** 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)
{
TLSX* extension;
@@ -1953,267 +9104,1660 @@ void TLSX_FreeAll(TLSX* list)
list = extension->next;
switch (extension->type) {
- case SERVER_NAME_INDICATION:
- SNI_FREE_ALL((SNI*)extension->data);
+
+ case TLSX_SERVER_NAME:
+ SNI_FREE_ALL((SNI*)extension->data, heap);
+ break;
+
+ case TLSX_TRUSTED_CA_KEYS:
+ TCA_FREE_ALL((TCA*)extension->data, heap);
break;
- case MAX_FRAGMENT_LENGTH:
- MFL_FREE_ALL(extension->data);
+ case TLSX_MAX_FRAGMENT_LENGTH:
+ MFL_FREE_ALL(extension->data, heap);
break;
- case TRUNCATED_HMAC:
+ case TLSX_TRUNCATED_HMAC:
/* Nothing to do. */
break;
- case ELLIPTIC_CURVES:
- EC_FREE_ALL(extension->data);
+ case TLSX_SUPPORTED_GROUPS:
+ EC_FREE_ALL((SupportedCurve*)extension->data, heap);
break;
- case SECURE_RENEGOTIATION:
- SCR_FREE_ALL(extension->data);
+ case TLSX_EC_POINT_FORMATS:
+ PF_FREE_ALL((PointFormat*)extension->data, heap);
break;
- case SESSION_TICKET:
- /* Nothing to do. */
+ case TLSX_STATUS_REQUEST:
+ CSR_FREE_ALL((CertificateStatusRequest*)extension->data, heap);
+ break;
+
+ case TLSX_STATUS_REQUEST_V2:
+ CSR2_FREE_ALL((CertificateStatusRequestItemV2*)extension->data,
+ heap);
+ break;
+
+ case TLSX_RENEGOTIATION_INFO:
+ SCR_FREE_ALL(extension->data, heap);
+ break;
+
+ case TLSX_SESSION_TICKET:
+ WOLF_STK_FREE(extension->data, heap);
+ break;
+
+ case TLSX_QUANTUM_SAFE_HYBRID:
+ QSH_FREE_ALL((QSHScheme*)extension->data, heap);
+ break;
+
+ case TLSX_APPLICATION_LAYER_PROTOCOL:
+ ALPN_FREE_ALL((ALPN*)extension->data, heap);
break;
+#if !defined(WOLFSSL_NO_SIGALG)
+ case TLSX_SIGNATURE_ALGORITHMS:
+ break;
+#endif
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+ case TLSX_ENCRYPT_THEN_MAC:
+ break;
+#endif
+#ifdef WOLFSSL_TLS13
+ case TLSX_SUPPORTED_VERSIONS:
+ break;
+
+ case TLSX_COOKIE:
+ CKE_FREE_ALL((Cookie*)extension->data, heap);
+ break;
+
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ case TLSX_PRE_SHARED_KEY:
+ PSK_FREE_ALL((PreSharedKey*)extension->data, heap);
+ break;
+
+ case TLSX_PSK_KEY_EXCHANGE_MODES:
+ break;
+ #endif
+
+ #ifdef WOLFSSL_EARLY_DATA
+ case TLSX_EARLY_DATA:
+ break;
+ #endif
+
+ #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+ case TLSX_POST_HANDSHAKE_AUTH:
+ 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
}
- XFREE(extension, 0, DYNAMIC_TYPE_TLSX);
+ XFREE(extension, heap, DYNAMIC_TYPE_TLSX);
}
+
+ (void)heap;
}
+/** Checks if the tls extensions are supported based on the protocol version. */
int TLSX_SupportExtensions(WOLFSSL* ssl) {
return ssl && (IsTLS(ssl) || ssl->version.major == DTLS_MAJOR);
}
-static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest)
+/** Tells the buffered size of the extensions in a list. */
+static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
+ word16* pLength)
{
- TLSX* extension;
+ int ret = 0;
+ TLSX* extension;
word16 length = 0;
+ byte isRequest = (msgType == client_hello ||
+ msgType == certificate_request);
while ((extension = list)) {
list = extension->next;
+ /* only extensions marked as response are sent back to the client. */
if (!isRequest && !extension->resp)
continue; /* skip! */
+ /* ssl level extensions are expected to override ctx level ones. */
if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type)))
continue; /* skip! */
- /* type + data length */
+ /* extension type + extension data length. */
length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
+
switch (extension->type) {
- case SERVER_NAME_INDICATION:
+
+ case TLSX_SERVER_NAME:
+ /* SNI only sends the name on the request. */
+ if (isRequest)
+ length += SNI_GET_SIZE((SNI*)extension->data);
+ break;
+
+ case TLSX_TRUSTED_CA_KEYS:
+ /* TCA only sends the list on the request. */
if (isRequest)
- length += SNI_GET_SIZE(extension->data);
+ length += TCA_GET_SIZE((TCA*)extension->data);
break;
- case MAX_FRAGMENT_LENGTH:
+
+ case TLSX_MAX_FRAGMENT_LENGTH:
length += MFL_GET_SIZE(extension->data);
break;
- case TRUNCATED_HMAC:
- /* empty extension. */
+ case TLSX_TRUNCATED_HMAC:
+ /* always empty. */
+ break;
+
+ case TLSX_SUPPORTED_GROUPS:
+ length += EC_GET_SIZE((SupportedCurve*)extension->data);
+ break;
+
+ case TLSX_EC_POINT_FORMATS:
+ length += PF_GET_SIZE((PointFormat*)extension->data);
+ break;
+
+ case TLSX_STATUS_REQUEST:
+ length += CSR_GET_SIZE(
+ (CertificateStatusRequest*)extension->data, isRequest);
+ break;
+
+ case TLSX_STATUS_REQUEST_V2:
+ length += CSR2_GET_SIZE(
+ (CertificateStatusRequestItemV2*)extension->data,
+ isRequest);
+ break;
+
+ case TLSX_RENEGOTIATION_INFO:
+ length += SCR_GET_SIZE((SecureRenegotiation*)extension->data,
+ isRequest);
+ break;
+
+ case TLSX_SESSION_TICKET:
+ length += WOLF_STK_GET_SIZE((SessionTicket*)extension->data,
+ isRequest);
break;
- case ELLIPTIC_CURVES:
- length += EC_GET_SIZE(extension->data);
+ case TLSX_QUANTUM_SAFE_HYBRID:
+ length += QSH_GET_SIZE((QSHScheme*)extension->data, isRequest);
break;
- case SECURE_RENEGOTIATION:
- length += SCR_GET_SIZE(extension->data, isRequest);
+ case TLSX_APPLICATION_LAYER_PROTOCOL:
+ length += ALPN_GET_SIZE((ALPN*)extension->data);
break;
+#if !defined(WOLFSSL_NO_SIGALG)
+ case TLSX_SIGNATURE_ALGORITHMS:
+ length += SA_GET_SIZE(extension->data);
+ break;
+#endif
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+ case TLSX_ENCRYPT_THEN_MAC:
+ ret = ETM_GET_SIZE(msgType, &length);
+ break;
+#endif /* HAVE_ENCRYPT_THEN_MAC */
+#ifdef WOLFSSL_TLS13
+ case TLSX_SUPPORTED_VERSIONS:
+ ret = SV_GET_SIZE(extension->data, msgType, &length);
+ break;
+
+ case TLSX_COOKIE:
+ ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &length);
+ break;
+
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ case TLSX_PRE_SHARED_KEY:
+ ret = PSK_GET_SIZE((PreSharedKey*)extension->data, msgType,
+ &length);
+ break;
+
+ case TLSX_PSK_KEY_EXCHANGE_MODES:
+ ret = PKM_GET_SIZE(extension->val, msgType, &length);
+ break;
+ #endif
+
+ #ifdef WOLFSSL_EARLY_DATA
+ case TLSX_EARLY_DATA:
+ ret = EDI_GET_SIZE(msgType, &length);
+ break;
+ #endif
+
+ #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+ case TLSX_POST_HANDSHAKE_AUTH:
+ ret = PHA_GET_SIZE(msgType, &length);
+ 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 SESSION_TICKET:
- length += STK_GET_SIZE(extension->data, isRequest);
+ case TLSX_KEY_SHARE:
+ length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType);
break;
+#endif
}
+ /* marks the extension as processed so ctx level */
+ /* extensions don't overlap with ssl level ones. */
TURN_ON(semaphore, TLSX_ToSemaphore(extension->type));
}
- return length;
+ *pLength += length;
+
+ return ret;
}
-static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
- byte isRequest)
+/** Writes the extensions of a list in a buffer. */
+static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
+ byte msgType, word16* pOffset)
{
- TLSX* extension;
+ int ret = 0;
+ TLSX* extension;
word16 offset = 0;
word16 length_offset = 0;
+ byte isRequest = (msgType == client_hello ||
+ msgType == certificate_request);
while ((extension = list)) {
list = extension->next;
+ /* only extensions marked as response are written in a response. */
if (!isRequest && !extension->resp)
continue; /* skip! */
+ /* ssl level extensions are expected to override ctx level ones. */
if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type)))
continue; /* skip! */
- /* extension type */
+ /* writes extension type. */
c16toa(extension->type, output + offset);
offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
length_offset = offset;
- /* extension data should be written internally */
+ /* extension data should be written internally. */
switch (extension->type) {
- case SERVER_NAME_INDICATION:
- if (isRequest)
- offset += SNI_WRITE(extension->data, output + offset);
+ case TLSX_SERVER_NAME:
+ if (isRequest) {
+ WOLFSSL_MSG("SNI extension to write");
+ offset += SNI_WRITE((SNI*)extension->data, output + offset);
+ }
break;
- case MAX_FRAGMENT_LENGTH:
- offset += MFL_WRITE(extension->data, output + offset);
+ case TLSX_TRUSTED_CA_KEYS:
+ WOLFSSL_MSG("Trusted CA Indication extension to write");
+ if (isRequest) {
+ offset += TCA_WRITE((TCA*)extension->data, output + offset);
+ }
+ break;
+
+ case TLSX_MAX_FRAGMENT_LENGTH:
+ WOLFSSL_MSG("Max Fragment Length extension to write");
+ offset += MFL_WRITE((byte*)extension->data, output + offset);
+ break;
+
+ case TLSX_TRUNCATED_HMAC:
+ WOLFSSL_MSG("Truncated HMAC extension to write");
+ /* always empty. */
+ break;
+
+ case TLSX_SUPPORTED_GROUPS:
+ WOLFSSL_MSG("Supported Groups extension to write");
+ offset += EC_WRITE((SupportedCurve*)extension->data,
+ output + offset);
break;
- case TRUNCATED_HMAC:
- /* empty extension. */
+ case TLSX_EC_POINT_FORMATS:
+ WOLFSSL_MSG("Point Formats extension to write");
+ offset += PF_WRITE((PointFormat*)extension->data,
+ output + offset);
break;
- case ELLIPTIC_CURVES:
- offset += EC_WRITE(extension->data, output + offset);
+ case TLSX_STATUS_REQUEST:
+ WOLFSSL_MSG("Certificate Status Request extension to write");
+ offset += CSR_WRITE((CertificateStatusRequest*)extension->data,
+ output + offset, isRequest);
break;
- case SECURE_RENEGOTIATION:
- offset += SCR_WRITE(extension->data, output + offset,
- isRequest);
+ case TLSX_STATUS_REQUEST_V2:
+ WOLFSSL_MSG("Certificate Status Request v2 extension to write");
+ offset += CSR2_WRITE(
+ (CertificateStatusRequestItemV2*)extension->data,
+ output + offset, isRequest);
+ break;
+
+ case TLSX_RENEGOTIATION_INFO:
+ WOLFSSL_MSG("Secure Renegotiation extension to write");
+ offset += SCR_WRITE((SecureRenegotiation*)extension->data,
+ output + offset, isRequest);
+ break;
+
+ case TLSX_SESSION_TICKET:
+ WOLFSSL_MSG("Session Ticket extension to write");
+ offset += WOLF_STK_WRITE((SessionTicket*)extension->data,
+ output + offset, isRequest);
+ break;
+
+ case TLSX_QUANTUM_SAFE_HYBRID:
+ WOLFSSL_MSG("Quantum-Safe-Hybrid extension to write");
+ if (isRequest) {
+ offset += QSH_WRITE((QSHScheme*)extension->data, output + offset);
+ }
+ offset += QSHPK_WRITE((QSHScheme*)extension->data, output + offset);
+ offset += QSH_SERREQ(output + offset, isRequest);
break;
- case SESSION_TICKET:
- offset += STK_WRITE(extension->data, output + offset,
- isRequest);
+ case TLSX_APPLICATION_LAYER_PROTOCOL:
+ WOLFSSL_MSG("ALPN extension to write");
+ offset += ALPN_WRITE((ALPN*)extension->data, output + offset);
break;
+#if !defined(WOLFSSL_NO_SIGALG)
+ case TLSX_SIGNATURE_ALGORITHMS:
+ WOLFSSL_MSG("Signature Algorithms extension to write");
+ offset += SA_WRITE(extension->data, output + offset);
+ break;
+#endif
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+ case TLSX_ENCRYPT_THEN_MAC:
+ WOLFSSL_MSG("Encrypt-Then-Mac extension to write");
+ ret = ETM_WRITE(extension->data, output, msgType, &offset);
+ break;
+#endif /* HAVE_ENCRYPT_THEN_MAC */
+#ifdef WOLFSSL_TLS13
+ case TLSX_SUPPORTED_VERSIONS:
+ WOLFSSL_MSG("Supported Versions extension to write");
+ ret = SV_WRITE(extension->data, output + offset, msgType, &offset);
+ break;
+
+ case TLSX_COOKIE:
+ WOLFSSL_MSG("Cookie extension to write");
+ ret = CKE_WRITE((Cookie*)extension->data, output + offset,
+ msgType, &offset);
+ break;
+
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ case TLSX_PRE_SHARED_KEY:
+ WOLFSSL_MSG("Pre-Shared Key extension to write");
+ ret = PSK_WRITE((PreSharedKey*)extension->data, output + offset,
+ msgType, &offset);
+ break;
+
+ case TLSX_PSK_KEY_EXCHANGE_MODES:
+ WOLFSSL_MSG("PSK Key Exchange Modes extension to write");
+ ret = PKM_WRITE(extension->val, output + offset, msgType,
+ &offset);
+ break;
+ #endif
+
+ #ifdef WOLFSSL_EARLY_DATA
+ case TLSX_EARLY_DATA:
+ WOLFSSL_MSG("Early Data extension to write");
+ ret = EDI_WRITE(extension->val, output + offset, msgType,
+ &offset);
+ break;
+ #endif
+
+ #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+ case TLSX_POST_HANDSHAKE_AUTH:
+ WOLFSSL_MSG("Post-Handshake Authentication extension to write");
+ ret = PHA_WRITE(output + offset, msgType, &offset);
+ 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
}
- /* writing extension data length */
+ /* writes extension data length. */
c16toa(offset - length_offset, output + length_offset - OPAQUE16_LEN);
+ /* marks the extension as processed so ctx level */
+ /* extensions don't overlap with ssl level ones. */
TURN_ON(semaphore, TLSX_ToSemaphore(extension->type));
}
- return offset;
+ *pOffset += offset;
+
+ return ret;
}
-#ifndef NO_WOLFSSL_CLIENT
-word16 TLSX_GetRequestSize(WOLFSSL* ssl)
+#if defined(HAVE_NTRU) && defined(HAVE_QSH)
+
+static word32 GetEntropy(unsigned char* out, word32 num_bytes)
{
- word16 length = 0;
+ int ret = 0;
- if (TLSX_SupportExtensions(ssl)) {
- byte semaphore[SEMAPHORE_SIZE] = {0};
+ if (gRng == NULL) {
+ if ((gRng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL,
+ DYNAMIC_TYPE_TLSX)) == NULL)
+ return DRBG_OUT_OF_MEMORY;
+ wc_InitRng(gRng);
+ }
- EC_VALIDATE_REQUEST(ssl, semaphore);
- STK_VALIDATE_REQUEST(ssl);
+ if (gRngMutex == NULL) {
+ if ((gRngMutex = (wolfSSL_Mutex*)XMALLOC(sizeof(wolfSSL_Mutex), NULL,
+ DYNAMIC_TYPE_TLSX)) == NULL)
+ return DRBG_OUT_OF_MEMORY;
+ wc_InitMutex(gRngMutex);
+ }
- if (ssl->extensions)
- length += TLSX_GetSize(ssl->extensions, semaphore, 1);
+ ret |= wc_LockMutex(gRngMutex);
+ ret |= wc_RNG_GenerateBlock(gRng, out, num_bytes);
+ ret |= wc_UnLockMutex(gRngMutex);
- if (ssl->ctx && ssl->ctx->extensions)
- length += TLSX_GetSize(ssl->ctx->extensions, semaphore, 1);
+ if (ret != 0)
+ return DRBG_ENTROPY_FAIL;
- if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz)
- length += ssl->suites->hashSigAlgoSz + HELLO_EXT_LEN;
+ return DRBG_OK;
+}
+#endif
+
+
+#ifdef HAVE_QSH
+static int TLSX_CreateQSHKey(WOLFSSL* ssl, int type)
+{
+ int ret = -1;
+
+ (void)ssl;
+
+ switch (type) {
+#ifdef HAVE_NTRU
+ case WOLFSSL_NTRU_EESS439:
+ case WOLFSSL_NTRU_EESS593:
+ case WOLFSSL_NTRU_EESS743:
+ ret = TLSX_CreateNtruKey(ssl, type);
+ break;
+#endif
+ default:
+ WOLFSSL_MSG("Unknown type for creating NTRU key");
+ break;
}
- if (length)
- length += OPAQUE16_LEN; /* for total length storage */
+ return ret;
+}
- return length;
+
+static int TLSX_AddQSHKey(QSHKey** list, QSHKey* key)
+{
+ QSHKey* current;
+
+ if (key == NULL)
+ return BAD_FUNC_ARG;
+
+ /* if no public key stored in key then do not add */
+ if (key->pub.length == 0 || key->pub.buffer == NULL)
+ return 0;
+
+ /* first element to be added to the list */
+ current = *list;
+ if (current == NULL) {
+ *list = key;
+ return 0;
+ }
+
+ while (current->next) {
+ /* can only have one of the key in the list */
+ if (current->name == key->name)
+ return -1;
+ current = (QSHKey*)current->next;
+ }
+
+ current->next = (struct QSHKey*)key;
+
+ return 0;
}
-word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output)
+
+#if defined(HAVE_NTRU)
+int TLSX_CreateNtruKey(WOLFSSL* ssl, int type)
{
- word16 offset = 0;
+ int ret = -1;
+ int ntruType;
- if (TLSX_SupportExtensions(ssl) && output) {
- byte semaphore[SEMAPHORE_SIZE] = {0};
+ /* variable declarations for NTRU*/
+ QSHKey* temp = NULL;
+ byte public_key[1027];
+ word16 public_key_len = sizeof(public_key);
+ byte private_key[1120];
+ word16 private_key_len = sizeof(private_key);
+ DRBG_HANDLE drbg;
- offset += OPAQUE16_LEN; /* extensions length */
+ if (ssl == NULL)
+ return BAD_FUNC_ARG;
+
+ switch (type) {
+ case WOLFSSL_NTRU_EESS439:
+ ntruType = NTRU_EES439EP1;
+ break;
+ case WOLFSSL_NTRU_EESS593:
+ ntruType = NTRU_EES593EP1;
+ break;
+ case WOLFSSL_NTRU_EESS743:
+ ntruType = NTRU_EES743EP1;
+ break;
+ default:
+ WOLFSSL_MSG("Unknown type for creating NTRU key");
+ return -1;
+ }
+ ret = ntru_crypto_drbg_external_instantiate(GetEntropy, &drbg);
+ if (ret != DRBG_OK) {
+ WOLFSSL_MSG("NTRU drbg instantiate failed\n");
+ return ret;
+ }
+
+ if ((ret = ntru_crypto_ntru_encrypt_keygen(drbg, ntruType,
+ &public_key_len, NULL, &private_key_len, NULL)) != NTRU_OK)
+ return ret;
+
+ if ((ret = ntru_crypto_ntru_encrypt_keygen(drbg, ntruType,
+ &public_key_len, public_key, &private_key_len, private_key)) != NTRU_OK)
+ return ret;
+
+ ret = ntru_crypto_drbg_uninstantiate(drbg);
+ if (ret != NTRU_OK) {
+ WOLFSSL_MSG("NTRU drbg uninstantiate failed\n");
+ return ret;
+ }
+
+ if ((temp = (QSHKey*)XMALLOC(sizeof(QSHKey), ssl->heap,
+ DYNAMIC_TYPE_TLSX)) == NULL)
+ return MEMORY_E;
+ temp->name = type;
+ temp->pub.length = public_key_len;
+ temp->pub.buffer = (byte*)XMALLOC(public_key_len, ssl->heap,
+ DYNAMIC_TYPE_PUBLIC_KEY);
+ XMEMCPY(temp->pub.buffer, public_key, public_key_len);
+ temp->pri.length = private_key_len;
+ temp->pri.buffer = (byte*)XMALLOC(private_key_len, ssl->heap,
+ DYNAMIC_TYPE_ARRAYS);
+ XMEMCPY(temp->pri.buffer, private_key, private_key_len);
+ temp->next = NULL;
+
+ TLSX_AddQSHKey(&ssl->QSH_Key, temp);
+
+ (void)ssl;
+ (void)type;
+
+ return ret;
+}
+#endif
+
+
+/*
+ Used to find a public key from the list of keys
+ pubLen length of array
+ name input the name of the scheme looking for ie WOLFSSL_NTRU_ESSXXX
+
+ returns a pointer to public key byte* or NULL if not found
+ */
+static byte* TLSX_QSHKeyFind_Pub(QSHKey* qsh, word16* pubLen, word16 name)
+{
+ QSHKey* current = qsh;
+
+ if (qsh == NULL || pubLen == NULL)
+ return NULL;
+
+ *pubLen = 0;
+
+ while(current) {
+ if (current->name == name) {
+ *pubLen = current->pub.length;
+ return current->pub.buffer;
+ }
+ current = (QSHKey*)current->next;
+ }
+
+ return NULL;
+}
+#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_CURVE448) && defined(HAVE_SUPPORTED_CURVES)) || \
+ ((defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+ defined(HAVE_CURVE448)) && 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
+#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */
+
+ #ifndef HAVE_FIPS
+ #if defined(HAVE_CURVE448)
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_X448, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #endif /* HAVE_FIPS */
+
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+ #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 */
+
+ /* Add FFDHE supported groups. */
+ #ifdef HAVE_FFDHE_8192
+ if (8192/8 >= ssl->options.minDhKeySz &&
+ 8192/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_8192, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ #endif
+ #ifdef HAVE_FFDHE_6144
+ if (6144/8 >= ssl->options.minDhKeySz &&
+ 6144/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_6144, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ #endif
+ #ifdef HAVE_FFDHE_4096
+ if (4096/8 >= ssl->options.minDhKeySz &&
+ 4096/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_4096, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ #endif
+ #ifdef HAVE_FFDHE_3072
+ if (3072/8 >= ssl->options.minDhKeySz &&
+ 3072/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_3072, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ #endif
+ #ifdef HAVE_FFDHE_2048
+ if (2048/8 >= ssl->options.minDhKeySz &&
+ 2048/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_2048, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ #endif
+
+ (void)ssl;
+ (void)extensions;
+
+ return ret;
+}
+
+#endif
+
+int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
+{
+ int ret = 0;
+ byte* public_key = NULL;
+ word16 public_key_len = 0;
+#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK))
+ int usingPSK = 0;
+#endif
+#ifdef HAVE_QSH
+ TLSX* extension;
+ QSHScheme* qsh;
+ QSHScheme* next;
+
+ /* add supported QSHSchemes */
+ WOLFSSL_MSG("Adding supported QSH Schemes");
+#endif
+
+ /* server will add extension depending on what is parsed from client */
+ if (!isServer) {
+#ifdef HAVE_QSH
+ /* test if user has set a specific scheme already */
+ if (!ssl->user_set_QSHSchemes) {
+ if (ssl->sendQSHKeys && ssl->QSH_Key == NULL) {
+ if ((ret = TLSX_CreateQSHKey(ssl, WOLFSSL_NTRU_EESS743)) != 0) {
+ WOLFSSL_MSG("Error creating ntru keys");
+ return ret;
+ }
+ if ((ret = TLSX_CreateQSHKey(ssl, WOLFSSL_NTRU_EESS593)) != 0) {
+ WOLFSSL_MSG("Error creating ntru keys");
+ return ret;
+ }
+ if ((ret = TLSX_CreateQSHKey(ssl, WOLFSSL_NTRU_EESS439)) != 0) {
+ WOLFSSL_MSG("Error creating ntru keys");
+ return ret;
+ }
+
+ /* add NTRU 256 */
+ public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key,
+ &public_key_len, WOLFSSL_NTRU_EESS743);
+ }
+ if (TLSX_UseQSHScheme(&ssl->extensions, WOLFSSL_NTRU_EESS743,
+ public_key, public_key_len, ssl->heap)
+ != WOLFSSL_SUCCESS)
+ ret = -1;
+
+ /* add NTRU 196 */
+ if (ssl->sendQSHKeys) {
+ public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key,
+ &public_key_len, WOLFSSL_NTRU_EESS593);
+ }
+ if (TLSX_UseQSHScheme(&ssl->extensions, WOLFSSL_NTRU_EESS593,
+ public_key, public_key_len, ssl->heap)
+ != WOLFSSL_SUCCESS)
+ ret = -1;
+
+ /* add NTRU 128 */
+ if (ssl->sendQSHKeys) {
+ public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key,
+ &public_key_len, WOLFSSL_NTRU_EESS439);
+ }
+ if (TLSX_UseQSHScheme(&ssl->extensions, WOLFSSL_NTRU_EESS439,
+ public_key, public_key_len, ssl->heap)
+ != WOLFSSL_SUCCESS)
+ ret = -1;
+ }
+ else if (ssl->sendQSHKeys && ssl->QSH_Key == NULL) {
+ /* for each scheme make a client key */
+ extension = TLSX_Find(ssl->extensions, TLSX_QUANTUM_SAFE_HYBRID);
+ if (extension) {
+ qsh = (QSHScheme*)extension->data;
+
+ while (qsh) {
+ if ((ret = TLSX_CreateQSHKey(ssl, qsh->name)) != 0)
+ return ret;
+
+ /* get next now because qsh could be freed */
+ next = qsh->next;
+
+ /* find the public key created and add to extension*/
+ public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key,
+ &public_key_len, qsh->name);
+ if (TLSX_UseQSHScheme(&ssl->extensions, qsh->name,
+ public_key, public_key_len,
+ ssl->heap) != WOLFSSL_SUCCESS)
+ ret = -1;
+ qsh = next;
+ }
+ }
+ }
+#endif
+
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+ if (!ssl->options.disallowEncThenMac) {
+ ret = TLSX_EncryptThenMac_Use(ssl);
+ if (ret != 0)
+ return ret;
+ }
+#endif
+
+#if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+ defined(HAVE_CURVE448)) && 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 || CURVE25519 || CURVE448) && HAVE_SUPPORTED_CURVES */
+ } /* is not server */
+
+#if !defined(WOLFSSL_NO_SIGALG)
+ WOLFSSL_MSG("Adding signature algorithms extension");
+ if ((ret = TLSX_SetSignatureAlgorithms(&ssl->extensions, ssl, ssl->heap))
+ != 0) {
+ return ret;
+ }
+#else
+ ret = 0;
+#endif
+ #ifdef WOLFSSL_TLS13
+ if (!isServer && IsAtLeastTLSv1_3(ssl->version)) {
+ /* Add mandatory TLS v1.3 extension: supported version */
+ WOLFSSL_MSG("Adding supported versions extension");
+ if ((ret = TLSX_SetSupportedVersions(&ssl->extensions, ssl,
+ ssl->heap)) != 0) {
+ return ret;
+ }
+
+ #if !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) && \
+ !defined(HAVE_CURVE448) && 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;
+ ret = 0;
+ }
+ #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && 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) {
+ 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)
+ namedGroup = WOLFSSL_ECC_X25519;
+ #elif defined(HAVE_CURVE448)
+ namedGroup = WOLFSSL_ECC_X448;
+ #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)
+ namedGroup = WOLFSSL_FFDHE_2048;
+ #elif defined(HAVE_FFDHE_3072)
+ namedGroup = WOLFSSL_FFDHE_3072;
+ #elif defined(HAVE_FFDHE_4096)
+ namedGroup = WOLFSSL_FFDHE_4096;
+ #elif defined(HAVE_FFDHE_6144)
+ namedGroup = WOLFSSL_FFDHE_6144;
+ #elif defined(HAVE_FFDHE_8192)
+ namedGroup = WOLFSSL_FFDHE_8192;
+ #else
+ 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 && ssl->session.ticketLen > 0) {
+ WOLFSSL_SESSION* sess = &ssl->session;
+ word32 milli;
+
+ if (sess->ticketLen > MAX_PSK_ID_LEN) {
+ WOLFSSL_MSG("Session ticket length for PSK ext is too large");
+ return BUFFER_ERROR;
+ }
+
+ /* Determine the MAC algorithm for the cipher suite used. */
+ ssl->options.cipherSuite0 = sess->cipherSuite0;
+ ssl->options.cipherSuite = sess->cipherSuite;
+ ret = SetCipherSpecs(ssl);
+ if (ret != 0)
+ return ret;
+ milli = TimeNowInMilliseconds() - sess->ticketSeen +
+ sess->ticketAdd;
+ /* Pre-shared key is mandatory extension for resumption. */
+ ret = TLSX_PreSharedKey_Use(ssl, sess->ticket, sess->ticketLen,
+ milli, ssl->specs.mac_algorithm,
+ ssl->options.cipherSuite0,
+ ssl->options.cipherSuite, 1,
+ NULL);
+ if (ret != 0)
+ return ret;
+
+ usingPSK = 1;
+ }
+ #endif
+ #ifndef NO_PSK
+ if (ssl->options.client_psk_cb != NULL ||
+ ssl->options.client_psk_tls13_cb != NULL) {
+ /* Default ciphersuite. */
+ byte cipherSuite0 = TLS13_BYTE;
+ byte cipherSuite = WOLFSSL_DEF_PSK_CIPHER;
+ const char* cipherName = NULL;
+
+ if (ssl->options.client_psk_tls13_cb != NULL) {
+ ssl->arrays->psk_keySz = ssl->options.client_psk_tls13_cb(
+ ssl, ssl->arrays->server_hint,
+ ssl->arrays->client_identity, MAX_PSK_ID_LEN,
+ ssl->arrays->psk_key, MAX_PSK_KEY_LEN, &cipherName);
+ if (GetCipherSuiteFromName(cipherName, &cipherSuite0,
+ &cipherSuite) != 0) {
+ return PSK_KEY_ERROR;
+ }
+ }
+ else {
+ ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl,
+ ssl->arrays->server_hint, ssl->arrays->client_identity,
+ MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN);
+ }
+ if (ssl->arrays->psk_keySz == 0 ||
+ ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) {
+ return PSK_KEY_ERROR;
+ }
+ ssl->arrays->client_identity[MAX_PSK_ID_LEN] = '\0';
+ /* TODO: Callback should be able to change ciphersuite. */
+ ssl->options.cipherSuite0 = cipherSuite0;
+ ssl->options.cipherSuite = cipherSuite;
+ ret = SetCipherSpecs(ssl);
+ if (ret != 0)
+ return ret;
+
+ ret = TLSX_PreSharedKey_Use(ssl,
+ (byte*)ssl->arrays->client_identity,
+ (word16)XSTRLEN(ssl->arrays->client_identity),
+ 0, ssl->specs.mac_algorithm,
+ cipherSuite0, cipherSuite, 0,
+ NULL);
+ if (ret != 0)
+ return ret;
+
+ usingPSK = 1;
+ }
+ #endif
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ if (usingPSK) {
+ byte modes;
+
+ /* Pre-shared key modes: mandatory extension for resumption. */
+ modes = 1 << PSK_KE;
+ #if !defined(NO_DH) || defined(HAVE_ECC) || \
+ defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)
+ if (!ssl->options.noPskDheKe)
+ modes |= 1 << PSK_DHE_KE;
+ #endif
+ ret = TLSX_PskKeModes_Use(ssl, modes);
+ if (ret != 0)
+ return ret;
+ }
+ #endif
+ #if defined(WOLFSSL_POST_HANDSHAKE_AUTH)
+ if (!isServer && ssl->options.postHandshakeAuth) {
+ ret = TLSX_PostHandAuth_Use(ssl);
+ if (ret != 0)
+ return ret;
+ }
+ #endif
+ }
+
+ #endif
+
+ (void)isServer;
+ (void)public_key;
+ (void)public_key_len;
+ (void)ssl;
+
+ return ret;
+}
+
+
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
+
+/** Tells the buffered size of extensions to be sent into the client hello. */
+int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word16* pLength)
+{
+ int ret = 0;
+ word16 length = 0;
+ byte semaphore[SEMAPHORE_SIZE] = {0};
+
+ if (!TLSX_SupportExtensions(ssl))
+ return 0;
+ if (msgType == client_hello) {
EC_VALIDATE_REQUEST(ssl, semaphore);
+ PF_VALIDATE_REQUEST(ssl, semaphore);
+ QSH_VALIDATE_REQUEST(ssl, semaphore);
+ WOLF_STK_VALIDATE_REQUEST(ssl);
+#if !defined(WOLFSSL_NO_SIGALG)
+ if (ssl->suites->hashSigAlgoSz == 0)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
+#endif
+#if defined(WOLFSSL_TLS13)
+ if (!IsAtLeastTLSv1_2(ssl))
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+ if (!IsAtLeastTLSv1_3(ssl->version)) {
+ 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));
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES));
+ #endif
+ #ifdef WOLFSSL_EARLY_DATA
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
+ #endif
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
+ #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_POST_HANDSHAKE_AUTH));
+ #endif
+ }
+#endif
+ #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
+ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+ if (!ssl->ctx->cm->ocspStaplingEnabled) {
+ /* mark already sent, so it won't send it */
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST_V2));
+ }
+ #endif
+ }
- if (ssl->extensions)
- offset += TLSX_Write(ssl->extensions, output + offset,
- semaphore, 1);
+#ifdef WOLFSSL_TLS13
+ #ifndef NO_CERTS
+ else if (msgType == certificate_request) {
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+#if !defined(WOLFSSL_NO_SIGALG)
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
+#endif
+ /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
+ * TLSX_CERTIFICATE_AUTHORITIES, OID_FILTERS
+ * TLSX_STATUS_REQUEST
+ */
+ }
+ #endif
+#endif
+ if (ssl->extensions) {
+ ret = TLSX_GetSize(ssl->extensions, semaphore, msgType, &length);
+ if (ret != 0)
+ return ret;
+ }
+ if (ssl->ctx && ssl->ctx->extensions) {
+ ret = TLSX_GetSize(ssl->ctx->extensions, semaphore, msgType, &length);
+ if (ret != 0)
+ return ret;
+ }
- if (ssl->ctx && ssl->ctx->extensions)
- offset += TLSX_Write(ssl->ctx->extensions, output + offset,
- semaphore, 1);
+#ifdef HAVE_EXTENDED_MASTER
+ if (msgType == client_hello && ssl->options.haveEMS &&
+ (!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade)) {
+ length += HELLO_EXT_SZ;
+ }
+#endif
- if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz)
- {
- int i;
- /* extension type */
- c16toa(HELLO_EXT_SIG_ALGO, output + offset);
- offset += HELLO_EXT_TYPE_SZ;
+ if (length)
+ length += OPAQUE16_LEN; /* for total length storage. */
- /* extension data length */
- c16toa(OPAQUE16_LEN + ssl->suites->hashSigAlgoSz, output + offset);
- offset += OPAQUE16_LEN;
+ *pLength += length;
- /* sig algos length */
- c16toa(ssl->suites->hashSigAlgoSz, output + offset);
- offset += OPAQUE16_LEN;
+ return ret;
+}
- /* sig algos */
- for (i = 0; i < ssl->suites->hashSigAlgoSz; i++, offset++)
- output[offset] = ssl->suites->hashSigAlgo[i];
+/** Writes the extensions to be sent into the client hello. */
+int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word16* pOffset)
+{
+ int ret = 0;
+ word16 offset = 0;
+ byte semaphore[SEMAPHORE_SIZE] = {0};
+
+ if (!TLSX_SupportExtensions(ssl) || output == NULL)
+ return 0;
+
+ offset += OPAQUE16_LEN; /* extensions length */
+
+ if (msgType == client_hello) {
+ EC_VALIDATE_REQUEST(ssl, semaphore);
+ PF_VALIDATE_REQUEST(ssl, semaphore);
+ WOLF_STK_VALIDATE_REQUEST(ssl);
+ QSH_VALIDATE_REQUEST(ssl, semaphore);
+#if !defined(WOLFSSL_NO_SIGALG)
+ if (ssl->suites->hashSigAlgoSz == 0)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
+#endif
+#ifdef WOLFSSL_TLS13
+ if (!IsAtLeastTLSv1_2(ssl))
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+ if (!IsAtLeastTLSv1_3(ssl->version)) {
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES));
+ #endif
+ #ifdef WOLFSSL_EARLY_DATA
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
+ #endif
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
+ #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_POST_HANDSHAKE_AUTH));
+ #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
+ * protocol.
+ */
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ #endif
+#endif
+ #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
+ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+ /* mark already sent, so it won't send it */
+ if (!ssl->ctx->cm->ocspStaplingEnabled) {
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST_V2));
}
+ #endif
+ }
+#ifdef WOLFSSL_TLS13
+ #ifndef NO_CERTS
+ else if (msgType == certificate_request) {
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+#if !defined(WOLFSSL_NO_SIGALG)
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
+#endif
+ /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
+ * TLSX_CERTIFICATE_AUTHORITIES, TLSX_OID_FILTERS
+ * TLSX_STATUS_REQUEST
+ */
+ }
+ #endif
+#endif
+ if (ssl->extensions) {
+ ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+ msgType, &offset);
+ if (ret != 0)
+ return ret;
+ }
+ if (ssl->ctx && ssl->ctx->extensions) {
+ ret = TLSX_Write(ssl->ctx->extensions, output + offset, semaphore,
+ msgType, &offset);
+ if (ret != 0)
+ return ret;
+ }
- if (offset > OPAQUE16_LEN)
- c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
+#ifdef HAVE_EXTENDED_MASTER
+ if (msgType == client_hello && ssl->options.haveEMS &&
+ (!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade)) {
+ WOLFSSL_MSG("EMS extension to write");
+ c16toa(HELLO_EXT_EXTMS, output + offset);
+ offset += HELLO_EXT_TYPE_SZ;
+ c16toa(0, output + offset);
+ offset += HELLO_EXT_SZ_SZ;
}
+#endif
- return offset;
+#ifdef WOLFSSL_TLS13
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ if (msgType == client_hello && IsAtLeastTLSv1_3(ssl->version)) {
+ /* Write out what we can of Pre-shared key extension. */
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+ client_hello, &offset);
+ if (ret != 0)
+ return ret;
+ }
+ #endif
+#endif
+
+ if (offset > OPAQUE16_LEN || msgType != client_hello)
+ c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
+
+ *pOffset += offset;
+
+ return ret;
}
-#endif /* NO_WOLFSSL_CLIENT */
+#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */
-#ifndef NO_WOLFSSL_SERVER
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_SERVER)
-word16 TLSX_GetResponseSize(WOLFSSL* ssl)
+/** Tells the buffered size of extensions to be sent into the server hello. */
+int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength)
{
+ int ret = 0;
word16 length = 0;
byte semaphore[SEMAPHORE_SIZE] = {0};
- if (TLSX_SupportExtensions(ssl))
- length += TLSX_GetSize(ssl->extensions, semaphore, 0);
+ switch (msgType) {
+#ifndef NO_WOLFSSL_SERVER
+ case server_hello:
+ PF_VALIDATE_RESPONSE(ssl, semaphore);
+ #ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version)) {
+ 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)
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ #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));
+ 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));
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ #endif
+ #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+ #endif
+ #if defined(HAVE_SECURE_RENEGOTIATION)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_RENEGOTIATION_INFO));
+ #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:
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+ /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
+ * TLSX_SERVER_CERTIFICATE_TYPE
+ */
+ break;
+ #endif
+#endif
+ }
+
+ #ifdef HAVE_QSH
+ /* change response if not using TLS_QSH */
+ if (!ssl->options.haveQSH) {
+ TLSX* ext = TLSX_Find(ssl->extensions, TLSX_QUANTUM_SAFE_HYBRID);
+ if (ext)
+ ext->resp = 0;
+ }
+ #endif
+
+#ifdef HAVE_EXTENDED_MASTER
+ if (ssl->options.haveEMS && msgType == server_hello &&
+ !IsAtLeastTLSv1_3(ssl->version)) {
+ length += HELLO_EXT_SZ;
+ }
+#endif
+
+ if (TLSX_SupportExtensions(ssl)) {
+ ret = TLSX_GetSize(ssl->extensions, semaphore, msgType, &length);
+ if (ret != 0)
+ return ret;
+ }
/* All the response data is set at the ssl object only, so no ctx here. */
- if (length)
- length += OPAQUE16_LEN; /* for total length storage */
+ if (length || msgType != server_hello)
+ length += OPAQUE16_LEN; /* for total length storage. */
- return length;
+ *pLength += length;
+
+ return ret;
}
-word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output)
+/** Writes the server hello extensions into a buffer. */
+int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset)
{
+ int ret = 0;
word16 offset = 0;
if (TLSX_SupportExtensions(ssl) && output) {
byte semaphore[SEMAPHORE_SIZE] = {0};
+ switch (msgType) {
+#ifndef NO_WOLFSSL_SERVER
+ case server_hello:
+ PF_VALIDATE_RESPONSE(ssl, semaphore);
+ #ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version)) {
+ 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)
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ #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));
+ /* 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));
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ #endif
+ #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+ #endif
+ #if defined(HAVE_SECURE_RENEGOTIATION)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_RENEGOTIATION_INFO));
+ #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:
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+ /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
+ * TLSX_SERVER_CERTIFICATE_TYPE
+ */
+ break;
+ #endif
+ #endif
+ }
+
offset += OPAQUE16_LEN; /* extensions length */
- offset += TLSX_Write(ssl->extensions, output + offset, semaphore, 0);
+ ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+ msgType, &offset);
+ if (ret != 0)
+ return ret;
+
+#ifdef WOLFSSL_TLS13
+ if (msgType == hello_retry_request) {
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
+ ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+ msgType, &offset);
+ if (ret != 0)
+ return ret;
+ }
+#endif
+
+#ifdef HAVE_EXTENDED_MASTER
+ 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;
+ c16toa(0, output + offset);
+ offset += HELLO_EXT_SZ_SZ;
+ }
+#endif
- if (offset > OPAQUE16_LEN)
+ if (offset > OPAQUE16_LEN || msgType != server_hello)
c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
}
- return offset;
+ if (pOffset)
+ *pOffset += offset;
+
+ return ret;
}
-#endif /* NO_WOLFSSL_SERVER */
+#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_SERVER */
+
+#ifdef WOLFSSL_TLS13
+int TLSX_ParseVersion(WOLFSSL* ssl, byte* input, word16 length, byte msgType,
+ int* found)
+{
+ int ret = 0;
+ int offset = 0;
+
+ *found = 0;
+ while (offset < (int)length) {
+ word16 type;
+ word16 size;
+
+ if (offset + (2 * OPAQUE16_LEN) > length) {
+ ret = BUFFER_ERROR;
+ break;
+ }
+
+ ato16(input + offset, &type);
+ offset += HELLO_EXT_TYPE_SZ;
+
+ ato16(input + offset, &size);
+ offset += OPAQUE16_LEN;
+
+ if (offset + size > length) {
+ ret = BUFFER_ERROR;
+ break;
+ }
+
+ if (type == TLSX_SUPPORTED_VERSIONS) {
+ *found = 1;
-int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
+ WOLFSSL_MSG("Supported Versions extension received");
+
+ ret = SV_PARSE(ssl, input + offset, size, msgType);
+ break;
+ }
+
+ offset += size;
+ }
+
+ return ret;
+}
+#endif
+
+/** Parses a buffer of TLS extensions. */
+int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType,
Suites *suites)
{
int ret = 0;
word16 offset = 0;
+ 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
if (!ssl || !input || (isRequest && !suites))
return BAD_FUNC_ARG;
@@ -2222,6 +10766,11 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
word16 type;
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;
@@ -2235,67 +10784,416 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
return BUFFER_ERROR;
switch (type) {
- case SERVER_NAME_INDICATION:
+ case TLSX_SERVER_NAME:
WOLFSSL_MSG("SNI extension received");
-
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->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 = SNI_PARSE(ssl, input + offset, size, isRequest);
break;
- case MAX_FRAGMENT_LENGTH:
- WOLFSSL_MSG("Max Fragment Length extension received");
+ case TLSX_TRUSTED_CA_KEYS:
+ WOLFSSL_MSG("Trusted CA extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version) &&
+ msgType != client_hello &&
+ msgType != encrypted_extensions) {
+ return EXT_NOT_ALLOWED;
+ }
+#endif
+ ret = TCA_PARSE(ssl, input + offset, size, isRequest);
+ break;
+ case TLSX_MAX_FRAGMENT_LENGTH:
+ WOLFSSL_MSG("Max Fragment Length extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->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);
break;
- case TRUNCATED_HMAC:
+ case TLSX_TRUNCATED_HMAC:
WOLFSSL_MSG("Truncated HMAC extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version))
+ break;
+#endif
ret = THM_PARSE(ssl, input + offset, size, isRequest);
break;
- case ELLIPTIC_CURVES:
- WOLFSSL_MSG("Elliptic Curves extension received");
-
+ case TLSX_SUPPORTED_GROUPS:
+ WOLFSSL_MSG("Supported Groups extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->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 = EC_PARSE(ssl, input + offset, size, isRequest);
break;
- case SECURE_RENEGOTIATION:
+ case TLSX_EC_POINT_FORMATS:
+ WOLFSSL_MSG("Point Formats extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version))
+ break;
+#endif
+ ret = PF_PARSE(ssl, input + offset, size, isRequest);
+ break;
+
+ case TLSX_STATUS_REQUEST:
+ WOLFSSL_MSG("Certificate Status Request extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ #ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version) &&
+ msgType != client_hello &&
+ msgType != certificate_request &&
+ msgType != certificate) {
+ break;
+ }
+ #endif
+ ret = CSR_PARSE(ssl, input + offset, size, isRequest);
+ break;
+
+ case TLSX_STATUS_REQUEST_V2:
+ WOLFSSL_MSG("Certificate Status Request v2 extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version) &&
+ msgType != client_hello &&
+ msgType != certificate_request &&
+ msgType != certificate) {
+ return EXT_NOT_ALLOWED;
+ }
+#endif
+ ret = CSR2_PARSE(ssl, input + offset, size, isRequest);
+ break;
+
+#ifdef HAVE_EXTENDED_MASTER
+ case HELLO_EXT_EXTMS:
+ WOLFSSL_MSG("Extended Master Secret extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version))
+ break;
+#endif
+ if (size != 0)
+ return BUFFER_ERROR;
+
+#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_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version))
+ break;
+#endif
ret = SCR_PARSE(ssl, input + offset, size, isRequest);
break;
- case SESSION_TICKET:
+ case TLSX_SESSION_TICKET:
WOLFSSL_MSG("Session Ticket extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#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;
+
+ case TLSX_QUANTUM_SAFE_HYBRID:
+ WOLFSSL_MSG("Quantum-Safe-Hybrid extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version))
+ break;
+#endif
+ ret = QSH_PARSE(ssl, input + offset, size, isRequest);
+ break;
+
+ case TLSX_APPLICATION_LAYER_PROTOCOL:
+ WOLFSSL_MSG("ALPN extension received");
+
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
- ret = STK_PARSE(ssl, input + offset, size, isRequest);
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->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);
break;
+#if !defined(WOLFSSL_NO_SIGALG)
+ case TLSX_SIGNATURE_ALGORITHMS:
+ WOLFSSL_MSG("Signature Algorithms extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_2(ssl))
+ break;
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version) &&
+ msgType != client_hello &&
+ msgType != certificate_request) {
+ return EXT_NOT_ALLOWED;
+ }
+#endif
+ ret = SA_PARSE(ssl, input + offset, size, isRequest, suites);
+ break;
+#endif
- case HELLO_EXT_SIG_ALGO:
- if (isRequest) {
- /* do not mess with offset inside the switch! */
- if (IsAtLeastTLSv1_2(ssl)) {
- ato16(input + offset, &suites->hashSigAlgoSz);
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+ case TLSX_ENCRYPT_THEN_MAC:
+ WOLFSSL_MSG("Encrypt-Then-Mac extension received");
- if (suites->hashSigAlgoSz > size - OPAQUE16_LEN)
- return BUFFER_ERROR;
+ /* Ignore for TLS 1.3+ */
+ if (IsAtLeastTLSv1_3(ssl->version))
+ break;
- XMEMCPY(suites->hashSigAlgo,
- input + offset + OPAQUE16_LEN,
- min(suites->hashSigAlgoSz,
- HELLO_EXT_SIGALGO_MAX));
- }
- } else {
- WOLFSSL_MSG("Servers MUST NOT send SIG ALGO extension.");
+ ret = ETM_PARSE(ssl, input + offset, size, msgType);
+ break;
+#endif /* HAVE_ENCRYPT_THEN_MAC */
+
+#ifdef WOLFSSL_TLS13
+ case TLSX_SUPPORTED_VERSIONS:
+ WOLFSSL_MSG("Skipping Supported Versions - already processed");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ break;
+
+ case TLSX_COOKIE:
+ WOLFSSL_MSG("Cookie extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->version))
+ break;
+
+ 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");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->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");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->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");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->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");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->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");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->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");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->version))
+ break;
+
+ if (msgType != client_hello && msgType != server_hello &&
+ msgType != hello_retry_request) {
+ return EXT_NOT_ALLOWED;
+ }
+ ret = KS_PARSE(ssl, input + offset, size, msgType);
+ break;
+#endif
+ default:
+ WOLFSSL_MSG("Unknown TLS extension type");
}
/* offset should be updated here! */
offset += size;
}
+#ifdef HAVE_EXTENDED_MASTER
+ if (!isRequest && ssl->options.haveEMS && !pendingEMS)
+ ssl->options.haveEMS = 0;
+#endif
+
+ if (ret == 0)
+ ret = SNI_VERIFY_PARSE(ssl, isRequest);
+ if (ret == 0)
+ ret = TCA_VERIFY_PARSE(ssl, isRequest);
+
return ret;
}
@@ -2304,143 +11202,554 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
#undef TURN_ON
#undef SEMAPHORE_SIZE
-#endif
-
+#endif /* HAVE_TLS_EXTENSIONS */
#ifndef NO_WOLFSSL_CLIENT
-#ifndef NO_OLD_TLS
+ WOLFSSL_METHOD* wolfTLS_client_method(void)
+ {
+ return wolfTLS_client_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLS_client_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* method =
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLS_client_method_ex");
+ if (method) {
+ #if defined(WOLFSSL_TLS13)
+ InitSSL_Method(method, MakeTLSv1_3());
+ #elif !defined(WOLFSSL_NO_TLS12)
+ InitSSL_Method(method, MakeTLSv1_2());
+ #elif !defined(NO_OLD_TLS)
+ InitSSL_Method(method, MakeTLSv1_1());
+ #elif defined(WOLFSSL_ALLOW_TLSV10)
+ InitSSL_Method(method, MakeTLSv1());
+ #else
+ #error No TLS version enabled!
+ #endif
+
+ method->downgrade = 1;
+ method->side = WOLFSSL_CLIENT_END;
+ }
+ return method;
+ }
+#ifndef NO_OLD_TLS
+ #ifdef WOLFSSL_ALLOW_TLSV10
WOLFSSL_METHOD* wolfTLSv1_client_method(void)
{
+ return wolfTLSv1_client_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_client_method_ex(void* heap)
+ {
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (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)
+ {
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (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 NO_SHA256 /* can't use without SHA256 */
-
+#ifndef WOLFSSL_NO_TLS12
+ WOLFSSL_ABI
WOLFSSL_METHOD* wolfTLSv1_2_client_method(void)
{
+ return wolfTLSv1_2_client_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_2_client_method_ex(void* heap)
+ {
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ 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 */
-#endif
+#ifdef WOLFSSL_TLS13
+ /* The TLS v1.3 client method data.
+ *
+ * returns the method data for a TLS v1.3 client.
+ */
+ WOLFSSL_ABI
+ WOLFSSL_METHOD* wolfTLSv1_3_client_method(void)
+ {
+ return wolfTLSv1_3_client_method_ex(NULL);
+ }
+ /* The TLS v1.3 client method data.
+ *
+ * heap The heap used for allocation.
+ * returns the method data for a TLS v1.3 client.
+ */
+ WOLFSSL_METHOD* wolfTLSv1_3_client_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* method = (WOLFSSL_METHOD*)
+ XMALLOC(sizeof(WOLFSSL_METHOD), heap,
+ DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLSv1_3_client_method_ex");
+ if (method)
+ InitSSL_Method(method, MakeTLSv1_3());
+ return method;
+ }
+#endif /* WOLFSSL_TLS13 */
+
+#ifdef WOLFSSL_DTLS
- WOLFSSL_METHOD* wolfSSLv23_client_method(void)
+ WOLFSSL_METHOD* wolfDTLS_client_method(void)
+ {
+ return wolfDTLS_client_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfDTLS_client_method_ex(void* heap)
{
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("DTLS_client_method_ex");
if (method) {
-#ifndef NO_SHA256 /* 1.2 requires SHA256 */
- InitSSL_Method(method, MakeTLSv1_2());
-#else
- InitSSL_Method(method, MakeTLSv1_1());
-#endif
-#ifndef NO_OLD_TLS
+ #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;
-#endif
+ method->side = WOLFSSL_CLIENT_END;
}
return method;
}
+ #ifndef NO_OLD_TLS
+ 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
+ #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_TLS13
+ /* Gets a WOLFSL_METHOD type that is not set as client or server
+ *
+ * Returns a pointer to a WOLFSSL_METHOD struct
+ */
+ WOLFSSL_METHOD* wolfTLSv1_3_method(void)
+ {
+ return wolfTLSv1_3_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_3_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* m;
+ WOLFSSL_ENTER("TLSv1_3_method");
+ #ifndef NO_WOLFSSL_CLIENT
+ m = wolfTLSv1_3_client_method_ex(heap);
+ #else
+ m = wolfTLSv1_3_server_method_ex(heap);
+ #endif
+ if (m != NULL) {
+ m->side = WOLFSSL_NEITHER_END;
+ }
+ return m;
+ }
+ #endif /* WOLFSSL_TLS13 */
+
+#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 */
+
#ifndef NO_WOLFSSL_SERVER
-#ifndef NO_OLD_TLS
+ WOLFSSL_METHOD* wolfTLS_server_method(void)
+ {
+ return wolfTLS_server_method_ex(NULL);
+ }
+
+ WOLFSSL_METHOD* wolfTLS_server_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* method =
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLS_server_method_ex");
+ if (method) {
+ #if defined(WOLFSSL_TLS13)
+ InitSSL_Method(method, MakeTLSv1_3());
+ #elif !defined(WOLFSSL_NO_TLS12)
+ InitSSL_Method(method, MakeTLSv1_2());
+ #elif !defined(NO_OLD_TLS)
+ InitSSL_Method(method, MakeTLSv1_1());
+ #elif defined(WOLFSSL_ALLOW_TLSV10)
+ InitSSL_Method(method, MakeTLSv1());
+ #else
+ #error No TLS version enabled!
+ #endif
+
+ method->downgrade = 1;
+ method->side = WOLFSSL_SERVER_END;
+ }
+ return method;
+ }
+#ifndef NO_OLD_TLS
+ #ifdef WOLFSSL_ALLOW_TLSV10
WOLFSSL_METHOD* wolfTLSv1_server_method(void)
{
+ return wolfTLSv1_server_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_server_method_ex(void* heap)
+ {
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLSv1_server_method_ex");
if (method) {
InitSSL_Method(method, MakeTLSv1());
method->side = WOLFSSL_SERVER_END;
}
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)
+ {
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (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());
method->side = WOLFSSL_SERVER_END;
}
return method;
}
-
#endif /* !NO_OLD_TLS */
-#ifndef NO_SHA256 /* can't use without SHA256 */
+#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)
+ {
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLSv1_2_server_method_ex");
if (method) {
InitSSL_Method(method, MakeTLSv1_2());
method->side = WOLFSSL_SERVER_END;
}
return method;
}
+#endif /* !WOLFSSL_NO_TLS12 */
-#endif
+#ifdef WOLFSSL_TLS13
+ /* The TLS v1.3 server method data.
+ *
+ * returns the method data for a TLS v1.3 server.
+ */
+ WOLFSSL_METHOD* wolfTLSv1_3_server_method(void)
+ {
+ return wolfTLSv1_3_server_method_ex(NULL);
+ }
+ /* The TLS v1.3 server method data.
+ *
+ * heap The heap used for allocation.
+ * returns the method data for a TLS v1.3 server.
+ */
+ WOLFSSL_METHOD* wolfTLSv1_3_server_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* method =
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLSv1_3_server_method_ex");
+ if (method) {
+ InitSSL_Method(method, MakeTLSv1_3());
+ method->side = WOLFSSL_SERVER_END;
+ }
+ return method;
+ }
+#endif /* WOLFSSL_TLS13 */
- WOLFSSL_METHOD* wolfSSLv23_server_method(void)
+#ifdef WOLFSSL_DTLS
+ WOLFSSL_METHOD* wolfDTLS_server_method(void)
+ {
+ return wolfDTLS_server_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfDTLS_server_method_ex(void* heap)
{
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("DTLS_server_method_ex");
if (method) {
-#ifndef NO_SHA256 /* 1.2 requires SHA256 */
- InitSSL_Method(method, MakeTLSv1_2());
-#else
- InitSSL_Method(method, MakeTLSv1_1());
-#endif
- method->side = WOLFSSL_SERVER_END;
-#ifndef NO_OLD_TLS
+ #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;
-#endif /* !NO_OLD_TLS */
+ method->side = WOLFSSL_SERVER_END;
}
return method;
}
+ #ifndef NO_OLD_TLS
+ 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 /* NO_TLS */
+#endif /* WOLFCRYPT_ONLY */