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