diff options
Diffstat (limited to 'src/core/security')
-rw-r--r-- | src/core/security/auth.c | 2 | ||||
-rw-r--r-- | src/core/security/credentials.c | 235 | ||||
-rw-r--r-- | src/core/security/credentials.h | 14 | ||||
-rw-r--r-- | src/core/security/security_context.c | 71 | ||||
-rw-r--r-- | src/core/security/security_context.h | 11 | ||||
-rw-r--r-- | src/core/security/server_secure_chttp2.c | 2 |
6 files changed, 298 insertions, 37 deletions
diff --git a/src/core/security/auth.c b/src/core/security/auth.c index 6480dd2239..9ce0c69d96 100644 --- a/src/core/security/auth.c +++ b/src/core/security/auth.c @@ -75,7 +75,7 @@ static void call_op(grpc_call_element *elem, grpc_call_op *op) { switch (op->type) { case GRPC_SEND_START: { grpc_credentials *channel_creds = - channeld->security_context->request_metadata_only_creds; + channeld->security_context->request_metadata_creds; /* TODO(jboeuf): Decide on the policy in this case: - populate both channel and call? diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index 969a97369c..7ff48f9123 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -47,12 +47,10 @@ #include <stdio.h> /* -- Constants. -- */ - #define GRPC_COMPUTE_ENGINE_TOKEN_REFRESH_THRESHOLD_SECS 60 #define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata" #define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \ "computeMetadata/v1/instance/service-accounts/default/token" -#define GRPC_AUTHORIZATION_METADATA_KEY "Authorization" /* -- Common. -- */ @@ -108,7 +106,13 @@ int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) { void grpc_credentials_get_request_metadata(grpc_credentials *creds, grpc_credentials_metadata_cb cb, void *user_data) { - if (creds == NULL || !grpc_credentials_has_request_metadata(creds)) return; + if (creds == NULL || !grpc_credentials_has_request_metadata(creds) || + creds->vtable->get_request_metadata == NULL) { + if (cb != NULL) { + cb(user_data, NULL, 0, GRPC_CREDENTIALS_OK); + } + return; + } creds->vtable->get_request_metadata(creds, cb, user_data); } @@ -521,14 +525,235 @@ grpc_fake_transport_security_server_credentials_create() { return c; } +/* -- Composite credentials. -- */ + +typedef struct { + grpc_credentials base; + grpc_credentials_array inner; +} grpc_composite_credentials; + +typedef struct { + grpc_composite_credentials *composite_creds; + size_t creds_index; + grpc_mdelem **md_elems; + size_t num_md; + void *user_data; + grpc_credentials_metadata_cb cb; +} grpc_composite_credentials_metadata_context; + +static void composite_destroy(grpc_credentials *creds) { + grpc_composite_credentials *c = (grpc_composite_credentials *)creds; + size_t i; + for (i = 0; i < c->inner.num_creds; i++) { + grpc_credentials_unref(c->inner.creds_array[i]); + } + gpr_free(c->inner.creds_array); + gpr_free(creds); +} + +static int composite_has_request_metadata(const grpc_credentials *creds) { + const grpc_composite_credentials *c = + (const grpc_composite_credentials *)creds; + size_t i; + for (i = 0; i < c->inner.num_creds; i++) { + if (grpc_credentials_has_request_metadata(c->inner.creds_array[i])) { + return 1; + } + } + return 0; +} + +static int composite_has_request_metadata_only(const grpc_credentials *creds) { + const grpc_composite_credentials *c = + (const grpc_composite_credentials *)creds; + size_t i; + for (i = 0; i < c->inner.num_creds; i++) { + if (!grpc_credentials_has_request_metadata_only(c->inner.creds_array[i])) { + return 0; + } + } + return 1; +} + +static void composite_md_context_destroy( + grpc_composite_credentials_metadata_context *ctx) { + size_t i; + for (i = 0; i < ctx->num_md; i++) { + grpc_mdelem_unref(ctx->md_elems[i]); + } + gpr_free(ctx->md_elems); + gpr_free(ctx); +} + +static void composite_metadata_cb(void *user_data, grpc_mdelem **md_elems, + size_t num_md, + grpc_credentials_status status) { + grpc_composite_credentials_metadata_context *ctx = + (grpc_composite_credentials_metadata_context *)user_data; + size_t i; + if (status != GRPC_CREDENTIALS_OK) { + ctx->cb(ctx->user_data, NULL, 0, status); + return; + } + + /* Copy the metadata in the context. */ + if (num_md > 0) { + ctx->md_elems = gpr_realloc(ctx->md_elems, + (ctx->num_md + num_md) * sizeof(grpc_mdelem *)); + for (i = 0; i < num_md; i++) { + ctx->md_elems[i + ctx->num_md] = grpc_mdelem_ref(md_elems[i]); + } + ctx->num_md += num_md; + } + + /* See if we need to get some more metadata. */ + while (ctx->creds_index < ctx->composite_creds->inner.num_creds) { + grpc_credentials *inner_creds = + ctx->composite_creds->inner.creds_array[ctx->creds_index++]; + if (grpc_credentials_has_request_metadata(inner_creds)) { + grpc_credentials_get_request_metadata(inner_creds, composite_metadata_cb, + ctx); + return; + } + } + + /* We're done!. */ + ctx->cb(ctx->user_data, ctx->md_elems, ctx->num_md, GRPC_CREDENTIALS_OK); + composite_md_context_destroy(ctx); +} + +static void composite_get_request_metadata(grpc_credentials *creds, + grpc_credentials_metadata_cb cb, + void *user_data) { + grpc_composite_credentials *c = (grpc_composite_credentials *)creds; + grpc_composite_credentials_metadata_context *ctx; + if (!grpc_credentials_has_request_metadata(creds)) { + cb(user_data, NULL, 0, GRPC_CREDENTIALS_OK); + return; + } + ctx = gpr_malloc(sizeof(grpc_composite_credentials_metadata_context)); + memset(ctx, 0, sizeof(grpc_composite_credentials_metadata_context)); + ctx->user_data = user_data; + ctx->cb = cb; + ctx->composite_creds = c; + while (ctx->creds_index < c->inner.num_creds) { + grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++]; + if (grpc_credentials_has_request_metadata(inner_creds)) { + grpc_credentials_get_request_metadata(inner_creds, composite_metadata_cb, + ctx); + return; + } + } + GPR_ASSERT(0); /* Should have exited before. */ +} -/* -- Composite credentials TODO(jboeuf). -- */ +static grpc_credentials_vtable composite_credentials_vtable = { + composite_destroy, composite_has_request_metadata, + composite_has_request_metadata_only, composite_get_request_metadata}; + +static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) { + grpc_credentials_array result; + grpc_credentials *creds = *creds_addr; + result.creds_array = creds_addr; + result.num_creds = 1; + if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE)) { + result = *grpc_composite_credentials_get_credentials(creds); + } + return result; +} grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1, grpc_credentials *creds2) { - return NULL; + size_t i; + grpc_credentials_array creds1_array; + grpc_credentials_array creds2_array; + grpc_composite_credentials *c; + GPR_ASSERT(creds1 != NULL); + GPR_ASSERT(creds2 != NULL); + c = gpr_malloc(sizeof(grpc_composite_credentials)); + memset(c, 0, sizeof(grpc_composite_credentials)); + c->base.type = GRPC_CREDENTIALS_TYPE_COMPOSITE; + c->base.vtable = &composite_credentials_vtable; + gpr_ref_init(&c->base.refcount, 1); + creds1_array = get_creds_array(&creds1); + creds2_array = get_creds_array(&creds2); + c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds; + c->inner.creds_array = + gpr_malloc(c->inner.num_creds * sizeof(grpc_credentials *)); + for (i = 0; i < creds1_array.num_creds; i++) { + c->inner.creds_array[i] = grpc_credentials_ref(creds1_array.creds_array[i]); + } + for (i = 0; i < creds2_array.num_creds; i++) { + c->inner.creds_array[i + creds1_array.num_creds] = + grpc_credentials_ref(creds2_array.creds_array[i]); + } + return &c->base; +} + +const grpc_credentials_array *grpc_composite_credentials_get_credentials( + grpc_credentials *creds) { + const grpc_composite_credentials *c = + (const grpc_composite_credentials *)creds; + GPR_ASSERT(!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE)); + return &c->inner; +} + +/* -- IAM credentials. -- */ + +typedef struct { + grpc_credentials base; + grpc_mdctx *md_ctx; + grpc_mdelem *token_md; + grpc_mdelem *authority_selector_md; +} grpc_iam_credentials; + +static void iam_destroy(grpc_credentials *creds) { + grpc_iam_credentials *c = (grpc_iam_credentials *)creds; + grpc_mdelem_unref(c->token_md); + grpc_mdelem_unref(c->authority_selector_md); + grpc_mdctx_orphan(c->md_ctx); + gpr_free(c); +} + +static int iam_has_request_metadata(const grpc_credentials *creds) { return 1; } + +static int iam_has_request_metadata_only(const grpc_credentials *creds) { + return 1; +} + +static void iam_get_request_metadata(grpc_credentials *creds, + grpc_credentials_metadata_cb cb, + void *user_data) { + grpc_iam_credentials *c = (grpc_iam_credentials *)creds; + grpc_mdelem *md_array[2]; + md_array[0] = c->token_md; + md_array[1] = c->authority_selector_md; + cb(user_data, md_array, 2, GRPC_CREDENTIALS_OK); +} + +static grpc_credentials_vtable iam_vtable = { + iam_destroy, iam_has_request_metadata, iam_has_request_metadata_only, + iam_get_request_metadata}; + +grpc_credentials *grpc_iam_credentials_create(const char *token, + const char *authority_selector) { + grpc_iam_credentials *c; + GPR_ASSERT(token != NULL); + GPR_ASSERT(authority_selector != NULL); + c = gpr_malloc(sizeof(grpc_iam_credentials)); + memset(c, 0, sizeof(grpc_iam_credentials)); + c->base.type = GRPC_CREDENTIALS_TYPE_IAM; + c->base.vtable = &iam_vtable; + gpr_ref_init(&c->base.refcount, 1); + c->md_ctx = grpc_mdctx_create(); + c->token_md = grpc_mdelem_from_strings( + c->md_ctx, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token); + c->authority_selector_md = grpc_mdelem_from_strings( + c->md_ctx, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector); + return &c->base; } /* -- Default credentials TODO(jboeuf). -- */ grpc_credentials *grpc_default_credentials_create(void) { return NULL; } + diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index 1432611ec6..9fb82e1ecd 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -50,9 +50,15 @@ typedef enum { #define GRPC_CREDENTIALS_TYPE_SSL "Ssl" #define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2" +#define GRPC_CREDENTIALS_TYPE_IAM "Iam" #define GRPC_CREDENTIALS_TYPE_COMPOSITE "Composite" #define GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY "FakeTransportSecurity" +#define GRPC_AUTHORIZATION_METADATA_KEY "Authorization" +#define GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY \ + "x-goog-iam-authorization-token" +#define GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY "x-goog-iam-authority-selector" + /* --- grpc_credentials. --- */ typedef void (*grpc_credentials_metadata_cb)(void *user_data, @@ -94,6 +100,14 @@ typedef struct { const grpc_ssl_config *grpc_ssl_credentials_get_config( const grpc_credentials *ssl_creds); +typedef struct { + grpc_credentials **creds_array; + size_t num_creds; +} grpc_credentials_array; + +const grpc_credentials_array *grpc_composite_credentials_get_credentials( + grpc_credentials *composite_creds); + /* Exposed for testing only. */ grpc_credentials_status grpc_compute_engine_credentials_parse_server_response( const struct grpc_httpcli_response *response, grpc_mdctx *ctx, diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index beda64cba2..c56692ae83 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -37,6 +37,8 @@ #include "src/core/endpoint/secure_endpoint.h" #include "src/core/security/credentials.h" +#include "src/core/surface/lame_client.h" +#include "src/core/transport/chttp2/alpn.h" #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <grpc/support/slice_buffer.h> @@ -47,7 +49,6 @@ /* -- Constants. -- */ -#define GRPC_ALPN_PROTOCOL_STRING "h2-15" /* Defines the cipher suites that we accept. All these cipher suites are compliant with TLS 1.2 and use an RSA public key. We prefer GCM over CBC and ECDHE-RSA over just RSA. */ @@ -122,11 +123,11 @@ grpc_security_context *grpc_find_security_context_in_args( return NULL; } -static int check_request_metadata_only_creds(grpc_credentials *creds) { - if (creds != NULL && !grpc_credentials_has_request_metadata_only(creds)) { +static int check_request_metadata_creds(grpc_credentials *creds) { + if (creds != NULL && !grpc_credentials_has_request_metadata(creds)) { gpr_log(GPR_ERROR, "Incompatible credentials for channel security context: needs to " - "only set request metadata."); + "set request metadata."); return 0; } return 1; @@ -136,7 +137,7 @@ static int check_request_metadata_only_creds(grpc_credentials *creds) { 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_only_creds); + grpc_credentials_unref(c->request_metadata_creds); gpr_free(ctx); } @@ -191,15 +192,14 @@ 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_only_creds) { + 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; - GPR_ASSERT(check_request_metadata_only_creds(request_metadata_only_creds)); - c->request_metadata_only_creds = - grpc_credentials_ref(request_metadata_only_creds); + GPR_ASSERT(check_request_metadata_creds(request_metadata_creds)); + c->request_metadata_creds = grpc_credentials_ref(request_metadata_creds); return c; } @@ -226,7 +226,7 @@ typedef struct { static void ssl_channel_destroy(grpc_security_context *ctx) { grpc_ssl_channel_security_context *c = (grpc_ssl_channel_security_context *)ctx; - grpc_credentials_unref(c->base.request_metadata_only_creds); + grpc_credentials_unref(c->base.request_metadata_creds); if (c->handshaker_factory != NULL) { tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); } @@ -282,8 +282,8 @@ static grpc_security_status ssl_check_peer(const char *secure_peer_name, gpr_log(GPR_ERROR, "Invalid or missing selected ALPN property."); return GRPC_SECURITY_ERROR; } - if (strncmp(GRPC_ALPN_PROTOCOL_STRING, p->value.string.data, - p->value.string.length)) { + if (!grpc_chttp2_is_alpn_version_supported(p->value.string.data, + p->value.string.length)) { gpr_log(GPR_ERROR, "Invalid ALPN value."); return GRPC_SECURITY_ERROR; } @@ -320,10 +320,9 @@ static grpc_security_context_vtable ssl_server_vtable = { ssl_server_destroy, ssl_server_create_handshaker, ssl_server_check_peer}; grpc_security_status grpc_ssl_channel_security_context_create( - grpc_credentials *request_metadata_only_creds, - const grpc_ssl_config *config, const char *secure_peer_name, - grpc_channel_security_context **ctx) { - const char *alpn_protocol_string = GRPC_ALPN_PROTOCOL_STRING; + grpc_credentials *request_metadata_creds, const grpc_ssl_config *config, + const char *secure_peer_name, grpc_channel_security_context **ctx) { + const char *alpn_protocol_string = GRPC_CHTTP2_ALPN_VERSION; unsigned char alpn_protocol_string_len = (unsigned char)strlen(alpn_protocol_string); tsi_result result = TSI_OK; @@ -334,7 +333,7 @@ grpc_security_status grpc_ssl_channel_security_context_create( gpr_log(GPR_ERROR, "An ssl channel needs a secure name and root certs."); return GRPC_SECURITY_ERROR; } - if (!check_request_metadata_only_creds(request_metadata_only_creds)) { + if (!check_request_metadata_creds(request_metadata_creds)) { return GRPC_SECURITY_ERROR; } @@ -344,8 +343,7 @@ grpc_security_status grpc_ssl_channel_security_context_create( gpr_ref_init(&c->base.base.refcount, 1); c->base.base.vtable = &ssl_channel_vtable; c->base.base.is_client_side = 1; - c->base.request_metadata_only_creds = - grpc_credentials_ref(request_metadata_only_creds); + 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); } @@ -368,7 +366,7 @@ grpc_security_status grpc_ssl_channel_security_context_create( grpc_security_status grpc_ssl_server_security_context_create( const grpc_ssl_config *config, grpc_security_context **ctx) { - const char *alpn_protocol_string = GRPC_ALPN_PROTOCOL_STRING; + const char *alpn_protocol_string = GRPC_CHTTP2_ALPN_VERSION; unsigned char alpn_protocol_string_len = (unsigned char)strlen(alpn_protocol_string); tsi_result result = TSI_OK; @@ -427,7 +425,7 @@ static grpc_channel *grpc_ssl_channel_create(grpc_credentials *creds, status = grpc_ssl_channel_security_context_create(creds, config, secure_peer_name, &ctx); if (status != GRPC_SECURITY_OK) { - return NULL; /* TODO(ctiller): return lame channel. */ + return grpc_lame_client_channel_create(); } channel = grpc_secure_channel_create_internal(target, args, ctx); grpc_security_context_unref(&ctx->base); @@ -435,13 +433,38 @@ static grpc_channel *grpc_ssl_channel_create(grpc_credentials *creds, } +static grpc_credentials *get_creds_from_composite( + grpc_credentials *composite_creds, const char *type) { + size_t i; + const grpc_credentials_array *inner_creds_array = + grpc_composite_credentials_get_credentials(composite_creds); + for (i = 0; i < inner_creds_array->num_creds; i++) { + if (!strcmp(type, inner_creds_array->creds_array[i]->type)) { + return inner_creds_array->creds_array[i]; + } + } + return NULL; +} + +static grpc_channel *grpc_channel_create_from_composite_creds( + grpc_credentials *composite_creds, const char *target, + const grpc_channel_args *args) { + grpc_credentials *creds = + get_creds_from_composite(composite_creds, GRPC_CREDENTIALS_TYPE_SSL); + if (creds != NULL) { + return grpc_ssl_channel_create( + composite_creds, grpc_ssl_credentials_get_config(creds), target, args); + } + return NULL; /* TODO(ctiller): return lame channel. */ +} + grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, const char *target, const grpc_channel_args *args) { if (grpc_credentials_has_request_metadata_only(creds)) { gpr_log(GPR_ERROR, "Credentials is insufficient to create a secure channel."); - return NULL; /* TODO(ctiller): return lame channel. */ + return grpc_lame_client_channel_create(); } if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) { return grpc_ssl_channel_create(NULL, grpc_ssl_credentials_get_config(creds), @@ -455,11 +478,11 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, grpc_security_context_unref(&ctx->base); return channel; } else if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE)) { - return NULL; /* TODO(jboeuf) Implement. */ + return grpc_channel_create_from_composite_creds(creds, target, args); } else { gpr_log(GPR_ERROR, "Unknown credentials type %s for creating a secure channel."); - return NULL; /* TODO(ctiller): return lame channel. */ + return grpc_lame_client_channel_create(); } } diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h index 59c9bbdf34..0c6025643a 100644 --- a/src/core/security/security_context.h +++ b/src/core/security/security_context.h @@ -119,7 +119,7 @@ typedef struct grpc_channel_security_context grpc_channel_security_context; struct grpc_channel_security_context { grpc_security_context base; /* requires is_client_side to be non 0. */ - grpc_credentials *request_metadata_only_creds; + grpc_credentials *request_metadata_creds; }; /* --- Creation security contexts. --- */ @@ -127,14 +127,14 @@ struct grpc_channel_security_context { /* For TESTING ONLY! Creates a fake context that emulates real channel security. */ grpc_channel_security_context *grpc_fake_channel_security_context_create( - grpc_credentials *request_metadata_only_creds); + grpc_credentials *request_metadata_creds); /* For TESTING ONLY! Creates a fake context that emulates real server security. */ grpc_security_context *grpc_fake_server_security_context_create(void); /* Creates an SSL channel_security_context. - - request_metadata_only_creds is the credentials object which metadata + - request_metadata_creds is the credentials object which metadata will be sent with each request. This parameter can be NULL. - config is the SSL config to be used for the SSL channel establishment. - is_client should be 0 for a server or a non-0 value for a client. @@ -147,9 +147,8 @@ grpc_security_context *grpc_fake_server_security_context_create(void); specific error code otherwise. */ grpc_security_status grpc_ssl_channel_security_context_create( - grpc_credentials *request_metadata_only_creds, - const grpc_ssl_config *config, const char *secure_peer_name, - grpc_channel_security_context **ctx); + grpc_credentials *request_metadata_creds, const grpc_ssl_config *config, + const char *secure_peer_name, grpc_channel_security_context **ctx); /* Creates an SSL server_security_context. - config is the SSL config to be used for the SSL channel establishment. diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c index bce27ec3ab..335d502217 100644 --- a/src/core/security/server_secure_chttp2.c +++ b/src/core/security/server_secure_chttp2.c @@ -109,7 +109,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr) { for (i = 0; i < resolved->naddrs; i++) { if (grpc_tcp_server_add_port(tcp, (struct sockaddr *)&resolved->addrs[i].addr, - resolved->addrs[i].len) >= 0) { + resolved->addrs[i].len)) { count++; } } |