Skip to content

Commit 8a72319

Browse files
TLS ECH keylogging
1 parent c4c71ee commit 8a72319

8 files changed

Lines changed: 225 additions & 22 deletions

File tree

src/internal.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,12 @@ void wolfssl_priv_der_unblind_free(DerBuffer* key)
535535
#define SSC_TLS13_EES "EARLY_EXPORTER_SECRET"
536536
/* Label string for exporter secret. */
537537
#define SSC_TLS13_ES "EXPORTER_SECRET"
538+
#ifdef HAVE_ECH
539+
/* Label string for ECH KEM shared secret. */
540+
#define SSC_TLS13_ECH_S "ECH_SECRET"
541+
/* Label string for ECHConfig used to construct ECH. */
542+
#define SSC_TLS13_ECH_C "ECH_CONFIG"
543+
#endif
538544

539545
/*
540546
* This function builds up string for key-logging then call user's
@@ -594,6 +600,18 @@ void wolfssl_priv_der_unblind_free(DerBuffer* key)
594600
label = SSC_TLS13_ES;
595601
break;
596602

603+
#ifdef HAVE_ECH
604+
case ECH_SECRET:
605+
labelSz = sizeof(SSC_TLS13_ECH_S);
606+
label = SSC_TLS13_ECH_S;
607+
break;
608+
609+
case ECH_CONFIG:
610+
labelSz = sizeof(SSC_TLS13_ECH_C);
611+
label = SSC_TLS13_ECH_C;
612+
break;
613+
#endif
614+
597615
default:
598616
return BAD_FUNC_ARG;
599617
}

src/tls.c

Lines changed: 117 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13845,6 +13845,42 @@ static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech, byte msgType)
1384513845
return (int)size;
1384613846
}
1384713847

13848+
#ifdef HAVE_SECRET_CALLBACK
13849+
/* log ECH_SECRET and ECH_CONFIG
13850+
* returns 0 on success, TLS13_SECRET_CB_E otherwise */
13851+
static int EchWriteKeyLog(WOLFSSL* ssl, const byte* secret, word32 secretSz,
13852+
const byte* config, word32 configSz)
13853+
{
13854+
int ret = 0;
13855+
if (ssl->tls13SecretCb != NULL) {
13856+
ret = ssl->tls13SecretCb(ssl, ECH_SECRET, secret, (int)secretSz,
13857+
ssl->tls13SecretCtx);
13858+
if (ret == 0) {
13859+
ret = ssl->tls13SecretCb(ssl, ECH_CONFIG, config, (int)configSz,
13860+
ssl->tls13SecretCtx);
13861+
}
13862+
if (ret != 0) {
13863+
WOLFSSL_ERROR_VERBOSE(TLS13_SECRET_CB_E);
13864+
ret = TLS13_SECRET_CB_E;
13865+
}
13866+
}
13867+
#ifdef OPENSSL_EXTRA
13868+
if (ret == 0 && ssl->tls13KeyLogCb != NULL) {
13869+
ret = ssl->tls13KeyLogCb(ssl, ECH_SECRET, secret, (int)secretSz, NULL);
13870+
if (ret == 0) {
13871+
ret = ssl->tls13KeyLogCb(ssl, ECH_CONFIG, config, (int)configSz,
13872+
NULL);
13873+
}
13874+
if (ret != 0) {
13875+
WOLFSSL_ERROR_VERBOSE(TLS13_SECRET_CB_E);
13876+
ret = TLS13_SECRET_CB_E;
13877+
}
13878+
}
13879+
#endif /* OPENSSL_EXTRA */
13880+
return ret;
13881+
}
13882+
#endif /* HAVE_SECRET_CALLBACK */
13883+
1384813884
/* rough check that inner hello fields do not exceed length of decrypted
1384913885
* information. Additionally, this function will check that all padding bytes
1385013886
* are zero and decrease the innerHelloLen accordingly if so.
@@ -14259,15 +14295,15 @@ static int TLSX_ECH_ExpandOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech,
1425914295
/* return status after attempting to open the hpke encrypted ech extension, if
1426014296
* successful the inner client hello will be stored in
1426114297
* ech->innerClientHelloLen */
14262-
static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
14263-
byte* aad, word32 aadLen, void* heap)
14298+
static int TLSX_ExtractEch(WOLFSSL* ssl, WOLFSSL_ECH* ech,
14299+
WOLFSSL_EchConfig* echConfig, byte* aad, word32 aadLen)
1426414300
{
1426514301
int ret = 0;
1426614302
int i;
1426714303
word32 rawConfigLen = 0;
1426814304
byte* info = NULL;
1426914305
word32 infoLen = 0;
14270-
if (ech == NULL || echConfig == NULL || aad == NULL)
14306+
if (ssl == NULL || ech == NULL || echConfig == NULL || aad == NULL)
1427114307
return BAD_FUNC_ARG;
1427214308
/* verify the kem and key len */
1427314309
if (wc_HpkeKemGetEncLen(echConfig->kemId) != ech->encLen)
@@ -14284,13 +14320,14 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
1428414320
}
1428514321
/* check if hpke already exists, may if HelloRetryRequest */
1428614322
if (ech->hpke == NULL) {
14287-
ech->hpke = (Hpke*)XMALLOC(sizeof(Hpke), heap, DYNAMIC_TYPE_TMP_BUFFER);
14323+
ech->hpke = (Hpke*)XMALLOC(sizeof(Hpke), ssl->heap,
14324+
DYNAMIC_TYPE_TMP_BUFFER);
1428814325
if (ech->hpke == NULL)
1428914326
ret = MEMORY_E;
1429014327
/* init the hpke struct */
1429114328
if (ret == 0) {
1429214329
ret = wc_HpkeInit(ech->hpke, echConfig->kemId,
14293-
ech->cipherSuite.kdfId, ech->cipherSuite.aeadId, heap);
14330+
ech->cipherSuite.kdfId, ech->cipherSuite.aeadId, ssl->heap);
1429414331
}
1429514332
if (ret == 0) {
1429614333
/* allocate hpkeContext */
@@ -14308,7 +14345,7 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
1430814345
/* create info */
1430914346
if (ret == 0) {
1431014347
infoLen = TLS_INFO_CONST_STRING_SZ + 1 + rawConfigLen;
14311-
info = (byte*)XMALLOC(infoLen, heap, DYNAMIC_TYPE_TMP_BUFFER);
14348+
info = (byte*)XMALLOC(infoLen, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
1431214349

1431314350
if (info == NULL)
1431414351
ret = MEMORY_E;
@@ -14319,6 +14356,16 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
1431914356
TLS_INFO_CONST_STRING_SZ + 1, &rawConfigLen);
1432014357
}
1432114358
}
14359+
#ifdef HAVE_SECRET_CALLBACK
14360+
/* allocate secret buffer for wc_HpkeInitOpenContext to copy into */
14361+
if (ret == 0 && (ssl->tls13SecretCb != NULL
14362+
#ifdef OPENSSL_EXTRA
14363+
|| ssl->tls13KeyLogCb != NULL
14364+
#endif
14365+
)) {
14366+
ret = wc_HpkeInitEchSecret(ech->hpke);
14367+
}
14368+
#endif /* HAVE_SECRET_CALLBACK */
1432214369
/* init the context for opening */
1432314370
if (ret == 0) {
1432414371
ret = wc_HpkeInitOpenContext(ech->hpke, ech->hpkeContext,
@@ -14332,16 +14379,44 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
1433214379
ech->outerClientPayload, ech->innerClientHelloLen,
1433314380
ech->innerClientHello + HANDSHAKE_HEADER_SZ);
1433414381
}
14382+
14383+
#ifdef HAVE_SECRET_CALLBACK
14384+
if (ret == 0 && ech->hpke->echSecret != NULL) {
14385+
/* server does not store raw configs, so it needs to be built here */
14386+
byte* echConfigRaw = NULL;
14387+
word32 echConfigRawSz = 0;
14388+
ret = GetEchConfig(echConfig, NULL, &echConfigRawSz);
14389+
if (ret == WC_NO_ERR_TRACE(LENGTH_ONLY_E))
14390+
ret = 0;
14391+
if (ret == 0) {
14392+
echConfigRaw = (byte*)XMALLOC(echConfigRawSz, ssl->heap,
14393+
DYNAMIC_TYPE_TMP_BUFFER);
14394+
if (echConfigRaw == NULL)
14395+
ret = MEMORY_E;
14396+
}
14397+
if (ret == 0)
14398+
ret = GetEchConfig(echConfig, echConfigRaw, &echConfigRawSz);
14399+
if (ret == 0) {
14400+
ret = EchWriteKeyLog(ssl, ech->hpke->echSecret, ech->hpke->Nsecret,
14401+
echConfigRaw, echConfigRawSz);
14402+
}
14403+
XFREE(echConfigRaw, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
14404+
}
14405+
#endif /* HAVE_SECRET_CALLBACK */
14406+
1433514407
/* free the hpke and context on failure */
1433614408
if (ret != 0) {
14337-
XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER);
14409+
#ifdef HAVE_SECRET_CALLBACK
14410+
wc_HpkeFreeEchSecret(ech->hpke);
14411+
#endif
14412+
XFREE(ech->hpke, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
1433814413
ech->hpke = NULL;
14339-
XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER);
14414+
XFREE(ech->hpkeContext, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
1434014415
ech->hpkeContext = NULL;
1434114416
}
1434214417

1434314418
if (info != NULL)
14344-
XFREE(info, heap, DYNAMIC_TYPE_TMP_BUFFER);
14419+
XFREE(info, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
1434514420

1434614421
return ret;
1434714422
}
@@ -14512,8 +14587,8 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
1451214587
echConfig = ssl->ctx->echConfigs;
1451314588
while (echConfig != NULL) {
1451414589
if (echConfig->configId == ech->configId) {
14515-
ret = TLSX_ExtractEch(ech, echConfig, aadCopy, ech->aadLen,
14516-
ssl->heap);
14590+
ret = TLSX_ExtractEch(ssl, ech, echConfig, aadCopy,
14591+
ech->aadLen);
1451714592
break;
1451814593
}
1451914594
echConfig = echConfig->next;
@@ -14522,8 +14597,8 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
1452214597
if (echConfig == NULL || ret != 0) {
1452314598
echConfig = ssl->ctx->echConfigs;
1452414599
while (echConfig != NULL) {
14525-
ret = TLSX_ExtractEch(ech, echConfig, aadCopy, ech->aadLen,
14526-
ssl->heap);
14600+
ret = TLSX_ExtractEch(ssl, ech, echConfig, aadCopy,
14601+
ech->aadLen);
1452714602
if (ret == 0)
1452814603
break;
1452914604
echConfig = echConfig->next;
@@ -14558,10 +14633,14 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap)
1455814633
if (ech->ephemeralKey != NULL)
1455914634
wc_HpkeFreeKey(ech->hpke, ech->hpke->kem, ech->ephemeralKey,
1456014635
ech->hpke->heap);
14636+
#ifdef HAVE_SECRET_CALLBACK
14637+
wc_HpkeFreeEchSecret(ech->hpke);
14638+
#endif
1456114639
XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER);
1456214640
}
14563-
if (ech->hpkeContext != NULL)
14641+
if (ech->hpkeContext != NULL) {
1456414642
XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER);
14643+
}
1456514644
if (ech->privateName != NULL)
1456614645
XFREE((char*)ech->privateName, heap, DYNAMIC_TYPE_TMP_BUFFER);
1456714646

