• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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