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 "src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h"
18
19 #include <grpc/credentials.h>
20 #include <grpc/grpc_security.h>
21 #include <grpc/support/port_platform.h>
22
23 #include "absl/log/check.h"
24 #include "absl/status/status.h"
25
SetKeyMaterials(const std::string & cert_name,absl::optional<std::string> pem_root_certs,absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pairs)26 void grpc_tls_certificate_distributor::SetKeyMaterials(
27 const std::string& cert_name, absl::optional<std::string> pem_root_certs,
28 absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pairs) {
29 CHECK(pem_root_certs.has_value() || pem_key_cert_pairs.has_value());
30 grpc_core::MutexLock lock(&mu_);
31 auto& cert_info = certificate_info_map_[cert_name];
32 if (pem_root_certs.has_value()) {
33 // Successful credential updates will clear any pre-existing error.
34 cert_info.SetRootError(absl::OkStatus());
35 for (auto* watcher_ptr : cert_info.root_cert_watchers) {
36 CHECK_NE(watcher_ptr, nullptr);
37 const auto watcher_it = watchers_.find(watcher_ptr);
38 CHECK(watcher_it != watchers_.end());
39 CHECK(watcher_it->second.root_cert_name.has_value());
40 absl::optional<grpc_core::PemKeyCertPairList>
41 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 if (!identity_cert_info.pem_key_cert_pairs.empty()) {
49 pem_key_cert_pairs_to_report = identity_cert_info.pem_key_cert_pairs;
50 }
51 }
52 watcher_ptr->OnCertificatesChanged(
53 pem_root_certs, std::move(pem_key_cert_pairs_to_report));
54 }
55 cert_info.pem_root_certs = std::move(*pem_root_certs);
56 }
57 if (pem_key_cert_pairs.has_value()) {
58 // Successful credential updates will clear any pre-existing error.
59 cert_info.SetIdentityError(absl::OkStatus());
60 for (const auto watcher_ptr : cert_info.identity_cert_watchers) {
61 CHECK_NE(watcher_ptr, nullptr);
62 const auto watcher_it = watchers_.find(watcher_ptr);
63 CHECK(watcher_it != watchers_.end());
64 CHECK(watcher_it->second.identity_cert_name.has_value());
65 absl::optional<absl::string_view> pem_root_certs_to_report;
66 if (pem_root_certs.has_value() &&
67 watcher_it->second.root_cert_name == cert_name) {
68 // In this case, We've already sent the credential updates at the time
69 // when checking pem_root_certs, so we will skip here.
70 continue;
71 } else if (watcher_it->second.root_cert_name.has_value()) {
72 auto& root_cert_info =
73 certificate_info_map_[*watcher_it->second.root_cert_name];
74 if (!root_cert_info.pem_root_certs.empty()) {
75 pem_root_certs_to_report = root_cert_info.pem_root_certs;
76 }
77 }
78 watcher_ptr->OnCertificatesChanged(pem_root_certs_to_report,
79 pem_key_cert_pairs);
80 }
81 cert_info.pem_key_cert_pairs = std::move(*pem_key_cert_pairs);
82 }
83 }
84
HasRootCerts(const std::string & root_cert_name)85 bool grpc_tls_certificate_distributor::HasRootCerts(
86 const std::string& root_cert_name) {
87 grpc_core::MutexLock lock(&mu_);
88 const auto it = certificate_info_map_.find(root_cert_name);
89 return it != certificate_info_map_.end() &&
90 !it->second.pem_root_certs.empty();
91 };
92
HasKeyCertPairs(const std::string & identity_cert_name)93 bool grpc_tls_certificate_distributor::HasKeyCertPairs(
94 const std::string& identity_cert_name) {
95 grpc_core::MutexLock lock(&mu_);
96 const auto it = certificate_info_map_.find(identity_cert_name);
97 return it != certificate_info_map_.end() &&
98 !it->second.pem_key_cert_pairs.empty();
99 };
100
SetErrorForCert(const std::string & cert_name,absl::optional<grpc_error_handle> root_cert_error,absl::optional<grpc_error_handle> identity_cert_error)101 void grpc_tls_certificate_distributor::SetErrorForCert(
102 const std::string& cert_name,
103 absl::optional<grpc_error_handle> root_cert_error,
104 absl::optional<grpc_error_handle> identity_cert_error) {
105 CHECK(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 CHECK_NE(watcher_ptr, nullptr);
111 const auto watcher_it = watchers_.find(watcher_ptr);
112 CHECK(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_handle identity_cert_error_to_report;
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(*root_cert_error, identity_cert_error_to_report);
125 }
126 cert_info.SetRootError(*root_cert_error);
127 }
128 if (identity_cert_error.has_value()) {
129 for (auto* watcher_ptr : cert_info.identity_cert_watchers) {
130 CHECK_NE(watcher_ptr, nullptr);
131 const auto watcher_it = watchers_.find(watcher_ptr);
132 CHECK(watcher_it != watchers_.end());
133 // root_cert_error_to_report is the error of the root cert this watcher is
134 // watching, if there is any.
135 grpc_error_handle root_cert_error_to_report;
136 if (root_cert_error.has_value() &&
137 watcher_it->second.root_cert_name == cert_name) {
138 // In this case, We've already sent the error updates at the time when
139 // checking root_cert_error, so we will skip here.
140 continue;
141 } else if (watcher_it->second.root_cert_name.has_value()) {
142 auto& root_cert_info =
143 certificate_info_map_[*watcher_it->second.root_cert_name];
144 root_cert_error_to_report = root_cert_info.root_cert_error;
145 }
146 watcher_ptr->OnError(root_cert_error_to_report, *identity_cert_error);
147 }
148 cert_info.SetIdentityError(*identity_cert_error);
149 }
150 };
151
SetError(grpc_error_handle error)152 void grpc_tls_certificate_distributor::SetError(grpc_error_handle error) {
153 CHECK(!error.ok());
154 grpc_core::MutexLock lock(&mu_);
155 for (const auto& watcher : watchers_) {
156 const auto watcher_ptr = watcher.first;
157 CHECK_NE(watcher_ptr, nullptr);
158 const auto& watcher_info = watcher.second;
159 watcher_ptr->OnError(
160 watcher_info.root_cert_name.has_value() ? error : absl::OkStatus(),
161 watcher_info.identity_cert_name.has_value() ? error : absl::OkStatus());
162 }
163 for (auto& cert_info_entry : certificate_info_map_) {
164 auto& cert_info = cert_info_entry.second;
165 cert_info.SetRootError(error);
166 cert_info.SetIdentityError(error);
167 }
168 };
169
WatchTlsCertificates(std::unique_ptr<TlsCertificatesWatcherInterface> watcher,absl::optional<std::string> root_cert_name,absl::optional<std::string> identity_cert_name)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 CHECK(root_cert_name.has_value() || identity_cert_name.has_value());
179 TlsCertificatesWatcherInterface* watcher_ptr = watcher.get();
180 CHECK_NE(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 CHECK(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<grpc_core::PemKeyCertPairList> updated_identity_pairs;
192 grpc_error_handle root_error;
193 grpc_error_handle identity_error;
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 = 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 = 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.ok() || !identity_error.ok()) {
229 watcher_ptr->OnError(root_error, identity_error);
230 }
231 }
232 // Invoke watch status callback if needed.
233 {
234 grpc_core::MutexLock lock(&callback_mu_);
235 if (watch_status_callback_ != nullptr) {
236 if (root_cert_name == identity_cert_name &&
237 (start_watching_root_cert || start_watching_identity_cert)) {
238 watch_status_callback_(*root_cert_name, start_watching_root_cert,
239 start_watching_identity_cert);
240 } else {
241 if (start_watching_root_cert) {
242 watch_status_callback_(*root_cert_name, true,
243 already_watching_identity_for_root_cert);
244 }
245 if (start_watching_identity_cert) {
246 watch_status_callback_(*identity_cert_name,
247 already_watching_root_for_identity_cert, true);
248 }
249 }
250 }
251 }
252 };
253
CancelTlsCertificatesWatch(TlsCertificatesWatcherInterface * watcher)254 void grpc_tls_certificate_distributor::CancelTlsCertificatesWatch(
255 TlsCertificatesWatcherInterface* watcher) {
256 absl::optional<std::string> root_cert_name;
257 absl::optional<std::string> identity_cert_name;
258 bool stop_watching_root_cert = false;
259 bool already_watching_identity_for_root_cert = false;
260 bool stop_watching_identity_cert = false;
261 bool already_watching_root_for_identity_cert = false;
262 // Update watchers_ and certificate_info_map_.
263 {
264 grpc_core::MutexLock lock(&mu_);
265 auto it = watchers_.find(watcher);
266 if (it == watchers_.end()) return;
267 WatcherInfo& watcher_info = it->second;
268 root_cert_name = std::move(watcher_info.root_cert_name);
269 identity_cert_name = std::move(watcher_info.identity_cert_name);
270 watchers_.erase(it);
271 if (root_cert_name.has_value()) {
272 auto it = certificate_info_map_.find(*root_cert_name);
273 CHECK(it != certificate_info_map_.end());
274 CertificateInfo& cert_info = it->second;
275 cert_info.root_cert_watchers.erase(watcher);
276 stop_watching_root_cert = cert_info.root_cert_watchers.empty();
277 already_watching_identity_for_root_cert =
278 !cert_info.identity_cert_watchers.empty();
279 if (stop_watching_root_cert && !already_watching_identity_for_root_cert) {
280 certificate_info_map_.erase(it);
281 }
282 }
283 if (identity_cert_name.has_value()) {
284 auto it = certificate_info_map_.find(*identity_cert_name);
285 CHECK(it != certificate_info_map_.end());
286 CertificateInfo& cert_info = it->second;
287 cert_info.identity_cert_watchers.erase(watcher);
288 stop_watching_identity_cert = cert_info.identity_cert_watchers.empty();
289 already_watching_root_for_identity_cert =
290 !cert_info.root_cert_watchers.empty();
291 if (stop_watching_identity_cert &&
292 !already_watching_root_for_identity_cert) {
293 certificate_info_map_.erase(it);
294 }
295 }
296 }
297 // Invoke watch status callback if needed.
298 {
299 grpc_core::MutexLock lock(&callback_mu_);
300 if (watch_status_callback_ != nullptr) {
301 if (root_cert_name == identity_cert_name &&
302 (stop_watching_root_cert || stop_watching_identity_cert)) {
303 watch_status_callback_(*root_cert_name, !stop_watching_root_cert,
304 !stop_watching_identity_cert);
305 } else {
306 if (stop_watching_root_cert) {
307 watch_status_callback_(*root_cert_name, false,
308 already_watching_identity_for_root_cert);
309 }
310 if (stop_watching_identity_cert) {
311 watch_status_callback_(*identity_cert_name,
312 already_watching_root_for_identity_cert,
313 false);
314 }
315 }
316 }
317 }
318 };
319
320 /// -- Wrapper APIs declared in grpc_security.h -- *
321
grpc_tls_identity_pairs_create()322 grpc_tls_identity_pairs* grpc_tls_identity_pairs_create() {
323 return new grpc_tls_identity_pairs();
324 }
325
grpc_tls_identity_pairs_add_pair(grpc_tls_identity_pairs * pairs,const char * private_key,const char * cert_chain)326 void grpc_tls_identity_pairs_add_pair(grpc_tls_identity_pairs* pairs,
327 const char* private_key,
328 const char* cert_chain) {
329 CHECK_NE(pairs, nullptr);
330 CHECK_NE(private_key, nullptr);
331 CHECK_NE(cert_chain, nullptr);
332 pairs->pem_key_cert_pairs.emplace_back(private_key, cert_chain);
333 }
334
grpc_tls_identity_pairs_destroy(grpc_tls_identity_pairs * pairs)335 void grpc_tls_identity_pairs_destroy(grpc_tls_identity_pairs* pairs) {
336 CHECK_NE(pairs, nullptr);
337 delete pairs;
338 }
339