Skip to content

Commit

Permalink
Merge pull request #3820 from Rohde-Schwarz/tls13/cli_client_hello_util
Browse files Browse the repository at this point in the history
[TLS 1.3] CLI: ./botan tls_client_hello can deal with TLS 1.3
  • Loading branch information
reneme authored Dec 6, 2023
2 parents 40751c6 + fb25f9e commit 6a6ba96
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 18 deletions.
68 changes: 54 additions & 14 deletions src/cli/tls_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
#include <botan/tls_messages.h>
#include <botan/tls_policy.h>
#include <botan/tls_version.h>
#include <botan/internal/fmt.h>
#include <botan/internal/loadstor.h>
#include <botan/internal/stl_util.h>
#include <sstream>

#include "tls_helpers.h"
Expand Down Expand Up @@ -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") {}
Expand Down Expand Up @@ -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) {
Expand All @@ -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<Botan::TLS::Client_Hello_13, Botan::TLS::Client_Hello_12>& 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";
Expand All @@ -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 << " ";
Expand All @@ -151,11 +165,35 @@ class TLS_Client_Hello_Reader final : public Command {
oss << "\n";
}

if(auto sg = hello_base.extensions().get<Botan::TLS::Supported_Groups>()) {
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<std::string, bool> 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<Botan::TLS::Key_Share>()) {
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";
Expand All @@ -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
13 changes: 9 additions & 4 deletions src/scripts/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 6a6ba96

Please sign in to comment.