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