Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, 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/httpcli/httpcli.h"
35 :
36 : #include <string.h>
37 :
38 : #include "src/core/security/handshake.h"
39 : #include "src/core/support/string.h"
40 : #include <grpc/support/alloc.h>
41 : #include <grpc/support/log.h>
42 : #include <grpc/support/string_util.h>
43 : #include "src/core/tsi/ssl_transport_security.h"
44 :
45 : typedef struct {
46 : grpc_channel_security_connector base;
47 : tsi_ssl_handshaker_factory *handshaker_factory;
48 : char *secure_peer_name;
49 : } grpc_httpcli_ssl_channel_security_connector;
50 :
51 0 : static void httpcli_ssl_destroy(grpc_security_connector *sc) {
52 0 : grpc_httpcli_ssl_channel_security_connector *c =
53 : (grpc_httpcli_ssl_channel_security_connector *)sc;
54 0 : if (c->handshaker_factory != NULL) {
55 0 : tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
56 : }
57 0 : if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name);
58 0 : gpr_free(sc);
59 0 : }
60 :
61 0 : static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
62 : grpc_security_connector *sc,
63 : grpc_endpoint *nonsecure_endpoint,
64 : grpc_security_handshake_done_cb cb,
65 : void *user_data) {
66 0 : grpc_httpcli_ssl_channel_security_connector *c =
67 : (grpc_httpcli_ssl_channel_security_connector *)sc;
68 0 : tsi_result result = TSI_OK;
69 : tsi_handshaker *handshaker;
70 0 : if (c->handshaker_factory == NULL) {
71 0 : cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, nonsecure_endpoint, NULL);
72 0 : return;
73 : }
74 0 : result = tsi_ssl_handshaker_factory_create_handshaker(
75 0 : c->handshaker_factory, c->secure_peer_name, &handshaker);
76 0 : if (result != TSI_OK) {
77 0 : gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
78 : tsi_result_to_string(result));
79 0 : cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, nonsecure_endpoint, NULL);
80 : } else {
81 0 : grpc_do_security_handshake(exec_ctx, handshaker, sc, nonsecure_endpoint, cb,
82 : user_data);
83 : }
84 : }
85 :
86 0 : static grpc_security_status httpcli_ssl_check_peer(grpc_security_connector *sc,
87 : tsi_peer peer,
88 : grpc_security_check_cb cb,
89 : void *user_data) {
90 0 : grpc_httpcli_ssl_channel_security_connector *c =
91 : (grpc_httpcli_ssl_channel_security_connector *)sc;
92 0 : grpc_security_status status = GRPC_SECURITY_OK;
93 :
94 : /* Check the peer name. */
95 0 : if (c->secure_peer_name != NULL &&
96 0 : !tsi_ssl_peer_matches_name(&peer, c->secure_peer_name)) {
97 0 : gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate",
98 : c->secure_peer_name);
99 0 : status = GRPC_SECURITY_ERROR;
100 : }
101 0 : tsi_peer_destruct(&peer);
102 0 : return status;
103 : }
104 :
105 : static grpc_security_connector_vtable httpcli_ssl_vtable = {
106 : httpcli_ssl_destroy, httpcli_ssl_do_handshake, httpcli_ssl_check_peer};
107 :
108 0 : static grpc_security_status httpcli_ssl_channel_security_connector_create(
109 : const unsigned char *pem_root_certs, size_t pem_root_certs_size,
110 : const char *secure_peer_name, grpc_channel_security_connector **sc) {
111 0 : tsi_result result = TSI_OK;
112 : grpc_httpcli_ssl_channel_security_connector *c;
113 :
114 0 : if (secure_peer_name != NULL && pem_root_certs == NULL) {
115 0 : gpr_log(GPR_ERROR,
116 : "Cannot assert a secure peer name without a trust root.");
117 0 : return GRPC_SECURITY_ERROR;
118 : }
119 :
120 0 : c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_connector));
121 0 : memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_connector));
122 :
123 0 : gpr_ref_init(&c->base.base.refcount, 1);
124 0 : c->base.base.is_client_side = 1;
125 0 : c->base.base.vtable = &httpcli_ssl_vtable;
126 0 : if (secure_peer_name != NULL) {
127 0 : c->secure_peer_name = gpr_strdup(secure_peer_name);
128 : }
129 0 : result = tsi_create_ssl_client_handshaker_factory(
130 : NULL, 0, NULL, 0, pem_root_certs, pem_root_certs_size, NULL, NULL, NULL,
131 : 0, &c->handshaker_factory);
132 0 : if (result != TSI_OK) {
133 0 : gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
134 : tsi_result_to_string(result));
135 0 : httpcli_ssl_destroy(&c->base.base);
136 0 : *sc = NULL;
137 0 : return GRPC_SECURITY_ERROR;
138 : }
139 0 : *sc = &c->base;
140 0 : return GRPC_SECURITY_OK;
141 : }
142 :
143 : /* handshaker */
144 :
145 : typedef struct {
146 : void (*func)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint);
147 : void *arg;
148 : } on_done_closure;
149 :
150 0 : static void on_secure_transport_setup_done(grpc_exec_ctx *exec_ctx, void *rp,
151 : grpc_security_status status,
152 : grpc_endpoint *wrapped_endpoint,
153 : grpc_endpoint *secure_endpoint) {
154 0 : on_done_closure *c = rp;
155 0 : if (status != GRPC_SECURITY_OK) {
156 0 : gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status);
157 0 : c->func(exec_ctx, c->arg, NULL);
158 : } else {
159 0 : c->func(exec_ctx, c->arg, secure_endpoint);
160 : }
161 0 : gpr_free(c);
162 0 : }
163 :
164 0 : static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
165 : grpc_endpoint *tcp, const char *host,
166 : void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
167 : grpc_endpoint *endpoint)) {
168 0 : grpc_channel_security_connector *sc = NULL;
169 0 : const unsigned char *pem_root_certs = NULL;
170 0 : on_done_closure *c = gpr_malloc(sizeof(*c));
171 0 : size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs);
172 0 : if (pem_root_certs == NULL || pem_root_certs_size == 0) {
173 0 : gpr_log(GPR_ERROR, "Could not get default pem root certs.");
174 0 : on_done(exec_ctx, arg, NULL);
175 0 : gpr_free(c);
176 0 : return;
177 : }
178 0 : c->func = on_done;
179 0 : c->arg = arg;
180 0 : GPR_ASSERT(httpcli_ssl_channel_security_connector_create(
181 : pem_root_certs, pem_root_certs_size, host, &sc) ==
182 : GRPC_SECURITY_OK);
183 0 : grpc_security_connector_do_handshake(exec_ctx, &sc->base, tcp,
184 : on_secure_transport_setup_done, c);
185 0 : GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
186 : }
187 :
188 : const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake};
|