@@ -14571,13 +14650,15 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap)
1457114650

1457214651
/* encrypt the client hello and store it in ech->outerClientPayload, return
1457314652
* status */
14574-
int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen)
14653+
int TLSX_FinalizeEch(WOLFSSL* ssl, WOLFSSL_ECH* ech, byte* aad, word32 aadLen)
1457514654
{
1457614655
int ret = 0;
1457714656
void* receiverPubkey = NULL;
1457814657
byte* info = NULL;
1457914658
int infoLen = 0;
1458014659
byte* aadCopy = NULL;
14660+
if (ssl == NULL || ech == NULL || aad == NULL)
14661+
return BAD_FUNC_ARG;
1458114662
/* setup hpke context to seal, should be done at most once per connection */
1458214663
if (ech->hpkeContext == NULL) {
1458314664
/* import the server public key */
@@ -14605,6 +14686,18 @@ int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen)
1460514686
TLS_INFO_CONST_STRING_SZ + 1);
1460614687
XMEMCPY(info + TLS_INFO_CONST_STRING_SZ + 1,
1460714688
ech->echConfig->raw, ech->echConfig->rawLen);
14689+
}
14690+
#ifdef HAVE_SECRET_CALLBACK
14691+
/* allocate secret buffer for wc_HpkeInitSealContext to copy into */
14692+
if (ret == 0 && (ssl->tls13SecretCb != NULL
14693+
#ifdef OPENSSL_EXTRA
14694+
|| ssl->tls13KeyLogCb != NULL
14695+
#endif
14696+
)) {
14697+
ret = wc_HpkeInitEchSecret(ech->hpke);
14698+
}
14699+
#endif /* HAVE_SECRET_CALLBACK */
14700+
if (ret == 0) {
1460814701
/* init the context for seal with info and keys */
1460914702
ret = wc_HpkeInitSealContext(ech->hpke, ech->hpkeContext,
1461014703
ech->ephemeralKey, receiverPubkey, info, infoLen);
@@ -14625,6 +14718,14 @@ int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen)
1462514718
aadLen, ech->innerClientHello,
1462614719
ech->innerClientHelloLen - ech->hpke->Nt, ech->outerClientPayload);
1462714720
}
14721+
14722+
#ifdef HAVE_SECRET_CALLBACK
14723+
if (ret == 0 && ech->hpke->echSecret != NULL) {
14724+
ret = EchWriteKeyLog(ssl, ech->hpke->echSecret, ech->hpke->Nsecret,
14725+
ech->echConfig->raw, ech->echConfig->rawLen);
14726+
}
14727+
#endif /* HAVE_SECRET_CALLBACK */
14728+
1462814729
if (info != NULL)
1462914730
XFREE(info, ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER);
1463014731
if (aadCopy != NULL)
@@ -14643,7 +14744,7 @@ int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen)
1464314744
#define ECH_PARSE TLSX_ECH_Parse
1464414745
#define ECH_FREE TLSX_ECH_Free
1464514746

