Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,12 @@ void wolfssl_priv_der_unblind_free(DerBuffer* key)
#define SSC_TLS13_EES "EARLY_EXPORTER_SECRET"
/* Label string for exporter secret. */
#define SSC_TLS13_ES "EXPORTER_SECRET"
#ifdef HAVE_ECH
/* Label string for ECH KEM shared secret. */
#define SSC_TLS13_ECH_S "ECH_SECRET"
/* Label string for ECHConfig used to construct ECH. */
#define SSC_TLS13_ECH_C "ECH_CONFIG"
#endif

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

#ifdef HAVE_ECH
case ECH_SECRET:
labelSz = sizeof(SSC_TLS13_ECH_S);
label = SSC_TLS13_ECH_S;
break;

case ECH_CONFIG:
labelSz = sizeof(SSC_TLS13_ECH_C);
label = SSC_TLS13_ECH_C;
break;
#endif

default:
return BAD_FUNC_ARG;
}
Expand Down
176 changes: 133 additions & 43 deletions src/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -13952,6 +13952,42 @@ static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech, byte msgType)
return (int)size;
}

#ifdef HAVE_SECRET_CALLBACK
/* log ECH_SECRET and ECH_CONFIG
* returns 0 on success, TLS13_SECRET_CB_E otherwise */
static int EchWriteKeyLog(WOLFSSL* ssl, const byte* secret, word32 secretSz,
Comment thread
sebastian-carpenter marked this conversation as resolved.
const byte* config, word32 configSz)
{
int ret = 0;
if (ssl->tls13SecretCb != NULL) {
ret = ssl->tls13SecretCb(ssl, ECH_SECRET, secret, (int)secretSz,
ssl->tls13SecretCtx);
if (ret == 0) {
ret = ssl->tls13SecretCb(ssl, ECH_CONFIG, config, (int)configSz,
ssl->tls13SecretCtx);
}
if (ret != 0) {
WOLFSSL_ERROR_VERBOSE(TLS13_SECRET_CB_E);
ret = TLS13_SECRET_CB_E;
}
}
#ifdef OPENSSL_EXTRA
if (ret == 0 && ssl->tls13KeyLogCb != NULL) {
ret = ssl->tls13KeyLogCb(ssl, ECH_SECRET, secret, (int)secretSz, NULL);
if (ret == 0) {
ret = ssl->tls13KeyLogCb(ssl, ECH_CONFIG, config, (int)configSz,
NULL);
}
if (ret != 0) {
WOLFSSL_ERROR_VERBOSE(TLS13_SECRET_CB_E);
ret = TLS13_SECRET_CB_E;
}
}
#endif /* OPENSSL_EXTRA */
return ret;
}
#endif /* HAVE_SECRET_CALLBACK */

