"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.4/libcanlock/src/canlock.c" (27 Jun 2017, 11501 Bytes) of package /linux/misc/tin-2.4.4.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * COPYRIGHT AND PERMISSION NOTICE
    3  *
    4  * Copyright (c) 2017 Dennis Preiser
    5  * Copyright (c) 2003 G.J. Andruk
    6  *
    7  * All rights reserved.
    8  *
    9  * Permission is hereby granted, free of charge, to any person obtaining
   10  * a copy of this software and associated documentation files (the
   11  * "Software"), to deal in the Software without restriction, including
   12  * without limitation the rights to use, copy, modify, merge, publish,
   13  * distribute, and/or sell copies of the Software, and to permit persons
   14  * to whom the Software is furnished to do so, provided that the above
   15  * copyright notice(s) and this permission notice appear in all copies of
   16  * the Software and that both the above copyright notice(s) and this
   17  * permission notice appear in supporting documentation.
   18  *
   19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
   22  * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
   23  * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
   24  * SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
   25  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
   26  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
   27  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   28  *
   29  * Except as contained in this notice, the name of a copyright holder
   30  * shall not be used in advertising or otherwise to promote the sale, use
   31  * or other dealings in this Software without prior written authorization
   32  * of the copyright holder.
   33  */
   34 
   35 /* C99 */
   36 #include <ctype.h>
   37 #include <limits.h>
   38 #include <stdio.h>
   39 #include <stdlib.h>
   40 #include <string.h>
   41 #include "base64.h"
   42 
   43 /* Local */
   44 #include "sha.h"
   45 #include "canlock.h"
   46 
   47 
   48 /* Map external hash type 'cl_hash_version' to local SHA implementation */
   49 static enum SHAversion which_cl_hash(int which_hash)
   50 {
   51    switch (which_hash)
   52    {
   53       case CL_SHA1:
   54          return SHA1;
   55       case CL_SHA224:
   56          return SHA224;
   57       case CL_SHA384:
   58          return SHA384;
   59       case CL_SHA512:
   60          return SHA512;
   61 
   62       /* Mandatory algorithm */
   63       case CL_SHA256:
   64       default:
   65          return SHA256;
   66    }
   67 }
   68 
   69 
   70 /*
   71  * Portable replacement for 'strdup()'
   72  *
   73  * 'strdup()' requires SUSv2, XSI extension or POSIX.1-2008
   74  * http://pubs.opengroup.org/onlinepubs/007908799/xsh/strdup.html
   75  * http://pubs.opengroup.org/onlinepubs/009695399/functions/strdup.html
   76  * http://pubs.opengroup.org/onlinepubs/9699919799/functions/strdup.html
   77  *
   78  * Note:
   79  * 'malloc()' already gives the correct return (and 'errno') values required by
   80  * POSIX.
   81  */
   82 static char *my_strdup(const char *s)
   83 {
   84    char *res;
   85    size_t len;
   86 
   87    len = strlen(s);
   88    res = (char *) malloc(len + (size_t) 1);
   89    if (NULL != res)
   90    {
   91       strncpy(res, s, len);
   92       res[len] = 0;
   93    }
   94 
   95    return res;
   96 }
   97 
   98 
   99 /*
  100  * Extract a <c-lock-string> or <c-key-string> element respectively from 'key'
  101  * (that is, with the <scheme>: prefix removed)
  102  *
  103  * The <scheme> is written to 'type' on success, else empty string on failure.
  104  * The caller must ensure that the provided buffer is large enough.
  105  *
  106  * Returns a malloc()'d buffer on success, that the caller will need to free().
  107  * Returns NULL (on failure).
  108  */
  109 char *lock_strip_alpha(char *key, char *type)
  110 {
  111    char *ret;
  112    int offset;
  113 
  114    /* Strip scheme and write it to 'type' */
  115    do
  116    {
  117       *type = (char) tolower((int) (unsigned char) *key);
  118       type++;
  119       key++;
  120    } while (*key && *key != ':');
  121    *type = '\0';
  122 
  123    key++;  /* Skip colon */
  124 
  125    /* Copy <c-lock-string> or <c-key-string> respectively */
  126    ret = my_strdup(key);
  127    if (NULL != ret)
  128    {
  129       /*
  130        * Strip potential trailing <clue-string> element
  131        * (that is, a :xx suffix is removed).
  132        *
  133        * Note:
  134        * This element was removed from an early draft, but could still be
  135        * present.
  136        */
  137       offset = 0;
  138       while (ret[offset] && ret[offset] != ':')
  139          offset++;
  140       ret[offset] = '\0';
  141    }
  142    return ret;
  143 }
  144 
  145 
  146 char *lock_strip(char *key, char *type)
  147 {
  148    return lock_strip_alpha(key, type);
  149 }
  150 
  151 
  152 /*
  153  * Split a <c-lock> or <c-key> element respectively
  154  *
  155  * 'input' is split on the first colon into <scheme> and <c-lock-string> or
  156  * <c-key-string> elements respectively.
  157  *
  158  * If scheme is supported, the corresponding ID is returned.
  159  *
  160  * A pointer to <c-lock-string> or <c-key-string> respectively is written to
  161  * the location pointed to by 'klstring' (no memory is allocated, the address
  162  * points to the memory used for 'input').
  163  *
  164  * Returns the hash alorithm ID for scheme (on success).
  165  * Returns CL_INVALID (on failure, NULL was written to 'klstring' in this case).
  166  */
  167 int cl_split(char *input, char **klstring)
  168 {
  169    int hash = CL_INVALID;
  170    char *scheme, *junk;
  171 
  172    *klstring = strchr(input, (int) ':');
  173    if (NULL != *klstring)
  174    {
  175       (*klstring)++;  /* Skip colon */
  176       scheme = (char *) malloc(strlen(input) + (size_t) 1);
  177       if (NULL == scheme) { *klstring = NULL; }
  178       else
  179       {
  180          junk = lock_strip_alpha(input, scheme);
  181          if (NULL != junk)
  182          {
  183             if (!strcmp(scheme, "sha1"))  { hash = CL_SHA1; }
  184             else if (!strcmp(scheme, "sha224"))  { hash = CL_SHA224; }
  185             else if (!strcmp(scheme, "sha256"))  { hash = CL_SHA256; }
  186             else if (!strcmp(scheme, "sha384"))  { hash = CL_SHA384; }
  187             else if (!strcmp(scheme, "sha512"))  { hash = CL_SHA512; }
  188             free((void *) junk);
  189          }
  190          free((void *) scheme);
  191       }
  192    }
  193    return hash;
  194 }
  195 
  196 
  197 /*
  198  * Generate a SHA1 cancel key
  199  * Returns a malloc()'d buffer that the caller will need to free() (on success).
  200  * Returns NULL (on failure).
  201  */
  202 char *sha_key(const unsigned char *secret, size_t seclen,
  203         const unsigned char *message, size_t msglen)
  204 {
  205    return cl_get_key(CL_SHA1, secret, seclen, message, msglen);
  206 }
  207 
  208 
  209 /*
  210  * Generate a cancel key
  211  * Returns a malloc()'d buffer that the caller will need to free() (on success).
  212  * Returns NULL (on failure).
  213  */
  214 char *cl_get_key(int which_hash, const unsigned char *secret, size_t seclen,
  215                  const unsigned char *message, size_t msglen)
  216 {
  217    char *cankey[1], *tmp;
  218    const char *scheme;
  219    enum SHAversion which_sha;
  220    size_t keysize, scheme_len;
  221    uint8_t hmacbuff[USHAMaxHashSize];
  222 
  223    which_sha = which_cl_hash(which_hash);
  224 
  225    /* Ensure that size data from external caller can be represented as 'int' */
  226    if ((size_t) INT_MAX < msglen || (size_t) INT_MAX < seclen)
  227       return NULL;
  228 
  229    if (hmac(which_sha, message, (int) msglen, secret, (int) seclen, hmacbuff)
  230        != shaSuccess)
  231       return NULL;
  232 
  233    if (!(keysize = base64_encode(hmacbuff, USHAHashSize(which_sha), cankey)))
  234       return NULL;
  235 
  236    switch (which_sha)
  237    {
  238       case SHA1:
  239          scheme = "sha1:";
  240          break;
  241       case SHA224:
  242          scheme = "sha224:";
  243          break;
  244       case SHA256:
  245          scheme = "sha256:";
  246          break;
  247       case SHA384:
  248          scheme = "sha384:";
  249          break;
  250       case SHA512:
  251          scheme = "sha512:";
  252          break;
  253       default:
  254          return NULL;
  255    }
  256 
  257    scheme_len = strlen(scheme);
  258 
  259    tmp = (char *) realloc((void *) *cankey, keysize + scheme_len + 1);
  260    if (NULL != tmp) { *cankey = tmp; }
  261    else
  262    {
  263       free((void *) *cankey);
  264       return NULL;
  265    }
  266 
  267    memmove((void *) (*cankey + scheme_len), (void *) *cankey, keysize + 1);
  268    strncpy(*cankey, scheme, scheme_len);
  269    return (*cankey);
  270 }
  271 
  272 
  273 /*
  274  * Generate a SHA1 cancel lock
  275  * Returns a malloc()'d buffer that the caller will need to free() (on success).
  276  * Returns NULL (on failure).
  277  */
  278 char *sha_lock(const unsigned char *secret, size_t seclen,
  279                const unsigned char *message, size_t msglen)
  280 {
  281    return cl_get_lock(CL_SHA1, secret, seclen, message, msglen);
  282 }
  283 
  284 
  285 /*
  286  * Generate cancel lock
  287  * Returns a malloc()'d buffer that the caller will need to free() (on success).
  288  * Returns NULL (on failure).
  289  */
  290 char *cl_get_lock(int which_hash, const unsigned char *secret, size_t seclen,
  291                   const unsigned char *message, size_t msglen)
  292 {
  293    USHAContext hash_ctx;
  294    char *canlock[1], *tmp, *junk;
  295    const char *scheme;
  296    enum SHAversion which_sha;
  297    size_t hash_size, locksize, scheme_len;
  298    uint8_t *cankey, hmacbuff[USHAMaxHashSize];
  299 
  300    which_sha = which_cl_hash(which_hash);
  301 
  302    /* The function 'USHAHashSize()' never returns negative values */
  303    hash_size = (size_t) USHAHashSize(which_sha);
  304 
  305    if (!(tmp = cl_get_key(which_hash, secret, seclen, message, msglen)))
  306       return NULL;
  307 
  308    if (!(junk = malloc(hash_size + 1)))
  309    {
  310       free(tmp);
  311       return NULL;
  312    }
  313 
  314    cankey = (unsigned char *) lock_strip_alpha(tmp, junk);
  315 
  316    free(tmp);
  317    free(junk);
  318 
  319    if (USHAReset(&hash_ctx, which_sha) != shaSuccess)
  320    {
  321       free(cankey);
  322       return NULL;
  323    }
  324 
  325    if (USHAInput(&hash_ctx, cankey, (unsigned int) strlen((char *) cankey))
  326        != shaSuccess)
  327    {
  328       free(cankey);
  329       return NULL;
  330    }
  331 
  332    free(cankey);
  333 
  334    if (USHAResult(&hash_ctx, hmacbuff) != shaSuccess)
  335       return NULL;
  336 
  337    if (!(locksize = base64_encode(hmacbuff, (int) hash_size, canlock)))
  338       return NULL;
  339 
  340    switch (which_sha)
  341    {
  342       case SHA1:
  343          scheme = "sha1:";
  344          break;
  345       case SHA224:
  346          scheme = "sha224:";
  347          break;
  348       case SHA256:
  349          scheme = "sha256:";
  350          break;
  351       case SHA384:
  352          scheme = "sha384:";
  353          break;
  354       case SHA512:
  355          scheme = "sha512:";
  356          break;
  357       default:
  358          return NULL;
  359    }
  360 
  361    scheme_len = strlen(scheme);
  362 
  363    tmp = (char *) realloc((void *) *canlock, locksize + scheme_len + 1);
  364    if (NULL != tmp) { *canlock = tmp; }
  365    else
  366    {
  367       free((void *) *canlock);
  368       return NULL;
  369    }
  370 
  371    memmove((void *) (*canlock + scheme_len), (void *) *canlock, locksize + 1);
  372    strncpy(*canlock, scheme, scheme_len);
  373    return (*canlock);
  374 }
  375 
  376 
  377 /*
  378  * Verify a SHA1 cancel key against a cancel lock
  379  * Returns 0 on success, nonzero on failure.
  380  */
  381 int sha_verify(const char *key, const char *lock)
  382 {
  383    return cl_verify(CL_SHA1, key, lock);
  384 }
  385 
  386 /*
  387  * Verify a cancel key against a cancel lock
  388  * Returns 0 on success, nonzero on failure.
  389  */
  390 int cl_verify(int which_hash, const char *key, const char *lock)
  391 {
  392    int res;
  393    USHAContext hash_ctx;
  394    char *templock[1];
  395    enum SHAversion which_sha;
  396    size_t key_size, hash_size;
  397    uint8_t hashbuff[USHAMaxHashSize];
  398 
  399    /* Defeat the fallback to SHA256 default */
  400    if (CL_INVALID == which_hash)
  401       return -1;
  402 
  403    /*
  404     * Ensure that key length is supported
  405     * Currently the maximum length is for base64 encoded SHA512: 88
  406     * Theoretical limit: UINT_MAX
  407     * (must always be representable as 'unsigned int')
  408     */
  409    key_size = strlen(key);
  410    if ((size_t) 88 < key_size)
  411       return -1;
  412 
  413    which_sha = which_cl_hash(which_hash);
  414 
  415    /* The function 'USHAHashSize()' never returns negative values */
  416    hash_size = (size_t) USHAHashSize(which_sha);
  417 
  418    if (USHAReset(&hash_ctx, which_sha) != shaSuccess)
  419       return -1;
  420 
  421    if (USHAInput(&hash_ctx, (const uint8_t *) key, (unsigned int) key_size)
  422        != shaSuccess)
  423       return -1;
  424 
  425    if (USHAResult(&hash_ctx, hashbuff) != shaSuccess)
  426       return -1;
  427 
  428    if (!base64_encode(hashbuff, (int) hash_size, templock))
  429       return -1;
  430 
  431    res = strcmp(*templock, lock);
  432    free((void*) *templock);
  433 
  434    return res;
  435 }