1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/cert_verifier/cert_verifier_service.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "mojo/public/cpp/bindings/remote.h"
10 #include "net/base/completion_once_callback.h"
11 #include "services/cert_verifier/cert_net_url_loader/cert_net_fetcher_url_loader.h"
12 #include "services/network/public/mojom/cert_verifier_service.mojom.h"
13
14 namespace cert_verifier {
15 namespace internal {
16
17 namespace {
18
19 // Owns everything once |Verify()| is called on the underlying CertVerifier.
20 // Handles disconnection of the remote cert verification request gracefully.
21 class CertVerifyResultHelper {
22 public:
23 CertVerifyResultHelper() = default;
24
Initialize(mojo::PendingRemote<mojom::CertVerifierRequest> request,std::unique_ptr<net::CertVerifyResult> result)25 void Initialize(mojo::PendingRemote<mojom::CertVerifierRequest> request,
26 std::unique_ptr<net::CertVerifyResult> result) {
27 request_.Bind(std::move(request));
28 result_ = std::move(result);
29
30 // base::Unretained is safe because |request_| is owned by this object, so
31 // the disconnect handler cannot be called after this object is destroyed.
32 request_.set_disconnect_handler(base::BindOnce(
33 &CertVerifyResultHelper::DisconnectRequest, base::Unretained(this)));
34 }
35
36 // This member function is meant to be wrapped in a OnceCallback that owns
37 // |this|, and passed to |CertVerifier::Verify()|.
CompleteCertVerifierRequest(int net_error)38 void CompleteCertVerifierRequest(int net_error) {
39 DCHECK(request_.is_bound());
40 DCHECK(local_request_);
41 DCHECK(result_);
42
43 request_->Complete(*result_, net_error);
44
45 // After returning from this function, |this| will be deleted.
46 }
47
DisconnectRequest()48 void DisconnectRequest() {
49 DCHECK(request_.is_bound());
50 DCHECK(local_request_);
51 DCHECK(result_);
52
53 // |request_| disconnected. At this point we should delete our
54 // |local_request_| to pass on the "cancellation message" to the underlying
55 // cert verifier. Deleting |local_request_| will also delete |this|.
56 // Deleting |local_request_| also guarantees that
57 // CompleteCertVerifierRequest() will never get called.
58 local_request_.reset();
59 }
60
local_request()61 std::unique_ptr<net::CertVerifier::Request>* local_request() {
62 return &local_request_;
63 }
64
65 private:
66 mojo::Remote<mojom::CertVerifierRequest> request_;
67 std::unique_ptr<net::CertVerifyResult> result_;
68 std::unique_ptr<net::CertVerifier::Request> local_request_;
69 };
70
ReconnectURLLoaderFactory(mojo::Remote<mojom::URLLoaderFactoryConnector> * reconnector,mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)71 void ReconnectURLLoaderFactory(
72 mojo::Remote<mojom::URLLoaderFactoryConnector>* reconnector,
73 mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) {
74 (*reconnector)->CreateURLLoaderFactory(std::move(receiver));
75 }
76
77 } // namespace
78
CertVerifierServiceImpl(std::unique_ptr<net::CertVerifier> verifier,mojo::PendingReceiver<mojom::CertVerifierService> receiver,scoped_refptr<CertNetFetcherURLLoader> cert_net_fetcher)79 CertVerifierServiceImpl::CertVerifierServiceImpl(
80 std::unique_ptr<net::CertVerifier> verifier,
81 mojo::PendingReceiver<mojom::CertVerifierService> receiver,
82 scoped_refptr<CertNetFetcherURLLoader> cert_net_fetcher)
83 : verifier_(std::move(verifier)),
84 receiver_(this, std::move(receiver)),
85 cert_net_fetcher_(std::move(cert_net_fetcher)) {
86 // base::Unretained is safe because |this| owns |receiver_|, so deleting
87 // |this| will prevent |receiver_| from calling this callback.
88 receiver_.set_disconnect_handler(
89 base::BindRepeating(&CertVerifierServiceImpl::OnDisconnectFromService,
90 base::Unretained(this)));
91 }
92
93 // Note: this object owns the underlying CertVerifier, which owns all of the
94 // callbacks passed to their Verify methods. These callbacks own the
95 // mojo::Remote<CertVerifierRequest> objects, so destroying this object cancels
96 // the verifications and all the callbacks.
~CertVerifierServiceImpl()97 CertVerifierServiceImpl::~CertVerifierServiceImpl() {
98 if (cert_net_fetcher_)
99 cert_net_fetcher_->Shutdown();
100 }
101
SetConfig(const net::CertVerifier::Config & config)102 void CertVerifierServiceImpl::SetConfig(
103 const net::CertVerifier::Config& config) {
104 verifier_->SetConfig(config);
105 }
106
EnableNetworkAccess(mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory,mojo::PendingRemote<mojom::URLLoaderFactoryConnector> reconnector)107 void CertVerifierServiceImpl::EnableNetworkAccess(
108 mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory,
109 mojo::PendingRemote<mojom::URLLoaderFactoryConnector> reconnector) {
110 if (cert_net_fetcher_) {
111 auto reconnect_cb =
112 std::make_unique<mojo::Remote<mojom::URLLoaderFactoryConnector>>(
113 std::move(reconnector));
114 cert_net_fetcher_->SetURLLoaderFactoryAndReconnector(
115 std::move(url_loader_factory),
116 base::BindRepeating(&ReconnectURLLoaderFactory,
117 base::Owned(std::move(reconnect_cb))));
118 }
119 }
120
Verify(const net::CertVerifier::RequestParams & params,mojo::PendingRemote<mojom::CertVerifierRequest> cert_verifier_request)121 void CertVerifierServiceImpl::Verify(
122 const net::CertVerifier::RequestParams& params,
123 mojo::PendingRemote<mojom::CertVerifierRequest> cert_verifier_request) {
124 DVLOG(3) << "Received certificate validation request for hostname: "
125 << params.hostname();
126 auto result = std::make_unique<net::CertVerifyResult>();
127
128 auto result_helper = std::make_unique<CertVerifyResultHelper>();
129
130 CertVerifyResultHelper* result_helper_ptr = result_helper.get();
131
132 // It's okay for this callback to delete |result_helper| and its
133 // |local_request_| variable, as CertVerifier::Verify allows it, even though
134 // in MultiThreadedCertVerifier, |local_request_| will in turn own this
135 // callback. |local_request_| gives up ownership of the callback before
136 // calling it.
137 net::CompletionOnceCallback callback =
138 base::BindOnce(&CertVerifyResultHelper::CompleteCertVerifierRequest,
139 std::move(result_helper));
140
141 int net_err = verifier_->Verify(
142 params, result.get(), std::move(callback),
143 result_helper_ptr->local_request(),
144 net::NetLogWithSource::Make(net::NetLog::Get(),
145 net::NetLogSourceType::CERT_VERIFIER_JOB));
146 if (net_err == net::ERR_IO_PENDING) {
147 // If this request is to be completely asynchronously, give the callback
148 // ownership of our mojom::CertVerifierRequest and net::CertVerifyResult.
149 result_helper_ptr->Initialize(std::move(cert_verifier_request),
150 std::move(result));
151 } else {
152 // If we already finished, then we can just complete the request
153 // immediately.
154 mojo::Remote<mojom::CertVerifierRequest> remote(
155 std::move(cert_verifier_request));
156 remote->Complete(*result, net_err);
157 }
158 }
159
OnDisconnectFromService()160 void CertVerifierServiceImpl::OnDisconnectFromService() {
161 delete this;
162 }
163
164 } // namespace internal
165 } // namespace cert_verifier
166