Skip to content

Commit 6871014

Browse files
ech public extension management
1 parent aec2756 commit 6871014

3 files changed

Lines changed: 164 additions & 137 deletions

File tree

src/tls.c

Lines changed: 135 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -13737,14 +13737,20 @@ static int TLSX_ECH_Use(WOLFSSL_EchConfig* echConfig, TLSX** extensions,
1373713737
/* setup the ephemeralKey */
1373813738
if (ret == 0)
1373913739
ret = wc_HpkeGenerateKeyPair(ech->hpke, &ech->ephemeralKey, rng);
13740+
/* use the chosen config's public name for the outer SNI */
1374013741
if (ret == 0) {
13741-
ret = TLSX_Push(extensions, TLSX_ECH, ech, heap);
13742-
if (ret != 0) {
13743-
wc_HpkeFreeKey(ech->hpke, ech->hpke->kem, ech->ephemeralKey,
13744-
ech->hpke->heap);
13745-
}
13742+
ret = TLSX_UseSNI(&ech->extensions, WOLFSSL_SNI_HOST_NAME,
13743+
echConfig->publicName, (word16)XSTRLEN(echConfig->publicName),
13744+
heap);
13745+
if (ret == WOLFSSL_SUCCESS)
13746+
ret = 0;
1374613747
}
13748+
if (ret == 0)
13749+
ret = TLSX_Push(extensions, TLSX_ECH, ech, heap);
1374713750
if (ret != 0) {
13751+
TLSX_FreeAll(ech->extensions, heap);
13752+
wc_HpkeFreeKey(ech->hpke, ech->hpke->kem, ech->ephemeralKey,
13753+
ech->hpke->heap);
1374813754
XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER);
1374913755
XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER);
1375013756
}
@@ -14716,15 +14722,13 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap)
1471614722
{
1471714723
XFREE(ech->innerClientHello, heap, DYNAMIC_TYPE_TMP_BUFFER);
1471814724
if (ech->hpke != NULL) {
14719-
if (ech->ephemeralKey != NULL)
14720-
wc_HpkeFreeKey(ech->hpke, ech->hpke->kem, ech->ephemeralKey,
14721-
ech->hpke->heap);
14725+
wc_HpkeFreeKey(ech->hpke, ech->hpke->kem, ech->ephemeralKey,
14726+
ech->hpke->heap);
1472214727
XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER);
1472314728
}
1472414729
if (ech->hpkeContext != NULL)
1472514730
XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER);
14726-
if (ech->privateName != NULL)
14727-
XFREE((char*)ech->privateName, heap, DYNAMIC_TYPE_TMP_BUFFER);
14731+
TLSX_FreeAll(ech->extensions, heap);
1472814732

1472914733
XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER);
1473014734
(void)heap;
@@ -16441,97 +16445,95 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
1644116445
#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
1644216446

