1 /*
2 * Copyright (c) 2014 by Farsight Security, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "fstrm-private.h"
25
26 struct fstrm_control {
27 fstrm_control_type type;
28 fs_bufvec *content_types;
29 };
30
31 const char *
fstrm_control_type_to_str(fstrm_control_type type)32 fstrm_control_type_to_str(fstrm_control_type type)
33 {
34 switch (type) {
35 case FSTRM_CONTROL_ACCEPT:
36 return "FSTRM_CONTROL_ACCEPT";
37 case FSTRM_CONTROL_START:
38 return "FSTRM_CONTROL_START";
39 case FSTRM_CONTROL_STOP:
40 return "FSTRM_CONTROL_STOP";
41 case FSTRM_CONTROL_READY:
42 return "FSTRM_CONTROL_READY";
43 case FSTRM_CONTROL_FINISH:
44 return "FSTRM_CONTROL_FINISH";
45 default:
46 return "FSTRM_CONTROL_UNKNOWN";
47 }
48 }
49
50 const char *
fstrm_control_field_type_to_str(fstrm_control_field f_type)51 fstrm_control_field_type_to_str(fstrm_control_field f_type)
52 {
53 switch (f_type) {
54 case FSTRM_CONTROL_FIELD_CONTENT_TYPE:
55 return "FSTRM_CONTROL_FIELD_CONTENT_TYPE";
56 default:
57 return "FSTRM_CONTROL_FIELD_UNKNOWN";
58 }
59 }
60
61 struct fstrm_control *
fstrm_control_init(void)62 fstrm_control_init(void)
63 {
64 struct fstrm_control *c;
65 c = my_calloc(1, sizeof(*c));
66 c->content_types = fs_bufvec_init(1);
67 return c;
68 }
69
70 void
fstrm_control_destroy(struct fstrm_control ** c)71 fstrm_control_destroy(struct fstrm_control **c)
72 {
73 if (*c != NULL) {
74 fstrm_control_reset(*c);
75 fs_bufvec_destroy(&(*c)->content_types);
76 my_free(*c);
77 }
78 }
79
80 void
fstrm_control_reset(struct fstrm_control * c)81 fstrm_control_reset(struct fstrm_control *c)
82 {
83 for (size_t i = 0; i < fs_bufvec_size(c->content_types); i++) {
84 fs_buf buf = fs_bufvec_value(c->content_types, i);
85 my_free(buf.data);
86 }
87 fs_bufvec_reset(c->content_types);
88 c->type = 0;
89 }
90
91 fstrm_res
fstrm_control_get_type(const struct fstrm_control * c,fstrm_control_type * type)92 fstrm_control_get_type(const struct fstrm_control *c, fstrm_control_type *type)
93 {
94 switch (c->type) {
95 case FSTRM_CONTROL_ACCEPT: /* FALLTHROUGH */
96 case FSTRM_CONTROL_START: /* FALLTHROUGH */
97 case FSTRM_CONTROL_STOP: /* FALLTHROUGH */
98 case FSTRM_CONTROL_READY: /* FALLTHROUGH */
99 case FSTRM_CONTROL_FINISH:
100 *type = c->type;
101 return fstrm_res_success;
102 default:
103 return fstrm_res_failure;
104 }
105 }
106
107 fstrm_res
fstrm_control_set_type(struct fstrm_control * c,fstrm_control_type type)108 fstrm_control_set_type(struct fstrm_control *c, fstrm_control_type type)
109 {
110 switch (type) {
111 case FSTRM_CONTROL_ACCEPT: /* FALLTHROUGH */
112 case FSTRM_CONTROL_START: /* FALLTHROUGH */
113 case FSTRM_CONTROL_STOP: /* FALLTHROUGH */
114 case FSTRM_CONTROL_READY: /* FALLTHROUGH */
115 case FSTRM_CONTROL_FINISH:
116 c->type = type;
117 return fstrm_res_success;
118 default:
119 return fstrm_res_failure;
120 }
121 }
122
123 fstrm_res
fstrm_control_get_num_field_content_type(const struct fstrm_control * c,size_t * n_content_type)124 fstrm_control_get_num_field_content_type(const struct fstrm_control *c,
125 size_t *n_content_type)
126 {
127 *n_content_type = fs_bufvec_size(c->content_types);
128
129 switch (c->type) {
130 case FSTRM_CONTROL_STOP: /* FALLTHROUGH */
131 case FSTRM_CONTROL_FINISH: /* FALLTHROUGH */
132 /*
133 * STOP and FINISH frames may not have any content type fields.
134 */
135 *n_content_type = 0;
136 break;
137 case FSTRM_CONTROL_START:
138 /* START frames may not have more than one content type field. */
139 if (*n_content_type > 1)
140 *n_content_type = 1;
141 break;
142 default:
143 break;
144 }
145
146 return fstrm_res_success;
147 }
148
149 fstrm_res
fstrm_control_get_field_content_type(const struct fstrm_control * c,const size_t idx,const uint8_t ** content_type,size_t * len_content_type)150 fstrm_control_get_field_content_type(const struct fstrm_control *c,
151 const size_t idx,
152 const uint8_t **content_type,
153 size_t *len_content_type)
154 {
155 if (idx < fs_bufvec_size(c->content_types)) {
156 fs_buf buf = fs_bufvec_value(c->content_types, idx);
157 *content_type = buf.data;
158 *len_content_type = buf.len;
159 return fstrm_res_success;
160 }
161 return fstrm_res_failure;
162 }
163
164 fstrm_res
fstrm_control_add_field_content_type(struct fstrm_control * c,const uint8_t * content_type,size_t len_content_type)165 fstrm_control_add_field_content_type(struct fstrm_control *c,
166 const uint8_t *content_type,
167 size_t len_content_type)
168 {
169 fs_buf ctype;
170 ctype.len = len_content_type;
171 ctype.data = my_malloc(ctype.len);
172 memcpy(ctype.data, content_type, ctype.len);
173 fs_bufvec_add(c->content_types, ctype);
174
175 return fstrm_res_success;
176 }
177
178 fstrm_res
fstrm_control_match_field_content_type(const struct fstrm_control * c,const uint8_t * match,const size_t len_match)179 fstrm_control_match_field_content_type(const struct fstrm_control *c,
180 const uint8_t *match,
181 const size_t len_match)
182 {
183 fstrm_res res;
184 size_t n_ctype = 0;
185
186 /*
187 * STOP and FINISH frames don't have a content type. They never match.
188 */
189 if (c->type == FSTRM_CONTROL_STOP || c->type == FSTRM_CONTROL_FINISH)
190 return fstrm_res_failure;
191
192 res = fstrm_control_get_num_field_content_type(c, &n_ctype);
193 if (res != fstrm_res_success)
194 return res;
195
196 if (n_ctype == 0) {
197 /* Control frame doesn't set any content type. */
198 return fstrm_res_success;
199 } else {
200 /*
201 * The content type must match one of the control frame's
202 * content types.
203 */
204
205 if (match == NULL) {
206 /*
207 * The control frame has at least one content type set,
208 * which cannot match an unset content type.
209 */
210 return fstrm_res_failure;
211 }
212
213 for (size_t idx = 0; idx < n_ctype; idx++) {
214 /*
215 * Check against all the content types in the control
216 * frame.
217 */
218 const uint8_t *content_type = NULL;
219 size_t len_content_type = 0;
220
221 res = fstrm_control_get_field_content_type(c, idx,
222 &content_type, &len_content_type);
223 if (res != fstrm_res_success)
224 return res;
225
226 if (len_content_type != len_match)
227 continue;
228 if (memcmp(content_type, match, len_match) == 0) {
229 /* Exact match. */
230 return fstrm_res_success;
231 }
232 }
233 }
234
235 return fstrm_res_failure;
236 }
237
238 fstrm_res
fstrm_control_decode(struct fstrm_control * c,const void * control_frame,size_t len_control_frame,const uint32_t flags)239 fstrm_control_decode(struct fstrm_control *c,
240 const void *control_frame,
241 size_t len_control_frame,
242 const uint32_t flags)
243 {
244 const uint8_t *buf = control_frame;
245 size_t len = len_control_frame;
246 uint32_t val;
247
248 fstrm_control_reset(c);
249
250 if (flags & FSTRM_CONTROL_FLAG_WITH_HEADER) {
251 /* Read the outer frame length. */
252 if (!fs_load_be32(&buf, &len, &val))
253 return fstrm_res_failure;
254
255 /* The outer frame length must be zero, since this is a control frame. */
256 if (val != 0)
257 return fstrm_res_failure;
258
259 /* Read the control frame length. */
260 if (!fs_load_be32(&buf, &len, &val))
261 return fstrm_res_failure;
262
263 /* Enforce maximum control frame size. */
264 if (val > FSTRM_CONTROL_FRAME_LENGTH_MAX)
265 return fstrm_res_failure;
266
267 /*
268 * Require that the control frame length matches the number of
269 * bytes remaining in 'buf'.
270 */
271 if (val != len)
272 return fstrm_res_failure;
273 } else {
274 /* Enforce maximum control frame size. */
275 if (len_control_frame > FSTRM_CONTROL_FRAME_LENGTH_MAX)
276 return fstrm_res_failure;
277 }
278
279 /* Read the control frame type. */
280 if (!fs_load_be32(&buf, &len, &val))
281 return fstrm_res_failure;
282 switch (val) {
283 case FSTRM_CONTROL_ACCEPT: /* FALLTHROUGH */
284 case FSTRM_CONTROL_START: /* FALLTHROUGH */
285 case FSTRM_CONTROL_STOP: /* FALLTHROUGH */
286 case FSTRM_CONTROL_READY: /* FALLTHROUGH */
287 case FSTRM_CONTROL_FINISH:
288 c->type = (fstrm_control_type) val;
289 break;
290 default:
291 return fstrm_res_failure;
292 }
293
294 /* Read any control frame fields. */
295 while (len > 0) {
296 /* Read the control frame field type. */
297 if (!fs_load_be32(&buf, &len, &val))
298 return fstrm_res_failure;
299
300 switch (val) {
301 case FSTRM_CONTROL_FIELD_CONTENT_TYPE: {
302 fs_buf c_type;
303
304 /* Read the length of the "Content Type" payload. */
305 if (!fs_load_be32(&buf, &len, &val))
306 return fstrm_res_failure;
307 c_type.len = val;
308
309 /*
310 * Sanity check the length field. It cannot be larger
311 * than 'len', the number of bytes remaining in 'buf'.
312 */
313 if (c_type.len > len)
314 return fstrm_res_failure;
315
316 /* Enforce limit on "Content Type" payload length. */
317 if (c_type.len > FSTRM_CONTROL_FIELD_CONTENT_TYPE_LENGTH_MAX)
318 return fstrm_res_failure;
319
320 /* Read the "Content Type" payload. */
321 c_type.data = my_malloc(c_type.len);
322 if (!fs_load_bytes(c_type.data, c_type.len, &buf, &len))
323 {
324 my_free(c_type.data);
325 return fstrm_res_failure;
326 }
327
328 /* Insert the "Content Type" field. */
329 fs_bufvec_add(c->content_types, c_type);
330
331 break;
332 }
333 default:
334 return fstrm_res_failure;
335 }
336 }
337
338 /* Enforce limits on the number of "Content Type" fields. */
339 const size_t n_ctype = fs_bufvec_size(c->content_types);
340 switch (c->type) {
341 case FSTRM_CONTROL_START:
342 if (n_ctype > 1)
343 return fstrm_res_failure;
344 break;
345 case FSTRM_CONTROL_STOP:
346 /* FALLTHROUGH */
347 case FSTRM_CONTROL_FINISH:
348 if (n_ctype > 0)
349 return fstrm_res_failure;
350 break;
351 case FSTRM_CONTROL_ACCEPT:
352 /* FALLTHROUGH */
353 case FSTRM_CONTROL_READY:
354 /* FALLTHROUGH */
355 default:
356 break;
357 }
358
359 return fstrm_res_success;
360 }
361
362 fstrm_res
fstrm_control_encoded_size(const struct fstrm_control * c,size_t * len_control_frame,const uint32_t flags)363 fstrm_control_encoded_size(const struct fstrm_control *c,
364 size_t *len_control_frame,
365 const uint32_t flags)
366 {
367 size_t len = 0;
368
369 if (flags & FSTRM_CONTROL_FLAG_WITH_HEADER) {
370 /* Escape: 32-bit BE integer. */
371 len += sizeof(uint32_t);
372
373 /* Frame length: 32-bit BE integer. */
374 len += sizeof(uint32_t);
375 }
376
377 /* Control type: 32-bit BE integer. */
378 len += sizeof(uint32_t);
379
380 /* "Content Type" fields. */
381 for (size_t i = 0; i < fs_bufvec_size(c->content_types); i++) {
382 /* Do not add "Content Type" fields to STOP or FINISH frames. */
383 if (c->type == FSTRM_CONTROL_STOP ||
384 c->type == FSTRM_CONTROL_FINISH)
385 {
386 break;
387 }
388
389 fs_buf c_type = fs_bufvec_value(c->content_types, i);
390
391 /* FSTRM_CONTROL_FIELD_CONTENT_TYPE: 32-bit BE integer. */
392 len += sizeof(uint32_t);
393
394 /* Length of the "Content Type" string: 32-bit BE integer. */
395 len += sizeof(uint32_t);
396
397 /* Enforce limit on "Content Type" payload length. */
398 if (c_type.len > FSTRM_CONTROL_FIELD_CONTENT_TYPE_LENGTH_MAX)
399 return fstrm_res_failure;
400
401 /* The "Content Type" payload. */
402 len += c_type.len;
403
404 /* Only add one "Content Type" field to START frames. */
405 if (c->type == FSTRM_CONTROL_START)
406 break;
407 }
408
409 /* Sanity check the overall length. */
410 if (len > FSTRM_CONTROL_FRAME_LENGTH_MAX)
411 return fstrm_res_failure;
412
413 *len_control_frame = len;
414 return fstrm_res_success;
415 }
416
417 fstrm_res
fstrm_control_encode(const struct fstrm_control * c,void * control_frame,size_t * len_control_frame,const uint32_t flags)418 fstrm_control_encode(const struct fstrm_control *c,
419 void *control_frame,
420 size_t *len_control_frame,
421 const uint32_t flags)
422 {
423 fstrm_res res;
424 size_t encoded_size;
425
426 /* Calculate the size of the control frame. */
427 res = fstrm_control_encoded_size(c, &encoded_size, flags);
428 if (res != fstrm_res_success)
429 return res;
430
431 /*
432 * The caller must have provided a large enough buffer to serialize the
433 * control frame.
434 */
435 if (*len_control_frame < encoded_size)
436 return fstrm_res_failure;
437
438 /*
439 * Now actually serialize the control frame.
440 */
441 size_t len = encoded_size;
442 uint8_t *buf = control_frame;
443
444 if (flags & FSTRM_CONTROL_FLAG_WITH_HEADER) {
445 /* Escape: 32-bit BE integer. Zero. */
446 if (!fs_store_be32(&buf, &len, 0))
447 return fstrm_res_failure;
448
449 /*
450 * Frame length: 32-bit BE integer.
451 *
452 * This does not include the length of the escape frame or the length
453 * of the frame length field itself, so subtract 2*4 bytes from the
454 * total length.
455 */
456 if (!fs_store_be32(&buf, &len, encoded_size - 2 * sizeof(uint32_t)))
457 return fstrm_res_failure;
458 }
459
460 /* Control type: 32-bit BE integer. */
461 if (!fs_store_be32(&buf, &len, c->type))
462 return fstrm_res_failure;
463
464 /* "Content Type" fields. */
465 for (size_t i = 0; i < fs_bufvec_size(c->content_types); i++) {
466 /* Do not add "Content Type" fields to STOP or FINISH frames. */
467 if (c->type == FSTRM_CONTROL_STOP ||
468 c->type == FSTRM_CONTROL_FINISH)
469 {
470 break;
471 }
472
473 fs_buf c_type = fs_bufvec_value(c->content_types, i);
474
475 /* FSTRM_CONTROL_FIELD_CONTENT_TYPE: 32-bit BE integer. */
476 if (!fs_store_be32(&buf, &len, FSTRM_CONTROL_FIELD_CONTENT_TYPE))
477 return fstrm_res_failure;
478
479 /* Length of the "Content Type" payload: 32-bit BE integer. */
480 if (!fs_store_be32(&buf, &len, c_type.len))
481 return fstrm_res_failure;
482
483 /* The "Content Type" string itself. */
484 if (!fs_store_bytes(&buf, &len, c_type.data, c_type.len))
485 return fstrm_res_failure;
486
487 /* Only add one "Content Type" field to START frames. */
488 if (c->type == FSTRM_CONTROL_START)
489 break;
490 }
491
492 *len_control_frame = encoded_size;
493 return fstrm_res_success;
494 }
495