Merge pull request #5623 from dgarske/hpke

Adds support for TLS v1.3 Encrypted Client Hello (ECH) and HPKE (Hybrid Public Key Encryption)
pull/5912/head
JacobBarthelmeh 2023-01-19 10:03:28 -07:00 committed by GitHub
commit fc19aed8c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 4109 additions and 47 deletions

View File

@ -742,6 +742,7 @@ then
test "$enable_trusted_ca" = "" && enable_trusted_ca=yes test "$enable_trusted_ca" = "" && enable_trusted_ca=yes
test "$enable_session_ticket" = "" && enable_session_ticket=yes test "$enable_session_ticket" = "" && enable_session_ticket=yes
test "$enable_earlydata" = "" && enable_earlydata=yes test "$enable_earlydata" = "" && enable_earlydata=yes
test "$enable_ech" = "" && enable_ech=yes
if test "$ENABLED_32BIT" != "yes" if test "$ENABLED_32BIT" != "yes"
then then
@ -1120,6 +1121,25 @@ AC_ARG_ENABLE([cryptonly],
AS_IF([test "x$FIPS_VERSION" = "xrand"],[ENABLED_CRYPTONLY="yes"]) AS_IF([test "x$FIPS_VERSION" = "xrand"],[ENABLED_CRYPTONLY="yes"])
# ECH
AC_ARG_ENABLE([ech],
[AS_HELP_STRING([--enable-ech],[Enable ECH (default: disabled)])],
[ ENABLED_ECH=$enableval ],
[ ENABLED_ECH=no ]
)
if test "$ENABLED_ECH" = "yes"
then
AM_CFLAGS="$AM_CFLAGS -DHAVE_ECH"
test "$enable_hpke" = "" && enable_hpke=yes
test "$enable_ecc" = "" && enable_ecc=yes
test "$enable_curve25519" = "" && enable_curve25519=yes
test "$enable_sha256" = "" && enable_sha256=yes
test "$enable_tlsx" = "" && enable_tlsx=yes
test "$enable_sni" = "" && enable_sni=yes
test "$enable_tls13" = "" && enable_tls13=yes
fi
# DTLS # DTLS
# DTLS is a prereq for the options mcast, sctp, and jni. Enabling any of those # DTLS is a prereq for the options mcast, sctp, and jni. Enabling any of those
# without DTLS will also enable DTLS. # without DTLS will also enable DTLS.
@ -2980,6 +3000,20 @@ then
AM_CFLAGS="$AM_CFLAGS -DHAVE_HKDF" AM_CFLAGS="$AM_CFLAGS -DHAVE_HKDF"
fi fi
# HPKE
AC_ARG_ENABLE([hpke],
[AS_HELP_STRING([--enable-hpke],[Enable HKPE support (default: disabled)])],
[ ENABLED_HPKE=$enableval ],
[ ENABLED_HPKE=no ]
)
if test "$ENABLED_HPKE" = "yes"
then
AM_CFLAGS="$AM_CFLAGS -DHAVE_HPKE"
test "$enable_hkdf" = "" && enable_hkdf=yes
fi
# X9.63 KDF # X9.63 KDF
AC_ARG_ENABLE([x963kdf], AC_ARG_ENABLE([x963kdf],
[AS_HELP_STRING([--enable-x963kdf],[Enable X9.63 KDF support (default: disabled)])], [AS_HELP_STRING([--enable-x963kdf],[Enable X9.63 KDF support (default: disabled)])],
@ -8450,6 +8484,7 @@ AM_CONDITIONAL([BUILD_PSA],[test "x$ENABLED_PSA" = "xyes"])
AM_CONDITIONAL([BUILD_DTLS13],[test "x$ENABLED_DTLS13" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_DTLS13],[test "x$ENABLED_DTLS13" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_QUIC],[test "x$ENABLED_QUIC" = "xyes"]) AM_CONDITIONAL([BUILD_QUIC],[test "x$ENABLED_QUIC" = "xyes"])
AM_CONDITIONAL([BUILD_DTLS_CID],[test "x$ENABLED_DTLS_CID" = "xyes"]) AM_CONDITIONAL([BUILD_DTLS_CID],[test "x$ENABLED_DTLS_CID" = "xyes"])
AM_CONDITIONAL([BUILD_HPKE],[test "x$ENABLED_HPKE" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_DTLS],[test "x$ENABLED_DTLS" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_DTLS],[test "x$ENABLED_DTLS" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_MAXQ10XX],[test "x$ENABLED_MAXQ10XX" = "xyes"]) AM_CONDITIONAL([BUILD_MAXQ10XX],[test "x$ENABLED_MAXQ10XX" = "xyes"])
@ -8740,6 +8775,7 @@ echo " * PWDBASED: $ENABLED_PWDBASED"
echo " * scrypt: $ENABLED_SCRYPT" echo " * scrypt: $ENABLED_SCRYPT"
echo " * wolfCrypt Only: $ENABLED_CRYPTONLY" echo " * wolfCrypt Only: $ENABLED_CRYPTONLY"
echo " * HKDF: $ENABLED_HKDF" echo " * HKDF: $ENABLED_HKDF"
echo " * HPKE: $ENABLED_HPKE"
echo " * X9.63 KDF: $ENABLED_X963KDF" echo " * X9.63 KDF: $ENABLED_X963KDF"
echo " * MD4: $ENABLED_MD4" echo " * MD4: $ENABLED_MD4"
echo " * PSK: $ENABLED_PSK" echo " * PSK: $ENABLED_PSK"

View File

@ -234,6 +234,9 @@ extern "C" {
#define HAVE_KEYING_MATERIAL #define HAVE_KEYING_MATERIAL
#define WOLFSSL_HAVE_PRF #define WOLFSSL_HAVE_PRF
/* Encrypted Client Hello */
#define HAVE_HPKE
#define HAVE_ECH
/* Non-Standard Algorithms (DG disabled) */ /* Non-Standard Algorithms (DG disabled) */
//#define HAVE_CAMELLIA //#define HAVE_CAMELLIA

View File

@ -509,6 +509,10 @@ if BUILD_ASN
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/asn.c src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/asn.c
endif endif
if BUILD_HPKE
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/hpke.c
endif
endif !BUILD_FIPS_RAND endif !BUILD_FIPS_RAND
if BUILD_CODING if BUILD_CODING

View File

@ -2398,6 +2398,36 @@ void wolfSSL_CRYPTO_cleanup_ex_data(WOLFSSL_CRYPTO_EX_DATA* ex_data)
} }
#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ #endif /* HAVE_EX_DATA_CLEANUP_HOOKS */
#if defined(HAVE_ECH)
/* free all ech configs in the list */
static void FreeEchConfigs(WOLFSSL_EchConfig* configs, void* heap)
{
WOLFSSL_EchConfig* working_config = configs;
WOLFSSL_EchConfig* next_config;
while (working_config != NULL) {
next_config = working_config->next;
XFREE(working_config->cipherSuites, heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(working_config->publicName, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (working_config->raw != NULL)
XFREE(working_config->raw, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (working_config->receiverPrivkey != NULL) {
wc_HpkeFreeKey(NULL, working_config->kemId,
working_config->receiverPrivkey, heap);
}
XFREE(working_config, heap, DYNAMIC_TYPE_TMP_BUFFER);
working_config = next_config;
}
(void)heap;
}
#endif
/* In case contexts are held in array and don't want to free actual ctx. */ /* In case contexts are held in array and don't want to free actual ctx. */
/* The allocations done in InitSSL_Ctx must be free'd with ctx->onHeapHint /* The allocations done in InitSSL_Ctx must be free'd with ctx->onHeapHint
@ -2554,6 +2584,10 @@ void SSL_CtxResourceFree(WOLFSSL_CTX* ctx)
ctx->staticKELockInit = 0; ctx->staticKELockInit = 0;
} }
#endif #endif
#endif
#if defined(HAVE_ECH)
FreeEchConfigs(ctx->echConfigs, ctx->heap);
ctx->echConfigs = NULL;
#endif #endif
(void)heapAtCTXInit; (void)heapAtCTXInit;
} }
@ -6538,6 +6572,71 @@ void FreeHandshakeHashes(WOLFSSL* ssl)
} }
} }
/* copy the hashes from source to a newly made destination return status */
int InitHandshakeHashesAndCopy(WOLFSSL* ssl, HS_Hashes* source,
HS_Hashes** destination)
{
int ret = 0;
HS_Hashes* tmpHashes;
if (source == NULL)
return BAD_FUNC_ARG;
/* save the original so we can put it back afterward */
tmpHashes = ssl->hsHashes;
ssl->hsHashes = NULL;
InitHandshakeHashes(ssl);
*destination = ssl->hsHashes;
ssl->hsHashes = tmpHashes;
/* now copy the source contents to the destination */
#ifndef NO_OLD_TLS
#ifndef NO_SHA
ret = wc_ShaCopy(&source->hashSha, &(*destination)->hashSha);
#endif
#ifndef NO_MD5
if (ret == 0)
ret = wc_Md5Copy(&source->hashMd5, &(*destination)->hashMd5);
#endif
#endif /* !NO_OLD_TLS */
#ifndef NO_SHA256
if (ret == 0)
ret = wc_Sha256Copy(&source->hashSha256,
&(*destination)->hashSha256);
#endif
#ifdef WOLFSSL_SHA384
if (ret == 0)
ret = wc_Sha384Copy(&source->hashSha384,
&(*destination)->hashSha384);
#endif
#ifdef WOLFSSL_SHA512
if (ret == 0)
ret = wc_Sha512Copy(&source->hashSha512,
&(*destination)->hashSha512);
#endif
#if (defined(HAVE_ED25519) || defined(HAVE_ED448)) && \
!defined(WOLFSSL_NO_CLIENT_AUTH)
if (ret == 0 && source->messages != NULL) {
(*destination)->messages = (byte*)XMALLOC(source->length, ssl->heap,
DYNAMIC_TYPE_HASHES);
(*destination)->length = source->length;
(*destination)->prevLen = source->prevLen;
if ((*destination)->messages == NULL) {
ret = MEMORY_E;
}
else {
XMEMCPY((*destination)->messages, source->messages,
source->length);
}
}
#endif
return ret;
}
/* called if user attempts to re-use WOLFSSL object for a new session. /* called if user attempts to re-use WOLFSSL object for a new session.
* For example wolfSSL_clear() is called then wolfSSL_connect or accept */ * For example wolfSSL_clear() is called then wolfSSL_connect or accept */
int ReinitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) int ReinitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
@ -7505,6 +7604,17 @@ void SSL_ResourceFree(WOLFSSL* ssl)
ForceZero(&ssl->clientSecret, sizeof(ssl->clientSecret)); ForceZero(&ssl->clientSecret, sizeof(ssl->clientSecret));
ForceZero(&ssl->serverSecret, sizeof(ssl->serverSecret)); ForceZero(&ssl->serverSecret, sizeof(ssl->serverSecret));
} }
#if defined(HAVE_ECH)
if (ssl->options.useEch == 1) {
FreeEchConfigs(ssl->echConfigs, ssl->heap);
ssl->echConfigs = NULL;
/* free the ech specific hashes */
ssl->hsHashes = ssl->hsHashesEch;
FreeHandshakeHashes(ssl);
ssl->options.useEch = 0;
}
#endif
#endif #endif
#ifdef WOLFSSL_HAVE_TLS_UNIQUE #ifdef WOLFSSL_HAVE_TLS_UNIQUE
ForceZero(&ssl->clientFinished, TLS_FINISHED_SZ_MAX); ForceZero(&ssl->clientFinished, TLS_FINISHED_SZ_MAX);

594
src/ssl.c
View File

@ -222,6 +222,8 @@
#endif /* !WOLFSSL_NO_OPENSSL_RAND_CB */ #endif /* !WOLFSSL_NO_OPENSSL_RAND_CB */
#endif /* OPENSSL_EXTRA */ #endif /* OPENSSL_EXTRA */
#include <wolfssl/wolfcrypt/hpke.h>
#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) #if defined(OPENSSL_EXTRA) && defined(HAVE_ECC)
const WOLF_EC_NIST_NAME kNistCurves[] = { const WOLF_EC_NIST_NAME kNistCurves[] = {
{XSTR_SIZEOF("P-192"), "P-192", NID_X9_62_prime192v1}, {XSTR_SIZEOF("P-192"), "P-192", NID_X9_62_prime192v1},
@ -260,6 +262,598 @@ const WOLF_EC_NIST_NAME kNistCurves[] = {
}; };
#endif #endif
#if defined(HAVE_ECH)
/* create the hpke key and ech config to send to clients */
int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName,
word16 kemId, word16 kdfId, word16 aeadId)
{
int ret = 0;
word16 encLen = DHKEM_X25519_ENC_LEN;
#ifdef WOLFSSL_SMALL_STACK
Hpke* hpke = NULL;
WC_RNG* rng;
#else
Hpke hpke[1];
WC_RNG rng[1];
#endif
if (ctx == NULL || publicName == NULL)
return BAD_FUNC_ARG;
#ifdef WOLFSSL_SMALL_STACK
rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), ctx->heap, DYNAMIC_TYPE_RNG);
if (rng == NULL)
return MEMORY_E;
#endif
ret = wc_InitRng(rng);
if (ret != 0) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(rng, ctx->heap, DYNAMIC_TYPE_RNG);
#endif
return ret;
}
ctx->echConfigs = (WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig),
ctx->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (ctx->echConfigs == NULL)
ret = MEMORY_E;
else
XMEMSET(ctx->echConfigs, 0, sizeof(WOLFSSL_EchConfig));
/* set random config id */
if (ret == 0)
ret = wc_RNG_GenerateByte(rng, &ctx->echConfigs->configId);
/* if 0 is selected for algorithms use default, may change with draft */
if (kemId == 0)
kemId = DHKEM_X25519_HKDF_SHA256;
if (kdfId == 0)
kdfId = HKDF_SHA256;
if (aeadId == 0)
aeadId = HPKE_AES_128_GCM;
if (ret == 0) {
/* set the kem id */
ctx->echConfigs->kemId = kemId;
/* set the cipher suite, only 1 for now */
ctx->echConfigs->numCipherSuites = 1;
ctx->echConfigs->cipherSuites = (EchCipherSuite*)XMALLOC(
sizeof(EchCipherSuite), ctx->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (ctx->echConfigs->cipherSuites == NULL) {
ret = MEMORY_E;
}
else {
ctx->echConfigs->cipherSuites[0].kdfId = kdfId;
ctx->echConfigs->cipherSuites[0].aeadId = aeadId;
}
}
#ifdef WOLFSSL_SMALL_STACK
if (ret == 0) {
hpke = (Hpke*)XMALLOC(sizeof(Hpke), ctx->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (hpke == NULL)
ret = MEMORY_E;
}
#endif
if (ret == 0)
ret = wc_HpkeInit(hpke, kemId, kdfId, aeadId, ctx->heap);
/* generate the receiver private key */
if (ret == 0)
ret = wc_HpkeGenerateKeyPair(hpke, &ctx->echConfigs->receiverPrivkey,
rng);
/* done with RNG */
wc_FreeRng(rng);
/* serialize the receiver key */
if (ret == 0)
ret = wc_HpkeSerializePublicKey(hpke, ctx->echConfigs->receiverPrivkey,
ctx->echConfigs->receiverPubkey, &encLen);
if (ret == 0) {
ctx->echConfigs->publicName = (char*)XMALLOC(XSTRLEN(publicName) + 1,
ctx->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (ctx->echConfigs->publicName == NULL) {
ret = MEMORY_E;
}
else {
XMEMCPY(ctx->echConfigs->publicName, publicName,
XSTRLEN(publicName) + 1);
}
}
if (ret != 0) {
if (ctx->echConfigs) {
XFREE(ctx->echConfigs->cipherSuites, ctx->heap,
DYNAMIC_TYPE_TMP_BUFFER);
XFREE(ctx->echConfigs->publicName, ctx->heap,
DYNAMIC_TYPE_TMP_BUFFER);
XFREE(ctx->echConfigs, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER);
/* set to null to avoid double free in cleanup */
ctx->echConfigs = NULL;
}
}
if (ret == 0)
ret = WOLFSSL_SUCCESS;
#ifdef WOLFSSL_SMALL_STACK
XFREE(hpke, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(rng, ctx->heap, DYNAMIC_TYPE_RNG);
#endif
return ret;
}
/* get the ech configs that the server context is using */
int wolfSSL_CTX_GetEchConfigs(WOLFSSL_CTX* ctx, byte* output,
word32* outputLen) {
if (ctx == NULL || outputLen == NULL)
return BAD_FUNC_ARG;
/* if we don't have ech configs */
if (ctx->echConfigs == NULL) {
return WOLFSSL_FATAL_ERROR;
}
return GetEchConfigsEx(ctx->echConfigs, output, outputLen);
}
/* set the ech config from base64 for our client ssl object, base64 is the
* format ech configs are sent using dns records */
int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64,
word32 echConfigs64Len)
{
int ret = 0;
word32 decodedLen = echConfigs64Len * 3 / 4 + 1;
byte* decodedConfigs;
if (ssl == NULL || echConfigs64 == NULL || echConfigs64Len == 0)
return BAD_FUNC_ARG;
/* already have ech configs */
if (ssl->options.useEch == 1) {
return WOLFSSL_FATAL_ERROR;
}
decodedConfigs = (byte*)XMALLOC(decodedLen, ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (decodedConfigs == NULL)
return MEMORY_E;
decodedConfigs[decodedLen - 1] = 0;
/* decode the echConfigs */
ret = Base64_Decode((byte*)echConfigs64, echConfigs64Len,
decodedConfigs, &decodedLen);
if (ret != 0) {
XFREE(decodedConfigs, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
ret = wolfSSL_SetEchConfigs(ssl, decodedConfigs, decodedLen);
XFREE(decodedConfigs, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
/* set the ech config from a raw buffer, this is the format ech configs are
* sent using retry_configs from the ech server */
int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs,
word32 echConfigsLen)
{
int ret = 0;
int i;
int j;
word16 totalLength;
word16 version;
word16 length;
word16 hpkePubkeyLen;
word16 cipherSuitesLen;
word16 publicNameLen;
WOLFSSL_EchConfig* configList = NULL;
WOLFSSL_EchConfig* workingConfig = NULL;
WOLFSSL_EchConfig* lastConfig = NULL;
byte* echConfig = NULL;
if (ssl == NULL || echConfigs == NULL || echConfigsLen == 0)
return BAD_FUNC_ARG;
/* already have ech configs */
if (ssl->options.useEch == 1) {
return WOLFSSL_FATAL_ERROR;
}
/* check that the total length is well formed */
ato16(echConfigs, &totalLength);
if (totalLength != echConfigsLen - 2) {
return WOLFSSL_FATAL_ERROR;
}
/* skip the total length uint16_t */
i = 2;
do {
echConfig = (byte*)echConfigs + i;
ato16(echConfig, &version);
ato16(echConfig + 2, &length);
/* if the version does not match */
if (version != TLSX_ECH) {
/* we hit the end of the configs */
if ( (word32)i + 2 >= echConfigsLen ) {
break;
}
/* skip this config, +4 for version and length */
i += length + 4;
continue;
}
/* check if the length will overrun the buffer */
if ((word32)i + length + 4 > echConfigsLen) {
break;
}
if (workingConfig == NULL) {
workingConfig =
(WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig),
ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
configList = workingConfig;
workingConfig->next = NULL;
}
else {
lastConfig = workingConfig;
workingConfig->next =
(WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig),
ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
workingConfig = workingConfig->next;
}
if (workingConfig == NULL) {
ret = MEMORY_E;
break;
}
XMEMSET(workingConfig, 0, sizeof(WOLFSSL_EchConfig));
/* rawLen */
workingConfig->rawLen = length + 4;
/* raw body */
workingConfig->raw = (byte*)XMALLOC(workingConfig->rawLen,
ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (workingConfig->raw == NULL) {
ret = MEMORY_E;
break;
}
XMEMCPY(workingConfig->raw, echConfig, workingConfig->rawLen);
/* skip over version and length */
echConfig += 4;
/* configId, 1 byte */
workingConfig->configId = *(echConfig);
echConfig++;
/* kemId, 2 bytes */
ato16(echConfig, &workingConfig->kemId);
echConfig += 2;
/* hpke public_key length, 2 bytes */
ato16(echConfig, &hpkePubkeyLen);
echConfig += 2;
/* hpke public_key */
XMEMCPY(workingConfig->receiverPubkey, echConfig, hpkePubkeyLen);
echConfig += hpkePubkeyLen;
/* cipherSuitesLen */
ato16(echConfig, &cipherSuitesLen);
workingConfig->cipherSuites = (EchCipherSuite*)XMALLOC(cipherSuitesLen,
ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (workingConfig->cipherSuites == NULL) {
ret = MEMORY_E;
break;
}
echConfig += 2;
workingConfig->numCipherSuites = cipherSuitesLen / 4;
/* cipherSuites */
for (j = 0; j < workingConfig->numCipherSuites; j++) {
ato16(echConfig + j * 4, &workingConfig->cipherSuites[j].kdfId);
ato16(echConfig + j * 4 + 2,
&workingConfig->cipherSuites[j].aeadId);
}
echConfig += cipherSuitesLen;
/* publicNameLen */
ato16(echConfig, &publicNameLen);
workingConfig->publicName = (char*)XMALLOC(publicNameLen + 1,
ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (workingConfig->publicName == NULL) {
ret = MEMORY_E;
break;
}
echConfig += 2;
/* publicName */
XMEMCPY(workingConfig->publicName, echConfig, publicNameLen);
/* null terminated */
workingConfig->publicName[publicNameLen] = 0;
/* add length to go to next config, +4 for version and length */
i += length + 4;
/* check that we support this config */
for (j = 0; j < HPKE_SUPPORTED_KEM_LEN; j++) {
if (hpkeSupportedKem[j] == workingConfig->kemId)
break;
}
/* if we don't support the kem or at least one cipher suite */
if (j >= HPKE_SUPPORTED_KEM_LEN ||
EchConfigGetSupportedCipherSuite(workingConfig) < 0)
{
XFREE(workingConfig->cipherSuites, ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
XFREE(workingConfig->publicName, ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
XFREE(workingConfig->raw, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
workingConfig = lastConfig;
}
} while ((word32)i < echConfigsLen);
/* if we found valid configs */
if (ret == 0 && configList != NULL) {
ssl->options.useEch = 1;
ssl->echConfigs = configList;
return WOLFSSL_SUCCESS;
}
workingConfig = configList;
while (workingConfig != NULL) {
lastConfig = workingConfig;
workingConfig = workingConfig->next;
XFREE(lastConfig->cipherSuites, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(lastConfig->publicName, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(lastConfig->raw, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(lastConfig, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
if (ret == 0)
return WOLFSSL_FATAL_ERROR;
return ret;
}
/* get the raw ech config from our struct */
int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen)
{
int i;
word16 totalLen = 0;
if (config == NULL || (output == NULL && outputLen == NULL))
return BAD_FUNC_ARG;
/* 2 for version */
totalLen += 2;
/* 2 for length */
totalLen += 2;
/* 1 for configId */
totalLen += 1;
/* 2 for kemId */
totalLen += 2;
/* 2 for hpke_len */
totalLen += 2;
/* hpke_pub_key */
switch (config->kemId) {
case DHKEM_P256_HKDF_SHA256:
totalLen += DHKEM_P256_ENC_LEN;
break;
case DHKEM_P384_HKDF_SHA384:
totalLen += DHKEM_P384_ENC_LEN;
break;
case DHKEM_P521_HKDF_SHA512:
totalLen += DHKEM_P521_ENC_LEN;
break;
case DHKEM_X25519_HKDF_SHA256:
totalLen += DHKEM_X25519_ENC_LEN;
break;
case DHKEM_X448_HKDF_SHA512:
totalLen += DHKEM_X448_ENC_LEN;
break;
}
/* cipherSuitesLen */
totalLen += 2;
/* cipherSuites */
totalLen += config->numCipherSuites * 4;
/* public name len */
totalLen += 2;
/* public name */
totalLen += XSTRLEN(config->publicName);
/* trailing zeros */
totalLen += 2;
if (output == NULL) {
*outputLen = totalLen;
return LENGTH_ONLY_E;
}
if (totalLen > *outputLen) {
*outputLen = totalLen;
return INPUT_SIZE_E;
}
/* version */
c16toa(TLSX_ECH, output);
output += 2;
/* length - 4 for version and length itself */
c16toa(totalLen - 4, output);
output += 2;
/* configId */
*output = config->configId;
output++;
/* kemId */
c16toa(config->kemId, output);
output += 2;
/* length and key itself */
switch (config->kemId) {
case DHKEM_P256_HKDF_SHA256:
c16toa(DHKEM_P256_ENC_LEN, output);
output += 2;
XMEMCPY(output, config->receiverPubkey, DHKEM_P256_ENC_LEN);
output += DHKEM_P256_ENC_LEN;
break;
case DHKEM_P384_HKDF_SHA384:
c16toa(DHKEM_P384_ENC_LEN, output);
output += 2;
XMEMCPY(output, config->receiverPubkey, DHKEM_P384_ENC_LEN);
output += DHKEM_P384_ENC_LEN;
break;
case DHKEM_P521_HKDF_SHA512:
c16toa(DHKEM_P521_ENC_LEN, output);
output += 2;
XMEMCPY(output, config->receiverPubkey, DHKEM_P521_ENC_LEN);
output += DHKEM_P521_ENC_LEN;
break;
case DHKEM_X25519_HKDF_SHA256:
c16toa(DHKEM_X25519_ENC_LEN, output);
output += 2;
XMEMCPY(output, config->receiverPubkey, DHKEM_X25519_ENC_LEN);
output += DHKEM_X25519_ENC_LEN;
break;
case DHKEM_X448_HKDF_SHA512:
c16toa(DHKEM_X448_ENC_LEN, output);
output += 2;
XMEMCPY(output, config->receiverPubkey, DHKEM_X448_ENC_LEN);
output += DHKEM_X448_ENC_LEN;
break;
}
/* cipherSuites len */
c16toa(config->numCipherSuites * 4, output);
output += 2;
/* cipherSuites */
for (i = 0; i < config->numCipherSuites; i++) {
c16toa(config->cipherSuites[i].kdfId, output);
output += 2;
c16toa(config->cipherSuites[i].aeadId, output);
output += 2;
}
/* publicName len */
c16toa(XSTRLEN(config->publicName), output);
output += 2;
/* publicName */
XMEMCPY(output, config->publicName,
XSTRLEN(config->publicName));
output += XSTRLEN(config->publicName);
/* terminating zeros */
c16toa(0, output);
/* output += 2; */
*outputLen = totalLen;
return 0;
}
/* wrapper function to get ech configs from application code */
int wolfSSL_GetEchConfigs(WOLFSSL* ssl, byte* output, word32* outputLen)
{
if (ssl == NULL || outputLen == NULL)
return BAD_FUNC_ARG;
/* if we don't have ech configs */
if (ssl->options.useEch != 1) {
return WOLFSSL_FATAL_ERROR;
}
return GetEchConfigsEx(ssl->echConfigs, output, outputLen);
}
/* get the raw ech configs from our linked list of ech config structs */
int GetEchConfigsEx(WOLFSSL_EchConfig* configs, byte* output, word32* outputLen)
{
int ret = 0;
WOLFSSL_EchConfig* workingConfig = NULL;
byte* outputStart = output;
word32 totalLen = 2;
word32 workingOutputLen;
if (configs == NULL || outputLen == NULL)
return BAD_FUNC_ARG;
workingOutputLen = *outputLen - totalLen;
/* skip over total length which we fill in later */
if (output != NULL)
output += 2;
workingConfig = configs;
while (workingConfig != NULL) {
/* get this config */
ret = GetEchConfig(workingConfig, output, &workingOutputLen);
if (output != NULL)
output += workingOutputLen;
/* add this config's length to the total length */
totalLen += workingOutputLen;
if (totalLen > *outputLen)
workingOutputLen = 0;
else
workingOutputLen = *outputLen - totalLen;
/* only error we break on, other 2 we need to keep finding length */
if (ret == BAD_FUNC_ARG)
return BAD_FUNC_ARG;
workingConfig = workingConfig->next;
}
if (output == NULL) {
*outputLen = totalLen;
return LENGTH_ONLY_E;
}
if (totalLen > *outputLen) {
*outputLen = totalLen;
return INPUT_SIZE_E;
}
/* total size -2 for size itself */
c16toa(totalLen - 2, outputStart);
*outputLen = totalLen;
return WOLFSSL_SUCCESS;
}
#endif /* HAVE_ECH */
#if defined(WOLFSSL_RENESAS_TSIP_TLS) || defined(WOLFSSL_RENESAS_SCEPROTECT) #if defined(WOLFSSL_RENESAS_TSIP_TLS) || defined(WOLFSSL_RENESAS_SCEPROTECT)
#include <wolfssl/wolfcrypt/port/Renesas/renesas_cmn.h> #include <wolfssl/wolfcrypt/port/Renesas/renesas_cmn.h>
#endif #endif

1044
src/tls.c

File diff suppressed because it is too large Load Diff

View File

@ -165,6 +165,23 @@ static const byte tls13ProtocolLabel[TLS13_PROTOCOL_LABEL_SZ + 1] = "tls13 ";
static const byte dtls13ProtocolLabel[DTLS13_PROTOCOL_LABEL_SZ + 1] = "dtls13"; static const byte dtls13ProtocolLabel[DTLS13_PROTOCOL_LABEL_SZ + 1] = "dtls13";
#endif /* WOLFSSL_DTLS13 */ #endif /* WOLFSSL_DTLS13 */
#if defined(HAVE_ECH)
#define ECH_ACCEPT_CONFIRMATION_SZ 8
#define ECH_ACCEPT_CONFIRMATION_LABEL_SZ 23
static const byte
echAcceptConfirmationLabel[ECH_ACCEPT_CONFIRMATION_LABEL_SZ + 1] =
"ech accept confirmation";
#endif
#ifndef NO_CERTS
#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \
defined(HAVE_ED448) || defined(HAVE_PQC)
static WC_INLINE int GetMsgHash(WOLFSSL* ssl, byte* hash);
#endif
#endif
/* Expand data using HMAC, salt and label and info. /* Expand data using HMAC, salt and label and info.
* TLS v1.3 defines this function. Use callback if available. * TLS v1.3 defines this function. Use callback if available.
* *
@ -253,7 +270,6 @@ PRAGMA_GCC_DIAG_POP;
} }
#endif /* !HAVE_FIPS || !wc_Tls13_HKDF_Expand_Label */ #endif /* !HAVE_FIPS || !wc_Tls13_HKDF_Expand_Label */
/* Derive a key from a message. /* Derive a key from a message.
* *
* ssl The SSL/TLS object. * ssl The SSL/TLS object.
@ -3830,6 +3846,71 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx)
} }
#endif #endif
#if defined(HAVE_ECH)
/* returns the index of the first supported cipher suite, -1 if none */
int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config)
{
int i, j, supported = 0;
for (i = 0; i < config->numCipherSuites; i++) {
supported = 0;
for (j = 0; j < HPKE_SUPPORTED_KDF_LEN; j++) {
if (config->cipherSuites[i].kdfId == hpkeSupportedKdf[j])
break;
}
if (j < HPKE_SUPPORTED_KDF_LEN)
for (j = 0; j < HPKE_SUPPORTED_AEAD_LEN; j++) {
if (config->cipherSuites[i].aeadId == hpkeSupportedAead[j]) {
supported = 1;
break;
}
}
if (supported)
return i;
}
return -1;
}
/* returns status after we hash the ech inner */
static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech)
{
int ret;
HS_Hashes* tmpHashes;
byte falseHeader[HANDSHAKE_HEADER_SZ];
if (ssl == NULL || ech == NULL)
return BAD_FUNC_ARG;
/* switch hsHashes to the ech version */
InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, &ssl->hsHashesEch);
/* swap hsHashes so the regular hash functions work */
tmpHashes = ssl->hsHashes;
ssl->hsHashes = ssl->hsHashesEch;
/* do the handshake header then the body */
AddTls13HandShakeHeader(falseHeader,
ech->innerClientHelloLen - ech->paddingLen - ech->hpke->Nt, 0, 0,
client_hello, ssl);
ret = HashRaw(ssl, falseHeader, HANDSHAKE_HEADER_SZ);
/* hash the body */
if (ret == 0) {
ret = HashRaw(ssl, ech->innerClientHello,
ech->innerClientHelloLen - ech->paddingLen - ech->hpke->Nt);
}
/* swap hsHashes back */
ssl->hsHashes = tmpHashes;
return ret;
}
#endif
/* handle generation of TLS 1.3 client_hello (1) */ /* handle generation of TLS 1.3 client_hello (1) */
/* Send a ClientHello message to the server. /* Send a ClientHello message to the server.
* Include the information required to start a handshake with servers using * Include the information required to start a handshake with servers using
@ -3845,6 +3926,11 @@ typedef struct Sch13Args {
word32 idx; word32 idx;
int sendSz; int sendSz;
word16 length; word16 length;
#if defined(HAVE_ECH)
int clientRandomOffset;
int preXLength;
WOLFSSL_ECH* ech;
#endif
} Sch13Args; } Sch13Args;
int SendTls13ClientHello(WOLFSSL* ssl) int SendTls13ClientHello(WOLFSSL* ssl)
@ -3859,7 +3945,6 @@ int SendTls13ClientHello(WOLFSSL* ssl)
byte major, tls12minor; byte major, tls12minor;
const Suites* suites; const Suites* suites;
WOLFSSL_START(WC_FUNC_CLIENT_HELLO_SEND); WOLFSSL_START(WC_FUNC_CLIENT_HELLO_SEND);
WOLFSSL_ENTER("SendTls13ClientHello"); WOLFSSL_ENTER("SendTls13ClientHello");
@ -4018,6 +4103,38 @@ int SendTls13ClientHello(WOLFSSL* ssl)
return ret; return ret;
} }
#endif #endif
/* find length of outer and inner */
#if defined(HAVE_ECH)
if (ssl->options.useEch == 1) {
TLSX* echX = TLSX_Find(ssl->extensions, TLSX_ECH);
if (echX == NULL)
return -1;
args->ech = (WOLFSSL_ECH*)echX->data;
if (args->ech == NULL)
return -1;
/* set the type to inner */
args->ech->type = ECH_TYPE_INNER;
args->preXLength = args->length;
/* get size for inner */
ret = TLSX_GetRequestSize(ssl, client_hello, &args->length);
if (ret != 0)
return ret;
/* set the type to outer */
args->ech->type = 0;
/* set innerClientHelloLen to ClientHelloInner + padding + tag */
args->ech->paddingLen = 31 - ((args->length - 1) % 32);
args->ech->innerClientHelloLen = args->length +
args->ech->paddingLen + args->ech->hpke->Nt;
/* set the length back to before we computed ClientHelloInner size */
args->length = args->preXLength;
}
#endif
/* Include length of TLS extensions. */ /* Include length of TLS extensions. */
ret = TLSX_GetRequestSize(ssl, client_hello, &args->length); ret = TLSX_GetRequestSize(ssl, client_hello, &args->length);
if (ret != 0) if (ret != 0)
@ -4063,6 +4180,11 @@ int SendTls13ClientHello(WOLFSSL* ssl)
} }
else else
XMEMCPY(args->output + args->idx, ssl->arrays->clientRandom, RAN_LEN); XMEMCPY(args->output + args->idx, ssl->arrays->clientRandom, RAN_LEN);
#if defined(HAVE_ECH)
args->clientRandomOffset = args->idx;
#endif
args->idx += RAN_LEN; args->idx += RAN_LEN;
if (ssl->session->sessionIDSz > 0) { if (ssl->session->sessionIDSz > 0) {
@ -4124,14 +4246,78 @@ int SendTls13ClientHello(WOLFSSL* ssl)
args->output[args->idx++] = COMP_LEN; args->output[args->idx++] = COMP_LEN;
args->output[args->idx++] = NO_COMPRESSION; args->output[args->idx++] = NO_COMPRESSION;
#if defined(HAVE_ECH)
/* write inner then outer */
if (ssl->options.useEch == 1) {
/* set the type to inner */
args->ech->type = ECH_TYPE_INNER;
/* allocate the inner */
args->ech->innerClientHello =
(byte*)XMALLOC(args->ech->innerClientHelloLen - args->ech->hpke->Nt,
ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (args->ech->innerClientHello == NULL)
return MEMORY_E;
/* set the padding bytes to 0 */
XMEMSET(args->ech->innerClientHello + args->ech->innerClientHelloLen -
args->ech->hpke->Nt - args->ech->paddingLen, 0,
args->ech->paddingLen);
/* copy the client hello to the ech innerClientHello, exclude record */
/* and handshake headers */
XMEMCPY(args->ech->innerClientHello,
args->output + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ,
args->idx - (RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ));
/* copy the client random to inner */
XMEMCPY(ssl->arrays->clientRandomInner, ssl->arrays->clientRandom,
RAN_LEN);
/* change the outer client random */
ret = wc_RNG_GenerateBlock(ssl->rng, args->output +
args->clientRandomOffset, RAN_LEN);
if (ret != 0)
return ret;
/* copy the new client random */
XMEMCPY(ssl->arrays->clientRandom, args->output +
args->clientRandomOffset, RAN_LEN);
/* write the extensions for inner */
args->length = 0;
ret = TLSX_WriteRequest(ssl, args->ech->innerClientHello + args->idx -
(RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ), client_hello,
&args->length);
if (ret != 0)
return ret;
/* set the type to outer */
args->ech->type = 0;
}
#endif
/* Write out extensions for a request. */ /* Write out extensions for a request. */
args->length = 0; args->length = 0;
ret = TLSX_WriteRequest(ssl, args->output + args->idx, client_hello, ret = TLSX_WriteRequest(ssl, args->output + args->idx, client_hello,
&args->length); &args->length);
if (ret != 0) if (ret != 0)
return ret; return ret;
args->idx += args->length; args->idx += args->length;
#if defined(HAVE_ECH)
/* encrypt and pack the ech innerClientHello */
if (ssl->options.useEch == 1) {
ret = TLSX_FinalizeEch(args->ech,
args->output + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ,
args->sendSz - (RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ));
if (ret != 0)
return ret;
}
#endif
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
/* Resumption has a specific set of extensions and binder is calculated /* Resumption has a specific set of extensions and binder is calculated
* for each identity. * for each identity.
@ -4141,7 +4327,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
} }
else else
#endif #endif
{ {
#ifdef WOLFSSL_DTLS13 #ifdef WOLFSSL_DTLS13
if (ssl->options.dtls) if (ssl->options.dtls)
ret = Dtls13HashHandshake(ssl, ret = Dtls13HashHandshake(ssl,
@ -4149,8 +4335,19 @@ int SendTls13ClientHello(WOLFSSL* ssl)
(word16)args->idx - Dtls13GetRlHeaderLength(ssl, 0)); (word16)args->idx - Dtls13GetRlHeaderLength(ssl, 0));
else else
#endif /* WOLFSSL_DTLS13 */ #endif /* WOLFSSL_DTLS13 */
{
#if defined(HAVE_ECH)
/* compute the inner hash */
if (ssl->options.useEch == 1) {
ret = EchHashHelloInner(ssl, args->ech);
}
#endif
/* compute the outer hash */
if (ret == 0)
ret = HashOutput(ssl, args->output, args->idx, 0); ret = HashOutput(ssl, args->output, args->idx, 0);
} }
}
if (ret != 0) if (ret != 0)
return ret; return ret;
@ -4236,6 +4433,233 @@ static int Dtls13DoDowngrade(WOLFSSL* ssl)
} }
#endif /* WOLFSSL_DTLS13 && !WOLFSSL_NO_CLIENT*/ #endif /* WOLFSSL_DTLS13 && !WOLFSSL_NO_CLIENT*/
#if defined(HAVE_ECH)
/* check if the server accepted ech or not */
static int EchCheckAcceptance(WOLFSSL* ssl, const byte* input,
int serverRandomOffset, int helloSz)
{
int ret = 0;
int digestType;
int digestSize;
HS_Hashes* tmpHashes;
HS_Hashes* acceptHashes;
byte zeros[WC_MAX_DIGEST_SIZE] = {0};
byte transcriptEchConf[WC_MAX_DIGEST_SIZE];
byte expandLabelPrk[WC_MAX_DIGEST_SIZE];
byte acceptConfirmation[ECH_ACCEPT_CONFIRMATION_SZ];
/* copy ech hashes to accept */
ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashesEch, &acceptHashes);
/* swap hsHashes to acceptHashes */
tmpHashes = ssl->hsHashes;
ssl->hsHashes = acceptHashes;
/* hash up to the last 8 bytes */
if (ret == 0)
ret = HashRaw(ssl, input, serverRandomOffset + RAN_LEN -
ECH_ACCEPT_CONFIRMATION_SZ);
/* hash 8 zeros */
if (ret == 0)
ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ);
/* hash the rest of the hello */
if (ret == 0)
ret = HashRaw(ssl, input + serverRandomOffset + RAN_LEN,
helloSz + HANDSHAKE_HEADER_SZ - (serverRandomOffset + RAN_LEN));
/* get the modified transcript hash */
if (ret == 0)
ret = GetMsgHash(ssl, transcriptEchConf);
if (ret > 0)
ret = 0;
/* pick the right type and size based on mac_algorithm */
if (ret == 0)
switch (ssl->specs.mac_algorithm) {
#ifndef NO_SHA256
case sha256_mac:
digestType = WC_SHA256;
digestSize = WC_SHA256_DIGEST_SIZE;
break;
#endif /* !NO_SHA256 */
#ifdef WOLFSSL_SHA384
case sha384_mac:
digestType = WC_SHA384;
digestSize = WC_SHA384_DIGEST_SIZE;
break;
#endif /* WOLFSSL_SHA384 */
#ifdef WOLFSSL_TLS13_SHA512
case sha512_mac:
digestType = WC_SHA512;
digestSize = WC_SHA512_DIGEST_SIZE;
break;
#endif /* WOLFSSL_TLS13_SHA512 */
default:
ret = -1;
break;
}
/* extract clientRandomInner with a key of all zeros */
if (ret == 0)
ret = wc_HKDF_Extract(digestType, zeros, digestSize,
ssl->arrays->clientRandomInner, RAN_LEN, expandLabelPrk);
/* tls expand with the confirmation label */
if (ret == 0)
ret = wc_Tls13_HKDF_Expand_Label(acceptConfirmation,
ECH_ACCEPT_CONFIRMATION_SZ,
expandLabelPrk, digestSize, tls13ProtocolLabel,
TLS13_PROTOCOL_LABEL_SZ, echAcceptConfirmationLabel,
ECH_ACCEPT_CONFIRMATION_LABEL_SZ, transcriptEchConf, digestSize,
digestType);
if (ret == 0) {
/* last 8 bytes should match our expand output */
ret = XMEMCMP(acceptConfirmation,
ssl->arrays->serverRandom + RAN_LEN - ECH_ACCEPT_CONFIRMATION_SZ,
ECH_ACCEPT_CONFIRMATION_SZ);
/* ech accepted */
if (ret == 0) {
/* use the inner random for client random */
XMEMCPY(ssl->arrays->clientRandom, ssl->arrays->clientRandomInner,
RAN_LEN);
/* switch back to original hsHashes */
ssl->hsHashes = tmpHashes;
/* free hsHashes */
FreeHandshakeHashes(ssl);
/* set the final hsHashes to the ech hashes */
tmpHashes = ssl->hsHashesEch;
/* set hsHashesEch to NULL to avoid double free */
ssl->hsHashesEch = NULL;
}
/* ech rejected */
else {
/* switch to hsHashesEch */
ssl->hsHashes = ssl->hsHashesEch;
/* free ech hashes */
FreeHandshakeHashes(ssl);
}
/* continue with outer if we failed to verify ech was accepted */
ret = 0;
}
/* switch to acceptHashes */
ssl->hsHashes = acceptHashes;
/* free acceptHashes */
FreeHandshakeHashes(ssl);
ssl->hsHashes = tmpHashes;
return ret;
}
/* replace the last 8 bytes of the server random with the ech acceptance
* parameter, return status */
static int EchWriteAcceptance(WOLFSSL* ssl, byte* output,
int serverRandomOffset, int helloSz)
{
int ret = 0;
int digestType;
int digestSize;
HS_Hashes* tmpHashes;
HS_Hashes* acceptHashes;
byte zeros[WC_MAX_DIGEST_SIZE] = {0};
byte transcriptEchConf[WC_MAX_DIGEST_SIZE];
byte expandLabelPrk[WC_MAX_DIGEST_SIZE];
/* copy ech hashes to accept */
ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, &acceptHashes);
/* swap hsHashes to acceptHashes */
tmpHashes = ssl->hsHashes;
ssl->hsHashes = acceptHashes;
/* hash up to the last 8 bytes */
if (ret == 0)
ret = HashRaw(ssl, output, serverRandomOffset + RAN_LEN -
ECH_ACCEPT_CONFIRMATION_SZ);
/* hash 8 zeros */
if (ret == 0)
ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ);
/* hash the rest of the hello */
if (ret == 0)
ret = HashRaw(ssl, output + serverRandomOffset + RAN_LEN,
helloSz - (serverRandomOffset + RAN_LEN));
/* get the modified transcript hash */
if (ret == 0)
ret = GetMsgHash(ssl, transcriptEchConf);
if (ret > 0)
ret = 0;
/* pick the right type and size based on mac_algorithm */
if (ret == 0)
switch (ssl->specs.mac_algorithm) {
#ifndef NO_SHA256
case sha256_mac:
digestType = WC_SHA256;
digestSize = WC_SHA256_DIGEST_SIZE;
break;
#endif /* !NO_SHA256 */
#ifdef WOLFSSL_SHA384
case sha384_mac:
digestType = WC_SHA384;
digestSize = WC_SHA384_DIGEST_SIZE;
break;
#endif /* WOLFSSL_SHA384 */
#ifdef WOLFSSL_TLS13_SHA512
case sha512_mac:
digestType = WC_SHA512;
digestSize = WC_SHA512_DIGEST_SIZE;
break;
#endif /* WOLFSSL_TLS13_SHA512 */
default:
ret = -1;
break;
}
/* extract clientRandom with a key of all zeros */
if (ret == 0)
ret = wc_HKDF_Extract(digestType, zeros, digestSize,
ssl->arrays->clientRandom, RAN_LEN, expandLabelPrk);
/* tls expand with the confirmation label */
if (ret == 0)
ret = wc_Tls13_HKDF_Expand_Label(
output + serverRandomOffset + RAN_LEN - ECH_ACCEPT_CONFIRMATION_SZ,
ECH_ACCEPT_CONFIRMATION_SZ,
expandLabelPrk, digestSize, tls13ProtocolLabel,
TLS13_PROTOCOL_LABEL_SZ, echAcceptConfirmationLabel,
ECH_ACCEPT_CONFIRMATION_LABEL_SZ, transcriptEchConf, digestSize,
digestType);
if (ret == 0)
XMEMCPY(ssl->arrays->serverRandom, output + serverRandomOffset,
RAN_LEN);
/* free acceptHashes */
FreeHandshakeHashes(ssl);
ssl->hsHashes = tmpHashes;
return ret;
}
#endif
/* handle processing of TLS 1.3 server_hello (2) and hello_retry_request (6) */ /* handle processing of TLS 1.3 server_hello (2) and hello_retry_request (6) */
/* Handle the ServerHello message from the server. /* Handle the ServerHello message from the server.
* Only a client will receive this message. * Only a client will receive this message.
@ -4256,6 +4680,9 @@ typedef struct Dsh13Args {
word16 totalExtSz; word16 totalExtSz;
byte sessIdSz; byte sessIdSz;
byte extMsgType; byte extMsgType;
#if defined(HAVE_ECH)
int serverRandomOffset;
#endif
} Dsh13Args; } Dsh13Args;
int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
@ -4403,6 +4830,9 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
/* Server random - keep for debugging. */ /* Server random - keep for debugging. */
XMEMCPY(ssl->arrays->serverRandom, input + args->idx, RAN_LEN); XMEMCPY(ssl->arrays->serverRandom, input + args->idx, RAN_LEN);
#if defined(HAVE_ECH)
args->serverRandomOffset = args->idx;
#endif
args->idx += RAN_LEN; args->idx += RAN_LEN;
/* Session id */ /* Session id */
@ -4685,6 +5115,16 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
ret = SetCipherSpecs(ssl); ret = SetCipherSpecs(ssl);
if (ret != 0) if (ret != 0)
return ret; return ret;
#if defined(HAVE_ECH)
/* check for acceptConfirmation and HashInput with 8 0 bytes */
if (ssl->options.useEch == 1) {
ret = EchCheckAcceptance(ssl, input, args->serverRandomOffset, helloSz);
if (ret != 0)
return ret;
}
#endif
#ifdef HAVE_NULL_CIPHER #ifdef HAVE_NULL_CIPHER
if (ssl->options.cipherSuite0 == ECC_BYTE && if (ssl->options.cipherSuite0 == ECC_BYTE &&
(ssl->options.cipherSuite == TLS_SHA256_SHA256 || (ssl->options.cipherSuite == TLS_SHA256_SHA256 ||
@ -5829,6 +6269,10 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#else #else
Dch13Args args[1]; Dch13Args args[1];
#endif #endif
#if defined(HAVE_ECH)
word32 echInOutIdx;
TLSX* echX = NULL;
#endif
WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO); WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO);
WOLFSSL_ENTER("DoTls13ClientHello"); WOLFSSL_ENTER("DoTls13ClientHello");
@ -6042,12 +6486,31 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
if ((ret = TLSX_PopulateExtensions(ssl, 1)) != 0) if ((ret = TLSX_PopulateExtensions(ssl, 1)) != 0)
goto exit_dch; goto exit_dch;
#if defined(HAVE_ECH)
if (ssl->ctx->echConfigs != NULL) {
/* save the start of the buffer so we can use it when parsing ech */
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
if (echX == NULL)
return -1;
((WOLFSSL_ECH*)echX->data)->aad = input + HANDSHAKE_HEADER_SZ;
((WOLFSSL_ECH*)echX->data)->aadLen = helloSz;
}
#endif
/* Parse extensions */ /* Parse extensions */
if ((ret = TLSX_Parse(ssl, input + args->idx, totalExtSz, client_hello, if ((ret = TLSX_Parse(ssl, input + args->idx, totalExtSz, client_hello,
args->clSuites))) { args->clSuites))) {
goto exit_dch; goto exit_dch;
} }
#if defined(HAVE_ECH)
/* jump to the end to clean things up */
if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE)
goto exit_dch;
#endif
#ifdef HAVE_SNI #ifdef HAVE_SNI
if ((ret = SNI_Callback(ssl)) != 0) if ((ret = SNI_Callback(ssl)) != 0)
goto exit_dch; goto exit_dch;
@ -6282,6 +6745,27 @@ exit_dch:
WOLFSSL_ERROR_VERBOSE(ret); WOLFSSL_ERROR_VERBOSE(ret);
} }
#if defined(HAVE_ECH)
/* do the hello again with the inner */
if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE) {
/* reset the idx */
echInOutIdx = args->begin;
/* add the header to the inner hello */
AddTls13HandShakeHeader(((WOLFSSL_ECH*)echX->data)->innerClientHello,
((WOLFSSL_ECH*)echX->data)->innerClientHelloLen, 0, 0,
client_hello, ssl);
ret = DoTls13ClientHello(ssl,
((WOLFSSL_ECH*)echX->data)->innerClientHello,
&echInOutIdx, ((WOLFSSL_ECH*)echX->data)->innerClientHelloLen);
/* inner hello succeeded, consider this handshake message processed */
if (ret == 0)
*inOutIdx = args->begin + helloSz;
}
#endif
return ret; return ret;
} }
@ -6299,6 +6783,10 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
word16 length; word16 length;
word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
int sendSz; int sendSz;
#if defined(HAVE_ECH)
TLSX* echX = NULL;
word32 serverRandomOffset;
#endif
WOLFSSL_START(WC_FUNC_SERVER_HELLO_SEND); WOLFSSL_START(WC_FUNC_SERVER_HELLO_SEND);
WOLFSSL_ENTER("SendTls13ServerHello"); WOLFSSL_ENTER("SendTls13ServerHello");
@ -6350,6 +6838,10 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
XMEMCPY(output + idx, helloRetryRequestRandom, RAN_LEN); XMEMCPY(output + idx, helloRetryRequestRandom, RAN_LEN);
} }
#if defined(HAVE_ECH)
serverRandomOffset = idx;
#endif
/* Store in SSL for debugging. */ /* Store in SSL for debugging. */
XMEMCPY(ssl->arrays->serverRandom, output + idx, RAN_LEN); XMEMCPY(ssl->arrays->serverRandom, output + idx, RAN_LEN);
idx += RAN_LEN; idx += RAN_LEN;
@ -6401,7 +6893,26 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
else else
#endif /* WOLFSSL_DTLS13 */ #endif /* WOLFSSL_DTLS13 */
{ {
ret = HashOutput(ssl, output, sendSz, 0); #if defined(HAVE_ECH)
if (ssl->ctx->echConfigs != NULL) {
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
if (echX == NULL)
return -1;
/* replace the last 8 bytes of server random with the accept */
if (((WOLFSSL_ECH*)echX->data)->state == ECH_PARSED_INTERNAL) {
ret = EchWriteAcceptance(ssl, output + RECORD_HEADER_SZ,
serverRandomOffset - RECORD_HEADER_SZ,
sendSz - RECORD_HEADER_SZ);
/* remove ech so we don't keep sending it in write */
TLSX_Remove(&ssl->extensions, TLSX_ECH, ssl->heap);
}
}
#endif
if (ret == 0)
ret = HashOutput(ssl, output, sendSz, 0);
} }
} }

