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 897 : static void security_handshake_done(grpc_exec_ctx *exec_ctx,
68 : grpc_security_handshake *h,
69 : int is_success) {
70 897 : if (is_success) {
71 878 : h->cb(exec_ctx, h->user_data, GRPC_SECURITY_OK, h->wrapped_endpoint,
72 : h->secure_endpoint);
73 : } else {
74 19 : if (h->secure_endpoint != NULL) {
75 0 : grpc_endpoint_shutdown(exec_ctx, h->secure_endpoint);
76 0 : grpc_endpoint_destroy(exec_ctx, h->secure_endpoint);
77 : } else {
78 19 : grpc_endpoint_destroy(exec_ctx, h->wrapped_endpoint);
79 : }
80 19 : h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, h->wrapped_endpoint,
81 : NULL);
82 : }
83 897 : if (h->handshaker != NULL) tsi_handshaker_destroy(h->handshaker);
84 897 : if (h->handshake_buffer != NULL) gpr_free(h->handshake_buffer);
85 897 : gpr_slice_buffer_destroy(&h->left_overs);
86 897 : gpr_slice_buffer_destroy(&h->outgoing);
87 897 : gpr_slice_buffer_destroy(&h->incoming);
88 897 : GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake");
89 897 : gpr_free(h);
90 897 : }
91 :
92 878 : static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data,
93 : grpc_security_status status) {
94 878 : grpc_security_handshake *h = user_data;
95 : tsi_frame_protector *protector;
96 : tsi_result result;
97 878 : if (status != GRPC_SECURITY_OK) {
98 0 : gpr_log(GPR_ERROR, "Error checking peer.");
99 0 : security_handshake_done(exec_ctx, h, 0);
100 0 : return;
101 : }
102 878 : result =
103 878 : tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector);
104 878 : if (result != TSI_OK) {
105 0 : gpr_log(GPR_ERROR, "Frame protector creation failed with error %s.",
106 : tsi_result_to_string(result));
107 0 : security_handshake_done(exec_ctx, h, 0);
108 0 : return;
109 : }
110 878 : h->secure_endpoint =
111 878 : grpc_secure_endpoint_create(protector, h->wrapped_endpoint,
112 : h->left_overs.slices, h->left_overs.count);
113 878 : h->left_overs.count = 0;
114 878 : h->left_overs.length = 0;
115 878 : security_handshake_done(exec_ctx, h, 1);
116 878 : return;
117 : }
118 :
119 878 : static void check_peer(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h) {
120 : grpc_security_status peer_status;
121 : tsi_peer peer;
122 878 : tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer);
123 :
124 878 : if (result != TSI_OK) {
125 0 : gpr_log(GPR_ERROR, "Peer extraction failed with error %s",
126 : tsi_result_to_string(result));
127 0 : security_handshake_done(exec_ctx, h, 0);
128 0 : return;
129 : }
130 878 : peer_status = grpc_security_connector_check_peer(h->connector, peer,
131 : on_peer_checked, h);
132 878 : if (peer_status == GRPC_SECURITY_ERROR) {
133 0 : gpr_log(GPR_ERROR, "Peer check failed.");
134 0 : security_handshake_done(exec_ctx, h, 0);
135 0 : return;
136 878 : } else if (peer_status == GRPC_SECURITY_OK) {
137 878 : on_peer_checked(exec_ctx, h, peer_status);
138 : }
139 : }
140 :
141 1859 : static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx,
142 : grpc_security_handshake *h) {
143 1859 : size_t offset = 0;
144 1859 : tsi_result result = TSI_OK;
145 : gpr_slice to_send;
146 :
147 : do {
148 2605 : size_t to_send_size = h->handshake_buffer_size - offset;
149 2605 : result = tsi_handshaker_get_bytes_to_send_to_peer(
150 2605 : h->handshaker, h->handshake_buffer + offset, &to_send_size);
151 2605 : offset += to_send_size;
152 2605 : if (result == TSI_INCOMPLETE_DATA) {
153 746 : h->handshake_buffer_size *= 2;
154 746 : h->handshake_buffer =
155 746 : gpr_realloc(h->handshake_buffer, h->handshake_buffer_size);
156 : }
157 2605 : } while (result == TSI_INCOMPLETE_DATA);
158 :
159 1859 : if (result != TSI_OK) {
160 0 : gpr_log(GPR_ERROR, "Handshake failed with error %s",
161 : tsi_result_to_string(result));
162 0 : security_handshake_done(exec_ctx, h, 0);
163 1859 : return;
164 : }
165 :
166 1859 : to_send =
167 1859 : gpr_slice_from_copied_buffer((const char *)h->handshake_buffer, offset);
168 1859 : gpr_slice_buffer_reset_and_unref(&h->outgoing);
169 1859 : gpr_slice_buffer_add(&h->outgoing, to_send);
170 : /* TODO(klempner,jboeuf): This should probably use the client setup
171 : deadline */
172 1859 : grpc_endpoint_write(exec_ctx, h->wrapped_endpoint, &h->outgoing,
173 : &h->on_handshake_data_sent_to_peer);
174 : }
175 :
176 1786 : static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
177 : void *handshake, int success) {
178 1786 : grpc_security_handshake *h = handshake;
179 1786 : size_t consumed_slice_size = 0;
180 1786 : tsi_result result = TSI_OK;
181 : size_t i;
182 : size_t num_left_overs;
183 1786 : int has_left_overs_in_current_slice = 0;
184 :
185 1786 : if (!success) {
186 19 : gpr_log(GPR_ERROR, "Read failed.");
187 19 : security_handshake_done(exec_ctx, h, 0);
188 19 : return;
189 : }
190 :
191 2729 : for (i = 0; i < h->incoming.count; i++) {
192 1767 : consumed_slice_size = GPR_SLICE_LENGTH(h->incoming.slices[i]);
193 3534 : result = tsi_handshaker_process_bytes_from_peer(
194 3534 : h->handshaker, GPR_SLICE_START_PTR(h->incoming.slices[i]),
195 : &consumed_slice_size);
196 1767 : if (!tsi_handshaker_is_in_progress(h->handshaker)) break;
197 : }
198 :
199 1767 : if (tsi_handshaker_is_in_progress(h->handshaker)) {
200 : /* We may need more data. */
201 962 : if (result == TSI_INCOMPLETE_DATA) {
202 0 : grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming,
203 : &h->on_handshake_data_received_from_peer);
204 0 : return;
205 : } else {
206 962 : send_handshake_bytes_to_peer(exec_ctx, h);
207 962 : return;
208 : }
209 : }
210 :
211 805 : if (result != TSI_OK) {
212 0 : gpr_log(GPR_ERROR, "Handshake failed with error %s",
213 : tsi_result_to_string(result));
214 0 : security_handshake_done(exec_ctx, h, 0);
215 0 : return;
216 : }
217 :
218 : /* Handshake is done and successful this point. */
219 805 : has_left_overs_in_current_slice =
220 805 : (consumed_slice_size < GPR_SLICE_LENGTH(h->incoming.slices[i]));
221 805 : num_left_overs =
222 805 : (has_left_overs_in_current_slice ? 1 : 0) + h->incoming.count - i - 1;
223 805 : if (num_left_overs == 0) {
224 732 : check_peer(exec_ctx, h);
225 732 : return;
226 : }
227 :
228 : /* Put the leftovers in our buffer (ownership transfered). */
229 73 : if (has_left_overs_in_current_slice) {
230 146 : gpr_slice_buffer_add(
231 : &h->left_overs,
232 73 : gpr_slice_split_tail(&h->incoming.slices[i], consumed_slice_size));
233 73 : gpr_slice_unref(
234 73 : h->incoming.slices[i]); /* split_tail above increments refcount. */
235 : }
236 146 : gpr_slice_buffer_addn(
237 73 : &h->left_overs, &h->incoming.slices[i + 1],
238 73 : num_left_overs - (size_t)has_left_overs_in_current_slice);
239 73 : check_peer(exec_ctx, h);
240 : }
241 :
242 : /* If handshake is NULL, the handshake is done. */
243 1859 : static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx,
244 : void *handshake, int success) {
245 1859 : grpc_security_handshake *h = handshake;
246 :
247 : /* Make sure that write is OK. */
248 1859 : if (!success) {
249 0 : gpr_log(GPR_ERROR, "Write failed.");
250 0 : if (handshake != NULL) security_handshake_done(exec_ctx, h, 0);
251 1859 : return;
252 : }
253 :
254 : /* We may be done. */
255 1859 : if (tsi_handshaker_is_in_progress(h->handshaker)) {
256 : /* TODO(klempner,jboeuf): This should probably use the client setup
257 : deadline */
258 1786 : grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming,
259 : &h->on_handshake_data_received_from_peer);
260 : } else {
261 73 : check_peer(exec_ctx, h);
262 : }
263 : }
264 :
265 897 : void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
266 : tsi_handshaker *handshaker,
267 : grpc_security_connector *connector,
268 : grpc_endpoint *nonsecure_endpoint,
269 : grpc_security_handshake_done_cb cb,
270 : void *user_data) {
271 897 : grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake));
272 897 : memset(h, 0, sizeof(grpc_security_handshake));
273 897 : h->handshaker = handshaker;
274 897 : h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake");
275 897 : h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
276 897 : h->handshake_buffer = gpr_malloc(h->handshake_buffer_size);
277 897 : h->wrapped_endpoint = nonsecure_endpoint;
278 897 : h->user_data = user_data;
279 897 : h->cb = cb;
280 897 : grpc_closure_init(&h->on_handshake_data_sent_to_peer,
281 : on_handshake_data_sent_to_peer, h);
282 897 : grpc_closure_init(&h->on_handshake_data_received_from_peer,
283 : on_handshake_data_received_from_peer, h);
284 897 : gpr_slice_buffer_init(&h->left_overs);
285 897 : gpr_slice_buffer_init(&h->outgoing);
286 897 : gpr_slice_buffer_init(&h->incoming);
287 897 : send_handshake_bytes_to_peer(exec_ctx, h);
288 897 : }
|