Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(944)

Side by Side Diff: third_party/grpc/src/core/security/handshake.c

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

Powered by Google App Engine
This is Rietveld 408576698