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