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