aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/security
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/security')
-rw-r--r--src/core/security/client_auth_filter.c2
-rw-r--r--src/core/security/security_connector.c74
-rw-r--r--src/core/security/security_connector.h1
-rw-r--r--src/core/security/security_context.c150
-rw-r--r--src/core/security/security_context.h54
-rw-r--r--src/core/security/server_auth_filter.c50
6 files changed, 289 insertions, 42 deletions
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
index 1d9788b8dd..9e1198919b 100644
--- a/src/core/security/client_auth_filter.c
+++ b/src/core/security/client_auth_filter.c
@@ -189,6 +189,8 @@ static void auth_start_transport_op(grpc_call_element *elem,
grpc_linked_mdelem *l;
size_t i;
+ /* TODO(jboeuf): write the call auth context. */
+
if (op->send_ops && !calld->sent_initial_metadata) {
size_t nops = op->send_ops->nops;
grpc_stream_op *ops = op->send_ops->ops;
diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c
index 035f3735e3..11505f8cb0 100644
--- a/src/core/security/security_connector.c
+++ b/src/core/security/security_connector.c
@@ -37,6 +37,7 @@
#include "src/core/security/credentials.h"
#include "src/core/security/secure_endpoint.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"
@@ -194,10 +195,14 @@ typedef struct {
static void fake_channel_destroy(grpc_security_connector *sc) {
grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
grpc_credentials_unref(c->request_metadata_creds);
+ grpc_auth_context_unref(sc->auth_context);
gpr_free(sc);
}
-static void fake_server_destroy(grpc_security_connector *sc) { gpr_free(sc); }
+static void fake_server_destroy(grpc_security_connector *sc) {
+ grpc_auth_context_unref(sc->auth_context);
+ gpr_free(sc);
+}
static grpc_security_status fake_channel_create_handshaker(
grpc_security_connector *sc, tsi_handshaker **handshaker) {
@@ -236,6 +241,12 @@ static grpc_security_status fake_check_peer(grpc_security_connector *sc,
status = GRPC_SECURITY_ERROR;
goto end;
}
+ grpc_auth_context_unref(sc->auth_context);
+ sc->auth_context = grpc_auth_context_create(NULL, 1);
+ sc->auth_context->properties[0] = grpc_auth_property_init_from_cstring(
+ GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+ GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
+
end:
tsi_peer_destruct(&peer);
return status;
@@ -264,6 +275,7 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
grpc_credentials *request_metadata_creds, int call_host_check_is_async) {
grpc_fake_channel_security_connector *c =
gpr_malloc(sizeof(grpc_fake_channel_security_connector));
+ memset(c, 0, sizeof(grpc_fake_channel_security_connector));
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.is_client_side = 1;
c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
@@ -277,6 +289,7 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
grpc_security_connector *grpc_fake_server_security_connector_create(void) {
grpc_security_connector *c = gpr_malloc(sizeof(grpc_security_connector));
+ memset(c, 0, sizeof(grpc_security_connector));
gpr_ref_init(&c->refcount, 1);
c->is_client_side = 0;
c->vtable = &fake_server_vtable;
@@ -309,6 +322,7 @@ static void ssl_channel_destroy(grpc_security_connector *sc) {
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);
+ grpc_auth_context_unref(sc->auth_context);
gpr_free(sc);
}
@@ -318,6 +332,7 @@ static void ssl_server_destroy(grpc_security_connector *sc) {
if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
}
+ grpc_auth_context_unref(sc->auth_context);
gpr_free(sc);
}
@@ -370,7 +385,51 @@ static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) {
return r;
}
-static grpc_security_status ssl_check_peer(const char *peer_name,
+static grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) {
+ /* We bet that iterating over a handful of properties twice will be faster
+ than having to realloc on average . */
+ size_t auth_prop_count = 1; /* for transport_security_type. */
+ size_t i;
+ const char *peer_identity_property_name = NULL;
+ grpc_auth_context *ctx = NULL;
+ for (i = 0; i < peer->property_count; i++) {
+ const tsi_peer_property *prop = &peer->properties[i];
+ if (prop->name == NULL) continue;
+ if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
+ auth_prop_count++;
+ /* If there is no subject alt name, have the CN as the identity. */
+ if (peer_identity_property_name == NULL) {
+ peer_identity_property_name = prop->name;
+ }
+ } else if (strcmp(prop->name,
+ TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
+ auth_prop_count++;
+ peer_identity_property_name = prop->name;
+ }
+ }
+ ctx = grpc_auth_context_create(NULL, auth_prop_count);
+ ctx->properties[0] = grpc_auth_property_init_from_cstring(
+ GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+ GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+ ctx->property_count = 1;
+ for (i = 0; i < peer->property_count; i++) {
+ const tsi_peer_property *prop = &peer->properties[i];
+ if (prop->name == NULL) continue;
+ if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
+ ctx->properties[ctx->property_count++] = grpc_auth_property_init(
+ GRPC_X509_CN_PROPERTY_NAME, prop->value.data, prop->value.length);
+ } else if (strcmp(prop->name,
+ TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
+ ctx->properties[ctx->property_count++] = grpc_auth_property_init(
+ GRPC_X509_SAN_PROPERTY_NAME, prop->value.data, prop->value.length);
+ }
+ }
+ GPR_ASSERT(auth_prop_count == ctx->property_count);
+ return ctx;
+}
+
+static grpc_security_status ssl_check_peer(grpc_security_connector *sc,
+ const char *peer_name,
const tsi_peer *peer) {
/* Check the ALPN. */
const tsi_peer_property *p =
@@ -389,7 +448,7 @@ static grpc_security_status ssl_check_peer(const char *peer_name,
gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name);
return GRPC_SECURITY_ERROR;
}
-
+ sc->auth_context = tsi_ssl_peer_to_auth_context(peer);
return GRPC_SECURITY_OK;
}
@@ -402,9 +461,9 @@ static grpc_security_status ssl_channel_check_peer(grpc_security_connector *sc,
grpc_security_status status;
tsi_peer_destruct(&c->peer);
c->peer = peer;
- status = ssl_check_peer(c->overridden_target_name != NULL
- ? c->overridden_target_name
- : c->target_name,
+ status = ssl_check_peer(sc, c->overridden_target_name != NULL
+ ? c->overridden_target_name
+ : c->target_name,
&peer);
return status;
}
@@ -413,8 +472,7 @@ static grpc_security_status ssl_server_check_peer(grpc_security_connector *sc,
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);
+ grpc_security_status status = ssl_check_peer(sc, NULL, &peer);
tsi_peer_destruct(&peer);
return status;
}
diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h
index 87b7ca9b8b..0617041448 100644
--- a/src/core/security/security_connector.h
+++ b/src/core/security/security_connector.h
@@ -77,6 +77,7 @@ struct grpc_security_connector {
gpr_refcount refcount;
int is_client_side;
const char *url_scheme;
+ grpc_auth_context *auth_context; /* Populated after the peer is checked. */
};
/* Increments the refcount. */
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
index b90dc5097a..c9fcff661f 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_context.c
@@ -35,11 +35,14 @@
#include "src/core/security/security_context.h"
#include "src/core/surface/call.h"
+#include "src/core/support/string.h"
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+/* --- grpc_call --- */
+
grpc_call_error grpc_call_set_credentials(grpc_call *call,
grpc_credentials *creds) {
grpc_client_security_context *ctx = NULL;
@@ -65,6 +68,16 @@ grpc_call_error grpc_call_set_credentials(grpc_call *call,
return GRPC_CALL_OK;
}
+const grpc_auth_context *grpc_call_auth_context(grpc_call *call) {
+ void *sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY);
+ if (sec_ctx == NULL) return NULL;
+ return grpc_call_is_client(call)
+ ? ((grpc_client_security_context *)sec_ctx)->auth_context
+ : ((grpc_server_security_context *)sec_ctx)->auth_context;
+}
+
+/* --- grpc_client_security_context --- */
+
grpc_client_security_context *grpc_client_security_context_create(void) {
grpc_client_security_context *ctx =
gpr_malloc(sizeof(grpc_client_security_context));
@@ -75,5 +88,142 @@ grpc_client_security_context *grpc_client_security_context_create(void) {
void grpc_client_security_context_destroy(void *ctx) {
grpc_client_security_context *c = (grpc_client_security_context *)ctx;
grpc_credentials_unref(c->creds);
+ grpc_auth_context_unref(c->auth_context);
+ gpr_free(ctx);
+}
+
+/* --- grpc_server_security_context --- */
+
+grpc_server_security_context *grpc_server_security_context_create(void) {
+ grpc_server_security_context *ctx =
+ gpr_malloc(sizeof(grpc_server_security_context));
+ memset(ctx, 0, sizeof(grpc_server_security_context));
+ return ctx;
+}
+
+void grpc_server_security_context_destroy(void *ctx) {
+ grpc_server_security_context *c = (grpc_server_security_context *)ctx;
+ grpc_auth_context_unref(c->auth_context);
gpr_free(ctx);
}
+
+/* --- grpc_auth_context --- */
+
+grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained,
+ size_t property_count) {
+ grpc_auth_context *ctx = gpr_malloc(sizeof(grpc_auth_context));
+ memset(ctx, 0, sizeof(grpc_auth_context));
+ ctx->properties = gpr_malloc(property_count * sizeof(grpc_auth_property));
+ memset(ctx->properties, 0, property_count * sizeof(grpc_auth_property));
+ ctx->property_count = property_count;
+ gpr_ref_init(&ctx->refcount, 1);
+ if (chained != NULL) ctx->chained = grpc_auth_context_ref(chained);
+ return ctx;
+}
+
+grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx) {
+ if (ctx == NULL) return NULL;
+ gpr_ref(&ctx->refcount);
+ return ctx;
+}
+
+void grpc_auth_context_unref(grpc_auth_context *ctx) {
+ if (ctx == NULL) return;
+ if (gpr_unref(&ctx->refcount)) {
+ size_t i;
+ grpc_auth_context_unref(ctx->chained);
+ if (ctx->properties != NULL) {
+ for (i = 0; i < ctx->property_count; i++) {
+ grpc_auth_property_reset(&ctx->properties[i]);
+ }
+ gpr_free(ctx->properties);
+ }
+ }
+}
+
+const char *grpc_auth_context_peer_identity_property_name(
+ const grpc_auth_context *ctx) {
+ return ctx->peer_identity_property_name;
+}
+
+grpc_auth_property_iterator *grpc_auth_context_property_iterator(
+ const grpc_auth_context *ctx) {
+ grpc_auth_property_iterator *it;
+ if (ctx == NULL) return NULL;
+ it = gpr_malloc(sizeof(grpc_auth_property_iterator));
+ memset(it, 0, sizeof(grpc_auth_property_iterator));
+ it->ctx = ctx;
+ return it;
+}
+
+const grpc_auth_property *grpc_auth_property_iterator_next(
+ grpc_auth_property_iterator *it) {
+ if (it == NULL) return NULL;
+ while (it->index == it->ctx->property_count) {
+ if (it->ctx->chained == NULL) return NULL;
+ it->ctx = it->ctx->chained;
+ it->index = 0;
+ }
+ if (it->name == NULL) {
+ return &it->ctx->properties[it->index++];
+ } else {
+ while (it->index < it->ctx->property_count) {
+ const grpc_auth_property *prop = &it->ctx->properties[it->index++];
+ GPR_ASSERT(prop->name != NULL);
+ if (strcmp(it->name, prop->name) == 0) {
+ return prop;
+ }
+ }
+ /* We could not find the name, try another round. */
+ return grpc_auth_property_iterator_next(it);
+ }
+}
+
+grpc_auth_property_iterator *grpc_auth_context_find_properties_by_name(
+ const grpc_auth_context *ctx, const char *name) {
+ grpc_auth_property_iterator *it;
+ if (ctx == NULL || name == NULL) return NULL;
+ it = grpc_auth_context_property_iterator(ctx);
+ it->name = gpr_strdup(name);
+ return it;
+}
+
+grpc_auth_property_iterator *grpc_auth_context_peer_identity(
+ const grpc_auth_context *ctx) {
+ if (ctx == NULL || ctx->peer_identity_property_name == NULL) return NULL;
+ return grpc_auth_context_find_properties_by_name(
+ ctx, ctx->peer_identity_property_name);
+}
+
+void grpc_auth_property_iterator_destroy(grpc_auth_property_iterator *it) {
+ if (it == NULL) return;
+ if (it->name != NULL) gpr_free(it->name);
+ gpr_free(it);
+}
+
+grpc_auth_property grpc_auth_property_init_from_cstring(const char *name,
+ const char *value) {
+ grpc_auth_property prop;
+ prop.name = gpr_strdup(name);
+ prop.value = gpr_strdup(value);
+ prop.value_length = strlen(value);
+ return prop;
+}
+
+grpc_auth_property grpc_auth_property_init(const char *name, const char *value,
+ size_t value_length) {
+ grpc_auth_property prop;
+ prop.name = gpr_strdup(name);
+ prop.value = gpr_malloc(value_length + 1);
+ memcpy(prop.value, value, value_length);
+ prop.value[value_length] = '\0';
+ prop.value_length = value_length;
+ return prop;
+}
+
+void grpc_auth_property_reset(grpc_auth_property *property) {
+ if (property->name != NULL) gpr_free(property->name);
+ if (property->value != NULL) gpr_free(property->value);
+ memset(property, 0, sizeof(grpc_auth_property));
+}
+
diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h
index 561633b452..60a3177773 100644
--- a/src/core/security/security_context.h
+++ b/src/core/security/security_context.h
@@ -36,13 +36,65 @@
#include "src/core/security/credentials.h"
-/* Security context attached to a client-side call. */
+/* --- grpc_auth_context ---
+
+ High level authentication context object. Can optionally be chained. */
+
+/* Property names are always NULL terminated. */
+
+struct grpc_auth_property_iterator {
+ const grpc_auth_context *ctx;
+ size_t index;
+ char *name;
+};
+
+struct grpc_auth_context {
+ struct grpc_auth_context *chained;
+ grpc_auth_property *properties;
+ size_t property_count;
+ gpr_refcount refcount;
+ const char *peer_identity_property_name;
+};
+
+/* Constructor. */
+grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained,
+ size_t property_count);
+
+/* Refcounting. */
+grpc_auth_context *grpc_auth_context_ref(
+ grpc_auth_context *ctx);
+void grpc_auth_context_unref(grpc_auth_context *ctx);
+
+grpc_auth_property grpc_auth_property_init_from_cstring(const char *name,
+ const char *value);
+
+grpc_auth_property grpc_auth_property_init(const char *name, const char *value,
+ size_t value_length);
+
+void grpc_auth_property_reset(grpc_auth_property *property);
+
+/* --- grpc_client_security_context ---
+
+ Internal client-side security context. */
+
typedef struct {
grpc_credentials *creds;
+ grpc_auth_context *auth_context;
} grpc_client_security_context;
grpc_client_security_context *grpc_client_security_context_create(void);
void grpc_client_security_context_destroy(void *ctx);
+/* --- grpc_server_security_context ---
+
+ Internal server-side security context. */
+
+typedef struct {
+ grpc_auth_context *auth_context;
+} grpc_server_security_context;
+
+grpc_server_security_context *grpc_server_security_context_create(void);
+void grpc_server_security_context_destroy(void *ctx);
+
#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */
diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c
index 7779bcc407..03372328ed 100644
--- a/src/core/security/server_auth_filter.c
+++ b/src/core/security/server_auth_filter.c
@@ -33,6 +33,7 @@
#include "src/core/security/auth_filters.h"
#include "src/core/security/security_connector.h"
+#include "src/core/security/security_context.h"
#include <grpc/support/log.h>
@@ -44,20 +45,6 @@ typedef struct channel_data {
grpc_security_connector *security_connector;
} channel_data;
-/* used to silence 'variable not used' warnings */
-static void ignore_unused(void *ignored) {}
-
-static void noop_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
- /* grab pointers to our data from the call element */
- call_data *calld = elem->call_data;
- channel_data *chand = elem->channel_data;
-
- ignore_unused(calld);
- ignore_unused(chand);
-
- /* do nothing */
-}
-
/* Called either:
- in response to an API call (or similar) from above, to send something
- a network event (or similar) from below, to receive something
@@ -65,7 +52,7 @@ static void noop_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
that is being sent or received. */
static void auth_start_transport_op(grpc_call_element *elem,
grpc_transport_op *op) {
- noop_mutate_op(elem, op);
+ /* TODO(jboeuf): Get the metadata and get a new context from it. */
/* pass control down the stack */
grpc_call_next_op(elem, op);
@@ -75,17 +62,7 @@ static void auth_start_transport_op(grpc_call_element *elem,
calls on the server */
static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
- /* grab pointers to our data from the channel element */
- channel_data *chand = elem->channel_data;
-
- ignore_unused(chand);
-
- switch (op->type) {
- default:
- /* pass control up or down the stack depending on op->dir */
- grpc_channel_next_op(elem, op);
- break;
- }
+ grpc_channel_next_op(elem, op);
}
/* Constructor for call_data */
@@ -94,21 +71,28 @@ static void init_call_elem(grpc_call_element *elem,
grpc_transport_op *initial_op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
+ channel_data *chand = elem->channel_data;
+ grpc_server_security_context *server_ctx = NULL;
/* initialize members */
calld->unused = 0;
- if (initial_op) noop_mutate_op(elem, initial_op);
+ GPR_ASSERT(initial_op && initial_op->contexts != NULL &&
+ chand->security_connector->auth_context != NULL &&
+ initial_op->contexts[GRPC_CONTEXT_SECURITY].value == NULL);
+
+ /* Create a security context for the call and reference the auth context from
+ the channel. */
+ server_ctx = grpc_server_security_context_create();
+ server_ctx->auth_context =
+ grpc_auth_context_ref(chand->security_connector->auth_context);
+ initial_op->contexts[GRPC_CONTEXT_SECURITY].value = server_ctx;
+ initial_op->contexts[GRPC_CONTEXT_SECURITY].destroy =
+ grpc_server_security_context_destroy;
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element *elem) {
- /* grab pointers to our data from the call element */
- call_data *calld = elem->call_data;
- channel_data *chand = elem->channel_data;
-
- ignore_unused(calld);
- ignore_unused(chand);
}
/* Constructor for channel_data */