Skip to content

Commit 49db055

Browse files
testing + bug fixes for TLS ECH
1 parent 1a5cfa0 commit 49db055

7 files changed

Lines changed: 814 additions & 109 deletions

File tree

src/internal.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8634,10 +8634,9 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl)
86348634
ForceZero(&ssl->serverSecret, sizeof(ssl->serverSecret));
86358635

86368636
#if defined(HAVE_ECH)
8637-
if (ssl->options.useEch == 1) {
8637+
if (ssl->echConfigs != NULL) {
86388638
FreeEchConfigs(ssl->echConfigs, ssl->heap);
86398639
ssl->echConfigs = NULL;
8640-
ssl->options.useEch = 0;
86418640
}
86428641
#endif /* HAVE_ECH */
86438642
#endif /* WOLFSSL_TLS13 */

src/ssl_ech.c

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName,
3636
int ret = 0;
3737
word16 encLen = DHKEM_X25519_ENC_LEN;
3838
WOLFSSL_EchConfig* newConfig;
39-
WOLFSSL_EchConfig* parentConfig;
4039
#ifdef WOLFSSL_SMALL_STACK
4140
Hpke* hpke = NULL;
4241
WC_RNG* rng;
@@ -63,7 +62,9 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName,
6362
else
6463
XMEMSET(newConfig, 0, sizeof(WOLFSSL_EchConfig));
6564

66-
/* set random config id */
65+
/* set random configId */
66+
/* TODO: if an equal configId is found should the old config be removed from
67+
* the LL? Prevents growth beyond 255+ items */
6768
if (ret == 0)
6869
ret = wc_RNG_GenerateByte(rng, &newConfig->configId);
6970

@@ -139,17 +140,14 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName,
139140
}
140141
}
141142
else {
142-
parentConfig = ctx->echConfigs;
143-
144-
if (parentConfig == NULL) {
143+
/* insert new configs at beginning of LL as preference should be given
144+
* to the most recently generated configs */
145+
if (ctx->echConfigs == NULL) {
145146
ctx->echConfigs = newConfig;
146147
}
147148
else {
148-
while (parentConfig->next != NULL) {
149-
parentConfig = parentConfig->next;
150-
}
151-
152-
parentConfig->next = newConfig;
149+
newConfig->next = ctx->echConfigs;
150+
ctx->echConfigs = newConfig;
153151
}
154152
}
155153

@@ -242,7 +240,7 @@ void wolfSSL_CTX_SetEchEnable(WOLFSSL_CTX* ctx, byte enable)
242240

243241
/* set the ech config from base64 for our client ssl object, base64 is the
244242
* format ech configs are sent using dns records */
245-
int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64,
243+
int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, const char* echConfigs64,
246244
word32 echConfigs64Len)
247245
{
248246
int ret = 0;
@@ -253,7 +251,7 @@ int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64,
253251
return BAD_FUNC_ARG;
254252

255253
/* already have ech configs */
256-
if (ssl->options.useEch == 1) {
254+
if (ssl->echConfigs != NULL) {
257255
return WOLFSSL_FATAL_ERROR;
258256
}
259257

@@ -266,7 +264,7 @@ int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64,
266264
decodedConfigs[decodedLen - 1] = 0;
267265

268266
/* decode the echConfigs */
269-
ret = Base64_Decode((byte*)echConfigs64, echConfigs64Len,
267+
ret = Base64_Decode((const byte*)echConfigs64, echConfigs64Len,
270268
decodedConfigs, &decodedLen);
271269

272270
if (ret != 0) {
@@ -292,7 +290,7 @@ int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs,
292290
return BAD_FUNC_ARG;
293291

294292
/* already have ech configs */
295-
if (ssl->options.useEch == 1) {
293+
if (ssl->echConfigs != NULL) {
296294
return WOLFSSL_FATAL_ERROR;
297295
}
298296

@@ -301,7 +299,6 @@ int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs,
301299

302300
/* if we found valid configs */
303301
if (ret == 0) {
304-
ssl->options.useEch = 1;
305302
return WOLFSSL_SUCCESS;
306303
}
307304

@@ -459,7 +456,7 @@ int wolfSSL_GetEchConfigs(WOLFSSL* ssl, byte* output, word32* outputLen)
459456
return BAD_FUNC_ARG;
460457

461458
/* if we don't have ech configs */
462-
if (ssl->options.useEch != 1) {
459+
if (ssl->echConfigs == NULL) {
463460
return WOLFSSL_FATAL_ERROR;
464461
}
465462

src/tls.c

Lines changed: 88 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2233,9 +2233,10 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, const byte* input, word16 length,
22332233
byte type;
22342234
byte matched;
22352235
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
2236+
TLSX* echX = NULL;
22362237
WOLFSSL_ECH* ech = NULL;
22372238
WOLFSSL_EchConfig* workingConfig;
2238-
TLSX* echX;
2239+
word16 privateNameLen;
22392240
#endif
22402241
#endif /* !NO_WOLFSSL_SERVER */
22412242
TLSX *extension = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
@@ -2266,6 +2267,15 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, const byte* input, word16 length,
22662267
#endif
22672268
}
22682269

2270+
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
2271+
if (!ssl->options.disableECH) {
2272+
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
2273+
if (echX != NULL) {
2274+
ech = (WOLFSSL_ECH*)(echX->data);
2275+
}
2276+
}
2277+
#endif
2278+
22692279
#ifndef NO_WOLFSSL_SERVER
22702280
if (!extension || !extension->data) {
22712281
/* This will keep SNI even though TLSX_UseSNI has not been called.
@@ -2282,11 +2292,32 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, const byte* input, word16 length,
22822292
if (cacheOnly) {
22832293
WOLFSSL_MSG("Forcing SSL object to store SNI parameter");
22842294
}
2295+
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
2296+
else if (ech != NULL && ech->sniState != ECH_OUTER_SNI) {
2297+
/* verifying the outer SNI is not necessary, but the inner SNI does
2298+
* need to be verified - so error when server SNI does not exist and
2299+
* ECH is being used */
2300+
SendAlert(ssl, alert_fatal, UNKNOWN_SNI_HOST_NAME_E);
2301+
WOLFSSL_ERROR_VERBOSE(UNKNOWN_SNI_HOST_NAME_E);
2302+
return UNKNOWN_SNI_HOST_NAME_E;
2303+
}
2304+
#endif
22852305
else {
22862306
/* Skipping, SNI not enabled at server side. */
22872307
return 0;
22882308
}
22892309
}
2310+
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
2311+
else if (ech != NULL && ech->sniState == ECH_INNER_SNI) {
2312+
if (ssl->ctx->sniRecvCb) {
2313+
cacheOnly = 1;
2314+
}
2315+
2316+
if (cacheOnly) {
2317+
WOLFSSL_MSG("Forcing SSL object to store SNI parameter (inner)");
2318+
}
2319+
}
2320+
#endif
22902321

22912322
if (OPAQUE16_LEN > length)
22922323
return BUFFER_ERROR;
@@ -2315,24 +2346,58 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, const byte* input, word16 length,
23152346
if (!cacheOnly && !(sni = TLSX_SNI_Find((SNI*)extension->data, type)))
23162347
return 0; /* not using this type of SNI. */
23172348

2318-
#ifdef WOLFSSL_TLS13
2349+
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
2350+
if (ech != NULL && ech->sniState == ECH_INNER_SNI){
2351+
/* SNI status is carried over from processing the outer hello so it is
2352+
* necessary to clear it before processing the inner hello */
2353+
ech->sniState = ECH_INNER_SNI_ATTEMPT;
2354+
if (sni != NULL){
2355+
sni->status = WOLFSSL_SNI_NO_MATCH;
2356+
}
2357+
}
2358+
else if (ech != NULL && ech->sniState == ECH_OUTER_SNI &&
2359+
ech->privateName == NULL && sni != NULL){
2360+
/* save the private SNI before it is overwritten by the public SNI */
2361+
privateNameLen = (word16)XSTRLEN(sni->data.host_name) + 1;
2362+
ech->privateName = (char*)XMALLOC(privateNameLen, ssl->heap,
2363+
DYNAMIC_TYPE_TMP_BUFFER);
2364+
if (ech->privateName == NULL)
2365+
return MEMORY_E;
2366+
XMEMCPY((char*)ech->privateName, sni->data.host_name,
2367+
privateNameLen);
2368+
}
2369+
#endif
2370+
2371+
#if defined(WOLFSSL_TLS13)
23192372
/* Don't process the second ClientHello SNI extension if there
23202373
* was problems with the first.
23212374
*/
2322-
if (!cacheOnly && sni->status != 0)
2375+
if (!cacheOnly && sni->status != WOLFSSL_SNI_NO_MATCH)
23232376
return 0;
23242377
#endif
2325-
matched = cacheOnly || (XSTRLEN(sni->data.host_name) == size &&
2326-
XSTRNCMP(sni->data.host_name, (const char*)input + offset, size) == 0);
23272378

2328-
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
2329-
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
2330-
if (echX != NULL)
2331-
ech = (WOLFSSL_ECH*)(echX->data);
2379+
#if defined(HAVE_ECH)
2380+
if (ech != NULL && ech->sniState == ECH_INNER_SNI_ATTEMPT) {
2381+
if (ech->privateName != NULL) {
2382+
matched = cacheOnly || (XSTRLEN(ech->privateName) == size &&
2383+
XSTRNCMP(ech->privateName, (const char*)input + offset,
2384+
size) == 0);
2385+
}
2386+
else {
2387+
matched = cacheOnly;
2388+
}
2389+
}
2390+
else
2391+
#endif
2392+
{
2393+
matched = cacheOnly || (XSTRLEN(sni->data.host_name) == size &&
2394+
XSTRNCMP(sni->data.host_name, (const char*)input + offset,
2395+
size) == 0);
2396+
}
23322397

2333-
if (!matched && ech != NULL) {
2398+
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
2399+
if (!matched && ech != NULL && ech->sniState == ECH_OUTER_SNI) {
23342400
workingConfig = ech->echConfig;
2335-
23362401
while (workingConfig != NULL) {
23372402
matched = XSTRLEN(workingConfig->publicName) == size &&
23382403
XSTRNCMP(workingConfig->publicName,
@@ -2350,6 +2415,7 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, const byte* input, word16 length,
23502415
int matchStat;
23512416
int r = TLSX_UseSNI(&ssl->extensions, type, input + offset, size,
23522417
ssl->heap);
2418+
23532419
if (r != WOLFSSL_SUCCESS)
23542420
return r; /* throws error. */
23552421

@@ -13886,12 +13952,12 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
1388613952
byte* aadCopy;
1388713953
byte* readBuf_p = (byte*)readBuf;
1388813954
WOLFSSL_MSG("TLSX_ECH_Parse");
13889-
if (size == 0)
13890-
return BAD_FUNC_ARG;
1389113955
if (ssl->options.disableECH) {
1389213956
WOLFSSL_MSG("TLSX_ECH_Parse: ECH disabled. Ignoring.");
1389313957
return 0;
1389413958
}
13959+
if (size == 0)
13960+
return BAD_FUNC_ARG;
1389513961
/* retry configs */
1389613962
if (msgType == encrypted_extensions) {
1389713963
ret = wolfSSL_SetEchConfigs(ssl, readBuf, size);
@@ -13900,7 +13966,8 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
1390013966
ret = 0;
1390113967
}
1390213968
/* HRR with special confirmation */
13903-
else if (msgType == hello_retry_request && ssl->options.useEch) {
13969+
else if (msgType == hello_retry_request && ssl->echConfigs != NULL &&
13970+
!ssl->options.disableECH) {
1390413971
/* length must be 8 */
1390513972
if (size != ECH_ACCEPT_CONFIRMATION_SZ)
1390613973
return BAD_FUNC_ARG;
@@ -14000,6 +14067,7 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
1400014067
if (ret == 0) {
1400114068
i = 0;
1400214069
/* decrement until before the padding */
14070+
/* TODO: verify padding is 0, abort with illegal_parameter */
1400314071
while (ech->innerClientHello[ech->innerClientHelloLen +
1400414072
HANDSHAKE_HEADER_SZ - i - 1] != ECH_TYPE_INNER) {
1400514073
i++;
@@ -14035,6 +14103,8 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap)
1403514103
XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER);
1403614104
if (ech->hpkeContext != NULL)
1403714105
XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER);
14106+
if (ech->privateName != NULL)
14107+
XFREE((char*)ech->privateName, heap, DYNAMIC_TYPE_TMP_BUFFER);
1403814108

1403914109
XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER);
1404014110
(void)heap;
@@ -15814,7 +15884,7 @@ int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word32* pLength)
1581415884
}
1581515885
#endif
1581615886
#if defined(HAVE_ECH)
15817-
if (ssl->options.useEch == 1 && !ssl->options.disableECH
15887+
if (ssl->echConfigs != NULL && !ssl->options.disableECH
1581815888
&& msgType == client_hello) {
1581915889
ret = TLSX_GetSizeWithEch(ssl, semaphore, msgType, &length);
1582015890
if (ret != 0)
@@ -16000,7 +16070,7 @@ int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word32* pOffset)
1600016070
#endif
1600116071
#endif
1600216072
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
16003-
if (ssl->options.useEch == 1 && !ssl->options.disableECH
16073+
if (ssl->echConfigs != NULL && !ssl->options.disableECH
1600416074
&& msgType == client_hello) {
1600516075
ret = TLSX_WriteWithEch(ssl, output, semaphore,
1600616076
msgType, &offset);
@@ -17280,7 +17350,8 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
1728017350

1728117351
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
1728217352
/* If client used ECH, server HRR must include ECH confirmation */
17283-
if (ret == 0 && msgType == hello_retry_request && ssl->options.useEch == 1) {
17353+
if (ret == 0 && msgType == hello_retry_request && ssl->echConfigs != NULL &&
17354+
!ssl->options.disableECH) {
1728417355
TLSX* echX = TLSX_Find(ssl->extensions, TLSX_ECH);
1728517356
if (echX == NULL || ((WOLFSSL_ECH*)echX->data)->confBuf == NULL) {
1728617357
WOLFSSL_MSG("ECH used but HRR missing ECH confirmation");

0 commit comments

Comments
 (0)