• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 gRPC authors.
3 //
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
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
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.
15 //
16 
17 #include "src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h"
18 
19 #include <grpc/credentials.h>
20 #include <grpc/grpc_security.h>
21 #include <grpc/support/port_platform.h>
22 
23 #include "absl/log/check.h"
24 #include "absl/status/status.h"
25 
SetKeyMaterials(const std::string & cert_name,absl::optional<std::string> pem_root_certs,absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pairs)26 void grpc_tls_certificate_distributor::SetKeyMaterials(
27     const std::string& cert_name, absl::optional<std::string> pem_root_certs,
28     absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pairs) {
29   CHECK(pem_root_certs.has_value() || pem_key_cert_pairs.has_value());
30   grpc_core::MutexLock lock(&mu_);
31   auto& cert_info = certificate_info_map_[cert_name];
32   if (pem_root_certs.has_value()) {
33     // Successful credential updates will clear any pre-existing error.
34     cert_info.SetRootError(absl::OkStatus());
35     for (auto* watcher_ptr : cert_info.root_cert_watchers) {
36       CHECK_NE(watcher_ptr, nullptr);
37       const auto watcher_it = watchers_.find(watcher_ptr);
38       CHECK(watcher_it != watchers_.end());
39       CHECK(watcher_it->second.root_cert_name.has_value());
40       absl::optional<grpc_core::PemKeyCertPairList>
41           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         if (!identity_cert_info.pem_key_cert_pairs.empty()) {
49           pem_key_cert_pairs_to_report = identity_cert_info.pem_key_cert_pairs;
50         }
51       }
52       watcher_ptr->OnCertificatesChanged(
53           pem_root_certs, std::move(pem_key_cert_pairs_to_report));
54     }
55     cert_info.pem_root_certs = std::move(*pem_root_certs);
56   }
57   if (pem_key_cert_pairs.has_value()) {
58     // Successful credential updates will clear any pre-existing error.
59     cert_info.SetIdentityError(absl::OkStatus());
60     for (const auto watcher_ptr : cert_info.identity_cert_watchers) {
61       CHECK_NE(watcher_ptr, nullptr);
62       const auto watcher_it = watchers_.find(watcher_ptr);
63       CHECK(watcher_it != watchers_.end());
64       CHECK(watcher_it->second.identity_cert_name.has_value());
65       absl::optional<absl::string_view> pem_root_certs_to_report;
66       if (pem_root_certs.has_value() &&
67           watcher_it->second.root_cert_name == cert_name) {
68         // In this case, We've already sent the credential updates at the time
69         // when checking pem_root_certs, so we will skip here.
70         continue;
71       } else if (watcher_it->second.root_cert_name.has_value()) {
72         auto& root_cert_info =
73             certificate_info_map_[*watcher_it->second.root_cert_name];
74         if (!root_cert_info.pem_root_certs.empty()) {
75           pem_root_certs_to_report = root_cert_info.pem_root_certs;
76         }
77       }
78       watcher_ptr->OnCertificatesChanged(pem_root_certs_to_report,
79                                          pem_key_cert_pairs);
80     }
81     cert_info.pem_key_cert_pairs = std::move(*pem_key_cert_pairs);
82   }
83 }
84 
HasRootCerts(const std::string & root_cert_name)85 bool grpc_tls_certificate_distributor::HasRootCerts(
86     const std::string& root_cert_name) {
87   grpc_core::MutexLock lock(&mu_);
88   const auto it = certificate_info_map_.find(root_cert_name);
89   return it != certificate_info_map_.end() &&
90          !it->second.pem_root_certs.empty();
91 };
92 
HasKeyCertPairs(const std::string & identity_cert_name)93 bool grpc_tls_certificate_distributor::HasKeyCertPairs(
94     const std::string& identity_cert_name) {
95   grpc_core::MutexLock lock(&mu_);
96   const auto it = certificate_info_map_.find(identity_cert_name);
97   return it != certificate_info_map_.end() &&
98          !it->second.pem_key_cert_pairs.empty();
99 };
100 
SetErrorForCert(const std::string & cert_name,absl::optional<grpc_error_handle> root_cert_error,absl::optional<grpc_error_handle> identity_cert_error)101 void grpc_tls_certificate_distributor::SetErrorForCert(
102     const std::string& cert_name,
103     absl::optional<grpc_error_handle> root_cert_error,
104     absl::optional<grpc_error_handle> identity_cert_error) {
105   CHECK(root_cert_error.has_value() || identity_cert_error.has_value());
106   grpc_core::MutexLock lock(&mu_);
107   CertificateInfo& cert_info = certificate_info_map_[cert_name];
108   if (root_cert_error.has_value()) {
109     for (auto* watcher_ptr : cert_info.root_cert_watchers) {
110       CHECK_NE(watcher_ptr, nullptr);
111       const auto watcher_it = watchers_.find(watcher_ptr);
112       CHECK(watcher_it != watchers_.end());
113       // identity_cert_error_to_report is the error of the identity cert this
114       // watcher is watching, if there is any.
115       grpc_error_handle identity_cert_error_to_report;
116       if (identity_cert_error.has_value() &&
117           watcher_it->second.identity_cert_name == cert_name) {
118         identity_cert_error_to_report = *identity_cert_error;
119       } else if (watcher_it->second.identity_cert_name.has_value()) {
120         auto& identity_cert_info =
121             certificate_info_map_[*watcher_it->second.identity_cert_name];
122         identity_cert_error_to_report = identity_cert_info.identity_cert_error;
123       }
124       watcher_ptr->OnError(*root_cert_error, identity_cert_error_to_report);
125     }
126     cert_info.SetRootError(*root_cert_error);
127   }
128   if (identity_cert_error.has_value()) {
129     for (auto* watcher_ptr : cert_info.identity_cert_watchers) {
130       CHECK_NE(watcher_ptr, nullptr);
131       const auto watcher_it = watchers_.find(watcher_ptr);
132       CHECK(watcher_it != watchers_.end());
133       // root_cert_error_to_report is the error of the root cert this watcher is
134       // watching, if there is any.
135       grpc_error_handle root_cert_error_to_report;
136       if (root_cert_error.has_value() &&
137           watcher_it->second.root_cert_name == cert_name) {
138         // In this case, We've already sent the error updates at the time when
139         // checking root_cert_error, so we will skip here.
140         continue;
141       } else if (watcher_it->second.root_cert_name.has_value()) {
142         auto& root_cert_info =
143             certificate_info_map_[*watcher_it->second.root_cert_name];
144         root_cert_error_to_report = root_cert_info.root_cert_error;
145       }
146       watcher_ptr->OnError(root_cert_error_to_report, *identity_cert_error);
147     }
148     cert_info.SetIdentityError(*identity_cert_error);
149   }
150 };
151 
SetError(grpc_error_handle error)152 void grpc_tls_certificate_distributor::SetError(grpc_error_handle error) {
153   CHECK(!error.ok());
154   grpc_core::MutexLock lock(&mu_);
155   for (const auto& watcher : watchers_) {
156     const auto watcher_ptr = watcher.first;
157     CHECK_NE(watcher_ptr, nullptr);
158     const auto& watcher_info = watcher.second;
159     watcher_ptr->OnError(
160         watcher_info.root_cert_name.has_value() ? error : absl::OkStatus(),
161         watcher_info.identity_cert_name.has_value() ? error : absl::OkStatus());
162   }
163   for (auto& cert_info_entry : certificate_info_map_) {
164     auto& cert_info = cert_info_entry.second;
165     cert_info.SetRootError(error);
166     cert_info.SetIdentityError(error);
167   }
168 };
169 
WatchTlsCertificates(std::unique_ptr<TlsCertificatesWatcherInterface> watcher,absl::optional<std::string> root_cert_name,absl::optional<std::string> identity_cert_name)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   CHECK(root_cert_name.has_value() || identity_cert_name.has_value());
179   TlsCertificatesWatcherInterface* watcher_ptr = watcher.get();
180   CHECK_NE(watcher_ptr, nullptr);
181   // Update watchers_ and certificate_info_map_.
182   {
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
186     // the watcher.
187     CHECK(watcher_it == watchers_.end());
188     watchers_[watcher_ptr] = {std::move(watcher), root_cert_name,
189                               identity_cert_name};
190     absl::optional<absl::string_view> updated_root_certs;
191     absl::optional<grpc_core::PemKeyCertPairList> updated_identity_pairs;
192     grpc_error_handle root_error;
193     grpc_error_handle identity_error;
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 = 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;
204       }
205     }
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 = 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;
216       }
217     }
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
222     // *_cert_error.
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));
226     }
227     // Notify this watcher if the certs it is watching already had some errors.
228     if (!root_error.ok() || !identity_error.ok()) {
229       watcher_ptr->OnError(root_error, identity_error);
230     }
231   }
232   // Invoke watch status callback if needed.
233   {
234     grpc_core::MutexLock lock(&callback_mu_);
235     if (watch_status_callback_ != nullptr) {
236       if (root_cert_name == identity_cert_name &&
237           (start_watching_root_cert || start_watching_identity_cert)) {
238         watch_status_callback_(*root_cert_name, start_watching_root_cert,
239                                start_watching_identity_cert);
240       } else {
241         if (start_watching_root_cert) {
242           watch_status_callback_(*root_cert_name, true,
243                                  already_watching_identity_for_root_cert);
244         }
245         if (start_watching_identity_cert) {
246           watch_status_callback_(*identity_cert_name,
247                                  already_watching_root_for_identity_cert, true);
248         }
249       }
250     }
251   }
252 };
253 
CancelTlsCertificatesWatch(TlsCertificatesWatcherInterface * watcher)254 void grpc_tls_certificate_distributor::CancelTlsCertificatesWatch(
255     TlsCertificatesWatcherInterface* watcher) {
256   absl::optional<std::string> root_cert_name;
257   absl::optional<std::string> identity_cert_name;
258   bool stop_watching_root_cert = false;
259   bool already_watching_identity_for_root_cert = false;
260   bool stop_watching_identity_cert = false;
261   bool already_watching_root_for_identity_cert = false;
262   // Update watchers_ and certificate_info_map_.
263   {
264     grpc_core::MutexLock lock(&mu_);
265     auto it = watchers_.find(watcher);
266     if (it == watchers_.end()) return;
267     WatcherInfo& watcher_info = it->second;
268     root_cert_name = std::move(watcher_info.root_cert_name);
269     identity_cert_name = std::move(watcher_info.identity_cert_name);
270     watchers_.erase(it);
271     if (root_cert_name.has_value()) {
272       auto it = certificate_info_map_.find(*root_cert_name);
273       CHECK(it != certificate_info_map_.end());
274       CertificateInfo& cert_info = it->second;
275       cert_info.root_cert_watchers.erase(watcher);
276       stop_watching_root_cert = cert_info.root_cert_watchers.empty();
277       already_watching_identity_for_root_cert =
278           !cert_info.identity_cert_watchers.empty();
279       if (stop_watching_root_cert && !already_watching_identity_for_root_cert) {
280         certificate_info_map_.erase(it);
281       }
282     }
283     if (identity_cert_name.has_value()) {
284       auto it = certificate_info_map_.find(*identity_cert_name);
285       CHECK(it != certificate_info_map_.end());
286       CertificateInfo& cert_info = it->second;
287       cert_info.identity_cert_watchers.erase(watcher);
288       stop_watching_identity_cert = cert_info.identity_cert_watchers.empty();
289       already_watching_root_for_identity_cert =
290           !cert_info.root_cert_watchers.empty();
291       if (stop_watching_identity_cert &&
292           !already_watching_root_for_identity_cert) {
293         certificate_info_map_.erase(it);
294       }
295     }
296   }
297   // Invoke watch status callback if needed.
298   {
299     grpc_core::MutexLock lock(&callback_mu_);
300     if (watch_status_callback_ != nullptr) {
301       if (root_cert_name == identity_cert_name &&
302           (stop_watching_root_cert || stop_watching_identity_cert)) {
303         watch_status_callback_(*root_cert_name, !stop_watching_root_cert,
304                                !stop_watching_identity_cert);
305       } else {
306         if (stop_watching_root_cert) {
307           watch_status_callback_(*root_cert_name, false,
308                                  already_watching_identity_for_root_cert);
309         }
310         if (stop_watching_identity_cert) {
311           watch_status_callback_(*identity_cert_name,
312                                  already_watching_root_for_identity_cert,
313                                  false);
314         }
315       }
316     }
317   }
318 };
319 
320 /// -- Wrapper APIs declared in grpc_security.h -- *
321 
grpc_tls_identity_pairs_create()322 grpc_tls_identity_pairs* grpc_tls_identity_pairs_create() {
323   return new grpc_tls_identity_pairs();
324 }
325 
grpc_tls_identity_pairs_add_pair(grpc_tls_identity_pairs * pairs,const char * private_key,const char * cert_chain)326 void grpc_tls_identity_pairs_add_pair(grpc_tls_identity_pairs* pairs,
327                                       const char* private_key,
328                                       const char* cert_chain) {
329   CHECK_NE(pairs, nullptr);
330   CHECK_NE(private_key, nullptr);
331   CHECK_NE(cert_chain, nullptr);
332   pairs->pem_key_cert_pairs.emplace_back(private_key, cert_chain);
333 }
334 
grpc_tls_identity_pairs_destroy(grpc_tls_identity_pairs * pairs)335 void grpc_tls_identity_pairs_destroy(grpc_tls_identity_pairs* pairs) {
336   CHECK_NE(pairs, nullptr);
337   delete pairs;
338 }
339