/* rough check that inner hello fields do not exceed length of decrypted
* information. Additionally, this function will check that all padding bytes
* are zero and decrease the innerHelloLen accordingly if so.
Expand Down Expand Up @@ -14361,16 +14397,16 @@ static int TLSX_ECH_ExpandOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech,
/* return status after attempting to open the hpke encrypted ech extension, if
* successful the inner client hello will be stored in
* ech->innerClientHelloLen */
static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
byte* aad, word32 aadLen, void* heap)
static int TLSX_ExtractEch(WOLFSSL* ssl, WOLFSSL_ECH* ech,
WOLFSSL_EchConfig* echConfig, byte* aad, word32 aadLen)
{
int ret = 0;
int i;
int allocatedHpke = 0;
word32 rawConfigLen = 0;
byte* info = NULL;
word32 infoLen = 0;
if (ech == NULL || echConfig == NULL || aad == NULL)
if (ssl == NULL || ech == NULL || echConfig == NULL || aad == NULL)
return BAD_FUNC_ARG;
/* verify the kem and key len */
if (wc_HpkeKemGetEncLen(echConfig->kemId) != ech->encLen)
Expand All @@ -14388,13 +14424,14 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
/* check if hpke already exists, may if HelloRetryRequest */
if (ech->hpke == NULL) {
allocatedHpke = 1;
ech->hpke = (Hpke*)XMALLOC(sizeof(Hpke), heap, DYNAMIC_TYPE_TMP_BUFFER);
ech->hpke = (Hpke*)XMALLOC(sizeof(Hpke), ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (ech->hpke == NULL)
ret = MEMORY_E;
/* init the hpke struct */
if (ret == 0) {
ret = wc_HpkeInit(ech->hpke, echConfig->kemId,
ech->cipherSuite.kdfId, ech->cipherSuite.aeadId, heap);
ech->cipherSuite.kdfId, ech->cipherSuite.aeadId, ssl->heap);
}
if (ret == 0) {
/* allocate hpkeContext */
Expand All @@ -14412,7 +14449,7 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
/* create info */
if (ret == 0) {
infoLen = TLS_INFO_CONST_STRING_SZ + 1 + rawConfigLen;
info = (byte*)XMALLOC(infoLen, heap, DYNAMIC_TYPE_TMP_BUFFER);
info = (byte*)XMALLOC(infoLen, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);

if (info == NULL)
ret = MEMORY_E;
Expand All @@ -14423,6 +14460,16 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
TLS_INFO_CONST_STRING_SZ + 1, &rawConfigLen);
}
}
#ifdef HAVE_SECRET_CALLBACK
/* allocate secret buffer for wc_HpkeInitOpenContext to copy into */
if (ret == 0 && (ssl->tls13SecretCb != NULL
#ifdef OPENSSL_EXTRA
|| ssl->tls13KeyLogCb != NULL
#endif
)) {
ret = wc_HpkeInitEchSecret(ech->hpke);
}
#endif /* HAVE_SECRET_CALLBACK */
/* init the context for opening */
if (ret == 0) {
ret = wc_HpkeInitOpenContext(ech->hpke, ech->hpkeContext,
Expand All @@ -14436,17 +14483,29 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig,
ech->outerClientPayload, ech->innerClientHelloLen,
ech->innerClientHello + HANDSHAKE_HEADER_SZ);
}

#ifdef HAVE_SECRET_CALLBACK
if (ret == 0 && ech->hpke->echSecret != NULL) {
ret = EchWriteKeyLog(ssl, ech->hpke->echSecret, ech->hpke->Nsecret,
info + TLS_INFO_CONST_STRING_SZ + 1, rawConfigLen);
}
wc_HpkeFreeEchSecret(ech->hpke);
#endif /* HAVE_SECRET_CALLBACK */

/* only free hpke/hpkeContext if allocated in this call; otherwise preserve
* them for clientHello2 */
if (ret != 0 && allocatedHpke) {
XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(ech->hpke, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
ech->hpke = NULL;
XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER);
ech->hpkeContext = NULL;
if (ech->hpkeContext != NULL) {
ForceZero(ech->hpkeContext, sizeof(HpkeBaseContext));
XFREE(ech->hpkeContext, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
ech->hpkeContext = NULL;
}
}

if (info != NULL)
XFREE(info, heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(info, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);

return ret;
}
Expand Down Expand Up @@ -14650,9 +14709,9 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
echConfig = ssl->ctx->echConfigs;
while (echConfig != NULL) {
if (echConfig->configId == ech->configId) {
ret = TLSX_ExtractEch(ech, echConfig, aadCopy, ech->aadLen,
ssl->heap);
if (ret == 0)
ret = TLSX_ExtractEch(ssl, ech, echConfig, aadCopy,
ech->aadLen);
if (ret == 0 || ret == WC_NO_ERR_TRACE(TLS13_SECRET_CB_E))
break;
}
echConfig = echConfig->next;
Expand All @@ -14662,42 +14721,46 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
echConfig = ssl->ctx->echConfigs;
while (echConfig != NULL) {
if (echConfig->configId != ech->configId) {
ret = TLSX_ExtractEch(ech, echConfig, aadCopy, ech->aadLen,
ssl->heap);
if (ret == 0)
ret = TLSX_ExtractEch(ssl, ech, echConfig, aadCopy,
ech->aadLen);
if (ret == 0 || ret == WC_NO_ERR_TRACE(TLS13_SECRET_CB_E))
break;
}
echConfig = echConfig->next;
}
}
/* if we failed to extract/expand */
if (ret != 0 || echConfig == NULL) {
WOLFSSL_MSG("ECH rejected");
/* TLS13_SECRET_CB_E isn't correlated with ECH acceptance so skip both
* paths */
if (ret != WC_NO_ERR_TRACE(TLS13_SECRET_CB_E)) {
/* if we failed to extract/expand */
if (ret != 0 || echConfig == NULL) {
WOLFSSL_MSG("ECH rejected");

if (ssl->options.echAccepted == 1) {
/* on SH2 this is fatal */
SendAlert(ssl, alert_fatal, decrypt_error);
WOLFSSL_ERROR_VERBOSE(DECRYPT_ERROR);
ret = DECRYPT_ERROR;
if (ssl->options.echAccepted == 0) {
/* on SH1 prepare to write retry configs */
XFREE(ech->innerClientHello, ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
ech->innerClientHello = NULL;
ech->state = ECH_WRITE_RETRY_CONFIGS;
ret = 0;
}
else {
/* on SH2 failure to decrypt is fatal */
SendAlert(ssl, alert_fatal, decrypt_error);
WOLFSSL_ERROR_VERBOSE(DECRYPT_ERROR);
ret = DECRYPT_ERROR;
}
}
else {
/* on SH1 prepare to write retry configs */
XFREE(ech->innerClientHello, ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
ech->innerClientHello = NULL;
ech->state = ECH_WRITE_RETRY_CONFIGS;
ret = 0;
}
}
else {
WOLFSSL_MSG("ECH accepted");
ssl->options.echAccepted = 1;
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);
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) {
Expand All @@ -14719,10 +14782,14 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap)
if (ech->ephemeralKey != NULL)
wc_HpkeFreeKey(ech->hpke, ech->hpke->kem, ech->ephemeralKey,
ech->hpke->heap);
/* wc_HpkeFreeEchSecret is intentionally not here, free it in
* TLSX_ExtractEch / TLSX_FinalizeEch */
XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER);
}
if (ech->hpkeContext != NULL)
if (ech->hpkeContext != NULL) {
ForceZero(ech->hpkeContext, sizeof(HpkeBaseContext));
XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER);
}
if (ech->privateName != NULL)
XFREE((char*)ech->privateName, heap, DYNAMIC_TYPE_TMP_BUFFER);

Expand All @@ -14732,13 +14799,15 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap)

/* encrypt the client hello and store it in ech->outerClientPayload, return
* status */
int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen)
int TLSX_FinalizeEch(WOLFSSL* ssl, WOLFSSL_ECH* ech, byte* aad, word32 aadLen)
{
int ret = 0;
void* receiverPubkey = NULL;
byte* info = NULL;
int infoLen = 0;
byte* aadCopy = NULL;
if (ssl == NULL || ech == NULL || aad == NULL)
return BAD_FUNC_ARG;
/* setup hpke context to seal, should be done at most once per connection */
if (ech->hpkeContext == NULL) {
/* import the server public key */
Expand Down Expand Up @@ -14766,6 +14835,18 @@ int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen)
TLS_INFO_CONST_STRING_SZ + 1);
XMEMCPY(info + TLS_INFO_CONST_STRING_SZ + 1,
ech->echConfig->raw, ech->echConfig->rawLen);
}
#ifdef HAVE_SECRET_CALLBACK
/* allocate secret buffer for wc_HpkeInitSealContext to copy into */
if (ret == 0 && (ssl->tls13SecretCb != NULL
#ifdef OPENSSL_EXTRA
|| ssl->tls13KeyLogCb != NULL
#endif
)) {
ret = wc_HpkeInitEchSecret(ech->hpke);
}
#endif /* HAVE_SECRET_CALLBACK */
if (ret == 0) {
/* init the context for seal with info and keys */
ret = wc_HpkeInitSealContext(ech->hpke, ech->hpkeContext,
ech->ephemeralKey, receiverPubkey, info, infoLen);
Expand All @@ -14786,6 +14867,15 @@ int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen)
aadLen, ech->innerClientHello,
ech->innerClientHelloLen - ech->hpke->Nt, ech->outerClientPayload);
}

