Skip to content

Commit

Permalink
Add CRL checking to gRPC Core (grpc#28418)
Browse files Browse the repository at this point in the history
  • Loading branch information
krestofur authored Jan 5, 2022
1 parent 0bd1ab3 commit 7759632
Show file tree
Hide file tree
Showing 25 changed files with 494 additions and 15 deletions.
41 changes: 41 additions & 0 deletions CMakeLists.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions build_autogenerated.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions grpc.def

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions include/grpc/grpc_security.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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;
Expand All @@ -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
4 changes: 4 additions & 0 deletions src/core/lib/security/security_connector/ssl_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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 =
Expand All @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/core/lib/security/security_connector/ssl_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,15 @@ 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(
tsi_ssl_pem_key_cert_pair* key_cert_pairs, size_t num_key_cert_pairs,
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. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
46 changes: 44 additions & 2 deletions src/core/tsi/ssl_transport_security.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
18 changes: 16 additions & 2 deletions src/core/tsi/ssl_transport_security.h
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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.
Expand Down Expand Up @@ -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),
Expand All @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions src/ruby/ext/grpc/rb_grpc_imports.generated.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/ruby/ext/grpc/rb_grpc_imports.generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions test/core/surface/public_headers_must_be_c89.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions test/core/tsi/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down
Loading

0 comments on commit 7759632

Please sign in to comment.