2 // Copyright 2020 gRPC authors.
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
17 #include <grpc/support/port_platform.h>
19 #include "src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h"
21 #include <grpc/support/alloc.h>
22 #include <grpc/support/log.h>
23 #include <grpc/support/string_util.h>
27 void grpc_tls_certificate_distributor::SetKeyMaterials(
28 const std::string& cert_name, absl::optional<std::string> pem_root_certs,
29 absl::optional<PemKeyCertPairList> pem_key_cert_pairs) {
30 GPR_ASSERT(pem_root_certs.has_value() || pem_key_cert_pairs.has_value());
31 grpc_core::MutexLock lock(&mu_);
32 auto& cert_info = certificate_info_map_[cert_name];
33 if (pem_root_certs.has_value()) {
34 // Successful credential updates will clear any pre-existing error.
35 cert_info.SetRootError(GRPC_ERROR_NONE);
36 for (auto* watcher_ptr : cert_info.root_cert_watchers) {
37 GPR_ASSERT(watcher_ptr != nullptr);
38 const auto watcher_it = watchers_.find(watcher_ptr);
39 GPR_ASSERT(watcher_it != watchers_.end());
40 GPR_ASSERT(watcher_it->second.root_cert_name.has_value());
41 absl::optional<PemKeyCertPairList> pem_key_cert_pairs_to_report;
42 if (pem_key_cert_pairs.has_value() &&
43 watcher_it->second.identity_cert_name == cert_name) {
44 pem_key_cert_pairs_to_report = pem_key_cert_pairs;
45 } else if (watcher_it->second.identity_cert_name.has_value()) {
46 auto& identity_cert_info =
47 certificate_info_map_[*watcher_it->second.identity_cert_name];
48 pem_key_cert_pairs_to_report = identity_cert_info.pem_key_cert_pairs;
50 watcher_ptr->OnCertificatesChanged(
51 pem_root_certs, std::move(pem_key_cert_pairs_to_report));
53 cert_info.pem_root_certs = std::move(*pem_root_certs);
55 if (pem_key_cert_pairs.has_value()) {
56 // Successful credential updates will clear any pre-existing error.
57 cert_info.SetIdentityError(GRPC_ERROR_NONE);
58 for (const auto watcher_ptr : cert_info.identity_cert_watchers) {
59 GPR_ASSERT(watcher_ptr != nullptr);
60 const auto watcher_it = watchers_.find(watcher_ptr);
61 GPR_ASSERT(watcher_it != watchers_.end());
62 GPR_ASSERT(watcher_it->second.identity_cert_name.has_value());
63 absl::optional<absl::string_view> pem_root_certs_to_report;
64 if (pem_root_certs.has_value() &&
65 watcher_it->second.root_cert_name == cert_name) {
66 // In this case, We've already sent the credential updates at the time
67 // when checking pem_root_certs, so we will skip here.
69 } else if (watcher_it->second.root_cert_name.has_value()) {
70 auto& root_cert_info =
71 certificate_info_map_[*watcher_it->second.root_cert_name];
72 pem_root_certs_to_report = root_cert_info.pem_root_certs;
74 watcher_ptr->OnCertificatesChanged(pem_root_certs_to_report,
77 cert_info.pem_key_cert_pairs = std::move(*pem_key_cert_pairs);
81 bool grpc_tls_certificate_distributor::HasRootCerts(
82 const std::string& root_cert_name) {
83 grpc_core::MutexLock lock(&mu_);
84 const auto it = certificate_info_map_.find(root_cert_name);
85 return it != certificate_info_map_.end() &&
86 !it->second.pem_root_certs.empty();
89 bool grpc_tls_certificate_distributor::HasKeyCertPairs(
90 const std::string& identity_cert_name) {
91 grpc_core::MutexLock lock(&mu_);
92 const auto it = certificate_info_map_.find(identity_cert_name);
93 return it != certificate_info_map_.end() &&
94 !it->second.pem_key_cert_pairs.empty();
97 void grpc_tls_certificate_distributor::SetErrorForCert(
98 const std::string& cert_name, absl::optional<grpc_error*> root_cert_error,
99 absl::optional<grpc_error*> identity_cert_error) {
100 GPR_ASSERT(root_cert_error.has_value() || identity_cert_error.has_value());
101 grpc_core::MutexLock lock(&mu_);
102 CertificateInfo& cert_info = certificate_info_map_[cert_name];
103 if (root_cert_error.has_value()) {
104 for (auto* watcher_ptr : cert_info.root_cert_watchers) {
105 GPR_ASSERT(watcher_ptr != nullptr);
106 const auto watcher_it = watchers_.find(watcher_ptr);
107 GPR_ASSERT(watcher_it != watchers_.end());
108 // identity_cert_error_to_report is the error of the identity cert this
109 // watcher is watching, if there is any.
110 grpc_error* identity_cert_error_to_report = GRPC_ERROR_NONE;
111 if (identity_cert_error.has_value() &&
112 watcher_it->second.identity_cert_name == cert_name) {
113 identity_cert_error_to_report = *identity_cert_error;
114 } else if (watcher_it->second.identity_cert_name.has_value()) {
115 auto& identity_cert_info =
116 certificate_info_map_[*watcher_it->second.identity_cert_name];
117 identity_cert_error_to_report = identity_cert_info.identity_cert_error;
119 watcher_ptr->OnError(GRPC_ERROR_REF(*root_cert_error),
120 GRPC_ERROR_REF(identity_cert_error_to_report));
122 cert_info.SetRootError(*root_cert_error);
124 if (identity_cert_error.has_value()) {
125 for (auto* watcher_ptr : cert_info.identity_cert_watchers) {
126 GPR_ASSERT(watcher_ptr != nullptr);
127 const auto watcher_it = watchers_.find(watcher_ptr);
128 GPR_ASSERT(watcher_it != watchers_.end());
129 // root_cert_error_to_report is the error of the root cert this watcher is
130 // watching, if there is any.
131 grpc_error* root_cert_error_to_report = GRPC_ERROR_NONE;
132 if (root_cert_error.has_value() &&
133 watcher_it->second.root_cert_name == cert_name) {
134 // In this case, We've already sent the error updates at the time when
135 // checking root_cert_error, so we will skip here.
137 } else if (watcher_it->second.root_cert_name.has_value()) {
138 auto& root_cert_info =
139 certificate_info_map_[*watcher_it->second.root_cert_name];
140 root_cert_error_to_report = root_cert_info.root_cert_error;
142 watcher_ptr->OnError(GRPC_ERROR_REF(root_cert_error_to_report),
143 GRPC_ERROR_REF(*identity_cert_error));
145 cert_info.SetIdentityError(*identity_cert_error);
149 void grpc_tls_certificate_distributor::SetError(grpc_error* error) {
150 GPR_ASSERT(error != GRPC_ERROR_NONE);
151 grpc_core::MutexLock lock(&mu_);
152 for (const auto& watcher : watchers_) {
153 const auto watcher_ptr = watcher.first;
154 GPR_ASSERT(watcher_ptr != nullptr);
155 const auto& watcher_info = watcher.second;
156 watcher_ptr->OnError(
157 watcher_info.root_cert_name.has_value() ? GRPC_ERROR_REF(error)
159 watcher_info.identity_cert_name.has_value() ? GRPC_ERROR_REF(error)
162 for (auto& cert_info_entry : certificate_info_map_) {
163 auto& cert_info = cert_info_entry.second;
164 cert_info.SetRootError(GRPC_ERROR_REF(error));
165 cert_info.SetIdentityError(GRPC_ERROR_REF(error));
167 GRPC_ERROR_UNREF(error);
170 void grpc_tls_certificate_distributor::WatchTlsCertificates(
171 std::unique_ptr<TlsCertificatesWatcherInterface> watcher,
172 absl::optional<std::string> root_cert_name,
173 absl::optional<std::string> identity_cert_name) {
174 bool start_watching_root_cert = false;
175 bool already_watching_identity_for_root_cert = false;
176 bool start_watching_identity_cert = false;
177 bool already_watching_root_for_identity_cert = false;
178 GPR_ASSERT(root_cert_name.has_value() || identity_cert_name.has_value());
179 TlsCertificatesWatcherInterface* watcher_ptr = watcher.get();
180 GPR_ASSERT(watcher_ptr != nullptr);
181 // Update watchers_ and certificate_info_map_.
183 grpc_core::MutexLock lock(&mu_);
184 const auto watcher_it = watchers_.find(watcher_ptr);
185 // The caller needs to cancel the watcher first if it wants to re-register
187 GPR_ASSERT(watcher_it == watchers_.end());
188 watchers_[watcher_ptr] = {std::move(watcher), root_cert_name,
190 absl::optional<absl::string_view> updated_root_certs;
191 absl::optional<PemKeyCertPairList> updated_identity_pairs;
192 grpc_error* root_error = GRPC_ERROR_NONE;
193 grpc_error* identity_error = GRPC_ERROR_NONE;
194 if (root_cert_name.has_value()) {
195 CertificateInfo& cert_info = certificate_info_map_[*root_cert_name];
196 start_watching_root_cert = cert_info.root_cert_watchers.empty();
197 already_watching_identity_for_root_cert =
198 !cert_info.identity_cert_watchers.empty();
199 cert_info.root_cert_watchers.insert(watcher_ptr);
200 root_error = GRPC_ERROR_REF(cert_info.root_cert_error);
201 // Empty credentials will be treated as no updates.
202 if (!cert_info.pem_root_certs.empty()) {
203 updated_root_certs = cert_info.pem_root_certs;
206 if (identity_cert_name.has_value()) {
207 CertificateInfo& cert_info = certificate_info_map_[*identity_cert_name];
208 start_watching_identity_cert = cert_info.identity_cert_watchers.empty();
209 already_watching_root_for_identity_cert =
210 !cert_info.root_cert_watchers.empty();
211 cert_info.identity_cert_watchers.insert(watcher_ptr);
212 identity_error = GRPC_ERROR_REF(cert_info.identity_cert_error);
213 // Empty credentials will be treated as no updates.
214 if (!cert_info.pem_key_cert_pairs.empty()) {
215 updated_identity_pairs = cert_info.pem_key_cert_pairs;
218 // Notify this watcher if the certs it is watching already had some
219 // contents. Note that an *_cert_error in cert_info only indicates error
220 // occurred while trying to fetch the latest cert, but the updated_*_certs
221 // should always be valid. So we will send the updates regardless of
223 if (updated_root_certs.has_value() || updated_identity_pairs.has_value()) {
224 watcher_ptr->OnCertificatesChanged(updated_root_certs,
225 std::move(updated_identity_pairs));
227 // Notify this watcher if the certs it is watching already had some errors.
228 if (root_error != GRPC_ERROR_NONE || identity_error != GRPC_ERROR_NONE) {
229 watcher_ptr->OnError(GRPC_ERROR_REF(root_error),
230 GRPC_ERROR_REF(identity_error));
232 GRPC_ERROR_UNREF(root_error);
233 GRPC_ERROR_UNREF(identity_error);
235 // Invoke watch status callback if needed.
237 grpc_core::MutexLock lock(&callback_mu_);
238 if (watch_status_callback_ != nullptr) {
239 if (root_cert_name == identity_cert_name &&
240 (start_watching_root_cert || start_watching_identity_cert)) {
241 watch_status_callback_(*root_cert_name, start_watching_root_cert,
242 start_watching_identity_cert);
244 if (start_watching_root_cert) {
245 watch_status_callback_(*root_cert_name, true,
246 already_watching_identity_for_root_cert);
248 if (start_watching_identity_cert) {
249 watch_status_callback_(*identity_cert_name,
250 already_watching_root_for_identity_cert, true);
257 void grpc_tls_certificate_distributor::CancelTlsCertificatesWatch(
258 TlsCertificatesWatcherInterface* watcher) {
259 absl::optional<std::string> root_cert_name;
260 absl::optional<std::string> identity_cert_name;
261 bool stop_watching_root_cert = false;
262 bool already_watching_identity_for_root_cert = false;
263 bool stop_watching_identity_cert = false;
264 bool already_watching_root_for_identity_cert = false;
265 // Update watchers_ and certificate_info_map_.
267 grpc_core::MutexLock lock(&mu_);
268 auto it = watchers_.find(watcher);
269 if (it == watchers_.end()) return;
270 WatcherInfo& watcher_info = it->second;
271 root_cert_name = std::move(watcher_info.root_cert_name);
272 identity_cert_name = std::move(watcher_info.identity_cert_name);
274 if (root_cert_name.has_value()) {
275 auto it = certificate_info_map_.find(*root_cert_name);
276 GPR_ASSERT(it != certificate_info_map_.end());
277 CertificateInfo& cert_info = it->second;
278 cert_info.root_cert_watchers.erase(watcher);
279 stop_watching_root_cert = cert_info.root_cert_watchers.empty();
280 already_watching_identity_for_root_cert =
281 !cert_info.identity_cert_watchers.empty();
282 if (stop_watching_root_cert && !already_watching_identity_for_root_cert) {
283 certificate_info_map_.erase(it);
286 if (identity_cert_name.has_value()) {
287 auto it = certificate_info_map_.find(*identity_cert_name);
288 GPR_ASSERT(it != certificate_info_map_.end());
289 CertificateInfo& cert_info = it->second;
290 cert_info.identity_cert_watchers.erase(watcher);
291 stop_watching_identity_cert = cert_info.identity_cert_watchers.empty();
292 already_watching_root_for_identity_cert =
293 !cert_info.root_cert_watchers.empty();
294 if (stop_watching_identity_cert &&
295 !already_watching_root_for_identity_cert) {
296 certificate_info_map_.erase(it);
300 // Invoke watch status callback if needed.
302 grpc_core::MutexLock lock(&callback_mu_);
303 if (watch_status_callback_ != nullptr) {
304 if (root_cert_name == identity_cert_name &&
305 (stop_watching_root_cert || stop_watching_identity_cert)) {
306 watch_status_callback_(*root_cert_name, !stop_watching_root_cert,
307 !stop_watching_identity_cert);
309 if (stop_watching_root_cert) {
310 watch_status_callback_(*root_cert_name, false,
311 already_watching_identity_for_root_cert);
313 if (stop_watching_identity_cert) {
314 watch_status_callback_(*identity_cert_name,
315 already_watching_root_for_identity_cert,