From 5acdcf6ad7bc36bf735188cbb8203576ae6e1bbc Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Mon, 16 Mar 2026 09:39:55 -0600 Subject: [PATCH 1/7] hpke uses wrong kdf/kem digest --- src/ssl_ech.c | 2 +- tests/api.c | 66 +++++++++++++++++++++++++++++++++++++++- wolfcrypt/src/hpke.c | 58 +++++++++++++++++++---------------- wolfcrypt/test/test.c | 30 ++++++++++++++++++ wolfssl/wolfcrypt/hpke.h | 1 + 5 files changed, 128 insertions(+), 29 deletions(-) diff --git a/src/ssl_ech.c b/src/ssl_ech.c index 6eccc3f8718..a880b34d0c3 100644 --- a/src/ssl_ech.c +++ b/src/ssl_ech.c @@ -34,8 +34,8 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName, word16 kemId, word16 kdfId, word16 aeadId) { int ret = 0; - word16 encLen = DHKEM_X25519_ENC_LEN; WOLFSSL_EchConfig* newConfig; + word16 encLen = sizeof(newConfig->receiverPubkey); #ifdef WOLFSSL_SMALL_STACK Hpke* hpke = NULL; WC_RNG* rng; diff --git a/tests/api.c b/tests/api.c index 9e9689b9e8c..10aea8d3fd9 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14438,6 +14438,9 @@ static byte echCbTestConfigs[512]; static word32 echCbTestConfigsLen; static const char* echCbTestPublicName = "ech-public-name.com"; static const char* echCbTestPrivateName = "ech-private-name.com"; +static word16 echCbTestKemID = 0; +static word16 echCbTestKdfID = 0; +static word16 echCbTestAeadID = 0; /* the arg is whether the client has ech enabled or not */ static int test_ech_server_sni_callback(WOLFSSL* ssl, int* ad, void* arg) @@ -14469,7 +14472,8 @@ static int test_ech_server_ctx_ready(WOLFSSL_CTX* ctx) { int ret; - ret = wolfSSL_CTX_GenerateEchConfig(ctx, echCbTestPublicName, 0, 0, 0); + ret = wolfSSL_CTX_GenerateEchConfig(ctx, echCbTestPublicName, + echCbTestKemID, echCbTestKdfID, echCbTestAeadID); if (ret != WOLFSSL_SUCCESS) return TEST_FAIL; @@ -14512,6 +14516,65 @@ static int test_ech_client_ssl_ready(WOLFSSL* ssl) return TEST_SUCCESS; } +static int test_wolfSSL_Tls13_ECH_all_algos_ex(void) +{ + EXPECT_DECLS; + struct test_ssl_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + test_ctx.s_cb.method = wolfTLSv1_3_server_method; + test_ctx.c_cb.method = wolfTLSv1_3_client_method; + + test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready; + test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready; + test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready; + + ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS); + + ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS); + ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 1); + + test_ssl_memio_cleanup(&test_ctx); + + return EXPECT_RESULT(); +} + +static int test_wolfSSL_Tls13_ECH_all_algos(void) +{ + EXPECT_DECLS; + int i; + int j; + int k; + static const word16 kems[] = { + DHKEM_P256_HKDF_SHA256, + DHKEM_P384_HKDF_SHA384, + DHKEM_P521_HKDF_SHA512, + DHKEM_X25519_HKDF_SHA256, + }; + static const word16 kdfs[] = { HKDF_SHA256, HKDF_SHA384, HKDF_SHA512 }; + static const word16 aeads[] = { HPKE_AES_128_GCM, HPKE_AES_256_GCM }; + + /* test each KEM with default KDF and AEAD */ + for (i = 0; i < (int)(sizeof(kems) / sizeof(*kems)); i++) { + echCbTestKemID = kems[i]; + for (j = 0; j < (int)(sizeof(kdfs) / sizeof(*kdfs)); j++) { + echCbTestKdfID = kdfs[j]; + for (k = 0; k < (int)(sizeof(aeads) / sizeof(*aeads)); k++) { + echCbTestAeadID = aeads[k]; + ExpectIntEQ(test_wolfSSL_Tls13_ECH_all_algos_ex(), + WOLFSSL_SUCCESS); + } + } + } + + echCbTestKemID = 0; + echCbTestKdfID = 0; + echCbTestAeadID = 0; + + return EXPECT_RESULT(); +} + /* Test ECH when no private SNI is set */ static int test_wolfSSL_Tls13_ECH_no_private_name(void) { @@ -34426,6 +34489,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_SubTls13_ECH), #endif #if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) + TEST_DECL(test_wolfSSL_Tls13_ECH_all_algos), TEST_DECL(test_wolfSSL_Tls13_ECH_no_private_name), TEST_DECL(test_wolfSSL_Tls13_ECH_bad_configs), TEST_DECL(test_wolfSSL_Tls13_ECH_new_config), diff --git a/wolfcrypt/src/hpke.c b/wolfcrypt/src/hpke.c index 86b740c9d02..cf13e91c8ae 100644 --- a/wolfcrypt/src/hpke.c +++ b/wolfcrypt/src/hpke.c @@ -170,7 +170,7 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) case DHKEM_P256_HKDF_SHA256: hpke->curve_id = ECC_SECP256R1; hpke->Nsecret = WC_SHA256_DIGEST_SIZE; - hpke->Nh = WC_SHA256_DIGEST_SIZE; + hpke->kem_digest = WC_SHA256; hpke->Ndh = (word32)wc_ecc_get_curve_size_from_id(hpke->curve_id); hpke->Npk = 1 + hpke->Ndh * 2; break; @@ -180,7 +180,7 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) case DHKEM_P384_HKDF_SHA384: hpke->curve_id = ECC_SECP384R1; hpke->Nsecret = WC_SHA384_DIGEST_SIZE; - hpke->Nh = WC_SHA384_DIGEST_SIZE; + hpke->kem_digest = WC_SHA384; hpke->Ndh = (word32)wc_ecc_get_curve_size_from_id(hpke->curve_id); hpke->Npk = 1 + hpke->Ndh * 2; break; @@ -190,7 +190,7 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) case DHKEM_P521_HKDF_SHA512: hpke->curve_id = ECC_SECP521R1; hpke->Nsecret = WC_SHA512_DIGEST_SIZE; - hpke->Nh = WC_SHA512_DIGEST_SIZE; + hpke->kem_digest = WC_SHA512; hpke->Ndh = (word32)wc_ecc_get_curve_size_from_id(hpke->curve_id); hpke->Npk = 1 + hpke->Ndh * 2; break; @@ -201,7 +201,7 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) case DHKEM_X25519_HKDF_SHA256: hpke->Nsecret = WC_SHA256_DIGEST_SIZE; - hpke->Nh = WC_SHA256_DIGEST_SIZE; + hpke->kem_digest = WC_SHA256; hpke->Ndh = CURVE25519_KEYSIZE; hpke->Npk = CURVE25519_PUB_KEY_SIZE; break; @@ -211,7 +211,7 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) (defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)) case DHKEM_X448_HKDF_SHA512: hpke->Nsecret = WC_SHA512_DIGEST_SIZE; - hpke->Nh = WC_SHA512_DIGEST_SIZE; + hpke->kem_digest = WC_SHA512; /* size of x448 shared secret */ hpke->Ndh = 64; hpke->Npk = CURVE448_PUB_KEY_SIZE; @@ -228,14 +228,17 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) if (ret == 0) { switch (kdf) { case HKDF_SHA256: + hpke->Nh = WC_SHA256_DIGEST_SIZE; hpke->kdf_digest = WC_SHA256; break; case HKDF_SHA384: + hpke->Nh = WC_SHA384_DIGEST_SIZE; hpke->kdf_digest = WC_SHA384; break; case HKDF_SHA512: + hpke->Nh = WC_SHA512_DIGEST_SIZE; hpke->kdf_digest = WC_SHA512; break; @@ -459,7 +462,7 @@ void wc_HpkeFreeKey(Hpke* hpke, word16 kem, void* keypair, void* heap) } static int wc_HpkeLabeledExtract(Hpke* hpke, byte* suite_id, - word32 suite_id_len, byte* salt, word32 salt_len, byte* label, + word32 suite_id_len, int digest, byte* salt, word32 salt_len, byte* label, word32 label_len, byte* ikm, word32 ikm_len, byte* out) { int ret; @@ -516,7 +519,7 @@ static int wc_HpkeLabeledExtract(Hpke* hpke, byte* suite_id, /* call extract */ PRIVATE_KEY_UNLOCK(); - ret = wc_HKDF_Extract(hpke->kdf_digest, salt, salt_len, labeled_ikm, + ret = wc_HKDF_Extract(digest, salt, salt_len, labeled_ikm, (word32)(size_t)(labeled_ikm_p - labeled_ikm), out); PRIVATE_KEY_LOCK(); @@ -528,8 +531,8 @@ static int wc_HpkeLabeledExtract(Hpke* hpke, byte* suite_id, /* do hkdf expand with the format specified in the hpke rfc, return 0 or * error */ static int wc_HpkeLabeledExpand(Hpke* hpke, byte* suite_id, word32 suite_id_len, - byte* prk, word32 prk_len, byte* label, word32 label_len, byte* info, - word32 infoSz, word32 L, byte* out) + int digest, byte* prk, word32 prk_len, byte* label, word32 label_len, + byte* info, word32 infoSz, word32 L, byte* out) { int ret; byte* labeled_info_p; @@ -592,10 +595,8 @@ static int wc_HpkeLabeledExpand(Hpke* hpke, byte* suite_id, word32 suite_id_len, /* call expand */ PRIVATE_KEY_UNLOCK(); - ret = wc_HKDF_Expand(hpke->kdf_digest, - prk, prk_len, - labeled_info, (word32)(size_t)(labeled_info_p - labeled_info), - out, L); + ret = wc_HKDF_Expand(digest, prk, prk_len, labeled_info, + (word32)(size_t)(labeled_info_p - labeled_info), out, L); PRIVATE_KEY_LOCK(); } @@ -643,15 +644,16 @@ static int wc_HpkeExtractAndExpand( Hpke* hpke, byte* dh, word32 dh_len, /* extract */ ret = wc_HpkeLabeledExtract(hpke, hpke->kem_suite_id, - sizeof( hpke->kem_suite_id ), NULL, 0, (byte*)EAE_PRK_LABEL_STR, - EAE_PRK_LABEL_STR_LEN, dh, dh_len, eae_prk); + sizeof( hpke->kem_suite_id ), hpke->kem_digest, NULL, 0, + (byte*)EAE_PRK_LABEL_STR, EAE_PRK_LABEL_STR_LEN, dh, dh_len, eae_prk); /* expand */ if ( ret == 0 ) { ret = wc_HpkeLabeledExpand(hpke, hpke->kem_suite_id, - sizeof( hpke->kem_suite_id ), eae_prk, hpke->Nh, - (byte*)SHARED_SECRET_LABEL_STR, SHARED_SECRET_LABEL_STR_LEN, - kemContext, kem_context_length, hpke->Nsecret, sharedSecret); + sizeof( hpke->kem_suite_id ), hpke->kem_digest, eae_prk, + hpke->Nsecret, (byte*)SHARED_SECRET_LABEL_STR, + SHARED_SECRET_LABEL_STR_LEN, kemContext, kem_context_length, + hpke->Nsecret, sharedSecret); } ForceZero(eae_prk, WC_MAX_DIGEST_SIZE); @@ -701,35 +703,37 @@ static int wc_HpkeKeyScheduleBase(Hpke* hpke, HpkeBaseContext* context, /* extract psk_id, which for base is null */ ret = wc_HpkeLabeledExtract(hpke, hpke->hpke_suite_id, - sizeof( hpke->hpke_suite_id ), NULL, 0, (byte*)PSK_ID_HASH_LABEL_STR, - PSK_ID_HASH_LABEL_STR_LEN, NULL, 0, key_schedule_context + 1); + sizeof( hpke->hpke_suite_id ), hpke->kdf_digest, NULL, 0, + (byte*)PSK_ID_HASH_LABEL_STR, PSK_ID_HASH_LABEL_STR_LEN, NULL, 0, + key_schedule_context + 1); /* extract info */ if (ret == 0) { ret = wc_HpkeLabeledExtract(hpke, hpke->hpke_suite_id, - sizeof( hpke->hpke_suite_id ), NULL, 0, (byte*)INFO_HASH_LABEL_STR, - INFO_HASH_LABEL_STR_LEN, info, infoSz, + sizeof( hpke->hpke_suite_id ), hpke->kdf_digest, NULL, 0, + (byte*)INFO_HASH_LABEL_STR, INFO_HASH_LABEL_STR_LEN, info, infoSz, key_schedule_context + 1 + hpke->Nh); } /* extract secret */ if (ret == 0) { ret = wc_HpkeLabeledExtract(hpke, hpke->hpke_suite_id, - sizeof( hpke->hpke_suite_id ), sharedSecret, hpke->Nsecret, - (byte*)SECRET_LABEL_STR, SECRET_LABEL_STR_LEN, NULL, 0, secret); + sizeof( hpke->hpke_suite_id ), hpke->kdf_digest, sharedSecret, + hpke->Nsecret, (byte*)SECRET_LABEL_STR, SECRET_LABEL_STR_LEN, + NULL, 0, secret); } /* expand key */ if (ret == 0) ret = wc_HpkeLabeledExpand(hpke, hpke->hpke_suite_id, - sizeof( hpke->hpke_suite_id ), secret, hpke->Nh, + sizeof( hpke->hpke_suite_id ), hpke->kdf_digest, secret, hpke->Nh, (byte*)KEY_LABEL_STR, KEY_LABEL_STR_LEN, key_schedule_context, 1 + 2 * hpke->Nh, hpke->Nk, context->key); /* expand nonce */ if (ret == 0) { ret = wc_HpkeLabeledExpand(hpke, hpke->hpke_suite_id, - sizeof( hpke->hpke_suite_id ), secret, hpke->Nh, + sizeof( hpke->hpke_suite_id ), hpke->kdf_digest, secret, hpke->Nh, (byte*)BASE_NONCE_LABEL_STR, BASE_NONCE_LABEL_STR_LEN, key_schedule_context, 1 + 2 * hpke->Nh, hpke->Nn, context->base_nonce); @@ -738,7 +742,7 @@ static int wc_HpkeKeyScheduleBase(Hpke* hpke, HpkeBaseContext* context, /* expand exporter_secret */ if (ret == 0) { ret = wc_HpkeLabeledExpand(hpke, hpke->hpke_suite_id, - sizeof( hpke->hpke_suite_id ), secret, hpke->Nh, + sizeof( hpke->hpke_suite_id ), hpke->kdf_digest, secret, hpke->Nh, (byte*)EXP_LABEL_STR, EXP_LABEL_STR_LEN, key_schedule_context, 1 + 2 * hpke->Nh, hpke->Nh, context->exporter_secret); } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index cad604a6bed..ade14b78f0d 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -32102,9 +32102,24 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) ret = hpke_test_multi(hpke); if (ret != 0) return ret; + #endif + #if (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) && \ + (defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)) + /* p256 with sha512 kdf */ + ret = wc_HpkeInit(hpke, DHKEM_P256_HKDF_SHA256, 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 + #if defined(WOLFSSL_SHA384) && \ (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) /* p384 */ @@ -32134,6 +32149,21 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) if (ret != 0) return ret; #endif + + #if defined(WOLFSSL_SHA384) && defined(WOLFSSL_SHA512) && \ + (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) + /* p521 with sha384 kdf */ + ret = wc_HpkeInit(hpke, DHKEM_P521_HKDF_SHA512, 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 #endif #if defined(HAVE_CURVE25519) diff --git a/wolfssl/wolfcrypt/hpke.h b/wolfssl/wolfcrypt/hpke.h index 307f46b6ea9..d6d82aaf1f5 100644 --- a/wolfssl/wolfcrypt/hpke.h +++ b/wolfssl/wolfcrypt/hpke.h @@ -99,6 +99,7 @@ typedef struct { word32 Npk; word32 Nsecret; int kdf_digest; + int kem_digest; int curve_id; byte kem_suite_id[KEM_SUITE_ID_LEN]; byte hpke_suite_id[HPKE_SUITE_ID_LEN]; From 36580b0ae84ce21fbba82cb0d953ee41799fc3c6 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Mon, 16 Mar 2026 09:47:04 -0600 Subject: [PATCH 2/7] move hpke-esque code out of tls --- src/ssl_ech.c | 27 +------- src/tls.c | 59 ++++------------- src/tls13.c | 25 +++----- tests/api.c | 32 +++++++++- wolfcrypt/src/hpke.c | 134 ++++++++++++++++++++++++++++++++------- wolfssl/wolfcrypt/hpke.h | 19 +++--- 6 files changed, 170 insertions(+), 126 deletions(-) diff --git a/src/ssl_ech.c b/src/ssl_ech.c index a880b34d0c3..a03e29e9163 100644 --- a/src/ssl_ech.c +++ b/src/ssl_ech.c @@ -338,23 +338,7 @@ int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen) totalLen += 2; /* hpke_pub_key */ - switch (config->kemId) { - case DHKEM_P256_HKDF_SHA256: - totalLen += DHKEM_P256_ENC_LEN; - break; - case DHKEM_P384_HKDF_SHA384: - totalLen += DHKEM_P384_ENC_LEN; - break; - case DHKEM_P521_HKDF_SHA512: - totalLen += DHKEM_P521_ENC_LEN; - break; - case DHKEM_X25519_HKDF_SHA256: - totalLen += DHKEM_X25519_ENC_LEN; - break; - case DHKEM_X448_HKDF_SHA512: - totalLen += DHKEM_X448_ENC_LEN; - break; - } + totalLen += wc_HpkeKemGetEncLen(config->kemId); /* cipherSuitesLen */ totalLen += 2; @@ -693,16 +677,9 @@ int SetEchConfigsEx(WOLFSSL_EchConfig** outputConfigs, void* heap, break; } - /* check that we support this config */ - for (j = 0; j < HPKE_SUPPORTED_KEM_LEN; j++) { - if (hpkeSupportedKem[j] == workingConfig->kemId) - break; - } - /* KEM or ciphersuite not supported, free this config and then try to * parse another */ - if (j >= HPKE_SUPPORTED_KEM_LEN || - EchConfigGetSupportedCipherSuite(workingConfig) < 0) { + if (EchConfigGetSupportedCipherSuite(workingConfig) < 0) { XFREE(workingConfig->cipherSuites, heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(workingConfig->publicName, heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(workingConfig->raw, heap, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/src/tls.c b/src/tls.c index ec949a752fc..bb56c052afc 100644 --- a/src/tls.c +++ b/src/tls.c @@ -13259,24 +13259,7 @@ static int TLSX_ECH_Use(WOLFSSL_EchConfig* echConfig, TLSX** extensions, /* configId */ ech->configId = echConfig->configId; /* encLen */ - switch (echConfig->kemId) - { - case DHKEM_P256_HKDF_SHA256: - ech->encLen = DHKEM_P256_ENC_LEN; - break; - case DHKEM_P384_HKDF_SHA384: - ech->encLen = DHKEM_P384_ENC_LEN; - break; - case DHKEM_P521_HKDF_SHA512: - ech->encLen = DHKEM_P521_ENC_LEN; - break; - case DHKEM_X25519_HKDF_SHA256: - ech->encLen = DHKEM_X25519_ENC_LEN; - break; - case DHKEM_X448_HKDF_SHA512: - ech->encLen = DHKEM_X448_ENC_LEN; - break; - } + ech->encLen = wc_HpkeKemGetEncLen(echConfig->kemId); /* setup hpke */ ech->hpke = (Hpke*)XMALLOC(sizeof(Hpke), heap, DYNAMIC_TYPE_TMP_BUFFER); if (ech->hpke == NULL) { @@ -13288,8 +13271,13 @@ static int TLSX_ECH_Use(WOLFSSL_EchConfig* echConfig, TLSX** extensions, /* setup the ephemeralKey */ if (ret == 0) ret = wc_HpkeGenerateKeyPair(ech->hpke, &ech->ephemeralKey, rng); - if (ret == 0) + if (ret == 0) { ret = TLSX_Push(extensions, TLSX_ECH, ech, heap); + if (ret != 0) { + wc_HpkeFreeKey(ech->hpke, ech->hpke->kem, ech->ephemeralKey, + ech->hpke->heap); + } + } if (ret != 0) { XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -13916,7 +13904,6 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig, byte* aad, word32 aadLen, void* heap) { int ret = 0; - int expectedEncLen; int i; word32 rawConfigLen = 0; byte* info = NULL; @@ -13924,28 +13911,7 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig, if (ech == NULL || echConfig == NULL || aad == NULL) return BAD_FUNC_ARG; /* verify the kem and key len */ - switch (echConfig->kemId) - { - case DHKEM_P256_HKDF_SHA256: - expectedEncLen = DHKEM_P256_ENC_LEN; - break; - case DHKEM_P384_HKDF_SHA384: - expectedEncLen = DHKEM_P384_ENC_LEN; - break; - case DHKEM_P521_HKDF_SHA512: - expectedEncLen = DHKEM_P521_ENC_LEN; - break; - case DHKEM_X25519_HKDF_SHA256: - expectedEncLen = DHKEM_X25519_ENC_LEN; - break; - case DHKEM_X448_HKDF_SHA512: - expectedEncLen = DHKEM_X448_ENC_LEN; - break; - default: - expectedEncLen = 0; - break; - } - if (expectedEncLen != ech->encLen) + if (wc_HpkeKemGetEncLen(echConfig->kemId) != ech->encLen) return BAD_FUNC_ARG; /* verify the cipher suite */ for (i = 0; i < echConfig->numCipherSuites; i++) { @@ -14229,11 +14195,12 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size, static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap) { XFREE(ech->innerClientHello, heap, DYNAMIC_TYPE_TMP_BUFFER); - if (ech->ephemeralKey != NULL) - wc_HpkeFreeKey(ech->hpke, ech->hpke->kem, ech->ephemeralKey, - ech->hpke->heap); - if (ech->hpke != NULL) + if (ech->hpke != NULL) { + if (ech->ephemeralKey != NULL) + wc_HpkeFreeKey(ech->hpke, ech->hpke->kem, ech->ephemeralKey, + ech->hpke->heap); XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER); + } if (ech->hpkeContext != NULL) XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER); if (ech->privateName != NULL) diff --git a/src/tls13.c b/src/tls13.c index 0401b83e036..749e4137052 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -3782,26 +3782,17 @@ static byte helloRetryRequestRandom[] = { /* returns the index of the first supported cipher suite, -1 if none */ int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config) { - int i, j, supported = 0; + int i = 0; - for (i = 0; i < config->numCipherSuites; i++) { - supported = 0; - - for (j = 0; j < HPKE_SUPPORTED_KDF_LEN; j++) { - if (config->cipherSuites[i].kdfId == hpkeSupportedKdf[j]) - break; - } - - if (j < HPKE_SUPPORTED_KDF_LEN) - for (j = 0; j < HPKE_SUPPORTED_AEAD_LEN; j++) { - if (config->cipherSuites[i].aeadId == hpkeSupportedAead[j]) { - supported = 1; - break; - } - } + if (!wc_HpkeKemIsSupported(config->kemId)) { + return WOLFSSL_FATAL_ERROR; + } - if (supported) + for (i = 0; i < config->numCipherSuites; i++) { + if (wc_HpkeKdfIsSupported(config->cipherSuites[i].kdfId) && + wc_HpkeAeadIsSupported(config->cipherSuites[i].aeadId)) { return i; + } } return WOLFSSL_FATAL_ERROR; diff --git a/tests/api.c b/tests/api.c index 10aea8d3fd9..ce610df6278 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14547,15 +14547,41 @@ static int test_wolfSSL_Tls13_ECH_all_algos(void) int j; int k; static const word16 kems[] = { +#if defined(HAVE_ECC) +#if (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) DHKEM_P256_HKDF_SHA256, +#endif +#if defined(WOLFSSL_SHA384) DHKEM_P384_HKDF_SHA384, +#endif +#if (defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)) DHKEM_P521_HKDF_SHA512, +#endif +#endif /* HAVE_ECC */ +#if defined(HAVE_CURVE25519) && (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) DHKEM_X25519_HKDF_SHA256, +#endif + }; + static const word16 kdfs[] = { +#if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) + HKDF_SHA256, +#endif +#ifdef WOLFSSL_SHA384 + HKDF_SHA384, +#endif +#ifdef WOLFSSL_SHA512 + HKDF_SHA512, +#endif + }; + static const word16 aeads[] = { +#ifdef WOLFSSL_AES_128 + HPKE_AES_128_GCM, +#endif +#ifdef WOLFSSL_AES_256 + HPKE_AES_256_GCM, +#endif }; - static const word16 kdfs[] = { HKDF_SHA256, HKDF_SHA384, HKDF_SHA512 }; - static const word16 aeads[] = { HPKE_AES_128_GCM, HPKE_AES_256_GCM }; - /* test each KEM with default KDF and AEAD */ for (i = 0; i < (int)(sizeof(kems) / sizeof(*kems)); i++) { echCbTestKemID = kems[i]; for (j = 0; j < (int)(sizeof(kdfs) / sizeof(*kdfs)); j++) { diff --git a/wolfcrypt/src/hpke.c b/wolfcrypt/src/hpke.c index cf13e91c8ae..4039b4cf22c 100644 --- a/wolfcrypt/src/hpke.c +++ b/wolfcrypt/src/hpke.c @@ -45,24 +45,6 @@ #include #endif -const int hpkeSupportedKem[HPKE_SUPPORTED_KEM_LEN] = { - DHKEM_P256_HKDF_SHA256, - DHKEM_P384_HKDF_SHA384, - DHKEM_P521_HKDF_SHA512, - DHKEM_X25519_HKDF_SHA256, -}; - -const int hpkeSupportedKdf[HPKE_SUPPORTED_KDF_LEN] = { - HKDF_SHA256, - HKDF_SHA384, - HKDF_SHA512, -}; - -const int hpkeSupportedAead[HPKE_SUPPORTED_AEAD_LEN] = { - HPKE_AES_128_GCM, - HPKE_AES_256_GCM, -}; - static const char* KEM_STR = "KEM"; static const int KEM_STR_LEN = 3; @@ -132,9 +114,9 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) } XMEMSET(hpke, 0, sizeof(*hpke)); - hpke->kem = (word32)kem; - hpke->kdf = (word32)kdf; - hpke->aead = (word32)aead; + hpke->kem = (word16)kem; + hpke->kdf = (word16)kdf; + hpke->aead = (word16)aead; hpke->heap = heap; /* set kem_suite_id */ @@ -227,20 +209,26 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) if (ret == 0) { switch (kdf) { +#if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) case HKDF_SHA256: hpke->Nh = WC_SHA256_DIGEST_SIZE; hpke->kdf_digest = WC_SHA256; break; +#endif +#ifdef WOLFSSL_SHA384 case HKDF_SHA384: hpke->Nh = WC_SHA384_DIGEST_SIZE; hpke->kdf_digest = WC_SHA384; break; +#endif +#ifdef WOLFSSL_SHA512 case HKDF_SHA512: hpke->Nh = WC_SHA512_DIGEST_SIZE; hpke->kdf_digest = WC_SHA512; break; +#endif default: ret = BAD_FUNC_ARG; @@ -250,17 +238,21 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) if (ret == 0) { switch (aead) { +#ifdef WOLFSSL_AES_128 case HPKE_AES_128_GCM: hpke->Nk = AES_128_KEY_SIZE; hpke->Nn = GCM_NONCE_MID_SZ; hpke->Nt = WC_AES_BLOCK_SIZE; break; +#endif +#ifdef WOLFSSL_AES_256 case HPKE_AES_256_GCM: hpke->Nk = AES_256_KEY_SIZE; hpke->Nn = GCM_NONCE_MID_SZ; hpke->Nt = WC_AES_BLOCK_SIZE; break; +#endif default: ret = BAD_FUNC_ARG; @@ -329,7 +321,7 @@ int wc_HpkeGenerateKeyPair(Hpke* hpke, void** keypair, WC_RNG* rng) ret = MEMORY_E; if (ret != 0 && *keypair != NULL) { - wc_HpkeFreeKey(hpke, (word16)hpke->kem, *keypair, hpke->heap); + wc_HpkeFreeKey(hpke, hpke->kem, *keypair, hpke->heap); *keypair = NULL; } @@ -427,7 +419,7 @@ int wc_HpkeDeserializePublicKey(Hpke* hpke, void** key, const byte* in, ret = MEMORY_E; if (ret != 0 && *key != NULL) { - wc_HpkeFreeKey(hpke, (word16)hpke->kem, *key, hpke->heap); + wc_HpkeFreeKey(hpke, hpke->kem, *key, hpke->heap); *key = NULL; } @@ -1083,7 +1075,7 @@ static int wc_HpkeDecap(Hpke* hpke, void* receiverKey, const byte* pubKey, } if (ephemeralKey != NULL) - wc_HpkeFreeKey(hpke, (word16)hpke->kem, ephemeralKey, hpke->heap); + wc_HpkeFreeKey(hpke, hpke->kem, ephemeralKey, hpke->heap); if (ret == 0) { /* copy pubKey into kemContext */ @@ -1226,4 +1218,98 @@ int wc_HpkeOpenBase(Hpke* hpke, void* receiverKey, const byte* pubKey, return ret; } +WOLFSSL_LOCAL word16 wc_HpkeKemGetEncLen(word16 kemId) +{ + switch (kemId) + { +#if defined(HAVE_ECC) +#if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) + case DHKEM_P256_HKDF_SHA256: + return DHKEM_P256_ENC_LEN; +#endif +#ifdef WOLFSSL_SHA384 + case DHKEM_P384_HKDF_SHA384: + return DHKEM_P384_ENC_LEN; +#endif +#if defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) + case DHKEM_P521_HKDF_SHA512: + return DHKEM_P521_ENC_LEN; +#endif +#endif /* HAVE_ECC */ +#if defined(HAVE_CURVE25519) && \ + (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) + case DHKEM_X25519_HKDF_SHA256: + return DHKEM_X25519_ENC_LEN; +#endif +#if defined(HAVE_CURVE448) &&\ + (defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)) + case DHKEM_X448_HKDF_SHA512: + return DHKEM_X448_ENC_LEN; +#endif + default: + return 0; + } +} + +WOLFSSL_LOCAL int wc_HpkeKemIsSupported(word16 kemId) +{ + switch (kemId) { +#if defined(HAVE_ECC) +#if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) + case DHKEM_P256_HKDF_SHA256: +#endif +#ifdef WOLFSSL_SHA384 + case DHKEM_P384_HKDF_SHA384: +#endif +#if defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) + case DHKEM_P521_HKDF_SHA512: +#endif +#endif /* HAVE_ECC */ +#if defined(HAVE_CURVE25519) && \ + (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) + case DHKEM_X25519_HKDF_SHA256: +#endif + return 1; + + case DHKEM_X448_HKDF_SHA512: + default: + return 0; + } +} + +WOLFSSL_LOCAL int wc_HpkeKdfIsSupported(word16 kdfId) +{ + switch (kdfId) { +#if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) + case HKDF_SHA256: +#endif +#ifdef WOLFSSL_SHA384 + case HKDF_SHA384: +#endif +#ifdef WOLFSSL_SHA512 + case HKDF_SHA512: +#endif + return 1; + + default: + return 0; + } +} + +WOLFSSL_LOCAL int wc_HpkeAeadIsSupported(word16 aeadId) +{ + switch (aeadId) { +#ifdef WOLFSSL_AES_128 + case HPKE_AES_128_GCM: +#endif +#ifdef WOLFSSL_AES_256 + case HPKE_AES_256_GCM: +#endif + return 1; + + default: + return 0; + } +} + #endif /* HAVE_HPKE && (HAVE_ECC || HAVE_CURVE25519) && HAVE_AESGCM */ diff --git a/wolfssl/wolfcrypt/hpke.h b/wolfssl/wolfcrypt/hpke.h index d6d82aaf1f5..09f0e6bc117 100644 --- a/wolfssl/wolfcrypt/hpke.h +++ b/wolfssl/wolfcrypt/hpke.h @@ -64,14 +64,6 @@ enum { HPKE_AES_256_GCM = 0x0002 }; -/* TODO better way of doing this */ -#define HPKE_SUPPORTED_KEM_LEN 4 -#define HPKE_SUPPORTED_KDF_LEN 3 -#define HPKE_SUPPORTED_AEAD_LEN 2 -extern const int hpkeSupportedKem[HPKE_SUPPORTED_KEM_LEN]; -extern const int hpkeSupportedKdf[HPKE_SUPPORTED_KDF_LEN]; -extern const int hpkeSupportedAead[HPKE_SUPPORTED_AEAD_LEN]; - #define HPKE_Nh_MAX 64 #define HPKE_Nk_MAX 32 #define HPKE_Nn_MAX 12 @@ -88,9 +80,6 @@ extern const int hpkeSupportedAead[HPKE_SUPPORTED_AEAD_LEN]; typedef struct { void* heap; - word32 kem; - word32 kdf; - word32 aead; word32 Nh; word32 Nk; word32 Nn; @@ -101,6 +90,9 @@ typedef struct { int kdf_digest; int kem_digest; int curve_id; + word16 kem; + word16 kdf; + word16 aead; byte kem_suite_id[KEM_SUITE_ID_LEN]; byte hpke_suite_id[HPKE_SUITE_ID_LEN]; } Hpke; @@ -137,6 +129,11 @@ 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); +WOLFSSL_LOCAL word16 wc_HpkeKemGetEncLen(word16 kemId); +WOLFSSL_LOCAL int wc_HpkeKemIsSupported(word16 kemId); +WOLFSSL_LOCAL int wc_HpkeKdfIsSupported(word16 kdfId); +WOLFSSL_LOCAL int wc_HpkeAeadIsSupported(word16 aeadId); + #endif #endif /* HAVE_HPKE && HAVE_ECC */ From 8445493dd9d81c45b87c54455b125d29f820a6ae Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Mon, 16 Mar 2026 11:37:10 -0600 Subject: [PATCH 3/7] hpke snake_case to camelCase --- wolfcrypt/src/hpke.c | 46 ++++++++++++++++++++-------------------- wolfssl/wolfcrypt/hpke.h | 6 +++--- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/wolfcrypt/src/hpke.c b/wolfcrypt/src/hpke.c index 4039b4cf22c..9785332794c 100644 --- a/wolfcrypt/src/hpke.c +++ b/wolfcrypt/src/hpke.c @@ -150,30 +150,30 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) #if defined(HAVE_ECC) #if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) case DHKEM_P256_HKDF_SHA256: - hpke->curve_id = ECC_SECP256R1; + hpke->curveId = ECC_SECP256R1; hpke->Nsecret = WC_SHA256_DIGEST_SIZE; - hpke->kem_digest = WC_SHA256; - hpke->Ndh = (word32)wc_ecc_get_curve_size_from_id(hpke->curve_id); + hpke->kemDigest = WC_SHA256; + hpke->Ndh = (word32)wc_ecc_get_curve_size_from_id(hpke->curveId); hpke->Npk = 1 + hpke->Ndh * 2; break; #endif #ifdef WOLFSSL_SHA384 case DHKEM_P384_HKDF_SHA384: - hpke->curve_id = ECC_SECP384R1; + hpke->curveId = ECC_SECP384R1; hpke->Nsecret = WC_SHA384_DIGEST_SIZE; - hpke->kem_digest = WC_SHA384; - hpke->Ndh = (word32)wc_ecc_get_curve_size_from_id(hpke->curve_id); + hpke->kemDigest = WC_SHA384; + hpke->Ndh = (word32)wc_ecc_get_curve_size_from_id(hpke->curveId); hpke->Npk = 1 + hpke->Ndh * 2; break; #endif #if defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) case DHKEM_P521_HKDF_SHA512: - hpke->curve_id = ECC_SECP521R1; + hpke->curveId = ECC_SECP521R1; hpke->Nsecret = WC_SHA512_DIGEST_SIZE; - hpke->kem_digest = WC_SHA512; - hpke->Ndh = (word32)wc_ecc_get_curve_size_from_id(hpke->curve_id); + hpke->kemDigest = WC_SHA512; + hpke->Ndh = (word32)wc_ecc_get_curve_size_from_id(hpke->curveId); hpke->Npk = 1 + hpke->Ndh * 2; break; #endif @@ -183,7 +183,7 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) case DHKEM_X25519_HKDF_SHA256: hpke->Nsecret = WC_SHA256_DIGEST_SIZE; - hpke->kem_digest = WC_SHA256; + hpke->kemDigest = WC_SHA256; hpke->Ndh = CURVE25519_KEYSIZE; hpke->Npk = CURVE25519_PUB_KEY_SIZE; break; @@ -193,7 +193,7 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) (defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)) case DHKEM_X448_HKDF_SHA512: hpke->Nsecret = WC_SHA512_DIGEST_SIZE; - hpke->kem_digest = WC_SHA512; + hpke->kemDigest = WC_SHA512; /* size of x448 shared secret */ hpke->Ndh = 64; hpke->Npk = CURVE448_PUB_KEY_SIZE; @@ -212,21 +212,21 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) #if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) case HKDF_SHA256: hpke->Nh = WC_SHA256_DIGEST_SIZE; - hpke->kdf_digest = WC_SHA256; + hpke->kdfDigest = WC_SHA256; break; #endif #ifdef WOLFSSL_SHA384 case HKDF_SHA384: hpke->Nh = WC_SHA384_DIGEST_SIZE; - hpke->kdf_digest = WC_SHA384; + hpke->kdfDigest = WC_SHA384; break; #endif #ifdef WOLFSSL_SHA512 case HKDF_SHA512: hpke->Nh = WC_SHA512_DIGEST_SIZE; - hpke->kdf_digest = WC_SHA512; + hpke->kdfDigest = WC_SHA512; break; #endif @@ -392,7 +392,7 @@ int wc_HpkeDeserializePublicKey(Hpke* hpke, void** key, const byte* in, if (*key != NULL) { /* import the x963 key */ ret = wc_ecc_import_x963_ex(in, inSz, (ecc_key*)*key, - hpke->curve_id); + hpke->curveId); } break; #endif @@ -636,13 +636,13 @@ static int wc_HpkeExtractAndExpand( Hpke* hpke, byte* dh, word32 dh_len, /* extract */ ret = wc_HpkeLabeledExtract(hpke, hpke->kem_suite_id, - sizeof( hpke->kem_suite_id ), hpke->kem_digest, NULL, 0, + sizeof( hpke->kem_suite_id ), hpke->kemDigest, NULL, 0, (byte*)EAE_PRK_LABEL_STR, EAE_PRK_LABEL_STR_LEN, dh, dh_len, eae_prk); /* expand */ if ( ret == 0 ) { ret = wc_HpkeLabeledExpand(hpke, hpke->kem_suite_id, - sizeof( hpke->kem_suite_id ), hpke->kem_digest, eae_prk, + sizeof( hpke->kem_suite_id ), hpke->kemDigest, eae_prk, hpke->Nsecret, (byte*)SHARED_SECRET_LABEL_STR, SHARED_SECRET_LABEL_STR_LEN, kemContext, kem_context_length, hpke->Nsecret, sharedSecret); @@ -695,14 +695,14 @@ static int wc_HpkeKeyScheduleBase(Hpke* hpke, HpkeBaseContext* context, /* extract psk_id, which for base is null */ ret = wc_HpkeLabeledExtract(hpke, hpke->hpke_suite_id, - sizeof( hpke->hpke_suite_id ), hpke->kdf_digest, NULL, 0, + sizeof( hpke->hpke_suite_id ), hpke->kdfDigest, NULL, 0, (byte*)PSK_ID_HASH_LABEL_STR, PSK_ID_HASH_LABEL_STR_LEN, NULL, 0, key_schedule_context + 1); /* extract info */ if (ret == 0) { ret = wc_HpkeLabeledExtract(hpke, hpke->hpke_suite_id, - sizeof( hpke->hpke_suite_id ), hpke->kdf_digest, NULL, 0, + sizeof( hpke->hpke_suite_id ), hpke->kdfDigest, NULL, 0, (byte*)INFO_HASH_LABEL_STR, INFO_HASH_LABEL_STR_LEN, info, infoSz, key_schedule_context + 1 + hpke->Nh); } @@ -710,7 +710,7 @@ static int wc_HpkeKeyScheduleBase(Hpke* hpke, HpkeBaseContext* context, /* extract secret */ if (ret == 0) { ret = wc_HpkeLabeledExtract(hpke, hpke->hpke_suite_id, - sizeof( hpke->hpke_suite_id ), hpke->kdf_digest, sharedSecret, + sizeof( hpke->hpke_suite_id ), hpke->kdfDigest, sharedSecret, hpke->Nsecret, (byte*)SECRET_LABEL_STR, SECRET_LABEL_STR_LEN, NULL, 0, secret); } @@ -718,14 +718,14 @@ static int wc_HpkeKeyScheduleBase(Hpke* hpke, HpkeBaseContext* context, /* expand key */ if (ret == 0) ret = wc_HpkeLabeledExpand(hpke, hpke->hpke_suite_id, - sizeof( hpke->hpke_suite_id ), hpke->kdf_digest, secret, hpke->Nh, + sizeof( hpke->hpke_suite_id ), hpke->kdfDigest, secret, hpke->Nh, (byte*)KEY_LABEL_STR, KEY_LABEL_STR_LEN, key_schedule_context, 1 + 2 * hpke->Nh, hpke->Nk, context->key); /* expand nonce */ if (ret == 0) { ret = wc_HpkeLabeledExpand(hpke, hpke->hpke_suite_id, - sizeof( hpke->hpke_suite_id ), hpke->kdf_digest, secret, hpke->Nh, + sizeof( hpke->hpke_suite_id ), hpke->kdfDigest, secret, hpke->Nh, (byte*)BASE_NONCE_LABEL_STR, BASE_NONCE_LABEL_STR_LEN, key_schedule_context, 1 + 2 * hpke->Nh, hpke->Nn, context->base_nonce); @@ -734,7 +734,7 @@ static int wc_HpkeKeyScheduleBase(Hpke* hpke, HpkeBaseContext* context, /* expand exporter_secret */ if (ret == 0) { ret = wc_HpkeLabeledExpand(hpke, hpke->hpke_suite_id, - sizeof( hpke->hpke_suite_id ), hpke->kdf_digest, secret, hpke->Nh, + sizeof( hpke->hpke_suite_id ), hpke->kdfDigest, secret, hpke->Nh, (byte*)EXP_LABEL_STR, EXP_LABEL_STR_LEN, key_schedule_context, 1 + 2 * hpke->Nh, hpke->Nh, context->exporter_secret); } diff --git a/wolfssl/wolfcrypt/hpke.h b/wolfssl/wolfcrypt/hpke.h index 09f0e6bc117..558d7d8c53c 100644 --- a/wolfssl/wolfcrypt/hpke.h +++ b/wolfssl/wolfcrypt/hpke.h @@ -87,9 +87,9 @@ typedef struct { word32 Ndh; word32 Npk; word32 Nsecret; - int kdf_digest; - int kem_digest; - int curve_id; + int kdfDigest; + int kemDigest; + int curveId; word16 kem; word16 kdf; word16 aead; From 7e9f9dc1406bd30ef58ed6ce24565d97ac6b2b32 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Tue, 17 Mar 2026 12:05:30 -0600 Subject: [PATCH 4/7] refactor openssl-ech workflow + add suite testing --- .github/scripts/openssl-ech.sh | 190 ++++++++++++++++++++++++++++++ .github/workflows/openssl-ech.yml | 133 ++++----------------- examples/server/server.c | 35 +++++- tests/api.c | 24 ++++ 4 files changed, 265 insertions(+), 117 deletions(-) create mode 100644 .github/scripts/openssl-ech.sh diff --git a/.github/scripts/openssl-ech.sh b/.github/scripts/openssl-ech.sh new file mode 100644 index 00000000000..a2d31785152 --- /dev/null +++ b/.github/scripts/openssl-ech.sh @@ -0,0 +1,190 @@ +#!/bin/bash + +set -e + +cleanup() { + cat "$TMP_LOG" + rm -f "$TMP_LOG" +} +trap cleanup EXIT + +usage() { + echo "Usage: $0 [--suite ] [--workspace ]" + exit 1 +} + +MODE="" +SUITE="" + +WORKSPACE=${GITHUB_WORKSPACE:-"."} + +if [ $# -lt 1 ]; then + usage +fi + +case "$1" in + client|server) MODE="$1" ;; + *) usage ;; +esac +shift + +while [ $# -gt 0 ]; do + case "$1" in + --suite) + [ -z "$2" ] && { echo "ERROR: --suite requires a value"; exit 1; } + SUITE="$2" + shift 2 + echo "" + echo "Using suite: $SUITE" + echo "" + ;; + --workspace) + [ -z "$2" ] && { echo "ERROR: --workspace requires a value"; exit 1; } + WORKSPACE="$2" + shift 2 + ;; + *) echo "Unknown argument: $1"; usage ;; + esac +done + +OPENSSL=${OPENSSL:-"openssl"} +WOLFSSL_CLIENT=${WOLFSSL_CLIENT:-"$WORKSPACE/examples/client/client"} +WOLFSSL_SERVER=${WOLFSSL_SERVER:-"$WORKSPACE/examples/server/server"} +CERT_DIR=${CERT_DIR:-"$WORKSPACE/certs"} + +TMP_LOG="$WORKSPACE/tmp_file.log" +PRIV_NAME="ech-private-name.com" +PUB_NAME="ech-public-name.com" +MAX_WAIT=50 + +openssl_server(){ + local ech_file="$WORKSPACE/ech_config.pem" + local ech_config="" + local port="" + + rm -f "$ech_file" + + $OPENSSL ech -public_name "$PUB_NAME" -out "$ech_file" $SUITE &>> "$TMP_LOG" + + # parse ECH config from file + ech_config=$(sed -n '/BEGIN ECHCONFIG/,/END ECHCONFIG/{/BEGIN ECHCONFIG\|END ECHCONFIG/d;p}' "$ech_file" | tr -d '\n') + echo "parsed ech config: $ech_config" &>> "$TMP_LOG" + + # start OpenSSL ECH server with ephemeral port and make sure it is + # line-buffered + stdbuf -oL $OPENSSL s_server \ + -tls1_3 \ + -cert "$CERT_DIR/server-cert.pem" \ + -key "$CERT_DIR/server-key.pem" \ + -cert2 "$CERT_DIR/server-cert.pem" \ + -key2 "$CERT_DIR/server-key.pem" \ + -ech_key "$ech_file" \ + -servername "$PRIV_NAME" \ + -accept 0 \ + -naccept 1 \ + &>> "$TMP_LOG" <<< "wolfssl!" & + + # wait for server port to be ready and capture it + counter=0 + while [ -z "$port" ]; do + port=$(grep -m1 "ACCEPT" "$TMP_LOG" | sed 's/.*:\([0-9]*\)$/\1/') + sleep 0.1 + counter=$((counter + 1)) + if [ "$counter" -gt "$MAX_WAIT" ]; then + echo "ERROR: server port not found" &>> "$TMP_LOG" + exit 1 + fi + done + echo "parsed port: $port" &>> "$TMP_LOG" + + # test with wolfssl client + $WOLFSSL_CLIENT -v 4 \ + -p "$port" \ + -S "$PRIV_NAME" \ + --ech "$ech_config" \ + &>> "$TMP_LOG" + + rm -f "$ech_file" + + grep -q "ech_success=1" "$TMP_LOG" +} + +openssl_client(){ + local ready_file="$WORKSPACE/wolfssl_tls13_ready$$" + local ech_config="" + local port=0 + + rm -f "$ready_file" + + # start server with ephemeral port + ready file + # also set server to be line buffered so the log can be grepped + stdbuf -oL $WOLFSSL_SERVER \ + -v 4 \ + -R "$ready_file" \ + -p "$port" \ + -S "$PRIV_NAME" \ + --ech "$PUB_NAME" \ + $SUITE \ + &>> "$TMP_LOG" & + + # wait for server to be ready, then get port + counter=0 + while [ ! -s "$ready_file" ]; do + sleep 0.1 + counter=$((counter + 1)) + if [ "$counter" -gt "$MAX_WAIT" ]; then + echo "ERROR: no ready file" &>> "$TMP_LOG" + exit 1 + fi + done + port="$(cat "$ready_file")" + rm -f "$ready_file" + echo "parsed port: $port" &>> "$TMP_LOG" + + # get ECH config from server + counter=0 + while [ -z "$ech_config" ]; do + ech_config=$(grep -m1 "ECH config (base64): " "$TMP_LOG" \ + 2>/dev/null | sed 's/ECH config (base64): //g') + sleep 0.1 + counter=$((counter + 1)) + if [ "$counter" -gt "$MAX_WAIT" ]; then + echo "ERROR: no ECH configs" &>> "$TMP_LOG" + exit 1 + fi + done + echo "parsed ech config: $ech_config" &>> "$TMP_LOG" + + # Test with OpenSSL s_client using ECH + echo "wolfssl" | $OPENSSL s_client \ + -tls1_3 \ + -connect "localhost:$port" \ + -cert "$CERT_DIR/client-cert.pem" \ + -key "$CERT_DIR/client-key.pem" \ + -CAfile "$CERT_DIR/ca-cert.pem" \ + -servername "$PRIV_NAME" \ + -ech_config_list "$ech_config" \ + &>> "$TMP_LOG" + + grep -q "ECH: success: 1" "$TMP_LOG" +} + +rm -f "$TMP_LOG" + +case "$MODE" in + server) + if [ -n "$SUITE" ]; then + SUITE="-suite $SUITE" + fi + openssl_server + ;; + client) + if [ -n "$SUITE" ]; then + SUITE="--ech-suite $SUITE" + fi + openssl_client + ;; + *) + exit 1 + ;; +esac diff --git a/.github/workflows/openssl-ech.yml b/.github/workflows/openssl-ech.yml index 83a73ee55db..e0832738d28 100644 --- a/.github/workflows/openssl-ech.yml +++ b/.github/workflows/openssl-ech.yml @@ -23,7 +23,8 @@ jobs: uses: wolfSSL/actions-build-autotools-project@v1 with: path: wolfssl - configure: --enable-ech CFLAGS='-DUSE_FLAT_TEST_H' + configure: >- + --enable-ech --enable-sha512 --enable-aes CFLAGS='-DUSE_FLAT_TEST_H' install: true - name: tar build-dir @@ -38,6 +39,10 @@ jobs: cp -r "$GITHUB_WORKSPACE/wolfssl/certs" build-dir/certs tar -zcf build-dir.tgz build-dir + # need the ech script to run tests + cp "$GITHUB_WORKSPACE/wolfssl/.github/scripts/openssl-ech.sh" \ + build-dir/openssl-ech.sh + - name: Upload built wolfSSL uses: actions/upload-artifact@v4 with: @@ -117,76 +122,23 @@ jobs: export LD_LIBRARY_PATH="$GITHUB_WORKSPACE/openssl-install/lib64:$GITHUB_WORKSPACE/openssl-install/lib:$GITHUB_WORKSPACE/build-dir/lib:$LD_LIBRARY_PATH" - OPENSSL=$GITHUB_WORKSPACE/openssl-install/bin/openssl - WOLFSSL_SERVER=$GITHUB_WORKSPACE/build-dir/bin/server - + OPENSSL="$GITHUB_WORKSPACE/openssl-install/bin/openssl" + WOLFSSL_SERVER="$GITHUB_WORKSPACE/build-dir/bin/server" CERT_DIR="$GITHUB_WORKSPACE/build-dir/certs" - READY_FILE="$GITHUB_WORKSPACE/wolfssl_tls13_ready$$" LOG_FILE="$GITHUB_WORKSPACE/log_file.log" - PRIV_NAME="ech-private-name.com" - PUB_NAME="ech-public-name.com" - ECH_CONFIG="" - PORT=0 - - rm -f "$READY_FILE" # need to cd into build-dir so the certs/ dir is available for server cd build-dir $OPENSSL version | tee "$LOG_FILE" - # start server with ephemeral port + ready file - # also set server to be line buffered so the log can be grepped - stdbuf -oL $WOLFSSL_SERVER \ - -v 4 \ - -R "$READY_FILE" \ - -p "$PORT" \ - -S "$PRIV_NAME" \ - --ech "$PUB_NAME" \ - &>> "$LOG_FILE" & - - # wait for server to be ready, then get port - counter=0 - while [ ! -s "$READY_FILE" ]; do - sleep 0.1 - counter=$((counter + 1)) - if [ "$counter" -gt 50 ]; then - echo "ERROR: no ready file" &>> "$LOG_FILE" - exit 1 - fi - done - PORT="$(cat "$READY_FILE")" - echo "parsed port: $PORT" &>> "$LOG_FILE" - - # get ECH config from server - counter=0 - while [ -z "$ECH_CONFIG" ]; do - ECH_CONFIG=$(grep -m1 "ECH config (base64): " "$LOG_FILE" \ - 2>/dev/null | sed 's/ECH config (base64): //g') - sleep 0.1 - counter=$((counter + 1)) - if [ "$counter" -gt 50 ]; then - echo "ERROR: no ECH configs" &>> "$LOG_FILE" - exit 1 - fi - done - echo "parsed ech config: $ECH_CONFIG" &>> "$LOG_FILE" - - # Test with OpenSSL s_client using ECH - echo "wolfssl" | $OPENSSL s_client \ - -tls1_3 \ - -connect "localhost:$PORT" \ - -cert "$CERT_DIR/client-cert.pem" \ - -key "$CERT_DIR/client-key.pem" \ - -CAfile "$CERT_DIR/ca-cert.pem" \ - -servername "$PRIV_NAME" \ - -ech_config_list "$ECH_CONFIG" \ - &>> "$LOG_FILE" - - grep "ECH: success: 1" "$LOG_FILE" + # default suite (DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, HPKE_AES_128_GCM) + bash ./openssl-ech.sh client &>> "$LOG_FILE" + + # weird suite (DHKEM_P521_HKDF_SHA512, HKDF_SHA256, HPKE_AES_256_GCM) + bash ./openssl-ech.sh client --suite "18,3,2" &>> "$LOG_FILE" # cleanup - rm -f "$READY_FILE" rm -f "$LOG_FILE" - name: Print debug info on failure @@ -238,69 +190,24 @@ jobs: export LD_LIBRARY_PATH="$GITHUB_WORKSPACE/openssl-install/lib64:$GITHUB_WORKSPACE/openssl-install/lib:$GITHUB_WORKSPACE/build-dir/lib:$LD_LIBRARY_PATH" - OPENSSL=$GITHUB_WORKSPACE/openssl-install/bin/openssl - WOLFSSL_CLIENT=$GITHUB_WORKSPACE/build-dir/bin/client - + OPENSSL="$GITHUB_WORKSPACE/openssl-install/bin/openssl" + WOLFSSL_CLIENT="$GITHUB_WORKSPACE/build-dir/bin/client" CERT_DIR="$GITHUB_WORKSPACE/build-dir/certs" LOG_FILE="$GITHUB_WORKSPACE/log_file.log" - ECH_FILE="$GITHUB_WORKSPACE/ech_config.pem" - PRIV_NAME="ech-private-name.com" - PUB_NAME="ech-public-name.com" - PORT="" - ECH_CONFIG="" - - rm -f "$ECH_FILE" # need to cd into build-dir so the certs/ dir is available for client cd build-dir $OPENSSL version | tee "$LOG_FILE" - $OPENSSL ech -public_name "$PUB_NAME" -out "$ECH_FILE" &>> "$LOG_FILE" - - # parse ECH config from file - ECH_CONFIG=$(sed -n '/BEGIN ECHCONFIG/,/END ECHCONFIG/{/BEGIN ECHCONFIG\|END ECHCONFIG/d;p}' "$ECH_FILE" | tr -d '\n') - echo "parsed ech config: $ECH_CONFIG" &>> "$LOG_FILE" - - # start OpenSSL ECH server with ephemeral port and make sure it is - # line-buffered - stdbuf -oL $OPENSSL s_server \ - -tls1_3 \ - -cert "$CERT_DIR/server-cert.pem" \ - -key "$CERT_DIR/server-key.pem" \ - -cert2 "$CERT_DIR/server-cert.pem" \ - -key2 "$CERT_DIR/server-key.pem" \ - -ech_key "$ECH_FILE" \ - -servername "$PRIV_NAME" \ - -accept 0 \ - -naccept 1 \ - &>> "$LOG_FILE" <<< "wolfssl!" & - - # wait for server port to be ready and capture it - counter=0 - while [ -z "$PORT" ]; do - PORT=$(grep -m1 "ACCEPT" "$LOG_FILE" | sed 's/.*:\([0-9]*\)$/\1/') - sleep 0.1 - counter=$((counter + 1)) - if [ "$counter" -gt 50 ]; then - echo "ERROR: server port not found" &>> "$LOG_FILE" - exit 1 - fi - done - echo "parsed port: $PORT" &>> "$LOG_FILE" - - # test with wolfssl client - $WOLFSSL_CLIENT -v 4 \ - -p "$PORT" \ - -S "$PRIV_NAME" \ - --ech "$ECH_CONFIG" \ - &>> "$LOG_FILE" - - grep "ech_success=1" "$LOG_FILE" + # default suite (DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, HPKE_AES_128_GCM) + bash ./openssl-ech.sh server &>> "$LOG_FILE" + + # weird suite (DHKEM_P521_HKDF_SHA512, HKDF_SHA256, HPKE_AES_256_GCM) + bash ./openssl-ech.sh server --suite "18,3,2" &>> "$LOG_FILE" # cleanup rm -f "$LOG_FILE" - rm -f "$ECH_FILE" - name: Print debug info on failure if: ${{ failure() }} diff --git a/examples/server/server.c b/examples/server/server.c index 07e480eb558..921fa1621c3 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -919,7 +919,7 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519, /* 4. add the same message into Japanese section */ /* (will be translated later) */ /* 5. add printf() into suitable position of Usage() */ -static const char* server_usage_msg[][69] = { +static const char* server_usage_msg[][70] = { /* English */ { " NOTE: All files relative to wolfSSL home dir\n", /* 0 */ @@ -1120,11 +1120,14 @@ static const char* server_usage_msg[][69] = { "--ech Generate Encrypted Client Hello config with " "public name \n", /* 67 */ + "--ech-suite HPKE suite to use for ech config. " + "Supplied as 3 integers (e.g., 32,1,3)\n", + /* 68 */ #endif "\n" "For simpler wolfSSL TLS server examples, visit\n" "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", - /* 68 */ + /* 69 */ NULL, }, #ifndef NO_MULTIBYTE_PRINT @@ -1502,6 +1505,7 @@ static void Usage(void) #endif #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) printf("%s", msg[++msgId]); /* --ech */ + printf("%s", msg[++msgId]); /* --ech-suite */ #endif printf("%s", msg[++msgId]); /* Examples repo link */ } @@ -1627,6 +1631,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #endif /* WOLFSSL_SYS_CRYPTO_POLICY */ #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) { "ech", 1, 269 }, + { "ech-suite", 1, 270 }, #endif { 0, 0, 0 } }; @@ -1706,6 +1711,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #endif #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) char* echPublicName = NULL; + char* echSuite = NULL; #endif #ifdef HAVE_TRUSTED_CA @@ -2539,6 +2545,9 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) case 269: echPublicName = myoptarg; break; + case 270: + echSuite = myoptarg; + break; #endif case -1: @@ -3107,9 +3116,27 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) char echConfigBase64[512]; char* echConfigBase64Ptr; word32 echConfigBase64Len = sizeof(echConfigBase64); + word16 kemId = 0; + word16 kdfId = 0; + word16 aeadId = 0; - if (wolfSSL_CTX_GenerateEchConfig(ctx, echPublicName, 0, 0, 0) - != WOLFSSL_SUCCESS) { + /* an optimistic approach to parsing the ciphersuite */ + if (echSuite != NULL) { + const char* s = echSuite; + + kemId = (word16)atoi(s); + for (; *s != '\0' && *s != ','; s++); + if (*s == ',') s++; + + kdfId = (word16)atoi(s); + for (; *s != '\0' && *s != ','; s++); + if (*s == ',') s++; + + aeadId = (word16)atoi(s); + } + + if (wolfSSL_CTX_GenerateEchConfig(ctx, echPublicName, kemId, kdfId, + aeadId) != WOLFSSL_SUCCESS) { err_sys_ex(runWithErrors, "GenerateEchConfig failed"); } if (wolfSSL_CTX_GetEchConfigs(ctx, echConfig, &echConfigLen) diff --git a/tests/api.c b/tests/api.c index ce610df6278..99d5a5380da 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14535,6 +14535,30 @@ static int test_wolfSSL_Tls13_ECH_all_algos_ex(void) ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS); ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 1); + if (echCbTestKemID != 0 && echCbTestKdfID != 0 && echCbTestAeadID != 0) { + TLSX* echX = TLSX_Find(test_ctx.c_ssl->extensions, TLSX_ECH); + ExpectNotNull(echX); + if (echX != NULL) { + WOLFSSL_ECH* ech = (WOLFSSL_ECH*)echX->data; + ExpectNotNull(ech); + if (ech != NULL) { + /* verify that the ech extension has the correct algos */ + ExpectIntEQ(ech->kemId, echCbTestKemID); + ExpectIntEQ(ech->cipherSuite.kdfId, echCbTestKdfID); + ExpectIntEQ(ech->cipherSuite.aeadId, echCbTestAeadID); + if (ech->hpke != NULL) { + /* and that hpke was initialized with these algos */ + ExpectIntEQ(ech->hpke->kem, echCbTestKemID); + ExpectIntEQ(ech->hpke->kdf, echCbTestKdfID); + ExpectIntEQ(ech->hpke->aead, echCbTestAeadID); + } + if (ech->echConfig != NULL) { + ExpectIntEQ(ech->echConfig->kemId, echCbTestKemID); + } + } + } + } + test_ssl_memio_cleanup(&test_ctx); return EXPECT_RESULT(); From fcedc91d3885e559d140e13ef87ebbe7459a3bc7 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Wed, 18 Mar 2026 10:30:27 -0600 Subject: [PATCH 5/7] touch-ups: - shrink ech interop workflow - x448 macro now unused in hpke WOLFSSL_LOCAL functions - bug fixes in added tests --- .github/scripts/openssl-ech.sh | 6 +- .github/workflows/openssl-ech.yml | 98 +++++++------------------------ examples/server/server.c | 58 +++++++++++------- src/ssl_ech.c | 2 +- src/tls.c | 4 ++ tests/api.c | 2 +- wolfcrypt/src/hpke.c | 14 +++-- 7 files changed, 77 insertions(+), 107 deletions(-) diff --git a/.github/scripts/openssl-ech.sh b/.github/scripts/openssl-ech.sh index a2d31785152..d3dde32b6ef 100644 --- a/.github/scripts/openssl-ech.sh +++ b/.github/scripts/openssl-ech.sh @@ -3,8 +3,10 @@ set -e cleanup() { - cat "$TMP_LOG" - rm -f "$TMP_LOG" + if [ -f "$TMP_LOG" ]; then + cat "$TMP_LOG" + rm -f "$TMP_LOG" + fi } trap cleanup EXIT diff --git a/.github/workflows/openssl-ech.yml b/.github/workflows/openssl-ech.yml index e0832738d28..e295062c716 100644 --- a/.github/workflows/openssl-ech.yml +++ b/.github/workflows/openssl-ech.yml @@ -37,12 +37,13 @@ jobs: # need certs so 'wolfSSL error: wolf root not found' does not show up cp -r "$GITHUB_WORKSPACE/wolfssl/certs" build-dir/certs - tar -zcf build-dir.tgz build-dir # need the ech script to run tests cp "$GITHUB_WORKSPACE/wolfssl/.github/scripts/openssl-ech.sh" \ build-dir/openssl-ech.sh + tar -zcf build-dir.tgz build-dir + - name: Upload built wolfSSL uses: actions/upload-artifact@v4 with: @@ -82,8 +83,8 @@ jobs: path: openssl-install.tgz retention-days: 5 - ech_server_interop_test: - name: ECH Server Interop Test + ech_interop_test: + name: ECH Interop Test if: github.repository_owner == 'wolfssl' needs: [build_wolfssl, build_openssl_ech] runs-on: ubuntu-24.04 @@ -104,7 +105,7 @@ jobs: tar -xzf build-dir.tgz tar -xzf openssl-install.tgz - - name: Build wolfssl server example + - name: Build wolfssl client and server examples run: | export WOLFSSL_INSTALL_DIR="$GITHUB_WORKSPACE/build-dir" export WOLFSSL_BIN_DIR="$WOLFSSL_INSTALL_DIR/bin" @@ -112,19 +113,24 @@ jobs: export LIBS="-L$WOLFSSL_INSTALL_DIR/lib -lm -lwolfssl" export LD_LIBRARY_PATH="$WOLFSSL_INSTALL_DIR/lib/:$LD_LIBRARY_PATH" + gcc -o "$WOLFSSL_BIN_DIR/client" \ + "$WOLFSSL_INSTALL_DIR/share/doc/wolfssl/example/client.c" \ + $CFLAGS $LIBS -I"$WOLFSSL_INSTALL_DIR/share/doc/wolfssl/example" + gcc -o "$WOLFSSL_BIN_DIR/server" \ "$WOLFSSL_INSTALL_DIR/share/doc/wolfssl/example/server.c" \ $CFLAGS $LIBS -I"$WOLFSSL_INSTALL_DIR/share/doc/wolfssl/example" - - name: ECH interop - wolfSSL server, OpenSSL client + - name: Interop test run: | set -e export LD_LIBRARY_PATH="$GITHUB_WORKSPACE/openssl-install/lib64:$GITHUB_WORKSPACE/openssl-install/lib:$GITHUB_WORKSPACE/build-dir/lib:$LD_LIBRARY_PATH" - OPENSSL="$GITHUB_WORKSPACE/openssl-install/bin/openssl" - WOLFSSL_SERVER="$GITHUB_WORKSPACE/build-dir/bin/server" - CERT_DIR="$GITHUB_WORKSPACE/build-dir/certs" + export OPENSSL="$GITHUB_WORKSPACE/openssl-install/bin/openssl" + export WOLFSSL_CLIENT="$GITHUB_WORKSPACE/build-dir/bin/client" + export WOLFSSL_SERVER="$GITHUB_WORKSPACE/build-dir/bin/server" + export CERT_DIR="$GITHUB_WORKSPACE/build-dir/certs" LOG_FILE="$GITHUB_WORKSPACE/log_file.log" # need to cd into build-dir so the certs/ dir is available for server @@ -133,78 +139,18 @@ jobs: $OPENSSL version | tee "$LOG_FILE" # default suite (DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, HPKE_AES_128_GCM) + echo -e "\nTesting default suite with OpenSSL server and wolfSSL client\n" &>> "$LOG_FILE" + bash ./openssl-ech.sh server &>> "$LOG_FILE" + + echo -e "\nTesting default suite with OpenSSL client and wolfSSL server\n" &>> "$LOG_FILE" bash ./openssl-ech.sh client &>> "$LOG_FILE" # weird suite (DHKEM_P521_HKDF_SHA512, HKDF_SHA256, HPKE_AES_256_GCM) - bash ./openssl-ech.sh client --suite "18,3,2" &>> "$LOG_FILE" - - # cleanup - rm -f "$LOG_FILE" - - - name: Print debug info on failure - if: ${{ failure() }} - run: | - if [ -s "$GITHUB_WORKSPACE/log_file.log" ]; then - cat "$GITHUB_WORKSPACE/log_file.log" - else - echo "No log file" - fi + echo -e "\nTesting weird suite with OpenSSL server and wolfSSL client\n" &>> "$LOG_FILE" + bash ./openssl-ech.sh server --suite "18,1,2" &>> "$LOG_FILE" - ech_client_interop_test: - name: ECH Client Interop Test - if: github.repository_owner == 'wolfssl' - needs: [build_wolfssl, build_openssl_ech] - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Download wolfSSL build - uses: actions/download-artifact@v4 - with: - name: wolf-install-openssl-ech - - - name: Download OpenSSL build - uses: actions/download-artifact@v4 - with: - name: openssl-ech-install - - - name: Extract builds - run: | - tar -xzf build-dir.tgz - tar -xzf openssl-install.tgz - - - name: Build wolfssl client example - run: | - export WOLFSSL_INSTALL_DIR="$GITHUB_WORKSPACE/build-dir" - export WOLFSSL_BIN_DIR="$WOLFSSL_INSTALL_DIR/bin" - export CFLAGS="-Wall -I$WOLFSSL_INSTALL_DIR/include" - export LIBS="-L$WOLFSSL_INSTALL_DIR/lib -lm -lwolfssl" - export LD_LIBRARY_PATH="$WOLFSSL_INSTALL_DIR/lib/:$LD_LIBRARY_PATH" - - gcc -o "$WOLFSSL_BIN_DIR/client" \ - "$WOLFSSL_INSTALL_DIR/share/doc/wolfssl/example/client.c" \ - $CFLAGS $LIBS -I"$WOLFSSL_INSTALL_DIR/share/doc/wolfssl/example" - - - name: ECH interop - wolfSSL client, OpenSSL server - run: | - set -e - - export LD_LIBRARY_PATH="$GITHUB_WORKSPACE/openssl-install/lib64:$GITHUB_WORKSPACE/openssl-install/lib:$GITHUB_WORKSPACE/build-dir/lib:$LD_LIBRARY_PATH" - - OPENSSL="$GITHUB_WORKSPACE/openssl-install/bin/openssl" - WOLFSSL_CLIENT="$GITHUB_WORKSPACE/build-dir/bin/client" - CERT_DIR="$GITHUB_WORKSPACE/build-dir/certs" - LOG_FILE="$GITHUB_WORKSPACE/log_file.log" - - # need to cd into build-dir so the certs/ dir is available for client - cd build-dir - - $OPENSSL version | tee "$LOG_FILE" - - # default suite (DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, HPKE_AES_128_GCM) - bash ./openssl-ech.sh server &>> "$LOG_FILE" - - # weird suite (DHKEM_P521_HKDF_SHA512, HKDF_SHA256, HPKE_AES_256_GCM) - bash ./openssl-ech.sh server --suite "18,3,2" &>> "$LOG_FILE" + echo -e "\nTesting weird suite with OpenSSL client and wolfSSL server\n" &>> "$LOG_FILE" + bash ./openssl-ech.sh client --suite "18,1,2" &>> "$LOG_FILE" # cleanup rm -f "$LOG_FILE" diff --git a/examples/server/server.c b/examples/server/server.c index 921fa1621c3..85de7610c15 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -1120,8 +1120,8 @@ static const char* server_usage_msg[][70] = { "--ech Generate Encrypted Client Hello config with " "public name \n", /* 67 */ - "--ech-suite HPKE suite to use for ech config. " - "Supplied as 3 integers (e.g., 32,1,3)\n", + "--ech-suite HPKE suite to use for ech config.\n" + " Supplied as 3 integers (ex: 32,1,3)\n", /* 68 */ #endif "\n" @@ -1338,12 +1338,20 @@ static const char* server_usage_msg[][70] = { #endif #ifdef WOLFSSL_SYS_CRYPTO_POLICY "--crypto-policy \n", /* 66 */ +#endif +#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) + "--ech Generate Encrypted Client Hello config with " + "public name \n", + /* 67 */ + "--ech-suite HPKE suite to use for ech config.\n" + " Supplied as 3 integers (ex: 32,1,3)\n", + /* 68 */ #endif "\n" "より簡単なwolfSSL TSL クライアントの例については" "下記にアクセスしてください\n" "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", - /* 67 */ + /* 69 */ NULL, }, #endif @@ -1712,6 +1720,9 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) char* echPublicName = NULL; char* echSuite = NULL; + word16 kemId = 0; + word16 kdfId = 0; + word16 aeadId = 0; #endif #ifdef HAVE_TRUSTED_CA @@ -2547,6 +2558,29 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) break; case 270: echSuite = myoptarg; + + /* parse alg id's ignoring overflows + * commas can be entered with no number to accept the default */ + if (echSuite != NULL) { + kemId = (word16)atoi(echSuite); + for (; *echSuite != '\0' && *echSuite != ','; echSuite++); + if (*echSuite != ',') { + LOG_ERROR("Expected two commas '%s'\n", myoptarg); + XEXIT_T(EXIT_FAILURE); + } + echSuite++; + + kdfId = (word16)atoi(echSuite); + for (; *echSuite != '\0' && *echSuite != ','; echSuite++); + if (*echSuite != ',') { + LOG_ERROR("Expected two commas'%s'\n", myoptarg); + XEXIT_T(EXIT_FAILURE); + } + echSuite++; + + aeadId = (word16)atoi(echSuite); + } + break; #endif @@ -3116,24 +3150,6 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) char echConfigBase64[512]; char* echConfigBase64Ptr; word32 echConfigBase64Len = sizeof(echConfigBase64); - word16 kemId = 0; - word16 kdfId = 0; - word16 aeadId = 0; - - /* an optimistic approach to parsing the ciphersuite */ - if (echSuite != NULL) { - const char* s = echSuite; - - kemId = (word16)atoi(s); - for (; *s != '\0' && *s != ','; s++); - if (*s == ',') s++; - - kdfId = (word16)atoi(s); - for (; *s != '\0' && *s != ','; s++); - if (*s == ',') s++; - - aeadId = (word16)atoi(s); - } if (wolfSSL_CTX_GenerateEchConfig(ctx, echPublicName, kemId, kdfId, aeadId) != WOLFSSL_SUCCESS) { diff --git a/src/ssl_ech.c b/src/ssl_ech.c index a03e29e9163..86f6fe40ee0 100644 --- a/src/ssl_ech.c +++ b/src/ssl_ech.c @@ -35,7 +35,7 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName, { int ret = 0; WOLFSSL_EchConfig* newConfig; - word16 encLen = sizeof(newConfig->receiverPubkey); + word16 encLen = HPKE_Npk_MAX; #ifdef WOLFSSL_SMALL_STACK Hpke* hpke = NULL; WC_RNG* rng; diff --git a/src/tls.c b/src/tls.c index bb56c052afc..1ad10c6ab7f 100644 --- a/src/tls.c +++ b/src/tls.c @@ -13260,6 +13260,10 @@ static int TLSX_ECH_Use(WOLFSSL_EchConfig* echConfig, TLSX** extensions, ech->configId = echConfig->configId; /* encLen */ ech->encLen = wc_HpkeKemGetEncLen(echConfig->kemId); + if (ech->encLen == 0) { + XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER); + return BAD_FUNC_ARG; + } /* setup hpke */ ech->hpke = (Hpke*)XMALLOC(sizeof(Hpke), heap, DYNAMIC_TYPE_TMP_BUFFER); if (ech->hpke == NULL) { diff --git a/tests/api.c b/tests/api.c index 99d5a5380da..59a04dacf90 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14613,7 +14613,7 @@ static int test_wolfSSL_Tls13_ECH_all_algos(void) for (k = 0; k < (int)(sizeof(aeads) / sizeof(*aeads)); k++) { echCbTestAeadID = aeads[k]; ExpectIntEQ(test_wolfSSL_Tls13_ECH_all_algos_ex(), - WOLFSSL_SUCCESS); + TEST_SUCCESS); } } } diff --git a/wolfcrypt/src/hpke.c b/wolfcrypt/src/hpke.c index 9785332794c..f9ee11aff06 100644 --- a/wolfcrypt/src/hpke.c +++ b/wolfcrypt/src/hpke.c @@ -1218,6 +1218,8 @@ int wc_HpkeOpenBase(Hpke* hpke, void* receiverKey, const byte* pubKey, return ret; } +/* return the encrypted length of the KEM + * return 0 otherwise */ WOLFSSL_LOCAL word16 wc_HpkeKemGetEncLen(word16 kemId) { switch (kemId) @@ -1240,17 +1242,14 @@ WOLFSSL_LOCAL word16 wc_HpkeKemGetEncLen(word16 kemId) (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) case DHKEM_X25519_HKDF_SHA256: return DHKEM_X25519_ENC_LEN; -#endif -#if defined(HAVE_CURVE448) &&\ - (defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)) - case DHKEM_X448_HKDF_SHA512: - return DHKEM_X448_ENC_LEN; #endif default: return 0; } } +/* return true if hpke is compiled with support for the given KEM + * return false otherwise */ WOLFSSL_LOCAL int wc_HpkeKemIsSupported(word16 kemId) { switch (kemId) { @@ -1271,12 +1270,13 @@ WOLFSSL_LOCAL int wc_HpkeKemIsSupported(word16 kemId) #endif return 1; - case DHKEM_X448_HKDF_SHA512: default: return 0; } } +/* return true if hpke is compiled with support for the given KDF + * return false otherwise */ WOLFSSL_LOCAL int wc_HpkeKdfIsSupported(word16 kdfId) { switch (kdfId) { @@ -1296,6 +1296,8 @@ WOLFSSL_LOCAL int wc_HpkeKdfIsSupported(word16 kdfId) } } +/* return true if hpke is compiled with support for the given AEAD + * return false otherwise */ WOLFSSL_LOCAL int wc_HpkeAeadIsSupported(word16 aeadId) { switch (aeadId) { From cbb7bfc53ab73916f7ea2ccbaccc914296c8ae1c Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Thu, 19 Mar 2026 13:59:57 -0600 Subject: [PATCH 6/7] improved ifdef's for hpke --- examples/server/server.c | 6 ++-- wolfcrypt/src/hpke.c | 78 ++++++++++++++++++++++++++-------------- wolfcrypt/test/test.c | 46 +++++++++++++----------- wolfcrypt/test/test.h | 5 ++- wolfssl/wolfcrypt/hpke.h | 5 +-- 5 files changed, 87 insertions(+), 53 deletions(-) diff --git a/examples/server/server.c b/examples/server/server.c index 85de7610c15..166939e7834 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -2559,13 +2559,13 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) case 270: echSuite = myoptarg; - /* parse alg id's ignoring overflows + /* parse alg id's * commas can be entered with no number to accept the default */ if (echSuite != NULL) { kemId = (word16)atoi(echSuite); for (; *echSuite != '\0' && *echSuite != ','; echSuite++); if (*echSuite != ',') { - LOG_ERROR("Expected two commas '%s'\n", myoptarg); + LOG_ERROR("Expected two commas in '%s'\n", myoptarg); XEXIT_T(EXIT_FAILURE); } echSuite++; @@ -2573,7 +2573,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) kdfId = (word16)atoi(echSuite); for (; *echSuite != '\0' && *echSuite != ','; echSuite++); if (*echSuite != ',') { - LOG_ERROR("Expected two commas'%s'\n", myoptarg); + LOG_ERROR("Expected two commas in '%s'\n", myoptarg); XEXIT_T(EXIT_FAILURE); } echSuite++; diff --git a/wolfcrypt/src/hpke.c b/wolfcrypt/src/hpke.c index f9ee11aff06..fd5f76a2663 100644 --- a/wolfcrypt/src/hpke.c +++ b/wolfcrypt/src/hpke.c @@ -148,7 +148,7 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) if (ret == 0) { switch (kem) { #if defined(HAVE_ECC) -#if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) +#if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && !defined(NO_SHA256) case DHKEM_P256_HKDF_SHA256: hpke->curveId = ECC_SECP256R1; hpke->Nsecret = WC_SHA256_DIGEST_SIZE; @@ -158,7 +158,8 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) break; #endif -#ifdef WOLFSSL_SHA384 +#if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \ + defined(WOLFSSL_SHA384) case DHKEM_P384_HKDF_SHA384: hpke->curveId = ECC_SECP384R1; hpke->Nsecret = WC_SHA384_DIGEST_SIZE; @@ -168,7 +169,8 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) break; #endif -#if defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) +#if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \ + defined(WOLFSSL_SHA512) case DHKEM_P521_HKDF_SHA512: hpke->curveId = ECC_SECP521R1; hpke->Nsecret = WC_SHA512_DIGEST_SIZE; @@ -177,10 +179,9 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) hpke->Npk = 1 + hpke->Ndh * 2; break; #endif -#endif +#endif /* HAVE_ECC */ -#if defined(HAVE_CURVE25519) &&\ - (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) +#if defined(HAVE_CURVE25519) && !defined(NO_SHA256) case DHKEM_X25519_HKDF_SHA256: hpke->Nsecret = WC_SHA256_DIGEST_SIZE; hpke->kemDigest = WC_SHA256; @@ -189,8 +190,7 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) break; #endif -#if defined(HAVE_CURVE448) &&\ - (defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)) +#if defined(HAVE_CURVE448) && defined(WOLFSSL_SHA512) case DHKEM_X448_HKDF_SHA512: hpke->Nsecret = WC_SHA512_DIGEST_SIZE; hpke->kemDigest = WC_SHA512; @@ -209,7 +209,7 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) if (ret == 0) { switch (kdf) { -#if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) +#if !defined(NO_SHA256) case HKDF_SHA256: hpke->Nh = WC_SHA256_DIGEST_SIZE; hpke->kdfDigest = WC_SHA256; @@ -278,26 +278,34 @@ int wc_HpkeGenerateKeyPair(Hpke* hpke, void** keypair, WC_RNG* rng) switch (hpke->kem) { #if defined(HAVE_ECC) + #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && !defined(NO_SHA256) case DHKEM_P256_HKDF_SHA256: *keypair = wc_ecc_key_new(hpke->heap); if (*keypair != NULL) ret = wc_ecc_make_key_ex(rng, 32, (ecc_key*)*keypair, ECC_SECP256R1); break; +#endif + #if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \ + defined(WOLFSSL_SHA384) case DHKEM_P384_HKDF_SHA384: *keypair = wc_ecc_key_new(hpke->heap); if (*keypair != NULL) ret = wc_ecc_make_key_ex(rng, 48, (ecc_key*)*keypair, ECC_SECP384R1); break; + #endif + #if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \ + defined(WOLFSSL_SHA512) case DHKEM_P521_HKDF_SHA512: *keypair = wc_ecc_key_new(hpke->heap); if (*keypair != NULL) ret = wc_ecc_make_key_ex(rng, 66, (ecc_key*)*keypair, ECC_SECP521R1); break; + #endif #endif -#if defined(HAVE_CURVE25519) +#if defined(HAVE_CURVE25519) && !defined(NO_SHA256) case DHKEM_X25519_HKDF_SHA256: *keypair = XMALLOC(sizeof(curve25519_key), hpke->heap, DYNAMIC_TYPE_CURVE25519); @@ -310,8 +318,10 @@ int wc_HpkeGenerateKeyPair(Hpke* hpke, void** keypair, WC_RNG* rng) } break; #endif +#if defined(HAVE_CURVE448) && defined(WOLFSSL_SHA512) case DHKEM_X448_HKDF_SHA512: /* TODO: Add X448 */ +#endif default: ret = BAD_FUNC_ARG; break; @@ -350,13 +360,16 @@ int wc_HpkeSerializePublicKey(Hpke* hpke, void* key, byte* out, word16* outSz) ret = wc_ecc_export_x963_ex((ecc_key*)key, out, &tmpOutSz, 0); break; #endif -#if defined(HAVE_CURVE25519) +#if defined(HAVE_CURVE25519) && !defined(NO_SHA256) case DHKEM_X25519_HKDF_SHA256: ret = wc_curve25519_export_public_ex((curve25519_key*)key, out, &tmpOutSz, EC25519_LITTLE_ENDIAN); break; #endif +#if defined(HAVE_CURVE448) && defined(WOLFSSL_SHA512) case DHKEM_X448_HKDF_SHA512: + /* TODO: Add X448 */ +#endif default: ret = -1; break; @@ -396,7 +409,7 @@ int wc_HpkeDeserializePublicKey(Hpke* hpke, void** key, const byte* in, } break; #endif -#if defined(HAVE_CURVE25519) +#if defined(HAVE_CURVE25519) && !defined(NO_SHA256) case DHKEM_X25519_HKDF_SHA256: *key = XMALLOC(sizeof(curve25519_key), hpke->heap, DYNAMIC_TYPE_CURVE25519); @@ -409,7 +422,10 @@ int wc_HpkeDeserializePublicKey(Hpke* hpke, void** key, const byte* in, } break; #endif +#if defined(HAVE_CURVE448) && defined(WOLFSSL_SHA512) case DHKEM_X448_HKDF_SHA512: + /* TODO: Add X448 */ +#endif default: ret = -1; break; @@ -438,14 +454,16 @@ void wc_HpkeFreeKey(Hpke* hpke, word16 kem, void* keypair, void* heap) wc_ecc_key_free((ecc_key*)keypair); break; #endif -#if defined(HAVE_CURVE25519) +#if defined(HAVE_CURVE25519) && !defined(NO_SHA256) case DHKEM_X25519_HKDF_SHA256: wc_curve25519_free((curve25519_key*)keypair); XFREE(keypair, heap, DYNAMIC_TYPE_CURVE25519); break; #endif +#if defined(HAVE_CURVE448) && defined(WOLFSSL_SHA512) case DHKEM_X448_HKDF_SHA512: /* TODO: Add X448 */ +#endif default: break; } @@ -753,7 +771,7 @@ static int wc_HpkeEncap(Hpke* hpke, void* ephemeralKey, void* receiverKey, byte* sharedSecret) { int ret; -#ifdef ECC_TIMING_RESISTANT +#if defined(ECC_TIMING_RESISTANT) && defined(HAVE_ECC) WC_RNG* rng; #endif word32 dh_len; @@ -814,15 +832,17 @@ static int wc_HpkeEncap(Hpke* hpke, void* ephemeralKey, void* receiverKey, #endif break; #endif -#if defined(HAVE_CURVE25519) +#if defined(HAVE_CURVE25519) && !defined(NO_SHA256) case DHKEM_X25519_HKDF_SHA256: ret = wc_curve25519_shared_secret_ex((curve25519_key*)ephemeralKey, (curve25519_key*)receiverKey, dh, &dh_len, EC25519_LITTLE_ENDIAN); break; #endif +#if defined(HAVE_CURVE448) && defined(WOLFSSL_SHA512) case DHKEM_X448_HKDF_SHA512: /* TODO: Add X448 */ +#endif default: ret = -1; break; @@ -1047,7 +1067,7 @@ static int wc_HpkeDecap(Hpke* hpke, void* receiverKey, const byte* pubKey, #endif break; #endif -#if defined(HAVE_CURVE25519) +#if defined(HAVE_CURVE25519) && !defined(NO_SHA256) case DHKEM_X25519_HKDF_SHA256: #ifdef WOLFSSL_CURVE25519_BLINDING rng = wc_rng_new(NULL, 0, hpke->heap); @@ -1067,8 +1087,10 @@ static int wc_HpkeDecap(Hpke* hpke, void* receiverKey, const byte* pubKey, #endif break; #endif +#if defined(HAVE_CURVE448) && defined(WOLFSSL_SHA512) case DHKEM_X448_HKDF_SHA512: /* TODO: Add X448 */ +#endif default: ret = -1; break; @@ -1225,21 +1247,22 @@ WOLFSSL_LOCAL word16 wc_HpkeKemGetEncLen(word16 kemId) switch (kemId) { #if defined(HAVE_ECC) -#if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) +#if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && !defined(NO_SHA256) case DHKEM_P256_HKDF_SHA256: return DHKEM_P256_ENC_LEN; #endif -#ifdef WOLFSSL_SHA384 +#if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \ + defined(WOLFSSL_SHA384) case DHKEM_P384_HKDF_SHA384: return DHKEM_P384_ENC_LEN; #endif -#if defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) +#if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \ + defined(WOLFSSL_SHA512) case DHKEM_P521_HKDF_SHA512: return DHKEM_P521_ENC_LEN; #endif #endif /* HAVE_ECC */ -#if defined(HAVE_CURVE25519) && \ - (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) +#if defined(HAVE_CURVE25519) && !defined(NO_SHA256) case DHKEM_X25519_HKDF_SHA256: return DHKEM_X25519_ENC_LEN; #endif @@ -1254,18 +1277,19 @@ WOLFSSL_LOCAL int wc_HpkeKemIsSupported(word16 kemId) { switch (kemId) { #if defined(HAVE_ECC) -#if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) +#if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && !defined(NO_SHA256) case DHKEM_P256_HKDF_SHA256: #endif -#ifdef WOLFSSL_SHA384 +#if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \ + defined(WOLFSSL_SHA384) case DHKEM_P384_HKDF_SHA384: #endif -#if defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) +#if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \ + defined(WOLFSSL_SHA512) case DHKEM_P521_HKDF_SHA512: #endif #endif /* HAVE_ECC */ -#if defined(HAVE_CURVE25519) && \ - (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) +#if defined(HAVE_CURVE25519) && !defined(NO_SHA256) case DHKEM_X25519_HKDF_SHA256: #endif return 1; @@ -1280,7 +1304,7 @@ WOLFSSL_LOCAL int wc_HpkeKemIsSupported(word16 kemId) WOLFSSL_LOCAL int wc_HpkeKdfIsSupported(word16 kdfId) { switch (kdfId) { -#if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) +#if !defined(NO_SHA256) case HKDF_SHA256: #endif #ifdef WOLFSSL_SHA384 diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index ade14b78f0d..7687c584f72 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -639,8 +639,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sshkdf_test(void); WOLFSSL_TEST_SUBROUTINE wc_test_ret_t tls13_kdf_test(void); #endif WOLFSSL_TEST_SUBROUTINE wc_test_ret_t x963kdf_test(void); -#if defined(HAVE_HPKE) && defined(HAVE_ECC) && defined(HAVE_AESGCM) && \ - defined(WOLFSSL_AES_256) +#if defined(HAVE_HPKE) && \ + (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && \ + defined(HAVE_AESGCM) WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void); #endif #ifdef WC_SRTP_KDF @@ -2360,8 +2362,10 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ TEST_PASS("X963-KDF test passed!\n"); #endif -#if defined(HAVE_HPKE) && defined(HAVE_ECC) && defined(HAVE_AESGCM) && \ - defined(WOLFSSL_AES_256) +#if defined(HAVE_HPKE) && \ + (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && \ + defined(HAVE_AESGCM) PRIVATE_KEY_UNLOCK(); if ( (ret = hpke_test()) != 0) TEST_FAIL("HPKE test failed!\n", ret); @@ -31859,8 +31863,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t x963kdf_test(void) #endif /* HAVE_X963_KDF */ #if defined(HAVE_HPKE) && \ - (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)) && \ - defined(HAVE_AESGCM) && defined(WOLFSSL_AES_256) + (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && \ + defined(HAVE_AESGCM) static wc_test_ret_t hpke_test_single(Hpke* hpke) { @@ -32089,8 +32094,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) Hpke hpke[1]; WOLFSSL_ENTER("hpke_test"); -#if defined(HAVE_ECC) - #if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) +#if defined(HAVE_ECC) && defined(WOLFSSL_AES_128) + #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && !defined(NO_SHA256) /* p256 */ ret = wc_HpkeInit(hpke, DHKEM_P256_HKDF_SHA256, HKDF_SHA256, HPKE_AES_128_GCM, NULL); @@ -32104,8 +32109,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) return ret; #endif - #if (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) && \ - (defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)) + #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ + !defined(NO_SHA256) && defined(WOLFSSL_SHA512) /* p256 with sha512 kdf */ ret = wc_HpkeInit(hpke, DHKEM_P256_HKDF_SHA256, HKDF_SHA512, HPKE_AES_128_GCM, NULL); @@ -32120,8 +32125,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) #endif - #if defined(WOLFSSL_SHA384) && \ - (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) + #if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \ + defined(WOLFSSL_SHA384) /* p384 */ ret = wc_HpkeInit(hpke, DHKEM_P384_HKDF_SHA384, HKDF_SHA384, HPKE_AES_128_GCM, NULL); @@ -32135,8 +32140,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) return ret; #endif - #if (defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)) && \ - (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) + #if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \ + defined(WOLFSSL_SHA512) /* p521 */ ret = wc_HpkeInit(hpke, DHKEM_P521_HKDF_SHA512, HKDF_SHA512, HPKE_AES_128_GCM, NULL); @@ -32150,8 +32155,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) return ret; #endif - #if defined(WOLFSSL_SHA384) && defined(WOLFSSL_SHA512) && \ - (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) + #if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \ + defined(WOLFSSL_SHA384) && defined(WOLFSSL_SHA512) /* p521 with sha384 kdf */ ret = wc_HpkeInit(hpke, DHKEM_P521_HKDF_SHA512, HKDF_SHA384, HPKE_AES_128_GCM, NULL); @@ -32166,7 +32171,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) #endif #endif -#if defined(HAVE_CURVE25519) +#if defined(HAVE_CURVE25519) && !defined(NO_SHA256) && defined(WOLFSSL_AES_256) /* test with curve25519 and aes256 */ ret = wc_HpkeInit(hpke, DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, HPKE_AES_256_GCM, NULL); @@ -32181,8 +32186,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) #endif -#if defined(HAVE_CURVE448) && \ - (defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)) +#if defined(HAVE_CURVE448) && defined(WOLFSSL_SHA512) && \ + defined(WOLFSSL_AES_256) /* test with curve448 and aes256 */ ret = wc_HpkeInit(hpke, DHKEM_X448_HKDF_SHA512, HKDF_SHA512, HPKE_AES_256_GCM, NULL); @@ -32203,7 +32208,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) return ret; } -#endif /* HAVE_HPKE && HAVE_ECC && HAVE_AESGCM && WOLFSSL_AES_256 */ +#endif /* HAVE_HPKE && (HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448) && + HAVE_AESGCM */ #if defined(WC_SRTP_KDF) typedef struct Srtp_Kdf_Tv { diff --git a/wolfcrypt/test/test.h b/wolfcrypt/test/test.h index b1b1b5feb9c..ddaea0f310f 100644 --- a/wolfcrypt/test/test.h +++ b/wolfcrypt/test/test.h @@ -163,7 +163,10 @@ extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sshkdf_test(void); extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t tls13_kdf_test(void); #endif extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t x963kdf_test(void); -#if defined(HAVE_HPKE) && defined(HAVE_ECC) && defined(HAVE_AESGCM) +#if defined(HAVE_HPKE) && \ + (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && \ + defined(HAVE_AESGCM) extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void); #endif #ifdef WC_SRTP_KDF diff --git a/wolfssl/wolfcrypt/hpke.h b/wolfssl/wolfcrypt/hpke.h index 558d7d8c53c..c71619ccf79 100644 --- a/wolfssl/wolfcrypt/hpke.h +++ b/wolfssl/wolfcrypt/hpke.h @@ -31,7 +31,8 @@ extern "C" { #endif -#if defined(HAVE_HPKE) && defined(HAVE_ECC) +#if defined(HAVE_HPKE) && (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \ + defined(HAVE_AESGCM) #ifndef WOLFCRYPT_HPKE #define WOLFCRYPT_HPKE @@ -136,7 +137,7 @@ WOLFSSL_LOCAL int wc_HpkeAeadIsSupported(word16 aeadId); #endif -#endif /* HAVE_HPKE && HAVE_ECC */ +#endif /* HAVE_HPKE && (HAVE_ECC || HAVE_CURVE25519) && HAVE_AESGCM */ #ifdef __cplusplus } /* extern "C" */ From 25dcc0082d162d6976caefbb0702603313e33296 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Fri, 20 Mar 2026 14:39:29 -0600 Subject: [PATCH 7/7] small changes: - better ifdef's in hpke api.c tests - updated ssl_ech.c to use wc_HpkeKemGetEncLen in both locations - removed Ndh check in hpke.c, made it inline with the ecc cases --- src/ssl_ech.c | 42 +++++++++--------------------------------- tests/api.c | 12 +++++++----- wolfcrypt/src/hpke.c | 25 ++++++++++++++++++------- 3 files changed, 34 insertions(+), 45 deletions(-) diff --git a/src/ssl_ech.c b/src/ssl_ech.c index 86f6fe40ee0..eb9b9a6a5aa 100644 --- a/src/ssl_ech.c +++ b/src/ssl_ech.c @@ -316,6 +316,7 @@ int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen) { int i; word16 totalLen = 0; + word16 kemEncLen; word16 publicNameLen; if (config == NULL || (output == NULL && outputLen == NULL)) @@ -338,7 +339,10 @@ int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen) totalLen += 2; /* hpke_pub_key */ - totalLen += wc_HpkeKemGetEncLen(config->kemId); + kemEncLen = wc_HpkeKemGetEncLen(config->kemId); + if (kemEncLen == 0) + return BAD_FUNC_ARG; + totalLen += kemEncLen; /* cipherSuitesLen */ totalLen += 2; @@ -378,38 +382,10 @@ int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen) output += 2; /* length and key itself */ - switch (config->kemId) { - case DHKEM_P256_HKDF_SHA256: - c16toa(DHKEM_P256_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_P256_ENC_LEN); - output += DHKEM_P256_ENC_LEN; - break; - case DHKEM_P384_HKDF_SHA384: - c16toa(DHKEM_P384_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_P384_ENC_LEN); - output += DHKEM_P384_ENC_LEN; - break; - case DHKEM_P521_HKDF_SHA512: - c16toa(DHKEM_P521_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_P521_ENC_LEN); - output += DHKEM_P521_ENC_LEN; - break; - case DHKEM_X25519_HKDF_SHA256: - c16toa(DHKEM_X25519_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_X25519_ENC_LEN); - output += DHKEM_X25519_ENC_LEN; - break; - case DHKEM_X448_HKDF_SHA512: - c16toa(DHKEM_X448_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_X448_ENC_LEN); - output += DHKEM_X448_ENC_LEN; - break; - } + c16toa(kemEncLen, output); + output += 2; + XMEMCPY(output, config->receiverPubkey, kemEncLen); + output += kemEncLen; /* cipherSuites len */ c16toa(config->numCipherSuites * 4, output); diff --git a/tests/api.c b/tests/api.c index 59a04dacf90..a2fe2baa6b0 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14572,22 +14572,24 @@ static int test_wolfSSL_Tls13_ECH_all_algos(void) int k; static const word16 kems[] = { #if defined(HAVE_ECC) -#if (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) +#if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && !defined(NO_SHA256) DHKEM_P256_HKDF_SHA256, #endif -#if defined(WOLFSSL_SHA384) +#if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \ + defined(WOLFSSL_SHA384) DHKEM_P384_HKDF_SHA384, #endif -#if (defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)) +#if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \ + defined(WOLFSSL_SHA512) DHKEM_P521_HKDF_SHA512, #endif #endif /* HAVE_ECC */ -#if defined(HAVE_CURVE25519) && (defined(WOLFSSL_SHA224) || !defined(NO_SHA256)) +#if defined(HAVE_CURVE25519) && !defined(NO_SHA256) DHKEM_X25519_HKDF_SHA256, #endif }; static const word16 kdfs[] = { -#if defined(WOLFSSL_SHA224) || !defined(NO_SHA256) +#if !defined(NO_SHA256) HKDF_SHA256, #endif #ifdef WOLFSSL_SHA384 diff --git a/wolfcrypt/src/hpke.c b/wolfcrypt/src/hpke.c index fd5f76a2663..a67da93ca91 100644 --- a/wolfcrypt/src/hpke.c +++ b/wolfcrypt/src/hpke.c @@ -153,7 +153,12 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) hpke->curveId = ECC_SECP256R1; hpke->Nsecret = WC_SHA256_DIGEST_SIZE; hpke->kemDigest = WC_SHA256; - hpke->Ndh = (word32)wc_ecc_get_curve_size_from_id(hpke->curveId); + ret = wc_ecc_get_curve_size_from_id(hpke->curveId); + if (ret < 0) { + break; + } + hpke->Ndh = (word32)ret; + ret = 0; hpke->Npk = 1 + hpke->Ndh * 2; break; #endif @@ -164,7 +169,12 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) hpke->curveId = ECC_SECP384R1; hpke->Nsecret = WC_SHA384_DIGEST_SIZE; hpke->kemDigest = WC_SHA384; - hpke->Ndh = (word32)wc_ecc_get_curve_size_from_id(hpke->curveId); + ret = wc_ecc_get_curve_size_from_id(hpke->curveId); + if (ret < 0) { + break; + } + hpke->Ndh = (word32)ret; + ret = 0; hpke->Npk = 1 + hpke->Ndh * 2; break; #endif @@ -175,7 +185,12 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) hpke->curveId = ECC_SECP521R1; hpke->Nsecret = WC_SHA512_DIGEST_SIZE; hpke->kemDigest = WC_SHA512; - hpke->Ndh = (word32)wc_ecc_get_curve_size_from_id(hpke->curveId); + ret = wc_ecc_get_curve_size_from_id(hpke->curveId); + if (ret < 0) { + break; + } + hpke->Ndh = (word32)ret; + ret = 0; hpke->Npk = 1 + hpke->Ndh * 2; break; #endif @@ -260,10 +275,6 @@ int wc_HpkeInit(Hpke* hpke, int kem, int kdf, int aead, void* heap) } } - if ((int)hpke->Ndh < 0) { - return (int)hpke->Ndh; - } - return ret; }