From c98372a24e278bb5346208f3311a41cd0b506bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Meusel?= Date: Fri, 18 Oct 2024 11:00:05 +0200 Subject: [PATCH] Add TLS 1.3 groups ML-KEM-512, -768 and -1024 Those groups are described in draft-connolly-tls-mlkem-key-agreement and request registration of code points 0x0512, 0x0768 and 0x1024 from IANA. --- src/lib/tls/tls_algos.cpp | 17 +++++++++++++++++ src/lib/tls/tls_algos.h | 18 ++++++++++++++++-- src/lib/tls/tls_callbacks.cpp | 16 ++++++++++++++++ src/scripts/test_cli.py | 6 ++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/lib/tls/tls_algos.cpp b/src/lib/tls/tls_algos.cpp index eac5d4e9afd..1a58e54b17d 100644 --- a/src/lib/tls/tls_algos.cpp +++ b/src/lib/tls/tls_algos.cpp @@ -186,6 +186,16 @@ std::optional Group_Params::from_string(std::string_view group_nam return Group_Params::KYBER_1024_R3_OQS; } + if(group_name == "ML-KEM-512") { + return Group_Params::ML_KEM_512; + } + if(group_name == "ML-KEM-768") { + return Group_Params::ML_KEM_768; + } + if(group_name == "ML-KEM-1024") { + return Group_Params::ML_KEM_1024; + } + if(group_name == "eFrodoKEM-640-SHAKE") { return Group_Params::eFRODOKEM_640_SHAKE_OQS; } @@ -303,6 +313,13 @@ std::optional Group_Params::to_string() const { case Group_Params::KYBER_1024_R3_OQS: return "Kyber-1024-r3"; + case Group_Params::ML_KEM_512: + return "ML-KEM-512"; + case Group_Params::ML_KEM_768: + return "ML-KEM-768"; + case Group_Params::ML_KEM_1024: + return "ML-KEM-1024"; + case Group_Params::eFRODOKEM_640_SHAKE_OQS: return "eFrodoKEM-640-SHAKE"; case Group_Params::eFRODOKEM_976_SHAKE_OQS: diff --git a/src/lib/tls/tls_algos.h b/src/lib/tls/tls_algos.h index b3ea759336b..6ce615b6bec 100644 --- a/src/lib/tls/tls_algos.h +++ b/src/lib/tls/tls_algos.h @@ -104,6 +104,11 @@ enum class Group_Params_Code : uint16_t { KYBER_768_R3_OQS = 0x023C, KYBER_1024_R3_OQS = 0x023D, + // https://datatracker.ietf.org/doc/draft-connolly-tls-mlkem-key-agreement/02/ + ML_KEM_512 = 0x0512, + ML_KEM_768 = 0x0768, + ML_KEM_1024 = 0x1024, + eFRODOKEM_640_SHAKE_OQS = 0x0201, eFRODOKEM_976_SHAKE_OQS = 0x0203, eFRODOKEM_1344_SHAKE_OQS = 0x0205, @@ -194,6 +199,11 @@ class BOTAN_PUBLIC_API(3, 2) Group_Params final { m_code == Group_Params_Code::FFDHE_8192; } + constexpr bool is_pure_ml_kem() const { + return m_code == Group_Params_Code::ML_KEM_512 || m_code == Group_Params_Code::ML_KEM_768 || + m_code == Group_Params_Code::ML_KEM_1024; + } + constexpr bool is_pure_kyber() const { return m_code == Group_Params_Code::KYBER_512_R3_OQS || m_code == Group_Params_Code::KYBER_768_R3_OQS || m_code == Group_Params_Code::KYBER_1024_R3_OQS; @@ -210,7 +220,9 @@ class BOTAN_PUBLIC_API(3, 2) Group_Params final { constexpr bool is_pure_ecc_group() const { return is_x25519() || is_x448() || is_ecdh_named_curve(); } - constexpr bool is_post_quantum() const { return is_pure_kyber() || is_pure_frodokem() || is_pqc_hybrid(); } + constexpr bool is_post_quantum() const { + return is_pure_kyber() || is_pure_ml_kem() || is_pure_frodokem() || is_pqc_hybrid(); + } constexpr bool is_pqc_hybrid() const { BOTAN_DIAGNOSTIC_PUSH @@ -238,7 +250,9 @@ class BOTAN_PUBLIC_API(3, 2) Group_Params final { BOTAN_DIAGNOSTIC_POP } - constexpr bool is_kem() const { return is_pure_kyber() || is_pure_frodokem() || is_pqc_hybrid(); } + constexpr bool is_kem() const { + return is_pure_kyber() || is_pure_ml_kem() || is_pure_frodokem() || is_pqc_hybrid(); + } // Returns std::nullopt if the param has no known name std::optional to_string() const; diff --git a/src/lib/tls/tls_callbacks.cpp b/src/lib/tls/tls_callbacks.cpp index 13dcc06bed5..73aa76e61e7 100644 --- a/src/lib/tls/tls_callbacks.cpp +++ b/src/lib/tls/tls_callbacks.cpp @@ -34,6 +34,10 @@ #include #endif +#if defined(BOTAN_HAS_ML_KEM) + #include +#endif + #if defined(BOTAN_HAS_FRODOKEM) #include #endif @@ -228,6 +232,12 @@ std::unique_ptr TLS::Callbacks::tls_deserialize_peer_public_key( } #endif +#if defined(BOTAN_HAS_ML_KEM) + if(group_params.is_pure_ml_kem()) { + return std::make_unique(key_bits, ML_KEM_Mode(group_params.to_string().value())); + } +#endif + #if defined(BOTAN_HAS_KYBER) if(group_params.is_pure_kyber()) { return std::make_unique(key_bits, KyberMode(group_params.to_string().value())); @@ -244,6 +254,12 @@ std::unique_ptr TLS::Callbacks::tls_deserialize_peer_public_key( } std::unique_ptr TLS::Callbacks::tls_kem_generate_key(TLS::Group_Params group, RandomNumberGenerator& rng) { +#if defined(BOTAN_HAS_ML_KEM) + if(group.is_pure_ml_kem()) { + return std::make_unique(rng, KyberMode(group.to_string().value())); + } +#endif + #if defined(BOTAN_HAS_KYBER) if(group.is_pure_kyber()) { return std::make_unique(rng, KyberMode(group.to_string().value())); diff --git a/src/scripts/test_cli.py b/src/scripts/test_cli.py index e3f5bac09f3..592f0c8af44 100755 --- a/src/scripts/test_cli.py +++ b/src/scripts/test_cli.py @@ -1346,6 +1346,12 @@ def get_oqs_rootca(): TestConfig("test.openquantumsafe.org", "secp256r1/Kyber-768-r3", port=oqsp['p256_kyber768'], ca=oqs_test_ca), TestConfig("test.openquantumsafe.org", "secp384r1/Kyber-768-r3", port=oqsp['p384_kyber768'], ca=oqs_test_ca), TestConfig("test.openquantumsafe.org", "secp521r1/Kyber-1024-r3", port=oqsp['p521_kyber1024'], ca=oqs_test_ca), + # Currently oqs did not adopt the 0x0512 code point defined in draft-connolly-tls-mlkem-key-agreement-02. + # To be fair: this code point was proposed only in the latest revision of the draft (published 8 days ago). + # TODO: enable this test once the code point is adopted by oqs + # TestConfig("test.openquantumsafe.org", "ML-KEM-512", port=oqsp['mlkem512'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "ML-KEM-768", port=oqsp['mlkem768'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "ML-KEM-1024", port=oqsp['mlkem1024'], ca=oqs_test_ca), TestConfig("test.openquantumsafe.org", "Kyber-512-r3", port=oqsp['kyber512'], ca=oqs_test_ca), TestConfig("test.openquantumsafe.org", "Kyber-768-r3", port=oqsp['kyber768'], ca=oqs_test_ca), TestConfig("test.openquantumsafe.org", "Kyber-1024-r3", port=oqsp['kyber1024'], ca=oqs_test_ca),