|
|
|
@ -34,6 +34,7 @@ |
|
|
|
|
#include "src/core/lib/security/context/security_context.h" |
|
|
|
|
#include "src/core/lib/security/credentials/credentials.h" |
|
|
|
|
#include "src/core/lib/security/credentials/fake/fake_credentials.h" |
|
|
|
|
#include "src/core/lib/security/credentials/ssl/ssl_credentials.h" |
|
|
|
|
#include "src/core/lib/security/transport/lb_targets_info.h" |
|
|
|
|
#include "src/core/lib/security/transport/secure_endpoint.h" |
|
|
|
|
#include "src/core/lib/security/transport/security_handshaker.h" |
|
|
|
@ -277,6 +278,30 @@ grpc_security_connector *grpc_security_connector_find_in_args( |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static tsi_client_certificate_request_type |
|
|
|
|
get_tsi_client_certificate_request_type( |
|
|
|
|
grpc_ssl_client_certificate_request_type grpc_request_type) { |
|
|
|
|
switch (grpc_request_type) { |
|
|
|
|
case GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE: |
|
|
|
|
return TSI_DONT_REQUEST_CLIENT_CERTIFICATE; |
|
|
|
|
|
|
|
|
|
case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: |
|
|
|
|
return TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY; |
|
|
|
|
|
|
|
|
|
case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY: |
|
|
|
|
return TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY; |
|
|
|
|
|
|
|
|
|
case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: |
|
|
|
|
return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY; |
|
|
|
|
|
|
|
|
|
case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY: |
|
|
|
|
return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY; |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
return TSI_DONT_REQUEST_CLIENT_CERTIFICATE; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* -- Fake implementation. -- */ |
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
@ -533,6 +558,15 @@ typedef struct { |
|
|
|
|
tsi_ssl_server_handshaker_factory *server_handshaker_factory; |
|
|
|
|
} grpc_ssl_server_security_connector; |
|
|
|
|
|
|
|
|
|
static bool server_connector_has_cert_config_fetcher( |
|
|
|
|
grpc_ssl_server_security_connector *c) { |
|
|
|
|
GPR_ASSERT(c != NULL); |
|
|
|
|
grpc_ssl_server_credentials *server_creds = |
|
|
|
|
(grpc_ssl_server_credentials *)c->base.server_creds; |
|
|
|
|
GPR_ASSERT(server_creds != NULL); |
|
|
|
|
return server_creds->certificate_config_fetcher.cb != NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_security_connector *sc) { |
|
|
|
|
grpc_ssl_channel_security_connector *c = |
|
|
|
@ -573,7 +607,6 @@ static void ssl_channel_add_handshakers(grpc_exec_ctx *exec_ctx, |
|
|
|
|
tsi_result_to_string(result)); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Create handshakers.
|
|
|
|
|
grpc_handshake_manager_add( |
|
|
|
|
handshake_mgr, |
|
|
|
@ -581,12 +614,102 @@ static void ssl_channel_add_handshakers(grpc_exec_ctx *exec_ctx, |
|
|
|
|
exec_ctx, tsi_create_adapter_handshaker(tsi_hs), &sc->base)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static const char **fill_alpn_protocol_strings(size_t *num_alpn_protocols) { |
|
|
|
|
GPR_ASSERT(num_alpn_protocols != NULL); |
|
|
|
|
*num_alpn_protocols = grpc_chttp2_num_alpn_versions(); |
|
|
|
|
const char **alpn_protocol_strings = |
|
|
|
|
(const char **)gpr_malloc(sizeof(const char *) * (*num_alpn_protocols)); |
|
|
|
|
for (size_t i = 0; i < *num_alpn_protocols; i++) { |
|
|
|
|
alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i); |
|
|
|
|
} |
|
|
|
|
return alpn_protocol_strings; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Attempts to replace the server_handshaker_factory with a new factory using
|
|
|
|
|
* the provided grpc_ssl_server_certificate_config. Should new factory creation |
|
|
|
|
* fail, the existing factory will not be replaced. Returns true on success (new |
|
|
|
|
* factory created). */ |
|
|
|
|
static bool try_replace_server_handshaker_factory( |
|
|
|
|
grpc_ssl_server_security_connector *sc, |
|
|
|
|
const grpc_ssl_server_certificate_config *config) { |
|
|
|
|
if (config == NULL) { |
|
|
|
|
gpr_log(GPR_ERROR, |
|
|
|
|
"Server certificate config callback returned invalid (NULL) " |
|
|
|
|
"config."); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
gpr_log(GPR_DEBUG, "Using new server certificate config (%p).", config); |
|
|
|
|
|
|
|
|
|
size_t num_alpn_protocols = 0; |
|
|
|
|
const char **alpn_protocol_strings = |
|
|
|
|
fill_alpn_protocol_strings(&num_alpn_protocols); |
|
|
|
|
tsi_ssl_pem_key_cert_pair *cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs( |
|
|
|
|
config->pem_key_cert_pairs, config->num_key_cert_pairs); |
|
|
|
|
tsi_ssl_server_handshaker_factory *new_handshaker_factory = NULL; |
|
|
|
|
grpc_ssl_server_credentials *server_creds = |
|
|
|
|
(grpc_ssl_server_credentials *)sc->base.server_creds; |
|
|
|
|
tsi_result result = tsi_create_ssl_server_handshaker_factory_ex( |
|
|
|
|
cert_pairs, config->num_key_cert_pairs, config->pem_root_certs, |
|
|
|
|
get_tsi_client_certificate_request_type( |
|
|
|
|
server_creds->config.client_certificate_request), |
|
|
|
|
ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols, |
|
|
|
|
&new_handshaker_factory); |
|
|
|
|
gpr_free(cert_pairs); |
|
|
|
|
gpr_free((void *)alpn_protocol_strings); |
|
|
|
|
|
|
|
|
|
if (result != TSI_OK) { |
|
|
|
|
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", |
|
|
|
|
tsi_result_to_string(result)); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
tsi_ssl_server_handshaker_factory_unref(sc->server_handshaker_factory); |
|
|
|
|
sc->server_handshaker_factory = new_handshaker_factory; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Attempts to fetch the server certificate config if a callback is available.
|
|
|
|
|
* Current certificate config will continue to be used if the callback returns |
|
|
|
|
* an error. Returns true if new credentials were sucessfully loaded. */ |
|
|
|
|
static bool try_fetch_ssl_server_credentials( |
|
|
|
|
grpc_ssl_server_security_connector *sc) { |
|
|
|
|
grpc_ssl_server_certificate_config *certificate_config = NULL; |
|
|
|
|
bool status; |
|
|
|
|
|
|
|
|
|
GPR_ASSERT(sc != NULL); |
|
|
|
|
if (!server_connector_has_cert_config_fetcher(sc)) return false; |
|
|
|
|
|
|
|
|
|
grpc_ssl_server_credentials *server_creds = |
|
|
|
|
(grpc_ssl_server_credentials *)sc->base.server_creds; |
|
|
|
|
grpc_ssl_certificate_config_reload_status cb_result = |
|
|
|
|
server_creds->certificate_config_fetcher.cb( |
|
|
|
|
server_creds->certificate_config_fetcher.user_data, |
|
|
|
|
&certificate_config); |
|
|
|
|
if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED) { |
|
|
|
|
gpr_log(GPR_DEBUG, "No change in SSL server credentials."); |
|
|
|
|
status = false; |
|
|
|
|
} else if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW) { |
|
|
|
|
status = try_replace_server_handshaker_factory(sc, certificate_config); |
|
|
|
|
} else { |
|
|
|
|
// Log error, continue using previously-loaded credentials.
|
|
|
|
|
gpr_log(GPR_ERROR, |
|
|
|
|
"Failed fetching new server credentials, continuing to " |
|
|
|
|
"use previously-loaded credentials."); |
|
|
|
|
status = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (certificate_config != NULL) { |
|
|
|
|
grpc_ssl_server_certificate_config_destroy(certificate_config); |
|
|
|
|
} |
|
|
|
|
return status; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void ssl_server_add_handshakers(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_server_security_connector *sc, |
|
|
|
|
grpc_handshake_manager *handshake_mgr) { |
|
|
|
|
grpc_ssl_server_security_connector *c = |
|
|
|
|
(grpc_ssl_server_security_connector *)sc; |
|
|
|
|
// Instantiate TSI handshaker.
|
|
|
|
|
try_fetch_ssl_server_credentials(c); |
|
|
|
|
tsi_handshaker *tsi_hs = NULL; |
|
|
|
|
tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker( |
|
|
|
|
c->server_handshaker_factory, &tsi_hs); |
|
|
|
@ -595,7 +718,6 @@ static void ssl_server_add_handshakers(grpc_exec_ctx *exec_ctx, |
|
|
|
|
tsi_result_to_string(result)); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Create handshakers.
|
|
|
|
|
grpc_handshake_manager_add( |
|
|
|
|
handshake_mgr, |
|
|
|
@ -857,31 +979,6 @@ grpc_slice grpc_get_default_ssl_roots_for_testing(void) { |
|
|
|
|
return compute_default_pem_root_certs_once(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static tsi_client_certificate_request_type |
|
|
|
|
get_tsi_client_certificate_request_type( |
|
|
|
|
grpc_ssl_client_certificate_request_type grpc_request_type) { |
|
|
|
|
switch (grpc_request_type) { |
|
|
|
|
case GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE: |
|
|
|
|
return TSI_DONT_REQUEST_CLIENT_CERTIFICATE; |
|
|
|
|
|
|
|
|
|
case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: |
|
|
|
|
return TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY; |
|
|
|
|
|
|
|
|
|
case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY: |
|
|
|
|
return TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY; |
|
|
|
|
|
|
|
|
|
case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: |
|
|
|
|
return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY; |
|
|
|
|
|
|
|
|
|
case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY: |
|
|
|
|
return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY; |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
// Is this a sane default
|
|
|
|
|
return TSI_DONT_REQUEST_CLIENT_CERTIFICATE; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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. */ |
|
|
|
@ -897,18 +994,14 @@ grpc_security_status grpc_ssl_channel_security_connector_create( |
|
|
|
|
grpc_call_credentials *request_metadata_creds, |
|
|
|
|
const grpc_ssl_config *config, const char *target_name, |
|
|
|
|
const char *overridden_target_name, grpc_channel_security_connector **sc) { |
|
|
|
|
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); |
|
|
|
|
size_t num_alpn_protocols = 0; |
|
|
|
|
const char **alpn_protocol_strings = |
|
|
|
|
(const char **)gpr_malloc(sizeof(const char *) * num_alpn_protocols); |
|
|
|
|
fill_alpn_protocol_strings(&num_alpn_protocols); |
|
|
|
|
tsi_result result = TSI_OK; |
|
|
|
|
grpc_ssl_channel_security_connector *c; |
|
|
|
|
size_t i; |
|
|
|
|
const char *pem_root_certs; |
|
|
|
|
char *port; |
|
|
|
|
bool has_key_cert_pair; |
|
|
|
|
for (i = 0; i < num_alpn_protocols; i++) { |
|
|
|
|
alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (config == NULL || target_name == NULL) { |
|
|
|
|
gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name."); |
|
|
|
@ -965,50 +1058,64 @@ error: |
|
|
|
|
return GRPC_SECURITY_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_ssl_server_security_connector * |
|
|
|
|
grpc_ssl_server_security_connector_initialize( |
|
|
|
|
grpc_server_credentials *server_creds) { |
|
|
|
|
grpc_ssl_server_security_connector *c = |
|
|
|
|
(grpc_ssl_server_security_connector *)gpr_zalloc( |
|
|
|
|
sizeof(grpc_ssl_server_security_connector)); |
|
|
|
|
gpr_ref_init(&c->base.base.refcount, 1); |
|
|
|
|
c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; |
|
|
|
|
c->base.base.vtable = &ssl_server_vtable; |
|
|
|
|
c->base.add_handshakers = ssl_server_add_handshakers; |
|
|
|
|
c->base.server_creds = grpc_server_credentials_ref(server_creds); |
|
|
|
|
return c; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_security_status grpc_ssl_server_security_connector_create( |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_creds, |
|
|
|
|
const grpc_ssl_server_config *config, grpc_server_security_connector **sc) { |
|
|
|
|
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); |
|
|
|
|
const char **alpn_protocol_strings = |
|
|
|
|
(const char **)gpr_malloc(sizeof(const char *) * num_alpn_protocols); |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_server_credentials *gsc, |
|
|
|
|
grpc_server_security_connector **sc) { |
|
|
|
|
tsi_result result = TSI_OK; |
|
|
|
|
grpc_ssl_server_security_connector *c; |
|
|
|
|
size_t i; |
|
|
|
|
grpc_ssl_server_credentials *server_credentials = |
|
|
|
|
(grpc_ssl_server_credentials *)gsc; |
|
|
|
|
grpc_security_status retval = GRPC_SECURITY_OK; |
|
|
|
|
|
|
|
|
|
for (i = 0; i < num_alpn_protocols; i++) { |
|
|
|
|
alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i); |
|
|
|
|
} |
|
|
|
|
GPR_ASSERT(server_credentials != NULL); |
|
|
|
|
GPR_ASSERT(sc != NULL); |
|
|
|
|
|
|
|
|
|
if (config == NULL || config->num_key_cert_pairs == 0) { |
|
|
|
|
gpr_log(GPR_ERROR, "An SSL server needs a key and a cert."); |
|
|
|
|
goto error; |
|
|
|
|
grpc_ssl_server_security_connector *c = |
|
|
|
|
grpc_ssl_server_security_connector_initialize(gsc); |
|
|
|
|
if (server_connector_has_cert_config_fetcher(c)) { |
|
|
|
|
// Load initial credentials from certificate_config_fetcher:
|
|
|
|
|
if (!try_fetch_ssl_server_credentials(c)) { |
|
|
|
|
gpr_log(GPR_ERROR, "Failed loading SSL server credentials from fetcher."); |
|
|
|
|
retval = GRPC_SECURITY_ERROR; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
size_t num_alpn_protocols = 0; |
|
|
|
|
const char **alpn_protocol_strings = |
|
|
|
|
fill_alpn_protocol_strings(&num_alpn_protocols); |
|
|
|
|
result = tsi_create_ssl_server_handshaker_factory_ex( |
|
|
|
|
server_credentials->config.pem_key_cert_pairs, |
|
|
|
|
server_credentials->config.num_key_cert_pairs, |
|
|
|
|
server_credentials->config.pem_root_certs, |
|
|
|
|
get_tsi_client_certificate_request_type( |
|
|
|
|
server_credentials->config.client_certificate_request), |
|
|
|
|
ssl_cipher_suites(), alpn_protocol_strings, |
|
|
|
|
(uint16_t)num_alpn_protocols, &c->server_handshaker_factory); |
|
|
|
|
gpr_free((void *)alpn_protocol_strings); |
|
|
|
|
if (result != TSI_OK) { |
|
|
|
|
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", |
|
|
|
|
tsi_result_to_string(result)); |
|
|
|
|
retval = GRPC_SECURITY_ERROR; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
c = (grpc_ssl_server_security_connector *)gpr_zalloc( |
|
|
|
|
sizeof(grpc_ssl_server_security_connector)); |
|
|
|
|
|
|
|
|
|
gpr_ref_init(&c->base.base.refcount, 1); |
|
|
|
|
c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; |
|
|
|
|
c->base.base.vtable = &ssl_server_vtable; |
|
|
|
|
c->base.server_creds = grpc_server_credentials_ref(server_creds); |
|
|
|
|
result = tsi_create_ssl_server_handshaker_factory_ex( |
|
|
|
|
config->pem_key_cert_pairs, config->num_key_cert_pairs, |
|
|
|
|
config->pem_root_certs, get_tsi_client_certificate_request_type( |
|
|
|
|
config->client_certificate_request), |
|
|
|
|
ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols, |
|
|
|
|
&c->server_handshaker_factory); |
|
|
|
|
if (result != TSI_OK) { |
|
|
|
|
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", |
|
|
|
|
tsi_result_to_string(result)); |
|
|
|
|
ssl_server_destroy(exec_ctx, &c->base.base); |
|
|
|
|
*sc = NULL; |
|
|
|
|
goto error; |
|
|
|
|
if (retval == GRPC_SECURITY_OK) { |
|
|
|
|
*sc = &c->base; |
|
|
|
|
} else { |
|
|
|
|
if (c != NULL) ssl_server_destroy(exec_ctx, &c->base.base); |
|
|
|
|
if (sc != NULL) *sc = NULL; |
|
|
|
|
} |
|
|
|
|
c->base.add_handshakers = ssl_server_add_handshakers; |
|
|
|
|
*sc = &c->base; |
|
|
|
|
gpr_free((void *)alpn_protocol_strings); |
|
|
|
|
return GRPC_SECURITY_OK; |
|
|
|
|
|
|
|
|
|
error: |
|
|
|
|
gpr_free((void *)alpn_protocol_strings); |
|
|
|
|
return GRPC_SECURITY_ERROR; |
|
|
|
|
return retval; |
|
|
|
|
} |
|
|
|
|