Merge pull request #23165 from matthewstevenson88/matt-tls13

Enable TLS 1.3 in the C-core and all wrapped languages.
pull/23376/head
matthewstevenson88 4 years ago committed by GitHub
commit c1e07d8308
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      include/grpc/grpc_security_constants.h
  2. 20
      src/core/lib/security/credentials/ssl/ssl_credentials.cc
  3. 10
      src/core/lib/security/credentials/ssl/ssl_credentials.h
  4. 6
      src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
  5. 5
      src/core/lib/security/security_connector/ssl/ssl_security_connector.h
  6. 15
      src/core/lib/security/security_connector/ssl_utils.cc
  7. 3
      src/core/lib/security/security_connector/ssl_utils.h
  8. 111
      src/core/tsi/ssl_transport_security.cc
  9. 16
      src/core/tsi/ssl_transport_security.h
  10. 5
      src/core/tsi/transport_security_interface.h
  11. 6
      src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
  12. 10
      src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py
  13. 1
      test/core/end2end/end2end_tests.h
  14. 50
      test/core/end2end/fixtures/h2_oauth2.cc
  15. 50
      test/core/end2end/fixtures/h2_ssl.cc
  16. 50
      test/core/end2end/fixtures/h2_ssl_cred_reload.cc
  17. 10
      test/core/end2end/tests/filter_call_init_fails.cc
  18. 80
      test/core/tsi/ssl_transport_security_test.cc

@ -139,6 +139,9 @@ typedef enum {
*/
typedef enum { UDS = 0, LOCAL_TCP } grpc_local_connect_type;
/** The TLS versions that are supported by the SSL stack. **/
typedef enum { TLS1_2, TLS1_3 } grpc_tls_version;
#ifdef __cplusplus
}
#endif