1644316447
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
16444-
static int TLSX_EchChangeSNI(WOLFSSL* ssl, TLSX** pEchX,
16445-
char* serverName, TLSX** pServerNameX,
16446-
TLSX*** pExtensions)
16448+
/* Returns 1 if the extensions should be hidden for this write */
16449+
static int TLSX_EchShouldHideInner(WOLFSSL* ssl, WOLFSSL_ECH* ech)
1644716450
{
16448-
int ret = 0;
16449-
TLSX* echX = NULL;
16450-
TLSX* serverNameX = NULL;
16451-
TLSX** extensions = NULL;
16452-
16453-
/* calculate the rest of the extensions length with inner ech */
16454-
if (ssl->extensions)
16455-
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
16456-
16457-
if (echX == NULL && ssl->ctx && ssl->ctx->extensions)
16458-
/* if not NULL the semaphore will stop it from being counted */
16459-
echX = TLSX_Find(ssl->ctx->extensions, TLSX_ECH);
16460-
16461-
/* if type is outer change sni to public name */
16462-
if (echX != NULL &&
16463-
((WOLFSSL_ECH*)echX->data)->type == ECH_TYPE_OUTER &&
16464-
(ssl->options.echAccepted ||
16465-
((WOLFSSL_ECH*)echX->data)->innerCount == 0)) {
16466-
if (ssl->extensions) {
16467-
serverNameX = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
16468-
16469-
if (serverNameX != NULL)
16470-
extensions = &ssl->extensions;
16471-
}
16472-
16473-
if (serverNameX == NULL && ssl->ctx && ssl->ctx->extensions) {
16474-
serverNameX = TLSX_Find(ssl->ctx->extensions, TLSX_SERVER_NAME);
16475-
if (serverNameX != NULL)
16476-
extensions = &ssl->ctx->extensions;
16477-
}
16451+
if (ech == NULL || ech->type != ECH_TYPE_OUTER)
16452+
return 0;
16453+
return ssl->options.echAccepted || ech->innerCount == 0;
16454+
}
1647816455

16479-
/* ECH requires an inner SNI to be present for ClientHelloInner.
16480-
* Without it, fail instead of mutating extension lists. */
16481-
if (serverNameX == NULL) {
16482-
ret = BAD_FUNC_ARG;
16456+
/* Swap matching extension types between *sslExts and *echExts.
16457+
* Non-matched extensions in *echExts are prepended to *sslExts
16458+
* popCount is the number of leading extensions to move from
16459+
* *sslExts to *echExts
16460+
*
16461+
* Ordering is kept in mind for OuterExtensions. This is why the leading
16462+
* popCount extensions are 'reversed' off the list.
16463+
*
16464+
* Returns a count of extensions prepended to sslExts. */
16465+
static word16 TLSX_EchSwapExtensions(TLSX** sslExts, TLSX** echExts,
16466+
word16 popCount)
16467+
{
16468+
TLSX* chunk = NULL;
16469+
TLSX* node;
16470+
TLSX* outer;
16471+
TLSX* inner;
16472+
TLSX** outerLink;
16473+
TLSX** innerLink;
16474+
word16 appended = 0;
16475+
16476+
/* unhook popCount nodes off *sslExts head into chunk.
16477+
* Head-prepend undoes the reversal caused by appending onto sslExts. */
16478+
while (popCount > 0 && *sslExts != NULL) {
16479+
node = *sslExts;
16480+
*sslExts = node->next;
16481+
node->next = chunk;
16482+
chunk = node;
16483+
popCount--;
16484+
}
16485+
16486+
outerLink = echExts;
16487+
while (*outerLink != NULL) {
16488+
innerLink = sslExts;
16489+
outer = *outerLink;
16490+
16491+
while (*innerLink != NULL && (*innerLink)->type != outer->type)
16492+
innerLink = &(*innerLink)->next;
16493+
16494+
if (*innerLink != NULL) {
16495+
inner = *innerLink;
16496+
16497+
*innerLink = outer;
16498+
*outerLink = inner;
16499+
node = outer->next;
16500+
outer->next = inner->next;
16501+
inner->next = node;
16502+
16503+
outerLink = &inner->next;
1648316504
}
16484-
16485-
/* store the inner server name */
16486-
if (ret == 0 && serverNameX != NULL) {
16487-
char* hostName = ((SNI*)serverNameX->data)->data.host_name;
16488-
word32 hostNameSz = (word32)XSTRLEN(hostName) + 1;
16489-
16490-
if (hostNameSz > WOLFSSL_HOST_NAME_MAX)
16491-
ret = BAD_LENGTH_E;
16492-
else
16493-
XMEMCPY(serverName, hostName, hostNameSz);
16505+
else {
16506+
*outerLink = outer->next;
16507+
outer->next = *sslExts;
16508+
*sslExts = outer;
16509+
appended++;
1649416510
}
16511+
}
1649516512

16496-
/* only swap the SNI if one was found; extensions is non-NULL if an
16497-
* SNI entry was found on ssl->extensions or ctx->extensions */
16498-
if (ret == 0 && extensions != NULL) {
16499-
/* remove the inner server name */
16500-
TLSX_Remove(extensions, TLSX_SERVER_NAME, ssl->heap);
16513+
/* outerLink is at the tail of *echExts; append the chunk */
16514+
*outerLink = chunk;
1650116515

16502-
/* set the public name as the server name */
16503-
if ((ret = TLSX_UseSNI(extensions, WOLFSSL_SNI_HOST_NAME,
16504-
((WOLFSSL_ECH*)echX->data)->echConfig->publicName,
16505-
XSTRLEN(((WOLFSSL_ECH*)echX->data)->echConfig->publicName),
16506-
ssl->heap)) == WOLFSSL_SUCCESS)
16507-
ret = 0;
16508-
}
16509-
}
16510-
*pServerNameX = serverNameX;
16511-
*pExtensions = extensions;
16512-
*pEchX = echX;
16513-
return ret;
16516+
return appended;
1651416517
}
1651516518

16516-
static int TLSX_EchRestoreSNI(WOLFSSL* ssl, char* serverName,
16517-
TLSX* serverNameX, TLSX** extensions)
16519+
/* If ECH is accepted, delete ech->extensions
16520+
* If rejected, replace matching ssl->extensions with ech->extensions, appending
16521+
* to head if necessary */
16522+
void TLSX_EchReplaceExtensions(WOLFSSL* ssl, byte accepted)
1651816523
{
16519-
int ret = 0;
16524+
TLSX* echX;
16525+
WOLFSSL_ECH* ech;
1652016526

16521-
/* always remove the publicName SNI we injected, regardless of whether
16522-
* there was a prior inner SNI to restore */
16523-
if (extensions != NULL)
16524-
TLSX_Remove(extensions, TLSX_SERVER_NAME, ssl->heap);
16527+
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
16528+
if (echX == NULL || echX->data == NULL)
16529+
return;
16530+
ech = (WOLFSSL_ECH*)echX->data;
1652516531

16526-
if (serverNameX != NULL) {
16527-
/* restore the inner server name */
16528-
ret = TLSX_UseSNI(extensions, WOLFSSL_SNI_HOST_NAME,
16529-
serverName, XSTRLEN(serverName), ssl->heap);
16532+
if (!accepted)
16533+
(void)TLSX_EchSwapExtensions(&ssl->extensions, &ech->extensions, 0);
1653016534

16531-
if (ret == WOLFSSL_SUCCESS)
16532-
ret = 0;
16533-
}
16534-
return ret;
16535+
TLSX_FreeAll(ech->extensions, ssl->heap);
16536+
ech->extensions = NULL;
1653516537
}
1653616538

1653716539
/* Returns 1 if the extension may be encoded into ech_outer_extensions,
@@ -16641,45 +16643,48 @@ static int TLSX_ECH_BuildOuterExtensions(WOLFSSL* ssl, const byte* semaphore,
1664116643
static int TLSX_GetSizeWithEch(WOLFSSL* ssl, byte* semaphore, byte msgType,
1664216644
word16* pLength)
1664316645
{
16644-
int ret = 0, r = 0;
16646+
int ret = 0;
1664516647
TLSX* echX = NULL;
16646-
TLSX* serverNameX = NULL;
16647-
TLSX** extensions = NULL;
1664816648
WOLFSSL_ECH* ech = NULL;
1664916649
word16 count = 0;
16650-
WC_DECLARE_VAR(serverName, char, WOLFSSL_HOST_NAME_MAX, 0);
16650+
word16 appended = 0;
16651+
byte installed = 0;
1665116652

16652-
WC_ALLOC_VAR_EX(serverName, char, WOLFSSL_HOST_NAME_MAX, NULL,
16653-
DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
16653+
if (ssl->extensions)
16654+
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
16655+
if (echX == NULL && ssl->ctx && ssl->ctx->extensions)
16656+
echX = TLSX_Find(ssl->ctx->extensions, TLSX_ECH);
16657+
if (echX != NULL)
16658+
ech = (WOLFSSL_ECH*)echX->data;
1665416659

16655-
r = TLSX_EchChangeSNI(ssl, &echX, serverName, &serverNameX, &extensions);
16660+
if (TLSX_EchShouldHideInner(ssl, ech)) {
16661+
appended = TLSX_EchSwapExtensions(&ssl->extensions,
16662+
&ech->extensions, 0);
16663+
installed = 1;
16664+
}
1665616665

1665716666
if (echX != NULL)
1665816667
ech = (WOLFSSL_ECH*)echX->data;
1665916668

1666016669
/* If ECH won't be written exclude it from the size calculation */
16661-
if (r == 0 && !ssl->options.echAccepted && ech != NULL &&
16662-
ech->innerCount != 0) {
16670+
if (!ssl->options.echAccepted && ech != NULL && ech->innerCount != 0) {
1666316671
TURN_ON(semaphore, TLSX_ToSemaphore(echX->type));
1666416672
}
1666516673

1666616674
/* if encoding, then count encoded form of inner ClientHello.
1666716675
* `semaphore` is in/out so encodable extensions will later be ignored */
16668-
if (r == 0 && ech != NULL && ech->type == ECH_TYPE_INNER &&
16669-
ech->writeEncoded) {
16676+
if (ech != NULL && ech->type == ECH_TYPE_INNER && ech->writeEncoded) {
1667016677
ret = TLSX_ECH_BuildOuterExtensions(ssl, semaphore, msgType,
1667116678
NULL, pLength, &count, semaphore);
1667216679
}
16673-
if (r == 0 && ret == 0 && ssl->extensions)
16680+
if (ret == 0 && ssl->extensions)
1667416681
ret = TLSX_GetSize(ssl->extensions, semaphore, msgType, pLength);
16675-
if (r == 0 && ret == 0 && ssl->ctx && ssl->ctx->extensions)
16682+
if (ret == 0 && ssl->ctx && ssl->ctx->extensions)
1667616683
ret = TLSX_GetSize(ssl->ctx->extensions, semaphore, msgType, pLength);
16677-
if (r == 0)
16678-
r = TLSX_EchRestoreSNI(ssl, serverName, serverNameX, extensions);
1667916684

16680-
WC_FREE_VAR_EX(serverName, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
16681-
if (ret == 0 && r != 0)
16682-
ret = r;
16685+
if (installed)
16686+
(void)TLSX_EchSwapExtensions(&ssl->extensions, &ech->extensions,
16687+
appended);
1668316688
return ret;
1668416689
}
1668516690
#endif
@@ -16810,19 +16815,26 @@ int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word32* pLength)
1681016815
static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore,
1681116816
byte msgType, word16* pOffset)
1681216817
{
16813-
int r = 0, ret = 0;
16818+
int ret = 0;
1681416819
TLSX* echX = NULL;
16815-
TLSX* serverNameX = NULL;
16816-
TLSX** extensions = NULL;
1681716820
WOLFSSL_ECH* ech = NULL;
16818-
WC_DECLARE_VAR(serverName, char, WOLFSSL_HOST_NAME_MAX, 0);
16821+
word16 appended = 0;
16822+
byte installed = 0;
1681916823

16820-
WC_ALLOC_VAR_EX(serverName, char, WOLFSSL_HOST_NAME_MAX, NULL,
16821-
DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
16822-
r = TLSX_EchChangeSNI(ssl, &echX, serverName, &serverNameX, &extensions);
16823-
ret = r;
16824-
if (ret == 0 && echX != NULL) {
16824+
if (ssl->extensions)
16825+
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
16826+
if (echX == NULL && ssl->ctx && ssl->ctx->extensions)
16827+
echX = TLSX_Find(ssl->ctx->extensions, TLSX_ECH);
16828+
if (echX != NULL)
1682516829
ech = (WOLFSSL_ECH*)echX->data;
16830+
16831+
if (TLSX_EchShouldHideInner(ssl, ech)) {
16832+
appended = TLSX_EchSwapExtensions(&ssl->extensions,
16833+
&ech->extensions, 0);
16834+
installed = 1;
16835+
}
16836+
16837+
if (echX != NULL) {
1682616838
/* turn ech on so it doesn't write, then write it last */
1682716839
TURN_ON(semaphore, TLSX_ToSemaphore(echX->type));
1682816840
}
@@ -16871,14 +16883,11 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore,
1687116883

1687216884
/* only write ECH if there is a shot at acceptance */
1687316885
if (ret == 0 && echX != NULL &&
16874-
(ssl->options.echAccepted ||
16875-
((WOLFSSL_ECH*)echX->data)->innerCount == 0)) {
16876-
if (echX != NULL) {
16877-
/* turn off and write it last */
16878-
TURN_OFF(semaphore, TLSX_ToSemaphore(echX->type));
16879-
}
16886+
(ssl->options.echAccepted || ech->innerCount == 0)) {
16887+
/* turn off and write it last */
16888+
TURN_OFF(semaphore, TLSX_ToSemaphore(echX->type));
1688016889

16881-
if (ret == 0 && ssl->extensions) {
16890+
if (ssl->extensions) {
1688216891
ret = TLSX_Write(ssl->extensions, output + *pOffset, semaphore,
1688316892
msgType, pOffset);
1688416893
}
@@ -16889,12 +16898,9 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore,
1688916898
}
1689016899
}
1689116900

16892-
if (r == 0)
16893-
r = TLSX_EchRestoreSNI(ssl, serverName, serverNameX, extensions);
16894-
WC_FREE_VAR_EX(serverName, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
16895-
16896-
if (ret == 0 && r != 0)
16897-
ret = r;
16901+
if (installed)
16902+
(void)TLSX_EchSwapExtensions(&ssl->extensions, &ech->extensions,
16903+
appended);
1689816904
return ret;
1689916905
}
1690016906
#endif

0 commit comments

Comments
 (0)