aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Julien Boeuf <jboeuf@google.com>2016-01-27 15:41:12 -0800
committerGravatar Julien Boeuf <jboeuf@google.com>2016-01-27 15:41:12 -0800
commit373debd5c094a3a1c60b2d1b4adc420e933653e7 (patch)
tree02aad31c9e3961a869047e231bde13178a33ed98
parent26e4f5b1b6478809edc576646d3b4cd24562d549 (diff)
Adding a function to override the ssl default roots path.
Fixes the first part of #4834.
-rw-r--r--include/grpc/grpc_security.h16
-rw-r--r--src/core/security/security_connector.c39
-rw-r--r--src/core/security/security_connector.h3
-rw-r--r--test/core/security/security_connector_test.c55
4 files changed, 103 insertions, 10 deletions
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 655f45a29b..46e493b347 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -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. */
diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c
index 61336a1057..7e5cb67146 100644
--- a/src/core/security/security_connector.c
+++ b/src/core/security/security_connector.c
@@ -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) {
diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h
index 2b734109b3..39df7821f0 100644
--- a/src/core/security/security_connector.h
+++ b/src/core/security/security_connector.h
@@ -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;
diff --git a/test/core/security/security_connector_test.c b/test/core/security/security_connector_test.c
index 0dcffa40ce..ed9f87dccc 100644
--- a/test/core/security/security_connector_test.c
+++ b/test/core/security/security_connector_test.c
@@ -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;