#ifdef HAVE_SECRET_CALLBACK
if (ret == 0 && ech->hpke->echSecret != NULL) {
ret = EchWriteKeyLog(ssl, ech->hpke->echSecret, ech->hpke->Nsecret,
ech->echConfig->raw, ech->echConfig->rawLen);
Comment thread
sebastian-carpenter marked this conversation as resolved.
}
wc_HpkeFreeEchSecret(ech->hpke);
#endif /* HAVE_SECRET_CALLBACK */

if (info != NULL)
XFREE(info, ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (aadCopy != NULL)
Expand All @@ -14804,7 +14894,7 @@ int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen)
#define ECH_PARSE TLSX_ECH_Parse
#define ECH_FREE TLSX_ECH_Free

#endif
#endif /* WOLFSSL_TLS13 && HAVE_ECH */

/** Releases all extensions in the provided list. */
void TLSX_FreeAll(TLSX* list, void* heap)
Expand Down
17 changes: 12 additions & 5 deletions src/tls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -5097,7 +5097,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
return ret;
}
#endif
ret = TLSX_FinalizeEch(args->ech,
ret = TLSX_FinalizeEch(ssl, args->ech,
args->output + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ,
(word32)(args->sendSz - (RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ)));

Expand Down Expand Up @@ -5879,7 +5879,8 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
if (ret != 0)
return ret;
/* use the inner random for client random */
if (args->extMsgType != hello_retry_request) {
if (args->extMsgType != hello_retry_request &&
ssl->options.echAccepted) {
XMEMCPY(ssl->arrays->clientRandom,
ssl->arrays->clientRandomInner, RAN_LEN);
}
Expand Down Expand Up @@ -7452,7 +7453,8 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,

/* From here on we are a TLS 1.3 ClientHello. */

/* Client random */
/* Client random
* ECH Accepted -> This will fill with the innerClientRandom */
XMEMCPY(ssl->arrays->clientRandom, input + args->idx, RAN_LEN);
args->idx += RAN_LEN;

Expand Down Expand Up @@ -13686,8 +13688,7 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
* Only on first inner ClientHello (before HRR), not CH2. */
if (copyRandom) {
XMEMCPY(ssl->arrays->clientRandomInner,
((WOLFSSL_ECH*)echX->data)->innerClientHello +
HANDSHAKE_HEADER_SZ + VERSION_SZ, RAN_LEN);
ssl->arrays->clientRandom, RAN_LEN);
}
*inOutIdx += size;
}
Expand Down Expand Up @@ -16099,6 +16100,12 @@ int tls13ShowSecrets(WOLFSSL* ssl, int id, const unsigned char* secret,
str = "SERVER_TRAFFIC_SECRET_0"; break;
case EXPORTER_SECRET:
str = "EXPORTER_SECRET"; break;
#ifdef HAVE_ECH
case ECH_SECRET:
str = "ECH_SECRET"; break;
case ECH_CONFIG:
str = "ECH_CONFIG"; break;
#endif
default:
#ifdef WOLFSSL_SSLKEYLOGFILE_OUTPUT
XFCLOSE(fp);
Expand Down
Loading
Loading