• 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 * > root_cert_error,absl::optional<grpc_error * > identity_cert_error)102 void grpc_tls_certificate_distributor::SetErrorForCert(
103     const std::string& cert_name, absl::optional<grpc_error*> root_cert_error,
104     absl::optional<grpc_error*> identity_cert_error) {
105   GPR_ASSERT(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       GPR_ASSERT(watcher_ptr != nullptr);
111       const auto watcher_it = watchers_.find(watcher_ptr);
112       GPR_ASSERT(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* identity_cert_error_to_report = GRPC_ERROR_NONE;
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(GRPC_ERROR_REF(*root_cert_error),
125                            GRPC_ERROR_REF(identity_cert_error_to_report));
126     }
127     cert_info.SetRootError(*root_cert_error);
128   }
129   if (identity_cert_error.has_value()) {
130     for (auto* watcher_ptr : cert_info.identity_cert_watchers) {
131       GPR_ASSERT(watcher_ptr != nullptr);
132       const auto watcher_it = watchers_.find(watcher_ptr);
133       GPR_ASSERT(watcher_it != watchers_.end());
134       // root_cert_error_to_report is the error of the root cert this watcher is
135       // watching, if there is any.
136       grpc_error* root_cert_error_to_report = GRPC_ERROR_NONE;
137       if (root_cert_error.has_value() &&
138           watcher_it->second.root_cert_name == cert_name) {
139         // In this case, We've already sent the error updates at the time when
140         // checking root_cert_error, so we will skip here.
141         continue;
142       } else if (watcher_it->second.root_cert_name.has_value()) {
143         auto& root_cert_info =
144             certificate_info_map_[*watcher_it->second.root_cert_name];
145         root_cert_error_to_report = root_cert_info.root_cert_error;
146       }
147       watcher_ptr->OnError(GRPC_ERROR_REF(root_cert_error_to_report),
148                            GRPC_ERROR_REF(*identity_cert_error));
149     }
150     cert_info.SetIdentityError(*identity_cert_error);
151   }
152 };
153 
SetError(grpc_error * error)154 void grpc_tls_certificate_distributor::SetError(grpc_error* error) {
155   GPR_ASSERT(error != GRPC_ERROR_NONE);
156   grpc_core::MutexLock lock(&mu_);
157   for (const auto& watcher : watchers_) {
158     const auto watcher_ptr = watcher.first;
159     GPR_ASSERT(watcher_ptr != nullptr);
160     const auto& watcher_info = watcher.second;
161     watcher_ptr->OnError(
162         watcher_info.root_cert_name.has_value() ? GRPC_ERROR_REF(error)
163                                                 : GRPC_ERROR_NONE,
164         watcher_info.identity_cert_name.has_value() ? GRPC_ERROR_REF(error)
165                                                     : GRPC_ERROR_NONE);
166   }
167   for (auto& cert_info_entry : certificate_info_map_) {
168     auto& cert_info = cert_info_entry.second;
169     cert_info.SetRootError(GRPC_ERROR_REF(error));
170     cert_info.SetIdentityError(GRPC_ERROR_REF(error));
171   }
172   GRPC_ERROR_UNREF(error);
173 };
174 
WatchTlsCertificates(std::unique_ptr<TlsCertificatesWatcherInterface> watcher,absl::optional<std::string> root_cert_name,absl::optional<std::string> identity_cert_name)175 void grpc_tls_certificate_distributor::WatchTlsCertificates(
176     std::unique_ptr<TlsCertificatesWatcherInterface> watcher,
177     absl::optional<std::string> root_cert_name,
178     absl::optional<std::string> identity_cert_name) {
179   bool start_watching_root_cert = false;
180   bool already_watching_identity_for_root_cert = false;
181   bool start_watching_identity_cert = false;
182   bool already_watching_root_for_identity_cert = false;
183   GPR_ASSERT(root_cert_name.has_value() || identity_cert_name.has_value());
184   TlsCertificatesWatcherInterface* watcher_ptr = watcher.get();
185   GPR_ASSERT(watcher_ptr != nullptr);
186   // Update watchers_ and certificate_info_map_.
187   {
188     grpc_core::MutexLock lock(&mu_);
189     const auto watcher_it = watchers_.find(watcher_ptr);
190     // The caller needs to cancel the watcher first if it wants to re-register
191     // the watcher.
192     GPR_ASSERT(watcher_it == watchers_.end());
193     watchers_[watcher_ptr] = {std::move(watcher), root_cert_name,
194                               identity_cert_name};
195     absl::optional<absl::string_view> updated_root_certs;
196     absl::optional<grpc_core::PemKeyCertPairList> updated_identity_pairs;
197     grpc_error* root_error = GRPC_ERROR_NONE;
198     grpc_error* identity_error = GRPC_ERROR_NONE;
199     if (root_cert_name.has_value()) {
200       CertificateInfo& cert_info = certificate_info_map_[*root_cert_name];
201       start_watching_root_cert = cert_info.root_cert_watchers.empty();
202       already_watching_identity_for_root_cert =
203           !cert_info.identity_cert_watchers.empty();
204       cert_info.root_cert_watchers.insert(watcher_ptr);
205       root_error = GRPC_ERROR_REF(cert_info.root_cert_error);
206       // Empty credentials will be treated as no updates.
207       if (!cert_info.pem_root_certs.empty()) {
208         updated_root_certs = cert_info.pem_root_certs;
209       }
210     }
211     if (identity_cert_name.has_value()) {
212       CertificateInfo& cert_info = certificate_info_map_[*identity_cert_name];
213       start_watching_identity_cert = cert_info.identity_cert_watchers.empty();
214       already_watching_root_for_identity_cert =
215           !cert_info.root_cert_watchers.empty();
216       cert_info.identity_cert_watchers.insert(watcher_ptr);
217       identity_error = GRPC_ERROR_REF(cert_info.identity_cert_error);
218       // Empty credentials will be treated as no updates.
219       if (!cert_info.pem_key_cert_pairs.empty()) {
220         updated_identity_pairs = cert_info.pem_key_cert_pairs;
221       }
222     }
223     // Notify this watcher if the certs it is watching already had some
224     // contents. Note that an *_cert_error in cert_info only indicates error
225     // occurred while trying to fetch the latest cert, but the updated_*_certs
226     // should always be valid. So we will send the updates regardless of
227     // *_cert_error.
228     if (updated_root_certs.has_value() || updated_identity_pairs.has_value()) {
229       watcher_ptr->OnCertificatesChanged(updated_root_certs,
230                                          std::move(updated_identity_pairs));
231     }
232     // Notify this watcher if the certs it is watching already had some errors.
233     if (root_error != GRPC_ERROR_NONE || identity_error != GRPC_ERROR_NONE) {
234       watcher_ptr->OnError(GRPC_ERROR_REF(root_error),
235                            GRPC_ERROR_REF(identity_error));
236     }
237     GRPC_ERROR_UNREF(root_error);
238     GRPC_ERROR_UNREF(identity_error);
239   }
240   // Invoke watch status callback if needed.
241   {
242     grpc_core::MutexLock lock(&callback_mu_);
243     if (watch_status_callback_ != nullptr) {
244       if (root_cert_name == identity_cert_name &&
245           (start_watching_root_cert || start_watching_identity_cert)) {
246         watch_status_callback_(*root_cert_name, start_watching_root_cert,
247                                start_watching_identity_cert);
248       } else {
249         if (start_watching_root_cert) {
250           watch_status_callback_(*root_cert_name, true,
251                                  already_watching_identity_for_root_cert);
252         }
253         if (start_watching_identity_cert) {
254           watch_status_callback_(*identity_cert_name,
255                                  already_watching_root_for_identity_cert, true);
256         }
257       }
258     }
259   }
260 };
261 
CancelTlsCertificatesWatch(TlsCertificatesWatcherInterface * watcher)262 void grpc_tls_certificate_distributor::CancelTlsCertificatesWatch(
263     TlsCertificatesWatcherInterface* watcher) {
264   absl::optional<std::string> root_cert_name;
265   absl::optional<std::string> identity_cert_name;
266   bool stop_watching_root_cert = false;
267   bool already_watching_identity_for_root_cert = false;
268   bool stop_watching_identity_cert = false;
269   bool already_watching_root_for_identity_cert = false;
270   // Update watchers_ and certificate_info_map_.
271   {
272     grpc_core::MutexLock lock(&mu_);
273     auto it = watchers_.find(watcher);
274     if (it == watchers_.end()) return;
275     WatcherInfo& watcher_info = it->second;
276     root_cert_name = std::move(watcher_info.root_cert_name);
277     identity_cert_name = std::move(watcher_info.identity_cert_name);
278     watchers_.erase(it);
279     if (root_cert_name.has_value()) {
280       auto it = certificate_info_map_.find(*root_cert_name);
281       GPR_ASSERT(it != certificate_info_map_.end());
282       CertificateInfo& cert_info = it->second;
283       cert_info.root_cert_watchers.erase(watcher);
284       stop_watching_root_cert = cert_info.root_cert_watchers.empty();
285       already_watching_identity_for_root_cert =
286           !cert_info.identity_cert_watchers.empty();
287       if (stop_watching_root_cert && !already_watching_identity_for_root_cert) {
288         certificate_info_map_.erase(it);
289       }
290     }
291     if (identity_cert_name.has_value()) {
292       auto it = certificate_info_map_.find(*identity_cert_name);
293       GPR_ASSERT(it != certificate_info_map_.end());
294       CertificateInfo& cert_info = it->second;
295       cert_info.identity_cert_watchers.erase(watcher);
296       stop_watching_identity_cert = cert_info.identity_cert_watchers.empty();
297       already_watching_root_for_identity_cert =
298           !cert_info.root_cert_watchers.empty();
299       if (stop_watching_identity_cert &&
300           !already_watching_root_for_identity_cert) {
301         certificate_info_map_.erase(it);
302       }
303     }
304   }
305   // Invoke watch status callback if needed.
306   {
307     grpc_core::MutexLock lock(&callback_mu_);
308     if (watch_status_callback_ != nullptr) {
309       if (root_cert_name == identity_cert_name &&
310           (stop_watching_root_cert || stop_watching_identity_cert)) {
311         watch_status_callback_(*root_cert_name, !stop_watching_root_cert,
312                                !stop_watching_identity_cert);
313       } else {
314         if (stop_watching_root_cert) {
315           watch_status_callback_(*root_cert_name, false,
316                                  already_watching_identity_for_root_cert);
317         }
318         if (stop_watching_identity_cert) {
319           watch_status_callback_(*identity_cert_name,
320                                  already_watching_root_for_identity_cert,
321                                  false);
322         }
323       }
324     }
325   }
326 };
327 
328 /** -- Wrapper APIs declared in grpc_security.h -- **/
329 
grpc_tls_identity_pairs_create()330 grpc_tls_identity_pairs* grpc_tls_identity_pairs_create() {
331   return new grpc_tls_identity_pairs();
332 }
333 
grpc_tls_identity_pairs_add_pair(grpc_tls_identity_pairs * pairs,const char * private_key,const char * cert_chain)334 void grpc_tls_identity_pairs_add_pair(grpc_tls_identity_pairs* pairs,
335                                       const char* private_key,
336                                       const char* cert_chain) {
337   GPR_ASSERT(pairs != nullptr);
338   GPR_ASSERT(private_key != nullptr);
339   GPR_ASSERT(cert_chain != nullptr);
340   pairs->pem_key_cert_pairs.emplace_back(private_key, cert_chain);
341 }
342 
grpc_tls_identity_pairs_destroy(grpc_tls_identity_pairs * pairs)343 void grpc_tls_identity_pairs_destroy(grpc_tls_identity_pairs* pairs) {
344   GPR_ASSERT(pairs != nullptr);
345   delete pairs;
346 }
347