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