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