From 6d0774bd7e73adcbe74645c54ea7ac4335f5124d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Thu, 1 Aug 2024 10:01:32 +0200 Subject: [PATCH] Add more PQC hybrid key exchange algorithms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for all remaining hybrid PQC + ECC hybrid key exchange groups to match OQS. Next to two new combinations with SECP curves, this mainly also adds support for combinations with X25519 and X448. This also enables compatability with the PQC key exchange support in Chromium browsers and Mozilla Firefox (hybrid Kyber768 and X25519; when `WOLFSSL_KYBER_ORIGINAL` is defined). In the process of extending support, some code and logic cleanup happened. Furthermore, two memory leaks within the hybrid code path have been fixed. Signed-off-by: Tobias Frauenschläger --- examples/benchmark/tls_bench.c | 11 +- examples/client/client.c | 25 +- examples/server/server.c | 24 ++ src/internal.c | 23 ++ src/ssl.c | 68 ++++- src/tls.c | 403 ++++++++++++++++---------- tests/include.am | 6 +- tests/suites.c | 50 +--- tests/test-dtls13-pq-2-frag.conf | 23 -- tests/test-dtls13-pq-2.conf | 13 - tests/test-dtls13-pq-frag.conf | 1 - tests/test-dtls13-pq-hybrid-frag.conf | 71 +++++ tests/test-dtls13-pq-hybrid.conf | 25 ++ tests/test-tls13-pq-2.conf | 29 -- tests/test-tls13-pq-hybrid.conf | 79 +++++ wolfssl/internal.h | 5 +- wolfssl/ssl.h | 75 ++--- 17 files changed, 606 insertions(+), 325 deletions(-) delete mode 100644 tests/test-dtls13-pq-2-frag.conf delete mode 100644 tests/test-dtls13-pq-2.conf create mode 100644 tests/test-dtls13-pq-hybrid-frag.conf create mode 100644 tests/test-dtls13-pq-hybrid.conf delete mode 100644 tests/test-tls13-pq-2.conf create mode 100644 tests/test-tls13-pq-hybrid.conf diff --git a/examples/benchmark/tls_bench.c b/examples/benchmark/tls_bench.c index 609481a3e0..177c3c3988 100644 --- a/examples/benchmark/tls_bench.c +++ b/examples/benchmark/tls_bench.c @@ -291,9 +291,14 @@ static struct group_info groups[] = { { WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" }, { WOLFSSL_KYBER_LEVEL3, "KYBER_LEVEL3" }, { WOLFSSL_KYBER_LEVEL5, "KYBER_LEVEL5" }, - { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" }, - { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" }, - { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" }, + { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" }, + { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" }, + { WOLFSSL_P256_KYBER_LEVEL3, "P256_KYBER_LEVEL3" }, + { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" }, + { WOLFSSL_P384_KYBER_LEVEL5, "P384_KYBER_LEVEL5" }, + { WOLFSSL_X25519_KYBER_LEVEL1, "X25519_KYBER_LEVEL1" }, + { WOLFSSL_X448_KYBER_LEVEL3, "X448_KYBER_LEVEL3" }, + { WOLFSSL_X25519_KYBER_LEVEL3, "X25519_KYBER_LEVEL3" }, #endif { 0, NULL } }; diff --git a/examples/client/client.c b/examples/client/client.c index b8adcc1924..3fdd2b1a8b 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -426,15 +426,38 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519, if (XSTRCMP(pqcAlg, "P384_KYBER_LEVEL3") == 0) { group = WOLFSSL_P384_KYBER_LEVEL3; } + else if (XSTRCMP(pqcAlg, "P256_KYBER_LEVEL3") == 0) { + group = WOLFSSL_P256_KYBER_LEVEL3; + } else #endif #ifndef WOLFSSL_NO_KYBER1024 if (XSTRCMP(pqcAlg, "P521_KYBER_LEVEL5") == 0) { group = WOLFSSL_P521_KYBER_LEVEL5; } + else if (XSTRCMP(pqcAlg, "P384_KYBER_LEVEL5") == 0) { + group = WOLFSSL_P384_KYBER_LEVEL5; + } else #endif - { + #if !defined(WOLFSSL_NO_KYBER512) && defined(HAVE_CURVE25519) + if (XSTRCMP(pqcAlg, "X25519_KYBER_LEVEL1") == 0) { + group = WOLFSSL_X25519_KYBER_LEVEL1; + } + else + #endif + #if !defined(WOLFSSL_NO_KYBER768) && defined(HAVE_CURVE25519) + if (XSTRCMP(pqcAlg, "X25519_KYBER_LEVEL3") == 0) { + group = WOLFSSL_X25519_KYBER_LEVEL3; + } + else + #endif + #if !defined(WOLFSSL_NO_KYBER768) && defined(HAVE_CURVE448) + if (XSTRCMP(pqcAlg, "X448_KYBER_LEVEL3") == 0) { + group = WOLFSSL_X448_KYBER_LEVEL3; + } + #endif + else { err_sys("invalid post-quantum KEM specified"); } diff --git a/examples/server/server.c b/examples/server/server.c index 2f42a909e3..c2af4dadb7 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -740,12 +740,36 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519, if (XSTRCMP(pqcAlg, "P384_KYBER_LEVEL3") == 0) { groups[count] = WOLFSSL_P384_KYBER_LEVEL3; } + else if (XSTRCMP(pqcAlg, "P256_KYBER_LEVEL3") == 0) { + groups[count] = WOLFSSL_P256_KYBER_LEVEL3; + } else #endif #ifndef WOLFSSL_NO_KYBER1024 if (XSTRCMP(pqcAlg, "P521_KYBER_LEVEL5") == 0) { groups[count] = WOLFSSL_P521_KYBER_LEVEL5; } + else if (XSTRCMP(pqcAlg, "P384_KYBER_LEVEL5") == 0) { + groups[count] = WOLFSSL_P384_KYBER_LEVEL5; + } + else + #endif + #if !defined(WOLFSSL_NO_KYBER512) && defined(HAVE_CURVE25519) + if (XSTRCMP(pqcAlg, "X25519_KYBER_LEVEL1") == 0) { + groups[count] = WOLFSSL_X25519_KYBER_LEVEL1; + } + else + #endif + #if !defined(WOLFSSL_NO_KYBER768) && defined(HAVE_CURVE25519) + if (XSTRCMP(pqcAlg, "X25519_KYBER_LEVEL3") == 0) { + groups[count] = WOLFSSL_X25519_KYBER_LEVEL3; + } + else + #endif + #if !defined(WOLFSSL_NO_KYBER768) && defined(HAVE_CURVE448) + if (XSTRCMP(pqcAlg, "X448_KYBER_LEVEL3") == 0) { + groups[count] = WOLFSSL_X448_KYBER_LEVEL3; + } else #endif { diff --git a/src/internal.c b/src/internal.c index 2fc63753f6..390493cda5 100644 --- a/src/internal.c +++ b/src/internal.c @@ -34131,6 +34131,29 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } #endif /* HAVE_ECC */ +#ifdef WOLFSSL_HAVE_KYBER + /* Returns 1 when the given group is a PQC group, 0 otherwise. */ + int NamedGroupIsPqc(int group) + { + switch (group) { + case WOLFSSL_KYBER_LEVEL1: + case WOLFSSL_KYBER_LEVEL3: + case WOLFSSL_KYBER_LEVEL5: + case WOLFSSL_P256_KYBER_LEVEL3: + case WOLFSSL_X25519_KYBER_LEVEL3: + case WOLFSSL_P384_KYBER_LEVEL5: + case WOLFSSL_P256_KYBER_LEVEL1: + case WOLFSSL_P384_KYBER_LEVEL3: + case WOLFSSL_P521_KYBER_LEVEL5: + case WOLFSSL_X25519_KYBER_LEVEL1: + case WOLFSSL_X448_KYBER_LEVEL3: + return 1; + default: + return 0; + } + } +#endif /* WOLFSSL_HAVE_KYBER */ + int TranslateErrorToAlert(int err) { switch (err) { diff --git a/src/ssl.c b/src/ssl.c index 264f2c04ec..4f39fa5380 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -3304,6 +3304,11 @@ static int isValidCurveGroup(word16 name) case WOLFSSL_P256_KYBER_LEVEL1: case WOLFSSL_P384_KYBER_LEVEL3: case WOLFSSL_P521_KYBER_LEVEL5: + case WOLFSSL_P384_KYBER_LEVEL5: + case WOLFSSL_X25519_KYBER_LEVEL1: + case WOLFSSL_X448_KYBER_LEVEL3: + case WOLFSSL_X25519_KYBER_LEVEL3: + case WOLFSSL_P256_KYBER_LEVEL3: #endif #endif return 1; @@ -14448,37 +14453,67 @@ const char* wolfSSL_get_curve_name(WOLFSSL* ssl) * check to override this result in the case of a hybrid. */ if (IsAtLeastTLSv1_3(ssl->version)) { switch (ssl->namedGroup) { -#ifdef HAVE_LIBOQS - case WOLFSSL_KYBER_LEVEL1: - return "KYBER_LEVEL1"; - case WOLFSSL_KYBER_LEVEL3: - return "KYBER_LEVEL3"; - case WOLFSSL_KYBER_LEVEL5: - return "KYBER_LEVEL5"; - case WOLFSSL_P256_KYBER_LEVEL1: - return "P256_KYBER_LEVEL1"; - case WOLFSSL_P384_KYBER_LEVEL3: - return "P384_KYBER_LEVEL3"; - case WOLFSSL_P521_KYBER_LEVEL5: - return "P521_KYBER_LEVEL5"; -#elif defined(WOLFSSL_WC_KYBER) +#if defined(WOLFSSL_WC_KYBER) #ifdef WOLFSSL_KYBER512 case WOLFSSL_KYBER_LEVEL1: return "KYBER_LEVEL1"; case WOLFSSL_P256_KYBER_LEVEL1: return "P256_KYBER_LEVEL1"; + #ifdef HAVE_CURVE25519 + case WOLFSSL_X25519_KYBER_LEVEL1: + return "X25519_KYBER_LEVEL1"; + #endif #endif #ifdef WOLFSSL_KYBER768 case WOLFSSL_KYBER_LEVEL3: return "KYBER_LEVEL3"; case WOLFSSL_P384_KYBER_LEVEL3: return "P384_KYBER_LEVEL3"; + case WOLFSSL_P256_KYBER_LEVEL3: + return "P256_KYBER_LEVEL3"; + #ifdef HAVE_CURVE25519 + case WOLFSSL_X25519_KYBER_LEVEL3: + return "X25519_KYBER_LEVEL3"; + #endif + #ifdef HAVE_CURVE448 + case WOLFSSL_X448_KYBER_LEVEL3: + return "X448_KYBER_LEVEL3"; + #endif #endif #ifdef WOLFSSL_KYBER1024 case WOLFSSL_KYBER_LEVEL5: return "KYBER_LEVEL5"; case WOLFSSL_P521_KYBER_LEVEL5: return "P521_KYBER_LEVEL5"; + case WOLFSSL_P384_KYBER_LEVEL5: + return "P384_KYBER_LEVEL5"; + #endif +#elif defined (HAVE_LIBOQS) + case WOLFSSL_KYBER_LEVEL1: + return "KYBER_LEVEL1"; + case WOLFSSL_KYBER_LEVEL3: + return "KYBER_LEVEL3"; + case WOLFSSL_KYBER_LEVEL5: + return "KYBER_LEVEL5"; + case WOLFSSL_P256_KYBER_LEVEL1: + return "P256_KYBER_LEVEL1"; + case WOLFSSL_P384_KYBER_LEVEL3: + return "P384_KYBER_LEVEL3"; + case WOLFSSL_P256_KYBER_LEVEL3: + return "P256_KYBER_LEVEL3"; + case WOLFSSL_P521_KYBER_LEVEL5: + return "P521_KYBER_LEVEL5"; + case WOLFSSL_P384_KYBER_LEVEL5: + return "P384_KYBER_LEVEL5"; + #ifdef HAVE_CURVE25519 + case WOLFSSL_X25519_KYBER_LEVEL1: + return "X25519_KYBER_LEVEL1"; + case WOLFSSL_X25519_KYBER_LEVEL3: + return "X25519_KYBER_LEVEL3"; + #endif + #ifdef HAVE_CURVE448 + case WOLFSSL_X448_KYBER_LEVEL3: + return "X448_KYBER_LEVEL3"; #endif #endif } @@ -21775,7 +21810,12 @@ const WOLF_EC_NIST_NAME kNistCurves[] = { #if (defined(WOLFSSL_WC_KYBER) || defined(HAVE_LIBOQS)) && defined(HAVE_ECC) {CURVE_NAME("P256_KYBER_LEVEL1"), WOLFSSL_P256_KYBER_LEVEL1, WOLFSSL_P256_KYBER_LEVEL1}, {CURVE_NAME("P384_KYBER_LEVEL3"), WOLFSSL_P384_KYBER_LEVEL3, WOLFSSL_P256_KYBER_LEVEL1}, + {CURVE_NAME("P256_KYBER_LEVEL3"), WOLFSSL_P256_KYBER_LEVEL3, WOLFSSL_P256_KYBER_LEVEL1}, {CURVE_NAME("P521_KYBER_LEVEL5"), WOLFSSL_P521_KYBER_LEVEL5, WOLFSSL_P256_KYBER_LEVEL1}, + {CURVE_NAME("P384_KYBER_LEVEL5"), WOLFSSL_P384_KYBER_LEVEL5, WOLFSSL_P256_KYBER_LEVEL1}, + {CURVE_NAME("X25519_KYBER_LEVEL1"), WOLFSSL_X25519_KYBER_LEVEL1, WOLFSSL_P256_KYBER_LEVEL1}, + {CURVE_NAME("X448_KYBER_LEVEL3"), WOLFSSL_X448_KYBER_LEVEL3, WOLFSSL_P256_KYBER_LEVEL1}, + {CURVE_NAME("X25519_KYBER_LEVEL3"), WOLFSSL_X25519_KYBER_LEVEL3, WOLFSSL_P256_KYBER_LEVEL1}, #endif #endif #ifdef WOLFSSL_SM2 diff --git a/src/tls.c b/src/tls.c index 0aff791697..9c646481d8 100644 --- a/src/tls.c +++ b/src/tls.c @@ -7435,6 +7435,7 @@ static int TLSX_KeyShare_GenX25519Key(WOLFSSL *ssl, KeyShareEntry* kse) if (ret == 0) { /* setting "key" means okay to call wc_curve25519_free */ key = (curve25519_key*)kse->key; + kse->keyLen = CURVE25519_KEYSIZE; #ifdef WOLFSSL_STATIC_EPHEMERAL ret = wolfSSL_StaticEphemeralKeyLoad(ssl, WC_PK_TYPE_CURVE25519, kse->key); @@ -7520,6 +7521,7 @@ static int TLSX_KeyShare_GenX448Key(WOLFSSL *ssl, KeyShareEntry* kse) ret = wc_curve448_init((curve448_key*)kse->key); if (ret == 0) { key = (curve448_key*)kse->key; + kse->keyLen = CURVE448_KEY_SIZE; #ifdef WOLFSSL_STATIC_EPHEMERAL ret = wolfSSL_StaticEphemeralKeyLoad(ssl, WC_PK_TYPE_CURVE448, kse->key); @@ -7777,8 +7779,22 @@ static const PqcHybridMapping pqc_hybrid_mapping[] = { .pqc = WOLFSSL_KYBER_LEVEL1}, {.hybrid = WOLFSSL_P384_KYBER_LEVEL3, .ecc = WOLFSSL_ECC_SECP384R1, .pqc = WOLFSSL_KYBER_LEVEL3}, + {.hybrid = WOLFSSL_P256_KYBER_LEVEL3, .ecc = WOLFSSL_ECC_SECP256R1, + .pqc = WOLFSSL_KYBER_LEVEL3}, {.hybrid = WOLFSSL_P521_KYBER_LEVEL5, .ecc = WOLFSSL_ECC_SECP521R1, .pqc = WOLFSSL_KYBER_LEVEL5}, + {.hybrid = WOLFSSL_P384_KYBER_LEVEL5, .ecc = WOLFSSL_ECC_SECP384R1, + .pqc = WOLFSSL_KYBER_LEVEL5}, +#ifdef HAVE_CURVE25519 + {.hybrid = WOLFSSL_X25519_KYBER_LEVEL1, .ecc = WOLFSSL_ECC_X25519, + .pqc = WOLFSSL_KYBER_LEVEL1}, + {.hybrid = WOLFSSL_X25519_KYBER_LEVEL3, .ecc = WOLFSSL_ECC_X25519, + .pqc = WOLFSSL_KYBER_LEVEL3}, +#endif +#ifdef HAVE_CURVE448 + {.hybrid = WOLFSSL_X448_KYBER_LEVEL3, .ecc = WOLFSSL_ECC_X448, + .pqc = WOLFSSL_KYBER_LEVEL3}, +#endif {.hybrid = 0, .ecc = 0, .pqc = 0} }; @@ -7812,7 +7828,7 @@ static void findEccPqc(int *ecc, int *pqc, int group) } } -/* Create a key share entry using liboqs parameters group. +/* Create a key share entry using pqc parameters group. * Generates a key pair. * * ssl The SSL/TLS object. @@ -7827,7 +7843,7 @@ static int TLSX_KeyShare_GenPqcKey(WOLFSSL *ssl, KeyShareEntry* kse) byte* pubKey = NULL; byte* privKey = NULL; KeyShareEntry *ecc_kse = NULL; - int oqs_group = 0; + int pqc_group = 0; int ecc_group = 0; word32 privSz = 0; word32 pubSz = 0; @@ -7839,8 +7855,8 @@ static int TLSX_KeyShare_GenPqcKey(WOLFSSL *ssl, KeyShareEntry* kse) return ret; } - findEccPqc(&ecc_group, &oqs_group, kse->group); - ret = kyber_id2type(oqs_group, &type); + findEccPqc(&ecc_group, &pqc_group, kse->group); + ret = kyber_id2type(pqc_group, &type); if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { WOLFSSL_MSG("Invalid Kyber algorithm specified."); ret = BAD_FUNC_ARG; @@ -7873,8 +7889,22 @@ static int TLSX_KeyShare_GenPqcKey(WOLFSSL *ssl, KeyShareEntry* kse) if (ret == 0 && ecc_group != 0) { ecc_kse->group = ecc_group; - ret = TLSX_KeyShare_GenEccKey(ssl, ecc_kse); - /* If fail, no error message, TLSX_KeyShare_GenEccKey will do it. */ + #ifdef HAVE_CURVE25519 + if (ecc_group == WOLFSSL_ECC_X25519) { + ret = TLSX_KeyShare_GenX25519Key(ssl, ecc_kse); + } + else + #endif + #ifdef HAVE_CURVE448 + if (ecc_group == WOLFSSL_ECC_X448) { + ret = TLSX_KeyShare_GenX448Key(ssl, ecc_kse); + } + else + #endif + { + ret = TLSX_KeyShare_GenEccKey(ssl, ecc_kse); + } + /* No error message, TLSX_KeyShare_GenKey will do it. */ } if (ret == 0) { @@ -7914,7 +7944,7 @@ static int TLSX_KeyShare_GenPqcKey(WOLFSSL *ssl, KeyShareEntry* kse) kse->pubKeyLen = ecc_kse->pubKeyLen + pubSz; pubKey = NULL; - /* Note we are saving the OQS private key and ECC private key + /* Note we are saving the PQC private key and ECC private key * separately. That's because the ECC private key is not simply a * buffer. Its is an ecc_key struct. Typically do not need the private * key size, but will need to zero it out upon freeing. */ @@ -8303,6 +8333,8 @@ static int TLSX_KeyShare_ProcessX25519(WOLFSSL* ssl, wc_curve25519_free((curve25519_key*)keyShareEntry->key); XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); keyShareEntry->key = NULL; + XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + keyShareEntry->ke = NULL; #else (void)ssl; (void)keyShareEntry; @@ -8381,6 +8413,8 @@ static int TLSX_KeyShare_ProcessX448(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) wc_curve448_free((curve448_key*)keyShareEntry->key); XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); keyShareEntry->key = NULL; + XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + keyShareEntry->ke = NULL; #else (void)ssl; (void)keyShareEntry; @@ -8548,58 +8582,36 @@ static int TLSX_KeyShare_ProcessPqc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) int ret = 0; int type; KyberKey kem[1]; - byte* sharedSecret = NULL; - word32 sharedSecretLen = 0; - int oqs_group = 0; + int pqc_group = 0; int ecc_group = 0; - ecc_key eccpubkey; + KeyShareEntry *ecc_kse = NULL; word32 outlen = 0; word32 privSz = 0; word32 ctSz = 0; word32 ssSz = 0; - if (keyShareEntry->ke == NULL) { - WOLFSSL_MSG("Invalid OQS algorithm specified."); - return BAD_FUNC_ARG; - } - if (ssl->options.side == WOLFSSL_SERVER_END) { /* I am the server, the shared secret has already been generated and - * is in keyShareEntry->ke; copy it to the pre-master secret - * pre-allocated buffer. */ - if (keyShareEntry->keLen > ENCRYPT_LEN) { - WOLFSSL_MSG("shared secret is too long."); - return LENGTH_ERROR; - } - - XMEMCPY(ssl->arrays->preMasterSecret, keyShareEntry->ke, - keyShareEntry->keLen); - ssl->arrays->preMasterSz = keyShareEntry->keLen; - XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_SECRET); - keyShareEntry->ke = NULL; - keyShareEntry->keLen = 0; + * is in ssl->arrays->preMasterSecret, so nothing really to do here. */ return 0; } - /* I am the client, the ciphertext is in keyShareEntry->ke */ - findEccPqc(&ecc_group, &oqs_group, keyShareEntry->group); - - ret = wc_ecc_init_ex(&eccpubkey, ssl->heap, ssl->devId); - if (ret != 0) { - WOLFSSL_MSG("Memory allocation error."); - return MEMORY_E; + if (keyShareEntry->ke == NULL) { + WOLFSSL_MSG("Invalid PQC algorithm specified."); + return BAD_FUNC_ARG; } - ret = kyber_id2type(oqs_group, &type); + /* I am the client, the ciphertext is in keyShareEntry->ke */ + findEccPqc(&ecc_group, &pqc_group, keyShareEntry->group); + + ret = kyber_id2type(pqc_group, &type); if (ret != 0) { - wc_ecc_free(&eccpubkey); - WOLFSSL_MSG("Invalid OQS algorithm specified."); + WOLFSSL_MSG("Invalid PQC algorithm specified."); return BAD_FUNC_ARG; } ret = wc_KyberKey_Init(type, kem, ssl->heap, ssl->devId); if (ret != 0) { - wc_ecc_free(&eccpubkey); WOLFSSL_MSG("Error creating Kyber KEM"); return MEMORY_E; } @@ -8608,35 +8620,62 @@ static int TLSX_KeyShare_ProcessPqc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) ret = wc_KyberKey_SharedSecretSize(kem, &ssSz); } if (ret == 0) { - sharedSecretLen = ssSz; - switch (ecc_group) { - case WOLFSSL_ECC_SECP256R1: - sharedSecretLen += 32; - outlen = 32; - break; - case WOLFSSL_ECC_SECP384R1: - sharedSecretLen += 48; - outlen = 48; - break; - case WOLFSSL_ECC_SECP521R1: - sharedSecretLen += 66; - outlen = 66; - break; - default: - break; - } + ret = wc_KyberKey_CipherTextSize(kem, &ctSz); } - if (ret == 0) { - sharedSecret = (byte*)XMALLOC(sharedSecretLen, ssl->heap, - DYNAMIC_TYPE_TLSX); - if (sharedSecret == NULL) { - WOLFSSL_MSG("Memory allocation error."); - ret = MEMORY_E; + + if (ret == 0 && ecc_group != 0) { + /* We are performing a hybrid key exchange */ + ecc_kse = (KeyShareEntry*)XMALLOC(sizeof(*ecc_kse), ssl->heap, + DYNAMIC_TYPE_TLSX); + if (ecc_kse == NULL) { + WOLFSSL_MSG("ecc_kse memory allocation failure"); + ret = MEMORY_ERROR; } + if (ret == 0) { + XMEMSET(ecc_kse, 0, sizeof(*ecc_kse)); + ecc_kse->group = ecc_group; + ecc_kse->keLen = keyShareEntry->keLen - ctSz; + ecc_kse->key = keyShareEntry->key; + ecc_kse->ke = (byte*)XMALLOC(ecc_kse->keLen, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (ecc_kse->ke == NULL) { + WOLFSSL_MSG("ecc_kse memory allocation failure"); + ret = MEMORY_ERROR; + } + } + if (ret == 0) { + XMEMCPY(ecc_kse->ke, keyShareEntry->ke, ecc_kse->keLen); + + #ifdef HAVE_CURVE25519 + if (ecc_group == WOLFSSL_ECC_X25519) { + ret = TLSX_KeyShare_ProcessX25519(ssl, ecc_kse); + } + else + #endif + #ifdef HAVE_CURVE448 + if (ecc_group == WOLFSSL_ECC_X448) { + ret = TLSX_KeyShare_ProcessX448(ssl, ecc_kse); + } + else + #endif + { + ret = TLSX_KeyShare_ProcessEcc(ssl, ecc_kse); + } + } + if (ret == 0) { + outlen = ssl->arrays->preMasterSz; + ssSz += ssl->arrays->preMasterSz; + keyShareEntry->key = ecc_kse->key; + + if ((ret == 0) && (ssSz > ENCRYPT_LEN)) { + WOLFSSL_MSG("shared secret is too long."); + ret = LENGTH_ERROR; + } + } + /* ecc_kse->ke is freed in the TLSX_KeyShare_Process methods */ + XFREE(ecc_kse, ssl->heap, DYNAMIC_TYPE_TLSX); } - if (ret == 0) { - ret = wc_KyberKey_CipherTextSize(kem, &ctSz); - } + if (ret == 0) { ret = wc_KyberKey_PrivateKeySize(kem, &privSz); } @@ -8644,62 +8683,17 @@ static int TLSX_KeyShare_ProcessPqc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) ret = wc_KyberKey_DecodePrivateKey(kem, keyShareEntry->privKey, privSz); } if (ret == 0) { - ret = wc_KyberKey_Decapsulate(kem, sharedSecret + outlen, - keyShareEntry->ke + keyShareEntry->keLen - ctSz, ctSz); + ret = wc_KyberKey_Decapsulate(kem, ssl->arrays->preMasterSecret + outlen, + keyShareEntry->ke + keyShareEntry->keLen - ctSz, ctSz); if (ret != 0) { WOLFSSL_MSG("wc_KyberKey decapsulation failure."); ret = BAD_FUNC_ARG; } } - - if (ecc_group != 0) { - if (ret == 0) { - /* Point is validated by import function. */ - ret = wc_ecc_import_x963(keyShareEntry->ke, - keyShareEntry->keLen - ctSz, - &eccpubkey); - if (ret != 0) { - WOLFSSL_MSG("ECC Public key import error."); - } - } - -#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ - (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \ - !defined(HAVE_SELFTEST) - if (ret == 0) { - ret = wc_ecc_set_rng((ecc_key *)keyShareEntry->key, ssl->rng); - if (ret != 0) { - WOLFSSL_MSG("Failure to set the ECC private key RNG."); - } - } -#endif - - if (ret == 0) { - PRIVATE_KEY_UNLOCK(); - ret = wc_ecc_shared_secret((ecc_key *)keyShareEntry->key, - &eccpubkey, sharedSecret, &outlen); - PRIVATE_KEY_LOCK(); - if (outlen != sharedSecretLen - ssSz) { - WOLFSSL_MSG("ECC shared secret derivation error."); - ret = BAD_FUNC_ARG; - } - } - } - if ((ret == 0) && (sharedSecretLen > ENCRYPT_LEN)) { - WOLFSSL_MSG("shared secret is too long."); - ret = LENGTH_ERROR; - } - if (ret == 0) { - /* Copy the shared secret to the pre-master secret pre-allocated - * buffer. */ - XMEMCPY(ssl->arrays->preMasterSecret, sharedSecret, sharedSecretLen); - ssl->arrays->preMasterSz = (word32) sharedSecretLen; + ssl->arrays->preMasterSz = ssSz; } - XFREE(sharedSecret, ssl->heap, DYNAMIC_TYPE_SECRET); - - wc_ecc_free(&eccpubkey); wc_KyberKey_Free(kem); return ret; } @@ -9062,41 +9056,32 @@ static int server_generate_pqc_ciphertext(WOLFSSL* ssl, */ int type; KyberKey kem[1]; - byte* sharedSecret = NULL; byte* ciphertext = NULL; int ret = 0; - int oqs_group = 0; + int pqc_group = 0; int ecc_group = 0; KeyShareEntry *ecc_kse = NULL; - ecc_key eccpubkey; word32 outlen = 0; word32 pubSz = 0; word32 ctSz = 0; word32 ssSz = 0; - findEccPqc(&ecc_group, &oqs_group, keyShareEntry->group); - ret = kyber_id2type(oqs_group, &type); + findEccPqc(&ecc_group, &pqc_group, keyShareEntry->group); + ret = kyber_id2type(pqc_group, &type); if (ret != 0) { WOLFSSL_MSG("Invalid Kyber algorithm specified."); return BAD_FUNC_ARG; } - ret = wc_ecc_init_ex(&eccpubkey, ssl->heap, ssl->devId); - if (ret != 0) { - WOLFSSL_MSG("Could not do ECC public key initialization."); - return MEMORY_E; - } - ret = wc_KyberKey_Init(type, kem, ssl->heap, ssl->devId); if (ret != 0) { - wc_ecc_free(&eccpubkey); WOLFSSL_MSG("Error creating Kyber KEM"); return MEMORY_E; } if (ret == 0) { ecc_kse = (KeyShareEntry*)XMALLOC(sizeof(*ecc_kse), ssl->heap, - DYNAMIC_TYPE_TLSX); + DYNAMIC_TYPE_TLSX); if (ecc_kse == NULL) { WOLFSSL_MSG("ecc_kse memory allocation failure"); ret = MEMORY_ERROR; @@ -9109,8 +9094,22 @@ static int server_generate_pqc_ciphertext(WOLFSSL* ssl, if (ret == 0 && ecc_group != 0) { ecc_kse->group = ecc_group; - ret = TLSX_KeyShare_GenEccKey(ssl, ecc_kse); - /* No message, TLSX_KeyShare_GenEccKey() will do it. */ + #ifdef HAVE_CURVE25519 + if (ecc_group == WOLFSSL_ECC_X25519) { + ret = TLSX_KeyShare_GenX25519Key(ssl, ecc_kse); + } + else + #endif + #ifdef HAVE_CURVE448 + if (ecc_group == WOLFSSL_ECC_X448) { + ret = TLSX_KeyShare_GenX448Key(ssl, ecc_kse); + } + else + #endif + { + ret = TLSX_KeyShare_GenEccKey(ssl, ecc_kse); + } + /* No error message, TLSX_KeyShare_GenKey will do it. */ } if (ret == 0) { @@ -9129,41 +9128,45 @@ static int server_generate_pqc_ciphertext(WOLFSSL* ssl, } if (ret == 0) { - sharedSecret = (byte*)XMALLOC(ecc_kse->keyLen + ssSz, ssl->heap, - DYNAMIC_TYPE_SECRET); ciphertext = (byte*)XMALLOC(ecc_kse->pubKeyLen + ctSz, ssl->heap, DYNAMIC_TYPE_TLSX); - if (sharedSecret == NULL || ciphertext == NULL) { - WOLFSSL_MSG("Ciphertext/shared secret memory allocation failure."); + if (ciphertext == NULL) { + WOLFSSL_MSG("Ciphertext memory allocation failure."); ret = MEMORY_E; } } - if (ecc_group != 0) { + if (ret == 0 && ecc_group != 0) { + ecc_kse->keLen = len - pubSz; + ecc_kse->ke = (byte*)XMALLOC(ecc_kse->keLen, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (ecc_kse->ke == NULL) { + WOLFSSL_MSG("ecc_kse memory allocation failure"); + ret = MEMORY_ERROR; + } if (ret == 0) { - /* Point is validated by import function. */ - ret = wc_ecc_import_x963(data, len - pubSz, &eccpubkey); - if (ret != 0) { - WOLFSSL_MSG("Bad ECC public key."); + XMEMCPY(ecc_kse->ke, data, ecc_kse->keLen); + + #ifdef HAVE_CURVE25519 + if (ecc_group == WOLFSSL_ECC_X25519) { + ret = TLSX_KeyShare_ProcessX25519(ssl, ecc_kse); + } + else + #endif + #ifdef HAVE_CURVE448 + if (ecc_group == WOLFSSL_ECC_X448) { + ret = TLSX_KeyShare_ProcessX448(ssl, ecc_kse); + } + else + #endif + { + ret = TLSX_KeyShare_ProcessEcc(ssl, ecc_kse); } } - -#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ - (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \ - !defined(HAVE_SELFTEST) if (ret == 0) { - ret = wc_ecc_set_rng((ecc_key *)ecc_kse->key, ssl->rng); - } -#endif + outlen = ssl->arrays->preMasterSz; - if (ret == 0) { - outlen = ecc_kse->keyLen; - PRIVATE_KEY_UNLOCK(); - ret = wc_ecc_shared_secret((ecc_key *)ecc_kse->key, &eccpubkey, - sharedSecret, - &outlen); - PRIVATE_KEY_LOCK(); if (outlen != ecc_kse->keyLen) { WOLFSSL_MSG("Data length mismatch."); ret = BAD_FUNC_ARG; @@ -9171,13 +9174,18 @@ static int server_generate_pqc_ciphertext(WOLFSSL* ssl, } } + if (ret == 0 && outlen + ssSz > ENCRYPT_LEN) { + WOLFSSL_MSG("shared secret is too long."); + ret = LENGTH_ERROR; + } + if (ret == 0) { ret = wc_KyberKey_DecodePublicKey(kem, data + ecc_kse->pubKeyLen, pubSz); } if (ret == 0) { ret = wc_KyberKey_Encapsulate(kem, ciphertext + ecc_kse->pubKeyLen, - sharedSecret + outlen, ssl->rng); + ssl->arrays->preMasterSecret + outlen, ssl->rng); if (ret != 0) { WOLFSSL_MSG("wc_KyberKey encapsulation failure."); } @@ -9186,9 +9194,9 @@ static int server_generate_pqc_ciphertext(WOLFSSL* ssl, if (ret == 0) { XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); - keyShareEntry->ke = sharedSecret; - keyShareEntry->keLen = outlen + ssSz; - sharedSecret = NULL; + ssl->arrays->preMasterSz = outlen + ssSz; + keyShareEntry->ke = NULL; + keyShareEntry->keLen = 0; if (ecc_kse->pubKeyLen > 0) XMEMCPY(ciphertext, ecc_kse->pubKey, ecc_kse->pubKeyLen); @@ -9202,9 +9210,7 @@ static int server_generate_pqc_ciphertext(WOLFSSL* ssl, } TLSX_KeyShare_FreeAll(ecc_kse, ssl->heap); - XFREE(sharedSecret, ssl->heap, DYNAMIC_TYPE_SECRET); XFREE(ciphertext, ssl->heap, DYNAMIC_TYPE_TLSX); - wc_ecc_free(&eccpubkey); wc_KyberKey_Free(kem); return ret; } @@ -9427,14 +9433,25 @@ static int TLSX_KeyShare_IsSupported(int namedGroup) #ifdef WOLFSSL_KYBER512 case WOLFSSL_KYBER_LEVEL1: case WOLFSSL_P256_KYBER_LEVEL1: + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + case WOLFSSL_X25519_KYBER_LEVEL1: + #endif #endif #ifdef WOLFSSL_KYBER768 case WOLFSSL_KYBER_LEVEL3: case WOLFSSL_P384_KYBER_LEVEL3: + case WOLFSSL_P256_KYBER_LEVEL3: + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + case WOLFSSL_X25519_KYBER_LEVEL3: + #endif + #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448 + case WOLFSSL_X448_KYBER_LEVEL3: + #endif #endif #ifdef WOLFSSL_KYBER1024 case WOLFSSL_KYBER_LEVEL5: case WOLFSSL_P521_KYBER_LEVEL5: + case WOLFSSL_P384_KYBER_LEVEL5: #endif break; #elif defined(HAVE_LIBOQS) @@ -9443,7 +9460,12 @@ static int TLSX_KeyShare_IsSupported(int namedGroup) case WOLFSSL_KYBER_LEVEL5: case WOLFSSL_P256_KYBER_LEVEL1: case WOLFSSL_P384_KYBER_LEVEL3: + case WOLFSSL_P256_KYBER_LEVEL3: case WOLFSSL_P521_KYBER_LEVEL5: + case WOLFSSL_P384_KYBER_LEVEL5: + case WOLFSSL_X25519_KYBER_LEVEL1: + case WOLFSSL_X448_KYBER_LEVEL3: + case WOLFSSL_X25519_KYBER_LEVEL3: { int ret; int id; @@ -9509,14 +9531,25 @@ static const word16 preferredGroup[] = { #ifdef WOLFSSL_KYBER512 WOLFSSL_KYBER_LEVEL1, WOLFSSL_P256_KYBER_LEVEL1, + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + WOLFSSL_X25519_KYBER_LEVEL1, + #endif #endif #ifdef WOLFSSL_KYBER768 WOLFSSL_KYBER_LEVEL3, WOLFSSL_P384_KYBER_LEVEL3, + WOLFSSL_P256_KYBER_LEVEL3, + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + WOLFSSL_X25519_KYBER_LEVEL3, + #endif + #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448 + WOLFSSL_X448_KYBER_LEVEL3, + #endif #endif #ifdef WOLFSSL_KYBER1024 WOLFSSL_KYBER_LEVEL5, WOLFSSL_P521_KYBER_LEVEL5, + WOLFSSL_P384_KYBER_LEVEL5, #endif #elif defined(HAVE_LIBOQS) /* These require a runtime call to TLSX_KeyShare_IsSupported to use */ @@ -9525,7 +9558,16 @@ static const word16 preferredGroup[] = { WOLFSSL_KYBER_LEVEL5, WOLFSSL_P256_KYBER_LEVEL1, WOLFSSL_P384_KYBER_LEVEL3, + WOLFSSL_P256_KYBER_LEVEL3, WOLFSSL_P521_KYBER_LEVEL5, + WOLFSSL_P384_KYBER_LEVEL5, + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + WOLFSSL_X25519_KYBER_LEVEL1, + WOLFSSL_X25519_KYBER_LEVEL3, + #endif + #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448 + WOLFSSL_X448_KYBER_LEVEL3, + #endif #endif WOLFSSL_NAMED_GROUP_INVALID }; @@ -9809,7 +9851,8 @@ int TLSX_KeyShare_Choose(const WOLFSSL *ssl, TLSX* extensions, /* Use server's preference order. */ for (clientKSE = list; clientKSE != NULL; clientKSE = clientKSE->next) { - if (clientKSE->ke == NULL) + if ((clientKSE->ke == NULL) && + (!WOLFSSL_NAMED_GROUP_IS_PQC(clientKSE->group))) continue; #ifdef WOLFSSL_SM2 @@ -9888,7 +9931,7 @@ int TLSX_KeyShare_Setup(WOLFSSL *ssl, KeyShareEntry* clientKSE) return BAD_FUNC_ARG; } - /* Generate a new key pair except in the case of OQS KEM because we + /* Generate a new key pair except in the case of PQC KEM because we * are going to encapsulate and that does not require us to generate a * key pair. */ @@ -13132,6 +13175,11 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) if (ret == WOLFSSL_SUCCESS) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_KYBER_LEVEL1, ssl->heap); + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_KYBER_LEVEL1, + ssl->heap); + #endif #endif #ifdef WOLFSSL_KYBER768 if (ret == WOLFSSL_SUCCESS) @@ -13140,6 +13188,19 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) if (ret == WOLFSSL_SUCCESS) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_KYBER_LEVEL3, ssl->heap); + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_KYBER_LEVEL3, + ssl->heap); + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_KYBER_LEVEL3, + ssl->heap); + #endif + #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448 + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X448_KYBER_LEVEL3, + ssl->heap); + #endif #endif #ifdef WOLFSSL_KYBER1024 if (ret == WOLFSSL_SUCCESS) @@ -13148,6 +13209,9 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) if (ret == WOLFSSL_SUCCESS) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P521_KYBER_LEVEL5, ssl->heap); + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_KYBER_LEVEL5, + ssl->heap); #endif #elif defined(HAVE_LIBOQS) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_KYBER_LEVEL1, ssl->heap); @@ -13163,9 +13227,28 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) if (ret == WOLFSSL_SUCCESS) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_KYBER_LEVEL3, ssl->heap); + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_KYBER_LEVEL3, + ssl->heap); if (ret == WOLFSSL_SUCCESS) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P521_KYBER_LEVEL5, ssl->heap); + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_KYBER_LEVEL5, + ssl->heap); + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_KYBER_LEVEL1, + ssl->heap); + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_KYBER_LEVEL3, + ssl->heap); + #endif + #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448 + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X448_KYBER_LEVEL3, + ssl->heap); + #endif #endif /* HAVE_LIBOQS */ #endif /* WOLFSSL_HAVE_KYBER */ diff --git a/tests/include.am b/tests/include.am index 5ed4fe40dc..1bb9fa38ab 100644 --- a/tests/include.am +++ b/tests/include.am @@ -27,11 +27,11 @@ EXTRA_DIST += tests/unit.h \ tests/test-tls13-ecc.conf \ tests/test-tls13-psk.conf \ tests/test-tls13-pq.conf \ - tests/test-tls13-pq-2.conf \ + tests/test-tls13-pq-hybrid.conf \ tests/test-dtls13-pq.conf \ tests/test-dtls13-pq-frag.conf \ - tests/test-dtls13-pq-2.conf \ - tests/test-dtls13-pq-2-frag.conf \ + tests/test-dtls13-pq-hybrid.conf \ + tests/test-dtls13-pq-hybrid-frag.conf \ tests/test-psk.conf \ tests/test-psk-no-id.conf \ tests/test-psk-no-id-sha2.conf \ diff --git a/tests/suites.c b/tests/suites.c index 7328789f46..8d65cfaf34 100644 --- a/tests/suites.c +++ b/tests/suites.c @@ -969,9 +969,8 @@ int SuiteTest(int argc, char** argv) args.return_code = EXIT_FAILURE; goto exit; } - #ifdef HAVE_LIBOQS - /* add TLSv13 pq tests */ - XSTRLCPY(argv0[1], "tests/test-tls13-pq-2.conf", sizeof(argv0[1])); + /* add TLSv13 pq hybrid tests */ + XSTRLCPY(argv0[1], "tests/test-tls13-pq-hybrid.conf", sizeof(argv0[1])); printf("starting TLSv13 post-quantum groups tests\n"); test_harness(&args); if (args.return_code != 0) { @@ -980,29 +979,6 @@ int SuiteTest(int argc, char** argv) goto exit; } #endif - #endif - #ifdef HAVE_PQC - /* add TLSv13 pq tests */ - XSTRLCPY(argv0[1], "tests/test-tls13-pq.conf", sizeof(argv0[1])); - printf("starting TLSv13 post-quantum groups tests\n"); - test_harness(&args); - if (args.return_code != 0) { - printf("error from script %d\n", args.return_code); - args.return_code = EXIT_FAILURE; - goto exit; - } - #ifdef HAVE_LIBOQS - /* add TLSv13 pq tests */ - XSTRLCPY(argv0[1], "tests/test-tls13-pq-2.conf", sizeof(argv0[1])); - printf("starting TLSv13 post-quantum groups tests\n"); - test_harness(&args); - if (args.return_code != 0) { - printf("error from script %d\n", args.return_code); - args.return_code = EXIT_FAILURE; - goto exit; - } - #endif - #endif #if defined(HAVE_PQC) && defined(WOLFSSL_DTLS13) /* add DTLSv13 pq tests */ XSTRLCPY(argv0[1], "tests/test-dtls13-pq.conf", sizeof(argv0[1])); @@ -1013,30 +989,27 @@ int SuiteTest(int argc, char** argv) args.return_code = EXIT_FAILURE; goto exit; } - #ifdef WOLFSSL_DTLS_CH_FRAG - /* add DTLSv13 pq frag tests */ - XSTRLCPY(argv0[1], "tests/test-dtls13-pq-frag.conf", sizeof(argv0[1])); - printf("starting DTLSv13 post-quantum groups tests with fragmentation\n"); + /* add DTLSv13 pq hybrid tests */ + XSTRLCPY(argv0[1], "tests/test-dtls13-pq-hybrid.conf", sizeof(argv0[1])); + printf("starting DTLSv13 post-quantum 2 groups tests\n"); test_harness(&args); if (args.return_code != 0) { printf("error from script %d\n", args.return_code); args.return_code = EXIT_FAILURE; goto exit; } - #endif - #ifdef HAVE_LIBOQS - /* add DTLSv13 pq 2 tests */ - XSTRLCPY(argv0[1], "tests/test-dtls13-pq-2.conf", sizeof(argv0[1])); - printf("starting DTLSv13 post-quantum 2 groups tests\n"); + #ifdef WOLFSSL_DTLS_CH_FRAG + /* add DTLSv13 pq frag tests */ + XSTRLCPY(argv0[1], "tests/test-dtls13-pq-frag.conf", sizeof(argv0[1])); + printf("starting DTLSv13 post-quantum groups tests with fragmentation\n"); test_harness(&args); if (args.return_code != 0) { printf("error from script %d\n", args.return_code); args.return_code = EXIT_FAILURE; goto exit; } - #ifdef WOLFSSL_DTLS_CH_FRAG - /* add DTLSv13 pq 2 frag tests */ - XSTRLCPY(argv0[1], "tests/test-dtls13-pq-2-frag.conf", sizeof(argv0[1])); + /* add DTLSv13 pq hybrid frag tests */ + XSTRLCPY(argv0[1], "tests/test-dtls13-pq-hybrid-frag.conf", sizeof(argv0[1])); printf("starting DTLSv13 post-quantum 2 groups tests with fragmentation\n"); test_harness(&args); if (args.return_code != 0) { @@ -1046,7 +1019,6 @@ int SuiteTest(int argc, char** argv) } #endif #endif - #endif #endif #if defined(WC_RSA_PSS) && (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) && \ diff --git a/tests/test-dtls13-pq-2-frag.conf b/tests/test-dtls13-pq-2-frag.conf deleted file mode 100644 index 6ea8317db0..0000000000 --- a/tests/test-dtls13-pq-2-frag.conf +++ /dev/null @@ -1,23 +0,0 @@ -# server DTLSv1.3 with post-quantum group --u --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P384_KYBER_LEVEL3 - -# client DTLSv1.3 with post-quantum group --u --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P384_KYBER_LEVEL3 - -# server DTLSv1.3 with post-quantum group --u --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P521_KYBER_LEVEL5 - -# client DTLSv1.3 with post-quantum group --u --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P521_KYBER_LEVEL5 diff --git a/tests/test-dtls13-pq-2.conf b/tests/test-dtls13-pq-2.conf deleted file mode 100644 index 6a4bfac084..0000000000 --- a/tests/test-dtls13-pq-2.conf +++ /dev/null @@ -1,13 +0,0 @@ -# server DTLSv1.3 with post-quantum group --u --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P256_KYBER_LEVEL1 - -# client DTLSv1.3 with post-quantum group --u --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P256_KYBER_LEVEL1 - -# P384_KYBER_LEVEL3 and P521_KYBER_LEVEL5 would fragment the ClientHello. diff --git a/tests/test-dtls13-pq-frag.conf b/tests/test-dtls13-pq-frag.conf index 01aaf477fe..3696286078 100644 --- a/tests/test-dtls13-pq-frag.conf +++ b/tests/test-dtls13-pq-frag.conf @@ -21,4 +21,3 @@ -v 4 -l TLS13-AES256-GCM-SHA384 --pqc KYBER_LEVEL5 - diff --git a/tests/test-dtls13-pq-hybrid-frag.conf b/tests/test-dtls13-pq-hybrid-frag.conf new file mode 100644 index 0000000000..88ee706764 --- /dev/null +++ b/tests/test-dtls13-pq-hybrid-frag.conf @@ -0,0 +1,71 @@ +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_KYBER_LEVEL3 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_KYBER_LEVEL3 + +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_KYBER_LEVEL3 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_KYBER_LEVEL3 + +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P521_KYBER_LEVEL5 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P521_KYBER_LEVEL5 + +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_KYBER_LEVEL5 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_KYBER_LEVEL5 + +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_KYBER_LEVEL3 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_KYBER_LEVEL3 + +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X448_KYBER_LEVEL3 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X448_KYBER_LEVEL3 diff --git a/tests/test-dtls13-pq-hybrid.conf b/tests/test-dtls13-pq-hybrid.conf new file mode 100644 index 0000000000..64332b5dd0 --- /dev/null +++ b/tests/test-dtls13-pq-hybrid.conf @@ -0,0 +1,25 @@ +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_KYBER_LEVEL1 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_KYBER_LEVEL1 + +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_KYBER_LEVEL1 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_KYBER_LEVEL1 + +# Hybrids with KYBER_LEVEL3 and KYBER_LEVEL5 would fragment the ClientHello. diff --git a/tests/test-tls13-pq-2.conf b/tests/test-tls13-pq-2.conf deleted file mode 100644 index ff09d72a71..0000000000 --- a/tests/test-tls13-pq-2.conf +++ /dev/null @@ -1,29 +0,0 @@ -# server TLSv1.3 with post-quantum group --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P256_KYBER_LEVEL1 - -# client TLSv1.3 with post-quantum group --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P256_KYBER_LEVEL1 - -# server TLSv1.3 with post-quantum group --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P384_KYBER_LEVEL3 - -# client TLSv1.3 with post-quantum group --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P384_KYBER_LEVEL3 - -# server TLSv1.3 with post-quantum group --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P521_KYBER_LEVEL5 - -# client TLSv1.3 with post-quantum group --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P521_KYBER_LEVEL5 diff --git a/tests/test-tls13-pq-hybrid.conf b/tests/test-tls13-pq-hybrid.conf new file mode 100644 index 0000000000..3d98f94c45 --- /dev/null +++ b/tests/test-tls13-pq-hybrid.conf @@ -0,0 +1,79 @@ +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_KYBER_LEVEL1 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_KYBER_LEVEL1 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_KYBER_LEVEL3 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_KYBER_LEVEL3 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_KYBER_LEVEL3 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_KYBER_LEVEL3 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P521_KYBER_LEVEL5 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P521_KYBER_LEVEL5 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_KYBER_LEVEL5 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_KYBER_LEVEL5 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_KYBER_LEVEL1 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_KYBER_LEVEL1 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_KYBER_LEVEL3 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_KYBER_LEVEL3 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X448_KYBER_LEVEL3 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X448_KYBER_LEVEL3 diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 37cf731ae2..ffe523a92b 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1861,9 +1861,8 @@ enum Misc { #define WOLFSSL_NAMED_GROUP_IS_FFHDE(group) \ (MIN_FFHDE_GROUP <= (group) && (group) <= MAX_FFHDE_GROUP) #ifdef WOLFSSL_HAVE_KYBER -#define WOLFSSL_NAMED_GROUP_IS_PQC(group) \ - ((WOLFSSL_PQC_SIMPLE_MIN <= (group) && (group) <= WOLFSSL_PQC_SIMPLE_MAX) || \ - (WOLFSSL_PQC_HYBRID_MIN <= (group) && (group) <= WOLFSSL_PQC_HYBRID_MAX)) +WOLFSSL_LOCAL int NamedGroupIsPqc(int group); +#define WOLFSSL_NAMED_GROUP_IS_PQC(group) NamedGroupIsPqc(group) #else #define WOLFSSL_NAMED_GROUP_IS_PQC(group) ((void)(group), 0) #endif /* WOLFSSL_HAVE_KYBER */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 90f711589e..59850e58ff 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -4108,51 +4108,54 @@ enum { WOLFSSL_FFDHE_8192 = 260, #ifdef HAVE_PQC - /* These group numbers were taken from OQS's openssl provider, see: + +#ifdef WOLFSSL_KYBER_ORIGINAL + /* Old code points to keep compatibility with Kyber Round 3. + * To be removed in the future. + * Taken from OQS's openssl provider, see: * https://github.com/open-quantum-safe/oqs-provider/blob/main/oqs-template/ - * oqs-kem-info.md. - * - * The levels in the group name refer to the claimed NIST level of each - * parameter set. The associated parameter set name is listed as a comment - * beside the group number. Please see the NIST PQC Competition's submitted - * papers for more details. - * - * LEVEL1 means that an attack on that parameter set would require the same - * or more resources as a key search on AES 128. LEVEL3 would require the - * same or more resources as a key search on AES 192. LEVEL5 would require - * the same or more resources as a key search on AES 256. None of the - * algorithms have LEVEL2 and LEVEL4 because none of these submissions - * included them. */ - -#ifndef WOLFSSL_ML_KEM - WOLFSSL_PQC_MIN = 570, - WOLFSSL_PQC_SIMPLE_MIN = 570, + * oqs-kem-info.md + */ WOLFSSL_KYBER_LEVEL1 = 570, /* KYBER_512 */ WOLFSSL_KYBER_LEVEL3 = 572, /* KYBER_768 */ WOLFSSL_KYBER_LEVEL5 = 573, /* KYBER_1024 */ - WOLFSSL_PQC_SIMPLE_MAX = 573, - WOLFSSL_PQC_HYBRID_MIN = 12090, WOLFSSL_P256_KYBER_LEVEL1 = 12090, WOLFSSL_P384_KYBER_LEVEL3 = 12092, WOLFSSL_P521_KYBER_LEVEL5 = 12093, - WOLFSSL_PQC_HYBRID_MAX = 12093, - WOLFSSL_PQC_MAX = 12093, + WOLFSSL_P384_KYBER_LEVEL5 = 12094, /* Not defined in OQS! */ + WOLFSSL_X25519_KYBER_LEVEL1 = 12089, + WOLFSSL_X448_KYBER_LEVEL3 = 12176, + WOLFSSL_X25519_KYBER_LEVEL3 = 25497, + WOLFSSL_P256_KYBER_LEVEL3 = 25498, + #else - WOLFSSL_PQC_MIN = 583, - WOLFSSL_PQC_SIMPLE_MIN = 583, - WOLFSSL_KYBER_LEVEL1 = 583, /* ML-KEM 512 */ - WOLFSSL_KYBER_LEVEL3 = 584, /* ML-KEM 768 */ - WOLFSSL_KYBER_LEVEL5 = 585, /* ML-KEM 1024 */ - WOLFSSL_PQC_SIMPLE_MAX = 585, - - WOLFSSL_PQC_HYBRID_MIN = 12103, - WOLFSSL_P256_KYBER_LEVEL1 = 12103, - WOLFSSL_P384_KYBER_LEVEL3 = 12104, - WOLFSSL_P521_KYBER_LEVEL5 = 12105, - WOLFSSL_PQC_HYBRID_MAX = 12105, - WOLFSSL_PQC_MAX = 12105, -#endif /* WOLFSSL_ML_KEM */ + /* Taken from OQS's openssl provider, see: + * https://github.com/open-quantum-safe/oqs-provider/blob/main/oqs-template/ + * oqs-kem-info.md + */ + WOLFSSL_KYBER_LEVEL1 = 586, /* ML-KEM 512 */ + WOLFSSL_KYBER_LEVEL3 = 1896, /* ML-KEM 768 */ + WOLFSSL_KYBER_LEVEL5 = 4132, /* ML-KEM 1024 */ + + /* Taken from draft-kwiatkowski-tls-ecdhe-mlkem. see: + * https://github.com/post-quantum-cryptography/ + * draft-kwiatkowski-tls-ecdhe-mlkem/ + */ + WOLFSSL_P256_KYBER_LEVEL3 = 4587, + WOLFSSL_X25519_KYBER_LEVEL3 = 4588, + WOLFSSL_P384_KYBER_LEVEL5 = 4589, + + /* Taken from OQS's openssl provider, see: + * https://github.com/open-quantum-safe/oqs-provider/blob/main/oqs-template/ + * oqs-kem-info.md + */ + WOLFSSL_P256_KYBER_LEVEL1 = 12107, + WOLFSSL_P384_KYBER_LEVEL3 = 12108, + WOLFSSL_P521_KYBER_LEVEL5 = 12109, + WOLFSSL_X25519_KYBER_LEVEL1 = 12214, + WOLFSSL_X448_KYBER_LEVEL3 = 12215, +#endif /* WOLFSSL_KYBER_ORIGINAL */ #endif /* HAVE_PQC */ };