Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TLS 1.3] Limited TLS 1.3 Client Implementation #2922

Merged
merged 20 commits into from
Jul 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 185 additions & 49 deletions src/bogo_shim/bogo_shim.cpp

Large diffs are not rendered by default.

148 changes: 133 additions & 15 deletions src/bogo_shim/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
"Resume-Client-CipherMismatch": "Unexpected error",
"InvalidECDHPoint-Server": "Unexpected error",
"NoSharedCipher": "Unexpected error",
"NoSharedCipher-TLS13": "Unexpected error",

"PartialFinishedWithServerHelloDone": "Unexpected record vs excess handshake data"
"PartialFinishedWithServerHelloDone": "Unexpected record vs excess handshake data",
"HelloRetryRequest-DuplicateCurve-TLS13": "expects 'illegal parameter' but we want to stick with 'decode error'",
"HelloRetryRequest-DuplicateCookie-TLS13": "expects 'illegal parameter' but we want to stick with 'decode error'",
"EncryptedExtensionsWithKeyShare-TLS13": "expects 'unsupported extension' but RFC requires 'illegal parameter'"
},

"DisabledTests": {
Expand All @@ -27,21 +31,111 @@

"*SCSV*": "SCSV is meaningless without TLS 1.0/1.1 support",

"*KeyUpdate*": "No TLS 1.3",
"*TLS13*": "No TLS 1.3",
"Server-JDK11*": "No TLS 1.3",
"AllExtensions-*": "Not all extensions are implemented",

"EchoTLS13CompatibilitySessionID": "Succeeds, but we prepend a TLS 1.3 CCS and BoGo doesn't like that",

"Client-RejectJDK11DowngradeRandom": "We don't implement this workaround",
"ExportTrafficSecrets-*": "Exporting traffic secrets is not implemented",
"TooManyChangeCipherSpec-Client-TLS13": "Limits on the number of CCS are not implemented",
"TooManyKeyUpdates": "Limits on the number of KeyUpdates are not implemented",

"CertificateVerificationSucceed-Client-TLS13-*" : "TLS 1.3 session resumption is NYI",
"Client-VerifyDefault-*-TLS13" : "TLS 1.3 session resumption is NYI",
"Client-Verify-*-TLS13" : "TLS 1.3 session resumption is NYI",
"ExportKeyingMaterial-TLS13" : "TLS 1.3 session resumption is NYI",
"InvalidPSKIdentity-TLS13" : "TLS 1.3 session resumption is NYI",
"NegotiatePSKResumption-TLS13" : "TLS 1.3 session resumption is NYI",
"Resume-Client-CipherMismatch-TLS13" : "TLS 1.3 session resumption is NYI",
"Resume-Client-Mismatch-TLS13-TLS12-TLS" : "TLS 1.3 session resumption is NYI",
"Resume-Client-TLS13-TLS13-TLS" : "TLS 1.3 session resumption is NYI",
"TLS-TLS13-AES_128_GCM_SHA256-client" : "TLS 1.3 session resumption is NYI",
"TLS-TLS13-AES_256_GCM_SHA384-client" : "TLS 1.3 session resumption is NYI",
"TLS-TLS13-CHACHA20_POLY1305_SHA256-client" : "TLS 1.3 session resumption is NYI",
"TLS12SessionID-TLS13" : "TLS 1.3 session resumption is NYI",
"TLS13-HonorServerSessionTicketLifetime" : "TLS 1.3 session resumption is NYI",
"TLS13-TestBadTicketAge-Client" : "TLS 1.3 session resumption is NYI",
"TLS13-TestValidTicketAge-Client" : "TLS 1.3 session resumption is NYI",
"TLS13SessionID-TLS13" : "TLS 1.3 session resumption is NYI",
"TolerateServerNameAck-TLS-TLS13" : "TLS 1.3 session resumption is NYI",
"OCSPStapling-Client-TLS13-*" : "TLS 1.3 session resumption is NYI",
"Resume-Client-NoResume-TLS12-TLS13-TLS": "TLS 1.3 session resumption is NYI",
"Resume-Client-Mismatch-TLS12-TLS13-TLS": "TLS 1.3 session resumption is NYI",
"Ticket-Forbidden-TLS13": "TLS 1.3 session resumption is NYI",
"Resume-Client-PRFMismatch-TLS13": "TLS 1.3 session resumption is NYI",
"TLS13-HelloRetryRequest-Client-*": "TLS 1.3 session resumption is NYI",
"TLS13-TicketAgeSkew-*": "TLS 1.3 session resumption is NYI",
"CurveID-Resume-Client-TLS13": "TLS 1.3 session resumption is NYI",
"ALPNClient-TLS-TLS13": "TLS 1.3 session resumption is NYI",

"KeyUpdate-FromServer": "No TLS 1.3 server, yet",
"FragmentedClientVersion": "No TLS 1.3 server, yet",
"DelegatedCredentials*": "No TLS 1.3 server, yet",
"IgnoreClientVersionOrder": "No TLS 1.3 server, yet",
"Resume-Server-OmitPSKsOnSecondClientHello": "No TLS 1.3 server, yet",
"PartialClientFinishedWithSecondClientHello": "No TLS 1.3 server, yet",
"Server-JDK11*": "No TLS 1.3 server, yet",

"CertCompression*-TLS13": "No TLS 1.3 server, yet",
"DuplicateKeyShares-TLS13": "No TLS 1.3 server, yet",
"ECDSACurveMismatch-Sign-TLS13": "No TLS 1.3 server, yet",
"MinimumVersion-Server*-TLS13*": "No TLS 1.3 server, yet",
"Resume-Server*TLS13*": "No TLS 1.3 server, yet",
"Server-Sign-*-TLS13": "No TLS 1.3 server, yet",
"Server-Verify-*-TLS13": "No TLS 1.3 server, yet",
"Server-VerifyDefault-*-TLS13": "No TLS 1.3 server, yet",

"TLS-TLS13-*-server": "No TLS 1.3 server, yet",
"TLS13-Server-*": "No TLS 1.3 server, yet",
"TLS13-*-Server*": "No TLS 1.3 server, yet",
"*-Server-TLS13": "No TLS 1.3 server, yet",
"*-TLS13-Server": "No TLS 1.3 server, yet",
"RSAKeyUsage-Server-*-TLS13": "No TLS 1.3 server, yet",

"ExportKeyingMaterial-Server-HalfRTT-TLS13": "No TLS 1.3 server, yet",
"ExtraClientEncryptedExtension-TLS-TLS13": "No TLS 1.3 server, yet",
"ExtraCompressionMethods-TLS13": "No TLS 1.3 server, yet",
"LooseInitialRecordVersion-TLS13": "No TLS 1.3 server, yet",
"NoSupportedCurves-TLS13": "No TLS 1.3 server, yet",
"RequireAnyClientCertificate-TLS13": "No TLS 1.3 server, yet",
"SecondClientHelloMissingKeyShare-TLS13": "No TLS 1.3 server, yet",
"SecondClientHelloWrongCurve-TLS13": "No TLS 1.3 server, yet",
"SendExtensionOnClientCertificate-TLS13": "No TLS 1.3 server, yet",
"ServerAuth-NoFallback-TLS13": "No TLS 1.3 server, yet",
"ServerSkipCertificateVerify-TLS13": "No TLS 1.3 server, yet",
"SkipClientCertificate-TLS13": "No TLS 1.3 server, yet",
"TLS13-NoTicket-NoMint": "No TLS 1.3 server, yet",
"TrailingKeyShareData-TLS13": "No TLS 1.3 server, yet",
"UnexpectedClientEncryptedExtensions-TLS-TLS13": "No TLS 1.3 server, yet",
"UnknownCipher-TLS13": "No TLS 1.3 server, yet",
"VersionTolerance-TLS13": "No TLS 1.3 server, yet",

"*EarlyData*": "No TLS 1.3 Early Data, yet",
"TLS13-1RTT-Client-*": "No TLS 1.3 Early Data, yet",

"FailCertCallback-Client-TLS13": "No client auth in TLS 1.3, yet",
"Client-Sign*-TLS13": "No client auth in TLS 1.3, yet",
"TLS13-Client-ClientAuth-": "No client auth in TLS 1.3, yet",
"ClientAuth-*-TLS13": "No client auth in TLS 1.3, yet",
"TLS13-Client-ClientAuth-*": "No client auth in TLS 1.3, yet",
"NoClientCertificate-TLS13": "No client auth in TLS 1.3, yet",
"NoCommonAlgorithms-TLS13": "No client auth in TLS 1.3, yet",
"ClientAuth-*-TLS13-*": "No client auth in TLS 1.3, yet",
"TrailingMessageData-TLS13-CertificateRequest-TLS": "No client auth in TLS 1.3, yet",
"RequestContextInHandshake-TLS13": "No client auth in TLS 1.3, yet",
"UnknownExtensionInCertificateRequest-TLS13": "No client auth in TLS 1.3, yet",
"MissingSignatureAlgorithmsInCertificateRequest-TLS13": "No client auth in TLS 1.3, yet",
"ClientSkipCertificateVerify-TLS13": "No client auth in TLS 1.3, yet",
"SendReceiveIntermediate-Client-TLS13": "No client auth in TLS 1.3, yet",
"TLS13-Client-CertReq-CA-List": "No client auth in TLS 1.3, yet",
"SendNoClientCertificateExtensions-TLS13": "No client auth in TLS 1.3, yet",

"KeyUpdate-RequestACK-UnfinishedWrite": "-read-with-unfinished-write currently not supported in the shim",

"*Binder*": "No TLS 1.3",
"PartialEncryptedExtensionsWithServerHello": "No TLS 1.3",
"Client-RejectJDK11DowngradeRandom": "No TLS 1.3",
"FragmentedClientVersion": "No TLS 1.3",
"NoExportEarlyKeyingMaterial*": "No TLS 1.3",
"EarlyDataEnabled*": "No TLS 1.3",
"DelegatedCredentials*": "No TLS 1.3",
"ExportTrafficSecrets-*": "No TLS 1.3",
"IgnoreClientVersionOrder": "No TLS 1.3",
"Resume-Server-OmitPSKsOnSecondClientHello": "No TLS 1.3",
"PartialServerHelloWithHelloRetryRequest": "No TLS 1.3",
"PartialClientFinishedWithSecondClientHello": "No TLS 1.3",
"TLS-ECH*": "No ECH support",
"ECH*": "No ECH support",

"DuplicateCertCompressionExt*": "No support for 1.3 cert compression extension",
Expand Down Expand Up @@ -73,6 +167,8 @@
"*SCT*": "No support for SCT",
"Renegotiation-ChangeAuthProperties": "No support for SCT",
"UnsolicitedCertificateExtensions-*": "No support for SCT",
"IgnoreExtensionsOnIntermediates-TLS13": "No support for SCT",
"SendNoExtensionsOnIntermediate-TLS13": "No support for SCT",

"CertificateVerificationSoftFail*": "Fail, but don't fail... wtf?",

Expand Down Expand Up @@ -156,6 +252,28 @@
"PartialClientFinishedWithClientHello": "Need to check for buffered messages when CCS (bug)",
"SendUnencryptedFinished-DTLS": "Need to check for buffered messages when CCS (bug)",

"RSAKeyUsage-*-UnenforcedTLS*": "We always enforce key usage"
}
"RSAKeyUsage-*-UnenforcedTLS*": "We always enforce key usage",

