Skip to content

Commit

Permalink
[EV] Clear Cached Client Cert When Reported
Browse files Browse the repository at this point in the history
When the enterprise.reportingPrivate.getCertificate extension is called,
propagate a notification through the network service to clear the
cached client certificate for a particular host, and have the existing connections flushed, if the cached certificate does not match the one
about to be reported.

Wrapped the trigger (in the browser process) behind a disabled feature
flag.

Bug: b:280693847
Change-Id: I38e5abce072d3b51d6c245148780d5cc8d7ed7f0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4774601
Commit-Queue: Sébastien Lalancette <seblalancette@chromium.org>
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
Reviewed-by: Matt Mueller <mattm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1187504}
  • Loading branch information
Sebastien Lalancette authored and Chromium LUCI CQ committed Aug 23, 2023
1 parent 667123d commit e14bb0e
Show file tree
Hide file tree
Showing 15 changed files with 647 additions and 60 deletions.
75 changes: 62 additions & 13 deletions chrome/browser/enterprise/signals/client_certificate_fetcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,53 +11,94 @@
#include "chrome/browser/net/profile_network_context_service.h"
#include "chrome/browser/net/profile_network_context_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "components/device_signals/core/common/signals_features.h"
#include "net/cert/cert_database.h"
#include "net/ssl/client_cert_identity.h"
#include "net/ssl/client_cert_store.h"
#include "net/ssl/ssl_cert_request_info.h"

namespace enterprise_signals {

class ProfileNetworkContextServiceWrapperImpl
: public ProfileNetworkContextServiceWrapper {
public:
explicit ProfileNetworkContextServiceWrapperImpl(
ProfileNetworkContextService* profile_network_context_service)
: profile_network_context_service_(profile_network_context_service) {
CHECK(profile_network_context_service_);
}

~ProfileNetworkContextServiceWrapperImpl() override = default;

// ProfileNetworkContextServiceWrapper:
std::unique_ptr<net::ClientCertStore> CreateClientCertStore() override {
return profile_network_context_service_->CreateClientCertStore();
}

void FlushCachedClientCertIfNeeded(
const net::HostPortPair& host,
const scoped_refptr<net::X509Certificate>& certificate) override {
profile_network_context_service_->FlushCachedClientCertIfNeeded(
host, certificate);
}

private:
raw_ptr<ProfileNetworkContextService> profile_network_context_service_;
};

ClientCertificateFetcher::ClientCertificateFetcher(
std::unique_ptr<net::ClientCertStore> client_cert_store,
content::BrowserContext* browser_context)
: client_cert_store_(std::move(client_cert_store)),
profile_(Profile::FromBrowserContext(browser_context)) {}
std::unique_ptr<ProfileNetworkContextServiceWrapper>
profile_network_context_service_wrapper,
Profile* profile)
: profile_network_context_service_wrapper_(
std::move(profile_network_context_service_wrapper)),
profile_(profile) {
CHECK(profile_network_context_service_wrapper_);
CHECK(profile_);
client_cert_store_ =
profile_network_context_service_wrapper_->CreateClientCertStore();
}

ClientCertificateFetcher::~ClientCertificateFetcher() = default;

// static
std::unique_ptr<ClientCertificateFetcher> ClientCertificateFetcher::Create(
content::BrowserContext* browser_context) {
auto* profile_network_context_service =
ProfileNetworkContextServiceFactory::GetForContext(browser_context);
if (!profile_network_context_service) {
return nullptr;
}

return std::make_unique<ClientCertificateFetcher>(
ProfileNetworkContextServiceFactory::GetForContext(browser_context)
->CreateClientCertStore(),
browser_context);
std::make_unique<ProfileNetworkContextServiceWrapperImpl>(
profile_network_context_service),
Profile::FromBrowserContext(browser_context));
}

