blob: 174d991c89f6140ed71deeb6a2f92b46c0276ac8 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
3 * Copyright 2014, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include "src/core/security/security_context.h"
35
36#include <string.h>
37
38#include "src/core/endpoint/secure_endpoint.h"
39#include "src/core/security/credentials.h"
nnoble0c475f02014-12-05 15:37:39 -080040#include "src/core/surface/lame_client.h"
41#include "src/core/transport/chttp2/alpn.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080042#include <grpc/support/alloc.h>
43#include <grpc/support/log.h>
44#include <grpc/support/slice_buffer.h>
45#include <grpc/support/string.h>
46
47#include "src/core/tsi/fake_transport_security.h"
48#include "src/core/tsi/ssl_transport_security.h"
49
50/* -- Constants. -- */
51
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080052/* Defines the cipher suites that we accept. All these cipher suites are
53 compliant with TLS 1.2 and use an RSA public key. We prefer GCM over CBC
54 and ECDHE-RSA over just RSA. */
55#define GRPC_SSL_CIPHER_SUITES \
56 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:AES128-GCM-SHA256:" \
57 "AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:AES128-" \
58 "SHA256:AES256-SHA256"
59
60/* -- Common methods. -- */
61
62grpc_security_status grpc_security_context_create_handshaker(
63 grpc_security_context *ctx, tsi_handshaker **handshaker) {
64 if (ctx == NULL || handshaker == NULL) return GRPC_SECURITY_ERROR;
65 return ctx->vtable->create_handshaker(ctx, handshaker);
66}
67
68grpc_security_status grpc_security_context_check_peer(
69 grpc_security_context *ctx, const tsi_peer *peer,
70 grpc_security_check_peer_cb cb, void *user_data) {
71 if (ctx == NULL) return GRPC_SECURITY_ERROR;
72 return ctx->vtable->check_peer(ctx, peer, cb, user_data);
73}
74
75void grpc_security_context_unref(grpc_security_context *ctx) {
76 if (ctx == NULL) return;
77 if (gpr_unref(&ctx->refcount)) ctx->vtable->destroy(ctx);
78}
79
80grpc_security_context *grpc_security_context_ref(grpc_security_context *ctx) {
81 if (ctx == NULL) return NULL;
82 gpr_ref(&ctx->refcount);
83 return ctx;
84}
85
86static void context_pointer_arg_destroy(void *p) {
87 grpc_security_context_unref(p);
88}
89
90static void *context_pointer_arg_copy(void *p) {
91 return grpc_security_context_ref(p);
92}
93
94grpc_arg grpc_security_context_to_arg(grpc_security_context *ctx) {
95 grpc_arg result;
96 result.type = GRPC_ARG_POINTER;
97 result.key = GRPC_SECURITY_CONTEXT_ARG;
98 result.value.pointer.destroy = context_pointer_arg_destroy;
99 result.value.pointer.copy = context_pointer_arg_copy;
100 result.value.pointer.p = ctx;
101 return result;
102}
103
104grpc_security_context *grpc_security_context_from_arg(
105 const grpc_arg *arg) {
106 if (strcmp(arg->key, GRPC_SECURITY_CONTEXT_ARG)) return NULL;
107 if (arg->type != GRPC_ARG_POINTER) {
108 gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
109 GRPC_SECURITY_CONTEXT_ARG);
110 return NULL;
111 }
112 return arg->value.pointer.p;
113}
114
115grpc_security_context *grpc_find_security_context_in_args(
116 const grpc_channel_args *args) {
117 size_t i;
118 if (args == NULL) return NULL;
119 for (i = 0; i < args->num_args; i++) {
120 grpc_security_context *ctx = grpc_security_context_from_arg(&args->args[i]);
121 if (ctx != NULL) return ctx;
122 }
123 return NULL;
124}
125
nnoble0c475f02014-12-05 15:37:39 -0800126static int check_request_metadata_creds(grpc_credentials *creds) {
127 if (creds != NULL && !grpc_credentials_has_request_metadata(creds)) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800128 gpr_log(GPR_ERROR,
129 "Incompatible credentials for channel security context: needs to "
nnoble0c475f02014-12-05 15:37:39 -0800130 "set request metadata.");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800131 return 0;
132 }
133 return 1;
134}
135
136/* -- Fake implementation. -- */
137
138static void fake_channel_destroy(grpc_security_context *ctx) {
139 grpc_channel_security_context *c = (grpc_channel_security_context *)ctx;
nnoble0c475f02014-12-05 15:37:39 -0800140 grpc_credentials_unref(c->request_metadata_creds);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800141 gpr_free(ctx);
142}
143
144static void fake_server_destroy(grpc_security_context *ctx) {
145 gpr_free(ctx);
146}
147
148static grpc_security_status fake_channel_create_handshaker(
149 grpc_security_context *ctx, tsi_handshaker **handshaker) {
150 *handshaker = tsi_create_fake_handshaker(1);
151 return GRPC_SECURITY_OK;
152}
153
154static grpc_security_status fake_server_create_handshaker(
155 grpc_security_context *ctx, tsi_handshaker **handshaker) {
156 *handshaker = tsi_create_fake_handshaker(0);
157 return GRPC_SECURITY_OK;
158}
159
160static grpc_security_status fake_check_peer(grpc_security_context *ctx,
161 const tsi_peer *peer,
162 grpc_security_check_peer_cb cb,
163 void *user_data) {
164 const char *prop_name;
165 if (peer->property_count != 1) {
166 gpr_log(GPR_ERROR, "Fake peers should only have 1 property.");
167 return GRPC_SECURITY_ERROR;
168 }
169 prop_name = peer->properties[0].name;
170 if (prop_name == NULL ||
171 strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) {
172 gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.",
173 prop_name == NULL ? "<EMPTY>" : prop_name);
174 return GRPC_SECURITY_ERROR;
175 }
176 if (peer->properties[0].type != TSI_PEER_PROPERTY_TYPE_STRING) {
177 gpr_log(GPR_ERROR, "Invalid type of cert type property.");
178 return GRPC_SECURITY_ERROR;
179 }
180 if (strncmp(peer->properties[0].value.string.data, TSI_FAKE_CERTIFICATE_TYPE,
181 peer->properties[0].value.string.length)) {
182 gpr_log(GPR_ERROR, "Invalid value for cert type property.");
183 return GRPC_SECURITY_ERROR;
184 }
185 return GRPC_SECURITY_OK;
186}
187
188static grpc_security_context_vtable fake_channel_vtable = {
189 fake_channel_destroy, fake_channel_create_handshaker, fake_check_peer};
190
191static grpc_security_context_vtable fake_server_vtable = {
192 fake_server_destroy, fake_server_create_handshaker, fake_check_peer};
193
194grpc_channel_security_context *grpc_fake_channel_security_context_create(
nnoble0c475f02014-12-05 15:37:39 -0800195 grpc_credentials *request_metadata_creds) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800196 grpc_channel_security_context *c =
197 gpr_malloc(sizeof(grpc_channel_security_context));
198 gpr_ref_init(&c->base.refcount, 1);
199 c->base.is_client_side = 1;
200 c->base.vtable = &fake_channel_vtable;
nnoble0c475f02014-12-05 15:37:39 -0800201 GPR_ASSERT(check_request_metadata_creds(request_metadata_creds));
202 c->request_metadata_creds = grpc_credentials_ref(request_metadata_creds);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800203 return c;
204}
205
206grpc_security_context *grpc_fake_server_security_context_create(void) {
207 grpc_security_context *c = gpr_malloc(sizeof(grpc_security_context));
208 gpr_ref_init(&c->refcount, 1);
209 c->vtable = &fake_server_vtable;
210 return c;
211}
212
213/* --- Ssl implementation. --- */
214
215typedef struct {
216 grpc_channel_security_context base;
217 tsi_ssl_handshaker_factory *handshaker_factory;
218 char *secure_peer_name;
219} grpc_ssl_channel_security_context;
220
221typedef struct {
222 grpc_security_context base;
223 tsi_ssl_handshaker_factory *handshaker_factory;
224} grpc_ssl_server_security_context;
225
226static void ssl_channel_destroy(grpc_security_context *ctx) {
227 grpc_ssl_channel_security_context *c =
228 (grpc_ssl_channel_security_context *)ctx;
nnoble0c475f02014-12-05 15:37:39 -0800229 grpc_credentials_unref(c->base.request_metadata_creds);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800230 if (c->handshaker_factory != NULL) {
231 tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
232 }
233 if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name);
234 gpr_free(ctx);
235}
236
237static void ssl_server_destroy(grpc_security_context *ctx) {
238 grpc_ssl_server_security_context *c =
239 (grpc_ssl_server_security_context *)ctx;
240 if (c->handshaker_factory != NULL) {
241 tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
242 }
243 gpr_free(ctx);
244}
245
246static grpc_security_status ssl_create_handshaker(
247 tsi_ssl_handshaker_factory *handshaker_factory, int is_client,
248 const char *secure_peer_name, tsi_handshaker **handshaker) {
249 tsi_result result = TSI_OK;
250 if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
251 result = tsi_ssl_handshaker_factory_create_handshaker(
252 handshaker_factory, is_client ? secure_peer_name : NULL, handshaker);
253 if (result != TSI_OK) {
254 gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
255 tsi_result_to_string(result));
256 return GRPC_SECURITY_ERROR;
257 }
258 return GRPC_SECURITY_OK;
259}
260
261static grpc_security_status ssl_channel_create_handshaker(
262 grpc_security_context *ctx, tsi_handshaker **handshaker) {
263 grpc_ssl_channel_security_context *c =
264 (grpc_ssl_channel_security_context *)ctx;
265 return ssl_create_handshaker(c->handshaker_factory, 1, c->secure_peer_name,
266 handshaker);
267}
268
269static grpc_security_status ssl_server_create_handshaker(
270 grpc_security_context *ctx, tsi_handshaker **handshaker) {
271 grpc_ssl_server_security_context *c =
272 (grpc_ssl_server_security_context *)ctx;
273 return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker);
274}
275
276static grpc_security_status ssl_check_peer(const char *secure_peer_name,
277 const tsi_peer *peer) {
278 /* Check the ALPN. */
279 const tsi_peer_property *p =
280 tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
281 if (p == NULL || p->type != TSI_PEER_PROPERTY_TYPE_STRING) {
282 gpr_log(GPR_ERROR, "Invalid or missing selected ALPN property.");
283 return GRPC_SECURITY_ERROR;
284 }
nnoble0c475f02014-12-05 15:37:39 -0800285 if (!grpc_chttp2_is_alpn_version_supported(p->value.string.data,
286 p->value.string.length)) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800287 gpr_log(GPR_ERROR, "Invalid ALPN value.");
288 return GRPC_SECURITY_ERROR;
289 }
290
291 /* Check the peer name if specified. */
292 if (secure_peer_name != NULL &&
293 !tsi_ssl_peer_matches_name(peer, secure_peer_name)) {
294 gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate",
295 secure_peer_name);
296 return GRPC_SECURITY_ERROR;
297 }
298 return GRPC_SECURITY_OK;
299}
300
301static grpc_security_status ssl_channel_check_peer(
302 grpc_security_context *ctx, const tsi_peer *peer,
303 grpc_security_check_peer_cb cb, void *user_data) {
304 grpc_ssl_channel_security_context *c =
305 (grpc_ssl_channel_security_context *)ctx;
306 return ssl_check_peer(c->secure_peer_name, peer);
307}
308
309static grpc_security_status ssl_server_check_peer(
310 grpc_security_context *ctx, const tsi_peer *peer,
311 grpc_security_check_peer_cb cb, void *user_data) {
312 /* TODO(jboeuf): Find a way to expose the peer to the authorization layer. */
313 return ssl_check_peer(NULL, peer);
314}
315
316static grpc_security_context_vtable ssl_channel_vtable = {
317 ssl_channel_destroy, ssl_channel_create_handshaker, ssl_channel_check_peer};
318
319static grpc_security_context_vtable ssl_server_vtable = {
320 ssl_server_destroy, ssl_server_create_handshaker, ssl_server_check_peer};
321
322grpc_security_status grpc_ssl_channel_security_context_create(
nnoble0c475f02014-12-05 15:37:39 -0800323 grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
324 const char *secure_peer_name, grpc_channel_security_context **ctx) {
ctiller84518b42014-12-09 15:05:40 -0800325 size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
326 const unsigned char **alpn_protocol_strings =
327 gpr_malloc(sizeof(const char *) * num_alpn_protocols);
328 unsigned char *alpn_protocol_string_lengths =
329 gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800330 tsi_result result = TSI_OK;
331 grpc_ssl_channel_security_context *c;
ctiller84518b42014-12-09 15:05:40 -0800332 size_t i;
333
334 for (i = 0; i < num_alpn_protocols; i++) {
335 alpn_protocol_strings[i] =
336 (const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
337 alpn_protocol_string_lengths[i] =
338 strlen(grpc_chttp2_get_alpn_version_index(i));
339 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800340
341 if (config == NULL || secure_peer_name == NULL ||
342 config->pem_root_certs == NULL) {
343 gpr_log(GPR_ERROR, "An ssl channel needs a secure name and root certs.");
ctiller84518b42014-12-09 15:05:40 -0800344 goto error;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800345 }
nnoble0c475f02014-12-05 15:37:39 -0800346 if (!check_request_metadata_creds(request_metadata_creds)) {
ctiller84518b42014-12-09 15:05:40 -0800347 goto error;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800348 }
349
350 c = gpr_malloc(sizeof(grpc_ssl_channel_security_context));
351 memset(c, 0, sizeof(grpc_ssl_channel_security_context));
352
353 gpr_ref_init(&c->base.base.refcount, 1);
354 c->base.base.vtable = &ssl_channel_vtable;
355 c->base.base.is_client_side = 1;
nnoble0c475f02014-12-05 15:37:39 -0800356 c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800357 if (secure_peer_name != NULL) {
358 c->secure_peer_name = gpr_strdup(secure_peer_name);
359 }
360 result = tsi_create_ssl_client_handshaker_factory(
361 config->pem_private_key, config->pem_private_key_size,
362 config->pem_cert_chain, config->pem_cert_chain_size,
363 config->pem_root_certs, config->pem_root_certs_size,
ctiller84518b42014-12-09 15:05:40 -0800364 GRPC_SSL_CIPHER_SUITES, alpn_protocol_strings,
365 alpn_protocol_string_lengths, 1, &c->handshaker_factory);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800366 if (result != TSI_OK) {
367 gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
368 tsi_result_to_string(result));
369 ssl_channel_destroy(&c->base.base);
370 *ctx = NULL;
ctiller84518b42014-12-09 15:05:40 -0800371 goto error;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800372 }
373 *ctx = &c->base;
ctiller84518b42014-12-09 15:05:40 -0800374 gpr_free(alpn_protocol_strings);
375 gpr_free(alpn_protocol_string_lengths);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800376 return GRPC_SECURITY_OK;
ctiller84518b42014-12-09 15:05:40 -0800377
378error:
379 gpr_free(alpn_protocol_strings);
380 gpr_free(alpn_protocol_string_lengths);
381 return GRPC_SECURITY_ERROR;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800382}
383
384grpc_security_status grpc_ssl_server_security_context_create(
385 const grpc_ssl_config *config, grpc_security_context **ctx) {
ctiller84518b42014-12-09 15:05:40 -0800386 size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
387 const unsigned char **alpn_protocol_strings =
388 gpr_malloc(sizeof(const char *) * num_alpn_protocols);
389 unsigned char *alpn_protocol_string_lengths =
390 gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800391 tsi_result result = TSI_OK;
392 grpc_ssl_server_security_context *c;
ctiller84518b42014-12-09 15:05:40 -0800393 size_t i;
394
395 for (i = 0; i < num_alpn_protocols; i++) {
396 alpn_protocol_strings[i] =
397 (const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
398 alpn_protocol_string_lengths[i] =
399 strlen(grpc_chttp2_get_alpn_version_index(i));
400 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800401
402 if (config == NULL || config->pem_private_key == NULL ||
403 config->pem_cert_chain == NULL) {
404 gpr_log(GPR_ERROR, "An SSL server needs a key and a cert.");
ctiller84518b42014-12-09 15:05:40 -0800405 goto error;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800406 }
407 c = gpr_malloc(sizeof(grpc_ssl_server_security_context));
408 memset(c, 0, sizeof(grpc_ssl_server_security_context));
409
410 gpr_ref_init(&c->base.refcount, 1);
411 c->base.vtable = &ssl_server_vtable;
412 result = tsi_create_ssl_server_handshaker_factory(
413 (const unsigned char **)&config->pem_private_key,
414 (const gpr_uint32 *)&config->pem_private_key_size,
415 (const unsigned char **)&config->pem_cert_chain,
416 (const gpr_uint32 *)&config->pem_cert_chain_size, 1,
417 config->pem_root_certs, config->pem_root_certs_size,
ctiller84518b42014-12-09 15:05:40 -0800418 GRPC_SSL_CIPHER_SUITES, alpn_protocol_strings,
419 alpn_protocol_string_lengths, 1, &c->handshaker_factory);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800420 if (result != TSI_OK) {
421 gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
422 tsi_result_to_string(result));
423 ssl_server_destroy(&c->base);
424 *ctx = NULL;
ctiller84518b42014-12-09 15:05:40 -0800425 goto error;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800426 }
427 *ctx = &c->base;
ctiller84518b42014-12-09 15:05:40 -0800428 gpr_free(alpn_protocol_strings);
429 gpr_free(alpn_protocol_string_lengths);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800430 return GRPC_SECURITY_OK;
ctiller84518b42014-12-09 15:05:40 -0800431
432error:
433 gpr_free(alpn_protocol_strings);
434 gpr_free(alpn_protocol_string_lengths);
435 return GRPC_SECURITY_ERROR;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800436}
437
438
439
440/* -- High level objects. -- */
441
442static grpc_channel *grpc_ssl_channel_create(grpc_credentials *creds,
443 const grpc_ssl_config *config,
444 const char *target,
445 const grpc_channel_args *args) {
446 grpc_channel_security_context *ctx = NULL;
447 grpc_channel *channel = NULL;
448 grpc_security_status status = GRPC_SECURITY_OK;
449 size_t i = 0;
450 const char *secure_peer_name = target;
451 for (i = 0; i < args->num_args; i++) {
452 grpc_arg *arg = &args->args[i];
453 if (!strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) &&
454 arg->type == GRPC_ARG_STRING) {
455 secure_peer_name = arg->value.string;
456 break;
457 }
458 }
459 status = grpc_ssl_channel_security_context_create(creds, config,
460 secure_peer_name, &ctx);
461 if (status != GRPC_SECURITY_OK) {
nnoble0c475f02014-12-05 15:37:39 -0800462 return grpc_lame_client_channel_create();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800463 }
464 channel = grpc_secure_channel_create_internal(target, args, ctx);
465 grpc_security_context_unref(&ctx->base);
466 return channel;
467}
468
469
nnoble0c475f02014-12-05 15:37:39 -0800470static grpc_credentials *get_creds_from_composite(
471 grpc_credentials *composite_creds, const char *type) {
472 size_t i;
473 const grpc_credentials_array *inner_creds_array =
474 grpc_composite_credentials_get_credentials(composite_creds);
475 for (i = 0; i < inner_creds_array->num_creds; i++) {
476 if (!strcmp(type, inner_creds_array->creds_array[i]->type)) {
477 return inner_creds_array->creds_array[i];
478 }
479 }
480 return NULL;
481}
482
483static grpc_channel *grpc_channel_create_from_composite_creds(
484 grpc_credentials *composite_creds, const char *target,
485 const grpc_channel_args *args) {
486 grpc_credentials *creds =
487 get_creds_from_composite(composite_creds, GRPC_CREDENTIALS_TYPE_SSL);
488 if (creds != NULL) {
489 return grpc_ssl_channel_create(
490 composite_creds, grpc_ssl_credentials_get_config(creds), target, args);
491 }
492 return NULL; /* TODO(ctiller): return lame channel. */
493}
494
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800495grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
496 const char *target,
497 const grpc_channel_args *args) {
498 if (grpc_credentials_has_request_metadata_only(creds)) {
499 gpr_log(GPR_ERROR,
500 "Credentials is insufficient to create a secure channel.");
nnoble0c475f02014-12-05 15:37:39 -0800501 return grpc_lame_client_channel_create();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800502 }
503 if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
504 return grpc_ssl_channel_create(NULL, grpc_ssl_credentials_get_config(creds),
505 target, args);
506 } else if (!strcmp(creds->type,
507 GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY)) {
508 grpc_channel_security_context *ctx =
509 grpc_fake_channel_security_context_create(NULL);
510 grpc_channel *channel =
511 grpc_secure_channel_create_internal(target, args, ctx);
512 grpc_security_context_unref(&ctx->base);
513 return channel;
514 } else if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE)) {
nnoble0c475f02014-12-05 15:37:39 -0800515 return grpc_channel_create_from_composite_creds(creds, target, args);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800516 } else {
517 gpr_log(GPR_ERROR,
518 "Unknown credentials type %s for creating a secure channel.");
nnoble0c475f02014-12-05 15:37:39 -0800519 return grpc_lame_client_channel_create();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800520 }
521}
522
523grpc_channel *grpc_default_secure_channel_create(
524 const char *target, const grpc_channel_args *args) {
525 return grpc_secure_channel_create(grpc_default_credentials_create(), target,
526 args);
527}
528
529grpc_server *grpc_secure_server_create(grpc_server_credentials *creds,
530 grpc_completion_queue *cq,
531 const grpc_channel_args *args) {
532 grpc_security_status status = GRPC_SECURITY_ERROR;
533 grpc_security_context *ctx = NULL;
534 grpc_server *server = NULL;
535 if (creds == NULL) return NULL; /* TODO(ctiller): Return lame server. */
536 if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
537 status = grpc_ssl_server_security_context_create(
538 grpc_ssl_server_credentials_get_config(creds), &ctx);
539 } else if (!strcmp(creds->type,
540 GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY)) {
541 ctx = grpc_fake_server_security_context_create();
542 status = GRPC_SECURITY_OK;
543 } else {
544 gpr_log(GPR_ERROR,
545 "Unable to create secure server with credentials of type %s.",
546 creds->type);
547 }
548 if (status != GRPC_SECURITY_OK) {
549 return NULL; /* TODO(ctiller): Return lame server. */
550 }
551 server = grpc_secure_server_create_internal(cq, args, ctx);
552 grpc_security_context_unref(ctx);
553 return server;
554}