14646-
#endif
14747+
#endif /* WOLFSSL_TLS13 && HAVE_ECH */
1464714748

1464814749
/** Releases all extensions in the provided list. */
1464914750
void TLSX_FreeAll(TLSX* list, void* heap)

src/tls13.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4965,7 +4965,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
49654965
/* encrypt and pack the ech innerClientHello */
49664966
if (ssl->echConfigs != NULL && !ssl->options.disableECH &&
49674967
(ssl->options.echAccepted || args->ech->innerCount == 0)) {
4968-
ret = TLSX_FinalizeEch(args->ech,
4968+
ret = TLSX_FinalizeEch(ssl, args->ech,
49694969
args->output + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ,
49704970
(word32)(args->sendSz - (RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ)));
49714971

@@ -15809,6 +15809,12 @@ int tls13ShowSecrets(WOLFSSL* ssl, int id, const unsigned char* secret,
1580915809
str = "SERVER_TRAFFIC_SECRET_0"; break;
1581015810
case EXPORTER_SECRET:
1581115811
str = "EXPORTER_SECRET"; break;
15812+
#ifdef HAVE_ECH
15813+
case ECH_SECRET:
15814+
str = "ECH_SECRET"; break;
15815+
case ECH_CONFIG:
15816+
str = "ECH_CONFIG"; break;
15817+
#endif
1581215818
default:
1581315819
#ifdef WOLFSSL_SSLKEYLOGFILE_OUTPUT
1581415820
XFCLOSE(fp);

tests/api.c

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14157,6 +14157,12 @@ static int test_wolfSSL_Tls12_Key_Logging_test(void)
1415714157

1415814158
#if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \
1415914159
defined(HAVE_SECRET_CALLBACK)
14160+
#ifdef HAVE_ECH
14161+
static int test_ech_server_ctx_ready(WOLFSSL_CTX* ctx);
14162+
static int test_ech_server_ssl_ready(WOLFSSL* ssl);
14163+
static int test_ech_client_ssl_ready(WOLFSSL* ssl);
14164+
#endif
14165+
1416014166
static int test_wolfSSL_Tls13_Key_Logging_client_ctx_ready(WOLFSSL_CTX* ctx)
1416114167
{
1416214168
/* set keylog callback */
@@ -14176,11 +14182,21 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void)
1417614182
test_ssl_cbf server_cbf;
1417714183
test_ssl_cbf client_cbf;
1417814184
XFILE fp = XBADFILE;
14185+
#ifdef HAVE_ECH
14186+
const int label_count = 7;
14187+
#else
14188+
const int label_count = 5;
14189+
#endif
1417914190

1418014191
XMEMSET(&server_cbf, 0, sizeof(test_ssl_cbf));
1418114192
XMEMSET(&client_cbf, 0, sizeof(test_ssl_cbf));
1418214193
server_cbf.method = wolfTLSv1_3_server_method; /* TLS1.3 */
1418314194
client_cbf.ctx_ready = &test_wolfSSL_Tls13_Key_Logging_client_ctx_ready;
14195+
#ifdef HAVE_ECH
14196+
server_cbf.ctx_ready = &test_ech_server_ctx_ready;
14197+
server_cbf.ssl_ready = &test_ech_server_ssl_ready;
14198+
client_cbf.ssl_ready = &test_ech_client_ssl_ready;
14199+
#endif
1418414200

1418514201
/* clean up keylog file */
1418614202
ExpectTrue((fp = XFOPEN("./MyKeyLog.txt", "w")) != XBADFILE);
@@ -14195,7 +14211,7 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void)
1419514211
/* check if the keylog file exists */
1419614212
{
1419714213
char buff[300] = {0};
14198-
int found[4] = {0};
14214+
int found[7] = {0};
1419914215
int numfnd = 0;
1420014216
int i;
1420114217

@@ -14223,14 +14239,31 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void)
1422314239
found[3] = 1;
1422414240
continue;
1422514241
}
14242+
else if (0 == strncmp(buff, "EXPORTER_SECRET ",
14243+
sizeof("EXPORTER_SECRET ")-1)) {
14244+
found[4] = 1;
14245+
continue;
14246+
}
14247+
#ifdef HAVE_ECH
14248+
else if (0 == strncmp(buff, "ECH_SECRET ",
14249+
sizeof("ECH_SECRET ")-1)) {
14250+
found[5] = 1;
14251+
continue;
14252+
}
14253+
else if (0 == strncmp(buff, "ECH_CONFIG ",
14254+
sizeof("ECH_CONFIG ")-1)) {
14255+
found[6] = 1;
14256+
continue;
14257+
}
14258+
#endif
1422614259
}
1422714260
if (fp != XBADFILE)
1422814261
XFCLOSE(fp);
14229-
for (i = 0; i < 4; i++) {
14262+
for (i = 0; i < label_count; i++) {
1423014263
if (found[i] != 0)
1423114264
numfnd++;
1423214265
}
14233-
ExpectIntEQ(numfnd, 4);
14266+
ExpectIntEQ(numfnd, label_count);
1423414267
}
1423514268
#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK && WOLFSSL_TLS13 */
1423614269
return EXPECT_RESULT();

0 commit comments

Comments
 (0)