1 //
2 //
3 // Copyright 2020 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <grpc/support/port_platform.h>
20
21 #include "src/core/ext/xds/xds_certificate_provider.h"
22
23 #include <utility>
24
25 #include "absl/functional/bind_front.h"
26 #include "absl/types/optional.h"
27
28 #include <grpc/support/log.h>
29
30 #include "src/core/lib/channel/channel_args.h"
31 #include "src/core/lib/iomgr/error.h"
32 #include "src/core/lib/security/security_connector/ssl_utils.h"
33
34 namespace grpc_core {
35
36 namespace {
37
38 class RootCertificatesWatcher
39 : public grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface {
40 public:
41 // Takes a ref to \a parent instead of a raw pointer since the watcher is
42 // owned by the root certificate distributor and not by \a parent. Note that
43 // presently, the watcher is immediately deleted when
44 // CancelTlsCertificatesWatch() is called, but that can potentially change in
45 // the future.
RootCertificatesWatcher(RefCountedPtr<grpc_tls_certificate_distributor> parent,std::string cert_name)46 RootCertificatesWatcher(
47 RefCountedPtr<grpc_tls_certificate_distributor> parent,
48 std::string cert_name)
49 : parent_(std::move(parent)), cert_name_(std::move(cert_name)) {}
50
OnCertificatesChanged(absl::optional<absl::string_view> root_certs,absl::optional<PemKeyCertPairList>)51 void OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
52 absl::optional<PemKeyCertPairList>
53 /* key_cert_pairs */) override {
54 if (root_certs.has_value()) {
55 parent_->SetKeyMaterials(cert_name_, std::string(root_certs.value()),
56 absl::nullopt);
57 }
58 }
59
OnError(grpc_error_handle root_cert_error,grpc_error_handle)60 void OnError(grpc_error_handle root_cert_error,
61 grpc_error_handle /*identity_cert_error*/) override {
62 if (!root_cert_error.ok()) {
63 parent_->SetErrorForCert(cert_name_, root_cert_error /* pass the ref */,
64 absl::nullopt);
65 }
66 }
67
68 private:
69 RefCountedPtr<grpc_tls_certificate_distributor> parent_;
70 std::string cert_name_;
71 };
72
73 class IdentityCertificatesWatcher
74 : public grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface {
75 public:
76 // Takes a ref to \a parent instead of a raw pointer since the watcher is
77 // owned by the root certificate distributor and not by \a parent. Note that
78 // presently, the watcher is immediately deleted when
79 // CancelTlsCertificatesWatch() is called, but that can potentially change in
80 // the future.
IdentityCertificatesWatcher(RefCountedPtr<grpc_tls_certificate_distributor> parent,std::string cert_name)81 IdentityCertificatesWatcher(
82 RefCountedPtr<grpc_tls_certificate_distributor> parent,
83 std::string cert_name)
84 : parent_(std::move(parent)), cert_name_(std::move(cert_name)) {}
85
OnCertificatesChanged(absl::optional<absl::string_view>,absl::optional<PemKeyCertPairList> key_cert_pairs)86 void OnCertificatesChanged(
87 absl::optional<absl::string_view> /* root_certs */,
88 absl::optional<PemKeyCertPairList> key_cert_pairs) override {
89 if (key_cert_pairs.has_value()) {
90 parent_->SetKeyMaterials(cert_name_, absl::nullopt, key_cert_pairs);
91 }
92 }
93
OnError(grpc_error_handle,grpc_error_handle identity_cert_error)94 void OnError(grpc_error_handle /*root_cert_error*/,
95 grpc_error_handle identity_cert_error) override {
96 if (!identity_cert_error.ok()) {
97 parent_->SetErrorForCert(cert_name_, absl::nullopt,
98 identity_cert_error /* pass the ref */);
99 }
100 }
101
102 private:
103 RefCountedPtr<grpc_tls_certificate_distributor> parent_;
104 std::string cert_name_;
105 };
106
107 } // namespace
108
109 //
110 // XdsCertificateProvider::ClusterCertificateState
111 //
112
~ClusterCertificateState()113 XdsCertificateProvider::ClusterCertificateState::~ClusterCertificateState() {
114 if (root_cert_watcher_ != nullptr) {
115 root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_);
116 }
117 if (identity_cert_watcher_ != nullptr) {
118 identity_cert_distributor_->CancelTlsCertificatesWatch(
119 identity_cert_watcher_);
120 }
121 }
122
IsSafeToRemove() const123 bool XdsCertificateProvider::ClusterCertificateState::IsSafeToRemove() const {
124 return !watching_root_certs_ && !watching_identity_certs_ &&
125 root_cert_distributor_ == nullptr &&
126 identity_cert_distributor_ == nullptr;
127 }
128
129 void XdsCertificateProvider::ClusterCertificateState::
UpdateRootCertNameAndDistributor(const std::string & cert_name,absl::string_view root_cert_name,RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor)130 UpdateRootCertNameAndDistributor(
131 const std::string& cert_name, absl::string_view root_cert_name,
132 RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor) {
133 if (root_cert_name_ == root_cert_name &&
134 root_cert_distributor_ == root_cert_distributor) {
135 return;
136 }
137 root_cert_name_ = std::string(root_cert_name);
138 if (watching_root_certs_) {
139 // The root certificates are being watched. Swap out the watcher.
140 if (root_cert_distributor_ != nullptr) {
141 root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_);
142 }
143 if (root_cert_distributor != nullptr) {
144 UpdateRootCertWatcher(cert_name, root_cert_distributor.get());
145 } else {
146 root_cert_watcher_ = nullptr;
147 xds_certificate_provider_->distributor_->SetErrorForCert(
148 "",
149 GRPC_ERROR_CREATE(
150 "No certificate provider available for root certificates"),
151 absl::nullopt);
152 }
153 }
154 // Swap out the root certificate distributor
155 root_cert_distributor_ = std::move(root_cert_distributor);
156 }
157
158 void XdsCertificateProvider::ClusterCertificateState::
UpdateIdentityCertNameAndDistributor(const std::string & cert_name,absl::string_view identity_cert_name,RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor)159 UpdateIdentityCertNameAndDistributor(
160 const std::string& cert_name, absl::string_view identity_cert_name,
161 RefCountedPtr<grpc_tls_certificate_distributor>
162 identity_cert_distributor) {
163 if (identity_cert_name_ == identity_cert_name &&
164 identity_cert_distributor_ == identity_cert_distributor) {
165 return;
166 }
167 identity_cert_name_ = std::string(identity_cert_name);
168 if (watching_identity_certs_) {
169 // The identity certificates are being watched. Swap out the watcher.
170 if (identity_cert_distributor_ != nullptr) {
171 identity_cert_distributor_->CancelTlsCertificatesWatch(
172 identity_cert_watcher_);
173 }
174 if (identity_cert_distributor != nullptr) {
175 UpdateIdentityCertWatcher(cert_name, identity_cert_distributor.get());
176 } else {
177 identity_cert_watcher_ = nullptr;
178 xds_certificate_provider_->distributor_->SetErrorForCert(
179 "", absl::nullopt,
180 GRPC_ERROR_CREATE(
181 "No certificate provider available for identity certificates"));
182 }
183 }
184 // Swap out the identity certificate distributor
185 identity_cert_distributor_ = std::move(identity_cert_distributor);
186 }
187
UpdateRootCertWatcher(const std::string & cert_name,grpc_tls_certificate_distributor * root_cert_distributor)188 void XdsCertificateProvider::ClusterCertificateState::UpdateRootCertWatcher(
189 const std::string& cert_name,
190 grpc_tls_certificate_distributor* root_cert_distributor) {
191 auto watcher = std::make_unique<RootCertificatesWatcher>(
192 xds_certificate_provider_->distributor_, cert_name);
193 root_cert_watcher_ = watcher.get();
194 root_cert_distributor->WatchTlsCertificates(std::move(watcher),
195 root_cert_name_, absl::nullopt);
196 }
197
UpdateIdentityCertWatcher(const std::string & cert_name,grpc_tls_certificate_distributor * identity_cert_distributor)198 void XdsCertificateProvider::ClusterCertificateState::UpdateIdentityCertWatcher(
199 const std::string& cert_name,
200 grpc_tls_certificate_distributor* identity_cert_distributor) {
201 auto watcher = std::make_unique<IdentityCertificatesWatcher>(
202 xds_certificate_provider_->distributor_, cert_name);
203 identity_cert_watcher_ = watcher.get();
204 identity_cert_distributor->WatchTlsCertificates(
205 std::move(watcher), absl::nullopt, identity_cert_name_);
206 }
207
WatchStatusCallback(const std::string & cert_name,bool root_being_watched,bool identity_being_watched)208 void XdsCertificateProvider::ClusterCertificateState::WatchStatusCallback(
209 const std::string& cert_name, bool root_being_watched,
210 bool identity_being_watched) {
211 // We aren't specially handling the case where root_cert_distributor is same
212 // as identity_cert_distributor. Always using two separate watchers
213 // irrespective of the fact results in a straightforward design, and using a
214 // single watcher does not seem to provide any benefit other than cutting down
215 // on the number of callbacks.
216 if (root_being_watched && !watching_root_certs_) {
217 // We need to start watching root certs.
218 watching_root_certs_ = true;
219 if (root_cert_distributor_ == nullptr) {
220 xds_certificate_provider_->distributor_->SetErrorForCert(
221 cert_name,
222 GRPC_ERROR_CREATE(
223 "No certificate provider available for root certificates"),
224 absl::nullopt);
225 } else {
226 UpdateRootCertWatcher(cert_name, root_cert_distributor_.get());
227 }
228 } else if (!root_being_watched && watching_root_certs_) {
229 // We need to cancel root certs watch.
230 watching_root_certs_ = false;
231 if (root_cert_distributor_ != nullptr) {
232 root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_);
233 root_cert_watcher_ = nullptr;
234 }
235 GPR_ASSERT(root_cert_watcher_ == nullptr);
236 }
237 if (identity_being_watched && !watching_identity_certs_) {
238 watching_identity_certs_ = true;
239 if (identity_cert_distributor_ == nullptr) {
240 xds_certificate_provider_->distributor_->SetErrorForCert(
241 cert_name, absl::nullopt,
242 GRPC_ERROR_CREATE(
243 "No certificate provider available for identity certificates"));
244 } else {
245 UpdateIdentityCertWatcher(cert_name, identity_cert_distributor_.get());
246 }
247 } else if (!identity_being_watched && watching_identity_certs_) {
248 watching_identity_certs_ = false;
249 if (identity_cert_distributor_ != nullptr) {
250 identity_cert_distributor_->CancelTlsCertificatesWatch(
251 identity_cert_watcher_);
252 identity_cert_watcher_ = nullptr;
253 }
254 GPR_ASSERT(identity_cert_watcher_ == nullptr);
255 }
256 }
257
258 //
259 // XdsCertificateProvider
260 //
261
XdsCertificateProvider()262 XdsCertificateProvider::XdsCertificateProvider()
263 : distributor_(MakeRefCounted<grpc_tls_certificate_distributor>()) {
264 distributor_->SetWatchStatusCallback(
265 absl::bind_front(&XdsCertificateProvider::WatchStatusCallback, this));
266 }
267
~XdsCertificateProvider()268 XdsCertificateProvider::~XdsCertificateProvider() {
269 distributor_->SetWatchStatusCallback(nullptr);
270 }
271
type() const272 UniqueTypeName XdsCertificateProvider::type() const {
273 static UniqueTypeName::Factory kFactory("Xds");
274 return kFactory.Create();
275 }
276
ProvidesRootCerts(const std::string & cert_name)277 bool XdsCertificateProvider::ProvidesRootCerts(const std::string& cert_name) {
278 MutexLock lock(&mu_);
279 auto it = certificate_state_map_.find(cert_name);
280 if (it == certificate_state_map_.end()) return false;
281 return it->second->ProvidesRootCerts();
282 }
283
UpdateRootCertNameAndDistributor(const std::string & cert_name,absl::string_view root_cert_name,RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor)284 void XdsCertificateProvider::UpdateRootCertNameAndDistributor(
285 const std::string& cert_name, absl::string_view root_cert_name,
286 RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor) {
287 MutexLock lock(&mu_);
288 auto it = certificate_state_map_.find(cert_name);
289 if (it == certificate_state_map_.end()) {
290 it =
291 certificate_state_map_
292 .emplace(cert_name, std::make_unique<ClusterCertificateState>(this))
293 .first;
294 }
295 it->second->UpdateRootCertNameAndDistributor(cert_name, root_cert_name,
296 root_cert_distributor);
297 // Delete unused entries.
298 if (it->second->IsSafeToRemove()) certificate_state_map_.erase(it);
299 }
300
ProvidesIdentityCerts(const std::string & cert_name)301 bool XdsCertificateProvider::ProvidesIdentityCerts(
302 const std::string& cert_name) {
303 MutexLock lock(&mu_);
304 auto it = certificate_state_map_.find(cert_name);
305 if (it == certificate_state_map_.end()) return false;
306 return it->second->ProvidesIdentityCerts();
307 }
308
UpdateIdentityCertNameAndDistributor(const std::string & cert_name,absl::string_view identity_cert_name,RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor)309 void XdsCertificateProvider::UpdateIdentityCertNameAndDistributor(
310 const std::string& cert_name, absl::string_view identity_cert_name,
311 RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor) {
312 MutexLock lock(&mu_);
313 auto it = certificate_state_map_.find(cert_name);
314 if (it == certificate_state_map_.end()) {
315 it =
316 certificate_state_map_
317 .emplace(cert_name, std::make_unique<ClusterCertificateState>(this))
318 .first;
319 }
320 it->second->UpdateIdentityCertNameAndDistributor(
321 cert_name, identity_cert_name, identity_cert_distributor);
322 // Delete unused entries.
323 if (it->second->IsSafeToRemove()) certificate_state_map_.erase(it);
324 }
325
GetRequireClientCertificate(const std::string & cert_name)326 bool XdsCertificateProvider::GetRequireClientCertificate(
327 const std::string& cert_name) {
328 MutexLock lock(&mu_);
329 auto it = certificate_state_map_.find(cert_name);
330 if (it == certificate_state_map_.end()) return false;
331 return it->second->require_client_certificate();
332 }
333
UpdateRequireClientCertificate(const std::string & cert_name,bool require_client_certificate)334 void XdsCertificateProvider::UpdateRequireClientCertificate(
335 const std::string& cert_name, bool require_client_certificate) {
336 MutexLock lock(&mu_);
337 auto it = certificate_state_map_.find(cert_name);
338 if (it == certificate_state_map_.end()) return;
339 it->second->set_require_client_certificate(require_client_certificate);
340 }
341
GetSanMatchers(const std::string & cluster)342 std::vector<StringMatcher> XdsCertificateProvider::GetSanMatchers(
343 const std::string& cluster) {
344 MutexLock lock(&san_matchers_mu_);
345 auto it = san_matcher_map_.find(cluster);
346 if (it == san_matcher_map_.end()) return {};
347 return it->second;
348 }
349
UpdateSubjectAlternativeNameMatchers(const std::string & cluster,std::vector<StringMatcher> matchers)350 void XdsCertificateProvider::UpdateSubjectAlternativeNameMatchers(
351 const std::string& cluster, std::vector<StringMatcher> matchers) {
352 MutexLock lock(&san_matchers_mu_);
353 if (matchers.empty()) {
354 san_matcher_map_.erase(cluster);
355 } else {
356 san_matcher_map_[cluster] = std::move(matchers);
357 }
358 }
359
WatchStatusCallback(std::string cert_name,bool root_being_watched,bool identity_being_watched)360 void XdsCertificateProvider::WatchStatusCallback(std::string cert_name,
361 bool root_being_watched,
362 bool identity_being_watched) {
363 MutexLock lock(&mu_);
364 auto it = certificate_state_map_.find(cert_name);
365 if (it == certificate_state_map_.end()) {
366 it =
367 certificate_state_map_
368 .emplace(cert_name, std::make_unique<ClusterCertificateState>(this))
369 .first;
370 }
371 it->second->WatchStatusCallback(cert_name, root_being_watched,
372 identity_being_watched);
373 // Delete unused entries.
374 if (it->second->IsSafeToRemove()) certificate_state_map_.erase(it);
375 }
376
377 namespace {
378
XdsCertificateProviderArgCopy(void * p)379 void* XdsCertificateProviderArgCopy(void* p) {
380 XdsCertificateProvider* xds_certificate_provider =
381 static_cast<XdsCertificateProvider*>(p);
382 return xds_certificate_provider->Ref().release();
383 }
384
XdsCertificateProviderArgDestroy(void * p)385 void XdsCertificateProviderArgDestroy(void* p) {
386 XdsCertificateProvider* xds_certificate_provider =
387 static_cast<XdsCertificateProvider*>(p);
388 xds_certificate_provider->Unref();
389 }
390
XdsCertificateProviderArgCmp(void * p,void * q)391 int XdsCertificateProviderArgCmp(void* p, void* q) {
392 return QsortCompare(p, q);
393 }
394
395 const grpc_arg_pointer_vtable kChannelArgVtable = {
396 XdsCertificateProviderArgCopy, XdsCertificateProviderArgDestroy,
397 XdsCertificateProviderArgCmp};
398
399 } // namespace
400
MakeChannelArg() const401 grpc_arg XdsCertificateProvider::MakeChannelArg() const {
402 return grpc_channel_arg_pointer_create(
403 const_cast<char*>(GRPC_ARG_XDS_CERTIFICATE_PROVIDER),
404 const_cast<XdsCertificateProvider*>(this), &kChannelArgVtable);
405 }
406
407 RefCountedPtr<XdsCertificateProvider>
GetFromChannelArgs(const grpc_channel_args * args)408 XdsCertificateProvider::GetFromChannelArgs(const grpc_channel_args* args) {
409 XdsCertificateProvider* xds_certificate_provider =
410 grpc_channel_args_find_pointer<XdsCertificateProvider>(
411 args, GRPC_ARG_XDS_CERTIFICATE_PROVIDER);
412 return xds_certificate_provider != nullptr ? xds_certificate_provider->Ref()
413 : nullptr;
414 }
415
416 } // namespace grpc_core
417