Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 1 | /* |
| 2 | * |
Craig Tiller | 6169d5f | 2016-03-31 07:46:18 -0700 | [diff] [blame] | 3 | * Copyright 2015, Google Inc. |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 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 | |
Craig Tiller | 9533d04 | 2016-03-25 17:11:06 -0700 | [diff] [blame] | 34 | #include "src/core/lib/tsi/fake_transport_security.h" |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 35 | |
| 36 | #include <stdlib.h> |
| 37 | #include <string.h> |
| 38 | |
Nicolas "Pixel" Noble | b29d8cf | 2016-04-08 01:38:29 +0200 | [diff] [blame] | 39 | #include <grpc/support/alloc.h> |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 40 | #include <grpc/support/log.h> |
Craig Tiller | be5c6e5 | 2015-01-16 07:57:58 -0800 | [diff] [blame] | 41 | #include <grpc/support/port_platform.h> |
Nicolas "Pixel" Noble | 213ed91 | 2015-01-30 02:11:35 +0100 | [diff] [blame] | 42 | #include <grpc/support/useful.h> |
Craig Tiller | 9533d04 | 2016-03-25 17:11:06 -0700 | [diff] [blame] | 43 | #include "src/core/lib/tsi/transport_security.h" |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 44 | |
| 45 | /* --- Constants. ---*/ |
| 46 | #define TSI_FAKE_FRAME_HEADER_SIZE 4 |
| 47 | #define TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE 64 |
| 48 | #define TSI_FAKE_DEFAULT_FRAME_SIZE 16384 |
| 49 | |
| 50 | /* --- Structure definitions. ---*/ |
| 51 | |
| 52 | /* a frame is encoded like this: |
| 53 | | size | data | |
| 54 | where the size field value is the size of the size field plus the size of |
| 55 | the data encoded in little endian on 4 bytes. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 56 | typedef struct { |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 57 | unsigned char *data; |
Craig Tiller | be5c6e5 | 2015-01-16 07:57:58 -0800 | [diff] [blame] | 58 | size_t size; |
| 59 | size_t allocated_size; |
| 60 | size_t offset; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 61 | int needs_draining; |
| 62 | } tsi_fake_frame; |
| 63 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 64 | typedef enum { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 65 | TSI_FAKE_CLIENT_INIT = 0, |
| 66 | TSI_FAKE_SERVER_INIT = 1, |
| 67 | TSI_FAKE_CLIENT_FINISHED = 2, |
| 68 | TSI_FAKE_SERVER_FINISHED = 3, |
| 69 | TSI_FAKE_HANDSHAKE_MESSAGE_MAX = 4 |
| 70 | } tsi_fake_handshake_message; |
| 71 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 72 | typedef struct { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 73 | tsi_handshaker base; |
| 74 | int is_client; |
| 75 | tsi_fake_handshake_message next_message_to_send; |
| 76 | int needs_incoming_message; |
| 77 | tsi_fake_frame incoming; |
| 78 | tsi_fake_frame outgoing; |
| 79 | tsi_result result; |
| 80 | } tsi_fake_handshaker; |
| 81 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 82 | typedef struct { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 83 | tsi_frame_protector base; |
| 84 | tsi_fake_frame protect_frame; |
| 85 | tsi_fake_frame unprotect_frame; |
Craig Tiller | be5c6e5 | 2015-01-16 07:57:58 -0800 | [diff] [blame] | 86 | size_t max_frame_size; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 87 | } tsi_fake_frame_protector; |
| 88 | |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 89 | /* --- Utils. ---*/ |
| 90 | |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 91 | static const char *tsi_fake_handshake_message_strings[] = { |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 92 | "CLIENT_INIT", "SERVER_INIT", "CLIENT_FINISHED", "SERVER_FINISHED"}; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 93 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 94 | static const char *tsi_fake_handshake_message_to_string(int msg) { |
| 95 | if (msg < 0 || msg >= TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { |
| 96 | gpr_log(GPR_ERROR, "Invalid message %d", msg); |
| 97 | return "UNKNOWN"; |
| 98 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 99 | return tsi_fake_handshake_message_strings[msg]; |
| 100 | } |
| 101 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 102 | static tsi_result tsi_fake_handshake_message_from_string( |
| 103 | const char *msg_string, tsi_fake_handshake_message *msg) { |
Craig Tiller | f96dfc3 | 2015-09-10 14:43:18 -0700 | [diff] [blame] | 104 | tsi_fake_handshake_message i; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 105 | for (i = 0; i < TSI_FAKE_HANDSHAKE_MESSAGE_MAX; i++) { |
| 106 | if (strncmp(msg_string, tsi_fake_handshake_message_strings[i], |
| 107 | strlen(tsi_fake_handshake_message_strings[i])) == 0) { |
| 108 | *msg = i; |
| 109 | return TSI_OK; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 110 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 111 | } |
| 112 | gpr_log(GPR_ERROR, "Invalid handshake message."); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 113 | return TSI_DATA_CORRUPTED; |
| 114 | } |
| 115 | |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 116 | static uint32_t load32_little_endian(const unsigned char *buf) { |
| 117 | return ((uint32_t)(buf[0]) | (uint32_t)(buf[1] << 8) | |
| 118 | (uint32_t)(buf[2] << 16) | (uint32_t)(buf[3] << 24)); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 119 | } |
| 120 | |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 121 | static void store32_little_endian(uint32_t value, unsigned char *buf) { |
David Garcia Quintas | d76cdac | 2015-10-03 15:57:09 -0700 | [diff] [blame] | 122 | buf[3] = (unsigned char)((value >> 24) & 0xFF); |
| 123 | buf[2] = (unsigned char)((value >> 16) & 0xFF); |
| 124 | buf[1] = (unsigned char)((value >> 8) & 0xFF); |
Craig Tiller | 1f41b6b | 2015-10-09 15:07:02 -0700 | [diff] [blame] | 125 | buf[0] = (unsigned char)((value)&0xFF); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 126 | } |
| 127 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 128 | static void tsi_fake_frame_reset(tsi_fake_frame *frame, int needs_draining) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 129 | frame->offset = 0; |
| 130 | frame->needs_draining = needs_draining; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 131 | if (!needs_draining) frame->size = 0; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 132 | } |
| 133 | |
| 134 | /* Returns 1 if successful, 0 otherwise. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 135 | static int tsi_fake_frame_ensure_size(tsi_fake_frame *frame) { |
| 136 | if (frame->data == NULL) { |
| 137 | frame->allocated_size = frame->size; |
Nicolas "Pixel" Noble | 7c9a154 | 2016-03-26 01:33:34 +0100 | [diff] [blame] | 138 | frame->data = gpr_malloc(frame->allocated_size); |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 139 | if (frame->data == NULL) return 0; |
| 140 | } else if (frame->size > frame->allocated_size) { |
Nicolas "Pixel" Noble | b29d8cf | 2016-04-08 01:38:29 +0200 | [diff] [blame] | 141 | unsigned char *new_data = gpr_realloc(frame->data, frame->size); |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 142 | if (new_data == NULL) { |
Nicolas "Pixel" Noble | 7c9a154 | 2016-03-26 01:33:34 +0100 | [diff] [blame] | 143 | gpr_free(frame->data); |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 144 | frame->data = NULL; |
| 145 | return 0; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 146 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 147 | frame->data = new_data; |
| 148 | frame->allocated_size = frame->size; |
| 149 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 150 | return 1; |
| 151 | } |
| 152 | |
| 153 | /* This method should not be called if frame->needs_framing is not 0. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 154 | static tsi_result fill_frame_from_bytes(const unsigned char *incoming_bytes, |
| 155 | size_t *incoming_bytes_size, |
| 156 | tsi_fake_frame *frame) { |
Craig Tiller | be5c6e5 | 2015-01-16 07:57:58 -0800 | [diff] [blame] | 157 | size_t available_size = *incoming_bytes_size; |
| 158 | size_t to_read_size = 0; |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 159 | const unsigned char *bytes_cursor = incoming_bytes; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 160 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 161 | if (frame->needs_draining) return TSI_INTERNAL_ERROR; |
| 162 | if (frame->data == NULL) { |
| 163 | frame->allocated_size = TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE; |
Nicolas "Pixel" Noble | 7c9a154 | 2016-03-26 01:33:34 +0100 | [diff] [blame] | 164 | frame->data = gpr_malloc(frame->allocated_size); |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 165 | if (frame->data == NULL) return TSI_OUT_OF_RESOURCES; |
| 166 | } |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 167 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 168 | if (frame->offset < TSI_FAKE_FRAME_HEADER_SIZE) { |
| 169 | to_read_size = TSI_FAKE_FRAME_HEADER_SIZE - frame->offset; |
| 170 | if (to_read_size > available_size) { |
| 171 | /* Just fill what we can and exit. */ |
| 172 | memcpy(frame->data + frame->offset, bytes_cursor, available_size); |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 173 | bytes_cursor += available_size; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 174 | frame->offset += available_size; |
| 175 | *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes); |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 176 | return TSI_INCOMPLETE_DATA; |
| 177 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 178 | memcpy(frame->data + frame->offset, bytes_cursor, to_read_size); |
| 179 | bytes_cursor += to_read_size; |
| 180 | frame->offset += to_read_size; |
| 181 | available_size -= to_read_size; |
| 182 | frame->size = load32_little_endian(frame->data); |
| 183 | if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES; |
| 184 | } |
| 185 | |
| 186 | to_read_size = frame->size - frame->offset; |
| 187 | if (to_read_size > available_size) { |
| 188 | memcpy(frame->data + frame->offset, bytes_cursor, available_size); |
| 189 | frame->offset += available_size; |
| 190 | bytes_cursor += available_size; |
| 191 | *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes); |
| 192 | return TSI_INCOMPLETE_DATA; |
| 193 | } |
| 194 | memcpy(frame->data + frame->offset, bytes_cursor, to_read_size); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 195 | bytes_cursor += to_read_size; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 196 | *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes); |
| 197 | tsi_fake_frame_reset(frame, 1 /* needs_draining */); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 198 | return TSI_OK; |
| 199 | } |
| 200 | |
| 201 | /* This method should not be called if frame->needs_framing is 0. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 202 | static tsi_result drain_frame_to_bytes(unsigned char *outgoing_bytes, |
| 203 | size_t *outgoing_bytes_size, |
| 204 | tsi_fake_frame *frame) { |
Craig Tiller | be5c6e5 | 2015-01-16 07:57:58 -0800 | [diff] [blame] | 205 | size_t to_write_size = frame->size - frame->offset; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 206 | if (!frame->needs_draining) return TSI_INTERNAL_ERROR; |
| 207 | if (*outgoing_bytes_size < to_write_size) { |
| 208 | memcpy(outgoing_bytes, frame->data + frame->offset, *outgoing_bytes_size); |
| 209 | frame->offset += *outgoing_bytes_size; |
| 210 | return TSI_INCOMPLETE_DATA; |
| 211 | } |
| 212 | memcpy(outgoing_bytes, frame->data + frame->offset, to_write_size); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 213 | *outgoing_bytes_size = to_write_size; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 214 | tsi_fake_frame_reset(frame, 0 /* needs_draining */); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 215 | return TSI_OK; |
| 216 | } |
| 217 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 218 | static tsi_result bytes_to_frame(unsigned char *bytes, size_t bytes_size, |
| 219 | tsi_fake_frame *frame) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 220 | frame->offset = 0; |
| 221 | frame->size = bytes_size + TSI_FAKE_FRAME_HEADER_SIZE; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 222 | if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES; |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 223 | store32_little_endian((uint32_t)frame->size, frame->data); |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 224 | memcpy(frame->data + TSI_FAKE_FRAME_HEADER_SIZE, bytes, bytes_size); |
| 225 | tsi_fake_frame_reset(frame, 1 /* needs draining */); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 226 | return TSI_OK; |
| 227 | } |
| 228 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 229 | static void tsi_fake_frame_destruct(tsi_fake_frame *frame) { |
Nicolas "Pixel" Noble | 7c9a154 | 2016-03-26 01:33:34 +0100 | [diff] [blame] | 230 | if (frame->data != NULL) gpr_free(frame->data); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 231 | } |
| 232 | |
| 233 | /* --- tsi_frame_protector methods implementation. ---*/ |
| 234 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 235 | static tsi_result fake_protector_protect(tsi_frame_protector *self, |
| 236 | const unsigned char *unprotected_bytes, |
| 237 | size_t *unprotected_bytes_size, |
| 238 | unsigned char *protected_output_frames, |
| 239 | size_t *protected_output_frames_size) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 240 | tsi_result result = TSI_OK; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 241 | tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 242 | unsigned char frame_header[TSI_FAKE_FRAME_HEADER_SIZE]; |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 243 | tsi_fake_frame *frame = &impl->protect_frame; |
Craig Tiller | be5c6e5 | 2015-01-16 07:57:58 -0800 | [diff] [blame] | 244 | size_t saved_output_size = *protected_output_frames_size; |
| 245 | size_t drained_size = 0; |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 246 | size_t *num_bytes_written = protected_output_frames_size; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 247 | *num_bytes_written = 0; |
| 248 | |
| 249 | /* Try to drain first. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 250 | if (frame->needs_draining) { |
| 251 | drained_size = saved_output_size - *num_bytes_written; |
| 252 | result = |
| 253 | drain_frame_to_bytes(protected_output_frames, &drained_size, frame); |
| 254 | *num_bytes_written += drained_size; |
| 255 | protected_output_frames += drained_size; |
| 256 | if (result != TSI_OK) { |
| 257 | if (result == TSI_INCOMPLETE_DATA) { |
| 258 | *unprotected_bytes_size = 0; |
| 259 | result = TSI_OK; |
| 260 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 261 | return result; |
| 262 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 263 | } |
| 264 | |
| 265 | /* Now process the unprotected_bytes. */ |
| 266 | if (frame->needs_draining) return TSI_INTERNAL_ERROR; |
| 267 | if (frame->size == 0) { |
| 268 | /* New frame, create a header. */ |
| 269 | size_t written_in_frame_size = 0; |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 270 | store32_little_endian((uint32_t)impl->max_frame_size, frame_header); |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 271 | written_in_frame_size = TSI_FAKE_FRAME_HEADER_SIZE; |
| 272 | result = fill_frame_from_bytes(frame_header, &written_in_frame_size, frame); |
| 273 | if (result != TSI_INCOMPLETE_DATA) { |
| 274 | gpr_log(GPR_ERROR, "fill_frame_from_bytes returned %s", |
| 275 | tsi_result_to_string(result)); |
| 276 | return result; |
| 277 | } |
| 278 | } |
| 279 | result = |
| 280 | fill_frame_from_bytes(unprotected_bytes, unprotected_bytes_size, frame); |
| 281 | if (result != TSI_OK) { |
| 282 | if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; |
| 283 | return result; |
| 284 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 285 | |
| 286 | /* Try to drain again. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 287 | if (!frame->needs_draining) return TSI_INTERNAL_ERROR; |
| 288 | if (frame->offset != 0) return TSI_INTERNAL_ERROR; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 289 | drained_size = saved_output_size - *num_bytes_written; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 290 | result = drain_frame_to_bytes(protected_output_frames, &drained_size, frame); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 291 | *num_bytes_written += drained_size; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 292 | if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 293 | return result; |
| 294 | } |
| 295 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 296 | static tsi_result fake_protector_protect_flush( |
| 297 | tsi_frame_protector *self, unsigned char *protected_output_frames, |
| 298 | size_t *protected_output_frames_size, size_t *still_pending_size) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 299 | tsi_result result = TSI_OK; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 300 | tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self; |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 301 | tsi_fake_frame *frame = &impl->protect_frame; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 302 | if (!frame->needs_draining) { |
| 303 | /* Create a short frame. */ |
| 304 | frame->size = frame->offset; |
| 305 | frame->offset = 0; |
| 306 | frame->needs_draining = 1; |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 307 | store32_little_endian((uint32_t)frame->size, |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 308 | frame->data); /* Overwrite header. */ |
| 309 | } |
| 310 | result = drain_frame_to_bytes(protected_output_frames, |
| 311 | protected_output_frames_size, frame); |
| 312 | if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 313 | *still_pending_size = frame->size - frame->offset; |
| 314 | return result; |
| 315 | } |
| 316 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 317 | static tsi_result fake_protector_unprotect( |
| 318 | tsi_frame_protector *self, const unsigned char *protected_frames_bytes, |
| 319 | size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes, |
| 320 | size_t *unprotected_bytes_size) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 321 | tsi_result result = TSI_OK; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 322 | tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self; |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 323 | tsi_fake_frame *frame = &impl->unprotect_frame; |
Craig Tiller | be5c6e5 | 2015-01-16 07:57:58 -0800 | [diff] [blame] | 324 | size_t saved_output_size = *unprotected_bytes_size; |
| 325 | size_t drained_size = 0; |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 326 | size_t *num_bytes_written = unprotected_bytes_size; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 327 | *num_bytes_written = 0; |
| 328 | |
| 329 | /* Try to drain first. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 330 | if (frame->needs_draining) { |
| 331 | /* Go past the header if needed. */ |
| 332 | if (frame->offset == 0) frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; |
| 333 | drained_size = saved_output_size - *num_bytes_written; |
| 334 | result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame); |
| 335 | unprotected_bytes += drained_size; |
| 336 | *num_bytes_written += drained_size; |
| 337 | if (result != TSI_OK) { |
| 338 | if (result == TSI_INCOMPLETE_DATA) { |
| 339 | *protected_frames_bytes_size = 0; |
| 340 | result = TSI_OK; |
| 341 | } |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 342 | return result; |
| 343 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 344 | } |
| 345 | |
| 346 | /* Now process the protected_bytes. */ |
| 347 | if (frame->needs_draining) return TSI_INTERNAL_ERROR; |
| 348 | result = fill_frame_from_bytes(protected_frames_bytes, |
| 349 | protected_frames_bytes_size, frame); |
| 350 | if (result != TSI_OK) { |
| 351 | if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; |
| 352 | return result; |
| 353 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 354 | |
| 355 | /* Try to drain again. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 356 | if (!frame->needs_draining) return TSI_INTERNAL_ERROR; |
| 357 | if (frame->offset != 0) return TSI_INTERNAL_ERROR; |
| 358 | frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; /* Go past the header. */ |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 359 | drained_size = saved_output_size - *num_bytes_written; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 360 | result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 361 | *num_bytes_written += drained_size; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 362 | if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 363 | return result; |
| 364 | } |
| 365 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 366 | static void fake_protector_destroy(tsi_frame_protector *self) { |
| 367 | tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self; |
| 368 | tsi_fake_frame_destruct(&impl->protect_frame); |
| 369 | tsi_fake_frame_destruct(&impl->unprotect_frame); |
Nicolas "Pixel" Noble | 7c9a154 | 2016-03-26 01:33:34 +0100 | [diff] [blame] | 370 | gpr_free(self); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 371 | } |
| 372 | |
| 373 | static const tsi_frame_protector_vtable frame_protector_vtable = { |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 374 | fake_protector_protect, fake_protector_protect_flush, |
| 375 | fake_protector_unprotect, fake_protector_destroy, |
Craig Tiller | d6c98df | 2015-08-18 09:33:44 -0700 | [diff] [blame] | 376 | }; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 377 | |
| 378 | /* --- tsi_handshaker methods implementation. ---*/ |
| 379 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 380 | static tsi_result fake_handshaker_get_bytes_to_send_to_peer( |
| 381 | tsi_handshaker *self, unsigned char *bytes, size_t *bytes_size) { |
| 382 | tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 383 | tsi_result result = TSI_OK; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 384 | if (impl->needs_incoming_message || impl->result == TSI_OK) { |
| 385 | *bytes_size = 0; |
| 386 | return TSI_OK; |
| 387 | } |
| 388 | if (!impl->outgoing.needs_draining) { |
| 389 | tsi_fake_handshake_message next_message_to_send = |
| 390 | impl->next_message_to_send + 2; |
| 391 | const char *msg_string = |
| 392 | tsi_fake_handshake_message_to_string(impl->next_message_to_send); |
| 393 | result = bytes_to_frame((unsigned char *)msg_string, strlen(msg_string), |
| 394 | &impl->outgoing); |
| 395 | if (result != TSI_OK) return result; |
| 396 | if (next_message_to_send > TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { |
| 397 | next_message_to_send = TSI_FAKE_HANDSHAKE_MESSAGE_MAX; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 398 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 399 | if (tsi_tracing_enabled) { |
| 400 | gpr_log(GPR_INFO, "%s prepared %s.", |
| 401 | impl->is_client ? "Client" : "Server", |
| 402 | tsi_fake_handshake_message_to_string(impl->next_message_to_send)); |
Julien Boeuf | 980f600 | 2015-02-26 16:41:41 -0800 | [diff] [blame] | 403 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 404 | impl->next_message_to_send = next_message_to_send; |
| 405 | } |
| 406 | result = drain_frame_to_bytes(bytes, bytes_size, &impl->outgoing); |
| 407 | if (result != TSI_OK) return result; |
| 408 | if (!impl->is_client && |
| 409 | impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { |
| 410 | /* We're done. */ |
| 411 | if (tsi_tracing_enabled) { |
| 412 | gpr_log(GPR_INFO, "Server is done."); |
Julien Boeuf | 980f600 | 2015-02-26 16:41:41 -0800 | [diff] [blame] | 413 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 414 | impl->result = TSI_OK; |
| 415 | } else { |
| 416 | impl->needs_incoming_message = 1; |
| 417 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 418 | return TSI_OK; |
| 419 | } |
| 420 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 421 | static tsi_result fake_handshaker_process_bytes_from_peer( |
| 422 | tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 423 | tsi_result result = TSI_OK; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 424 | tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self; |
Nicolas "Pixel" Noble | 213ed91 | 2015-01-30 02:11:35 +0100 | [diff] [blame] | 425 | tsi_fake_handshake_message expected_msg = impl->next_message_to_send - 1; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 426 | tsi_fake_handshake_message received_msg; |
| 427 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 428 | if (!impl->needs_incoming_message || impl->result == TSI_OK) { |
| 429 | *bytes_size = 0; |
| 430 | return TSI_OK; |
| 431 | } |
| 432 | result = fill_frame_from_bytes(bytes, bytes_size, &impl->incoming); |
| 433 | if (result != TSI_OK) return result; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 434 | |
| 435 | /* We now have a complete frame. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 436 | result = tsi_fake_handshake_message_from_string( |
| 437 | (const char *)impl->incoming.data + TSI_FAKE_FRAME_HEADER_SIZE, |
| 438 | &received_msg); |
| 439 | if (result != TSI_OK) { |
| 440 | impl->result = result; |
| 441 | return result; |
| 442 | } |
| 443 | if (received_msg != expected_msg) { |
| 444 | gpr_log(GPR_ERROR, "Invalid received message (%s instead of %s)", |
| 445 | tsi_fake_handshake_message_to_string(received_msg), |
| 446 | tsi_fake_handshake_message_to_string(expected_msg)); |
| 447 | } |
| 448 | if (tsi_tracing_enabled) { |
| 449 | gpr_log(GPR_INFO, "%s received %s.", impl->is_client ? "Client" : "Server", |
| 450 | tsi_fake_handshake_message_to_string(received_msg)); |
| 451 | } |
| 452 | tsi_fake_frame_reset(&impl->incoming, 0 /* needs_draining */); |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 453 | impl->needs_incoming_message = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 454 | if (impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { |
| 455 | /* We're done. */ |
| 456 | if (tsi_tracing_enabled) { |
| 457 | gpr_log(GPR_INFO, "%s is done.", impl->is_client ? "Client" : "Server"); |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 458 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 459 | impl->result = TSI_OK; |
| 460 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 461 | return TSI_OK; |
| 462 | } |
| 463 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 464 | static tsi_result fake_handshaker_get_result(tsi_handshaker *self) { |
| 465 | tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 466 | return impl->result; |
| 467 | } |
| 468 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 469 | static tsi_result fake_handshaker_extract_peer(tsi_handshaker *self, |
| 470 | tsi_peer *peer) { |
| 471 | tsi_result result = tsi_construct_peer(1, peer); |
| 472 | if (result != TSI_OK) return result; |
| 473 | result = tsi_construct_string_peer_property_from_cstring( |
| 474 | TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_FAKE_CERTIFICATE_TYPE, |
| 475 | &peer->properties[0]); |
| 476 | if (result != TSI_OK) tsi_peer_destruct(peer); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 477 | return result; |
| 478 | } |
| 479 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 480 | static tsi_result fake_handshaker_create_frame_protector( |
| 481 | tsi_handshaker *self, size_t *max_protected_frame_size, |
| 482 | tsi_frame_protector **protector) { |
| 483 | *protector = tsi_create_fake_protector(max_protected_frame_size); |
| 484 | if (*protector == NULL) return TSI_OUT_OF_RESOURCES; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 485 | return TSI_OK; |
| 486 | } |
| 487 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 488 | static void fake_handshaker_destroy(tsi_handshaker *self) { |
| 489 | tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self; |
| 490 | tsi_fake_frame_destruct(&impl->incoming); |
| 491 | tsi_fake_frame_destruct(&impl->outgoing); |
Nicolas "Pixel" Noble | 7c9a154 | 2016-03-26 01:33:34 +0100 | [diff] [blame] | 492 | gpr_free(self); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 493 | } |
| 494 | |
| 495 | static const tsi_handshaker_vtable handshaker_vtable = { |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 496 | fake_handshaker_get_bytes_to_send_to_peer, |
Craig Tiller | f40df23 | 2016-03-25 13:38:14 -0700 | [diff] [blame] | 497 | fake_handshaker_process_bytes_from_peer, |
| 498 | fake_handshaker_get_result, |
| 499 | fake_handshaker_extract_peer, |
| 500 | fake_handshaker_create_frame_protector, |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 501 | fake_handshaker_destroy, |
Craig Tiller | d6c98df | 2015-08-18 09:33:44 -0700 | [diff] [blame] | 502 | }; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 503 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 504 | tsi_handshaker *tsi_create_fake_handshaker(int is_client) { |
Nicolas "Pixel" Noble | 367e5d8 | 2016-03-26 01:37:43 +0100 | [diff] [blame] | 505 | tsi_fake_handshaker *impl = gpr_malloc(sizeof(*impl)); |
| 506 | memset(impl, 0, sizeof(*impl)); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 507 | impl->base.vtable = &handshaker_vtable; |
| 508 | impl->is_client = is_client; |
| 509 | impl->result = TSI_HANDSHAKE_IN_PROGRESS; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 510 | if (is_client) { |
| 511 | impl->needs_incoming_message = 0; |
| 512 | impl->next_message_to_send = TSI_FAKE_CLIENT_INIT; |
| 513 | } else { |
| 514 | impl->needs_incoming_message = 1; |
| 515 | impl->next_message_to_send = TSI_FAKE_SERVER_INIT; |
| 516 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 517 | return &impl->base; |
| 518 | } |
| 519 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 520 | tsi_frame_protector *tsi_create_fake_protector( |
| 521 | size_t *max_protected_frame_size) { |
Nicolas "Pixel" Noble | 367e5d8 | 2016-03-26 01:37:43 +0100 | [diff] [blame] | 522 | tsi_fake_frame_protector *impl = gpr_malloc(sizeof(*impl)); |
| 523 | memset(impl, 0, sizeof(*impl)); |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 524 | impl->max_frame_size = (max_protected_frame_size == NULL) |
| 525 | ? TSI_FAKE_DEFAULT_FRAME_SIZE |
| 526 | : *max_protected_frame_size; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 527 | impl->base.vtable = &frame_protector_vtable; |
| 528 | return &impl->base; |
Craig Tiller | 190d360 | 2015-02-18 09:23:38 -0800 | [diff] [blame] | 529 | } |