blob: 9086945d385d1cecbd723012d3d192efb5e8b0de [file]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/network/ssl_config_service_mojo.h"
#include <string_view>
#include "base/strings/string_util.h"
#include "mojo/public/cpp/bindings/type_converter.h"
#include "services/network/ssl_config_type_converter.h"
namespace network {
namespace {
// Returns true if |hostname| is a subdomain of |pattern| (including if they are
// equal).
bool IsSubdomain(std::string_view hostname, std::string_view pattern) {
if (hostname == pattern) {
return true;
}
if (hostname.length() <= (pattern.length() + 1)) {
return false;
}
if (!base::EndsWith(hostname, pattern)) {
return false;
}
return hostname[hostname.length() - pattern.length() - 1] == '.';
}
} // namespace
SSLConfigServiceMojo::SSLConfigServiceMojo(
mojom::SSLConfigPtr initial_config,
mojo::PendingReceiver<mojom::SSLConfigClient> ssl_config_client_receiver,
std::unique_ptr<net::EchModeGetter> ech_mode_getter)
: ech_mode_getter_(std::move(ech_mode_getter)),
client_cert_pooling_policy_(
initial_config ? initial_config->client_cert_pooling_policy
: std::vector<std::string>()) {
if (initial_config) {
ech_enabled_ = initial_config->ech_enabled;
cert_verifier_config_ = MojoSSLConfigToCertVerifierConfig(initial_config);
ssl_context_config_ = MojoSSLConfigToSSLContextConfig(initial_config);
}
if (ssl_config_client_receiver)
receiver_.Bind(std::move(ssl_config_client_receiver));
}
SSLConfigServiceMojo::~SSLConfigServiceMojo() = default;
void SSLConfigServiceMojo::SetCertVerifierForConfiguring(
net::CertVerifier* cert_verifier) {
cert_verifier_ = cert_verifier;
if (cert_verifier_) {
cert_verifier_->SetConfig(cert_verifier_config_);
}
}
void SSLConfigServiceMojo::OnSSLConfigUpdated(mojom::SSLConfigPtr ssl_config) {
// Connection pooling logic does not take into account EchMode. If ECH is
// enabled, or disabled, by a change in policy, force an update to clean up
// any existing connection. This makes it sure that we abide the new ECH
// policy. Note: we don't account for EchMode in the pooling logic because a
// change in policy is the only way to change EchMode for a given host.
bool force_notification =
client_cert_pooling_policy_ != ssl_config->client_cert_pooling_policy ||
ech_enabled_ != ssl_config->ech_enabled;
ech_enabled_ = ssl_config->ech_enabled;
client_cert_pooling_policy_ = ssl_config->client_cert_pooling_policy;
net::SSLContextConfig old_config = ssl_context_config_;
ssl_context_config_ = MojoSSLConfigToSSLContextConfig(ssl_config);
ProcessConfigUpdate(old_config, ssl_context_config_, force_notification);
net::CertVerifier::Config old_cert_verifier_config = cert_verifier_config_;
cert_verifier_config_ = MojoSSLConfigToCertVerifierConfig(ssl_config);
if (cert_verifier_ && (old_cert_verifier_config != cert_verifier_config_)) {
cert_verifier_->SetConfig(cert_verifier_config_);
}
}
net::SSLContextConfig SSLConfigServiceMojo::GetSSLContextConfig() {
return ssl_context_config_;
}
net::EchMode SSLConfigServiceMojo::GetEchMode(std::string_view hostname) const {
if (!ech_enabled_) {
return net::EchMode::kDisabled;
}
if (ech_mode_getter_) {
return ech_mode_getter_->GetEchMode(hostname);
}
return net::EchMode::kOpportunistic;
}
bool SSLConfigServiceMojo::CanShareConnectionWithClientCerts(
std::string_view hostname) const {
// Hostnames (and the patterns configured for this class) must be
// canonicalized before comparison, or the comparison will fail.
for (const std::string& pattern : client_cert_pooling_policy_) {
if (pattern.empty()) {
continue;
}
// If the pattern starts with a '.', |hostname| must match it exactly
// (except for the leading dot) for the pattern to be a match.
if (pattern[0] == '.') {
if (pattern.compare(1, std::string::npos, hostname) == 0) {
return true;
} else {
continue;
}
}
// Patterns that don't start with a dot match subdomains as well as an exact
// pattern match. For example, a pattern of "example.com" should match a
// hostname of "example.com", "sub.example.com", but not "notexample.com".
if (IsSubdomain(hostname, pattern)) {
return true;
}
}
return false;
}
} // namespace network