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