From 35600ee3f0f925cbba559eb5a0aa0b28840f7c24 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, 0x0513 and 0x0514 from IANA. This commit implements the groups as described in the ...-05 draft version. --- src/lib/tls/tls_algos.cpp | 17 +++++++++++++++++ src/lib/tls/tls_algos.h | 22 ++++++++++++++++------ src/lib/tls/tls_callbacks.cpp | 16 ++++++++++++++++ src/scripts/test_cli.py | 12 +++++++++--- 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/lib/tls/tls_algos.cpp b/src/lib/tls/tls_algos.cpp index 77b564c886..5d3be9396f 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; } @@ -311,6 +321,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 f16ea90680..92e5cdfc8d 100644 --- a/src/lib/tls/tls_algos.h +++ b/src/lib/tls/tls_algos.h @@ -78,7 +78,7 @@ Auth_Method BOTAN_TEST_API auth_method_from_string(std::string_view str); #define BOTAN_TLS_KYBER_R3_DEPRECATED \ BOTAN_DEPRECATED( \ - "Kyber r3 TLS support will be removed completely in Botan 3.7.0 (early 2025) see https://github.com/randombit/botan/issues/4403") + "Kyber r3 TLS support will be removed completely in Botan 3.7.0 (early 2025) use ML-KEM and see https://github.com/randombit/botan/issues/4403") /* * Matches with wire encoding @@ -108,11 +108,16 @@ enum class Group_Params_Code : uint16_t { KYBER_768_R3_OQS BOTAN_TLS_KYBER_R3_DEPRECATED = 0x023C, KYBER_1024_R3_OQS BOTAN_TLS_KYBER_R3_DEPRECATED = 0x023D, - eFRODOKEM_640_SHAKE_OQS = 0x0201, + // https://datatracker.ietf.org/doc/draft-connolly-tls-mlkem-key-agreement/05/ + ML_KEM_512 = 0x0200, + ML_KEM_768 = 0x0201, + ML_KEM_1024 = 0x0202, + + eFRODOKEM_640_SHAKE_OQS = 0xFE01, eFRODOKEM_976_SHAKE_OQS = 0x0203, eFRODOKEM_1344_SHAKE_OQS = 0x0205, - eFRODOKEM_640_AES_OQS = 0x0200, - eFRODOKEM_976_AES_OQS = 0x0202, + eFRODOKEM_640_AES_OQS = 0xFE00, + eFRODOKEM_976_AES_OQS = 0xFE02, eFRODOKEM_1344_AES_OQS = 0x0204, // Cloudflare code points for hybrid PQC @@ -202,6 +207,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; + } + BOTAN_TLS_KYBER_R3_DEPRECATED constexpr bool is_pure_kyber() const { BOTAN_DIAGNOSTIC_PUSH BOTAN_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS @@ -227,7 +237,7 @@ class BOTAN_PUBLIC_API(3, 2) Group_Params final { BOTAN_DIAGNOSTIC_PUSH BOTAN_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS - return is_pure_kyber() || is_pure_frodokem() || is_pqc_hybrid(); + return is_pure_kyber() || is_pure_ml_kem() || is_pure_frodokem() || is_pqc_hybrid(); BOTAN_DIAGNOSTIC_POP } @@ -264,7 +274,7 @@ class BOTAN_PUBLIC_API(3, 2) Group_Params final { BOTAN_DIAGNOSTIC_PUSH BOTAN_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS - return is_pure_kyber() || is_pure_frodokem() || is_pqc_hybrid(); + return is_pure_kyber() || is_pure_ml_kem() || is_pure_frodokem() || is_pqc_hybrid(); BOTAN_DIAGNOSTIC_POP } diff --git a/src/lib/tls/tls_callbacks.cpp b/src/lib/tls/tls_callbacks.cpp index 13dcc06bed..ec2c219fce 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, ML_KEM_Mode(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 0eac794b42..1de9cadd3e 100755 --- a/src/scripts/test_cli.py +++ b/src/scripts/test_cli.py @@ -1350,14 +1350,20 @@ 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 0x0200, 0x0201 and 0x0202 code point defined in draft-connolly-tls-mlkem-key-agreement-05. + # Neither did they deploy a new server that re-assigns the respective Frodo code points that used those before. + # TODO: enable those tests once the code point are re-assigned by the OQS test server + # 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), - TestConfig("test.openquantumsafe.org", "eFrodoKEM-640-SHAKE", port=oqsp['frodo640shake'], ca=oqs_test_ca), + # TestConfig("test.openquantumsafe.org", "eFrodoKEM-640-SHAKE", port=oqsp['frodo640shake'], ca=oqs_test_ca), TestConfig("test.openquantumsafe.org", "eFrodoKEM-976-SHAKE", port=oqsp['frodo976shake'], ca=oqs_test_ca), TestConfig("test.openquantumsafe.org", "eFrodoKEM-1344-SHAKE", port=oqsp['frodo1344shake'], ca=oqs_test_ca), - TestConfig("test.openquantumsafe.org", "eFrodoKEM-640-AES", port=oqsp['frodo640aes'], ca=oqs_test_ca), - TestConfig("test.openquantumsafe.org", "eFrodoKEM-976-AES", port=oqsp['frodo976aes'], ca=oqs_test_ca), + # TestConfig("test.openquantumsafe.org", "eFrodoKEM-640-AES", port=oqsp['frodo640aes'], ca=oqs_test_ca), + # TestConfig("test.openquantumsafe.org", "eFrodoKEM-976-AES", port=oqsp['frodo976aes'], ca=oqs_test_ca), TestConfig("test.openquantumsafe.org", "eFrodoKEM-1344-AES", port=oqsp['frodo1344aes'], ca=oqs_test_ca), TestConfig("test.openquantumsafe.org", "x25519/eFrodoKEM-640-SHAKE", port=oqsp['x25519_frodo640shake'], ca=oqs_test_ca), TestConfig("test.openquantumsafe.org", "x25519/eFrodoKEM-640-AES", port=oqsp['x25519_frodo640aes'], ca=oqs_test_ca),