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