"Basic-Client-RenewTicket*" : "Needs investigation -- apparently Botan TLS 1.2 does not fully support renewing tickets after resumption?",

"AllExtensions-Client-Permute-TLS-TLS12" : "Requires new shim flags that are NYI (as of March 2022)",
"AllExtensions-Client-Permute-DTLS-TLS12" : "Requires new shim flags that are NYI (as of March 2022)",
"EarlyData-WriteAfterEncryptedExtensions" : "Requires new shim flags that are NYI (as of March 2022)",
"EarlyData-WriteAfterServerHello" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-SignatureInput" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-KeyShare" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-HandshakerHelloRetryRequest" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-ShimHelloRetryRequest" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-SignatureAlgorithm" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-NoTickets1" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-NoTickets2" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-Version2" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-CertificateRequest" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-CertificateCompression-HandshakerOnly" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-CertificateCompression-ShimOnly" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-CertificateCompression-AlgorithmMismatch" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-CertificateCompression-InputMismatch" : "Requires new shim flags that are NYI (as of March 2022)",
"TLS-HintMismatch-Version1" : "Requires new shim flags that are NYI (as of March 2022)"

}
}
23 changes: 14 additions & 9 deletions src/cli/tls_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* (C) 2014,2015 Jack Lloyd
* 2016 Matthias Gierlings
* 2017 René Korthaus, Rohde & Schwarz Cybersecurity
* 2022 René Meusel, Hannes Rantzsch - neXenio GmbH
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
Expand Down Expand Up @@ -34,7 +35,7 @@ class TLS_Client final : public Command, public Botan::TLS::Callbacks
public:
TLS_Client()
: Command("tls_client host --port=443 --print-certs --policy=default "
"--skip-system-cert-store --trusted-cas= "
"--skip-system-cert-store --trusted-cas= --tls-version=default "
"--session-db= --session-db-pass= --next-protocols= --type=tcp "
"--client-cert= --client-cert-key=")
{
Expand Down Expand Up @@ -72,6 +73,7 @@ class TLS_Client final : public Command, public Botan::TLS::Callbacks
const std::string next_protos = get_arg("next-protocols");
const bool use_system_cert_store = flag_set("skip-system-cert-store") == false;
const std::string trusted_CAs = get_arg("trusted-cas");
const auto tls_version = get_arg("tls-version");

if(!sessions_db.empty())
{
Expand All @@ -95,22 +97,25 @@ class TLS_Client final : public Command, public Botan::TLS::Callbacks
throw CLI_Usage_Error("Invalid transport type '" + transport + "' for TLS");
}

const bool use_tcp = (transport == "tcp");

const std::vector<std::string> protocols_to_offer = Command::split_on(next_protos, ',');

Botan::TLS::Protocol_Version version =
use_tcp ? Botan::TLS::Protocol_Version::TLS_V12 : Botan::TLS::Protocol_Version::DTLS_V12;

if(!policy)
{
policy.reset(new Botan::TLS::Policy);
}

if(policy->acceptable_protocol_version(version) == false)
{
throw CLI_Usage_Error("The policy specified does not allow the requested TLS version");
const bool use_tcp = (transport == "tcp");
Botan::TLS::Protocol_Version version = policy->latest_supported_version(!use_tcp);

if(tls_version != "default") {
if(tls_version == "1.2") {
version = Botan::TLS::Protocol_Version::TLS_V12;
} else if (tls_version == "1.3") {
version = Botan::TLS::Protocol_Version::TLS_V13;
} else {
error_output() << "Unknown TLS protocol version " << tls_version << '\n';
}
}

struct sockaddr_storage addrbuf;
std::string hostname;
Expand Down
5 changes: 3 additions & 2 deletions src/cli/tls_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ class TLS_Client_Hello_Reader final : public Command

try
{
// TODO: deal with Client_Hello_13
Copy link
Collaborator Author

@hrantzsch hrantzsch Mar 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • allow printing Client_Hello_13 infos in cli utils

We'll need to allow deserializing a Client Hello w/o knowing if it'll be 1.2 or 1.3, just as we'll eventually need to do for the TLS 1.3 server.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to allow deserializing a Client Hello w/o knowing if it'll be 1.2 or 1.3, just as we'll eventually need to do for the TLS 1.3 server.

I feel, it would be fine to postpone that until the TLS 1.3 server is implemented.

Botan::TLS::Client_Hello_12 hello(input);

output() << format_hello(hello);
Expand Down Expand Up @@ -182,12 +183,12 @@ class TLS_Client_Hello_Reader final : public Command
{
try
{
auto s = sig_scheme_to_string(scheme);
auto s = scheme.to_string();
oss << s << " ";
}
catch(...)
{
oss << "(" << std::hex << static_cast<uint16_t>(scheme) << ") ";
oss << "(" << std::hex << static_cast<unsigned int>(scheme.wire_code()) << ") ";
}
}
oss << "\n";
Expand Down
1 change: 1 addition & 0 deletions src/lib/tls/info.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ tls_policy.h
tls_server.h
tls_session.h
tls_session_manager.h
tls_signature_scheme.h
tls_version.h
</header:public>

Expand Down
3 changes: 1 addition & 2 deletions src/lib/tls/msg_cert_req.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Certificate_Req::Certificate_Req(const std::vector<uint8_t>& buf)

for(size_t i = 0; i != algs.size(); i += 2)
{
m_schemes.push_back(static_cast<Signature_Scheme>(make_uint16(algs[i], algs[i+1])));
m_schemes.emplace_back(make_uint16(algs[i], algs[i+1]));
}

const uint16_t purported_size = reader.get_uint16_t();
Expand Down Expand Up @@ -161,5 +161,4 @@ std::vector<uint8_t> Certificate_Req::serialize() const

return buf;
}

}
76 changes: 67 additions & 9 deletions src/lib/tls/msg_cert_verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,28 +47,25 @@ Certificate_Verify::Certificate_Verify(const std::vector<uint8_t>& buf)
{
TLS_Data_Reader reader("CertificateVerify", buf);

m_scheme = static_cast<Signature_Scheme>(reader.get_uint16_t());
m_scheme = Signature_Scheme(reader.get_uint16_t());
m_signature = reader.get_range<uint8_t>(2, 0, 65535);
reader.assert_done();

if(m_scheme == Signature_Scheme::NONE)
if(!m_scheme.is_set())
{ throw Decoding_Error("Counterparty did not send hash/sig IDS"); }

}

/*
* Serialize a Certificate Verify message
*/
std::vector<uint8_t> Certificate_Verify::serialize() const
{
BOTAN_ASSERT_NOMSG(m_scheme.is_set());
std::vector<uint8_t> buf;

if(m_scheme != Signature_Scheme::NONE)
{
const uint16_t scheme_code = static_cast<uint16_t>(m_scheme);
buf.push_back(get_byte<0>(scheme_code));
buf.push_back(get_byte<1>(scheme_code));
}
const auto code = m_scheme.wire_code();
buf.push_back(get_byte<0>(code));
buf.push_back(get_byte<1>(code));

if(m_signature.size() > 0xFFFF)
{ throw Encoding_Error("Certificate_Verify signature too long to encode"); }
Expand Down Expand Up @@ -97,6 +94,65 @@ bool Certificate_Verify_12::verify(const X509_Certificate& cert,
state.callbacks().tls_verify_message(*key, format.first, format.second,
state.hash().get_contents(), m_signature);

#if defined(BOTAN_UNSAFE_FUZZER_MODE)
BOTAN_UNUSED(signature_valid);
return true;

#else
return signature_valid;

#endif
}

#if defined(BOTAN_HAS_TLS_13)

Certificate_Verify_13::Certificate_Verify_13(const std::vector<uint8_t>& buf,
const Connection_Side side)
: Certificate_Verify(buf)
, m_side(side)
{
if(!m_scheme.is_available())
{ throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Peer sent unknown signature scheme"); }

if(!m_scheme.is_compatible_with(Protocol_Version::TLS_V13))
{ throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Peer sent signature algorithm that is not suitable for TLS 1.3"); }
}

/*
* Verify a Certificate Verify message
*/
bool Certificate_Verify_13::verify(const X509_Certificate& cert,
Callbacks& callbacks,
const Transcript_Hash& transcript_hash) const
{
BOTAN_ASSERT_NOMSG(m_scheme.is_available());

// RFC 8446 4.2.3
// The keys found in certificates MUST [...] be of appropriate type for
// the signature algorithms they are used with.
if(m_scheme.algorithm_identifier() != cert.subject_public_key_algo())
{ throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Signature algorithm does not match certificate's public key"); }

std::vector<uint8_t> msg(64, 0x20);
msg.reserve(64 + 32 + 1 + transcript_hash.size());

const std::string context_string = (m_side == Botan::TLS::Connection_Side::SERVER)
? "TLS 1.3, server CertificateVerify"
: "TLS 1.3, client CertificateVerify";

msg.insert(msg.end(), context_string.cbegin(), context_string.cend());
msg.push_back(0x00);

msg.insert(msg.end(), transcript_hash.cbegin(), transcript_hash.cend());

const auto key = cert.load_subject_public_key();
const bool signature_valid =
callbacks.tls_verify_message(*key,
m_scheme.padding_string(),
m_scheme.format().value(),
msg,
m_signature);

#if defined(BOTAN_UNSAFE_FUZZER_MODE)
BOTAN_UNUSED(signature_valid);
return true;
Expand All @@ -105,4 +161,6 @@ bool Certificate_Verify_12::verify(const X509_Certificate& cert,
#endif
}

#endif // BOTAN_HAS_TLS_13

}
Loading