Imported Upstream version 1.33.0
[platform/upstream/grpc.git] / src / core / lib / security / credentials / tls / grpc_tls_certificate_distributor.cc
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
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;
49       }
50       watcher_ptr->OnCertificatesChanged(
51           pem_root_certs, std::move(pem_key_cert_pairs_to_report));
52     }
53     cert_info.pem_root_certs = std::move(*pem_root_certs);
54   }
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.
68         continue;
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;
73       }
74       watcher_ptr->OnCertificatesChanged(pem_root_certs_to_report,
75                                          pem_key_cert_pairs);
76     }
77     cert_info.pem_key_cert_pairs = std::move(*pem_key_cert_pairs);
78   }
79 }
80
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();
87 };
88
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();
95 };
96
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;
118       }
119       watcher_ptr->OnError(GRPC_ERROR_REF(*root_cert_error),
120                            GRPC_ERROR_REF(identity_cert_error_to_report));
121     }
122     cert_info.SetRootError(*root_cert_error);
123   }
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.
136         continue;
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;
141       }
142       watcher_ptr->OnError(GRPC_ERROR_REF(root_cert_error_to_report),
143                            GRPC_ERROR_REF(*identity_cert_error));
144     }
145     cert_info.SetIdentityError(*identity_cert_error);
146   }
147 };
148
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)
158                                                 : GRPC_ERROR_NONE,
159         watcher_info.identity_cert_name.has_value() ? GRPC_ERROR_REF(error)
160                                                     : GRPC_ERROR_NONE);
161   }
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));
166   }
167   GRPC_ERROR_UNREF(error);
168 };
169
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_.
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     GPR_ASSERT(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<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;
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 = 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;
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 != GRPC_ERROR_NONE || identity_error != GRPC_ERROR_NONE) {
229       watcher_ptr->OnError(GRPC_ERROR_REF(root_error),
230                            GRPC_ERROR_REF(identity_error));
231     }
232     GRPC_ERROR_UNREF(root_error);
233     GRPC_ERROR_UNREF(identity_error);
234   }
235   // Invoke watch status callback if needed.
236   {
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);
243       } else {
244         if (start_watching_root_cert) {
245           watch_status_callback_(*root_cert_name, true,
246                                  already_watching_identity_for_root_cert);
247         }
248         if (start_watching_identity_cert) {
249           watch_status_callback_(*identity_cert_name,
250                                  already_watching_root_for_identity_cert, true);
251         }
252       }
253     }
254   }
255 };
256
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_.
266   {
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);
273     watchers_.erase(it);
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);
284       }
285     }
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);
297       }
298     }
299   }
300   // Invoke watch status callback if needed.
301   {
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);
308       } else {
309         if (stop_watching_root_cert) {
310           watch_status_callback_(*root_cert_name, false,
311                                  already_watching_identity_for_root_cert);
312         }
313         if (stop_watching_identity_cert) {
314           watch_status_callback_(*identity_cert_name,
315                                  already_watching_root_for_identity_cert,
316                                  false);
317         }
318       }
319     }
320   }
321 };