Merge pull request #6805 from jpbland1/ech-hello-retry

Ech hello retry request
This commit is contained in:
Sean Parkinson
2025-03-13 09:17:58 +10:00
committed by GitHub
9 changed files with 678 additions and 445 deletions

View File

@@ -7298,7 +7298,7 @@ int InitHandshakeHashesAndCopy(WOLFSSL* ssl, HS_Hashes* source,
/* save the original so we can put it back afterward */
tmpHashes = ssl->hsHashes;
ssl->hsHashes = NULL;
ssl->hsHashes = *destination;
ret = InitHandshakeHashes(ssl);
if (ret != 0) {
@@ -8435,6 +8435,13 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl)
}
FreeSuites(ssl);
FreeHandshakeHashes(ssl);
#ifdef HAVE_ECH
/* try to free the ech hashes in case we errored out */
ssl->hsHashes = ssl->hsHashesEch;
FreeHandshakeHashes(ssl);
ssl->hsHashes = ssl->hsHashesEchInner;
FreeHandshakeHashes(ssl);
#endif
XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN);
/* clear keys struct after session */
@@ -8448,9 +8455,6 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl)
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 /* HAVE_ECH */

View File

@@ -683,16 +683,17 @@ int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs,
&workingConfig->cipherSuites[j].aeadId);
}
echConfig += cipherSuitesLen;
/* ignore the maximum name length */
echConfig++;
/* publicNameLen */
ato16(echConfig, &publicNameLen);
publicNameLen = *(echConfig);
workingConfig->publicName = (char*)XMALLOC(publicNameLen + 1,
ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (workingConfig->publicName == NULL) {
ret = MEMORY_E;
break;
}
echConfig += 2;
echConfig++;
/* publicName */
XMEMCPY(workingConfig->publicName, echConfig, publicNameLen);
/* null terminated */
@@ -869,9 +870,13 @@ int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen)
output += 2;
}
/* set maximum name length to 0 */
*output = 0;
output++;
/* publicName len */
c16toa(XSTRLEN(config->publicName), output);
output += 2;
*output = XSTRLEN(config->publicName);
output++;
/* publicName */
XMEMCPY(output, config->publicName,

329
src/tls.c
View File

@@ -12881,41 +12881,35 @@ static int TLSX_ECH_Use(WOLFSSL_EchConfig* echConfig, TLSX** extensions,
{
int ret = 0;
int suiteIndex;
TLSX* echX;
WOLFSSL_ECH* ech;
if (extensions == NULL)
return BAD_FUNC_ARG;
/* skip if we already have an ech extension, we will for hrr */
echX = TLSX_Find(*extensions, TLSX_ECH);
if (echX != NULL)
return 0;
/* find a supported cipher suite */
suiteIndex = EchConfigGetSupportedCipherSuite(echConfig);
if (suiteIndex < 0)
return suiteIndex;
ech = (WOLFSSL_ECH*)XMALLOC(sizeof(WOLFSSL_ECH), heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (ech == NULL)
return MEMORY_E;
ForceZero(ech, sizeof(WOLFSSL_ECH));
ech->state = ECH_WRITE_REAL;
ech->echConfig = echConfig;
/* 0 for outer */
ech->type = ECH_TYPE_OUTER;
/* kemId */
ech->kemId = echConfig->kemId;
/* cipherSuite kdf */
ech->cipherSuite.kdfId = echConfig->cipherSuites[suiteIndex].kdfId;
/* cipherSuite aead */
ech->cipherSuite.aeadId = echConfig->cipherSuites[suiteIndex].aeadId;
/* configId */
ech->configId = echConfig->configId;
/* encLen */
switch (echConfig->kemId)
{
@@ -12935,30 +12929,23 @@ static int TLSX_ECH_Use(WOLFSSL_EchConfig* echConfig, TLSX** extensions,
ech->encLen = DHKEM_X448_ENC_LEN;
break;
}
/* setup hpke */
ech->hpke = (Hpke*)XMALLOC(sizeof(Hpke), heap, DYNAMIC_TYPE_TMP_BUFFER);
if (ech->hpke == NULL) {
XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
ret = wc_HpkeInit(ech->hpke, ech->kemId, ech->cipherSuite.kdfId,
ech->cipherSuite.aeadId, heap);
/* setup the ephemeralKey */
if (ret == 0)
ret = wc_HpkeGenerateKeyPair(ech->hpke, &ech->ephemeralKey, rng);
if (ret == 0)
ret = TLSX_Push(extensions, TLSX_ECH, ech, heap);
if (ret != 0) {
XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER);
}
return ret;
}
@@ -12969,41 +12956,31 @@ static int TLSX_ServerECH_Use(TLSX** extensions, void* heap,
int ret;
WOLFSSL_ECH* ech;
TLSX* echX;
if (extensions == NULL)
return BAD_FUNC_ARG;
/* if we already have ech don't override it */
echX = TLSX_Find(*extensions, TLSX_ECH);
if (echX != NULL)
return 0;
ech = (WOLFSSL_ECH*)XMALLOC(sizeof(WOLFSSL_ECH), heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (ech == NULL)
return MEMORY_E;
ForceZero(ech, sizeof(WOLFSSL_ECH));
ech->state = ECH_WRITE_NONE;
/* 0 for outer */
ech->type = ECH_TYPE_OUTER;
ech->echConfig = configs;
/* setup the rest of the settings when we receive ech from the client */
ret = TLSX_Push(extensions, TLSX_ECH, ech, heap);
if (ret != 0)
XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
/* return length after writing the ech */
static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte* writeBuf, word16* offset)
/* return status after writing the ech and updating offset */
static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte msgType, byte* writeBuf,
word16* offset)
{
int ret = 0;
int rngRet = -1;
@@ -13017,84 +12994,75 @@ static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte* writeBuf, word16* offset)
Hpke hpke[1];
WC_RNG rng[1];
#endif
WOLFSSL_MSG("TLSX_ECH_Write");
if (msgType == hello_retry_request) {
/* reserve space to write the confirmation to */
*offset += ECH_ACCEPT_CONFIRMATION_SZ;
/* set confBuf */
ech->confBuf = writeBuf;
return 0;
}
if (ech->state == ECH_WRITE_NONE || ech->state == ECH_PARSED_INTERNAL)
return 0;
if (ech->state == ECH_WRITE_RETRY_CONFIGS) {
/* get size then write */
ret = GetEchConfigsEx(ech->echConfig, NULL, &configsLen);
if (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E))
return ret;
ret = GetEchConfigsEx(ech->echConfig, writeBuf, &configsLen);
if (ret != WOLFSSL_SUCCESS)
return ret;
*offset += configsLen;
return 0;
}
#ifdef WOLFSSL_SMALL_STACK
hpke = (Hpke*)XMALLOC(sizeof(Hpke), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (hpke == NULL)
return MEMORY_E;
rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
if (rng == NULL) {
XFREE(hpke, NULL, DYNAMIC_TYPE_RNG);
return MEMORY_E;
}
#endif
/* type */
*writeBuf_p = ech->type;
writeBuf_p += sizeof(ech->type);
/* outer has body, inner does not */
if (ech->type == ECH_TYPE_OUTER) {
/* kdfId */
c16toa(ech->cipherSuite.kdfId, writeBuf_p);
writeBuf_p += sizeof(ech->cipherSuite.kdfId);
/* aeadId */
c16toa(ech->cipherSuite.aeadId, writeBuf_p);
writeBuf_p += sizeof(ech->cipherSuite.aeadId);
/* configId */
*writeBuf_p = ech->configId;
writeBuf_p += sizeof(ech->configId);
/* encLen */
if (ech->hpkeContext == NULL) {
c16toa(ech->encLen, writeBuf_p);
}
else {
/* set to 0 if this is clientInner 2 */
c16toa(0, writeBuf_p);
}
writeBuf_p += 2;
if (ech->state == ECH_WRITE_GREASE) {
#ifdef WOLFSSL_SMALL_STACK
hpke = (Hpke*)XMALLOC(sizeof(Hpke), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (hpke == NULL)
return MEMORY_E;
rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
if (rng == NULL) {
XFREE(hpke, NULL, DYNAMIC_TYPE_RNG);
return MEMORY_E;
}
#endif
/* hpke init */
ret = wc_HpkeInit(hpke, ech->kemId, ech->cipherSuite.kdfId,
ech->cipherSuite.aeadId, NULL);
if (ret == 0)
rngRet = ret = wc_InitRng(rng);
/* create the ephemeralKey */
if (ret == 0)
ret = wc_HpkeGenerateKeyPair(hpke, &ephemeralKey, rng);
/* enc */
if (ret == 0) {
ret = wc_HpkeSerializePublicKey(hpke, ephemeralKey, writeBuf_p,
&ech->encLen);
writeBuf_p += ech->encLen;
}
if (ret == 0) {
/* innerClientHelloLen */
c16toa(GREASE_ECH_SIZE + ((writeBuf_p + 2 - writeBuf) % 32),
@@ -13106,45 +13074,40 @@ static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte* writeBuf, word16* offset)
((writeBuf_p - writeBuf) % 32));
writeBuf_p += GREASE_ECH_SIZE + ((writeBuf_p - writeBuf) % 32);
}
if (rngRet == 0)
wc_FreeRng(rng);
if (ephemeralKey != NULL)
wc_HpkeFreeKey(hpke, hpke->kem, ephemeralKey, hpke->heap);
#ifdef WOLFSSL_SMALL_STACK
XFREE(hpke, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(rng, NULL, DYNAMIC_TYPE_RNG);
#endif
}
else {
/* only write enc if this is our first ech, no hpke context */
if (ech->hpkeContext == NULL) {
/* write enc to writeBuf_p */
ret = wc_HpkeSerializePublicKey(ech->hpke, ech->ephemeralKey,
writeBuf_p, &ech->encLen);
writeBuf_p += ech->encLen;
}
/* innerClientHelloLen */
c16toa(ech->innerClientHelloLen, writeBuf_p);
writeBuf_p += 2;
/* set payload offset for when we finalize */
ech->outerClientPayload = writeBuf_p;
/* write zeros for payload */
XMEMSET(writeBuf_p, 0, ech->innerClientHelloLen);
writeBuf_p += ech->innerClientHelloLen;
}
}
#ifdef WOLFSSL_SMALL_STACK
XFREE(hpke, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(rng, NULL, DYNAMIC_TYPE_RNG);
#endif
if (ret == 0)
*offset += (writeBuf_p - writeBuf);
return ret;
}
/* return the size needed for the ech extension */
static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech)
static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech, byte msgType)
{
int ret;
word32 size;
@@ -13156,6 +13119,9 @@ static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech)
size += GREASE_ECH_SIZE + (size % 32);
}
else if (msgType == hello_retry_request) {
size = ECH_ACCEPT_CONFIRMATION_SZ;
}
else if (ech->state == ECH_WRITE_NONE ||
ech->state == ECH_PARSED_INTERNAL) {
size = 0;
@@ -13174,8 +13140,11 @@ static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech)
else
{
size = sizeof(ech->type) + sizeof(ech->cipherSuite) +
sizeof(ech->configId) + sizeof(word16) + ech->encLen +
sizeof(word16) + ech->innerClientHelloLen;
sizeof(ech->configId) + sizeof(word16) + sizeof(word16) +
ech->innerClientHelloLen;
/* only set encLen if this is inner hello 1 */
if (ech->hpkeContext == NULL)
size += ech->encLen;
}
return (int)size;
@@ -13193,10 +13162,8 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
word32 rawConfigLen = 0;
byte* info = NULL;
word32 infoLen = 0;
if (ech == NULL || echConfig == NULL || aad == NULL)
return BAD_FUNC_ARG;
/* verify the kem and key len */
switch (echConfig->kemId)
{
@@ -13219,10 +13186,8 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
expectedEncLen = 0;
break;
}
if (expectedEncLen != ech->encLen)
return BAD_FUNC_ARG;
/* verify the cipher suite */
for (i = 0; i < echConfig->numCipherSuites; i++) {
if (echConfig->cipherSuites[i].kdfId == ech->cipherSuite.kdfId &&
@@ -13230,26 +13195,32 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
break;
}
}
if (i >= echConfig->numCipherSuites) {
return BAD_FUNC_ARG;
}
/* check if hpke already exists, may if HelloRetryRequest */
if (ech->hpke == NULL) {
ech->hpke = (Hpke*)XMALLOC(sizeof(Hpke), heap, DYNAMIC_TYPE_TMP_BUFFER);
if (ech->hpke == NULL)
return MEMORY_E;
ret = wc_HpkeInit(ech->hpke, echConfig->kemId, ech->cipherSuite.kdfId,
ech->cipherSuite.aeadId, heap);
ret = MEMORY_E;
/* init the hpke struct */
if (ret == 0) {
ret = wc_HpkeInit(ech->hpke, echConfig->kemId,
ech->cipherSuite.kdfId, ech->cipherSuite.aeadId, heap);
}
if (ret == 0) {
/* allocate hpkeContext */
ech->hpkeContext =
(HpkeBaseContext*)XMALLOC(sizeof(HpkeBaseContext),
ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (ech->hpkeContext == NULL)
ret = MEMORY_E;
}
/* get the rawConfigLen */
if (ret == 0)
ret = GetEchConfig(echConfig, NULL, &rawConfigLen);
if (ret == WC_NO_ERR_TRACE(LENGTH_ONLY_E))
ret = 0;
/* create info */
if (ret == 0) {
infoLen = TLS_INFO_CONST_STRING_SZ + 1 + rawConfigLen;
@@ -13264,19 +13235,28 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
TLS_INFO_CONST_STRING_SZ + 1, &rawConfigLen);
}
}
/* init the context for opening */
if (ret == 0) {
ret = wc_HpkeInitOpenContext(ech->hpke, ech->hpkeContext,
echConfig->receiverPrivkey, ech->enc, ech->encLen, info,
infoLen);
}
}
/* decrypt the ech payload */
if (ret == 0)
ret = wc_HpkeOpenBase(ech->hpke, echConfig->receiverPrivkey, ech->enc,
ech->encLen, info, infoLen, aad, aadLen, ech->outerClientPayload,
ech->innerClientHelloLen,
if (ret == 0) {
ret = wc_HpkeContextOpenBase(ech->hpke, ech->hpkeContext, aad, aadLen,
ech->outerClientPayload, ech->innerClientHelloLen,
ech->innerClientHello + HANDSHAKE_HEADER_SZ);
}
/* free the hpke and context on failure */
if (ret != 0) {
XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER);
ech->hpke = NULL;
XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER);
ech->hpkeContext = NULL;
}
if (info != NULL)
XFREE(info, heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
@@ -13294,94 +13274,98 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
WOLFSSL_EchConfig* echConfig;
byte* aadCopy;
byte* readBuf_p = (byte*)readBuf;
WOLFSSL_MSG("TLSX_ECH_Parse");
if (size == 0)
return BAD_FUNC_ARG;
if (ssl->options.disableECH) {
WOLFSSL_MSG("TLSX_ECH_Parse: ECH disabled. Ignoring.");
return 0;
}
/* retry configs */
if (msgType == encrypted_extensions) {
ret = wolfSSL_SetEchConfigs(ssl, readBuf, size);
if (ret == WOLFSSL_SUCCESS)
ret = 0;
}
else if (msgType == client_hello && ssl->ctx->echConfigs != NULL) {
/* HRR with special confirmation */
else if (msgType == hello_retry_request && ssl->options.useEch) {
/* length must be 8 */
if (size != ECH_ACCEPT_CONFIRMATION_SZ)
return BAD_FUNC_ARG;
/* get extension */
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
if (echX == NULL)
return BAD_FUNC_ARG;
ech = (WOLFSSL_ECH*)echX->data;
ech->confBuf = (byte*)readBuf;
}
else if (msgType == client_hello && ssl->ctx->echConfigs != NULL) {
/* get extension */
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
if (echX == NULL)
return BAD_FUNC_ARG;
ech = (WOLFSSL_ECH*)echX->data;
/* read the ech parameters before the payload */
ech->type = *readBuf_p;
readBuf_p++;
if (ech->type == ECH_TYPE_INNER) {
ech->state = ECH_PARSED_INTERNAL;
return 0;
}
/* technically the payload would only be 1 byte at this length */
if (size < 11 + ech->encLen)
return BAD_FUNC_ARG;
/* read kdfId */
ato16(readBuf_p, &ech->cipherSuite.kdfId);
readBuf_p += 2;
/* read aeadId */
ato16(readBuf_p, &ech->cipherSuite.aeadId);
readBuf_p += 2;
/* read configId */
ech->configId = *readBuf_p;
readBuf_p++;
/* only get enc if we don't already have the hpke context */
if (ech->hpkeContext == NULL) {
/* read encLen */
ato16(readBuf_p, &ech->encLen);
readBuf_p += 2;
if (ech->encLen > HPKE_Npk_MAX)
return BAD_FUNC_ARG;
/* read enc */
XMEMCPY(ech->enc, readBuf_p, ech->encLen);
readBuf_p += ech->encLen;
}
else {
readBuf_p += 2;
}
/* read hello inner len */
ato16(readBuf_p, &ech->innerClientHelloLen);
ech->innerClientHelloLen -= WC_AES_BLOCK_SIZE;
readBuf_p += 2;
ech->outerClientPayload = readBuf_p;
/* make a copy of the aad */
aadCopy = (byte*)XMALLOC(ech->aadLen, ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (aadCopy == NULL)
return MEMORY_E;
XMEMCPY(aadCopy, ech->aad, ech->aadLen);
/* set the ech payload of the copy to zeros */
XMEMSET(aadCopy + (readBuf_p - ech->aad), 0,
ech->innerClientHelloLen + WC_AES_BLOCK_SIZE);
/* free the old ech in case this is our second client hello */
if (ech->innerClientHello != NULL)
XFREE(ech->innerClientHello, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
/* allocate the inner payload buffer */
ech->innerClientHello =
(byte*)XMALLOC(ech->innerClientHelloLen + HANDSHAKE_HEADER_SZ,
ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (ech->innerClientHello == NULL) {
XFREE(aadCopy, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
/* first check if the config id matches */
echConfig = ssl->ctx->echConfigs;
while (echConfig != NULL) {
/* decrypt with this config */
if (echConfig->configId == ech->configId) {
@@ -13389,26 +13373,20 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
ssl->heap);
break;
}
echConfig = echConfig->next;
}
/* try to decrypt with all configs */
if (echConfig == NULL || ret != 0) {
echConfig = ssl->ctx->echConfigs;
while (echConfig != NULL) {
ret = TLSX_ExtractEch(ech, echConfig, aadCopy, ech->aadLen,
ssl->heap);
if (ret== 0)
break;
echConfig = echConfig->next;
}
}
/* if we failed to extract */
/* if we failed to extract, set state to retry configs */
if (ret != 0) {
XFREE(ech->innerClientHello, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
ech->innerClientHello = NULL;
@@ -13416,19 +13394,15 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
}
else {
i = 0;
/* decrement until before the padding */
while (ech->innerClientHello[ech->innerClientHelloLen +
HANDSHAKE_HEADER_SZ - i - 1] != ECH_TYPE_INNER) {
i++;
}
/* subtract the length of the padding from the length */
ech->innerClientHelloLen -= i;
}
XFREE(aadCopy, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
return 0;
}
@@ -13442,7 +13416,10 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap)
if (ech->ephemeralKey != NULL)
wc_HpkeFreeKey(ech->hpke, ech->hpke->kem, ech->ephemeralKey,
ech->hpke->heap);
if (ech->hpke != NULL)
XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (ech->hpkeContext != NULL)
XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER);
(void)heap;
@@ -13452,16 +13429,24 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap)
* status */
int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen)
{
int ret;
int ret = 0;
void* receiverPubkey = NULL;
byte* info;
int infoLen;
byte* aadCopy;
byte* info = NULL;
int infoLen = 0;
byte* aadCopy = NULL;
/* setup hpke context to seal, should be done at most once per connection */
if (ech->hpkeContext == NULL) {
/* import the server public key */
ret = wc_HpkeDeserializePublicKey(ech->hpke, &receiverPubkey,
ech->echConfig->receiverPubkey, ech->encLen);
if (ret == 0) {
/* allocate hpke context */
ech->hpkeContext =
(HpkeBaseContext*)XMALLOC(sizeof(HpkeBaseContext),
ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (ech->hpkeContext == NULL)
ret = MEMORY_E;
}
if (ret == 0) {
/* create info */
infoLen = TLS_INFO_CONST_STRING_SZ + 1 + ech->echConfig->rawLen;
@@ -13469,41 +13454,40 @@ int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen)
DYNAMIC_TYPE_TMP_BUFFER);
if (info == NULL)
ret = MEMORY_E;
}
if (ret == 0) {
/* puts the null byte in for me */
XMEMCPY(info, (byte*)TLS_INFO_CONST_STRING, TLS_INFO_CONST_STRING_SZ
+ 1);
XMEMCPY(info + TLS_INFO_CONST_STRING_SZ + 1, ech->echConfig->raw,
ech->echConfig->rawLen);
XMEMCPY(info, (byte*)TLS_INFO_CONST_STRING,
TLS_INFO_CONST_STRING_SZ + 1);
XMEMCPY(info + TLS_INFO_CONST_STRING_SZ + 1,
ech->echConfig->raw, ech->echConfig->rawLen);
/* init the context for seal with info and keys */
ret = wc_HpkeInitSealContext(ech->hpke, ech->hpkeContext,
ech->ephemeralKey, receiverPubkey, info, infoLen);
}
}
if (ret == 0) {
/* make a copy of the aad since we overwrite it */
aadCopy = (byte*)XMALLOC(aadLen, ech->hpke->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (aadCopy == NULL) {
XFREE(info, ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER);
ret = MEMORY_E;
}
}
if (ret == 0) {
XMEMCPY(aadCopy, aad, aadLen);
/* seal the payload */
ret = wc_HpkeSealBase(ech->hpke, ech->ephemeralKey, receiverPubkey,
info, (word32)infoLen, aadCopy, aadLen, ech->innerClientHello,
ech->innerClientHelloLen - ech->hpke->Nt,
ech->outerClientPayload);
/* seal the payload with context */
ret = wc_HpkeContextSealBase(ech->hpke, ech->hpkeContext, aadCopy,
aadLen, ech->innerClientHello,
ech->innerClientHelloLen - ech->hpke->Nt, ech->outerClientPayload);
}
if (info != NULL)
XFREE(info, ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (aadCopy != NULL)
XFREE(aadCopy, ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
}
if (receiverPubkey != NULL)
wc_HpkeFreeKey(ech->hpke, ech->hpke->kem, receiverPubkey,
ech->hpke->heap);
return ret;
}
@@ -13891,7 +13875,7 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
#endif /* WOLFSSL_DTLS_CID */
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
case TLSX_ECH:
length += ECH_GET_SIZE((WOLFSSL_ECH*)extension->data);
length += ECH_GET_SIZE((WOLFSSL_ECH*)extension->data, msgType);
break;
#endif
default:
@@ -14141,7 +14125,7 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
case TLSX_ECH:
WOLFSSL_MSG("ECH extension to write");
ret = ECH_WRITE((WOLFSSL_ECH*)extension->data,
ret = ECH_WRITE((WOLFSSL_ECH*)extension->data, msgType,
output + offset, &offset);
break;
#endif
@@ -14999,7 +14983,9 @@ static int TLSX_GetSizeWithEch(WOLFSSL* ssl, byte* semaphore, byte msgType,
echX = TLSX_Find(ssl->ctx->extensions, TLSX_ECH);
/* if type is outer change sni to public name */
if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->type == ECH_TYPE_OUTER) {
if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->type == ECH_TYPE_OUTER &&
(ssl->options.echAccepted ||
((WOLFSSL_ECH*)echX->data)->innerCount == 0)) {
if (ssl->extensions) {
serverNameX = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
@@ -15206,7 +15192,9 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore,
}
/* if type is outer change sni to public name */
if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->type == ECH_TYPE_OUTER) {
if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->type == ECH_TYPE_OUTER &&
(ssl->options.echAccepted ||
((WOLFSSL_ECH*)echX->data)->innerCount == 0)) {
if (ssl->extensions) {
serverNameX = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
@@ -15266,6 +15254,10 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore,
msgType, pOffset);
}
/* only write if have a shot at acceptance */
if (echX != NULL &&
(ssl->options.echAccepted ||
((WOLFSSL_ECH*)echX->data)->innerCount == 0)) {
if (echX != NULL) {
/* turn off and write it last */
TURN_OFF(semaphore, TLSX_ToSemaphore(echX->type));
@@ -15292,6 +15284,7 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore,
if (ret == WOLFSSL_SUCCESS)
ret = 0;
}
}
#ifdef WOLFSSL_SMALL_STACK
XFREE(tmpServerName, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
@@ -15507,6 +15500,10 @@ int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength)
#endif
#ifdef WOLFSSL_SEND_HRR_COOKIE
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
#endif
#ifdef HAVE_ECH
/* send the special confirmation */
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_ECH));
#endif
break;
#endif
@@ -15650,6 +15647,10 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset
/* Write out KeyShare in HelloRetryRequest. */
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
}
#endif
#ifdef HAVE_ECH
/* send the special confirmation */
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_ECH));
#endif
/* Cookie is written below as last extension. */
break;

View File

@@ -180,11 +180,14 @@ static const byte dtls13ProtocolLabel[DTLS13_PROTOCOL_LABEL_SZ + 1] = "dtls13";
#endif /* WOLFSSL_DTLS13 */
#if defined(HAVE_ECH)
#define ECH_ACCEPT_CONFIRMATION_SZ 8
#define ECH_ACCEPT_CONFIRMATION_LABEL_SZ 23
#define ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ 27
static const byte
echAcceptConfirmationLabel[ECH_ACCEPT_CONFIRMATION_LABEL_SZ + 1] =
"ech accept confirmation";
static const byte
echHrrAcceptConfirmationLabel[ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ + 1] =
"hrr ech accept confirmation";
#endif
#ifndef NO_CERTS
@@ -4166,7 +4169,8 @@ int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config)
/* returns status after we hash the ech inner */
static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech)
{
int ret;
int ret = 0;
word32 realSz;
HS_Hashes* tmpHashes;
#ifdef WOLFSSL_DTLS13
byte falseHeader[DTLS13_HANDSHAKE_HEADER_SZ];
@@ -4176,29 +4180,46 @@ static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech)
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 */
realSz = ech->innerClientHelloLen - ech->paddingLen - ech->hpke->Nt;
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 */
ssl->hsHashes = NULL;
/* init the ech hashes */
InitHandshakeHashes(ssl);
ssl->hsHashesEch = ssl->hsHashes;
if (ret == 0) {
ret = HashRaw(ssl, ech->innerClientHello,
(int)(ech->innerClientHelloLen - ech->paddingLen - ech->hpke->Nt));
/* do the handshake header then the body */
AddTls13HandShakeHeader(falseHeader, realSz, 0, 0, client_hello, ssl);
ret = HashRaw(ssl, falseHeader, HANDSHAKE_HEADER_SZ);
/* hash with inner */
if (ret == 0) {
/* init hsHashesEchInner */
if (ech->innerCount == 0) {
ssl->hsHashes = ssl->hsHashesEchInner;
InitHandshakeHashes(ssl);
ssl->hsHashesEchInner = ssl->hsHashes;
ech->innerCount = 1;
}
else {
/* switch back to hsHashes so we have hrr -> echInner2 */
ssl->hsHashes = tmpHashes;
InitHandshakeHashesAndCopy(ssl, ssl->hsHashes,
&ssl->hsHashesEchInner);
}
ssl->hsHashes = ssl->hsHashesEchInner;
ret = HashRaw(ssl, falseHeader, HANDSHAKE_HEADER_SZ);
ssl->hsHashes = ssl->hsHashesEch;
}
}
/* hash the body */
if (ret == 0)
ret = HashRaw(ssl, ech->innerClientHello, realSz);
/* hash with inner */
if (ret == 0) {
ssl->hsHashes = ssl->hsHashesEchInner;
ret = HashRaw(ssl, ech->innerClientHello, realSz);
}
/* swap hsHashes back */
ssl->hsHashes = tmpHashes;
return ret;
}
#endif
@@ -4443,6 +4464,8 @@ int SendTls13ClientHello(WOLFSSL* ssl)
if (args->ech == NULL)
return WOLFSSL_FATAL_ERROR;
/* only prepare if we have a chance at acceptance */
if (ssl->options.echAccepted || args->ech->innerCount == 0) {
/* set the type to inner */
args->ech->type = ECH_TYPE_INNER;
args->preXLength = (int)args->length;
@@ -4461,6 +4484,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
/* set the length back to before we computed ClientHelloInner size */
args->length = (word32)args->preXLength;
}
}
#endif
{
@@ -4585,42 +4609,41 @@ int SendTls13ClientHello(WOLFSSL* ssl)
#if defined(HAVE_ECH)
/* write inner then outer */
if (ssl->options.useEch == 1 && !ssl->options.disableECH) {
if (ssl->options.useEch == 1 && !ssl->options.disableECH &&
(ssl->options.echAccepted || args->ech->innerCount == 0)) {
/* set the type to inner */
args->ech->type = ECH_TYPE_INNER;
/* innerClientHello may already exist from hrr, free if it does */
if (args->ech->innerClientHello != NULL) {
XFREE(args->ech->innerClientHello, ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
}
/* 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 -
@@ -4628,7 +4651,6 @@ int SendTls13ClientHello(WOLFSSL* ssl)
&args->length);
if (ret != 0)
return ret;
/* set the type to outer */
args->ech->type = 0;
}
@@ -4645,7 +4667,8 @@ int SendTls13ClientHello(WOLFSSL* ssl)
#if defined(HAVE_ECH)
/* encrypt and pack the ech innerClientHello */
if (ssl->options.useEch == 1 && !ssl->options.disableECH) {
if (ssl->options.useEch == 1 && !ssl->options.disableECH &&
(ssl->options.echAccepted || args->ech->innerCount == 0)) {
ret = TLSX_FinalizeEch(args->ech,
args->output + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ,
(word32)(args->sendSz - (RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ)));
@@ -4675,7 +4698,8 @@ int SendTls13ClientHello(WOLFSSL* ssl)
{
#if defined(HAVE_ECH)
/* compute the inner hash */
if (ssl->options.useEch == 1 && !ssl->options.disableECH)
if (ssl->options.useEch == 1 && !ssl->options.disableECH &&
(ssl->options.echAccepted || args->ech->innerCount == 0))
ret = EchHashHelloInner(ssl, args->ech);
#endif
/* compute the outer hash */
@@ -4768,15 +4792,15 @@ static int Dtls13ClientDoDowngrade(WOLFSSL* ssl)
#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)
/* check if the server accepted ech or not, must be run after an hsHashes
* restart */
static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz,
const byte* input, int acceptOffset, int helloSz)
{
int ret = 0;
int digestType = 0;
int digestSize = 0;
HS_Hashes* tmpHashes;
HS_Hashes* acceptHashes;
byte zeros[WC_MAX_DIGEST_SIZE];
byte transcriptEchConf[WC_MAX_DIGEST_SIZE];
byte expandLabelPrk[WC_MAX_DIGEST_SIZE];
@@ -4785,22 +4809,20 @@ static int EchCheckAcceptance(WOLFSSL* ssl, const byte* input,
XMEMSET(transcriptEchConf, 0, sizeof(transcriptEchConf));
XMEMSET(expandLabelPrk, 0, sizeof(expandLabelPrk));
XMEMSET(acceptConfirmation, 0, sizeof(acceptConfirmation));
/* copy ech hashes to accept */
ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashesEch, &acceptHashes);
/* swap hsHashes to acceptHashes */
/* store so we can restore regardless of the outcome */
tmpHashes = ssl->hsHashes;
ssl->hsHashes = acceptHashes;
/* swap hsHashes to hsHashesEch */
ssl->hsHashes = ssl->hsHashesEch;
/* hash up to the last 8 bytes */
if (ret == 0)
ret = HashRaw(ssl, input, serverRandomOffset + RAN_LEN -
ECH_ACCEPT_CONFIRMATION_SZ);
ret = HashRaw(ssl, input, acceptOffset);
/* 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));
ret = HashRaw(ssl, input + acceptOffset + ECH_ACCEPT_CONFIRMATION_SZ,
helloSz + HANDSHAKE_HEADER_SZ -
(acceptOffset + ECH_ACCEPT_CONFIRMATION_SZ));
}
/* get the modified transcript hash */
if (ret == 0)
@@ -4856,97 +4878,83 @@ static int EchCheckAcceptance(WOLFSSL* ssl, const byte* input,
/* tls expand with the confirmation label */
if (ret == 0) {
PRIVATE_KEY_UNLOCK();
ret = Tls13HKDFExpandKeyLabel(ssl,
acceptConfirmation, ECH_ACCEPT_CONFIRMATION_SZ,
expandLabelPrk, (word32)digestSize,
tls13ProtocolLabel, TLS13_PROTOCOL_LABEL_SZ,
echAcceptConfirmationLabel, ECH_ACCEPT_CONFIRMATION_LABEL_SZ,
transcriptEchConf, (word32)digestSize, digestType, WOLFSSL_SERVER_END);
ret = Tls13HKDFExpandKeyLabel(ssl, acceptConfirmation,
ECH_ACCEPT_CONFIRMATION_SZ, expandLabelPrk, (word32)digestSize,
tls13ProtocolLabel, TLS13_PROTOCOL_LABEL_SZ, label, labelSz,
transcriptEchConf, (word32)digestSize, digestType,
WOLFSSL_SERVER_END);
PRIVATE_KEY_LOCK();
}
if (ret == 0) {
/* last 8 bytes should match our expand output */
ret = XMEMCMP(acceptConfirmation,
ssl->arrays->serverRandom + RAN_LEN - ECH_ACCEPT_CONFIRMATION_SZ,
ret = XMEMCMP(acceptConfirmation, input + acceptOffset,
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 to free */
/* set echAccepted to 1 */
ssl->options.echAccepted = 1;
/* free hsHashes and go with inner */
ssl->hsHashes = tmpHashes;
/* set the final hsHashes to the ech hashes */
tmpHashes = ssl->hsHashesEch;
FreeHandshakeHashes(ssl);
ssl->hsHashes = ssl->hsHashesEch;
tmpHashes = ssl->hsHashesEchInner;
ssl->hsHashesEchInner = NULL;
}
/* ech rejected */
else {
/* switch to hsHashesEch to free */
ssl->hsHashes = ssl->hsHashesEch;
}
/* free hsHashes */
/* set echAccepted to 0, needed in case HRR */
ssl->options.echAccepted = 0;
/* free inner since we're continuing with outer */
ssl->hsHashes = ssl->hsHashesEchInner;
FreeHandshakeHashes(ssl);
/* set hsHashesEch to NULL to avoid double free */
ssl->hsHashesEch = NULL;
ssl->hsHashesEchInner = NULL;
}
/* continue with outer if we failed to verify ech was accepted */
ret = 0;
}
/* switch to acceptHashes */
ssl->hsHashes = acceptHashes;
/* free acceptHashes */
FreeHandshakeHashes(ssl);
/* swap to tmp, will ech if accepted, hsHashes if rejected */
/* set hsHashesEch to NULL to avoid double free */
ssl->hsHashesEch = NULL;
/* swap to tmp, will be inner if accepted, hsHashes if rejected */
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)
/* replace the last acceptance field for either sever hello or hrr with the ech
* acceptance parameter, return status */
static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz,
byte* output, int acceptOffset, int helloSz, byte msgType)
{
int ret = 0;
int digestType = 0;
int digestSize = 0;
HS_Hashes* tmpHashes = NULL;
HS_Hashes* acceptHashes = NULL;
byte zeros[WC_MAX_DIGEST_SIZE];
byte transcriptEchConf[WC_MAX_DIGEST_SIZE];
byte expandLabelPrk[WC_MAX_DIGEST_SIZE];
XMEMSET(zeros, 0, sizeof(zeros));
XMEMSET(transcriptEchConf, 0, sizeof(transcriptEchConf));
XMEMSET(expandLabelPrk, 0, sizeof(expandLabelPrk));
/* copy ech hashes to accept */
ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, &acceptHashes);
/* swap hsHashes to acceptHashes */
/* store so we can restore regardless of the outcome */
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);
ssl->hsHashes = ssl->hsHashesEch;
/* hash up to the acceptOffset */
ret = HashRaw(ssl, output, acceptOffset);
/* 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));
if (ret == 0) {
ret = HashRaw(ssl, output + acceptOffset + ECH_ACCEPT_CONFIRMATION_SZ,
helloSz - (acceptOffset + ECH_ACCEPT_CONFIRMATION_SZ));
}
/* 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)
if (ret == 0) {
switch (ssl->specs.mac_algorithm) {
#ifndef NO_SHA256
case sha256_mac:
@@ -4976,7 +4984,7 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* output,
ret = WOLFSSL_FATAL_ERROR;
break;
}
}
/* extract clientRandom with a key of all zeros */
if (ret == 0) {
PRIVATE_KEY_UNLOCK();
@@ -4991,29 +4999,23 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* output,
#endif
PRIVATE_KEY_LOCK();
}
/* tls expand with the confirmation label */
if (ret == 0) {
PRIVATE_KEY_UNLOCK();
ret = Tls13HKDFExpandKeyLabel(ssl,
output + serverRandomOffset + RAN_LEN - ECH_ACCEPT_CONFIRMATION_SZ,
ECH_ACCEPT_CONFIRMATION_SZ,
expandLabelPrk, (word32)digestSize,
tls13ProtocolLabel, TLS13_PROTOCOL_LABEL_SZ,
echAcceptConfirmationLabel, ECH_ACCEPT_CONFIRMATION_LABEL_SZ,
transcriptEchConf, (word32)digestSize, digestType, WOLFSSL_SERVER_END);
ret = Tls13HKDFExpandKeyLabel(ssl, output + acceptOffset,
ECH_ACCEPT_CONFIRMATION_SZ, expandLabelPrk, (word32)digestSize,
tls13ProtocolLabel, TLS13_PROTOCOL_LABEL_SZ, label, labelSz,
transcriptEchConf, (word32)digestSize, digestType,
WOLFSSL_SERVER_END);
PRIVATE_KEY_LOCK();
}
if (ret == 0)
XMEMCPY(ssl->arrays->serverRandom, output + serverRandomOffset,
RAN_LEN);
/* free acceptHashes */
/* mark that ech was accepted */
if (ret == 0 && msgType != hello_retry_request)
ssl->options.echAccepted = 1;
/* free hsHashesEch, if this is an HRR we will start at client hello 2*/
FreeHandshakeHashes(ssl);
ssl->hsHashesEch = NULL;
ssl->hsHashes = tmpHashes;
return ret;
}
#endif
@@ -5039,7 +5041,10 @@ typedef struct Dsh13Args {
byte sessIdSz;
byte extMsgType;
#if defined(HAVE_ECH)
int serverRandomOffset;
TLSX* echX;
byte* acceptLabel;
word32 acceptOffset;
word16 acceptLabelSz;
#endif
} Dsh13Args;
@@ -5196,7 +5201,8 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
/* Server random - keep for debugging. */
XMEMCPY(ssl->arrays->serverRandom, input + args->idx, RAN_LEN);
#if defined(HAVE_ECH)
args->serverRandomOffset = (int)args->idx;
/* last 8 bytes of server random */
args->acceptOffset = args->idx + RAN_LEN - ECH_ACCEPT_CONFIRMATION_SZ;
#endif
args->idx += RAN_LEN;
@@ -5492,15 +5498,6 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
if (ret != 0)
return ret;
#if defined(HAVE_ECH)
/* check for acceptConfirmation and HashInput with 8 0 bytes */
if (ssl->options.useEch == 1 && !ssl->options.disableECH) {
ret = EchCheckAcceptance(ssl, input, args->serverRandomOffset, (int)helloSz);
if (ret != 0)
return ret;
}
#endif
#ifdef HAVE_NULL_CIPHER
if (ssl->options.cipherSuite0 == ECC_BYTE &&
(ssl->options.cipherSuite == TLS_SHA256_SHA256 ||
@@ -5538,6 +5535,36 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
return MATCH_SUITE_ERROR;
}
#if defined(HAVE_ECH)
/* check for acceptConfirmation, must be done after hashes restart */
if (ssl->options.useEch == 1) {
args->echX = TLSX_Find(ssl->extensions, TLSX_ECH);
/* account for hrr extension instead of server random */
if (args->extMsgType == hello_retry_request) {
args->acceptOffset =
(word32)(((WOLFSSL_ECH*)args->echX->data)->confBuf - input);
args->acceptLabel = (byte*)echHrrAcceptConfirmationLabel;
args->acceptLabelSz = ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ;
}
else {
args->acceptLabel = (byte*)echAcceptConfirmationLabel;
args->acceptLabelSz = ECH_ACCEPT_CONFIRMATION_LABEL_SZ;
}
/* check acceptance */
if (ret == 0) {
ret = EchCheckAcceptance(ssl, args->acceptLabel,
args->acceptLabelSz, input, args->acceptOffset, helloSz);
}
if (ret != 0)
return ret;
/* use the inner random for client random */
if (args->extMsgType != hello_retry_request) {
XMEMCPY(ssl->arrays->clientRandom, ssl->arrays->clientRandomInner,
RAN_LEN);
}
}
#endif /* HAVE_ECH */
if (*extMsgType == server_hello) {
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
PreSharedKey* psk = NULL;
@@ -6706,6 +6733,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#endif
#if defined(HAVE_ECH)
TLSX* echX = NULL;
HS_Hashes* tmpHashes;
#endif
WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO);
@@ -7029,6 +7057,22 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
}
#endif
#if defined(HAVE_ECH)
/* hash clientHelloInner to hsHashesEch independently since it can't include
* the HRR */
if (ssl->ctx->echConfigs != NULL && !ssl->options.disableECH) {
tmpHashes = ssl->hsHashes;
ssl->hsHashes = NULL;
ret = InitHandshakeHashes(ssl);
if (ret != 0)
goto exit_dch;
if ((ret = HashInput(ssl, input + args->begin, (int)helloSz)) != 0)
goto exit_dch;
ssl->hsHashesEch = ssl->hsHashes;
ssl->hsHashes = tmpHashes;
}
#endif
#if (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \
defined(HAVE_TLS_EXTENSIONS)
ret = CheckPreSharedKeys(ssl, input + args->begin, helloSz, ssl->clSuites,
@@ -7309,7 +7353,9 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
int sendSz;
#if defined(HAVE_ECH)
TLSX* echX = NULL;
word32 serverRandomOffset;
byte* acceptLabel = (byte*)echAcceptConfirmationLabel;
word32 acceptOffset;
word16 acceptLabelSz = ECH_ACCEPT_CONFIRMATION_LABEL_SZ;
#endif
WOLFSSL_START(WC_FUNC_SERVER_HELLO_SEND);
@@ -7368,7 +7414,8 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
}
#if defined(HAVE_ECH)
serverRandomOffset = idx;
/* last 8 bytes of server random */
acceptOffset = idx + RAN_LEN - ECH_ACCEPT_CONFIRMATION_SZ;
#endif
/* Store in SSL for debugging. */
@@ -7432,20 +7479,39 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
#if defined(HAVE_ECH)
if (ssl->ctx->echConfigs != NULL && !ssl->options.disableECH) {
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
if (echX == NULL)
return WOLFSSL_FATAL_ERROR;
/* use hrr offset */
if (extMsgType == hello_retry_request) {
acceptOffset =
(word32)(((WOLFSSL_ECH*)echX->data)->confBuf - output);
acceptLabel = (byte*)echHrrAcceptConfirmationLabel;
acceptLabelSz = ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ;
}
/* 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,
(int)serverRandomOffset - RECORD_HEADER_SZ,
sendSz - RECORD_HEADER_SZ);
if (ret == 0) {
ret = EchWriteAcceptance(ssl, acceptLabel,
acceptLabelSz, output + RECORD_HEADER_SZ,
acceptOffset - RECORD_HEADER_SZ,
sendSz - RECORD_HEADER_SZ, extMsgType);
}
if (extMsgType == hello_retry_request) {
/* reset the ech state for round 2 */
((WOLFSSL_ECH*)echX->data)->state = ECH_WRITE_NONE;
}
else {
if (ret == 0) {
/* update serverRandom on success */
XMEMCPY(ssl->arrays->serverRandom,
output + acceptOffset -
(RAN_LEN -ECH_ACCEPT_CONFIRMATION_SZ), RAN_LEN);
}
/* 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);
@@ -12684,16 +12750,15 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
if (echX != NULL &&
((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE) {
/* reset the inOutIdx to the outer start */
*inOutIdx = echInOutIdx;
/* call again with the inner hello */
if (ret == 0) {
ret = DoTls13ClientHello(ssl,
((WOLFSSL_ECH*)echX->data)->innerClientHello,
&echInOutIdx,
((WOLFSSL_ECH*)echX->data)->innerClientHelloLen);
}
/* if the inner ech parsed successfully we have successfully
* handled the hello and can skip the whole message */
if (ret == 0)

View File

@@ -50140,7 +50140,7 @@ static int test_wolfSSL_Tls13_ECH_params(void)
return EXPECT_RESULT();
}
static int test_wolfSSL_Tls13_ECH(void)
static int test_wolfSSL_Tls13_ECH_ex(int hrr)
{
EXPECT_DECLS;
tcp_ready ready;
@@ -50211,8 +50211,14 @@ static int test_wolfSSL_Tls13_ECH(void)
ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME,
privateName, privateNameLen));
/* force hello retry request */
if (hrr)
ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_NoKeyShares(ssl));
/* connect like normal */
ExpectIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS);
ExpectIntEQ(ssl->options.echAccepted, 1);
ExpectIntEQ(wolfSSL_write(ssl, privateName, privateNameLen),
privateNameLen);
ExpectIntGT((replyLen = wolfSSL_read(ssl, reply, sizeof(reply))), 0);
@@ -50231,6 +50237,16 @@ static int test_wolfSSL_Tls13_ECH(void)
return EXPECT_RESULT();
}
static int test_wolfSSL_Tls13_ECH(void)
{
return test_wolfSSL_Tls13_ECH_ex(0);
}
static int test_wolfSSL_Tls13_ECH_HRR(void)
{
return test_wolfSSL_Tls13_ECH_ex(1);
}
#endif /* HAVE_ECH && WOLFSSL_TLS13 */
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && \
@@ -90415,6 +90431,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfSSL_Tls13_ECH_params),
/* Uses Assert in handshake callback. */
TEST_DECL(test_wolfSSL_Tls13_ECH),
TEST_DECL(test_wolfSSL_Tls13_ECH_HRR),
#endif
TEST_DECL(test_wolfSSL_X509_TLS_version_test_1),

