fix bad ech transaction hash calculations

This commit is contained in:
John Bland
2025-03-10 09:12:13 -04:00
parent 8ff08740f8
commit 1fd952d6d0
2 changed files with 95 additions and 79 deletions

View File

@@ -14983,7 +14983,9 @@ static int TLSX_GetSizeWithEch(WOLFSSL* ssl, byte* semaphore, byte msgType,
echX = TLSX_Find(ssl->ctx->extensions, TLSX_ECH); echX = TLSX_Find(ssl->ctx->extensions, TLSX_ECH);
/* if type is outer change sni to public name */ /* 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) { if (ssl->extensions) {
serverNameX = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME); serverNameX = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
@@ -15190,7 +15192,9 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore,
} }
/* if type is outer change sni to public name */ /* 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) { if (ssl->extensions) {
serverNameX = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME); serverNameX = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
@@ -15250,6 +15254,8 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore,
msgType, pOffset); msgType, pOffset);
} }
/* only write if have a shot at acceptance */
if (ssl->options.echAccepted || ((WOLFSSL_ECH*)echX->data)->innerCount == 0) {
if (echX != NULL) { if (echX != NULL) {
/* turn off and write it last */ /* turn off and write it last */
TURN_OFF(semaphore, TLSX_ToSemaphore(echX->type)); TURN_OFF(semaphore, TLSX_ToSemaphore(echX->type));
@@ -15276,6 +15282,7 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore,
if (ret == WOLFSSL_SUCCESS) if (ret == WOLFSSL_SUCCESS)
ret = 0; ret = 0;
} }
}
#ifdef WOLFSSL_SMALL_STACK #ifdef WOLFSSL_SMALL_STACK
XFREE(tmpServerName, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(tmpServerName, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);

View File

@@ -4182,10 +4182,10 @@ static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
realSz = ech->innerClientHelloLen - ech->paddingLen - ech->hpke->Nt; realSz = ech->innerClientHelloLen - ech->paddingLen - ech->hpke->Nt;
tmpHashes = ssl->hsHashes; tmpHashes = ssl->hsHashes;
ssl->hsHashes = NULL;
/* init the ech hashes */ /* init the ech hashes */
InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, &ssl->hsHashesEch); InitHandshakeHashes(ssl);
/* swap hsHashes so the regular hash functions work */ ssl->hsHashesEch = ssl->hsHashes;
ssl->hsHashes = ssl->hsHashesEch;
if (ret == 0) { if (ret == 0) {
/* do the handshake header then the body */ /* do the handshake header then the body */
AddTls13HandShakeHeader(falseHeader, realSz, 0, 0, client_hello, ssl); AddTls13HandShakeHeader(falseHeader, realSz, 0, 0, client_hello, ssl);
@@ -4200,7 +4200,7 @@ static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech)
ech->innerCount = 1; ech->innerCount = 1;
} }
else { else {
/* switch back to primary so we can copy it to inner */ /* switch back to hsHashes so we have hrr -> echInner2 */
ssl->hsHashes = tmpHashes; ssl->hsHashes = tmpHashes;
InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, InitHandshakeHashesAndCopy(ssl, ssl->hsHashes,
&ssl->hsHashesEchInner); &ssl->hsHashesEchInner);
@@ -4464,6 +4464,8 @@ int SendTls13ClientHello(WOLFSSL* ssl)
if (args->ech == NULL) if (args->ech == NULL)
return WOLFSSL_FATAL_ERROR; 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 */ /* set the type to inner */
args->ech->type = ECH_TYPE_INNER; args->ech->type = ECH_TYPE_INNER;
args->preXLength = (int)args->length; args->preXLength = (int)args->length;
@@ -4482,6 +4484,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
/* set the length back to before we computed ClientHelloInner size */ /* set the length back to before we computed ClientHelloInner size */
args->length = (word32)args->preXLength; args->length = (word32)args->preXLength;
} }
}
#endif #endif
{ {
@@ -4606,7 +4609,8 @@ int SendTls13ClientHello(WOLFSSL* ssl)
#if defined(HAVE_ECH) #if defined(HAVE_ECH)
/* write inner then outer */ /* 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 */ /* set the type to inner */
args->ech->type = ECH_TYPE_INNER; args->ech->type = ECH_TYPE_INNER;
/* innerClientHello may already exist from hrr, free if it does */ /* innerClientHello may already exist from hrr, free if it does */
@@ -4663,7 +4667,8 @@ int SendTls13ClientHello(WOLFSSL* ssl)
#if defined(HAVE_ECH) #if defined(HAVE_ECH)
/* encrypt and pack the ech innerClientHello */ /* 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, ret = TLSX_FinalizeEch(args->ech,
args->output + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ, args->output + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ,
(word32)(args->sendSz - (RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ))); (word32)(args->sendSz - (RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ)));
@@ -4693,7 +4698,8 @@ int SendTls13ClientHello(WOLFSSL* ssl)
{ {
#if defined(HAVE_ECH) #if defined(HAVE_ECH)
/* compute the inner hash */ /* 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); ret = EchHashHelloInner(ssl, args->ech);
#endif #endif
/* compute the outer hash */ /* compute the outer hash */
@@ -4789,13 +4795,12 @@ static int Dtls13ClientDoDowngrade(WOLFSSL* ssl)
/* check if the server accepted ech or not, must be run after an hsHashes /* check if the server accepted ech or not, must be run after an hsHashes
* restart */ * restart */
static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz,
const byte* input, int acceptOffset, int helloSz, byte msgType) const byte* input, int acceptOffset, int helloSz)
{ {
int ret = 0; int ret = 0;
int digestType = 0; int digestType = 0;
int digestSize = 0; int digestSize = 0;
HS_Hashes* tmpHashes; HS_Hashes* tmpHashes;
HS_Hashes* acceptHashes = NULL;
byte zeros[WC_MAX_DIGEST_SIZE]; byte zeros[WC_MAX_DIGEST_SIZE];
byte transcriptEchConf[WC_MAX_DIGEST_SIZE]; byte transcriptEchConf[WC_MAX_DIGEST_SIZE];
byte expandLabelPrk[WC_MAX_DIGEST_SIZE]; byte expandLabelPrk[WC_MAX_DIGEST_SIZE];
@@ -4806,14 +4811,10 @@ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz,
XMEMSET(acceptConfirmation, 0, sizeof(acceptConfirmation)); XMEMSET(acceptConfirmation, 0, sizeof(acceptConfirmation));
/* store so we can restore regardless of the outcome */ /* store so we can restore regardless of the outcome */
tmpHashes = ssl->hsHashes; tmpHashes = ssl->hsHashes;
/* copy ech hashes to accept */ /* swap hsHashes to hsHashesEch */
ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashesEch, &acceptHashes); ssl->hsHashes = ssl->hsHashesEch;
if (ret == 0) {
/* swap hsHashes to acceptHashes */
ssl->hsHashes = acceptHashes;
/* hash up to the last 8 bytes */ /* hash up to the last 8 bytes */
ret = HashRaw(ssl, input, acceptOffset); ret = HashRaw(ssl, input, acceptOffset);
}
/* hash 8 zeros */ /* hash 8 zeros */
if (ret == 0) if (ret == 0)
ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ); ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ);
@@ -4903,17 +4904,17 @@ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz,
else { else {
/* set echAccepted to 0, needed in case HRR */ /* set echAccepted to 0, needed in case HRR */
ssl->options.echAccepted = 0; ssl->options.echAccepted = 0;
/* free inner since we're continuing with outer */
ssl->hsHashes = ssl->hsHashesEchInner;
FreeHandshakeHashes(ssl);
ssl->hsHashesEchInner = NULL;
} }
/* continue with outer if we failed to verify ech was accepted */ /* continue with outer if we failed to verify ech was accepted */
ret = 0; ret = 0;
} }
/* free hsHashesEch */
if (ssl->options.echAccepted == 0 || msgType != hello_retry_request) {
/* free hsHashesEch */
FreeHandshakeHashes(ssl); FreeHandshakeHashes(ssl);
/* set hsHashesEch to NULL to avoid double free */ /* set hsHashesEch to NULL to avoid double free */
ssl->hsHashesEch = NULL; ssl->hsHashesEch = NULL;
}
/* swap to tmp, will be inner if accepted, hsHashes if rejected */ /* swap to tmp, will be inner if accepted, hsHashes if rejected */
ssl->hsHashes = tmpHashes; ssl->hsHashes = tmpHashes;
return ret; return ret;
@@ -4928,7 +4929,6 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz,
int digestType = 0; int digestType = 0;
int digestSize = 0; int digestSize = 0;
HS_Hashes* tmpHashes = NULL; HS_Hashes* tmpHashes = NULL;
HS_Hashes* acceptHashes = NULL;
byte zeros[WC_MAX_DIGEST_SIZE]; byte zeros[WC_MAX_DIGEST_SIZE];
byte transcriptEchConf[WC_MAX_DIGEST_SIZE]; byte transcriptEchConf[WC_MAX_DIGEST_SIZE];
byte expandLabelPrk[WC_MAX_DIGEST_SIZE]; byte expandLabelPrk[WC_MAX_DIGEST_SIZE];
@@ -4937,14 +4937,9 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz,
XMEMSET(expandLabelPrk, 0, sizeof(expandLabelPrk)); XMEMSET(expandLabelPrk, 0, sizeof(expandLabelPrk));
/* store so we can restore regardless of the outcome */ /* store so we can restore regardless of the outcome */
tmpHashes = ssl->hsHashes; tmpHashes = ssl->hsHashes;
/* copy ech hashes to accept */ ssl->hsHashes = ssl->hsHashesEch;
ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashesEch, &acceptHashes);
if (ret == 0) {
/* swap hsHashes to acceptHashes */
ssl->hsHashes = acceptHashes;
/* hash up to the acceptOffset */ /* hash up to the acceptOffset */
ret = HashRaw(ssl, output, acceptOffset); ret = HashRaw(ssl, output, acceptOffset);
}
/* hash 8 zeros */ /* hash 8 zeros */
if (ret == 0) if (ret == 0)
ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ); ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ);
@@ -5015,13 +5010,13 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz,
PRIVATE_KEY_LOCK(); PRIVATE_KEY_LOCK();
} }
if (ret == 0) { if (ret == 0) {
/* free hsHashesEch if this is the last ech involved message */ /* free hsHashesEch, if this is an HRR we will start at client hello 2*/
if (msgType != hello_retry_request) {
FreeHandshakeHashes(ssl); FreeHandshakeHashes(ssl);
ssl->hsHashesEch = NULL; ssl->hsHashesEch = NULL;
/* mark that ech was accepted */
if (msgType != hello_retry_request)
ssl->options.echAccepted = 1; ssl->options.echAccepted = 1;
} }
}
ssl->hsHashes = tmpHashes; ssl->hsHashes = tmpHashes;
return ret; return ret;
} }
@@ -5560,8 +5555,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
/* check acceptance */ /* check acceptance */
if (ret == 0) { if (ret == 0) {
ret = EchCheckAcceptance(ssl, args->acceptLabel, ret = EchCheckAcceptance(ssl, args->acceptLabel,
args->acceptLabelSz, input, args->acceptOffset, helloSz, args->acceptLabelSz, input, args->acceptOffset, helloSz);
args->extMsgType);
} }
if (ret != 0) if (ret != 0)
return ret; return ret;
@@ -6741,6 +6735,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#endif #endif
#if defined(HAVE_ECH) #if defined(HAVE_ECH)
TLSX* echX = NULL; TLSX* echX = NULL;
HS_Hashes* tmpHashes;
#endif #endif
WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO); WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO);
@@ -7064,6 +7059,22 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
} }
#endif #endif
#if defined(HAVE_ECH)
/* hash clientHelloInner to hsHashesEch independently since it can't include
* the HRR */
if (!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)) && \ #if (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \
defined(HAVE_TLS_EXTENSIONS) defined(HAVE_TLS_EXTENSIONS)
ret = CheckPreSharedKeys(ssl, input + args->begin, helloSz, ssl->clSuites, ret = CheckPreSharedKeys(ssl, input + args->begin, helloSz, ssl->clSuites,
@@ -7481,8 +7492,6 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
} }
/* replace the last 8 bytes of server random with the accept */ /* replace the last 8 bytes of server random with the accept */
if (((WOLFSSL_ECH*)echX->data)->state == ECH_PARSED_INTERNAL) { if (((WOLFSSL_ECH*)echX->data)->state == ECH_PARSED_INTERNAL) {
ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashes,
&ssl->hsHashesEch);
if (ret == 0) { if (ret == 0) {
ret = EchWriteAcceptance(ssl, acceptLabel, ret = EchWriteAcceptance(ssl, acceptLabel,
acceptLabelSz, output + RECORD_HEADER_SZ, acceptLabelSz, output + RECORD_HEADER_SZ,