LCOV - code coverage report
Current view: top level - lib - fko_util.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 258 278 92.8 %
Date: 2014-11-16 Functions: 18 18 100.0 %
Branches: 207 258 80.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  *****************************************************************************
       3                 :            :  *
       4                 :            :  * File:    fko_util.c
       5                 :            :  *
       6                 :            :  * Purpose: Provide a set of common utility functions that fwknop can use.
       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_util.h"
      33                 :            : #include <errno.h>
      34                 :            : #include <stdarg.h>
      35                 :            : 
      36                 :            : #ifndef WIN32
      37                 :            :   /* for inet_aton() IP validation
      38                 :            :   */
      39                 :            :   #include <sys/socket.h>
      40                 :            :   #include <netinet/in.h>
      41                 :            :   #include <arpa/inet.h>
      42                 :            : #endif
      43                 :            : 
      44                 :            : /* Check for a FKO error returned by a function an return the error code */
      45                 :            : #define RETURN_ON_FKO_ERROR(e, f)   do { if (((e)=(f)) != FKO_SUCCESS) { return (e); } } while(0);
      46                 :            : 
      47                 :            : #define FKO_ENCRYPTION_MODE_BUFSIZE 16                      /*!< Maximum size of an encryption mode string */
      48                 :            : #define FKO_ENC_MODE_SUPPORTED      0                       /*!< Defined a supported fko encryption mode */
      49                 :            : #define FKO_ENC_MODE_NOT_SUPPORTED  !FKO_ENC_MODE_SUPPORTED /*!< Defined an unsupported fko encryption mode */
      50                 :            : 
      51                 :            : #define NULL_STRING                 "<NULL>"                /*!< String which represents a NULL buffer */
      52                 :            : 
      53                 :            : /**
      54                 :            :  * Structure to handle an encryption mode string string and its associated integer value
      55                 :            :  */
      56                 :            : typedef struct fko_enc_mode_str
      57                 :            : {
      58                 :            :     const char  str[FKO_ENCRYPTION_MODE_BUFSIZE];   /*!< String which represents an encryption mode value for the FKO library */
      59                 :            :     int         val;                                /*!< Value of the encryption mode according to the FKO library */
      60                 :            :     int         supported;                          /*!< SUPPORTED or NOT_SUPPORTED */
      61                 :            : } fko_enc_mode_str_t;
      62                 :            : 
      63                 :            : /**
      64                 :            :  * Array to associate all of encryption modes with their respective string
      65                 :            :  */
      66                 :            : static fko_enc_mode_str_t fko_enc_mode_strs[] =
      67                 :            : {
      68                 :            :     { "CBC",            FKO_ENC_MODE_CBC,           FKO_ENC_MODE_SUPPORTED      },
      69                 :            :     { "ECB",            FKO_ENC_MODE_ECB,           FKO_ENC_MODE_SUPPORTED      },
      70                 :            :     { "CFB",            FKO_ENC_MODE_CFB,           FKO_ENC_MODE_SUPPORTED      },
      71                 :            :     { "PCBC",           FKO_ENC_MODE_PCBC,          FKO_ENC_MODE_NOT_SUPPORTED  },
      72                 :            :     { "OFB",            FKO_ENC_MODE_OFB,           FKO_ENC_MODE_SUPPORTED      },
      73                 :            :     { "CTR",            FKO_ENC_MODE_CTR,           FKO_ENC_MODE_SUPPORTED      },
      74                 :            :     { "Asymmetric",     FKO_ENC_MODE_ASYMMETRIC,    FKO_ENC_MODE_SUPPORTED      },
      75                 :            :     { "legacy",         FKO_ENC_MODE_CBC_LEGACY_IV, FKO_ENC_MODE_SUPPORTED      }
      76                 :            : };
      77                 :            : 
      78                 :            : /* Compare all bytes with constant run time regardless of
      79                 :            :  * input characteristics (i.e. don't return early if a difference
      80                 :            :  * is found before comparing all bytes).  This code was adapted
      81                 :            :  * from YaSSL which is GPLv2 after a timing bug was reported by
      82                 :            :  * Ryman through github (#85)
      83                 :            : */
      84                 :            : int
      85                 :    9211656 : constant_runtime_cmp(const char *a, const char *b, int len)
      86                 :            : {
      87                 :    9211656 :     int good = 0;
      88                 :    9211656 :     int bad  = 0;
      89                 :            :     int i;
      90                 :            : 
      91         [ +  + ]:  326562590 :     for(i=0; i < len; i++) {
      92         [ +  + ]:  317350934 :         if (a[i] == b[i])
      93                 :  175618744 :             good++;
      94                 :            :         else
      95                 :  141732190 :             bad++;
      96                 :            :     }
      97                 :            : 
      98         [ +  + ]:    9211656 :     if (good == len)
      99                 :            :         return 0;
     100                 :            :     else
     101                 :    5441822 :         return 0 - bad;
     102                 :            : }
     103                 :            : 
     104                 :            : /* Validate encoded message length
     105                 :            : */
     106                 :            : int
     107                 :   24393095 : is_valid_encoded_msg_len(const int len)
     108                 :            : {
     109                 :            : #if HAVE_LIBFIU
     110         [ +  + ]:   24393095 :     fiu_return_on("is_valid_encoded_msg_len_val", 0);
     111                 :            : #endif
     112         [ +  + ]:   24393094 :     if(len < MIN_SPA_ENCODED_MSG_SIZE || len >= MAX_SPA_ENCODED_MSG_SIZE)
     113                 :            :         return(0);
     114                 :            : 
     115                 :   24283406 :     return(1);
     116                 :            : }
     117                 :            : 
     118                 :            : /* Validate an IPv4 address
     119                 :            : */
     120                 :            : int
     121                 :    3796083 : is_valid_ipv4_addr(const char * const ip_str)
     122                 :            : {
     123                 :    3796083 :     const char         *ndx     = ip_str;
     124                 :    3796083 :     int                 dot_ctr = 0, char_ctr = 0;
     125                 :    3796083 :     int                 res     = 1;
     126                 :            : #if HAVE_SYS_SOCKET_H
     127                 :            :     struct in_addr      in;
     128                 :            : #endif
     129                 :            : 
     130         [ +  + ]:    3796083 :     if(ip_str == NULL)
     131                 :            :         return 0;
     132                 :            : 
     133         [ +  + ]:   44057217 :     while(*ndx != '\0')
     134                 :            :     {
     135                 :   40261142 :         char_ctr++;
     136         [ +  - ]:   40261142 :         if(char_ctr >= MAX_IPV4_STR_LEN)
     137                 :            :         {
     138                 :            :             res = 0;
     139                 :            :             break;
     140                 :            :         }
     141         [ +  + ]:   40261142 :         if(*ndx == '.')
     142                 :   11339398 :             dot_ctr++;
     143         [ +  + ]:   28921744 :         else if(isdigit(*ndx) == 0)
     144                 :            :         {
     145                 :            :             res = 0;
     146                 :            :             break;
     147                 :            :         }
     148                 :   40261136 :         ndx++;
     149                 :            :     }
     150         [ -  + ]:    3796081 :     if(char_ctr >= MAX_IPV4_STR_LEN)
     151                 :          0 :         res = 0;
     152                 :            : 
     153         [ +  + ]:    3796081 :     if ((res == 1) && (char_ctr < MIN_IPV4_STR_LEN))
     154                 :      23071 :         res = 0;
     155                 :            : 
     156         [ +  + ]:    3796081 :     if((res == 1) && dot_ctr != 3)
     157                 :       7471 :         res = 0;
     158                 :            : 
     159                 :            : #if HAVE_SYS_SOCKET_H
     160                 :            :     /* Stronger IP validation now that we have a candidate that looks
     161                 :            :      * close enough
     162                 :            :     */
     163 [ +  + ][ +  + ]:    3796081 :     if((res == 1) && (inet_aton(ip_str, &in) == 0))
     164                 :       6246 :         res = 0;
     165                 :            : #endif
     166                 :            : 
     167                 :    3796081 :     return(res);
     168                 :            : }
     169                 :            : 
     170                 :            : /* Convert a digest_type string to its integer value.
     171                 :            : */
     172                 :            : short
     173                 :         71 : digest_strtoint(const char *dt_str)
     174                 :            : {
     175         [ +  + ]:         71 :     if(strcasecmp(dt_str, "md5") == 0)
     176                 :            :         return(FKO_DIGEST_MD5);
     177         [ +  + ]:         51 :     else if(strcasecmp(dt_str, "sha1") == 0)
     178                 :            :         return(FKO_DIGEST_SHA1);
     179         [ +  + ]:         20 :     else if(strcasecmp(dt_str, "sha256") == 0)
     180                 :            :         return(FKO_DIGEST_SHA256);
     181         [ +  + ]:         10 :     else if(strcasecmp(dt_str, "sha384") == 0)
     182                 :            :         return(FKO_DIGEST_SHA384);
     183         [ +  + ]:          7 :     else if(strcasecmp(dt_str, "sha512") == 0)
     184                 :            :         return(FKO_DIGEST_SHA512);
     185                 :            :     else
     186                 :          2 :         return(-1);
     187                 :            : }
     188                 :            : 
     189                 :            : /**
     190                 :            :  * \brief Return a digest string according to a digest integer value
     191                 :            :  *
     192                 :            :  * This function checks the digest integer is valid, and write the digest
     193                 :            :  * string associated.
     194                 :            :  *
     195                 :            :  * \param digest Digest inetger value (FKO_DIGEST_MD5, FKO_DIGEST_SHA1 ...)
     196                 :            :  * \param digest_str Buffer to write the digest string
     197                 :            :  * \param digest_size size of the digest string buffer
     198                 :            :  *
     199                 :            :  * \return -1 if the digest integer value is not supported, 0 otherwise
     200                 :            :  */
     201                 :            : short
     202                 :       3045 : digest_inttostr(int digest, char* digest_str, size_t digest_size)
     203                 :            : {
     204                 :       3045 :     short digest_not_valid = 0;
     205                 :            : 
     206                 :            :     memset(digest_str, 0, digest_size);
     207                 :            : 
     208   [ +  +  +  +  :       3045 :     switch (digest)
                   +  - ]
     209                 :            :     {
     210                 :            :         case FKO_DIGEST_MD5:
     211                 :         10 :             strlcpy(digest_str, "MD5", digest_size);
     212                 :         10 :             break;
     213                 :            :         case FKO_DIGEST_SHA1:
     214                 :         39 :             strlcpy(digest_str, "SHA1", digest_size);
     215                 :         39 :             break;
     216                 :            :         case FKO_DIGEST_SHA256:
     217                 :       2976 :             strlcpy(digest_str, "SHA256", digest_size);
     218                 :       2976 :             break;
     219                 :            :         case FKO_DIGEST_SHA384:
     220                 :          8 :             strlcpy(digest_str, "SHA384", digest_size);
     221                 :          8 :             break;
     222                 :            :         case FKO_DIGEST_SHA512:
     223                 :         12 :             strlcpy(digest_str, "SHA512", digest_size);
     224                 :         12 :             break;
     225                 :            :         default:
     226                 :          0 :             strlcpy(digest_str, "Unknown", digest_size);
     227                 :          0 :             digest_not_valid = -1;
     228                 :          0 :             break;
     229                 :            :     }
     230                 :            : 
     231                 :       3045 :     return digest_not_valid;
     232                 :            : }
     233                 :            : 
     234                 :            : short
     235                 :        332 : hmac_digest_strtoint(const char *dt_str)
     236                 :            : {
     237         [ +  + ]:        332 :     if(strcasecmp(dt_str, "md5") == 0)
     238                 :            :         return(FKO_HMAC_MD5);
     239         [ +  + ]:        315 :     else if(strcasecmp(dt_str, "sha1") == 0)
     240                 :            :         return(FKO_HMAC_SHA1);
     241         [ +  + ]:        266 :     else if(strcasecmp(dt_str, "sha256") == 0)
     242                 :            :         return(FKO_HMAC_SHA256);
     243         [ +  + ]:         35 :     else if(strcasecmp(dt_str, "sha384") == 0)
     244                 :            :         return(FKO_HMAC_SHA384);
     245         [ +  + ]:         22 :     else if(strcasecmp(dt_str, "sha512") == 0)
     246                 :            :         return(FKO_HMAC_SHA512);
     247                 :            :     else
     248                 :          5 :         return(-1);
     249                 :            : }
     250                 :            : 
     251                 :            : /* Return encryption type string representation
     252                 :            : */
     253                 :            : const char *
     254                 :       3033 : enc_type_inttostr(const int type)
     255                 :            : {
     256         [ +  - ]:       3033 :     if(type == FKO_ENC_MODE_UNKNOWN)
     257                 :            :         return("Unknown encryption type");
     258         [ +  + ]:       3033 :     else if(type == FKO_ENCRYPTION_RIJNDAEL)
     259                 :            :         return("Rijndael");
     260         [ -  + ]:        131 :     else if(type == FKO_ENCRYPTION_GPG)
     261                 :            :         return("GPG");
     262                 :            : 
     263                 :          0 :     return("Unknown encryption type");
     264                 :            : }
     265                 :            : 
     266                 :            : /* Return message type string representation
     267                 :            : */
     268                 :            : const char *
     269                 :       3033 : msg_type_inttostr(const int type)
     270                 :            : {
     271         [ +  + ]:       3033 :     if(type == FKO_COMMAND_MSG)
     272                 :            :         return("Command msg");
     273         [ +  + ]:       2857 :     else if(type == FKO_ACCESS_MSG)
     274                 :            :         return("Access msg");
     275         [ +  + ]:        277 :     else if(type == FKO_NAT_ACCESS_MSG)
     276                 :            :         return("NAT access msg");
     277         [ +  + ]:        143 :     else if(type == FKO_CLIENT_TIMEOUT_ACCESS_MSG)
     278                 :            :         return("Client timeout access msg");
     279         [ +  + ]:         94 :     else if(type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG)
     280                 :            :         return("Client timeout NAT access msg");
     281         [ +  + ]:         24 :     else if(type == FKO_LOCAL_NAT_ACCESS_MSG)
     282                 :            :         return("Local NAT access msg");
     283         [ -  + ]:          2 :     else if(type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
     284                 :            :         return("Client timeout local NAT access msg");
     285                 :            : 
     286                 :          0 :     return("Unknown message type");
     287                 :            : }
     288                 :            : 
     289                 :            : /**
     290                 :            :  * \brief Return a hmac digest string according to a hmac digest integer value
     291                 :            :  *
     292                 :            :  * This function checks if the digest integer is valid, and write the digest
     293                 :            :  * string associated.
     294                 :            :  *
     295                 :            :  * \param digest Digest inetger value (FKO_HMAC_MD5, FKO_HMAC_SHA1 ...)
     296                 :            :  * \param digest_str Buffer to write the digest string
     297                 :            :  * \param digest_size size of the digest string buffer
     298                 :            :  *
     299                 :            :  * \return -1 if the digest integer value is not supported, 0 otherwise
     300                 :            :  */
     301                 :            : short
     302                 :       1067 : hmac_digest_inttostr(int digest, char* digest_str, size_t digest_size)
     303                 :            : {
     304                 :       1067 :     short digest_not_valid = 0;
     305                 :            : 
     306                 :            :     memset(digest_str, 0, digest_size);
     307                 :            : 
     308   [ +  +  +  +  :       1067 :     switch (digest)
                   +  - ]
     309                 :            :     {
     310                 :            :         case FKO_HMAC_MD5:
     311                 :         12 :             strlcpy(digest_str, "MD5", digest_size);
     312                 :         12 :             break;
     313                 :            :         case FKO_HMAC_SHA1:
     314                 :         54 :             strlcpy(digest_str, "SHA1", digest_size);
     315                 :         54 :             break;
     316                 :            :         case FKO_HMAC_SHA256:
     317                 :        974 :             strlcpy(digest_str, "SHA256", digest_size);
     318                 :        974 :             break;
     319                 :            :         case FKO_HMAC_SHA384:
     320                 :         12 :             strlcpy(digest_str, "SHA384", digest_size);
     321                 :         12 :             break;
     322                 :            :         case FKO_HMAC_SHA512:
     323                 :         15 :             strlcpy(digest_str, "SHA512", digest_size);
     324                 :         15 :             break;
     325                 :            :         default:
     326                 :          0 :             strlcpy(digest_str, "Unknown", digest_size);
     327                 :          0 :             digest_not_valid = -1;
     328                 :          0 :             break;
     329                 :            :     }
     330                 :            : 
     331                 :       1067 :     return digest_not_valid;
     332                 :            : }
     333                 :            : 
     334                 :            : /* Validate plaintext input size
     335                 :            : */
     336                 :            : int
     337                 :    2402187 : is_valid_pt_msg_len(const int len)
     338                 :            : {
     339                 :            : #if HAVE_LIBFIU
     340         [ +  + ]:    2402187 :     fiu_return_on("is_valid_pt_msg_len_val", 0);
     341                 :            : #endif
     342         [ +  - ]:    2402186 :     if(len < MIN_SPA_PLAINTEXT_MSG_SIZE || len >= MAX_SPA_PLAINTEXT_MSG_SIZE)
     343                 :            :         return(0);
     344                 :            : 
     345                 :    2402186 :     return(1);
     346                 :            : }
     347                 :            : 
     348                 :            : /**
     349                 :            :  * @brief Convert an encryption mode string to its integer value.
     350                 :            :  *
     351                 :            :  * @param enc_mode_str Encryption mode string (CBC,ECB...)
     352                 :            :  *
     353                 :            :  * @return -1 if the encryption mode string is not supported,
     354                 :            :  *         otherwise the encryption mode value
     355                 :            :  */
     356                 :            : int
     357                 :         55 : enc_mode_strtoint(const char *enc_mode_str)
     358                 :            : {
     359                 :            :     unsigned char           ndx_enc_mode;
     360                 :         55 :     int                     enc_mode_int = -1;     /* Encryption mode integer value */
     361                 :            :     fko_enc_mode_str_t     *enc_mode_str_pt;
     362                 :            : 
     363                 :            :     /* Look into the fko_enc_mode_strs array to find out the right encryption mode */
     364         [ +  + ]:        326 :     for (ndx_enc_mode = 0 ; ndx_enc_mode < ARRAY_SIZE(fko_enc_mode_strs) ; ndx_enc_mode++)
     365                 :            :     {
     366                 :        322 :         enc_mode_str_pt = &(fko_enc_mode_strs[ndx_enc_mode]);
     367                 :            : 
     368                 :            :         /* If the encryption mode matches, grab it */
     369         [ +  + ]:        322 :         if (   (strcasecmp(enc_mode_str, enc_mode_str_pt->str) == 0)
     370         [ +  + ]:         52 :             && (enc_mode_str_pt->supported == FKO_ENC_MODE_SUPPORTED) )
     371                 :            :         {
     372                 :         51 :             enc_mode_int = enc_mode_str_pt->val;
     373                 :         51 :             break;
     374                 :            :         }
     375                 :            :     }
     376                 :            : 
     377                 :         55 :     return enc_mode_int;
     378                 :            : }
     379                 :            : 
     380                 :            : /**
     381                 :            :  * @brief Return an encryption mode string according to an enc_mode integer value
     382                 :            :  *
     383                 :            :  * This function checks if the encryption mode integer is valid, and write the
     384                 :            :  * encryption mode string associated.
     385                 :            :  *
     386                 :            :  * @param enc_mode Encryption mode integer value (FKO_ENC_MODE_CBC, FKO_ENC_MODE_ECB ...)
     387                 :            :  * @param enc_mode_str Buffer to write the encryption mode string to
     388                 :            :  * @param enc_mode_size Size of the encryption mode string buffer
     389                 :            :  *
     390                 :            :  * @return -1 if the encryption mode integer value is not supported, 0 otherwise
     391                 :            :  */
     392                 :            : short
     393                 :       3035 : enc_mode_inttostr(int enc_mode, char* enc_mode_str, size_t enc_mode_size)
     394                 :            : {
     395                 :       3035 :     short                   enc_mode_error = -1;
     396                 :            :     unsigned char           ndx_enc_mode;
     397                 :            :     fko_enc_mode_str_t     *enc_mode_str_pt;
     398                 :            : 
     399                 :            :     /* Initialize the protocol string */
     400                 :            :     memset(enc_mode_str, 0, enc_mode_size);
     401                 :            : 
     402                 :            :     /* Look into the fko_enc_mode_strs array to find out the right protocol */
     403         [ +  - ]:       4010 :     for (ndx_enc_mode = 0 ; ndx_enc_mode < ARRAY_SIZE(fko_enc_mode_strs) ; ndx_enc_mode++)
     404                 :            :     {
     405                 :       4010 :         enc_mode_str_pt = &(fko_enc_mode_strs[ndx_enc_mode]);
     406                 :            : 
     407                 :            :         /* If the encryption mode matches, grab it */
     408         [ +  + ]:       4010 :         if (   (enc_mode_str_pt->val == enc_mode)
     409         [ +  - ]:       3035 :             && (enc_mode_str_pt->supported == FKO_ENC_MODE_SUPPORTED) )
     410                 :            :         {
     411                 :       3035 :             strlcpy(enc_mode_str, enc_mode_str_pt->str, enc_mode_size);
     412                 :       3035 :             enc_mode_error = 0;
     413                 :       3035 :             break;
     414                 :            :         }
     415                 :            :     }
     416                 :            : 
     417                 :       3035 :     return enc_mode_error;
     418                 :            : }
     419                 :            : 
     420                 :            : int
     421                 :   11344609 : strtol_wrapper(const char * const str, const int min,
     422                 :            :     const int max, const int exit_upon_err, int *err)
     423                 :            : {
     424                 :            :     int val;
     425                 :            : 
     426                 :   11344609 :     errno = 0;
     427                 :   11344609 :     *err = FKO_SUCCESS;
     428                 :            : 
     429                 :   11344609 :     val = strtol(str, (char **) NULL, 10);
     430                 :            : 
     431 [ +  - ][ -  + ]:   11344609 :     if ((errno == ERANGE || (errno != 0 && val == 0)))
                 [ #  # ]
     432                 :            :     {
     433                 :          0 :         *err = errno;
     434         [ #  # ]:          0 :         if(exit_upon_err == EXIT_UPON_ERR)
     435                 :            :         {
     436                 :          0 :             perror("strtol");
     437                 :          0 :             fprintf(stderr, "[*] Value %d out of range [(%d)-(%d)]\n",
     438                 :            :                 val, min, max);
     439                 :          0 :             exit(EXIT_FAILURE);
     440                 :            :         }
     441                 :            :     }
     442                 :            : 
     443         [ +  + ]:   11344609 :     if(val < min)
     444                 :            :     {
     445                 :       1376 :         *err = FKO_ERROR_INVALID_DATA_UTIL_STRTOL_LT_MIN;
     446         [ +  + ]:       1376 :         if(exit_upon_err == EXIT_UPON_ERR)
     447                 :            :         {
     448                 :          1 :             fprintf(stderr, "[*] Value %d out of range [(%d)-(%d)]\n",
     449                 :            :                 val, min, max);
     450                 :          1 :             exit(EXIT_FAILURE);
     451                 :            :         }
     452                 :            :     }
     453                 :            : 
     454                 :            :     /* allow max == -1 to be an exception where we don't care about the
     455                 :            :      * maximum - note that the ERANGE check is still in place above
     456                 :            :     */
     457         [ +  + ]:   11344608 :     if((max >= 0) && (val > max))
     458                 :            :     {
     459                 :        314 :         *err = FKO_ERROR_INVALID_DATA_UTIL_STRTOL_GT_MAX;
     460         [ -  + ]:        314 :         if(exit_upon_err == EXIT_UPON_ERR)
     461                 :            :         {
     462                 :          0 :             fprintf(stderr, "[*] Value %d out of range [(%d)-(%d)]\n",
     463                 :            :                 val, min, max);
     464                 :          0 :             exit(EXIT_FAILURE);
     465                 :            :         }
     466                 :            :     }
     467                 :            : 
     468                 :            : #if HAVE_LIBFIU
     469         [ +  - ]:   11344608 :     fiu_return_on("strtol_wrapper_lt_min",
     470                 :            :             FKO_ERROR_INVALID_DATA_UTIL_STRTOL_LT_MIN);
     471         [ +  - ]:   11344608 :     fiu_return_on("strtol_wrapper_gt_max",
     472                 :            :             FKO_ERROR_INVALID_DATA_UTIL_STRTOL_GT_MAX);
     473                 :            : #endif
     474                 :            : 
     475                 :   11344608 :     return val;
     476                 :            : }
     477                 :            : 
     478                 :            : /* zero out a buffer before free()
     479                 :            : */
     480                 :   28573683 : int zero_free(char *buf, int len)
     481                 :            : {
     482                 :   28573683 :     int res = FKO_SUCCESS;
     483                 :            : 
     484         [ +  - ]:   28573683 :     if(buf == NULL)
     485                 :            :         return res;
     486                 :            : 
     487         [ -  + ]:   28573683 :     if(len == 0)
     488                 :            :     {
     489                 :          0 :         free(buf);  /* always free() if buf != NULL */
     490                 :          0 :         return res;
     491                 :            :     }
     492                 :            : 
     493                 :   28573683 :     res = zero_buf(buf, len);
     494                 :            : 
     495                 :   28573683 :     free(buf);
     496                 :            : 
     497                 :            : #if HAVE_LIBFIU
     498         [ +  + ]:   28573683 :     fiu_return_on("zero_free_err", FKO_ERROR_ZERO_OUT_DATA);
     499                 :            : #endif
     500                 :            : 
     501                 :   28573674 :     return res;
     502                 :            : }
     503                 :            : 
     504                 :            : /* zero out sensitive information in a way that isn't optimized out by the compiler
     505                 :            :  * since we force a comparision and return an error if there is a problem (though
     506                 :            :  * the caller should do something with this information too).
     507                 :            : */
     508                 :            : int
     509                 :   43263825 : zero_buf(char *buf, int len)
     510                 :            : {
     511                 :   43263825 :     int i, res = FKO_SUCCESS;
     512                 :            : 
     513                 :            : #if HAVE_LIBFIU
     514         [ +  + ]:   43263825 :     fiu_return_on("zero_buf_err", FKO_ERROR_ZERO_OUT_DATA);
     515                 :            : #endif
     516                 :            : 
     517         [ +  - ]:   43263813 :     if(buf == NULL || len == 0)
     518                 :            :         return res;
     519                 :            : 
     520         [ +  + ]:   43263813 :     if(len < 0 || len > MAX_SPA_ENCODED_MSG_SIZE)
     521                 :            :         return FKO_ERROR_ZERO_OUT_DATA;
     522                 :            : 
     523         [ +  + ]: 5320271727 :     for(i=0; i < len; i++)
     524                 : 5277065786 :         buf[i] = 0x0;
     525                 :            : 
     526         [ +  + ]: 5320271727 :     for(i=0; i < len; i++)
     527         [ -  + ]: 5277065786 :         if(buf[i] != 0x0)
     528                 :          0 :             res = FKO_ERROR_ZERO_OUT_DATA;
     529                 :            : 
     530                 :            :     return res;
     531                 :            : }
     532                 :            : 
     533                 :            : #if defined(WIN32) || !defined(HAVE_STRNDUP)
     534                 :            : /* Windows does not have strndup, so we well implement it here.
     535                 :            :  * This was the Public Domain C Library (PDCLib).
     536                 :            : */
     537                 :            : char
     538                 :            : *strndup( const char * s, size_t len )
     539                 :            : {
     540                 :            :     char* ns = NULL;
     541                 :            :     if(s) {
     542                 :            :         ns = calloc(1, len + 1);
     543                 :            :         if(ns) {
     544                 :            :             ns[len] = 0;
     545                 :            :             // strncpy to be pedantic about modification in multithreaded 
     546                 :            :             // applications
     547                 :            :             return strncpy(ns, s, len);
     548                 :            :         }
     549                 :            :     }
     550                 :            :     return ns;
     551                 :            : }
     552                 :            : #endif
     553                 :            : 
     554                 :            : /**
     555                 :            :  * @brief Add a printf style message to a buffer
     556                 :            :  *
     557                 :            :  * This function allows to append a printf style message to a buffer
     558                 :            :  * and prevents buffer overflow by taking care of the size the buffer.
     559                 :            :  * It returns the number of bytes really written to the buffer.
     560                 :            :  * Thus if an error is encoutered during the process the number of bytes
     561                 :            :  * written is set to 0. This way the user knows exactly how many bytes
     562                 :            :  * can be appended afterwards.
     563                 :            :  *
     564                 :            :  * @param buf       Buffer to write the formated message to
     565                 :            :  * @param buf_size  Maximum number of bytes to write to the buffer
     566                 :            :  * @param msg       Message to format and to append to the buffer
     567                 :            :  *
     568                 :            :  * @return the number of bytes written to the buffer
     569                 :            :  */
     570                 :            : static int
     571                 :      55904 : append_msg_to_buf(char *buf, size_t buf_size, const char* msg, ...)
     572                 :            : {
     573                 :      55904 :     int     bytes_written = 0;  /* Number of bytes written to buf */
     574                 :            :     va_list ap;
     575                 :            : 
     576                 :            :     /* Check if the buffer is valid */
     577         [ +  - ]:      55904 :     if (buf_size > 0)
     578                 :            :     {
     579                 :      55904 :         va_start(ap, msg);
     580                 :            : 
     581                 :            :         /* Format the message like a printf message */
     582                 :      55904 :         bytes_written = vsnprintf(buf, buf_size, msg, ap);
     583                 :            : 
     584                 :            :         /* It looks like the message has been truncated or an error occured*/
     585         [ +  - ]:      55904 :         if (bytes_written < 0)
     586                 :            :             bytes_written = 0;
     587                 :            : 
     588         [ -  + ]:      55904 :         else if (bytes_written >= buf_size)
     589                 :          0 :             bytes_written = buf_size;
     590                 :            : 
     591                 :            :         /* The messsage has been formatted correctly */
     592                 :            :         else;
     593                 :            : 
     594                 :      55904 :         va_end(ap);
     595                 :            :     }
     596                 :            : 
     597                 :            :     /* No valid buffer has been supplied, thus we do not write anything */
     598                 :            :     else;
     599                 :            : 
     600                 :            :     /* Return the number of bytes written to the buffer */
     601                 :      55904 :     return bytes_written;
     602                 :            : }
     603                 :            : 
     604                 :            : /* Determine if a buffer contains only characters from the base64
     605                 :            :  * encoding set
     606                 :            : */
     607                 :            : int
     608                 :    2722389 : is_base64(const unsigned char * const buf, const unsigned short int len)
     609                 :            : {
     610                 :            :     unsigned short int  i;
     611                 :    2722389 :     int                 rv = 1;
     612                 :            : 
     613         [ +  + ]:  653468218 :     for(i=0; i<len; i++)
     614                 :            :     {
     615 [ +  + ][ +  + ]:  650745871 :         if(!(isalnum(buf[i]) || buf[i] == '/' || buf[i] == '+' || buf[i] == '='))
         [ +  + ][ +  + ]
     616                 :            :         {
     617                 :            :             rv = 0;
     618                 :            :             break;
     619                 :            :         }
     620                 :            :     }
     621                 :            : 
     622                 :    2722389 :     return rv;
     623                 :            : }
     624                 :            : 
     625                 :            : /**
     626                 :            :  * @brief Dump a FKO context to a buffer
     627                 :            :  *
     628                 :            :  * This function parses a FKO context and decodes each field to dump them to a
     629                 :            :  * buffer in a comprehensible way.
     630                 :            :  *
     631                 :            :  * @param ctx           FKO context to dump
     632                 :            :  * @param dump_buf      Buffer where to store the dump of the context
     633                 :            :  * @param dump_buf_len  Number of bytes available in the dump_buf array
     634                 :            :  *
     635                 :            :  * @return a FKO error code. FKO_SUCCESS if successful.
     636                 :            :  */
     637                 :            : int
     638                 :       3053 : dump_ctx_to_buffer(fko_ctx_t ctx, char *dump_buf, size_t dump_buf_len)
     639                 :            : {
     640                 :       3053 :     int         cp = 0;
     641                 :       3053 :     int         err = FKO_LAST_ERROR;
     642                 :            : 
     643                 :       3053 :     char       *rand_val        = NULL;
     644                 :       3053 :     char       *username        = NULL;
     645                 :       3053 :     char       *version         = NULL;
     646                 :       3053 :     char       *spa_message     = NULL;
     647                 :       3053 :     char       *nat_access      = NULL;
     648                 :       3053 :     char       *server_auth     = NULL;
     649                 :       3053 :     char       *enc_data        = NULL;
     650                 :       3053 :     char       *hmac_data       = NULL;
     651                 :       3053 :     char       *spa_digest      = NULL;
     652                 :            : #if HAVE_LIBGPGME
     653                 :       3053 :     char          *gpg_signer        = NULL;
     654                 :       3053 :     char          *gpg_recip         = NULL;
     655                 :       3053 :     char          *gpg_sig_id        = NULL;
     656                 :       3053 :     unsigned char  gpg_sig_verify    = 0;
     657                 :       3053 :     unsigned char  gpg_ignore_verify = 0;
     658                 :       3053 :     char          *gpg_sig_fpr       = NULL;
     659                 :       3053 :     char          *gpg_home_dir      = NULL;
     660                 :       3053 :     char          *gpg_exe           = NULL;
     661                 :       3053 :     int            gpg_sigsum        = -1;
     662                 :       3053 :     int            gpg_sig_stat      = -1;
     663                 :            : #endif
     664                 :       3053 :     char       *spa_data         = NULL;
     665                 :       3053 :     char        digest_str[24]   = {0};
     666                 :       3053 :     char        hmac_str[24]     = {0};
     667                 :       3053 :     char        enc_mode_str[FKO_ENCRYPTION_MODE_BUFSIZE] = {0};
     668                 :            : 
     669                 :       3053 :     time_t      timestamp       = 0;
     670                 :       3053 :     short       msg_type        = -1;
     671                 :       3053 :     short       digest_type     = -1;
     672                 :       3053 :     short       hmac_type       = -1;
     673                 :       3053 :     short       encryption_type = -1;
     674                 :       3053 :     int         encryption_mode = -1;
     675                 :       3053 :     int         client_timeout  = -1;
     676                 :            : 
     677                 :            :     /* Zero-ed the buffer */
     678                 :            :     memset(dump_buf, 0, dump_buf_len);
     679                 :            : 
     680                 :            :     /* Make sure the FKO context is initialized before printing it */
     681 [ +  - ][ +  - ]:       3053 :     if(!CTX_INITIALIZED(ctx))
     682                 :            :         err = FKO_ERROR_CTX_NOT_INITIALIZED;
     683                 :            : 
     684                 :            :     else
     685                 :            :     {
     686                 :            :         /* Parse the FKO context and collect data */
     687         [ +  - ]:       3053 :         RETURN_ON_FKO_ERROR(err, fko_get_rand_value(ctx, &rand_val));
     688         [ +  + ]:       3053 :         RETURN_ON_FKO_ERROR(err, fko_get_username(ctx, &username));
     689         [ +  + ]:       3051 :         RETURN_ON_FKO_ERROR(err, fko_get_timestamp(ctx, &timestamp));
     690         [ +  + ]:       3049 :         RETURN_ON_FKO_ERROR(err, fko_get_version(ctx, &version));
     691         [ +  + ]:       3047 :         RETURN_ON_FKO_ERROR(err, fko_get_spa_message_type(ctx, &msg_type));
     692         [ +  + ]:       3045 :         RETURN_ON_FKO_ERROR(err, fko_get_spa_message(ctx, &spa_message));
     693         [ +  + ]:       3043 :         RETURN_ON_FKO_ERROR(err, fko_get_spa_nat_access(ctx, &nat_access));
     694         [ +  + ]:       3041 :         RETURN_ON_FKO_ERROR(err, fko_get_spa_server_auth(ctx, &server_auth));
     695         [ +  + ]:       3039 :         RETURN_ON_FKO_ERROR(err, fko_get_spa_client_timeout(ctx, &client_timeout));
     696         [ +  + ]:       3037 :         RETURN_ON_FKO_ERROR(err, fko_get_spa_digest_type(ctx, &digest_type));
     697         [ +  - ]:       3035 :         RETURN_ON_FKO_ERROR(err, fko_get_spa_hmac_type(ctx, &hmac_type));
     698         [ +  - ]:       3035 :         RETURN_ON_FKO_ERROR(err, fko_get_spa_encryption_type(ctx, &encryption_type));
     699         [ +  - ]:       3035 :         RETURN_ON_FKO_ERROR(err, fko_get_spa_encryption_mode(ctx, &encryption_mode));
     700         [ +  - ]:       3035 :         RETURN_ON_FKO_ERROR(err, fko_get_encoded_data(ctx, &enc_data));
     701         [ +  - ]:       3035 :         RETURN_ON_FKO_ERROR(err, fko_get_spa_hmac(ctx, &hmac_data));
     702         [ +  + ]:       3035 :         RETURN_ON_FKO_ERROR(err, fko_get_spa_digest(ctx, &spa_digest));
     703         [ +  - ]:       3033 :         RETURN_ON_FKO_ERROR(err, fko_get_spa_data(ctx, &spa_data));
     704                 :            : 
     705                 :            : #if HAVE_LIBGPGME
     706         [ +  + ]:       3033 :         if(encryption_mode == FKO_ENC_MODE_ASYMMETRIC)
     707                 :            :         {
     708                 :            :             /* Populate GPG variables
     709                 :            :             */
     710         [ +  - ]:        131 :             RETURN_ON_FKO_ERROR(err, fko_get_gpg_signer(ctx, &gpg_signer));
     711         [ +  - ]:        131 :             RETURN_ON_FKO_ERROR(err, fko_get_gpg_recipient(ctx, &gpg_recip));
     712         [ +  - ]:        131 :             RETURN_ON_FKO_ERROR(err, fko_get_gpg_signature_verify(ctx, &gpg_sig_verify));
     713         [ +  - ]:        131 :             RETURN_ON_FKO_ERROR(err, fko_get_gpg_ignore_verify_error(ctx, &gpg_ignore_verify));
     714         [ +  - ]:        131 :             RETURN_ON_FKO_ERROR(err, fko_get_gpg_home_dir(ctx, &gpg_home_dir));
     715         [ +  - ]:        131 :             RETURN_ON_FKO_ERROR(err, fko_get_gpg_exe(ctx, &gpg_exe));
     716         [ +  + ]:        131 :             if(fko_get_gpg_signature_id(ctx, &gpg_sig_id) != FKO_SUCCESS)
     717                 :         74 :                 gpg_sig_id = NULL;
     718         [ +  + ]:        131 :             if(fko_get_gpg_signature_summary(ctx, &gpg_sigsum) != FKO_SUCCESS)
     719                 :         74 :                 gpg_sigsum = -1;
     720         [ +  + ]:        131 :             if(fko_get_gpg_signature_status(ctx, &gpg_sig_stat) != FKO_SUCCESS)
     721                 :         74 :                 gpg_sig_stat = -1;
     722         [ +  + ]:        131 :             if(fko_get_gpg_signature_fpr(ctx, &gpg_sig_fpr) != FKO_SUCCESS)
     723                 :         74 :                 gpg_sig_fpr = NULL;
     724                 :            :         }
     725                 :            : #endif
     726                 :            : 
     727                 :            :         /* Convert the digest integer to a string */
     728         [ +  - ]:       3033 :         if (digest_inttostr(digest_type, digest_str, sizeof(digest_str)) != 0)
     729                 :            :             return (FKO_ERROR_INVALID_DIGEST_TYPE);
     730                 :            : 
     731                 :            :         /* Convert the encryption mode integer to a string */
     732         [ +  - ]:       3033 :         if (enc_mode_inttostr(encryption_mode, enc_mode_str, sizeof(enc_mode_str)) != 0)
     733                 :            :             return (FKO_ERROR_INVALID_ENCRYPTION_TYPE);
     734                 :            : 
     735                 :            :         /* Convert the HMAC digest integer to a string if a HMAC message is available */
     736         [ +  + ]:       3033 :         if (ctx->msg_hmac_len != 0)
     737                 :            :         {
     738         [ +  - ]:       1057 :             if (hmac_digest_inttostr(hmac_type, hmac_str, sizeof(hmac_str)) != 0)
     739                 :            :                 return (FKO_ERROR_UNSUPPORTED_HMAC_MODE);
     740                 :            :         }
     741                 :            : 
     742                 :            :         /* Fill in the buffer to dump */
     743                 :       3033 :         cp  = append_msg_to_buf(dump_buf,    dump_buf_len,    "SPA Field Values:\n=================\n");
     744         [ +  - ]:       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "   Random Value: %s\n", rand_val == NULL ? NULL_STRING : rand_val);
     745         [ +  - ]:       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "       Username: %s\n", username == NULL ? NULL_STRING : username);
     746                 :       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "      Timestamp: %u\n", (unsigned int) timestamp);
     747         [ +  - ]:       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "    FKO Version: %s\n", version == NULL ? NULL_STRING : version);
     748                 :       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "   Message Type: %i (%s)\n", msg_type, msg_type_inttostr(msg_type));
     749         [ +  - ]:       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Message String: %s\n", spa_message == NULL ? NULL_STRING : spa_message);
     750         [ +  + ]:       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "     Nat Access: %s\n", nat_access == NULL ? NULL_STRING : nat_access);
     751         [ +  + ]:       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "    Server Auth: %s\n", server_auth == NULL ? NULL_STRING : server_auth);
     752                 :       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Client Timeout: %u\n", client_timeout);
     753                 :       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "    Digest Type: %u (%s)\n", digest_type, digest_str);
     754         [ +  + ]:       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "      HMAC Type: %u (%s)\n", hmac_type, hmac_type == 0 ? "None" : hmac_str);
     755                 :       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "Encryption Type: %d (%s)\n", encryption_type, enc_type_inttostr(encryption_type));
     756                 :       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "Encryption Mode: %d (%s)\n", encryption_mode, enc_mode_str);
     757                 :            : #if HAVE_LIBGPGME
     758         [ +  + ]:       3033 :         if(encryption_mode == FKO_ENC_MODE_ASYMMETRIC)
     759                 :            :         {
     760         [ +  + ]:        131 :             cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "     GPG signer: %s\n", gpg_signer == NULL ? NULL_STRING : gpg_signer);
     761         [ +  + ]:        131 :             cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "  GPG recipient: %s\n", gpg_recip == NULL ? NULL_STRING : gpg_recip);
     762         [ +  + ]:        131 :             cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " GPG sig verify: %s\n", gpg_sig_verify == 0 ? "No" : "Yes");
     763         [ +  + ]:        131 :             cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " GPG ignore sig: %s\n", gpg_ignore_verify == 0 ? "No" : "Yes");
     764         [ +  + ]:        131 :             cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "     GPG sig ID: %s\n", gpg_sig_id == NULL ? NULL_STRING : gpg_sig_id);
     765         [ +  + ]:        131 :             cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "    GPG sig fpr: %s\n", gpg_sig_fpr == NULL ? NULL_STRING : gpg_sig_fpr);
     766                 :        131 :             cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "GPG sig summary: %d\n", gpg_sigsum);
     767                 :        131 :             cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " GPG sig status: %d\n", gpg_sig_stat);
     768         [ +  - ]:        131 :             cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "   GPG home dir: %s\n", gpg_home_dir == NULL ? NULL_STRING : gpg_home_dir);
     769         [ +  + ]:        131 :             cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "        GPG exe: %s\n", gpg_exe == NULL ? GPG_EXE : gpg_exe);
     770                 :            :         }
     771                 :            : #endif
     772         [ +  - ]:       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "   Encoded Data: %s\n", enc_data == NULL ? NULL_STRING : enc_data);
     773         [ +  - ]:       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "SPA Data Digest: %s\n", spa_digest == NULL ? NULL_STRING : spa_digest);
     774         [ +  + ]:       3033 :         cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "           HMAC: %s\n", hmac_data == NULL ? NULL_STRING : hmac_data);
     775                 :       3033 :         append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Final SPA Data: %s\n", spa_data);
     776                 :            : 
     777                 :       3033 :         err = FKO_SUCCESS;
     778                 :            :     }
     779                 :            : 
     780                 :       3033 :     return (err);
     781                 :            : }
     782                 :            : 
     783                 :            : /***EOF***/

Generated by: LCOV version 1.10