diff --git a/examples/benchmark/tls_bench.c b/examples/benchmark/tls_bench.c index 15e053dfd..e44f164c2 100644 --- a/examples/benchmark/tls_bench.c +++ b/examples/benchmark/tls_bench.c @@ -296,17 +296,26 @@ static struct group_info groups[] = { { WOLFSSL_ML_KEM_512, "ML_KEM_512" }, { WOLFSSL_ML_KEM_768, "ML_KEM_768" }, { WOLFSSL_ML_KEM_1024, "ML_KEM_1024" }, - { WOLFSSL_P256_ML_KEM_512, "P256_ML_KEM_512" }, - { WOLFSSL_P384_ML_KEM_768, "P384_ML_KEM_768" }, - { WOLFSSL_P521_ML_KEM_1024, "P521_ML_KEM_1024" }, + { WOLFSSL_P256_ML_KEM_512, "P256_ML_KEM_512" }, + { WOLFSSL_P384_ML_KEM_768, "P384_ML_KEM_768" }, + { WOLFSSL_P256_ML_KEM_768, "P256_ML_KEM_768" }, + { WOLFSSL_P521_ML_KEM_1024, "P521_ML_KEM_1024" }, + { WOLFSSL_P384_ML_KEM_1024, "P384_ML_KEM_1024" }, + { WOLFSSL_X25519_ML_KEM_512, "X25519_ML_KEM_512" }, + { WOLFSSL_X448_ML_KEM_768, "X448_ML_KEM_768" }, + { WOLFSSL_X25519_ML_KEM_768, "X25519_ML_KEM_768" }, #endif #ifdef WOLFSSL_KYBER_ORIGINAL { 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_X25519_KYBER_LEVEL1, "X25519_KYBER_LEVEL1" }, + { WOLFSSL_X448_KYBER_LEVEL3, "X448_KYBER_LEVEL3" }, + { WOLFSSL_X25519_KYBER_LEVEL3, "X25519_KYBER_LEVEL3" }, #endif #endif { 0, NULL } diff --git a/examples/client/client.c b/examples/client/client.c index 5c2e34053..dca255c19 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -431,12 +431,36 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519, if (XSTRCMP(pqcAlg, "P384_ML_KEM_768") == 0) { group = WOLFSSL_P384_ML_KEM_768; } + else if (XSTRCMP(pqcAlg, "P256_ML_KEM_768") == 0) { + group = WOLFSSL_P256_ML_KEM_768; + } else #endif #ifndef WOLFSSL_NO_ML_KEM_1024 if (XSTRCMP(pqcAlg, "P521_ML_KEM_1024") == 0) { group = WOLFSSL_P521_ML_KEM_1024; } + else if (XSTRCMP(pqcAlg, "P384_ML_KEM_1024") == 0) { + group = WOLFSSL_P384_ML_KEM_1024; + } + else + #endif + #if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_CURVE25519) + if (XSTRCMP(pqcAlg, "X25519_ML_KEM_512") == 0) { + group = WOLFSSL_X25519_ML_KEM_512; + } + else + #endif + #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519) + if (XSTRCMP(pqcAlg, "X25519_ML_KEM_768") == 0) { + group = WOLFSSL_X25519_ML_KEM_768; + } + else + #endif + #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE448) + if (XSTRCMP(pqcAlg, "X448_ML_KEM_768") == 0) { + group = WOLFSSL_X448_ML_KEM_768; + } else #endif #endif /* WOLFSSL_NO_ML_KEM */ @@ -469,6 +493,9 @@ 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 @@ -477,6 +504,24 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519, } 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; + } + else + #endif #endif /* WOLFSSL_KYBER_ORIGINAL */ { err_sys("invalid post-quantum KEM specified"); @@ -1378,12 +1423,18 @@ static const char* client_usage_msg[][78] = { #ifndef WOLFSSL_NO_ML_KEM " ML_KEM_512, ML_KEM_768, ML_KEM_1024, P256_ML_KEM_512," "\n" - " P384_ML_KEM_768, P521_ML_KEM_1024\n" + " P384_ML_KEM_768, P256_ML_KEM_768, P521_ML_KEM_1024,\n" + " P384_ML_KEM_1024, X25519_ML_KEM_512, " + "X25519_ML_KEM_768,\n" + " X448_ML_KEM_768\n" #endif #ifdef WOLFSSL_KYBER_ORIGINAL " KYBER_LEVEL1, KYBER_LEVEL3, KYBER_LEVEL5, " "P256_KYBER_LEVEL1,\n" - " P384_KYBER_LEVEL3, P521_KYBER_LEVEL5\n" + " P384_KYBER_LEVEL3, P256_KYBER_LEVEL3, " + "P521_KYBER_LEVEL5,\n" + " X25519_KYBER_LEVEL1, X25519_KYBER_LEVEL3, " + "X448_KYBER_LEVEL3\n" #endif "", /* 69 */ diff --git a/examples/server/server.c b/examples/server/server.c index 83581ee42..2f093d161 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -744,12 +744,36 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519, if (XSTRCMP(pqcAlg, "P384_ML_KEM_768") == 0) { groups[count] = WOLFSSL_P384_ML_KEM_768; } + else if (XSTRCMP(pqcAlg, "P256_ML_KEM_768") == 0) { + groups[count] = WOLFSSL_P256_ML_KEM_768; + } else #endif #ifndef WOLFSSL_NO_ML_KEM_1024 if (XSTRCMP(pqcAlg, "P521_ML_KEM_1024") == 0) { groups[count] = WOLFSSL_P521_ML_KEM_1024; } + else if (XSTRCMP(pqcAlg, "P384_ML_KEM_1024") == 0) { + groups[count] = WOLFSSL_P384_ML_KEM_1024; + } + else + #endif + #if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_CURVE25519) + if (XSTRCMP(pqcAlg, "X25519_ML_KEM_512") == 0) { + groups[count] = WOLFSSL_X25519_ML_KEM_512; + } + else + #endif + #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519) + if (XSTRCMP(pqcAlg, "X25519_ML_KEM_768") == 0) { + groups[count] = WOLFSSL_X25519_ML_KEM_768; + } + else + #endif + #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE448) + if (XSTRCMP(pqcAlg, "X448_ML_KEM_768") == 0) { + groups[count] = WOLFSSL_X448_ML_KEM_768; + } else #endif #endif /* WOLFSSL_NO_ML_KEM */ @@ -782,6 +806,9 @@ 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 @@ -790,6 +817,24 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519, } 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 #endif { err_sys("invalid post-quantum KEM specified"); @@ -1027,12 +1072,18 @@ static const char* server_usage_msg[][66] = { #ifndef WOLFSSL_NO_ML_KEM " ML_KEM_512, ML_KEM_768, ML_KEM_1024, P256_ML_KEM_512," "\n" - " P384_ML_KEM_768, P521_ML_KEM_1024\n" + " P384_ML_KEM_768, P256_ML_KEM_768, P521_ML_KEM_1024,\n" + " P384_ML_KEM_1024, X25519_ML_KEM_512, " + "X25519_ML_KEM_768,\n" + " X448_ML_KEM_768\n" #endif #ifdef WOLFSSL_KYBER_ORIGINAL " KYBER_LEVEL1, KYBER_LEVEL3, KYBER_LEVEL5, " "P256_KYBER_LEVEL1,\n" - " P384_KYBER_LEVEL3, P521_KYBER_LEVEL5\n" + " P384_KYBER_LEVEL3, P256_KYBER_LEVEL3, " + "P521_KYBER_LEVEL5,\n" + " X25519_KYBER_LEVEL1, X25519_KYBER_LEVEL3, " + "X448_KYBER_LEVEL3\n" #endif "", /* 60 */ diff --git a/src/internal.c b/src/internal.c index c34d94b2a..b7f90a864 100644 --- a/src/internal.c +++ b/src/internal.c @@ -35136,6 +35136,57 @@ 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) { + #ifndef WOLFSSL_NO_ML_KEM + case WOLFSSL_ML_KEM_512: + case WOLFSSL_ML_KEM_768: + case WOLFSSL_ML_KEM_1024: + #endif + #ifdef WOLFSSL_KYBER_ORIGINAL + case WOLFSSL_KYBER_LEVEL1: + case WOLFSSL_KYBER_LEVEL3: + case WOLFSSL_KYBER_LEVEL5: + #endif + return 1; + default: + return 0; + } + } + + /* Returns 1 when the given group is a PQC hybrid group, 0 otherwise. */ + int NamedGroupIsPqcHybrid(int group) + { + switch (group) { + #ifndef WOLFSSL_NO_ML_KEM + case WOLFSSL_P256_ML_KEM_768: + case WOLFSSL_X25519_ML_KEM_768: + case WOLFSSL_P384_ML_KEM_1024: + case WOLFSSL_P256_ML_KEM_512: + case WOLFSSL_P384_ML_KEM_768: + case WOLFSSL_P521_ML_KEM_1024: + case WOLFSSL_X25519_ML_KEM_512: + case WOLFSSL_X448_ML_KEM_768: + #endif + #ifdef WOLFSSL_KYBER_ORIGINAL + case WOLFSSL_P256_KYBER_LEVEL3: + case WOLFSSL_X25519_KYBER_LEVEL3: + 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: + #endif + 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 fca23c9b8..c674d7e48 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -3601,6 +3601,11 @@ static int isValidCurveGroup(word16 name) case WOLFSSL_P256_ML_KEM_512: case WOLFSSL_P384_ML_KEM_768: case WOLFSSL_P521_ML_KEM_1024: + case WOLFSSL_P384_ML_KEM_1024: + case WOLFSSL_X25519_ML_KEM_512: + case WOLFSSL_X448_ML_KEM_768: + case WOLFSSL_X25519_ML_KEM_768: + case WOLFSSL_P256_ML_KEM_768: #endif #endif /* !WOLFSSL_NO_ML_KEM */ #ifdef WOLFSSL_KYBER_ORIGINAL @@ -3611,6 +3616,10 @@ static int isValidCurveGroup(word16 name) 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: + case WOLFSSL_X25519_KYBER_LEVEL3: + case WOLFSSL_P256_KYBER_LEVEL3: #endif #endif /* WOLFSSL_KYBER_ORIGINAL */ #endif @@ -15381,66 +15390,97 @@ const char* wolfSSL_get_curve_name(WOLFSSL* ssl) if (IsAtLeastTLSv1_3(ssl->version)) { switch (ssl->namedGroup) { #ifndef WOLFSSL_NO_ML_KEM -#ifdef HAVE_LIBOQS - case WOLFSSL_ML_KEM_512: - return "ML_KEM_512"; - case WOLFSSL_ML_KEM_768: - return "ML_KEM_768"; - case WOLFSSL_ML_KEM_1024: - return "ML_KEM_1024"; - case WOLFSSL_P256_ML_KEM_512: - return "P256_ML_KEM_512"; - case WOLFSSL_P384_ML_KEM_768: - return "P384_ML_KEM_768"; - case WOLFSSL_P521_ML_KEM_1024: - return "P521_ML_KEM_1024"; -#elif defined(WOLFSSL_WC_KYBER) +#if defined(WOLFSSL_WC_KYBER) #ifndef WOLFSSL_NO_ML_KEM_512 case WOLFSSL_ML_KEM_512: return "ML_KEM_512"; case WOLFSSL_P256_ML_KEM_512: return "P256_ML_KEM_512"; + #ifdef HAVE_CURVE25519 + case WOLFSSL_X25519_ML_KEM_512: + return "X25519_ML_KEM_512"; + #endif #endif #ifndef WOLFSSL_NO_ML_KEM_768 case WOLFSSL_ML_KEM_768: return "ML_KEM_768"; case WOLFSSL_P384_ML_KEM_768: return "P384_ML_KEM_768"; + case WOLFSSL_P256_ML_KEM_768: + return "P256_ML_KEM_768"; + #ifdef HAVE_CURVE25519 + case WOLFSSL_X25519_ML_KEM_768: + return "X25519_ML_KEM_768"; + #endif + #ifdef HAVE_CURVE448 + case WOLFSSL_X448_ML_KEM_768: + return "X448_ML_KEM_768"; + #endif #endif #ifndef WOLFSSL_NO_ML_KEM_1024 case WOLFSSL_ML_KEM_1024: return "ML_KEM_1024"; case WOLFSSL_P521_ML_KEM_1024: return "P521_ML_KEM_1024"; + case WOLFSSL_P384_ML_KEM_1024: + return "P384_ML_KEM_1024"; #endif -#endif -#endif +#elif defined(HAVE_LIBOQS) + case WOLFSSL_ML_KEM_512: + return "ML_KEM_512"; + case WOLFSSL_ML_KEM_768: + return "ML_KEM_768"; + case WOLFSSL_ML_KEM_1024: + return "ML_KEM_1024"; + case WOLFSSL_P256_ML_KEM_512: + return "P256_ML_KEM_512"; + case WOLFSSL_P384_ML_KEM_768: + return "P384_ML_KEM_768"; + case WOLFSSL_P256_ML_KEM_768: + return "P256_ML_KEM_768"; + case WOLFSSL_P521_ML_KEM_1024: + return "P521_ML_KEM_1024"; + case WOLFSSL_P384_ML_KEM_1024: + return "P384_ML_KEM_1024"; + #ifdef HAVE_CURVE25519 + case WOLFSSL_X25519_ML_KEM_512: + return "X25519_ML_KEM_512"; + case WOLFSSL_X25519_ML_KEM_768: + return "X25519_ML_KEM_768"; + #endif + #ifdef HAVE_CURVE448 + case WOLFSSL_X448_ML_KEM_768: + return "X448_ML_KEM_768"; + #endif +#endif /* WOLFSSL_WC_KYBER */ +#endif /* WOLFSSL_NO_ML_KEM */ #ifdef WOLFSSL_KYBER_ORIGINAL -#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) #ifndef WOLFSSL_NO_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 #ifndef WOLFSSL_NO_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 #ifndef WOLFSSL_NO_KYBER1024 case WOLFSSL_KYBER_LEVEL5: @@ -15448,8 +15488,33 @@ const char* wolfSSL_get_curve_name(WOLFSSL* ssl) case WOLFSSL_P521_KYBER_LEVEL5: return "P521_KYBER_LEVEL5"; #endif -#endif -#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"; + #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 /* WOLFSSL_WC_KYBER */ +#endif /* WOLFSSL_KYBER_ORIGINAL */ } } #endif /* WOLFSSL_TLS13 && WOLFSSL_HAVE_KYBER */ @@ -22934,8 +22999,18 @@ const WOLF_EC_NIST_NAME kNistCurves[] = { WOLFSSL_P256_ML_KEM_512}, {CURVE_NAME("P384_ML_KEM_768"), WOLFSSL_P384_ML_KEM_768, WOLFSSL_P384_ML_KEM_768}, + {CURVE_NAME("P256_ML_KEM_768"), WOLFSSL_P256_ML_KEM_768, + WOLFSSL_P256_ML_KEM_768}, {CURVE_NAME("P521_ML_KEM_1024"), WOLFSSL_P521_ML_KEM_1024, WOLFSSL_P521_ML_KEM_1024}, + {CURVE_NAME("P384_ML_KEM_1024"), WOLFSSL_P384_ML_KEM_1024, + WOLFSSL_P384_ML_KEM_1024}, + {CURVE_NAME("X25519_ML_KEM_512"), WOLFSSL_X25519_ML_KEM_512, + WOLFSSL_X25519_ML_KEM_512}, + {CURVE_NAME("X448_ML_KEM_768"), WOLFSSL_X448_ML_KEM_768, + WOLFSSL_X448_ML_KEM_768}, + {CURVE_NAME("X25519_ML_KEM_768"), WOLFSSL_X25519_ML_KEM_768, + WOLFSSL_X25519_ML_KEM_768}, #endif #endif /* !WOLFSSL_NO_ML_KEM */ #ifdef WOLFSSL_KYBER_ORIGINAL @@ -22943,9 +23018,20 @@ const WOLF_EC_NIST_NAME kNistCurves[] = { {CURVE_NAME("KYBER_LEVEL3"), WOLFSSL_KYBER_LEVEL3, WOLFSSL_KYBER_LEVEL3}, {CURVE_NAME("KYBER_LEVEL5"), WOLFSSL_KYBER_LEVEL5, WOLFSSL_KYBER_LEVEL5}, #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_P384_KYBER_LEVEL3}, - {CURVE_NAME("P521_KYBER_LEVEL5"), WOLFSSL_P521_KYBER_LEVEL5, WOLFSSL_P521_KYBER_LEVEL5}, + {CURVE_NAME("P256_KYBER_LEVEL1"), WOLFSSL_P256_KYBER_LEVEL1, + WOLFSSL_P256_KYBER_LEVEL1}, + {CURVE_NAME("P384_KYBER_LEVEL3"), WOLFSSL_P384_KYBER_LEVEL3, + WOLFSSL_P384_KYBER_LEVEL3}, + {CURVE_NAME("P256_KYBER_LEVEL3"), WOLFSSL_P256_KYBER_LEVEL3, + WOLFSSL_P256_KYBER_LEVEL3}, + {CURVE_NAME("P521_KYBER_LEVEL5"), WOLFSSL_P521_KYBER_LEVEL5, + WOLFSSL_P521_KYBER_LEVEL5}, + {CURVE_NAME("X25519_KYBER_LEVEL1"), WOLFSSL_X25519_KYBER_LEVEL1, + WOLFSSL_X25519_KYBER_LEVEL1}, + {CURVE_NAME("X448_KYBER_LEVEL3"), WOLFSSL_X448_KYBER_LEVEL3, + WOLFSSL_X448_KYBER_LEVEL3}, + {CURVE_NAME("X25519_KYBER_LEVEL3"), WOLFSSL_X25519_KYBER_LEVEL3, + WOLFSSL_X25519_KYBER_LEVEL3}, #endif #endif /* WOLFSSL_KYBER_ORIGINAL */ #endif /* WOLFSSL_HAVE_KYBER */ diff --git a/src/tls.c b/src/tls.c index b38d49f53..617f8de7e 100644 --- a/src/tls.c +++ b/src/tls.c @@ -4920,7 +4920,7 @@ static int tlsx_ffdhe_find_group(WOLFSSL* ssl, SupportedCurve* clientGroup, const DhParams* params = NULL; for (; serverGroup != NULL; serverGroup = serverGroup->next) { - if (!WOLFSSL_NAMED_GROUP_IS_FFHDE(serverGroup->name)) + if (!WOLFSSL_NAMED_GROUP_IS_FFDHE(serverGroup->name)) continue; for (group = clientGroup; group != NULL; group = group->next) { @@ -4997,7 +4997,7 @@ static int tlsx_ffdhe_find_group(WOLFSSL* ssl, SupportedCurve* clientGroup, word32 p_len; for (; serverGroup != NULL; serverGroup = serverGroup->next) { - if (!WOLFSSL_NAMED_GROUP_IS_FFHDE(serverGroup->name)) + if (!WOLFSSL_NAMED_GROUP_IS_FFDHE(serverGroup->name)) continue; for (group = clientGroup; group != NULL; group = group->next) { @@ -5101,7 +5101,7 @@ int TLSX_SupportedFFDHE_Set(WOLFSSL* ssl) return 0; clientGroup = (SupportedCurve*)extension->data; for (group = clientGroup; group != NULL; group = group->next) { - if (WOLFSSL_NAMED_GROUP_IS_FFHDE(group->name)) { + if (WOLFSSL_NAMED_GROUP_IS_FFDHE(group->name)) { found = 1; break; } @@ -7786,6 +7786,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); @@ -7871,6 +7872,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); @@ -8136,62 +8138,6 @@ static int kyber_id2type(int id, int *type) return ret; } -typedef struct PqcHybridMapping { - int hybrid; - int ecc; - int pqc; -} PqcHybridMapping; - -static const PqcHybridMapping pqc_hybrid_mapping[] = { -#ifndef WOLFSSL_NO_ML_KEM - {.hybrid = WOLFSSL_P256_ML_KEM_512, .ecc = WOLFSSL_ECC_SECP256R1, - .pqc = WOLFSSL_ML_KEM_512}, - {.hybrid = WOLFSSL_P384_ML_KEM_768, .ecc = WOLFSSL_ECC_SECP384R1, - .pqc = WOLFSSL_ML_KEM_768}, - {.hybrid = WOLFSSL_P521_ML_KEM_1024, .ecc = WOLFSSL_ECC_SECP521R1, - .pqc = WOLFSSL_ML_KEM_1024}, -#endif -#ifdef WOLFSSL_KYBER_ORIGINAL - {.hybrid = WOLFSSL_P256_KYBER_LEVEL1, .ecc = WOLFSSL_ECC_SECP256R1, - .pqc = WOLFSSL_KYBER_LEVEL1}, - {.hybrid = WOLFSSL_P384_KYBER_LEVEL3, .ecc = WOLFSSL_ECC_SECP384R1, - .pqc = WOLFSSL_KYBER_LEVEL3}, - {.hybrid = WOLFSSL_P521_KYBER_LEVEL5, .ecc = WOLFSSL_ECC_SECP521R1, - .pqc = WOLFSSL_KYBER_LEVEL5}, -#endif - {.hybrid = 0, .ecc = 0, .pqc = 0} -}; - -/* This will map an ecc-pqs hybrid group into its ecc group and pqc kem group. - * If it cannot find a mapping then *pqc is set to group. ecc is optional. */ -static void findEccPqc(int *ecc, int *pqc, int group) -{ - int i; - if (pqc == NULL) { - return; - } - - *pqc = 0; - if (ecc != NULL) { - *ecc = 0; - } - - for (i = 0; pqc_hybrid_mapping[i].hybrid != 0; i++) { - if (pqc_hybrid_mapping[i].hybrid == group) { - *pqc = pqc_hybrid_mapping[i].pqc; - if (ecc != NULL) { - *ecc = pqc_hybrid_mapping[i].ecc; - } - break; - } - } - - if (*pqc == 0) { - /* It is not a hybrid, so maybe its simple. */ - *pqc = group; - } -} - #if defined(WOLFSSL_MLKEM_CACHE_A) && \ !defined(WOLFSSL_TLSX_PQC_MLKEM_STORE_PRIV_KEY) /* Store KyberKey object rather than private key bytes in key share entry. @@ -8205,14 +8151,14 @@ static void findEccPqc(int *ecc, int *pqc, int group) #endif #ifndef WOLFSSL_KYBER_NO_MAKE_KEY -/* Create a key share entry using liboqs parameters group. +/* Create a key share entry using pqc parameters group on the client side. * Generates a key pair. * * ssl The SSL/TLS object. * kse The key share entry object. * returns 0 on success, otherwise failure. */ -static int TLSX_KeyShare_GenPqcKey(WOLFSSL *ssl, KeyShareEntry* kse) +static int TLSX_KeyShare_GenPqcKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) { int ret = 0; int type = 0; @@ -8221,13 +8167,8 @@ static int TLSX_KeyShare_GenPqcKey(WOLFSSL *ssl, KeyShareEntry* kse) byte* privKey = NULL; word32 privSz = 0; #else - KyberKey* kem; + KyberKey* kem = NULL; #endif - byte* pubKey = NULL; - KeyShareEntry *ecc_kse = NULL; - int oqs_group = 0; - int ecc_group = 0; - word32 pubSz = 0; /* This gets called twice. Once during parsing of the key share and once * during the population of the extension. No need to do work the second @@ -8236,8 +8177,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); + /* Get the type of key we need from the key share group. */ + ret = kyber_id2type(kse->group, &type); if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { WOLFSSL_MSG("Invalid Kyber algorithm specified."); ret = BAD_FUNC_ARG; @@ -8255,7 +8196,7 @@ static int TLSX_KeyShare_GenPqcKey(WOLFSSL *ssl, KeyShareEntry* kse) ret = wc_KyberKey_PrivateKeySize(kem, &privSz); } if (ret == 0) { - ret = wc_KyberKey_PublicKeySize(kem, &pubSz); + ret = wc_KyberKey_PublicKeySize(kem, &kse->pubKeyLen); } if (ret == 0) { @@ -8267,6 +8208,7 @@ static int TLSX_KeyShare_GenPqcKey(WOLFSSL *ssl, KeyShareEntry* kse) } #else if (ret == 0) { + /* Allocate a Kyber key to hold private key. */ kem = (KyberKey*)XMALLOC(sizeof(KyberKey), ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); if (kem == NULL) { @@ -8281,33 +8223,14 @@ static int TLSX_KeyShare_GenPqcKey(WOLFSSL *ssl, KeyShareEntry* kse) } } if (ret == 0) { - ret = wc_KyberKey_PublicKeySize(kem, &pubSz); + ret = wc_KyberKey_PublicKeySize(kem, &kse->pubKeyLen); } #endif if (ret == 0) { - 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)); - } - - 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. */ - } - - if (ret == 0) { - pubKey = (byte*)XMALLOC(ecc_kse->pubKeyLen + pubSz, ssl->heap, - DYNAMIC_TYPE_PUBLIC_KEY); - if (pubKey == NULL) { + kse->pubKey = (byte*)XMALLOC(kse->pubKeyLen, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (kse->pubKey == NULL) { WOLFSSL_MSG("pubkey memory allocation failure"); ret = MEMORY_ERROR; } @@ -8320,36 +8243,245 @@ static int TLSX_KeyShare_GenPqcKey(WOLFSSL *ssl, KeyShareEntry* kse) } } if (ret == 0) { - ret = wc_KyberKey_EncodePublicKey(kem, pubKey + ecc_kse->pubKeyLen, - pubSz); + ret = wc_KyberKey_EncodePublicKey(kem, kse->pubKey, + kse->pubKeyLen); } + #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ if (ret == 0) { ret = wc_KyberKey_EncodePrivateKey(kem, privKey, privSz); } #endif - if (ret == 0) { - if (ecc_kse->pubKeyLen > 0) - XMEMCPY(pubKey, ecc_kse->pubKey, ecc_kse->pubKeyLen); - kse->pubKey = pubKey; - kse->pubKeyLen = ecc_kse->pubKeyLen + pubSz; - pubKey = NULL; - /* Note we are saving the OQS 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. */ -#ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ - kse->privKey = privKey; - privKey = NULL; - kse->privKeyLen = privSz; -#else - kse->privKey = (byte*)kem; - kem = NULL; - kse->privKeyLen = sizeof(KyberKey); +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Public Kyber Key"); + WOLFSSL_BUFFER(kse->pubKey, kse->pubKeyLen ); #endif + if (ret != 0) { + /* Data owned by key share entry otherwise. */ + wc_KyberKey_Free(kem); + XFREE(kse->pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + kse->pubKey = NULL; + #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ + XFREE(privKey, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + #else + XFREE(kem, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + kse->key = NULL; + #endif + } + else { + #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ + wc_KyberKey_Free(kem); + kse->privKey = (byte*)privKey; + kse->privKeyLen = privSz; + #else + kse->key = kem; + #endif + } + + return ret; +} + +/* Structures and objects needed for hybrid key exchanges using both classic + * ECDHE and PQC KEM key material. */ +typedef struct PqcHybridMapping { + int hybrid; + int ecc; + int pqc; + int pqc_first; +} PqcHybridMapping; + +static const PqcHybridMapping pqc_hybrid_mapping[] = { +#ifndef WOLFSSL_NO_ML_KEM + {.hybrid = WOLFSSL_P256_ML_KEM_512, .ecc = WOLFSSL_ECC_SECP256R1, + .pqc = WOLFSSL_ML_KEM_512, .pqc_first = 0}, + {.hybrid = WOLFSSL_P384_ML_KEM_768, .ecc = WOLFSSL_ECC_SECP384R1, + .pqc = WOLFSSL_ML_KEM_768, .pqc_first = 0}, + {.hybrid = WOLFSSL_P256_ML_KEM_768, .ecc = WOLFSSL_ECC_SECP256R1, + .pqc = WOLFSSL_ML_KEM_768, .pqc_first = 0}, + {.hybrid = WOLFSSL_P521_ML_KEM_1024, .ecc = WOLFSSL_ECC_SECP521R1, + .pqc = WOLFSSL_ML_KEM_1024, .pqc_first = 0}, + {.hybrid = WOLFSSL_P384_ML_KEM_1024, .ecc = WOLFSSL_ECC_SECP384R1, + .pqc = WOLFSSL_ML_KEM_1024, .pqc_first = 0}, +#ifdef HAVE_CURVE25519 + {.hybrid = WOLFSSL_X25519_ML_KEM_512, .ecc = WOLFSSL_ECC_X25519, + .pqc = WOLFSSL_ML_KEM_512, .pqc_first = 1}, + {.hybrid = WOLFSSL_X25519_ML_KEM_768, .ecc = WOLFSSL_ECC_X25519, + .pqc = WOLFSSL_ML_KEM_768, .pqc_first = 1}, +#endif +#ifdef HAVE_CURVE448 + {.hybrid = WOLFSSL_X448_ML_KEM_768, .ecc = WOLFSSL_ECC_X448, + .pqc = WOLFSSL_ML_KEM_768, .pqc_first = 1}, +#endif +#endif /* WOLFSSL_NO_ML_KEM */ +#ifdef WOLFSSL_KYBER_ORIGINAL + {.hybrid = WOLFSSL_P256_KYBER_LEVEL1, .ecc = WOLFSSL_ECC_SECP256R1, + .pqc = WOLFSSL_KYBER_LEVEL1, .pqc_first = 0}, + {.hybrid = WOLFSSL_P384_KYBER_LEVEL3, .ecc = WOLFSSL_ECC_SECP384R1, + .pqc = WOLFSSL_KYBER_LEVEL3, .pqc_first = 0}, + {.hybrid = WOLFSSL_P256_KYBER_LEVEL3, .ecc = WOLFSSL_ECC_SECP256R1, + .pqc = WOLFSSL_KYBER_LEVEL3, .pqc_first = 0}, + {.hybrid = WOLFSSL_P521_KYBER_LEVEL5, .ecc = WOLFSSL_ECC_SECP521R1, + .pqc = WOLFSSL_KYBER_LEVEL5, .pqc_first = 0}, +#ifdef HAVE_CURVE25519 + {.hybrid = WOLFSSL_X25519_KYBER_LEVEL1, .ecc = WOLFSSL_ECC_X25519, + .pqc = WOLFSSL_KYBER_LEVEL1, .pqc_first = 0}, + {.hybrid = WOLFSSL_X25519_KYBER_LEVEL3, .ecc = WOLFSSL_ECC_X25519, + .pqc = WOLFSSL_KYBER_LEVEL3, .pqc_first = 0}, +#endif +#ifdef HAVE_CURVE448 + {.hybrid = WOLFSSL_X448_KYBER_LEVEL3, .ecc = WOLFSSL_ECC_X448, + .pqc = WOLFSSL_KYBER_LEVEL3, .pqc_first = 0}, +#endif +#endif /* WOLFSSL_KYBER_ORIGINAL */ + {.hybrid = 0, .ecc = 0, .pqc = 0, .pqc_first = 0} +}; + +/* Map an ecc-pqc hybrid group into its ecc group and pqc kem group. */ +static void findEccPqc(int *ecc, int *pqc, int *pqc_first, int group) +{ + int i; + + if (pqc != NULL) + *pqc = 0; + if (ecc != NULL) + *ecc = 0; + if (pqc_first != NULL) + *pqc_first = 0; + + for (i = 0; pqc_hybrid_mapping[i].hybrid != 0; i++) { + if (pqc_hybrid_mapping[i].hybrid == group) { + if (pqc != NULL) + *pqc = pqc_hybrid_mapping[i].pqc; + if (ecc != NULL) + *ecc = pqc_hybrid_mapping[i].ecc; + if (pqc_first != NULL) + *pqc_first = pqc_hybrid_mapping[i].pqc_first; + break; + } + } +} + +/* Create a key share entry using both ecdhe and pqc parameters groups. + * Generates two key pairs on the client side. + * + * ssl The SSL/TLS object. + * kse The key share entry object. + * returns 0 on success, otherwise failure. + */ +static int TLSX_KeyShare_GenPqcHybridKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) +{ + int ret = 0; + KeyShareEntry *ecc_kse = NULL; + KeyShareEntry *pqc_kse = NULL; + int pqc_group = 0; + int ecc_group = 0; + int pqc_first = 0; + + /* This gets called twice. Once during parsing of the key share and once + * during the population of the extension. No need to do work the second + * time. Just return success if its already been done. */ + if (kse->pubKey != NULL) { + return ret; + } + + /* Determine the ECC and PQC group of the hybrid combination */ + findEccPqc(&ecc_group, &pqc_group, &pqc_first, kse->group); + if (ecc_group == 0 || pqc_group == 0) { + WOLFSSL_MSG("Invalid hybrid group"); + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + ecc_kse = (KeyShareEntry*)XMALLOC(sizeof(*ecc_kse), ssl->heap, + DYNAMIC_TYPE_TLSX); + pqc_kse = (KeyShareEntry*)XMALLOC(sizeof(*pqc_kse), ssl->heap, + DYNAMIC_TYPE_TLSX); + if (ecc_kse == NULL || pqc_kse == NULL) { + WOLFSSL_MSG("kse memory allocation failure"); + ret = MEMORY_ERROR; + } + } + + if (ret == 0) { + XMEMSET(ecc_kse, 0, sizeof(*ecc_kse)); + XMEMSET(pqc_kse, 0, sizeof(*pqc_kse)); + } + + /* Generate ECC key share part */ + if (ret == 0) { + ecc_kse->group = ecc_group; + #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_Gen*Key will do it. */ + } + + /* Generate PQC key share part */ + if (ret == 0) { + pqc_kse->group = pqc_group; + ret = TLSX_KeyShare_GenPqcKeyClient(ssl, pqc_kse); + /* No error message, TLSX_KeyShare_GenPqcKeyClient will do it. */ + } + + /* Allocate memory for combined public key */ + if (ret == 0) { + kse->pubKey = (byte*)XMALLOC(ecc_kse->pubKeyLen + pqc_kse->pubKeyLen, + ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (kse->pubKey == NULL) { + WOLFSSL_MSG("pubkey memory allocation failure"); + ret = MEMORY_ERROR; + } + } + + /* Create combined public key. The order of classic/pqc key material is + * indicated by the pqc_first variable. */ + if (ret == 0) { + if (pqc_first) { + XMEMCPY(kse->pubKey, pqc_kse->pubKey, pqc_kse->pubKeyLen); + XMEMCPY(kse->pubKey + pqc_kse->pubKeyLen, ecc_kse->pubKey, + ecc_kse->pubKeyLen); + } + else { + XMEMCPY(kse->pubKey, ecc_kse->pubKey, ecc_kse->pubKeyLen); + XMEMCPY(kse->pubKey + ecc_kse->pubKeyLen, pqc_kse->pubKey, + pqc_kse->pubKeyLen); + } + kse->pubKeyLen = ecc_kse->pubKeyLen + pqc_kse->pubKeyLen; + } + + /* Store the private keys. + * 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. */ + if (ret == 0) { + #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ + /* PQC private key is an encoded byte array */ + kse->privKey = pqc_kse->privKey; + kse->privKeyLen = pqc_kse->privKeyLen; + pqc_kse->privKey = NULL; + #else + /* PQC private key is a pointer to KyberKey object */ + kse->privKey = (byte*)pqc_kse->key; + kse->privKeyLen = 0; + pqc_kse->key = NULL; + #endif + /* ECC private key is a pointer to ecc_key object */ kse->key = ecc_kse->key; + kse->keyLen = ecc_kse->keyLen; ecc_kse->key = NULL; } @@ -8358,18 +8490,12 @@ static int TLSX_KeyShare_GenPqcKey(WOLFSSL *ssl, KeyShareEntry* kse) WOLFSSL_BUFFER(kse->pubKey, kse->pubKeyLen ); #endif - wc_KyberKey_Free(kem); TLSX_KeyShare_FreeAll(ecc_kse, ssl->heap); - XFREE(pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); -#ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ - XFREE(privKey, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); -#else - XFREE(kem, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); -#endif + TLSX_KeyShare_FreeAll(pqc_kse, ssl->heap); return ret; } -#endif +#endif /* !WOLFSSL_KYBER_NO_MAKE_KEY */ #endif /* WOLFSSL_HAVE_KYBER */ /* Generate a secret/key using the key share entry. @@ -8381,7 +8507,7 @@ int TLSX_KeyShare_GenKey(WOLFSSL *ssl, KeyShareEntry *kse) { int ret; /* Named FFDHE groups have a bit set to identify them. */ - if (WOLFSSL_NAMED_GROUP_IS_FFHDE(kse->group)) + if (WOLFSSL_NAMED_GROUP_IS_FFDHE(kse->group)) ret = TLSX_KeyShare_GenDhKey(ssl, kse); else if (kse->group == WOLFSSL_ECC_X25519) ret = TLSX_KeyShare_GenX25519Key(ssl, kse); @@ -8389,7 +8515,9 @@ int TLSX_KeyShare_GenKey(WOLFSSL *ssl, KeyShareEntry *kse) ret = TLSX_KeyShare_GenX448Key(ssl, kse); #if defined(WOLFSSL_HAVE_KYBER) && !defined(WOLFSSL_KYBER_NO_MAKE_KEY) else if (WOLFSSL_NAMED_GROUP_IS_PQC(kse->group)) - ret = TLSX_KeyShare_GenPqcKey(ssl, kse); + ret = TLSX_KeyShare_GenPqcKeyClient(ssl, kse); + else if (WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(kse->group)) + ret = TLSX_KeyShare_GenPqcHybridKeyClient(ssl, kse); #endif else ret = TLSX_KeyShare_GenEccKey(ssl, kse); @@ -8410,7 +8538,7 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap) while ((current = list) != NULL) { list = current->next; - if (WOLFSSL_NAMED_GROUP_IS_FFHDE(current->group)) { + if (WOLFSSL_NAMED_GROUP_IS_FFDHE(current->group)) { #ifndef NO_DH wc_FreeDhKey((DhKey*)current->key); #endif @@ -8427,18 +8555,42 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap) } #ifdef WOLFSSL_HAVE_KYBER else if (WOLFSSL_NAMED_GROUP_IS_PQC(current->group)) { - if (current->key != NULL) { - ForceZero((byte*)current->key, current->keyLen); - } - XFREE(current->pubKey, heap, DYNAMIC_TYPE_PUBLIC_KEY); - current->pubKey = NULL; + #ifdef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ + wc_KyberKey_Free((KyberKey*)current->key); + #else if (current->privKey != NULL) { ForceZero(current->privKey, current->privKeyLen); - #ifdef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ - wc_KyberKey_Free((KyberKey*)current->privKey); + } + #endif + } + else if (WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(current->group)) { + int ecc_group = 0; + findEccPqc(&ecc_group, NULL, NULL, current->group); + + /* Free PQC private key */ + #ifdef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ + wc_KyberKey_Free((KyberKey*)current->privKey); + #else + if (current->privKey != NULL) { + ForceZero(current->privKey, current->privKeyLen); + } + #endif + + /* Free ECC private key */ + if (ecc_group == WOLFSSL_ECC_X25519) { + #ifdef HAVE_CURVE25519 + wc_curve25519_free((curve25519_key*)current->key); + #endif + } + else if (ecc_group == WOLFSSL_ECC_X448) { + #ifdef HAVE_CURVE448 + wc_curve448_free((curve448_key*)current->key); + #endif + } + else { + #ifdef HAVE_ECC + wc_ecc_free((ecc_key*)current->key); #endif - XFREE(current->privKey, heap, DYNAMIC_TYPE_PRIVATE_KEY); - current->privKey = NULL; } } #endif @@ -8448,7 +8600,7 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap) #endif } XFREE(current->key, heap, DYNAMIC_TYPE_PRIVATE_KEY); - #if !defined(NO_DH) && (!defined(NO_CERTS) || !defined(NO_PSK)) + #if !defined(NO_DH) || defined(WOLFSSL_HAVE_KYBER) XFREE(current->privKey, heap, DYNAMIC_TYPE_PRIVATE_KEY); #endif XFREE(current->pubKey, heap, DYNAMIC_TYPE_PUBLIC_KEY); @@ -8674,10 +8826,15 @@ static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) * * ssl The SSL/TLS object. * keyShareEntry The key share entry object to use to calculate shared secret. + * ssOutput The destination buffer for the shared secret. + * ssOutSz The size of the generated shared secret. + * * returns 0 on success and other values indicate failure. */ -static int TLSX_KeyShare_ProcessX25519(WOLFSSL* ssl, - KeyShareEntry* keyShareEntry) +static int TLSX_KeyShare_ProcessX25519_ex(WOLFSSL* ssl, + KeyShareEntry* keyShareEntry, + unsigned char* ssOutput, + word32* ssOutSz) { int ret; @@ -8732,9 +8889,7 @@ static int TLSX_KeyShare_ProcessX25519(WOLFSSL* ssl, if (ret == 0) { #endif ret = wc_curve25519_shared_secret_ex(key, peerX25519Key, - ssl->arrays->preMasterSecret, - &ssl->arrays->preMasterSz, - EC25519_LITTLE_ENDIAN); + ssOutput, ssOutSz, EC25519_LITTLE_ENDIAN); } wc_curve25519_free(peerX25519Key); @@ -8742,9 +8897,13 @@ 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; + (void)ssOutput; + (void)ssOutSz; ret = PEER_KEY_ERROR; WOLFSSL_ERROR_VERBOSE(ret); @@ -8753,13 +8912,33 @@ static int TLSX_KeyShare_ProcessX25519(WOLFSSL* ssl, return ret; } +/* Process the X25519 key share extension on the client side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to use to calculate shared secret. + * + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_ProcessX25519(WOLFSSL* ssl, + KeyShareEntry* keyShareEntry) +{ + return TLSX_KeyShare_ProcessX25519_ex(ssl, keyShareEntry, + ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz); +} + /* Process the X448 key share extension on the client side. * * ssl The SSL/TLS object. * keyShareEntry The key share entry object to use to calculate shared secret. + * ssOutput The destination buffer for the shared secret. + * ssOutSz The size of the generated shared secret. + * * returns 0 on success and other values indicate failure. */ -static int TLSX_KeyShare_ProcessX448(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) +static int TLSX_KeyShare_ProcessX448_ex(WOLFSSL* ssl, + KeyShareEntry* keyShareEntry, + unsigned char* ssOutput, + word32* ssOutSz) { int ret; @@ -8810,9 +8989,7 @@ static int TLSX_KeyShare_ProcessX448(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) ssl->ecdhCurveOID = ECC_X448_OID; ret = wc_curve448_shared_secret_ex(key, peerX448Key, - ssl->arrays->preMasterSecret, - &ssl->arrays->preMasterSz, - EC448_LITTLE_ENDIAN); + ssOutput, ssOutSz, EC448_LITTLE_ENDIAN); } wc_curve448_free(peerX448Key); @@ -8820,9 +8997,13 @@ 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; + (void)ssOutput; + (void)ssOutSz; ret = PEER_KEY_ERROR; WOLFSSL_ERROR_VERBOSE(ret); @@ -8831,13 +9012,31 @@ static int TLSX_KeyShare_ProcessX448(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) return ret; } -/* Process the ECC key share extension on the client side. +/* Process the X448 key share extension on the client side. * * ssl The SSL/TLS object. * keyShareEntry The key share entry object to use to calculate shared secret. * returns 0 on success and other values indicate failure. */ -static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) +static int TLSX_KeyShare_ProcessX448(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) +{ + return TLSX_KeyShare_ProcessX448_ex(ssl, keyShareEntry, + ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz); +} + +/* Process the ECC key share extension on the client side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to use to calculate shared secret. + * ssOutput The destination buffer for the shared secret. + * ssOutSz The size of the generated shared secret. + * + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_ProcessEcc_ex(WOLFSSL* ssl, + KeyShareEntry* keyShareEntry, + unsigned char* ssOutput, + word32* ssOutSz) { int ret = 0; #ifdef HAVE_ECC @@ -8937,9 +9136,7 @@ static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) if (ret == 0) { ret = EccSharedSecret(ssl, eccKey, ssl->peerEccKey, keyShareEntry->ke, &keyShareEntry->keLen, - ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz, - ssl->options.side - ); + ssOutput, ssOutSz, ssl->options.side); #ifdef WOLFSSL_ASYNC_CRYPT if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) return ret; @@ -8967,6 +9164,8 @@ static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) #else (void)ssl; (void)keyShareEntry; + (void)ssOutput; + (void)ssOutSz; ret = PEER_KEY_ERROR; WOLFSSL_ERROR_VERBOSE(ret); @@ -8975,185 +9174,359 @@ static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) return ret; } -#if defined(WOLFSSL_HAVE_KYBER) && !defined(WOLFSSL_KYBER_NO_DECAPSULATE) -/* Process the Kyber key share extension on the client side. +/* Process the ECC key share extension on the client side. * * ssl The SSL/TLS object. * keyShareEntry The key share entry object to use to calculate shared secret. * returns 0 on success and other values indicate failure. */ -static int TLSX_KeyShare_ProcessPqc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) +static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) { - int ret = 0; - int type; -#ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ - KyberKey kem[1]; - word32 privSz = 0; -#else - KyberKey* kem; -#endif - byte* sharedSecret = NULL; - word32 sharedSecretLen = 0; - int oqs_group = 0; - int ecc_group = 0; - ecc_key eccpubkey; - word32 outlen = 0; - word32 ctSz = 0; - word32 ssSz = 0; + return TLSX_KeyShare_ProcessEcc_ex(ssl, keyShareEntry, + ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz); +} - if (keyShareEntry->ke == NULL) { - WOLFSSL_MSG("Invalid OQS algorithm specified."); - return BAD_FUNC_ARG; - } +#if defined(WOLFSSL_HAVE_KYBER) && !defined(WOLFSSL_KYBER_NO_DECAPSULATE) +/* Process the Kyber key share extension on the client side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to use to calculate shared secret. + * ssOutput The destination buffer for the shared secret. + * ssOutSz The size of the generated shared secret. + * + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_ProcessPqcClient_ex(WOLFSSL* ssl, + KeyShareEntry* keyShareEntry, + unsigned char* ssOutput, + word32* ssOutSz) +{ + int ret = 0; + KyberKey* kem = (KyberKey*)keyShareEntry->key; +#ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ + word32 privSz = 0; +#endif + word32 ctSz = 0; + word32 ssSz = 0; 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; - } - - ret = kyber_id2type(oqs_group, &type); - if (ret != 0) { - wc_ecc_free(&eccpubkey); - WOLFSSL_MSG("Invalid OQS algorithm specified."); + if (keyShareEntry->ke == NULL) { + WOLFSSL_MSG("Invalid PQC algorithm specified."); return BAD_FUNC_ARG; } + if (ssOutSz == NULL) + return BAD_FUNC_ARG; #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ - 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 (kem == NULL) { + int type = 0; + + /* Allocate a Kyber key to hold private key. */ + kem = (KyberKey*) XMALLOC(sizeof(KyberKey), ssl->heap, + DYNAMIC_TYPE_PRIVATE_KEY); + if (kem == NULL) { + WOLFSSL_MSG("GenPqcKey memory error"); + ret = MEMORY_E; + } + if (ret == 0) { + ret = kyber_id2type(keyShareEntry->group, &type); + } + if (ret != 0) { + WOLFSSL_MSG("Invalid PQC algorithm specified."); + ret = BAD_FUNC_ARG; + } + if (ret == 0) { + ret = wc_KyberKey_Init(type, kem, ssl->heap, ssl->devId); + if (ret != 0) { + WOLFSSL_MSG("Error creating Kyber KEM"); + } + } } #else - kem = (KyberKey*)keyShareEntry->privKey; - keyShareEntry->privKey = NULL; + if (kem == NULL || keyShareEntry->privKeyLen != 0) { + WOLFSSL_MSG("Invalid Kyber key."); + ret = BAD_FUNC_ARG; + } #endif if (ret == 0) { 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; - } - } - 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) { ret = wc_KyberKey_CipherTextSize(kem, &ctSz); } + #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ if (ret == 0) { ret = wc_KyberKey_PrivateKeySize(kem, &privSz); } + if (ret == 0 && privSz != keyShareEntry->privKeyLen) { + WOLFSSL_MSG("Invalid private key size."); + ret = BAD_FUNC_ARG; + } if (ret == 0) { ret = wc_KyberKey_DecodePrivateKey(kem, keyShareEntry->privKey, privSz); } #endif + if (ret == 0) { - ret = wc_KyberKey_Decapsulate(kem, sharedSecret + outlen, - keyShareEntry->ke + keyShareEntry->keLen - ctSz, ctSz); + ret = wc_KyberKey_Decapsulate(kem, ssOutput, + keyShareEntry->ke, 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) { + *ssOutSz = ssSz; } - if ((ret == 0) && (sharedSecretLen > ENCRYPT_LEN)) { - WOLFSSL_MSG("shared secret is too long."); - ret = LENGTH_ERROR; + + wc_KyberKey_Free(kem); + + XFREE(kem, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + keyShareEntry->key = NULL; + + XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + keyShareEntry->ke = NULL; + + return ret; +} + +/* Process the Kyber key share extension on the client side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to use to calculate shared secret. + * + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_ProcessPqcClient(WOLFSSL* ssl, + KeyShareEntry* keyShareEntry) +{ + return TLSX_KeyShare_ProcessPqcClient_ex(ssl, keyShareEntry, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz); +} + +/* Process the hybrid key share extension on the client side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to use to calculate shared secret. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_ProcessPqcHybridClient(WOLFSSL* ssl, + KeyShareEntry* keyShareEntry) +{ + int ret = 0; + int pqc_group = 0; + int ecc_group = 0; + int pqc_first = 0; + KeyShareEntry* pqc_kse = NULL; + KeyShareEntry *ecc_kse = NULL; + word32 ctSz = 0; + word32 ssSzPqc = 0; + word32 ssSzEcc = 0; + + if (ssl->options.side == WOLFSSL_SERVER_END) { + /* I am the server, the shared secret has already been generated and + * is in ssl->arrays->preMasterSecret, so nothing really to do here. */ + return 0; + } + + if (keyShareEntry->ke == NULL) { + WOLFSSL_MSG("Invalid PQC algorithm specified."); + return BAD_FUNC_ARG; + } + + /* I am the client, both the PQC ciphertext and the ECHD public key are in + * keyShareEntry->ke */ + + /* Determine the ECC and PQC group of the hybrid combination */ + findEccPqc(&ecc_group, &pqc_group, &pqc_first, keyShareEntry->group); + if (ecc_group == 0 || pqc_group == 0) { + WOLFSSL_MSG("Invalid hybrid group"); + ret = BAD_FUNC_ARG; } 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; + ecc_kse = (KeyShareEntry*)XMALLOC(sizeof(*ecc_kse), ssl->heap, + DYNAMIC_TYPE_TLSX); + pqc_kse = (KeyShareEntry*)XMALLOC(sizeof(*pqc_kse), ssl->heap, + DYNAMIC_TYPE_TLSX); + if (ecc_kse == NULL || pqc_kse == NULL) { + WOLFSSL_MSG("kse memory allocation failure"); + ret = MEMORY_ERROR; + } } - XFREE(sharedSecret, ssl->heap, DYNAMIC_TYPE_SECRET); + /* The ciphertext and shared secret sizes of a KEM are fixed. Hence, we + * decode these sizes to separate the KEM ciphertext from the ECDH public + * key. */ + if (ret == 0) { + #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ + int type; + KyberKey* kem; + #endif + + XMEMSET(pqc_kse, 0, sizeof(*pqc_kse)); + pqc_kse->group = pqc_group; + pqc_kse->privKeyLen = keyShareEntry->privKeyLen; + #ifdef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ + pqc_kse->key = keyShareEntry->privKey; + #else + pqc_kse->privKey = keyShareEntry->privKey; + + /* Allocate a Kyber key to hold private key. */ + kem = (KyberKey*) XMALLOC(sizeof(KyberKey), ssl->heap, + DYNAMIC_TYPE_PRIVATE_KEY); + if (kem == NULL) { + WOLFSSL_MSG("GenPqcKey memory error"); + ret = MEMORY_E; + } + if (ret == 0) { + ret = kyber_id2type(pqc_group, &type); + } + if (ret != 0) { + WOLFSSL_MSG("Invalid Kyber algorithm specified."); + ret = BAD_FUNC_ARG; + } + if (ret == 0) { + ret = wc_KyberKey_Init(type, kem, ssl->heap, ssl->devId); + if (ret != 0) { + WOLFSSL_MSG("Error creating Kyber KEM"); + } + } + if (ret == 0) { + pqc_kse->key = kem; + } + #endif + + if (ret == 0) { + ret = wc_KyberKey_SharedSecretSize((KyberKey*)pqc_kse->key, + &ssSzPqc); + } + if (ret == 0) { + ret = wc_KyberKey_CipherTextSize((KyberKey*)pqc_kse->key, + &ctSz); + if (ret == 0 && keyShareEntry->keLen <= ctSz) { + WOLFSSL_MSG("Invalid ciphertext size."); + ret = BAD_FUNC_ARG; + } + } + if (ret == 0) { + pqc_kse->keLen = ctSz; + pqc_kse->ke = (byte*)XMALLOC(pqc_kse->keLen, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (pqc_kse->ke == NULL) { + WOLFSSL_MSG("pqc_kse memory allocation failure"); + ret = MEMORY_ERROR; + } + /* Copy the PQC KEM ciphertext. Depending on the pqc_first flag, + * the KEM ciphertext comes before or after the ECDH public key. */ + if (ret == 0) { + int offset = keyShareEntry->keLen - ctSz; + + if (pqc_first) + offset = 0; + + XMEMCPY(pqc_kse->ke, keyShareEntry->ke + offset, ctSz); + } + } + } + + 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; + } + /* Copy the ECDH public key. Depending on the pqc_first flag, the + * KEM ciphertext comes before or after the ECDH public key. */ + if (ret == 0) { + int offset = 0; + + if (pqc_first) + offset = ctSz; + + XMEMCPY(ecc_kse->ke, keyShareEntry->ke + offset, ecc_kse->keLen); + } + } + + /* Process ECDH key share part. The generated shared secret is directly + * stored in the ssl->arrays->preMasterSecret buffer. Depending on the + * pqc_first flag, the ECDH shared secret part goes before or after the + * KEM part. */ + if (ret == 0) { + int offset = 0; + + /* Set the ECC size variable to the initial buffer size */ + ssSzEcc = ssl->arrays->preMasterSz; + + if (pqc_first) + offset = ssSzPqc; + + #ifdef HAVE_CURVE25519 + if (ecc_group == WOLFSSL_ECC_X25519) { + ret = TLSX_KeyShare_ProcessX25519_ex(ssl, ecc_kse, + ssl->arrays->preMasterSecret + offset, &ssSzEcc); + } + else + #endif + #ifdef HAVE_CURVE448 + if (ecc_group == WOLFSSL_ECC_X448) { + ret = TLSX_KeyShare_ProcessX448_ex(ssl, ecc_kse, + ssl->arrays->preMasterSecret + offset, &ssSzEcc); + } + else + #endif + { + ret = TLSX_KeyShare_ProcessEcc_ex(ssl, ecc_kse, + ssl->arrays->preMasterSecret + offset, &ssSzEcc); + } + } + + if (ret == 0) { + keyShareEntry->key = ecc_kse->key; + + if ((ret == 0) && ((ssSzEcc + ssSzPqc) > ENCRYPT_LEN)) { + WOLFSSL_MSG("shared secret is too long."); + ret = LENGTH_ERROR; + } + } + + /* Process PQC KEM key share part. Depending on the pqc_first flag, the + * KEM shared secret part goes before or after the ECDH part. */ + if (ret == 0) { + int offset = ssSzEcc; + + if (pqc_first) + offset = 0; + + ret = TLSX_KeyShare_ProcessPqcClient_ex(ssl, pqc_kse, + ssl->arrays->preMasterSecret + offset, &ssSzPqc); + } + + if (ret == 0) { + keyShareEntry->privKey = (byte*)pqc_kse->key; + + ssl->arrays->preMasterSz = ssSzEcc + ssSzPqc; + } + + TLSX_KeyShare_FreeAll(ecc_kse, ssl->heap); + TLSX_KeyShare_FreeAll(pqc_kse, ssl->heap); - wc_ecc_free(&eccpubkey); - wc_KyberKey_Free(kem); return ret; } -#endif /* WOLFSSL_HAVE_KYBER */ +#endif /* WOLFSSL_HAVE_KYBER && !WOLFSSL_KYBER_NO_DECAPSULATE */ /* Process the key share extension on the client side. * @@ -9173,7 +9546,7 @@ static int TLSX_KeyShare_Process(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) ssl->arrays->preMasterSz = ENCRYPT_LEN; /* Use Key Share Data from server. */ - if (WOLFSSL_NAMED_GROUP_IS_FFHDE(keyShareEntry->group)) + if (WOLFSSL_NAMED_GROUP_IS_FFDHE(keyShareEntry->group)) ret = TLSX_KeyShare_ProcessDh(ssl, keyShareEntry); else if (keyShareEntry->group == WOLFSSL_ECC_X25519) ret = TLSX_KeyShare_ProcessX25519(ssl, keyShareEntry); @@ -9181,7 +9554,9 @@ static int TLSX_KeyShare_Process(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) ret = TLSX_KeyShare_ProcessX448(ssl, keyShareEntry); #if defined(WOLFSSL_HAVE_KYBER) && !defined(WOLFSSL_KYBER_NO_DECAPSULATE) else if (WOLFSSL_NAMED_GROUP_IS_PQC(keyShareEntry->group)) - ret = TLSX_KeyShare_ProcessPqc(ssl, keyShareEntry); + ret = TLSX_KeyShare_ProcessPqcClient(ssl, keyShareEntry); + else if (WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(keyShareEntry->group)) + ret = TLSX_KeyShare_ProcessPqcHybridClient(ssl, keyShareEntry); #endif else ret = TLSX_KeyShare_ProcessEcc(ssl, keyShareEntry); @@ -9231,10 +9606,17 @@ static int TLSX_KeyShareEntry_Parse(const WOLFSSL* ssl, const byte* input, return BUFFER_ERROR; #ifdef WOLFSSL_HAVE_KYBER - if (WOLFSSL_NAMED_GROUP_IS_PQC(group) && + if ((WOLFSSL_NAMED_GROUP_IS_PQC(group) || + WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(group)) && ssl->options.side == WOLFSSL_SERVER_END) { - /* For KEMs, the public key is not stored. Casting away const because - * we know for KEMs, it will be read-only.*/ + /* When handling a key share containing a KEM public key on the server + * end, we have to perform the encapsulation immediately in order to + * send the resulting ciphertext back to the client in the ServerHello + * message. As the public key is not stored and we do not modify it, we + * don't have to create a copy of it. + * In case of a hybrid key exchange, the ECDH part is also performed + * immediately (to not split the generation of the master secret). + * Hence, we also don't have to store this public key either. */ ke = (byte *)&input[offset]; } else #endif @@ -9504,132 +9886,91 @@ static int TLSX_KeyShare_New(KeyShareEntry** list, int group, void *heap, } #if defined(WOLFSSL_HAVE_KYBER) && !defined(WOLFSSL_KYBER_NO_ENCAPSULATE) -static int server_generate_pqc_ciphertext(WOLFSSL* ssl, - KeyShareEntry* keyShareEntry, byte* data, word16 len) +/* Process the Kyber key share extension on the server side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to be sent to the client. + * data The key share data received from the client. + * len The length of the key share data from the client. + * ssOutput The destination buffer for the shared secret. + * ssOutSz The size of the generated shared secret. + * + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_HandlePqcKeyServer(WOLFSSL* ssl, + KeyShareEntry* keyShareEntry, byte* clientData, word16 clientLen, + unsigned char* ssOutput, word32* ssOutSz) { - /* I am the server. The data parameter is the client's public key. I need - * to generate the public information (AKA ciphertext) and shared secret - * here. Note the "public information" is equivalent to a the public key in - * key exchange parlance. That's why it is being assigned to pubKey. - */ - int type; - KyberKey kem[1]; - byte* sharedSecret = NULL; + /* We are on the server side. The key share contains a PQC KEM public key + * that we are using for an encapsulate operation. The resulting ciphertext + * is stored in the server key share. */ + KyberKey* kemKey = (KyberKey*)keyShareEntry->key; byte* ciphertext = NULL; int ret = 0; - int oqs_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); - if (ret != 0) { - WOLFSSL_MSG("Invalid Kyber algorithm specified."); + if (clientData == NULL) { + WOLFSSL_MSG("No KEM public key from the client."); 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; - } + if (kemKey == NULL) { + int type = 0; - 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); - if (ecc_kse == NULL) { - WOLFSSL_MSG("ecc_kse memory allocation failure"); - ret = MEMORY_ERROR; + /* Allocate a Kyber key to hold private key. */ + kemKey = (KyberKey*) XMALLOC(sizeof(KyberKey), ssl->heap, + DYNAMIC_TYPE_PRIVATE_KEY); + if (kemKey == NULL) { + WOLFSSL_MSG("GenPqcKey memory error"); + ret = MEMORY_E; + } + if (ret == 0) { + ret = kyber_id2type(keyShareEntry->group, &type); + } + if (ret != 0) { + WOLFSSL_MSG("Invalid PQC algorithm specified."); + ret = BAD_FUNC_ARG; + } + if (ret == 0) { + ret = wc_KyberKey_Init(type, kemKey, ssl->heap, ssl->devId); + if (ret != 0) { + WOLFSSL_MSG("Error creating Kyber KEM"); + } } } if (ret == 0) { - XMEMSET(ecc_kse, 0, sizeof(*ecc_kse)); - } - - 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. */ - } - - if (ret == 0) { - ret = wc_KyberKey_PublicKeySize(kem, &pubSz); + ret = wc_KyberKey_PublicKeySize(kemKey, &pubSz); } if (ret == 0) { - ret = wc_KyberKey_CipherTextSize(kem, &ctSz); + ret = wc_KyberKey_CipherTextSize(kemKey, &ctSz); } if (ret == 0) { - ret = wc_KyberKey_SharedSecretSize(kem, &ssSz); + ret = wc_KyberKey_SharedSecretSize(kemKey, &ssSz); } - if (ret == 0 && len != pubSz + ecc_kse->pubKeyLen) { + if (ret == 0 && clientLen != pubSz) { WOLFSSL_MSG("Invalid public key."); ret = BAD_FUNC_ARG; } 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); + ciphertext = (byte*)XMALLOC(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) { - /* Point is validated by import function. */ - ret = wc_ecc_import_x963(data, len - pubSz, &eccpubkey); - if (ret != 0) { - WOLFSSL_MSG("Bad ECC public key."); - } - } - -#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 - - 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; - } - } - } - if (ret == 0) { - ret = wc_KyberKey_DecodePublicKey(kem, data + ecc_kse->pubKeyLen, - pubSz); + ret = wc_KyberKey_DecodePublicKey(kemKey, clientData, pubSz); } if (ret == 0) { - ret = wc_KyberKey_Encapsulate(kem, ciphertext + ecc_kse->pubKeyLen, - sharedSecret + outlen, ssl->rng); + ret = wc_KyberKey_Encapsulate(kemKey, ciphertext, + ssOutput, ssl->rng); if (ret != 0) { WOLFSSL_MSG("wc_KyberKey encapsulation failure."); } @@ -9638,14 +9979,248 @@ 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; + *ssOutSz = ssSz; + keyShareEntry->ke = NULL; + keyShareEntry->keLen = 0; - if (ecc_kse->pubKeyLen > 0) - XMEMCPY(ciphertext, ecc_kse->pubKey, ecc_kse->pubKeyLen); keyShareEntry->pubKey = ciphertext; - keyShareEntry->pubKeyLen = (word32)(ecc_kse->pubKeyLen + ctSz); + keyShareEntry->pubKeyLen = ctSz; + ciphertext = NULL; + + /* Set namedGroup so wolfSSL_get_curve_name() can function properly on + * the server side. */ + ssl->namedGroup = keyShareEntry->group; + } + + XFREE(ciphertext, ssl->heap, DYNAMIC_TYPE_TLSX); + + wc_KyberKey_Free(kemKey); + XFREE(kemKey, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + keyShareEntry->key = NULL; + return ret; +} + +static int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl, + KeyShareEntry* keyShareEntry, byte* data, word16 len) +{ + /* I am the server. The data parameter is the concatenation of the client's + * ECDH public key and the KEM public key. I need to generate a matching + * public key for ECDH and encapsulate a shared secret using the KEM public + * key. We send the ECDH public key and the KEM ciphertext back to the + * client. Additionally, we create the ECDH shared secret here already. + */ + int type; + byte* ciphertext = NULL; + int ret = 0; + int pqc_group = 0; + int ecc_group = 0; + int pqc_first = 0; + KeyShareEntry *ecc_kse = NULL; + KeyShareEntry *pqc_kse = NULL; + word32 pubSz = 0; + word32 ctSz = 0; + word32 ssSzPqc = 0; + word32 ssSzEcc = 0; + + if (data == NULL) { + WOLFSSL_MSG("No hybrid key share data from the client."); + return BAD_FUNC_ARG; + } + + /* Determine the ECC and PQC group of the hybrid combination */ + findEccPqc(&ecc_group, &pqc_group, &pqc_first, keyShareEntry->group); + if (ecc_group == 0 || pqc_group == 0) { + WOLFSSL_MSG("Invalid hybrid group"); + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + ecc_kse = (KeyShareEntry*)XMALLOC(sizeof(*ecc_kse), ssl->heap, + DYNAMIC_TYPE_TLSX); + pqc_kse = (KeyShareEntry*)XMALLOC(sizeof(*pqc_kse), ssl->heap, + DYNAMIC_TYPE_TLSX); + if (ecc_kse == NULL || pqc_kse == NULL) { + WOLFSSL_MSG("kse memory allocation failure"); + ret = MEMORY_ERROR; + } + } + + /* The ciphertext and shared secret sizes of a KEM are fixed. Hence, we + * decode these sizes to properly concatenate the KEM ciphertext with the + * ECDH public key. */ + if (ret == 0) { + XMEMSET(pqc_kse, 0, sizeof(*pqc_kse)); + pqc_kse->group = pqc_group; + + /* Allocate a Kyber key to hold private key. */ + pqc_kse->key = (KyberKey*) XMALLOC(sizeof(KyberKey), ssl->heap, + DYNAMIC_TYPE_PRIVATE_KEY); + if (pqc_kse->key == NULL) { + WOLFSSL_MSG("GenPqcKey memory error"); + ret = MEMORY_E; + } + if (ret == 0) { + ret = kyber_id2type(pqc_kse->group, &type); + } + if (ret != 0) { + WOLFSSL_MSG("Invalid PQC algorithm specified."); + ret = BAD_FUNC_ARG; + } + if (ret == 0) { + ret = wc_KyberKey_Init(type, (KyberKey*)pqc_kse->key, + ssl->heap, ssl->devId); + if (ret != 0) { + WOLFSSL_MSG("Error creating Kyber KEM"); + } + } + if (ret == 0) { + ret = wc_KyberKey_SharedSecretSize((KyberKey*)pqc_kse->key, + &ssSzPqc); + } + if (ret == 0) { + ret = wc_KyberKey_CipherTextSize((KyberKey*)pqc_kse->key, + &ctSz); + } + if (ret == 0) { + ret = wc_KyberKey_PublicKeySize((KyberKey*)pqc_kse->key, + &pubSz); + } + } + + /* Generate the ECDH key share part to be sent to the client */ + if (ret == 0 && ecc_group != 0) { + XMEMSET(ecc_kse, 0, sizeof(*ecc_kse)); + ecc_kse->group = ecc_group; + #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 && len != pubSz + ecc_kse->pubKeyLen) { + WOLFSSL_MSG("Invalid public key."); + ret = BAD_FUNC_ARG; + } + + /* Allocate buffer for the concatenated client key share data + * (PQC KEM ciphertext + ECDH public key) */ + if (ret == 0) { + ciphertext = (byte*)XMALLOC(ecc_kse->pubKeyLen + ctSz, ssl->heap, + DYNAMIC_TYPE_TLSX); + + if (ciphertext == NULL) { + WOLFSSL_MSG("Ciphertext memory allocation failure."); + ret = MEMORY_E; + } + } + + /* Process ECDH key share part. The generated shared secret is directly + * stored in the ssl->arrays->preMasterSecret buffer. Depending on the + * pqc_first flag, the ECDH shared secret part goes before or after the + * KEM part. */ + if (ret == 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) { + int pubOffset = 0; + int ssOffset = 0; + + /* Set the ECC size variable to the initial buffer size */ + ssSzEcc = ssl->arrays->preMasterSz; + + if (pqc_first) { + pubOffset = pubSz; + ssOffset = ssSzPqc; + } + + XMEMCPY(ecc_kse->ke, data + pubOffset, ecc_kse->keLen); + + #ifdef HAVE_CURVE25519 + if (ecc_group == WOLFSSL_ECC_X25519) { + ret = TLSX_KeyShare_ProcessX25519_ex(ssl, ecc_kse, + ssl->arrays->preMasterSecret + ssOffset, &ssSzEcc); + } + else + #endif + #ifdef HAVE_CURVE448 + if (ecc_group == WOLFSSL_ECC_X448) { + ret = TLSX_KeyShare_ProcessX448_ex(ssl, ecc_kse, + ssl->arrays->preMasterSecret + ssOffset, &ssSzEcc); + } + else + #endif + { + ret = TLSX_KeyShare_ProcessEcc_ex(ssl, ecc_kse, + ssl->arrays->preMasterSecret + ssOffset, &ssSzEcc); + } + } + if (ret == 0) { + if (ssSzEcc != ecc_kse->keyLen) { + WOLFSSL_MSG("Data length mismatch."); + ret = BAD_FUNC_ARG; + } + } + } + + if (ret == 0 && ssSzEcc + ssSzPqc > ENCRYPT_LEN) { + WOLFSSL_MSG("shared secret is too long."); + ret = LENGTH_ERROR; + } + + /* Process PQC KEM key share part. Depending on the pqc_first flag, the + * KEM shared secret part goes before or after the ECDH part. */ + if (ret == 0) { + int input_offset = ecc_kse->keLen; + int output_offset = ssSzEcc; + + if (pqc_first) { + input_offset = 0; + output_offset = 0; + } + + ret = TLSX_KeyShare_HandlePqcKeyServer(ssl, pqc_kse, + data + input_offset, pubSz, + ssl->arrays->preMasterSecret + output_offset, &ssSzPqc); + } + + if (ret == 0) { + XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + + ssl->arrays->preMasterSz = ssSzEcc + ssSzPqc; + keyShareEntry->ke = NULL; + keyShareEntry->keLen = 0; + + /* Concatenate the ECDH public key and the PQC KEM ciphertext. Based on + * the pqc_first flag, the ECDH public key goes before or after the KEM + * ciphertext. */ + if (pqc_first) { + XMEMCPY(ciphertext, pqc_kse->pubKey, ctSz); + XMEMCPY(ciphertext + ctSz, ecc_kse->pubKey, ecc_kse->pubKeyLen); + } + else { + XMEMCPY(ciphertext, ecc_kse->pubKey, ecc_kse->pubKeyLen); + XMEMCPY(ciphertext + ecc_kse->pubKeyLen, pqc_kse->pubKey, ctSz); + } + + keyShareEntry->pubKey = ciphertext; + keyShareEntry->pubKeyLen = ecc_kse->pubKeyLen + ctSz; ciphertext = NULL; /* Set namedGroup so wolfSSL_get_curve_name() can function properly on @@ -9654,13 +10229,11 @@ static int server_generate_pqc_ciphertext(WOLFSSL* ssl, } TLSX_KeyShare_FreeAll(ecc_kse, ssl->heap); - XFREE(sharedSecret, ssl->heap, DYNAMIC_TYPE_SECRET); + TLSX_KeyShare_FreeAll(pqc_kse, ssl->heap); XFREE(ciphertext, ssl->heap, DYNAMIC_TYPE_TLSX); - wc_ecc_free(&eccpubkey); - wc_KyberKey_Free(kem); return ret; } -#endif /* WOLFSSL_HAVE_KYBER */ +#endif /* WOLFSSL_HAVE_KYBER && !WOLFSSL_KYBER_NO_ENCAPSULATE */ /* Use the data to create a new key share object in the extensions. * @@ -9710,10 +10283,21 @@ int TLSX_KeyShare_Use(const WOLFSSL* ssl, word16 group, word16 len, byte* data, #if defined(WOLFSSL_HAVE_KYBER) && !defined(WOLFSSL_KYBER_NO_ENCAPSULATE) - if (WOLFSSL_NAMED_GROUP_IS_PQC(group) && - ssl->options.side == WOLFSSL_SERVER_END) { - ret = server_generate_pqc_ciphertext((WOLFSSL*)ssl, keyShareEntry, data, - len); + if (ssl->options.side == WOLFSSL_SERVER_END && + WOLFSSL_NAMED_GROUP_IS_PQC(group)) { + ret = TLSX_KeyShare_HandlePqcKeyServer((WOLFSSL*)ssl, + keyShareEntry, + data, len, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz); + if (ret != 0) + return ret; + } + else if (ssl->options.side == WOLFSSL_SERVER_END && + WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(group)) { + ret = TLSX_KeyShare_HandlePqcHybridKeyServer((WOLFSSL*)ssl, + keyShareEntry, + data, len); if (ret != 0) return ret; } @@ -9880,27 +10464,56 @@ static int TLSX_KeyShare_IsSupported(int namedGroup) #ifndef WOLFSSL_NO_ML_KEM_512 case WOLFSSL_ML_KEM_512: case WOLFSSL_P256_ML_KEM_512: + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + case WOLFSSL_X25519_ML_KEM_512: + #endif #endif #ifndef WOLFSSL_NO_ML_KEM_768 case WOLFSSL_ML_KEM_768: case WOLFSSL_P384_ML_KEM_768: + case WOLFSSL_P256_ML_KEM_768: + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + case WOLFSSL_X25519_ML_KEM_768: + #endif + #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448 + case WOLFSSL_X448_ML_KEM_768: + #endif #endif #ifndef WOLFSSL_NO_ML_KEM_1024 case WOLFSSL_ML_KEM_1024: case WOLFSSL_P521_ML_KEM_1024: + case WOLFSSL_P384_ML_KEM_1024: #endif break; #elif defined(HAVE_LIBOQS) case WOLFSSL_ML_KEM_512: case WOLFSSL_ML_KEM_768: case WOLFSSL_ML_KEM_1024: - case WOLFSSL_P256_ML_KEM_512: - case WOLFSSL_P384_ML_KEM_768: - case WOLFSSL_P521_ML_KEM_1024: { int ret; int id; - findEccPqc(NULL, &namedGroup, namedGroup); + ret = kyber_id2type(namedGroup, &id); + if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { + return 0; + } + + if (! ext_kyber_enabled(id)) { + return 0; + } + break; + } + case WOLFSSL_P256_ML_KEM_512: + case WOLFSSL_P384_ML_KEM_768: + case WOLFSSL_P256_ML_KEM_768: + case WOLFSSL_P521_ML_KEM_1024: + case WOLFSSL_P384_ML_KEM_1024: + case WOLFSSL_X25519_ML_KEM_512: + case WOLFSSL_X448_ML_KEM_768: + case WOLFSSL_X25519_ML_KEM_768: + { + int ret; + int id; + findEccPqc(NULL, &namedGroup, NULL, namedGroup); ret = kyber_id2type(namedGroup, &id); if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { return 0; @@ -9912,16 +10525,26 @@ static int TLSX_KeyShare_IsSupported(int namedGroup) break; } #endif -#endif +#endif /* WOLFSSL_NO_ML_KEM */ #ifdef WOLFSSL_KYBER_ORIGINAL #ifdef WOLFSSL_WC_KYBER #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: @@ -9932,13 +10555,30 @@ static int TLSX_KeyShare_IsSupported(int namedGroup) case WOLFSSL_KYBER_LEVEL1: case WOLFSSL_KYBER_LEVEL3: case WOLFSSL_KYBER_LEVEL5: - case WOLFSSL_P256_KYBER_LEVEL1: - case WOLFSSL_P384_KYBER_LEVEL3: - case WOLFSSL_P521_KYBER_LEVEL5: { int ret; int id; - findEccPqc(NULL, &namedGroup, namedGroup); + ret = kyber_id2type(namedGroup, &id); + if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { + return 0; + } + + if (! ext_kyber_enabled(id)) { + return 0; + } + break; + } + case WOLFSSL_P256_KYBER_LEVEL1: + case WOLFSSL_P384_KYBER_LEVEL3: + case WOLFSSL_P256_KYBER_LEVEL3: + case WOLFSSL_P521_KYBER_LEVEL5: + case WOLFSSL_X25519_KYBER_LEVEL1: + case WOLFSSL_X448_KYBER_LEVEL3: + case WOLFSSL_X25519_KYBER_LEVEL3: + { + int ret; + int id; + findEccPqc(NULL, &namedGroup, NULL, namedGroup); ret = kyber_id2type(namedGroup, &id); if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { return 0; @@ -10002,14 +10642,25 @@ static const word16 preferredGroup[] = { #ifndef WOLFSSL_NO_ML_KEM_512 WOLFSSL_ML_KEM_512, WOLFSSL_P256_ML_KEM_512, + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + WOLFSSL_X25519_ML_KEM_512, + #endif #endif #ifndef WOLFSSL_NO_ML_KEM_768 WOLFSSL_ML_KEM_768, WOLFSSL_P384_ML_KEM_768, + WOLFSSL_P256_ML_KEM_768, + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + WOLFSSL_X25519_ML_KEM_768, + #endif + #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448 + WOLFSSL_X448_ML_KEM_768, + #endif #endif #ifndef WOLFSSL_NO_ML_KEM_1024 WOLFSSL_ML_KEM_1024, WOLFSSL_P521_ML_KEM_1024, + WOLFSSL_P384_ML_KEM_1024, #endif #elif defined(HAVE_LIBOQS) /* These require a runtime call to TLSX_KeyShare_IsSupported to use */ @@ -10018,7 +10669,16 @@ static const word16 preferredGroup[] = { WOLFSSL_ML_KEM_1024, WOLFSSL_P256_ML_KEM_512, WOLFSSL_P384_ML_KEM_768, + WOLFSSL_P256_ML_KEM_768, WOLFSSL_P521_ML_KEM_1024, + WOLFSSL_P384_ML_KEM_1024, + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + WOLFSSL_X25519_ML_KEM_512, + WOLFSSL_X25519_ML_KEM_768, + #endif + #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448 + WOLFSSL_X448_ML_KEM_768, + #endif #endif #endif /* !WOLFSSL_NO_ML_KEM */ #ifdef WOLFSSL_KYBER_ORIGINAL @@ -10026,10 +10686,20 @@ 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, @@ -10042,7 +10712,15 @@ static const word16 preferredGroup[] = { WOLFSSL_KYBER_LEVEL5, WOLFSSL_P256_KYBER_LEVEL1, WOLFSSL_P384_KYBER_LEVEL3, + WOLFSSL_P256_KYBER_LEVEL3, WOLFSSL_P521_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 #endif /* WOLFSSL_KYBER_ORIGINAL */ WOLFSSL_NAMED_GROUP_INVALID @@ -10337,7 +11015,9 @@ 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)) && + (!WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(clientKSE->group))) continue; #ifdef WOLFSSL_SM2 @@ -10357,11 +11037,12 @@ int TLSX_KeyShare_Choose(const WOLFSSL *ssl, TLSX* extensions, if (!TLSX_SupportedGroups_Find(ssl, clientKSE->group, extensions)) continue; - if (!WOLFSSL_NAMED_GROUP_IS_FFHDE(clientKSE->group)) { + if (!WOLFSSL_NAMED_GROUP_IS_FFDHE(clientKSE->group)) { /* Check max value supported. */ if (clientKSE->group > WOLFSSL_ECC_MAX) { #ifdef WOLFSSL_HAVE_KYBER - if (!WOLFSSL_NAMED_GROUP_IS_PQC(clientKSE->group)) + if (!WOLFSSL_NAMED_GROUP_IS_PQC(clientKSE->group) && + !WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(clientKSE->group)) #endif continue; } @@ -10416,7 +11097,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. */ @@ -10426,7 +11107,8 @@ int TLSX_KeyShare_Setup(WOLFSSL *ssl, KeyShareEntry* clientKSE) if (clientKSE->key == NULL) { #ifdef WOLFSSL_HAVE_KYBER - if (WOLFSSL_NAMED_GROUP_IS_PQC(clientKSE->group)) { + if (WOLFSSL_NAMED_GROUP_IS_PQC(clientKSE->group) || + WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(clientKSE->group)) { /* Going to need the public key (AKA ciphertext). */ serverKSE->pubKey = clientKSE->pubKey; clientKSE->pubKey = NULL; @@ -13674,6 +14356,11 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) if (ret == WOLFSSL_SUCCESS) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_ML_KEM_512, ssl->heap); + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_ML_KEM_512, + ssl->heap); + #endif #endif #ifndef WOLFSSL_NO_ML_KEM_768 if (ret == WOLFSSL_SUCCESS) @@ -13682,6 +14369,19 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) if (ret == WOLFSSL_SUCCESS) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_ML_KEM_768, ssl->heap); + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_ML_KEM_768, + ssl->heap); + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_ML_KEM_768, + ssl->heap); + #endif + #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448 + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X448_ML_KEM_768, + ssl->heap); + #endif #endif #ifndef WOLFSSL_NO_ML_KEM_1024 if (ret == WOLFSSL_SUCCESS) @@ -13690,6 +14390,9 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) if (ret == WOLFSSL_SUCCESS) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P521_ML_KEM_1024, ssl->heap); + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_ML_KEM_1024, + ssl->heap); #endif #elif defined(HAVE_LIBOQS) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_512, ssl->heap); @@ -13705,9 +14408,28 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) if (ret == WOLFSSL_SUCCESS) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_ML_KEM_768, ssl->heap); + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_ML_KEM_768, + ssl->heap); if (ret == WOLFSSL_SUCCESS) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P521_ML_KEM_1024, ssl->heap); + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_ML_KEM_1024, + ssl->heap); + #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_ML_KEM_512, + ssl->heap); + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_ML_KEM_768, + ssl->heap); + #endif + #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448 + if (ret == WOLFSSL_SUCCESS) + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X448_ML_KEM_768, + ssl->heap); + #endif #endif /* HAVE_LIBOQS */ #endif /* !WOLFSSL_NO_ML_KEM */ #ifdef WOLFSSL_KYBER_ORIGINAL @@ -13719,6 +14441,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) @@ -13727,6 +14454,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) @@ -13750,9 +14490,25 @@ 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 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_KYBER_ORIGINAL */ #endif /* WOLFSSL_HAVE_KYBER */ diff --git a/src/tls13.c b/src/tls13.c index f41f1f42f..7bc18d5cc 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -13607,7 +13607,8 @@ int wolfSSL_UseKeyShare(WOLFSSL* ssl, word16 group) #endif #if defined(WOLFSSL_HAVE_KYBER) - if (WOLFSSL_NAMED_GROUP_IS_PQC(group)) { + if (WOLFSSL_NAMED_GROUP_IS_PQC(group) || + WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(group)) { if (ssl->ctx != NULL && ssl->ctx->method != NULL && !IsAtLeastTLSv1_3(ssl->version)) { diff --git a/tests/include.am b/tests/include.am index 0f4df2de1..cd629eed2 100644 --- a/tests/include.am +++ b/tests/include.am @@ -30,11 +30,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 074a9a03f..503dec1de 100644 --- a/tests/suites.c +++ b/tests/suites.c @@ -992,9 +992,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) { @@ -1003,29 +1002,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])); @@ -1036,6 +1012,15 @@ int SuiteTest(int argc, char** argv) args.return_code = EXIT_FAILURE; goto exit; } + /* 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; + } #ifdef WOLFSSL_DTLS_CH_FRAG /* add DTLSv13 pq frag tests */ XSTRLCPY(argv0[1], "tests/test-dtls13-pq-frag.conf", sizeof(argv0[1])); @@ -1046,20 +1031,8 @@ int SuiteTest(int argc, char** argv) 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"); - 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) { @@ -1069,7 +1042,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 6ea8317db..000000000 --- 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 bd5e32697..000000000 --- a/tests/test-dtls13-pq-2.conf +++ /dev/null @@ -1,27 +0,0 @@ -# server DTLSv1.3 with post-quantum group --u --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P256_ML_KEM_512 - -# client DTLSv1.3 with post-quantum group --u --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P256_ML_KEM_512 - -# P384_ML_KEM_768 and P521_ML_KEM_1024 would fragment the ClientHello. - -# 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 01aaf477f..5592ecb79 100644 --- a/tests/test-dtls13-pq-frag.conf +++ b/tests/test-dtls13-pq-frag.conf @@ -1,3 +1,27 @@ +# server DTLSv1.3 with post-quantum group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc ML_KEM_768 + +# client DTLSv1.3 with post-quantum group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc ML_KEM_768 + +# server DTLSv1.3 with post-quantum group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc ML_KEM_1024 + +# client DTLSv1.3 with post-quantum group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc ML_KEM_1024 + # server DTLSv1.3 with post-quantum group -u -v 4 @@ -21,4 +45,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 000000000..c9edc6907 --- /dev/null +++ b/tests/test-dtls13-pq-hybrid-frag.conf @@ -0,0 +1,131 @@ +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_ML_KEM_768 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_ML_KEM_768 + +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_ML_KEM_768 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_ML_KEM_768 + +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P521_ML_KEM_1024 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P521_ML_KEM_1024 + +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_ML_KEM_1024 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_ML_KEM_1024 + +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_ML_KEM_768 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_ML_KEM_768 + +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X448_ML_KEM_768 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X448_ML_KEM_768 + +# 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 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 000000000..3bb14cac5 --- /dev/null +++ b/tests/test-dtls13-pq-hybrid.conf @@ -0,0 +1,51 @@ +# server DTLSv1.3 with post-quantum group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_ML_KEM_512 + +# client DTLSv1.3 with post-quantum group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_ML_KEM_512 + +# server DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_ML_KEM_512 + +# client DTLSv1.3 with post-quantum hybrid group +-u +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_ML_KEM_512 + +# Hybrids with ML_KEM_768 and ML_KEM_1024 would fragment the ClientHello. + +# 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-dtls13-pq.conf b/tests/test-dtls13-pq.conf index 37abf2c77..559741f32 100644 --- a/tests/test-dtls13-pq.conf +++ b/tests/test-dtls13-pq.conf @@ -16,12 +16,12 @@ -u -v 4 -l TLS13-AES256-GCM-SHA384 ---pqc ML_KEM_512 +--pqc KYBER_LEVEL1 # client DTLSv1.3 with post-quantum group -u -v 4 -l TLS13-AES256-GCM-SHA384 ---pqc ML_KEM_512 +--pqc KYBER_LEVEL1 # 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 26f5f525d..000000000 --- a/tests/test-tls13-pq-2.conf +++ /dev/null @@ -1,59 +0,0 @@ -# server TLSv1.3 with post-quantum group --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P256_ML_KEM_512 - -# client TLSv1.3 with post-quantum group --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P256_ML_KEM_512 - -# server TLSv1.3 with post-quantum group --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P384_ML_KEM_768 - -# client TLSv1.3 with post-quantum group --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P384_ML_KEM_768 - -# server TLSv1.3 with post-quantum group --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P521_ML_KEM1024 - -# client TLSv1.3 with post-quantum group --v 4 --l TLS13-AES256-GCM-SHA384 ---pqc P521_ML_KEM1024 - -# 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 000000000..242cd3089 --- /dev/null +++ b/tests/test-tls13-pq-hybrid.conf @@ -0,0 +1,149 @@ +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_ML_KEM_512 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_ML_KEM_512 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_ML_KEM_768 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_ML_KEM_768 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_ML_KEM_768 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P256_ML_KEM_768 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P521_ML_KEM_1024 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P521_ML_KEM_1024 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_ML_KEM_1024 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc P384_ML_KEM_1024 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_ML_KEM_512 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_ML_KEM_512 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_ML_KEM_768 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X25519_ML_KEM_768 + +# server TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X448_ML_KEM_768 + +# client TLSv1.3 with post-quantum hybrid group +-v 4 +-l TLS13-AES256-GCM-SHA384 +--pqc X448_ML_KEM_768 + +# 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 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 8ce9aac4e..2198b917c 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1906,14 +1906,16 @@ enum Misc { #define AEAD_AUTH_DATA_SZ 13 #endif -#define WOLFSSL_NAMED_GROUP_IS_FFHDE(group) \ - (MIN_FFHDE_GROUP <= (group) && (group) <= MAX_FFHDE_GROUP) +#define WOLFSSL_NAMED_GROUP_IS_FFDHE(group) \ + (WOLFSSL_FFDHE_START <= (group) && (group) <= WOLFSSL_FFDHE_END) #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); +WOLFSSL_LOCAL int NamedGroupIsPqcHybrid(int group); +#define WOLFSSL_NAMED_GROUP_IS_PQC(group) NamedGroupIsPqc(group) +#define WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(group) NamedGroupIsPqcHybrid(group) #else -#define WOLFSSL_NAMED_GROUP_IS_PQC(group) ((void)(group), 0) +#define WOLFSSL_NAMED_GROUP_IS_PQC(group) ((void)(group), 0) +#define WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(group) ((void)(group), 0) #endif /* WOLFSSL_HAVE_KYBER */ /* minimum Downgrade Minor version */ @@ -3603,8 +3605,8 @@ typedef struct KeyShareEntry { byte* pubKey; /* Public key */ word32 pubKeyLen; /* Public key length */ #if !defined(NO_DH) || defined(WOLFSSL_HAVE_KYBER) - byte* privKey; /* Private key - DH and PQ KEMs only */ - word32 privKeyLen;/* Only for PQ KEMs. */ + byte* privKey; /* Private key */ + word32 privKeyLen;/* Private key length - PQC only */ #endif #ifdef WOLFSSL_ASYNC_CRYPT int lastRet; diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 1c46f2b35..7260799fe 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -4568,62 +4568,54 @@ enum { WOLFSSL_FFDHE_4096 = 258, WOLFSSL_FFDHE_6144 = 259, WOLFSSL_FFDHE_8192 = 260, + WOLFSSL_FFDHE_END = 511, #ifdef HAVE_PQC - /* These group numbers were 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. */ #ifdef WOLFSSL_KYBER_ORIGINAL - WOLFSSL_PQC_MIN = 570, - WOLFSSL_PQC_SIMPLE_MIN = 570, + /* Old code points to keep compatibility with Kyber Round 3. + * 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 = 570, /* KYBER_512 */ WOLFSSL_KYBER_LEVEL3 = 572, /* KYBER_768 */ WOLFSSL_KYBER_LEVEL5 = 573, /* KYBER_1024 */ -#ifdef WOLFSSL_NO_ML_KEM - WOLFSSL_PQC_SIMPLE_MAX = 573, -#endif - WOLFSSL_PQC_HYBRID_MIN = 12090, WOLFSSL_P256_KYBER_LEVEL1 = 12090, WOLFSSL_P384_KYBER_LEVEL3 = 12092, WOLFSSL_P521_KYBER_LEVEL5 = 12093, -#ifdef WOLFSSL_NO_ML_KEM - WOLFSSL_PQC_HYBRID_MAX = 12093, - WOLFSSL_PQC_MAX = 12093, -#endif -#endif + WOLFSSL_X25519_KYBER_LEVEL1 = 12089, + WOLFSSL_X448_KYBER_LEVEL3 = 12176, + WOLFSSL_X25519_KYBER_LEVEL3 = 25497, + WOLFSSL_P256_KYBER_LEVEL3 = 25498, +#endif /* WOLFSSL_KYBER_ORIGINAL */ #ifndef WOLFSSL_NO_ML_KEM -#ifndef WOLFSSL_KYBER_ORIGINAL - WOLFSSL_PQC_MIN = 512, - WOLFSSL_PQC_SIMPLE_MIN = 512, -#endif - WOLFSSL_ML_KEM_512 = 512, /* ML-KEM 512 */ - WOLFSSL_ML_KEM_768 = 513, /* ML-KEM 768 */ - WOLFSSL_ML_KEM_1024 = 514, /* ML-KEM 1024 */ - WOLFSSL_PQC_SIMPLE_MAX = 514, + /* Taken from draft-connolly-tls-mlkem-key-agreement, see: + * https://github.com/dconnolly/draft-connolly-tls-mlkem-key-agreement/ + */ + WOLFSSL_ML_KEM_512 = 512, + WOLFSSL_ML_KEM_768 = 513, + WOLFSSL_ML_KEM_1024 = 514, -#ifndef WOLFSSL_KYBER_ORIGINAL - WOLFSSL_PQC_HYBRID_MIN = 12107, -#endif + /* Taken from draft-kwiatkowski-tls-ecdhe-mlkem. see: + * https://github.com/post-quantum-cryptography/ + * draft-kwiatkowski-tls-ecdhe-mlkem/ + */ + WOLFSSL_P256_ML_KEM_768 = 4587, + WOLFSSL_X25519_ML_KEM_768 = 4588, + WOLFSSL_P384_ML_KEM_1024 = 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_ML_KEM_512 = 12107, WOLFSSL_P384_ML_KEM_768 = 12108, WOLFSSL_P521_ML_KEM_1024 = 12109, - WOLFSSL_PQC_HYBRID_MAX = 12109, - WOLFSSL_PQC_MAX = 12109, -#endif /* !WOLFSSL_NO_ML_KEM */ + WOLFSSL_X25519_ML_KEM_512 = 12214, + WOLFSSL_X448_ML_KEM_768 = 12215, +#endif /* WOLFSSL_NO_ML_KEM */ #endif /* HAVE_PQC */ WOLF_ENUM_DUMMY_LAST_ELEMENT(SSL_H) }; diff --git a/wolfssl/wolfcrypt/ext_kyber.h b/wolfssl/wolfcrypt/ext_kyber.h index e4f20a790..0fe421f56 100644 --- a/wolfssl/wolfcrypt/ext_kyber.h +++ b/wolfssl/wolfcrypt/ext_kyber.h @@ -39,8 +39,14 @@ #if defined (HAVE_LIBOQS) #include - #define EXT_KYBER_MAX_PRIV_SZ OQS_KEM_kyber_1024_length_secret_key - #define EXT_KYBER_MAX_PUB_SZ OQS_KEM_kyber_1024_length_public_key + + #ifndef WOLFSSL_NO_ML_KEM + #define EXT_KYBER_MAX_PRIV_SZ OQS_KEM_ml_kem_1024_length_secret_key + #define EXT_KYBER_MAX_PUB_SZ OQS_KEM_ml_kem_1024_length_public_key + #elif defined(WOLFSSL_KYBER_ORIGINAL) + #define EXT_KYBER_MAX_PRIV_SZ OQS_KEM_kyber_1024_length_secret_key + #define EXT_KYBER_MAX_PUB_SZ OQS_KEM_kyber_1024_length_public_key + #endif #endif struct KyberKey {