Adding a function to override the ssl default roots path.

Fixes the first part of #4834.
pull/4929/head
Julien Boeuf 9 years ago
parent 26e4f5b1b6
commit 373debd5c0
  1. 16
      include/grpc/grpc_security.h
  2. 39
      src/core/security/security_connector.c
  3. 3
      src/core/security/security_connector.h
  4. 55
      test/core/security/security_connector_test.c

@ -143,6 +143,16 @@ grpc_channel_credentials *grpc_google_default_credentials_create(void);
#define GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR \
"GRPC_DEFAULT_SSL_ROOTS_FILE_PATH"
/* Overrides the default path for TLS/SSL roots.
The path must point to a PEM encoded file with all the roots such as the one
that can be downloaded from https://pki.google.com/roots.pem.
This function is not thread-safe and must be called at initialization time
before any ssl credentials are created to have the desired side effect.
It also does not do any checks about the validity or contents of the path.
If the GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment is set, it will override
the roots_path specified in this function. */
void grpc_override_ssl_default_roots_file_path(const char *roots_path);
/* Object that holds a private key / certificate chain pair in PEM format. */
typedef struct {
/* private_key is the NULL-terminated string containing the PEM encoding of
@ -159,8 +169,10 @@ typedef struct {
of the server root certificates. If this parameter is NULL, the
implementation will first try to dereference the file pointed by the
GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable, and if that fails,
get the roots from a well-known place on disk (in the grpc install
directory).
try to get the roots from the path specified in the function
grpc_override_ssl_default_roots_file_path. Eventually, if all these fail,
it will try to get the roots from a well-known place on disk (in the grpc
install directory).
- pem_key_cert_pair is a pointer on the object containing client's private
key and certificate chain. This parameter can be NULL if the client does
not have such a key/cert pair. */

@ -61,6 +61,14 @@ static const char *installed_roots_path =
INSTALL_PREFIX "/share/grpc/roots.pem";
#endif
/* -- Overridden default roots file path. -- */
static const char *overridden_default_roots_file_path = NULL;
void grpc_override_ssl_default_roots_file_path(const char *roots_path) {
overridden_default_roots_file_path = roots_path;
}
/* -- Cipher suites. -- */
/* Defines the cipher suites that we accept by default. All these cipher suites
@ -595,23 +603,38 @@ static grpc_security_connector_vtable ssl_channel_vtable = {
static grpc_security_connector_vtable ssl_server_vtable = {
ssl_server_destroy, ssl_server_do_handshake, ssl_server_check_peer};
static gpr_slice default_pem_root_certs;
static gpr_slice compute_default_pem_root_certs_once(void) {
gpr_slice result = gpr_empty_slice();
static void init_default_pem_root_certs(void) {
/* 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 == NULL) {
default_pem_root_certs = gpr_empty_slice();
} else {
default_pem_root_certs = gpr_load_file(default_root_certs_path, 0, NULL);
if (default_root_certs_path != NULL) {
result = gpr_load_file(default_root_certs_path, 0, NULL);
gpr_free(default_root_certs_path);
}
/* Try overridden roots path if needed. */
if (GPR_SLICE_IS_EMPTY(result) &&
overridden_default_roots_file_path != NULL) {
result = gpr_load_file(overridden_default_roots_file_path, 0, NULL);
}
/* Fall back to installed certs if needed. */
if (GPR_SLICE_IS_EMPTY(default_pem_root_certs)) {
default_pem_root_certs = gpr_load_file(installed_roots_path, 0, NULL);
if (GPR_SLICE_IS_EMPTY(result)) {
result = gpr_load_file(installed_roots_path, 0, NULL);
}
return result;
}
static gpr_slice default_pem_root_certs;
static void init_default_pem_root_certs(void) {
default_pem_root_certs = compute_default_pem_root_certs_once();
}
gpr_slice grpc_get_default_ssl_roots_for_testing(void) {
return compute_default_pem_root_certs_once();
}
size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {

@ -209,6 +209,9 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
/* Gets the default ssl roots. */
size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs);
/* Exposed for TESTING ONLY!. */
gpr_slice grpc_get_default_ssl_roots_for_testing(void);
/* Config for ssl servers. */
typedef struct {
unsigned char **pem_private_keys;

@ -36,6 +36,9 @@
#include "src/core/security/security_connector.h"
#include "src/core/security/security_context.h"
#include "src/core/support/env.h"
#include "src/core/support/file.h"
#include "src/core/support/string.h"
#include "src/core/tsi/ssl_transport_security.h"
#include "src/core/tsi/transport_security.h"
#include "test/core/util/test_config.h"
@ -297,6 +300,57 @@ static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context(
GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
}
static void test_default_ssl_roots(void) {
const char *roots_for_override_api = "roots for override api";
const char *roots_for_env_var = "roots for env var";
char *roots_api_file_path;
FILE *roots_api_file =
gpr_tmpfile("test_roots_for_api_override", &roots_api_file_path);
fwrite(roots_for_override_api, 1, strlen(roots_for_override_api),
roots_api_file);
fclose(roots_api_file);
char *roots_env_var_file_path;
FILE *roots_env_var_file =
gpr_tmpfile("test_roots_for_env_var", &roots_env_var_file_path);
fwrite(roots_for_env_var, 1, strlen(roots_for_env_var), roots_env_var_file);
fclose(roots_env_var_file);
/* First let's get the root through the override (no env are set). */
grpc_override_ssl_default_roots_file_path(roots_api_file_path);
gpr_slice roots = grpc_get_default_ssl_roots_for_testing();
char *roots_contents = gpr_dump_slice(roots, GPR_DUMP_ASCII);
gpr_slice_unref(roots);
GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
gpr_free(roots_contents);
/* Now let's set the env var: We should get the contents pointed value
instead. */
gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_env_var_file_path);
roots = grpc_get_default_ssl_roots_for_testing();
roots_contents = gpr_dump_slice(roots, GPR_DUMP_ASCII);
gpr_slice_unref(roots);
GPR_ASSERT(strcmp(roots_contents, roots_for_env_var) == 0);
gpr_free(roots_contents);
/* Now reset the env var. We should fall back to the value overridden using
the api. */
gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, "");
roots = grpc_get_default_ssl_roots_for_testing();
roots_contents = gpr_dump_slice(roots, GPR_DUMP_ASCII);
gpr_slice_unref(roots);
GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
gpr_free(roots_contents);
/* Cleanup. */
remove(roots_api_file_path);
remove(roots_env_var_file_path);
gpr_free(roots_api_file_path);
gpr_free(roots_env_var_file_path);
}
/* TODO(jboeuf): Unit-test tsi_shallow_peer_from_auth_context. */
int main(int argc, char **argv) {
@ -308,6 +362,7 @@ int main(int argc, char **argv) {
test_cn_and_one_san_ssl_peer_to_auth_context();
test_cn_and_multiple_sans_ssl_peer_to_auth_context();
test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context();
test_default_ssl_roots();
grpc_shutdown();
return 0;

Loading…
Cancel
Save