blob: 3723b10819ae6e92f885f3413d2ffaa87b9edde8 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/net/server_certificate_database_nss_migrator.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/bind_post_task.h"
#include "base/task/thread_pool.h"
#include "chrome/browser/net/server_certificate_database_service.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/scoped_nss_types.h"
#include "crypto/sha2.h"
#include "net/cert/internal/trust_store_nss.h"
#include "net/cert/nss_cert_database.h"
namespace net {
namespace {
auto MapTrust(const bssl::CertificateTrust& trust) {
if (trust.IsDistrusted()) {
return chrome_browser_server_certificate_database::CertificateTrust::
CERTIFICATE_TRUST_TYPE_DISTRUSTED;
}
if (trust.IsTrustAnchor() || trust.IsTrustLeaf()) {
return chrome_browser_server_certificate_database::CertificateTrust::
CERTIFICATE_TRUST_TYPE_TRUSTED;
}
return chrome_browser_server_certificate_database::CertificateTrust::
CERTIFICATE_TRUST_TYPE_UNSPECIFIED;
}
void MigrateCertsOnBackgroundThread(
std::vector<net::PlatformTrustStore::CertWithTrust> certs_to_migrate,
ServerCertificateDatabaseNSSMigrator::ResultCallback callback,
net::ServerCertificateDatabase* server_cert_database) {
ServerCertificateDatabaseNSSMigrator::MigrationResult result;
result.cert_count = certs_to_migrate.size();
for (net::PlatformTrustStore::CertWithTrust& cert_to_migrate :
certs_to_migrate) {
net::ServerCertificateDatabase::CertInformation cert_info(
cert_to_migrate.cert_bytes);
cert_info.cert_metadata.mutable_trust()->set_trust_type(
MapTrust(cert_to_migrate.trust));
std::vector<net::ServerCertificateDatabase::CertInformation> cert_infos;
cert_infos.push_back(std::move(cert_info));
bool ok = server_cert_database->InsertOrUpdateCerts(cert_infos);
if (!ok) {
result.error_count++;
LOG(ERROR) << "error importing cert " << cert_info.sha256hash_hex;
}
}
std::move(callback).Run(std::move(result));
}
void ReadNSSCertsOnBackgroundThread(
crypto::ScopedPK11Slot slot,
base::OnceCallback<
void(std::vector<net::PlatformTrustStore::CertWithTrust>)> callback) {
TrustStoreNSS trust_store_nss(
TrustStoreNSS::UserSlotTrustSetting(std::move(slot)));
std::move(callback).Run(trust_store_nss.GetAllUserAddedCerts());
}
void GotNSSCertDatabaseOnIOThread(
base::OnceCallback<
void(std::vector<net::PlatformTrustStore::CertWithTrust>)> callback,
net::NSSCertDatabase* cert_db) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce(&ReadNSSCertsOnBackgroundThread, cert_db->GetPublicSlot(),
std::move(callback)));
}
void GetNSSCertDatabaseOnIOThread(
ServerCertificateDatabaseNSSMigrator::NssCertDatabaseGetter database_getter,
base::OnceCallback<
void(std::vector<net::PlatformTrustStore::CertWithTrust>)> callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
auto split_callback = base::SplitOnceCallback(
base::BindOnce(&GotNSSCertDatabaseOnIOThread, std::move(callback)));
net::NSSCertDatabase* cert_db =
std::move(database_getter).Run(std::move(split_callback.first));
// If the NSS database was already available, |cert_db| is non-null and
// |did_get_cert_db_callback| has not been called. Call it explicitly.
if (cert_db) {
std::move(split_callback.second).Run(cert_db);
}
}
} // namespace
ServerCertificateDatabaseNSSMigrator::ServerCertificateDatabaseNSSMigrator(
net::ServerCertificateDatabaseService* cert_db_service,
NssCertDatabaseGetter nss_cert_db_getter)
: cert_db_service_(cert_db_service),
nss_cert_db_getter_(std::move(nss_cert_db_getter)) {}
ServerCertificateDatabaseNSSMigrator::~ServerCertificateDatabaseNSSMigrator() =
default;
void ServerCertificateDatabaseNSSMigrator::MigrateCerts(
ResultCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(
&GetNSSCertDatabaseOnIOThread, std::move(nss_cert_db_getter_),
base::BindPostTaskToCurrentDefault(base::BindOnce(
&ServerCertificateDatabaseNSSMigrator::GotCertsFromNSS,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)))));
}
void ServerCertificateDatabaseNSSMigrator::GotCertsFromNSS(
ResultCallback callback,
std::vector<net::PlatformTrustStore::CertWithTrust> certs_to_migrate) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
cert_db_service_->PostTaskWithDatabase(base::BindOnce(
&MigrateCertsOnBackgroundThread, std::move(certs_to_migrate),
base::BindPostTaskToCurrentDefault(base::BindOnce(
&ServerCertificateDatabaseNSSMigrator::FinishedMigration,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)))));
}
void ServerCertificateDatabaseNSSMigrator::FinishedMigration(
ResultCallback callback,
MigrationResult result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::move(callback).Run(std::move(result));
// `this` object may be deleted by the callback, do not access object after
// this point.
}
} // namespace net