blob: 64aac2c05a05259a44b8955ca946f052f881ab85 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller8a9fd522016-03-25 17:09:29 -07003 * Copyright 2015-2016, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * 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/tsi/transport_security.h"
35
36#include <stdlib.h>
37#include <string.h>
38
Julien Boeuf980f6002015-02-26 16:41:41 -080039/* --- Tracing. --- */
40
41int tsi_tracing_enabled = 0;
42
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080043/* --- Utils. --- */
44
Craig Tillera82950e2015-09-22 12:33:20 -070045char *tsi_strdup(const char *src) {
Craig Tiller45724b32015-09-22 10:42:19 -070046 char *dst;
Julien Boeufb222b4d2015-01-15 17:01:39 -080047 size_t len;
Craig Tillera82950e2015-09-22 12:33:20 -070048 if (!src) return NULL;
49 len = strlen(src) + 1;
50 dst = malloc(len);
51 if (!dst) return NULL;
52 memcpy(dst, src, len);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080053 return dst;
54}
55
56/* --- tsi_result common implementation. --- */
57
Craig Tillera82950e2015-09-22 12:33:20 -070058const char *tsi_result_to_string(tsi_result result) {
59 switch (result) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080060 case TSI_OK:
61 return "TSI_OK";
62 case TSI_UNKNOWN_ERROR:
63 return "TSI_UNKNOWN_ERROR";
64 case TSI_INVALID_ARGUMENT:
65 return "TSI_INVALID_ARGUMENT";
66 case TSI_PERMISSION_DENIED:
67 return "TSI_PERMISSION_DENIED";
68 case TSI_INCOMPLETE_DATA:
69 return "TSI_INCOMPLETE_DATA";
70 case TSI_FAILED_PRECONDITION:
71 return "TSI_FAILED_PRECONDITION";
72 case TSI_UNIMPLEMENTED:
73 return "TSI_UNIMPLEMENTED";
74 case TSI_INTERNAL_ERROR:
75 return "TSI_INTERNAL_ERROR";
76 case TSI_DATA_CORRUPTED:
77 return "TSI_DATA_CORRUPTED";
78 case TSI_NOT_FOUND:
79 return "TSI_NOT_FOUND";
80 case TSI_PROTOCOL_FAILURE:
81 return "TSI_PROTOCOL_FAILURE";
82 case TSI_HANDSHAKE_IN_PROGRESS:
83 return "TSI_HANDSHAKE_IN_PROGRESS";
84 case TSI_OUT_OF_RESOURCES:
85 return "TSI_OUT_OF_RESOURCES";
86 default:
87 return "UNKNOWN";
Craig Tillera82950e2015-09-22 12:33:20 -070088 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080089}
90
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080091/* --- tsi_frame_protector common implementation. ---
92
93 Calls specific implementation after state/input validation. */
94
Craig Tillera82950e2015-09-22 12:33:20 -070095tsi_result tsi_frame_protector_protect(tsi_frame_protector *self,
96 const unsigned char *unprotected_bytes,
97 size_t *unprotected_bytes_size,
98 unsigned char *protected_output_frames,
99 size_t *protected_output_frames_size) {
100 if (self == NULL || unprotected_bytes == NULL ||
101 unprotected_bytes_size == NULL || protected_output_frames == NULL ||
102 protected_output_frames_size == NULL) {
103 return TSI_INVALID_ARGUMENT;
104 }
105 return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size,
106 protected_output_frames,
107 protected_output_frames_size);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800108}
109
Craig Tillera82950e2015-09-22 12:33:20 -0700110tsi_result tsi_frame_protector_protect_flush(
111 tsi_frame_protector *self, unsigned char *protected_output_frames,
112 size_t *protected_output_frames_size, size_t *still_pending_size) {
113 if (self == NULL || protected_output_frames == NULL ||
114 protected_output_frames == NULL || still_pending_size == NULL) {
115 return TSI_INVALID_ARGUMENT;
116 }
117 return self->vtable->protect_flush(self, protected_output_frames,
118 protected_output_frames_size,
119 still_pending_size);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800120}
121
Craig Tillera82950e2015-09-22 12:33:20 -0700122tsi_result tsi_frame_protector_unprotect(
123 tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
124 size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
125 size_t *unprotected_bytes_size) {
126 if (self == NULL || protected_frames_bytes == NULL ||
127 protected_frames_bytes_size == NULL || unprotected_bytes == NULL ||
128 unprotected_bytes_size == NULL) {
129 return TSI_INVALID_ARGUMENT;
130 }
131 return self->vtable->unprotect(self, protected_frames_bytes,
132 protected_frames_bytes_size, unprotected_bytes,
133 unprotected_bytes_size);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800134}
135
Craig Tillera82950e2015-09-22 12:33:20 -0700136void tsi_frame_protector_destroy(tsi_frame_protector *self) {
137 if (self == NULL) return;
138 self->vtable->destroy(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800139}
140
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800141/* --- tsi_handshaker common implementation. ---
142
143 Calls specific implementation after state/input validation. */
144
Craig Tillera82950e2015-09-22 12:33:20 -0700145tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
146 unsigned char *bytes,
147 size_t *bytes_size) {
Julien Boeuf4c8e8182015-12-07 11:34:12 -0800148 if (self == NULL || bytes == NULL || bytes_size == NULL) {
149 return TSI_INVALID_ARGUMENT;
150 }
Craig Tillera82950e2015-09-22 12:33:20 -0700151 if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
152 return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800153}
154
Craig Tillera82950e2015-09-22 12:33:20 -0700155tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self,
156 const unsigned char *bytes,
157 size_t *bytes_size) {
Julien Boeuf4c8e8182015-12-07 11:34:12 -0800158 if (self == NULL || bytes == NULL || bytes_size == NULL) {
159 return TSI_INVALID_ARGUMENT;
160 }
Craig Tillera82950e2015-09-22 12:33:20 -0700161 if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
162 return self->vtable->process_bytes_from_peer(self, bytes, bytes_size);
Craig Tiller45724b32015-09-22 10:42:19 -0700163}
164
Craig Tillera82950e2015-09-22 12:33:20 -0700165tsi_result tsi_handshaker_get_result(tsi_handshaker *self) {
166 if (self == NULL) return TSI_INVALID_ARGUMENT;
167 if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
168 return self->vtable->get_result(self);
Craig Tiller45724b32015-09-22 10:42:19 -0700169}
170
Craig Tillera82950e2015-09-22 12:33:20 -0700171tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer) {
172 if (self == NULL || peer == NULL) return TSI_INVALID_ARGUMENT;
173 memset(peer, 0, sizeof(tsi_peer));
174 if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
175 if (tsi_handshaker_get_result(self) != TSI_OK) {
Craig Tiller45724b32015-09-22 10:42:19 -0700176 return TSI_FAILED_PRECONDITION;
Craig Tillera82950e2015-09-22 12:33:20 -0700177 }
178 return self->vtable->extract_peer(self, peer);
Craig Tiller45724b32015-09-22 10:42:19 -0700179}
180
Craig Tillera82950e2015-09-22 12:33:20 -0700181tsi_result tsi_handshaker_create_frame_protector(
182 tsi_handshaker *self, size_t *max_protected_frame_size,
183 tsi_frame_protector **protector) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800184 tsi_result result;
Craig Tillera82950e2015-09-22 12:33:20 -0700185 if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT;
186 if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
187 if (tsi_handshaker_get_result(self) != TSI_OK) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800188 return TSI_FAILED_PRECONDITION;
Craig Tillera82950e2015-09-22 12:33:20 -0700189 }
190 result = self->vtable->create_frame_protector(self, max_protected_frame_size,
191 protector);
192 if (result == TSI_OK) {
193 self->frame_protector_created = 1;
194 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800195 return result;
196}
197
Craig Tillera82950e2015-09-22 12:33:20 -0700198void tsi_handshaker_destroy(tsi_handshaker *self) {
199 if (self == NULL) return;
200 self->vtable->destroy(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800201}
202
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800203/* --- tsi_peer implementation. --- */
204
Craig Tillera82950e2015-09-22 12:33:20 -0700205tsi_peer_property tsi_init_peer_property(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800206 tsi_peer_property property;
Craig Tillera82950e2015-09-22 12:33:20 -0700207 memset(&property, 0, sizeof(tsi_peer_property));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800208 return property;
209}
210
Craig Tillera82950e2015-09-22 12:33:20 -0700211static void tsi_peer_destroy_list_property(tsi_peer_property *children,
212 size_t child_count) {
Julien Boeufb222b4d2015-01-15 17:01:39 -0800213 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -0700214 for (i = 0; i < child_count; i++) {
215 tsi_peer_property_destruct(&children[i]);
216 }
217 free(children);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800218}
219
Craig Tillera82950e2015-09-22 12:33:20 -0700220void tsi_peer_property_destruct(tsi_peer_property *property) {
221 if (property->name != NULL) {
222 free(property->name);
223 }
224 if (property->value.data != NULL) {
225 free(property->value.data);
226 }
227 *property = tsi_init_peer_property(); /* Reset everything to 0. */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800228}
229
Craig Tillera82950e2015-09-22 12:33:20 -0700230void tsi_peer_destruct(tsi_peer *self) {
231 if (self == NULL) return;
232 if (self->properties != NULL) {
233 tsi_peer_destroy_list_property(self->properties, self->property_count);
234 self->properties = NULL;
235 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800236 self->property_count = 0;
237}
238
Craig Tillera82950e2015-09-22 12:33:20 -0700239tsi_result tsi_construct_allocated_string_peer_property(
240 const char *name, size_t value_length, tsi_peer_property *property) {
241 *property = tsi_init_peer_property();
242 if (name != NULL) {
243 property->name = tsi_strdup(name);
244 if (property->name == NULL) return TSI_OUT_OF_RESOURCES;
245 }
246 if (value_length > 0) {
247 property->value.data = calloc(1, value_length);
248 if (property->value.data == NULL) {
249 tsi_peer_property_destruct(property);
250 return TSI_OUT_OF_RESOURCES;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800251 }
Craig Tillera82950e2015-09-22 12:33:20 -0700252 property->value.length = value_length;
253 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800254 return TSI_OK;
255}
256
Craig Tillera82950e2015-09-22 12:33:20 -0700257tsi_result tsi_construct_string_peer_property_from_cstring(
258 const char *name, const char *value, tsi_peer_property *property) {
259 return tsi_construct_string_peer_property(name, value, strlen(value),
260 property);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800261}
262
Craig Tillera82950e2015-09-22 12:33:20 -0700263tsi_result tsi_construct_string_peer_property(const char *name,
264 const char *value,
265 size_t value_length,
266 tsi_peer_property *property) {
267 tsi_result result = tsi_construct_allocated_string_peer_property(
268 name, value_length, property);
269 if (result != TSI_OK) return result;
270 if (value_length > 0) {
271 memcpy(property->value.data, value, value_length);
272 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800273 return TSI_OK;
274}
275
Craig Tillera82950e2015-09-22 12:33:20 -0700276tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer) {
277 memset(peer, 0, sizeof(tsi_peer));
278 if (property_count > 0) {
279 peer->properties = calloc(property_count, sizeof(tsi_peer_property));
280 if (peer->properties == NULL) return TSI_OUT_OF_RESOURCES;
281 peer->property_count = property_count;
282 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800283 return TSI_OK;
Craig Tiller190d3602015-02-18 09:23:38 -0800284}