mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-09 13:50:50 +02:00
testing + bug fixes for TLS ECH
This commit is contained in:
+1
-2
@@ -8634,10 +8634,9 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl)
|
||||
ForceZero(&ssl->serverSecret, sizeof(ssl->serverSecret));
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
if (ssl->options.useEch == 1) {
|
||||
if (ssl->echConfigs != NULL) {
|
||||
FreeEchConfigs(ssl->echConfigs, ssl->heap);
|
||||
ssl->echConfigs = NULL;
|
||||
ssl->options.useEch = 0;
|
||||
}
|
||||
#endif /* HAVE_ECH */
|
||||
#endif /* WOLFSSL_TLS13 */
|
||||
|
||||
+13
-16
@@ -36,7 +36,6 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName,
|
||||
int ret = 0;
|
||||
word16 encLen = DHKEM_X25519_ENC_LEN;
|
||||
WOLFSSL_EchConfig* newConfig;
|
||||
WOLFSSL_EchConfig* parentConfig;
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
Hpke* hpke = NULL;
|
||||
WC_RNG* rng;
|
||||
@@ -67,7 +66,9 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName,
|
||||
else
|
||||
XMEMSET(newConfig, 0, sizeof(WOLFSSL_EchConfig));
|
||||
|
||||
/* set random config id */
|
||||
/* set random configId */
|
||||
/* TODO: if an equal configId is found should the old config be removed from
|
||||
* the LL? Prevents growth beyond 255+ items */
|
||||
if (ret == 0)
|
||||
ret = wc_RNG_GenerateByte(rng, &newConfig->configId);
|
||||
|
||||
@@ -147,17 +148,14 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName,
|
||||
}
|
||||
}
|
||||
else {
|
||||
parentConfig = ctx->echConfigs;
|
||||
|
||||
if (parentConfig == NULL) {
|
||||
/* insert new configs at beginning of LL as preference should be given
|
||||
* to the most recently generated configs */
|
||||
if (ctx->echConfigs == NULL) {
|
||||
ctx->echConfigs = newConfig;
|
||||
}
|
||||
else {
|
||||
while (parentConfig->next != NULL) {
|
||||
parentConfig = parentConfig->next;
|
||||
}
|
||||
|
||||
parentConfig->next = newConfig;
|
||||
newConfig->next = ctx->echConfigs;
|
||||
ctx->echConfigs = newConfig;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +248,7 @@ void wolfSSL_CTX_SetEchEnable(WOLFSSL_CTX* ctx, byte enable)
|
||||
|
||||
/* set the ech config from base64 for our client ssl object, base64 is the
|
||||
* format ech configs are sent using dns records */
|
||||
int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64,
|
||||
int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, const char* echConfigs64,
|
||||
word32 echConfigs64Len)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -261,7 +259,7 @@ int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64,
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* already have ech configs */
|
||||
if (ssl->options.useEch == 1) {
|
||||
if (ssl->echConfigs != NULL) {
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
}
|
||||
|
||||
@@ -274,7 +272,7 @@ int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64,
|
||||
decodedConfigs[decodedLen - 1] = 0;
|
||||
|
||||
/* decode the echConfigs */
|
||||
ret = Base64_Decode((byte*)echConfigs64, echConfigs64Len,
|
||||
ret = Base64_Decode((const byte*)echConfigs64, echConfigs64Len,
|
||||
decodedConfigs, &decodedLen);
|
||||
|
||||
if (ret != 0) {
|
||||
@@ -300,7 +298,7 @@ int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs,
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* already have ech configs */
|
||||
if (ssl->options.useEch == 1) {
|
||||
if (ssl->echConfigs != NULL) {
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
}
|
||||
|
||||
@@ -309,7 +307,6 @@ int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs,
|
||||
|
||||
/* if we found valid configs */
|
||||
if (ret == 0) {
|
||||
ssl->options.useEch = 1;
|
||||
return WOLFSSL_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -472,7 +469,7 @@ int wolfSSL_GetEchConfigs(WOLFSSL* ssl, byte* output, word32* outputLen)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* if we don't have ech configs */
|
||||
if (ssl->options.useEch != 1) {
|
||||
if (ssl->echConfigs == NULL) {
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -2257,9 +2257,10 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
||||
byte type;
|
||||
byte matched;
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
TLSX* echX = NULL;
|
||||
WOLFSSL_ECH* ech = NULL;
|
||||
WOLFSSL_EchConfig* workingConfig;
|
||||
TLSX* echX;
|
||||
word16 privateNameLen;
|
||||
#endif
|
||||
#endif /* !NO_WOLFSSL_SERVER */
|
||||
TLSX *extension = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
|
||||
@@ -2291,7 +2292,22 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
||||
}
|
||||
|
||||
#ifndef NO_WOLFSSL_SERVER
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
if (!ssl->options.disableECH) {
|
||||
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
|
||||
if (echX != NULL) {
|
||||
ech = (WOLFSSL_ECH*)(echX->data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
if ((!extension || !extension->data) ||
|
||||
(ech != NULL && ech->sniState == ECH_INNER_SNI &&
|
||||
ech->privateName == NULL)) {
|
||||
#else
|
||||
if (!extension || !extension->data) {
|
||||
#endif
|
||||
/* This will keep SNI even though TLSX_UseSNI has not been called.
|
||||
* Enable it so that the received sni is available to functions
|
||||
* that use a custom callback when SNI is received.
|
||||
@@ -2339,24 +2355,52 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
||||
if (!cacheOnly && !(sni = TLSX_SNI_Find((SNI*)extension->data, type)))
|
||||
return 0; /* not using this type of SNI. */
|
||||
|
||||
#ifdef WOLFSSL_TLS13
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
if (ech != NULL && ech->sniState == ECH_INNER_SNI){
|
||||
/* SNI status is carried over from processing the outer hello so it is
|
||||
* necessary to clear it before processing the inner hello */
|
||||
ech->sniState = ECH_INNER_SNI_ATTEMPT;
|
||||
if (sni != NULL){
|
||||
sni->status = WOLFSSL_SNI_NO_MATCH;
|
||||
}
|
||||
}
|
||||
else if (ech != NULL && ech->sniState == ECH_OUTER_SNI &&
|
||||
ech->privateName == NULL && sni != NULL){
|
||||
/* save the private SNI before it is overwritten by the public SNI */
|
||||
privateNameLen = (word16)XSTRLEN(sni->data.host_name) + 1;
|
||||
ech->privateName = (char*)XMALLOC(privateNameLen, ssl->heap,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (ech->privateName == NULL)
|
||||
return MEMORY_E;
|
||||
XMEMCPY((char*)ech->privateName, sni->data.host_name,
|
||||
privateNameLen);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_TLS13)
|
||||
/* Don't process the second ClientHello SNI extension if there
|
||||
* was problems with the first.
|
||||
*/
|
||||
if (!cacheOnly && sni->status != 0)
|
||||
if (!cacheOnly && sni->status != WOLFSSL_SNI_NO_MATCH)
|
||||
return 0;
|
||||
#endif
|
||||
matched = cacheOnly || (XSTRLEN(sni->data.host_name) == size &&
|
||||
XSTRNCMP(sni->data.host_name, (const char*)input + offset, size) == 0);
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
if (ech != NULL && ech->sniState == ECH_INNER_SNI_ATTEMPT) {
|
||||
matched = cacheOnly || (XSTRLEN(ech->privateName) == size &&
|
||||
XSTRNCMP(ech->privateName, (const char*)input + offset, size) == 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
matched = cacheOnly || (XSTRLEN(sni->data.host_name) == size &&
|
||||
XSTRNCMP(sni->data.host_name, (const char*)input + offset,
|
||||
size) == 0);
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
|
||||
if (echX != NULL)
|
||||
ech = (WOLFSSL_ECH*)(echX->data);
|
||||
|
||||
if (!matched && ech != NULL) {
|
||||
if (!matched && ech != NULL && ech->sniState == ECH_OUTER_SNI) {
|
||||
workingConfig = ech->echConfig;
|
||||
|
||||
while (workingConfig != NULL) {
|
||||
matched = XSTRLEN(workingConfig->publicName) == size &&
|
||||
XSTRNCMP(workingConfig->publicName,
|
||||
@@ -2374,6 +2418,7 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
||||
int matchStat;
|
||||
int r = TLSX_UseSNI(&ssl->extensions, type, input + offset, size,
|
||||
ssl->heap);
|
||||
|
||||
if (r != WOLFSSL_SUCCESS)
|
||||
return r; /* throws error. */
|
||||
|
||||
@@ -13922,13 +13967,12 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
|
||||
word16 len;
|
||||
|
||||
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;
|
||||
}
|
||||
if (size == 0)
|
||||
return BAD_FUNC_ARG;
|
||||
/* retry configs */
|
||||
if (msgType == encrypted_extensions) {
|
||||
ret = wolfSSL_SetEchConfigs(ssl, readBuf, size);
|
||||
@@ -13937,7 +13981,8 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
|
||||
ret = 0;
|
||||
}
|
||||
/* HRR with special confirmation */
|
||||
else if (msgType == hello_retry_request && ssl->options.useEch) {
|
||||
else if (msgType == hello_retry_request && ssl->echConfigs != NULL &&
|
||||
!ssl->options.disableECH) {
|
||||
/* length must be 8 */
|
||||
if (size != ECH_ACCEPT_CONFIRMATION_SZ)
|
||||
return BAD_FUNC_ARG;
|
||||
@@ -14055,6 +14100,7 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
|
||||
if (ret == 0) {
|
||||
i = 0;
|
||||
/* decrement until before the padding */
|
||||
/* TODO: verify padding is 0, abort with illegal_parameter */
|
||||
while (ech->innerClientHello[ech->innerClientHelloLen +
|
||||
HANDSHAKE_HEADER_SZ - i - 1] != ECH_TYPE_INNER) {
|
||||
i++;
|
||||
@@ -14090,6 +14136,8 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap)
|
||||
XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (ech->hpkeContext != NULL)
|
||||
XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (ech->privateName != NULL)
|
||||
XFREE((char*)ech->privateName, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
(void)heap;
|
||||
@@ -15868,7 +15916,7 @@ int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word32* pLength)
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_ECH)
|
||||
if (ssl->options.useEch == 1 && !ssl->options.disableECH
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH
|
||||
&& msgType == client_hello) {
|
||||
ret = TLSX_GetSizeWithEch(ssl, semaphore, msgType, &length);
|
||||
if (ret != 0)
|
||||
@@ -16053,7 +16101,7 @@ int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word32* pOffset)
|
||||
#endif
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
if (ssl->options.useEch == 1 && !ssl->options.disableECH
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH
|
||||
&& msgType == client_hello) {
|
||||
ret = TLSX_WriteWithEch(ssl, output, semaphore,
|
||||
msgType, &offset);
|
||||
@@ -17332,7 +17380,8 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
/* If client used ECH, server HRR must include ECH confirmation */
|
||||
if (ret == 0 && msgType == hello_retry_request && ssl->options.useEch == 1) {
|
||||
if (ret == 0 && msgType == hello_retry_request && ssl->echConfigs != NULL &&
|
||||
!ssl->options.disableECH) {
|
||||
TLSX* echX = TLSX_Find(ssl->extensions, TLSX_ECH);
|
||||
if (echX == NULL || ((WOLFSSL_ECH*)echX->data)->confBuf == NULL) {
|
||||
WOLFSSL_MSG("ECH used but HRR missing ECH confirmation");
|
||||
|
||||
+28
-11
@@ -4720,7 +4720,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
|
||||
/* find length of outer and inner */
|
||||
#if defined(HAVE_ECH)
|
||||
if (ssl->options.useEch == 1 && !ssl->options.disableECH) {
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH) {
|
||||
TLSX* echX = TLSX_Find(ssl->extensions, TLSX_ECH);
|
||||
if (echX == NULL)
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
@@ -4874,7 +4874,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
/* write inner then outer */
|
||||
if (ssl->options.useEch == 1 && !ssl->options.disableECH &&
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH &&
|
||||
(ssl->options.echAccepted || args->ech->innerCount == 0)) {
|
||||
/* set the type to inner */
|
||||
args->ech->type = ECH_TYPE_INNER;
|
||||
@@ -4939,7 +4939,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
/* encrypt and pack the ech innerClientHello */
|
||||
if (ssl->options.useEch == 1 && !ssl->options.disableECH &&
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH &&
|
||||
(ssl->options.echAccepted || args->ech->innerCount == 0)) {
|
||||
ret = TLSX_FinalizeEch(args->ech,
|
||||
args->output + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ,
|
||||
@@ -4970,7 +4970,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
{
|
||||
#if defined(HAVE_ECH)
|
||||
/* compute the inner hash */
|
||||
if (ssl->options.useEch == 1 && !ssl->options.disableECH &&
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH &&
|
||||
(ssl->options.echAccepted || args->ech->innerCount == 0)) {
|
||||
ret = EchHashHelloInner(ssl, args->ech);
|
||||
}
|
||||
@@ -5664,7 +5664,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
/* check for acceptConfirmation, must be done after hashes restart */
|
||||
if (ssl->options.useEch == 1) {
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH) {
|
||||
args->echX = TLSX_Find(ssl->extensions, TLSX_ECH);
|
||||
/* account for hrr extension instead of server random */
|
||||
if (args->extMsgType == hello_retry_request) {
|
||||
@@ -7165,9 +7165,19 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
}
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
/* jump to the end to clean things up */
|
||||
if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE)
|
||||
goto exit_dch;
|
||||
if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE) {
|
||||
if (((WOLFSSL_ECH*)echX->data)->innerClientHello != NULL) {
|
||||
/* Client sent real ECH and inner hello was decrypted, jump to
|
||||
* exit so the caller can re-invoke with the inner hello */
|
||||
goto exit_dch;
|
||||
}
|
||||
else {
|
||||
/* Server has ECH but client did not send ECH. Clear the
|
||||
* response flag so the empty ECH extension is not written
|
||||
* in EncryptedExtensions. */
|
||||
echX->resp = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SNI
|
||||
@@ -7244,7 +7254,8 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
#if defined(HAVE_ECH)
|
||||
/* hash clientHelloInner to hsHashesEch */
|
||||
if (echX != NULL && ssl->ctx->echConfigs != NULL &&
|
||||
!ssl->options.disableECH) {
|
||||
!ssl->options.disableECH &&
|
||||
((WOLFSSL_ECH*)echX->data)->innerClientHello != NULL) {
|
||||
ret = EchHashHelloInner(ssl, (WOLFSSL_ECH*)echX->data);
|
||||
if (ret != 0)
|
||||
goto exit_dch;
|
||||
@@ -7503,7 +7514,8 @@ exit_dch:
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
if (ret == 0 && echX != NULL &&
|
||||
((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE) {
|
||||
((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE &&
|
||||
((WOLFSSL_ECH*)echX->data)->innerClientHello != NULL) {
|
||||
|
||||
/* add the header to the inner hello */
|
||||
AddTls13HandShakeHeader(((WOLFSSL_ECH*)echX->data)->innerClientHello,
|
||||
@@ -13072,16 +13084,21 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
|
||||
|
||||
if (echX != NULL &&
|
||||
((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE) {
|
||||
((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE &&
|
||||
((WOLFSSL_ECH*)echX->data)->innerClientHello != NULL) {
|
||||
byte copyRandom = ((WOLFSSL_ECH*)echX->data)->innerCount == 0;
|
||||
/* reset the inOutIdx to the outer start */
|
||||
*inOutIdx = echInOutIdx;
|
||||
/* call again with the inner hello */
|
||||
if (ret == 0) {
|
||||
((WOLFSSL_ECH*)echX->data)->sniState = ECH_INNER_SNI;
|
||||
|
||||
ret = DoTls13ClientHello(ssl,
|
||||
((WOLFSSL_ECH*)echX->data)->innerClientHello,
|
||||
&echInOutIdx,
|
||||
((WOLFSSL_ECH*)echX->data)->innerClientHelloLen);
|
||||
|
||||
((WOLFSSL_ECH*)echX->data)->sniState = ECH_SNI_DONE;
|
||||
}
|
||||
/* if the inner ech parsed successfully we have successfully
|
||||
* handled the hello and can skip the whole message */
|
||||
|
||||
Reference in New Issue
Block a user