View File

@ -340,7 +340,8 @@
#if (defined(SESSION_CERTS) && defined(TEST_PEER_CERT_CHAIN)) || \ #if (defined(SESSION_CERTS) && defined(TEST_PEER_CERT_CHAIN)) || \
defined(HAVE_SESSION_TICKET) || (defined(OPENSSL_EXTRA) && \ defined(HAVE_SESSION_TICKET) || (defined(OPENSSL_EXTRA) && \
defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN)) || \ defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN)) || \
defined(WOLFSSL_TEST_STATIC_BUILD) || defined(WOLFSSL_DTLS) defined(WOLFSSL_TEST_STATIC_BUILD) || defined(WOLFSSL_DTLS) || \
defined(HAVE_ECH)
/* for testing SSL_get_peer_cert_chain, or SESSION_TICKET_HINT_DEFAULT, /* for testing SSL_get_peer_cert_chain, or SESSION_TICKET_HINT_DEFAULT,
* for setting authKeyIdSrc in WOLFSSL_X509, or testing DTLS sequence * for setting authKeyIdSrc in WOLFSSL_X509, or testing DTLS sequence
* number tracking */ * number tracking */
@ -8542,51 +8543,61 @@ static int test_wolfSSL_UseSNI_connection(void)
server_cb.devId = testDevId; server_cb.devId = testDevId;
/* success case at ctx */ /* success case at ctx */
printf("success case at ctx\n");
client_cb.ctx_ready = use_SNI_at_ctx; client_cb.ssl_ready = NULL; client_cb.on_result = NULL; client_cb.ctx_ready = use_SNI_at_ctx; client_cb.ssl_ready = NULL; client_cb.on_result = NULL;
server_cb.ctx_ready = use_SNI_at_ctx; server_cb.ssl_ready = NULL; server_cb.on_result = verify_SNI_real_matching; server_cb.ctx_ready = use_SNI_at_ctx; server_cb.ssl_ready = NULL; server_cb.on_result = verify_SNI_real_matching;
test_wolfSSL_client_server(&client_cb, &server_cb); test_wolfSSL_client_server(&client_cb, &server_cb);
/* success case at ssl */ /* success case at ssl */
printf("success case at ssl\n");
client_cb.ctx_ready = NULL; client_cb.ssl_ready = use_SNI_at_ssl; client_cb.on_result = verify_SNI_real_matching; client_cb.ctx_ready = NULL; client_cb.ssl_ready = use_SNI_at_ssl; client_cb.on_result = verify_SNI_real_matching;
server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_SNI_at_ssl; server_cb.on_result = verify_SNI_real_matching; server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_SNI_at_ssl; server_cb.on_result = verify_SNI_real_matching;
test_wolfSSL_client_server(&client_cb, &server_cb); test_wolfSSL_client_server(&client_cb, &server_cb);
/* default mismatch behavior */ /* default mismatch behavior */
printf("default mismatch behavior\n");
client_cb.ctx_ready = NULL; client_cb.ssl_ready = different_SNI_at_ssl; client_cb.on_result = verify_FATAL_ERROR_on_client; client_cb.ctx_ready = NULL; client_cb.ssl_ready = different_SNI_at_ssl; client_cb.on_result = verify_FATAL_ERROR_on_client;
server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_SNI_at_ssl; server_cb.on_result = verify_UNKNOWN_SNI_on_server; server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_SNI_at_ssl; server_cb.on_result = verify_UNKNOWN_SNI_on_server;
test_wolfSSL_client_server(&client_cb, &server_cb); test_wolfSSL_client_server(&client_cb, &server_cb);
/* continue on mismatch */ /* continue on mismatch */
printf("continue on mismatch\n");
client_cb.ctx_ready = NULL; client_cb.ssl_ready = different_SNI_at_ssl; client_cb.on_result = NULL; client_cb.ctx_ready = NULL; client_cb.ssl_ready = different_SNI_at_ssl; client_cb.on_result = NULL;
server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_SNI_WITH_CONTINUE_at_ssl; server_cb.on_result = verify_SNI_no_matching; server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_SNI_WITH_CONTINUE_at_ssl; server_cb.on_result = verify_SNI_no_matching;
test_wolfSSL_client_server(&client_cb, &server_cb); test_wolfSSL_client_server(&client_cb, &server_cb);
/* fake answer on mismatch */ /* fake answer on mismatch */
printf("fake answer on mismatch\n");
client_cb.ctx_ready = NULL; client_cb.ssl_ready = different_SNI_at_ssl; client_cb.on_result = NULL; client_cb.ctx_ready = NULL; client_cb.ssl_ready = different_SNI_at_ssl; client_cb.on_result = NULL;
server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_SNI_WITH_FAKE_ANSWER_at_ssl; server_cb.on_result = verify_SNI_fake_matching; server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_SNI_WITH_FAKE_ANSWER_at_ssl; server_cb.on_result = verify_SNI_fake_matching;
test_wolfSSL_client_server(&client_cb, &server_cb); test_wolfSSL_client_server(&client_cb, &server_cb);
/* sni abort - success */ /* sni abort - success */
printf("sni abort - success\n");
client_cb.ctx_ready = use_SNI_at_ctx; client_cb.ssl_ready = NULL; client_cb.on_result = NULL; client_cb.ctx_ready = use_SNI_at_ctx; client_cb.ssl_ready = NULL; client_cb.on_result = NULL;
server_cb.ctx_ready = use_MANDATORY_SNI_at_ctx; server_cb.ssl_ready = NULL; server_cb.on_result = verify_SNI_real_matching; server_cb.ctx_ready = use_MANDATORY_SNI_at_ctx; server_cb.ssl_ready = NULL; server_cb.on_result = verify_SNI_real_matching;
test_wolfSSL_client_server(&client_cb, &server_cb); test_wolfSSL_client_server(&client_cb, &server_cb);
/* sni abort - abort when absent (ctx) */ /* sni abort - abort when absent (ctx) */
printf("sni abort - abort when absent (ctx)\n");
client_cb.ctx_ready = NULL; client_cb.ssl_ready = NULL; client_cb.on_result = verify_FATAL_ERROR_on_client; client_cb.ctx_ready = NULL; client_cb.ssl_ready = NULL; client_cb.on_result = verify_FATAL_ERROR_on_client;
server_cb.ctx_ready = use_MANDATORY_SNI_at_ctx; server_cb.ssl_ready = NULL; server_cb.on_result = verify_SNI_ABSENT_on_server; server_cb.ctx_ready = use_MANDATORY_SNI_at_ctx; server_cb.ssl_ready = NULL; server_cb.on_result = verify_SNI_ABSENT_on_server;
test_wolfSSL_client_server(&client_cb, &server_cb); test_wolfSSL_client_server(&client_cb, &server_cb);
/* sni abort - abort when absent (ssl) */ /* sni abort - abort when absent (ssl) */
printf("sni abort - abort when absent (ssl)\n");
client_cb.ctx_ready = NULL; client_cb.ssl_ready = NULL; client_cb.on_result = verify_FATAL_ERROR_on_client; client_cb.ctx_ready = NULL; client_cb.ssl_ready = NULL; client_cb.on_result = verify_FATAL_ERROR_on_client;
server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_MANDATORY_SNI_at_ssl; server_cb.on_result = verify_SNI_ABSENT_on_server; server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_MANDATORY_SNI_at_ssl; server_cb.on_result = verify_SNI_ABSENT_on_server;
test_wolfSSL_client_server(&client_cb, &server_cb); test_wolfSSL_client_server(&client_cb, &server_cb);
/* sni abort - success when overwritten */ /* sni abort - success when overwritten */
printf("sni abort - success when overwritten\n");
client_cb.ctx_ready = NULL; client_cb.ssl_ready = NULL; client_cb.on_result = NULL; client_cb.ctx_ready = NULL; client_cb.ssl_ready = NULL; client_cb.on_result = NULL;
server_cb.ctx_ready = use_MANDATORY_SNI_at_ctx; server_cb.ssl_ready = use_SNI_at_ssl; server_cb.on_result = verify_SNI_no_matching; server_cb.ctx_ready = use_MANDATORY_SNI_at_ctx; server_cb.ssl_ready = use_SNI_at_ssl; server_cb.on_result = verify_SNI_no_matching;
test_wolfSSL_client_server(&client_cb, &server_cb); test_wolfSSL_client_server(&client_cb, &server_cb);
/* sni abort - success when allowing mismatches */ /* sni abort - success when allowing mismatches */
printf("sni abort - success when allowing mismatches\n");
client_cb.ctx_ready = NULL; client_cb.ssl_ready = different_SNI_at_ssl; client_cb.on_result = NULL; client_cb.ctx_ready = NULL; client_cb.ssl_ready = different_SNI_at_ssl; client_cb.on_result = NULL;
server_cb.ctx_ready = use_PSEUDO_MANDATORY_SNI_at_ctx; server_cb.ssl_ready = NULL; server_cb.on_result = verify_SNI_fake_matching; server_cb.ctx_ready = use_PSEUDO_MANDATORY_SNI_at_ctx; server_cb.ssl_ready = NULL; server_cb.on_result = verify_SNI_fake_matching;
test_wolfSSL_client_server(&client_cb, &server_cb); test_wolfSSL_client_server(&client_cb, &server_cb);
@ -35308,6 +35319,89 @@ static int test_wolfSSL_CTX_add_client_CA(void)
#endif /* OPENSSL_EXTRA && !NO_RSA && !NO_CERTS && !NO_WOLFSSL_CLIENT */ #endif /* OPENSSL_EXTRA && !NO_RSA && !NO_CERTS && !NO_WOLFSSL_CLIENT */
return res; return res;
} }
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
static THREAD_RETURN WOLFSSL_THREAD server_task_ech(void* args)
{
callback_functions* callbacks = ((func_args*)args)->callbacks;
WOLFSSL_CTX* ctx = callbacks->ctx;
WOLFSSL* ssl = NULL;
SOCKET_T sfd = 0;
SOCKET_T cfd = 0;
word16 port;
char input[1024];
int idx;
int ret, err = 0;
const char* privateName = "ech-private-name.com";
int privateNameLen = (int)XSTRLEN(privateName);
((func_args*)args)->return_code = TEST_FAIL;
port = ((func_args*)args)->signal->port;
AssertIntEQ(WOLFSSL_SUCCESS,
wolfSSL_CTX_load_verify_locations(ctx, cliCertFile, 0));
AssertIntEQ(WOLFSSL_SUCCESS,
wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
WOLFSSL_FILETYPE_PEM));
AssertIntEQ(WOLFSSL_SUCCESS,
wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
WOLFSSL_FILETYPE_PEM));
if (callbacks->ctx_ready)
callbacks->ctx_ready(ctx);
ssl = wolfSSL_new(ctx);
/* set the sni for the server */
wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, privateName, privateNameLen);
tcp_accept(&sfd, &cfd, (func_args*)args, port, 0, 0, 0, 0, 1, NULL, NULL);
CloseSocket(sfd);
AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_set_fd(ssl, cfd));
if (callbacks->ssl_ready)
callbacks->ssl_ready(ssl);
do {
err = 0; /* Reset error */
ret = wolfSSL_accept(ssl);
if (ret != WOLFSSL_SUCCESS) {
err = wolfSSL_get_error(ssl, 0);
}
} while (ret != WOLFSSL_SUCCESS && err == WC_PENDING_E);
if (ret != WOLFSSL_SUCCESS) {
char buff[WOLFSSL_MAX_ERROR_SZ];
printf("error = %d, %s\n", err, wolfSSL_ERR_error_string(err, buff));
}
else {
if (0 < (idx = wolfSSL_read(ssl, input, sizeof(input)-1))) {
input[idx] = 0;
printf("Client message: %s\n", input);
}
AssertIntEQ(privateNameLen, wolfSSL_write(ssl, privateName,
privateNameLen));
((func_args*)args)->return_code = TEST_SUCCESS;
}
if (callbacks->on_result)
callbacks->on_result(ssl);
wolfSSL_shutdown(ssl);
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
CloseSocket(cfd);
#ifdef FP_ECC
wc_ecc_fp_free();
#endif
return 0;
}
#endif /* HAVE_ECH && WOLFSSL_TLS13 */
#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK) #if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
static THREAD_RETURN WOLFSSL_THREAD server_task(void* args) static THREAD_RETURN WOLFSSL_THREAD server_task(void* args)
{ {
@ -35673,6 +35767,154 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void)
#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK && WOLFSSL_TLS13 */ #endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK && WOLFSSL_TLS13 */
return res; return res;
} }
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
static int test_wolfSSL_Tls13_ECH_params(void)
{
#if !defined(NO_WOLFSSL_CLIENT)
word32 outputLen = 0;
byte testBuf[72];
WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
WOLFSSL *ssl = wolfSSL_new(ctx);
AssertNotNull(ctx);
AssertNotNull(ssl);
/* invalid ctx */
AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(NULL,
"ech-public-name.com", 0, 0, 0));
/* invalid public name */
AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(ctx, NULL, 0,
0, 0));
/* invalid algorithms */
AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(ctx,
"ech-public-name.com", 1000, 1000, 1000));
/* invalid ctx */
AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(NULL, NULL,
&outputLen));
/* invalid output len */
AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(ctx, NULL, NULL));
/* invalid ssl */
AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(NULL,
(char*)testBuf, sizeof(testBuf)));
/* invalid configs64 */
AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(ssl, NULL,
sizeof(testBuf)));
/* invalid size */
AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(ssl,
(char*)testBuf, 0));
/* invalid ssl */
AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(NULL, testBuf,
sizeof(testBuf)));
/* invalid configs */
AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, NULL,
sizeof(testBuf)));
/* invalid size */
AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, testBuf, 0));
/* invalid ssl */
AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_GetEchConfigs(NULL, NULL, &outputLen));
/* invalid size */
AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_GetEchConfigs(ssl, NULL, NULL));
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
#endif /* !NO_WOLFSSL_CLIENT */
return TEST_SUCCESS;
}
static int test_wolfSSL_Tls13_ECH(void)
{
tcp_ready ready;
func_args client_args;
func_args server_args;
THREAD_TYPE serverThread;
callback_functions server_cbf;
callback_functions client_cbf;
SOCKET_T sockfd = 0;
WOLFSSL_CTX* ctx;
WOLFSSL* ssl;
const char* publicName = "ech-public-name.com";
const char* privateName = "ech-private-name.com";
int privateNameLen = 20;
char reply[1024];
int replyLen = 0;
byte rawEchConfig[128];
word32 rawEchConfigLen = sizeof(rawEchConfig);
InitTcpReady(&ready);
ready.port = 22222;
XMEMSET(&client_args, 0, sizeof(func_args));
XMEMSET(&server_args, 0, sizeof(func_args));
XMEMSET(&server_cbf, 0, sizeof(callback_functions));
XMEMSET(&client_cbf, 0, sizeof(callback_functions));
server_cbf.method = wolfTLSv1_3_server_method; /* TLS1.3 */
/* create the server context here so we can get the ech config */
AssertNotNull(server_cbf.ctx =
wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
/* generate ech config */
AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(server_cbf.ctx,
publicName, 0, 0, 0));
/* get the config for the client to use */
AssertIntEQ(WOLFSSL_SUCCESS,
wolfSSL_CTX_GetEchConfigs(server_cbf.ctx, rawEchConfig,
&rawEchConfigLen));
server_args.callbacks = &server_cbf;
server_args.signal = &ready;
/* start server task */
start_thread(server_task_ech, &server_args, &serverThread);
wait_tcp_ready(&server_args);
/* run as a TLS1.3 client */
AssertNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
AssertIntEQ(WOLFSSL_SUCCESS,
wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0));
AssertIntEQ(WOLFSSL_SUCCESS,
wolfSSL_CTX_use_certificate_file(ctx, cliCertFile, SSL_FILETYPE_PEM));
AssertIntEQ(WOLFSSL_SUCCESS,
wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile, SSL_FILETYPE_PEM));
tcp_connect(&sockfd, wolfSSLIP, server_args.signal->port, 0, 0, NULL);
/* get connected the server task */
AssertNotNull(ssl = wolfSSL_new(ctx));
/* set the ech configs for the client */
AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, rawEchConfig,
rawEchConfigLen));
/* set the sni for the client */
AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME,
privateName, privateNameLen));
AssertIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS);
AssertIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS);
AssertIntEQ(wolfSSL_write(ssl, privateName, privateNameLen),
privateNameLen);
AssertIntGT((replyLen = wolfSSL_read(ssl, reply, sizeof(reply))), 0);
/* add th null terminator for string compare */
reply[replyLen] = 0;
/* check that the server replied with the private name */
AssertStrEQ(privateName, reply);
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
join_thread(serverThread);
FreeTcpReady(&ready);
return TEST_SUCCESS;
}
#endif /* HAVE_ECH && WOLFSSL_TLS13 */
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && \ #if defined(HAVE_IO_TESTS_DEPENDENCIES) && \
defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \ defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
@ -60187,6 +60429,10 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfSSL_wolfSSL_UseSecureRenegotiation), TEST_DECL(test_wolfSSL_wolfSSL_UseSecureRenegotiation),
TEST_DECL(test_wolfSSL_SCR_Reconnect), TEST_DECL(test_wolfSSL_SCR_Reconnect),
TEST_DECL(test_tls_ext_duplicate), TEST_DECL(test_tls_ext_duplicate),
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
TEST_DECL(test_wolfSSL_Tls13_ECH_params),
TEST_DECL(test_wolfSSL_Tls13_ECH),
#endif
/* X509 tests */ /* X509 tests */
TEST_DECL(test_wolfSSL_X509_NAME_get_entry), TEST_DECL(test_wolfSSL_X509_NAME_get_entry),