View File

@@ -875,49 +875,63 @@ static int wc_HpkeSetupBaseSender(Hpke* hpke, HpkeBaseContext* context,
return ret;
}
/* give SetupBaseSender a more intuitive and wolfCrypt friendly name */
int wc_HpkeInitSealContext(Hpke* hpke, HpkeBaseContext* context,
void* ephemeralKey, void* receiverKey, byte* info, word32 infoSz)
{
if (hpke == NULL || context == NULL || ephemeralKey == NULL ||
receiverKey == NULL || (info == NULL && infoSz > 0)) {
return BAD_FUNC_ARG;
}
/* zero out all fields */
XMEMSET(context, 0, sizeof(HpkeBaseContext));
return wc_HpkeSetupBaseSender(hpke, context, ephemeralKey, receiverKey,
info, infoSz);
}
/* encrypt a message using an hpke base context, return 0 or error */
static int wc_HpkeContextSealBase(Hpke* hpke, HpkeBaseContext* context,
int wc_HpkeContextSealBase(Hpke* hpke, HpkeBaseContext* context,
byte* aad, word32 aadSz, byte* plaintext, word32 ptSz, byte* out)
{
int ret;
byte nonce[HPKE_Nn_MAX];
#ifndef WOLFSSL_SMALL_STACK
Aes aes_key[1];
Aes aes[1];
#else
Aes* aes_key;
Aes* aes;
#endif
if (hpke == NULL) {
if (hpke == NULL || context == NULL || (aad == NULL && aadSz > 0) ||
plaintext == NULL || out == NULL) {
return BAD_FUNC_ARG;
}
#ifdef WOLFSSL_SMALL_STACK
aes_key = (Aes*)XMALLOC(sizeof(Aes), hpke->heap, DYNAMIC_TYPE_AES);
if (aes_key == NULL) {
aes = (Aes*)XMALLOC(sizeof(Aes), hpke->heap, DYNAMIC_TYPE_AES);
if (aes == NULL) {
return MEMORY_E;
}
#endif
ret = wc_AesInit(aes_key, hpke->heap, INVALID_DEVID);
ret = wc_AesInit(aes, hpke->heap, INVALID_DEVID);
if (ret == 0) {
/* compute nonce */
ret = wc_HpkeContextComputeNonce(hpke, context, nonce);
if (ret == 0) {
ret = wc_AesGcmSetKey(aes_key, context->key, hpke->Nk);
ret = wc_AesGcmSetKey(aes, context->key, hpke->Nk);
}
if (ret == 0) {
ret = wc_AesGcmEncrypt(aes_key, out, plaintext, ptSz, nonce,
ret = wc_AesGcmEncrypt(aes, out, plaintext, ptSz, nonce,
hpke->Nn, out + ptSz, hpke->Nt, aad, aadSz);
}
/* increment sequence for non one shot */
if (ret == 0) {
context->seq++;
}
wc_AesFree(aes_key);
wc_AesFree(aes);
}
#ifdef WOLFSSL_SMALL_STACK
XFREE(aes_key, hpke->heap, DYNAMIC_TYPE_AES);
XFREE(aes, hpke->heap, DYNAMIC_TYPE_AES);
#endif
return ret;
}
@@ -1113,49 +1127,60 @@ static int wc_HpkeSetupBaseReceiver(Hpke* hpke, HpkeBaseContext* context,
return ret;
}
/* give SetupBaseReceiver a more intuitive and wolfCrypt friendly name */
int wc_HpkeInitOpenContext(Hpke* hpke, HpkeBaseContext* context,
void* receiverKey, const byte* pubKey, word16 pubKeySz, byte* info,
word32 infoSz)
{
if (hpke == NULL || context == NULL || receiverKey == NULL || pubKey == NULL
|| (info == NULL && infoSz > 0)) {
return BAD_FUNC_ARG;
}
return wc_HpkeSetupBaseReceiver(hpke, context, receiverKey, pubKey,
pubKeySz, info, infoSz);
}
/* decrypt a message using a setup hpke context, return 0 or error */
static int wc_HpkeContextOpenBase(Hpke* hpke, HpkeBaseContext* context,
byte* aad, word32 aadSz, byte* ciphertext, word32 ctSz, byte* out)
int wc_HpkeContextOpenBase(Hpke* hpke, HpkeBaseContext* context, byte* aad,
word32 aadSz, byte* ciphertext, word32 ctSz, byte* out)
{
int ret;
byte nonce[HPKE_Nn_MAX];
#ifndef WOLFSSL_SMALL_STACK
Aes aes_key[1];
Aes aes[1];
#else
Aes* aes_key;
Aes* aes;
#endif
if (hpke == NULL) {
return BAD_FUNC_ARG;
}
XMEMSET(nonce, 0, sizeof(nonce));
#ifdef WOLFSSL_SMALL_STACK
aes_key = (Aes*)XMALLOC(sizeof(Aes), hpke->heap, DYNAMIC_TYPE_AES);
if (aes_key == NULL) {
aes = (Aes*)XMALLOC(sizeof(Aes), hpke->heap, DYNAMIC_TYPE_AES);
if (aes == NULL) {
return MEMORY_E;
}
#endif
/* compute nonce */
ret = wc_HpkeContextComputeNonce(hpke, context, nonce);
if (ret == 0)
ret = wc_AesInit(aes_key, hpke->heap, INVALID_DEVID);
ret = wc_AesInit(aes, hpke->heap, INVALID_DEVID);
if (ret == 0) {
ret = wc_AesGcmSetKey(aes_key, context->key, hpke->Nk);
ret = wc_AesGcmSetKey(aes, context->key, hpke->Nk);
if (ret == 0) {
ret = wc_AesGcmDecrypt(aes_key, out, ciphertext, ctSz, nonce,
ret = wc_AesGcmDecrypt(aes, out, ciphertext, ctSz, nonce,
hpke->Nn, ciphertext + ctSz, hpke->Nt, aad, aadSz);
}
/* increment sequence for non one shot */
if (ret == 0) {
context->seq++;
}
wc_AesFree(aes_key);
wc_AesFree(aes);
}
#ifdef WOLFSSL_SMALL_STACK
XFREE(aes_key, hpke->heap, DYNAMIC_TYPE_AES);
XFREE(aes, hpke->heap, DYNAMIC_TYPE_AES);
#endif
return ret;
}

View File

@@ -28671,6 +28671,106 @@ static wc_test_ret_t hpke_test_single(Hpke* hpke)
return ret;
}
static wc_test_ret_t hpke_test_multi(Hpke* hpke)
{
wc_test_ret_t 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 ciphertexts[2][MAX_HPKE_LABEL_SZ];
byte plaintext[MAX_HPKE_LABEL_SZ];
void* receiverKey = NULL;
void* ephemeralKey = NULL;
#ifdef WOLFSSL_SMALL_STACK
HpkeBaseContext* context = NULL;
byte *pubKey = NULL; /* public key */
word16 pubKeySz = (word16)HPKE_Npk_MAX;
#else
HpkeBaseContext context[1];
byte pubKey[HPKE_Npk_MAX]; /* public key */
word16 pubKeySz = (word16)sizeof(pubKey);
#endif
rngRet = ret = wc_InitRng(rng);
if (ret != 0)
return ret;
#ifdef WOLFSSL_SMALL_STACK
pubKey = (byte *)XMALLOC(pubKeySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
if (pubKey == NULL)
ret = MEMORY_E;
if (ret == 0) {
context = (HpkeBaseContext*)XMALLOC(sizeof(HpkeBaseContext), HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER);
}
if (context == NULL)
ret = MEMORY_E;
#endif
/* generate the keys */
if (ret == 0)
ret = wc_HpkeGenerateKeyPair(hpke, &ephemeralKey, rng);
if (ret == 0)
ret = wc_HpkeGenerateKeyPair(hpke, &receiverKey, rng);
/* setup seal context */
if (ret == 0) {
ret = wc_HpkeInitSealContext(hpke, context, ephemeralKey, receiverKey,
(byte*)info_text, (word32)XSTRLEN(info_text));
}
/* seal message 0 */
if (ret == 0) {
ret = wc_HpkeContextSealBase(hpke, context,
(byte*)aad_text, (word32)XSTRLEN(aad_text),
(byte*)start_text, (word32)XSTRLEN(start_text),
ciphertexts[context->seq]);
}
/* seal message 1 */
if (ret == 0) {
ret = wc_HpkeContextSealBase(hpke, context,
(byte*)aad_text, (word32)XSTRLEN(aad_text),
(byte*)start_text, (word32)XSTRLEN(start_text),
ciphertexts[context->seq]);
}
/* export ephemeral key */
if (ret == 0)
ret = wc_HpkeSerializePublicKey(hpke, ephemeralKey, pubKey, &pubKeySz);
/* setup open context */
if (ret == 0) {
ret = wc_HpkeInitOpenContext(hpke, context, receiverKey, pubKey,
pubKeySz, (byte*)info_text, (word32)XSTRLEN(info_text));
}
/* open message 0 */
if (ret == 0) {
ret = wc_HpkeContextOpenBase(hpke, context, (byte*)aad_text,
(word32)XSTRLEN(aad_text), ciphertexts[context->seq],
(word32)XSTRLEN(start_text), plaintext);
}
/* check message 0 */
if (ret == 0)
ret = XMEMCMP(plaintext, start_text, XSTRLEN(start_text));
/* open message 1 */
if (ret == 0) {
ret = wc_HpkeContextOpenBase(hpke, context, (byte*)aad_text,
(word32)XSTRLEN(aad_text), ciphertexts[context->seq],
(word32)XSTRLEN(start_text), plaintext);
}
/* check message 1 */
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);
#ifdef WOLFSSL_SMALL_STACK
if (pubKey != NULL)
XFREE(pubKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
if (context != NULL)
XFREE(context, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
#endif
if (rngRet == 0)
wc_FreeRng(rng);
return ret;
}
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void)
{
wc_test_ret_t ret = 0;
@@ -28682,14 +28782,15 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void)
/* p256 */
ret = wc_HpkeInit(hpke, DHKEM_P256_HKDF_SHA256, HKDF_SHA256,
HPKE_AES_128_GCM, NULL);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
ret = hpke_test_single(hpke);
if (ret != 0)
return ret;
ret = hpke_test_multi(hpke);
if (ret != 0)
return ret;
#endif
#if defined(WOLFSSL_SHA384) && \
@@ -28697,12 +28798,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void)
/* p384 */
ret = wc_HpkeInit(hpke, DHKEM_P384_HKDF_SHA384, HKDF_SHA384,
HPKE_AES_128_GCM, NULL);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
ret = hpke_test_single(hpke);
if (ret != 0)
return ret;
ret = hpke_test_multi(hpke);
if (ret != 0)
return ret;
#endif
@@ -28712,12 +28813,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void)
/* p521 */
ret = wc_HpkeInit(hpke, DHKEM_P521_HKDF_SHA512, HKDF_SHA512,
HPKE_AES_128_GCM, NULL);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
ret = hpke_test_single(hpke);
if (ret != 0)
return ret;
ret = hpke_test_multi(hpke);
if (ret != 0)
return ret;
#endif
@@ -28727,12 +28828,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void)
/* test with curve25519 and aes256 */
ret = wc_HpkeInit(hpke, DHKEM_X25519_HKDF_SHA256, HKDF_SHA256,
HPKE_AES_256_GCM, NULL);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
ret = hpke_test_single(hpke);
if (ret != 0)
return ret;
ret = hpke_test_multi(hpke);
if (ret != 0)
return ret;
#endif

View File

@@ -3117,6 +3117,7 @@ typedef struct RpkState {
#endif /* HAVE_RPK */
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
#define ECH_ACCEPT_CONFIRMATION_SZ 8
typedef enum {
ECH_TYPE_OUTER = 0,
@@ -3151,11 +3152,13 @@ typedef struct WOLFSSL_EchConfig {
typedef struct WOLFSSL_ECH {
Hpke* hpke;
HpkeBaseContext* hpkeContext;
const byte* aad;
void* ephemeralKey;
WOLFSSL_EchConfig* echConfig;
byte* innerClientHello;
byte* outerClientPayload;
byte* confBuf;
EchCipherSuite cipherSuite;
word16 aadLen;
word16 paddingLen;
@@ -3166,6 +3169,7 @@ typedef struct WOLFSSL_ECH {
byte type;
byte configId;
byte enc[HPKE_Npk_MAX];
byte innerCount;
} WOLFSSL_ECH;
WOLFSSL_LOCAL int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config);
@@ -5092,7 +5096,8 @@ struct Options {
word16 useDtlsCID:1;
#endif /* WOLFSSL_DTLS_CID */
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
word16 useEch:1; /* Do we have a valid config */
word16 useEch:1;
word16 echAccepted:1;
byte disableECH:1; /* Did the user disable ech */
#endif
#ifdef WOLFSSL_SEND_HRR_COOKIE
@@ -5819,6 +5824,7 @@ struct WOLFSSL {
HS_Hashes* hsHashes;
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
HS_Hashes* hsHashesEch;
HS_Hashes* hsHashesEchInner;
#endif
void* IOCB_ReadCtx;
void* IOCB_WriteCtx;

View File

@@ -120,9 +120,18 @@ 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_HpkeInitSealContext(Hpke* hpke, HpkeBaseContext* context,
void* ephemeralKey, void* receiverKey, byte* info, word32 infoSz);
WOLFSSL_API int wc_HpkeContextSealBase(Hpke* hpke, HpkeBaseContext* context,
byte* aad, word32 aadSz, byte* plaintext, word32 ptSz, byte* out);
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_HpkeInitOpenContext(Hpke* hpke, HpkeBaseContext* context,
void* receiverKey, const byte* pubKey, word16 pubKeySz, byte* info,
word32 infoSz);
WOLFSSL_API int wc_HpkeContextOpenBase(Hpke* hpke, HpkeBaseContext* context,
byte* aad, word32 aadSz, byte* ciphertext, word32 ctSz, byte* out);
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);