"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.2/libcanlock/src/canlock.c" (27 Jun 2017, 11501 Bytes) of package /linux/misc/tin-2.4.2.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. For more information about "canlock.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.1_vs_2.4.2.

    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 }