Skip to content

Commit

Permalink
Merge pull request #4375 from Rohde-Schwarz/tls/ml_kem_hybrids
Browse files Browse the repository at this point in the history
  • Loading branch information
reneme authored Oct 19, 2024
2 parents 087f6ca + 59abd7a commit 6babd82
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 10 deletions.
14 changes: 10 additions & 4 deletions src/bogo_shim/bogo_shim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -998,12 +998,18 @@ class Shim_Policy final : public Botan::TLS::Policy {
groups.push_back(group);
}

// Given that this is still a draft-standard, we didn't add the
// hybrid groups to the default policy, yet.
//
// Eventually the pre-standard hybrid exchange using Kyber-R3 will be
// retired and removed. Hence, it will likely never be part of the
// default `TLS::Policy::key_exchange_groups()`.
if(group == Botan::TLS::Group_Params::HYBRID_X25519_KYBER_768_R3_OQS) {
groups.push_back(group);
}

// TODO: once `TLS::Policy::key_exchange_groups()` contains it by
// default, remove this explicit check.
if(group == Botan::TLS::Group_Params::HYBRID_X25519_KYBER_768_R3_OQS) {
//
// See: https://github.com/randombit/botan/pull/4305
if(group == Botan::TLS::Group_Params::HYBRID_X25519_ML_KEM_768) {
groups.push_back(group);
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/bogo_shim/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,9 @@
"Renegotiate-Client-UnfinishedWrite": "BoringSSL specific API test",
"FailEarlyCallback": "BoringSSL specific API test",

"*MLKEM*": "No support for hybrid key exchange with ML-KEM, yet",

"MLKEMKeyShareIncludedSecond": "BoringSSL specific policy test (we may offer solo PQ/T groups)",
"NotJustMLKEMKeyShare": "BoringSSL specific policy test (we may offer solo PQ/T groups)",
"MLKEMKeyShareIncludedThird": "BoringSSL specific policy test (we may offer solo PQ/T groups)",
"NotJustKyberKeyShare": "BoringSSL specific policy test (we may offer solo PQ/T groups)",
"KyberKeyShareIncludedSecond": "BoringSSL specific policy test (we may offer solo PQ/T groups)",
"KyberKeyShareIncludedThird": "BoringSSL specific policy test (we may offer solo PQ/T groups)",
Expand Down
7 changes: 4 additions & 3 deletions src/examples/tls_13_hybrid_key_exchange_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,17 @@ class Client_Policy : public Botan::TLS::Default_Policy {
// additional to the default (classical) key exchange groups
std::vector<Botan::TLS::Group_Params> key_exchange_groups() const override {
auto groups = Botan::TLS::Default_Policy::key_exchange_groups();
groups.push_back(Botan::TLS::Group_Params::HYBRID_X25519_ML_KEM_768);
groups.push_back(Botan::TLS::Group_Params::HYBRID_SECP256R1_ML_KEM_768);
groups.push_back(Botan::TLS::Group_Params::HYBRID_X25519_KYBER_768_R3_OQS);
groups.push_back(Botan::TLS::Group_Params::HYBRID_X25519_KYBER_512_R3_OQS);
groups.push_back(Botan::TLS::Group_Params::HYBRID_SECP256R1_KYBER_768_R3_OQS);
return groups;
}

// Define that the client should exclusively pre-offer hybrid groups
// in its initial Client Hello.
std::vector<Botan::TLS::Group_Params> key_exchange_groups_to_offer() const override {
return {Botan::TLS::Group_Params::HYBRID_X25519_KYBER_768_R3_OQS,
Botan::TLS::Group_Params::HYBRID_X25519_KYBER_512_R3_OQS};
return {Botan::TLS::Group_Params::HYBRID_X25519_ML_KEM_768};
}
};

Expand Down
21 changes: 21 additions & 0 deletions src/lib/tls/tls13_pqc/hybrid_public_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ std::vector<std::pair<std::string, std::string>> algorithm_specs_for_group(Group
BOTAN_ARG_CHECK(group.is_pqc_hybrid(), "Group is not hybrid");

switch(group.code()) {
// draft-kwiatkowski-tls-ecdhe-mlkem-02 Section 3
//
// NIST's special publication 800-56Cr2 approves the usage of HKDF with
// two distinct shared secrets, with the condition that the first one
// is computed by a FIPS-approved key-establishment scheme. FIPS also
// requires a certified implementation of the scheme, which will remain
// more ubiqutous for secp256r1 in the coming years.
//
// For this reason we put the ML-KEM-768 shared secret first in
// X25519MLKEM768, and the secp256r1 shared secret first in
// SecP256r1MLKEM768.
case Group_Params::HYBRID_X25519_ML_KEM_768:
return {{"ML-KEM", "ML-KEM-768"}, {"X25519", "X25519"}};
case Group_Params::HYBRID_SECP256R1_ML_KEM_768:
return {{"ECDH", "secp256r1"}, {"ML-KEM", "ML-KEM-768"}};

case Group_Params::HYBRID_X25519_KYBER_512_R3_OQS:
case Group_Params::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE:
return {{"X25519", "X25519"}, {"Kyber", "Kyber-512-r3"}};
Expand Down Expand Up @@ -98,6 +114,11 @@ std::vector<size_t> public_value_lengths_for_group(Group_Params group) {
// TODO: Find a way to expose important algorithm constants globally
// in the library, to avoid violating the DRY principle.
switch(group.code()) {
case Group_Params::HYBRID_X25519_ML_KEM_768:
return {1184, 32};
case Group_Params::HYBRID_SECP256R1_ML_KEM_768:
return {32, 1184};

case Group_Params::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE:
case Group_Params::HYBRID_X25519_KYBER_512_R3_OQS:
return {32, 800};
Expand Down
14 changes: 14 additions & 0 deletions src/lib/tls/tls_algos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,14 @@ std::optional<Group_Params> Group_Params::from_string(std::string_view group_nam
if(group_name == "x25519/Kyber-768-r3") {
return Group_Params::HYBRID_X25519_KYBER_768_R3_OQS;
}

if(group_name == "x25519/ML-KEM-768") {
return Group_Params::HYBRID_X25519_ML_KEM_768;
}
if(group_name == "secp256r1/ML-KEM-768") {
return Group_Params::HYBRID_SECP256R1_ML_KEM_768;
}

if(group_name == "x448/Kyber-768-r3") {
return Group_Params::HYBRID_X448_KYBER_768_R3_OQS;
}
Expand Down Expand Up @@ -344,6 +352,12 @@ std::optional<std::string> Group_Params::to_string() const {
return "x25519/Kyber-512-r3";
case Group_Params::HYBRID_X25519_KYBER_768_R3_OQS:
return "x25519/Kyber-768-r3";

case Group_Params::HYBRID_X25519_ML_KEM_768:
return "x25519/ML-KEM-768";
case Group_Params::HYBRID_SECP256R1_ML_KEM_768:
return "secp256r1/ML-KEM-768";

case Group_Params::HYBRID_X448_KYBER_768_R3_OQS:
return "x448/Kyber-768-r3";

Expand Down
8 changes: 7 additions & 1 deletion src/lib/tls/tls_algos.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ enum class Group_Params_Code : uint16_t {
HYBRID_X25519_KYBER_512_R3_OQS = 0x2F39,
HYBRID_X25519_KYBER_768_R3_OQS = 0x6399,

// https://datatracker.ietf.org/doc/draft-kwiatkowski-tls-ecdhe-mlkem/02/
HYBRID_SECP256R1_ML_KEM_768 = 0x11EB,
HYBRID_X25519_ML_KEM_768 = 0x11EC,

HYBRID_X448_KYBER_768_R3_OQS = 0x2F90,

HYBRID_SECP256R1_KYBER_512_R3_OQS = 0x2F3A,
Expand Down Expand Up @@ -216,7 +220,9 @@ class BOTAN_PUBLIC_API(3, 2) Group_Params final {
BOTAN_DIAGNOSTIC_PUSH
BOTAN_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS

return m_code == Group_Params_Code::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE ||
return m_code == Group_Params_Code::HYBRID_SECP256R1_ML_KEM_768 ||
m_code == Group_Params_Code::HYBRID_X25519_ML_KEM_768 ||
m_code == Group_Params_Code::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE ||
m_code == Group_Params_Code::HYBRID_X25519_KYBER_512_R3_OQS ||
m_code == Group_Params_Code::HYBRID_X25519_KYBER_768_R3_OQS ||
m_code == Group_Params_Code::HYBRID_X448_KYBER_768_R3_OQS ||
Expand Down
4 changes: 4 additions & 0 deletions src/scripts/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1324,7 +1324,9 @@ def get_oqs_rootca():

test_cfg = [
TestConfig("pq.cloudflareresearch.com", "x25519/Kyber-768-r3"),
TestConfig("pq.cloudflareresearch.com", "x25519/ML-KEM-768"),
TestConfig("google.com", "x25519/Kyber-768-r3"),
TestConfig("google.com", "x25519/ML-KEM-768"),

TestConfig("qsc.eu-de.kms.cloud.ibm.com", "secp256r1/Kyber-512-r3"),
TestConfig("qsc.eu-de.kms.cloud.ibm.com", "secp384r1/Kyber-768-r3"),
Expand All @@ -1339,6 +1341,8 @@ def get_oqs_rootca():
if oqsp and oqs_test_ca:
# src/scripts/test_cli.py --run-online-tests ./botan pqc_hybrid_tests
test_cfg += [
TestConfig("test.openquantumsafe.org", "x25519/ML-KEM-768", port=oqsp['X25519MLKEM768'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "secp256r1/ML-KEM-768", port=oqsp['SecP256r1MLKEM768'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "x25519/Kyber-512-r3", port=oqsp['x25519_kyber512'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "x25519/Kyber-768-r3", port=oqsp['x25519_kyber768'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "x448/Kyber-768-r3", port=oqsp['x448_kyber768'], ca=oqs_test_ca),
Expand Down

0 comments on commit 6babd82

Please sign in to comment.