1163
wolfcrypt/src/hpke.c 100644

File diff suppressed because it is too large Load Diff

View File

@ -253,6 +253,9 @@
#ifdef HAVE_ECC #ifdef HAVE_ECC
#include <wolfssl/wolfcrypt/ecc.h> #include <wolfssl/wolfcrypt/ecc.h>
#endif #endif
#ifdef HAVE_HPKE
#include <wolfssl/wolfcrypt/hpke.h>
#endif
#ifdef HAVE_CURVE25519 #ifdef HAVE_CURVE25519
#include <wolfssl/wolfcrypt/curve25519.h> #include <wolfssl/wolfcrypt/curve25519.h>
#endif #endif
@ -434,6 +437,7 @@ WOLFSSL_TEST_SUBROUTINE int sshkdf_test(void);
WOLFSSL_TEST_SUBROUTINE int tls13_kdf_test(void); WOLFSSL_TEST_SUBROUTINE int tls13_kdf_test(void);
#endif #endif
WOLFSSL_TEST_SUBROUTINE int x963kdf_test(void); WOLFSSL_TEST_SUBROUTINE int x963kdf_test(void);
WOLFSSL_TEST_SUBROUTINE int hpke_test(void);
WOLFSSL_TEST_SUBROUTINE int arc4_test(void); WOLFSSL_TEST_SUBROUTINE int arc4_test(void);
#ifdef WC_RC2 #ifdef WC_RC2
WOLFSSL_TEST_SUBROUTINE int rc2_test(void); WOLFSSL_TEST_SUBROUTINE int rc2_test(void);
@ -1064,6 +1068,13 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\
TEST_PASS("X963-KDF test passed!\n"); TEST_PASS("X963-KDF test passed!\n");
#endif #endif
#if defined(HAVE_HPKE) && defined(HAVE_ECC) && defined(HAVE_AESGCM)
if ( (ret = hpke_test()) != 0)
return err_sys("HPKE test failed!\n", ret);
else
TEST_PASS("HPKE test passed!\n");
#endif
#if defined(HAVE_AESGCM) && defined(WOLFSSL_AES_128) && \ #if defined(HAVE_AESGCM) && defined(WOLFSSL_AES_128) && \
!defined(WOLFSSL_AFALG_XILINX_AES) && !defined(WOLFSSL_XILINX_CRYPT) !defined(WOLFSSL_AFALG_XILINX_AES) && !defined(WOLFSSL_XILINX_CRYPT)
if ( (ret = gmac_test()) != 0) if ( (ret = gmac_test()) != 0)
@ -22244,8 +22255,8 @@ WOLFSSL_TEST_SUBROUTINE int tls13_kdf_test(void)
ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz, ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz,
secret, hashAlgSz, secret, hashAlgSz,
(byte*)protocolLabel, (word32)strlen(protocolLabel), (byte*)protocolLabel, (word32)XSTRLEN(protocolLabel),
(byte*)ceTrafficLabel, (word32)strlen(ceTrafficLabel), (byte*)ceTrafficLabel, (word32)XSTRLEN(ceTrafficLabel),
tv->hashHello1, hashAlgSz, tv->hashAlg); tv->hashHello1, hashAlgSz, tv->hashAlg);
if (ret != 0) break; if (ret != 0) break;
@ -22254,8 +22265,8 @@ WOLFSSL_TEST_SUBROUTINE int tls13_kdf_test(void)
ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz, ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz,
secret, hashAlgSz, secret, hashAlgSz,
(byte*)protocolLabel, (word32)strlen(protocolLabel), (byte*)protocolLabel, (word32)XSTRLEN(protocolLabel),
(byte*)eExpMasterLabel, (word32)strlen(eExpMasterLabel), (byte*)eExpMasterLabel, (word32)XSTRLEN(eExpMasterLabel),
tv->hashHello1, hashAlgSz, tv->hashAlg); tv->hashHello1, hashAlgSz, tv->hashAlg);
if (ret != 0) break; if (ret != 0) break;
@ -22264,8 +22275,8 @@ WOLFSSL_TEST_SUBROUTINE int tls13_kdf_test(void)
ret = wc_Tls13_HKDF_Expand_Label(salt, hashAlgSz, ret = wc_Tls13_HKDF_Expand_Label(salt, hashAlgSz,
secret, hashAlgSz, secret, hashAlgSz,
(byte*)protocolLabel, (word32)strlen(protocolLabel), (byte*)protocolLabel, (word32)XSTRLEN(protocolLabel),
(byte*)derivedLabel, (word32)strlen(derivedLabel), (byte*)derivedLabel, (word32)XSTRLEN(derivedLabel),
hashZero, hashAlgSz, tv->hashAlg); hashZero, hashAlgSz, tv->hashAlg);
if (ret != 0) break; if (ret != 0) break;
@ -22276,8 +22287,8 @@ WOLFSSL_TEST_SUBROUTINE int tls13_kdf_test(void)
ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz, ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz,
secret, hashAlgSz, secret, hashAlgSz,
(byte*)protocolLabel, (word32)strlen(protocolLabel), (byte*)protocolLabel, (word32)XSTRLEN(protocolLabel),
(byte*)cHsTrafficLabel, (word32)strlen(cHsTrafficLabel), (byte*)cHsTrafficLabel, (word32)XSTRLEN(cHsTrafficLabel),
tv->hashHello2, hashAlgSz, tv->hashAlg); tv->hashHello2, hashAlgSz, tv->hashAlg);
if (ret != 0) break; if (ret != 0) break;
@ -22287,8 +22298,8 @@ WOLFSSL_TEST_SUBROUTINE int tls13_kdf_test(void)
ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz, ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz,
secret, hashAlgSz, secret, hashAlgSz,
(byte*)protocolLabel, (word32)strlen(protocolLabel), (byte*)protocolLabel, (word32)XSTRLEN(protocolLabel),
(byte*)sHsTrafficLabel, (word32)strlen(sHsTrafficLabel), (byte*)sHsTrafficLabel, (word32)XSTRLEN(sHsTrafficLabel),
tv->hashHello2, hashAlgSz, tv->hashAlg); tv->hashHello2, hashAlgSz, tv->hashAlg);
if (ret != 0) break; if (ret != 0) break;
@ -22297,8 +22308,8 @@ WOLFSSL_TEST_SUBROUTINE int tls13_kdf_test(void)
ret = wc_Tls13_HKDF_Expand_Label(salt, hashAlgSz, ret = wc_Tls13_HKDF_Expand_Label(salt, hashAlgSz,
secret, hashAlgSz, secret, hashAlgSz,
(byte*)protocolLabel, (word32)strlen(protocolLabel), (byte*)protocolLabel, (word32)XSTRLEN(protocolLabel),
(byte*)derivedLabel, (word32)strlen(derivedLabel), (byte*)derivedLabel, (word32)XSTRLEN(derivedLabel),
hashZero, hashAlgSz, tv->hashAlg); hashZero, hashAlgSz, tv->hashAlg);
if (ret != 0) break; if (ret != 0) break;
@ -22308,8 +22319,8 @@ WOLFSSL_TEST_SUBROUTINE int tls13_kdf_test(void)
ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz, ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz,
secret, hashAlgSz, secret, hashAlgSz,
(byte*)protocolLabel, (word32)strlen(protocolLabel), (byte*)protocolLabel, (word32)XSTRLEN(protocolLabel),
(byte*)cAppTrafficLabel, (word32)strlen(cAppTrafficLabel), (byte*)cAppTrafficLabel, (word32)XSTRLEN(cAppTrafficLabel),
tv->hashFinished1, hashAlgSz, tv->hashAlg); tv->hashFinished1, hashAlgSz, tv->hashAlg);
if (ret != 0) break; if (ret != 0) break;
@ -22318,8 +22329,8 @@ WOLFSSL_TEST_SUBROUTINE int tls13_kdf_test(void)
ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz, ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz,
secret, hashAlgSz, secret, hashAlgSz,
(byte*)protocolLabel, (word32)strlen(protocolLabel), (byte*)protocolLabel, (word32)XSTRLEN(protocolLabel),
(byte*)sAppTrafficLabel, (word32)strlen(sAppTrafficLabel), (byte*)sAppTrafficLabel, (word32)XSTRLEN(sAppTrafficLabel),
tv->hashFinished1, hashAlgSz, tv->hashAlg); tv->hashFinished1, hashAlgSz, tv->hashAlg);
if (ret != 0) break; if (ret != 0) break;
@ -22328,8 +22339,8 @@ WOLFSSL_TEST_SUBROUTINE int tls13_kdf_test(void)
ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz, ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz,
secret, hashAlgSz, secret, hashAlgSz,
(byte*)protocolLabel, (word32)strlen(protocolLabel), (byte*)protocolLabel, (word32)XSTRLEN(protocolLabel),
(byte*)expMasterLabel, (word32)strlen(expMasterLabel), (byte*)expMasterLabel, (word32)XSTRLEN(expMasterLabel),
tv->hashFinished1, hashAlgSz, tv->hashAlg); tv->hashFinished1, hashAlgSz, tv->hashAlg);
if (ret != 0) break; if (ret != 0) break;
@ -22338,8 +22349,8 @@ WOLFSSL_TEST_SUBROUTINE int tls13_kdf_test(void)
ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz, ret = wc_Tls13_HKDF_Expand_Label(output, hashAlgSz,
secret, hashAlgSz, secret, hashAlgSz,
(byte*)protocolLabel, (word32)strlen(protocolLabel), (byte*)protocolLabel, (word32)XSTRLEN(protocolLabel),
(byte*)resMasterLabel, (word32)strlen(resMasterLabel), (byte*)resMasterLabel, (word32)XSTRLEN(resMasterLabel),
tv->hashFinished2, hashAlgSz, tv->hashAlg); tv->hashFinished2, hashAlgSz, tv->hashAlg);
if (ret != 0) break; if (ret != 0) break;
@ -22498,6 +22509,138 @@ WOLFSSL_TEST_SUBROUTINE int x963kdf_test(void)
#endif /* HAVE_X963_KDF */ #endif /* HAVE_X963_KDF */
#if defined(HAVE_HPKE) && (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
defined(HAVE_AESGCM)
static int hpke_test_single(Hpke* hpke)
{
int ret = 0;
int rngRet = 0;
WC_RNG rng[1];
const char* start_text = "this is a test";
const char* info_text = "info";
const char* aad_text = "aad";
byte ciphertext[MAX_HPKE_LABEL_SZ];
byte plaintext[MAX_HPKE_LABEL_SZ];
void* receiverKey = NULL;
void* ephemeralKey = NULL;
uint8_t pubKey[HPKE_Npk_MAX]; /* public key */
word16 pubKeySz = (word16)sizeof(pubKey);
rngRet = ret = wc_InitRng(rng);
if (ret != 0)
return ret;
/* generate the keys */
if (ret == 0)
ret = wc_HpkeGenerateKeyPair(hpke, &ephemeralKey, rng);
if (ret == 0)
ret = wc_HpkeGenerateKeyPair(hpke, &receiverKey, rng);
/* seal */
if (ret == 0)
ret = wc_HpkeSealBase(hpke, ephemeralKey, receiverKey,
(byte*)info_text, (word32)XSTRLEN(info_text),
(byte*)aad_text, (word32)XSTRLEN(aad_text),
(byte*)start_text, (word32)XSTRLEN(start_text),
ciphertext);
/* export ephemeral key */
if (ret == 0)
ret = wc_HpkeSerializePublicKey(hpke, ephemeralKey, pubKey, &pubKeySz);
/* open with exported ephemeral key */
if (ret == 0)
ret = wc_HpkeOpenBase(hpke, receiverKey, pubKey, pubKeySz,
(byte*)info_text, (word32)XSTRLEN(info_text),
(byte*)aad_text, (word32)XSTRLEN(aad_text),
ciphertext, (word32)XSTRLEN(start_text),
plaintext);
if (ret == 0)
ret = XMEMCMP(plaintext, start_text, XSTRLEN(start_text));
if (ephemeralKey != NULL)
wc_HpkeFreeKey(hpke, hpke->kem, ephemeralKey, hpke->heap);
if (receiverKey != NULL)
wc_HpkeFreeKey(hpke, hpke->kem, receiverKey, hpke->heap);
if (rngRet == 0)
wc_FreeRng(rng);
return ret;
}
WOLFSSL_TEST_SUBROUTINE int hpke_test(void)
{
int ret = 0;
Hpke hpke[1];
#if defined(HAVE_ECC)
#if defined(WOLFSSL_SHA224) || !defined(NO_SHA256)
/* p256 */
ret = wc_HpkeInit(hpke, DHKEM_P256_HKDF_SHA256, HKDF_SHA256,
HPKE_AES_128_GCM, NULL);
if (ret != 0)
return ret;
ret = hpke_test_single(hpke);
if (ret != 0)
return ret;
#endif
#ifdef WOLFSSL_SHA384
/* p384 */
ret = wc_HpkeInit(hpke, DHKEM_P384_HKDF_SHA384, HKDF_SHA384,
HPKE_AES_128_GCM, NULL);
if (ret != 0)
return ret;
ret = hpke_test_single(hpke);
if (ret != 0)
return ret;
#endif
#if defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)
/* p521 */
ret = wc_HpkeInit(hpke, DHKEM_P521_HKDF_SHA512, HKDF_SHA512,
HPKE_AES_128_GCM, NULL);
if (ret != 0)
return ret;
ret = hpke_test_single(hpke);
if (ret != 0)
return ret;
#endif
#endif
#if defined(HAVE_CURVE25519)
/* test with curve25519 and aes256 */
ret = wc_HpkeInit(hpke, DHKEM_X25519_HKDF_SHA256, HKDF_SHA256,
HPKE_AES_256_GCM, NULL);
if (ret != 0)
return ret;
ret = hpke_test_single(hpke);
if (ret != 0)
return ret;
#endif
return ret;
/* x448 and chacha20 are unimplemented */
}
#endif /* HAVE_HPKE && HAVE_ECC && HAVE_AESGCM */
#ifdef HAVE_ECC #ifdef HAVE_ECC

