|
|
|
@ -69,12 +69,22 @@ grpc_security_status grpc_security_context_create_handshaker( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_security_status grpc_security_context_check_peer( |
|
|
|
|
grpc_security_context *ctx, const tsi_peer *peer, |
|
|
|
|
grpc_security_check_peer_cb cb, void *user_data) { |
|
|
|
|
if (ctx == NULL) return GRPC_SECURITY_ERROR; |
|
|
|
|
grpc_security_context *ctx, tsi_peer peer, grpc_security_check_cb cb, |
|
|
|
|
void *user_data) { |
|
|
|
|
if (ctx == NULL) { |
|
|
|
|
tsi_peer_destruct(&peer); |
|
|
|
|
return GRPC_SECURITY_ERROR; |
|
|
|
|
} |
|
|
|
|
return ctx->vtable->check_peer(ctx, peer, cb, user_data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_security_status grpc_channel_security_context_check_call_host( |
|
|
|
|
grpc_channel_security_context *ctx, const char *host, |
|
|
|
|
grpc_security_check_cb cb, void *user_data) { |
|
|
|
|
if (ctx == NULL || ctx->check_call_host == NULL) return GRPC_SECURITY_ERROR; |
|
|
|
|
return ctx->check_call_host(ctx, host, cb, user_data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void grpc_security_context_unref(grpc_security_context *ctx) { |
|
|
|
|
if (ctx == NULL) return; |
|
|
|
|
if (gpr_unref(&ctx->refcount)) ctx->vtable->destroy(ctx); |
|
|
|
@ -137,6 +147,11 @@ static int check_request_metadata_creds(grpc_credentials *creds) { |
|
|
|
|
|
|
|
|
|
/* -- Fake implementation. -- */ |
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
grpc_channel_security_context base; |
|
|
|
|
int call_host_check_is_async; |
|
|
|
|
} grpc_fake_channel_security_context; |
|
|
|
|
|
|
|
|
|
static void fake_channel_destroy(grpc_security_context *ctx) { |
|
|
|
|
grpc_channel_security_context *c = (grpc_channel_security_context *)ctx; |
|
|
|
|
grpc_credentials_unref(c->request_metadata_creds); |
|
|
|
@ -158,31 +173,51 @@ static grpc_security_status fake_server_create_handshaker( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_security_status fake_check_peer(grpc_security_context *ctx, |
|
|
|
|
const tsi_peer *peer, |
|
|
|
|
grpc_security_check_peer_cb cb, |
|
|
|
|
tsi_peer peer, |
|
|
|
|
grpc_security_check_cb cb, |
|
|
|
|
void *user_data) { |
|
|
|
|
const char *prop_name; |
|
|
|
|
if (peer->property_count != 1) { |
|
|
|
|
grpc_security_status status = GRPC_SECURITY_OK; |
|
|
|
|
if (peer.property_count != 1) { |
|
|
|
|
gpr_log(GPR_ERROR, "Fake peers should only have 1 property."); |
|
|
|
|
return GRPC_SECURITY_ERROR; |
|
|
|
|
status = GRPC_SECURITY_ERROR; |
|
|
|
|
goto end; |
|
|
|
|
} |
|
|
|
|
prop_name = peer->properties[0].name; |
|
|
|
|
prop_name = peer.properties[0].name; |
|
|
|
|
if (prop_name == NULL || |
|
|
|
|
strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) { |
|
|
|
|
gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.", |
|
|
|
|
prop_name == NULL ? "<EMPTY>" : prop_name); |
|
|
|
|
return GRPC_SECURITY_ERROR; |
|
|
|
|
status = GRPC_SECURITY_ERROR; |
|
|
|
|
goto end; |
|
|
|
|
} |
|
|
|
|
if (peer->properties[0].type != TSI_PEER_PROPERTY_TYPE_STRING) { |
|
|
|
|
if (peer.properties[0].type != TSI_PEER_PROPERTY_TYPE_STRING) { |
|
|
|
|
gpr_log(GPR_ERROR, "Invalid type of cert type property."); |
|
|
|
|
return GRPC_SECURITY_ERROR; |
|
|
|
|
status = GRPC_SECURITY_ERROR; |
|
|
|
|
goto end; |
|
|
|
|
} |
|
|
|
|
if (strncmp(peer->properties[0].value.string.data, TSI_FAKE_CERTIFICATE_TYPE, |
|
|
|
|
peer->properties[0].value.string.length)) { |
|
|
|
|
if (strncmp(peer.properties[0].value.string.data, TSI_FAKE_CERTIFICATE_TYPE, |
|
|
|
|
peer.properties[0].value.string.length)) { |
|
|
|
|
gpr_log(GPR_ERROR, "Invalid value for cert type property."); |
|
|
|
|
return GRPC_SECURITY_ERROR; |
|
|
|
|
status = GRPC_SECURITY_ERROR; |
|
|
|
|
goto end; |
|
|
|
|
} |
|
|
|
|
end: |
|
|
|
|
tsi_peer_destruct(&peer); |
|
|
|
|
return status; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_security_status fake_channel_check_call_host( |
|
|
|
|
grpc_channel_security_context *ctx, const char *host, |
|
|
|
|
grpc_security_check_cb cb, void *user_data) { |
|
|
|
|
grpc_fake_channel_security_context *c = |
|
|
|
|
(grpc_fake_channel_security_context *)ctx; |
|
|
|
|
if (c->call_host_check_is_async) { |
|
|
|
|
cb(user_data, GRPC_SECURITY_OK); |
|
|
|
|
return GRPC_SECURITY_PENDING; |
|
|
|
|
} else { |
|
|
|
|
return GRPC_SECURITY_OK; |
|
|
|
|
} |
|
|
|
|
return GRPC_SECURITY_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_security_context_vtable fake_channel_vtable = { |
|
|
|
@ -192,15 +227,17 @@ static grpc_security_context_vtable fake_server_vtable = { |
|
|
|
|
fake_server_destroy, fake_server_create_handshaker, fake_check_peer}; |
|
|
|
|
|
|
|
|
|
grpc_channel_security_context *grpc_fake_channel_security_context_create( |
|
|
|
|
grpc_credentials *request_metadata_creds) { |
|
|
|
|
grpc_channel_security_context *c = |
|
|
|
|
gpr_malloc(sizeof(grpc_channel_security_context)); |
|
|
|
|
gpr_ref_init(&c->base.refcount, 1); |
|
|
|
|
c->base.is_client_side = 1; |
|
|
|
|
c->base.vtable = &fake_channel_vtable; |
|
|
|
|
grpc_credentials *request_metadata_creds, int call_host_check_is_async) { |
|
|
|
|
grpc_fake_channel_security_context *c = |
|
|
|
|
gpr_malloc(sizeof(grpc_fake_channel_security_context)); |
|
|
|
|
gpr_ref_init(&c->base.base.refcount, 1); |
|
|
|
|
c->base.base.is_client_side = 1; |
|
|
|
|
c->base.base.vtable = &fake_channel_vtable; |
|
|
|
|
GPR_ASSERT(check_request_metadata_creds(request_metadata_creds)); |
|
|
|
|
c->request_metadata_creds = grpc_credentials_ref(request_metadata_creds); |
|
|
|
|
return c; |
|
|
|
|
c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds); |
|
|
|
|
c->base.check_call_host = fake_channel_check_call_host; |
|
|
|
|
c->call_host_check_is_async = call_host_check_is_async; |
|
|
|
|
return &c->base; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_security_context *grpc_fake_server_security_context_create(void) { |
|
|
|
@ -215,7 +252,9 @@ grpc_security_context *grpc_fake_server_security_context_create(void) { |
|
|
|
|
typedef struct { |
|
|
|
|
grpc_channel_security_context base; |
|
|
|
|
tsi_ssl_handshaker_factory *handshaker_factory; |
|
|
|
|
char *secure_peer_name; |
|
|
|
|
char *target_name; |
|
|
|
|
char *overridden_target_name; |
|
|
|
|
tsi_peer peer; |
|
|
|
|
} grpc_ssl_channel_security_context; |
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
@ -230,7 +269,9 @@ static void ssl_channel_destroy(grpc_security_context *ctx) { |
|
|
|
|
if (c->handshaker_factory != NULL) { |
|
|
|
|
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); |
|
|
|
|
} |
|
|
|
|
if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name); |
|
|
|
|
if (c->target_name != NULL) gpr_free(c->target_name); |
|
|
|
|
if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name); |
|
|
|
|
tsi_peer_destruct(&c->peer); |
|
|
|
|
gpr_free(ctx); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -244,11 +285,11 @@ static void ssl_server_destroy(grpc_security_context *ctx) { |
|
|
|
|
|
|
|
|
|
static grpc_security_status ssl_create_handshaker( |
|
|
|
|
tsi_ssl_handshaker_factory *handshaker_factory, int is_client, |
|
|
|
|
const char *secure_peer_name, tsi_handshaker **handshaker) { |
|
|
|
|
const char *peer_name, tsi_handshaker **handshaker) { |
|
|
|
|
tsi_result result = TSI_OK; |
|
|
|
|
if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR; |
|
|
|
|
result = tsi_ssl_handshaker_factory_create_handshaker( |
|
|
|
|
handshaker_factory, is_client ? secure_peer_name : NULL, handshaker); |
|
|
|
|
handshaker_factory, is_client ? peer_name : NULL, handshaker); |
|
|
|
|
if (result != TSI_OK) { |
|
|
|
|
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", |
|
|
|
|
tsi_result_to_string(result)); |
|
|
|
@ -261,7 +302,10 @@ static grpc_security_status ssl_channel_create_handshaker( |
|
|
|
|
grpc_security_context *ctx, tsi_handshaker **handshaker) { |
|
|
|
|
grpc_ssl_channel_security_context *c = |
|
|
|
|
(grpc_ssl_channel_security_context *)ctx; |
|
|
|
|
return ssl_create_handshaker(c->handshaker_factory, 1, c->secure_peer_name, |
|
|
|
|
return ssl_create_handshaker(c->handshaker_factory, 1, |
|
|
|
|
c->overridden_target_name != NULL |
|
|
|
|
? c->overridden_target_name |
|
|
|
|
: c->target_name, |
|
|
|
|
handshaker); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -271,7 +315,7 @@ static grpc_security_status ssl_server_create_handshaker( |
|
|
|
|
return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_security_status ssl_check_peer(const char *secure_peer_name, |
|
|
|
|
static grpc_security_status ssl_check_peer(const char *peer_name, |
|
|
|
|
const tsi_peer *peer) { |
|
|
|
|
/* Check the ALPN. */ |
|
|
|
|
const tsi_peer_property *p = |
|
|
|
@ -291,28 +335,54 @@ static grpc_security_status ssl_check_peer(const char *secure_peer_name, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Check the peer name if specified. */ |
|
|
|
|
if (secure_peer_name != NULL && |
|
|
|
|
!tsi_ssl_peer_matches_name(peer, secure_peer_name)) { |
|
|
|
|
gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", |
|
|
|
|
secure_peer_name); |
|
|
|
|
if (peer_name != NULL && |
|
|
|
|
!tsi_ssl_peer_matches_name(peer, peer_name)) { |
|
|
|
|
gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name); |
|
|
|
|
return GRPC_SECURITY_ERROR; |
|
|
|
|
} |
|
|
|
|
return GRPC_SECURITY_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_security_status ssl_channel_check_peer( |
|
|
|
|
grpc_security_context *ctx, const tsi_peer *peer, |
|
|
|
|
grpc_security_check_peer_cb cb, void *user_data) { |
|
|
|
|
static grpc_security_status ssl_channel_check_peer(grpc_security_context *ctx, |
|
|
|
|
tsi_peer peer, |
|
|
|
|
grpc_security_check_cb cb, |
|
|
|
|
void *user_data) { |
|
|
|
|
grpc_ssl_channel_security_context *c = |
|
|
|
|
(grpc_ssl_channel_security_context *)ctx; |
|
|
|
|
return ssl_check_peer(c->secure_peer_name, peer); |
|
|
|
|
grpc_security_status status = ssl_check_peer(c->overridden_target_name != NULL |
|
|
|
|
? c->overridden_target_name |
|
|
|
|
: c->target_name, |
|
|
|
|
&peer); |
|
|
|
|
c->peer = peer; |
|
|
|
|
return status; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_security_status ssl_server_check_peer(grpc_security_context *ctx, |
|
|
|
|
tsi_peer peer, |
|
|
|
|
grpc_security_check_cb cb, |
|
|
|
|
void *user_data) { |
|
|
|
|
/* TODO(jboeuf): Find a way to expose the peer to the authorization layer. */ |
|
|
|
|
grpc_security_status status = ssl_check_peer(NULL, &peer); |
|
|
|
|
tsi_peer_destruct(&peer); |
|
|
|
|
return status; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_security_status ssl_server_check_peer( |
|
|
|
|
grpc_security_context *ctx, const tsi_peer *peer, |
|
|
|
|
grpc_security_check_peer_cb cb, void *user_data) { |
|
|
|
|
/* TODO(jboeuf): Find a way to expose the peer to the authorization layer. */ |
|
|
|
|
return ssl_check_peer(NULL, peer); |
|
|
|
|
static grpc_security_status ssl_channel_check_call_host( |
|
|
|
|
grpc_channel_security_context *ctx, const char *host, |
|
|
|
|
grpc_security_check_cb cb, void *user_data) { |
|
|
|
|
grpc_ssl_channel_security_context *c = |
|
|
|
|
(grpc_ssl_channel_security_context *)ctx; |
|
|
|
|
|
|
|
|
|
if (tsi_ssl_peer_matches_name(&c->peer, host)) return GRPC_SECURITY_OK; |
|
|
|
|
|
|
|
|
|
/* If the target name was overridden, then the original target_name was
|
|
|
|
|
'checked' transitively during the previous peer check at the end of the |
|
|
|
|
handshake. */ |
|
|
|
|
if (c->overridden_target_name != NULL && !strcmp(host, c->target_name)) { |
|
|
|
|
return GRPC_SECURITY_OK; |
|
|
|
|
} else { |
|
|
|
|
return GRPC_SECURITY_ERROR; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_security_context_vtable ssl_channel_vtable = { |
|
|
|
@ -345,7 +415,8 @@ static size_t get_default_pem_roots(const unsigned char **pem_root_certs) { |
|
|
|
|
|
|
|
|
|
grpc_security_status grpc_ssl_channel_security_context_create( |
|
|
|
|
grpc_credentials *request_metadata_creds, const grpc_ssl_config *config, |
|
|
|
|
const char *secure_peer_name, grpc_channel_security_context **ctx) { |
|
|
|
|
const char *target_name, const char *overridden_target_name, |
|
|
|
|
grpc_channel_security_context **ctx) { |
|
|
|
|
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); |
|
|
|
|
const unsigned char **alpn_protocol_strings = |
|
|
|
|
gpr_malloc(sizeof(const char *) * num_alpn_protocols); |
|
|
|
@ -364,8 +435,8 @@ grpc_security_status grpc_ssl_channel_security_context_create( |
|
|
|
|
strlen(grpc_chttp2_get_alpn_version_index(i)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (config == NULL || secure_peer_name == NULL) { |
|
|
|
|
gpr_log(GPR_ERROR, "An ssl channel needs a config and a secure name."); |
|
|
|
|
if (config == NULL || target_name == NULL) { |
|
|
|
|
gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name."); |
|
|
|
|
goto error; |
|
|
|
|
} |
|
|
|
|
if (!check_request_metadata_creds(request_metadata_creds)) { |
|
|
|
@ -379,8 +450,12 @@ grpc_security_status grpc_ssl_channel_security_context_create( |
|
|
|
|
c->base.base.vtable = &ssl_channel_vtable; |
|
|
|
|
c->base.base.is_client_side = 1; |
|
|
|
|
c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds); |
|
|
|
|
if (secure_peer_name != NULL) { |
|
|
|
|
c->secure_peer_name = gpr_strdup(secure_peer_name); |
|
|
|
|
c->base.check_call_host = ssl_channel_check_call_host; |
|
|
|
|
if (target_name != NULL) { |
|
|
|
|
c->target_name = gpr_strdup(target_name); |
|
|
|
|
} |
|
|
|
|
if (overridden_target_name != NULL) { |
|
|
|
|
c->overridden_target_name = gpr_strdup(overridden_target_name); |
|
|
|
|
} |
|
|
|
|
if (config->pem_root_certs == NULL) { |
|
|
|
|
pem_root_certs_size = get_default_pem_roots(&pem_root_certs); |
|
|
|
@ -478,7 +553,7 @@ grpc_channel *grpc_ssl_channel_create(grpc_credentials *ssl_creds, |
|
|
|
|
grpc_channel *channel = NULL; |
|
|
|
|
grpc_security_status status = GRPC_SECURITY_OK; |
|
|
|
|
size_t i = 0; |
|
|
|
|
const char *secure_peer_name = target; |
|
|
|
|
const char *overridden_target_name = NULL; |
|
|
|
|
grpc_arg arg; |
|
|
|
|
grpc_channel_args *new_args; |
|
|
|
|
|
|
|
|
@ -486,13 +561,13 @@ grpc_channel *grpc_ssl_channel_create(grpc_credentials *ssl_creds, |
|
|
|
|
grpc_arg *arg = &args->args[i]; |
|
|
|
|
if (!strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) && |
|
|
|
|
arg->type == GRPC_ARG_STRING) { |
|
|
|
|
secure_peer_name = arg->value.string; |
|
|
|
|
overridden_target_name = arg->value.string; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
status = grpc_ssl_channel_security_context_create( |
|
|
|
|
request_metadata_creds, grpc_ssl_credentials_get_config(ssl_creds), |
|
|
|
|
secure_peer_name, &ctx); |
|
|
|
|
target, overridden_target_name, &ctx); |
|
|
|
|
if (status != GRPC_SECURITY_OK) { |
|
|
|
|
return grpc_lame_client_channel_create(); |
|
|
|
|
} |
|
|
|
@ -510,7 +585,7 @@ grpc_channel *grpc_fake_transport_security_channel_create( |
|
|
|
|
grpc_credentials *fake_creds, grpc_credentials *request_metadata_creds, |
|
|
|
|
const char *target, const grpc_channel_args *args) { |
|
|
|
|
grpc_channel_security_context *ctx = |
|
|
|
|
grpc_fake_channel_security_context_create(request_metadata_creds); |
|
|
|
|
grpc_fake_channel_security_context_create(request_metadata_creds, 1); |
|
|
|
|
grpc_channel *channel = |
|
|
|
|
grpc_secure_channel_create_internal(target, args, ctx); |
|
|
|
|
grpc_security_context_unref(&ctx->base); |
|
|
|
|