forked from wolfSSL/wolfssl
Merge pull request #6805 from jpbland1/ech-hello-retry
Ech hello retry request
This commit is contained in:
@@ -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 */
|
||||
|
17
src/ssl.c
17
src/ssl.c
@@ -556,7 +556,7 @@ int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64,
|
||||
/* 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)
|
||||
word32 echConfigsLen)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
@@ -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,
|
||||
|
469
src/tls.c
469
src/tls.c
@@ -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 */
|
||||
c16toa(ech->encLen, writeBuf_p);
|
||||
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 {
|
||||
/* write enc to writeBuf_p */
|
||||
ret = wc_HpkeSerializePublicKey(ech->hpke, ech->ephemeralKey,
|
||||
writeBuf_p, &ech->encLen);
|
||||
writeBuf_p += ech->encLen;
|
||||
|
||||
/* 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,54 +13195,69 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= echConfig->numCipherSuites) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
info = (byte*)XMALLOC(infoLen, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
if (info == NULL)
|
||||
/* 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)
|
||||
ret = MEMORY_E;
|
||||
else {
|
||||
XMEMCPY(info, (byte*)TLS_INFO_CONST_STRING,
|
||||
TLS_INFO_CONST_STRING_SZ + 1);
|
||||
ret = GetEchConfig(echConfig, info +
|
||||
TLS_INFO_CONST_STRING_SZ + 1, &rawConfigLen);
|
||||
/* 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;
|
||||
info = (byte*)XMALLOC(infoLen, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
if (info == NULL)
|
||||
ret = MEMORY_E;
|
||||
else {
|
||||
XMEMCPY(info, (byte*)TLS_INFO_CONST_STRING,
|
||||
TLS_INFO_CONST_STRING_SZ + 1);
|
||||
ret = GetEchConfig(echConfig, info +
|
||||
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;
|
||||
}
|
||||
|
||||
XFREE(info, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
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++;
|
||||
|
||||
ato16(readBuf_p, &ech->encLen);
|
||||
readBuf_p += 2;
|
||||
|
||||
if (ech->encLen > HPKE_Npk_MAX)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
XMEMCPY(ech->enc, readBuf_p, ech->encLen);
|
||||
readBuf_p += ech->encLen;
|
||||
|
||||
/* 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);
|
||||
XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
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,58 +13429,65 @@ 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;
|
||||
|
||||
/* import the server public key */
|
||||
ret = wc_HpkeDeserializePublicKey(ech->hpke, &receiverPubkey,
|
||||
ech->echConfig->receiverPubkey, ech->encLen);
|
||||
|
||||
if (ret == 0) {
|
||||
/* create info */
|
||||
infoLen = TLS_INFO_CONST_STRING_SZ + 1 + ech->echConfig->rawLen;
|
||||
info = (byte*)XMALLOC(infoLen, ech->hpke->heap,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (info == NULL)
|
||||
ret = MEMORY_E;
|
||||
|
||||
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;
|
||||
info = (byte*)XMALLOC(infoLen, ech->hpke->heap,
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
|
||||
XFREE(info, ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(aadCopy, ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
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) {
|
||||
ret = MEMORY_E;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
XMEMCPY(aadCopy, aad, aadLen);
|
||||
/* 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,31 +15254,36 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore,
|
||||
msgType, pOffset);
|
||||
}
|
||||
|
||||
if (echX != NULL) {
|
||||
/* turn off and write it last */
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(echX->type));
|
||||
}
|
||||
/* 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));
|
||||
}
|
||||
|
||||
if (ret == 0 && ssl->extensions) {
|
||||
ret = TLSX_Write(ssl->extensions, output + *pOffset, semaphore,
|
||||
msgType, pOffset);
|
||||
}
|
||||
if (ret == 0 && ssl->extensions) {
|
||||
ret = TLSX_Write(ssl->extensions, output + *pOffset, semaphore,
|
||||
msgType, pOffset);
|
||||
}
|
||||
|
||||
if (ret == 0 && ssl->ctx && ssl->ctx->extensions) {
|
||||
ret = TLSX_Write(ssl->ctx->extensions, output + *pOffset, semaphore,
|
||||
msgType, pOffset);
|
||||
}
|
||||
if (ret == 0 && ssl->ctx && ssl->ctx->extensions) {
|
||||
ret = TLSX_Write(ssl->ctx->extensions, output + *pOffset, semaphore,
|
||||
msgType, pOffset);
|
||||
}
|
||||
|
||||
if (serverNameX != NULL) {
|
||||
/* remove the public name SNI */
|
||||
TLSX_Remove(extensions, TLSX_SERVER_NAME, ssl->heap);
|
||||
if (serverNameX != NULL) {
|
||||
/* remove the public name SNI */
|
||||
TLSX_Remove(extensions, TLSX_SERVER_NAME, ssl->heap);
|
||||
|
||||
ret = TLSX_UseSNI(extensions, WOLFSSL_SNI_HOST_NAME, tmpServerName,
|
||||
XSTRLEN(tmpServerName), ssl->heap);
|
||||
ret = TLSX_UseSNI(extensions, WOLFSSL_SNI_HOST_NAME, tmpServerName,
|
||||
XSTRLEN(tmpServerName), ssl->heap);
|
||||
|
||||
/* restore the inner server name */
|
||||
if (ret == WOLFSSL_SUCCESS)
|
||||
ret = 0;
|
||||
/* restore the inner server name */
|
||||
if (ret == WOLFSSL_SUCCESS)
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
@@ -15508,6 +15501,10 @@ int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength)
|
||||
#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
|
||||
|
||||
@@ -15651,6 +15648,10 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset
|
||||
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;
|
||||
#endif
|
||||
|
373
src/tls13.c
373
src/tls13.c
@@ -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,23 +4464,26 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
if (args->ech == NULL)
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
|
||||
/* set the type to inner */
|
||||
args->ech->type = ECH_TYPE_INNER;
|
||||
args->preXLength = (int)args->length;
|
||||
/* 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;
|
||||
|
||||
/* get size for inner */
|
||||
ret = TLSX_GetRequestSize(ssl, client_hello, &args->length);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
/* 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 = (word16)(args->length +
|
||||
args->ech->paddingLen + args->ech->hpke->Nt);
|
||||
/* set the length back to before we computed ClientHelloInner size */
|
||||
args->length = (word32)args->preXLength;
|
||||
/* 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 = (word16)(args->length +
|
||||
args->ech->paddingLen + args->ech->hpke->Nt);
|
||||
/* 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;
|
||||
/* 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);
|
||||
ssl->hsHashesEchInner = NULL;
|
||||
}
|
||||
/* free hsHashes */
|
||||
FreeHandshakeHashes(ssl);
|
||||
/* set hsHashesEch to NULL to avoid double free */
|
||||
ssl->hsHashesEch = 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);
|
||||
|
||||
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,18 +7479,37 @@ 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);
|
||||
|
||||
/* remove ech so we don't keep sending it in write */
|
||||
TLSX_Remove(&ssl->extensions, TLSX_ECH, ssl->heap);
|
||||
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
|
||||
@@ -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 */
|
||||
ret = DoTls13ClientHello(ssl,
|
||||
((WOLFSSL_ECH*)echX->data)->innerClientHello,
|
||||
&echInOutIdx,
|
||||
((WOLFSSL_ECH*)echX->data)->innerClientHelloLen);
|
||||
|
||||
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)
|
||||
|
19
tests/api.c
19
tests/api.c
@@ -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),
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
@@ -28726,13 +28827,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void)
|
||||
#if defined(HAVE_CURVE25519)
|
||||
/* test with curve25519 and aes256 */
|
||||
ret = wc_HpkeInit(hpke, DHKEM_X25519_HKDF_SHA256, HKDF_SHA256,
|
||||
HPKE_AES_256_GCM, NULL);
|
||||
|
||||
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
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user