@ -117,6 +117,16 @@ void grpc_ssl_credentials::build_config(
}
}
void grpc_ssl_credentials::set_min_tls_version(
grpc_tls_version min_tls_version) {
config_.min_tls_version = min_tls_version;
}
void grpc_ssl_credentials::set_max_tls_version(
grpc_tls_version max_tls_version) {
config_.max_tls_version = max_tls_version;
}
/* Deprecated in favor of grpc_ssl_credentials_create_ex. Will be removed
* once all of its call sites are migrated to grpc_ssl_credentials_create_ex. */
grpc_channel_credentials* grpc_ssl_credentials_create(
@ -213,6 +223,16 @@ void grpc_ssl_server_credentials::build_config(
config_.num_key_cert_pairs = num_key_cert_pairs;
}
void grpc_ssl_server_credentials::set_min_tls_version(
grpc_tls_version min_tls_version) {
config_.min_tls_version = min_tls_version;
}
void grpc_ssl_server_credentials::set_max_tls_version(
grpc_tls_version max_tls_version) {
config_.max_tls_version = max_tls_version;
}
grpc_ssl_server_certificate_config* grpc_ssl_server_certificate_config_create(
const char* pem_root_certs,
const grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs,

@ -38,6 +38,11 @@ class grpc_ssl_credentials : public grpc_channel_credentials {
const char* target, const grpc_channel_args* args,
grpc_channel_args** new_args) override;
// TODO(mattstev): Plumb to wrapped languages. Until then, setting the TLS
// version should be done for testing purposes only.
void set_min_tls_version(grpc_tls_version min_tls_version);
void set_max_tls_version(grpc_tls_version max_tls_version);
private:
void build_config(const char* pem_root_certs,
grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
@ -77,6 +82,11 @@ class grpc_ssl_server_credentials final : public grpc_server_credentials {
config);
}
// TODO(mattstev): Plumb to wrapped languages. Until then, setting the TLS
// version should be done for testing purposes only.
void set_min_tls_version(grpc_tls_version min_tls_version);
void set_max_tls_version(grpc_tls_version max_tls_version);
const grpc_ssl_server_config& config() const { return config_; }
private:

@ -107,6 +107,8 @@ class grpc_ssl_channel_security_connector final
}
options.cipher_suites = grpc_get_ssl_cipher_suites();
options.session_cache = ssl_session_cache;
options.min_tls_version = grpc_get_tsi_tls_version(config->min_tls_version);
options.max_tls_version = grpc_get_tsi_tls_version(config->max_tls_version);
const tsi_result result =
tsi_create_ssl_client_handshaker_factory_with_options(
&options, &client_handshaker_factory_);
@ -251,6 +253,10 @@ class grpc_ssl_server_security_connector
options.cipher_suites = grpc_get_ssl_cipher_suites();
options.alpn_protocols = alpn_protocol_strings;
options.num_alpn_protocols = static_cast<uint16_t>(num_alpn_protocols);
options.min_tls_version = grpc_get_tsi_tls_version(
server_credentials->config().min_tls_version);
options.max_tls_version = grpc_get_tsi_tls_version(
server_credentials->config().max_tls_version);
const tsi_result result =
tsi_create_ssl_server_handshaker_factory_with_options(
&options, &server_handshaker_factory_);

@ -33,7 +33,10 @@ struct grpc_ssl_config {
tsi_ssl_pem_key_cert_pair* pem_key_cert_pair;
char* pem_root_certs;
verify_peer_options verify_options;
grpc_tls_version min_tls_version = grpc_tls_version::TLS1_2;
grpc_tls_version max_tls_version = grpc_tls_version::TLS1_3;
};
/* Creates an SSL channel_security_connector.
- request_metadata_creds is the credentials object which metadata
will be sent with each request. This parameter can be NULL.
@ -62,6 +65,8 @@ struct grpc_ssl_server_config {
char* pem_root_certs = nullptr;
grpc_ssl_client_certificate_request_type client_certificate_request =
GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE;
grpc_tls_version min_tls_version = grpc_tls_version::TLS1_2;
grpc_tls_version max_tls_version = grpc_tls_version::TLS1_3;
};
/* Creates an SSL server_security_connector.
- config is the SSL config to be used for the SSL channel establishment.

@ -67,6 +67,9 @@ static const char* cipher_suites = nullptr;
// All cipher suites for default are compliant with HTTP2.
GPR_GLOBAL_CONFIG_DEFINE_STRING(
grpc_ssl_cipher_suites,
"TLS_AES_128_GCM_SHA256:"
"TLS_AES_256_GCM_SHA384:"
"TLS_CHACHA20_POLY1305_SHA256:"
"ECDHE-ECDSA-AES128-GCM-SHA256:"
"ECDHE-ECDSA-AES256-GCM-SHA384:"
"ECDHE-RSA-AES128-GCM-SHA256:"
@ -134,6 +137,18 @@ grpc_get_tsi_client_certificate_request_type(
}
}
tsi_tls_version grpc_get_tsi_tls_version(grpc_tls_version tls_version) {
switch (tls_version) {
case grpc_tls_version::TLS1_2:
return tsi_tls_version::TSI_TLS1_2;
case grpc_tls_version::TLS1_3:
return tsi_tls_version::TSI_TLS1_3;
default:
gpr_log(GPR_INFO, "Falling back to TLS 1.2.");
return tsi_tls_version::TSI_TLS1_2;
}
}
grpc_error* grpc_ssl_check_alpn(const tsi_peer* peer) {
#if TSI_OPENSSL_ALPN_SUPPORT
/* Check the ALPN if ALPN is supported. */

@ -73,6 +73,9 @@ grpc_get_tsi_client_certificate_request_type(
grpc_security_level grpc_tsi_security_level_string_to_enum(
const char* security_level);
/* Map grpc_tls_version to tsi_tls_version. */
tsi_tls_version grpc_get_tsi_tls_version(grpc_tls_version tls_version);
/* Map grpc_security_level enum to a string. */
const char* grpc_security_level_to_string(grpc_security_level security_level);

@ -51,6 +51,7 @@ extern "C" {
#include <openssl/engine.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/tls1.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
}
@ -890,6 +891,50 @@ static int NullVerifyCallback(int /*preverify_ok*/, X509_STORE_CTX* /*ctx*/) {
return 1;
}
// Sets the min and max TLS version of |ssl_context| to |min_tls_version| and
// |max_tls_version|, respectively. Calling this method is a no-op when using
// OpenSSL versions < 1.1.
static tsi_result tsi_set_min_and_max_tls_versions(
SSL_CTX* ssl_context, tsi_tls_version min_tls_version,
tsi_tls_version max_tls_version) {
if (ssl_context == nullptr) {
gpr_log(GPR_INFO,
"Invalid nullptr argument to |tsi_set_min_and_max_tls_versions|.");
return TSI_INVALID_ARGUMENT;
}
#if OPENSSL_VERSION_NUMBER >= 0x10100000
// Set the min TLS version of the SSL context.
switch (min_tls_version) {
case tsi_tls_version::TSI_TLS1_2:
SSL_CTX_set_min_proto_version(ssl_context, TLS1_2_VERSION);
break;
#if defined(TLS1_3_VERSION)
case tsi_tls_version::TSI_TLS1_3:
SSL_CTX_set_min_proto_version(ssl_context, TLS1_3_VERSION);
break;
#endif
default:
gpr_log(GPR_INFO, "TLS version is not supported.");
return TSI_FAILED_PRECONDITION;
}
// Set the max TLS version of the SSL context.
switch (max_tls_version) {
case tsi_tls_version::TSI_TLS1_2:
SSL_CTX_set_max_proto_version(ssl_context, TLS1_2_VERSION);
break;
#if defined(TLS1_3_VERSION)
case tsi_tls_version::TSI_TLS1_3:
SSL_CTX_set_max_proto_version(ssl_context, TLS1_3_VERSION);
break;
#endif
default:
gpr_log(GPR_INFO, "TLS version is not supported.");
return TSI_FAILED_PRECONDITION;
}
#endif
return TSI_OK;
}
/* --- tsi_ssl_root_certs_store methods implementation. ---*/
tsi_ssl_root_certs_store* tsi_ssl_root_certs_store_create(
@ -1301,7 +1346,7 @@ static const tsi_handshaker_result_vtable handshaker_result_vtable = {
};
static tsi_result ssl_handshaker_result_create(
tsi_ssl_handshaker* handshaker, const unsigned char* unused_bytes,
tsi_ssl_handshaker* handshaker, unsigned char* unused_bytes,
size_t unused_bytes_size, tsi_handshaker_result** handshaker_result) {
if (handshaker == nullptr || handshaker_result == nullptr ||
(unused_bytes_size > 0 && unused_bytes == nullptr)) {
@ -1315,11 +1360,8 @@ static tsi_result ssl_handshaker_result_create(
handshaker->ssl = nullptr;
result->network_io = handshaker->network_io;
handshaker->network_io = nullptr;
if (unused_bytes_size > 0) {
result->unused_bytes =
static_cast<unsigned char*>(gpr_malloc(unused_bytes_size));
memcpy(result->unused_bytes, unused_bytes, unused_bytes_size);
}
/* Transfer ownership of |unused_bytes| to the handshaker result. */
result->unused_bytes = unused_bytes;
result->unused_bytes_size = unused_bytes_size;
*handshaker_result = &result->base;
return TSI_OK;
@ -1412,6 +1454,36 @@ static void ssl_handshaker_destroy(tsi_handshaker* self) {
gpr_free(impl);
}
// Removes the bytes remaining in |impl->SSL|'s read BIO and writes them to
// |bytes_remaining|.
static tsi_result ssl_bytes_remaining(tsi_ssl_handshaker* impl,
unsigned char** bytes_remaining,
size_t* bytes_remaining_size) {
if (impl == nullptr || bytes_remaining == nullptr ||
bytes_remaining_size == nullptr) {
return TSI_INVALID_ARGUMENT;
}
// Atempt to read all of the bytes in SSL's read BIO. These bytes should
// contain application data records that were appended to a handshake record
// containing the ClientFinished or ServerFinished message.
size_t bytes_in_ssl = BIO_pending(SSL_get_rbio(impl->ssl));
if (bytes_in_ssl == 0) return TSI_OK;
*bytes_remaining = static_cast<uint8_t*>(gpr_malloc(bytes_in_ssl));
int bytes_read = BIO_read(SSL_get_rbio(impl->ssl), *bytes_remaining,
static_cast<int>(bytes_in_ssl));
// If an unexpected number of bytes were read, return an error status and free
// all of the bytes that were read.
if (bytes_read < 0 || static_cast<size_t>(bytes_read) != bytes_in_ssl) {
gpr_log(GPR_ERROR,
"Failed to read the expected number of bytes from SSL object.");
gpr_free(*bytes_remaining);
*bytes_remaining = nullptr;
return TSI_INTERNAL_ERROR;
}
*bytes_remaining_size = static_cast<size_t>(bytes_read);
return TSI_OK;
}
static tsi_result ssl_handshaker_next(
tsi_handshaker* self, const unsigned char* received_bytes,
size_t received_bytes_size, const unsigned char** bytes_to_send,
@ -1452,9 +1524,19 @@ static tsi_result ssl_handshaker_next(
if (ssl_handshaker_get_result(impl) == TSI_HANDSHAKE_IN_PROGRESS) {
*handshaker_result = nullptr;
} else {
size_t unused_bytes_size = received_bytes_size - bytes_consumed;
const unsigned char* unused_bytes =
unused_bytes_size == 0 ? nullptr : received_bytes + bytes_consumed;
// Any bytes that remain in |impl->ssl|'s read BIO after the handshake is
// complete must be extracted and set to the unused bytes of the handshaker
// result. This indicates to the gRPC stack that there are bytes from the
// peer that must be processed.
unsigned char* unused_bytes = nullptr;
size_t unused_bytes_size = 0;
status = ssl_bytes_remaining(impl, &unused_bytes, &unused_bytes_size);
if (status != TSI_OK) return status;
if (unused_bytes_size > received_bytes_size) {
gpr_log(GPR_ERROR, "More unused bytes than received bytes.");
gpr_free(unused_bytes);
return TSI_INTERNAL_ERROR;
}
status = ssl_handshaker_result_create(impl, unused_bytes, unused_bytes_size,
handshaker_result);
if (status == TSI_OK) {
@ -1807,11 +1889,14 @@ tsi_result tsi_create_ssl_client_handshaker_factory_with_options(
return TSI_INVALID_ARGUMENT;
}
#if defined(OPENSSL_NO_TLS1_2_METHOD) || OPENSSL_API_COMPAT >= 0x10100000L
#if OPENSSL_VERSION_NUMBER >= 0x10100000
ssl_context = SSL_CTX_new(TLS_method());
#else
ssl_context = SSL_CTX_new(TLSv1_2_method());
#endif
result = tsi_set_min_and_max_tls_versions(
ssl_context, options->min_tls_version, options->max_tls_version);
if (result != TSI_OK) return result;
if (ssl_context == nullptr) {
gpr_log(GPR_ERROR, "Could not create ssl context.");
return TSI_INVALID_ARGUMENT;
@ -1971,11 +2056,15 @@ tsi_result tsi_create_ssl_server_handshaker_factory_with_options(
for (i = 0; i < options->num_key_cert_pairs; i++) {
do {
#if defined(OPENSSL_NO_TLS1_2_METHOD) || OPENSSL_API_COMPAT >= 0x10100000L
#if OPENSSL_VERSION_NUMBER >= 0x10100000
impl->ssl_contexts[i] = SSL_CTX_new(TLS_method());
#else
impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method());
#endif
result = tsi_set_min_and_max_tls_versions(impl->ssl_contexts[i],
options->min_tls_version,
options->max_tls_version);
if (result != TSI_OK) return result;
if (impl->ssl_contexts[i] == nullptr) {
gpr_log(GPR_ERROR, "Could not create ssl context.");
result = TSI_OUT_OF_RESOURCES;

@ -21,6 +21,7 @@
#include <grpc/support/port_platform.h>
#include <grpc/grpc_security_constants.h>
#include "absl/strings/string_view.h"
#include "src/core/tsi/transport_security_interface.h"
@ -152,6 +153,10 @@ struct tsi_ssl_client_handshaker_options {
/* skip server certificate verification. */
bool skip_server_certificate_verification;
/* The min and max TLS versions that will be negotiated by the handshaker. */
tsi_tls_version min_tls_version;
tsi_tls_version max_tls_version;
tsi_ssl_client_handshaker_options()
: pem_key_cert_pair(nullptr),
pem_root_certs(nullptr),
@ -160,7 +165,9 @@ struct tsi_ssl_client_handshaker_options {
alpn_protocols(nullptr),
num_alpn_protocols(0),
session_cache(nullptr),
skip_server_certificate_verification(false) {}
skip_server_certificate_verification(false),
min_tls_version(tsi_tls_version::TSI_TLS1_2),
max_tls_version(tsi_tls_version::TSI_TLS1_3) {}
};
/* Creates a client handshaker factory.
@ -276,6 +283,9 @@ struct tsi_ssl_server_handshaker_options {
const char* session_ticket_key;
/* session_ticket_key_size is a size of session ticket encryption key. */
size_t session_ticket_key_size;
/* The min and max TLS versions that will be negotiated by the handshaker. */
tsi_tls_version min_tls_version;
tsi_tls_version max_tls_version;
tsi_ssl_server_handshaker_options()
: pem_key_cert_pairs(nullptr),
@ -286,7 +296,9 @@ struct tsi_ssl_server_handshaker_options {
alpn_protocols(nullptr),
num_alpn_protocols(0),
session_ticket_key(nullptr),
session_ticket_key_size(0) {}
session_ticket_key_size(0),
min_tls_version(tsi_tls_version::TSI_TLS1_2),
max_tls_version(tsi_tls_version::TSI_TLS1_3) {}
};
/* Creates a server handshaker factory.

@ -64,6 +64,11 @@ typedef enum {
TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY,
} tsi_client_certificate_request_type;
typedef enum {
TSI_TLS1_2,
TSI_TLS1_3,
} tsi_tls_version;
const char* tsi_result_to_string(tsi_result result);
const char* tsi_security_level_to_string(tsi_security_level security_level);

@ -246,8 +246,10 @@ namespace Grpc.IntegrationTesting
private void CheckRejected()
{
var ex = Assert.Throws<RpcException>(() => client.UnaryCall(new SimpleRequest { ResponseSize = 10 }));
Assert.AreEqual(StatusCode.Unavailable, ex.Status.StatusCode);
}
if (ex.Status.StatusCode != StatusCode.Unavailable & ex.Status.StatusCode != StatusCode.Unknown) {
Assert.Fail("Expect status to be either Unavailable or Unknown");
}
}
private async Task CheckAuthContextIsPopulated()
{

@ -161,8 +161,14 @@ class _ServerSSLCertReloadTest(
else:
with self.assertRaises(grpc.RpcError) as exception_context:
client_stub.UnUn(request)
self.assertEqual(exception_context.exception.code(),
grpc.StatusCode.UNAVAILABLE)
# If TLS 1.2 is used, then the client receives an alert message
# before the handshake is complete, so the status is UNAVAILABLE. If
# TLS 1.3 is used, then the client receives the alert message after
# the handshake is complete, so the TSI handshaker returns the
# TSI_PROTOCOL_FAILURE result. This result does not have a
# corresponding status code, so this yields an UNKNOWN status.
self.assertTrue(exception_context.exception.code(
) in [grpc.StatusCode.UNAVAILABLE, grpc.StatusCode.UNKNOWN])
def _do_one_shot_client_rpc(self,
expect_success,

@ -35,6 +35,7 @@ typedef struct grpc_end2end_test_config grpc_end2end_test_config;
#define FEATURE_MASK_DOES_NOT_SUPPORT_NETWORK_STATUS_CHANGE 128
#define FEATURE_MASK_SUPPORTS_WORKAROUNDS 256
#define FEATURE_MASK_DOES_NOT_SUPPORT_SEND_CALL_CREDENTIALS 512
#define FEATURE_MASK_DOES_NOT_SUPPORT_CLIENT_HANDSHAKE_COMPLETE_FIRST 1024
#define FAIL_AUTH_CHECK_SERVER_ARG_NAME "fail_auth_check"

@ -26,6 +26,7 @@
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
#include "test/core/end2end/end2end_tests.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
@ -40,6 +41,7 @@ static const char* client_identity = "Brainy Smurf";
struct fullstack_secure_fixture_data {
std::string localaddr;
grpc_tls_version tls_version;
};
static const grpc_metadata* find_metadata(const grpc_metadata* md,
@ -93,18 +95,32 @@ static void process_oauth2_failure(void* state, grpc_auth_context* /*ctx*/,
}
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
grpc_channel_args* /*client_args*/, grpc_channel_args* /*server_args*/) {
grpc_channel_args* /*client_args*/, grpc_channel_args* /*server_args*/,
grpc_tls_version tls_version) {
grpc_end2end_test_fixture f;
int port = grpc_pick_unused_port_or_die();
fullstack_secure_fixture_data* ffd = new fullstack_secure_fixture_data();
memset(&f, 0, sizeof(f));
ffd->localaddr = grpc_core::JoinHostPort("localhost", port);
ffd->tls_version = tls_version;
f.fixture_data = ffd;
f.cq = grpc_completion_queue_create_for_next(nullptr);
f.shutdown_cq = grpc_completion_queue_create_for_pluck(nullptr);
return f;
}
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack_tls1_2(
grpc_channel_args* client_args, grpc_channel_args* server_args) {
return chttp2_create_fixture_secure_fullstack(client_args, server_args,
grpc_tls_version::TLS1_2);
}
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack_tls1_3(
grpc_channel_args* client_args, grpc_channel_args* server_args) {
return chttp2_create_fixture_secure_fullstack(client_args, server_args,
grpc_tls_version::TLS1_3);
}
static void chttp2_init_client_secure_fullstack(
grpc_end2end_test_fixture* f, grpc_channel_args* client_args,
grpc_channel_credentials* creds) {
@ -148,6 +164,15 @@ static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack(
reinterpret_cast<const char*> GRPC_SLICE_START_PTR(ca_slice);
grpc_channel_credentials* ssl_creds =
grpc_ssl_credentials_create(test_root_cert, nullptr, nullptr, nullptr);
if (f != nullptr && ssl_creds != nullptr) {
// Set the min and max TLS version.
grpc_ssl_credentials* creds =
reinterpret_cast<grpc_ssl_credentials*>(ssl_creds);
fullstack_secure_fixture_data* ffd =
static_cast<fullstack_secure_fixture_data*>(f->fixture_data);
creds->set_min_tls_version(ffd->tls_version);
creds->set_max_tls_version(ffd->tls_version);
}
grpc_call_credentials* oauth2_creds = grpc_md_only_test_credentials_create(
"authorization", oauth2_md, true /* is_async */);
grpc_channel_credentials* ssl_oauth2_creds =
@ -213,6 +238,15 @@ static void chttp2_init_server_simple_ssl_secure_fullstack(
grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {server_key, server_cert};
grpc_server_credentials* ssl_creds = grpc_ssl_server_credentials_create(
nullptr, &pem_key_cert_pair, 1, 0, nullptr);
if (f != nullptr && ssl_creds != nullptr) {
// Set the min and max TLS version.
grpc_ssl_server_credentials* creds =
reinterpret_cast<grpc_ssl_server_credentials*>(ssl_creds);
fullstack_secure_fixture_data* ffd =
static_cast<fullstack_secure_fixture_data*>(f->fixture_data);
creds->set_min_tls_version(ffd->tls_version);
creds->set_max_tls_version(ffd->tls_version);
}
grpc_server_credentials_set_auth_metadata_processor(
ssl_creds, test_processor_create(fail_server_auth_check(server_args)));
chttp2_init_server_secure_fullstack(f, server_args, ssl_creds);
@ -223,12 +257,22 @@ static void chttp2_init_server_simple_ssl_secure_fullstack(
/* All test configurations */
static grpc_end2end_test_config configs[] = {
{"chttp2/simple_ssl_with_oauth2_fullstack",
{"chttp2/simple_ssl_with_oauth2_fullstack_tls1_2",
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
"foo.test.google.fr", chttp2_create_fixture_secure_fullstack,
"foo.test.google.fr", chttp2_create_fixture_secure_fullstack_tls1_2,
chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack,
chttp2_init_server_simple_ssl_secure_fullstack,
chttp2_tear_down_secure_fullstack},
{"chttp2/simple_ssl_with_oauth2_fullstack_tls1_3",
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER |
FEATURE_MASK_DOES_NOT_SUPPORT_CLIENT_HANDSHAKE_COMPLETE_FIRST,
"foo.test.google.fr", chttp2_create_fixture_secure_fullstack_tls1_3,
chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack,
chttp2_init_server_simple_ssl_secure_fullstack,
chttp2_tear_down_secure_fullstack},

@ -27,6 +27,7 @@
#include "src/core/lib/gprpp/host_port.h"
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
#include "src/core/lib/security/security_connector/ssl_utils_config.h"
#include "test/core/end2end/end2end_tests.h"
#include "test/core/util/port.h"
@ -38,16 +39,19 @@
struct fullstack_secure_fixture_data {
std::string localaddr;
grpc_tls_version tls_version;
};
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
grpc_channel_args* /*client_args*/, grpc_channel_args* /*server_args*/) {
grpc_channel_args* /*client_args*/, grpc_channel_args* /*server_args*/,
grpc_tls_version tls_version) {
grpc_end2end_test_fixture f;
int port = grpc_pick_unused_port_or_die();
fullstack_secure_fixture_data* ffd = new fullstack_secure_fixture_data();
memset(&f, 0, sizeof(f));
ffd->localaddr = grpc_core::JoinHostPort("localhost", port);
ffd->tls_version = tls_version;
f.fixture_data = ffd;
f.cq = grpc_completion_queue_create_for_next(nullptr);
@ -56,6 +60,18 @@ static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
return f;
}
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack_tls1_2(
grpc_channel_args* client_args, grpc_channel_args* server_args) {
return chttp2_create_fixture_secure_fullstack(client_args, server_args,
grpc_tls_version::TLS1_2);
}
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack_tls1_3(
grpc_channel_args* client_args, grpc_channel_args* server_args) {
return chttp2_create_fixture_secure_fullstack(client_args, server_args,
grpc_tls_version::TLS1_3);
}
static void process_auth_failure(void* state, grpc_auth_context* /*ctx*/,
const grpc_metadata* /*md*/,
size_t /*md_count*/,
@ -102,6 +118,15 @@ static void chttp2_init_client_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture* f, grpc_channel_args* client_args) {
grpc_channel_credentials* ssl_creds =
grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
if (f != nullptr && ssl_creds != nullptr) {
// Set the min and max TLS version.
grpc_ssl_credentials* creds =
reinterpret_cast<grpc_ssl_credentials*>(ssl_creds);
fullstack_secure_fixture_data* ffd =
static_cast<fullstack_secure_fixture_data*>(f->fixture_data);
creds->set_min_tls_version(ffd->tls_version);
creds->set_max_tls_version(ffd->tls_version);
}
grpc_arg ssl_name_override = {
GRPC_ARG_STRING,
const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
@ -138,6 +163,15 @@ static void chttp2_init_server_simple_ssl_secure_fullstack(
grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {server_key, server_cert};
grpc_server_credentials* ssl_creds = grpc_ssl_server_credentials_create(
nullptr, &pem_key_cert_pair, 1, 0, nullptr);
if (f != nullptr && ssl_creds != nullptr) {
// Set the min and max TLS version.
grpc_ssl_server_credentials* creds =
reinterpret_cast<grpc_ssl_server_credentials*>(ssl_creds);
fullstack_secure_fixture_data* ffd =
static_cast<fullstack_secure_fixture_data*>(f->fixture_data);
creds->set_min_tls_version(ffd->tls_version);
creds->set_max_tls_version(ffd->tls_version);
}
grpc_slice_unref(cert_slice);
grpc_slice_unref(key_slice);
if (fail_server_auth_check(server_args)) {
@ -151,12 +185,22 @@ static void chttp2_init_server_simple_ssl_secure_fullstack(
/* All test configurations */
static grpc_end2end_test_config configs[] = {
{"chttp2/simple_ssl_fullstack",
{"chttp2/simple_ssl_fullstack_tls1_2",
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
"foo.test.google.fr", chttp2_create_fixture_secure_fullstack,
"foo.test.google.fr", chttp2_create_fixture_secure_fullstack_tls1_2,
chttp2_init_client_simple_ssl_secure_fullstack,
chttp2_init_server_simple_ssl_secure_fullstack,
chttp2_tear_down_secure_fullstack},
{"chttp2/simple_ssl_fullstack_tls1_3",
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER |
FEATURE_MASK_DOES_NOT_SUPPORT_CLIENT_HANDSHAKE_COMPLETE_FIRST,
"foo.test.google.fr", chttp2_create_fixture_secure_fullstack_tls1_3,
chttp2_init_client_simple_ssl_secure_fullstack,
chttp2_init_server_simple_ssl_secure_fullstack,
chttp2_tear_down_secure_fullstack},

@ -27,6 +27,7 @@
#include "src/core/lib/gprpp/host_port.h"
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
#include "src/core/lib/security/security_connector/ssl_utils_config.h"
#include "test/core/end2end/end2end_tests.h"
#include "test/core/util/port.h"
@ -38,6 +39,7 @@
struct fullstack_secure_fixture_data {
std::string localaddr;
grpc_tls_version tls_version;
bool server_credential_reloaded = false;
};
@ -77,12 +79,14 @@ ssl_server_certificate_config_callback(
}
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
grpc_channel_args* /*client_args*/, grpc_channel_args* /*server_args*/) {
grpc_channel_args* /*client_args*/, grpc_channel_args* /*server_args*/,
grpc_tls_version tls_version) {
grpc_end2end_test_fixture f;
int port = grpc_pick_unused_port_or_die();
fullstack_secure_fixture_data* ffd = new fullstack_secure_fixture_data();
memset(&f, 0, sizeof(f));
ffd->localaddr = grpc_core::JoinHostPort("localhost", port);
ffd->tls_version = tls_version;
f.fixture_data = ffd;
f.cq = grpc_completion_queue_create_for_next(nullptr);
@ -91,6 +95,18 @@ static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
return f;
}
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack_tls1_2(
grpc_channel_args* client_args, grpc_channel_args* server_args) {
return chttp2_create_fixture_secure_fullstack(client_args, server_args,
grpc_tls_version::TLS1_2);
}
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack_tls1_3(
grpc_channel_args* client_args, grpc_channel_args* server_args) {
return chttp2_create_fixture_secure_fullstack(client_args, server_args,
grpc_tls_version::TLS1_3);
}
static void process_auth_failure(void* state, grpc_auth_context* /*ctx*/,
const grpc_metadata* /*md*/,
size_t /*md_count*/,
@ -138,6 +154,15 @@ static void chttp2_init_client_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture* f, grpc_channel_args* client_args) {
grpc_channel_credentials* ssl_creds =
grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
if (f != nullptr && ssl_creds != nullptr) {
// Set the min and max TLS version.
grpc_ssl_credentials* creds =
reinterpret_cast<grpc_ssl_credentials*>(ssl_creds);
fullstack_secure_fixture_data* ffd =
static_cast<fullstack_secure_fixture_data*>(f->fixture_data);
creds->set_min_tls_version(ffd->tls_version);
creds->set_max_tls_version(ffd->tls_version);
}
grpc_arg ssl_name_override = {
GRPC_ARG_STRING,
const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
@ -168,6 +193,15 @@ static void chttp2_init_server_simple_ssl_secure_fullstack(
ssl_server_certificate_config_callback, f->fixture_data);
grpc_server_credentials* ssl_creds =
grpc_ssl_server_credentials_create_with_options(options);
if (f != nullptr && ssl_creds != nullptr) {
// Set the min and max TLS version.
grpc_ssl_server_credentials* creds =
reinterpret_cast<grpc_ssl_server_credentials*>(ssl_creds);
fullstack_secure_fixture_data* ffd =
static_cast<fullstack_secure_fixture_data*>(f->fixture_data);
creds->set_min_tls_version(ffd->tls_version);
creds->set_max_tls_version(ffd->tls_version);
}
if (fail_server_auth_check(server_args)) {
grpc_auth_metadata_processor processor = {process_auth_failure, nullptr,
nullptr};
@ -179,12 +213,22 @@ static void chttp2_init_server_simple_ssl_secure_fullstack(
/* All test configurations */
static grpc_end2end_test_config configs[] = {
{"chttp2/simple_ssl_fullstack",
{"chttp2/simple_ssl_fullstack_tls1_2",
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
"foo.test.google.fr", chttp2_create_fixture_secure_fullstack,
"foo.test.google.fr", chttp2_create_fixture_secure_fullstack_tls1_2,
chttp2_init_client_simple_ssl_secure_fullstack,
chttp2_init_server_simple_ssl_secure_fullstack,
chttp2_tear_down_secure_fullstack},
{"chttp2/simple_ssl_fullstack_tls1_3",
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER |
FEATURE_MASK_DOES_NOT_SUPPORT_CLIENT_HANDSHAKE_COMPLETE_FIRST,
"foo.test.google.fr", chttp2_create_fixture_secure_fullstack_tls1_3,
chttp2_init_client_simple_ssl_secure_fullstack,
chttp2_init_server_simple_ssl_secure_fullstack,
chttp2_tear_down_secure_fullstack},

@ -508,7 +508,15 @@ void filter_call_init_fails(grpc_end2end_test_config config) {
g_enable_client_channel_filter = true;
test_client_channel_filter(config);
g_enable_client_channel_filter = false;
if (config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL) {
// If the client handshake completes before the server handshake and the
// client is able to send application data before the server handshake
// completes, then testing the CLIENT_SUBCHANNEL filter will cause the server
// to hang waiting for the final handshake message from the client. This
// handshake message will never arrive because it would have been sent with
// the first application data message, which failed because of the filter.
if ((config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL) &&
!(config.feature_mask &
FEATURE_MASK_DOES_NOT_SUPPORT_CLIENT_HANDSHAKE_COMPLETE_FIRST)) {
gpr_log(GPR_INFO, "Testing CLIENT_SUBCHANNEL filter.");
g_enable_client_subchannel_filter = true;
test_client_subchannel_filter(config);

@ -55,6 +55,9 @@ const size_t kSessionTicketEncryptionKeySize = 80;
const size_t kSessionTicketEncryptionKeySize = 48;
#endif
// Indicates the TLS version used for the test.
static tsi_tls_version test_tls_version = tsi_tls_version::TSI_TLS1_3;
typedef enum AlpnMode {
NO_ALPN,
ALPN_CLIENT_NO_SERVER,
@ -127,6 +130,8 @@ static void ssl_test_setup_handshakers(tsi_test_fixture* fixture) {
if (ssl_fixture->session_cache != nullptr) {
client_options.session_cache = ssl_fixture->session_cache;
}
client_options.min_tls_version = test_tls_version;
client_options.max_tls_version = test_tls_version;
GPR_ASSERT(tsi_create_ssl_client_handshaker_factory_with_options(
&client_options, &ssl_fixture->client_handshaker_factory) ==
TSI_OK);
@ -159,6 +164,8 @@ static void ssl_test_setup_handshakers(tsi_test_fixture* fixture) {
}
server_options.session_ticket_key = ssl_fixture->session_ticket_key;
server_options.session_ticket_key_size = ssl_fixture->session_ticket_key_size;
server_options.min_tls_version = test_tls_version;
server_options.max_tls_version = test_tls_version;
GPR_ASSERT(tsi_create_ssl_server_handshaker_factory_with_options(
&server_options, &ssl_fixture->server_handshaker_factory) ==
TSI_OK);
@ -317,10 +324,18 @@ static void ssl_test_check_handshaker_peers(tsi_test_fixture* fixture) {
GPR_ASSERT(ssl_fixture->key_cert_lib != nullptr);
ssl_key_cert_lib* key_cert_lib = ssl_fixture->key_cert_lib;
tsi_peer peer;
bool expect_success =
// In TLS 1.3, the client-side handshake succeeds even if the client sends a
// bad certificate. In such a case, the server would fail the TLS handshake
// and send an alert to the client as the first application data message. In
// TLS 1.2, the client-side handshake will fail if the client sends a bad
// certificate.
bool expect_server_success =
!(key_cert_lib->use_bad_server_cert ||
(key_cert_lib->use_bad_client_cert && ssl_fixture->force_client_auth));
if (expect_success) {
bool expect_client_success = test_tls_version == tsi_tls_version::TSI_TLS1_2
? expect_server_success
: !key_cert_lib->use_bad_server_cert;
if (expect_client_success) {
GPR_ASSERT(tsi_handshaker_result_extract_peer(
ssl_fixture->base.client_result, &peer) == TSI_OK);
check_session_reusage(ssl_fixture, &peer);
@ -338,7 +353,7 @@ static void ssl_test_check_handshaker_peers(tsi_test_fixture* fixture) {
} else {
GPR_ASSERT(ssl_fixture->base.client_result == nullptr);
}
if (expect_success) {
if (expect_server_success) {
GPR_ASSERT(tsi_handshaker_result_extract_peer(
ssl_fixture->base.server_result, &peer) == TSI_OK);
check_session_reusage(ssl_fixture, &peer);
@ -421,7 +436,7 @@ static tsi_test_fixture* ssl_tsi_test_fixture_create() {
ssl_tsi_test_fixture* ssl_fixture =
static_cast<ssl_tsi_test_fixture*>(gpr_zalloc(sizeof(*ssl_fixture)));
tsi_test_fixture_init(&ssl_fixture->base);
ssl_fixture->base.test_unused_bytes = false;
ssl_fixture->base.test_unused_bytes = true;
ssl_fixture->base.vtable = &vtable;
/* Create ssl_key_cert_lib. */
ssl_key_cert_lib* key_cert_lib =
@ -494,6 +509,9 @@ void ssl_tsi_test_do_handshake_tiny_handshake_buffer() {
gpr_log(GPR_INFO, "ssl_tsi_test_do_handshake_tiny_handshake_buffer");
tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
fixture->handshake_buffer_size = TSI_TEST_TINY_HANDSHAKE_BUFFER_SIZE;
// Handshake buffer is too small to hold both handshake messages and the
// unused bytes.
fixture->test_unused_bytes = false;
tsi_test_do_handshake(fixture);
tsi_test_fixture_destroy(fixture);
}
@ -951,31 +969,39 @@ void ssl_tsi_test_extract_cert_chain() {
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
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();
const size_t number_tls_versions = 2;
const tsi_tls_version tls_versions[] = {tsi_tls_version::TSI_TLS1_2,
tsi_tls_version::TSI_TLS1_3};
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();
#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_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_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_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();
}
grpc_shutdown();
return 0;
}

Loading…
Cancel
Save