Enable CRL checking in gRPC core (#26287)

* enable crl checking in gRPC C core
reviewable/pr28406/r1
krestofur 3 years ago committed by GitHub
parent 465e3f4586
commit 7d8c9ae890
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 41
      CMakeLists.txt
  2. 15
      build_autogenerated.yaml
  3. 1
      grpc.def
  4. 10
      include/grpc/grpc_security.h
  5. 6
      src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc
  6. 7
      src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h
  7. 4
      src/core/lib/security/security_connector/ssl_utils.cc
  8. 2
      src/core/lib/security/security_connector/ssl_utils.h
  9. 4
      src/core/lib/security/security_connector/tls/tls_security_connector.cc
  10. 46
      src/core/tsi/ssl_transport_security.cc
  11. 18
      src/core/tsi/ssl_transport_security.h
  12. 2
      src/ruby/ext/grpc/rb_grpc_imports.generated.c
  13. 3
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  14. 1
      test/core/surface/public_headers_must_be_c89.c
  15. 25
      test/core/tsi/BUILD
  16. 279
      test/core/tsi/crl_ssl_transport_security_test.cc
  17. 1
      test/core/tsi/test_creds/crl_data/demoCA/index.txt.attr.old
  18. 1
      test/core/tsi/test_creds/demoCA/crlnumber
  19. 1
      test/core/tsi/test_creds/demoCA/index.txt
  20. 1
      test/core/tsi/test_creds/demoCA/index.txt.attr
  21. 0
      test/core/tsi/test_creds/demoCA/index.txt.old
  22. 1
      test/core/tsi/transport_security_test_lib.cc
  23. 22
      tools/run_tests/generated/tests.json

41
CMakeLists.txt generated

@ -825,6 +825,9 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx context_test)
add_dependencies(buildtests_cxx core_configuration_test)
add_dependencies(buildtests_cxx cpp_impl_of_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx crl_ssl_transport_security_test)
endif()
add_dependencies(buildtests_cxx delegating_channel_test)
add_dependencies(buildtests_cxx destroy_grpclb_channel_with_active_connect_stress_test)
add_dependencies(buildtests_cxx dual_ref_counted_test)
@ -9731,6 +9734,44 @@ target_link_libraries(cpp_impl_of_test
)
endif()
if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_executable(crl_ssl_transport_security_test
test/core/tsi/crl_ssl_transport_security_test.cc
test/core/tsi/transport_security_test_lib.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(crl_ssl_transport_security_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(crl_ssl_transport_security_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif()
endif()
if(gRPC_BUILD_TESTS)

@ -5392,6 +5392,21 @@ targets:
- test/core/gprpp/cpp_impl_of_test.cc
deps: []
uses_polling: false
- name: crl_ssl_transport_security_test
gtest: true
build: test
language: c++
headers:
- test/core/tsi/transport_security_test_lib.h
src:
- test/core/tsi/crl_ssl_transport_security_test.cc
- test/core/tsi/transport_security_test_lib.cc
deps:
- grpc_test_util
platforms:
- linux
- posix
- mac
- name: delegating_channel_test
gtest: true
build: test

1
grpc.def generated

@ -155,6 +155,7 @@ EXPORTS
grpc_tls_credentials_options_watch_identity_key_cert_pairs
grpc_tls_credentials_options_set_identity_cert_name
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_check_call_host
grpc_xds_credentials_create

@ -920,6 +920,16 @@ GRPCAPI void grpc_tls_credentials_options_set_identity_cert_name(
GRPCAPI void grpc_tls_credentials_options_set_cert_request_type(
grpc_tls_credentials_options* options,
grpc_ssl_client_certificate_request_type type);
/**
* EXPERIMENTAL API - Subject to change
*
* If set, gRPC will read all hashed x.509 CRL files in the directory and
* enforce the CRL files on all TLS handshakes. Only supported for OpenSSL
* version > 1.1.
* It is used for experimental purpose for now and subject to change.
*/
GRPCAPI void grpc_tls_credentials_options_set_crl_directory(
grpc_tls_credentials_options* options, const char* crl_directory);
/**
* EXPERIMENTAL API - Subject to change

@ -91,6 +91,12 @@ void grpc_tls_credentials_options_set_certificate_verifier(
options->set_certificate_verifier(verifier->Ref());
}
void grpc_tls_credentials_options_set_crl_directory(
grpc_tls_credentials_options* options, const char* crl_directory) {
GPR_ASSERT(options != nullptr);
options->set_crl_directory(crl_directory);
}
void grpc_tls_credentials_options_set_check_call_host(
grpc_tls_credentials_options* options, int check_call_host) {
GPR_ASSERT(options != nullptr);

@ -60,6 +60,7 @@ struct grpc_tls_credentials_options
const std::string& root_cert_name() { return root_cert_name_; }
bool watch_identity_pair() { return watch_identity_pair_; }
const std::string& identity_cert_name() { return identity_cert_name_; }
const std::string& crl_directory() { return crl_directory_; }
// Setters for member fields.
void set_cert_request_type(
@ -112,6 +113,11 @@ struct grpc_tls_credentials_options
identity_cert_name_ = std::move(identity_cert_name);
}
// 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 path) { crl_directory_ = std::move(path); }
private:
grpc_ssl_client_certificate_request_type cert_request_type_ =
GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE;
@ -125,6 +131,7 @@ struct grpc_tls_credentials_options
std::string root_cert_name_;
bool watch_identity_pair_ = false;
std::string identity_cert_name_;
std::string crl_directory_;
};
#endif // GRPC_CORE_LIB_SECURITY_CREDENTIALS_TLS_GRPC_TLS_CREDENTIALS_OPTIONS_H

@ -423,6 +423,7 @@ grpc_security_status grpc_ssl_tsi_client_handshaker_factory_init(
tsi_ssl_pem_key_cert_pair* pem_key_cert_pair, const char* pem_root_certs,
bool skip_server_certificate_verification, tsi_tls_version min_tls_version,
tsi_tls_version max_tls_version, tsi_ssl_session_cache* ssl_session_cache,
const char* crl_directory,
tsi_ssl_client_handshaker_factory** handshaker_factory) {
const char* root_certs;
const tsi_ssl_root_certs_store* root_store;
@ -459,6 +460,7 @@ grpc_security_status grpc_ssl_tsi_client_handshaker_factory_init(
skip_server_certificate_verification;
options.min_tls_version = min_tls_version;
options.max_tls_version = max_tls_version;
options.crl_directory = crl_directory;
const tsi_result result =
tsi_create_ssl_client_handshaker_factory_with_options(&options,
handshaker_factory);
@ -476,6 +478,7 @@ grpc_security_status grpc_ssl_tsi_server_handshaker_factory_init(
const char* pem_root_certs,
grpc_ssl_client_certificate_request_type client_certificate_request,
tsi_tls_version min_tls_version, tsi_tls_version max_tls_version,
const char* crl_directory,
tsi_ssl_server_handshaker_factory** handshaker_factory) {
size_t num_alpn_protocols = 0;
const char** alpn_protocol_strings =
@ -491,6 +494,7 @@ grpc_security_status grpc_ssl_tsi_server_handshaker_factory_init(
options.num_alpn_protocols = static_cast<uint16_t>(num_alpn_protocols);
options.min_tls_version = min_tls_version;
options.max_tls_version = max_tls_version;
options.crl_directory = crl_directory;
const tsi_result result =
tsi_create_ssl_server_handshaker_factory_with_options(&options,
handshaker_factory);

@ -91,6 +91,7 @@ grpc_security_status grpc_ssl_tsi_client_handshaker_factory_init(
tsi_ssl_pem_key_cert_pair* key_cert_pair, const char* pem_root_certs,
bool skip_server_certificate_verification, tsi_tls_version min_tls_version,
tsi_tls_version max_tls_version, tsi_ssl_session_cache* ssl_session_cache,
const char* crl_directory,
tsi_ssl_client_handshaker_factory** handshaker_factory);
grpc_security_status grpc_ssl_tsi_server_handshaker_factory_init(
@ -98,6 +99,7 @@ grpc_security_status grpc_ssl_tsi_server_handshaker_factory_init(
const char* pem_root_certs,
grpc_ssl_client_certificate_request_type client_certificate_request,
tsi_tls_version min_tls_version, tsi_tls_version max_tls_version,
const char* crl_directory,
tsi_ssl_server_handshaker_factory** handshaker_factory);
/* Exposed for testing only. */

@ -538,7 +538,7 @@ TlsChannelSecurityConnector::UpdateHandshakerFactoryLocked() {
skip_server_certificate_verification,
grpc_get_tsi_tls_version(options_->min_tls_version()),
grpc_get_tsi_tls_version(options_->max_tls_version()), ssl_session_cache_,
&client_handshaker_factory_);
options_->crl_directory().c_str(), &client_handshaker_factory_);
/* Free memory. */
if (pem_key_cert_pair != nullptr) {
grpc_tsi_ssl_pem_key_cert_pairs_destroy(pem_key_cert_pair, 1);
@ -806,7 +806,7 @@ TlsServerSecurityConnector::UpdateHandshakerFactoryLocked() {
options_->cert_request_type(),
grpc_get_tsi_tls_version(options_->min_tls_version()),
grpc_get_tsi_tls_version(options_->max_tls_version()),
&server_handshaker_factory_);
options_->crl_directory().c_str(), &server_handshaker_factory_);
/* Free memory. */
grpc_tsi_ssl_pem_key_cert_pairs_destroy(pem_key_cert_pairs,
num_key_cert_pairs);

@ -1921,6 +1921,14 @@ static int server_handshaker_factory_new_session_callback(
return 1;
}
static int verify_cb(int ok, X509_STORE_CTX* ctx) {
int cert_error = X509_STORE_CTX_get_error(ctx);
if (cert_error != 0) {
gpr_log(GPR_ERROR, "Certificate verify failed with code %d", cert_error);
}
return ok;
}
/* --- tsi_ssl_handshaker_factory constructors. --- */
static tsi_ssl_handshaker_factory_vtable client_handshaker_factory_vtable = {
@ -2041,7 +2049,24 @@ tsi_result tsi_create_ssl_client_handshaker_factory_with_options(
} else {
SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, nullptr);
}
/* TODO(jboeuf): Add revocation verification. */
#if OPENSSL_VERSION_NUMBER >= 0x10100000
if (options->crl_directory != nullptr &&
strcmp(options->crl_directory, "") != 0) {
gpr_log(GPR_INFO, "enabling client CRL checking with path: %s",
options->crl_directory);
X509_STORE* cert_store = SSL_CTX_get_cert_store(ssl_context);
X509_STORE_set_verify_cb(cert_store, verify_cb);
if (!X509_STORE_load_locations(cert_store, nullptr,
options->crl_directory)) {
gpr_log(GPR_ERROR, "Failed to load CRL File from directory.");
} else {
X509_VERIFY_PARAM* param = X509_STORE_get0_param(cert_store);
X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK);
gpr_log(GPR_INFO, "enabled client side CRL checking.");
}
}
#endif
*factory = impl;
return TSI_OK;
@ -2203,7 +2228,24 @@ tsi_result tsi_create_ssl_server_handshaker_factory_with_options(
nullptr);
break;
}
/* TODO(jboeuf): Add revocation verification. */
#if OPENSSL_VERSION_NUMBER >= 0x10100000
if (options->crl_directory != nullptr &&
strcmp(options->crl_directory, "") != 0) {
gpr_log(GPR_INFO, "enabling server CRL checking with path %s",
options->crl_directory);
X509_STORE* cert_store = SSL_CTX_get_cert_store(impl->ssl_contexts[i]);
X509_STORE_set_verify_cb(cert_store, verify_cb);
if (!X509_STORE_load_locations(cert_store, nullptr,
options->crl_directory)) {
gpr_log(GPR_ERROR, "Failed to load CRL File from directory.");
} else {
X509_VERIFY_PARAM* param = X509_STORE_get0_param(cert_store);
X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK);
gpr_log(GPR_INFO, "enabled server CRL checking.");
}
}
#endif
result = tsi_ssl_extract_x509_subject_names_from_pem_cert(
options->pem_key_cert_pairs[i].cert_chain,

@ -157,6 +157,12 @@ struct tsi_ssl_client_handshaker_options {
tsi_tls_version min_tls_version;
tsi_tls_version max_tls_version;
/* The directory where all hashed CRL files enforced by the handshaker are
located. If the directory is invalid, CRL checking will fail open and just
log. An empty directory will not enable crl checking. Only OpenSSL version
> 1.1 is supported for CRL checking*/
const char* crl_directory;
tsi_ssl_client_handshaker_options()
: pem_key_cert_pair(nullptr),
pem_root_certs(nullptr),
@ -167,7 +173,8 @@ struct tsi_ssl_client_handshaker_options {
session_cache(nullptr),
skip_server_certificate_verification(false),
min_tls_version(tsi_tls_version::TSI_TLS1_2),
max_tls_version(tsi_tls_version::TSI_TLS1_3) {}
max_tls_version(tsi_tls_version::TSI_TLS1_3),
crl_directory(nullptr) {}
};
/* Creates a client handshaker factory.
@ -287,6 +294,12 @@ struct tsi_ssl_server_handshaker_options {
tsi_tls_version min_tls_version;
tsi_tls_version max_tls_version;
/* The directory where all hashed CRL files are cached in the x.509 store and
* enforced by the handshaker are located. If the directory is invalid, CRL
* checking will fail open and just log. An empty directory will not enable
* crl checking. Only OpenSSL version > 1.1 is supported for CRL checking */
const char* crl_directory;
tsi_ssl_server_handshaker_options()
: pem_key_cert_pairs(nullptr),
num_key_cert_pairs(0),
@ -298,7 +311,8 @@ struct tsi_ssl_server_handshaker_options {
session_ticket_key(nullptr),
session_ticket_key_size(0),
min_tls_version(tsi_tls_version::TSI_TLS1_2),
max_tls_version(tsi_tls_version::TSI_TLS1_3) {}
max_tls_version(tsi_tls_version::TSI_TLS1_3),
crl_directory(nullptr) {}
};
/* Creates a server handshaker factory.

@ -178,6 +178,7 @@ grpc_tls_credentials_options_set_root_cert_name_type grpc_tls_credentials_option
grpc_tls_credentials_options_watch_identity_key_cert_pairs_type grpc_tls_credentials_options_watch_identity_key_cert_pairs_import;
grpc_tls_credentials_options_set_identity_cert_name_type grpc_tls_credentials_options_set_identity_cert_name_import;
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_check_call_host_type grpc_tls_credentials_options_set_check_call_host_import;
grpc_xds_credentials_create_type grpc_xds_credentials_create_import;
@ -466,6 +467,7 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_tls_credentials_options_watch_identity_key_cert_pairs_import = (grpc_tls_credentials_options_watch_identity_key_cert_pairs_type) GetProcAddress(library, "grpc_tls_credentials_options_watch_identity_key_cert_pairs");
grpc_tls_credentials_options_set_identity_cert_name_import = (grpc_tls_credentials_options_set_identity_cert_name_type) GetProcAddress(library, "grpc_tls_credentials_options_set_identity_cert_name");
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_check_call_host_import = (grpc_tls_credentials_options_set_check_call_host_type) GetProcAddress(library, "grpc_tls_credentials_options_set_check_call_host");
grpc_xds_credentials_create_import = (grpc_xds_credentials_create_type) GetProcAddress(library, "grpc_xds_credentials_create");

@ -509,6 +509,9 @@ extern grpc_tls_credentials_options_set_identity_cert_name_type grpc_tls_credent
typedef void(*grpc_tls_credentials_options_set_cert_request_type_type)(grpc_tls_credentials_options* options, grpc_ssl_client_certificate_request_type type);
extern grpc_tls_credentials_options_set_cert_request_type_type grpc_tls_credentials_options_set_cert_request_type_import;
#define grpc_tls_credentials_options_set_cert_request_type grpc_tls_credentials_options_set_cert_request_type_import
typedef void(*grpc_tls_credentials_options_set_crl_directory_type)(grpc_tls_credentials_options* options, const char* crl_directory);
extern grpc_tls_credentials_options_set_crl_directory_type grpc_tls_credentials_options_set_crl_directory_import;
#define grpc_tls_credentials_options_set_crl_directory grpc_tls_credentials_options_set_crl_directory_import
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

@ -222,6 +222,7 @@ int main(int argc, char **argv) {
printf("%lx", (unsigned long) grpc_tls_credentials_options_watch_identity_key_cert_pairs);
printf("%lx", (unsigned long) grpc_tls_credentials_options_set_identity_cert_name);
printf("%lx", (unsigned long) grpc_tls_credentials_options_set_cert_request_type);
printf("%lx", (unsigned long) grpc_tls_credentials_options_set_crl_directory);
printf("%lx", (unsigned long) grpc_tls_credentials_options_set_verify_server_cert);
printf("%lx", (unsigned long) grpc_tls_credentials_options_set_check_call_host);
printf("%lx", (unsigned long) grpc_xds_credentials_create);

@ -88,6 +88,31 @@ grpc_cc_test(
],
)
grpc_cc_test(
name = "crl_ssl_transport_security_test",
srcs = ["crl_ssl_transport_security_test.cc"],
data = [
"//test/core/tsi/test_creds/crl_data:ab06acdd.r0",
"//test/core/tsi/test_creds/crl_data:ca.pem",
"//test/core/tsi/test_creds/crl_data:revoked.key",
"//test/core/tsi/test_creds/crl_data:revoked.pem",
"//test/core/tsi/test_creds/crl_data:valid.key",
"//test/core/tsi/test_creds/crl_data:valid.pem",
],
external_deps = [
"gtest",
],
language = "C++",
tags = ["no_windows"],
deps = [
":transport_security_test_lib",
"//:gpr",
"//:grpc",
"//:tsi",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "transport_security_test",
srcs = ["transport_security_test.cc"],

@ -0,0 +1,279 @@
// Copyright 2021 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/security/security_connector/security_connector.h"
#include "src/core/tsi/ssl_transport_security.h"
#include "src/core/tsi/transport_security.h"
#include "src/core/tsi/transport_security_interface.h"
#include "test/core/tsi/transport_security_test_lib.h"
#include "test/core/util/test_config.h"
extern "C" {
#include <openssl/crypto.h>
#include <openssl/pem.h>
}
namespace {
const int kSslTsiTestRevokedKeyCertPairsNum = 1;
const int kSslTsiTestValidKeyCertPairsNum = 1;
const char* kSslTsiTestCrlSupportedCredentialsDir =
"test/core/tsi/test_creds/crl_data/";
class CrlSslTransportSecurityTest
: public testing::TestWithParam<tsi_tls_version> {
protected:
// A tsi_test_fixture implementation.
class SslTsiTestFixture {
public:
static SslTsiTestFixture* Create(bool use_revoked_server_cert,
bool use_revoked_client_cert) {
return new SslTsiTestFixture(use_revoked_server_cert,
use_revoked_client_cert);
}
void Run() {
tsi_test_do_handshake(&base_);
tsi_test_fixture_destroy(&base_);
}
private:
SslTsiTestFixture(bool use_revoked_server_cert,
bool use_revoked_client_cert)
: use_revoked_server_cert_(use_revoked_server_cert),
use_revoked_client_cert_(use_revoked_client_cert) {
tsi_test_fixture_init(&base_);
base_.test_unused_bytes = true;
base_.vtable = &kVtable;
// Load cert data.
revoked_pem_key_cert_pairs_ = static_cast<tsi_ssl_pem_key_cert_pair*>(
gpr_malloc(sizeof(tsi_ssl_pem_key_cert_pair) *
kSslTsiTestRevokedKeyCertPairsNum));
revoked_pem_key_cert_pairs_[0].private_key = LoadFile(
absl::StrCat(kSslTsiTestCrlSupportedCredentialsDir, "revoked.key"));
revoked_pem_key_cert_pairs_[0].cert_chain = LoadFile(
absl::StrCat(kSslTsiTestCrlSupportedCredentialsDir, "revoked.pem"));
valid_pem_key_cert_pairs_ = static_cast<tsi_ssl_pem_key_cert_pair*>(
gpr_malloc(sizeof(tsi_ssl_pem_key_cert_pair) *
kSslTsiTestValidKeyCertPairsNum));
valid_pem_key_cert_pairs_[0].private_key = LoadFile(
absl::StrCat(kSslTsiTestCrlSupportedCredentialsDir, "valid.key"));
valid_pem_key_cert_pairs_[0].cert_chain = LoadFile(
absl::StrCat(kSslTsiTestCrlSupportedCredentialsDir, "valid.pem"));
root_cert_ = LoadFile(
absl::StrCat(kSslTsiTestCrlSupportedCredentialsDir, "ca.pem"));
root_store_ = tsi_ssl_root_certs_store_create(root_cert_);
GPR_ASSERT(root_store_ != nullptr);
}
~SslTsiTestFixture() {
for (size_t i = 0; i < kSslTsiTestValidKeyCertPairsNum; i++) {
PemKeyCertPairDestroy(valid_pem_key_cert_pairs_[i]);
}
gpr_free(valid_pem_key_cert_pairs_);
for (size_t i = 0; i < kSslTsiTestRevokedKeyCertPairsNum; i++) {
PemKeyCertPairDestroy(revoked_pem_key_cert_pairs_[i]);
}
gpr_free(revoked_pem_key_cert_pairs_);
gpr_free(root_cert_);
tsi_ssl_root_certs_store_destroy(root_store_);
tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_);
tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory_);
}
static void SetupHandshakers(tsi_test_fixture* fixture) {
GPR_ASSERT(fixture != nullptr);
auto* self = reinterpret_cast<SslTsiTestFixture*>(fixture);
self->SetupHandshakers();
}
void SetupHandshakers() {
// Create client handshaker factory.
tsi_ssl_client_handshaker_options client_options;
client_options.pem_root_certs = root_cert_;
if (use_revoked_client_cert_) {
client_options.pem_key_cert_pair = revoked_pem_key_cert_pairs_;
} else {
client_options.pem_key_cert_pair = valid_pem_key_cert_pairs_;
}
client_options.crl_directory = kSslTsiTestCrlSupportedCredentialsDir;
client_options.root_store = root_store_;
client_options.min_tls_version = GetParam();
client_options.max_tls_version = GetParam();
EXPECT_EQ(tsi_create_ssl_client_handshaker_factory_with_options(
&client_options, &client_handshaker_factory_),
TSI_OK);
// Create server handshaker factory.
tsi_ssl_server_handshaker_options server_options;
if (use_revoked_server_cert_) {
server_options.pem_key_cert_pairs = revoked_pem_key_cert_pairs_;
server_options.num_key_cert_pairs = kSslTsiTestRevokedKeyCertPairsNum;
} else {
server_options.pem_key_cert_pairs = valid_pem_key_cert_pairs_;
server_options.num_key_cert_pairs = kSslTsiTestValidKeyCertPairsNum;
}
server_options.pem_client_root_certs = root_cert_;
server_options.crl_directory = kSslTsiTestCrlSupportedCredentialsDir;
server_options.client_certificate_request =
TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY;
server_options.session_ticket_key = nullptr;
server_options.session_ticket_key_size = 0;
server_options.min_tls_version = GetParam();
server_options.max_tls_version = GetParam();
EXPECT_EQ(tsi_create_ssl_server_handshaker_factory_with_options(
&server_options, &server_handshaker_factory_),
TSI_OK);
// Create server and client handshakers.
EXPECT_EQ(
tsi_ssl_client_handshaker_factory_create_handshaker(
client_handshaker_factory_, nullptr, &base_.client_handshaker),
TSI_OK);
EXPECT_EQ(tsi_ssl_server_handshaker_factory_create_handshaker(
server_handshaker_factory_, &base_.server_handshaker),
TSI_OK);
}
static void CheckHandshakerPeers(tsi_test_fixture* fixture) {
GPR_ASSERT(fixture != nullptr);
auto* self = reinterpret_cast<SslTsiTestFixture*>(fixture);
self->CheckHandshakerPeers();
}
void CheckHandshakerPeers() {
// In TLS 1.3, the client-side handshake succeeds even if the client
// sends a revoked 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 revoked certificate.
//
// For OpenSSL versions < 1.1, TLS 1.3 is not supported, so the
// client-side handshake should succeed precisely when the server-side
// handshake succeeds.
bool expect_server_success =
!(use_revoked_server_cert_ || use_revoked_client_cert_);
#if OPENSSL_VERSION_NUMBER >= 0x10100000
bool expect_client_success = GetParam() == tsi_tls_version::TSI_TLS1_2
? expect_server_success
: !use_revoked_server_cert_;
#else
bool expect_client_success = expect_server_success;
#endif
tsi_peer peer;
if (expect_client_success) {
EXPECT_EQ(
tsi_handshaker_result_extract_peer(base_.client_result, &peer),
TSI_OK);
tsi_peer_destruct(&peer);
} else {
EXPECT_EQ(base_.client_result, nullptr);
}
if (expect_server_success) {
EXPECT_EQ(
tsi_handshaker_result_extract_peer(base_.server_result, &peer),
TSI_OK);
tsi_peer_destruct(&peer);
} else {
EXPECT_EQ(base_.server_result, nullptr);
}
}
static void PemKeyCertPairDestroy(tsi_ssl_pem_key_cert_pair kp) {
gpr_free(const_cast<char*>(kp.private_key));
gpr_free(const_cast<char*>(kp.cert_chain));
}
static void Destruct(tsi_test_fixture* fixture) {
auto* self = reinterpret_cast<SslTsiTestFixture*>(fixture);
delete self;
}
static char* LoadFile(absl::string_view file_path) {
grpc_slice slice;
GPR_ASSERT(grpc_load_file(file_path.data(), 1, &slice) ==
GRPC_ERROR_NONE);
char* data = grpc_slice_to_c_string(slice);
grpc_slice_unref(slice);
return data;
}
static struct tsi_test_fixture_vtable kVtable;
tsi_test_fixture base_;
bool use_revoked_server_cert_;
bool use_revoked_client_cert_;
char* root_cert_;
tsi_ssl_root_certs_store* root_store_;
tsi_ssl_pem_key_cert_pair* revoked_pem_key_cert_pairs_;
tsi_ssl_pem_key_cert_pair* valid_pem_key_cert_pairs_;
tsi_ssl_server_handshaker_factory* server_handshaker_factory_;
tsi_ssl_client_handshaker_factory* client_handshaker_factory_;
};
};
struct tsi_test_fixture_vtable
CrlSslTransportSecurityTest::SslTsiTestFixture::kVtable = {
&CrlSslTransportSecurityTest::SslTsiTestFixture::SetupHandshakers,
&CrlSslTransportSecurityTest::SslTsiTestFixture::CheckHandshakerPeers,
&CrlSslTransportSecurityTest::SslTsiTestFixture::Destruct};
TEST_P(CrlSslTransportSecurityTest, RevokedServerCert) {
auto* fixture = SslTsiTestFixture::Create(/*use_revoked_server_cert=*/true,
/*use_revoked_client_cert=*/false);
fixture->Run();
}
TEST_P(CrlSslTransportSecurityTest, RevokedClientCert) {
auto* fixture = SslTsiTestFixture::Create(/*use_revoked_server_cert=*/false,
/*use_revoked_client_cert=*/true);
fixture->Run();
}
TEST_P(CrlSslTransportSecurityTest, ValidCerts) {
auto* fixture = SslTsiTestFixture::Create(/*use_revoked_server_cert=*/false,
/*use_revoked_client_cert=*/false);
fixture->Run();
}
std::string TestNameSuffix(
const ::testing::TestParamInfo<tsi_tls_version>& version) {
if (version.param == tsi_tls_version::TSI_TLS1_2) return "TLS_1_2";
GPR_ASSERT(version.param == tsi_tls_version::TSI_TLS1_3);
return "TLS_1_3";
}
INSTANTIATE_TEST_SUITE_P(TLSVersionsTest, CrlSslTransportSecurityTest,
testing::Values(tsi_tls_version::TSI_TLS1_2,
tsi_tls_version::TSI_TLS1_3),
&TestNameSuffix);
} // namespace
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -0,0 +1 @@
R 310920052448Z 211102205058Z 8B24B0063265547C unknown /CN=revoked

@ -605,6 +605,7 @@ static void tsi_test_channel_destroy(tsi_test_channel* channel) {
}
void tsi_test_fixture_init(tsi_test_fixture* fixture) {
memset(fixture, 0, sizeof(tsi_test_fixture));
fixture->config = tsi_test_frame_protector_config_create(
true, true, true, true, true, true, true);
fixture->handshake_buffer_size = TSI_TEST_DEFAULT_BUFFER_SIZE;

@ -3951,6 +3951,28 @@
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "crl_ssl_transport_security_test",
"platforms": [
"linux",
"mac",
"posix"
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save