From 5741e183c5d55d838ce383072976b6aca47051b6 Mon Sep 17 00:00:00 2001 From: Fabian Albert Date: Tue, 4 Jul 2023 13:00:49 +0200 Subject: [PATCH] length fix and code points for OQS --- src/lib/tls/tls13_pqc/hybrid_public_key.cpp | 23 ++++++++++++-- src/lib/tls/tls_algos.cpp | 35 +++++++++++++++++++-- src/lib/tls/tls_algos.h | 16 +++++++++- src/lib/tls/tls_callbacks.cpp | 3 ++ src/lib/tls/tls_policy.cpp | 4 --- src/scripts/test_cli.py | 7 +++-- 6 files changed, 76 insertions(+), 12 deletions(-) diff --git a/src/lib/tls/tls13_pqc/hybrid_public_key.cpp b/src/lib/tls/tls13_pqc/hybrid_public_key.cpp index 981d9875230..7485783e364 100644 --- a/src/lib/tls/tls13_pqc/hybrid_public_key.cpp +++ b/src/lib/tls/tls13_pqc/hybrid_public_key.cpp @@ -33,11 +33,20 @@ std::vector> algorithm_specs_for_group(Group BOTAN_ASSERT_NOMSG(is_hybrid(group)); switch(group) { + case Group_Params::HYBRID_X25519_KYBER_512_R3_OQS: case Group_Params::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE: return {{"Curve25519", "Curve25519"}, {"Kyber", "Kyber-512-r3"}}; + case Group_Params::HYBRID_X25519_KYBER_768_R3_OQS: case Group_Params::HYBRID_X25519_KYBER_768_R3_CLOUDFLARE: return {{"Curve25519", "Curve25519"}, {"Kyber", "Kyber-768-r3"}}; + case Group_Params::HYBRID_SECP256R1_KYBER_512_R3_OQS: + return {{"ECDH", "secp256r1"}, {"Kyber", "Kyber-512-r3"}}; + case Group_Params::HYBRID_SECP384R1_KYBER_768_R3_OQS: + return {{"ECDH", "secp384r1"}, {"Kyber", "Kyber-768-r3"}}; + case Group_Params::HYBRID_SECP521R1_KYBER_1024_R3_OQS: + return {{"ECDH", "secp521r1"}, {"Kyber", "Kyber-1024-r3"}}; + default: return {}; } @@ -72,9 +81,18 @@ std::vector public_value_lengths_for_group(Group_Params group) { // in the library, to avoid violating the DRY principle. switch(group) { case Group_Params::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE: - return {32, 768}; + case Group_Params::HYBRID_X25519_KYBER_512_R3_OQS: + return {32, 800}; case Group_Params::HYBRID_X25519_KYBER_768_R3_CLOUDFLARE: - return {32, 1088}; + case Group_Params::HYBRID_X25519_KYBER_768_R3_OQS: + return {32, 1184}; + + case Group_Params::HYBRID_SECP256R1_KYBER_512_R3_OQS: + return {32, 800}; + case Group_Params::HYBRID_SECP384R1_KYBER_768_R3_OQS: + return {48, 1184}; + case Group_Params::HYBRID_SECP521R1_KYBER_1024_R3_OQS: + return {66, 1568}; default: return {}; @@ -94,6 +112,7 @@ std::unique_ptr Hybrid_KEM_PublicKey::load_for_group( for(size_t idx = 0; idx < alg_ids.size(); ++idx) { pks.emplace_back(load_public_key(alg_ids[idx], public_value_slicer.take(public_value_lengths[idx]))); } + BOTAN_ASSERT(public_value_slicer.empty(), "Concatenated public value has the correct length"); return std::make_unique(std::move(pks)); } diff --git a/src/lib/tls/tls_algos.cpp b/src/lib/tls/tls_algos.cpp index 47bde50d5eb..11ae8118cd8 100644 --- a/src/lib/tls/tls_algos.cpp +++ b/src/lib/tls/tls_algos.cpp @@ -164,13 +164,30 @@ Group_Params group_param_from_string(std::string_view group_name) { return Group_Params::KYBER_1024_R3; } - if(group_name == "x25519/Kyber-512-r3") { + if(group_name == "x25519/Kyber-512-r3/cloudflare") { return Group_Params::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE; } - if(group_name == "x25519/Kyber-768-r3") { + if(group_name == "x25519/Kyber-768-r3/cloudflare") { return Group_Params::HYBRID_X25519_KYBER_768_R3_CLOUDFLARE; } + if(group_name == "x25519/Kyber-512-r3") { + return Group_Params::HYBRID_X25519_KYBER_512_R3_OQS; + } + if(group_name == "x25519/Kyber-768-r3") { + return Group_Params::HYBRID_X25519_KYBER_768_R3_OQS; + } + + if(group_name == "secp256r1/Kyber-512-r3") { + return Group_Params::HYBRID_SECP256R1_KYBER_512_R3_OQS; + } + if(group_name == "secp384r1/Kyber-768-r3") { + return Group_Params::HYBRID_SECP384R1_KYBER_768_R3_OQS; + } + if(group_name == "secp521r1/Kyber-1024-r3") { + return Group_Params::HYBRID_SECP521R1_KYBER_1024_R3_OQS; + } + return Group_Params::NONE; // unknown } @@ -210,10 +227,22 @@ std::string group_param_to_string(Group_Params group) { return "Kyber-1024-r3"; case Group_Params::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE: - return "x25519/Kyber-512-r3"; + return "x25519/Kyber-512-r3/cloudflare"; case Group_Params::HYBRID_X25519_KYBER_768_R3_CLOUDFLARE: + return "x25519/Kyber-768-r3/cloudflare"; + + case Group_Params::HYBRID_X25519_KYBER_512_R3_OQS: + return "x25519/Kyber-512-r3"; + case Group_Params::HYBRID_X25519_KYBER_768_R3_OQS: return "x25519/Kyber-768-r3"; + case Group_Params::HYBRID_SECP256R1_KYBER_512_R3_OQS: + return "secp256r1/Kyber-512-r3"; + case Group_Params::HYBRID_SECP384R1_KYBER_768_R3_OQS: + return "secp384r1/Kyber-768-r3"; + case Group_Params::HYBRID_SECP521R1_KYBER_1024_R3_OQS: + return "secp521r1/Kyber-1024-r3"; + default: return ""; } diff --git a/src/lib/tls/tls_algos.h b/src/lib/tls/tls_algos.h index 6eac539391c..c020dfa0a41 100644 --- a/src/lib/tls/tls_algos.h +++ b/src/lib/tls/tls_algos.h @@ -108,6 +108,15 @@ enum class Group_Params : uint16_t { // https://blog.cloudflare.com/post-quantum-for-all/ HYBRID_X25519_KYBER_512_R3_CLOUDFLARE = 0xFE30, HYBRID_X25519_KYBER_768_R3_CLOUDFLARE = 0xFE31, + + // libOQS defines those in: + // https://github.com/open-quantum-safe/oqs-provider/blob/main/oqs-template/oqs-kem-info.md + HYBRID_X25519_KYBER_512_R3_OQS = 0x2F39, + HYBRID_X25519_KYBER_768_R3_OQS = 0x6399, + + HYBRID_SECP256R1_KYBER_512_R3_OQS = 0x2F3A, + HYBRID_SECP384R1_KYBER_768_R3_OQS = 0x2F3C, + HYBRID_SECP521R1_KYBER_1024_R3_OQS = 0x2F3D, }; constexpr bool is_x25519(const Group_Params group) { @@ -132,7 +141,12 @@ constexpr bool is_kyber(const Group_Params group) { constexpr bool is_hybrid(const Group_Params group) { return group == Group_Params::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE || - group == Group_Params::HYBRID_X25519_KYBER_768_R3_CLOUDFLARE; + group == Group_Params::HYBRID_X25519_KYBER_768_R3_CLOUDFLARE || + group == Group_Params::HYBRID_X25519_KYBER_512_R3_OQS || + group == Group_Params::HYBRID_X25519_KYBER_768_R3_OQS || + group == Group_Params::HYBRID_SECP256R1_KYBER_512_R3_OQS || + group == Group_Params::HYBRID_SECP384R1_KYBER_768_R3_OQS || + group == Group_Params::HYBRID_SECP521R1_KYBER_1024_R3_OQS; } constexpr bool is_kem(const Group_Params group) { diff --git a/src/lib/tls/tls_callbacks.cpp b/src/lib/tls/tls_callbacks.cpp index baaaf19bdb1..2d73aded82a 100644 --- a/src/lib/tls/tls_callbacks.cpp +++ b/src/lib/tls/tls_callbacks.cpp @@ -181,6 +181,9 @@ KEM_Encapsulation TLS::Callbacks::tls_kem_encapsulate(TLS::Group_Params group, return PK_KEM_Encryptor(*kem_pub_key, "Raw").encrypt(rng); } + // TODO: We could use the KEX_to_KEM_Adapter to remove the case distinction + // of KEM and KEX. However, the workarounds in this adapter class + // should first be addressed. auto ephemeral_keypair = tls_generate_ephemeral_key(group, rng); return KEM_Encapsulation(ephemeral_keypair->public_value(), tls_ephemeral_key_agreement(group, *ephemeral_keypair, encoded_public_key, rng, policy)); diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp index 8b4683523a2..7abe946d808 100644 --- a/src/lib/tls/tls_policy.cpp +++ b/src/lib/tls/tls_policy.cpp @@ -162,10 +162,6 @@ std::vector Policy::key_exchange_groups() const { Group_Params::X25519, #endif -#if defined(BOTAN_HAS_KYBER) - Group_Params::KYBER_512_R3, Group_Params::KYBER_768_R3, Group_Params::KYBER_1024_R3, -#endif - Group_Params::SECP256R1, Group_Params::BRAINPOOL256R1, Group_Params::SECP384R1, Group_Params::BRAINPOOL384R1, Group_Params::SECP521R1, Group_Params::BRAINPOOL512R1, diff --git a/src/scripts/test_cli.py b/src/scripts/test_cli.py index 3b7d0fd8d0a..4c27df7f7d6 100755 --- a/src/scripts/test_cli.py +++ b/src/scripts/test_cli.py @@ -976,11 +976,14 @@ def __init__(self, name, protocol_version, policy, **kwargs): psk=psk, psk_identity=psk_identity, stdout_regex=r'TLS v1.2 using ECDHE_PSK_.*'), - TestConfig("Hybrid PQC", "1.3", "allow_tls12=false\nallow_tls13=true\nkey_exchange_groups=Kyber-512-r3") + TestConfig("Kyber KEM", "1.3", "allow_tls12=false\nallow_tls13=true\nkey_exchange_groups=Kyber-512-r3"), + + TestConfig("Hybrid PQ/T", "1.3", "allow_tls12=false\nallow_tls13=true\nkey_exchange_groups=x25519/Kyber-512-r3"), ] with open(tls_server_policy, 'w', encoding='utf8') as f: - f.write('key_exchange_methods = ECDH DH ECDHE_PSK') + f.write('key_exchange_methods = ECDH DH ECDHE_PSK\n') + f.write("key_exchange_groups = x25519 secp256r1 ffdhe/ietf/2048 Kyber-512-r3 x25519/Kyber-512-r3") tls_server = subprocess.Popen([CLI_PATH, 'tls_server', '--max-clients=%d' % (len(configs)), '--port=%d' % (server_port), '--policy=%s' % (tls_server_policy),