Branch data Line data Source code
1 : : /*
2 : : *****************************************************************************
3 : : *
4 : : * File: fko_decode.c
5 : : *
6 : : * Purpose: Decode an FKO SPA message after decryption.
7 : : *
8 : : * Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
9 : : * Copyright (C) 2009-2014 fwknop developers and contributors. For a full
10 : : * list of contributors, see the file 'CREDITS'.
11 : : *
12 : : * License (GNU General Public License):
13 : : *
14 : : * This program is free software; you can redistribute it and/or
15 : : * modify it under the terms of the GNU General Public License
16 : : * as published by the Free Software Foundation; either version 2
17 : : * of the License, or (at your option) any later version.
18 : : *
19 : : * This program is distributed in the hope that it will be useful,
20 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 : : * GNU General Public License for more details.
23 : : *
24 : : * You should have received a copy of the GNU General Public License
25 : : * along with this program; if not, write to the Free Software
26 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 : : * USA
28 : : *
29 : : *****************************************************************************
30 : : */
31 : : #include "fko_common.h"
32 : : #include "fko.h"
33 : : #include "cipher_funcs.h"
34 : : #include "base64.h"
35 : : #include "digest.h"
36 : :
37 : : #define FIELD_PARSERS 9
38 : :
39 : : /* Char used to separate SPA fields in an SPA packet */
40 : : #define SPA_FIELD_SEPARATOR ":"
41 : :
42 : : #ifdef HAVE_C_UNIT_TESTS
43 : : DECLARE_TEST_SUITE(fko_decode, "FKO decode test suite");
44 : : #endif
45 : :
46 : : static int
47 : 702 : num_fields(char *str)
48 : : {
49 : 702 : int i=0;
50 : 702 : char *tmp = NULL;
51 : :
52 : : /* Count the number of remaining SPA packet fields
53 : : */
54 [ + + ]: 4055 : for (i=0; i <= MAX_SPA_FIELDS+1; i++)
55 : : {
56 [ + + ]: 4049 : if ((tmp = strchr(str, ':')) == NULL)
57 : : break;
58 : 3353 : str = tmp + 1;
59 : : }
60 : 702 : return i;
61 : : }
62 : :
63 : : static int
64 : 380 : last_field(char *str)
65 : : {
66 : 380 : int i=0, pos_last=0;
67 : 380 : char *tmp = NULL;
68 : :
69 : : /* Count the number of bytes to the last ':' char
70 : : */
71 [ + + ]: 3069 : for (i=0; i <= MAX_SPA_FIELDS+1; i++)
72 : : {
73 [ + + ]: 3063 : if ((tmp = strchr(str, ':')) == NULL)
74 : : break;
75 : :
76 : 2689 : pos_last += (tmp - str) + 1;
77 : 2689 : str = tmp + 1;
78 : : }
79 : 380 : return pos_last;
80 : : }
81 : :
82 : : static int
83 : 748 : verify_digest(char *tbuf, int t_size, fko_ctx_t ctx)
84 : : {
85 : : #if AFL_FUZZING
86 : : return FKO_SUCCESS;
87 : : #endif
88 : :
89 : : switch(ctx->digest_type)
90 : : {
91 : : case FKO_DIGEST_MD5:
92 : : md5_base64(tbuf, (unsigned char*)ctx->encoded_msg, ctx->encoded_msg_len);
93 : : break;
94 : :
95 : : case FKO_DIGEST_SHA1:
96 : : sha1_base64(tbuf, (unsigned char*)ctx->encoded_msg, ctx->encoded_msg_len);
97 : : break;
98 : :
99 : : case FKO_DIGEST_SHA256:
100 : : sha256_base64(tbuf, (unsigned char*)ctx->encoded_msg, ctx->encoded_msg_len);
101 : : break;
102 : :
103 : : case FKO_DIGEST_SHA384:
104 : : sha384_base64(tbuf, (unsigned char*)ctx->encoded_msg, ctx->encoded_msg_len);
105 : : break;
106 : :
107 : : case FKO_DIGEST_SHA512:
108 : : sha512_base64(tbuf, (unsigned char*)ctx->encoded_msg, ctx->encoded_msg_len);
109 : : break;
110 : :
111 : : default: /* Invalid or unsupported digest */
112 : : return(FKO_ERROR_INVALID_DIGEST_TYPE);
113 : : }
114 : :
115 : : /* We give up here if the computed digest does not match the
116 : : * digest in the message data.
117 : : */
118 : : if(constant_runtime_cmp(ctx->digest, tbuf, t_size) != 0)
119 : : return(FKO_ERROR_DIGEST_VERIFICATION_FAILED);
120 : :
121 : : return FKO_SUCCESS;
122 : : }
123 : :
124 : : static int
125 : 380 : is_valid_digest_len(int t_size, fko_ctx_t ctx)
126 : : {
127 [ + + + + : 380 : switch(t_size)
+ + ]
128 : : {
129 : : case MD5_B64_LEN:
130 : 362 : ctx->digest_type = FKO_DIGEST_MD5;
131 : 362 : ctx->digest_len = MD5_B64_LEN;
132 : 362 : break;
133 : :
134 : : case SHA1_B64_LEN:
135 : 7 : ctx->digest_type = FKO_DIGEST_SHA1;
136 : 7 : ctx->digest_len = SHA1_B64_LEN;
137 : 7 : break;
138 : :
139 : : case SHA256_B64_LEN:
140 : 1 : ctx->digest_type = FKO_DIGEST_SHA256;
141 : 1 : ctx->digest_len = SHA256_B64_LEN;
142 : 1 : break;
143 : :
144 : : case SHA384_B64_LEN:
145 : 3 : ctx->digest_type = FKO_DIGEST_SHA384;
146 : 3 : ctx->digest_len = SHA384_B64_LEN;
147 : 3 : break;
148 : :
149 : : case SHA512_B64_LEN:
150 : 1 : ctx->digest_type = FKO_DIGEST_SHA512;
151 : 1 : ctx->digest_len = SHA512_B64_LEN;
152 : 1 : break;
153 : :
154 : : default: /* Invalid or unsupported digest */
155 : : return(FKO_ERROR_INVALID_DIGEST_TYPE);
156 : : }
157 : :
158 [ + - ]: 374 : if (ctx->encoded_msg_len - t_size < 0)
159 : : return(FKO_ERROR_INVALID_DATA_DECODE_ENC_MSG_LEN_MT_T_SIZE);
160 : :
161 : 374 : return FKO_SUCCESS;
162 : : }
163 : :
164 : : static int
165 : 305 : parse_msg(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
166 : : {
167 [ + + ]: 305 : if((*t_size = strcspn(*ndx, ":")) < 1)
168 : : return(FKO_ERROR_INVALID_DATA_DECODE_MESSAGE_MISSING);
169 : :
170 [ + + ]: 303 : if (*t_size > MAX_SPA_MESSAGE_SIZE)
171 : : return(FKO_ERROR_INVALID_DATA_DECODE_MESSAGE_TOOBIG);
172 : :
173 : 302 : strlcpy(tbuf, *ndx, *t_size+1);
174 : :
175 [ - + ]: 302 : if(ctx->message != NULL)
176 : 0 : free(ctx->message);
177 : :
178 : 302 : ctx->message = calloc(1, *t_size+1); /* Yes, more than we need */
179 : :
180 [ + - ]: 302 : if(ctx->message == NULL)
181 : : return(FKO_ERROR_MEMORY_ALLOCATION);
182 : :
183 [ + - ]: 302 : if(b64_decode(tbuf, (unsigned char*)ctx->message) < 0)
184 : : return(FKO_ERROR_INVALID_DATA_DECODE_MESSAGE_DECODEFAIL);
185 : :
186 [ + + ]: 302 : if(ctx->message_type == FKO_COMMAND_MSG)
187 : : {
188 : : /* Require a message similar to: 1.2.3.4,<command>
189 : : */
190 [ + + ]: 34 : if(validate_cmd_msg(ctx->message) != FKO_SUCCESS)
191 : : {
192 : : return(FKO_ERROR_INVALID_DATA_DECODE_MESSAGE_VALIDFAIL);
193 : : }
194 : : }
195 : : else
196 : : {
197 : : /* Require a message similar to: 1.2.3.4,tcp/22
198 : : */
199 [ + + ]: 268 : if(validate_access_msg(ctx->message) != FKO_SUCCESS)
200 : : {
201 : : return(FKO_ERROR_INVALID_DATA_DECODE_ACCESS_VALIDFAIL);
202 : : }
203 : : }
204 : :
205 : 155 : *ndx += *t_size + 1;
206 : 155 : return FKO_SUCCESS;
207 : : }
208 : :
209 : : static int
210 : 155 : parse_nat_msg(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
211 : : {
212 [ + + ]: 155 : if( ctx->message_type == FKO_NAT_ACCESS_MSG
213 : 155 : || ctx->message_type == FKO_LOCAL_NAT_ACCESS_MSG
214 [ + + ]: 148 : || ctx->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG
215 [ + + ]: 76 : || ctx->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
216 : : {
217 [ + + ]: 86 : if((*t_size = strcspn(*ndx, ":")) < 1)
218 : : return(FKO_ERROR_INVALID_DATA_DECODE_NATACCESS_MISSING);
219 : :
220 [ + + ]: 82 : if (*t_size > MAX_SPA_MESSAGE_SIZE)
221 : : return(FKO_ERROR_INVALID_DATA_DECODE_NATACCESS_TOOBIG);
222 : :
223 : 81 : strlcpy(tbuf, *ndx, *t_size+1);
224 : :
225 [ - + ]: 81 : if(ctx->nat_access != NULL)
226 : 0 : free(ctx->nat_access);
227 : :
228 : 81 : ctx->nat_access = calloc(1, *t_size+1); /* Yes, more than we need */
229 [ + - ]: 81 : if(ctx->nat_access == NULL)
230 : : return(FKO_ERROR_MEMORY_ALLOCATION);
231 : :
232 [ + - ]: 81 : if(b64_decode(tbuf, (unsigned char*)ctx->nat_access) < 0)
233 : : return(FKO_ERROR_INVALID_DATA_DECODE_NATACCESS_DECODEFAIL);
234 : :
235 [ + + ]: 81 : if(validate_nat_access_msg(ctx->nat_access) != FKO_SUCCESS)
236 : : return(FKO_ERROR_INVALID_DATA_DECODE_NATACCESS_VALIDFAIL);
237 : :
238 : 17 : *ndx += *t_size + 1;
239 : : }
240 : :
241 : : return FKO_SUCCESS;
242 : : }
243 : :
244 : : static int
245 : 86 : parse_server_auth(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
246 : : {
247 [ + + ]: 86 : if((*t_size = strlen(*ndx)) > 0)
248 : : {
249 [ + + ]: 50 : if (*t_size > MAX_SPA_MESSAGE_SIZE)
250 : : {
251 : : return(FKO_ERROR_INVALID_DATA_DECODE_SRVAUTH_MISSING);
252 : : }
253 : : }
254 : : else
255 : : return FKO_SUCCESS;
256 : :
257 [ + + ]: 49 : if( ctx->message_type == FKO_CLIENT_TIMEOUT_ACCESS_MSG
258 : : || ctx->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG
259 : 49 : || ctx->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
260 : : {
261 : : /* If we are here then we may still have a server_auth string,
262 : : * or a timeout, or both. So we look for a ':' delimiter. If
263 : : * it is there we have both, if not we check the message_type
264 : : * again.
265 : : */
266 [ + + ]: 45 : if(strchr(*ndx, ':'))
267 : : {
268 : 38 : *t_size = strcspn(*ndx, ":");
269 : :
270 [ + - ]: 38 : if (*t_size > MAX_SPA_MESSAGE_SIZE)
271 : : return(FKO_ERROR_INVALID_DATA_DECODE_EXTRA_TOOBIG);
272 : :
273 : 38 : strlcpy(tbuf, *ndx, *t_size+1);
274 : :
275 [ - + ]: 38 : if(ctx->server_auth != NULL)
276 : 0 : free(ctx->server_auth);
277 : :
278 : 38 : ctx->server_auth = calloc(1, *t_size+1); /* Yes, more than we need */
279 [ + - ]: 38 : if(ctx->server_auth == NULL)
280 : : return(FKO_ERROR_MEMORY_ALLOCATION);
281 : :
282 [ + - ]: 38 : if(b64_decode(tbuf, (unsigned char*)ctx->server_auth) < 0)
283 : : return(FKO_ERROR_INVALID_DATA_DECODE_EXTRA_DECODEFAIL);
284 : :
285 : 38 : *ndx += *t_size + 1;
286 : : }
287 : : }
288 : : else
289 : : {
290 : 4 : strlcpy(tbuf, *ndx, *t_size+1);
291 : :
292 [ - + ]: 4 : if(ctx->server_auth != NULL)
293 : 0 : free(ctx->server_auth);
294 : :
295 : 4 : ctx->server_auth = calloc(1, *t_size+1); /* Yes, more than we need */
296 [ + - ]: 4 : if(ctx->server_auth == NULL)
297 : : return(FKO_ERROR_MEMORY_ALLOCATION);
298 : :
299 [ + - ]: 4 : if(b64_decode(tbuf, (unsigned char*)ctx->server_auth) < 0)
300 : : return(FKO_ERROR_INVALID_DATA_DECODE_SRVAUTH_DECODEFAIL);
301 : : }
302 : :
303 : : return FKO_SUCCESS;
304 : : }
305 : :
306 : : static int
307 : 85 : parse_client_timeout(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
308 : : {
309 : : int is_err;
310 : :
311 [ + + ]: 85 : if( ctx->message_type == FKO_CLIENT_TIMEOUT_ACCESS_MSG
312 : : || ctx->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG
313 : 85 : || ctx->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
314 : : {
315 [ + + ]: 53 : if((*t_size = strlen(*ndx)) < 1)
316 : : return(FKO_ERROR_INVALID_DATA_DECODE_TIMEOUT_MISSING);
317 : :
318 [ + - ]: 19 : if (*t_size > MAX_SPA_MESSAGE_SIZE)
319 : : return(FKO_ERROR_INVALID_DATA_DECODE_TIMEOUT_TOOBIG);
320 : :
321 : : /* Should be a number only.
322 : : */
323 [ + + ]: 19 : if(strspn(*ndx, "0123456789") != *t_size)
324 : : return(FKO_ERROR_INVALID_DATA_DECODE_TIMEOUT_VALIDFAIL);
325 : :
326 : 9 : ctx->client_timeout = (unsigned int) strtol_wrapper(*ndx, 0,
327 : : (2 << 15), NO_EXIT_UPON_ERR, &is_err);
328 [ + + ]: 9 : if(is_err != FKO_SUCCESS)
329 : : return(FKO_ERROR_INVALID_DATA_DECODE_TIMEOUT_DECODEFAIL);
330 : : }
331 : :
332 : : return FKO_SUCCESS;
333 : : }
334 : :
335 : : static int
336 : 332 : parse_msg_type(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
337 : : {
338 : : int is_err, remaining_fields;
339 : :
340 [ + + ]: 332 : if((*t_size = strcspn(*ndx, ":")) < 1)
341 : : return(FKO_ERROR_INVALID_DATA_DECODE_MSGTYPE_MISSING);
342 : :
343 [ + + ]: 331 : if(*t_size > MAX_SPA_MESSAGE_TYPE_SIZE)
344 : : return(FKO_ERROR_INVALID_DATA_DECODE_MSGTYPE_TOOBIG);
345 : :
346 : 314 : strlcpy(tbuf, *ndx, *t_size+1);
347 : :
348 : 314 : ctx->message_type = strtol_wrapper(tbuf, 0,
349 : : FKO_LAST_MSG_TYPE-1, NO_EXIT_UPON_ERR, &is_err);
350 : :
351 [ + + ]: 314 : if(is_err != FKO_SUCCESS)
352 : : return(FKO_ERROR_INVALID_DATA_DECODE_MSGTYPE_DECODEFAIL);
353 : :
354 : : /* Now that we have a valid type, ensure that the total
355 : : * number of SPA fields is also valid for the type
356 : : */
357 [ + - ][ + + ]: 313 : remaining_fields = num_fields(*ndx);
[ + + ][ + - ]
358 : :
359 : : switch(ctx->message_type)
360 : : {
361 : : /* optional server_auth + digest */
362 : : case FKO_COMMAND_MSG:
363 : : case FKO_ACCESS_MSG:
364 [ + + ]: 145 : if(remaining_fields > 2)
365 : : return FKO_ERROR_INVALID_DATA_DECODE_WRONG_NUM_FIELDS;
366 : : break;
367 : :
368 : : /* nat or client timeout + optional server_auth + digest */
369 : : case FKO_NAT_ACCESS_MSG:
370 : : case FKO_LOCAL_NAT_ACCESS_MSG:
371 : : case FKO_CLIENT_TIMEOUT_ACCESS_MSG:
372 [ + + ]: 80 : if(remaining_fields > 3)
373 : : return FKO_ERROR_INVALID_DATA_DECODE_WRONG_NUM_FIELDS;
374 : : break;
375 : :
376 : : /* client timeout + nat + optional server_auth + digest */
377 : : case FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG:
378 : : case FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG:
379 [ + + ]: 88 : if(remaining_fields > 4)
380 : : return FKO_ERROR_INVALID_DATA_DECODE_WRONG_NUM_FIELDS;
381 : : break;
382 : :
383 : : default: /* Should not reach here */
384 : : return(FKO_ERROR_INVALID_DATA_DECODE_MSGTYPE_DECODEFAIL);
385 : : }
386 : :
387 : 305 : *ndx += *t_size + 1;
388 : 305 : return FKO_SUCCESS;
389 : : }
390 : :
391 : : static int
392 : 344 : parse_version(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
393 : : {
394 [ + + ]: 344 : if((*t_size = strcspn(*ndx, ":")) < 1)
395 : : return(FKO_ERROR_INVALID_DATA_DECODE_VERSION_MISSING);
396 : :
397 [ + + ]: 342 : if (*t_size > MAX_SPA_VERSION_SIZE)
398 : : return(FKO_ERROR_INVALID_DATA_DECODE_VERSION_TOOBIG);
399 : :
400 [ + - ]: 332 : if(ctx->version != NULL)
401 : 332 : free(ctx->version);
402 : :
403 : 332 : ctx->version = calloc(1, *t_size+1);
404 [ + - ]: 332 : if(ctx->version == NULL)
405 : : return(FKO_ERROR_MEMORY_ALLOCATION);
406 : :
407 : 332 : strlcpy(ctx->version, *ndx, *t_size+1);
408 : :
409 : 332 : *ndx += *t_size + 1;
410 : 332 : return FKO_SUCCESS;
411 : : }
412 : :
413 : : static int
414 : 350 : parse_timestamp(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
415 : : {
416 : : int is_err;
417 : :
418 [ + + ]: 350 : if((*t_size = strcspn(*ndx, ":")) < 1)
419 : : return(FKO_ERROR_INVALID_DATA_DECODE_TIMESTAMP_MISSING);
420 : :
421 [ + + ]: 349 : if (*t_size > MAX_SPA_TIMESTAMP_SIZE)
422 : : return(FKO_ERROR_INVALID_DATA_DECODE_TIMESTAMP_TOOBIG);
423 : :
424 : 345 : strlcpy(tbuf, *ndx, *t_size+1);
425 : :
426 : 345 : ctx->timestamp = (unsigned int) strtol_wrapper(tbuf,
427 : : 0, -1, NO_EXIT_UPON_ERR, &is_err);
428 [ + + ]: 345 : if(is_err != FKO_SUCCESS)
429 : : return(FKO_ERROR_INVALID_DATA_DECODE_TIMESTAMP_DECODEFAIL);
430 : :
431 : 344 : *ndx += *t_size + 1;
432 : :
433 : 344 : return FKO_SUCCESS;
434 : : }
435 : :
436 : : static int
437 : 366 : parse_username(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
438 : : {
439 [ + + ]: 366 : if((*t_size = strcspn(*ndx, ":")) < 1)
440 : : return(FKO_ERROR_INVALID_DATA_DECODE_USERNAME_MISSING);
441 : :
442 [ + + ]: 365 : if (*t_size > MAX_SPA_USERNAME_SIZE)
443 : : return(FKO_ERROR_INVALID_DATA_DECODE_USERNAME_TOOBIG);
444 : :
445 : 362 : strlcpy(tbuf, *ndx, *t_size+1);
446 : :
447 [ + - ]: 362 : if(ctx->username != NULL)
448 : 362 : free(ctx->username);
449 : :
450 : 362 : ctx->username = calloc(1, *t_size+1); /* Yes, more than we need */
451 [ + - ]: 362 : if(ctx->username == NULL)
452 : : return(FKO_ERROR_MEMORY_ALLOCATION);
453 : :
454 [ + - ]: 362 : if(b64_decode(tbuf, (unsigned char*)ctx->username) < 0)
455 : : return(FKO_ERROR_INVALID_DATA_DECODE_USERNAME_DECODEFAIL);
456 : :
457 [ + + ]: 362 : if(validate_username(ctx->username) != FKO_SUCCESS)
458 : : return(FKO_ERROR_INVALID_DATA_DECODE_USERNAME_VALIDFAIL);
459 : :
460 : 350 : *ndx += *t_size + 1;
461 : :
462 : 350 : return FKO_SUCCESS;
463 : : }
464 : :
465 : : static int
466 : 374 : parse_rand_val(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
467 : : {
468 [ + + ]: 374 : if((*t_size = strcspn(*ndx, ":")) < FKO_RAND_VAL_SIZE)
469 : : return(FKO_ERROR_INVALID_DATA_DECODE_RAND_MISSING);
470 : :
471 [ + - ]: 366 : if(ctx->rand_val != NULL)
472 : 366 : free(ctx->rand_val);
473 : :
474 : 366 : ctx->rand_val = calloc(1, FKO_RAND_VAL_SIZE+1);
475 [ + - ]: 366 : if(ctx->rand_val == NULL)
476 : : return(FKO_ERROR_MEMORY_ALLOCATION);
477 : :
478 : 732 : ctx->rand_val = strncpy(ctx->rand_val, *ndx, FKO_RAND_VAL_SIZE);
479 : :
480 : 366 : *ndx += *t_size + 1;
481 : :
482 : 366 : return FKO_SUCCESS;
483 : : }
484 : :
485 : : /* Decode the encoded SPA data.
486 : : */
487 : : int
488 : 434 : fko_decode_spa_data(fko_ctx_t ctx)
489 : : {
490 : : char *tbuf, *ndx;
491 : : int t_size, i, res;
492 : :
493 : : /* Array of function pointers to SPA field parsing functions
494 : : */
495 : 434 : int (*field_parser[FIELD_PARSERS])(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
496 : : = { parse_rand_val, /* Extract random value */
497 : : parse_username, /* Extract username */
498 : : parse_timestamp, /* Client timestamp */
499 : : parse_version, /* SPA version */
500 : : parse_msg_type, /* SPA msg type */
501 : : parse_msg, /* SPA msg string */
502 : : parse_nat_msg, /* SPA NAT msg string */
503 : : parse_server_auth, /* optional server authentication method */
504 : : parse_client_timeout /* client defined timeout */
505 : : };
506 : :
507 [ + - ]: 434 : if (! is_valid_encoded_msg_len(ctx->encoded_msg_len))
508 : : return(FKO_ERROR_INVALID_DATA_DECODE_MSGLEN_VALIDFAIL);
509 : :
510 : : /* Make sure there are no non-ascii printable chars
511 : : */
512 [ + + ]: 47703 : for (i=0; i < (int)strnlen(ctx->encoded_msg, MAX_SPA_ENCODED_MSG_SIZE); i++)
513 [ + + ]: 47314 : if(isprint(ctx->encoded_msg[i]) == 0)
514 : : return(FKO_ERROR_INVALID_DATA_DECODE_NON_ASCII);
515 : :
516 : : /* Make sure there are enough fields in the SPA packet
517 : : * delimited with ':' chars
518 : : */
519 : 389 : ndx = ctx->encoded_msg;
520 : :
521 [ + + ]: 389 : if (num_fields(ndx) < MIN_SPA_FIELDS)
522 : : return(FKO_ERROR_INVALID_DATA_DECODE_LT_MIN_FIELDS);
523 : :
524 : 380 : ndx += last_field(ndx);
525 : :
526 : 380 : t_size = strnlen(ndx, SHA512_B64_LEN+1);
527 : :
528 : : /* Validate digest length
529 : : */
530 : 380 : res = is_valid_digest_len(t_size, ctx);
531 [ + + ]: 380 : if(res != FKO_SUCCESS)
532 : : return res;
533 : :
534 [ - + ]: 374 : if(ctx->digest != NULL)
535 : 0 : free(ctx->digest);
536 : :
537 : : /* Copy the digest into the context and terminate the encoded data
538 : : * at that point so the original digest is not part of the
539 : : * encoded string.
540 : : */
541 : 374 : ctx->digest = strdup(ndx);
542 [ + - ]: 374 : if(ctx->digest == NULL)
543 : : return(FKO_ERROR_MEMORY_ALLOCATION);
544 : :
545 : : /* Chop the digest off of the encoded_msg bucket...
546 : : */
547 : 374 : bzero((ndx-1), t_size);
548 : :
549 : 374 : ctx->encoded_msg_len -= t_size+1;
550 : :
551 : : /* Make a tmp bucket for processing base64 encoded data and
552 : : * other general use.
553 : : */
554 : 374 : tbuf = calloc(1, FKO_ENCODE_TMP_BUF_SIZE);
555 [ + - ]: 374 : if(tbuf == NULL)
556 : : return(FKO_ERROR_MEMORY_ALLOCATION);
557 : :
558 : : /* Can now verify the digest.
559 : : */
560 : 374 : res = verify_digest(tbuf, t_size, ctx);
561 [ - + ]: 374 : if(res != FKO_SUCCESS)
562 : : {
563 : 0 : free(tbuf);
564 : 0 : return(FKO_ERROR_DIGEST_VERIFICATION_FAILED);
565 : : }
566 : :
567 : : /* Now we will work through the encoded data and extract (and base64-
568 : : * decode where necessary), the SPA data fields and populate the context.
569 : : */
570 : 374 : ndx = ctx->encoded_msg;
571 : :
572 [ + + ]: 2434 : for (i=0; i < FIELD_PARSERS; i++)
573 : : {
574 : 2397 : res = (*field_parser[i])(tbuf, &ndx, &t_size, ctx);
575 [ + + ]: 2397 : if(res != FKO_SUCCESS)
576 : : {
577 : 337 : free(tbuf);
578 : 337 : return res;
579 : : }
580 : : }
581 : :
582 : : /* Done with the tmp buffer.
583 : : */
584 : 37 : free(tbuf);
585 : :
586 : : /* Call the context initialized.
587 : : */
588 : 37 : ctx->initval = FKO_CTX_INITIALIZED;
589 : 37 : FKO_SET_CTX_INITIALIZED(ctx);
590 : :
591 : 37 : return(FKO_SUCCESS);
592 : : }
593 : :
594 : : #ifdef HAVE_C_UNIT_TESTS
595 : :
596 : : DECLARE_UTEST(num_fields, "Count the number of SPA fields in a SPA packet")
597 : : {
598 : : int ix_field=0;
599 : : char spa_packet[(MAX_SPA_FIELDS+1)*3];
600 : :
601 : : /* Zeroing the spa packet */
602 : : memset(spa_packet, 0, sizeof(spa_packet));
603 : :
604 : : /* Check we are able to count the number of SPA fields */
605 : : for(ix_field=0 ; ix_field<=MAX_SPA_FIELDS+2 ; ix_field++)
606 : : {
607 : : strcat(spa_packet, "x");
608 : : CU_ASSERT(num_fields(spa_packet) == ix_field);
609 : : strcat(spa_packet, SPA_FIELD_SEPARATOR);
610 : : }
611 : :
612 : : /* Check for possible overflow */
613 : : strcat(spa_packet, "x");
614 : : CU_ASSERT(num_fields(spa_packet) == MAX_SPA_FIELDS + 2);
615 : : strcat(spa_packet, "x");
616 : : strcat(spa_packet, SPA_FIELD_SEPARATOR);
617 : : CU_ASSERT(num_fields(spa_packet) == MAX_SPA_FIELDS + 2);
618 : : }
619 : :
620 : : DECLARE_UTEST(last_field, "Count the number of bytes to the last :")
621 : : {
622 : : int ix_field;
623 : : char spa_packet[(MAX_SPA_FIELDS+1)*3];
624 : :
625 : : /* Zeroing the spa packet */
626 : : memset(spa_packet, 0, sizeof(spa_packet));
627 : :
628 : : /* Check for a valid count when the number of field is less than MAX_SPA_FIELDS */
629 : : CU_ASSERT(last_field("a:") == 2);
630 : : CU_ASSERT(last_field("ab:abc:") == 7);
631 : : CU_ASSERT(last_field("abc:abcd:") == 9);
632 : : CU_ASSERT(last_field("abc:abcd:abc") == 9);
633 : :
634 : :
635 : : /* */
636 : : for(ix_field=0 ; ix_field<=MAX_SPA_FIELDS+2 ; ix_field++)
637 : : {
638 : : strcat(spa_packet, "x");
639 : : strcat(spa_packet, SPA_FIELD_SEPARATOR);
640 : : }
641 : : CU_ASSERT(last_field(spa_packet) == ((MAX_SPA_FIELDS+2)*2));
642 : : }
643 : :
644 : : int register_ts_fko_decode(void)
645 : : {
646 : : ts_init(&TEST_SUITE(fko_decode), TEST_SUITE_DESCR(fko_decode), NULL, NULL);
647 : : ts_add_utest(&TEST_SUITE(fko_decode), UTEST_FCT(num_fields), UTEST_DESCR(num_fields));
648 : : ts_add_utest(&TEST_SUITE(fko_decode), UTEST_FCT(last_field), UTEST_DESCR(last_field));
649 : :
650 : : return register_ts(&TEST_SUITE(fko_decode));
651 : : }
652 : :
653 : : #endif /* HAVE_C_UNIT_TESTS */
654 : :
655 : : /***EOF***/
|