View File

@ -265,6 +265,8 @@
#include <wolfssl/wolfcrypt/port/Renesas/renesas-tsip-crypt.h> #include <wolfssl/wolfcrypt/port/Renesas/renesas-tsip-crypt.h>
#endif #endif
#include <wolfssl/wolfcrypt/hpke.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -2594,8 +2596,74 @@ typedef enum {
#ifdef WOLFSSL_QUIC #ifdef WOLFSSL_QUIC
TLSX_KEY_QUIC_TP_PARAMS_DRAFT = 0xffa5, /* from draft-ietf-quic-tls-27 */ TLSX_KEY_QUIC_TP_PARAMS_DRAFT = 0xffa5, /* from draft-ietf-quic-tls-27 */
#endif #endif
#if defined(HAVE_ECH)
TLSX_ECH = 0xfe0d, /* from draft-ietf-tls-esni-13 */
#endif
} TLSX_Type; } TLSX_Type;
#if defined(HAVE_ECH)
typedef enum {
ECH_TYPE_OUTER = 0,
ECH_TYPE_INNER = 1
} EchType;
typedef enum {
ECH_WRITE_GREASE,
ECH_WRITE_REAL,
ECH_WRITE_RETRY_CONFIGS,
ECH_WRITE_NONE,
ECH_PARSED_INTERNAL,
} EchState;
typedef struct EchCipherSuite {
word16 kdfId;
word16 aeadId;
} EchCipherSuite;
typedef struct WOLFSSL_EchConfig {
byte* raw;
char* publicName;
void* receiverPrivkey;
struct WOLFSSL_EchConfig* next;
EchCipherSuite* cipherSuites;
word32 rawLen;
word16 kemId;
byte configId;
byte numCipherSuites;
byte receiverPubkey[HPKE_Npk_MAX];
} WOLFSSL_EchConfig;
typedef struct WOLFSSL_ECH {
Hpke* hpke;
const byte* aad;
void* ephemeralKey;
WOLFSSL_EchConfig* echConfig;
byte* innerClientHello;
byte* outerClientPayload;
EchCipherSuite cipherSuite;
word16 aadLen;
word16 paddingLen;
word16 innerClientHelloLen;
word16 kemId;
word16 encLen;
EchState state;
byte type;
byte configId;
byte enc[HPKE_Npk_MAX];
} WOLFSSL_ECH;
WOLFSSL_LOCAL int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config);
WOLFSSL_LOCAL int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen);
WOLFSSL_LOCAL int GetEchConfig(WOLFSSL_EchConfig* config, byte* output,
word32* outputLen);
WOLFSSL_LOCAL int GetEchConfigsEx(WOLFSSL_EchConfig* configs,
byte* output, word32* outputLen);
#endif
typedef struct TLSX { typedef struct TLSX {
TLSX_Type type; /* Extension Type */ TLSX_Type type; /* Extension Type */
void* data; /* Extension Data */ void* data; /* Extension Data */
@ -3498,6 +3566,9 @@ struct WOLFSSL_CTX {
const WOLFSSL_QUIC_METHOD *method; const WOLFSSL_QUIC_METHOD *method;
} quic; } quic;
#endif #endif
#if defined(HAVE_ECH)
WOLFSSL_EchConfig* echConfigs;
#endif
}; };
WOLFSSL_LOCAL WOLFSSL_LOCAL
@ -4258,6 +4329,12 @@ typedef struct Options {
#ifdef WOLFSSL_TLS13 #ifdef WOLFSSL_TLS13
word16 tls13MiddleBoxCompat:1; /* TLSv1.3 middlebox compatibility */ word16 tls13MiddleBoxCompat:1; /* TLSv1.3 middlebox compatibility */
#endif #endif
#ifdef WOLFSSL_DTLS_CID
byte useDtlsCID:1;
#endif /* WOLFSSL_DTLS_CID */
#if defined(HAVE_ECH)
byte useEch:1;
#endif
/* need full byte values for this section */ /* need full byte values for this section */
byte processReply; /* nonblocking resume */ byte processReply; /* nonblocking resume */
@ -4303,9 +4380,6 @@ typedef struct Options {
#ifdef WOLFSSL_TLS13 #ifdef WOLFSSL_TLS13
byte oldMinor; /* client preferred version < TLS 1.3 */ byte oldMinor; /* client preferred version < TLS 1.3 */
#endif #endif
#ifdef WOLFSSL_DTLS_CID
byte useDtlsCID:1;
#endif /* WOLFSSL_DTLS_CID */
} Options; } Options;
typedef struct Arrays { typedef struct Arrays {
@ -4321,6 +4395,9 @@ typedef struct Arrays {
byte psk_key[MAX_PSK_KEY_LEN]; byte psk_key[MAX_PSK_KEY_LEN];
#endif #endif
byte clientRandom[RAN_LEN]; byte clientRandom[RAN_LEN];
#if defined(HAVE_ECH)
byte clientRandomInner[RAN_LEN];
#endif
byte serverRandom[RAN_LEN]; byte serverRandom[RAN_LEN];
byte sessionID[ID_LEN]; byte sessionID[ID_LEN];
byte sessionIDSz; byte sessionIDSz;
@ -4889,6 +4966,9 @@ struct WOLFSSL {
byte serverSecret[SECRET_LEN]; byte serverSecret[SECRET_LEN];
#endif #endif
HS_Hashes* hsHashes; HS_Hashes* hsHashes;
#if defined(HAVE_ECH)
HS_Hashes* hsHashesEch;
#endif
void* IOCB_ReadCtx; void* IOCB_ReadCtx;
void* IOCB_WriteCtx; void* IOCB_WriteCtx;
WC_RNG* rng; WC_RNG* rng;
@ -5348,6 +5428,9 @@ struct WOLFSSL {
* content have not been handled yet by quic */ * content have not been handled yet by quic */
} quic; } quic;
#endif /* WOLFSSL_QUIC */ #endif /* WOLFSSL_QUIC */
#if defined(HAVE_ECH)
WOLFSSL_EchConfig* echConfigs;
#endif
}; };
/* /*
@ -5853,6 +5936,8 @@ WOLFSSL_LOCAL int SetDhExternal(WOLFSSL_DH *dh);
WOLFSSL_LOCAL int InitHandshakeHashes(WOLFSSL* ssl); WOLFSSL_LOCAL int InitHandshakeHashes(WOLFSSL* ssl);
WOLFSSL_LOCAL void FreeHandshakeHashes(WOLFSSL* ssl); WOLFSSL_LOCAL void FreeHandshakeHashes(WOLFSSL* ssl);
WOLFSSL_LOCAL int InitHandshakeHashesAndCopy(WOLFSSL* ssl, HS_Hashes* source,
HS_Hashes** destination);
#ifndef WOLFSSL_NO_TLS12 #ifndef WOLFSSL_NO_TLS12

View File

@ -992,6 +992,23 @@ WOLFSSL_API WOLFSSL_METHOD *wolfSSLv23_method(void);
#endif /* WOLFSSL_DTLS */ #endif /* WOLFSSL_DTLS */
#if defined(HAVE_ECH)
WOLFSSL_API int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx,
const char* publicName, word16 kemId, word16 kdfId, word16 aeadId);
WOLFSSL_API int wolfSSL_CTX_GetEchConfigs(WOLFSSL_CTX* ctx, byte* output,
word32* outputLen);
WOLFSSL_API int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64,
word32 echConfigs64Len);
WOLFSSL_API int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs,
word32 echConfigsLen);
WOLFSSL_API int wolfSSL_GetEchConfigs(WOLFSSL* ssl, byte* echConfigs,
word32* echConfigsLen);
#endif /* HAVE_ECH */
#ifdef HAVE_POLY1305 #ifdef HAVE_POLY1305
WOLFSSL_API int wolfSSL_use_old_poly(WOLFSSL* ssl, int value); WOLFSSL_API int wolfSSL_use_old_poly(WOLFSSL* ssl, int value);
#endif #endif
@ -3702,7 +3719,8 @@ WOLFSSL_API void* wolfSSL_CTX_GetHeap(WOLFSSL_CTX* ctx, WOLFSSL* ssl);
/* SNI types */ /* SNI types */
enum { enum {
WOLFSSL_SNI_HOST_NAME = 0 WOLFSSL_SNI_HOST_NAME = 0,
WOLFSSL_SNI_HOST_NAME_OUTER = 0,
}; };
WOLFSSL_ABI WOLFSSL_API int wolfSSL_UseSNI(WOLFSSL* ssl, unsigned char type, WOLFSSL_ABI WOLFSSL_API int wolfSSL_UseSNI(WOLFSSL* ssl, unsigned char type,

View File

@ -0,0 +1,136 @@
/* hpke.h
*
* Copyright (C) 2006-2022 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/*!
\file wolfssl/wolfcrypt/hpke.h
*/
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/types.h>
#include <wolfssl/wolfcrypt/ecc.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(HAVE_HPKE) && defined(HAVE_ECC)
#ifndef WOLFCRYPT_HPKE
#define WOLFCRYPT_HPKE
/* KEM enum */
enum {
DHKEM_P256_HKDF_SHA256 = 0x0010,
DHKEM_P384_HKDF_SHA384 = 0x0011,
DHKEM_P521_HKDF_SHA512 = 0x0012,
DHKEM_X25519_HKDF_SHA256 = 0x0020,
DHKEM_X448_HKDF_SHA512 = 0x0021,
};
#define DHKEM_P256_ENC_LEN 65
#define DHKEM_P384_ENC_LEN 97
#define DHKEM_P521_ENC_LEN 133
#define DHKEM_X25519_ENC_LEN 32
#define DHKEM_X448_ENC_LEN 56
/* KDF enum */
enum {
HKDF_SHA256 = 0x0001,
HKDF_SHA384 = 0x0002,
HKDF_SHA512 = 0x0003,
};
/* AEAD enum */
enum {
HPKE_AES_128_GCM = 0x0001,
HPKE_AES_256_GCM = 0x0002,
};
/* TODO better way of doing this */
#define HPKE_SUPPORTED_KEM_LEN 4
#define HPKE_SUPPORTED_KDF_LEN 3
#define HPKE_SUPPORTED_AEAD_LEN 2
extern const int hpkeSupportedKem[HPKE_SUPPORTED_KEM_LEN];
extern const int hpkeSupportedKdf[HPKE_SUPPORTED_KDF_LEN];
extern const int hpkeSupportedAead[HPKE_SUPPORTED_AEAD_LEN];
#define HPKE_Nh_MAX 64
#define HPKE_Nk_MAX 32
#define HPKE_Nn_MAX 12
#define HPKE_Nt_MAX 16
#define HPKE_Ndh_MAX 66
#define HPKE_Npk_MAX 133
#define HPKE_Nsecret_MAX 64
#define KEM_SUITE_ID_LEN 5
#define HPKE_SUITE_ID_LEN 10
#ifndef MAX_HPKE_LABEL_SZ
#define MAX_HPKE_LABEL_SZ 512
#endif
typedef struct {
void* heap;
word32 kem;
word32 kdf;
word32 aead;
word32 Nh;
word32 Nk;
word32 Nn;
word32 Nt;
word32 Ndh;
word32 Npk;
word32 Nsecret;
int kdf_digest;
int curve_id;
byte kem_suite_id[KEM_SUITE_ID_LEN];
byte hpke_suite_id[HPKE_SUITE_ID_LEN];
} Hpke;
typedef struct {
int seq;
byte key[HPKE_Nk_MAX];
byte base_nonce[HPKE_Nn_MAX];
byte exporter_secret[HPKE_Nsecret_MAX];
} HpkeBaseContext;
WOLFSSL_API int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap);
WOLFSSL_API int wc_HpkeGenerateKeyPair(Hpke* hpke, void** keypair, WC_RNG* rng);
WOLFSSL_API int wc_HpkeSerializePublicKey(Hpke* hpke, void* key, byte* out,
word16* outSz);
WOLFSSL_API int wc_HpkeDeserializePublicKey(Hpke* hpke, void** key,
const byte* in, word16 inSz);
WOLFSSL_API void wc_HpkeFreeKey(Hpke* hpke, word16 kem, void* keypair,
void* heap);
WOLFSSL_API int wc_HpkeSealBase(Hpke* hpke, void* ephemeralKey,
void* receiverKey, byte* info, word32 infoSz, byte* aad, word32 aadSz,
byte* plaintext, word32 ptSz, byte* ciphertext);
WOLFSSL_API int wc_HpkeOpenBase(Hpke* hpke, void* receiverKey,
const byte* pubKey, word16 pubKeySz, byte* info, word32 infoSz, byte* aad,
word32 aadSz, byte* ciphertext, word32 ctSz, byte* plaintext);
#endif
#endif /* HAVE_HPKE && HAVE_ECC */
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@ -32,6 +32,7 @@ nobase_include_HEADERS+= \
wolfssl/wolfcrypt/fips_test.h \ wolfssl/wolfcrypt/fips_test.h \
wolfssl/wolfcrypt/hash.h \ wolfssl/wolfcrypt/hash.h \
wolfssl/wolfcrypt/hmac.h \ wolfssl/wolfcrypt/hmac.h \
wolfssl/wolfcrypt/hpke.h \
wolfssl/wolfcrypt/kdf.h \ wolfssl/wolfcrypt/kdf.h \
wolfssl/wolfcrypt/integer.h \ wolfssl/wolfcrypt/integer.h \
wolfssl/wolfcrypt/md2.h \ wolfssl/wolfcrypt/md2.h \

View File

@ -2879,6 +2879,10 @@ extern void uITRON4_free(void *p) ;
#define WOLFSSL_NO_SHAKE256 #define WOLFSSL_NO_SHAKE256
#endif #endif
/* Encrypted Client Hello - requires HPKE */
#if defined(HAVE_ECH) && !defined(HAVE_HPKE)
#define HAVE_HPKE
#endif