diff --git a/src/tls.c b/src/tls.c index 0b6e35dd75..53dfba7853 100644 --- a/src/tls.c +++ b/src/tls.c @@ -13440,10 +13440,20 @@ static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech, byte msgType) return (int)size; } -/* locate the given extension type, use the extOffset to start off after where a - * previous call to this function ended */ -static const byte* EchFindOuterExtension(const byte* outerCh, word32 chLen, - word16 extType, word16* extLen, word16* extOffset, +/* Locate the given extension type, use the extOffset to start off after where a + * previous call to this function ended + * + * outerCh The outer ClientHello buffer. + * chLen Outer ClientHello length. + * extType Extension type to look for. + * extLen Out parameter, length of found extension. + * extOffset Offset into outer ClientHello to look for extension from. + * extensionsStart Start of outer ClientHello extensions. + * extensionsLen Length of outer ClientHello extensions. + * returns 0 on success and otherwise failure. + */ +static const byte* TLSX_ECH_FindOuterExtension(const byte* outerCh, + word32 chLen, word16 extType, word16* extLen, word16* extOffset, word16* extensionsStart, word16* extensionsLen) { word32 idx = *extOffset; @@ -13505,10 +13515,19 @@ static const byte* EchFindOuterExtension(const byte* outerCh, word32 chLen, return NULL; } -/* if newInnerCh is NULL, validate ordering and existence of references - * - updates newInnerChLen with total length of selected extensions - * if not NULL, copy extensions into the provided buffer */ -static int EchCopyOuterExtensions(const byte* outerCh, word32 outerChLen, +/* If newinnerCh is NULL, validate ordering and existence of references + * - updates newInnerChLen with total length of selected extensions + * If newinnerCh in not NULL, copy extensions into newInnerCh + * + * outerCh The outer ClientHello buffer. + * outerChLen Outer ClientHello length. + * newInnerCh The inner ClientHello buffer. + * newInnerChLen Inner ClientHello length. + * numOuterRefs Number of references described by OuterExtensions extension. + * numOuterTypes References described by OuterExtensions extension. + * returns 0 on success and otherwise failure. + */ +static int TLSX_ECH_CopyOuterExtensions(const byte* outerCh, word32 outerChLen, byte** newInnerCh, word32* newInnerChLen, word16 numOuterRefs, const byte* outerRefTypes) { @@ -13532,9 +13551,9 @@ static int EchCopyOuterExtensions(const byte* outerCh, word32 outerChLen, break; } - outerExtData = EchFindOuterExtension(outerCh, outerChLen, - refType, &outerExtLen, &outerExtOffset, - &extsStart, &extsLen); + outerExtData = TLSX_ECH_FindOuterExtension(outerCh, outerChLen, + refType, &outerExtLen, &outerExtOffset, + &extsStart, &extsLen); if (outerExtData == NULL) { WOLFSSL_MSG("ECH: referenced extension not in outer CH"); @@ -13551,9 +13570,9 @@ static int EchCopyOuterExtensions(const byte* outerCh, word32 outerChLen, while (numOuterRefs-- > 0) { ato16(outerRefTypes, &refType); - outerExtData = EchFindOuterExtension(outerCh, outerChLen, - refType, &outerExtLen, &outerExtOffset, - &extsStart, &extsLen); + outerExtData = TLSX_ECH_FindOuterExtension(outerCh, outerChLen, + refType, &outerExtLen, &outerExtOffset, + &extsStart, &extsLen); if (outerExtData == NULL) { ret = INVALID_PARAMETER; @@ -13570,13 +13589,21 @@ static int EchCopyOuterExtensions(const byte* outerCh, word32 outerChLen, return ret; } -/* expand ech_outer_extensions in the inner ClientHello by copying referenced - * extensions from the outer ClientHello +/* Expand ech_outer_extensions in the inner ClientHello by copying referenced + * extensions from the outer ClientHello. + * If the sessionID exists in the outer ClientHello then also copy that into the + * expanded inner ClientHello. + * + * ssl SSL/TLS object. + * ech ECH object. + * heap Heap hint. + * returns 0 on success and otherwise failure. */ -static int TLSX_ExpandEchOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech, +static int TLSX_ECH_ExpandOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech, void* heap) { int ret = 0; + int headerSz; const byte* innerCh; word32 innerChLen; const byte* outerCh; @@ -13604,7 +13631,14 @@ static int TLSX_ExpandEchOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech, if (ech == NULL || ech->innerClientHello == NULL || ech->aad == NULL) return BAD_FUNC_ARG; - innerCh = ech->innerClientHello + HANDSHAKE_HEADER_SZ; +#ifdef WOLFSSL_DTLS13 + headerSz = ssl->options.dtls ? DTLS13_HANDSHAKE_HEADER_SZ : + HANDSHAKE_HEADER_SZ; +#else + headerSz = HANDSHAKE_HEADER_SZ; +#endif + + innerCh = ech->innerClientHello + headerSz; innerChLen = ech->innerClientHelloLen; outerCh = ech->aad; outerChLen = ech->aadLen; @@ -13675,8 +13709,8 @@ static int TLSX_ExpandEchOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech, outerRefTypes = innerCh + idx + 1; numOuterRefs = outerExtListLen / OPAQUE16_LEN; - ret = EchCopyOuterExtensions(outerCh, outerChLen, NULL, &extraSize, - numOuterRefs, outerRefTypes); + ret = TLSX_ECH_CopyOuterExtensions(outerCh, outerChLen, NULL, + &extraSize, numOuterRefs, outerRefTypes); if (ret != 0) return ret; } @@ -13685,7 +13719,7 @@ static int TLSX_ExpandEchOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech, } newInnerChLen = innerChLen - echOuterExtLen + extraSize - sessionIdLen + - ssl->session->sessionIDSz; + ssl->session->sessionIDSz; if (!foundEchOuter && sessionIdLen == ssl->session->sessionIDSz) { /* no extensions + no sessionID to copy */ @@ -13693,8 +13727,8 @@ static int TLSX_ExpandEchOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech, return ret; } else { - newInnerCh = (byte*)XMALLOC(newInnerChLen + HANDSHAKE_HEADER_SZ, heap, - DYNAMIC_TYPE_TMP_BUFFER); + newInnerCh = (byte*)XMALLOC(newInnerChLen + headerSz, heap, + DYNAMIC_TYPE_TMP_BUFFER); if (newInnerCh == NULL) return MEMORY_E; } @@ -13704,7 +13738,7 @@ static int TLSX_ExpandEchOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech, * AddTls13HandShakeHeader() in DoTls13ClientHello(). */ /* copy everything up to EchOuterExtensions */ - newInnerChRef = newInnerCh + HANDSHAKE_HEADER_SZ; + newInnerChRef = newInnerCh + headerSz; copyLen = OPAQUE16_LEN + RAN_LEN; XMEMCPY(newInnerChRef, innerCh, copyLen); newInnerChRef += copyLen; @@ -13726,24 +13760,22 @@ static int TLSX_ExpandEchOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech, } else { copyLen = echOuterExtIdx - OPAQUE16_LEN - RAN_LEN - OPAQUE8_LEN - - sessionIdLen; + sessionIdLen; XMEMCPY(newInnerChRef, innerCh + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN + - sessionIdLen, copyLen); + sessionIdLen, copyLen); newInnerChRef += copyLen; /* update extensions length in the new ClientHello */ - innerExtIdx = innerExtIdx - sessionIdLen + ssl->session->sessionIDSz; c16toa(innerExtLen - echOuterExtLen + (word16)extraSize, - newInnerChRef - OPAQUE16_LEN); + newInnerChRef - OPAQUE16_LEN); - /* insert expanded extensions from outer ClientHello */ - ret = EchCopyOuterExtensions(outerCh, outerChLen, &newInnerChRef, + ret = TLSX_ECH_CopyOuterExtensions(outerCh, outerChLen, &newInnerChRef, &newInnerChLen, numOuterRefs, outerRefTypes); if (ret == 0) { /* copy remaining extensions after ech_outer_extensions */ copyLen = innerChLen - (echOuterExtIdx + echOuterExtLen); XMEMCPY(newInnerChRef, innerCh + echOuterExtIdx + echOuterExtLen, - copyLen); + copyLen); WOLFSSL_MSG("ECH: expanded ech_outer_extensions successfully"); } @@ -14020,13 +14052,7 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size, echConfig = echConfig->next; } } - /* 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; - ech->state = ECH_WRITE_RETRY_CONFIGS; - } - else { + if (ret == 0) { i = 0; /* decrement until before the padding */ while (ech->innerClientHello[ech->innerClientHelloLen + @@ -14036,15 +14062,15 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size, /* subtract the length of the padding from the length */ ech->innerClientHelloLen -= i; - /* expand EchOuterExtensions if present */ - ret = TLSX_ExpandEchOuterExtensions(ssl, ech, ssl->heap); - if (ret != 0) { - WOLFSSL_MSG_EX("ECH: failed to expand EchOuterExtensions"); - XFREE(ech->innerClientHello, ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); - ech->innerClientHello = NULL; - ech->state = ECH_WRITE_RETRY_CONFIGS; - } + /* expand EchOuterExtensions if present + * and, if it exists, copy sessionID from outer hello */ + ret = TLSX_ECH_ExpandOuterExtensions(ssl, ech, ssl->heap); + } + /* if we failed to extract/expand, set state to retry configs */ + if (ret != 0) { + XFREE(ech->innerClientHello, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + ech->innerClientHello = NULL; + ech->state = ECH_WRITE_RETRY_CONFIGS; } XFREE(aadCopy, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); return 0; diff --git a/src/tls13.c b/src/tls13.c index 9ad9e1580c..f53aeceb21 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -3806,6 +3806,255 @@ int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config) return WOLFSSL_FATAL_ERROR; } + +/* Hash the inner client hello, initializing the hsHashesEch field if needed. + * + * ssl SSL/TLS object. + * ech ECH object. + * returns 0 on success and otherwise failure. + */ +static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech) +{ + int ret = 0; + int headerSz; + word32 realSz; + HS_Hashes* tmpHashes; +#ifndef NO_WOLFSSL_CLIENT + byte falseHeader[HRR_MAX_HS_HEADER_SZ]; +#endif + + if (ssl == NULL || ech == NULL) { + return BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_DTLS13 + headerSz = ssl->options.dtls ? DTLS13_HANDSHAKE_HEADER_SZ : + HANDSHAKE_HEADER_SZ; +#else + headerSz = HANDSHAKE_HEADER_SZ; +#endif + + realSz = ech->innerClientHelloLen; +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + realSz -= ech->paddingLen + ech->hpke->Nt; + } +#endif + + tmpHashes = ssl->hsHashes; + + ssl->hsHashes = ssl->hsHashesEch; + if (ssl->options.echAccepted == 0 && ssl->hsHashes == NULL) { + ret = InitHandshakeHashes(ssl); + if (ret == 0) { + ssl->hsHashesEch = ssl->hsHashes; + ech->innerCount = 1; + } + } + + if (ret == 0) { +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + /* client-side: innerClientHello contains body only */ + AddTls13HandShakeHeader(falseHeader, realSz, 0, 0, client_hello, + ssl); + ret = HashRaw(ssl, falseHeader, headerSz); + if (ret == 0) { + ret = HashRaw(ssl, ech->innerClientHello, realSz); + } + } +#endif +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + /* server-side: innerClientHello contains header + body */ + ret = HashRaw(ssl, ech->innerClientHello, headerSz + realSz); + } +#endif + } + + ssl->hsHashes = tmpHashes; + return ret; +} + +/* Calculate the 8 ECH confirmation bytes. + * + * ssl SSL/TLS object. + * label Ascii string describing ECH acceptance or rejection. + * labelSz Length of label excluding NULL character. + * input The buffer to calculate confirmation off of. + * acceptOffset Where the 8 ECH confirmation bytes start. + * helloSz Size of hello message. + * isHrr Whether message is a HelloRetryRequest or not. + * acceptExpanded An 8 byte array to store calculated confirmation to. + * returns 0 on success and otherwise failure. + */ +static int EchCalcAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, + const byte* input, int acceptOffset, int helloSz, byte isHrr, + byte* acceptExpanded) +{ + int ret = 0; + int digestType = 0; + int digestSize = 0; + int hashSz = 0; + int headerSz; + HS_Hashes* tmpHashes; + HS_Hashes* acceptHash = NULL; + byte zeros[WC_MAX_DIGEST_SIZE]; + byte transcriptEchConf[WC_MAX_DIGEST_SIZE]; + byte clientHelloInnerHash[WC_MAX_DIGEST_SIZE]; + byte expandLabelPrk[WC_MAX_DIGEST_SIZE]; + byte messageHashHeader[HRR_MAX_HS_HEADER_SZ]; + + XMEMSET(zeros, 0, sizeof(zeros)); + XMEMSET(transcriptEchConf, 0, sizeof(transcriptEchConf)); + XMEMSET(clientHelloInnerHash, 0, sizeof(clientHelloInnerHash)); + XMEMSET(expandLabelPrk, 0, sizeof(expandLabelPrk)); + +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("ECH PRK", expandLabelPrk, sizeof(expandLabelPrk)); +#endif + + tmpHashes = ssl->hsHashes; + ssl->hsHashes = ssl->hsHashesEch; + +#ifdef WOLFSSL_DTLS13 + headerSz = ssl->options.dtls ? DTLS13_HANDSHAKE_HEADER_SZ : + HANDSHAKE_HEADER_SZ; +#else + headerSz = HANDSHAKE_HEADER_SZ; +#endif + + if (isHrr) { + /* the transcript hash of ClientHelloInner1 */ + hashSz = GetMsgHash(ssl, clientHelloInnerHash); + if (hashSz > 0) { + ret = 0; + } + + /* restart ECH transcript hash, similar to RestartHandshakeHash but + * don't add a cookie */ + if (ret == 0) { + ret = InitHandshakeHashes(ssl); + } + if (ret == 0) { + ssl->hsHashesEch = ssl->hsHashes; + AddTls13HandShakeHeader(messageHashHeader, (word32)hashSz, 0, 0, + message_hash, ssl); + ret = HashRaw(ssl, messageHashHeader, headerSz); + } + if (ret == 0) { + ret = HashRaw(ssl, clientHelloInnerHash, (word32)hashSz); + } + } + + /* hash with zeros for confirmation computation */ + if (ret == 0) { + ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashesEch, &acceptHash); + } + if (ret == 0) { + ssl->hsHashes = acceptHash; + ret = HashRaw(ssl, input, acceptOffset); + } + if (ret == 0) { + ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ); + } + if (ret == 0) { + ret = HashRaw(ssl, input + acceptOffset + ECH_ACCEPT_CONFIRMATION_SZ, + helloSz + headerSz - (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) { + switch (ssl->specs.mac_algorithm) { +#ifndef NO_SHA256 + case sha256_mac: + digestType = WC_SHA256; + digestSize = WC_SHA256_DIGEST_SIZE; + break; +#endif /* !NO_SHA256 */ +#ifdef WOLFSSL_SHA384 + case sha384_mac: + digestType = WC_SHA384; + digestSize = WC_SHA384_DIGEST_SIZE; + break; +#endif /* WOLFSSL_SHA384 */ +#ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + digestType = WC_SHA512; + digestSize = WC_SHA512_DIGEST_SIZE; + break; +#endif /* WOLFSSL_TLS13_SHA512 */ +#ifdef WOLFSSL_SM3 + case sm3_mac: + digestType = WC_SM3; + digestSize = WC_SM3_DIGEST_SIZE; + break; +#endif /* WOLFSSL_SM3 */ + default: + ret = WOLFSSL_FATAL_ERROR; + break; + } + } + + /* extract clientRandomInner with a key of all zeros */ + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); + #if !defined(HAVE_FIPS) || \ + (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(6,0)) + ret = wc_HKDF_Extract_ex(digestType, zeros, (word32)digestSize, + ssl->arrays->clientRandomInner, RAN_LEN, expandLabelPrk, + ssl->heap, ssl->devId); + #else + ret = wc_HKDF_Extract(digestType, zeros, digestSize, + ssl->arrays->clientRandomInner, RAN_LEN, expandLabelPrk); + #endif + PRIVATE_KEY_LOCK(); + } + + /* tls expand with the confirmation label */ + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + ret = Tls13HKDFExpandKeyLabel(ssl, acceptExpanded, + ECH_ACCEPT_CONFIRMATION_SZ, expandLabelPrk, (word32)digestSize, + dtls13ProtocolLabel, DTLS13_PROTOCOL_LABEL_SZ, label, labelSz, + transcriptEchConf, (word32)digestSize, digestType, + WOLFSSL_SERVER_END); + } + else +#endif + { + ret = Tls13HKDFExpandKeyLabel(ssl, acceptExpanded, + 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 (acceptHash != NULL) { + ssl->hsHashes = acceptHash; + FreeHandshakeHashes(ssl); + } + + ssl->hsHashes = tmpHashes; + ForceZero(expandLabelPrk, sizeof(expandLabelPrk)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(expandLabelPrk, sizeof(expandLabelPrk)); +#endif + return ret; +} + #endif #ifndef NO_WOLFSSL_CLIENT @@ -4226,90 +4475,6 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) } #endif -#if defined(HAVE_ECH) -/* returns the index of the first supported cipher suite, -1 if none */ -int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config) -{ - int i, j, supported = 0; - - for (i = 0; i < config->numCipherSuites; i++) { - supported = 0; - - for (j = 0; j < HPKE_SUPPORTED_KDF_LEN; j++) { - if (config->cipherSuites[i].kdfId == hpkeSupportedKdf[j]) - break; - } - - if (j < HPKE_SUPPORTED_KDF_LEN) - for (j = 0; j < HPKE_SUPPORTED_AEAD_LEN; j++) { - if (config->cipherSuites[i].aeadId == hpkeSupportedAead[j]) { - supported = 1; - break; - } - } - - if (supported) - return i; - } - - return WOLFSSL_FATAL_ERROR; -} - -/* returns status after we hash the inner client hello */ -static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech) -{ - int ret = 0; - word32 realSz; - HS_Hashes* tmpHashes; -#ifdef WOLFSSL_DTLS13 - byte falseHeader[DTLS13_HANDSHAKE_HEADER_SZ]; -#else - byte falseHeader[HANDSHAKE_HEADER_SZ]; -#endif - - if (ssl == NULL || ech == NULL) { - return BAD_FUNC_ARG; - } - - if (ssl->options.side == WOLFSSL_CLIENT_END) { - realSz = ech->innerClientHelloLen - ech->paddingLen - ech->hpke->Nt; - } - else { - realSz = ech->innerClientHelloLen; - } - - tmpHashes = ssl->hsHashes; - - ssl->hsHashes = ssl->hsHashesEch; - if (ssl->options.echAccepted == 0 && ssl->hsHashes == NULL) { - ret = InitHandshakeHashes(ssl); - if (ret == 0) { - ssl->hsHashesEch = ssl->hsHashes; - ech->innerCount = 1; - } - } - - if (ret == 0) { - if (ssl->options.side == WOLFSSL_CLIENT_END) { - /* client-side: innerClientHello contains body only */ - AddTls13HandShakeHeader(falseHeader, realSz, 0, 0, client_hello, ssl); - ret = HashRaw(ssl, falseHeader, sizeof(falseHeader)); - if (ret == 0) { - ret = HashRaw(ssl, ech->innerClientHello, realSz); - } - } - else { - /* server-side: innerClientHello contains header + body */ - ret = HashRaw(ssl, ech->innerClientHello, - sizeof(falseHeader) + realSz); - } - } - - ssl->hsHashes = tmpHashes; - return ret; -} -#endif - static void GetTls13SessionId(WOLFSSL* ssl, byte* output, word32* idx) { if (ssl->session->sessionIDSz > 0) { @@ -4900,162 +5065,24 @@ static int Dtls13ClientDoDowngrade(WOLFSSL* ssl) #endif /* WOLFSSL_DTLS13 && !WOLFSSL_NO_CLIENT*/ #if defined(HAVE_ECH) -static int EchCalcAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, - const byte* input, int acceptOffset, int helloSz, byte isHrr, - byte* acceptExpanded) -{ - int ret = 0; - int digestType = 0; - int digestSize = 0; - int hashSz = 0; - HS_Hashes* tmpHashes; - HS_Hashes* acceptHash = NULL; - byte zeros[WC_MAX_DIGEST_SIZE]; - byte transcriptEchConf[WC_MAX_DIGEST_SIZE]; - byte clientHelloInnerHash[WC_MAX_DIGEST_SIZE]; - byte expandLabelPrk[WC_MAX_DIGEST_SIZE]; - byte messageHashHeader[HANDSHAKE_HEADER_SZ]; - - XMEMSET(zeros, 0, sizeof(zeros)); - XMEMSET(transcriptEchConf, 0, sizeof(transcriptEchConf)); - XMEMSET(clientHelloInnerHash, 0, sizeof(clientHelloInnerHash)); - XMEMSET(expandLabelPrk, 0, sizeof(expandLabelPrk)); - -#ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("ECH PRK", expandLabelPrk, sizeof(expandLabelPrk)); -#endif - - tmpHashes = ssl->hsHashes; - - if (isHrr) { - /* the transcript hash of ClientHelloInner1 */ - hashSz = GetMsgHash(ssl, clientHelloInnerHash); - if (hashSz <= 0) { - ret = hashSz; - } - - /* restart ECH transcript hash, similar to RestartHandshakeHash but - * don't add a cookie */ - if (ret == 0) { - ret = InitHandshakeHashes(ssl); - } - if (ret == 0) { - ssl->hsHashesEch = ssl->hsHashes; - AddTls13HandShakeHeader(messageHashHeader, (word32)hashSz, 0, 0, - message_hash, ssl); - ret = HashRaw(ssl, messageHashHeader, sizeof(messageHashHeader)); - } - if (ret == 0) { - ret = HashRaw(ssl, clientHelloInnerHash, (word32)hashSz); - } - } - - /* hash with zeros for confirmation computation */ - if (ret == 0) { - ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashesEch, &acceptHash); - } - if (ret == 0) { - ssl->hsHashes = acceptHash; - ret = HashRaw(ssl, input, acceptOffset); - } - if (ret == 0) { - ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ); - } - if (ret == 0) { - 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) { - ret = GetMsgHash(ssl, transcriptEchConf); - if (ret > 0) { - ret = 0; - } - } - - /* pick the right type and size based on mac_algorithm */ - if (ret == 0) { - switch (ssl->specs.mac_algorithm) { -#ifndef NO_SHA256 - case sha256_mac: - digestType = WC_SHA256; - digestSize = WC_SHA256_DIGEST_SIZE; - break; -#endif /* !NO_SHA256 */ -#ifdef WOLFSSL_SHA384 - case sha384_mac: - digestType = WC_SHA384; - digestSize = WC_SHA384_DIGEST_SIZE; - break; -#endif /* WOLFSSL_SHA384 */ -#ifdef WOLFSSL_TLS13_SHA512 - case sha512_mac: - digestType = WC_SHA512; - digestSize = WC_SHA512_DIGEST_SIZE; - break; -#endif /* WOLFSSL_TLS13_SHA512 */ -#ifdef WOLFSSL_SM3 - case sm3_mac: - digestType = WC_SM3; - digestSize = WC_SM3_DIGEST_SIZE; - break; -#endif /* WOLFSSL_SM3 */ - default: - ret = WOLFSSL_FATAL_ERROR; - break; - } - } - - /* extract clientRandomInner with a key of all zeros */ - if (ret == 0) { - PRIVATE_KEY_UNLOCK(); - #if !defined(HAVE_FIPS) || \ - (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(6,0)) - ret = wc_HKDF_Extract_ex(digestType, zeros, (word32)digestSize, - ssl->arrays->clientRandomInner, RAN_LEN, expandLabelPrk, - ssl->heap, ssl->devId); - #else - ret = wc_HKDF_Extract(digestType, zeros, digestSize, - ssl->arrays->clientRandomInner, RAN_LEN, expandLabelPrk); - #endif - PRIVATE_KEY_LOCK(); - } - - /* tls expand with the confirmation label */ - if (ret == 0) { - PRIVATE_KEY_UNLOCK(); - ret = Tls13HKDFExpandKeyLabel(ssl, acceptExpanded, - 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 (acceptHash != NULL) { - ssl->hsHashes = acceptHash; - FreeHandshakeHashes(ssl); - } - - ssl->hsHashes = tmpHashes; - return ret; -} - /* check if the server accepted ech or not, return status */ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, const byte* input, int acceptOffset, int helloSz) { int ret = 0; int isHrr = 0; + int headerSz; HS_Hashes* tmpHashes; byte acceptConfirmation[ECH_ACCEPT_CONFIRMATION_SZ]; XMEMSET(acceptConfirmation, 0, sizeof(acceptConfirmation)); - tmpHashes = ssl->hsHashes; - ssl->hsHashes = ssl->hsHashesEch; +#ifdef WOLFSSL_DTLS13 + headerSz = ssl->options.dtls ? DTLS13_HANDSHAKE_HEADER_SZ : + HANDSHAKE_HEADER_SZ; +#else + headerSz = HANDSHAKE_HEADER_SZ; +#endif if (labelSz == ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ && XMEMCMP(label, echHrrAcceptConfirmationLabel, labelSz) == 0) { @@ -5065,6 +5092,9 @@ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, ret = EchCalcAcceptance(ssl, label, labelSz, input, acceptOffset, helloSz, isHrr, acceptConfirmation); + tmpHashes = ssl->hsHashes; + ssl->hsHashes = ssl->hsHashesEch; + if (ret == 0) { /* last 8 bytes must match the expand output */ ret = ConstantCompare(acceptConfirmation, input + acceptOffset, @@ -5076,8 +5106,7 @@ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, /* after HRR, hsHashesEch must contain: * message_hash(ClientHelloInner1) || HRR (actual, not zeros) */ if (isHrr) { - ssl->hsHashes = ssl->hsHashesEch; - ret = HashRaw(ssl, input, helloSz + HANDSHAKE_HEADER_SZ); + ret = HashRaw(ssl, input, helloSz + headerSz); } /* normal TLS code will calculate transcript of ServerHello */ else { @@ -5100,46 +5129,7 @@ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, ssl->hsHashes = tmpHashes; return ret; } - -/* replace the last acceptance field for either ServerHello 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; - HS_Hashes* tmpHashes; - - tmpHashes = ssl->hsHashes; - ssl->hsHashes = ssl->hsHashesEch; - - ret = EchCalcAcceptance(ssl, label, labelSz, output, acceptOffset, - helloSz - HANDSHAKE_HEADER_SZ, msgType == hello_retry_request, - output + acceptOffset); - - /* after HRR, hsHashesEch must contain: - * message_hash(ClientHelloInner1) || HRR (actual, not zeros) */ - if (ret == 0 && msgType == hello_retry_request) { - ssl->hsHashes = ssl->hsHashesEch; - ret = HashRaw(ssl, output, helloSz); - } - /* normal TLS code will calculate transcript of ServerHello */ - else if (ret == 0) { - ssl->options.echAccepted = 1; - - ssl->hsHashes = tmpHashes; - FreeHandshakeHashes(ssl); - tmpHashes = ssl->hsHashesEch; - ssl->hsHashesEch = NULL; - } - - ssl->hsHashes = tmpHashes; - ForceZero(expandLabelPrk, sizeof(expandLabelPrk)); -#ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Check(expandLabelPrk, sizeof(expandLabelPrk)); -#endif - return ret; -} -#endif +#endif /* HAVE_ECH */ /* handle processing of TLS 1.3 server_hello (2) and hello_retry_request (6) */ /* Handle the ServerHello message from the server. @@ -6782,6 +6772,60 @@ static int DoTls13SupportedVersions(WOLFSSL* ssl, const byte* input, word32 i, return 0; } +#ifdef HAVE_ECH +/* Calculate and write the 8 ECH confirmation bytes. + * Output into confirmation field on HRR and into ServerRandom on ServerHello. + * + * ssl SSL/TLS object. + * label Ascii string describing ECH acceptance or rejection. + * labelSz Length of label excluding NULL character. + * output The buffer to calculate/write confirmation from/to. + * acceptOffset Where the 8 ECH confirmation bytes should be placed. + * helloSz Size of hello message. + * msgType Type of message being written. + * returns 0 on success and otherwise failure. + */ +static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, + byte* output, int acceptOffset, int helloSz, byte msgType) +{ + int ret = 0; + int headerSz; + HS_Hashes* tmpHashes; + +#ifdef WOLFSSL_DTLS13 + headerSz = ssl->options.dtls ? DTLS13_HANDSHAKE_HEADER_SZ : + HANDSHAKE_HEADER_SZ; +#else + headerSz = HANDSHAKE_HEADER_SZ; +#endif + + ret = EchCalcAcceptance(ssl, label, labelSz, output, acceptOffset, + helloSz - headerSz, msgType == hello_retry_request, + output + acceptOffset); + + tmpHashes = ssl->hsHashes; + ssl->hsHashes = ssl->hsHashesEch; + + /* after HRR, hsHashesEch must contain: + * message_hash(ClientHelloInner1) || HRR (actual, not zeros) */ + if (ret == 0 && msgType == hello_retry_request) { + ret = HashRaw(ssl, output, helloSz); + } + /* normal TLS code will calculate transcript of ServerHello */ + else if (ret == 0) { + ssl->options.echAccepted = 1; + + ssl->hsHashes = tmpHashes; + FreeHandshakeHashes(ssl); + tmpHashes = ssl->hsHashesEch; + ssl->hsHashesEch = NULL; + } + + ssl->hsHashes = tmpHashes; + return ret; +} +#endif + /* Handle a ClientHello handshake message. * If the protocol version in the message is not TLS v1.3 or higher, use * DoClientHello() @@ -7199,7 +7243,8 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #if defined(HAVE_ECH) /* hash clientHelloInner to hsHashesEch */ - if (ssl->ctx->echConfigs != NULL && !ssl->options.disableECH) { + if (echX != NULL && ssl->ctx->echConfigs != NULL && + !ssl->options.disableECH) { ret = EchHashHelloInner(ssl, (WOLFSSL_ECH*)echX->data); if (ret != 0) goto exit_dch; @@ -7470,115 +7515,6 @@ exit_dch: return ret; } -#ifdef HAVE_ECH -/* 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; - 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)); -#ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("ECH PRK", expandLabelPrk, - sizeof(expandLabelPrk)); -#endif - /* store so we can restore regardless of the outcome */ - tmpHashes = ssl->hsHashes; - 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 + 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) { - switch (ssl->specs.mac_algorithm) { -#ifndef NO_SHA256 - case sha256_mac: - digestType = WC_SHA256; - digestSize = WC_SHA256_DIGEST_SIZE; - break; -#endif /* !NO_SHA256 */ -#ifdef WOLFSSL_SHA384 - case sha384_mac: - digestType = WC_SHA384; - digestSize = WC_SHA384_DIGEST_SIZE; - break; -#endif /* WOLFSSL_SHA384 */ -#ifdef WOLFSSL_TLS13_SHA512 - case sha512_mac: - digestType = WC_SHA512; - digestSize = WC_SHA512_DIGEST_SIZE; - break; -#endif /* WOLFSSL_TLS13_SHA512 */ -#ifdef WOLFSSL_SM3 - case sm3_mac: - digestType = WC_SM3; - digestSize = WC_SM3_DIGEST_SIZE; - break; -#endif /* WOLFSSL_SM3 */ - default: - ret = WOLFSSL_FATAL_ERROR; - break; - } - } - /* extract clientRandom with a key of all zeros */ - if (ret == 0) { - PRIVATE_KEY_UNLOCK(); - #if !defined(HAVE_FIPS) || \ - (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(6,0)) - ret = wc_HKDF_Extract_ex(digestType, zeros, (word32)digestSize, - ssl->arrays->clientRandom, RAN_LEN, expandLabelPrk, - ssl->heap, ssl->devId); - #else - ret = wc_HKDF_Extract(digestType, zeros, digestSize, - ssl->arrays->clientRandom, RAN_LEN, expandLabelPrk); - #endif - PRIVATE_KEY_LOCK(); - } - /* tls expand with the confirmation label */ - if (ret == 0) { - PRIVATE_KEY_UNLOCK(); - 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(); - } - /* 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; - ForceZero(expandLabelPrk, sizeof(expandLabelPrk)); -#ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Check(expandLabelPrk, sizeof(expandLabelPrk)); -#endif - return ret; -} -#endif - /* Send TLS v1.3 ServerHello message to client. * Only a server will send this message. *