Merge pull request #14722 from jiangtaoli2016/ssl_load_root_certs

load ssl default root certificates only once
pull/14635/merge
Jiangtao Li 7 years ago committed by GitHub
commit c7c779f51a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      src/core/lib/http/httpcli_security_connector.cc
  2. 138
      src/core/lib/security/security_connector/security_connector.cc
  3. 51
      src/core/lib/security/security_connector/security_connector.h
  4. 1
      src/core/lib/surface/init.cc
  5. 1
      src/core/lib/surface/init.h
  6. 7
      src/core/lib/surface/init_secure.cc
  7. 2
      src/core/lib/surface/init_unsecure.cc
  8. 78
      src/core/tsi/ssl_transport_security.cc
  9. 40
      src/core/tsi/ssl_transport_security.h
  10. 27
      test/core/security/security_connector_test.cc
  11. 38
      test/core/tsi/ssl_transport_security_test.cc

@ -102,8 +102,8 @@ static grpc_security_connector_vtable httpcli_ssl_vtable = {
httpcli_ssl_destroy, httpcli_ssl_check_peer, httpcli_ssl_cmp}; httpcli_ssl_destroy, httpcli_ssl_check_peer, httpcli_ssl_cmp};
static grpc_security_status httpcli_ssl_channel_security_connector_create( static grpc_security_status httpcli_ssl_channel_security_connector_create(
const char* pem_root_certs, const char* secure_peer_name, const char* pem_root_certs, const tsi_ssl_root_certs_store* root_store,
grpc_channel_security_connector** sc) { const char* secure_peer_name, grpc_channel_security_connector** sc) {
tsi_result result = TSI_OK; tsi_result result = TSI_OK;
grpc_httpcli_ssl_channel_security_connector* c; grpc_httpcli_ssl_channel_security_connector* c;
@ -124,6 +124,7 @@ static grpc_security_status httpcli_ssl_channel_security_connector_create(
tsi_ssl_client_handshaker_options options; tsi_ssl_client_handshaker_options options;
memset(&options, 0, sizeof(options)); memset(&options, 0, sizeof(options));
options.pem_root_certs = pem_root_certs; options.pem_root_certs = pem_root_certs;
options.root_store = root_store;
result = tsi_create_ssl_client_handshaker_factory_with_options( result = tsi_create_ssl_client_handshaker_factory_with_options(
&options, &c->handshaker_factory); &options, &c->handshaker_factory);
if (result != TSI_OK) { if (result != TSI_OK) {
@ -172,8 +173,11 @@ static void ssl_handshake(void* arg, grpc_endpoint* tcp, const char* host,
grpc_millis deadline, grpc_millis deadline,
void (*on_done)(void* arg, grpc_endpoint* endpoint)) { void (*on_done)(void* arg, grpc_endpoint* endpoint)) {
on_done_closure* c = static_cast<on_done_closure*>(gpr_malloc(sizeof(*c))); on_done_closure* c = static_cast<on_done_closure*>(gpr_malloc(sizeof(*c)));
const char* pem_root_certs = grpc_get_default_ssl_roots(); const char* pem_root_certs =
if (pem_root_certs == nullptr) { grpc_core::DefaultSslRootStore::GetPemRootCerts();
const tsi_ssl_root_certs_store* root_store =
grpc_core::DefaultSslRootStore::GetRootStore();
if (root_store == nullptr) {
gpr_log(GPR_ERROR, "Could not get default pem root certs."); gpr_log(GPR_ERROR, "Could not get default pem root certs.");
on_done(arg, nullptr); on_done(arg, nullptr);
gpr_free(c); gpr_free(c);
@ -183,7 +187,7 @@ static void ssl_handshake(void* arg, grpc_endpoint* tcp, const char* host,
c->arg = arg; c->arg = arg;
grpc_channel_security_connector* sc = nullptr; grpc_channel_security_connector* sc = nullptr;
GPR_ASSERT(httpcli_ssl_channel_security_connector_create( GPR_ASSERT(httpcli_ssl_channel_security_connector_create(
pem_root_certs, host, &sc) == GRPC_SECURITY_OK); pem_root_certs, root_store, host, &sc) == GRPC_SECURITY_OK);
grpc_arg channel_arg = grpc_security_connector_to_arg(&sc->base); grpc_arg channel_arg = grpc_security_connector_to_arg(&sc->base);
grpc_channel_args args = {1, &channel_arg}; grpc_channel_args args = {1, &channel_arg};
c->handshake_mgr = grpc_handshake_manager_create(); c->handshake_mgr = grpc_handshake_manager_create();

@ -965,63 +965,6 @@ static grpc_security_connector_vtable ssl_channel_vtable = {
static grpc_security_connector_vtable ssl_server_vtable = { static grpc_security_connector_vtable ssl_server_vtable = {
ssl_server_destroy, ssl_server_check_peer, ssl_server_cmp}; ssl_server_destroy, ssl_server_check_peer, ssl_server_cmp};
/* returns a NULL terminated slice. */
static grpc_slice compute_default_pem_root_certs_once(void) {
grpc_slice result = grpc_empty_slice();
/* First try to load the roots from the environment. */
char* default_root_certs_path =
gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
if (default_root_certs_path != nullptr) {
GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(default_root_certs_path, 1, &result));
gpr_free(default_root_certs_path);
}
/* Try overridden roots if needed. */
grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL;
if (GRPC_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != nullptr) {
char* pem_root_certs = nullptr;
ovrd_res = ssl_roots_override_cb(&pem_root_certs);
if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) {
GPR_ASSERT(pem_root_certs != nullptr);
result = grpc_slice_from_copied_buffer(
pem_root_certs,
strlen(pem_root_certs) + 1); // NULL terminator.
}
gpr_free(pem_root_certs);
}
/* Fall back to installed certs if needed. */
if (GRPC_SLICE_IS_EMPTY(result) &&
ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(installed_roots_path, 1, &result));
}
return result;
}
static grpc_slice default_pem_root_certs;
static void init_default_pem_root_certs(void) {
default_pem_root_certs = compute_default_pem_root_certs_once();
}
grpc_slice grpc_get_default_ssl_roots_for_testing(void) {
return compute_default_pem_root_certs_once();
}
const char* grpc_get_default_ssl_roots(void) {
/* TODO(jboeuf@google.com): Maybe revisit the approach which consists in
loading all the roots once for the lifetime of the process. */
static gpr_once once = GPR_ONCE_INIT;
gpr_once_init(&once, init_default_pem_root_certs);
return GRPC_SLICE_IS_EMPTY(default_pem_root_certs)
? nullptr
: reinterpret_cast<const char*>
GRPC_SLICE_START_PTR(default_pem_root_certs);
}
grpc_security_status grpc_ssl_channel_security_connector_create( grpc_security_status grpc_ssl_channel_security_connector_create(
grpc_channel_credentials* channel_creds, grpc_channel_credentials* channel_creds,
grpc_call_credentials* request_metadata_creds, grpc_call_credentials* request_metadata_creds,
@ -1043,7 +986,9 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
goto error; goto error;
} }
if (config->pem_root_certs == nullptr) { if (config->pem_root_certs == nullptr) {
options.pem_root_certs = grpc_get_default_ssl_roots(); // Use default root certificates.
options.pem_root_certs = grpc_core::DefaultSslRootStore::GetPemRootCerts();
options.root_store = grpc_core::DefaultSslRootStore::GetRootStore();
if (options.pem_root_certs == nullptr) { if (options.pem_root_certs == nullptr) {
gpr_log(GPR_ERROR, "Could not get default pem root certs."); gpr_log(GPR_ERROR, "Could not get default pem root certs.");
goto error; goto error;
@ -1051,7 +996,6 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
} else { } else {
options.pem_root_certs = config->pem_root_certs; options.pem_root_certs = config->pem_root_certs;
} }
c = static_cast<grpc_ssl_channel_security_connector*>( c = static_cast<grpc_ssl_channel_security_connector*>(
gpr_zalloc(sizeof(grpc_ssl_channel_security_connector))); gpr_zalloc(sizeof(grpc_ssl_channel_security_connector)));
@ -1157,3 +1101,79 @@ grpc_security_status grpc_ssl_server_security_connector_create(
} }
return retval; return retval;
} }
namespace grpc_core {
tsi_ssl_root_certs_store* DefaultSslRootStore::default_root_store_;
grpc_slice DefaultSslRootStore::default_pem_root_certs_;
const tsi_ssl_root_certs_store* DefaultSslRootStore::GetRootStore() {
InitRootStore();
return default_root_store_;
}
const char* DefaultSslRootStore::GetPemRootCerts() {
InitRootStore();
return GRPC_SLICE_IS_EMPTY(default_pem_root_certs_)
? nullptr
: reinterpret_cast<const char*>
GRPC_SLICE_START_PTR(default_pem_root_certs_);
}
void DefaultSslRootStore::Initialize() {
default_root_store_ = nullptr;
default_pem_root_certs_ = grpc_empty_slice();
}
void DefaultSslRootStore::Destroy() {
tsi_ssl_root_certs_store_destroy(default_root_store_);
grpc_slice_unref_internal(default_pem_root_certs_);
}
grpc_slice DefaultSslRootStore::ComputePemRootCerts() {
grpc_slice result = grpc_empty_slice();
// First try to load the roots from the environment.
char* default_root_certs_path =
gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
if (default_root_certs_path != nullptr) {
GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(default_root_certs_path, 1, &result));
gpr_free(default_root_certs_path);
}
// Try overridden roots if needed.
grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL;
if (GRPC_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != nullptr) {
char* pem_root_certs = nullptr;
ovrd_res = ssl_roots_override_cb(&pem_root_certs);
if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) {
GPR_ASSERT(pem_root_certs != nullptr);
result = grpc_slice_from_copied_buffer(
pem_root_certs,
strlen(pem_root_certs) + 1); // nullptr terminator.
}
gpr_free(pem_root_certs);
}
// Fall back to installed certs if needed.
if (GRPC_SLICE_IS_EMPTY(result) &&
ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(installed_roots_path, 1, &result));
}
return result;
}
void DefaultSslRootStore::InitRootStore() {
static gpr_once once = GPR_ONCE_INIT;
gpr_once_init(&once, DefaultSslRootStore::InitRootStoreOnce);
}
void DefaultSslRootStore::InitRootStoreOnce() {
default_pem_root_certs_ = ComputePemRootCerts();
if (!GRPC_SLICE_IS_EMPTY(default_pem_root_certs_)) {
default_root_store_ =
tsi_ssl_root_certs_store_create(reinterpret_cast<const char*>(
GRPC_SLICE_START_PTR(default_pem_root_certs_)));
}
}
} // namespace grpc_core

@ -216,12 +216,6 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
tsi_ssl_session_cache* ssl_session_cache, tsi_ssl_session_cache* ssl_session_cache,
grpc_channel_security_connector** sc); grpc_channel_security_connector** sc);
/* Gets the default ssl roots. Returns NULL if not found. */
const char* grpc_get_default_ssl_roots(void);
/* Exposed for TESTING ONLY!. */
grpc_slice grpc_get_default_ssl_roots_for_testing(void);
/* Config for ssl servers. */ /* Config for ssl servers. */
typedef struct { typedef struct {
tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs; tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs;
@ -250,4 +244,49 @@ tsi_peer tsi_shallow_peer_from_ssl_auth_context(
const grpc_auth_context* auth_context); const grpc_auth_context* auth_context);
void tsi_shallow_peer_destruct(tsi_peer* peer); void tsi_shallow_peer_destruct(tsi_peer* peer);
/* --- Default SSL Root Store. --- */
namespace grpc_core {
// The class implements default SSL root store.
class DefaultSslRootStore {
public:
// Gets the default SSL root store. Returns nullptr if not found.
static const tsi_ssl_root_certs_store* GetRootStore();
// Gets the default PEM root certificate.
static const char* GetPemRootCerts();
// Initializes the SSL root store's underlying data structure. It does not
// load default SSL root certificates. Should only be called by
// grpc_security_init().
static void Initialize();
// Destroys the default SSL root store. Should only be called by
// grpc_security_shutdown().
static void Destroy();
protected:
// Returns default PEM root certificates in nullptr terminated grpc_slice.
// This function is protected instead of private, so that it can be tested.
static grpc_slice ComputePemRootCerts();
private:
// Construct me not!
DefaultSslRootStore();
// Initialization of default SSL root store.
static void InitRootStore();
// One-time initialization of default SSL root store.
static void InitRootStoreOnce();
// SSL root store in tsi_ssl_root_certs_store object.
static tsi_ssl_root_certs_store* default_root_store_;
// Default PEM root certificates.
static grpc_slice default_pem_root_certs_;
};
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SECURITY_CONNECTOR_H */ #endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SECURITY_CONNECTOR_H */

@ -172,6 +172,7 @@ void grpc_shutdown(void) {
} }
} }
} }
grpc_security_shutdown();
grpc_iomgr_shutdown(); grpc_iomgr_shutdown();
gpr_timers_global_destroy(); gpr_timers_global_destroy();
grpc_tracer_shutdown(); grpc_tracer_shutdown();

