1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 11:37:44 +00:00

LibTLS: Simplify the way verify_chain is called

The `build_rsa_pre_master_secret` function originally called
`verify_chain_and_get_matching_certificate`, which verified the chain
and returned a certificate matching the specified hostname.

Since the first certificate in the chain should always be the one
matching with the hostname, we can simply use that one instead. This
means we can completely remove this method and just use `verify_chain`.

To make sure the hostname is still verified, `verify_chain` now also
checks that the first certificate in the chain matches the specified
hostname. If the hostname is empty, we currently fail the verification,
however this basically never happen, as the server name indication
extension is always used.
This commit is contained in:
Michiel Visser 2022-03-15 19:16:44 +01:00 committed by Ali Mohammad Pur
parent f8ce0eb648
commit d78813d902
3 changed files with 47 additions and 58 deletions

View file

@ -191,7 +191,31 @@ void TLSv12::set_root_certificates(Vector<Certificate> certificates)
dbgln_if(TLS_DEBUG, "{}: Set {} root certificates", this, m_context.root_certificates.size());
}
bool Context::verify_chain() const
static bool wildcard_matches(StringView host, StringView subject)
{
if (host.matches(subject))
return true;
if (subject.starts_with("*."))
return wildcard_matches(host, subject.substring_view(2));
return false;
}
static bool certificate_subject_matches_host(Certificate& cert, StringView host)
{
if (wildcard_matches(host, cert.subject.subject))
return true;
for (auto& san : cert.SAN) {
if (wildcard_matches(host, san))
return true;
}
return false;
}
bool Context::verify_chain(StringView host) const
{
if (!options.validate_certificates)
return true;
@ -209,6 +233,19 @@ bool Context::verify_chain() const
return false;
}
if (!host.is_empty()) {
auto first_certificate = local_chain->first();
auto subject_matches = certificate_subject_matches_host(first_certificate, host);
if (!subject_matches) {
dbgln("verify_chain: First certificate does not match the hostname");
return false;
}
} else {
// FIXME: The host is taken from m_context.extensions.SNI, when is this empty?
dbgln("FIXME: verify_chain called without host");
return false;
}
for (size_t cert_index = 0; cert_index < local_chain->size(); ++cert_index) {
auto cert = local_chain->at(cert_index);