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/security/handshake.h"
35 :
36 : #include <string.h>
37 :
38 : #include "src/core/security/secure_endpoint.h"
39 : #include <grpc/support/alloc.h>
40 : #include <grpc/support/log.h>
41 : #include <grpc/support/slice_buffer.h>
42 :
43 : #define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256
44 :
45 : typedef struct {
46 : grpc_security_connector *connector;
47 : tsi_handshaker *handshaker;
48 : unsigned char *handshake_buffer;
49 : size_t handshake_buffer_size;
50 : grpc_endpoint *wrapped_endpoint;
51 : grpc_endpoint *secure_endpoint;
52 : gpr_slice_buffer left_overs;
53 : gpr_slice_buffer incoming;
54 : gpr_slice_buffer outgoing;
55 : grpc_security_handshake_done_cb cb;
56 : void *user_data;
57 : grpc_closure on_handshake_data_sent_to_peer;
58 : grpc_closure on_handshake_data_received_from_peer;
59 : } grpc_security_handshake;
60 :
61 : static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
62 : void *setup, int success);
63 :
64 : static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *setup,
65 : int success);
66 :
67 595 : static void security_connector_remove_handshake(grpc_security_handshake *h) {
68 : grpc_security_connector_handshake_list *node;
69 : grpc_security_connector_handshake_list *tmp;
70 595 : grpc_security_connector *sc = h->connector;
71 595 : gpr_mu_lock(&sc->mu);
72 595 : node = sc->handshaking_handshakes;
73 595 : if (node && node->handshake == h) {
74 587 : sc->handshaking_handshakes = node->next;
75 587 : gpr_free(node);
76 587 : gpr_mu_unlock(&sc->mu);
77 587 : return;
78 : }
79 16 : while (node) {
80 3 : if (node->next->handshake == h) {
81 3 : tmp = node->next;
82 3 : node->next = node->next->next;
83 3 : gpr_free(tmp);
84 3 : gpr_mu_unlock(&sc->mu);
85 3 : return;
86 : }
87 0 : node = node->next;
88 : }
89 5 : gpr_mu_unlock(&sc->mu);
90 : }
91 :
92 1190 : static void security_handshake_done(grpc_exec_ctx *exec_ctx,
93 : grpc_security_handshake *h,
94 : int is_success) {
95 1190 : if (!h->connector->is_client_side) {
96 595 : security_connector_remove_handshake(h);
97 : }
98 1190 : if (is_success) {
99 1177 : h->cb(exec_ctx, h->user_data, GRPC_SECURITY_OK, h->secure_endpoint);
100 : } else {
101 13 : if (h->secure_endpoint != NULL) {
102 0 : grpc_endpoint_shutdown(exec_ctx, h->secure_endpoint);
103 0 : grpc_endpoint_destroy(exec_ctx, h->secure_endpoint);
104 : } else {
105 13 : grpc_endpoint_destroy(exec_ctx, h->wrapped_endpoint);
106 : }
107 13 : h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, NULL);
108 : }
109 1190 : if (h->handshaker != NULL) tsi_handshaker_destroy(h->handshaker);
110 1190 : if (h->handshake_buffer != NULL) gpr_free(h->handshake_buffer);
111 1190 : gpr_slice_buffer_destroy(&h->left_overs);
112 1190 : gpr_slice_buffer_destroy(&h->outgoing);
113 1190 : gpr_slice_buffer_destroy(&h->incoming);
114 1190 : GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake");
115 1190 : gpr_free(h);
116 1190 : }
117 :
118 1177 : static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data,
119 : grpc_security_status status) {
120 1143 : grpc_security_handshake *h = user_data;
121 : tsi_frame_protector *protector;
122 : tsi_result result;
123 1177 : if (status != GRPC_SECURITY_OK) {
124 0 : gpr_log(GPR_ERROR, "Error checking peer.");
125 0 : security_handshake_done(exec_ctx, h, 0);
126 0 : return;
127 : }
128 1177 : result =
129 1177 : tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector);
130 1177 : if (result != TSI_OK) {
131 0 : gpr_log(GPR_ERROR, "Frame protector creation failed with error %s.",
132 : tsi_result_to_string(result));
133 0 : security_handshake_done(exec_ctx, h, 0);
134 0 : return;
135 : }
136 1177 : h->secure_endpoint =
137 1177 : grpc_secure_endpoint_create(protector, h->wrapped_endpoint,
138 : h->left_overs.slices, h->left_overs.count);
139 1177 : h->left_overs.count = 0;
140 1177 : h->left_overs.length = 0;
141 1177 : security_handshake_done(exec_ctx, h, 1);
142 1177 : return;
143 : }
144 :
145 1177 : static void check_peer(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h) {
146 : grpc_security_status peer_status;
147 : tsi_peer peer;
148 1177 : tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer);
149 :
150 1177 : if (result != TSI_OK) {
151 0 : gpr_log(GPR_ERROR, "Peer extraction failed with error %s",
152 : tsi_result_to_string(result));
153 0 : security_handshake_done(exec_ctx, h, 0);
154 0 : return;
155 : }
156 1177 : peer_status = grpc_security_connector_check_peer(h->connector, peer,
157 : on_peer_checked, h);
158 1177 : if (peer_status == GRPC_SECURITY_ERROR) {
159 0 : gpr_log(GPR_ERROR, "Peer check failed.");
160 0 : security_handshake_done(exec_ctx, h, 0);
161 0 : return;
162 1177 : } else if (peer_status == GRPC_SECURITY_OK) {
163 1177 : on_peer_checked(exec_ctx, h, peer_status);
164 : }
165 : }
166 :
167 2480 : static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx,
168 : grpc_security_handshake *h) {
169 2412 : size_t offset = 0;
170 2412 : tsi_result result = TSI_OK;
171 : gpr_slice to_send;
172 :
173 : do {
174 3454 : size_t to_send_size = h->handshake_buffer_size - offset;
175 3454 : result = tsi_handshaker_get_bytes_to_send_to_peer(
176 3454 : h->handshaker, h->handshake_buffer + offset, &to_send_size);
177 3454 : offset += to_send_size;
178 3454 : if (result == TSI_INCOMPLETE_DATA) {
179 974 : h->handshake_buffer_size *= 2;
180 974 : h->handshake_buffer =
181 974 : gpr_realloc(h->handshake_buffer, h->handshake_buffer_size);
182 : }
183 3454 : } while (result == TSI_INCOMPLETE_DATA);
184 :
185 2480 : if (result != TSI_OK) {
186 0 : gpr_log(GPR_ERROR, "Handshake failed with error %s",
187 : tsi_result_to_string(result));
188 0 : security_handshake_done(exec_ctx, h, 0);
189 2480 : return;
190 : }
191 :
192 2480 : to_send =
193 2480 : gpr_slice_from_copied_buffer((const char *)h->handshake_buffer, offset);
194 2480 : gpr_slice_buffer_reset_and_unref(&h->outgoing);
195 2480 : gpr_slice_buffer_add(&h->outgoing, to_send);
196 : /* TODO(klempner,jboeuf): This should probably use the client setup
197 : deadline */
198 2480 : grpc_endpoint_write(exec_ctx, h->wrapped_endpoint, &h->outgoing,
199 : &h->on_handshake_data_sent_to_peer);
200 : }
201 :
202 2373 : static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
203 : void *handshake, int success) {
204 2305 : grpc_security_handshake *h = handshake;
205 2373 : size_t consumed_slice_size = 0;
206 2305 : tsi_result result = TSI_OK;
207 : size_t i;
208 : size_t num_left_overs;
209 2305 : int has_left_overs_in_current_slice = 0;
210 :
211 2373 : if (!success) {
212 13 : gpr_log(GPR_ERROR, "Read failed.");
213 13 : security_handshake_done(exec_ctx, h, 0);
214 13 : return;
215 : }
216 :
217 3582 : for (i = 0; i < h->incoming.count; i++) {
218 2360 : consumed_slice_size = GPR_SLICE_LENGTH(h->incoming.slices[i]);
219 4652 : result = tsi_handshaker_process_bytes_from_peer(
220 4584 : h->handshaker, GPR_SLICE_START_PTR(h->incoming.slices[i]),
221 : &consumed_slice_size);
222 2360 : if (!tsi_handshaker_is_in_progress(h->handshaker)) break;
223 : }
224 :
225 2360 : if (tsi_handshaker_is_in_progress(h->handshaker)) {
226 : /* We may need more data. */
227 1290 : if (result == TSI_INCOMPLETE_DATA) {
228 0 : grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming,
229 : &h->on_handshake_data_received_from_peer);
230 0 : return;
231 : } else {
232 1290 : send_handshake_bytes_to_peer(exec_ctx, h);
233 1290 : return;
234 : }
235 : }
236 :
237 1070 : if (result != TSI_OK) {
238 0 : gpr_log(GPR_ERROR, "Handshake failed with error %s",
239 : tsi_result_to_string(result));
240 0 : security_handshake_done(exec_ctx, h, 0);
241 0 : return;
242 : }
243 :
244 : /* Handshake is done and successful this point. */
245 1070 : has_left_overs_in_current_slice =
246 1070 : (consumed_slice_size < GPR_SLICE_LENGTH(h->incoming.slices[i]));
247 1070 : num_left_overs =
248 1070 : (has_left_overs_in_current_slice ? 1 : 0) + h->incoming.count - i - 1;
249 1070 : if (num_left_overs == 0) {
250 963 : check_peer(exec_ctx, h);
251 963 : return;
252 : }
253 :
254 : /* Put the leftovers in our buffer (ownership transfered). */
255 107 : if (has_left_overs_in_current_slice) {
256 214 : gpr_slice_buffer_add(
257 : &h->left_overs,
258 107 : gpr_slice_split_tail(&h->incoming.slices[i], consumed_slice_size));
259 107 : gpr_slice_unref(
260 107 : h->incoming.slices[i]); /* split_tail above increments refcount. */
261 : }
262 214 : gpr_slice_buffer_addn(
263 107 : &h->left_overs, &h->incoming.slices[i + 1],
264 107 : num_left_overs - (size_t)has_left_overs_in_current_slice);
265 107 : check_peer(exec_ctx, h);
266 : }
267 :
268 : /* If handshake is NULL, the handshake is done. */
269 2480 : static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx,
270 : void *handshake, int success) {
271 2412 : grpc_security_handshake *h = handshake;
272 :
273 : /* Make sure that write is OK. */
274 2480 : if (!success) {
275 0 : gpr_log(GPR_ERROR, "Write failed.");
276 0 : if (handshake != NULL) security_handshake_done(exec_ctx, h, 0);
277 2480 : return;
278 : }
279 :
280 : /* We may be done. */
281 2480 : if (tsi_handshaker_is_in_progress(h->handshaker)) {
282 : /* TODO(klempner,jboeuf): This should probably use the client setup
283 : deadline */
284 2373 : grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming,
285 : &h->on_handshake_data_received_from_peer);
286 : } else {
287 107 : check_peer(exec_ctx, h);
288 : }
289 : }
290 :
291 1190 : void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
292 : tsi_handshaker *handshaker,
293 : grpc_security_connector *connector,
294 : grpc_endpoint *nonsecure_endpoint,
295 : grpc_security_handshake_done_cb cb,
296 : void *user_data) {
297 : grpc_security_connector_handshake_list *handshake_node;
298 1190 : grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake));
299 1190 : memset(h, 0, sizeof(grpc_security_handshake));
300 1190 : h->handshaker = handshaker;
301 1190 : h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake");
302 1190 : h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
303 1190 : h->handshake_buffer = gpr_malloc(h->handshake_buffer_size);
304 1190 : h->wrapped_endpoint = nonsecure_endpoint;
305 1190 : h->user_data = user_data;
306 1190 : h->cb = cb;
307 1190 : grpc_closure_init(&h->on_handshake_data_sent_to_peer,
308 : on_handshake_data_sent_to_peer, h);
309 1190 : grpc_closure_init(&h->on_handshake_data_received_from_peer,
310 : on_handshake_data_received_from_peer, h);
311 1190 : gpr_slice_buffer_init(&h->left_overs);
312 1190 : gpr_slice_buffer_init(&h->outgoing);
313 1190 : gpr_slice_buffer_init(&h->incoming);
314 1190 : if (!connector->is_client_side) {
315 595 : handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list));
316 595 : handshake_node->handshake = h;
317 595 : gpr_mu_lock(&connector->mu);
318 595 : handshake_node->next = connector->handshaking_handshakes;
319 595 : connector->handshaking_handshakes = handshake_node;
320 595 : gpr_mu_unlock(&connector->mu);
321 : }
322 1190 : send_handshake_bytes_to_peer(exec_ctx, h);
323 1190 : }
324 :
325 5 : void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx,
326 : void *handshake) {
327 5 : grpc_security_handshake *h = handshake;
328 5 : grpc_endpoint_shutdown(exec_ctx, h->wrapped_endpoint);
329 5 : }
|