[tls] Remove use of SSL_CTX_set_client_CA_list for TLS server credentials. (#33558)

This PR does the following: for the TLS server credentials, stops
calling `SSL_CTX_set_client_CA_list` by default in
`ssl_transport_security.cc`, and gives users a knob to re-enable calling
this API.

## What does the `SSL_CTX_set_client_CA_list` API do?

When this API is called, a gRPC TLS server sends the following data in
the ServerHello: for each certificate in the server's trust bundle, the
CA name in the certificate.

This API does not change the set of certificates trusted by the server
in any way. Rather, it is just providing a hint to the client about what
client certificate should be sent to the server.

## Why are we removing the use of `SSL_CTX_set_client_CA_list` by
default for the TLS server credentials?

Removing the use of this API by default has 2 benefits:
1. Calling this API makes gRPC TLS unusable for servers with a
sufficiently large trust bundle. Indeed, if the server trust bundle is
too large, then the server will always fail to build the ServerHello.
2. Calling this API is introducing a huge amount of overhead (1000s of
bytes) to each ServerHello, so removing this feature will improve
connection establishment latency for all users of the TLS server
credentials.
pull/33573/head
Matthew Stevenson 2 years ago committed by GitHub
parent 21f2eba143
commit 278978d6f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      grpc.def
  2. 19
      include/grpc/grpc_security.h
  3. 12
      include/grpcpp/security/tls_credentials_options.h
  4. 8
      src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc
  5. 6
      src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h
  6. 3
      src/core/lib/security/security_connector/ssl_utils.cc
  7. 2
      src/core/lib/security/security_connector/ssl_utils.h
  8. 2
      src/core/lib/security/security_connector/tls/tls_security_connector.cc
  9. 7
      src/core/tsi/ssl_transport_security.cc
  10. 14
      src/core/tsi/ssl_transport_security.h
  11. 8
      src/cpp/common/tls_credentials_options.cc
  12. 2
      src/ruby/ext/grpc/rb_grpc_imports.generated.c
  13. 3
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  14. 10
      test/core/security/grpc_tls_credentials_options_comparator_test.cc
  15. 57
      test/core/tsi/ssl_transport_security_test.cc
  16. 8
      tools/codegen/core/gen_grpc_tls_credentials_options.py

1
grpc.def generated

@ -165,6 +165,7 @@ EXPORTS
grpc_tls_credentials_options_set_cert_request_type
grpc_tls_credentials_options_set_crl_directory
grpc_tls_credentials_options_set_verify_server_cert
grpc_tls_credentials_options_set_send_client_ca_list
grpc_tls_credentials_options_set_check_call_host
grpc_insecure_credentials_create
grpc_insecure_server_credentials_create

@ -21,6 +21,8 @@
#include <grpc/support/port_platform.h>
#include <stdbool.h>
#include <grpc/grpc.h>
#include <grpc/grpc_security_constants.h>
#include <grpc/status.h>
@ -896,6 +898,23 @@ GRPCAPI void grpc_tls_credentials_options_set_crl_directory(
GRPCAPI void grpc_tls_credentials_options_set_verify_server_cert(
grpc_tls_credentials_options* options, int verify_server_cert);
/**
* EXPERIMENTAL API - Subject to change
*
* Sets whether or not a TLS server should send a list of CA names in the
* ServerHello. This list of CA names is read from the server's trust bundle, so
* that the client can use this list as a hint to know which certificate it
* should send to the server.
*
* WARNING: This API is extremely dangerous and should not be used. If the
* server's trust bundle is too large, then the TLS server will be unable to
* form a ServerHello, and hence will be unusable. The definition of "too large"
* depends on the underlying SSL library being used and on the size of the CN
* fields of the certificates in the trust bundle.
*/
GRPCAPI void grpc_tls_credentials_options_set_send_client_ca_list(
grpc_tls_credentials_options* options, bool send_client_ca_list);
/**
* EXPERIMENTAL API - Subject to change
*

@ -148,6 +148,18 @@ class TlsServerCredentialsOptions final : public TlsCredentialsOptions {
void set_cert_request_type(
grpc_ssl_client_certificate_request_type cert_request_type);
// Sets whether or not a TLS server should send a list of CA names in the
// ServerHello. This list of CA names is read from the server's trust bundle,
// so that the client can use this list as a hint to know which certificate it
// should send to the server.
//
// By default, this option is turned off.
//
// WARNING: This API is extremely dangerous and should not be used. If the
// server's trust bundle is too large, then the TLS server will be unable to
// form a ServerHello, and hence will be unusable.
void set_send_client_ca_list(bool send_client_ca_list);
private:
};

@ -120,3 +120,11 @@ void grpc_tls_credentials_options_set_tls_session_key_log_file_path(
}
options->set_tls_session_key_log_file_path(path != nullptr ? path : "");
}
void grpc_tls_credentials_options_set_send_client_ca_list(
grpc_tls_credentials_options* options, bool send_client_ca_list) {
if (options == nullptr) {
return;
}
options->set_send_client_ca_list(send_client_ca_list);
}

@ -61,6 +61,7 @@ struct grpc_tls_credentials_options
const std::string& identity_cert_name() const { return identity_cert_name_; }
const std::string& tls_session_key_log_file_path() const { return tls_session_key_log_file_path_; }
const std::string& crl_directory() const { return crl_directory_; }
bool send_client_ca_list() const { return send_client_ca_list_; }
// Setters for member fields.
void set_cert_request_type(grpc_ssl_client_certificate_request_type cert_request_type) { cert_request_type_ = cert_request_type; }
@ -81,6 +82,7 @@ struct grpc_tls_credentials_options
void set_tls_session_key_log_file_path(std::string tls_session_key_log_file_path) { tls_session_key_log_file_path_ = std::move(tls_session_key_log_file_path); }
// gRPC will enforce CRLs on all handshakes from all hashed CRL files inside of the crl_directory. If not set, an empty string will be used, which will not enable CRL checking. Only supported for OpenSSL version > 1.1.
void set_crl_directory(std::string crl_directory) { crl_directory_ = std::move(crl_directory); }
void set_send_client_ca_list(bool send_client_ca_list) { send_client_ca_list_ = send_client_ca_list; }
bool operator==(const grpc_tls_credentials_options& other) const {
return cert_request_type_ == other.cert_request_type_ &&
@ -95,7 +97,8 @@ struct grpc_tls_credentials_options
watch_identity_pair_ == other.watch_identity_pair_ &&
identity_cert_name_ == other.identity_cert_name_ &&
tls_session_key_log_file_path_ == other.tls_session_key_log_file_path_ &&
crl_directory_ == other.crl_directory_;
crl_directory_ == other.crl_directory_ &&
send_client_ca_list_ == other.send_client_ca_list_;
}
private:
@ -112,6 +115,7 @@ struct grpc_tls_credentials_options
std::string identity_cert_name_;
std::string tls_session_key_log_file_path_;
std::string crl_directory_;
bool send_client_ca_list_ = false;
};
#endif // GRPC_SRC_CORE_LIB_SECURITY_CREDENTIALS_TLS_GRPC_TLS_CREDENTIALS_OPTIONS_H

@ -465,7 +465,7 @@ grpc_security_status grpc_ssl_tsi_server_handshaker_factory_init(
grpc_ssl_client_certificate_request_type client_certificate_request,
tsi_tls_version min_tls_version, tsi_tls_version max_tls_version,
tsi::TlsSessionKeyLoggerCache::TlsSessionKeyLogger* tls_session_key_logger,
const char* crl_directory,
const char* crl_directory, bool send_client_ca_list,
tsi_ssl_server_handshaker_factory** handshaker_factory) {
size_t num_alpn_protocols = 0;
const char** alpn_protocol_strings =
@ -483,6 +483,7 @@ grpc_security_status grpc_ssl_tsi_server_handshaker_factory_init(
options.max_tls_version = max_tls_version;
options.key_logger = tls_session_key_logger;
options.crl_directory = crl_directory;
options.send_client_ca_list = send_client_ca_list;
const tsi_result result =
tsi_create_ssl_server_handshaker_factory_with_options(&options,
handshaker_factory);

@ -93,7 +93,7 @@ grpc_security_status grpc_ssl_tsi_server_handshaker_factory_init(
grpc_ssl_client_certificate_request_type client_certificate_request,
tsi_tls_version min_tls_version, tsi_tls_version max_tls_version,
tsi::TlsSessionKeyLoggerCache::TlsSessionKeyLogger* tls_session_key_logger,
const char* crl_directory,
const char* crl_directory, bool send_client_ca_list,
tsi_ssl_server_handshaker_factory** handshaker_factory);
// Free the memory occupied by key cert pairs.

@ -830,7 +830,7 @@ TlsServerSecurityConnector::UpdateHandshakerFactoryLocked() {
grpc_get_tsi_tls_version(options_->min_tls_version()),
grpc_get_tsi_tls_version(options_->max_tls_version()),
tls_session_key_logger_.get(), options_->crl_directory().c_str(),
&server_handshaker_factory_);
options_->send_client_ca_list(), &server_handshaker_factory_);
// Free memory.
grpc_tsi_ssl_pem_key_cert_pairs_destroy(pem_key_cert_pairs,
num_key_cert_pairs);

@ -2202,12 +2202,15 @@ tsi_result tsi_create_ssl_server_handshaker_factory_with_options(
STACK_OF(X509_NAME)* root_names = nullptr;
result = ssl_ctx_load_verification_certs(
impl->ssl_contexts[i], options->pem_client_root_certs,
strlen(options->pem_client_root_certs), &root_names);
strlen(options->pem_client_root_certs),
options->send_client_ca_list ? &root_names : nullptr);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Invalid verification certs.");
break;
}
SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names);
if (options->send_client_ca_list) {
SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names);
}
}
switch (options->client_certificate_request) {
case TSI_DONT_REQUEST_CLIENT_CERTIFICATE:

@ -325,6 +325,17 @@ struct tsi_ssl_server_handshaker_options {
// crl checking. Only OpenSSL version > 1.1 is supported for CRL checking
const char* crl_directory;
// If true, the SSL server sends a list of CA names to the client in the
// ServerHello. This list of CA names is extracted from the server's trust
// bundle, and the client may use this lint as a hint to decide which
// certificate it should send to the server.
//
// WARNING: This is an extremely dangerous option. If the server's trust
// bundle is sufficiently large, then setting this bit to true will result in
// the server being unable to generate a ServerHello, and hence the server
// will be unusable.
bool send_client_ca_list;
tsi_ssl_server_handshaker_options()
: pem_key_cert_pairs(nullptr),
num_key_cert_pairs(0),
@ -338,7 +349,8 @@ struct tsi_ssl_server_handshaker_options {
min_tls_version(tsi_tls_version::TSI_TLS1_2),
max_tls_version(tsi_tls_version::TSI_TLS1_3),
key_logger(nullptr),
crl_directory(nullptr) {}
crl_directory(nullptr),
send_client_ca_list(true) {}
};
// Creates a server handshaker factory.

@ -106,5 +106,13 @@ void TlsServerCredentialsOptions::set_cert_request_type(
cert_request_type);
}
void TlsServerCredentialsOptions::set_send_client_ca_list(
bool send_client_ca_list) {
grpc_tls_credentials_options* options = c_credentials_options();
GPR_ASSERT(options != nullptr);
grpc_tls_credentials_options_set_send_client_ca_list(options,
send_client_ca_list);
}
} // namespace experimental
} // namespace grpc

@ -188,6 +188,7 @@ grpc_tls_credentials_options_set_identity_cert_name_type grpc_tls_credentials_op
grpc_tls_credentials_options_set_cert_request_type_type grpc_tls_credentials_options_set_cert_request_type_import;
grpc_tls_credentials_options_set_crl_directory_type grpc_tls_credentials_options_set_crl_directory_import;
grpc_tls_credentials_options_set_verify_server_cert_type grpc_tls_credentials_options_set_verify_server_cert_import;
grpc_tls_credentials_options_set_send_client_ca_list_type grpc_tls_credentials_options_set_send_client_ca_list_import;
grpc_tls_credentials_options_set_check_call_host_type grpc_tls_credentials_options_set_check_call_host_import;
grpc_insecure_credentials_create_type grpc_insecure_credentials_create_import;
grpc_insecure_server_credentials_create_type grpc_insecure_server_credentials_create_import;
@ -474,6 +475,7 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_tls_credentials_options_set_cert_request_type_import = (grpc_tls_credentials_options_set_cert_request_type_type) GetProcAddress(library, "grpc_tls_credentials_options_set_cert_request_type");
grpc_tls_credentials_options_set_crl_directory_import = (grpc_tls_credentials_options_set_crl_directory_type) GetProcAddress(library, "grpc_tls_credentials_options_set_crl_directory");
grpc_tls_credentials_options_set_verify_server_cert_import = (grpc_tls_credentials_options_set_verify_server_cert_type) GetProcAddress(library, "grpc_tls_credentials_options_set_verify_server_cert");
grpc_tls_credentials_options_set_send_client_ca_list_import = (grpc_tls_credentials_options_set_send_client_ca_list_type) GetProcAddress(library, "grpc_tls_credentials_options_set_send_client_ca_list");
grpc_tls_credentials_options_set_check_call_host_import = (grpc_tls_credentials_options_set_check_call_host_type) GetProcAddress(library, "grpc_tls_credentials_options_set_check_call_host");
grpc_insecure_credentials_create_import = (grpc_insecure_credentials_create_type) GetProcAddress(library, "grpc_insecure_credentials_create");
grpc_insecure_server_credentials_create_import = (grpc_insecure_server_credentials_create_type) GetProcAddress(library, "grpc_insecure_server_credentials_create");

@ -539,6 +539,9 @@ extern grpc_tls_credentials_options_set_crl_directory_type grpc_tls_credentials_
typedef void(*grpc_tls_credentials_options_set_verify_server_cert_type)(grpc_tls_credentials_options* options, int verify_server_cert);
extern grpc_tls_credentials_options_set_verify_server_cert_type grpc_tls_credentials_options_set_verify_server_cert_import;
#define grpc_tls_credentials_options_set_verify_server_cert grpc_tls_credentials_options_set_verify_server_cert_import
typedef void(*grpc_tls_credentials_options_set_send_client_ca_list_type)(grpc_tls_credentials_options* options, bool send_client_ca_list);
extern grpc_tls_credentials_options_set_send_client_ca_list_type grpc_tls_credentials_options_set_send_client_ca_list_import;
#define grpc_tls_credentials_options_set_send_client_ca_list grpc_tls_credentials_options_set_send_client_ca_list_import
typedef void(*grpc_tls_credentials_options_set_check_call_host_type)(grpc_tls_credentials_options* options, int check_call_host);
extern grpc_tls_credentials_options_set_check_call_host_type grpc_tls_credentials_options_set_check_call_host_import;
#define grpc_tls_credentials_options_set_check_call_host grpc_tls_credentials_options_set_check_call_host_import

@ -161,6 +161,16 @@ TEST(TlsCredentialsOptionsComparatorTest, DifferentCrlDirectory) {
delete options_1;
delete options_2;
}
TEST(TlsCredentialsOptionsComparatorTest, DifferentSendClientCaListValues) {
auto* options_1 = grpc_tls_credentials_options_create();
auto* options_2 = grpc_tls_credentials_options_create();
options_1->set_send_client_ca_list(false);
options_2->set_send_client_ca_list(true);
EXPECT_FALSE(*options_1 == *options_2);
EXPECT_FALSE(*options_2 == *options_1);
delete options_1;
delete options_2;
}
} // namespace
} // namespace grpc_core

@ -62,6 +62,7 @@ const size_t kSessionTicketEncryptionKeySize = 48;
// Indicates the TLS version used for the test.
static tsi_tls_version test_tls_version = tsi_tls_version::TSI_TLS1_3;
static bool test_send_client_ca_list = false;
typedef enum AlpnMode {
NO_ALPN,
@ -1171,35 +1172,37 @@ TEST(SslTransportSecurityTest, MainTest) {
for (size_t i = 0; i < number_tls_versions; i++) {
// Set the TLS version to be used in the tests.
test_tls_version = tls_versions[i];
// Run all the tests using that TLS version for both the client and server.
ssl_tsi_test_do_handshake_tiny_handshake_buffer();
ssl_tsi_test_do_handshake_small_handshake_buffer();
ssl_tsi_test_do_handshake();
ssl_tsi_test_do_handshake_with_root_store();
ssl_tsi_test_do_handshake_with_client_authentication();
ssl_tsi_test_do_handshake_with_client_authentication_and_root_store();
ssl_tsi_test_do_handshake_with_server_name_indication_exact_domain();
ssl_tsi_test_do_handshake_with_server_name_indication_wild_star_domain();
ssl_tsi_test_do_handshake_with_wrong_server_name_indication();
ssl_tsi_test_do_handshake_with_bad_server_cert();
ssl_tsi_test_do_handshake_with_bad_client_cert();
for (bool send_client_ca_list : {true, false}) {
test_send_client_ca_list = send_client_ca_list;
ssl_tsi_test_do_handshake_tiny_handshake_buffer();
ssl_tsi_test_do_handshake_small_handshake_buffer();
ssl_tsi_test_do_handshake();
ssl_tsi_test_do_handshake_with_root_store();
ssl_tsi_test_do_handshake_with_client_authentication();
ssl_tsi_test_do_handshake_with_client_authentication_and_root_store();
ssl_tsi_test_do_handshake_with_server_name_indication_exact_domain();
ssl_tsi_test_do_handshake_with_server_name_indication_wild_star_domain();
ssl_tsi_test_do_handshake_with_wrong_server_name_indication();
ssl_tsi_test_do_handshake_with_bad_server_cert();
ssl_tsi_test_do_handshake_with_bad_client_cert();
#ifdef OPENSSL_IS_BORINGSSL
// BoringSSL and OpenSSL have different behaviors on mismatched ALPN.
ssl_tsi_test_do_handshake_alpn_client_no_server();
ssl_tsi_test_do_handshake_alpn_client_server_mismatch();
// BoringSSL and OpenSSL have different behaviors on mismatched ALPN.
ssl_tsi_test_do_handshake_alpn_client_no_server();
ssl_tsi_test_do_handshake_alpn_client_server_mismatch();
#endif
ssl_tsi_test_do_handshake_alpn_server_no_client();
ssl_tsi_test_do_handshake_alpn_client_server_ok();
ssl_tsi_test_do_handshake_session_cache();
ssl_tsi_test_do_round_trip_for_all_configs();
ssl_tsi_test_do_round_trip_with_error_on_stack();
ssl_tsi_test_do_round_trip_odd_buffer_size();
ssl_tsi_test_handshaker_factory_internals();
ssl_tsi_test_duplicate_root_certificates();
ssl_tsi_test_extract_x509_subject_names();
ssl_tsi_test_extract_cert_chain();
ssl_tsi_test_do_handshake_with_custom_bio_pair();
ssl_tsi_test_do_handshake_with_intermediate_ca();
ssl_tsi_test_do_handshake_alpn_server_no_client();
ssl_tsi_test_do_handshake_alpn_client_server_ok();
ssl_tsi_test_do_handshake_session_cache();
ssl_tsi_test_do_round_trip_for_all_configs();
ssl_tsi_test_do_round_trip_with_error_on_stack();
ssl_tsi_test_do_round_trip_odd_buffer_size();
ssl_tsi_test_handshaker_factory_internals();
ssl_tsi_test_duplicate_root_certificates();
ssl_tsi_test_extract_x509_subject_names();
ssl_tsi_test_extract_cert_chain();
ssl_tsi_test_do_handshake_with_custom_bio_pair();
ssl_tsi_test_do_handshake_with_intermediate_ca();
}
}
grpc_shutdown();
}

@ -220,6 +220,14 @@ _DATA_MEMBERS = [
test_value_1='"crl_directory_1"',
test_value_2='"crl_directory_2"',
),
DataMember(
name="send_client_ca_list",
type="bool",
default_initializer="false",
test_name="DifferentSendClientCaListValues",
test_value_1="false",
test_value_2="true",
),
]

Loading…
Cancel
Save