diff --git a/cmd/lib/secutil.c b/cmd/lib/secutil.c --- a/cmd/lib/secutil.c +++ b/cmd/lib/secutil.c @@ -4212,17 +4212,21 @@ static const struct SSLNamedGroupString { NAME_AND_LEN("FF3072"), ssl_grp_ffdhe_3072 }, { NAME_AND_LEN("FF4096"), ssl_grp_ffdhe_4096 }, { NAME_AND_LEN("FF6144"), ssl_grp_ffdhe_6144 }, { NAME_AND_LEN("FF8192"), ssl_grp_ffdhe_8192 }, #ifndef NSS_DISABLE_KYBER { NAME_AND_LEN("xyber76800"), ssl_grp_kem_xyber768d00 }, #endif + { NAME_AND_LEN("x25519mlkem768"), ssl_grp_kem_mlkem768x25519 }, { NAME_AND_LEN("mlkem768x25519"), ssl_grp_kem_mlkem768x25519 }, + { NAME_AND_LEN("secp256r1mlkem768"), ssl_grp_kem_secp256r1mlkem768 }, { NAME_AND_LEN("mlkem768secp256r1"), ssl_grp_kem_secp256r1mlkem768 }, + { NAME_AND_LEN("secp384r1mlkem1024"), ssl_grp_kem_secp384r1mlkem1024 }, + { NAME_AND_LEN("mlkem1024secp384r1"), ssl_grp_kem_secp384r1mlkem1024}, }; static const size_t sslNamedGroupStringLen=PR_ARRAY_SIZE(sslNamedGroupStringArray); static SSLNamedGroup groupNameToNamedGroup(char *name) { int len = PL_strlen(name); @@ -4231,21 +4235,16 @@ groupNameToNamedGroup(char *name) for (i=0; i < sslNamedGroupStringLen; i++) { const struct SSLNamedGroupString *ngs = &sslNamedGroupStringArray[i]; if (len == ngs->len) { if (!strncmp(name, ngs->name, len)) { return ngs->grp; } } } - if (PL_strlen(name) == 14) { - if (!strncmp(name, "mlkem768x25519", 14)) { - return ssl_grp_kem_mlkem768x25519; - } - } return ssl_grp_none; } static SECStatus countItems(const char *arg, unsigned int *numItems) { char *str = PORT_Strdup(arg); diff --git a/cmd/selfserv/selfserv.c b/cmd/selfserv/selfserv.c --- a/cmd/selfserv/selfserv.c +++ b/cmd/selfserv/selfserv.c @@ -226,17 +226,17 @@ PrintParameterUsage() "-Q enables ALPN for HTTP/1.1 [RFC7301]\n" "-I comma separated list of enabled groups for TLS key exchange.\n" " The following values are valid:\n" " P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192,\n" " " #ifndef NSS_DISABLE_KYBER "xyber768d00, " #endif - "mlkem768x25519, mlkem768secp256r1\n" + "x25519mlkem768, secp256r1mlkem768, secp384r1mlkem1024\n" "-J comma separated list of enabled signature schemes in preference order.\n" " The following values are valid:\n" " rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n" " ecdsa_sha1, ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,\n" " ecdsa_secp521r1_sha512,\n" " rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512,\n" " rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512,\n" "-Z enable 0-RTT (for TLS 1.3; also use -u)\n" diff --git a/cmd/tstclnt/tstclnt.c b/cmd/tstclnt/tstclnt.c --- a/cmd/tstclnt/tstclnt.c +++ b/cmd/tstclnt/tstclnt.c @@ -309,17 +309,17 @@ PrintParameterUsage() fprintf(stderr, "%-20s Disconnect and reconnect up to N times total\n", "-L"); fprintf(stderr, "%-20s Comma separated list of enabled groups for TLS key exchange.\n" "%-20s The following values are valid:\n" "%-20s P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n" "%-20s " #ifndef NSS_DISABLE_KYBER "xyber768d00, " #endif - "mlkem768x25519, mlkem768secp256r1\n", + "x25519mlkem768, secp256r1mlkem768, secp384r1mlkem1024\n", "-I", "", "", ""); fprintf(stderr, "%-20s Comma separated list of signature schemes in preference order.\n" "%-20s The following values are valid:\n" "%-20s rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n" "%-20s ecdsa_sha1, ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,\n" "%-20s ecdsa_secp521r1_sha512,\n" "%-20s rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512,\n" "%-20s rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512,\n" diff --git a/gtests/pk11_gtest/pk11_keygen.cc b/gtests/pk11_gtest/pk11_keygen.cc --- a/gtests/pk11_gtest/pk11_keygen.cc +++ b/gtests/pk11_gtest/pk11_keygen.cc @@ -162,15 +162,20 @@ std::unique_ptr Pkcs11KeyPa return std::unique_ptr( new KyberParamHolder(CKP_NSS_KYBER_768_ROUND3)); case CKM_NSS_ML_KEM_KEY_PAIR_GEN: std::cerr << "Generate ML-KEM768 pair" << std::endl; return std::unique_ptr( new KyberParamHolder(CKP_NSS_ML_KEM_768)); + case CKM_ML_KEM_KEY_PAIR_GEN: + std::cerr << "Generate ML-KEM1024 pair" << std::endl; + return std::unique_ptr( + new KyberParamHolder(CKP_ML_KEM_1024)); + default: - ADD_FAILURE() << "unknown OID " << mech_; + ADD_FAILURE() << "unknown Mechanism " << mech_; } return nullptr; } } // namespace nss_test diff --git a/gtests/pk11_gtest/pk11_kem_unittest.cc b/gtests/pk11_gtest/pk11_kem_unittest.cc --- a/gtests/pk11_gtest/pk11_kem_unittest.cc +++ b/gtests/pk11_gtest/pk11_kem_unittest.cc @@ -69,41 +69,50 @@ class Pkcs11KEMTest } CK_MECHANISM_TYPE keyGenMech() { switch (GetParam()) { case CKP_NSS_KYBER_768_ROUND3: return CKM_NSS_KYBER_KEY_PAIR_GEN; case CKP_NSS_ML_KEM_768: return CKM_NSS_ML_KEM_KEY_PAIR_GEN; + case CKP_ML_KEM_768: + case CKP_ML_KEM_1024: + return CKM_ML_KEM_KEY_PAIR_GEN; default: EXPECT_TRUE(false); return 0; } } CK_MECHANISM_TYPE encapsMech() { switch (GetParam()) { case CKP_NSS_KYBER_768_ROUND3: return CKM_NSS_KYBER; case CKP_NSS_ML_KEM_768: return CKM_NSS_ML_KEM; + case CKP_ML_KEM_768: + case CKP_ML_KEM_1024: + return CKM_ML_KEM; default: EXPECT_TRUE(false); return 0; } } }; TEST_P(Pkcs11KEMTest, KemConsistencyTest) { Pkcs11KeyPairGenerator generator(keyGenMech()); ScopedSECKEYPrivateKey priv; ScopedSECKEYPublicKey pub; generator.GenerateKey(&priv, &pub, false); + ASSERT_NE(nullptr, pub); + ASSERT_NE(nullptr, priv); + // Copy the public key to simulate receiving the key as an octet string ScopedSECKEYPublicKey pubCopy(SECKEY_CopyPublicKey(pub.get())); ASSERT_NE(nullptr, pubCopy); ScopedPK11SlotInfo slot(PK11_GetBestSlot(encapsMech(), nullptr)); ASSERT_NE(nullptr, slot); ASSERT_NE((unsigned int)CK_INVALID_HANDLE, @@ -139,11 +148,13 @@ TEST_P(Pkcs11KEMTest, KemConsistencyTest EXPECT_EQ(0, SECITEM_CompareItem(item1, item2)); } INSTANTIATE_TEST_SUITE_P(Pkcs11KEMTest, Pkcs11KEMTest, ::testing::Values( #ifndef NSS_DISABLE_KYBER CKP_NSS_KYBER_768_ROUND3, #endif + CKP_ML_KEM_768, + CKP_ML_KEM_1024, CKP_NSS_ML_KEM_768)); } // namespace nss_test diff --git a/gtests/ssl_gtest/tls_agent.cc b/gtests/ssl_gtest/tls_agent.cc --- a/gtests/ssl_gtest/tls_agent.cc +++ b/gtests/ssl_gtest/tls_agent.cc @@ -521,53 +521,57 @@ void TlsAgent::DisableAllCiphers() { const std::vector kAllDHEGroups = { ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1, ssl_grp_ec_secp521r1, ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072, ssl_grp_ffdhe_4096, ssl_grp_ffdhe_6144, ssl_grp_ffdhe_8192, #ifndef NSS_DISABLE_KYBER ssl_grp_kem_xyber768d00, #endif ssl_grp_kem_mlkem768x25519, ssl_grp_kem_secp256r1mlkem768, + ssl_grp_kem_secp384r1mlkem1024, }; const std::vector kNonPQDHEGroups = { ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1, ssl_grp_ec_secp521r1, ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072, ssl_grp_ffdhe_4096, ssl_grp_ffdhe_6144, ssl_grp_ffdhe_8192, }; const std::vector kECDHEGroups = { ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1, ssl_grp_ec_secp521r1, #ifndef NSS_DISABLE_KYBER ssl_grp_kem_xyber768d00, #endif - ssl_grp_kem_mlkem768x25519, ssl_grp_kem_secp256r1mlkem768 + ssl_grp_kem_mlkem768x25519, ssl_grp_kem_secp256r1mlkem768, + ssl_grp_kem_secp384r1mlkem1024, }; const std::vector kFFDHEGroups = { ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072, ssl_grp_ffdhe_4096, ssl_grp_ffdhe_6144, ssl_grp_ffdhe_8192}; // Defined because the big DHE groups are ridiculously slow. const std::vector kFasterDHEGroups = { ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1, ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072, #ifndef NSS_DISABLE_KYBER ssl_grp_kem_xyber768d00, #endif ssl_grp_kem_mlkem768x25519, ssl_grp_kem_secp256r1mlkem768, + ssl_grp_kem_secp384r1mlkem1024, }; const std::vector kEcdhHybridGroups = { #ifndef NSS_DISABLE_KYBER ssl_grp_kem_xyber768d00, #endif ssl_grp_kem_mlkem768x25519, ssl_grp_kem_secp256r1mlkem768, + ssl_grp_kem_secp384r1mlkem1024, }; void TlsAgent::EnableCiphersByKeyExchange(SSLKEAType kea) { EXPECT_TRUE(EnsureTlsSetup()); for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) { SSLCipherSuiteInfo csinfo; @@ -735,16 +739,19 @@ void TlsAgent::CheckKEA(SSLKEAType kea, #endif case ssl_grp_kem_mlkem768x25519: kea_size = 255; break; case ssl_grp_ec_secp256r1: case ssl_grp_kem_secp256r1mlkem768: kea_size = 256; break; + case ssl_grp_kem_secp384r1mlkem1024: + kea_size = 384; + break; case ssl_grp_ec_secp384r1: kea_size = 384; break; case ssl_grp_ffdhe_2048: kea_size = 2048; break; case ssl_grp_ffdhe_3072: kea_size = 3072; diff --git a/gtests/ssl_gtest/tls_mlkem_unittest.cc b/gtests/ssl_gtest/tls_mlkem_unittest.cc --- a/gtests/ssl_gtest/tls_mlkem_unittest.cc +++ b/gtests/ssl_gtest/tls_mlkem_unittest.cc @@ -35,16 +35,25 @@ TEST_P(TlsKeyExchangeTest13, Mlkem768Sec EnsureKeyShareSetup(); ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768}); Connect(); CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_secp256r1mlkem768, ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256); } +TEST_P(TlsKeyExchangeTest13, Mlkem1024Secp384r1Supported) { + EnsureKeyShareSetup(); + ConfigNamedGroups({ssl_grp_kem_secp384r1mlkem1024}); + + Connect(); + CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_secp384r1mlkem1024, + ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256); +} + TEST_P(TlsKeyExchangeTest, Tls12ClientMlkem768StartNotSupported) { EnsureKeyShareSetup(); client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, SSL_LIBRARY_VERSION_TLS_1_2); server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, SSL_LIBRARY_VERSION_TLS_1_3); client_->DisableAllCiphers(); client_->EnableCiphersByKeyExchange(ssl_kea_ecdh); @@ -53,16 +62,17 @@ TEST_P(TlsKeyExchangeTest, Tls12ClientMl client_->ssl_fd(), kECDHEGroups.size() + kEcdhHybridGroups.size())); Connect(); std::vector groups = GetGroupDetails(groups_capture_); for (auto group : groups) { EXPECT_NE(group, ssl_grp_kem_mlkem768x25519); EXPECT_NE(group, ssl_grp_kem_secp256r1mlkem768); + EXPECT_NE(group, ssl_grp_kem_secp384r1mlkem1024); } } TEST_P(TlsKeyExchangeTest13, Tls12ServerMlkem768x25519NotSupported) { EnsureKeyShareSetup(); client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, SSL_LIBRARY_VERSION_TLS_1_3); @@ -127,43 +137,63 @@ TEST_P(TlsKeyExchangeTest13, Mlkem768x25 Connect(); CheckKEXDetails({ssl_grp_kem_mlkem768x25519, ssl_grp_ec_secp256r1}, {ssl_grp_kem_mlkem768x25519}, ssl_grp_ec_secp256r1); } TEST_P(TlsKeyExchangeTest13, Mlkem768Secp256r1ClientDisabledByPolicy) { EnsureKeyShareSetup(); - client_->SetPolicy(SEC_OID_SECP256R1MLKEM768, 0, NSS_USE_ALG_IN_SSL_KX); + client_->SetPolicy(SEC_OID_SECP256R1MLKEM768, 0, NSS_USE_ALG_IN_SSL_KX); ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1}); Connect(); CheckKEXDetails({ssl_grp_ec_secp256r1}, {ssl_grp_ec_secp256r1}); } TEST_P(TlsKeyExchangeTest13, Mlkem768Secp256r1ServerDisabledByPolicy) { EnsureKeyShareSetup(); - server_->SetPolicy(SEC_OID_SECP256R1MLKEM768, 0, NSS_USE_ALG_IN_SSL_KX); + server_->SetPolicy(SEC_OID_SECP256R1MLKEM768, 0, NSS_USE_ALG_IN_SSL_KX); ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1}); Connect(); CheckKEXDetails({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1}, {ssl_grp_kem_secp256r1mlkem768}, ssl_grp_ec_secp256r1); } +TEST_P(TlsKeyExchangeTest13, Secp384r1Mlkem1024ClientDisabledByPolicy) { + EnsureKeyShareSetup(); + client_->SetPolicy(SEC_OID_SECP384R1MLKEM1024, 0, NSS_USE_ALG_IN_SSL_KX); + ConfigNamedGroups({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp256r1}); + + Connect(); + CheckKEXDetails({ssl_grp_ec_secp256r1}, {ssl_grp_ec_secp256r1}); +} + +TEST_P(TlsKeyExchangeTest13, Secp384r1Mlkem1024ServerDisabledByPolicy) { + EnsureKeyShareSetup(); + server_->SetPolicy(SEC_OID_SECP384R1MLKEM1024, 0, NSS_USE_ALG_IN_SSL_KX); + ConfigNamedGroups({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp256r1}); + + Connect(); + CheckKEXDetails({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp256r1}, + {ssl_grp_kem_secp384r1mlkem1024}, ssl_grp_ec_secp256r1); +} + static void CheckECDHShareReuse( const std::shared_ptr& capture) { EXPECT_TRUE(capture->captured()); const DataBuffer& ext = capture->extension(); - DataBuffer hybrid_share[4]; - DataBuffer ecdh_share[4]; - int hybrid_offset[4]; - SSLNamedGroup hybrid_ec_type[4]; - SSLNamedGroup ec_type[4]; - int ecdh_index[4]; + const int max_count=4; + DataBuffer hybrid_share[max_count]; + DataBuffer ecdh_share[max_count]; + int hybrid_offset[max_count]; + SSLNamedGroup hybrid_ec_type[max_count]; + SSLNamedGroup ec_type[max_count]; + int ecdh_index[max_count]; int nextHybrid = 0; int nextECDH = 0; size_t offset = 0; uint32_t ext_len; ext.Read(0, 2, &ext_len); EXPECT_EQ(ext.len() - 2, ext_len); offset += 2; @@ -180,30 +210,40 @@ static void CheckECDHShareReuse( hybrid_ec_type[nextHybrid] = ssl_grp_ec_curve25519; nextHybrid++; break; case ssl_grp_kem_secp256r1mlkem768: hybrid_share[nextHybrid] = DataBuffer(ext.data() + offset + 2 + 2, named_group_len); hybrid_offset[nextHybrid] = 0; hybrid_ec_type[nextHybrid] = ssl_grp_ec_secp256r1; nextHybrid++; + break; + case ssl_grp_kem_secp384r1mlkem1024: + hybrid_share[nextHybrid] = DataBuffer(ext.data() + offset + 2 + 2, named_group_len); + hybrid_offset[nextHybrid] = 0; + hybrid_ec_type[nextHybrid] = ssl_grp_ec_secp384r1; + nextHybrid++; + break; case ssl_grp_ec_curve25519: case ssl_grp_ec_secp256r1: + case ssl_grp_ec_secp384r1: ecdh_share[nextECDH] = DataBuffer(ext.data() + offset + 2 + 2, named_group_len); ec_type[nextECDH] = (SSLNamedGroup) named_group; nextECDH++; } offset += 2 + 2 + named_group_len; ext.Read(offset, 2, &named_group); ext.Read(offset + 2, 2, &named_group_len); } EXPECT_EQ(offset, ext.len()); ASSERT_TRUE(nextECDH > 0); ASSERT_TRUE(nextHybrid > 0); + ASSERT_TRUE(nextECDH <= max_count); + ASSERT_TRUE(nextHybrid <= max_count); /* setup the hybrid ecdh indeces */ for (int i=0; i < nextHybrid; i++) { ecdh_index[i] = -1; for (int j=0; j < nextECDH; j++) { if (hybrid_ec_type[i] == ec_type[j]) { ecdh_index[i] = j; break; } @@ -265,16 +305,40 @@ TEST_P(TlsKeyExchangeTest13, Mlkem768Sec Connect(); CheckKEXDetails({ssl_grp_ec_secp256r1, ssl_grp_kem_secp256r1mlkem768}, {ssl_grp_ec_secp256r1, ssl_grp_kem_secp256r1mlkem768}); CheckECDHShareReuse(shares_capture_); } +TEST_P(TlsKeyExchangeTest13, Secp384r1Mlkem1024ShareReuseFirst) { + EnsureKeyShareSetup(); + ConfigNamedGroups({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp384r1}); + EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1)); + + Connect(); + + CheckKEXDetails({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp384r1}, + {ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp384r1}); + CheckECDHShareReuse(shares_capture_); +} + +TEST_P(TlsKeyExchangeTest13, Secp384r1Mlkem1024ShareReuseSecond) { + EnsureKeyShareSetup(); + ConfigNamedGroups({ssl_grp_ec_secp384r1, ssl_grp_kem_secp384r1mlkem1024}); + EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1)); + + Connect(); + + CheckKEXDetails({ssl_grp_ec_secp384r1, ssl_grp_kem_secp384r1mlkem1024}, + {ssl_grp_ec_secp384r1, ssl_grp_kem_secp384r1mlkem1024}); + CheckECDHShareReuse(shares_capture_); +} + class Mlkem768x25519ShareDamager : public TlsExtensionFilter { public: typedef enum { downgrade, extend, truncate, zero_ecdh, modify_ecdh, diff --git a/lib/freebl/Makefile b/lib/freebl/Makefile --- a/lib/freebl/Makefile +++ b/lib/freebl/Makefile @@ -594,17 +594,22 @@ ifndef NSS_DISABLE_CHACHAPOLY EXTRA_SRCS += Hacl_Poly1305_128.c Hacl_Chacha20_Vec128.c Hacl_Chacha20Poly1305_128.c DEFINES += -DHACL_CAN_COMPILE_VEC128 endif endif # x86_64 VERIFIED_SRCS += Hacl_Poly1305_32.c Hacl_Chacha20.c Hacl_Chacha20Poly1305_32.c endif # NSS_DISABLE_CHACHAPOLY +ifndef NSS_DISABLE_KYBER +KYBER_PQCRYSTALS = kyber-pqcrystals-ref.c +endif + VERIFIED_SRCS += Hacl_Hash_SHA3.c Hacl_P256.c Hacl_P384.c Hacl_P521.c libcrux_mlkem768_portable.c libcrux_mlkem_portable.c libcrux_core.c +VERIFIED_SRCS += libcrux_mlkem1024_portable.c VERIFIED_SRCS += Hacl_Ed25519.c VERIFIED_SRCS += Hacl_Curve25519_51.c # Bug 1918767 / Bug 1918711 - by setting KRML_MUSTINLINE=inline here, we # avoid it being defined to `inline __forceinline` (for msvc) or `inline # __attribute__((always_inline))` (for gcc/clang) in # verified/karamel/include/krml/internal/target.h. These other # configurations can cause excessive stack usage. diff --git a/lib/freebl/freebl_base.gypi b/lib/freebl/freebl_base.gypi --- a/lib/freebl/freebl_base.gypi +++ b/lib/freebl/freebl_base.gypi @@ -27,17 +27,16 @@ 'ecl/ecp_secp521r1.c', 'fipsfreebl.c', 'blinit.c', 'freeblver.c', 'gcm.c', 'hmacct.c', 'jpake.c', 'kyber.c', - 'kyber-pqcrystals-ref.c', 'ldvector.c', 'md2.c', 'md5.c', 'mpi/mp_gf2m.c', 'mpi/mpcpucache.c', 'mpi/mpi.c', 'mpi/mplogic.c', 'mpi/mpmontg.c', @@ -228,13 +227,25 @@ 'MP_IS_LITTLE_ENDIAN', 'MPI_AMD64', 'MP_ASSEMBLY_MULTIPLY', 'NSS_USE_COMBA', ], }], ], }], + [ 'no_kyber_support==0', { + 'sources': [ + 'kyber-pqcrystals-ref.c', + ], + }] + [ 'ml_kem_1024_support==1', { + 'sources': [ + 'verified/libcrux_mlkem1024_portable.c', + ], + }] + + ], 'ldflags': [ '-Wl,-Bsymbolic' ], } diff --git a/lib/freebl/kyber.c b/lib/freebl/kyber.c --- a/lib/freebl/kyber.c +++ b/lib/freebl/kyber.c @@ -12,126 +12,168 @@ #include "secerr.h" #include "secitem.h" #include "kyber-pqcrystals-ref.h" #include "kyber.h" #include "verified/internal/libcrux_core.h" #include "verified/libcrux_mlkem768_portable.h" #include "verified/libcrux_mlkem768.h" +#include "verified/libcrux_mlkem1024_portable.h" +#include "verified/libcrux_mlkem1024.h" /* Consistency check between kyber-pqcrystals-ref.h and kyber.h */ PR_STATIC_ASSERT(KYBER768_PUBLIC_KEY_BYTES == pqcrystals_kyber768_PUBLICKEYBYTES); PR_STATIC_ASSERT(KYBER768_PRIVATE_KEY_BYTES == pqcrystals_kyber768_SECRETKEYBYTES); PR_STATIC_ASSERT(KYBER768_CIPHERTEXT_BYTES == pqcrystals_kyber768_CIPHERTEXTBYTES); PR_STATIC_ASSERT(KYBER_SHARED_SECRET_BYTES == pqcrystals_kyber768_BYTES); PR_STATIC_ASSERT(KYBER_KEYPAIR_COIN_BYTES == pqcrystals_kyber768_KEYPAIRCOINBYTES); PR_STATIC_ASSERT(KYBER_ENC_COIN_BYTES == pqcrystals_kyber768_ENCCOINBYTES); /* Consistency check between libcrux_mlkem768_portable.h and kyber.h */ PR_STATIC_ASSERT(KYBER768_PUBLIC_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM768_CPA_PKE_PUBLIC_KEY_SIZE_768); PR_STATIC_ASSERT(KYBER768_PRIVATE_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM768_SECRET_KEY_SIZE_768); PR_STATIC_ASSERT(KYBER768_CIPHERTEXT_BYTES == LIBCRUX_ML_KEM_MLKEM768_CPA_PKE_CIPHERTEXT_SIZE_768); PR_STATIC_ASSERT(KYBER_SHARED_SECRET_BYTES == LIBCRUX_ML_KEM_CONSTANTS_SHARED_SECRET_SIZE); + +/* Consistency check between libcrux_mlkem1024_portable.h and kyber.h */ +PR_STATIC_ASSERT(MLKEM1024_PUBLIC_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_PUBLIC_KEY_SIZE_1024); +PR_STATIC_ASSERT(MLKEM1024_PRIVATE_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM1024_SECRET_KEY_SIZE_1024); +PR_STATIC_ASSERT(MLKEM1024_CIPHERTEXT_BYTES == LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_CIPHERTEXT_SIZE_1024); + PR_STATIC_ASSERT(KYBER_KEYPAIR_COIN_BYTES == 64); PR_STATIC_ASSERT(KYBER_ENC_COIN_BYTES == 32); static bool valid_params(KyberParams params) { switch (params) { +#ifndef NSS_DISABLE_KYBER case params_kyber768_round3: case params_kyber768_round3_test_mode: +#endif case params_ml_kem768: case params_ml_kem768_test_mode: + case params_ml_kem1024: + case params_ml_kem1024_test_mode: return true; default: return false; } } static bool valid_pubkey(KyberParams params, const SECItem *pubkey) { switch (params) { +#ifndef NSS_DISABLE_KYBER case params_kyber768_round3: case params_kyber768_round3_test_mode: +#endif case params_ml_kem768: case params_ml_kem768_test_mode: return pubkey && pubkey->len == KYBER768_PUBLIC_KEY_BYTES; + case params_ml_kem1024: + case params_ml_kem1024_test_mode: + return pubkey && pubkey->len ==MLKEM1024_PUBLIC_KEY_BYTES; default: return false; } } static bool valid_privkey(KyberParams params, const SECItem *privkey) { switch (params) { +#ifndef NSS_DISABLE_KYBER case params_kyber768_round3: case params_kyber768_round3_test_mode: +#endif case params_ml_kem768: case params_ml_kem768_test_mode: return privkey && privkey->len == KYBER768_PRIVATE_KEY_BYTES; + case params_ml_kem1024: + case params_ml_kem1024_test_mode: + return privkey && privkey->len == MLKEM1024_PRIVATE_KEY_BYTES; default: return false; } } static bool valid_ciphertext(KyberParams params, const SECItem *ciphertext) { switch (params) { +#ifndef NSS_DISABLE_KYBER case params_kyber768_round3: case params_kyber768_round3_test_mode: +#endif case params_ml_kem768: case params_ml_kem768_test_mode: return ciphertext && ciphertext->len == KYBER768_CIPHERTEXT_BYTES; + case params_ml_kem1024: + case params_ml_kem1024_test_mode: + return ciphertext && ciphertext->len == MLKEM1024_CIPHERTEXT_BYTES; default: return false; } } static bool valid_secret(KyberParams params, const SECItem *secret) { switch (params) { +#ifndef NSS_DISABLE_KYBER case params_kyber768_round3: case params_kyber768_round3_test_mode: +#endif case params_ml_kem768: case params_ml_kem768_test_mode: + case params_ml_kem1024: + case params_ml_kem1024_test_mode: return secret && secret->len == KYBER_SHARED_SECRET_BYTES; default: return false; } } static bool valid_keypair_seed(KyberParams params, const SECItem *seed) { switch (params) { +#ifndef NSS_DISABLE_KYBER case params_kyber768_round3: case params_kyber768_round3_test_mode: +#endif case params_ml_kem768: case params_ml_kem768_test_mode: + case params_ml_kem1024: + case params_ml_kem1024_test_mode: return !seed || seed->len == KYBER_KEYPAIR_COIN_BYTES; default: return false; } } static bool valid_enc_seed(KyberParams params, const SECItem *seed) { switch (params) { +#ifndef NSS_DISABLE_KYBER case params_kyber768_round3: +#endif case params_ml_kem768: + case params_ml_kem1024: return !seed; +#ifndef NSS_DISABLE_KYBER case params_kyber768_round3_test_mode: +#endif case params_ml_kem768_test_mode: + case params_ml_kem1024_test_mode: + return !seed; return !seed || seed->len == KYBER_SHARED_SECRET_BYTES; default: return false; } } SECStatus Kyber_NewKey(KyberParams params, const SECItem *keypair_seed, SECItem *privkey, SECItem *pubkey) @@ -153,22 +195,28 @@ Kyber_NewKey(KyberParams params, const S } else { if (RNG_GenerateGlobalRandomBytes(randbuf, sizeof randbuf) != SECSuccess) { PORT_SetError(SEC_ERROR_NEED_RANDOM); return SECFailure; } coins = randbuf; } NSS_CLASSIFY(coins, KYBER_KEYPAIR_COIN_BYTES); - if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) { - pqcrystals_kyber768_ref_keypair_derand(pubkey->data, privkey->data, coins); - } else if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) { + if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) { libcrux_ml_kem_mlkem768_MlKem768KeyPair keys = libcrux_ml_kem_mlkem768_portable_generate_key_pair(coins); memcpy(pubkey->data, keys.pk.value, KYBER768_PUBLIC_KEY_BYTES); memcpy(privkey->data, keys.sk.value, KYBER768_PRIVATE_KEY_BYTES); + } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) { + libcrux_ml_kem_mlkem1024_MlKem1024KeyPair keys = libcrux_ml_kem_mlkem1024_portable_generate_key_pair(coins); + memcpy(pubkey->data, keys.pk.value, MLKEM1024_PUBLIC_KEY_BYTES); + memcpy(privkey->data, keys.sk.value, MLKEM1024_PRIVATE_KEY_BYTES); +#ifndef NSS_DISABLE_KYBER + } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) { + pqcrystals_kyber768_ref_keypair_derand(pubkey->data, privkey->data, coins); +#endif } else { /* unreachable */ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } NSS_DECLASSIFY(pubkey->data, pubkey->len); return SECSuccess; } @@ -193,31 +241,48 @@ Kyber_Encapsulate(KyberParams params, co } else { if (RNG_GenerateGlobalRandomBytes(randbuf, sizeof randbuf) != SECSuccess) { PORT_SetError(SEC_ERROR_NEED_RANDOM); return SECFailure; } coins = randbuf; } NSS_CLASSIFY(coins, KYBER_ENC_COIN_BYTES); - if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) { - pqcrystals_kyber768_ref_enc_derand(ciphertext->data, secret->data, pubkey->data, coins); - } else if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) { + if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) { + /* shouldn't this just use the typedef im libcrux_mlkem768.h? */ libcrux_ml_kem_types_MlKemPublicKey_15 pk_value; memcpy(pk_value.value, pubkey->data, KYBER768_PUBLIC_KEY_BYTES); bool valid_pk = libcrux_ml_kem_mlkem768_portable_validate_public_key(&pk_value); if (!valid_pk) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } tuple_3c encap = libcrux_ml_kem_mlkem768_portable_encapsulate(&pk_value, coins); memcpy(ciphertext->data, encap.fst.value, KYBER768_CIPHERTEXT_BYTES); memcpy(secret->data, encap.snd, KYBER_SHARED_SECRET_BYTES); + } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) { + /* shouldn't this just use the typedef im libcrux_mlkem1024.h? */ + libcrux_ml_kem_types_MlKemPublicKey_1f pk_value; + memcpy(pk_value.value, pubkey->data, MLKEM1024_PUBLIC_KEY_BYTES); + + bool valid_pk = libcrux_ml_kem_mlkem1024_portable_validate_public_key(&pk_value); + if (!valid_pk) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + tuple_21 encap = libcrux_ml_kem_mlkem1024_portable_encapsulate(&pk_value, coins); + memcpy(ciphertext->data, encap.fst.value, MLKEM1024_CIPHERTEXT_BYTES); + memcpy(secret->data, encap.snd, KYBER_SHARED_SECRET_BYTES); +#ifndef NSS_DISABLE_KYBER + } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) { + pqcrystals_kyber768_ref_enc_derand(ciphertext->data, secret->data, pubkey->data, coins); +#endif } else { /* unreachable */ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } return SECSuccess; } @@ -230,32 +295,48 @@ Kyber_Decapsulate(KyberParams params, co return SECFailure; } if (!(valid_privkey(params, privkey) && valid_ciphertext(params, ciphertext) && valid_secret(params, secret))) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) { - pqcrystals_kyber768_ref_dec(secret->data, ciphertext->data, privkey->data); - } else if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) { + if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) { libcrux_ml_kem_types_MlKemPrivateKey_55 private_key; memcpy(private_key.value, privkey->data, KYBER768_PRIVATE_KEY_BYTES); libcrux_ml_kem_mlkem768_MlKem768Ciphertext cipher_text; memcpy(cipher_text.value, ciphertext->data, KYBER768_CIPHERTEXT_BYTES); bool valid = libcrux_ml_kem_mlkem768_portable_validate_private_key(&private_key, &cipher_text); if (!valid) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } libcrux_ml_kem_mlkem768_portable_decapsulate(&private_key, &cipher_text, secret->data); + } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) { + libcrux_ml_kem_types_MlKemPrivateKey_95 private_key; + memcpy(private_key.value, privkey->data, MLKEM1024_PRIVATE_KEY_BYTES); + + libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext cipher_text; + memcpy(cipher_text.value, ciphertext->data, MLKEM1024_CIPHERTEXT_BYTES); + + bool valid = libcrux_ml_kem_mlkem1024_portable_validate_private_key(&private_key, &cipher_text); + if (!valid) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + libcrux_ml_kem_mlkem1024_portable_decapsulate(&private_key, &cipher_text, secret->data); +#ifndef NSS_DISABLE_KYBER + } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) { + pqcrystals_kyber768_ref_dec(secret->data, ciphertext->data, privkey->data); +#endif } else { // unreachable PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } return SECSuccess; } diff --git a/lib/freebl/manifest.mn b/lib/freebl/manifest.mn --- a/lib/freebl/manifest.mn +++ b/lib/freebl/manifest.mn @@ -152,17 +152,17 @@ CSRCS = \ rsa.c \ rsa_blind.c \ rsapkcs.c \ shvfy.c \ tlsprfalg.c \ jpake.c \ secmpi.c \ kyber.c \ - kyber-pqcrystals-ref.c \ + $(KYBER_PQCRYSTALS) \ $(MPI_SRCS) \ $(MPCPU_SRCS) \ $(ECL_SRCS) \ $(VERIFIED_SRCS) \ $(STUBS_SRCS) \ $(LOWHASH_SRCS) \ $(EXTRA_SRCS) \ $(NULL) diff --git a/lib/freebl/verified/libcrux_mlkem1024.h b/lib/freebl/verified/libcrux_mlkem1024.h new file mode 100644 --- /dev/null +++ b/lib/freebl/verified/libcrux_mlkem1024.h @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: 2024 Cryspen Sarl + * + * SPDX-License-Identifier: MIT or Apache-2.0 + * + * This code was generated with the following revisions: + * Charon: b351338f6a84c7a1afc27433eb0ffdc668b3581d + * Eurydice: 7efec1624422fd5e94388ef06b9c76dfe7a48d46 + * Karamel: c96fb69d15693284644d6aecaa90afa37e4de8f0 + * F*: 58c915a86a2c07c8eca8d9deafd76cb7a91f0eb7 + * Libcrux: 6ff01fb3c57ff29ecb59bc62d9dc7fd231060cfb + */ + +#ifndef __libcrux_mlkem1024_H +#define __libcrux_mlkem1024_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#include "eurydice_glue.h" +#include "libcrux_core.h" + +#define LIBCRUX_ML_KEM_MLKEM1024_VECTOR_U_COMPRESSION_FACTOR_1024 ((size_t)11U) + +#define LIBCRUX_ML_KEM_MLKEM1024_C1_BLOCK_SIZE_1024 \ + (LIBCRUX_ML_KEM_CONSTANTS_COEFFICIENTS_IN_RING_ELEMENT * \ + LIBCRUX_ML_KEM_MLKEM1024_VECTOR_U_COMPRESSION_FACTOR_1024 / (size_t)8U) + +#define LIBCRUX_ML_KEM_MLKEM1024_RANK_1024 ((size_t)4U) + +#define LIBCRUX_ML_KEM_MLKEM1024_C1_SIZE_1024 \ + (LIBCRUX_ML_KEM_MLKEM1024_C1_BLOCK_SIZE_1024 * \ + LIBCRUX_ML_KEM_MLKEM1024_RANK_1024) + +#define LIBCRUX_ML_KEM_MLKEM1024_VECTOR_V_COMPRESSION_FACTOR_1024 ((size_t)5U) + +#define LIBCRUX_ML_KEM_MLKEM1024_C2_SIZE_1024 \ + (LIBCRUX_ML_KEM_CONSTANTS_COEFFICIENTS_IN_RING_ELEMENT * \ + LIBCRUX_ML_KEM_MLKEM1024_VECTOR_V_COMPRESSION_FACTOR_1024 / (size_t)8U) + +#define LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_CIPHERTEXT_SIZE_1024 \ + (LIBCRUX_ML_KEM_MLKEM1024_C1_SIZE_1024 + \ + LIBCRUX_ML_KEM_MLKEM1024_C2_SIZE_1024) + +#define LIBCRUX_ML_KEM_MLKEM1024_T_AS_NTT_ENCODED_SIZE_1024 \ + (LIBCRUX_ML_KEM_MLKEM1024_RANK_1024 * \ + LIBCRUX_ML_KEM_CONSTANTS_COEFFICIENTS_IN_RING_ELEMENT * \ + LIBCRUX_ML_KEM_CONSTANTS_BITS_PER_COEFFICIENT / (size_t)8U) + +#define LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_PUBLIC_KEY_SIZE_1024 \ + (LIBCRUX_ML_KEM_MLKEM1024_T_AS_NTT_ENCODED_SIZE_1024 + (size_t)32U) + +#define LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_SECRET_KEY_SIZE_1024 \ + (LIBCRUX_ML_KEM_MLKEM1024_RANK_1024 * \ + LIBCRUX_ML_KEM_CONSTANTS_COEFFICIENTS_IN_RING_ELEMENT * \ + LIBCRUX_ML_KEM_CONSTANTS_BITS_PER_COEFFICIENT / (size_t)8U) + +#define LIBCRUX_ML_KEM_MLKEM1024_ETA1 ((size_t)2U) + +#define LIBCRUX_ML_KEM_MLKEM1024_ETA1_RANDOMNESS_SIZE \ + (LIBCRUX_ML_KEM_MLKEM1024_ETA1 * (size_t)64U) + +#define LIBCRUX_ML_KEM_MLKEM1024_ETA2 ((size_t)2U) + +#define LIBCRUX_ML_KEM_MLKEM1024_ETA2_RANDOMNESS_SIZE \ + (LIBCRUX_ML_KEM_MLKEM1024_ETA2 * (size_t)64U) + +#define LIBCRUX_ML_KEM_MLKEM1024_IMPLICIT_REJECTION_HASH_INPUT_SIZE \ + (LIBCRUX_ML_KEM_CONSTANTS_SHARED_SECRET_SIZE + \ + LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_CIPHERTEXT_SIZE_1024) + +typedef libcrux_ml_kem_types_MlKemPrivateKey_95 + libcrux_ml_kem_mlkem1024_MlKem1024PrivateKey; + +typedef libcrux_ml_kem_types_MlKemPublicKey_1f + libcrux_ml_kem_mlkem1024_MlKem1024PublicKey; + +#define LIBCRUX_ML_KEM_MLKEM1024_RANKED_BYTES_PER_RING_ELEMENT_1024 \ + (LIBCRUX_ML_KEM_MLKEM1024_RANK_1024 * \ + LIBCRUX_ML_KEM_CONSTANTS_BITS_PER_RING_ELEMENT / (size_t)8U) + +#define LIBCRUX_ML_KEM_MLKEM1024_SECRET_KEY_SIZE_1024 \ + (LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_SECRET_KEY_SIZE_1024 + \ + LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_PUBLIC_KEY_SIZE_1024 + \ + LIBCRUX_ML_KEM_CONSTANTS_H_DIGEST_SIZE + \ + LIBCRUX_ML_KEM_CONSTANTS_SHARED_SECRET_SIZE) + +#if defined(__cplusplus) +} +#endif + +#define __libcrux_mlkem1024_H_DEFINED +#endif diff --git a/lib/freebl/verified/libcrux_mlkem1024_portable.c b/lib/freebl/verified/libcrux_mlkem1024_portable.c new file mode 100644 --- /dev/null +++ b/lib/freebl/verified/libcrux_mlkem1024_portable.c @@ -0,0 +1,192 @@ +/* + * SPDX-FileCopyrightText: 2024 Cryspen Sarl + * + * SPDX-License-Identifier: MIT or Apache-2.0 + * + * This code was generated with the following revisions: + * Charon: b351338f6a84c7a1afc27433eb0ffdc668b3581d + * Eurydice: 7efec1624422fd5e94388ef06b9c76dfe7a48d46 + * Karamel: c96fb69d15693284644d6aecaa90afa37e4de8f0 + * F*: 58c915a86a2c07c8eca8d9deafd76cb7a91f0eb7 + * Libcrux: 6ff01fb3c57ff29ecb59bc62d9dc7fd231060cfb + */ + +#include "libcrux_mlkem1024_portable.h" + +#include "internal/libcrux_mlkem_portable.h" + +/** + Portable decapsulate +*/ +/** +A monomorphic instance of +libcrux_ml_kem.ind_cca.instantiations.portable.decapsulate with const generics +- K= 4 +- SECRET_KEY_SIZE= 3168 +- CPA_SECRET_KEY_SIZE= 1536 +- PUBLIC_KEY_SIZE= 1568 +- CIPHERTEXT_SIZE= 1568 +- T_AS_NTT_ENCODED_SIZE= 1536 +- C1_SIZE= 1408 +- C2_SIZE= 160 +- VECTOR_U_COMPRESSION_FACTOR= 11 +- VECTOR_V_COMPRESSION_FACTOR= 5 +- C1_BLOCK_SIZE= 352 +- ETA1= 2 +- ETA1_RANDOMNESS_SIZE= 128 +- ETA2= 2 +- ETA2_RANDOMNESS_SIZE= 128 +- IMPLICIT_REJECTION_HASH_INPUT_SIZE= 1600 +*/ +static void decapsulate_671( + libcrux_ml_kem_types_MlKemPrivateKey_95 *private_key, + libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext *ciphertext, + uint8_t ret[32U]) { + libcrux_ml_kem_ind_cca_decapsulate_1f1(private_key, ciphertext, ret); +} + +/** + Decapsulate ML-KEM 1024 + + Generates an [`MlKemSharedSecret`]. + The input is a reference to an [`MlKem1024PrivateKey`] and an + [`MlKem1024Ciphertext`]. +*/ +void libcrux_ml_kem_mlkem1024_portable_decapsulate( + libcrux_ml_kem_types_MlKemPrivateKey_95 *private_key, + libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext *ciphertext, + uint8_t ret[32U]) { + decapsulate_671(private_key, ciphertext, ret); +} + +/** +A monomorphic instance of +libcrux_ml_kem.ind_cca.instantiations.portable.encapsulate with const generics +- K= 4 +- CIPHERTEXT_SIZE= 1568 +- PUBLIC_KEY_SIZE= 1568 +- T_AS_NTT_ENCODED_SIZE= 1536 +- C1_SIZE= 1408 +- C2_SIZE= 160 +- VECTOR_U_COMPRESSION_FACTOR= 11 +- VECTOR_V_COMPRESSION_FACTOR= 5 +- VECTOR_U_BLOCK_LEN= 352 +- ETA1= 2 +- ETA1_RANDOMNESS_SIZE= 128 +- ETA2= 2 +- ETA2_RANDOMNESS_SIZE= 128 +*/ +static tuple_21 encapsulate_021( + libcrux_ml_kem_types_MlKemPublicKey_1f *public_key, + uint8_t randomness[32U]) { + libcrux_ml_kem_types_MlKemPublicKey_1f *uu____0 = public_key; + /* Passing arrays by value in Rust generates a copy in C */ + uint8_t copy_of_randomness[32U]; + memcpy(copy_of_randomness, randomness, (size_t)32U * sizeof(uint8_t)); + return libcrux_ml_kem_ind_cca_encapsulate_eb1(uu____0, copy_of_randomness); +} + +/** + Encapsulate ML-KEM 1024 + + Generates an ([`MlKem1024Ciphertext`], [`MlKemSharedSecret`]) tuple. + The input is a reference to an [`MlKem1024PublicKey`] and + [`SHARED_SECRET_SIZE`] bytes of `randomness`. +*/ +tuple_21 libcrux_ml_kem_mlkem1024_portable_encapsulate( + libcrux_ml_kem_types_MlKemPublicKey_1f *public_key, + uint8_t randomness[32U]) { + libcrux_ml_kem_types_MlKemPublicKey_1f *uu____0 = public_key; + /* Passing arrays by value in Rust generates a copy in C */ + uint8_t copy_of_randomness[32U]; + memcpy(copy_of_randomness, randomness, (size_t)32U * sizeof(uint8_t)); + return encapsulate_021(uu____0, copy_of_randomness); +} + +/** + Portable generate key pair. +*/ +/** +A monomorphic instance of +libcrux_ml_kem.ind_cca.instantiations.portable.generate_keypair with const +generics +- K= 4 +- CPA_PRIVATE_KEY_SIZE= 1536 +- PRIVATE_KEY_SIZE= 3168 +- PUBLIC_KEY_SIZE= 1568 +- BYTES_PER_RING_ELEMENT= 1536 +- ETA1= 2 +- ETA1_RANDOMNESS_SIZE= 128 +*/ +static libcrux_ml_kem_mlkem1024_MlKem1024KeyPair generate_keypair_871( + uint8_t randomness[64U]) { + /* Passing arrays by value in Rust generates a copy in C */ + uint8_t copy_of_randomness[64U]; + memcpy(copy_of_randomness, randomness, (size_t)64U * sizeof(uint8_t)); + return libcrux_ml_kem_ind_cca_generate_keypair_f61(copy_of_randomness); +} + +/** + Generate ML-KEM 1024 Key Pair +*/ +libcrux_ml_kem_mlkem1024_MlKem1024KeyPair +libcrux_ml_kem_mlkem1024_portable_generate_key_pair(uint8_t randomness[64U]) { + /* Passing arrays by value in Rust generates a copy in C */ + uint8_t copy_of_randomness[64U]; + memcpy(copy_of_randomness, randomness, (size_t)64U * sizeof(uint8_t)); + return generate_keypair_871(copy_of_randomness); +} + +/** + Portable private key validation +*/ +/** +A monomorphic instance of +libcrux_ml_kem.ind_cca.instantiations.portable.validate_private_key with const +generics +- K= 4 +- SECRET_KEY_SIZE= 3168 +- CIPHERTEXT_SIZE= 1568 +*/ +static KRML_MUSTINLINE bool validate_private_key_e81( + libcrux_ml_kem_types_MlKemPrivateKey_95 *private_key, + libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext *ciphertext) { + return libcrux_ml_kem_ind_cca_validate_private_key_dc(private_key, + ciphertext); +} + +/** + Validate a private key. + + Returns `true` if valid, and `false` otherwise. +*/ +bool libcrux_ml_kem_mlkem1024_portable_validate_private_key( + libcrux_ml_kem_types_MlKemPrivateKey_95 *private_key, + libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext *ciphertext) { + return validate_private_key_e81(private_key, ciphertext); +} + +/** + Portable public key validation +*/ +/** +A monomorphic instance of +libcrux_ml_kem.ind_cca.instantiations.portable.validate_public_key with const +generics +- K= 4 +- RANKED_BYTES_PER_RING_ELEMENT= 1536 +- PUBLIC_KEY_SIZE= 1568 +*/ +static KRML_MUSTINLINE bool validate_public_key_7d1(uint8_t *public_key) { + return libcrux_ml_kem_ind_cca_validate_public_key_b71(public_key); +} + +/** + Validate a public key. + + Returns `true` if valid, and `false` otherwise. +*/ +bool libcrux_ml_kem_mlkem1024_portable_validate_public_key( + libcrux_ml_kem_types_MlKemPublicKey_1f *public_key) { + return validate_public_key_7d1(public_key->value); +} diff --git a/lib/freebl/verified/libcrux_mlkem1024_portable.h b/lib/freebl/verified/libcrux_mlkem1024_portable.h new file mode 100644 --- /dev/null +++ b/lib/freebl/verified/libcrux_mlkem1024_portable.h @@ -0,0 +1,74 @@ +/* + * SPDX-FileCopyrightText: 2024 Cryspen Sarl + * + * SPDX-License-Identifier: MIT or Apache-2.0 + * + * This code was generated with the following revisions: + * Charon: b351338f6a84c7a1afc27433eb0ffdc668b3581d + * Eurydice: 7efec1624422fd5e94388ef06b9c76dfe7a48d46 + * Karamel: c96fb69d15693284644d6aecaa90afa37e4de8f0 + * F*: 58c915a86a2c07c8eca8d9deafd76cb7a91f0eb7 + * Libcrux: 6ff01fb3c57ff29ecb59bc62d9dc7fd231060cfb + */ + +#ifndef __libcrux_mlkem1024_portable_H +#define __libcrux_mlkem1024_portable_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#include "eurydice_glue.h" +#include "libcrux_core.h" + +/** + Decapsulate ML-KEM 1024 + + Generates an [`MlKemSharedSecret`]. + The input is a reference to an [`MlKem1024PrivateKey`] and an + [`MlKem1024Ciphertext`]. +*/ +void libcrux_ml_kem_mlkem1024_portable_decapsulate( + libcrux_ml_kem_types_MlKemPrivateKey_95 *private_key, + libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext *ciphertext, uint8_t ret[32U]); + +/** + Encapsulate ML-KEM 1024 + + Generates an ([`MlKem1024Ciphertext`], [`MlKemSharedSecret`]) tuple. + The input is a reference to an [`MlKem1024PublicKey`] and + [`SHARED_SECRET_SIZE`] bytes of `randomness`. +*/ +tuple_21 libcrux_ml_kem_mlkem1024_portable_encapsulate( + libcrux_ml_kem_types_MlKemPublicKey_1f *public_key, + uint8_t randomness[32U]); + +/** + Generate ML-KEM 1024 Key Pair +*/ +libcrux_ml_kem_mlkem1024_MlKem1024KeyPair +libcrux_ml_kem_mlkem1024_portable_generate_key_pair(uint8_t randomness[64U]); + +/** + Validate a private key. + + Returns `true` if valid, and `false` otherwise. +*/ +bool libcrux_ml_kem_mlkem1024_portable_validate_private_key( + libcrux_ml_kem_types_MlKemPrivateKey_95 *private_key, + libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext *ciphertext); + +/** + Validate a public key. + + Returns `true` if valid, and `false` otherwise. +*/ +bool libcrux_ml_kem_mlkem1024_portable_validate_public_key( + libcrux_ml_kem_types_MlKemPublicKey_1f *public_key); + +#if defined(__cplusplus) +} +#endif + +#define __libcrux_mlkem1024_portable_H_DEFINED +#endif diff --git a/lib/pk11wrap/pk11akey.c b/lib/pk11wrap/pk11akey.c --- a/lib/pk11wrap/pk11akey.c +++ b/lib/pk11wrap/pk11akey.c @@ -259,16 +259,21 @@ PK11_ImportPublicKey(PK11SlotInfo *slot, kemParams = CKP_NSS_KYBER_768_ROUND3; break; #endif case params_ml_kem768: case params_ml_kem768_test_mode: keyType = CKK_ML_KEM; kemParams = CKP_ML_KEM_768; break; + case params_ml_kem1024: + case params_ml_kem1024_test_mode: + keyType = CKK_ML_KEM; + kemParams = CKP_ML_KEM_1024; + break; default: kemParams = CKP_INVALID_ID; break; } /*fprintf(stderr, "PK11_ImportPublic KEY_TYPE=0x%08lx, kem_params=0x%08lxd\n", keyType, kemParams); */ PK11_SETATTRS(attrs, CKA_PARAMETER_SET, @@ -908,16 +913,19 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot case CKP_NSS_KYBER_768_ROUND3: pubKey->u.kyber.params = params_kyber768_round3; break; #endif case CKP_NSS_ML_KEM_768: case CKP_ML_KEM_768: pubKey->u.kyber.params = params_ml_kem768; break; + case CKP_ML_KEM_1024: + pubKey->u.kyber.params = params_ml_kem1024; + break; default: pubKey->u.kyber.params = params_kyber_invalid; break; } crv = pk11_Attr2SecItem(arena, value, &pubKey->u.kyber.publicValue); break; case fortezzaKey: case nullKey: diff --git a/lib/pk11wrap/pk11pars.c b/lib/pk11wrap/pk11pars.c --- a/lib/pk11wrap/pk11pars.c +++ b/lib/pk11wrap/pk11pars.c @@ -244,17 +244,32 @@ static const oidValDef curveOptList[] = { CIPHER_NAME("SECP521R1"), SEC_OID_SECG_EC_SECP521R1, NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE }, { CIPHER_NAME("CURVE25519"), SEC_OID_CURVE25519, NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE }, { CIPHER_NAME("XYBER768D00"), SEC_OID_XYBER768D00, NSS_USE_ALG_IN_SSL_KX }, { CIPHER_NAME("MLKEM768X25519"), SEC_OID_MLKEM768X25519, NSS_USE_ALG_IN_SSL_KX }, - { CIPHER_NAME("MLKEM768SECP256R1"), SEC_OID_SECP256R1MLKEM768, + { CIPHER_NAME("SECP256R1MLKEM768"), SEC_OID_SECP256R1MLKEM768, + NSS_USE_ALG_IN_SSL_KX }, + { CIPHER_NAME("MLKEM1024SECP384R1"), SEC_OID_SECP384R1MLKEM1024, + NSS_USE_ALG_IN_SSL_KX }, + { CIPHER_NAME("X25519MLKEM768"), SEC_OID_MLKEM768X25519, + NSS_USE_ALG_IN_SSL_KX }, + { CIPHER_NAME("SECP256R1MLKEM768"), SEC_OID_SECP256R1MLKEM768, + NSS_USE_ALG_IN_SSL_KX }, + { CIPHER_NAME("SECP384R1MLKEM1024"), SEC_OID_SECP384R1MLKEM1024, + NSS_USE_ALG_IN_SSL_KX }, + /* aliases for old names */ + { CIPHER_NAME("MLKEM768X25519"), SEC_OID_MLKEM768X25519, + NSS_USE_ALG_IN_SSL_KX }, + { CIPHER_NAME("SECP256R1MLKEM768"), SEC_OID_SECP256R1MLKEM768, + NSS_USE_ALG_IN_SSL_KX }, + { CIPHER_NAME("MLKEM1024SECP384R1"), SEC_OID_SECP384R1MLKEM1024, NSS_USE_ALG_IN_SSL_KX }, /* ANSI X9.62 named elliptic curves (characteristic two field) */ { CIPHER_NAME("C2PNB163V1"), SEC_OID_ANSIX962_EC_C2PNB163V1, NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE }, { CIPHER_NAME("C2PNB163V2"), SEC_OID_ANSIX962_EC_C2PNB163V2, NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE }, { CIPHER_NAME("C2PNB163V3"), SEC_OID_ANSIX962_EC_C2PNB163V3, NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE }, diff --git a/lib/pk11wrap/pk11skey.c b/lib/pk11wrap/pk11skey.c --- a/lib/pk11wrap/pk11skey.c +++ b/lib/pk11wrap/pk11skey.c @@ -3083,16 +3083,19 @@ static CK_ULONG pk11_KyberCiphertextLength(SECKEYKyberPublicKey *pubKey) { switch (pubKey->params) { case params_kyber768_round3: case params_kyber768_round3_test_mode: case params_ml_kem768: case params_ml_kem768_test_mode: return KYBER768_CIPHERTEXT_BYTES; + case params_ml_kem1024: + case params_ml_kem1024_test_mode: + return MLKEM1024_CIPHERTEXT_BYTES; default: // unreachable return 0; } } static CK_ULONG pk11_KEMCiphertextLength(SECKEYPublicKey *pubKey) diff --git a/lib/pk11wrap/secmodti.h b/lib/pk11wrap/secmodti.h --- a/lib/pk11wrap/secmodti.h +++ b/lib/pk11wrap/secmodti.h @@ -201,12 +201,13 @@ struct PK11GenericObjectStr { /* This mask includes all CK_FLAGs with an equivalent CKA_ attribute. */ #define CKF_KEY_OPERATION_FLAGS 0x000e7b00UL /* * private header file, so we can set real names for oids that aren't upstream * yet, so we applications don't try to use them and get hosed when they change */ -#define SEC_OID_SECP256R1MLKEM768 SEC_OID_PRIVATE_1 -#define SEC_OID_MLKEM1024SECP256R1 SEC_OID_PRIVATE_2 +#define SEC_OID_X25519MLKEM768 SEC_OID_MLKEM768X25519 +#define SEC_OID_SECP256R1MLKEM768 SEC_OID_PRIVATE_1 +#define SEC_OID_SECP384R1MLKEM1024 SEC_OID_PRIVATE_2 #endif /* _SECMODTI_H_ */ diff --git a/lib/softoken/kem.c b/lib/softoken/kem.c --- a/lib/softoken/kem.c +++ b/lib/softoken/kem.c @@ -7,77 +7,90 @@ #include "pkcs11i.h" #include "pkcs11n.h" #include "secerr.h" #include "secitem.h" #include "secport.h" #include "softoken.h" /* change to the largest KEM Secret Bytes value supported */ -#define MAX_SHARED_SECRET_BYTES KYBER_SHARED_SECRET_BYTES +/* currenly only mlkem is supported */ +#define MAX_KEM_SHARED_SECRET_BYTES KYBER_SHARED_SECRET_BYTES KyberParams sftk_kyber_PK11ParamToInternal(CK_ML_KEM_PARAMETER_SET_TYPE pk11ParamSet) { switch (pk11ParamSet) { #ifndef NSS_DISABLE_KYBER case CKP_NSS_KYBER_768_ROUND3: return params_kyber768_round3; #endif case CKP_NSS_ML_KEM_768: case CKP_ML_KEM_768: return params_ml_kem768; + case CKP_ML_KEM_1024: + return params_ml_kem1024; default: return params_kyber_invalid; } } SECItem * sftk_kyber_AllocPubKeyItem(KyberParams params, SECItem *pubkey) { switch (params) { #ifndef NSS_DISABLE_KYBER case params_kyber768_round3: case params_kyber768_round3_test_mode: #endif case params_ml_kem768: case params_ml_kem768_test_mode: return SECITEM_AllocItem(NULL, pubkey, KYBER768_PUBLIC_KEY_BYTES); + case params_ml_kem1024: + case params_ml_kem1024_test_mode: + return SECITEM_AllocItem(NULL, pubkey, MLKEM1024_PUBLIC_KEY_BYTES); default: return NULL; } } SECItem * sftk_kyber_AllocPrivKeyItem(KyberParams params, SECItem *privkey) { switch (params) { #ifndef NSS_DISABLE_KYBER case params_kyber768_round3: case params_kyber768_round3_test_mode: #endif case params_ml_kem768: case params_ml_kem768_test_mode: return SECITEM_AllocItem(NULL, privkey, KYBER768_PRIVATE_KEY_BYTES); + case params_ml_kem1024: + case params_ml_kem1024_test_mode: + return SECITEM_AllocItem(NULL, privkey, MLKEM1024_PRIVATE_KEY_BYTES); default: return NULL; } } SECItem * sftk_kyber_AllocCiphertextItem(KyberParams params, SECItem *ciphertext) { switch (params) { #ifndef NSS_DISABLE_KYBER case params_kyber768_round3: case params_kyber768_round3_test_mode: #endif case params_ml_kem768: case params_ml_kem768_test_mode: return SECITEM_AllocItem(NULL, ciphertext, KYBER768_CIPHERTEXT_BYTES); + case params_ml_kem1024: + case params_ml_kem1024_test_mode: + return SECITEM_AllocItem(NULL, ciphertext, MLKEM1024_CIPHERTEXT_BYTES); + default: return NULL; } } static PRBool sftk_kem_ValidateMechanism(CK_MECHANISM_PTR pMechanism) { @@ -147,16 +160,18 @@ sftk_kem_CiphertextLen(CK_MECHANISM_PTR case CKM_ML_KEM: switch (paramSet) { #ifndef NSS_DISABLE_KYBER case CKP_NSS_KYBER_768_ROUND3: #endif case CKP_NSS_ML_KEM_768: case CKP_ML_KEM_768: return KYBER768_CIPHERTEXT_BYTES; + case CKP_ML_KEM_1024: + return MLKEM1024_CIPHERTEXT_BYTES; default: break; } default: break; } return 0; } @@ -245,17 +260,17 @@ NSC_EncapsulateKey(CK_SESSION_HANDLE hSe goto cleanup; } SECItem ciphertext = { siBuffer, pCiphertext, ciphertextLen }; SECItem pubKey = { siBuffer, encapsulationKey->attrib.pValue, encapsulationKey->attrib.ulValueLen }; /* The length of secretBuf can be increased if we ever support other KEMs * by changing the define at the top of this file */ - uint8_t secretBuf[MAX_SHARED_SECRET_BYTES] = { 0 }; + uint8_t secretBuf[MAX_KEM_SHARED_SECRET_BYTES] = { 0 }; SECItem secret = { siBuffer, secretBuf, sizeof secretBuf }; key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_ENCAPSULATE, key, 0); key->source = SFTK_SOURCE_KEA; switch (pMechanism->mechanism) { #ifndef NSS_DISABLE_KYBER case CKM_NSS_KYBER: @@ -394,17 +409,17 @@ NSC_DecapsulateKey(CK_SESSION_HANDLE hSe } SECItem privKey = { siBuffer, decapsulationKey->attrib.pValue, decapsulationKey->attrib.ulValueLen }; SECItem ciphertext = { siBuffer, pCiphertext, ulCiphertextLen }; /* The length of secretBuf can be increased if we ever support other KEMs * by changing the define at the top of this file */ - uint8_t secretBuf[MAX_SHARED_SECRET_BYTES] = { 0 }; + uint8_t secretBuf[MAX_KEM_SHARED_SECRET_BYTES] = { 0 }; SECItem secret = { siBuffer, secretBuf, sizeof secretBuf }; key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_DECAPSULATE, key, 0); key->source = SFTK_SOURCE_KEA; switch (pMechanism->mechanism) { #ifndef NSS_DISABLE_KYBER case CKM_NSS_KYBER: diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c --- a/lib/softoken/pkcs11c.c +++ b/lib/softoken/pkcs11c.c @@ -5532,17 +5532,17 @@ sftk_PairwiseConsistencyCheck(CK_SESSION CK_KEY_TYPE genType = CKO_SECRET_KEY; CK_ATTRIBUTE template = { CKA_KEY_TYPE, NULL, 0 }; template.pValue = &genType; template.ulValueLen = sizeof(genType); crv = CKR_OK; switch (keyType) { case CKK_ML_KEM: - cipher_text_length = KYBER_SHARED_SECRET_BYTES; + cipher_text_length = MAX_ML_KEM_CIPHER_LENGTH; mech.mechanism = CKM_ML_KEM; break; case CKK_RSA: if (!isEncryptable) { /* already handled the pairwise test, no need to * do it again */ goto kem_done; } diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h --- a/lib/ssl/sslimpl.h +++ b/lib/ssl/sslimpl.h @@ -128,19 +128,19 @@ typedef enum { SSLAppOpRead = 0, #define DTLS_RETRANSMIT_MAX_MS 10000 /* Time to wait in FINISHED state for retransmissions. */ #define DTLS_RETRANSMIT_FINISHED_MS 30000 /* default number of entries in namedGroupPreferences */ #ifndef NSS_DISABLE_KYBER /* this define is checked against the namedGroup table * and compile time asserts kick in if it doesn't match */ -#define SSL_NAMED_GROUP_COUNT 34 +#define SSL_NAMED_GROUP_COUNT 35 #else -#define SSL_NAMED_GROUP_COUNT 33 +#define SSL_NAMED_GROUP_COUNT 34 #endif /* The maximum DH and RSA bit-length supported. */ #define SSL_MAX_DH_KEY_BITS 8192 #define SSL_MAX_RSA_KEY_BITS 8192 /* Types and names of elliptic curves used in TLS */ typedef enum { diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c --- a/lib/ssl/sslsock.c +++ b/lib/ssl/sslsock.c @@ -156,25 +156,26 @@ static const PRUint16 srtpCiphers[] = { } #define FFGROUP(size) \ { \ ssl_grp_ffdhe_##size, size, ssl_kea_dh, \ SEC_OID_TLS_FFDHE_##size, PR_TRUE \ } #define HYGROUP(kem, ec, size, kem_oid, ec_oid, assumeSupported) \ { \ - ssl_grp_kem_##kem##ec, size, ssl_kea_ecdh_hybrid, \ - SEC_OID_##kem_oid##ec_oid, assumeSupported \ + ssl_grp_kem_##ec##kem, size, ssl_kea_ecdh_hybrid, \ + SEC_OID_##ec_oid##kem_oid, assumeSupported \ } const sslNamedGroupDef ssl_named_groups[] = { /* Note that 256 for 25519 and hybrid is a lie, but we only use it for * checking bit security and expect 256 bits there (not 255). */ HYGROUP(mlkem768, x25519, 256, MLKEM768, X25519, PR_TRUE), HYGROUP(mlkem768, secp256r1, 256, MLKEM768, SECP256R1, PR_TRUE), + HYGROUP(mlkem1024, secp384r1, 384, MLKEM1024, SECP384R1, PR_TRUE), { ssl_grp_ec_curve25519, 256, ssl_kea_ecdh, SEC_OID_CURVE25519, PR_TRUE }, ECGROUP(secp256r1, 256, SECP256R1, PR_TRUE), ECGROUP(secp384r1, 384, SECP384R1, PR_TRUE), ECGROUP(secp521r1, 521, SECP521R1, PR_TRUE), #ifndef NSS_DISABLE_KYBER { ssl_grp_kem_xyber768d00, 256, ssl_kea_ecdh_hybrid, SEC_OID_XYBER768D00, PR_TRUE }, #endif FFGROUP(2048), @@ -204,16 +205,17 @@ const sslNamedGroupDef ssl_named_groups[ ECGROUP(sect409r1, 409, SECT409R1, PR_FALSE), ECGROUP(sect571k1, 571, SECT571K1, PR_FALSE), ECGROUP(sect571r1, 571, SECT571R1, PR_FALSE), }; PR_STATIC_ASSERT(SSL_NAMED_GROUP_COUNT == PR_ARRAY_SIZE(ssl_named_groups)); #undef ECGROUP #undef FFGROUP +#undef HYGROUP /* forward declarations. */ static sslSocket *ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant variant); static SECStatus ssl_MakeLocks(sslSocket *ss); static PRStatus ssl_SetDefaultsFromEnvironmentCallOnce(void); static void ssl_SetDefaultsFromEnvironment(void); static PRStatus ssl_PushIOLayer(sslSocket *ns, PRFileDesc *stack, PRDescIdentity id); diff --git a/lib/ssl/sslt.h b/lib/ssl/sslt.h --- a/lib/ssl/sslt.h +++ b/lib/ssl/sslt.h @@ -255,25 +255,29 @@ typedef enum { ssl_grp_ec_secp384r1 = 24, ssl_grp_ec_secp521r1 = 25, ssl_grp_ec_curve25519 = 29, /* RFC4492 */ ssl_grp_ffdhe_2048 = 256, /* RFC7919 */ ssl_grp_ffdhe_3072 = 257, ssl_grp_ffdhe_4096 = 258, ssl_grp_ffdhe_6144 = 259, ssl_grp_ffdhe_8192 = 260, - ssl_grp_kem_mlkem768x25519 = 4588, - ssl_grp_kem_secp256r1mlkem768 = 4587, + ssl_grp_kem_x25519mlkem768 = 4588, + ssl_grp_kem_secp256r1mlkem768 = 4587, + ssl_grp_kem_secp384r1mlkem1024 = 4589, #ifndef NSS_DISABLE_KYBER ssl_grp_kem_xyber768d00 = 25497, /* draft-tls-westerbaan-xyber768d00-02 */ #endif ssl_grp_none = 65537, /* special value */ ssl_grp_ffdhe_custom = 65538 /* special value */ } SSLNamedGroup; +/* alias old names */ +#define ssl_grp_kem_mlkem768x25519 ssl_grp_kem_x25519mlkem768 +#define ssl_grp_kem_mlkem768secp256r1 ssl_grp_kem_secp256r1mlkem768 typedef struct SSLExtraServerCertDataStr { /* When this struct is passed to SSL_ConfigServerCert, and authType is set * to a value other than ssl_auth_null, this limits the use of the key to * the type defined; otherwise, the certificate is configured for all * compatible types. */ SSLAuthType authType; /* The remainder of the certificate chain. */ const CERTCertificateList* certChain; diff --git a/lib/ssl/tls13con.c b/lib/ssl/tls13con.c --- a/lib/ssl/tls13con.c +++ b/lib/ssl/tls13con.c @@ -385,19 +385,23 @@ tls13_CreateKEMKeyPair(sslSocket *ss, co #ifndef NSS_DISABLE_KYBER case ssl_grp_kem_xyber768d00: mechanism = CKM_NSS_KYBER_KEY_PAIR_GEN; paramSet = CKP_NSS_KYBER_768_ROUND3; break; #endif case ssl_grp_kem_mlkem768x25519: case ssl_grp_kem_secp256r1mlkem768: - mechanism = CKM_NSS_ML_KEM_KEY_PAIR_GEN; + mechanism = CKM_ML_KEM_KEY_PAIR_GEN; paramSet = CKP_ML_KEM_768; break; + case ssl_grp_kem_secp384r1mlkem1024: + mechanism = CKM_ML_KEM_KEY_PAIR_GEN; + paramSet = CKP_ML_KEM_1024; + break; default: PORT_Assert(0); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } PK11SlotInfo *slot = PK11_GetBestSlot(mechanism, ss->pkcs11PinArg); if (!slot) { @@ -494,16 +498,20 @@ tls13_FindHybridKeyPair(sslSocket *ss, c { sslEphemeralKeyPair *hybridPair = NULL; switch (groupDef->name) { case ssl_grp_ec_secp256r1: /* future, this may be a loop to check multiple named groups */ hybridPair = ssl_LookupEphemeralKeyPair(ss, ssl_LookupNamedGroup(ssl_grp_kem_secp256r1mlkem768)); break; + case ssl_grp_ec_secp384r1: + hybridPair = ssl_LookupEphemeralKeyPair(ss, + ssl_LookupNamedGroup(ssl_grp_kem_secp384r1mlkem1024)); + break; case ssl_grp_ec_curve25519: #ifndef NSS_DISABLE_KYBER /* a loop to check multiple named groups */ SSLNamedGroup gnames[] = { ssl_grp_kem_xyber768d00, ssl_grp_kem_mlkem768x25519 }; for (int i=0; i < PR_ARRAY_SIZE(gnames); i++) { hybridPair = ssl_LookupEphemeralKeyPair(ss, ssl_LookupNamedGroup(gnames[i])); @@ -563,16 +571,19 @@ tls13_CreateKeyShare(sslSocket *ss, cons PORT_Assert(groupDef); switch (groupDef->keaType) { case ssl_kea_ecdh_hybrid: switch (groupDef->name) { case ssl_grp_kem_secp256r1mlkem768: dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp256r1); break; + case ssl_grp_kem_secp384r1mlkem1024: + dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp384r1); + break; #ifndef NSS_DISABLE_KYBER case ssl_grp_kem_xyber768d00: #endif case ssl_grp_kem_mlkem768x25519: dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_curve25519); break; default: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -832,16 +843,19 @@ tls13_ImportKEMKeyShare(SECKEYPublicKey break; #endif case ssl_grp_kem_mlkem768x25519: expected_len = X25519_PUBLIC_KEY_BYTES + KYBER768_PUBLIC_KEY_BYTES; break; case ssl_grp_kem_secp256r1mlkem768: expected_len = SECP256_PUBLIC_KEY_BYTES + KYBER768_PUBLIC_KEY_BYTES; break; + case ssl_grp_kem_secp384r1mlkem1024: + expected_len = SECP384_PUBLIC_KEY_BYTES + MLKEM1024_PUBLIC_KEY_BYTES; + break; default: PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); return SECFailure; } if (entry->key_exchange.len != expected_len) { PORT_SetError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE); return SECFailure; @@ -866,16 +880,23 @@ tls13_ImportKEMKeyShare(SECKEYPublicKey break; case ssl_grp_kem_secp256r1mlkem768: peerKey->keyType = kyberKey; peerKey->u.kyber.params = params_ml_kem768; /* key_exchange.data is `secp256 || mlkem768` */ pk.data = entry->key_exchange.data + SECP256_PUBLIC_KEY_BYTES; pk.len = KYBER768_PUBLIC_KEY_BYTES; break; + case ssl_grp_kem_secp384r1mlkem1024: + peerKey->keyType = kyberKey; + peerKey->u.kyber.params = params_ml_kem1024; + /* key_exchange.data is `secp384 || mlkem1024` */ + pk.data = entry->key_exchange.data + SECP384_PUBLIC_KEY_BYTES; + pk.len = MLKEM1024_PUBLIC_KEY_BYTES; + break; default: PORT_Assert(0); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } rv = SECITEM_CopyItem(peerKey->arena, &peerKey->u.kyber.publicValue, &pk); if (rv != SECSuccess) { @@ -914,16 +935,24 @@ tls13_HandleKEMCiphertext(sslSocket *ss, case ssl_grp_kem_secp256r1mlkem768: if (entry->key_exchange.len != SECP256_PUBLIC_KEY_BYTES + KYBER768_CIPHERTEXT_BYTES) { ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE); return SECFailure; } ct.data = entry->key_exchange.data + SECP256_PUBLIC_KEY_BYTES; ct.len = KYBER768_CIPHERTEXT_BYTES; break; + case ssl_grp_kem_secp384r1mlkem1024: + if (entry->key_exchange.len != SECP384_PUBLIC_KEY_BYTES + MLKEM1024_CIPHERTEXT_BYTES) { + ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE); + return SECFailure; + } + ct.data = entry->key_exchange.data + SECP384_PUBLIC_KEY_BYTES; + ct.len = MLKEM1024_CIPHERTEXT_BYTES; + break; default: PORT_Assert(0); ssl_MapLowLevelError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } rv = PK11_Decapsulate(keyPair->privKey, &ct, CKM_HKDF_DERIVE, PK11_ATTR_SESSION, CKF_DERIVE, outKey); @@ -1039,16 +1068,24 @@ tls13_HandleKeyShare(sslSocket *ss, case ssl_grp_kem_secp256r1mlkem768: dhLen = SECP256_PUBLIC_KEY_BYTES; /* secp256 share is at the beginning */ ec_data = entry->key_exchange.len < dhLen ? NULL : entry->key_exchange.data; dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp256r1); break; + case ssl_grp_kem_secp384r1mlkem1024: + dhLen = SECP384_PUBLIC_KEY_BYTES; + /* secp256 share is at the beginning */ + ec_data = entry->key_exchange.len < dhLen + ? NULL + : entry->key_exchange.data; + dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp384r1); + break; default: ec_data = NULL; break; } if (!ec_data) { PORT_SetError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE); goto loser; } @@ -2927,16 +2964,17 @@ tls13_HandleClientKeyShare(sslSocket *ss case ssl_grp_kem_xyber768d00: ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE); break; #endif case ssl_grp_kem_mlkem768x25519: ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(kemSecret, dheSecret, CKM_HKDF_DERIVE, CKA_DERIVE); break; case ssl_grp_kem_secp256r1mlkem768: + case ssl_grp_kem_secp384r1mlkem1024: ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE); break; default: PORT_Assert(0); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ss->ssl3.hs.dheSecret = NULL; break; } @@ -3791,16 +3829,17 @@ tls13_HandleServerKeyShare(sslSocket *ss case ssl_grp_kem_xyber768d00: ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE); break; #endif case ssl_grp_kem_mlkem768x25519: ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(kemSecret, dheSecret, CKM_HKDF_DERIVE, CKA_DERIVE); break; case ssl_grp_kem_secp256r1mlkem768: + case ssl_grp_kem_secp384r1mlkem1024: ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE); break; default: PORT_Assert(0); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ss->ssl3.hs.dheSecret = NULL; break; } diff --git a/lib/ssl/tls13exthandle.c b/lib/ssl/tls13exthandle.c --- a/lib/ssl/tls13exthandle.c +++ b/lib/ssl/tls13exthandle.c @@ -80,70 +80,47 @@ tls13_SizeOfKeyShareEntry(const sslEphem if (keyPair->kemKeys) { PORT_Assert(!keyPair->kemCt); PORT_Assert( #ifndef NSS_DISABLE_KYBER keyPair->group->name == ssl_grp_kem_xyber768d00 || #endif keyPair->group->name == ssl_grp_kem_mlkem768x25519 || - keyPair->group->name == ssl_grp_kem_secp256r1mlkem768); + keyPair->group->name == ssl_grp_kem_secp256r1mlkem768 || + keyPair->group->name == ssl_grp_kem_secp384r1mlkem1024); pubKey = keyPair->kemKeys->pubKey; size += pubKey->u.kyber.publicValue.len; } if (keyPair->kemCt) { PORT_Assert(!keyPair->kemKeys); PORT_Assert( #ifndef NSS_DISABLE_KYBER keyPair->group->name == ssl_grp_kem_xyber768d00 || #endif keyPair->group->name == ssl_grp_kem_mlkem768x25519 || - keyPair->group->name == ssl_grp_kem_secp256r1mlkem768); + keyPair->group->name == ssl_grp_kem_secp256r1mlkem768 || + keyPair->group->name == ssl_grp_kem_secp384r1mlkem1024); size += keyPair->kemCt->len; } return size; } +static SECStatus +tls13_WriteECCFirstMLKEMKeyExchangeInfo(sslBuffer *buf, sslEphemeralKeyPair *keyPair) + { + PORT_Assert(keyPair->group->name == ssl_grp_kem_secp256r1mlkem768 || #ifndef NSS_DISABLE_KYBER -static SECStatus -tls13_WriteXyber768D00KeyExchangeInfo(sslBuffer *buf, sslEphemeralKeyPair *keyPair) -{ - PORT_Assert(keyPair->group->name == ssl_grp_kem_xyber768d00); + keyPair->group->name == ssl_grp_kem_xyber768d00 || +#endif + keyPair->group->name == ssl_grp_kem_secp384r1mlkem1024); PORT_Assert(keyPair->keys->pubKey->keyType == ecKey); - // Encode the X25519 share first, then the Kyber768 key or ciphertext. - SECStatus rv; - rv = sslBuffer_Append(buf, keyPair->keys->pubKey->u.ec.publicValue.data, - keyPair->keys->pubKey->u.ec.publicValue.len); - if (rv != SECSuccess) { - return rv; - } - - if (keyPair->kemKeys) { - PORT_Assert(!keyPair->kemCt); - rv = sslBuffer_Append(buf, keyPair->kemKeys->pubKey->u.kyber.publicValue.data, keyPair->kemKeys->pubKey->u.kyber.publicValue.len); - } else if (keyPair->kemCt) { - rv = sslBuffer_Append(buf, keyPair->kemCt->data, keyPair->kemCt->len); - } else { - PORT_Assert(0); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - rv = SECFailure; - } - return rv; -} -#endif - -static SECStatus -tls13_WriteMLKEM768Secp256r1KeyExchangeInfo(sslBuffer *buf, sslEphemeralKeyPair *keyPair) - { - PORT_Assert(keyPair->group->name == ssl_grp_kem_secp256r1mlkem768); - PORT_Assert(keyPair->keys->pubKey->keyType == ecKey); - - // Encode the p256 key first, then the Kyber768 key or ciphertext. + // Encode the ECC key first, then the ML-KEM key or ciphertext. SECStatus rv; rv = sslBuffer_Append(buf, keyPair->keys->pubKey->u.ec.publicValue.data, keyPair->keys->pubKey->u.ec.publicValue.len); if (rv != SECSuccess) { return rv; } if (keyPair->kemKeys) { @@ -155,22 +132,22 @@ tls13_WriteMLKEM768Secp256r1KeyExchangeI PORT_Assert(0); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); rv = SECFailure; } return rv; } static SECStatus -tls13_WriteMLKEM768X25519KeyExchangeInfo(sslBuffer *buf, sslEphemeralKeyPair *keyPair) +tls13_WriteMLKEMFirstKeyExchangeInfo(sslBuffer *buf, sslEphemeralKeyPair *keyPair) { PORT_Assert(keyPair->group->name == ssl_grp_kem_mlkem768x25519); PORT_Assert(keyPair->keys->pubKey->keyType == ecKey); - // Encode the ML-KEM-768 key or ciphertext first, then the X25519 share. + // Encode the ML-KEM key or ciphertext first, then the ecc share. SECStatus rv; if (keyPair->kemKeys) { PORT_Assert(!keyPair->kemCt); rv = sslBuffer_Append(buf, keyPair->kemKeys->pubKey->u.kyber.publicValue.data, keyPair->kemKeys->pubKey->u.kyber.publicValue.len); } else if (keyPair->kemCt) { rv = sslBuffer_Append(buf, keyPair->kemCt->data, keyPair->kemCt->len); } else { PORT_Assert(0); @@ -223,26 +200,24 @@ tls13_EncodeKeyShareEntry(sslBuffer *buf rv = sslBuffer_AppendNumber(buf, size - 4, 2); if (rv != SECSuccess) { return rv; } switch (keyPair->group->name) { #ifndef NSS_DISABLE_KYBER case ssl_grp_kem_xyber768d00: - rv = tls13_WriteXyber768D00KeyExchangeInfo(buf, keyPair); +#endif + case ssl_grp_kem_secp256r1mlkem768: + case ssl_grp_kem_secp384r1mlkem1024: + rv = tls13_WriteECCFirstMLKEMKeyExchangeInfo(buf, keyPair); break; -#endif case ssl_grp_kem_mlkem768x25519: - rv = tls13_WriteMLKEM768X25519KeyExchangeInfo(buf, keyPair); + rv = tls13_WriteMLKEMFirstKeyExchangeInfo(buf, keyPair); break; - case ssl_grp_kem_secp256r1mlkem768: - rv = tls13_WriteMLKEM768Secp256r1KeyExchangeInfo(buf, keyPair); - break; - default: rv = tls13_WriteKeyExchangeInfo(buf, keyPair); break; } return rv; } SECStatus diff --git a/lib/util/eccutil.h b/lib/util/eccutil.h --- a/lib/util/eccutil.h +++ b/lib/util/eccutil.h @@ -2,16 +2,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef _FREEBL_H_ #define _FREEBL_H_ #define X25519_PUBLIC_KEY_BYTES 32U #define SECP256_PUBLIC_KEY_BYTES 65U +#define SECP384_PUBLIC_KEY_BYTES 97U /* deprecated */ typedef enum { ECPoint_Uncompressed, ECPoint_XOnly, ECPoint_Undefined } ECPointEncoding; diff --git a/lib/util/kyber.h b/lib/util/kyber.h --- a/lib/util/kyber.h +++ b/lib/util/kyber.h @@ -4,20 +4,28 @@ #ifndef KYBER_UTIL_H #define KYBER_UTIL_H #define KYBER768_PUBLIC_KEY_BYTES 1184U #define KYBER768_PRIVATE_KEY_BYTES 2400U #define KYBER768_CIPHERTEXT_BYTES 1088U +#define MLKEM1024_PUBLIC_KEY_BYTES 1568U +#define MLKEM1024_PRIVATE_KEY_BYTES 3168U +#define MLKEM1024_CIPHERTEXT_BYTES 1568U + #define KYBER_SHARED_SECRET_BYTES 32U #define KYBER_KEYPAIR_COIN_BYTES 64U #define KYBER_ENC_COIN_BYTES 32U +#define MAX_ML_KEM_CIPHER_LENGTH MLKEM1024_CIPHERTEXT_BYTES +#define MAX_ML_KEM_PRIVATE_KEY_LENGTH MLKEM1024_PRIVATE_KEY_BYTES +#define MAX_ML_KEM_PUBLIC_KEY_LENGTH MLKEM1024_PUBLIC_KEY_BYTES + typedef enum { params_kyber_invalid, /* * The Kyber768 parameters specified in version 3.02 of the NIST submission * https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf */ params_kyber768_round3, @@ -34,11 +42,24 @@ typedef enum { */ params_ml_kem768, /* * Identical to params_ml_kem768 except that this parameter set allows * the use of a seed in `Kyber_Encapsulate` for testing. */ params_ml_kem768_test_mode, + + /* + * The ML-KEM parameters specified in FIPS 203. + * https://csrc.nist.gov/pubs/fips/203/final + */ + params_ml_kem1024, + + /* + * Identical to params_ml_kem1024 except that this parameter set allows + * the use of a seed in `Kyber_Encapsulate` for testing. + */ + params_ml_kem1024_test_mode, + } KyberParams; #endif /* KYBER_UTIL_H */ diff --git a/tests/ssl/ssl.sh b/tests/ssl/ssl.sh --- a/tests/ssl/ssl.sh +++ b/tests/ssl/ssl.sh @@ -119,19 +119,19 @@ ssl_init() # List of cipher suites to test, including ECC cipher suites. CIPHER_SUITES="-c ${EC_SUITES}${NON_EC_SUITES}" TLS13_CIPHER_SUITES="-c ${TLS13_SUITES}${EC_SUITES}${NON_EC_SUITES}" # FIPS specific options for both clients and servers FIPS_OPTIONS="" # in fips mode, turn off curve25519 until it's NIST approved - ALL_GROUPS="P256,P384,P521,x25519,FF2048,FF3072,FF4096,FF6144,FF8192,mlkem768secp256r1,mlkem768x25519" + ALL_GROUPS="P256,P384,P521,x25519,FF2048,FF3072,FF4096,FF6144,FF8192,secp256r1mlkem768,secp384r1mlkem1024, mlkem768x25519" NON_PQ_GROUPS="P256,P384,P521,x25519,FF2048,FF3072,FF4096,FF6144,FF8192" - FIPS_GROUPS="P256,P384,P521,FF2048,FF3072,FF4096,FF6144,FF8192,mlkem768secp256r1,mlkem768x25519" + FIPS_GROUPS="P256,P384,P521,FF2048,FF3072,FF4096,FF6144,FF8192,secp256r1mlkem768,secp384r1mlkem1024,mlkem768x25519" # in non-fips mode, tstclnt may run without the db password in some # cases, but in fips mode it's always needed CLIENT_PW="" CLIENT_PW_FIPS="-w nss" CLIENT_PW_NORMAL="" if [ "${OS_ARCH}" != "WINNT" ]; then @@ -372,19 +372,21 @@ ssl_cov() if [ "$VMAX" = "ssl3" -a "$VMIN" = "tls1.1" ]; then kill_selfserv start_selfserv $CIPHER_SUITES VMIN="ssl3" fi TLS_GROUPS=${CLIENT_GROUPS} if [ "$ectype" = "MLKEM256" ]; then - TLS_GROUPS="mlkem768secp256r1" + TLS_GROUPS="secp256r1mlkem768" elif [ "$ectype" = "MLKEM219" ]; then - TLS_GROUPS="mlkem768x25519" + TLS_GROUPS="x25519mlkem768" + elif [ "$ectype" = "MLKEM384" ]; then + TLS_GROUPS="secp384r1mlkem1024" fi echo "TLS_GROUPS=${TLS_GROUPS}" echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -I \"${TLS_GROUPS}\" -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} \\" echo " -f -d ${P_R_CLIENTDIR} $verbose -w nss < ${REQUEST_FILE}" rm ${TMP}/$HOST.tmp.$$ 2>/dev/null ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -I "${TLS_GROUPS}" -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} -f \ diff --git a/tests/ssl/sslcov.txt b/tests/ssl/sslcov.txt --- a/tests/ssl/sslcov.txt +++ b/tests/ssl/sslcov.txt @@ -148,14 +148,17 @@ # Test against server with RSA-PSS server certificate # ECC TLS12 :C02F TLS12_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - RSA-PSS ECC TLS12 :C030 TLS12_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - RSA-PSS # test TLS 1.3 ECC TLS13 :1301 TLS13_ECDHE_WITH_AES_128_GCM_SHA256 ECC TLS13 :1302 TLS13_ECDHE_WITH_AES_256_GCM_SHA384 ECC TLS13 :1303 TLS13_ECDHE_WITH_CHACHA20_POLY1305_SHA256 -MLKEM256 TLS13 :1301 TLS13_MLKEMP256_WITH_AES_128_GCM_SHA256 -MLKEM256 TLS13 :1302 TLS13_MLKEMP256_WITH_AES_256_GCM_SHA384 -MLKEM256 TLS13 :1303 TLS13_MLKEMP256_WITH_CHACHA20_POLY1305_SHA256 -MLKEM219 TLS13 :1301 TLS13_MLKEMX25519_WITH_AES_128_GCM_SHA256 -MLKEM219 TLS13 :1302 TLS13_MLKEMX25519_WITH_AES_256_GCM_SHA384 -MLKEM219 TLS13 :1303 TLS13_MLKEMX25519_WITH_CHACHA20_POLY1305_SHA256 +MLKEM384 TLS13 :1301 TLS13_MLKEM1024P384_WITH_AES_128_GCM_SHA256 +MLKEM384 TLS13 :1302 TLS13_MLKEM1024P384_WITH_AES_256_GCM_SHA384 +MLKEM384 TLS13 :1303 TLS13_MLKEM1024P384_WITH_CHACHA20_POLY1305_SHA256 +MLKEM256 TLS13 :1301 TLS13_MLKEM768P256_WITH_AES_128_GCM_SHA256 +MLKEM256 TLS13 :1302 TLS13_MLKEM768P256_WITH_AES_256_GCM_SHA384 +MLKEM256 TLS13 :1303 TLS13_MLKEM768P256_WITH_CHACHA20_POLY1305_SHA256 +MLKEM219 TLS13 :1301 TLS13_MLKEM768X25519_WITH_AES_128_GCM_SHA256 +MLKEM219 TLS13 :1302 TLS13_MLKEM768X25519_WITH_AES_256_GCM_SHA384 +MLKEM219 TLS13 :1303 TLS13_MLKEM768X25519_WITH_CHACHA20_POLY1305_SHA256