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/tsi/transport_security.h"
35 :
36 : #include <stdlib.h>
37 : #include <string.h>
38 :
39 : /* --- Tracing. --- */
40 :
41 : int tsi_tracing_enabled = 0;
42 :
43 : /* --- Utils. --- */
44 :
45 4558 : char *tsi_strdup(const char *src) {
46 : char *dst;
47 : size_t len;
48 4558 : if (!src) return NULL;
49 4558 : len = strlen(src) + 1;
50 4558 : dst = malloc(len);
51 4558 : if (!dst) return NULL;
52 4558 : memcpy(dst, src, len);
53 4558 : return dst;
54 : }
55 :
56 : /* --- tsi_result common implementation. --- */
57 :
58 0 : const char *tsi_result_to_string(tsi_result result) {
59 0 : switch (result) {
60 : case TSI_OK:
61 0 : return "TSI_OK";
62 : case TSI_UNKNOWN_ERROR:
63 0 : return "TSI_UNKNOWN_ERROR";
64 : case TSI_INVALID_ARGUMENT:
65 0 : return "TSI_INVALID_ARGUMENT";
66 : case TSI_PERMISSION_DENIED:
67 0 : return "TSI_PERMISSION_DENIED";
68 : case TSI_INCOMPLETE_DATA:
69 0 : return "TSI_INCOMPLETE_DATA";
70 : case TSI_FAILED_PRECONDITION:
71 0 : return "TSI_FAILED_PRECONDITION";
72 : case TSI_UNIMPLEMENTED:
73 0 : return "TSI_UNIMPLEMENTED";
74 : case TSI_INTERNAL_ERROR:
75 0 : return "TSI_INTERNAL_ERROR";
76 : case TSI_DATA_CORRUPTED:
77 0 : return "TSI_DATA_CORRUPTED";
78 : case TSI_NOT_FOUND:
79 0 : return "TSI_NOT_FOUND";
80 : case TSI_PROTOCOL_FAILURE:
81 0 : return "TSI_PROTOCOL_FAILURE";
82 : case TSI_HANDSHAKE_IN_PROGRESS:
83 0 : return "TSI_HANDSHAKE_IN_PROGRESS";
84 : case TSI_OUT_OF_RESOURCES:
85 0 : return "TSI_OUT_OF_RESOURCES";
86 : default:
87 0 : return "UNKNOWN";
88 : }
89 : }
90 :
91 : /* --- tsi_frame_protector common implementation. ---
92 :
93 : Calls specific implementation after state/input validation. */
94 :
95 161668 : tsi_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 161668 : if (self == NULL || unprotected_bytes == NULL ||
101 161667 : unprotected_bytes_size == NULL || protected_output_frames == NULL ||
102 : protected_output_frames_size == NULL) {
103 0 : return TSI_INVALID_ARGUMENT;
104 : }
105 161668 : return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size,
106 : protected_output_frames,
107 : protected_output_frames_size);
108 : }
109 :
110 137418 : tsi_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 137418 : if (self == NULL || protected_output_frames == NULL ||
114 137418 : protected_output_frames == NULL || still_pending_size == NULL) {
115 0 : return TSI_INVALID_ARGUMENT;
116 : }
117 137418 : return self->vtable->protect_flush(self, protected_output_frames,
118 : protected_output_frames_size,
119 : still_pending_size);
120 : }
121 :
122 1530251 : tsi_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 1530251 : if (self == NULL || protected_frames_bytes == NULL ||
127 1530251 : protected_frames_bytes_size == NULL || unprotected_bytes == NULL ||
128 : unprotected_bytes_size == NULL) {
129 0 : return TSI_INVALID_ARGUMENT;
130 : }
131 1530251 : return self->vtable->unprotect(self, protected_frames_bytes,
132 : protected_frames_bytes_size, unprotected_bytes,
133 : unprotected_bytes_size);
134 : }
135 :
136 946 : void tsi_frame_protector_destroy(tsi_frame_protector *self) {
137 1892 : if (self == NULL) return;
138 946 : self->vtable->destroy(self);
139 : }
140 :
141 : /* --- tsi_handshaker common implementation. ---
142 :
143 : Calls specific implementation after state/input validation. */
144 :
145 2605 : tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
146 : unsigned char *bytes,
147 : size_t *bytes_size) {
148 2605 : if (self == NULL) return TSI_INVALID_ARGUMENT;
149 2605 : if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
150 2605 : return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size);
151 : }
152 :
153 1767 : tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self,
154 : const unsigned char *bytes,
155 : size_t *bytes_size) {
156 1767 : if (self == NULL) return TSI_INVALID_ARGUMENT;
157 1767 : if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
158 1767 : return self->vtable->process_bytes_from_peer(self, bytes, bytes_size);
159 : }
160 :
161 8624 : tsi_result tsi_handshaker_get_result(tsi_handshaker *self) {
162 8624 : if (self == NULL) return TSI_INVALID_ARGUMENT;
163 8624 : if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
164 8624 : return self->vtable->get_result(self);
165 : }
166 :
167 878 : tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer) {
168 878 : if (self == NULL || peer == NULL) return TSI_INVALID_ARGUMENT;
169 878 : memset(peer, 0, sizeof(tsi_peer));
170 878 : if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
171 878 : if (tsi_handshaker_get_result(self) != TSI_OK) {
172 0 : return TSI_FAILED_PRECONDITION;
173 : }
174 878 : return self->vtable->extract_peer(self, peer);
175 : }
176 :
177 878 : tsi_result tsi_handshaker_create_frame_protector(
178 : tsi_handshaker *self, size_t *max_protected_frame_size,
179 : tsi_frame_protector **protector) {
180 : tsi_result result;
181 878 : if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT;
182 878 : if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
183 878 : if (tsi_handshaker_get_result(self) != TSI_OK) {
184 0 : return TSI_FAILED_PRECONDITION;
185 : }
186 878 : result = self->vtable->create_frame_protector(self, max_protected_frame_size,
187 : protector);
188 878 : if (result == TSI_OK) {
189 878 : self->frame_protector_created = 1;
190 : }
191 878 : return result;
192 : }
193 :
194 897 : void tsi_handshaker_destroy(tsi_handshaker *self) {
195 1794 : if (self == NULL) return;
196 897 : self->vtable->destroy(self);
197 : }
198 :
199 : /* --- tsi_peer implementation. --- */
200 :
201 9116 : tsi_peer_property tsi_init_peer_property(void) {
202 : tsi_peer_property property;
203 9116 : memset(&property, 0, sizeof(tsi_peer_property));
204 9116 : return property;
205 : }
206 :
207 1382 : static void tsi_peer_destroy_list_property(tsi_peer_property *children,
208 : size_t child_count) {
209 : size_t i;
210 5940 : for (i = 0; i < child_count; i++) {
211 4558 : tsi_peer_property_destruct(&children[i]);
212 : }
213 1382 : free(children);
214 1382 : }
215 :
216 4558 : void tsi_peer_property_destruct(tsi_peer_property *property) {
217 4558 : if (property->name != NULL) {
218 4558 : free(property->name);
219 : }
220 4558 : if (property->value.data != NULL) {
221 4553 : free(property->value.data);
222 : }
223 4558 : *property = tsi_init_peer_property(); /* Reset everything to 0. */
224 4558 : }
225 :
226 1816 : void tsi_peer_destruct(tsi_peer *self) {
227 3632 : if (self == NULL) return;
228 1816 : if (self->properties != NULL) {
229 1382 : tsi_peer_destroy_list_property(self->properties, self->property_count);
230 1382 : self->properties = NULL;
231 : }
232 1816 : self->property_count = 0;
233 : }
234 :
235 4558 : tsi_result tsi_construct_allocated_string_peer_property(
236 : const char *name, size_t value_length, tsi_peer_property *property) {
237 4558 : *property = tsi_init_peer_property();
238 4558 : if (name != NULL) {
239 4558 : property->name = tsi_strdup(name);
240 4558 : if (property->name == NULL) return TSI_OUT_OF_RESOURCES;
241 : }
242 4558 : if (value_length > 0) {
243 4553 : property->value.data = calloc(1, value_length);
244 4553 : if (property->value.data == NULL) {
245 0 : tsi_peer_property_destruct(property);
246 0 : return TSI_OUT_OF_RESOURCES;
247 : }
248 4553 : property->value.length = value_length;
249 : }
250 4558 : return TSI_OK;
251 : }
252 :
253 590 : tsi_result tsi_construct_string_peer_property_from_cstring(
254 : const char *name, const char *value, tsi_peer_property *property) {
255 590 : return tsi_construct_string_peer_property(name, value, strlen(value),
256 : property);
257 : }
258 :
259 4558 : tsi_result tsi_construct_string_peer_property(const char *name,
260 : const char *value,
261 : size_t value_length,
262 : tsi_peer_property *property) {
263 4558 : tsi_result result = tsi_construct_allocated_string_peer_property(
264 : name, value_length, property);
265 4558 : if (result != TSI_OK) return result;
266 4558 : if (value_length > 0) {
267 4553 : memcpy(property->value.data, value, value_length);
268 : }
269 4558 : return TSI_OK;
270 : }
271 :
272 1015 : tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer) {
273 1015 : memset(peer, 0, sizeof(tsi_peer));
274 1015 : if (property_count > 0) {
275 1015 : peer->properties = calloc(property_count, sizeof(tsi_peer_property));
276 1015 : if (peer->properties == NULL) return TSI_OUT_OF_RESOURCES;
277 1015 : peer->property_count = property_count;
278 : }
279 1015 : return TSI_OK;
280 : }
|