mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 11:40:53 +02:00
Merge pull request #10469 from sebastian-carpenter/tls-ech-server-improvements
Enhancement (ECH): Trial decryption and ECH connection status
This commit is contained in:
+2
-1
@@ -8024,7 +8024,8 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
|
||||
ssl->options.disallowEncThenMac = ctx->disallowEncThenMac;
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
ssl->options.disableECH = ctx->disableECH;
|
||||
ssl->options.disableECH = ctx->disableECH;
|
||||
ssl->options.enableEchTrialDecrypt = ctx->enableEchTrialDecrypt;
|
||||
#endif
|
||||
|
||||
/* default alert state (none) */
|
||||
|
||||
@@ -272,6 +272,15 @@ void wolfSSL_CTX_SetEchEnable(WOLFSSL_CTX* ctx, byte enable)
|
||||
}
|
||||
}
|
||||
|
||||
/* disabled (default) -> only decrypt the ClientHello with configs that have a
|
||||
* matching configId
|
||||
* enabled -> try to decrypt the inner ClientHello with all configs */
|
||||
void wolfSSL_CTX_SetEchEnableTrialDecrypt(WOLFSSL_CTX* ctx, byte enable)
|
||||
{
|
||||
if (ctx != NULL)
|
||||
ctx->enableEchTrialDecrypt = (enable != 0);
|
||||
}
|
||||
|
||||
/* 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, const char* echConfigs64,
|
||||
@@ -491,6 +500,71 @@ void wolfSSL_SetEchEnable(WOLFSSL* ssl, byte enable)
|
||||
}
|
||||
}
|
||||
|
||||
/* disabled (default) -> only decrypt the ClientHello with configs that have a
|
||||
* matching configId
|
||||
* enabled -> try to decrypt the inner ClientHello with all configs */
|
||||
void wolfSSL_SetEchEnableTrialDecrypt(WOLFSSL* ssl, byte enable)
|
||||
{
|
||||
if (ssl != NULL)
|
||||
ssl->options.enableEchTrialDecrypt = (enable != 0);
|
||||
}
|
||||
|
||||
/* Return the status of the ECH connection. Possible return values:
|
||||
* WOLFSSL_ECH_STATUS_NOT_OFFERED:
|
||||
* server - client did not send ECH or it is not setup
|
||||
* client - ECH is not setup
|
||||
* pending - connection has not been initiated
|
||||
*
|
||||
* WOLFSSL_ECH_STATUS_GREASE:
|
||||
* client - GREASE ECH extension sent
|
||||
*
|
||||
* WOLFSSL_ECH_STATUS_REJECTED:
|
||||
* server - ECH was not accepted (decryption of inner ClientHello failed)
|
||||
* client - ECH was offered but the server rejected it
|
||||
*
|
||||
* In both cases the connection fell back to the outer transcript.
|
||||
*
|
||||
* WOLFSSL_ECH_STATUS_ACCEPTED:
|
||||
* Decryption of the inner ClientHello was successful and the inner
|
||||
* transcript was used.
|
||||
*
|
||||
* Returns BAD_FUNC_ARG if ssl is NULL. */
|
||||
int wolfSSL_GetEchStatus(const WOLFSSL* ssl)
|
||||
{
|
||||
if (ssl == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
if (ssl->options.disableECH)
|
||||
return WOLFSSL_ECH_STATUS_NOT_OFFERED;
|
||||
if (ssl->options.echAccepted)
|
||||
return WOLFSSL_ECH_STATUS_ACCEPTED;
|
||||
|
||||
if (ssl->options.side == WOLFSSL_SERVER_END) {
|
||||
TLSX* echX = TLSX_Find(ssl->extensions, TLSX_ECH);
|
||||
WOLFSSL_ECH* ech;
|
||||
|
||||
if (echX == NULL || echX->data == NULL)
|
||||
return WOLFSSL_ECH_STATUS_NOT_OFFERED;
|
||||
|
||||
/* state stays at ECH_WRITE_NONE and innerClientHello stays NULL when
|
||||
* the client did not send an ECH extension */
|
||||
ech = (WOLFSSL_ECH*)echX->data;
|
||||
if (ech->state == ECH_WRITE_NONE && ech->innerClientHello == NULL)
|
||||
return WOLFSSL_ECH_STATUS_NOT_OFFERED;
|
||||
|
||||
return WOLFSSL_ECH_STATUS_REJECTED;
|
||||
}
|
||||
|
||||
/* client */
|
||||
if (ssl->options.connectState < CLIENT_HELLO_SENT)
|
||||
return WOLFSSL_ECH_STATUS_NOT_OFFERED;
|
||||
|
||||
if (ssl->echConfigs == NULL)
|
||||
return WOLFSSL_ECH_STATUS_GREASE;
|
||||
|
||||
return WOLFSSL_ECH_STATUS_REJECTED;
|
||||
}
|
||||
|
||||
/* Walk the ECHConfigExtension list and check for mandatory extensions.
|
||||
* Returns:
|
||||
* 0 if all extensions are known/optional,
|
||||
|
||||
@@ -14646,23 +14646,26 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
|
||||
if (echConfig->configId == ech->configId) {
|
||||
ret = TLSX_ExtractEch(ech, echConfig, aadCopy, ech->aadLen,
|
||||
ssl->heap);
|
||||
break;
|
||||
if (ret == 0)
|
||||
break;
|
||||
}
|
||||
echConfig = echConfig->next;
|
||||
}
|
||||
/* otherwise, try to decrypt with all configs */
|
||||
if (echConfig == NULL || ret != 0) {
|
||||
/* otherwise, try to decrypt with all configs (trial decryption) */
|
||||
if (echConfig == NULL && ssl->options.enableEchTrialDecrypt) {
|
||||
echConfig = ssl->ctx->echConfigs;
|
||||
while (echConfig != NULL) {
|
||||
ret = TLSX_ExtractEch(ech, echConfig, aadCopy, ech->aadLen,
|
||||
ssl->heap);
|
||||
if (ret == 0)
|
||||
break;
|
||||
if (echConfig->configId != ech->configId) {
|
||||
ret = TLSX_ExtractEch(ech, echConfig, aadCopy, ech->aadLen,
|
||||
ssl->heap);
|
||||
if (ret == 0)
|
||||
break;
|
||||
}
|
||||
echConfig = echConfig->next;
|
||||
}
|
||||
}
|
||||
/* if we failed to extract/expand */
|
||||
if (ret != 0) {
|
||||
if (ret != 0 || echConfig == NULL) {
|
||||
WOLFSSL_MSG("ECH rejected");
|
||||
|
||||
if (ssl->options.echAccepted == 1) {
|
||||
@@ -14681,20 +14684,15 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
|
||||
}
|
||||
}
|
||||
else {
|
||||
WOLFSSL_MSG("ECH accepted");
|
||||
ssl->options.echAccepted = 1;
|
||||
|
||||
ret = TLSX_ECH_CheckInnerPadding(ssl, ech);
|
||||
if (ret == 0) {
|
||||
/* expand EchOuterExtensions if present.
|
||||
* Also, if it exists, copy sessionID from outer hello */
|
||||
ret = TLSX_ECH_ExpandOuterExtensions(ssl, ech, ssl->heap);
|
||||
}
|
||||
|
||||
if (ret == 0){
|
||||
WOLFSSL_MSG("ECH accepted");
|
||||
ssl->options.echAccepted = 1;
|
||||
}
|
||||
else {
|
||||
WOLFSSL_MSG("ECH rejected");
|
||||
}
|
||||
}
|
||||
if (ret != 0) {
|
||||
XFREE(ech->innerClientHello, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
+175
-23
@@ -14983,7 +14983,7 @@ static int test_wolfSSL_ECH_conn_ex(method_provider serverMeth,
|
||||
/* connect like normal */
|
||||
ExpectIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(ssl->options.echAccepted, 1);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(ssl), WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
ExpectIntEQ(wolfSSL_write(ssl, privateName, privateNameLen),
|
||||
privateNameLen);
|
||||
ExpectIntGT((replyLen = wolfSSL_read(ssl, reply, sizeof(reply))), 0);
|
||||
@@ -15089,6 +15089,16 @@ static int test_ech_server_ctx_ready(WOLFSSL_CTX* ctx)
|
||||
return TEST_SUCCESS;
|
||||
}
|
||||
|
||||
/* Server ctx_ready callback: generate ECH config and opt into trial
|
||||
* decryption at the CTX level so the SSL inherits it on creation */
|
||||
static int test_ech_server_ctx_ready_trial_decrypt(WOLFSSL_CTX* ctx)
|
||||
{
|
||||
int ret = test_ech_server_ctx_ready(ctx);
|
||||
if (ret == TEST_SUCCESS)
|
||||
wolfSSL_CTX_SetEchEnableTrialDecrypt(ctx, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Server ssl_ready callback: set SNI */
|
||||
static int test_ech_server_ssl_ready(WOLFSSL* ssl)
|
||||
{
|
||||
@@ -15136,7 +15146,10 @@ static int test_wolfSSL_Tls13_ECH_all_algos_ex(void)
|
||||
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 1);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
|
||||
if (echCbTestKemID != 0 && echCbTestKdfID != 0 && echCbTestAeadID != 0) {
|
||||
TLSX* echX = TLSX_Find(test_ctx.c_ssl->extensions, TLSX_ECH);
|
||||
@@ -15249,7 +15262,10 @@ static int test_wolfSSL_Tls13_ECH_no_private_name(void)
|
||||
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 1);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
@@ -15269,7 +15285,10 @@ static int test_wolfSSL_Tls13_ECH_no_private_name(void)
|
||||
echCbTestConfigsLen), WOLFSSL_SUCCESS);
|
||||
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_NOT_OFFERED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_NOT_OFFERED);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
@@ -15288,7 +15307,10 @@ static int test_wolfSSL_Tls13_ECH_no_private_name(void)
|
||||
echCbTestConfigsLen), WOLFSSL_SUCCESS);
|
||||
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_NOT_OFFERED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_NOT_OFFERED);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
@@ -15347,7 +15369,10 @@ static int test_wolfSSL_Tls13_ECH_bad_configs_ex(int hrr, int sniCb)
|
||||
}
|
||||
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
@@ -15383,7 +15408,12 @@ static int test_wolfSSL_Tls13_ECH_bad_configs_ex(int hrr, int sniCb)
|
||||
}
|
||||
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
/* server decrypts inner successfully but rejects SNI, thus the client does
|
||||
* not receive the acceptance signal */
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
@@ -15444,7 +15474,10 @@ static int test_wolfSSL_Tls13_ECH_retry_configs_ex(int hrr)
|
||||
|
||||
/* ECH must fail and retry configs must be present */
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
|
||||
WC_NO_ERR_TRACE(ECH_REQUIRED_E));
|
||||
|
||||
@@ -15482,7 +15515,10 @@ static int test_wolfSSL_Tls13_ECH_retry_configs_ex(int hrr)
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL),
|
||||
TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 1);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
|
||||
wolfSSL_CTX_free(test_ctx.s_ctx);
|
||||
test_ctx.s_ctx = NULL;
|
||||
@@ -15604,7 +15640,10 @@ static int test_wolfSSL_Tls13_ECH_retry_configs_bad(void)
|
||||
/* bad retry configs are discarded - failure must be ECH_REQUIRED_E,
|
||||
* not a retry-config parse error */
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
|
||||
WC_NO_ERR_TRACE(ECH_REQUIRED_E));
|
||||
|
||||
@@ -15689,7 +15728,94 @@ static int test_wolfSSL_Tls13_ECH_new_config(void)
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 1);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* Test trial decryption for ECH: server has a single config, client receives a
|
||||
* copy of it but its configId is overwritten so it cannot match the server's */
|
||||
static int test_wolfSSL_Tls13_ECH_trial_decrypt(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
test_ssl_memio_ctx test_ctx;
|
||||
|
||||
/* --- CTX-enabled, SSL-disabled override: ECH rejected --- */
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
|
||||
test_ctx.s_cb.method = wolfTLSv1_3_server_method;
|
||||
test_ctx.c_cb.method = wolfTLSv1_3_client_method;
|
||||
|
||||
/* *_trial_decrypt sets enableEchTrialDecrypt to 1 - overriding the default
|
||||
* value of 0 */
|
||||
test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready_trial_decrypt;
|
||||
test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
|
||||
test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
|
||||
|
||||
/* SSL inherited the CTX setting */
|
||||
ExpectIntEQ(test_ctx.s_ctx->enableEchTrialDecrypt, 1);
|
||||
ExpectIntEQ(test_ctx.s_ssl->options.enableEchTrialDecrypt, 1);
|
||||
|
||||
/* override on the SSL */
|
||||
wolfSSL_SetEchEnableTrialDecrypt(test_ctx.s_ssl, 0);
|
||||
ExpectIntEQ(test_ctx.s_ssl->options.enableEchTrialDecrypt, 0);
|
||||
|
||||
/* alter the client's configId so it does not match the server's configId */
|
||||
ExpectNotNull(test_ctx.c_ssl->echConfigs);
|
||||
ExpectNotNull(test_ctx.s_ctx->echConfigs);
|
||||
if (EXPECT_SUCCESS()) {
|
||||
test_ctx.c_ssl->echConfigs->configId =
|
||||
(byte)(test_ctx.s_ctx->echConfigs->configId ^ 0x01);
|
||||
}
|
||||
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
|
||||
WC_NO_ERR_TRACE(ECH_REQUIRED_E));
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
/* --- trial decryption opted in on the SSL: ECH accepted --- */
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
|
||||
test_ctx.s_cb.method = wolfTLSv1_3_server_method;
|
||||
test_ctx.c_cb.method = wolfTLSv1_3_client_method;
|
||||
|
||||
test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
|
||||
test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
|
||||
test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
|
||||
|
||||
/* opt into trial decryption on the SSL */
|
||||
wolfSSL_SetEchEnableTrialDecrypt(test_ctx.s_ssl, 1);
|
||||
ExpectIntEQ(test_ctx.s_ssl->options.enableEchTrialDecrypt, 1);
|
||||
|
||||
/* alter the client's configId so it does not match the server's configId */
|
||||
ExpectNotNull(test_ctx.c_ssl->echConfigs);
|
||||
ExpectNotNull(test_ctx.s_ctx->echConfigs);
|
||||
if (EXPECT_SUCCESS()) {
|
||||
test_ctx.c_ssl->echConfigs->configId =
|
||||
(byte)(test_ctx.s_ctx->echConfigs->configId ^ 0x01);
|
||||
}
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
@@ -15731,9 +15857,11 @@ static int test_wolfSSL_Tls13_ECH_GREASE(void)
|
||||
/* handshake should succeed - server ignores the GREASE ECH extension */
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
|
||||
/* ECH should NOT be accepted since this was GREASE */
|
||||
ExpectIntEQ(test_ctx.s_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
/* server has no configs and client did not offer real ECH */
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_NOT_OFFERED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_GREASE);
|
||||
/* verify no ECH configs are received */
|
||||
ExpectNull(test_ctx.c_ssl->echConfigs);
|
||||
/* retry configs must not be saved */
|
||||
@@ -15769,9 +15897,12 @@ static int test_wolfSSL_Tls13_ECH_GREASE(void)
|
||||
/* handshake should succeed - server responds to the GREASE ECH extension */
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
|
||||
/* ECH should NOT be accepted since this was GREASE */
|
||||
ExpectIntEQ(test_ctx.s_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
/* server was unable to decrypt the ECH extension's payload
|
||||
* client never offered real ECH */
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_GREASE);
|
||||
/* verify no ECH configs are received */
|
||||
ExpectNull(test_ctx.c_ssl->echConfigs);
|
||||
/* retry configs must not be saved */
|
||||
@@ -15816,6 +15947,8 @@ static int test_wolfSSL_Tls13_ECH_disable_conn_ex(int enableServer,
|
||||
* normally but ECH is not accepted */
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL),
|
||||
TEST_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_NOT_OFFERED);
|
||||
}
|
||||
else if (!enableServer) {
|
||||
/* client sends ECH but server can't process it: server has no ECH
|
||||
@@ -15823,8 +15956,11 @@ static int test_wolfSSL_Tls13_ECH_disable_conn_ex(int enableServer,
|
||||
* rejection and aborts the handshake */
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL),
|
||||
TEST_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
}
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_NOT_OFFERED);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
@@ -15929,7 +16065,10 @@ static int test_wolfSSL_Tls13_ECH_HRR_rejection(void)
|
||||
|
||||
/* Handshake must fail: client aborts with ech_required */
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_NOT_OFFERED);
|
||||
/* hsHashesEch must have been freed by the HRR rejection code path */
|
||||
ExpectNull(test_ctx.c_ssl->hsHashesEch);
|
||||
ExpectIntEQ(wolfSSL_get_error(test_ctx.c_ssl, 0),
|
||||
@@ -15967,7 +16106,10 @@ static int test_wolfSSL_Tls13_ECH_ch2_no_ech(void)
|
||||
/* server must have committed to ECH acceptance in the HRR */
|
||||
ExpectIntEQ(test_ctx.s_ssl->options.serverState,
|
||||
SERVER_HELLO_RETRY_REQUEST_COMPLETE);
|
||||
ExpectIntEQ(test_ctx.s_ssl->options.echAccepted, 1);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
|
||||
/* disable ECH on the client so CH2 omits the ECH extension entirely */
|
||||
wolfSSL_SetEchEnable(test_ctx.c_ssl, 0);
|
||||
@@ -16009,7 +16151,10 @@ static int test_wolfSSL_Tls13_ECH_ch2_decrypt_error(void)
|
||||
|
||||
ExpectIntEQ(test_ctx.s_ssl->options.serverState,
|
||||
SERVER_HELLO_RETRY_REQUEST_COMPLETE);
|
||||
ExpectIntEQ(test_ctx.s_ssl->options.echAccepted, 1);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_ACCEPTED);
|
||||
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* Client reads HRR and writes CH2 into s_buff */
|
||||
@@ -16087,7 +16232,10 @@ static int test_wolfSSL_Tls13_ECH_rejected_cert_valid_ex(const char* publicName,
|
||||
/* client sends ECH but server can't process it, however it is possible to
|
||||
* fall back to the outer handshake */
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_NOT_OFFERED);
|
||||
|
||||
if (validName) {
|
||||
/* the server should see the handshake as successful
|
||||
@@ -16165,7 +16313,10 @@ static int test_wolfSSL_Tls13_ECH_rejected_empty_client_cert(void)
|
||||
publicName, (word16)XSTRLEN(publicName)), WOLFSSL_SUCCESS);
|
||||
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
|
||||
WOLFSSL_ECH_STATUS_REJECTED);
|
||||
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
|
||||
WOLFSSL_ECH_STATUS_NOT_OFFERED);
|
||||
|
||||
/* Server cert is valid for public_name, cert check passes, ech_required
|
||||
* is sent on the client side. */
|
||||
@@ -40615,6 +40766,7 @@ TEST_CASE testCases[] = {
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_retry_configs_bad),
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_retry_configs_auth_fail),
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_new_config),
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_trial_decrypt),
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_GREASE),
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_disable_conn),
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_long_SNI),
|
||||
|
||||
@@ -4045,6 +4045,8 @@ struct WOLFSSL_CTX {
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
byte disableECH:1;
|
||||
byte enableEchTrialDecrypt:1; /* Trial decryption of the
|
||||
inner hello */
|
||||
#endif
|
||||
word16 minProto:1; /* sets min to min available */
|
||||
word16 maxProto:1; /* sets max to max available */
|
||||
@@ -5252,6 +5254,8 @@ struct Options {
|
||||
word16 disableECH:1; /* Did the user disable ech */
|
||||
word16 echProcessingInner:1; /* Processing the inner hello */
|
||||
word16 echRetryConfigsAccepted:1;
|
||||
word16 enableEchTrialDecrypt:1; /* Trial decryption of the
|
||||
inner hello */
|
||||
#endif
|
||||
#ifdef WOLFSSL_SEND_HRR_COOKIE
|
||||
word16 cookieGood:1;
|
||||
|
||||
@@ -1246,6 +1246,9 @@ WOLFSSL_API int wolfSSL_CTX_GetEchConfigs(WOLFSSL_CTX* ctx, byte* output,
|
||||
|
||||
WOLFSSL_API void wolfSSL_CTX_SetEchEnable(WOLFSSL_CTX* ctx, byte enable);
|
||||
|
||||
WOLFSSL_API void wolfSSL_CTX_SetEchEnableTrialDecrypt(WOLFSSL_CTX* ctx,
|
||||
byte enable);
|
||||
|
||||
WOLFSSL_API int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl,
|
||||
const char* echConfigs64, word32 echConfigs64Len);
|
||||
|
||||
@@ -1259,6 +1262,14 @@ WOLFSSL_API int wolfSSL_GetEchRetryConfigs(WOLFSSL* ssl, byte* echConfigs,
|
||||
word32* echConfigsLen);
|
||||
|
||||
WOLFSSL_API void wolfSSL_SetEchEnable(WOLFSSL* ssl, byte enable);
|
||||
|
||||
WOLFSSL_API void wolfSSL_SetEchEnableTrialDecrypt(WOLFSSL* ssl, byte enable);
|
||||
|
||||
#define WOLFSSL_ECH_STATUS_NOT_OFFERED 0
|
||||
#define WOLFSSL_ECH_STATUS_GREASE 1
|
||||
#define WOLFSSL_ECH_STATUS_REJECTED 2
|
||||
#define WOLFSSL_ECH_STATUS_ACCEPTED 3
|
||||
WOLFSSL_API int wolfSSL_GetEchStatus(const WOLFSSL* ssl);
|
||||
#endif /* WOLFSSL_TLS13 && HAVE_ECH */
|
||||
|
||||
#ifdef HAVE_POLY1305
|
||||
|
||||
Reference in New Issue
Block a user