#include "services/network/ignore_errors_cert_verifier.h"
#include <algorithm>
#include <iterator>
#include <string_view>
#include <utility>
#include "base/base64.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string_split.h"
#include "crypto/hash.h"
#include "net/base/hash_value.h"
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
#include "net/cert/asn1_util.h"
#include "net/cert/cert_verify_result.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
#include "services/network/public/cpp/network_switches.h"
#include "services/network/public/cpp/spki_hash_set.h"
using ::net::CertVerifier;
using ::net::HashValue;
using ::net::SHA256HashValue;
using ::net::X509Certificate;
namespace network {
std::unique_ptr<CertVerifier> IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
const base::CommandLine& command_line,
const char* user_data_dir_switch,
std::unique_ptr<CertVerifier> verifier) {
if ((user_data_dir_switch && !command_line.HasSwitch(user_data_dir_switch)) ||
!command_line.HasSwitch(switches::kIgnoreCertificateErrorsSPKIList)) {
return verifier;
}
auto spki_list =
base::SplitString(command_line.GetSwitchValueASCII(
switches::kIgnoreCertificateErrorsSPKIList),
",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
return std::make_unique<IgnoreErrorsCertVerifier>(
std::move(verifier), CreateSPKIHashSet(spki_list));
}
IgnoreErrorsCertVerifier::IgnoreErrorsCertVerifier(
std::unique_ptr<CertVerifier> verifier,
SPKIHashSet allowlist)
: verifier_(std::move(verifier)), allowlist_(std::move(allowlist)) {}
IgnoreErrorsCertVerifier::~IgnoreErrorsCertVerifier() {}
int IgnoreErrorsCertVerifier::Verify(const RequestParams& params,
net::CertVerifyResult* verify_result,
net::CompletionOnceCallback callback,
std::unique_ptr<Request>* out_req,
const net::NetLogWithSource& net_log) {
std::vector<SHA256HashValue> public_key_hashes;
for (const auto& buffer : params.certificate()->cert_buffers()) {
std::string_view cert_spki;
if (net::asn1::ExtractSPKIFromDERCert(
net::x509_util::CryptoBufferAsStringPiece(buffer.get()),
&cert_spki)) {
public_key_hashes.push_back(crypto::hash::Sha256(cert_spki));
}
}
bool ignore_errors = false;
for (const auto& spki : public_key_hashes) {
if (allowlist_.contains(spki)) {
ignore_errors = true;
break;
}
}
if (ignore_errors) {
verify_result->Reset();
verify_result->verified_cert = params.certificate();
verify_result->public_key_hashes = std::move(public_key_hashes);
if (!params.ocsp_response().empty()) {
verify_result->ocsp_result.response_status =
bssl::OCSPVerifyResult::PROVIDED;
verify_result->ocsp_result.revocation_status =
bssl::OCSPRevocationStatus::GOOD;
}
return net::OK;
}
return verifier_->Verify(params, verify_result, std::move(callback), out_req,
net_log);
}
void IgnoreErrorsCertVerifier::Verify2QwacBinding(
const std::string& binding,
const std::string& hostname,
const scoped_refptr<X509Certificate>& tls_cert,
base::OnceCallback<void(const scoped_refptr<X509Certificate>&)> callback,
const net::NetLogWithSource& net_log) {
verifier_->Verify2QwacBinding(binding, hostname, tls_cert,
std::move(callback), net_log);
}
void IgnoreErrorsCertVerifier::SetConfig(const Config& config) {
verifier_->SetConfig(config);
}
void IgnoreErrorsCertVerifier::AddObserver(Observer* observer) {
verifier_->AddObserver(observer);
}
void IgnoreErrorsCertVerifier::RemoveObserver(Observer* observer) {
verifier_->RemoveObserver(observer);
}
void IgnoreErrorsCertVerifier::SetAllowlistForTesting(
const SPKIHashSet& allowlist) {
allowlist_ = allowlist;
}
}