• 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)40   explicit RootCertificatesWatcher(
41       RefCountedPtr<grpc_tls_certificate_distributor> parent)
42       : parent_(std::move(parent)) {}
43 
OnCertificatesChanged(absl::optional<absl::string_view> root_certs,absl::optional<PemKeyCertPairList>)44   void OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
45                              absl::optional<PemKeyCertPairList>
46                              /* key_cert_pairs */) override {
47     if (root_certs.has_value()) {
48       parent_->SetKeyMaterials("", std::string(root_certs.value()),
49                                absl::nullopt);
50     }
51   }
52 
OnError(grpc_error * root_cert_error,grpc_error * identity_cert_error)53   void OnError(grpc_error* root_cert_error,
54                grpc_error* identity_cert_error) override {
55     if (root_cert_error != GRPC_ERROR_NONE) {
56       parent_->SetErrorForCert("", root_cert_error /* pass the ref */,
57                                absl::nullopt);
58     }
59     GRPC_ERROR_UNREF(identity_cert_error);
60   }
61 
62  private:
63   RefCountedPtr<grpc_tls_certificate_distributor> parent_;
64 };
65 
66 class IdentityCertificatesWatcher
67     : public grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface {
68  public:
69   // Takes a ref to \a parent instead of a raw pointer since the watcher is
70   // owned by the root certificate distributor and not by \a parent. Note that
71   // presently, the watcher is immediately deleted when
72   // CancelTlsCertificatesWatch() is called, but that can potentially change in
73   // the future.
IdentityCertificatesWatcher(RefCountedPtr<grpc_tls_certificate_distributor> parent)74   explicit IdentityCertificatesWatcher(
75       RefCountedPtr<grpc_tls_certificate_distributor> parent)
76       : parent_(std::move(parent)) {}
77 
OnCertificatesChanged(absl::optional<absl::string_view>,absl::optional<PemKeyCertPairList> key_cert_pairs)78   void OnCertificatesChanged(
79       absl::optional<absl::string_view> /* root_certs */,
80       absl::optional<PemKeyCertPairList> key_cert_pairs) override {
81     if (key_cert_pairs.has_value()) {
82       parent_->SetKeyMaterials("", absl::nullopt, key_cert_pairs);
83     }
84   }
85 
OnError(grpc_error * root_cert_error,grpc_error * identity_cert_error)86   void OnError(grpc_error* root_cert_error,
87                grpc_error* identity_cert_error) override {
88     if (identity_cert_error != GRPC_ERROR_NONE) {
89       parent_->SetErrorForCert("", absl::nullopt,
90                                identity_cert_error /* pass the ref */);
91     }
92     GRPC_ERROR_UNREF(root_cert_error);
93   }
94 
95  private:
96   RefCountedPtr<grpc_tls_certificate_distributor> parent_;
97 };
98 
99 }  // namespace
100 
XdsCertificateProvider(absl::string_view root_cert_name,RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor,absl::string_view identity_cert_name,RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor,std::vector<XdsApi::StringMatcher> san_matchers)101 XdsCertificateProvider::XdsCertificateProvider(
102     absl::string_view root_cert_name,
103     RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor,
104     absl::string_view identity_cert_name,
105     RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor,
106     std::vector<XdsApi::StringMatcher> san_matchers)
107     : root_cert_name_(root_cert_name),
108       identity_cert_name_(identity_cert_name),
109       root_cert_distributor_(std::move(root_cert_distributor)),
110       identity_cert_distributor_(std::move(identity_cert_distributor)),
111       san_matchers_(std::move(san_matchers)),
112       distributor_(MakeRefCounted<grpc_tls_certificate_distributor>()) {
113   distributor_->SetWatchStatusCallback(
114       absl::bind_front(&XdsCertificateProvider::WatchStatusCallback, this));
115 }
116 
~XdsCertificateProvider()117 XdsCertificateProvider::~XdsCertificateProvider() {
118   distributor_->SetWatchStatusCallback(nullptr);
119 }
120 
UpdateRootCertNameAndDistributor(absl::string_view root_cert_name,RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor)121 void XdsCertificateProvider::UpdateRootCertNameAndDistributor(
122     absl::string_view root_cert_name,
123     RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor) {
124   MutexLock lock(&mu_);
125   if (root_cert_name_ == root_cert_name &&
126       root_cert_distributor_ == root_cert_distributor) {
127     return;
128   }
129   root_cert_name_ = std::string(root_cert_name);
130   if (watching_root_certs_) {
131     // The root certificates are being watched. Swap out the watcher.
132     if (root_cert_distributor_ != nullptr) {
133       root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_);
134     }
135     if (root_cert_distributor != nullptr) {
136       UpdateRootCertWatcher(root_cert_distributor.get());
137     } else {
138       root_cert_watcher_ = nullptr;
139       distributor_->SetErrorForCert(
140           "",
141           GRPC_ERROR_CREATE_FROM_STATIC_STRING(
142               "No certificate provider available for root certificates"),
143           absl::nullopt);
144     }
145   }
146   // Swap out the root certificate distributor
147   root_cert_distributor_ = std::move(root_cert_distributor);
148 }
149 
UpdateIdentityCertNameAndDistributor(absl::string_view identity_cert_name,RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor)150 void XdsCertificateProvider::UpdateIdentityCertNameAndDistributor(
151     absl::string_view identity_cert_name,
152     RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor) {
153   MutexLock lock(&mu_);
154   if (identity_cert_name_ == identity_cert_name &&
155       identity_cert_distributor_ == identity_cert_distributor) {
156     return;
157   }
158   identity_cert_name_ = std::string(identity_cert_name);
159   if (watching_identity_certs_) {
160     // The identity certificates are being watched. Swap out the watcher.
161     if (identity_cert_distributor_ != nullptr) {
162       identity_cert_distributor_->CancelTlsCertificatesWatch(
163           identity_cert_watcher_);
164     }
165     if (identity_cert_distributor != nullptr) {
166       UpdateIdentityCertWatcher(identity_cert_distributor.get());
167     } else {
168       identity_cert_watcher_ = nullptr;
169       distributor_->SetErrorForCert(
170           "", absl::nullopt,
171           GRPC_ERROR_CREATE_FROM_STATIC_STRING(
172               "No certificate provider available for identity certificates"));
173     }
174   }
175   // Swap out the identity certificate distributor
176   identity_cert_distributor_ = std::move(identity_cert_distributor);
177 }
178 
UpdateSubjectAlternativeNameMatchers(std::vector<XdsApi::StringMatcher> matchers)179 void XdsCertificateProvider::UpdateSubjectAlternativeNameMatchers(
180     std::vector<XdsApi::StringMatcher> matchers) {
181   MutexLock lock(&san_matchers_mu_);
182   san_matchers_ = std::move(matchers);
183 }
184 
WatchStatusCallback(std::string cert_name,bool root_being_watched,bool identity_being_watched)185 void XdsCertificateProvider::WatchStatusCallback(std::string cert_name,
186                                                  bool root_being_watched,
187                                                  bool identity_being_watched) {
188   // We aren't specially handling the case where root_cert_distributor is same
189   // as identity_cert_distributor. Always using two separate watchers
190   // irrespective of the fact results in a straightforward design, and using a
191   // single watcher does not seem to provide any benefit other than cutting down
192   // on the number of callbacks.
193   MutexLock lock(&mu_);
194   if (!cert_name.empty()) {
195     grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
196         absl::StrCat("Illegal certificate name: \'", cert_name,
197                      "\'. Should be empty.")
198             .c_str());
199     distributor_->SetErrorForCert(cert_name, GRPC_ERROR_REF(error),
200                                   GRPC_ERROR_REF(error));
201     GRPC_ERROR_UNREF(error);
202     return;
203   }
204   if (root_being_watched && !watching_root_certs_) {
205     // We need to start watching root certs.
206     watching_root_certs_ = true;
207     if (root_cert_distributor_ == nullptr) {
208       distributor_->SetErrorForCert(
209           "",
210           GRPC_ERROR_CREATE_FROM_STATIC_STRING(
211               "No certificate provider available for root certificates"),
212           absl::nullopt);
213     } else {
214       UpdateRootCertWatcher(root_cert_distributor_.get());
215     }
216   } else if (!root_being_watched && watching_root_certs_) {
217     // We need to cancel root certs watch.
218     watching_root_certs_ = false;
219     if (root_cert_distributor_ != nullptr) {
220       root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_);
221       root_cert_watcher_ = nullptr;
222     }
223     GPR_ASSERT(root_cert_watcher_ == nullptr);
224   }
225   if (identity_being_watched && !watching_identity_certs_) {
226     watching_identity_certs_ = true;
227     if (identity_cert_distributor_ == nullptr) {
228       distributor_->SetErrorForCert(
229           "", absl::nullopt,
230           GRPC_ERROR_CREATE_FROM_STATIC_STRING(
231               "No certificate provider available for identity certificates"));
232     } else {
233       UpdateIdentityCertWatcher(identity_cert_distributor_.get());
234     }
235   } else if (!identity_being_watched && watching_identity_certs_) {
236     watching_identity_certs_ = false;
237     if (identity_cert_distributor_ != nullptr) {
238       identity_cert_distributor_->CancelTlsCertificatesWatch(
239           identity_cert_watcher_);
240       identity_cert_watcher_ = nullptr;
241     }
242     GPR_ASSERT(identity_cert_watcher_ == nullptr);
243   }
244 }
245 
UpdateRootCertWatcher(grpc_tls_certificate_distributor * root_cert_distributor)246 void XdsCertificateProvider::UpdateRootCertWatcher(
247     grpc_tls_certificate_distributor* root_cert_distributor) {
248   auto watcher = absl::make_unique<RootCertificatesWatcher>(distributor());
249   root_cert_watcher_ = watcher.get();
250   root_cert_distributor->WatchTlsCertificates(std::move(watcher),
251                                               root_cert_name_, absl::nullopt);
252 }
253 
UpdateIdentityCertWatcher(grpc_tls_certificate_distributor * identity_cert_distributor)254 void XdsCertificateProvider::UpdateIdentityCertWatcher(
255     grpc_tls_certificate_distributor* identity_cert_distributor) {
256   auto watcher = absl::make_unique<IdentityCertificatesWatcher>(distributor());
257   identity_cert_watcher_ = watcher.get();
258   identity_cert_distributor->WatchTlsCertificates(
259       std::move(watcher), absl::nullopt, identity_cert_name_);
260 }
261 
262 namespace {
263 
XdsCertificateProviderArgCopy(void * p)264 void* XdsCertificateProviderArgCopy(void* p) {
265   XdsCertificateProvider* xds_certificate_provider =
266       static_cast<XdsCertificateProvider*>(p);
267   return xds_certificate_provider->Ref().release();
268 }
269 
XdsCertificateProviderArgDestroy(void * p)270 void XdsCertificateProviderArgDestroy(void* p) {
271   XdsCertificateProvider* xds_certificate_provider =
272       static_cast<XdsCertificateProvider*>(p);
273   xds_certificate_provider->Unref();
274 }
275 
XdsCertificateProviderArgCmp(void * p,void * q)276 int XdsCertificateProviderArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
277 
278 const grpc_arg_pointer_vtable kChannelArgVtable = {
279     XdsCertificateProviderArgCopy, XdsCertificateProviderArgDestroy,
280     XdsCertificateProviderArgCmp};
281 
282 }  // namespace
283 
MakeChannelArg() const284 grpc_arg XdsCertificateProvider::MakeChannelArg() const {
285   return grpc_channel_arg_pointer_create(
286       const_cast<char*>(GRPC_ARG_XDS_CERTIFICATE_PROVIDER),
287       const_cast<XdsCertificateProvider*>(this), &kChannelArgVtable);
288 }
289 
290 RefCountedPtr<XdsCertificateProvider>
GetFromChannelArgs(const grpc_channel_args * args)291 XdsCertificateProvider::GetFromChannelArgs(const grpc_channel_args* args) {
292   XdsCertificateProvider* xds_certificate_provider =
293       grpc_channel_args_find_pointer<XdsCertificateProvider>(
294           args, GRPC_ARG_XDS_CERTIFICATE_PROVIDER);
295   return xds_certificate_provider != nullptr ? xds_certificate_provider->Ref()
296                                              : nullptr;
297 }
298 
299 }  // namespace grpc_core
300