void ClientCertificateFetcher::FetchAutoSelectedCertificateForUrl(
const GURL& url,
FetchAutoSelectedCertificateForUrlCallback callback) {
if (!client_cert_store_) {
if (!url.is_valid() || !client_cert_store_) {
std::move(callback).Run(nullptr);
return;
}

requesting_url_ = url;

fetch_callback_ = std::move(callback);
cert_request_info_ = base::MakeRefCounted<net::SSLCertRequestInfo>();
client_cert_store_->GetClientCerts(
*cert_request_info_,
base::BindOnce(&ClientCertificateFetcher::OnGetClientCertsComplete,
weak_ptr_factory_.GetWeakPtr()));
weak_ptr_factory_.GetWeakPtr(), url));
}

void ClientCertificateFetcher::OnGetClientCertsComplete(
const GURL& url,
net::ClientCertIdentityList client_certs) {
net::ClientCertIdentityList matching_certificates, nonmatching_certificates;
chrome::enterprise_util::AutoSelectCertificates(
profile_, requesting_url_, std::move(client_certs),
&matching_certificates, &nonmatching_certificates);
profile_, url, std::move(client_certs), &matching_certificates,
&nonmatching_certificates);

std::unique_ptr<net::ClientCertIdentity> selected_cert;
if (!matching_certificates.empty()) {
Expand All @@ -66,6 +107,14 @@ void ClientCertificateFetcher::OnGetClientCertsComplete(
selected_cert = std::move(matching_certificates[0]);
}

// Make sure the network stack's cached client certificate matches with the
// one that is about to be returned (or not).
if (features::IsClearClientCertsOnExtensionReportEnabled()) {
profile_network_context_service_wrapper_->FlushCachedClientCertIfNeeded(
net::HostPortPair::FromURL(url),
selected_cert ? selected_cert->certificate() : nullptr);
}

std::move(fetch_callback_).Run(std::move(selected_cert));
}

Expand Down
27 changes: 21 additions & 6 deletions chrome/browser/enterprise/signals/client_certificate_fetcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "net/base/host_port_pair.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/client_cert_identity.h"
#include "url/gurl.h"

Expand All @@ -25,11 +27,23 @@ class SSLCertRequestInfo;

namespace enterprise_signals {

// Class that wraps a ProfileNetworkContextService instance to allow easier
// mocking of that instance in unit tests.
class ProfileNetworkContextServiceWrapper {
public:
virtual ~ProfileNetworkContextServiceWrapper() = default;

virtual std::unique_ptr<net::ClientCertStore> CreateClientCertStore() = 0;
virtual void FlushCachedClientCertIfNeeded(
const net::HostPortPair& host,
const scoped_refptr<net::X509Certificate>& certificate) = 0;
};

class ClientCertificateFetcher {
public:
ClientCertificateFetcher(
std::unique_ptr<net::ClientCertStore> client_cert_store,
content::BrowserContext* browser_context);
ClientCertificateFetcher(std::unique_ptr<ProfileNetworkContextServiceWrapper>
profile_network_context_service_wrapper,
Profile* profile);
~ClientCertificateFetcher();

static std::unique_ptr<ClientCertificateFetcher> Create(
Expand All @@ -43,13 +57,14 @@ class ClientCertificateFetcher {
FetchAutoSelectedCertificateForUrlCallback callback);

private:
void OnGetClientCertsComplete(net::ClientCertIdentityList client_certs);
void OnGetClientCertsComplete(const GURL& url,
net::ClientCertIdentityList client_certs);

std::unique_ptr<ProfileNetworkContextServiceWrapper>
profile_network_context_service_wrapper_;
std::unique_ptr<net::ClientCertStore> client_cert_store_;
raw_ptr<Profile> profile_;

GURL requesting_url_;

FetchAutoSelectedCertificateForUrlCallback fetch_callback_;
scoped_refptr<net::SSLCertRequestInfo> cert_request_info_;

Expand Down

0 comments on commit e14bb0e

Please sign in to comment.