From 34d7229d4ea09f43dd83dfca64cae26dd4b0e45a Mon Sep 17 00:00:00 2001 From: John Bland Date: Sat, 23 Sep 2023 18:16:06 -0400 Subject: [PATCH 01/19] add functions for using an hpke context multiple times --- wolfcrypt/src/hpke.c | 89 ++++++++++++++++++---------- wolfcrypt/test/test.c | 125 +++++++++++++++++++++++++++++++++++---- wolfssl/wolfcrypt/hpke.h | 9 +++ 3 files changed, 179 insertions(+), 44 deletions(-) diff --git a/wolfcrypt/src/hpke.c b/wolfcrypt/src/hpke.c index 15e8d8569..6502d3bd8 100644 --- a/wolfcrypt/src/hpke.c +++ b/wolfcrypt/src/hpke.c @@ -875,49 +875,63 @@ static int wc_HpkeSetupBaseSender(Hpke* hpke, HpkeBaseContext* context, return ret; } +/* give SetupBaseSender a more intuitive and wolfCrypt friendly name */ +int wc_HpkeInitSealContext(Hpke* hpke, HpkeBaseContext* context, + void* ephemeralKey, void* receiverKey, byte* info, word32 infoSz) +{ + if (hpke == NULL || context == NULL || ephemeralKey == NULL || + receiverKey == NULL || (info == NULL && infoSz > 0)) { + return BAD_FUNC_ARG; + } + + /* zero out all fields */ + XMEMSET(context, 0, sizeof(HpkeBaseContext)); + + return wc_HpkeSetupBaseSender(hpke, context, ephemeralKey, receiverKey, + info, infoSz); +} + /* encrypt a message using an hpke base context, return 0 or error */ -static int wc_HpkeContextSealBase(Hpke* hpke, HpkeBaseContext* context, +int wc_HpkeContextSealBase(Hpke* hpke, HpkeBaseContext* context, byte* aad, word32 aadSz, byte* plaintext, word32 ptSz, byte* out) { int ret; byte nonce[HPKE_Nn_MAX]; #ifndef WOLFSSL_SMALL_STACK - Aes aes_key[1]; + Aes aes[1]; #else - Aes* aes_key; + Aes* aes; #endif - - if (hpke == NULL) { + if (hpke == NULL || context == NULL || (aad == NULL && aadSz > 0) || + plaintext == NULL || out == NULL) { return BAD_FUNC_ARG; } - #ifdef WOLFSSL_SMALL_STACK - aes_key = (Aes*)XMALLOC(sizeof(Aes), hpke->heap, DYNAMIC_TYPE_AES); - if (aes_key == NULL) { + aes = (Aes*)XMALLOC(sizeof(Aes), hpke->heap, DYNAMIC_TYPE_AES); + if (aes == NULL) { return MEMORY_E; } #endif - - ret = wc_AesInit(aes_key, hpke->heap, INVALID_DEVID); + ret = wc_AesInit(aes, hpke->heap, INVALID_DEVID); if (ret == 0) { + /* compute nonce */ ret = wc_HpkeContextComputeNonce(hpke, context, nonce); if (ret == 0) { - ret = wc_AesGcmSetKey(aes_key, context->key, hpke->Nk); + ret = wc_AesGcmSetKey(aes, context->key, hpke->Nk); } if (ret == 0) { - ret = wc_AesGcmEncrypt(aes_key, out, plaintext, ptSz, nonce, + ret = wc_AesGcmEncrypt(aes, out, plaintext, ptSz, nonce, hpke->Nn, out + ptSz, hpke->Nt, aad, aadSz); } + /* increment sequence for non one shot */ if (ret == 0) { context->seq++; } - wc_AesFree(aes_key); + wc_AesFree(aes); } - #ifdef WOLFSSL_SMALL_STACK - XFREE(aes_key, hpke->heap, DYNAMIC_TYPE_AES); + XFREE(aes, hpke->heap, DYNAMIC_TYPE_AES); #endif - return ret; } @@ -1111,49 +1125,60 @@ static int wc_HpkeSetupBaseReceiver(Hpke* hpke, HpkeBaseContext* context, return ret; } +/* give SetupBaseReceiver a more intuitive and wolfCrypt friendly name */ +int wc_HpkeInitOpenContext(Hpke* hpke, HpkeBaseContext* context, + void* receiverKey, const byte* pubKey, word16 pubKeySz, byte* info, + word32 infoSz) +{ + if (hpke == NULL || context == NULL || receiverKey == NULL || pubKey == NULL + || (info == NULL && infoSz > 0)) { + return BAD_FUNC_ARG; + } + + return wc_HpkeSetupBaseReceiver(hpke, context, receiverKey, pubKey, + pubKeySz, info, infoSz); +} + /* decrypt a message using a setup hpke context, return 0 or error */ -static int wc_HpkeContextOpenBase(Hpke* hpke, HpkeBaseContext* context, - byte* aad, word32 aadSz, byte* ciphertext, word32 ctSz, byte* out) +int wc_HpkeContextOpenBase(Hpke* hpke, HpkeBaseContext* context, byte* aad, + word32 aadSz, byte* ciphertext, word32 ctSz, byte* out) { int ret; byte nonce[HPKE_Nn_MAX]; #ifndef WOLFSSL_SMALL_STACK - Aes aes_key[1]; + Aes aes[1]; #else - Aes* aes_key; + Aes* aes; #endif - if (hpke == NULL) { return BAD_FUNC_ARG; } - XMEMSET(nonce, 0, sizeof(nonce)); #ifdef WOLFSSL_SMALL_STACK - aes_key = (Aes*)XMALLOC(sizeof(Aes), hpke->heap, DYNAMIC_TYPE_AES); - if (aes_key == NULL) { + aes = (Aes*)XMALLOC(sizeof(Aes), hpke->heap, DYNAMIC_TYPE_AES); + if (aes == NULL) { return MEMORY_E; } #endif - + /* compute nonce */ ret = wc_HpkeContextComputeNonce(hpke, context, nonce); if (ret == 0) - ret = wc_AesInit(aes_key, hpke->heap, INVALID_DEVID); + ret = wc_AesInit(aes, hpke->heap, INVALID_DEVID); if (ret == 0) { - ret = wc_AesGcmSetKey(aes_key, context->key, hpke->Nk); + ret = wc_AesGcmSetKey(aes, context->key, hpke->Nk); if (ret == 0) { - ret = wc_AesGcmDecrypt(aes_key, out, ciphertext, ctSz, nonce, + ret = wc_AesGcmDecrypt(aes, out, ciphertext, ctSz, nonce, hpke->Nn, ciphertext + ctSz, hpke->Nt, aad, aadSz); } + /* increment sequence for non one shot */ if (ret == 0) { context->seq++; } - wc_AesFree(aes_key); + wc_AesFree(aes); } - #ifdef WOLFSSL_SMALL_STACK - XFREE(aes_key, hpke->heap, DYNAMIC_TYPE_AES); + XFREE(aes, hpke->heap, DYNAMIC_TYPE_AES); #endif - return ret; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index f8bab002b..a43abeaa4 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -25309,6 +25309,106 @@ static wc_test_ret_t hpke_test_single(Hpke* hpke) return ret; } +static wc_test_ret_t hpke_test_multi(Hpke* hpke) +{ + wc_test_ret_t ret = 0; + int rngRet = 0; + WC_RNG rng[1]; + const char* start_text = "this is a test"; + const char* info_text = "info"; + const char* aad_text = "aad"; + byte ciphertexts[2][MAX_HPKE_LABEL_SZ]; + byte plaintext[MAX_HPKE_LABEL_SZ]; + void* receiverKey = NULL; + void* ephemeralKey = NULL; +#ifdef WOLFSSL_SMALL_STACK + HpkeBaseContext* context = NULL; + byte *pubKey = NULL; /* public key */ + word16 pubKeySz = (word16)HPKE_Npk_MAX; +#else + HpkeBaseContext context[1]; + byte pubKey[HPKE_Npk_MAX]; /* public key */ + word16 pubKeySz = (word16)sizeof(pubKey); +#endif + rngRet = ret = wc_InitRng(rng); + if (ret != 0) + return ret; +#ifdef WOLFSSL_SMALL_STACK + pubKey = (byte *)XMALLOC(pubKeySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (pubKey == NULL) + ret = MEMORY_E; + if (ret == 0) { + context = (HpkeBaseContext*)XMALLOC(sizeof(HpkeBaseContext), HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER); + } + if (context == NULL) + ret = MEMORY_E; +#endif + /* generate the keys */ + if (ret == 0) + ret = wc_HpkeGenerateKeyPair(hpke, &ephemeralKey, rng); + if (ret == 0) + ret = wc_HpkeGenerateKeyPair(hpke, &receiverKey, rng); + /* setup seal context */ + if (ret == 0) { + ret = wc_HpkeInitSealContext(hpke, context, ephemeralKey, receiverKey, + (byte*)info_text, (word32)XSTRLEN(info_text)); + } + /* seal message 0 */ + if (ret == 0) { + ret = wc_HpkeContextSealBase(hpke, context, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), + ciphertexts[context->seq]); + } + /* seal message 1 */ + if (ret == 0) { + ret = wc_HpkeContextSealBase(hpke, context, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), + ciphertexts[context->seq]); + } + /* export ephemeral key */ + if (ret == 0) + ret = wc_HpkeSerializePublicKey(hpke, ephemeralKey, pubKey, &pubKeySz); + /* setup open context */ + if (ret == 0) { + ret = wc_HpkeInitOpenContext(hpke, context, receiverKey, pubKey, + pubKeySz, (byte*)info_text, (word32)XSTRLEN(info_text)); + } + /* open message 0 */ + if (ret == 0) { + ret = wc_HpkeContextOpenBase(hpke, context, (byte*)aad_text, + (word32)XSTRLEN(aad_text), ciphertexts[context->seq], + (word32)XSTRLEN(start_text), plaintext); + } + /* check message 0 */ + if (ret == 0) + ret = XMEMCMP(plaintext, start_text, XSTRLEN(start_text)); + /* open message 1 */ + if (ret == 0) { + ret = wc_HpkeContextOpenBase(hpke, context, (byte*)aad_text, + (word32)XSTRLEN(aad_text), ciphertexts[context->seq], + (word32)XSTRLEN(start_text), plaintext); + } + /* check message 1 */ + if (ret == 0) + ret = XMEMCMP(plaintext, start_text, XSTRLEN(start_text)); + if (ephemeralKey != NULL) + wc_HpkeFreeKey(hpke, hpke->kem, ephemeralKey, hpke->heap); + if (receiverKey != NULL) + wc_HpkeFreeKey(hpke, hpke->kem, receiverKey, hpke->heap); +#ifdef WOLFSSL_SMALL_STACK + if (pubKey != NULL) + XFREE(pubKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (context != NULL) + XFREE(context, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif + if (rngRet == 0) + wc_FreeRng(rng); + return ret; +} + WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) { wc_test_ret_t ret = 0; @@ -25319,14 +25419,15 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) /* p256 */ ret = wc_HpkeInit(hpke, DHKEM_P256_HKDF_SHA256, HKDF_SHA256, HPKE_AES_128_GCM, NULL); - if (ret != 0) return WC_TEST_RET_ENC_EC(ret); - ret = hpke_test_single(hpke); - if (ret != 0) return ret; + ret = hpke_test_multi(hpke); + if (ret != 0) + return ret; + #endif #if defined(WOLFSSL_SHA384) && \ @@ -25334,12 +25435,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) /* p384 */ ret = wc_HpkeInit(hpke, DHKEM_P384_HKDF_SHA384, HKDF_SHA384, HPKE_AES_128_GCM, NULL); - if (ret != 0) return WC_TEST_RET_ENC_EC(ret); - ret = hpke_test_single(hpke); - + if (ret != 0) + return ret; + ret = hpke_test_multi(hpke); if (ret != 0) return ret; #endif @@ -25349,12 +25450,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) /* p521 */ ret = wc_HpkeInit(hpke, DHKEM_P521_HKDF_SHA512, HKDF_SHA512, HPKE_AES_128_GCM, NULL); - if (ret != 0) return WC_TEST_RET_ENC_EC(ret); - ret = hpke_test_single(hpke); - + if (ret != 0) + return ret; + ret = hpke_test_multi(hpke); if (ret != 0) return ret; #endif @@ -25364,12 +25465,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) /* test with curve25519 and aes256 */ ret = wc_HpkeInit(hpke, DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, HPKE_AES_256_GCM, NULL); - if (ret != 0) return WC_TEST_RET_ENC_EC(ret); - ret = hpke_test_single(hpke); - + if (ret != 0) + return ret; + ret = hpke_test_multi(hpke); if (ret != 0) return ret; #endif diff --git a/wolfssl/wolfcrypt/hpke.h b/wolfssl/wolfcrypt/hpke.h index 432f574da..3e6b43c37 100644 --- a/wolfssl/wolfcrypt/hpke.h +++ b/wolfssl/wolfcrypt/hpke.h @@ -120,9 +120,18 @@ WOLFSSL_API int wc_HpkeDeserializePublicKey(Hpke* hpke, void** key, const byte* in, word16 inSz); WOLFSSL_API void wc_HpkeFreeKey(Hpke* hpke, word16 kem, void* keypair, void* heap); +WOLFSSL_API int wc_HpkeInitSealContext(Hpke* hpke, HpkeBaseContext* context, + void* ephemeralKey, void* receiverKey, byte* info, word32 infoSz); +WOLFSSL_API int wc_HpkeContextSealBase(Hpke* hpke, HpkeBaseContext* context, + byte* aad, word32 aadSz, byte* plaintext, word32 ptSz, byte* out); WOLFSSL_API int wc_HpkeSealBase(Hpke* hpke, void* ephemeralKey, void* receiverKey, byte* info, word32 infoSz, byte* aad, word32 aadSz, byte* plaintext, word32 ptSz, byte* ciphertext); +WOLFSSL_API int wc_HpkeInitOpenContext(Hpke* hpke, HpkeBaseContext* context, + void* receiverKey, const byte* pubKey, word16 pubKeySz, byte* info, + word32 infoSz); +WOLFSSL_API int wc_HpkeContextOpenBase(Hpke* hpke, HpkeBaseContext* context, + byte* aad, word32 aadSz, byte* ciphertext, word32 ctSz, byte* out); WOLFSSL_API int wc_HpkeOpenBase(Hpke* hpke, void* receiverKey, const byte* pubKey, word16 pubKeySz, byte* info, word32 infoSz, byte* aad, word32 aadSz, byte* ciphertext, word32 ctSz, byte* plaintext); From 83d722523604d4886ee250e71506edf6eee1424c Mon Sep 17 00:00:00 2001 From: John Bland Date: Sun, 24 Sep 2023 17:39:35 -0400 Subject: [PATCH 02/19] update ech to use multi use hpke context, still doesn' handle HRR --- src/tls.c | 270 +++++++++++++++++++-------------------------- wolfssl/internal.h | 1 + 2 files changed, 114 insertions(+), 157 deletions(-) diff --git a/src/tls.c b/src/tls.c index 48d76dfa2..ea3c423c4 100644 --- a/src/tls.c +++ b/src/tls.c @@ -11360,40 +11360,29 @@ static int TLSX_ECH_Use(WOLFSSL_EchConfig* echConfig, TLSX** extensions, int ret = 0; int suiteIndex; WOLFSSL_ECH* ech; - if (extensions == NULL) return BAD_FUNC_ARG; - /* find a supported cipher suite */ suiteIndex = EchConfigGetSupportedCipherSuite(echConfig); - if (suiteIndex < 0) return suiteIndex; - ech = (WOLFSSL_ECH*)XMALLOC(sizeof(WOLFSSL_ECH), heap, DYNAMIC_TYPE_TMP_BUFFER); - if (ech == NULL) return MEMORY_E; - ForceZero(ech, sizeof(WOLFSSL_ECH)); - ech->state = ECH_WRITE_REAL; - ech->echConfig = echConfig; - /* 0 for outer */ ech->type = ECH_TYPE_OUTER; /* kemId */ ech->kemId = echConfig->kemId; - /* cipherSuite kdf */ ech->cipherSuite.kdfId = echConfig->cipherSuites[suiteIndex].kdfId; /* cipherSuite aead */ ech->cipherSuite.aeadId = echConfig->cipherSuites[suiteIndex].aeadId; /* configId */ ech->configId = echConfig->configId; - /* encLen */ switch (echConfig->kemId) { @@ -11413,30 +11402,23 @@ static int TLSX_ECH_Use(WOLFSSL_EchConfig* echConfig, TLSX** extensions, ech->encLen = DHKEM_X448_ENC_LEN; break; } - /* setup hpke */ ech->hpke = (Hpke*)XMALLOC(sizeof(Hpke), heap, DYNAMIC_TYPE_TMP_BUFFER); - if (ech->hpke == NULL) { XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } - ret = wc_HpkeInit(ech->hpke, ech->kemId, ech->cipherSuite.kdfId, ech->cipherSuite.aeadId, heap); - /* setup the ephemeralKey */ if (ret == 0) ret = wc_HpkeGenerateKeyPair(ech->hpke, &ech->ephemeralKey, rng); - if (ret == 0) ret = TLSX_Push(extensions, TLSX_ECH, ech, heap); - if (ret != 0) { XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER); } - return ret; } @@ -11447,36 +11429,25 @@ static int TLSX_ServerECH_Use(TLSX** extensions, void* heap, int ret; WOLFSSL_ECH* ech; TLSX* echX; - if (extensions == NULL) return BAD_FUNC_ARG; - /* if we already have ech don't override it */ echX = TLSX_Find(*extensions, TLSX_ECH); if (echX != NULL) return 0; - ech = (WOLFSSL_ECH*)XMALLOC(sizeof(WOLFSSL_ECH), heap, DYNAMIC_TYPE_TMP_BUFFER); - if (ech == NULL) return MEMORY_E; - ForceZero(ech, sizeof(WOLFSSL_ECH)); - ech->state = ECH_WRITE_NONE; - /* 0 for outer */ ech->type = ECH_TYPE_OUTER; - ech->echConfig = configs; - /* setup the rest of the settings when we receive ech from the client */ ret = TLSX_Push(extensions, TLSX_ECH, ech, heap); - if (ret != 0) XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER); - return ret; } @@ -11495,84 +11466,62 @@ static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte* writeBuf, word16* offset) Hpke hpke[1]; WC_RNG rng[1]; #endif - WOLFSSL_MSG("TLSX_ECH_Write"); - if (ech->state == ECH_WRITE_NONE || ech->state == ECH_PARSED_INTERNAL) return 0; - if (ech->state == ECH_WRITE_RETRY_CONFIGS) { /* get size then write */ ret = GetEchConfigsEx(ech->echConfig, NULL, &configsLen); - if (ret != LENGTH_ONLY_E) return ret; - ret = GetEchConfigsEx(ech->echConfig, writeBuf, &configsLen); - if (ret != WOLFSSL_SUCCESS) return ret; - *offset += configsLen; - return 0; } - -#ifdef WOLFSSL_SMALL_STACK - hpke = (Hpke*)XMALLOC(sizeof(Hpke), NULL, DYNAMIC_TYPE_TMP_BUFFER); - - if (hpke == NULL) - return MEMORY_E; - - rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); - - if (rng == NULL) { - XFREE(hpke, NULL, DYNAMIC_TYPE_RNG); - return MEMORY_E; - } -#endif - /* type */ *writeBuf_p = ech->type; writeBuf_p += sizeof(ech->type); - /* outer has body, inner does not */ if (ech->type == ECH_TYPE_OUTER) { /* kdfId */ c16toa(ech->cipherSuite.kdfId, writeBuf_p); writeBuf_p += sizeof(ech->cipherSuite.kdfId); - /* aeadId */ c16toa(ech->cipherSuite.aeadId, writeBuf_p); writeBuf_p += sizeof(ech->cipherSuite.aeadId); - /* configId */ *writeBuf_p = ech->configId; writeBuf_p += sizeof(ech->configId); - /* encLen */ c16toa(ech->encLen, writeBuf_p); writeBuf_p += 2; - if (ech->state == ECH_WRITE_GREASE) { +#ifdef WOLFSSL_SMALL_STACK + hpke = (Hpke*)XMALLOC(sizeof(Hpke), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (hpke == NULL) + return MEMORY_E; + rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (rng == NULL) { + XFREE(hpke, NULL, DYNAMIC_TYPE_RNG); + return MEMORY_E; + } +#endif /* hpke init */ ret = wc_HpkeInit(hpke, ech->kemId, ech->cipherSuite.kdfId, ech->cipherSuite.aeadId, NULL); - if (ret == 0) rngRet = ret = wc_InitRng(rng); - /* create the ephemeralKey */ if (ret == 0) ret = wc_HpkeGenerateKeyPair(hpke, &ephemeralKey, rng); - /* enc */ if (ret == 0) { ret = wc_HpkeSerializePublicKey(hpke, ephemeralKey, writeBuf_p, &ech->encLen); writeBuf_p += ech->encLen; } - if (ret == 0) { /* innerClientHelloLen */ c16toa(GREASE_ECH_SIZE + ((writeBuf_p + 2 - writeBuf) % 32), @@ -11584,40 +11533,32 @@ static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte* writeBuf, word16* offset) ((writeBuf_p - writeBuf) % 32)); writeBuf_p += GREASE_ECH_SIZE + ((writeBuf_p - writeBuf) % 32); } - if (rngRet == 0) wc_FreeRng(rng); - if (ephemeralKey != NULL) wc_HpkeFreeKey(hpke, hpke->kem, ephemeralKey, hpke->heap); +#ifdef WOLFSSL_SMALL_STACK + XFREE(hpke, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rng, NULL, DYNAMIC_TYPE_RNG); +#endif } else { /* write enc to writeBuf_p */ ret = wc_HpkeSerializePublicKey(ech->hpke, ech->ephemeralKey, writeBuf_p, &ech->encLen); writeBuf_p += ech->encLen; - /* innerClientHelloLen */ c16toa(ech->innerClientHelloLen, writeBuf_p); writeBuf_p += 2; - /* set payload offset for when we finalize */ ech->outerClientPayload = writeBuf_p; - /* write zeros for payload */ XMEMSET(writeBuf_p, 0, ech->innerClientHelloLen); writeBuf_p += ech->innerClientHelloLen; } } - -#ifdef WOLFSSL_SMALL_STACK - XFREE(hpke, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(rng, NULL, DYNAMIC_TYPE_RNG); -#endif - if (ret == 0) *offset += (writeBuf_p - writeBuf); - return ret; } @@ -11671,10 +11612,8 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig, word32 rawConfigLen = 0; byte* info = NULL; word32 infoLen = 0; - if (ech == NULL || echConfig == NULL || aad == NULL) return BAD_FUNC_ARG; - /* verify the kem and key len */ switch (echConfig->kemId) { @@ -11697,10 +11636,8 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig, expectedEncLen = 0; break; } - if (expectedEncLen != ech->encLen) return BAD_FUNC_ARG; - /* verify the cipher suite */ for (i = 0; i < echConfig->numCipherSuites; i++) { if (echConfig->cipherSuites[i].kdfId == ech->cipherSuite.kdfId && @@ -11708,56 +11645,68 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig, break; } } - if (i >= echConfig->numCipherSuites) { return BAD_FUNC_ARG; } - - ech->hpke = (Hpke*)XMALLOC(sizeof(Hpke), heap, DYNAMIC_TYPE_TMP_BUFFER); - - if (ech->hpke == NULL) - return MEMORY_E; - - ret = wc_HpkeInit(ech->hpke, echConfig->kemId, ech->cipherSuite.kdfId, - ech->cipherSuite.aeadId, heap); - - /* get the rawConfigLen */ - if (ret == 0) - ret = GetEchConfig(echConfig, NULL, &rawConfigLen); - - if (ret == LENGTH_ONLY_E) - ret = 0; - - /* create info */ - if (ret == 0) { - infoLen = TLS_INFO_CONST_STRING_SZ + 1 + rawConfigLen; - info = (byte*)XMALLOC(infoLen, heap, DYNAMIC_TYPE_TMP_BUFFER); - - if (info == NULL) + /* check if hpke already exists, may if HelloRetryRequest */ + if (ech->hpke == NULL) { + ech->hpke = (Hpke*)XMALLOC(sizeof(Hpke), heap, DYNAMIC_TYPE_TMP_BUFFER); + if (ech->hpke == NULL) ret = MEMORY_E; - else { - XMEMCPY(info, (byte*)TLS_INFO_CONST_STRING, - TLS_INFO_CONST_STRING_SZ + 1); - ret = GetEchConfig(echConfig, info + - TLS_INFO_CONST_STRING_SZ + 1, &rawConfigLen); + /* init the hpke struct */ + if (ret == 0) { + ret = wc_HpkeInit(ech->hpke, echConfig->kemId, + ech->cipherSuite.kdfId, ech->cipherSuite.aeadId, heap); + } + if (ret == 0) { + /* allocate hpkeContext */ + ech->hpkeContext = + (HpkeBaseContext*)XMALLOC(sizeof(HpkeBaseContext), + ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (ech->hpkeContext == NULL) + ret = MEMORY_E; + } + /* get the rawConfigLen */ + if (ret == 0) + ret = GetEchConfig(echConfig, NULL, &rawConfigLen); + if (ret == LENGTH_ONLY_E) + ret = 0; + /* create info */ + if (ret == 0) { + infoLen = TLS_INFO_CONST_STRING_SZ + 1 + rawConfigLen; + info = (byte*)XMALLOC(infoLen, heap, DYNAMIC_TYPE_TMP_BUFFER); + + if (info == NULL) + ret = MEMORY_E; + else { + XMEMCPY(info, (byte*)TLS_INFO_CONST_STRING, + TLS_INFO_CONST_STRING_SZ + 1); + ret = GetEchConfig(echConfig, info + + TLS_INFO_CONST_STRING_SZ + 1, &rawConfigLen); + } + } + /* init the context for opening */ + if (ret == 0) { + ret = wc_HpkeInitOpenContext(ech->hpke, ech->hpkeContext, + echConfig->receiverPrivkey, ech->enc, ech->encLen, info, + infoLen); } } - /* decrypt the ech payload */ - if (ret == 0) - ret = wc_HpkeOpenBase(ech->hpke, echConfig->receiverPrivkey, ech->enc, - ech->encLen, info, infoLen, aad, aadLen, ech->outerClientPayload, - ech->innerClientHelloLen, + if (ret == 0) { + ret = wc_HpkeContextOpenBase(ech->hpke, ech->hpkeContext, aad, aadLen, + ech->outerClientPayload, ech->innerClientHelloLen, ech->innerClientHello + HANDSHAKE_HEADER_SZ); - + } + /* free the hpke and context on failure */ if (ret != 0) { XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER); ech->hpke = NULL; + XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER); + ech->hpkeContext = NULL; } - if (info != NULL) XFREE(info, heap, DYNAMIC_TYPE_TMP_BUFFER); - return ret; } @@ -11882,7 +11831,7 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size, } } - /* if we failed to extract */ + /* if we failed to extract, set state to retry configs */ if (ret != 0) { XFREE(ech->innerClientHello, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); ech->innerClientHello = NULL; @@ -11928,58 +11877,65 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap) * status */ int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen) { - int ret; + int ret = 0; void* receiverPubkey = NULL; - byte* info; + byte* info = NULL; int infoLen; - byte* aadCopy; - - /* import the server public key */ - ret = wc_HpkeDeserializePublicKey(ech->hpke, &receiverPubkey, - ech->echConfig->receiverPubkey, ech->encLen); - - if (ret == 0) { - /* create info */ - infoLen = TLS_INFO_CONST_STRING_SZ + 1 + ech->echConfig->rawLen; - info = (byte*)XMALLOC(infoLen, ech->hpke->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (info == NULL) - ret = MEMORY_E; - + byte* aadCopy = NULL; + /* setup hpke context to seal, should be done at most once per connection */ + if (ech->hpkeContext == NULL) { + /* import the server public key */ + ret = wc_HpkeDeserializePublicKey(ech->hpke, &receiverPubkey, + ech->echConfig->receiverPubkey, ech->encLen); + if (ret == 0) { + /* allocate hpke context */ + ech->hpkeContext = + (HpkeBaseContext*)XMALLOC(sizeof(HpkeBaseContext), + ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (ech->hpkeContext == NULL) + ret = MEMORY_E; + } + if (ret == 0) { + /* create info */ + infoLen = TLS_INFO_CONST_STRING_SZ + 1 + ech->echConfig->rawLen; + info = (byte*)XMALLOC(infoLen, ech->hpke->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (info == NULL) + ret = MEMORY_E; + } if (ret == 0) { /* puts the null byte in for me */ - XMEMCPY(info, (byte*)TLS_INFO_CONST_STRING, TLS_INFO_CONST_STRING_SZ - + 1); - XMEMCPY(info + TLS_INFO_CONST_STRING_SZ + 1, ech->echConfig->raw, - ech->echConfig->rawLen); - - /* make a copy of the aad since we overwrite it */ - aadCopy = (byte*)XMALLOC(aadLen, ech->hpke->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (aadCopy == NULL) { - XFREE(info, ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); - ret = MEMORY_E; - } - } - - if (ret == 0) { - XMEMCPY(aadCopy, aad, aadLen); - - /* seal the payload */ - ret = wc_HpkeSealBase(ech->hpke, ech->ephemeralKey, receiverPubkey, - info, infoLen, aadCopy, aadLen, ech->innerClientHello, - ech->innerClientHelloLen - ech->hpke->Nt, - ech->outerClientPayload); - - XFREE(info, ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(aadCopy, ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); + XMEMCPY(info, (byte*)TLS_INFO_CONST_STRING, + TLS_INFO_CONST_STRING_SZ + 1); + XMEMCPY(info + TLS_INFO_CONST_STRING_SZ + 1, + ech->echConfig->raw, ech->echConfig->rawLen); + /* init the context for seal with info and keys */ + ret = wc_HpkeInitSealContext(ech->hpke, ech->hpkeContext, + ech->ephemeralKey, receiverPubkey, info, infoLen); } } - + if (ret == 0) { + /* make a copy of the aad since we overwrite it */ + aadCopy = (byte*)XMALLOC(aadLen, ech->hpke->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (aadCopy == NULL) { + ret = MEMORY_E; + } + } + if (ret == 0) { + XMEMCPY(aadCopy, aad, aadLen); + /* seal the payload with context */ + ret = wc_HpkeContextSealBase(ech->hpke, ech->hpkeContext, aadCopy, + aadLen, ech->innerClientHello, + ech->innerClientHelloLen - ech->hpke->Nt, ech->outerClientPayload); + } + if (info != NULL) + XFREE(info, ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (aadCopy != NULL) + XFREE(aadCopy, ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); if (receiverPubkey != NULL) wc_HpkeFreeKey(ech->hpke, ech->hpke->kem, receiverPubkey, ech->hpke->heap); - return ret; } diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 0afd04b95..271f55bee 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2920,6 +2920,7 @@ typedef struct WOLFSSL_EchConfig { typedef struct WOLFSSL_ECH { Hpke* hpke; + HpkeBaseContext* hpkeContext; const byte* aad; void* ephemeralKey; WOLFSSL_EchConfig* echConfig; From 037c44609d9e8e554e8d276521043fdbb2fb4965 Mon Sep 17 00:00:00 2001 From: John Bland Date: Mon, 25 Sep 2023 01:48:58 -0400 Subject: [PATCH 03/19] refactor ECH code to handle hrr with special confirmation --- src/tls.c | 84 ++++++++++++++-------------- src/tls13.c | 135 ++++++++++++++++++++++++++------------------- wolfssl/internal.h | 2 + 3 files changed, 123 insertions(+), 98 deletions(-) diff --git a/src/tls.c b/src/tls.c index ea3c423c4..586713386 100644 --- a/src/tls.c +++ b/src/tls.c @@ -11451,8 +11451,9 @@ static int TLSX_ServerECH_Use(TLSX** extensions, void* heap, return ret; } -/* return length after writing the ech */ -static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte* writeBuf, word16* offset) +/* return status after writing the ech and updating offset */ +static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte msgType, byte* writeBuf, + word16* offset) { int ret = 0; int rngRet = -1; @@ -11467,6 +11468,13 @@ static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte* writeBuf, word16* offset) WC_RNG rng[1]; #endif WOLFSSL_MSG("TLSX_ECH_Write"); + if (msgType == hello_retry_request) { + /* reserve space to write the confirmation to */ + *offset += ECH_ACCEPT_CONFIRMATION_SZ; + /* set confBuf */ + ech->confBuf = writeBuf; + return 0; + } if (ech->state == ECH_WRITE_NONE || ech->state == ECH_PARSED_INTERNAL) return 0; if (ech->state == ECH_WRITE_RETRY_CONFIGS) { @@ -11543,9 +11551,15 @@ static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte* writeBuf, word16* offset) #endif } else { - /* write enc to writeBuf_p */ - ret = wc_HpkeSerializePublicKey(ech->hpke, ech->ephemeralKey, - writeBuf_p, &ech->encLen); + /* set to emptry string on hrr */ + if (msgType == hello_retry_request) { + XMEMSET(writeBuf_p, 0, ech->encLen); + } + else { + /* write enc to writeBuf_p */ + ret = wc_HpkeSerializePublicKey(ech->hpke, ech->ephemeralKey, + writeBuf_p, &ech->encLen); + } writeBuf_p += ech->encLen; /* innerClientHelloLen */ c16toa(ech->innerClientHelloLen, writeBuf_p); @@ -11722,89 +11736,85 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size, WOLFSSL_EchConfig* echConfig; byte* aadCopy; byte* readBuf_p = (byte*)readBuf; - WOLFSSL_MSG("TLSX_ECH_Parse"); - if (size == 0) return BAD_FUNC_ARG; - + /* retry configs */ if (msgType == encrypted_extensions) { ret = wolfSSL_SetEchConfigs(ssl, readBuf, size); if (ret == WOLFSSL_SUCCESS) ret = 0; } - else if (msgType == client_hello && ssl->ctx->echConfigs != NULL) { + /* HRR with special confirmation */ + else if (msgType == hello_retry_request && ssl->options.useEch) { + /* length must be 8 */ + if (size != ECH_ACCEPT_CONFIRMATION_SZ) + return BAD_FUNC_ARG; + /* get extension */ + echX = TLSX_Find(ssl->extensions, TLSX_ECH); + if (echX == NULL) + return BAD_FUNC_ARG; + ech = (WOLFSSL_ECH*)echX->data; + ech->confBuf = (byte*)readBuf; + } + else if (msgType == client_hello && ssl->ctx->echConfigs != NULL) { + /* get extension */ echX = TLSX_Find(ssl->extensions, TLSX_ECH); - if (echX == NULL) return BAD_FUNC_ARG; - ech = (WOLFSSL_ECH*)echX->data; - /* read the ech parameters before the payload */ ech->type = *readBuf_p; readBuf_p++; - if (ech->type == ECH_TYPE_INNER) { ech->state = ECH_PARSED_INTERNAL; return 0; } - /* technically the payload would only be 1 byte at this length */ if (size < 11 + ech->encLen) return BAD_FUNC_ARG; - + /* read kdfId */ ato16(readBuf_p, &ech->cipherSuite.kdfId); readBuf_p += 2; - + /* read aeadId */ ato16(readBuf_p, &ech->cipherSuite.aeadId); readBuf_p += 2; - + /* read configId */ ech->configId = *readBuf_p; readBuf_p++; - + /* read encLen */ ato16(readBuf_p, &ech->encLen); readBuf_p += 2; - if (ech->encLen > HPKE_Npk_MAX) return BAD_FUNC_ARG; - + /* read enc */ XMEMCPY(ech->enc, readBuf_p, ech->encLen); readBuf_p += ech->encLen; - + /* read hello inner len */ ato16(readBuf_p, &ech->innerClientHelloLen); ech->innerClientHelloLen -= AES_BLOCK_SIZE; readBuf_p += 2; - ech->outerClientPayload = readBuf_p; - /* make a copy of the aad */ aadCopy = (byte*)XMALLOC(ech->aadLen, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (aadCopy == NULL) return MEMORY_E; - XMEMCPY(aadCopy, ech->aad, ech->aadLen); - /* set the ech payload of the copy to zeros */ XMEMSET(aadCopy + (readBuf_p - ech->aad), 0, ech->innerClientHelloLen + AES_BLOCK_SIZE); - /* allocate the inner payload buffer */ ech->innerClientHello = (byte*)XMALLOC(ech->innerClientHelloLen + HANDSHAKE_HEADER_SZ, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (ech->innerClientHello == NULL) { XFREE(aadCopy, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } - /* first check if the config id matches */ echConfig = ssl->ctx->echConfigs; - while (echConfig != NULL) { /* decrypt with this config */ if (echConfig->configId == ech->configId) { @@ -11812,25 +11822,19 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size, ssl->heap); break; } - echConfig = echConfig->next; } - /* try to decrypt with all configs */ if (echConfig == NULL || ret != 0) { echConfig = ssl->ctx->echConfigs; - while (echConfig != NULL) { ret = TLSX_ExtractEch(ech, echConfig, aadCopy, ech->aadLen, ssl->heap); - if (ret== 0) break; - echConfig = echConfig->next; } } - /* if we failed to extract, set state to retry configs */ if (ret != 0) { XFREE(ech->innerClientHello, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -11839,19 +11843,15 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size, } else { i = 0; - /* decrement until before the padding */ while (ech->innerClientHello[ech->innerClientHelloLen + HANDSHAKE_HEADER_SZ - i - 1] != ECH_TYPE_INNER) { i++; } - /* subtract the length of the padding from the length */ ech->innerClientHelloLen -= i; } - XFREE(aadCopy, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - return 0; } @@ -11868,6 +11868,8 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap) ech->hpke->heap); if (ech->hpke != NULL) XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER); + if (ech->hpkeContext != NULL) + XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER); (void)heap; @@ -12536,7 +12538,7 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) case TLSX_ECH: WOLFSSL_MSG("ECH extension to write"); - ret = ECH_WRITE((WOLFSSL_ECH*)extension->data, + ret = ECH_WRITE((WOLFSSL_ECH*)extension->data, msgType, output + offset, &offset); break; #endif diff --git a/src/tls13.c b/src/tls13.c index eb4618075..db28de812 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -170,11 +170,14 @@ static const byte dtls13ProtocolLabel[DTLS13_PROTOCOL_LABEL_SZ + 1] = "dtls13"; #endif /* WOLFSSL_DTLS13 */ #if defined(HAVE_ECH) -#define ECH_ACCEPT_CONFIRMATION_SZ 8 #define ECH_ACCEPT_CONFIRMATION_LABEL_SZ 23 +#define ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ 27 static const byte echAcceptConfirmationLabel[ECH_ACCEPT_CONFIRMATION_LABEL_SZ + 1] = "ech accept confirmation"; +static const byte + echHrrAcceptConfirmationLabel[ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ + 1] = + "hrr ech accept confirmation"; #endif #ifndef NO_CERTS @@ -4719,8 +4722,8 @@ static int Dtls13DoDowngrade(WOLFSSL* ssl) #if defined(HAVE_ECH) /* check if the server accepted ech or not */ -static int EchCheckAcceptance(WOLFSSL* ssl, const byte* input, - int serverRandomOffset, int helloSz) +static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, + const byte* input, int acceptOffset, int helloSz) { int ret = 0; int digestType; @@ -4742,15 +4745,15 @@ static int EchCheckAcceptance(WOLFSSL* ssl, const byte* input, ssl->hsHashes = acceptHashes; /* hash up to the last 8 bytes */ if (ret == 0) - ret = HashRaw(ssl, input, serverRandomOffset + RAN_LEN - - ECH_ACCEPT_CONFIRMATION_SZ); + ret = HashRaw(ssl, input, acceptOffset); /* hash 8 zeros */ if (ret == 0) ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ); /* hash the rest of the hello */ if (ret == 0) { - ret = HashRaw(ssl, input + serverRandomOffset + RAN_LEN, - helloSz + HANDSHAKE_HEADER_SZ - (serverRandomOffset + RAN_LEN)); + ret = HashRaw(ssl, input + acceptOffset + ECH_ACCEPT_CONFIRMATION_SZ, + helloSz + HANDSHAKE_HEADER_SZ - + (acceptOffset + ECH_ACCEPT_CONFIRMATION_SZ)); } /* get the modified transcript hash */ if (ret == 0) @@ -4816,14 +4819,10 @@ static int EchCheckAcceptance(WOLFSSL* ssl, const byte* input, } if (ret == 0) { /* last 8 bytes should match our expand output */ - ret = XMEMCMP(acceptConfirmation, - ssl->arrays->serverRandom + RAN_LEN - ECH_ACCEPT_CONFIRMATION_SZ, + ret = XMEMCMP(acceptConfirmation, input + acceptOffset, ECH_ACCEPT_CONFIRMATION_SZ); /* ech accepted */ if (ret == 0) { - /* use the inner random for client random */ - XMEMCPY(ssl->arrays->clientRandom, ssl->arrays->clientRandomInner, - RAN_LEN); /* switch back to original hsHashes to free */ ssl->hsHashes = tmpHashes; /* set the final hsHashes to the ech hashes */ @@ -4850,10 +4849,10 @@ static int EchCheckAcceptance(WOLFSSL* ssl, const byte* input, return ret; } -/* replace the last 8 bytes of the server random with the ech acceptance - * parameter, return status */ -static int EchWriteAcceptance(WOLFSSL* ssl, byte* output, - int serverRandomOffset, int helloSz) +/* replace the last acceptance field for either sever hello or hrr with the ech + * acceptance parameter, return status */ +static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, + byte* output, int acceptOffset, int helloSz) { int ret = 0; int digestType; @@ -4866,37 +4865,30 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* output, XMEMSET(zeros, 0, sizeof(zeros)); XMEMSET(transcriptEchConf, 0, sizeof(transcriptEchConf)); XMEMSET(expandLabelPrk, 0, sizeof(expandLabelPrk)); - /* copy ech hashes to accept */ ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, &acceptHashes); - - /* swap hsHashes to acceptHashes */ - tmpHashes = ssl->hsHashes; - ssl->hsHashes = acceptHashes; - - /* hash up to the last 8 bytes */ - if (ret == 0) - ret = HashRaw(ssl, output, serverRandomOffset + RAN_LEN - - ECH_ACCEPT_CONFIRMATION_SZ); - + if (ret == 0) { + /* swap hsHashes to acceptHashes */ + tmpHashes = ssl->hsHashes; + ssl->hsHashes = acceptHashes; + /* hash up to the acceptOffset */ + ret = HashRaw(ssl, output, acceptOffset); + } /* hash 8 zeros */ if (ret == 0) - ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ); - + ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ); /* hash the rest of the hello */ - if (ret == 0) - ret = HashRaw(ssl, output + serverRandomOffset + RAN_LEN, - helloSz - (serverRandomOffset + RAN_LEN)); - + if (ret == 0) { + ret = HashRaw(ssl, output + acceptOffset + ECH_ACCEPT_CONFIRMATION_SZ, + helloSz - (acceptOffset + ECH_ACCEPT_CONFIRMATION_SZ)); + } /* get the modified transcript hash */ if (ret == 0) ret = GetMsgHash(ssl, transcriptEchConf); - if (ret > 0) ret = 0; - /* pick the right type and size based on mac_algorithm */ - if (ret == 0) + if (ret == 0) { switch (ssl->specs.mac_algorithm) { #ifndef NO_SHA256 case sha256_mac: @@ -4926,7 +4918,7 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* output, ret = -1; break; } - + } /* extract clientRandom with a key of all zeros */ if (ret == 0) { PRIVATE_KEY_UNLOCK(); @@ -4941,7 +4933,6 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* output, #endif PRIVATE_KEY_LOCK(); } - /* tls expand with the confirmation label */ if (ret == 0) { PRIVATE_KEY_UNLOCK(); @@ -4954,16 +4945,9 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* output, transcriptEchConf, digestSize, digestType, WOLFSSL_SERVER_END); PRIVATE_KEY_LOCK(); } - - if (ret == 0) - XMEMCPY(ssl->arrays->serverRandom, output + serverRandomOffset, - RAN_LEN); - /* free acceptHashes */ FreeHandshakeHashes(ssl); - ssl->hsHashes = tmpHashes; - return ret; } #endif @@ -4989,7 +4973,9 @@ typedef struct Dsh13Args { byte sessIdSz; byte extMsgType; #if defined(HAVE_ECH) - int serverRandomOffset; + byte* acceptLabel; + word32 acceptOffset; + word16 acceptLabelSz; #endif } Dsh13Args; @@ -5146,7 +5132,8 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* Server random - keep for debugging. */ XMEMCPY(ssl->arrays->serverRandom, input + args->idx, RAN_LEN); #if defined(HAVE_ECH) - args->serverRandomOffset = args->idx; + /* last 8 bytes of server random */ + args->acceptOffset = args->idx + RAN_LEN - ECH_ACCEPT_CONFIRMATION_SZ; #endif args->idx += RAN_LEN; @@ -5432,11 +5419,30 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return ret; #if defined(HAVE_ECH) + TLSX* echX = NULL; /* check for acceptConfirmation and HashInput with 8 0 bytes */ if (ssl->options.useEch == 1) { - ret = EchCheckAcceptance(ssl, input, args->serverRandomOffset, helloSz); + echX = TLSX_Find(ssl->extensions, TLSX_ECH); + /* account for hrr */ + if (args->extMsgType == hello_retry_request) { + args->acceptOffset = ((WOLFSSL_ECH*)echX->data)->confBuf - input; + args->acceptLabel = (byte*)echHrrAcceptConfirmationLabel; + args->acceptLabelSz = ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ; + } + else { + args->acceptLabel = (byte*)echAcceptConfirmationLabel; + args->acceptLabelSz = ECH_ACCEPT_CONFIRMATION_LABEL_SZ; + } + /* check acceptance */ + ret = EchCheckAcceptance(ssl, args->acceptLabel, args->acceptLabelSz, + input, args->acceptOffset, helloSz); if (ret != 0) return ret; + /* use the inner random for client random */ + if (args->extMsgType != hello_retry_request) { + XMEMCPY(ssl->arrays->clientRandom, ssl->arrays->clientRandomInner, + RAN_LEN); + } } #endif @@ -7236,7 +7242,9 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) int sendSz; #if defined(HAVE_ECH) TLSX* echX = NULL; - word32 serverRandomOffset; + byte* acceptLabel = (byte*)echAcceptConfirmationLabel; + word32 acceptOffset; + word16 acceptLabelSz = ECH_ACCEPT_CONFIRMATION_LABEL_SZ; #endif WOLFSSL_START(WC_FUNC_SERVER_HELLO_SEND); @@ -7295,7 +7303,8 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) } #if defined(HAVE_ECH) - serverRandomOffset = idx; + /* last 8 bytes of server random */ + acceptOffset = idx + RAN_LEN - ECH_ACCEPT_CONFIRMATION_SZ; #endif /* Store in SSL for debugging. */ @@ -7359,18 +7368,30 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) #if defined(HAVE_ECH) if (ssl->ctx->echConfigs != NULL) { echX = TLSX_Find(ssl->extensions, TLSX_ECH); - if (echX == NULL) return -1; - + /* use normal offset instead of hrr offset */ + if (extMsgType == hello_retry_request) { + acceptOffset = ((WOLFSSL_ECH*)echX->data)->confBuf - output; + acceptLabel = (byte*)echHrrAcceptConfirmationLabel; + acceptLabelSz = ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ; + } /* replace the last 8 bytes of server random with the accept */ if (((WOLFSSL_ECH*)echX->data)->state == ECH_PARSED_INTERNAL) { - ret = EchWriteAcceptance(ssl, output + RECORD_HEADER_SZ, - serverRandomOffset - RECORD_HEADER_SZ, + ret = EchWriteAcceptance(ssl, acceptLabel, acceptLabelSz, + output + RECORD_HEADER_SZ, + acceptOffset - RECORD_HEADER_SZ, sendSz - RECORD_HEADER_SZ); - - /* remove ech so we don't keep sending it in write */ - TLSX_Remove(&ssl->extensions, TLSX_ECH, ssl->heap); + if (extMsgType != hello_retry_request) { + if (ret == 0) { + /* update serverRandom on success */ + XMEMCPY(ssl->arrays->serverRandom, + output + acceptOffset - + (RAN_LEN -ECH_ACCEPT_CONFIRMATION_SZ), RAN_LEN); + } + /* remove ech so we don't keep sending it in write */ + TLSX_Remove(&ssl->extensions, TLSX_ECH, ssl->heap); + } } } #endif diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 271f55bee..eb03b7251 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2886,6 +2886,7 @@ typedef struct RpkState { #endif /* HAVE_RPK */ #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) +#define ECH_ACCEPT_CONFIRMATION_SZ 8 typedef enum { ECH_TYPE_OUTER = 0, @@ -2926,6 +2927,7 @@ typedef struct WOLFSSL_ECH { WOLFSSL_EchConfig* echConfig; byte* innerClientHello; byte* outerClientPayload; + byte* confBuf; EchCipherSuite cipherSuite; word16 aadLen; word16 paddingLen; From dfb45bc40eff32bdd0e6dd8fcdb02e61c8a32f44 Mon Sep 17 00:00:00 2001 From: John Bland Date: Mon, 25 Sep 2023 11:53:13 -0400 Subject: [PATCH 04/19] fix unitialized variable --- src/tls13.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index db28de812..ce492b831 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -4946,8 +4946,10 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, PRIVATE_KEY_LOCK(); } /* free acceptHashes */ - FreeHandshakeHashes(ssl); - ssl->hsHashes = tmpHashes; + if (ret == 0) { + FreeHandshakeHashes(ssl); + ssl->hsHashes = tmpHashes; + } return ret; } #endif From 000c42ef7045dad6d0d80a382c36e7f6b531f65b Mon Sep 17 00:00:00 2001 From: John Bland Date: Mon, 25 Sep 2023 12:40:16 -0400 Subject: [PATCH 05/19] fix implicit cast --- src/tls13.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index ce492b831..321c84cd7 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -5427,7 +5427,8 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, echX = TLSX_Find(ssl->extensions, TLSX_ECH); /* account for hrr */ if (args->extMsgType == hello_retry_request) { - args->acceptOffset = ((WOLFSSL_ECH*)echX->data)->confBuf - input; + args->acceptOffset = + (word32)(((WOLFSSL_ECH*)echX->data)->confBuf - input); args->acceptLabel = (byte*)echHrrAcceptConfirmationLabel; args->acceptLabelSz = ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ; } @@ -7374,7 +7375,8 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) return -1; /* use normal offset instead of hrr offset */ if (extMsgType == hello_retry_request) { - acceptOffset = ((WOLFSSL_ECH*)echX->data)->confBuf - output; + acceptOffset = + (word32)(((WOLFSSL_ECH*)echX->data)->confBuf - output); acceptLabel = (byte*)echHrrAcceptConfirmationLabel; acceptLabelSz = ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ; } From 167c702b6f9f0324a6f2b90b8779d63104958339 Mon Sep 17 00:00:00 2001 From: John Bland Date: Mon, 25 Sep 2023 13:36:35 -0400 Subject: [PATCH 06/19] don't mix declaration with code to satisfy compiler --- src/tls13.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index 321c84cd7..866b58d3f 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -4975,6 +4975,7 @@ typedef struct Dsh13Args { byte sessIdSz; byte extMsgType; #if defined(HAVE_ECH) + TLSX* echX; byte* acceptLabel; word32 acceptOffset; word16 acceptLabelSz; @@ -5421,14 +5422,13 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return ret; #if defined(HAVE_ECH) - TLSX* echX = NULL; /* check for acceptConfirmation and HashInput with 8 0 bytes */ if (ssl->options.useEch == 1) { - echX = TLSX_Find(ssl->extensions, TLSX_ECH); + args->echX = TLSX_Find(ssl->extensions, TLSX_ECH); /* account for hrr */ if (args->extMsgType == hello_retry_request) { args->acceptOffset = - (word32)(((WOLFSSL_ECH*)echX->data)->confBuf - input); + (word32)(((WOLFSSL_ECH*)args->echX->data)->confBuf - input); args->acceptLabel = (byte*)echHrrAcceptConfirmationLabel; args->acceptLabelSz = ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ; } From bc77f9f46667be8890af806b02fe7e00c6a2107b Mon Sep 17 00:00:00 2001 From: John Bland Date: Tue, 26 Sep 2023 13:24:27 -0400 Subject: [PATCH 07/19] fix writing empty string when sending enc in response to an hrr, fix bad getSize for hrr ech, fix using the wrong transcript hash for hrr ech, add new hrr test for ech to api.c --- src/tls.c | 19 +++++++++++++++---- src/tls13.c | 19 +++++++++++++------ tests/api.c | 18 +++++++++++++++++- 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/tls.c b/src/tls.c index 586713386..2d4f1b93a 100644 --- a/src/tls.c +++ b/src/tls.c @@ -11551,8 +11551,8 @@ static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte msgType, byte* writeBuf, #endif } else { - /* set to emptry string on hrr */ - if (msgType == hello_retry_request) { + /* write empty string for enc if this isn't our first ech */ + if (ech->hpkeContext != NULL) { XMEMSET(writeBuf_p, 0, ech->encLen); } else { @@ -11577,7 +11577,7 @@ static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte msgType, byte* writeBuf, } /* return the size needed for the ech extension */ -static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech) +static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech, byte msgType) { int ret; word32 size; @@ -11589,6 +11589,9 @@ static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech) size += GREASE_ECH_SIZE + (size % 32); } + else if (msgType == hello_retry_request) { + size = ECH_ACCEPT_CONFIRMATION_SZ; + } else if (ech->state == ECH_WRITE_NONE || ech->state == ECH_PARSED_INTERNAL) { size = 0; @@ -12308,7 +12311,7 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, #endif /* WOLFSSL_DTLS_CID */ #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) case TLSX_ECH: - length += ECH_GET_SIZE((WOLFSSL_ECH*)extension->data); + length += ECH_GET_SIZE((WOLFSSL_ECH*)extension->data, msgType); break; #endif default: @@ -13767,6 +13770,10 @@ int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength) #ifdef WOLFSSL_SEND_HRR_COOKIE TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE)); #endif +#ifdef HAVE_ECH + /* send the special confirmation */ + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_ECH)); +#endif break; #endif @@ -13908,6 +13915,10 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); } #endif +#ifdef HAVE_ECH + /* send the special confirmation */ + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_ECH)); +#endif /* Cookie is written below as last extension. */ break; #endif diff --git a/src/tls13.c b/src/tls13.c index 866b58d3f..fee31b88b 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -4740,12 +4740,13 @@ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, XMEMSET(acceptConfirmation, 0, sizeof(acceptConfirmation)); /* copy ech hashes to accept */ ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashesEch, &acceptHashes); - /* swap hsHashes to acceptHashes */ - tmpHashes = ssl->hsHashes; - ssl->hsHashes = acceptHashes; - /* hash up to the last 8 bytes */ - if (ret == 0) + if (ret == 0) { + /* swap hsHashes to acceptHashes */ + tmpHashes = ssl->hsHashes; + ssl->hsHashes = acceptHashes; + /* hash up to the last 8 bytes */ ret = HashRaw(ssl, input, acceptOffset); + } /* hash 8 zeros */ if (ret == 0) ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ); @@ -4866,7 +4867,7 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, XMEMSET(transcriptEchConf, 0, sizeof(transcriptEchConf)); XMEMSET(expandLabelPrk, 0, sizeof(expandLabelPrk)); /* copy ech hashes to accept */ - ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, &acceptHashes); + ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashesEch, &acceptHashes); if (ret == 0) { /* swap hsHashes to acceptHashes */ tmpHashes = ssl->hsHashes; @@ -7253,6 +7254,12 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) WOLFSSL_START(WC_FUNC_SERVER_HELLO_SEND); WOLFSSL_ENTER("SendTls13ServerHello"); +#ifdef HAVE_ECH + /* copy the hsHashes to hsHashesEch since they will get blown away by hrr */ + if (ssl->hsHashesEch == NULL) + InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, &ssl->hsHashesEch); +#endif + /* When ssl->options.dtlsStateful is not set then cookie is calculated in * dtls.c */ if (extMsgType == hello_retry_request diff --git a/tests/api.c b/tests/api.c index 4ded25ef3..a12009b91 100644 --- a/tests/api.c +++ b/tests/api.c @@ -36759,7 +36759,7 @@ static int test_wolfSSL_Tls13_ECH_params(void) return EXPECT_RESULT(); } -static int test_wolfSSL_Tls13_ECH(void) +static int test_wolfSSL_Tls13_ECH_ex(int hrr) { EXPECT_DECLS; tcp_ready ready; @@ -36830,6 +36830,11 @@ static int test_wolfSSL_Tls13_ECH(void) ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, privateName, privateNameLen)); + /* force hello retry request */ + if (hrr) + ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_NoKeyShares(ssl)); + + /* connect like normal */ ExpectIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS); ExpectIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS); ExpectIntEQ(wolfSSL_write(ssl, privateName, privateNameLen), @@ -36850,6 +36855,16 @@ static int test_wolfSSL_Tls13_ECH(void) return EXPECT_RESULT(); } + +static int test_wolfSSL_Tls13_ECH(void) +{ + return test_wolfSSL_Tls13_ECH_ex(0); +} + +static int test_wolfSSL_Tls13_ECH_HRR(void) +{ + return test_wolfSSL_Tls13_ECH_ex(1); +} #endif /* HAVE_ECH && WOLFSSL_TLS13 */ #if defined(HAVE_IO_TESTS_DEPENDENCIES) && \ @@ -70072,6 +70087,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_Tls13_ECH_params), /* Uses Assert in handshake callback. */ TEST_DECL(test_wolfSSL_Tls13_ECH), + TEST_DECL(test_wolfSSL_Tls13_ECH_HRR), #endif TEST_DECL(test_wolfSSL_X509_TLS_version_test_1), From 4c63ec3fce5c3c1460e4f5e9acdcc69074ad8bd3 Mon Sep 17 00:00:00 2001 From: John Bland Date: Tue, 26 Sep 2023 14:29:13 -0400 Subject: [PATCH 08/19] fix memory leaks --- src/internal.c | 5 +++++ src/tls.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/internal.c b/src/internal.c index 01e9de704..b8336af71 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7993,6 +7993,11 @@ void SSL_ResourceFree(WOLFSSL* ssl) } FreeSuites(ssl); FreeHandshakeHashes(ssl); +#ifdef HAVE_ECH + /* try to free the ech hashes in case we errored out */ + ssl->hsHashes = ssl->hsHashesEch; + FreeHandshakeHashes(ssl); +#endif XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN); /* clear keys struct after session */ diff --git a/src/tls.c b/src/tls.c index 2d4f1b93a..3edae684e 100644 --- a/src/tls.c +++ b/src/tls.c @@ -11808,6 +11808,9 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size, /* set the ech payload of the copy to zeros */ XMEMSET(aadCopy + (readBuf_p - ech->aad), 0, ech->innerClientHelloLen + AES_BLOCK_SIZE); + /* free the old ech in case this is our second client hello */ + if (ech->innerClientHello != NULL) + XFREE(ech->innerClientHello, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); /* allocate the inner payload buffer */ ech->innerClientHello = (byte*)XMALLOC(ech->innerClientHelloLen + HANDSHAKE_HEADER_SZ, From a23edb84d409fc2783406ba2ba84ce80adea95cf Mon Sep 17 00:00:00 2001 From: John Bland Date: Tue, 26 Sep 2023 15:16:52 -0400 Subject: [PATCH 09/19] only copy the hsHashes if the server is actually using ech --- src/tls13.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tls13.c b/src/tls13.c index fee31b88b..480959b27 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -7256,7 +7256,7 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) #ifdef HAVE_ECH /* copy the hsHashes to hsHashesEch since they will get blown away by hrr */ - if (ssl->hsHashesEch == NULL) + if (ssl->ctx->echConfigs != NULL && ssl->hsHashesEch == NULL) InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, &ssl->hsHashesEch); #endif From c0b49ce443b9fe14b30857090fa6026788470fb3 Mon Sep 17 00:00:00 2001 From: John Bland Date: Tue, 26 Sep 2023 18:03:15 -0400 Subject: [PATCH 10/19] stop double-populating the ech extension since that blows away the ech and it's current hpke context, causing the hrr handling to fail --- src/tls.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tls.c b/src/tls.c index 3edae684e..fc128aa58 100644 --- a/src/tls.c +++ b/src/tls.c @@ -11359,9 +11359,14 @@ static int TLSX_ECH_Use(WOLFSSL_EchConfig* echConfig, TLSX** extensions, { int ret = 0; int suiteIndex; + TLSX* echX; WOLFSSL_ECH* ech; if (extensions == NULL) return BAD_FUNC_ARG; + /* skip if we already have an ech extension, we will for hrr */ + echX = TLSX_Find(*extensions, TLSX_ECH); + if (echX != NULL) + return 0; /* find a supported cipher suite */ suiteIndex = EchConfigGetSupportedCipherSuite(echConfig); if (suiteIndex < 0) From a5963b4b9f89cdfa0384dfa63adbce698284a9a7 Mon Sep 17 00:00:00 2001 From: John Bland Date: Tue, 26 Sep 2023 19:20:01 -0400 Subject: [PATCH 11/19] free the innerClientHello since it may be previously allocated if an hrr happened --- src/tls13.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tls13.c b/src/tls13.c index 480959b27..613bac616 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -4540,6 +4540,11 @@ int SendTls13ClientHello(WOLFSSL* ssl) /* set the type to inner */ args->ech->type = ECH_TYPE_INNER; + /* innerClientHello may already exist from hrr, free if it does */ + if (args->ech->innerClientHello != NULL) { + XFREE(args->ech->innerClientHello, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + } /* allocate the inner */ args->ech->innerClientHello = (byte*)XMALLOC(args->ech->innerClientHelloLen - args->ech->hpke->Nt, From 36623f0869f7e1cae87ed163a8b0f2db27812d0e Mon Sep 17 00:00:00 2001 From: John Bland Date: Tue, 26 Sep 2023 20:41:33 -0400 Subject: [PATCH 12/19] fix ech config parsing to handle 1 byte public name len --- src/ssl.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 16be5dda7..8eaa1919a 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -652,7 +652,7 @@ int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64, /* set the ech config from a raw buffer, this is the format ech configs are * sent using retry_configs from the ech server */ int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs, - word32 echConfigsLen) + word32 echConfigsLen) { int ret = 0; int i; @@ -779,16 +779,17 @@ int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs, &workingConfig->cipherSuites[j].aeadId); } echConfig += cipherSuitesLen; + /* ignore the maximum name length */ + echConfig++; /* publicNameLen */ - ato16(echConfig, &publicNameLen); + publicNameLen = *(echConfig); workingConfig->publicName = (char*)XMALLOC(publicNameLen + 1, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); if (workingConfig->publicName == NULL) { ret = MEMORY_E; break; } - - echConfig += 2; + echConfig++; /* publicName */ XMEMCPY(workingConfig->publicName, echConfig, publicNameLen); /* null terminated */ @@ -965,9 +966,13 @@ int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen) output += 2; } + /* set maximum name length to 0 */ + *output = 0; + output++; + /* publicName len */ - c16toa(XSTRLEN(config->publicName), output); - output += 2; + *output = XSTRLEN(config->publicName); + output++; /* publicName */ XMEMCPY(output, config->publicName, From f6555fd753b00f605388597fdeebccc58f5406ea Mon Sep 17 00:00:00 2001 From: John Bland Date: Mon, 2 Oct 2023 01:26:14 -0400 Subject: [PATCH 13/19] update ech to use separate hsHashes for the ech log which are not restarted and the inner hsHashes which are restared on HRR. also send empty string with 0 encLen when sending clientHelloInner2. setup works wolfssl->wolfssl but fails to match acceptance for first HRR message when talking to an openssl server, does still work without HRR when talking to cloudflare's server without HRR. --- src/internal.c | 7 +- src/tls.c | 46 ++++++---- src/tls13.c | 224 +++++++++++++++++++++++++-------------------- tests/api.c | 1 + wolfssl/internal.h | 3 + 5 files changed, 161 insertions(+), 120 deletions(-) diff --git a/src/internal.c b/src/internal.c index b8336af71..a1c3128ce 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6942,7 +6942,7 @@ int InitHandshakeHashesAndCopy(WOLFSSL* ssl, HS_Hashes* source, /* save the original so we can put it back afterward */ tmpHashes = ssl->hsHashes; - ssl->hsHashes = NULL; + ssl->hsHashes = *destination; InitHandshakeHashes(ssl); @@ -7997,6 +7997,8 @@ void SSL_ResourceFree(WOLFSSL* ssl) /* try to free the ech hashes in case we errored out */ ssl->hsHashes = ssl->hsHashesEch; FreeHandshakeHashes(ssl); + ssl->hsHashes = ssl->hsHashesEchInner; + FreeHandshakeHashes(ssl); #endif XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN); @@ -8011,9 +8013,6 @@ void SSL_ResourceFree(WOLFSSL* ssl) if (ssl->options.useEch == 1) { FreeEchConfigs(ssl->echConfigs, ssl->heap); ssl->echConfigs = NULL; - /* free the ech specific hashes */ - ssl->hsHashes = ssl->hsHashesEch; - FreeHandshakeHashes(ssl); ssl->options.useEch = 0; } #endif /* HAVE_ECH */ diff --git a/src/tls.c b/src/tls.c index fc128aa58..a8ee856f7 100644 --- a/src/tls.c +++ b/src/tls.c @@ -11508,7 +11508,13 @@ static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte msgType, byte* writeBuf, *writeBuf_p = ech->configId; writeBuf_p += sizeof(ech->configId); /* encLen */ - c16toa(ech->encLen, writeBuf_p); + if (ech->hpkeContext == NULL) { + c16toa(ech->encLen, writeBuf_p); + } + else { + /* set to 0 if this is clientInner 2 */ + c16toa(0, writeBuf_p); + } writeBuf_p += 2; if (ech->state == ECH_WRITE_GREASE) { #ifdef WOLFSSL_SMALL_STACK @@ -11556,16 +11562,13 @@ static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte msgType, byte* writeBuf, #endif } else { - /* write empty string for enc if this isn't our first ech */ - if (ech->hpkeContext != NULL) { - XMEMSET(writeBuf_p, 0, ech->encLen); - } - else { + /* only write enc if this is our first ech, no hpke context */ + if (ech->hpkeContext == NULL) { /* write enc to writeBuf_p */ ret = wc_HpkeSerializePublicKey(ech->hpke, ech->ephemeralKey, writeBuf_p, &ech->encLen); + writeBuf_p += ech->encLen; } - writeBuf_p += ech->encLen; /* innerClientHelloLen */ c16toa(ech->innerClientHelloLen, writeBuf_p); writeBuf_p += 2; @@ -11615,8 +11618,11 @@ static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech, byte msgType) else { size = sizeof(ech->type) + sizeof(ech->cipherSuite) + - sizeof(ech->configId) + sizeof(word16) + ech->encLen + - sizeof(word16) + ech->innerClientHelloLen; + sizeof(ech->configId) + sizeof(word16) + sizeof(word16) + + ech->innerClientHelloLen; + /* only set encLen if this is inner hello 1 */ + if (ech->hpkeContext == NULL) + size += ech->encLen; } return (int)size; @@ -11791,14 +11797,20 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size, /* read configId */ ech->configId = *readBuf_p; readBuf_p++; - /* read encLen */ - ato16(readBuf_p, &ech->encLen); - readBuf_p += 2; - if (ech->encLen > HPKE_Npk_MAX) - return BAD_FUNC_ARG; - /* read enc */ - XMEMCPY(ech->enc, readBuf_p, ech->encLen); - readBuf_p += ech->encLen; + /* only get enc if we don't already have the hpke context */ + if (ech->hpkeContext == NULL) { + /* read encLen */ + ato16(readBuf_p, &ech->encLen); + readBuf_p += 2; + if (ech->encLen > HPKE_Npk_MAX) + return BAD_FUNC_ARG; + /* read enc */ + XMEMCPY(ech->enc, readBuf_p, ech->encLen); + readBuf_p += ech->encLen; + } + else { + readBuf_p += 2; + } /* read hello inner len */ ato16(readBuf_p, &ech->innerClientHelloLen); ech->innerClientHelloLen -= AES_BLOCK_SIZE; diff --git a/src/tls13.c b/src/tls13.c index 613bac616..ea3bc452b 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -4122,37 +4122,62 @@ int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config) } /* returns status after we hash the ech inner */ -static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech) +static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech, int server) { - int ret; + int ret = 0; + word32 realSz; HS_Hashes* tmpHashes; byte falseHeader[HANDSHAKE_HEADER_SZ]; - if (ssl == NULL || ech == NULL) return BAD_FUNC_ARG; - - /* switch hsHashes to the ech version */ - InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, &ssl->hsHashesEch); - - /* swap hsHashes so the regular hash functions work */ + if (server) + realSz = ech->innerClientHelloLen + HANDSHAKE_HEADER_SZ; + else + realSz = ech->innerClientHelloLen - ech->paddingLen - ech->hpke->Nt; tmpHashes = ssl->hsHashes; - ssl->hsHashes = ssl->hsHashesEch; - - /* do the handshake header then the body */ - AddTls13HandShakeHeader(falseHeader, - ech->innerClientHelloLen - ech->paddingLen - ech->hpke->Nt, 0, 0, - client_hello, ssl); - ret = HashRaw(ssl, falseHeader, HANDSHAKE_HEADER_SZ); - - /* hash the body */ - if (ret == 0) { - ret = HashRaw(ssl, ech->innerClientHello, - ech->innerClientHelloLen - ech->paddingLen - ech->hpke->Nt); + /* init the ech hashes */ + if (ssl->hsHashesEch == NULL) { + ssl->hsHashes = ssl->hsHashesEch; + InitHandshakeHashes(ssl); + ssl->hsHashesEch = ssl->hsHashes; + ssl->hsHashes = tmpHashes; + } + /* swap hsHashes so the regular hash functions work */ + ssl->hsHashes = ssl->hsHashesEch; + if (ret == 0 && server == 0) { + /* do the handshake header then the body */ + AddTls13HandShakeHeader(falseHeader, realSz, 0, 0, client_hello, ssl); + ret = HashRaw(ssl, falseHeader, HANDSHAKE_HEADER_SZ); + /* hash with inner */ + if (ret == 0) { + /* init hsHashesEchInner */ + if (ech->innerCount == 0) { + ssl->hsHashes = ssl->hsHashesEchInner; + InitHandshakeHashes(ssl); + ssl->hsHashesEchInner = ssl->hsHashes; + ech->innerCount = 1; + } + else { + /* switch back to primary so we can copy it to inner */ + ssl->hsHashes = tmpHashes; + InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, + &ssl->hsHashesEchInner); + } + ssl->hsHashes = ssl->hsHashesEchInner; + ret = HashRaw(ssl, falseHeader, HANDSHAKE_HEADER_SZ); + ssl->hsHashes = ssl->hsHashesEch; + } + } + /* hash the body */ + if (ret == 0) + ret = HashRaw(ssl, ech->innerClientHello, realSz); + /* hash with inner */ + if (ret == 0 && server == 0) { + ssl->hsHashes = ssl->hsHashesEchInner; + ret = HashRaw(ssl, ech->innerClientHello, realSz); } - /* swap hsHashes back */ ssl->hsHashes = tmpHashes; - return ret; } #endif @@ -4539,7 +4564,6 @@ int SendTls13ClientHello(WOLFSSL* ssl) if (ssl->options.useEch == 1) { /* set the type to inner */ args->ech->type = ECH_TYPE_INNER; - /* innerClientHello may already exist from hrr, free if it does */ if (args->ech->innerClientHello != NULL) { XFREE(args->ech->innerClientHello, ssl->heap, @@ -4551,32 +4575,26 @@ int SendTls13ClientHello(WOLFSSL* ssl) ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); if (args->ech->innerClientHello == NULL) return MEMORY_E; - /* set the padding bytes to 0 */ XMEMSET(args->ech->innerClientHello + args->ech->innerClientHelloLen - args->ech->hpke->Nt - args->ech->paddingLen, 0, args->ech->paddingLen); - /* copy the client hello to the ech innerClientHello, exclude record */ /* and handshake headers */ XMEMCPY(args->ech->innerClientHello, args->output + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ, args->idx - (RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ)); - /* copy the client random to inner */ XMEMCPY(ssl->arrays->clientRandomInner, ssl->arrays->clientRandom, RAN_LEN); - /* change the outer client random */ ret = wc_RNG_GenerateBlock(ssl->rng, args->output + args->clientRandomOffset, RAN_LEN); if (ret != 0) return ret; - /* copy the new client random */ XMEMCPY(ssl->arrays->clientRandom, args->output + args->clientRandomOffset, RAN_LEN); - /* write the extensions for inner */ args->length = 0; ret = TLSX_WriteRequest(ssl, args->ech->innerClientHello + args->idx - @@ -4584,7 +4602,6 @@ int SendTls13ClientHello(WOLFSSL* ssl) &args->length); if (ret != 0) return ret; - /* set the type to outer */ args->ech->type = 0; } @@ -4632,10 +4649,9 @@ int SendTls13ClientHello(WOLFSSL* ssl) #if defined(HAVE_ECH) /* compute the inner hash */ if (ssl->options.useEch == 1) { - ret = EchHashHelloInner(ssl, args->ech); + ret = EchHashHelloInner(ssl, args->ech, 0); } #endif - /* compute the outer hash */ if (ret == 0) ret = HashOutput(ssl, args->output, args->idx, 0); @@ -4726,9 +4742,10 @@ static int Dtls13DoDowngrade(WOLFSSL* ssl) #endif /* WOLFSSL_DTLS13 && !WOLFSSL_NO_CLIENT*/ #if defined(HAVE_ECH) -/* check if the server accepted ech or not */ +/* check if the server accepted ech or not, must be run after an hsHashes + * restart */ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, - const byte* input, int acceptOffset, int helloSz) + const byte* input, int acceptOffset, int helloSz, byte msgType) { int ret = 0; int digestType; @@ -4829,28 +4846,31 @@ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, ECH_ACCEPT_CONFIRMATION_SZ); /* ech accepted */ if (ret == 0) { - /* switch back to original hsHashes to free */ + /* set echAccepted to 1 */ + ssl->options.echAccepted = 1; + /* free hsHashes and go with inner */ ssl->hsHashes = tmpHashes; - /* set the final hsHashes to the ech hashes */ - tmpHashes = ssl->hsHashesEch; + FreeHandshakeHashes(ssl); + ssl->hsHashes = ssl->hsHashesEch; + tmpHashes = ssl->hsHashesEchInner; + ssl->hsHashesEchInner = NULL; } /* ech rejected */ else { - /* switch to hsHashesEch to free */ - ssl->hsHashes = ssl->hsHashesEch; + /* set echAccepted to 0, needed in case HRR */ + ssl->options.echAccepted = 0; } - /* free hsHashes */ - FreeHandshakeHashes(ssl); - /* set hsHashesEch to NULL to avoid double free */ - ssl->hsHashesEch = NULL; /* continue with outer if we failed to verify ech was accepted */ ret = 0; } - /* switch to acceptHashes */ - ssl->hsHashes = acceptHashes; - /* free acceptHashes */ - FreeHandshakeHashes(ssl); - /* swap to tmp, will ech if accepted, hsHashes if rejected */ + /* free hsHashesEch */ + if (ssl->options.echAccepted == 0 || msgType != hello_retry_request) { + /* free hsHashesEch */ + FreeHandshakeHashes(ssl); + /* set hsHashesEch to NULL to avoid double free */ + ssl->hsHashesEch = NULL; + } + /* swap to tmp, will be inner if accepted, hsHashes if rejected */ ssl->hsHashes = tmpHashes; return ret; } @@ -4858,7 +4878,7 @@ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, /* replace the last acceptance field for either sever hello or hrr with the ech * acceptance parameter, return status */ static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, - byte* output, int acceptOffset, int helloSz) + byte* output, int acceptOffset, int helloSz, byte msgType) { int ret = 0; int digestType; @@ -4951,11 +4971,13 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, transcriptEchConf, digestSize, digestType, WOLFSSL_SERVER_END); PRIVATE_KEY_LOCK(); } - /* free acceptHashes */ - if (ret == 0) { + /* free hsHashesEch if this is the last ech involved message */ + if (msgType != hello_retry_request) { FreeHandshakeHashes(ssl); - ssl->hsHashes = tmpHashes; + ssl->hsHashesEch = NULL; + ssl->options.echAccepted = 1; } + ssl->hsHashes = tmpHashes; return ret; } #endif @@ -4982,6 +5004,7 @@ typedef struct Dsh13Args { byte extMsgType; #if defined(HAVE_ECH) TLSX* echX; + HS_Hashes* tmpHashes; byte* acceptLabel; word32 acceptOffset; word16 acceptLabelSz; @@ -5427,34 +5450,6 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ret != 0) return ret; -#if defined(HAVE_ECH) - /* check for acceptConfirmation and HashInput with 8 0 bytes */ - if (ssl->options.useEch == 1) { - args->echX = TLSX_Find(ssl->extensions, TLSX_ECH); - /* account for hrr */ - if (args->extMsgType == hello_retry_request) { - args->acceptOffset = - (word32)(((WOLFSSL_ECH*)args->echX->data)->confBuf - input); - args->acceptLabel = (byte*)echHrrAcceptConfirmationLabel; - args->acceptLabelSz = ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ; - } - else { - args->acceptLabel = (byte*)echAcceptConfirmationLabel; - args->acceptLabelSz = ECH_ACCEPT_CONFIRMATION_LABEL_SZ; - } - /* check acceptance */ - ret = EchCheckAcceptance(ssl, args->acceptLabel, args->acceptLabelSz, - input, args->acceptOffset, helloSz); - if (ret != 0) - return ret; - /* use the inner random for client random */ - if (args->extMsgType != hello_retry_request) { - XMEMCPY(ssl->arrays->clientRandom, ssl->arrays->clientRandomInner, - RAN_LEN); - } - } -#endif - #ifdef HAVE_NULL_CIPHER if (ssl->options.cipherSuite0 == ECC_BYTE && (ssl->options.cipherSuite == TLS_SHA256_SHA256 || @@ -5492,6 +5487,37 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return MATCH_SUITE_ERROR; } +#if defined(HAVE_ECH) + /* check for acceptConfirmation, must be done after hashes restart */ + if (ssl->options.useEch == 1) { + args->echX = TLSX_Find(ssl->extensions, TLSX_ECH); + /* account for hrr extension instead of server random */ + if (args->extMsgType == hello_retry_request) { + args->acceptOffset = + (word32)(((WOLFSSL_ECH*)args->echX->data)->confBuf - input); + args->acceptLabel = (byte*)echHrrAcceptConfirmationLabel; + args->acceptLabelSz = ECH_HRR_ACCEPT_CONFIRMATION_LABEL_SZ; + } + else { + args->acceptLabel = (byte*)echAcceptConfirmationLabel; + args->acceptLabelSz = ECH_ACCEPT_CONFIRMATION_LABEL_SZ; + } + /* check acceptance */ + if (ret == 0) { + ret = EchCheckAcceptance(ssl, args->acceptLabel, + args->acceptLabelSz, input, args->acceptOffset, helloSz, + args->extMsgType); + } + if (ret != 0) + return ret; + /* use the inner random for client random */ + if (args->extMsgType != hello_retry_request) { + XMEMCPY(ssl->arrays->clientRandom, ssl->arrays->clientRandomInner, + RAN_LEN); + } + } +#endif /* HAVE_ECH */ + if (*extMsgType == server_hello) { #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) PreSharedKey* psk = NULL; @@ -7259,12 +7285,6 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) WOLFSSL_START(WC_FUNC_SERVER_HELLO_SEND); WOLFSSL_ENTER("SendTls13ServerHello"); -#ifdef HAVE_ECH - /* copy the hsHashes to hsHashesEch since they will get blown away by hrr */ - if (ssl->ctx->echConfigs != NULL && ssl->hsHashesEch == NULL) - InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, &ssl->hsHashesEch); -#endif - /* When ssl->options.dtlsStateful is not set then cookie is calculated in * dtls.c */ if (extMsgType == hello_retry_request @@ -7385,7 +7405,7 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) echX = TLSX_Find(ssl->extensions, TLSX_ECH); if (echX == NULL) return -1; - /* use normal offset instead of hrr offset */ + /* use hrr offset */ if (extMsgType == hello_retry_request) { acceptOffset = (word32)(((WOLFSSL_ECH*)echX->data)->confBuf - output); @@ -7394,11 +7414,18 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) } /* replace the last 8 bytes of server random with the accept */ if (((WOLFSSL_ECH*)echX->data)->state == ECH_PARSED_INTERNAL) { - ret = EchWriteAcceptance(ssl, acceptLabel, acceptLabelSz, - output + RECORD_HEADER_SZ, - acceptOffset - RECORD_HEADER_SZ, - sendSz - RECORD_HEADER_SZ); - if (extMsgType != hello_retry_request) { + ret = EchHashHelloInner(ssl, (WOLFSSL_ECH*)echX->data, 1); + if (ret == 0) { + ret = EchWriteAcceptance(ssl, acceptLabel, + acceptLabelSz, output + RECORD_HEADER_SZ, + acceptOffset - RECORD_HEADER_SZ, + sendSz - RECORD_HEADER_SZ, extMsgType); + } + if (extMsgType == hello_retry_request) { + /* reset the ech state for round 2 */ + ((WOLFSSL_ECH*)echX->data)->state = ECH_WRITE_NONE; + } + else { if (ret == 0) { /* update serverRandom on success */ XMEMCPY(ssl->arrays->serverRandom, @@ -11603,16 +11630,15 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE) { - /* reset the inOutIdx to the outer start */ *inOutIdx = echInOutIdx; - /* call again with the inner hello */ - ret = DoTls13ClientHello(ssl, - ((WOLFSSL_ECH*)echX->data)->innerClientHello, - &echInOutIdx, - ((WOLFSSL_ECH*)echX->data)->innerClientHelloLen); - + if (ret == 0) { + ret = DoTls13ClientHello(ssl, + ((WOLFSSL_ECH*)echX->data)->innerClientHello, + &echInOutIdx, + ((WOLFSSL_ECH*)echX->data)->innerClientHelloLen); + } /* if the inner ech parsed successfully we have successfully * handled the hello and can skip the whole message */ if (ret == 0) diff --git a/tests/api.c b/tests/api.c index a12009b91..cd72b346a 100644 --- a/tests/api.c +++ b/tests/api.c @@ -36837,6 +36837,7 @@ static int test_wolfSSL_Tls13_ECH_ex(int hrr) /* connect like normal */ ExpectIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS); ExpectIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS); + ExpectIntEQ(ssl->options.echAccepted, 1); ExpectIntEQ(wolfSSL_write(ssl, privateName, privateNameLen), privateNameLen); ExpectIntGT((replyLen = wolfSSL_read(ssl, reply, sizeof(reply))), 0); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index eb03b7251..69bda591a 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2938,6 +2938,7 @@ typedef struct WOLFSSL_ECH { byte type; byte configId; byte enc[HPKE_Npk_MAX]; + byte innerCount; } WOLFSSL_ECH; WOLFSSL_LOCAL int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config); @@ -4756,6 +4757,7 @@ struct Options { #endif /* WOLFSSL_DTLS_CID */ #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) word16 useEch:1; + word16 echAccepted:1; #endif #ifdef WOLFSSL_SEND_HRR_COOKIE word16 cookieGood:1; @@ -5413,6 +5415,7 @@ struct WOLFSSL { HS_Hashes* hsHashes; #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) HS_Hashes* hsHashesEch; + HS_Hashes* hsHashesEchInner; #endif void* IOCB_ReadCtx; void* IOCB_WriteCtx; From b62f582fcce6b2b906a66b9f6c84fc10453096b1 Mon Sep 17 00:00:00 2001 From: John Bland Date: Tue, 3 Oct 2023 02:03:14 -0400 Subject: [PATCH 14/19] copy full inner hashes to hsHashesEch so that it has the unmodified hrr and sh in the digest --- src/tls13.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index ea3bc452b..afe8b6704 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -4122,7 +4122,7 @@ int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config) } /* returns status after we hash the ech inner */ -static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech, int server) +static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech) { int ret = 0; word32 realSz; @@ -4130,21 +4130,13 @@ static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech, int server) byte falseHeader[HANDSHAKE_HEADER_SZ]; if (ssl == NULL || ech == NULL) return BAD_FUNC_ARG; - if (server) - realSz = ech->innerClientHelloLen + HANDSHAKE_HEADER_SZ; - else - realSz = ech->innerClientHelloLen - ech->paddingLen - ech->hpke->Nt; + realSz = ech->innerClientHelloLen - ech->paddingLen - ech->hpke->Nt; tmpHashes = ssl->hsHashes; /* init the ech hashes */ - if (ssl->hsHashesEch == NULL) { - ssl->hsHashes = ssl->hsHashesEch; - InitHandshakeHashes(ssl); - ssl->hsHashesEch = ssl->hsHashes; - ssl->hsHashes = tmpHashes; - } + InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, &ssl->hsHashesEch); /* swap hsHashes so the regular hash functions work */ ssl->hsHashes = ssl->hsHashesEch; - if (ret == 0 && server == 0) { + if (ret == 0) { /* do the handshake header then the body */ AddTls13HandShakeHeader(falseHeader, realSz, 0, 0, client_hello, ssl); ret = HashRaw(ssl, falseHeader, HANDSHAKE_HEADER_SZ); @@ -4172,7 +4164,7 @@ static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech, int server) if (ret == 0) ret = HashRaw(ssl, ech->innerClientHello, realSz); /* hash with inner */ - if (ret == 0 && server == 0) { + if (ret == 0) { ssl->hsHashes = ssl->hsHashesEchInner; ret = HashRaw(ssl, ech->innerClientHello, realSz); } @@ -4649,7 +4641,7 @@ int SendTls13ClientHello(WOLFSSL* ssl) #if defined(HAVE_ECH) /* compute the inner hash */ if (ssl->options.useEch == 1) { - ret = EchHashHelloInner(ssl, args->ech, 0); + ret = EchHashHelloInner(ssl, args->ech); } #endif /* compute the outer hash */ @@ -7414,7 +7406,8 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) } /* replace the last 8 bytes of server random with the accept */ if (((WOLFSSL_ECH*)echX->data)->state == ECH_PARSED_INTERNAL) { - ret = EchHashHelloInner(ssl, (WOLFSSL_ECH*)echX->data, 1); + ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, + &ssl->hsHashesEch); if (ret == 0) { ret = EchWriteAcceptance(ssl, acceptLabel, acceptLabelSz, output + RECORD_HEADER_SZ, From 36c89cc5adf193055698771f240fc31dac148bb6 Mon Sep 17 00:00:00 2001 From: John Bland Date: Tue, 2 Jan 2024 20:12:13 -0500 Subject: [PATCH 15/19] clean up some post-rebase issues --- src/tls13.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index afe8b6704..99f3f0149 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -4743,7 +4743,7 @@ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, int digestType; int digestSize; HS_Hashes* tmpHashes; - HS_Hashes* acceptHashes; + HS_Hashes* acceptHashes = NULL; byte zeros[WC_MAX_DIGEST_SIZE]; byte transcriptEchConf[WC_MAX_DIGEST_SIZE]; byte expandLabelPrk[WC_MAX_DIGEST_SIZE]; @@ -4752,11 +4752,12 @@ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, XMEMSET(transcriptEchConf, 0, sizeof(transcriptEchConf)); XMEMSET(expandLabelPrk, 0, sizeof(expandLabelPrk)); XMEMSET(acceptConfirmation, 0, sizeof(acceptConfirmation)); + /* store so we can restore regardless of the outcome */ + tmpHashes = ssl->hsHashes; /* copy ech hashes to accept */ ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashesEch, &acceptHashes); if (ret == 0) { /* swap hsHashes to acceptHashes */ - tmpHashes = ssl->hsHashes; ssl->hsHashes = acceptHashes; /* hash up to the last 8 bytes */ ret = HashRaw(ssl, input, acceptOffset); @@ -4824,11 +4825,9 @@ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, /* tls expand with the confirmation label */ if (ret == 0) { PRIVATE_KEY_UNLOCK(); - ret = Tls13HKDFExpandKeyLabel(ssl, - acceptConfirmation, ECH_ACCEPT_CONFIRMATION_SZ, - expandLabelPrk, digestSize, - tls13ProtocolLabel, TLS13_PROTOCOL_LABEL_SZ, - echAcceptConfirmationLabel, ECH_ACCEPT_CONFIRMATION_LABEL_SZ, + ret = Tls13HKDFExpandKeyLabel(ssl, acceptConfirmation, + ECH_ACCEPT_CONFIRMATION_SZ, expandLabelPrk, digestSize, + tls13ProtocolLabel, TLS13_PROTOCOL_LABEL_SZ, label, labelSz, transcriptEchConf, digestSize, digestType, WOLFSSL_SERVER_END); PRIVATE_KEY_LOCK(); } @@ -4876,18 +4875,19 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, int digestType; int digestSize; HS_Hashes* tmpHashes; - HS_Hashes* acceptHashes; + HS_Hashes* acceptHashes = NULL; byte zeros[WC_MAX_DIGEST_SIZE]; byte transcriptEchConf[WC_MAX_DIGEST_SIZE]; byte expandLabelPrk[WC_MAX_DIGEST_SIZE]; XMEMSET(zeros, 0, sizeof(zeros)); XMEMSET(transcriptEchConf, 0, sizeof(transcriptEchConf)); XMEMSET(expandLabelPrk, 0, sizeof(expandLabelPrk)); + /* store so we can restore regardless of the outcome */ + tmpHashes = ssl->hsHashes; /* copy ech hashes to accept */ ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashesEch, &acceptHashes); if (ret == 0) { /* swap hsHashes to acceptHashes */ - tmpHashes = ssl->hsHashes; ssl->hsHashes = acceptHashes; /* hash up to the acceptOffset */ ret = HashRaw(ssl, output, acceptOffset); @@ -4954,20 +4954,19 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, /* tls expand with the confirmation label */ if (ret == 0) { PRIVATE_KEY_UNLOCK(); - ret = Tls13HKDFExpandKeyLabel(ssl, - output + serverRandomOffset + RAN_LEN - ECH_ACCEPT_CONFIRMATION_SZ, - ECH_ACCEPT_CONFIRMATION_SZ, - expandLabelPrk, digestSize, - tls13ProtocolLabel, TLS13_PROTOCOL_LABEL_SZ, - echAcceptConfirmationLabel, ECH_ACCEPT_CONFIRMATION_LABEL_SZ, + ret = Tls13HKDFExpandKeyLabel(ssl, output + acceptOffset, + ECH_ACCEPT_CONFIRMATION_SZ, expandLabelPrk, digestSize, + tls13ProtocolLabel, TLS13_PROTOCOL_LABEL_SZ, label, labelSz, transcriptEchConf, digestSize, digestType, WOLFSSL_SERVER_END); PRIVATE_KEY_LOCK(); } - /* free hsHashesEch if this is the last ech involved message */ - if (msgType != hello_retry_request) { - FreeHandshakeHashes(ssl); - ssl->hsHashesEch = NULL; - ssl->options.echAccepted = 1; + if (ret == 0) { + /* free hsHashesEch if this is the last ech involved message */ + if (msgType != hello_retry_request) { + FreeHandshakeHashes(ssl); + ssl->hsHashesEch = NULL; + ssl->options.echAccepted = 1; + } } ssl->hsHashes = tmpHashes; return ret; From 1fd952d6d0bfc552bfed51f14d75974c377935c6 Mon Sep 17 00:00:00 2001 From: John Bland Date: Mon, 10 Mar 2025 09:12:13 -0400 Subject: [PATCH 16/19] fix bad ech transaction hash calculations --- src/tls.c | 51 ++++++++++++---------- src/tls13.c | 123 ++++++++++++++++++++++++++++------------------------ 2 files changed, 95 insertions(+), 79 deletions(-) diff --git a/src/tls.c b/src/tls.c index 94eb3f830..18ae2b53f 100644 --- a/src/tls.c +++ b/src/tls.c @@ -14983,7 +14983,9 @@ static int TLSX_GetSizeWithEch(WOLFSSL* ssl, byte* semaphore, byte msgType, echX = TLSX_Find(ssl->ctx->extensions, TLSX_ECH); /* if type is outer change sni to public name */ - if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->type == ECH_TYPE_OUTER) { + if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->type == ECH_TYPE_OUTER && + (ssl->options.echAccepted || + ((WOLFSSL_ECH*)echX->data)->innerCount == 0)) { if (ssl->extensions) { serverNameX = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME); @@ -15190,7 +15192,9 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore, } /* if type is outer change sni to public name */ - if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->type == ECH_TYPE_OUTER) { + if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->type == ECH_TYPE_OUTER && + (ssl->options.echAccepted || + ((WOLFSSL_ECH*)echX->data)->innerCount == 0)) { if (ssl->extensions) { serverNameX = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME); @@ -15250,31 +15254,34 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore, msgType, pOffset); } - if (echX != NULL) { - /* turn off and write it last */ - TURN_OFF(semaphore, TLSX_ToSemaphore(echX->type)); - } + /* only write if have a shot at acceptance */ + if (ssl->options.echAccepted || ((WOLFSSL_ECH*)echX->data)->innerCount == 0) { + if (echX != NULL) { + /* turn off and write it last */ + TURN_OFF(semaphore, TLSX_ToSemaphore(echX->type)); + } - if (ret == 0 && ssl->extensions) { - ret = TLSX_Write(ssl->extensions, output + *pOffset, semaphore, - msgType, pOffset); - } + if (ret == 0 && ssl->extensions) { + ret = TLSX_Write(ssl->extensions, output + *pOffset, semaphore, + msgType, pOffset); + } - if (ret == 0 && ssl->ctx && ssl->ctx->extensions) { - ret = TLSX_Write(ssl->ctx->extensions, output + *pOffset, semaphore, - msgType, pOffset); - } + if (ret == 0 && ssl->ctx && ssl->ctx->extensions) { + ret = TLSX_Write(ssl->ctx->extensions, output + *pOffset, semaphore, + msgType, pOffset); + } - if (serverNameX != NULL) { - /* remove the public name SNI */ - TLSX_Remove(extensions, TLSX_SERVER_NAME, ssl->heap); + if (serverNameX != NULL) { + /* remove the public name SNI */ + TLSX_Remove(extensions, TLSX_SERVER_NAME, ssl->heap); - ret = TLSX_UseSNI(extensions, WOLFSSL_SNI_HOST_NAME, tmpServerName, - XSTRLEN(tmpServerName), ssl->heap); + ret = TLSX_UseSNI(extensions, WOLFSSL_SNI_HOST_NAME, tmpServerName, + XSTRLEN(tmpServerName), ssl->heap); - /* restore the inner server name */ - if (ret == WOLFSSL_SUCCESS) - ret = 0; + /* restore the inner server name */ + if (ret == WOLFSSL_SUCCESS) + ret = 0; + } } #ifdef WOLFSSL_SMALL_STACK diff --git a/src/tls13.c b/src/tls13.c index f7c758105..3098f268c 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -4182,10 +4182,10 @@ static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech) return BAD_FUNC_ARG; realSz = ech->innerClientHelloLen - ech->paddingLen - ech->hpke->Nt; tmpHashes = ssl->hsHashes; + ssl->hsHashes = NULL; /* init the ech hashes */ - InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, &ssl->hsHashesEch); - /* swap hsHashes so the regular hash functions work */ - ssl->hsHashes = ssl->hsHashesEch; + InitHandshakeHashes(ssl); + ssl->hsHashesEch = ssl->hsHashes; if (ret == 0) { /* do the handshake header then the body */ AddTls13HandShakeHeader(falseHeader, realSz, 0, 0, client_hello, ssl); @@ -4200,7 +4200,7 @@ static int EchHashHelloInner(WOLFSSL* ssl, WOLFSSL_ECH* ech) ech->innerCount = 1; } else { - /* switch back to primary so we can copy it to inner */ + /* switch back to hsHashes so we have hrr -> echInner2 */ ssl->hsHashes = tmpHashes; InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, &ssl->hsHashesEchInner); @@ -4464,23 +4464,26 @@ int SendTls13ClientHello(WOLFSSL* ssl) if (args->ech == NULL) return WOLFSSL_FATAL_ERROR; - /* set the type to inner */ - args->ech->type = ECH_TYPE_INNER; - args->preXLength = (int)args->length; + /* only prepare if we have a chance at acceptance */ + if (ssl->options.echAccepted || args->ech->innerCount == 0) { + /* set the type to inner */ + args->ech->type = ECH_TYPE_INNER; + args->preXLength = (int)args->length; - /* get size for inner */ - ret = TLSX_GetRequestSize(ssl, client_hello, &args->length); - if (ret != 0) - return ret; + /* get size for inner */ + ret = TLSX_GetRequestSize(ssl, client_hello, &args->length); + if (ret != 0) + return ret; - /* set the type to outer */ - args->ech->type = 0; - /* set innerClientHelloLen to ClientHelloInner + padding + tag */ - args->ech->paddingLen = 31 - ((args->length - 1) % 32); - args->ech->innerClientHelloLen = (word16)(args->length + - args->ech->paddingLen + args->ech->hpke->Nt); - /* set the length back to before we computed ClientHelloInner size */ - args->length = (word32)args->preXLength; + /* set the type to outer */ + args->ech->type = 0; + /* set innerClientHelloLen to ClientHelloInner + padding + tag */ + args->ech->paddingLen = 31 - ((args->length - 1) % 32); + args->ech->innerClientHelloLen = (word16)(args->length + + args->ech->paddingLen + args->ech->hpke->Nt); + /* set the length back to before we computed ClientHelloInner size */ + args->length = (word32)args->preXLength; + } } #endif @@ -4606,7 +4609,8 @@ int SendTls13ClientHello(WOLFSSL* ssl) #if defined(HAVE_ECH) /* write inner then outer */ - if (ssl->options.useEch == 1 && !ssl->options.disableECH) { + if (ssl->options.useEch == 1 && !ssl->options.disableECH && + (ssl->options.echAccepted || args->ech->innerCount == 0)) { /* set the type to inner */ args->ech->type = ECH_TYPE_INNER; /* innerClientHello may already exist from hrr, free if it does */ @@ -4663,7 +4667,8 @@ int SendTls13ClientHello(WOLFSSL* ssl) #if defined(HAVE_ECH) /* encrypt and pack the ech innerClientHello */ - if (ssl->options.useEch == 1 && !ssl->options.disableECH) { + if (ssl->options.useEch == 1 && !ssl->options.disableECH && + (ssl->options.echAccepted || args->ech->innerCount == 0)) { ret = TLSX_FinalizeEch(args->ech, args->output + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ, (word32)(args->sendSz - (RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ))); @@ -4693,7 +4698,8 @@ int SendTls13ClientHello(WOLFSSL* ssl) { #if defined(HAVE_ECH) /* compute the inner hash */ - if (ssl->options.useEch == 1 && !ssl->options.disableECH) + if (ssl->options.useEch == 1 && !ssl->options.disableECH && + (ssl->options.echAccepted || args->ech->innerCount == 0)) ret = EchHashHelloInner(ssl, args->ech); #endif /* compute the outer hash */ @@ -4789,13 +4795,12 @@ static int Dtls13ClientDoDowngrade(WOLFSSL* ssl) /* check if the server accepted ech or not, must be run after an hsHashes * restart */ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, - const byte* input, int acceptOffset, int helloSz, byte msgType) + const byte* input, int acceptOffset, int helloSz) { int ret = 0; int digestType = 0; int digestSize = 0; HS_Hashes* tmpHashes; - HS_Hashes* acceptHashes = NULL; byte zeros[WC_MAX_DIGEST_SIZE]; byte transcriptEchConf[WC_MAX_DIGEST_SIZE]; byte expandLabelPrk[WC_MAX_DIGEST_SIZE]; @@ -4806,14 +4811,10 @@ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, XMEMSET(acceptConfirmation, 0, sizeof(acceptConfirmation)); /* store so we can restore regardless of the outcome */ tmpHashes = ssl->hsHashes; - /* copy ech hashes to accept */ - ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashesEch, &acceptHashes); - if (ret == 0) { - /* swap hsHashes to acceptHashes */ - ssl->hsHashes = acceptHashes; - /* hash up to the last 8 bytes */ - ret = HashRaw(ssl, input, acceptOffset); - } + /* swap hsHashes to hsHashesEch */ + ssl->hsHashes = ssl->hsHashesEch; + /* hash up to the last 8 bytes */ + ret = HashRaw(ssl, input, acceptOffset); /* hash 8 zeros */ if (ret == 0) ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ); @@ -4903,17 +4904,17 @@ static int EchCheckAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, else { /* set echAccepted to 0, needed in case HRR */ ssl->options.echAccepted = 0; + /* free inner since we're continuing with outer */ + ssl->hsHashes = ssl->hsHashesEchInner; + FreeHandshakeHashes(ssl); + ssl->hsHashesEchInner = NULL; } /* continue with outer if we failed to verify ech was accepted */ ret = 0; } - /* free hsHashesEch */ - if (ssl->options.echAccepted == 0 || msgType != hello_retry_request) { - /* free hsHashesEch */ - FreeHandshakeHashes(ssl); - /* set hsHashesEch to NULL to avoid double free */ - ssl->hsHashesEch = NULL; - } + FreeHandshakeHashes(ssl); + /* set hsHashesEch to NULL to avoid double free */ + ssl->hsHashesEch = NULL; /* swap to tmp, will be inner if accepted, hsHashes if rejected */ ssl->hsHashes = tmpHashes; return ret; @@ -4928,7 +4929,6 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, int digestType = 0; int digestSize = 0; HS_Hashes* tmpHashes = NULL; - HS_Hashes* acceptHashes = NULL; byte zeros[WC_MAX_DIGEST_SIZE]; byte transcriptEchConf[WC_MAX_DIGEST_SIZE]; byte expandLabelPrk[WC_MAX_DIGEST_SIZE]; @@ -4937,14 +4937,9 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, XMEMSET(expandLabelPrk, 0, sizeof(expandLabelPrk)); /* store so we can restore regardless of the outcome */ tmpHashes = ssl->hsHashes; - /* copy ech hashes to accept */ - ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashesEch, &acceptHashes); - if (ret == 0) { - /* swap hsHashes to acceptHashes */ - ssl->hsHashes = acceptHashes; - /* hash up to the acceptOffset */ - ret = HashRaw(ssl, output, acceptOffset); - } + ssl->hsHashes = ssl->hsHashesEch; + /* hash up to the acceptOffset */ + ret = HashRaw(ssl, output, acceptOffset); /* hash 8 zeros */ if (ret == 0) ret = HashRaw(ssl, zeros, ECH_ACCEPT_CONFIRMATION_SZ); @@ -5015,12 +5010,12 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, PRIVATE_KEY_LOCK(); } if (ret == 0) { - /* free hsHashesEch if this is the last ech involved message */ - if (msgType != hello_retry_request) { - FreeHandshakeHashes(ssl); - ssl->hsHashesEch = NULL; + /* free hsHashesEch, if this is an HRR we will start at client hello 2*/ + FreeHandshakeHashes(ssl); + ssl->hsHashesEch = NULL; + /* mark that ech was accepted */ + if (msgType != hello_retry_request) ssl->options.echAccepted = 1; - } } ssl->hsHashes = tmpHashes; return ret; @@ -5560,8 +5555,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* check acceptance */ if (ret == 0) { ret = EchCheckAcceptance(ssl, args->acceptLabel, - args->acceptLabelSz, input, args->acceptOffset, helloSz, - args->extMsgType); + args->acceptLabelSz, input, args->acceptOffset, helloSz); } if (ret != 0) return ret; @@ -6741,6 +6735,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif #if defined(HAVE_ECH) TLSX* echX = NULL; + HS_Hashes* tmpHashes; #endif WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO); @@ -7064,6 +7059,22 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } #endif +#if defined(HAVE_ECH) + /* hash clientHelloInner to hsHashesEch independently since it can't include + * the HRR */ + if (!ssl->options.disableECH) { + tmpHashes = ssl->hsHashes; + ssl->hsHashes = NULL; + ret = InitHandshakeHashes(ssl); + if (ret != 0) + goto exit_dch; + if ((ret = HashInput(ssl, input + args->begin, (int)helloSz)) != 0) + goto exit_dch; + ssl->hsHashesEch = ssl->hsHashes; + ssl->hsHashes = tmpHashes; + } +#endif + #if (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \ defined(HAVE_TLS_EXTENSIONS) ret = CheckPreSharedKeys(ssl, input + args->begin, helloSz, ssl->clSuites, @@ -7481,8 +7492,6 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) } /* replace the last 8 bytes of server random with the accept */ if (((WOLFSSL_ECH*)echX->data)->state == ECH_PARSED_INTERNAL) { - ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashes, - &ssl->hsHashesEch); if (ret == 0) { ret = EchWriteAcceptance(ssl, acceptLabel, acceptLabelSz, output + RECORD_HEADER_SZ, From a344ba1eb222e37057e86ea2a571637bbe0107af Mon Sep 17 00:00:00 2001 From: John Bland Date: Mon, 10 Mar 2025 09:35:40 -0400 Subject: [PATCH 17/19] add missing echConfigs check --- src/tls13.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index 3098f268c..d0e3b4584 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -5009,14 +5009,12 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, WOLFSSL_SERVER_END); PRIVATE_KEY_LOCK(); } - if (ret == 0) { - /* free hsHashesEch, if this is an HRR we will start at client hello 2*/ - FreeHandshakeHashes(ssl); - ssl->hsHashesEch = NULL; - /* mark that ech was accepted */ - if (msgType != hello_retry_request) - ssl->options.echAccepted = 1; - } + /* mark that ech was accepted */ + if (ret == 0 && msgType != hello_retry_request) + ssl->options.echAccepted = 1; + /* free hsHashesEch, if this is an HRR we will start at client hello 2*/ + FreeHandshakeHashes(ssl); + ssl->hsHashesEch = NULL; ssl->hsHashes = tmpHashes; return ret; } @@ -7062,7 +7060,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #if defined(HAVE_ECH) /* hash clientHelloInner to hsHashesEch independently since it can't include * the HRR */ - if (!ssl->options.disableECH) { + if (ssl->ctx->echConfigs != NULL && !ssl->options.disableECH) { tmpHashes = ssl->hsHashes; ssl->hsHashes = NULL; ret = InitHandshakeHashes(ssl); From 9b65bc22f19ff9476d5c5a8c8cdbb619bdfe4509 Mon Sep 17 00:00:00 2001 From: John Bland Date: Mon, 10 Mar 2025 10:18:48 -0400 Subject: [PATCH 18/19] fix uninitialized variable error --- src/tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tls.c b/src/tls.c index 18ae2b53f..91acca4d3 100644 --- a/src/tls.c +++ b/src/tls.c @@ -13432,7 +13432,7 @@ int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen) int ret = 0; void* receiverPubkey = NULL; byte* info = NULL; - int infoLen; + int infoLen = 0; byte* aadCopy = NULL; /* setup hpke context to seal, should be done at most once per connection */ if (ech->hpkeContext == NULL) { From c48b4f2d86145b339fc0eec68daeb430ec406dd1 Mon Sep 17 00:00:00 2001 From: John Bland Date: Mon, 10 Mar 2025 11:11:27 -0400 Subject: [PATCH 19/19] add missing echX NULL check --- src/tls.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tls.c b/src/tls.c index 91acca4d3..edf67d453 100644 --- a/src/tls.c +++ b/src/tls.c @@ -15255,7 +15255,9 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore, } /* only write if have a shot at acceptance */ - if (ssl->options.echAccepted || ((WOLFSSL_ECH*)echX->data)->innerCount == 0) { + if (echX != NULL && + (ssl->options.echAccepted || + ((WOLFSSL_ECH*)echX->data)->innerCount == 0)) { if (echX != NULL) { /* turn off and write it last */ TURN_OFF(semaphore, TLSX_ToSemaphore(echX->type));