Skip to content

Commit

Permalink
Add TLS 1.3 groups x25519/ML-KEM-768 and secp256r1/ML-KEM-768
Browse files Browse the repository at this point in the history
Those groups are described in draft-kwiatkowski-tls-ecdhe-mlkem and
the code points are officially provided by IANA. Therefore they
can be seen as 'fit for production use'.
  • Loading branch information
reneme committed Oct 15, 2024
1 parent 7d6c239 commit c7a5ddf
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 1 deletion.
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
3 changes: 3 additions & 0 deletions src/scripts/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1324,6 +1324,7 @@ 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("qsc.eu-de.kms.cloud.ibm.com", "secp256r1/Kyber-512-r3"),
Expand All @@ -1339,6 +1340,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 c7a5ddf

Please sign in to comment.