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