Merge pull request #10326 from sebastian-carpenter/tls-ech-maxnamelen

Add maximum_name_length to TLS ECH padding
This commit is contained in:
David Garske
2026-05-14 09:15:38 -07:00
committed by GitHub
5 changed files with 83 additions and 51 deletions
+60 -48
View File
@@ -32,6 +32,15 @@
/* create the hpke key and ech config to send to clients */
int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName,
word16 kemId, word16 kdfId, word16 aeadId)
{
return wolfSSL_CTX_GenerateEchConfigEx(ctx, publicName, kemId, kdfId,
aeadId, 0);
}
/* create the hpke key and ech config to send to clients
* maximum_name_length may also be set for a more stable padding length */
int wolfSSL_CTX_GenerateEchConfigEx(WOLFSSL_CTX* ctx, const char* publicName,
word16 kemId, word16 kdfId, word16 aeadId, byte maxNameLen)
{
int ret = 0;
WOLFSSL_EchConfig* newConfig;
@@ -129,8 +138,8 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName,
ret = MEMORY_E;
}
else {
XMEMCPY(newConfig->publicName, publicName,
XSTRLEN(publicName) + 1);
XMEMCPY(newConfig->publicName, publicName, XSTRLEN(publicName) + 1);
newConfig->maxNameLen = maxNameLen;
}
}
@@ -166,32 +175,51 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName,
return ret;
}
/* base64-decode echConfigs into a freshly allocated buffer */
static int DecodeEchConfigsBase64(void* heap, const char* echConfigs64,
word32 echConfigs64Len, byte** decodedConfigs, word32* decodedLen)
{
int ret = 0;
byte* buf;
word32 len = echConfigs64Len * 3 / 4 + 1;
if (echConfigs64 == NULL || echConfigs64Len == 0)
return BAD_FUNC_ARG;
buf = (byte*)XMALLOC(len, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (buf == NULL)
return MEMORY_E;
buf[len - 1] = 0;
/* decode the echConfigs */
ret = Base64_Decode((const byte*)echConfigs64, echConfigs64Len, buf, &len);
if (ret != 0) {
XFREE(buf, heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
*decodedConfigs = buf;
*decodedLen = len;
return 0;
}
int wolfSSL_CTX_SetEchConfigsBase64(WOLFSSL_CTX* ctx, const char* echConfigs64,
word32 echConfigs64Len)
{
int ret = 0;
word32 decodedLen = echConfigs64Len * 3 / 4 + 1;
int ret;
word32 decodedLen;
byte* decodedConfigs;
if (ctx == NULL || echConfigs64 == NULL || echConfigs64Len == 0)
if (ctx == NULL)
return BAD_FUNC_ARG;
decodedConfigs = (byte*)XMALLOC(decodedLen, ctx->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (decodedConfigs == NULL)
return MEMORY_E;
decodedConfigs[decodedLen - 1] = 0;
/* decode the echConfigs */
ret = Base64_Decode((const byte*)echConfigs64, echConfigs64Len,
decodedConfigs, &decodedLen);
if (ret != 0) {
XFREE(decodedConfigs, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER);
ret = DecodeEchConfigsBase64(ctx->heap, echConfigs64, echConfigs64Len,
&decodedConfigs, &decodedLen);
if (ret != 0)
return ret;
}
ret = wolfSSL_CTX_SetEchConfigs(ctx, decodedConfigs, decodedLen);
@@ -249,34 +277,17 @@ void wolfSSL_CTX_SetEchEnable(WOLFSSL_CTX* ctx, byte enable)
int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, const char* echConfigs64,
word32 echConfigs64Len)
{
int ret = 0;
word32 decodedLen = echConfigs64Len * 3 / 4 + 1;
int ret;
word32 decodedLen;
byte* decodedConfigs;
if (ssl == NULL || echConfigs64 == NULL || echConfigs64Len == 0)
if (ssl == NULL)
return BAD_FUNC_ARG;
/* already have ech configs */
if (ssl->echConfigs != NULL) {
return WOLFSSL_FATAL_ERROR;
}
decodedConfigs = (byte*)XMALLOC(decodedLen, ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (decodedConfigs == NULL)
return MEMORY_E;
decodedConfigs[decodedLen - 1] = 0;
/* decode the echConfigs */
ret = Base64_Decode((const byte*)echConfigs64, echConfigs64Len,
decodedConfigs, &decodedLen);
if (ret != 0) {
XFREE(decodedConfigs, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
ret = DecodeEchConfigsBase64(ssl->heap, echConfigs64, echConfigs64Len,
&decodedConfigs, &decodedLen);
if (ret != 0)
return ret;
}
ret = wolfSSL_SetEchConfigs(ssl, decodedConfigs, decodedLen);
@@ -418,8 +429,8 @@ int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen)
output += 2;
}
/* set maximum name length to 0 */
*output = 0;
/* maximum name len */
*output = config->maxNameLen;
output++;
/* publicName len */
@@ -430,7 +441,7 @@ int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen)
XMEMCPY(output, config->publicName, publicNameLen);
output += publicNameLen;
/* terminating zeros */
/* no extensions, print zeros */
c16toa(0, output);
/* output += 2; */
@@ -656,11 +667,12 @@ int SetEchConfigsEx(WOLFSSL_EchConfig** outputConfigs, void* heap,
idx += 4;
}
/* ignore maximum name length */
/* maxNameLen */
if (idx + 1 > length) {
ret = BUFFER_E;
break;
}
workingConfig->maxNameLen = echConfig[idx];
idx += 1;
/* publicName */
@@ -701,7 +713,7 @@ int SetEchConfigsEx(WOLFSSL_EchConfig** outputConfigs, void* heap,
}
ret = EchConfigCheckExtensions(echConfig + idx, extensionsLen);
if (ret < 0)
if (ret < 0 && ret != WC_NO_ERR_TRACE(UNSUPPORTED_EXTENSION))
break;
/* KEM, ciphersuite, or mandatory extension not supported, free this
+15 -1
View File
@@ -4825,9 +4825,23 @@ int SendTls13ClientHello(WOLFSSL* ssl)
if (ret != 0)
return ret;
/* calculate padding (RFC 9849, section 6.1.3) */
if (args->ech->privateName != NULL) {
word16 nameLen = (word16)XSTRLEN(args->ech->privateName);
if (nameLen > args->ech->echConfig->maxNameLen)
args->ech->paddingLen = 0;
else
args->ech->paddingLen =
(word16)args->ech->echConfig->maxNameLen - nameLen;
}
else {
args->ech->paddingLen = args->ech->echConfig->maxNameLen + 9;
}
/* innerClientHelloLen and padding are based on the
* encoded (sealed) inner */
args->ech->paddingLen = 31 - ((encodedLen - 1) % 32);
args->ech->paddingLen += 31 -
((encodedLen + args->ech->paddingLen - 1) % 32);
args->ech->innerClientHelloLen = encodedLen +
args->ech->paddingLen + args->ech->hpke->Nt;
+4 -2
View File
@@ -15066,8 +15066,10 @@ static int test_ech_server_ctx_ready(WOLFSSL_CTX* ctx)
{
int ret;
ret = wolfSSL_CTX_GenerateEchConfig(ctx, echCbTestPublicName,
echCbTestKemID, echCbTestKdfID, echCbTestAeadID);
/* +20 for this isn't significant, it just exercises the padding code */
ret = wolfSSL_CTX_GenerateEchConfigEx(ctx, echCbTestPublicName,
echCbTestKemID, echCbTestKdfID, echCbTestAeadID,
XSTRLEN(echCbTestPublicName) + 20);
if (ret != WOLFSSL_SUCCESS)
return TEST_FAIL;
+1
View File
@@ -3147,6 +3147,7 @@ typedef struct WOLFSSL_EchConfig {
byte configId;
byte numCipherSuites;
byte receiverPubkey[HPKE_Npk_MAX];
byte maxNameLen;
} WOLFSSL_EchConfig;
typedef struct WOLFSSL_ECH {
+3
View File
@@ -1231,6 +1231,9 @@ WOLFSSL_API WOLFSSL_METHOD *wolfSSLv23_method(void);
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
WOLFSSL_API int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx,
const char* publicName, word16 kemId, word16 kdfId, word16 aeadId);
WOLFSSL_API int wolfSSL_CTX_GenerateEchConfigEx(WOLFSSL_CTX* ctx,
const char* publicName, word16 kemId, word16 kdfId, word16 aeadId,
byte maxNameLen);
WOLFSSL_API int wolfSSL_CTX_SetEchConfigsBase64(WOLFSSL_CTX* ctx,
const char* echConfigs64, word32 echConfigs64Len);