• 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 <grpc/support/port_platform.h>
18 
19 #include "src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h"
20 
21 #include <grpc/support/alloc.h>
22 #include <grpc/support/log.h>
23 #include <grpc/support/string_util.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
SetKeyMaterials(const std::string & cert_name,absl::optional<std::string> pem_root_certs,absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pairs)27 void grpc_tls_certificate_distributor::SetKeyMaterials(
28     const std::string& cert_name, absl::optional<std::string> pem_root_certs,
29     absl::optional<grpc_core::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<grpc_core::PemKeyCertPairList>
42           pem_key_cert_pairs_to_report;
43       if (pem_key_cert_pairs.has_value() &&
44           watcher_it->second.identity_cert_name == cert_name) {
45         pem_key_cert_pairs_to_report = pem_key_cert_pairs;
46       } else if (watcher_it->second.identity_cert_name.has_value()) {
47         auto& identity_cert_info =
48             certificate_info_map_[*watcher_it->second.identity_cert_name];
49         if (!identity_cert_info.pem_key_cert_pairs.empty()) {
50           pem_key_cert_pairs_to_report = identity_cert_info.pem_key_cert_pairs;
51         }
52       }
53       watcher_ptr->OnCertificatesChanged(
54           pem_root_certs, std::move(pem_key_cert_pairs_to_report));
55     }
56     cert_info.pem_root_certs = std::move(*pem_root_certs);
57   }
58   if (pem_key_cert_pairs.has_value()) {
59     // Successful credential updates will clear any pre-existing error.
60     cert_info.SetIdentityError(GRPC_ERROR_NONE);
61     for (const auto watcher_ptr : cert_info.identity_cert_watchers) {
62       GPR_ASSERT(watcher_ptr != nullptr);
63       const auto watcher_it = watchers_.find(watcher_ptr);
64       GPR_ASSERT(watcher_it != watchers_.end());
65       GPR_ASSERT(watcher_it->second.identity_cert_name.has_value());
66       absl::optional<absl::string_view> pem_root_certs_to_report;
67       if (pem_root_certs.has_value() &&
68           watcher_it->second.root_cert_name == cert_name) {
69         // In this case, We've already sent the credential updates at the time
70         // when checking pem_root_certs, so we will skip here.
71         continue;
72       } else if (watcher_it->second.root_cert_name.has_value()) {
73         auto& root_cert_info =
74             certificate_info_map_[*watcher_it->second.root_cert_name];
75         if (!root_cert_info.pem_root_certs.empty()) {
76           pem_root_certs_to_report = root_cert_info.pem_root_certs;
77         }
78       }
79       watcher_ptr->OnCertificatesChanged(pem_root_certs_to_report,
80                                          pem_key_cert_pairs);
81     }
82     cert_info.pem_key_cert_pairs = std::move(*pem_key_cert_pairs);
83   }
84 }
85 
HasRootCerts(const std::string & root_cert_name)86 bool grpc_tls_certificate_distributor::HasRootCerts(
87     const std::string& root_cert_name) {
88   grpc_core::MutexLock lock(&mu_);
89   const auto it = certificate_info_map_.find(root_cert_name);
90   return it != certificate_info_map_.end() &&
91          !it->second.pem_root_certs.empty();
92 };
93 
HasKeyCertPairs(const std::string & identity_cert_name)94 bool grpc_tls_certificate_distributor::HasKeyCertPairs(
95     const std::string& identity_cert_name) {
96   grpc_core::MutexLock lock(&mu_);
97   const auto it = certificate_info_map_.find(identity_cert_name);
98   return it != certificate_info_map_.end() &&
99          !it->second.pem_key_cert_pairs.empty();
100 };
101 
SetErrorForCert(const std::string & cert_name,absl::optional<grpc_error_handle> root_cert_error,absl::optional<grpc_error_handle> identity_cert_error)102 void grpc_tls_certificate_distributor::SetErrorForCert(
103     const std::string& cert_name,
104     absl::optional<grpc_error_handle> root_cert_error,
105     absl::optional<grpc_error_handle> identity_cert_error) {
106   GPR_ASSERT(root_cert_error.has_value() || identity_cert_error.has_value());
107   grpc_core::MutexLock lock(&mu_);
108   CertificateInfo& cert_info = certificate_info_map_[cert_name];
109   if (root_cert_error.has_value()) {
110     for (auto* watcher_ptr : cert_info.root_cert_watchers) {
111       GPR_ASSERT(watcher_ptr != nullptr);
112       const auto watcher_it = watchers_.find(watcher_ptr);
113       GPR_ASSERT(watcher_it != watchers_.end());
114       // identity_cert_error_to_report is the error of the identity cert this
115       // watcher is watching, if there is any.
116       grpc_error_handle identity_cert_error_to_report = GRPC_ERROR_NONE;
117       if (identity_cert_error.has_value() &&
118           watcher_it->second.identity_cert_name == cert_name) {
119         identity_cert_error_to_report = *identity_cert_error;
120       } else if (watcher_it->second.identity_cert_name.has_value()) {
121         auto& identity_cert_info =
122             certificate_info_map_[*watcher_it->second.identity_cert_name];
123         identity_cert_error_to_report = identity_cert_info.identity_cert_error;
124       }
125       watcher_ptr->OnError(GRPC_ERROR_REF(*root_cert_error),
126                            GRPC_ERROR_REF(identity_cert_error_to_report));
127     }
128     cert_info.SetRootError(*root_cert_error);
129   }
130   if (identity_cert_error.has_value()) {
131     for (auto* watcher_ptr : cert_info.identity_cert_watchers) {
132       GPR_ASSERT(watcher_ptr != nullptr);
133       const auto watcher_it = watchers_.find(watcher_ptr);
134       GPR_ASSERT(watcher_it != watchers_.end());
135       // root_cert_error_to_report is the error of the root cert this watcher is
136       // watching, if there is any.
137       grpc_error_handle root_cert_error_to_report = GRPC_ERROR_NONE;
138       if (root_cert_error.has_value() &&
139           watcher_it->second.root_cert_name == cert_name) {
140         // In this case, We've already sent the error updates at the time when
141         // checking root_cert_error, so we will skip here.
142         continue;
143       } else if (watcher_it->second.root_cert_name.has_value()) {
144         auto& root_cert_info =
145             certificate_info_map_[*watcher_it->second.root_cert_name];
146         root_cert_error_to_report = root_cert_info.root_cert_error;
147       }
148       watcher_ptr->OnError(GRPC_ERROR_REF(root_cert_error_to_report),
149                            GRPC_ERROR_REF(*identity_cert_error));
150     }
151     cert_info.SetIdentityError(*identity_cert_error);
152   }
153 };
154 
SetError(grpc_error_handle error)155 void grpc_tls_certificate_distributor::SetError(grpc_error_handle error) {
156   GPR_ASSERT(error != GRPC_ERROR_NONE);
157   grpc_core::MutexLock lock(&mu_);
158   for (const auto& watcher : watchers_) {
159     const auto watcher_ptr = watcher.first;
160     GPR_ASSERT(watcher_ptr != nullptr);
161     const auto& watcher_info = watcher.second;
162     watcher_ptr->OnError(
163         watcher_info.root_cert_name.has_value() ? GRPC_ERROR_REF(error)
164                                                 : GRPC_ERROR_NONE,
165         watcher_info.identity_cert_name.has_value() ? GRPC_ERROR_REF(error)
166                                                     : GRPC_ERROR_NONE);
167   }
168   for (auto& cert_info_entry : certificate_info_map_) {
169     auto& cert_info = cert_info_entry.second;
170     cert_info.SetRootError(GRPC_ERROR_REF(error));
171     cert_info.SetIdentityError(GRPC_ERROR_REF(error));
172   }
173   GRPC_ERROR_UNREF(error);
174 };
175 
WatchTlsCertificates(std::unique_ptr<TlsCertificatesWatcherInterface> watcher,absl::optional<std::string> root_cert_name,absl::optional<std::string> identity_cert_name)176 void grpc_tls_certificate_distributor::WatchTlsCertificates(
177     std::unique_ptr<TlsCertificatesWatcherInterface> watcher,
178     absl::optional<std::string> root_cert_name,
179     absl::optional<std::string> identity_cert_name) {
180   bool start_watching_root_cert = false;
181   bool already_watching_identity_for_root_cert = false;
182   bool start_watching_identity_cert = false;
183   bool already_watching_root_for_identity_cert = false;
184   GPR_ASSERT(root_cert_name.has_value() || identity_cert_name.has_value());
185   TlsCertificatesWatcherInterface* watcher_ptr = watcher.get();
186   GPR_ASSERT(watcher_ptr != nullptr);
187   // Update watchers_ and certificate_info_map_.
188   {
189     grpc_core::MutexLock lock(&mu_);
190     const auto watcher_it = watchers_.find(watcher_ptr);
191     // The caller needs to cancel the watcher first if it wants to re-register
192     // the watcher.
193     GPR_ASSERT(watcher_it == watchers_.end());
194     watchers_[watcher_ptr] = {std::move(watcher), root_cert_name,
195                               identity_cert_name};
196     absl::optional<absl::string_view> updated_root_certs;
197     absl::optional<grpc_core::PemKeyCertPairList> updated_identity_pairs;
198     grpc_error_handle root_error = GRPC_ERROR_NONE;
199     grpc_error_handle identity_error = GRPC_ERROR_NONE;
200     if (root_cert_name.has_value()) {
201       CertificateInfo& cert_info = certificate_info_map_[*root_cert_name];
202       start_watching_root_cert = cert_info.root_cert_watchers.empty();
203       already_watching_identity_for_root_cert =
204           !cert_info.identity_cert_watchers.empty();
205       cert_info.root_cert_watchers.insert(watcher_ptr);
206       root_error = GRPC_ERROR_REF(cert_info.root_cert_error);
207       // Empty credentials will be treated as no updates.
208       if (!cert_info.pem_root_certs.empty()) {
209         updated_root_certs = cert_info.pem_root_certs;
210       }
211     }
212     if (identity_cert_name.has_value()) {
213       CertificateInfo& cert_info = certificate_info_map_[*identity_cert_name];
214       start_watching_identity_cert = cert_info.identity_cert_watchers.empty();
215       already_watching_root_for_identity_cert =
216           !cert_info.root_cert_watchers.empty();
217       cert_info.identity_cert_watchers.insert(watcher_ptr);
218       identity_error = GRPC_ERROR_REF(cert_info.identity_cert_error);
219       // Empty credentials will be treated as no updates.
220       if (!cert_info.pem_key_cert_pairs.empty()) {
221         updated_identity_pairs = cert_info.pem_key_cert_pairs;
222       }
223     }
224     // Notify this watcher if the certs it is watching already had some
225     // contents. Note that an *_cert_error in cert_info only indicates error
226     // occurred while trying to fetch the latest cert, but the updated_*_certs
227     // should always be valid. So we will send the updates regardless of
228     // *_cert_error.
229     if (updated_root_certs.has_value() || updated_identity_pairs.has_value()) {
230       watcher_ptr->OnCertificatesChanged(updated_root_certs,
231                                          std::move(updated_identity_pairs));
232     }
233     // Notify this watcher if the certs it is watching already had some errors.
234     if (root_error != GRPC_ERROR_NONE || identity_error != GRPC_ERROR_NONE) {
235       watcher_ptr->OnError(GRPC_ERROR_REF(root_error),
236                            GRPC_ERROR_REF(identity_error));
237     }
238     GRPC_ERROR_UNREF(root_error);
239     GRPC_ERROR_UNREF(identity_error);
240   }
241   // Invoke watch status callback if needed.
242   {
243     grpc_core::MutexLock lock(&callback_mu_);
244     if (watch_status_callback_ != nullptr) {
245       if (root_cert_name == identity_cert_name &&
246           (start_watching_root_cert || start_watching_identity_cert)) {
247         watch_status_callback_(*root_cert_name, start_watching_root_cert,
248                                start_watching_identity_cert);
249       } else {
250         if (start_watching_root_cert) {
251           watch_status_callback_(*root_cert_name, true,
252                                  already_watching_identity_for_root_cert);
253         }
254         if (start_watching_identity_cert) {
255           watch_status_callback_(*identity_cert_name,
256                                  already_watching_root_for_identity_cert, true);
257         }
258       }
259     }
260   }
261 };
262 
CancelTlsCertificatesWatch(TlsCertificatesWatcherInterface * watcher)263 void grpc_tls_certificate_distributor::CancelTlsCertificatesWatch(
264     TlsCertificatesWatcherInterface* watcher) {
265   absl::optional<std::string> root_cert_name;
266   absl::optional<std::string> identity_cert_name;
267   bool stop_watching_root_cert = false;
268   bool already_watching_identity_for_root_cert = false;
269   bool stop_watching_identity_cert = false;
270   bool already_watching_root_for_identity_cert = false;
271   // Update watchers_ and certificate_info_map_.
272   {
273     grpc_core::MutexLock lock(&mu_);
274     auto it = watchers_.find(watcher);
275     if (it == watchers_.end()) return;
276     WatcherInfo& watcher_info = it->second;
277     root_cert_name = std::move(watcher_info.root_cert_name);
278     identity_cert_name = std::move(watcher_info.identity_cert_name);
279     watchers_.erase(it);
280     if (root_cert_name.has_value()) {
281       auto it = certificate_info_map_.find(*root_cert_name);
282       GPR_ASSERT(it != certificate_info_map_.end());
283       CertificateInfo& cert_info = it->second;
284       cert_info.root_cert_watchers.erase(watcher);
285       stop_watching_root_cert = cert_info.root_cert_watchers.empty();
286       already_watching_identity_for_root_cert =
287           !cert_info.identity_cert_watchers.empty();
288       if (stop_watching_root_cert && !already_watching_identity_for_root_cert) {
289         certificate_info_map_.erase(it);
290       }
291     }
292     if (identity_cert_name.has_value()) {
293       auto it = certificate_info_map_.find(*identity_cert_name);
294       GPR_ASSERT(it != certificate_info_map_.end());
295       CertificateInfo& cert_info = it->second;
296       cert_info.identity_cert_watchers.erase(watcher);
297       stop_watching_identity_cert = cert_info.identity_cert_watchers.empty();
298       already_watching_root_for_identity_cert =
299           !cert_info.root_cert_watchers.empty();
300       if (stop_watching_identity_cert &&
301           !already_watching_root_for_identity_cert) {
302         certificate_info_map_.erase(it);
303       }
304     }
305   }
306   // Invoke watch status callback if needed.
307   {
308     grpc_core::MutexLock lock(&callback_mu_);
309     if (watch_status_callback_ != nullptr) {
310       if (root_cert_name == identity_cert_name &&
311           (stop_watching_root_cert || stop_watching_identity_cert)) {
312         watch_status_callback_(*root_cert_name, !stop_watching_root_cert,
313                                !stop_watching_identity_cert);
314       } else {
315         if (stop_watching_root_cert) {
316           watch_status_callback_(*root_cert_name, false,
317                                  already_watching_identity_for_root_cert);
318         }
319         if (stop_watching_identity_cert) {
320           watch_status_callback_(*identity_cert_name,
321                                  already_watching_root_for_identity_cert,
322                                  false);
323         }
324       }
325     }
326   }
327 };
328 
329 /** -- Wrapper APIs declared in grpc_security.h -- **/
330 
grpc_tls_identity_pairs_create()331 grpc_tls_identity_pairs* grpc_tls_identity_pairs_create() {
332   return new grpc_tls_identity_pairs();
333 }
334 
grpc_tls_identity_pairs_add_pair(grpc_tls_identity_pairs * pairs,const char * private_key,const char * cert_chain)335 void grpc_tls_identity_pairs_add_pair(grpc_tls_identity_pairs* pairs,
336                                       const char* private_key,
337                                       const char* cert_chain) {
338   GPR_ASSERT(pairs != nullptr);
339   GPR_ASSERT(private_key != nullptr);
340   GPR_ASSERT(cert_chain != nullptr);
341   pairs->pem_key_cert_pairs.emplace_back(private_key, cert_chain);
342 }
343 
grpc_tls_identity_pairs_destroy(grpc_tls_identity_pairs * pairs)344 void grpc_tls_identity_pairs_destroy(grpc_tls_identity_pairs* pairs) {
345   GPR_ASSERT(pairs != nullptr);
346   delete pairs;
347 }
348