blob: 4888043e6b1fd3cedc4f296af29515f8b1cd333a [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * 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
David Klempnera1e86932015-01-13 18:13:59 -080038#include "src/core/channel/channel_args.h"
David Klempnered0cbc82015-01-14 14:46:10 -080039#include "src/core/channel/http_client_filter.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080040#include "src/core/security/credentials.h"
ctiller2bbb6c42014-12-17 09:44:44 -080041#include "src/core/security/secure_endpoint.h"
Julien Boeuf026a4172015-02-02 18:36:37 -080042#include "src/core/support/env.h"
43#include "src/core/support/file.h"
Craig Tiller485d7762015-01-23 12:54:05 -080044#include "src/core/support/string.h"
nnoble0c475f02014-12-05 15:37:39 -080045#include "src/core/transport/chttp2/alpn.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080046#include <grpc/support/alloc.h>
47#include <grpc/support/log.h>
48#include <grpc/support/slice_buffer.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080049#include "src/core/tsi/fake_transport_security.h"
50#include "src/core/tsi/ssl_transport_security.h"
51
52/* -- Constants. -- */
53
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080054/* Defines the cipher suites that we accept. All these cipher suites are
55 compliant with TLS 1.2 and use an RSA public key. We prefer GCM over CBC
56 and ECDHE-RSA over just RSA. */
57#define GRPC_SSL_CIPHER_SUITES \
58 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:AES128-GCM-SHA256:" \
59 "AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:AES128-" \
60 "SHA256:AES256-SHA256"
61
Nicolas "Pixel" Noble72743822015-02-20 20:59:29 +010062#ifndef INSTALL_PREFIX
Nicolas "Pixel" Noble161ea232015-02-22 05:48:53 +010063static const char *installed_roots_path = "/usr/share/grpc/roots.pem";
Nicolas "Pixel" Noble72743822015-02-20 20:59:29 +010064#else
Nicolas "Pixel" Noble161ea232015-02-22 05:48:53 +010065static const char *installed_roots_path = INSTALL_PREFIX "/share/grpc/roots.pem";
Nicolas "Pixel" Noble72743822015-02-20 20:59:29 +010066#endif
67
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080068/* -- Common methods. -- */
69
70grpc_security_status grpc_security_context_create_handshaker(
71 grpc_security_context *ctx, tsi_handshaker **handshaker) {
72 if (ctx == NULL || handshaker == NULL) return GRPC_SECURITY_ERROR;
73 return ctx->vtable->create_handshaker(ctx, handshaker);
74}
75
76grpc_security_status grpc_security_context_check_peer(
Julien Boeuf54b21922015-02-04 16:39:35 -080077 grpc_security_context *ctx, tsi_peer peer, grpc_security_check_cb cb,
78 void *user_data) {
79 if (ctx == NULL) {
80 tsi_peer_destruct(&peer);
81 return GRPC_SECURITY_ERROR;
82 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080083 return ctx->vtable->check_peer(ctx, peer, cb, user_data);
84}
85
Julien Boeuf54b21922015-02-04 16:39:35 -080086grpc_security_status grpc_channel_security_context_check_call_host(
87 grpc_channel_security_context *ctx, const char *host,
88 grpc_security_check_cb cb, void *user_data) {
89 if (ctx == NULL || ctx->check_call_host == NULL) return GRPC_SECURITY_ERROR;
90 return ctx->check_call_host(ctx, host, cb, user_data);
91}
92
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080093void grpc_security_context_unref(grpc_security_context *ctx) {
94 if (ctx == NULL) return;
95 if (gpr_unref(&ctx->refcount)) ctx->vtable->destroy(ctx);
96}
97
98grpc_security_context *grpc_security_context_ref(grpc_security_context *ctx) {
99 if (ctx == NULL) return NULL;
100 gpr_ref(&ctx->refcount);
101 return ctx;
102}
103
104static void context_pointer_arg_destroy(void *p) {
105 grpc_security_context_unref(p);
106}
107
108static void *context_pointer_arg_copy(void *p) {
109 return grpc_security_context_ref(p);
110}
111
112grpc_arg grpc_security_context_to_arg(grpc_security_context *ctx) {
113 grpc_arg result;
114 result.type = GRPC_ARG_POINTER;
115 result.key = GRPC_SECURITY_CONTEXT_ARG;
116 result.value.pointer.destroy = context_pointer_arg_destroy;
117 result.value.pointer.copy = context_pointer_arg_copy;
118 result.value.pointer.p = ctx;
119 return result;
120}
121
Craig Tillerb5dcec52015-01-13 11:13:42 -0800122grpc_security_context *grpc_security_context_from_arg(const grpc_arg *arg) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800123 if (strcmp(arg->key, GRPC_SECURITY_CONTEXT_ARG)) return NULL;
124 if (arg->type != GRPC_ARG_POINTER) {
125 gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
126 GRPC_SECURITY_CONTEXT_ARG);
127 return NULL;
128 }
129 return arg->value.pointer.p;
130}
131
132grpc_security_context *grpc_find_security_context_in_args(
133 const grpc_channel_args *args) {
134 size_t i;
135 if (args == NULL) return NULL;
136 for (i = 0; i < args->num_args; i++) {
137 grpc_security_context *ctx = grpc_security_context_from_arg(&args->args[i]);
138 if (ctx != NULL) return ctx;
139 }
140 return NULL;
141}
142
nnoble0c475f02014-12-05 15:37:39 -0800143static int check_request_metadata_creds(grpc_credentials *creds) {
144 if (creds != NULL && !grpc_credentials_has_request_metadata(creds)) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800145 gpr_log(GPR_ERROR,
146 "Incompatible credentials for channel security context: needs to "
nnoble0c475f02014-12-05 15:37:39 -0800147 "set request metadata.");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800148 return 0;
149 }
150 return 1;
151}
152
153/* -- Fake implementation. -- */
154
Julien Boeuf54b21922015-02-04 16:39:35 -0800155typedef struct {
156 grpc_channel_security_context base;
157 int call_host_check_is_async;
158} grpc_fake_channel_security_context;
159
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800160static void fake_channel_destroy(grpc_security_context *ctx) {
161 grpc_channel_security_context *c = (grpc_channel_security_context *)ctx;
nnoble0c475f02014-12-05 15:37:39 -0800162 grpc_credentials_unref(c->request_metadata_creds);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800163 gpr_free(ctx);
164}
165
Craig Tillerb5dcec52015-01-13 11:13:42 -0800166static void fake_server_destroy(grpc_security_context *ctx) { gpr_free(ctx); }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800167
168static grpc_security_status fake_channel_create_handshaker(
169 grpc_security_context *ctx, tsi_handshaker **handshaker) {
170 *handshaker = tsi_create_fake_handshaker(1);
171 return GRPC_SECURITY_OK;
172}
173
174static grpc_security_status fake_server_create_handshaker(
175 grpc_security_context *ctx, tsi_handshaker **handshaker) {
176 *handshaker = tsi_create_fake_handshaker(0);
177 return GRPC_SECURITY_OK;
178}
179
180static grpc_security_status fake_check_peer(grpc_security_context *ctx,
Julien Boeuf54b21922015-02-04 16:39:35 -0800181 tsi_peer peer,
182 grpc_security_check_cb cb,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800183 void *user_data) {
184 const char *prop_name;
Julien Boeuf54b21922015-02-04 16:39:35 -0800185 grpc_security_status status = GRPC_SECURITY_OK;
186 if (peer.property_count != 1) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800187 gpr_log(GPR_ERROR, "Fake peers should only have 1 property.");
Julien Boeuf54b21922015-02-04 16:39:35 -0800188 status = GRPC_SECURITY_ERROR;
189 goto end;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800190 }
Julien Boeuf54b21922015-02-04 16:39:35 -0800191 prop_name = peer.properties[0].name;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800192 if (prop_name == NULL ||
193 strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) {
194 gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.",
195 prop_name == NULL ? "<EMPTY>" : prop_name);
Julien Boeuf54b21922015-02-04 16:39:35 -0800196 status = GRPC_SECURITY_ERROR;
197 goto end;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800198 }
Julien Boeuf54b21922015-02-04 16:39:35 -0800199 if (peer.properties[0].type != TSI_PEER_PROPERTY_TYPE_STRING) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800200 gpr_log(GPR_ERROR, "Invalid type of cert type property.");
Julien Boeuf54b21922015-02-04 16:39:35 -0800201 status = GRPC_SECURITY_ERROR;
202 goto end;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800203 }
Julien Boeuf54b21922015-02-04 16:39:35 -0800204 if (strncmp(peer.properties[0].value.string.data, TSI_FAKE_CERTIFICATE_TYPE,
205 peer.properties[0].value.string.length)) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800206 gpr_log(GPR_ERROR, "Invalid value for cert type property.");
Julien Boeuf54b21922015-02-04 16:39:35 -0800207 status = GRPC_SECURITY_ERROR;
208 goto end;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800209 }
Julien Boeuf54b21922015-02-04 16:39:35 -0800210end:
211 tsi_peer_destruct(&peer);
212 return status;
213}
214
215static grpc_security_status fake_channel_check_call_host(
216 grpc_channel_security_context *ctx, const char *host,
217 grpc_security_check_cb cb, void *user_data) {
218 grpc_fake_channel_security_context *c =
219 (grpc_fake_channel_security_context *)ctx;
220 if (c->call_host_check_is_async) {
221 cb(user_data, GRPC_SECURITY_OK);
222 return GRPC_SECURITY_PENDING;
223 } else {
224 return GRPC_SECURITY_OK;
225 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800226}
227
228static grpc_security_context_vtable fake_channel_vtable = {
229 fake_channel_destroy, fake_channel_create_handshaker, fake_check_peer};
230
231static grpc_security_context_vtable fake_server_vtable = {
232 fake_server_destroy, fake_server_create_handshaker, fake_check_peer};
233
234grpc_channel_security_context *grpc_fake_channel_security_context_create(
Julien Boeuf54b21922015-02-04 16:39:35 -0800235 grpc_credentials *request_metadata_creds, int call_host_check_is_async) {
236 grpc_fake_channel_security_context *c =
237 gpr_malloc(sizeof(grpc_fake_channel_security_context));
238 gpr_ref_init(&c->base.base.refcount, 1);
239 c->base.base.is_client_side = 1;
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800240 c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
Julien Boeuf54b21922015-02-04 16:39:35 -0800241 c->base.base.vtable = &fake_channel_vtable;
nnoble0c475f02014-12-05 15:37:39 -0800242 GPR_ASSERT(check_request_metadata_creds(request_metadata_creds));
Julien Boeuf54b21922015-02-04 16:39:35 -0800243 c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds);
244 c->base.check_call_host = fake_channel_check_call_host;
245 c->call_host_check_is_async = call_host_check_is_async;
246 return &c->base;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800247}
248
249grpc_security_context *grpc_fake_server_security_context_create(void) {
250 grpc_security_context *c = gpr_malloc(sizeof(grpc_security_context));
251 gpr_ref_init(&c->refcount, 1);
252 c->vtable = &fake_server_vtable;
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800253 c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800254 return c;
255}
256
257/* --- Ssl implementation. --- */
258
259typedef struct {
260 grpc_channel_security_context base;
261 tsi_ssl_handshaker_factory *handshaker_factory;
Julien Boeuf54b21922015-02-04 16:39:35 -0800262 char *target_name;
263 char *overridden_target_name;
264 tsi_peer peer;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800265} grpc_ssl_channel_security_context;
266
267typedef struct {
268 grpc_security_context base;
269 tsi_ssl_handshaker_factory *handshaker_factory;
270} grpc_ssl_server_security_context;
271
272static void ssl_channel_destroy(grpc_security_context *ctx) {
273 grpc_ssl_channel_security_context *c =
274 (grpc_ssl_channel_security_context *)ctx;
nnoble0c475f02014-12-05 15:37:39 -0800275 grpc_credentials_unref(c->base.request_metadata_creds);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800276 if (c->handshaker_factory != NULL) {
277 tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
278 }
Julien Boeuf54b21922015-02-04 16:39:35 -0800279 if (c->target_name != NULL) gpr_free(c->target_name);
280 if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name);
281 tsi_peer_destruct(&c->peer);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800282 gpr_free(ctx);
283}
284
285static void ssl_server_destroy(grpc_security_context *ctx) {
Craig Tillerb5dcec52015-01-13 11:13:42 -0800286 grpc_ssl_server_security_context *c = (grpc_ssl_server_security_context *)ctx;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800287 if (c->handshaker_factory != NULL) {
288 tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
289 }
290 gpr_free(ctx);
291}
292
293static grpc_security_status ssl_create_handshaker(
294 tsi_ssl_handshaker_factory *handshaker_factory, int is_client,
Julien Boeuf54b21922015-02-04 16:39:35 -0800295 const char *peer_name, tsi_handshaker **handshaker) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800296 tsi_result result = TSI_OK;
297 if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
298 result = tsi_ssl_handshaker_factory_create_handshaker(
Julien Boeuf54b21922015-02-04 16:39:35 -0800299 handshaker_factory, is_client ? peer_name : NULL, handshaker);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800300 if (result != TSI_OK) {
301 gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
302 tsi_result_to_string(result));
303 return GRPC_SECURITY_ERROR;
304 }
305 return GRPC_SECURITY_OK;
306}
307
308static grpc_security_status ssl_channel_create_handshaker(
309 grpc_security_context *ctx, tsi_handshaker **handshaker) {
310 grpc_ssl_channel_security_context *c =
311 (grpc_ssl_channel_security_context *)ctx;
Julien Boeuf54b21922015-02-04 16:39:35 -0800312 return ssl_create_handshaker(c->handshaker_factory, 1,
313 c->overridden_target_name != NULL
314 ? c->overridden_target_name
315 : c->target_name,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800316 handshaker);
317}
318
319static grpc_security_status ssl_server_create_handshaker(
320 grpc_security_context *ctx, tsi_handshaker **handshaker) {
Craig Tillerb5dcec52015-01-13 11:13:42 -0800321 grpc_ssl_server_security_context *c = (grpc_ssl_server_security_context *)ctx;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800322 return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker);
323}
324
Julien Boeuf54b21922015-02-04 16:39:35 -0800325static grpc_security_status ssl_check_peer(const char *peer_name,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800326 const tsi_peer *peer) {
327 /* Check the ALPN. */
328 const tsi_peer_property *p =
329 tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
ctiller48b5a452014-12-10 08:43:47 -0800330 if (p == NULL) {
331 gpr_log(GPR_ERROR, "Missing selected ALPN property.");
332 return GRPC_SECURITY_ERROR;
333 }
334 if (p->type != TSI_PEER_PROPERTY_TYPE_STRING) {
335 gpr_log(GPR_ERROR, "Invalid selected ALPN property.");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800336 return GRPC_SECURITY_ERROR;
337 }
nnoble0c475f02014-12-05 15:37:39 -0800338 if (!grpc_chttp2_is_alpn_version_supported(p->value.string.data,
339 p->value.string.length)) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800340 gpr_log(GPR_ERROR, "Invalid ALPN value.");
341 return GRPC_SECURITY_ERROR;
342 }
343
344 /* Check the peer name if specified. */
Julien Boeuf54b21922015-02-04 16:39:35 -0800345 if (peer_name != NULL &&
346 !tsi_ssl_peer_matches_name(peer, peer_name)) {
347 gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800348 return GRPC_SECURITY_ERROR;
349 }
350 return GRPC_SECURITY_OK;
351}
352
Julien Boeuf54b21922015-02-04 16:39:35 -0800353static grpc_security_status ssl_channel_check_peer(grpc_security_context *ctx,
354 tsi_peer peer,
355 grpc_security_check_cb cb,
356 void *user_data) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800357 grpc_ssl_channel_security_context *c =
358 (grpc_ssl_channel_security_context *)ctx;
Julien Boeuf5882b532015-02-17 15:51:43 -0800359 grpc_security_status status;
360 tsi_peer_destruct(&c->peer);
Julien Boeuf54b21922015-02-04 16:39:35 -0800361 c->peer = peer;
Julien Boeuf5882b532015-02-17 15:51:43 -0800362 status = ssl_check_peer(c->overridden_target_name != NULL
363 ? c->overridden_target_name
364 : c->target_name,
365 &peer);
Julien Boeuf54b21922015-02-04 16:39:35 -0800366 return status;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800367}
368
Julien Boeuf54b21922015-02-04 16:39:35 -0800369static grpc_security_status ssl_server_check_peer(grpc_security_context *ctx,
370 tsi_peer peer,
371 grpc_security_check_cb cb,
372 void *user_data) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800373 /* TODO(jboeuf): Find a way to expose the peer to the authorization layer. */
Julien Boeuf54b21922015-02-04 16:39:35 -0800374 grpc_security_status status = ssl_check_peer(NULL, &peer);
375 tsi_peer_destruct(&peer);
376 return status;
377}
378
379static grpc_security_status ssl_channel_check_call_host(
380 grpc_channel_security_context *ctx, const char *host,
381 grpc_security_check_cb cb, void *user_data) {
382 grpc_ssl_channel_security_context *c =
383 (grpc_ssl_channel_security_context *)ctx;
384
385 if (tsi_ssl_peer_matches_name(&c->peer, host)) return GRPC_SECURITY_OK;
386
387 /* If the target name was overridden, then the original target_name was
388 'checked' transitively during the previous peer check at the end of the
389 handshake. */
390 if (c->overridden_target_name != NULL && !strcmp(host, c->target_name)) {
391 return GRPC_SECURITY_OK;
392 } else {
393 return GRPC_SECURITY_ERROR;
394 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800395}
396
397static grpc_security_context_vtable ssl_channel_vtable = {
398 ssl_channel_destroy, ssl_channel_create_handshaker, ssl_channel_check_peer};
399
400static grpc_security_context_vtable ssl_server_vtable = {
401 ssl_server_destroy, ssl_server_create_handshaker, ssl_server_check_peer};
402
Julien Boeuf026a4172015-02-02 18:36:37 -0800403static gpr_slice default_pem_root_certs;
404
405static void init_default_pem_root_certs(void) {
Julien Boeuf3e001792015-02-20 15:02:36 -0800406 /* First try to load the roots from the environment. */
Julien Boeuf026a4172015-02-02 18:36:37 -0800407 char *default_root_certs_path =
408 gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
409 if (default_root_certs_path == NULL) {
410 default_pem_root_certs = gpr_empty_slice();
411 } else {
412 default_pem_root_certs = gpr_load_file(default_root_certs_path, NULL);
413 gpr_free(default_root_certs_path);
414 }
Julien Boeuf3e001792015-02-20 15:02:36 -0800415
416 /* Fall back to installed certs if needed. */
417 if (GPR_SLICE_IS_EMPTY(default_pem_root_certs)) {
418 default_pem_root_certs = gpr_load_file(installed_roots_path, NULL);
419 }
Julien Boeuf026a4172015-02-02 18:36:37 -0800420}
421
Julien Boeuf1bc21a42015-02-20 10:40:11 -0800422size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
Julien Boeuf026a4172015-02-02 18:36:37 -0800423 /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in
424 loading all the roots once for the lifetime of the process. */
425 static gpr_once once = GPR_ONCE_INIT;
426 gpr_once_init(&once, init_default_pem_root_certs);
427 *pem_root_certs = GPR_SLICE_START_PTR(default_pem_root_certs);
428 return GPR_SLICE_LENGTH(default_pem_root_certs);
429}
430
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800431grpc_security_status grpc_ssl_channel_security_context_create(
nnoble0c475f02014-12-05 15:37:39 -0800432 grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
Julien Boeuf54b21922015-02-04 16:39:35 -0800433 const char *target_name, const char *overridden_target_name,
434 grpc_channel_security_context **ctx) {
ctiller48b5a452014-12-10 08:43:47 -0800435 size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
436 const unsigned char **alpn_protocol_strings =
437 gpr_malloc(sizeof(const char *) * num_alpn_protocols);
438 unsigned char *alpn_protocol_string_lengths =
439 gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800440 tsi_result result = TSI_OK;
441 grpc_ssl_channel_security_context *c;
ctiller48b5a452014-12-10 08:43:47 -0800442 size_t i;
Julien Boeuf026a4172015-02-02 18:36:37 -0800443 const unsigned char *pem_root_certs;
444 size_t pem_root_certs_size;
ctiller48b5a452014-12-10 08:43:47 -0800445
446 for (i = 0; i < num_alpn_protocols; i++) {
447 alpn_protocol_strings[i] =
448 (const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
449 alpn_protocol_string_lengths[i] =
450 strlen(grpc_chttp2_get_alpn_version_index(i));
451 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800452
Julien Boeuf54b21922015-02-04 16:39:35 -0800453 if (config == NULL || target_name == NULL) {
454 gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name.");
ctiller48b5a452014-12-10 08:43:47 -0800455 goto error;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800456 }
nnoble0c475f02014-12-05 15:37:39 -0800457 if (!check_request_metadata_creds(request_metadata_creds)) {
ctiller48b5a452014-12-10 08:43:47 -0800458 goto error;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800459 }
460
461 c = gpr_malloc(sizeof(grpc_ssl_channel_security_context));
462 memset(c, 0, sizeof(grpc_ssl_channel_security_context));
463
464 gpr_ref_init(&c->base.base.refcount, 1);
465 c->base.base.vtable = &ssl_channel_vtable;
466 c->base.base.is_client_side = 1;
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800467 c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
nnoble0c475f02014-12-05 15:37:39 -0800468 c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds);
Julien Boeuf54b21922015-02-04 16:39:35 -0800469 c->base.check_call_host = ssl_channel_check_call_host;
470 if (target_name != NULL) {
471 c->target_name = gpr_strdup(target_name);
472 }
473 if (overridden_target_name != NULL) {
474 c->overridden_target_name = gpr_strdup(overridden_target_name);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800475 }
Julien Boeuf026a4172015-02-02 18:36:37 -0800476 if (config->pem_root_certs == NULL) {
Julien Boeuf1bc21a42015-02-20 10:40:11 -0800477 pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs);
Julien Boeuf026a4172015-02-02 18:36:37 -0800478 if (pem_root_certs == NULL || pem_root_certs_size == 0) {
479 gpr_log(GPR_ERROR, "Could not get default pem root certs.");
480 goto error;
481 }
482 } else {
483 pem_root_certs = config->pem_root_certs;
484 pem_root_certs_size = config->pem_root_certs_size;
485 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800486 result = tsi_create_ssl_client_handshaker_factory(
487 config->pem_private_key, config->pem_private_key_size,
Julien Boeuf026a4172015-02-02 18:36:37 -0800488 config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs,
489 pem_root_certs_size, GRPC_SSL_CIPHER_SUITES, alpn_protocol_strings,
ctiller48b5a452014-12-10 08:43:47 -0800490 alpn_protocol_string_lengths, num_alpn_protocols, &c->handshaker_factory);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800491 if (result != TSI_OK) {
492 gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
493 tsi_result_to_string(result));
494 ssl_channel_destroy(&c->base.base);
495 *ctx = NULL;
ctiller48b5a452014-12-10 08:43:47 -0800496 goto error;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800497 }
498 *ctx = &c->base;
ctiller48b5a452014-12-10 08:43:47 -0800499 gpr_free(alpn_protocol_strings);
500 gpr_free(alpn_protocol_string_lengths);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800501 return GRPC_SECURITY_OK;
ctiller48b5a452014-12-10 08:43:47 -0800502
503error:
504 gpr_free(alpn_protocol_strings);
505 gpr_free(alpn_protocol_string_lengths);
506 return GRPC_SECURITY_ERROR;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800507}
508
509grpc_security_status grpc_ssl_server_security_context_create(
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800510 const grpc_ssl_server_config *config, grpc_security_context **ctx) {
ctiller48b5a452014-12-10 08:43:47 -0800511 size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
512 const unsigned char **alpn_protocol_strings =
513 gpr_malloc(sizeof(const char *) * num_alpn_protocols);
514 unsigned char *alpn_protocol_string_lengths =
515 gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800516 tsi_result result = TSI_OK;
517 grpc_ssl_server_security_context *c;
ctiller48b5a452014-12-10 08:43:47 -0800518 size_t i;
519
520 for (i = 0; i < num_alpn_protocols; i++) {
521 alpn_protocol_strings[i] =
522 (const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
523 alpn_protocol_string_lengths[i] =
524 strlen(grpc_chttp2_get_alpn_version_index(i));
525 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800526
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800527 if (config == NULL || config->num_key_cert_pairs == 0) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800528 gpr_log(GPR_ERROR, "An SSL server needs a key and a cert.");
ctiller48b5a452014-12-10 08:43:47 -0800529 goto error;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800530 }
531 c = gpr_malloc(sizeof(grpc_ssl_server_security_context));
532 memset(c, 0, sizeof(grpc_ssl_server_security_context));
533
534 gpr_ref_init(&c->base.refcount, 1);
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800535 c->base.url_scheme = GRPC_SSL_URL_SCHEME;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800536 c->base.vtable = &ssl_server_vtable;
537 result = tsi_create_ssl_server_handshaker_factory(
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800538 (const unsigned char **)config->pem_private_keys,
539 config->pem_private_keys_sizes,
540 (const unsigned char **)config->pem_cert_chains,
541 config->pem_cert_chains_sizes, config->num_key_cert_pairs,
542 config->pem_root_certs, config->pem_root_certs_size,
543 GRPC_SSL_CIPHER_SUITES, alpn_protocol_strings,
544 alpn_protocol_string_lengths, num_alpn_protocols, &c->handshaker_factory);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800545 if (result != TSI_OK) {
546 gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
547 tsi_result_to_string(result));
548 ssl_server_destroy(&c->base);
549 *ctx = NULL;
ctiller48b5a452014-12-10 08:43:47 -0800550 goto error;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800551 }
552 *ctx = &c->base;
ctiller48b5a452014-12-10 08:43:47 -0800553 gpr_free(alpn_protocol_strings);
554 gpr_free(alpn_protocol_string_lengths);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800555 return GRPC_SECURITY_OK;
ctiller48b5a452014-12-10 08:43:47 -0800556
557error:
558 gpr_free(alpn_protocol_strings);
559 gpr_free(alpn_protocol_string_lengths);
560 return GRPC_SECURITY_ERROR;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800561}
562
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800563/* -- High level objects. -- */
564
jboeuf6ad120e2015-01-12 17:08:15 -0800565grpc_channel *grpc_ssl_channel_create(grpc_credentials *ssl_creds,
566 grpc_credentials *request_metadata_creds,
567 const char *target,
568 const grpc_channel_args *args) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800569 grpc_channel_security_context *ctx = NULL;
570 grpc_channel *channel = NULL;
571 grpc_security_status status = GRPC_SECURITY_OK;
572 size_t i = 0;
Julien Boeuf54b21922015-02-04 16:39:35 -0800573 const char *overridden_target_name = NULL;
David Klempnera1e86932015-01-13 18:13:59 -0800574 grpc_arg arg;
575 grpc_channel_args *new_args;
jboeuf6ad120e2015-01-12 17:08:15 -0800576
yangg4105e2b2015-01-09 14:19:44 -0800577 for (i = 0; args && i < args->num_args; i++) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800578 grpc_arg *arg = &args->args[i];
579 if (!strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) &&
580 arg->type == GRPC_ARG_STRING) {
Julien Boeuf54b21922015-02-04 16:39:35 -0800581 overridden_target_name = arg->value.string;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800582 break;
583 }
584 }
jboeuf6ad120e2015-01-12 17:08:15 -0800585 status = grpc_ssl_channel_security_context_create(
586 request_metadata_creds, grpc_ssl_credentials_get_config(ssl_creds),
Julien Boeuf54b21922015-02-04 16:39:35 -0800587 target, overridden_target_name, &ctx);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800588 if (status != GRPC_SECURITY_OK) {
nnoble0c475f02014-12-05 15:37:39 -0800589 return grpc_lame_client_channel_create();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800590 }
David Klempnera1e86932015-01-13 18:13:59 -0800591 arg.type = GRPC_ARG_STRING;
David Klempnered0cbc82015-01-14 14:46:10 -0800592 arg.key = GRPC_ARG_HTTP2_SCHEME;
David Klempnera1e86932015-01-13 18:13:59 -0800593 arg.value.string = "https";
594 new_args = grpc_channel_args_copy_and_add(args, &arg);
595 channel = grpc_secure_channel_create_internal(target, new_args, ctx);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800596 grpc_security_context_unref(&ctx->base);
David Klempnera1e86932015-01-13 18:13:59 -0800597 grpc_channel_args_destroy(new_args);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800598 return channel;
599}
600
jboeuf6ad120e2015-01-12 17:08:15 -0800601grpc_channel *grpc_fake_transport_security_channel_create(
602 grpc_credentials *fake_creds, grpc_credentials *request_metadata_creds,
603 const char *target, const grpc_channel_args *args) {
604 grpc_channel_security_context *ctx =
Julien Boeuf54b21922015-02-04 16:39:35 -0800605 grpc_fake_channel_security_context_create(request_metadata_creds, 1);
jboeuf6ad120e2015-01-12 17:08:15 -0800606 grpc_channel *channel =
607 grpc_secure_channel_create_internal(target, args, ctx);
608 grpc_security_context_unref(&ctx->base);
609 return channel;
nnoble0c475f02014-12-05 15:37:39 -0800610}
611
jboeuf6ad120e2015-01-12 17:08:15 -0800612grpc_channel *grpc_secure_channel_create_with_factories(
613 const grpc_secure_channel_factory *factories, size_t num_factories,
614 grpc_credentials *creds, const char *target,
nnoble0c475f02014-12-05 15:37:39 -0800615 const grpc_channel_args *args) {
jboeuf6ad120e2015-01-12 17:08:15 -0800616 size_t i;
yangg4105e2b2015-01-09 14:19:44 -0800617 if (creds == NULL) {
618 gpr_log(GPR_ERROR, "No credentials to create a secure channel.");
619 return grpc_lame_client_channel_create();
620 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800621 if (grpc_credentials_has_request_metadata_only(creds)) {
622 gpr_log(GPR_ERROR,
623 "Credentials is insufficient to create a secure channel.");
nnoble0c475f02014-12-05 15:37:39 -0800624 return grpc_lame_client_channel_create();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800625 }
jboeuf6ad120e2015-01-12 17:08:15 -0800626
627 for (i = 0; i < num_factories; i++) {
628 grpc_credentials *composite_creds = NULL;
629 grpc_credentials *transport_security_creds = NULL;
630 transport_security_creds = grpc_credentials_contains_type(
631 creds, factories[i].creds_type, &composite_creds);
632 if (transport_security_creds != NULL) {
633 return factories[i].factory(transport_security_creds, composite_creds,
634 target, args);
635 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800636 }
jboeuf6ad120e2015-01-12 17:08:15 -0800637
638 gpr_log(GPR_ERROR,
639 "Unknown credentials type %s for creating a secure channel.",
640 creds->type);
641 return grpc_lame_client_channel_create();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800642}
643
644grpc_channel *grpc_default_secure_channel_create(
645 const char *target, const grpc_channel_args *args) {
646 return grpc_secure_channel_create(grpc_default_credentials_create(), target,
647 args);
Craig Tiller190d3602015-02-18 09:23:38 -0800648}