3 // Copyright 2020 gRPC authors.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <grpc/support/port_platform.h>
21 #include "absl/functional/bind_front.h"
22 #include "absl/strings/str_cat.h"
24 #include "src/core/ext/xds/xds_certificate_provider.h"
30 class RootCertificatesWatcher
31 : public grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface {
33 // Takes a ref to \a parent instead of a raw pointer since the watcher is
34 // owned by the root certificate distributor and not by \a parent. Note that
35 // presently, the watcher is immediately deleted when
36 // CancelTlsCertificatesWatch() is called, but that can potentially change in
38 explicit RootCertificatesWatcher(
39 RefCountedPtr<grpc_tls_certificate_distributor> parent)
40 : parent_(std::move(parent)) {}
42 void OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
43 absl::optional<PemKeyCertPairList>
44 /* key_cert_pairs */) override {
45 if (root_certs.has_value()) {
46 parent_->SetKeyMaterials("", std::string(root_certs.value()),
51 void OnError(grpc_error* root_cert_error,
52 grpc_error* identity_cert_error) override {
53 if (root_cert_error != GRPC_ERROR_NONE) {
54 parent_->SetErrorForCert("", root_cert_error /* pass the ref */,
57 GRPC_ERROR_UNREF(identity_cert_error);
61 RefCountedPtr<grpc_tls_certificate_distributor> parent_;
64 class IdentityCertificatesWatcher
65 : public grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface {
67 // Takes a ref to \a parent instead of a raw pointer since the watcher is
68 // owned by the root certificate distributor and not by \a parent. Note that
69 // presently, the watcher is immediately deleted when
70 // CancelTlsCertificatesWatch() is called, but that can potentially change in
72 explicit IdentityCertificatesWatcher(
73 RefCountedPtr<grpc_tls_certificate_distributor> parent)
74 : parent_(std::move(parent)) {}
76 void OnCertificatesChanged(
77 absl::optional<absl::string_view> /* root_certs */,
78 absl::optional<PemKeyCertPairList> key_cert_pairs) override {
79 if (key_cert_pairs.has_value()) {
80 parent_->SetKeyMaterials("", absl::nullopt, key_cert_pairs);
84 void OnError(grpc_error* root_cert_error,
85 grpc_error* identity_cert_error) override {
86 if (identity_cert_error != GRPC_ERROR_NONE) {
87 parent_->SetErrorForCert("", absl::nullopt,
88 identity_cert_error /* pass the ref */);
90 GRPC_ERROR_UNREF(root_cert_error);
94 RefCountedPtr<grpc_tls_certificate_distributor> parent_;
99 XdsCertificateProvider::XdsCertificateProvider(
100 absl::string_view root_cert_name,
101 RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor,
102 absl::string_view identity_cert_name,
103 RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor)
104 : root_cert_name_(root_cert_name),
105 identity_cert_name_(identity_cert_name),
106 root_cert_distributor_(std::move(root_cert_distributor)),
107 identity_cert_distributor_(std::move(identity_cert_distributor)),
108 distributor_(MakeRefCounted<grpc_tls_certificate_distributor>()) {
109 distributor_->SetWatchStatusCallback(
110 absl::bind_front(&XdsCertificateProvider::WatchStatusCallback, this));
113 void XdsCertificateProvider::UpdateRootCertNameAndDistributor(
114 absl::string_view root_cert_name,
115 RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor) {
116 MutexLock lock(&mu_);
117 root_cert_name_ = std::string(root_cert_name);
118 if (watching_root_certs_) {
119 // The root certificates are being watched. Swap out the watcher.
120 if (root_cert_distributor_ != nullptr) {
121 root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_);
123 if (root_cert_distributor != nullptr) {
124 UpdateRootCertWatcher(root_cert_distributor.get());
126 root_cert_watcher_ = nullptr;
127 distributor_->SetErrorForCert(
129 GRPC_ERROR_CREATE_FROM_STATIC_STRING(
130 "No certificate provider available for root certificates"),
134 // Swap out the root certificate distributor
135 root_cert_distributor_ = std::move(root_cert_distributor);
138 void XdsCertificateProvider::UpdateIdentityCertNameAndDistributor(
139 absl::string_view identity_cert_name,
140 RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor) {
141 MutexLock lock(&mu_);
142 identity_cert_name_ = std::string(identity_cert_name);
143 if (watching_identity_certs_) {
144 // The identity certificates are being watched. Swap out the watcher.
145 if (identity_cert_distributor_ != nullptr) {
146 identity_cert_distributor_->CancelTlsCertificatesWatch(
147 identity_cert_watcher_);
149 if (identity_cert_distributor != nullptr) {
150 UpdateIdentityCertWatcher(identity_cert_distributor.get());
152 identity_cert_watcher_ = nullptr;
153 distributor_->SetErrorForCert(
155 GRPC_ERROR_CREATE_FROM_STATIC_STRING(
156 "No certificate provider available for identity certificates"));
159 // Swap out the identity certificate distributor
160 identity_cert_distributor_ = std::move(identity_cert_distributor);
163 void XdsCertificateProvider::WatchStatusCallback(std::string cert_name,
164 bool root_being_watched,
165 bool identity_being_watched) {
166 // We aren't specially handling the case where root_cert_distributor is same
167 // as identity_cert_distributor. Always using two separate watchers
168 // irrespective of the fact results in a straightforward design, and using a
169 // single watcher does not seem to provide any benefit other than cutting down
170 // on the number of callbacks.
171 MutexLock lock(&mu_);
172 if (!cert_name.empty()) {
173 grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
174 absl::StrCat("Illegal certificate name: \'", cert_name,
175 "\'. Should be empty.")
177 distributor_->SetErrorForCert(cert_name, GRPC_ERROR_REF(error),
178 GRPC_ERROR_REF(error));
179 GRPC_ERROR_UNREF(error);
182 if (root_being_watched && !watching_root_certs_) {
183 // We need to start watching root certs.
184 watching_root_certs_ = true;
185 if (root_cert_distributor_ == nullptr) {
186 distributor_->SetErrorForCert(
188 GRPC_ERROR_CREATE_FROM_STATIC_STRING(
189 "No certificate provider available for root certificates"),
192 UpdateRootCertWatcher(root_cert_distributor_.get());
194 } else if (!root_being_watched && watching_root_certs_) {
195 // We need to cancel root certs watch.
196 watching_root_certs_ = false;
197 if (root_cert_distributor_ != nullptr) {
198 root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_);
199 root_cert_watcher_ = nullptr;
201 GPR_ASSERT(root_cert_watcher_ == nullptr);
203 if (identity_being_watched && !watching_identity_certs_) {
204 watching_identity_certs_ = true;
205 if (identity_cert_distributor_ == nullptr) {
206 distributor_->SetErrorForCert(
208 GRPC_ERROR_CREATE_FROM_STATIC_STRING(
209 "No certificate provider available for identity certificates"));
211 UpdateIdentityCertWatcher(identity_cert_distributor_.get());
213 } else if (!identity_being_watched && watching_identity_certs_) {
214 watching_identity_certs_ = false;
215 if (identity_cert_distributor_ != nullptr) {
216 identity_cert_distributor_->CancelTlsCertificatesWatch(
217 identity_cert_watcher_);
218 identity_cert_watcher_ = nullptr;
220 GPR_ASSERT(identity_cert_watcher_ == nullptr);
224 void XdsCertificateProvider::UpdateRootCertWatcher(
225 grpc_tls_certificate_distributor* root_cert_distributor) {
226 auto watcher = absl::make_unique<RootCertificatesWatcher>(distributor());
227 root_cert_watcher_ = watcher.get();
228 root_cert_distributor->WatchTlsCertificates(std::move(watcher),
229 root_cert_name_, absl::nullopt);
232 void XdsCertificateProvider::UpdateIdentityCertWatcher(
233 grpc_tls_certificate_distributor* identity_cert_distributor) {
234 auto watcher = absl::make_unique<IdentityCertificatesWatcher>(distributor());
235 identity_cert_watcher_ = watcher.get();
236 identity_cert_distributor->WatchTlsCertificates(
237 std::move(watcher), absl::nullopt, identity_cert_name_);
240 } // namespace grpc_core