diff --git a/src/cli/tls_utils.cpp b/src/cli/tls_utils.cpp index 050f5b0d973..f4845268c84 100644 --- a/src/cli/tls_utils.cpp +++ b/src/cli/tls_utils.cpp @@ -12,7 +12,9 @@ #include #include #include + #include #include + #include #include #include "tls_helpers.h" @@ -58,6 +60,8 @@ class TLS_Ciphersuites final : public Command { BOTAN_REGISTER_COMMAND("tls_ciphers", TLS_Ciphersuites); + #if defined(BOTAN_HAS_TLS_13) + class TLS_Client_Hello_Reader final : public Command { public: TLS_Client_Hello_Reader() : Command("tls_client_hello --hex input") {} @@ -106,8 +110,7 @@ class TLS_Client_Hello_Reader final : public Command { } try { - // TODO: deal with Client_Hello_13 - Botan::TLS::Client_Hello_12 hello(input); + auto hello = Botan::TLS::Client_Hello_13::parse(input); output() << format_hello(hello); } catch(std::exception& e) { @@ -116,15 +119,26 @@ class TLS_Client_Hello_Reader final : public Command { } private: - static std::string format_hello(const Botan::TLS::Client_Hello_12& hello) { + static std::string format_hello( + const std::variant& hello) { std::ostringstream oss; - oss << "Version: " << hello.legacy_version().to_string() << "\n" - << "Random: " << Botan::hex_encode(hello.random()) << "\n"; - if(!hello.session_id().empty()) { - oss << "SessionID: " << Botan::hex_encode(hello.session_id().get()) << "\n"; + const auto& hello_base = + std::visit([](const auto& ch) -> const Botan::TLS::Client_Hello& { return ch; }, hello); + + const auto version = std::visit(Botan::overloaded{ + [](const Botan::TLS::Client_Hello_12&) { return "1.2"; }, + [](const Botan::TLS::Client_Hello_13&) { return "1.3"; }, + }, + hello); + + oss << "Version: " << version << "\n" + << "Random: " << Botan::hex_encode(hello_base.random()) << "\n"; + + if(!hello_base.session_id().empty()) { + oss << "SessionID: " << Botan::hex_encode(hello_base.session_id().get()) << "\n"; } - for(uint16_t csuite_id : hello.ciphersuites()) { + for(uint16_t csuite_id : hello_base.ciphersuites()) { const auto csuite = Botan::TLS::Ciphersuite::by_id(csuite_id); if(csuite && csuite->valid()) { oss << "Cipher: " << csuite->to_string() << "\n"; @@ -137,10 +151,10 @@ class TLS_Client_Hello_Reader final : public Command { oss << "Supported signature schemes: "; - if(hello.signature_schemes().empty()) { + if(hello_base.signature_schemes().empty()) { oss << "Did not send signature_algorithms extension\n"; } else { - for(Botan::TLS::Signature_Scheme scheme : hello.signature_schemes()) { + for(Botan::TLS::Signature_Scheme scheme : hello_base.signature_schemes()) { try { auto s = scheme.to_string(); oss << s << " "; @@ -151,11 +165,35 @@ class TLS_Client_Hello_Reader final : public Command { oss << "\n"; } + if(auto sg = hello_base.extensions().get()) { + oss << "Supported Groups: "; + for(const auto group : sg->groups()) { + oss << group.to_string().value_or(Botan::fmt("Unknown group: {}", group.wire_code())) << " "; + } + oss << "\n"; + } + std::map hello_flags; - hello_flags["ALPN"] = hello.supports_alpn(); - hello_flags["Encrypt Then Mac"] = hello.supports_encrypt_then_mac(); - hello_flags["Extended Master Secret"] = hello.supports_extended_master_secret(); - hello_flags["Session Ticket"] = hello.supports_session_ticket(); + hello_flags["ALPN"] = hello_base.supports_alpn(); + + std::visit(Botan::overloaded{ + [&](const Botan::TLS::Client_Hello_12& ch12) { + hello_flags["Encrypt Then Mac"] = ch12.supports_encrypt_then_mac(); + hello_flags["Extended Master Secret"] = ch12.supports_extended_master_secret(); + hello_flags["Session Ticket"] = ch12.supports_session_ticket(); + }, + [&](const Botan::TLS::Client_Hello_13& ch13) { + if(auto ks = ch13.extensions().get()) { + oss << "Key Shares: "; + for(const auto group : ks->offered_groups()) { + oss << group.to_string().value_or(Botan::fmt("Unknown group: {}", group.wire_code())) + << " "; + } + oss << "\n"; + } + }, + }, + hello); for(auto&& i : hello_flags) { oss << "Supports " << i.first << "? " << (i.second ? "yes" : "no") << "\n"; @@ -167,6 +205,8 @@ class TLS_Client_Hello_Reader final : public Command { BOTAN_REGISTER_COMMAND("tls_client_hello", TLS_Client_Hello_Reader); + #endif + } // namespace Botan_CLI #endif diff --git a/src/scripts/test_cli.py b/src/scripts/test_cli.py index 13fe9311d9c..62e0641deeb 100755 --- a/src/scripts/test_cli.py +++ b/src/scripts/test_cli.py @@ -1459,12 +1459,17 @@ def cli_uuid_tests(_tmp_dir): def cli_tls_client_hello_tests(_tmp_dir): - chello = "16030100cf010000cb03035b3cf2457b864d7bef2a4b1f84fc3ced2b68d9551f3455ffdd305af277a91bb200003a16b816b716ba16b9cca9cca8c02cc030c02bc02fc0adc0acc024c00ac028c014c023c009c027c013ccaa009f009ec09fc09e006b003900670033010000680000000e000c000009676d61696c2e636f6d000500050100000000000a001a0018001d0017001a0018001b0019001c01000101010201030104000b00020100000d00140012080508040806050106010401050306030403001600000017000000230000ff01000100" + chellos = [ + # TLS 1.2 + ("6073536D3FA201A37C1F3944F6DCDD5A83FAA67DF4B1C9CBE4FA4399FDE7673C", "16030100cf010000cb03035b3cf2457b864d7bef2a4b1f84fc3ced2b68d9551f3455ffdd305af277a91bb200003a16b816b716ba16b9cca9cca8c02cc030c02bc02fc0adc0acc024c00ac028c014c023c009c027c013ccaa009f009ec09fc09e006b003900670033010000680000000e000c000009676d61696c2e636f6d000500050100000000000a001a0018001d0017001a0018001b0019001c01000101010201030104000b00020100000d00140012080508040806050106010401050306030403001600000017000000230000ff01000100"), - output = test_cli("tls_client_hello", ["--hex", "-"], None, chello) + # TLS 1.3 + ("4D8BB87026C6AEB1356234A01BD62C7DEFB3FEA298B8C50900F5D3F3ADDAADEB", "1603010106010001020303657033B5C89B0356097C9D43B3917BC0D743E34CB118E1DD3FC806EC9CED2FB120657033B589AD50CADDC8CBA0B805A9841DB3A4F92334C1A44EE968DD4B2983450018130313021301CCA9CCA8C02CC030C02BC02FCCAA009F009E010000A10000000E000C0000096C6F63616C686F7374000A001A0018001D0017001A0018001B0019001C01000101010201030104003300260024001D002002CBD31A5D5754EFD5C8F5152E27302681278A710A22B04403EF9EF0F5F95C1E002B00050403040303000D00140012080508040806050106010401050306030403002D00020101000500050100000000FF01000100002300000017000000160000000B00020100"), + ] - output_hash = "D8D6717258CE7F2B10A6F59CCD065937CB9F3B6138319A548A7E0CFC2DF062BF" - test_cli("hash", ["--no-fsname", "--algo=SHA-256", "-"], output_hash, output) + for output_hash, chello in chellos: + output = test_cli("tls_client_hello", ["--hex", "-"], None, chello) + test_cli("hash", ["--no-fsname", "--algo=SHA-256", "-"], output_hash, output) def cli_speed_pk_tests(_tmp_dir): msec = 1