@ -22,6 +22,7 @@
void grpc_register_security_filters(void); void grpc_register_security_filters(void);
void grpc_security_pre_init(void); void grpc_security_pre_init(void);
void grpc_security_init(void); void grpc_security_init(void);
void grpc_security_shutdown(void);
int grpc_is_initialized(void); int grpc_is_initialized(void);
#endif /* GRPC_CORE_LIB_SURFACE_INIT_H */ #endif /* GRPC_CORE_LIB_SURFACE_INIT_H */

@ -75,4 +75,9 @@ void grpc_register_security_filters(void) {
maybe_prepend_server_auth_filter, nullptr); maybe_prepend_server_auth_filter, nullptr);
} }
void grpc_security_init() { grpc_security_register_handshaker_factories(); } void grpc_security_init() {
grpc_security_register_handshaker_factories();
grpc_core::DefaultSslRootStore::Initialize();
}
void grpc_security_shutdown() { grpc_core::DefaultSslRootStore::Destroy(); }

@ -25,3 +25,5 @@ void grpc_security_pre_init(void) {}
void grpc_register_security_filters(void) {} void grpc_register_security_filters(void) {}
void grpc_security_init(void) {} void grpc_security_init(void) {}
void grpc_security_shutdown(void) {}

@ -71,6 +71,10 @@ extern "C" {
/* --- Structure definitions. ---*/ /* --- Structure definitions. ---*/
struct tsi_ssl_root_certs_store {
X509_STORE* store;
};
struct tsi_ssl_handshaker_factory { struct tsi_ssl_handshaker_factory {
const tsi_ssl_handshaker_factory_vtable* vtable; const tsi_ssl_handshaker_factory_vtable* vtable;
gpr_refcount refcount; gpr_refcount refcount;
@ -553,21 +557,18 @@ static tsi_result ssl_ctx_use_private_key(SSL_CTX* context, const char* pem_key,
/* Loads in-memory PEM verification certs into the SSL context and optionally /* Loads in-memory PEM verification certs into the SSL context and optionally
returns the verification cert names (root_names can be NULL). */ returns the verification cert names (root_names can be NULL). */
static tsi_result ssl_ctx_load_verification_certs(SSL_CTX* context, static tsi_result x509_store_load_certs(X509_STORE* cert_store,
const char* pem_roots, const char* pem_roots,
size_t pem_roots_size, size_t pem_roots_size,
STACK_OF(X509_NAME) * STACK_OF(X509_NAME) * *root_names) {
*root_names) {
tsi_result result = TSI_OK; tsi_result result = TSI_OK;
size_t num_roots = 0; size_t num_roots = 0;
X509* root = nullptr; X509* root = nullptr;
X509_NAME* root_name = nullptr; X509_NAME* root_name = nullptr;
BIO* pem; BIO* pem;
X509_STORE* root_store;
GPR_ASSERT(pem_roots_size <= INT_MAX); GPR_ASSERT(pem_roots_size <= INT_MAX);
pem = BIO_new_mem_buf((void*)pem_roots, static_cast<int>(pem_roots_size)); pem = BIO_new_mem_buf((void*)pem_roots, static_cast<int>(pem_roots_size));
root_store = SSL_CTX_get_cert_store(context); if (cert_store == nullptr) return TSI_INVALID_ARGUMENT;
if (root_store == nullptr) return TSI_INVALID_ARGUMENT;
if (pem == nullptr) return TSI_OUT_OF_RESOURCES; if (pem == nullptr) return TSI_OUT_OF_RESOURCES;
if (root_names != nullptr) { if (root_names != nullptr) {
*root_names = sk_X509_NAME_new_null(); *root_names = sk_X509_NAME_new_null();
@ -595,7 +596,7 @@ static tsi_result ssl_ctx_load_verification_certs(SSL_CTX* context,
sk_X509_NAME_push(*root_names, root_name); sk_X509_NAME_push(*root_names, root_name);
root_name = nullptr; root_name = nullptr;
} }
if (!X509_STORE_add_cert(root_store, root)) { if (!X509_STORE_add_cert(cert_store, root)) {
gpr_log(GPR_ERROR, "Could not add root certificate to ssl context."); gpr_log(GPR_ERROR, "Could not add root certificate to ssl context.");
result = TSI_INTERNAL_ERROR; result = TSI_INTERNAL_ERROR;
break; break;
@ -621,6 +622,16 @@ static tsi_result ssl_ctx_load_verification_certs(SSL_CTX* context,
return result; return result;
} }
static tsi_result ssl_ctx_load_verification_certs(SSL_CTX* context,
const char* pem_roots,
size_t pem_roots_size,
STACK_OF(X509_NAME) *
*root_name) {
X509_STORE* cert_store = SSL_CTX_get_cert_store(context);
return x509_store_load_certs(cert_store, pem_roots, pem_roots_size,
root_name);
}
/* Populates the SSL context with a private key and a cert chain, and sets the /* Populates the SSL context with a private key and a cert chain, and sets the
cipher list and the ephemeral ECDH key. */ cipher list and the ephemeral ECDH key. */
static tsi_result populate_ssl_context( static tsi_result populate_ssl_context(
@ -730,6 +741,43 @@ static int NullVerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) {
return 1; return 1;
} }
/* --- tsi_ssl_root_certs_store methods implementation. ---*/
tsi_ssl_root_certs_store* tsi_ssl_root_certs_store_create(
const char* pem_roots) {
if (pem_roots == nullptr) {
gpr_log(GPR_ERROR, "The root certificates are empty.");
return nullptr;
}
tsi_ssl_root_certs_store* root_store = static_cast<tsi_ssl_root_certs_store*>(
gpr_zalloc(sizeof(tsi_ssl_root_certs_store)));
if (root_store == nullptr) {
gpr_log(GPR_ERROR, "Could not allocate buffer for ssl_root_certs_store.");
return nullptr;
}
root_store->store = X509_STORE_new();
if (root_store->store == nullptr) {
gpr_log(GPR_ERROR, "Could not allocate buffer for X509_STORE.");
gpr_free(root_store);
return nullptr;
}
tsi_result result = x509_store_load_certs(root_store->store, pem_roots,
strlen(pem_roots), nullptr);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Could not load root certificates.");
X509_STORE_free(root_store->store);
gpr_free(root_store);
return nullptr;
}
return root_store;
}
void tsi_ssl_root_certs_store_destroy(tsi_ssl_root_certs_store* self) {
if (self == nullptr) return;
X509_STORE_free(self->store);
gpr_free(self);
}
/* --- tsi_ssl_session_cache methods implementation. ---*/ /* --- tsi_ssl_session_cache methods implementation. ---*/
tsi_ssl_session_cache* tsi_ssl_session_cache_create_lru(size_t capacity) { tsi_ssl_session_cache* tsi_ssl_session_cache_create_lru(size_t capacity) {
@ -1468,7 +1516,9 @@ tsi_result tsi_create_ssl_client_handshaker_factory_with_options(
if (factory == nullptr) return TSI_INVALID_ARGUMENT; if (factory == nullptr) return TSI_INVALID_ARGUMENT;
*factory = nullptr; *factory = nullptr;
if (options->pem_root_certs == nullptr) return TSI_INVALID_ARGUMENT; if (options->pem_root_certs == nullptr && options->root_store == nullptr) {
return TSI_INVALID_ARGUMENT;
}
ssl_context = SSL_CTX_new(TLSv1_2_method()); ssl_context = SSL_CTX_new(TLSv1_2_method());
if (ssl_context == nullptr) { if (ssl_context == nullptr) {
@ -1480,9 +1530,7 @@ tsi_result tsi_create_ssl_client_handshaker_factory_with_options(
gpr_zalloc(sizeof(*impl))); gpr_zalloc(sizeof(*impl)));
tsi_ssl_handshaker_factory_init(&impl->base); tsi_ssl_handshaker_factory_init(&impl->base);
impl->base.vtable = &client_handshaker_factory_vtable; impl->base.vtable = &client_handshaker_factory_vtable;
impl->ssl_context = ssl_context; impl->ssl_context = ssl_context;
if (options->session_cache != nullptr) { if (options->session_cache != nullptr) {
// Unref is called manually on factory destruction. // Unref is called manually on factory destruction.
impl->session_cache = impl->session_cache =
@ -1498,6 +1546,15 @@ tsi_result tsi_create_ssl_client_handshaker_factory_with_options(
result = populate_ssl_context(ssl_context, options->pem_key_cert_pair, result = populate_ssl_context(ssl_context, options->pem_key_cert_pair,
options->cipher_suites); options->cipher_suites);
if (result != TSI_OK) break; if (result != TSI_OK) break;
#if OPENSSL_VERSION_NUMBER >= 0x10100000
// X509_STORE_up_ref is only available since OpenSSL 1.1.
if (options->root_store != nullptr) {
X509_STORE_up_ref(options->root_store->store);
SSL_CTX_set_cert_store(ssl_context, options->root_store->store);
}
#endif
if (OPENSSL_VERSION_NUMBER < 0x10100000 || options->root_store == nullptr) {
result = ssl_ctx_load_verification_certs( result = ssl_ctx_load_verification_certs(
ssl_context, options->pem_root_certs, strlen(options->pem_root_certs), ssl_context, options->pem_root_certs, strlen(options->pem_root_certs),
nullptr); nullptr);
@ -1505,6 +1562,7 @@ tsi_result tsi_create_ssl_client_handshaker_factory_with_options(
gpr_log(GPR_ERROR, "Cannot load server root certificates."); gpr_log(GPR_ERROR, "Cannot load server root certificates.");
break; break;
} }
}
if (options->num_alpn_protocols != 0) { if (options->num_alpn_protocols != 0) {
result = build_alpn_protocol_name_list( result = build_alpn_protocol_name_list(

@ -36,6 +36,20 @@
#define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol" #define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol"
/* --- tsi_ssl_root_certs_store object ---
This object stores SSL root certificates. It can be shared by multiple SSL
context. */
typedef struct tsi_ssl_root_certs_store tsi_ssl_root_certs_store;
/* Given a NULL-terminated string containing the PEM encoding of the root
certificates, creates a tsi_ssl_root_certs_store object. */
tsi_ssl_root_certs_store* tsi_ssl_root_certs_store_create(
const char* pem_roots);
/* Destroys the tsi_ssl_root_certs_store object. */
void tsi_ssl_root_certs_store_destroy(tsi_ssl_root_certs_store* self);
/* --- tsi_ssl_session_cache object --- /* --- tsi_ssl_session_cache object ---
Cache for SSL sessions for sessions resumption. */ Cache for SSL sessions for sessions resumption. */
@ -70,13 +84,13 @@ typedef struct {
const char* cert_chain; const char* cert_chain;
} tsi_ssl_pem_key_cert_pair; } tsi_ssl_pem_key_cert_pair;
/* Creates a client handshaker factory. /* TO BE DEPRECATED.
Creates a client handshaker factory.
- pem_key_cert_pair is a pointer to the object containing client's private - pem_key_cert_pair is a pointer to the object containing client's private
key and certificate chain. This parameter can be NULL if the client does key and certificate chain. This parameter can be NULL if the client does
not have such a key/cert pair. not have such a key/cert pair.
- pem_roots_cert is the NULL-terminated string containing the PEM encoding of - pem_roots_cert is the NULL-terminated string containing the PEM encoding of
the client root certificates. This parameter may be NULL if the server does the server root certificates.
not want the client to be authenticated with SSL.
- cipher_suites contains an optional list of the ciphers that the client - cipher_suites contains an optional list of the ciphers that the client
supports. The format of this string is described in: supports. The format of this string is described in:
https://www.openssl.org/docs/apps/ciphers.html. https://www.openssl.org/docs/apps/ciphers.html.
@ -103,9 +117,13 @@ typedef struct {
not have such a key/cert pair. */ not have such a key/cert pair. */
const tsi_ssl_pem_key_cert_pair* pem_key_cert_pair; const tsi_ssl_pem_key_cert_pair* pem_key_cert_pair;
/* pem_roots_cert is the NULL-terminated string containing the PEM encoding of /* pem_roots_cert is the NULL-terminated string containing the PEM encoding of
the client root certificates. This parameter may be NULL if the server does the client root certificates. */
not want the client to be authenticated with SSL. */
const char* pem_root_certs; const char* pem_root_certs;
/* root_store is a pointer to the ssl_root_certs_store object. If root_store
is not nullptr and SSL implementation permits, root_store will be used as
root certificates. Otherwise, pem_roots_cert will be used to load server
root certificates. */
const tsi_ssl_root_certs_store* root_store;
/* cipher_suites contains an optional list of the ciphers that the client /* cipher_suites contains an optional list of the ciphers that the client
supports. The format of this string is described in: supports. The format of this string is described in:
https://www.openssl.org/docs/apps/ciphers.html. https://www.openssl.org/docs/apps/ciphers.html.
@ -160,12 +178,14 @@ void tsi_ssl_client_handshaker_factory_unref(
typedef struct tsi_ssl_server_handshaker_factory typedef struct tsi_ssl_server_handshaker_factory
tsi_ssl_server_handshaker_factory; tsi_ssl_server_handshaker_factory;
/* Creates a server handshaker factory. /* TO BE DEPRECATED.
Creates a server handshaker factory.
- pem_key_cert_pairs is an array private key / certificate chains of the - pem_key_cert_pairs is an array private key / certificate chains of the
server. server.
- num_key_cert_pairs is the number of items in the pem_key_cert_pairs array. - num_key_cert_pairs is the number of items in the pem_key_cert_pairs array.
- pem_root_certs is the NULL-terminated string containing the PEM encoding - pem_root_certs is the NULL-terminated string containing the PEM encoding
of the server root certificates. of the client root certificates. This parameter may be NULL if the server
does not want the client to be authenticated with SSL.
- cipher_suites contains an optional list of the ciphers that the server - cipher_suites contains an optional list of the ciphers that the server
supports. The format of this string is described in: supports. The format of this string is described in:
https://www.openssl.org/docs/apps/ciphers.html. https://www.openssl.org/docs/apps/ciphers.html.
@ -187,7 +207,8 @@ tsi_result tsi_create_ssl_server_handshaker_factory(
const char** alpn_protocols, uint16_t num_alpn_protocols, const char** alpn_protocols, uint16_t num_alpn_protocols,
tsi_ssl_server_handshaker_factory** factory); tsi_ssl_server_handshaker_factory** factory);
/* Same as tsi_create_ssl_server_handshaker_factory method except uses /* TO BE DEPRECATED.
Same as tsi_create_ssl_server_handshaker_factory method except uses
tsi_client_certificate_request_type to support more ways to handle client tsi_client_certificate_request_type to support more ways to handle client
certificate authentication. certificate authentication.
- client_certificate_request, if set to non-zero will force the client to - client_certificate_request, if set to non-zero will force the client to
@ -208,7 +229,8 @@ typedef struct {
array. */ array. */
size_t num_key_cert_pairs; size_t num_key_cert_pairs;
/* pem_root_certs is the NULL-terminated string containing the PEM encoding /* pem_root_certs is the NULL-terminated string containing the PEM encoding
of the server root certificates. */ of the server root certificates. This parameter may be NULL if the server
does not want the client to be authenticated with SSL. */
const char* pem_client_root_certs; const char* pem_client_root_certs;
/* client_certificate_request, if set to non-zero will force the client to /* client_certificate_request, if set to non-zero will force the client to
authenticate with an SSL cert. Note that this option is ignored if authenticate with an SSL cert. Note that this option is ignored if

@ -340,6 +340,21 @@ static grpc_ssl_roots_override_result override_roots_permanent_failure(
return GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY; return GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY;
} }
namespace grpc_core {
namespace {
class TestDefafaultSllRootStore : public DefaultSslRootStore {
public:
static grpc_slice ComputePemRootCertsForTesting() {
return ComputePemRootCerts();
}
};
} // namespace
} // namespace grpc_core
// TODO: Convert this test to C++ test when security_connector implementation
// is converted to C++.
static void test_default_ssl_roots(void) { static void test_default_ssl_roots(void) {
const char* roots_for_env_var = "roots for env var"; const char* roots_for_env_var = "roots for env var";
@ -353,7 +368,8 @@ static void test_default_ssl_roots(void) {
value. */ value. */
gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, ""); gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, "");
grpc_set_ssl_roots_override_callback(override_roots_success); grpc_set_ssl_roots_override_callback(override_roots_success);
grpc_slice roots = grpc_get_default_ssl_roots_for_testing(); grpc_slice roots =
grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting();
char* roots_contents = grpc_slice_to_c_string(roots); char* roots_contents = grpc_slice_to_c_string(roots);
grpc_slice_unref(roots); grpc_slice_unref(roots);
GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0); GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
@ -362,7 +378,7 @@ static void test_default_ssl_roots(void) {
/* Now let's set the env var: We should get the contents pointed value /* Now let's set the env var: We should get the contents pointed value
instead. */ instead. */
gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_env_var_file_path); gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_env_var_file_path);
roots = grpc_get_default_ssl_roots_for_testing(); roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting();
roots_contents = grpc_slice_to_c_string(roots); roots_contents = grpc_slice_to_c_string(roots);
grpc_slice_unref(roots); grpc_slice_unref(roots);
GPR_ASSERT(strcmp(roots_contents, roots_for_env_var) == 0); GPR_ASSERT(strcmp(roots_contents, roots_for_env_var) == 0);
@ -371,7 +387,7 @@ static void test_default_ssl_roots(void) {
/* Now reset the env var. We should fall back to the value overridden using /* Now reset the env var. We should fall back to the value overridden using
the api. */ the api. */
gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, ""); gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, "");
roots = grpc_get_default_ssl_roots_for_testing(); roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting();
roots_contents = grpc_slice_to_c_string(roots); roots_contents = grpc_slice_to_c_string(roots);
grpc_slice_unref(roots); grpc_slice_unref(roots);
GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0); GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
@ -380,8 +396,11 @@ static void test_default_ssl_roots(void) {
/* Now setup a permanent failure for the overridden roots and we should get /* Now setup a permanent failure for the overridden roots and we should get
an empty slice. */ an empty slice. */
grpc_set_ssl_roots_override_callback(override_roots_permanent_failure); grpc_set_ssl_roots_override_callback(override_roots_permanent_failure);
roots = grpc_get_default_ssl_roots_for_testing(); roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting();
GPR_ASSERT(GRPC_SLICE_IS_EMPTY(roots)); GPR_ASSERT(GRPC_SLICE_IS_EMPTY(roots));
const tsi_ssl_root_certs_store* root_store =
grpc_core::TestDefafaultSllRootStore::GetRootStore();
GPR_ASSERT(root_store == nullptr);
/* Cleanup. */ /* Cleanup. */
remove(roots_env_var_file_path); remove(roots_env_var_file_path);

@ -61,7 +61,9 @@ typedef struct ssl_alpn_lib {
typedef struct ssl_key_cert_lib { typedef struct ssl_key_cert_lib {
bool use_bad_server_cert; bool use_bad_server_cert;
bool use_bad_client_cert; bool use_bad_client_cert;
bool use_root_store;
char* root_cert; char* root_cert;
tsi_ssl_root_certs_store* root_store;
tsi_ssl_pem_key_cert_pair* server_pem_key_cert_pairs; tsi_ssl_pem_key_cert_pair* server_pem_key_cert_pairs;
tsi_ssl_pem_key_cert_pair* bad_server_pem_key_cert_pairs; tsi_ssl_pem_key_cert_pair* bad_server_pem_key_cert_pairs;
tsi_ssl_pem_key_cert_pair client_pem_key_cert_pair; tsi_ssl_pem_key_cert_pair client_pem_key_cert_pair;
@ -108,6 +110,8 @@ static void ssl_test_setup_handshakers(tsi_test_fixture* fixture) {
client_options.alpn_protocols = alpn_lib->client_alpn_protocols; client_options.alpn_protocols = alpn_lib->client_alpn_protocols;
client_options.num_alpn_protocols = alpn_lib->num_client_alpn_protocols; client_options.num_alpn_protocols = alpn_lib->num_client_alpn_protocols;
} }
client_options.root_store =
key_cert_lib->use_root_store ? key_cert_lib->root_store : nullptr;
if (ssl_fixture->session_cache != nullptr) { if (ssl_fixture->session_cache != nullptr) {
client_options.session_cache = ssl_fixture->session_cache; client_options.session_cache = ssl_fixture->session_cache;
} }
@ -345,6 +349,7 @@ static void ssl_test_destruct(tsi_test_fixture* fixture) {
ssl_test_pem_key_cert_pair_destroy( ssl_test_pem_key_cert_pair_destroy(
key_cert_lib->bad_client_pem_key_cert_pair); key_cert_lib->bad_client_pem_key_cert_pair);
gpr_free(key_cert_lib->root_cert); gpr_free(key_cert_lib->root_cert);
tsi_ssl_root_certs_store_destroy(key_cert_lib->root_store);
gpr_free(key_cert_lib); gpr_free(key_cert_lib);
if (ssl_fixture->session_cache != nullptr) { if (ssl_fixture->session_cache != nullptr) {
tsi_ssl_session_cache_unref(ssl_fixture->session_cache); tsi_ssl_session_cache_unref(ssl_fixture->session_cache);
@ -384,6 +389,7 @@ static tsi_test_fixture* ssl_tsi_test_fixture_create() {
static_cast<ssl_key_cert_lib*>(gpr_zalloc(sizeof(*key_cert_lib))); static_cast<ssl_key_cert_lib*>(gpr_zalloc(sizeof(*key_cert_lib)));
key_cert_lib->use_bad_server_cert = false; key_cert_lib->use_bad_server_cert = false;
key_cert_lib->use_bad_client_cert = false; key_cert_lib->use_bad_client_cert = false;
key_cert_lib->use_root_store = false;
key_cert_lib->server_num_key_cert_pairs = key_cert_lib->server_num_key_cert_pairs =
SSL_TSI_TEST_SERVER_KEY_CERT_PAIRS_NUM; SSL_TSI_TEST_SERVER_KEY_CERT_PAIRS_NUM;
key_cert_lib->bad_server_num_key_cert_pairs = key_cert_lib->bad_server_num_key_cert_pairs =
@ -417,6 +423,9 @@ static tsi_test_fixture* ssl_tsi_test_fixture_create() {
key_cert_lib->bad_client_pem_key_cert_pair.cert_chain = key_cert_lib->bad_client_pem_key_cert_pair.cert_chain =
load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "badclient.pem"); load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "badclient.pem");
key_cert_lib->root_cert = load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "ca.pem"); key_cert_lib->root_cert = load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "ca.pem");
key_cert_lib->root_store =
tsi_ssl_root_certs_store_create(key_cert_lib->root_cert);
GPR_ASSERT(key_cert_lib->root_store != nullptr);
ssl_fixture->key_cert_lib = key_cert_lib; ssl_fixture->key_cert_lib = key_cert_lib;
/* Create ssl_alpn_lib. */ /* Create ssl_alpn_lib. */
ssl_alpn_lib* alpn_lib = ssl_alpn_lib* alpn_lib =
@ -462,6 +471,15 @@ void ssl_tsi_test_do_handshake() {
tsi_test_fixture_destroy(fixture); tsi_test_fixture_destroy(fixture);
} }
void ssl_tsi_test_do_handshake_with_root_store() {
tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
ssl_tsi_test_fixture* ssl_fixture =
reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
ssl_fixture->key_cert_lib->use_root_store = true;
tsi_test_do_handshake(fixture);
tsi_test_fixture_destroy(fixture);
}
void ssl_tsi_test_do_handshake_with_client_authentication() { void ssl_tsi_test_do_handshake_with_client_authentication() {
tsi_test_fixture* fixture = ssl_tsi_test_fixture_create(); tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
ssl_tsi_test_fixture* ssl_fixture = ssl_tsi_test_fixture* ssl_fixture =
@ -471,6 +489,16 @@ void ssl_tsi_test_do_handshake_with_client_authentication() {
tsi_test_fixture_destroy(fixture); tsi_test_fixture_destroy(fixture);
} }
void ssl_tsi_test_do_handshake_with_client_authentication_and_root_store() {
tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
ssl_tsi_test_fixture* ssl_fixture =
reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
ssl_fixture->force_client_auth = true;
ssl_fixture->key_cert_lib->use_root_store = true;
tsi_test_do_handshake(fixture);
tsi_test_fixture_destroy(fixture);
}
void ssl_tsi_test_do_handshake_with_server_name_indication_exact_domain() { void ssl_tsi_test_do_handshake_with_server_name_indication_exact_domain() {
/* server1 cert contains "waterzooi.test.google.be" in SAN. */ /* server1 cert contains "waterzooi.test.google.be" in SAN. */
tsi_test_fixture* fixture = ssl_tsi_test_fixture_create(); tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
@ -727,9 +755,11 @@ void test_tsi_ssl_client_handshaker_factory_bad_params() {
const char* cert_chain = "This is not a valid PEM file."; const char* cert_chain = "This is not a valid PEM file.";
tsi_ssl_client_handshaker_factory* client_handshaker_factory; tsi_ssl_client_handshaker_factory* client_handshaker_factory;
GPR_ASSERT(tsi_create_ssl_client_handshaker_factory( tsi_ssl_client_handshaker_options options;
nullptr, cert_chain, nullptr, nullptr, 0, memset(&options, 0, sizeof(options));
&client_handshaker_factory) == TSI_INVALID_ARGUMENT); options.pem_root_certs = cert_chain;
GPR_ASSERT(tsi_create_ssl_client_handshaker_factory_with_options(
&options, &client_handshaker_factory) == TSI_INVALID_ARGUMENT);
tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory); tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory);
} }
@ -746,7 +776,9 @@ int main(int argc, char** argv) {
ssl_tsi_test_do_handshake_tiny_handshake_buffer(); ssl_tsi_test_do_handshake_tiny_handshake_buffer();
ssl_tsi_test_do_handshake_small_handshake_buffer(); ssl_tsi_test_do_handshake_small_handshake_buffer();
ssl_tsi_test_do_handshake(); 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();
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_exact_domain();
ssl_tsi_test_do_handshake_with_server_name_indication_wild_star_domain(); ssl_tsi_test_do_handshake_with_server_name_indication_wild_star_domain();
ssl_tsi_test_do_handshake_with_bad_server_cert(); ssl_tsi_test_do_handshake_with_bad_server_cert();

Loading…
Cancel
Save