1 //
2 //
3 // Copyright 2018 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include "src/core/lib/security/security_connector/ssl/ssl_security_connector.h"
20
21 #include <grpc/support/alloc.h>
22 #include <grpc/support/port_platform.h>
23 #include <stdint.h>
24 #include <string.h>
25
26 #include <string>
27 #include <utility>
28
29 #include "absl/log/check.h"
30 #include "absl/log/log.h"
31 #include "absl/status/status.h"
32 #include "absl/strings/str_cat.h"
33 #include "absl/strings/str_format.h"
34 #include "absl/strings/string_view.h"
35 #include "src/core/handshaker/handshaker.h"
36 #include "src/core/handshaker/security/security_handshaker.h"
37 #include "src/core/lib/channel/channel_args.h"
38 #include "src/core/lib/iomgr/closure.h"
39 #include "src/core/lib/iomgr/endpoint.h"
40 #include "src/core/lib/iomgr/error.h"
41 #include "src/core/lib/iomgr/exec_ctx.h"
42 #include "src/core/lib/iomgr/iomgr_fwd.h"
43 #include "src/core/lib/promise/arena_promise.h"
44 #include "src/core/lib/promise/promise.h"
45 #include "src/core/lib/security/context/security_context.h"
46 #include "src/core/lib/security/credentials/credentials.h"
47 #include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
48 #include "src/core/lib/security/security_connector/ssl_utils.h"
49 #include "src/core/tsi/ssl_transport_security.h"
50 #include "src/core/tsi/transport_security.h"
51 #include "src/core/tsi/transport_security_interface.h"
52 #include "src/core/util/debug_location.h"
53 #include "src/core/util/host_port.h"
54 #include "src/core/util/ref_counted_ptr.h"
55 #include "src/core/util/sync.h"
56
57 namespace {
ssl_check_peer(const char * peer_name,const tsi_peer * peer,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context)58 grpc_error_handle ssl_check_peer(
59 const char* peer_name, const tsi_peer* peer,
60 grpc_core::RefCountedPtr<grpc_auth_context>* auth_context) {
61 grpc_error_handle error = grpc_ssl_check_alpn(peer);
62 if (!error.ok()) {
63 return error;
64 }
65 // Check the peer name if specified.
66 if (peer_name != nullptr && !grpc_ssl_host_matches_name(peer, peer_name)) {
67 return GRPC_ERROR_CREATE(
68 absl::StrCat("Peer name ", peer_name, " is not in peer certificate"));
69 }
70 *auth_context =
71 grpc_ssl_peer_to_auth_context(peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
72 return absl::OkStatus();
73 }
74
75 class grpc_ssl_channel_security_connector final
76 : public grpc_channel_security_connector {
77 public:
grpc_ssl_channel_security_connector(grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,const grpc_ssl_config * config,const char * target_name,const char * overridden_target_name,tsi_ssl_client_handshaker_factory * client_handshaker_factory)78 grpc_ssl_channel_security_connector(
79 grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
80 grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
81 const grpc_ssl_config* config, const char* target_name,
82 const char* overridden_target_name,
83 tsi_ssl_client_handshaker_factory* client_handshaker_factory)
84 : grpc_channel_security_connector(GRPC_SSL_URL_SCHEME,
85 std::move(channel_creds),
86 std::move(request_metadata_creds)),
87 client_handshaker_factory_(client_handshaker_factory),
88 overridden_target_name_(
89 overridden_target_name == nullptr ? "" : overridden_target_name),
90 verify_options_(&config->verify_options) {
91 absl::string_view host;
92 absl::string_view port;
93 grpc_core::SplitHostPort(target_name, &host, &port);
94 target_name_ = std::string(host);
95 }
96
~grpc_ssl_channel_security_connector()97 ~grpc_ssl_channel_security_connector() override {
98 tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory_);
99 }
100
add_handshakers(const grpc_core::ChannelArgs & args,grpc_pollset_set *,grpc_core::HandshakeManager * handshake_mgr)101 void add_handshakers(const grpc_core::ChannelArgs& args,
102 grpc_pollset_set* /*interested_parties*/,
103 grpc_core::HandshakeManager* handshake_mgr) override {
104 // Instantiate TSI handshaker.
105 tsi_handshaker* tsi_hs = nullptr;
106 tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
107 client_handshaker_factory_,
108 overridden_target_name_.empty() ? target_name_.c_str()
109 : overridden_target_name_.c_str(),
110 /*network_bio_buf_size=*/0,
111 /*ssl_bio_buf_size=*/0, &tsi_hs);
112 if (result != TSI_OK) {
113 LOG(ERROR) << "Handshaker creation failed with error "
114 << tsi_result_to_string(result);
115 return;
116 }
117 // Create handshakers.
118 handshake_mgr->Add(grpc_core::SecurityHandshakerCreate(tsi_hs, this, args));
119 }
120
check_peer(tsi_peer peer,grpc_endpoint *,const grpc_core::ChannelArgs &,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)121 void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/,
122 const grpc_core::ChannelArgs& /*args*/,
123 grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
124 grpc_closure* on_peer_checked) override {
125 const char* target_name = overridden_target_name_.empty()
126 ? target_name_.c_str()
127 : overridden_target_name_.c_str();
128 grpc_error_handle error = ssl_check_peer(target_name, &peer, auth_context);
129 if (error.ok() && verify_options_->verify_peer_callback != nullptr) {
130 const tsi_peer_property* p =
131 tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY);
132 if (p == nullptr) {
133 error =
134 GRPC_ERROR_CREATE("Cannot check peer: missing pem cert property.");
135 } else {
136 char* peer_pem = static_cast<char*>(gpr_malloc(p->value.length + 1));
137 memcpy(peer_pem, p->value.data, p->value.length);
138 peer_pem[p->value.length] = '\0';
139 int callback_status = verify_options_->verify_peer_callback(
140 target_name, peer_pem,
141 verify_options_->verify_peer_callback_userdata);
142 gpr_free(peer_pem);
143 if (callback_status) {
144 error = GRPC_ERROR_CREATE(absl::StrFormat(
145 "Verify peer callback returned a failure (%d)", callback_status));
146 }
147 }
148 }
149 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
150 tsi_peer_destruct(&peer);
151 }
152
cancel_check_peer(grpc_closure *,grpc_error_handle)153 void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
154 grpc_error_handle /*error*/) override {}
155
cmp(const grpc_security_connector * other_sc) const156 int cmp(const grpc_security_connector* other_sc) const override {
157 auto* other =
158 reinterpret_cast<const grpc_ssl_channel_security_connector*>(other_sc);
159 int c = channel_security_connector_cmp(other);
160 if (c != 0) return c;
161 c = target_name_.compare(other->target_name_);
162 if (c != 0) return c;
163 return overridden_target_name_.compare(other->overridden_target_name_);
164 }
165
CheckCallHost(absl::string_view host,grpc_auth_context * auth_context)166 grpc_core::ArenaPromise<absl::Status> CheckCallHost(
167 absl::string_view host, grpc_auth_context* auth_context) override {
168 return grpc_core::Immediate(
169 SslCheckCallHost(host, target_name_.c_str(),
170 overridden_target_name_.c_str(), auth_context));
171 }
172
173 private:
174 tsi_ssl_client_handshaker_factory* client_handshaker_factory_ = nullptr;
175 std::string target_name_;
176 std::string overridden_target_name_;
177 const verify_peer_options* verify_options_;
178 };
179
180 class grpc_ssl_server_security_connector
181 : public grpc_server_security_connector {
182 public:
grpc_ssl_server_security_connector(grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)183 explicit grpc_ssl_server_security_connector(
184 grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
185 : grpc_server_security_connector(GRPC_SSL_URL_SCHEME,
186 std::move(server_creds)) {}
187
~grpc_ssl_server_security_connector()188 ~grpc_ssl_server_security_connector() override {
189 tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_);
190 }
191
has_cert_config_fetcher() const192 bool has_cert_config_fetcher() const {
193 return static_cast<const grpc_ssl_server_credentials*>(server_creds())
194 ->has_cert_config_fetcher();
195 }
196
server_handshaker_factory() const197 const tsi_ssl_server_handshaker_factory* server_handshaker_factory() const {
198 return server_handshaker_factory_;
199 }
200
InitializeHandshakerFactory()201 grpc_security_status InitializeHandshakerFactory() {
202 if (has_cert_config_fetcher()) {
203 // Load initial credentials from certificate_config_fetcher:
204 if (!try_fetch_ssl_server_credentials()) {
205 LOG(ERROR) << "Failed loading SSL server credentials from fetcher.";
206 return GRPC_SECURITY_ERROR;
207 }
208 } else {
209 auto* server_credentials =
210 static_cast<const grpc_ssl_server_credentials*>(server_creds());
211 size_t num_alpn_protocols = 0;
212 const char** alpn_protocol_strings =
213 grpc_fill_alpn_protocol_strings(&num_alpn_protocols);
214 tsi_ssl_server_handshaker_options options;
215 options.pem_key_cert_pairs =
216 server_credentials->config().pem_key_cert_pairs;
217 options.num_key_cert_pairs =
218 server_credentials->config().num_key_cert_pairs;
219 options.pem_client_root_certs =
220 server_credentials->config().pem_root_certs;
221 options.client_certificate_request =
222 grpc_get_tsi_client_certificate_request_type(
223 server_credentials->config().client_certificate_request);
224 options.cipher_suites = grpc_get_ssl_cipher_suites();
225 options.alpn_protocols = alpn_protocol_strings;
226 options.num_alpn_protocols = static_cast<uint16_t>(num_alpn_protocols);
227 options.min_tls_version = grpc_get_tsi_tls_version(
228 server_credentials->config().min_tls_version);
229 options.max_tls_version = grpc_get_tsi_tls_version(
230 server_credentials->config().max_tls_version);
231 const tsi_result result =
232 tsi_create_ssl_server_handshaker_factory_with_options(
233 &options, &server_handshaker_factory_);
234 gpr_free(alpn_protocol_strings);
235 if (result != TSI_OK) {
236 LOG(ERROR) << "Handshaker factory creation failed with "
237 << tsi_result_to_string(result);
238 return GRPC_SECURITY_ERROR;
239 }
240 }
241 return GRPC_SECURITY_OK;
242 }
243
add_handshakers(const grpc_core::ChannelArgs & args,grpc_pollset_set *,grpc_core::HandshakeManager * handshake_mgr)244 void add_handshakers(const grpc_core::ChannelArgs& args,
245 grpc_pollset_set* /*interested_parties*/,
246 grpc_core::HandshakeManager* handshake_mgr) override {
247 // Instantiate TSI handshaker.
248 try_fetch_ssl_server_credentials();
249 tsi_handshaker* tsi_hs = nullptr;
250 tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker(
251 server_handshaker_factory_, /*network_bio_buf_size=*/0,
252 /*ssl_bio_buf_size=*/0, &tsi_hs);
253 if (result != TSI_OK) {
254 LOG(ERROR) << "Handshaker creation failed with error "
255 << tsi_result_to_string(result);
256 return;
257 }
258 // Create handshakers.
259 handshake_mgr->Add(grpc_core::SecurityHandshakerCreate(tsi_hs, this, args));
260 }
261
check_peer(tsi_peer peer,grpc_endpoint *,const grpc_core::ChannelArgs &,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)262 void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/,
263 const grpc_core::ChannelArgs& /*args*/,
264 grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
265 grpc_closure* on_peer_checked) override {
266 grpc_error_handle error = ssl_check_peer(nullptr, &peer, auth_context);
267 tsi_peer_destruct(&peer);
268 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
269 }
270
cancel_check_peer(grpc_closure *,grpc_error_handle)271 void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
272 grpc_error_handle /*error*/) override {}
273
cmp(const grpc_security_connector * other) const274 int cmp(const grpc_security_connector* other) const override {
275 return server_security_connector_cmp(
276 static_cast<const grpc_server_security_connector*>(other));
277 }
278
279 private:
280 // Attempts to fetch the server certificate config if a callback is available.
281 // Current certificate config will continue to be used if the callback returns
282 // an error. Returns true if new credentials were successfully loaded.
try_fetch_ssl_server_credentials()283 bool try_fetch_ssl_server_credentials() {
284 grpc_ssl_server_certificate_config* certificate_config = nullptr;
285 bool status;
286 if (!has_cert_config_fetcher()) return false;
287
288 grpc_core::MutexLock lock(&mu_);
289 grpc_ssl_server_credentials* server_creds =
290 static_cast<grpc_ssl_server_credentials*>(this->mutable_server_creds());
291 grpc_ssl_certificate_config_reload_status cb_result =
292 server_creds->FetchCertConfig(&certificate_config);
293 if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED) {
294 status = false;
295 } else if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW) {
296 status = try_replace_server_handshaker_factory(certificate_config);
297 } else {
298 // Log error, continue using previously-loaded credentials.
299 LOG(ERROR) << "Failed fetching new server credentials, continuing to "
300 "use previously-loaded credentials.";
301 status = false;
302 }
303
304 if (certificate_config != nullptr) {
305 grpc_ssl_server_certificate_config_destroy(certificate_config);
306 }
307 return status;
308 }
309
310 // Attempts to replace the server_handshaker_factory with a new factory using
311 // the provided grpc_ssl_server_certificate_config. Should new factory
312 // creation fail, the existing factory will not be replaced. Returns true on
313 // success (new factory created).
try_replace_server_handshaker_factory(const grpc_ssl_server_certificate_config * config)314 bool try_replace_server_handshaker_factory(
315 const grpc_ssl_server_certificate_config* config) {
316 if (config == nullptr) {
317 LOG(ERROR)
318 << "Server certificate config callback returned invalid (NULL) "
319 "config.";
320 return false;
321 }
322 VLOG(2) << "Using new server certificate config (" << config << ").";
323
324 size_t num_alpn_protocols = 0;
325 const char** alpn_protocol_strings =
326 grpc_fill_alpn_protocol_strings(&num_alpn_protocols);
327 tsi_ssl_server_handshaker_factory* new_handshaker_factory = nullptr;
328 const grpc_ssl_server_credentials* server_creds =
329 static_cast<const grpc_ssl_server_credentials*>(this->server_creds());
330 DCHECK_NE(config->pem_root_certs, nullptr);
331 tsi_ssl_server_handshaker_options options;
332 options.pem_key_cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs(
333 config->pem_key_cert_pairs, config->num_key_cert_pairs);
334 options.num_key_cert_pairs = config->num_key_cert_pairs;
335 options.pem_client_root_certs = config->pem_root_certs;
336 options.client_certificate_request =
337 grpc_get_tsi_client_certificate_request_type(
338 server_creds->config().client_certificate_request);
339 options.cipher_suites = grpc_get_ssl_cipher_suites();
340 options.alpn_protocols = alpn_protocol_strings;
341 options.num_alpn_protocols = static_cast<uint16_t>(num_alpn_protocols);
342 tsi_result result = tsi_create_ssl_server_handshaker_factory_with_options(
343 &options, &new_handshaker_factory);
344 grpc_tsi_ssl_pem_key_cert_pairs_destroy(
345 const_cast<tsi_ssl_pem_key_cert_pair*>(options.pem_key_cert_pairs),
346 options.num_key_cert_pairs);
347 gpr_free(alpn_protocol_strings);
348
349 if (result != TSI_OK) {
350 LOG(ERROR) << "Handshaker factory creation failed with "
351 << tsi_result_to_string(result);
352 return false;
353 }
354 set_server_handshaker_factory(new_handshaker_factory);
355 return true;
356 }
357
set_server_handshaker_factory(tsi_ssl_server_handshaker_factory * new_factory)358 void set_server_handshaker_factory(
359 tsi_ssl_server_handshaker_factory* new_factory) {
360 if (server_handshaker_factory_) {
361 tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_);
362 }
363 server_handshaker_factory_ = new_factory;
364 }
365
366 grpc_core::Mutex mu_;
367 tsi_ssl_server_handshaker_factory* server_handshaker_factory_ = nullptr;
368 };
369 } // namespace
370
371 grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_ssl_channel_security_connector_create(grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,const grpc_ssl_config * config,const char * target_name,const char * overridden_target_name,tsi_ssl_client_handshaker_factory * client_factory)372 grpc_ssl_channel_security_connector_create(
373 grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
374 grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
375 const grpc_ssl_config* config, const char* target_name,
376 const char* overridden_target_name,
377 tsi_ssl_client_handshaker_factory* client_factory) {
378 if (config == nullptr || target_name == nullptr) {
379 LOG(ERROR) << "An ssl channel needs a config and a target name.";
380 return nullptr;
381 }
382
383 grpc_core::RefCountedPtr<grpc_ssl_channel_security_connector> c =
384 grpc_core::MakeRefCounted<grpc_ssl_channel_security_connector>(
385 std::move(channel_creds), std::move(request_metadata_creds), config,
386 target_name, overridden_target_name,
387 tsi_ssl_client_handshaker_factory_ref(client_factory));
388 return c;
389 }
390
391 grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_ssl_server_security_connector_create(grpc_core::RefCountedPtr<grpc_server_credentials> server_credentials)392 grpc_ssl_server_security_connector_create(
393 grpc_core::RefCountedPtr<grpc_server_credentials> server_credentials) {
394 CHECK(server_credentials != nullptr);
395 grpc_core::RefCountedPtr<grpc_ssl_server_security_connector> c =
396 grpc_core::MakeRefCounted<grpc_ssl_server_security_connector>(
397 std::move(server_credentials));
398 const grpc_security_status retval = c->InitializeHandshakerFactory();
399 if (retval != GRPC_SECURITY_OK) {
400 return nullptr;
401 }
402 return c;
403 }
404