172 lines
5.0 KiB
C++
172 lines
5.0 KiB
C++
// Copyright 2012 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "net/cert/mock_cert_verifier.h"
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "base/callback_list.h"
|
|
#include "base/functional/bind.h"
|
|
#include "base/location.h"
|
|
#include "base/memory/raw_ptr.h"
|
|
#include "base/memory/ref_counted.h"
|
|
#include "base/memory/weak_ptr.h"
|
|
#include "base/strings/pattern.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "base/task/single_thread_task_runner.h"
|
|
#include "net/base/net_errors.h"
|
|
#include "net/cert/cert_status_flags.h"
|
|
#include "net/cert/cert_verify_result.h"
|
|
#include "net/cert/x509_certificate.h"
|
|
|
|
namespace net {
|
|
|
|
struct MockCertVerifier::Rule {
|
|
Rule(scoped_refptr<X509Certificate> cert_arg,
|
|
const std::string& hostname_arg,
|
|
const CertVerifyResult& result_arg,
|
|
int rv_arg)
|
|
: cert(std::move(cert_arg)),
|
|
hostname(hostname_arg),
|
|
result(result_arg),
|
|
rv(rv_arg) {
|
|
DCHECK(cert);
|
|
DCHECK(result.verified_cert);
|
|
}
|
|
|
|
scoped_refptr<X509Certificate> cert;
|
|
std::string hostname;
|
|
CertVerifyResult result;
|
|
int rv;
|
|
};
|
|
|
|
class MockCertVerifier::MockRequest : public CertVerifier::Request {
|
|
public:
|
|
MockRequest(MockCertVerifier* parent,
|
|
CertVerifyResult* result,
|
|
CompletionOnceCallback callback)
|
|
: result_(result), callback_(std::move(callback)) {
|
|
subscription_ = parent->request_list_.Add(
|
|
base::BindOnce(&MockRequest::Cleanup, weak_factory_.GetWeakPtr()));
|
|
}
|
|
|
|
void ReturnResultLater(int rv, const CertVerifyResult& result) {
|
|
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
|
|
FROM_HERE, base::BindOnce(&MockRequest::ReturnResult,
|
|
weak_factory_.GetWeakPtr(), rv, result));
|
|
}
|
|
|
|
private:
|
|
void ReturnResult(int rv, const CertVerifyResult& result) {
|
|
// If the MockCertVerifier has been deleted, the callback will have been
|
|
// reset to null.
|
|
if (!callback_)
|
|
return;
|
|
|
|
*result_ = result;
|
|
std::move(callback_).Run(rv);
|
|
}
|
|
|
|
void Cleanup() {
|
|
// Note: May delete |this_|.
|
|
std::move(callback_).Reset();
|
|
}
|
|
|
|
raw_ptr<CertVerifyResult> result_;
|
|
CompletionOnceCallback callback_;
|
|
base::CallbackListSubscription subscription_;
|
|
|
|
base::WeakPtrFactory<MockRequest> weak_factory_{this};
|
|
};
|
|
|
|
MockCertVerifier::MockCertVerifier() = default;
|
|
|
|
MockCertVerifier::~MockCertVerifier() {
|
|
// Reset the callbacks for any outstanding MockRequests to fulfill the
|
|
// respective net::CertVerifier contract.
|
|
request_list_.Notify();
|
|
}
|
|
|
|
int MockCertVerifier::Verify(const RequestParams& params,
|
|
CertVerifyResult* verify_result,
|
|
CompletionOnceCallback callback,
|
|
std::unique_ptr<Request>* out_req,
|
|
const NetLogWithSource& net_log) {
|
|
if (!async_) {
|
|
return VerifyImpl(params, verify_result);
|
|
}
|
|
|
|
auto request =
|
|
std::make_unique<MockRequest>(this, verify_result, std::move(callback));
|
|
CertVerifyResult result;
|
|
int rv = VerifyImpl(params, &result);
|
|
request->ReturnResultLater(rv, result);
|
|
*out_req = std::move(request);
|
|
return ERR_IO_PENDING;
|
|
}
|
|
|
|
void MockCertVerifier::AddObserver(Observer* observer) {
|
|
observers_.AddObserver(observer);
|
|
}
|
|
|
|
void MockCertVerifier::RemoveObserver(Observer* observer) {
|
|
observers_.RemoveObserver(observer);
|
|
}
|
|
|
|
void MockCertVerifier::AddResultForCert(scoped_refptr<X509Certificate> cert,
|
|
const CertVerifyResult& verify_result,
|
|
int rv) {
|
|
AddResultForCertAndHost(std::move(cert), "*", verify_result, rv);
|
|
}
|
|
|
|
void MockCertVerifier::AddResultForCertAndHost(
|
|
scoped_refptr<X509Certificate> cert,
|
|
const std::string& host_pattern,
|
|
const CertVerifyResult& verify_result,
|
|
int rv) {
|
|
rules_.push_back(Rule(std::move(cert), host_pattern, verify_result, rv));
|
|
}
|
|
|
|
void MockCertVerifier::ClearRules() {
|
|
rules_.clear();
|
|
}
|
|
|
|
void MockCertVerifier::SimulateOnCertVerifierChanged() {
|
|
for (Observer& observer : observers_) {
|
|
observer.OnCertVerifierChanged();
|
|
}
|
|
}
|
|
|
|
int MockCertVerifier::VerifyImpl(const RequestParams& params,
|
|
CertVerifyResult* verify_result) {
|
|
for (const Rule& rule : rules_) {
|
|
// Check just the server cert. Intermediates will be ignored.
|
|
if (!rule.cert->EqualsExcludingChain(params.certificate().get()))
|
|
continue;
|
|
if (!base::MatchPattern(params.hostname(), rule.hostname))
|
|
continue;
|
|
*verify_result = rule.result;
|
|
return rule.rv;
|
|
}
|
|
|
|
// Fall through to the default.
|
|
verify_result->verified_cert = params.certificate();
|
|
verify_result->cert_status = MapNetErrorToCertStatus(default_result_);
|
|
return default_result_;
|
|
}
|
|
|
|
CertVerifierObserverCounter::CertVerifierObserverCounter(
|
|
CertVerifier* verifier) {
|
|
obs_.Observe(verifier);
|
|
}
|
|
|
|
CertVerifierObserverCounter::~CertVerifierObserverCounter() = default;
|
|
|
|
void CertVerifierObserverCounter::OnCertVerifierChanged() {
|
|
change_count_++;
|
|
}
|
|
|
|
} // namespace net
|