LCOV - code coverage report
Current view: top level - lib - fko_decode.c (source / functions) Hit Total Coverage
Test: id:002084,src:002034,op:havoc,rep:2.lcov_info_final Lines: 170 177 96.0 %
Date: 2015-05-30 Functions: 14 14 100.0 %
Branches: 127 156 81.4 %

           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***/

Generated by: LCOV version 1.10