blob: ebf72a3abb431acd5a984ca36b1a2c51c5cc32b8 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * 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
Julien Boeuf8ca294e2016-05-02 14:56:30 -070034#include "src/core/lib/security/transport/security_connector.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080035
Julien Boeuf4f4d37c2016-02-24 22:07:36 -080036#include <stdbool.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080037#include <string.h>
38
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080039#include <grpc/support/alloc.h>
Julien Boeuf7fa3f412015-02-24 19:30:41 -080040#include <grpc/support/host_port.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080041#include <grpc/support/log.h>
42#include <grpc/support/slice_buffer.h>
Masood Malekghassemi701af602015-06-03 15:01:17 -070043#include <grpc/support/string_util.h>
Craig Tiller732a8752016-02-22 15:59:19 -080044
Craig Tillerd1697d92016-04-05 16:05:46 -070045#include "src/core/ext/transport/chttp2/alpn/alpn.h"
Craig Tiller85178862016-05-18 16:09:16 -070046#include "src/core/lib/iomgr/load_file.h"
Julien Boeuf8ca294e2016-05-02 14:56:30 -070047#include "src/core/lib/security/context/security_context.h"
48#include "src/core/lib/security/credentials/credentials.h"
49#include "src/core/lib/security/transport/handshake.h"
50#include "src/core/lib/security/transport/secure_endpoint.h"
Craig Tiller9533d042016-03-25 17:11:06 -070051#include "src/core/lib/support/env.h"
Craig Tiller9533d042016-03-25 17:11:06 -070052#include "src/core/lib/support/string.h"
Craig Tiller9533d042016-03-25 17:11:06 -070053#include "src/core/lib/tsi/fake_transport_security.h"
54#include "src/core/lib/tsi/ssl_transport_security.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080055
56/* -- Constants. -- */
57
Nicolas "Pixel" Noble72743822015-02-20 20:59:29 +010058#ifndef INSTALL_PREFIX
Nicolas "Pixel" Noble161ea232015-02-22 05:48:53 +010059static const char *installed_roots_path = "/usr/share/grpc/roots.pem";
Nicolas "Pixel" Noble72743822015-02-20 20:59:29 +010060#else
Craig Tillera82950e2015-09-22 12:33:20 -070061static const char *installed_roots_path =
62 INSTALL_PREFIX "/share/grpc/roots.pem";
Nicolas "Pixel" Noble72743822015-02-20 20:59:29 +010063#endif
64
Julien Boeufa50da472016-01-27 16:23:41 -080065/* -- Overridden default roots. -- */
Julien Boeuf373debd2016-01-27 15:41:12 -080066
Julien Boeufaaebf7a2016-01-28 17:04:42 -080067static grpc_ssl_roots_override_callback ssl_roots_override_cb = NULL;
Julien Boeuf373debd2016-01-27 15:41:12 -080068
Julien Boeufaaebf7a2016-01-28 17:04:42 -080069void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb) {
70 ssl_roots_override_cb = cb;
Julien Boeuf373debd2016-01-27 15:41:12 -080071}
72
Julien Boeuf8d6ec912015-02-24 20:07:59 -080073/* -- Cipher suites. -- */
74
75/* Defines the cipher suites that we accept by default. All these cipher suites
76 are compliant with HTTP2. */
Julien Boeufd43f0c32015-02-24 20:54:12 -080077#define GRPC_SSL_CIPHER_SUITES \
78 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-" \
79 "SHA384:ECDHE-RSA-AES256-GCM-SHA384"
Julien Boeuf8d6ec912015-02-24 20:07:59 -080080
81static gpr_once cipher_suites_once = GPR_ONCE_INIT;
82static const char *cipher_suites = NULL;
83
Craig Tillera82950e2015-09-22 12:33:20 -070084static void init_cipher_suites(void) {
85 char *overridden = gpr_getenv("GRPC_SSL_CIPHER_SUITES");
Julien Boeuf8d6ec912015-02-24 20:07:59 -080086 cipher_suites = overridden != NULL ? overridden : GRPC_SSL_CIPHER_SUITES;
87}
88
Craig Tillera82950e2015-09-22 12:33:20 -070089static const char *ssl_cipher_suites(void) {
90 gpr_once_init(&cipher_suites_once, init_cipher_suites);
Julien Boeuf8d6ec912015-02-24 20:07:59 -080091 return cipher_suites;
92}
93
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080094/* -- Common methods. -- */
95
Julien Boeuf77e8c1c2015-05-13 13:50:59 -070096/* Returns the first property with that name. */
Craig Tillera82950e2015-09-22 12:33:20 -070097const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,
98 const char *name) {
Julien Boeuf77e8c1c2015-05-13 13:50:59 -070099 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -0700100 if (peer == NULL) return NULL;
101 for (i = 0; i < peer->property_count; i++) {
102 const tsi_peer_property *property = &peer->properties[i];
103 if (name == NULL && property->name == NULL) {
104 return property;
Julien Boeuf77e8c1c2015-05-13 13:50:59 -0700105 }
Craig Tillera82950e2015-09-22 12:33:20 -0700106 if (name != NULL && property->name != NULL &&
107 strcmp(property->name, name) == 0) {
108 return property;
109 }
110 }
Julien Boeuf77e8c1c2015-05-13 13:50:59 -0700111 return NULL;
112}
113
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800114void grpc_server_security_connector_shutdown(
115 grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector) {
yang-g5e72a352015-11-20 09:49:36 -0800116 grpc_security_connector_handshake_list *tmp;
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800117 gpr_mu_lock(&connector->mu);
118 while (connector->handshaking_handshakes) {
119 tmp = connector->handshaking_handshakes;
120 grpc_security_handshake_shutdown(
121 exec_ctx, connector->handshaking_handshakes->handshake);
122 connector->handshaking_handshakes = tmp->next;
123 gpr_free(tmp);
yang-g5e72a352015-11-20 09:49:36 -0800124 }
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800125 gpr_mu_unlock(&connector->mu);
yang-g5e7f08a2015-11-19 01:27:43 -0800126}
127
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800128void grpc_channel_security_connector_do_handshake(
129 grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700130 grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer,
131 gpr_timespec deadline, grpc_security_handshake_done_cb cb,
132 void *user_data) {
Craig Tillera82950e2015-09-22 12:33:20 -0700133 if (sc == NULL || nonsecure_endpoint == NULL) {
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700134 gpr_free(read_buffer);
Julien Boeuf366f42c2015-12-16 22:05:46 -0800135 cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
Craig Tillera82950e2015-09-22 12:33:20 -0700136 } else {
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700137 sc->do_handshake(exec_ctx, sc, nonsecure_endpoint, read_buffer, deadline,
138 cb, user_data);
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800139 }
140}
141
142void grpc_server_security_connector_do_handshake(
143 grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
144 grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700145 gpr_slice_buffer *read_buffer, gpr_timespec deadline,
146 grpc_security_handshake_done_cb cb, void *user_data) {
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800147 if (sc == NULL || nonsecure_endpoint == NULL) {
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700148 gpr_free(read_buffer);
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800149 cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
150 } else {
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700151 sc->do_handshake(exec_ctx, sc, acceptor, nonsecure_endpoint, read_buffer,
152 deadline, cb, user_data);
Craig Tillera82950e2015-09-22 12:33:20 -0700153 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800154}
155
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800156void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
157 grpc_security_connector *sc,
158 tsi_peer peer,
159 grpc_security_peer_check_cb cb,
160 void *user_data) {
Craig Tillera82950e2015-09-22 12:33:20 -0700161 if (sc == NULL) {
Julien Boeuf366f42c2015-12-16 22:05:46 -0800162 cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL);
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800163 tsi_peer_destruct(&peer);
Julien Boeuf366f42c2015-12-16 22:05:46 -0800164 } else {
165 sc->vtable->check_peer(exec_ctx, sc, peer, cb, user_data);
Craig Tillera82950e2015-09-22 12:33:20 -0700166 }
Craig Tillera82950e2015-09-22 12:33:20 -0700167}
168
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800169void grpc_channel_security_connector_check_call_host(
Craig Tillera82950e2015-09-22 12:33:20 -0700170 grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800171 const char *host, grpc_auth_context *auth_context,
172 grpc_security_call_host_check_cb cb, void *user_data) {
173 if (sc == NULL || sc->check_call_host == NULL) {
174 cb(exec_ctx, user_data, GRPC_SECURITY_ERROR);
175 } else {
176 sc->check_call_host(exec_ctx, sc, host, auth_context, cb, user_data);
177 }
Julien Boeuf54b21922015-02-04 16:39:35 -0800178}
179
Craig Tiller5d44c062015-07-01 08:55:28 -0700180#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG
Craig Tillera82950e2015-09-22 12:33:20 -0700181grpc_security_connector *grpc_security_connector_ref(
182 grpc_security_connector *sc, const char *file, int line,
183 const char *reason) {
184 if (sc == NULL) return NULL;
185 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
186 "SECURITY_CONNECTOR:%p ref %d -> %d %s", sc,
187 (int)sc->refcount.count, (int)sc->refcount.count + 1, reason);
Craig Tiller5d44c062015-07-01 08:55:28 -0700188#else
Craig Tillera82950e2015-09-22 12:33:20 -0700189grpc_security_connector *grpc_security_connector_ref(
190 grpc_security_connector *sc) {
191 if (sc == NULL) return NULL;
Craig Tiller5d44c062015-07-01 08:55:28 -0700192#endif
Craig Tillera82950e2015-09-22 12:33:20 -0700193 gpr_ref(&sc->refcount);
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700194 return sc;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800195}
196
Craig Tiller5d44c062015-07-01 08:55:28 -0700197#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG
Craig Tillera82950e2015-09-22 12:33:20 -0700198void grpc_security_connector_unref(grpc_security_connector *sc,
199 const char *file, int line,
200 const char *reason) {
201 if (sc == NULL) return;
202 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
203 "SECURITY_CONNECTOR:%p unref %d -> %d %s", sc,
204 (int)sc->refcount.count, (int)sc->refcount.count - 1, reason);
Craig Tiller5d44c062015-07-01 08:55:28 -0700205#else
Craig Tillera82950e2015-09-22 12:33:20 -0700206void grpc_security_connector_unref(grpc_security_connector *sc) {
207 if (sc == NULL) return;
Craig Tiller5d44c062015-07-01 08:55:28 -0700208#endif
Craig Tillera82950e2015-09-22 12:33:20 -0700209 if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc);
Craig Tiller5d44c062015-07-01 08:55:28 -0700210}
211
Craig Tillera82950e2015-09-22 12:33:20 -0700212static void connector_pointer_arg_destroy(void *p) {
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200213 GRPC_SECURITY_CONNECTOR_UNREF(p, "connector_pointer_arg_destroy");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800214}
215
Craig Tillera82950e2015-09-22 12:33:20 -0700216static void *connector_pointer_arg_copy(void *p) {
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200217 return GRPC_SECURITY_CONNECTOR_REF(p, "connector_pointer_arg_copy");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800218}
219
Craig Tiller5de79ee2016-01-25 08:16:02 -0800220static int connector_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); }
Craig Tilleredc2fff2016-01-13 06:54:27 -0800221
222static const grpc_arg_pointer_vtable connector_pointer_vtable = {
Craig Tiller5de79ee2016-01-25 08:16:02 -0800223 connector_pointer_arg_copy, connector_pointer_arg_destroy,
224 connector_pointer_cmp};
Craig Tilleredc2fff2016-01-13 06:54:27 -0800225
Craig Tillera82950e2015-09-22 12:33:20 -0700226grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800227 grpc_arg result;
228 result.type = GRPC_ARG_POINTER;
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700229 result.key = GRPC_SECURITY_CONNECTOR_ARG;
Craig Tilleredc2fff2016-01-13 06:54:27 -0800230 result.value.pointer.vtable = &connector_pointer_vtable;
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700231 result.value.pointer.p = sc;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800232 return result;
233}
234
Craig Tillera82950e2015-09-22 12:33:20 -0700235grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) {
236 if (strcmp(arg->key, GRPC_SECURITY_CONNECTOR_ARG)) return NULL;
237 if (arg->type != GRPC_ARG_POINTER) {
238 gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
239 GRPC_SECURITY_CONNECTOR_ARG);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800240 return NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700241 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800242 return arg->value.pointer.p;
243}
244
Craig Tillera82950e2015-09-22 12:33:20 -0700245grpc_security_connector *grpc_find_security_connector_in_args(
246 const grpc_channel_args *args) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800247 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -0700248 if (args == NULL) return NULL;
249 for (i = 0; i < args->num_args; i++) {
250 grpc_security_connector *sc =
251 grpc_security_connector_from_arg(&args->args[i]);
252 if (sc != NULL) return sc;
253 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800254 return NULL;
255}
256
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800257/* -- Fake implementation. -- */
258
Craig Tillera82950e2015-09-22 12:33:20 -0700259static void fake_channel_destroy(grpc_security_connector *sc) {
260 grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
Julien Boeuf441176d2015-10-09 21:14:07 -0700261 grpc_call_credentials_unref(c->request_metadata_creds);
Craig Tillera82950e2015-09-22 12:33:20 -0700262 gpr_free(sc);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800263}
264
Craig Tillera82950e2015-09-22 12:33:20 -0700265static void fake_server_destroy(grpc_security_connector *sc) {
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800266 grpc_server_security_connector *c = (grpc_server_security_connector *)sc;
267 gpr_mu_destroy(&c->mu);
Craig Tillera82950e2015-09-22 12:33:20 -0700268 gpr_free(sc);
Julien Boeuf84d964a2015-04-29 11:31:06 -0700269}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800270
Julien Boeuf366f42c2015-12-16 22:05:46 -0800271static void fake_check_peer(grpc_exec_ctx *exec_ctx,
272 grpc_security_connector *sc, tsi_peer peer,
273 grpc_security_peer_check_cb cb, void *user_data) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800274 const char *prop_name;
Julien Boeuf54b21922015-02-04 16:39:35 -0800275 grpc_security_status status = GRPC_SECURITY_OK;
Julien Boeuf366f42c2015-12-16 22:05:46 -0800276 grpc_auth_context *auth_context = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700277 if (peer.property_count != 1) {
278 gpr_log(GPR_ERROR, "Fake peers should only have 1 property.");
279 status = GRPC_SECURITY_ERROR;
280 goto end;
281 }
Julien Boeuf54b21922015-02-04 16:39:35 -0800282 prop_name = peer.properties[0].name;
Craig Tillera82950e2015-09-22 12:33:20 -0700283 if (prop_name == NULL ||
284 strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) {
285 gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.",
286 prop_name == NULL ? "<EMPTY>" : prop_name);
287 status = GRPC_SECURITY_ERROR;
288 goto end;
289 }
290 if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE,
291 peer.properties[0].value.length)) {
292 gpr_log(GPR_ERROR, "Invalid value for cert type property.");
293 status = GRPC_SECURITY_ERROR;
294 goto end;
295 }
Julien Boeuf366f42c2015-12-16 22:05:46 -0800296 auth_context = grpc_auth_context_create(NULL);
Craig Tillera82950e2015-09-22 12:33:20 -0700297 grpc_auth_context_add_cstring_property(
Julien Boeuf366f42c2015-12-16 22:05:46 -0800298 auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
Craig Tillera82950e2015-09-22 12:33:20 -0700299 GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
Julien Boeuf84d964a2015-04-29 11:31:06 -0700300
Julien Boeuf54b21922015-02-04 16:39:35 -0800301end:
Julien Boeuf366f42c2015-12-16 22:05:46 -0800302 cb(exec_ctx, user_data, status, auth_context);
Julien Boeuf366f42c2015-12-16 22:05:46 -0800303 grpc_auth_context_unref(auth_context);
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800304 tsi_peer_destruct(&peer);
Julien Boeuf54b21922015-02-04 16:39:35 -0800305}
306
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800307static void fake_channel_check_call_host(grpc_exec_ctx *exec_ctx,
308 grpc_channel_security_connector *sc,
309 const char *host,
310 grpc_auth_context *auth_context,
311 grpc_security_call_host_check_cb cb,
312 void *user_data) {
313 cb(exec_ctx, user_data, GRPC_SECURITY_OK);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800314}
315
Craig Tillera82950e2015-09-22 12:33:20 -0700316static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx,
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800317 grpc_channel_security_connector *sc,
Craig Tillera82950e2015-09-22 12:33:20 -0700318 grpc_endpoint *nonsecure_endpoint,
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700319 gpr_slice_buffer *read_buffer,
Craig Tiller449c64b2016-06-13 16:26:50 -0700320 gpr_timespec deadline,
Craig Tillera82950e2015-09-22 12:33:20 -0700321 grpc_security_handshake_done_cb cb,
322 void *user_data) {
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800323 grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(1), &sc->base,
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700324 true, nonsecure_endpoint, read_buffer, deadline,
325 cb, user_data);
Julien Boeuf87047d72015-08-21 14:30:33 -0700326}
327
Mark D. Rotha3e7bd82016-08-04 11:17:22 -0700328static void fake_server_do_handshake(
329 grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
330 grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
331 gpr_slice_buffer *read_buffer, gpr_timespec deadline,
332 grpc_security_handshake_done_cb cb, void *user_data) {
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800333 grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(0), &sc->base,
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700334 false, nonsecure_endpoint, read_buffer, deadline,
335 cb, user_data);
Julien Boeuf87047d72015-08-21 14:30:33 -0700336}
337
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700338static grpc_security_connector_vtable fake_channel_vtable = {
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800339 fake_channel_destroy, fake_check_peer};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800340
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800341static grpc_security_connector_vtable fake_server_vtable = {fake_server_destroy,
342 fake_check_peer};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800343
Craig Tillera82950e2015-09-22 12:33:20 -0700344grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800345 grpc_call_credentials *request_metadata_creds) {
346 grpc_channel_security_connector *c = gpr_malloc(sizeof(*c));
347 memset(c, 0, sizeof(*c));
348 gpr_ref_init(&c->base.refcount, 1);
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800349 c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
350 c->base.vtable = &fake_channel_vtable;
Craig Tillerbe52c6e2016-01-04 15:35:26 -0800351 c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds);
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800352 c->check_call_host = fake_channel_check_call_host;
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800353 c->do_handshake = fake_channel_do_handshake;
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800354 return c;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800355}
356
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800357grpc_server_security_connector *grpc_fake_server_security_connector_create(
358 void) {
359 grpc_server_security_connector *c =
360 gpr_malloc(sizeof(grpc_server_security_connector));
361 memset(c, 0, sizeof(*c));
362 gpr_ref_init(&c->base.refcount, 1);
363 c->base.vtable = &fake_server_vtable;
364 c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
365 c->do_handshake = fake_server_do_handshake;
yang-g5e7f08a2015-11-19 01:27:43 -0800366 gpr_mu_init(&c->mu);
yang-g5e72a352015-11-20 09:49:36 -0800367 return c;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800368}
369
370/* --- Ssl implementation. --- */
371
Craig Tillera82950e2015-09-22 12:33:20 -0700372typedef struct {
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700373 grpc_channel_security_connector base;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800374 tsi_ssl_handshaker_factory *handshaker_factory;
Julien Boeuf54b21922015-02-04 16:39:35 -0800375 char *target_name;
376 char *overridden_target_name;
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700377} grpc_ssl_channel_security_connector;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800378
Craig Tillera82950e2015-09-22 12:33:20 -0700379typedef struct {
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800380 grpc_server_security_connector base;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800381 tsi_ssl_handshaker_factory *handshaker_factory;
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700382} grpc_ssl_server_security_connector;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800383
Craig Tillera82950e2015-09-22 12:33:20 -0700384static void ssl_channel_destroy(grpc_security_connector *sc) {
385 grpc_ssl_channel_security_connector *c =
386 (grpc_ssl_channel_security_connector *)sc;
Julien Boeuf441176d2015-10-09 21:14:07 -0700387 grpc_call_credentials_unref(c->base.request_metadata_creds);
Craig Tillera82950e2015-09-22 12:33:20 -0700388 if (c->handshaker_factory != NULL) {
389 tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
390 }
391 if (c->target_name != NULL) gpr_free(c->target_name);
392 if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name);
Craig Tillera82950e2015-09-22 12:33:20 -0700393 gpr_free(sc);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800394}
395
Craig Tillera82950e2015-09-22 12:33:20 -0700396static void ssl_server_destroy(grpc_security_connector *sc) {
397 grpc_ssl_server_security_connector *c =
398 (grpc_ssl_server_security_connector *)sc;
yang-g5e7f08a2015-11-19 01:27:43 -0800399
Craig Tillera82950e2015-09-22 12:33:20 -0700400 if (c->handshaker_factory != NULL) {
401 tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
402 }
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800403 gpr_mu_destroy(&c->base.mu);
Craig Tillera82950e2015-09-22 12:33:20 -0700404 gpr_free(sc);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800405}
406
Craig Tillera82950e2015-09-22 12:33:20 -0700407static grpc_security_status ssl_create_handshaker(
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800408 tsi_ssl_handshaker_factory *handshaker_factory, bool is_client,
Craig Tillera82950e2015-09-22 12:33:20 -0700409 const char *peer_name, tsi_handshaker **handshaker) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800410 tsi_result result = TSI_OK;
Craig Tillera82950e2015-09-22 12:33:20 -0700411 if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
412 result = tsi_ssl_handshaker_factory_create_handshaker(
413 handshaker_factory, is_client ? peer_name : NULL, handshaker);
414 if (result != TSI_OK) {
415 gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
416 tsi_result_to_string(result));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800417 return GRPC_SECURITY_ERROR;
Craig Tillera82950e2015-09-22 12:33:20 -0700418 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800419 return GRPC_SECURITY_OK;
420}
421
Craig Tillera82950e2015-09-22 12:33:20 -0700422static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx,
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800423 grpc_channel_security_connector *sc,
Craig Tillera82950e2015-09-22 12:33:20 -0700424 grpc_endpoint *nonsecure_endpoint,
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700425 gpr_slice_buffer *read_buffer,
Craig Tiller449c64b2016-06-13 16:26:50 -0700426 gpr_timespec deadline,
Craig Tillera82950e2015-09-22 12:33:20 -0700427 grpc_security_handshake_done_cb cb,
428 void *user_data) {
429 grpc_ssl_channel_security_connector *c =
430 (grpc_ssl_channel_security_connector *)sc;
Julien Boeufdb5282b2015-08-21 15:23:52 -0700431 tsi_handshaker *handshaker;
Craig Tillera82950e2015-09-22 12:33:20 -0700432 grpc_security_status status = ssl_create_handshaker(
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800433 c->handshaker_factory, true,
Craig Tillera82950e2015-09-22 12:33:20 -0700434 c->overridden_target_name != NULL ? c->overridden_target_name
435 : c->target_name,
436 &handshaker);
437 if (status != GRPC_SECURITY_OK) {
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700438 gpr_free(read_buffer);
Julien Boeuf366f42c2015-12-16 22:05:46 -0800439 cb(exec_ctx, user_data, status, NULL, NULL);
Craig Tillera82950e2015-09-22 12:33:20 -0700440 } else {
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800441 grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700442 nonsecure_endpoint, read_buffer, deadline, cb,
443 user_data);
Craig Tillera82950e2015-09-22 12:33:20 -0700444 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800445}
446
Mark D. Rotha3e7bd82016-08-04 11:17:22 -0700447static void ssl_server_do_handshake(
448 grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
449 grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
450 gpr_slice_buffer *read_buffer, gpr_timespec deadline,
451 grpc_security_handshake_done_cb cb, void *user_data) {
Craig Tillera82950e2015-09-22 12:33:20 -0700452 grpc_ssl_server_security_connector *c =
453 (grpc_ssl_server_security_connector *)sc;
Julien Boeufdb5282b2015-08-21 15:23:52 -0700454 tsi_handshaker *handshaker;
Craig Tillera82950e2015-09-22 12:33:20 -0700455 grpc_security_status status =
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800456 ssl_create_handshaker(c->handshaker_factory, false, NULL, &handshaker);
Craig Tillera82950e2015-09-22 12:33:20 -0700457 if (status != GRPC_SECURITY_OK) {
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700458 gpr_free(read_buffer);
Julien Boeuf366f42c2015-12-16 22:05:46 -0800459 cb(exec_ctx, user_data, status, NULL, NULL);
Craig Tillera82950e2015-09-22 12:33:20 -0700460 } else {
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800461 grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, false,
Mark D. Roth7d9f2762016-08-04 11:06:49 -0700462 nonsecure_endpoint, read_buffer, deadline, cb,
463 user_data);
Craig Tillera82950e2015-09-22 12:33:20 -0700464 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800465}
466
Craig Tillera82950e2015-09-22 12:33:20 -0700467static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) {
Craig Tillerdeb49dd2015-02-25 11:58:49 -0800468 char *allocated_name = NULL;
469 int r;
470
Craig Tillera82950e2015-09-22 12:33:20 -0700471 if (strchr(peer_name, ':') != NULL) {
472 char *ignored_port;
473 gpr_split_host_port(peer_name, &allocated_name, &ignored_port);
474 gpr_free(ignored_port);
475 peer_name = allocated_name;
476 if (!peer_name) return 0;
477 }
478 r = tsi_ssl_peer_matches_name(peer, peer_name);
479 gpr_free(allocated_name);
Craig Tillerdeb49dd2015-02-25 11:58:49 -0800480 return r;
481}
482
Craig Tillera82950e2015-09-22 12:33:20 -0700483grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) {
Julien Boeuf84d964a2015-04-29 11:31:06 -0700484 size_t i;
Julien Boeuf84d964a2015-04-29 11:31:06 -0700485 grpc_auth_context *ctx = NULL;
Julien Boeufea456fc2015-07-07 15:23:30 -0700486 const char *peer_identity_property_name = NULL;
Julien Boeufa701ade2015-06-18 15:23:40 +0200487
488 /* The caller has checked the certificate type property. */
Craig Tillera82950e2015-09-22 12:33:20 -0700489 GPR_ASSERT(peer->property_count >= 1);
490 ctx = grpc_auth_context_create(NULL);
491 grpc_auth_context_add_cstring_property(
492 ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
493 GRPC_SSL_TRANSPORT_SECURITY_TYPE);
494 for (i = 0; i < peer->property_count; i++) {
495 const tsi_peer_property *prop = &peer->properties[i];
496 if (prop->name == NULL) continue;
497 if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
498 /* If there is no subject alt name, have the CN as the identity. */
499 if (peer_identity_property_name == NULL) {
500 peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME;
501 }
502 grpc_auth_context_add_property(ctx, GRPC_X509_CN_PROPERTY_NAME,
503 prop->value.data, prop->value.length);
504 } else if (strcmp(prop->name,
505 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
506 peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME;
507 grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME,
508 prop->value.data, prop->value.length);
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700509 } else if (strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0) {
510 grpc_auth_context_add_property(ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME,
511 prop->value.data, prop->value.length);
Julien Boeuf84d964a2015-04-29 11:31:06 -0700512 }
Craig Tillera82950e2015-09-22 12:33:20 -0700513 }
514 if (peer_identity_property_name != NULL) {
515 GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
516 ctx, peer_identity_property_name) == 1);
517 }
Julien Boeuf84d964a2015-04-29 11:31:06 -0700518 return ctx;
519}
520
Craig Tillera82950e2015-09-22 12:33:20 -0700521static grpc_security_status ssl_check_peer(grpc_security_connector *sc,
522 const char *peer_name,
Julien Boeuf366f42c2015-12-16 22:05:46 -0800523 const tsi_peer *peer,
524 grpc_auth_context **auth_context) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800525 /* Check the ALPN. */
Craig Tillera82950e2015-09-22 12:33:20 -0700526 const tsi_peer_property *p =
527 tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
528 if (p == NULL) {
529 gpr_log(GPR_ERROR, "Missing selected ALPN property.");
530 return GRPC_SECURITY_ERROR;
531 }
532 if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) {
533 gpr_log(GPR_ERROR, "Invalid ALPN value.");
534 return GRPC_SECURITY_ERROR;
535 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800536
537 /* Check the peer name if specified. */
Craig Tillera82950e2015-09-22 12:33:20 -0700538 if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) {
539 gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name);
540 return GRPC_SECURITY_ERROR;
541 }
Julien Boeuf366f42c2015-12-16 22:05:46 -0800542 *auth_context = tsi_ssl_peer_to_auth_context(peer);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800543 return GRPC_SECURITY_OK;
544}
545
Craig Tillerbe52c6e2016-01-04 15:35:26 -0800546static void ssl_channel_check_peer(grpc_exec_ctx *exec_ctx,
547 grpc_security_connector *sc, tsi_peer peer,
548 grpc_security_peer_check_cb cb,
549 void *user_data) {
Craig Tillera82950e2015-09-22 12:33:20 -0700550 grpc_ssl_channel_security_connector *c =
551 (grpc_ssl_channel_security_connector *)sc;
Julien Boeuf5882b532015-02-17 15:51:43 -0800552 grpc_security_status status;
Julien Boeuf366f42c2015-12-16 22:05:46 -0800553 grpc_auth_context *auth_context = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700554 status = ssl_check_peer(sc, c->overridden_target_name != NULL
555 ? c->overridden_target_name
556 : c->target_name,
Julien Boeuf366f42c2015-12-16 22:05:46 -0800557 &peer, &auth_context);
558 cb(exec_ctx, user_data, status, auth_context);
559 grpc_auth_context_unref(auth_context);
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800560 tsi_peer_destruct(&peer);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800561}
562
Craig Tillerbe52c6e2016-01-04 15:35:26 -0800563static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx,
564 grpc_security_connector *sc, tsi_peer peer,
565 grpc_security_peer_check_cb cb,
566 void *user_data) {
Julien Boeuf366f42c2015-12-16 22:05:46 -0800567 grpc_auth_context *auth_context = NULL;
568 grpc_security_status status = ssl_check_peer(sc, NULL, &peer, &auth_context);
Craig Tillera82950e2015-09-22 12:33:20 -0700569 tsi_peer_destruct(&peer);
Julien Boeuf366f42c2015-12-16 22:05:46 -0800570 cb(exec_ctx, user_data, status, auth_context);
571 grpc_auth_context_unref(auth_context);
Julien Boeuf54b21922015-02-04 16:39:35 -0800572}
573
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700574static void add_shallow_auth_property_to_peer(tsi_peer *peer,
575 const grpc_auth_property *prop,
576 const char *tsi_prop_name) {
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800577 tsi_peer_property *tsi_prop = &peer->properties[peer->property_count++];
578 tsi_prop->name = (char *)tsi_prop_name;
579 tsi_prop->value.data = prop->value;
580 tsi_prop->value.length = prop->value_length;
581}
582
583tsi_peer tsi_shallow_peer_from_ssl_auth_context(
584 const grpc_auth_context *auth_context) {
585 size_t max_num_props = 0;
586 grpc_auth_property_iterator it;
587 const grpc_auth_property *prop;
588 tsi_peer peer;
589 memset(&peer, 0, sizeof(peer));
590
591 it = grpc_auth_context_property_iterator(auth_context);
592 while (grpc_auth_property_iterator_next(&it) != NULL) max_num_props++;
593
594 if (max_num_props > 0) {
595 peer.properties = gpr_malloc(max_num_props * sizeof(tsi_peer_property));
596 it = grpc_auth_context_property_iterator(auth_context);
597 while ((prop = grpc_auth_property_iterator_next(&it)) != NULL) {
598 if (strcmp(prop->name, GRPC_X509_SAN_PROPERTY_NAME) == 0) {
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700599 add_shallow_auth_property_to_peer(
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800600 &peer, prop, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY);
601 } else if (strcmp(prop->name, GRPC_X509_CN_PROPERTY_NAME) == 0) {
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700602 add_shallow_auth_property_to_peer(
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800603 &peer, prop, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY);
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700604 } else if (strcmp(prop->name, GRPC_X509_PEM_CERT_PROPERTY_NAME) == 0) {
605 add_shallow_auth_property_to_peer(&peer, prop,
606 TSI_X509_PEM_CERT_PROPERTY);
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800607 }
608 }
609 }
610 return peer;
611}
612
613void tsi_shallow_peer_destruct(tsi_peer *peer) {
614 if (peer->properties != NULL) gpr_free(peer->properties);
615}
616
617static void ssl_channel_check_call_host(grpc_exec_ctx *exec_ctx,
618 grpc_channel_security_connector *sc,
619 const char *host,
620 grpc_auth_context *auth_context,
621 grpc_security_call_host_check_cb cb,
622 void *user_data) {
Craig Tillera82950e2015-09-22 12:33:20 -0700623 grpc_ssl_channel_security_connector *c =
624 (grpc_ssl_channel_security_connector *)sc;
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800625 grpc_security_status status = GRPC_SECURITY_ERROR;
626 tsi_peer peer = tsi_shallow_peer_from_ssl_auth_context(auth_context);
627 if (ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK;
Julien Boeuf54b21922015-02-04 16:39:35 -0800628
629 /* If the target name was overridden, then the original target_name was
630 'checked' transitively during the previous peer check at the end of the
631 handshake. */
Craig Tillera82950e2015-09-22 12:33:20 -0700632 if (c->overridden_target_name != NULL && strcmp(host, c->target_name) == 0) {
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800633 status = GRPC_SECURITY_OK;
Craig Tillera82950e2015-09-22 12:33:20 -0700634 }
Julien Boeuf1d9ac662015-12-17 21:35:47 -0800635 cb(exec_ctx, user_data, status);
636 tsi_shallow_peer_destruct(&peer);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800637}
638
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700639static grpc_security_connector_vtable ssl_channel_vtable = {
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800640 ssl_channel_destroy, ssl_channel_check_peer};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800641
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700642static grpc_security_connector_vtable ssl_server_vtable = {
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800643 ssl_server_destroy, ssl_server_check_peer};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800644
Julien Boeuf373debd2016-01-27 15:41:12 -0800645static gpr_slice compute_default_pem_root_certs_once(void) {
646 gpr_slice result = gpr_empty_slice();
Julien Boeuf026a4172015-02-02 18:36:37 -0800647
Julien Boeuf3e001792015-02-20 15:02:36 -0800648 /* First try to load the roots from the environment. */
Craig Tillera82950e2015-09-22 12:33:20 -0700649 char *default_root_certs_path =
650 gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
Julien Boeuf373debd2016-01-27 15:41:12 -0800651 if (default_root_certs_path != NULL) {
Craig Tiller4727b9b2016-05-17 17:19:19 -0700652 GRPC_LOG_IF_ERROR("load_file",
Craig Tiller85178862016-05-18 16:09:16 -0700653 grpc_load_file(default_root_certs_path, 0, &result));
Craig Tillera82950e2015-09-22 12:33:20 -0700654 gpr_free(default_root_certs_path);
655 }
Julien Boeuf3e001792015-02-20 15:02:36 -0800656
Julien Boeuf434eda42016-01-28 17:06:57 -0800657 /* Try overridden roots if needed. */
Julien Boeufaaebf7a2016-01-28 17:04:42 -0800658 grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL;
659 if (GPR_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != NULL) {
660 char *pem_root_certs = NULL;
661 ovrd_res = ssl_roots_override_cb(&pem_root_certs);
662 if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) {
663 GPR_ASSERT(pem_root_certs != NULL);
664 result = gpr_slice_new(pem_root_certs, strlen(pem_root_certs), gpr_free);
665 }
Craig Tillera82950e2015-09-22 12:33:20 -0700666 }
Julien Boeuf373debd2016-01-27 15:41:12 -0800667
668 /* Fall back to installed certs if needed. */
Julien Boeufaaebf7a2016-01-28 17:04:42 -0800669 if (GPR_SLICE_IS_EMPTY(result) &&
670 ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
Craig Tiller4727b9b2016-05-17 17:19:19 -0700671 GRPC_LOG_IF_ERROR("load_file",
Craig Tiller85178862016-05-18 16:09:16 -0700672 grpc_load_file(installed_roots_path, 0, &result));
Julien Boeuf373debd2016-01-27 15:41:12 -0800673 }
674 return result;
675}
676
677static gpr_slice default_pem_root_certs;
678
679static void init_default_pem_root_certs(void) {
680 default_pem_root_certs = compute_default_pem_root_certs_once();
681}
682
683gpr_slice grpc_get_default_ssl_roots_for_testing(void) {
684 return compute_default_pem_root_certs_once();
Julien Boeuf026a4172015-02-02 18:36:37 -0800685}
686
Deepak Lukosedba4c5f2016-03-25 12:54:25 -0700687static tsi_client_certificate_request_type
688get_tsi_client_certificate_request_type(
689 grpc_ssl_client_certificate_request_type grpc_request_type) {
690 switch (grpc_request_type) {
691 case GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE:
692 return TSI_DONT_REQUEST_CLIENT_CERTIFICATE;
693
694 case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
695 return TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY;
696
697 case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY:
698 return TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY;
699
700 case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
701 return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY;
702
703 case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY:
704 return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY;
705
706 default:
707 // Is this a sane default
708 return TSI_DONT_REQUEST_CLIENT_CERTIFICATE;
709 }
710}
711
Craig Tillera82950e2015-09-22 12:33:20 -0700712size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
Julien Boeuf026a4172015-02-02 18:36:37 -0800713 /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in
714 loading all the roots once for the lifetime of the process. */
715 static gpr_once once = GPR_ONCE_INIT;
Craig Tillera82950e2015-09-22 12:33:20 -0700716 gpr_once_init(&once, init_default_pem_root_certs);
717 *pem_root_certs = GPR_SLICE_START_PTR(default_pem_root_certs);
718 return GPR_SLICE_LENGTH(default_pem_root_certs);
Julien Boeuf026a4172015-02-02 18:36:37 -0800719}
720
Craig Tillera82950e2015-09-22 12:33:20 -0700721grpc_security_status grpc_ssl_channel_security_connector_create(
Craig Tillerb1136492015-11-18 11:30:17 -0800722 grpc_call_credentials *request_metadata_creds,
723 const grpc_ssl_config *config, const char *target_name,
724 const char *overridden_target_name, grpc_channel_security_connector **sc) {
Craig Tillera82950e2015-09-22 12:33:20 -0700725 size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
726 const unsigned char **alpn_protocol_strings =
727 gpr_malloc(sizeof(const char *) * num_alpn_protocols);
728 unsigned char *alpn_protocol_string_lengths =
729 gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800730 tsi_result result = TSI_OK;
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700731 grpc_ssl_channel_security_connector *c;
ctiller48b5a452014-12-10 08:43:47 -0800732 size_t i;
Julien Boeuf026a4172015-02-02 18:36:37 -0800733 const unsigned char *pem_root_certs;
734 size_t pem_root_certs_size;
Julien Boeuf7fa3f412015-02-24 19:30:41 -0800735 char *port;
ctiller48b5a452014-12-10 08:43:47 -0800736
Craig Tillera82950e2015-09-22 12:33:20 -0700737 for (i = 0; i < num_alpn_protocols; i++) {
738 alpn_protocol_strings[i] =
739 (const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
740 alpn_protocol_string_lengths[i] =
741 (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i));
742 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800743
Craig Tillera82950e2015-09-22 12:33:20 -0700744 if (config == NULL || target_name == NULL) {
745 gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name.");
746 goto error;
747 }
Craig Tillera82950e2015-09-22 12:33:20 -0700748 if (config->pem_root_certs == NULL) {
749 pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs);
750 if (pem_root_certs == NULL || pem_root_certs_size == 0) {
751 gpr_log(GPR_ERROR, "Could not get default pem root certs.");
yang-g46f2d342015-08-24 10:43:51 -0700752 goto error;
753 }
Craig Tillera82950e2015-09-22 12:33:20 -0700754 } else {
755 pem_root_certs = config->pem_root_certs;
756 pem_root_certs_size = config->pem_root_certs_size;
757 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800758
Craig Tillera82950e2015-09-22 12:33:20 -0700759 c = gpr_malloc(sizeof(grpc_ssl_channel_security_connector));
760 memset(c, 0, sizeof(grpc_ssl_channel_security_connector));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800761
Craig Tillera82950e2015-09-22 12:33:20 -0700762 gpr_ref_init(&c->base.base.refcount, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800763 c->base.base.vtable = &ssl_channel_vtable;
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800764 c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
Julien Boeuf441176d2015-10-09 21:14:07 -0700765 c->base.request_metadata_creds =
766 grpc_call_credentials_ref(request_metadata_creds);
Julien Boeuf54b21922015-02-04 16:39:35 -0800767 c->base.check_call_host = ssl_channel_check_call_host;
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800768 c->base.do_handshake = ssl_channel_do_handshake;
Craig Tillera82950e2015-09-22 12:33:20 -0700769 gpr_split_host_port(target_name, &c->target_name, &port);
770 gpr_free(port);
771 if (overridden_target_name != NULL) {
772 c->overridden_target_name = gpr_strdup(overridden_target_name);
773 }
774 result = tsi_create_ssl_client_handshaker_factory(
775 config->pem_private_key, config->pem_private_key_size,
776 config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs,
777 pem_root_certs_size, ssl_cipher_suites(), alpn_protocol_strings,
778 alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols,
779 &c->handshaker_factory);
780 if (result != TSI_OK) {
781 gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
782 tsi_result_to_string(result));
783 ssl_channel_destroy(&c->base.base);
784 *sc = NULL;
785 goto error;
786 }
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700787 *sc = &c->base;
Craig Tiller565b18b2015-09-23 10:09:42 -0700788 gpr_free((void *)alpn_protocol_strings);
Craig Tillera82950e2015-09-22 12:33:20 -0700789 gpr_free(alpn_protocol_string_lengths);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800790 return GRPC_SECURITY_OK;
ctiller48b5a452014-12-10 08:43:47 -0800791
792error:
Craig Tiller565b18b2015-09-23 10:09:42 -0700793 gpr_free((void *)alpn_protocol_strings);
Craig Tillera82950e2015-09-22 12:33:20 -0700794 gpr_free(alpn_protocol_string_lengths);
ctiller48b5a452014-12-10 08:43:47 -0800795 return GRPC_SECURITY_ERROR;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800796}
797
Craig Tillera82950e2015-09-22 12:33:20 -0700798grpc_security_status grpc_ssl_server_security_connector_create(
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800799 const grpc_ssl_server_config *config, grpc_server_security_connector **sc) {
Craig Tillera82950e2015-09-22 12:33:20 -0700800 size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
801 const unsigned char **alpn_protocol_strings =
802 gpr_malloc(sizeof(const char *) * num_alpn_protocols);
803 unsigned char *alpn_protocol_string_lengths =
804 gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800805 tsi_result result = TSI_OK;
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700806 grpc_ssl_server_security_connector *c;
ctiller48b5a452014-12-10 08:43:47 -0800807 size_t i;
808
Craig Tillera82950e2015-09-22 12:33:20 -0700809 for (i = 0; i < num_alpn_protocols; i++) {
810 alpn_protocol_strings[i] =
811 (const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
812 alpn_protocol_string_lengths[i] =
813 (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i));
814 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800815
Craig Tillera82950e2015-09-22 12:33:20 -0700816 if (config == NULL || config->num_key_cert_pairs == 0) {
817 gpr_log(GPR_ERROR, "An SSL server needs a key and a cert.");
818 goto error;
819 }
820 c = gpr_malloc(sizeof(grpc_ssl_server_security_connector));
821 memset(c, 0, sizeof(grpc_ssl_server_security_connector));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800822
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800823 gpr_ref_init(&c->base.base.refcount, 1);
824 c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
825 c->base.base.vtable = &ssl_server_vtable;
Deepak Lukosedba4c5f2016-03-25 12:54:25 -0700826 result = tsi_create_ssl_server_handshaker_factory_ex(
Craig Tillera82950e2015-09-22 12:33:20 -0700827 (const unsigned char **)config->pem_private_keys,
828 config->pem_private_keys_sizes,
829 (const unsigned char **)config->pem_cert_chains,
830 config->pem_cert_chains_sizes, config->num_key_cert_pairs,
831 config->pem_root_certs, config->pem_root_certs_size,
Deepak Lukosedba4c5f2016-03-25 12:54:25 -0700832 get_tsi_client_certificate_request_type(
833 config->client_certificate_request),
834 ssl_cipher_suites(), alpn_protocol_strings, alpn_protocol_string_lengths,
835 (uint16_t)num_alpn_protocols, &c->handshaker_factory);
Craig Tillera82950e2015-09-22 12:33:20 -0700836 if (result != TSI_OK) {
837 gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
838 tsi_result_to_string(result));
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800839 ssl_server_destroy(&c->base.base);
Craig Tillera82950e2015-09-22 12:33:20 -0700840 *sc = NULL;
841 goto error;
842 }
yang-g5e72a352015-11-20 09:49:36 -0800843 gpr_mu_init(&c->base.mu);
Julien Boeuf4f4d37c2016-02-24 22:07:36 -0800844 c->base.do_handshake = ssl_server_do_handshake;
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700845 *sc = &c->base;
Craig Tiller565b18b2015-09-23 10:09:42 -0700846 gpr_free((void *)alpn_protocol_strings);
Craig Tillera82950e2015-09-22 12:33:20 -0700847 gpr_free(alpn_protocol_string_lengths);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800848 return GRPC_SECURITY_OK;
ctiller48b5a452014-12-10 08:43:47 -0800849
850error:
Craig Tiller565b18b2015-09-23 10:09:42 -0700851 gpr_free((void *)alpn_protocol_strings);
Craig Tillera82950e2015-09-22 12:33:20 -0700852 gpr_free(alpn_protocol_string_lengths);
ctiller48b5a452014-12-10 08:43:47 -0800853 return GRPC_SECURITY_ERROR;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800854}