"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.6.2/libcanlock/src/canlock.c" (23 Aug 2021, 11731 Bytes) of package /linux/misc/tin-2.6.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 last Fossies "Diffs" side-by-side code changes report: 2.4.5_vs_2.6.0.

    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  * https://pubs.opengroup.org/onlinepubs/007908799/xsh/strdup.html
   75  * https://pubs.opengroup.org/onlinepubs/009695399/functions/strdup.html
   76  * https://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 #if ! CL_API_V2
  110 static
  111 #endif  /* CL_API_V2 */
  112 char *lock_strip_alpha(char *key, char *type)
  113 {
  114    char *ret;
  115    int offset;
  116 
  117    /* Strip scheme and write it to 'type' */
  118    do
  119    {
  120       *type = (char) tolower((int) (unsigned char) *key);
  121       type++;
  122       key++;
  123    } while (*key && *key != ':');
  124    *type = '\0';
  125 
  126    key++;  /* Skip colon */
  127 
  128    /* Copy <c-lock-string> or <c-key-string> respectively */
  129    ret = my_strdup(key);
  130    if (NULL != ret)
  131    {
  132       /*
  133        * Strip potential trailing <clue-string> element
  134        * (that is, a :xx suffix is removed).
  135        *
  136        * Note:
  137        * This element was removed from an early draft, but could still be
  138        * present.
  139        */
  140       offset = 0;
  141       while (ret[offset] && ret[offset] != ':')
  142          offset++;
  143       ret[offset] = '\0';
  144    }
  145    return ret;
  146 }
  147 
  148 
  149 #if CL_API_V2
  150 char *lock_strip(char *key, char *type)
  151 {
  152    return lock_strip_alpha(key, type);
  153 }
  154 #endif  /* CL_API_V2 */
  155 
  156 
  157 /*
  158  * Split a <c-lock> or <c-key> element respectively
  159  *
  160  * 'input' is split on the first colon into <scheme> and <c-lock-string> or
  161  * <c-key-string> elements respectively.
  162  *
  163  * If scheme is supported, the corresponding ID is returned.
  164  *
  165  * A pointer to <c-lock-string> or <c-key-string> respectively is written to
  166  * the location pointed to by 'klstring' (no memory is allocated, the address
  167  * points to the memory used for 'input').
  168  *
  169  * Returns the hash algorithm ID for scheme (on success).
  170  * Returns CL_INVALID (on failure, NULL was written to 'klstring' in this case).
  171  */
  172 int cl_split(char *input, char **klstring)
  173 {
  174    int hash = CL_INVALID;
  175    char *scheme, *junk;
  176 
  177    *klstring = strchr(input, (int) ':');
  178    if (NULL != *klstring)
  179    {
  180       (*klstring)++;  /* Skip colon */
  181       scheme = (char *) malloc(strlen(input) + (size_t) 1);
  182       if (NULL == scheme) { *klstring = NULL; }
  183       else
  184       {
  185          junk = lock_strip_alpha(input, scheme);
  186          if (NULL != junk)
  187          {
  188             if (!strcmp(scheme, "sha1"))  { hash = CL_SHA1; }
  189             else if (!strcmp(scheme, "sha224"))  { hash = CL_SHA224; }
  190             else if (!strcmp(scheme, "sha256"))  { hash = CL_SHA256; }
  191             else if (!strcmp(scheme, "sha384"))  { hash = CL_SHA384; }
  192             else if (!strcmp(scheme, "sha512"))  { hash = CL_SHA512; }
  193             free((void *) junk);
  194          }
  195          free((void *) scheme);
  196       }
  197    }
  198    return hash;
  199 }
  200 
  201 
  202 #if CL_API_V2
  203 /*
  204  * Generate a SHA1 cancel key
  205  * Returns a malloc()'d buffer that the caller will need to free() (on success).
  206  * Returns NULL (on failure).
  207  */
  208 char *sha_key(const unsigned char *secret, size_t seclen,
  209         const unsigned char *message, size_t msglen)
  210 {
  211    return cl_get_key(CL_SHA1, secret, seclen, message, msglen);
  212 }
  213 #endif  /* CL_API_V2 */
  214 
  215 
  216 /*
  217  * Generate a cancel key
  218  * Returns a malloc()'d buffer that the caller will need to free() (on success).
  219  * Returns NULL (on failure).
  220  */
  221 char *cl_get_key(int which_hash, const unsigned char *secret, size_t seclen,
  222                  const unsigned char *message, size_t msglen)
  223 {
  224    char *cankey[1], *tmp;
  225    const char *scheme;
  226    enum SHAversion which_sha;
  227    size_t keysize, scheme_len;
  228    uint8_t hmacbuff[USHAMaxHashSize];
  229 
  230    which_sha = which_cl_hash(which_hash);
  231 
  232    /* Ensure that size data from external caller can be represented as 'int' */
  233    if ((size_t) INT_MAX < msglen || (size_t) INT_MAX < seclen)
  234       return NULL;
  235 
  236    if (RFC2104Hmac(which_sha, message, (int) msglen, secret, (int) seclen,
  237                    hmacbuff)
  238        != shaSuccess)
  239       return NULL;
  240 
  241    if (!(keysize = base64_encode(hmacbuff, USHAHashSize(which_sha), cankey)))
  242       return NULL;
  243 
  244    switch (which_sha)
  245    {
  246       case SHA1:
  247          scheme = "sha1:";
  248          break;
  249       case SHA224:
  250          scheme = "sha224:";
  251          break;
  252       case SHA256:
  253          scheme = "sha256:";
  254          break;
  255       case SHA384:
  256          scheme = "sha384:";
  257          break;
  258       case SHA512:
  259          scheme = "sha512:";
  260          break;
  261       default:
  262          return NULL;
  263    }
  264 
  265    scheme_len = strlen(scheme);
  266 
  267    tmp = (char *) realloc((void *) *cankey, keysize + scheme_len + 1);
  268    if (NULL != tmp) { *cankey = tmp; }
  269    else
  270    {
  271       free((void *) *cankey);
  272       return NULL;
  273    }
  274 
  275    memmove((void *) (*cankey + scheme_len), (void *) *cankey, keysize + 1);
  276    strncpy(*cankey, scheme, scheme_len);
  277    return (*cankey);
  278 }
  279 
  280 
  281 #if CL_API_V2
  282 /*
  283  * Generate a SHA1 cancel lock
  284  * Returns a malloc()'d buffer that the caller will need to free() (on success).
  285  * Returns NULL (on failure).
  286  */
  287 char *sha_lock(const unsigned char *secret, size_t seclen,
  288                const unsigned char *message, size_t msglen)
  289 {
  290    return cl_get_lock(CL_SHA1, secret, seclen, message, msglen);
  291 }
  292 #endif  /* CL_API_V2 */
  293 
  294 
  295 /*
  296  * Generate cancel lock
  297  * Returns a malloc()'d buffer that the caller will need to free() (on success).
  298  * Returns NULL (on failure).
  299  */
  300 char *cl_get_lock(int which_hash, const unsigned char *secret, size_t seclen,
  301                   const unsigned char *message, size_t msglen)
  302 {
  303    USHAContext hash_ctx;
  304    char *canlock[1], *tmp, *junk;
  305    const char *scheme;
  306    enum SHAversion which_sha;
  307    size_t hash_size, locksize, scheme_len;
  308    uint8_t *cankey, hmacbuff[USHAMaxHashSize];
  309 
  310    which_sha = which_cl_hash(which_hash);
  311 
  312    /* The function 'USHAHashSize()' never returns negative values */
  313    hash_size = (size_t) USHAHashSize(which_sha);
  314 
  315    if (!(tmp = cl_get_key(which_hash, secret, seclen, message, msglen)))
  316       return NULL;
  317 
  318    if (!(junk = malloc(hash_size + 1)))
  319    {
  320       free(tmp);
  321       return NULL;
  322    }
  323 
  324    cankey = (unsigned char *) lock_strip_alpha(tmp, junk);
  325 
  326    free(tmp);
  327    free(junk);
  328 
  329    if (USHAReset(&hash_ctx, which_sha) != shaSuccess)
  330    {
  331       free(cankey);
  332       return NULL;
  333    }
  334 
  335    if (USHAInput(&hash_ctx, cankey, (unsigned int) strlen((char *) cankey))
  336        != shaSuccess)
  337    {
  338       free(cankey);
  339       return NULL;
  340    }
  341 
  342    free(cankey);
  343 
  344    if (USHAResult(&hash_ctx, hmacbuff) != shaSuccess)
  345       return NULL;
  346 
  347    if (!(locksize = base64_encode(hmacbuff, (int) hash_size, canlock)))
  348       return NULL;
  349 
  350    switch (which_sha)
  351    {
  352       case SHA1:
  353          scheme = "sha1:";
  354          break;
  355       case SHA224:
  356          scheme = "sha224:";
  357          break;
  358       case SHA256:
  359          scheme = "sha256:";
  360          break;
  361       case SHA384:
  362          scheme = "sha384:";
  363          break;
  364       case SHA512:
  365          scheme = "sha512:";
  366          break;
  367       default:
  368          return NULL;
  369    }
  370 
  371    scheme_len = strlen(scheme);
  372 
  373    tmp = (char *) realloc((void *) *canlock, locksize + scheme_len + 1);
  374    if (NULL != tmp) { *canlock = tmp; }
  375    else
  376    {
  377       free((void *) *canlock);
  378       return NULL;
  379    }
  380 
  381    memmove((void *) (*canlock + scheme_len), (void *) *canlock, locksize + 1);
  382    strncpy(*canlock, scheme, scheme_len);
  383    return (*canlock);
  384 }
  385 
  386 
  387 #if CL_API_V2
  388 /*
  389  * Verify a SHA1 cancel key against a cancel lock
  390  * Returns 0 on success, nonzero on failure.
  391  */
  392 int sha_verify(const char *key, const char *lock)
  393 {
  394    return cl_verify(CL_SHA1, key, lock);
  395 }
  396 #endif  /* CL_API_V2 */
  397 
  398 
  399 /*
  400  * Verify a cancel key against a cancel lock
  401  * Returns 0 on success, nonzero on failure.
  402  */
  403 int cl_verify(int which_hash, const char *key, const char *lock)
  404 {
  405    int res;
  406    USHAContext hash_ctx;
  407    char *templock[1];
  408    enum SHAversion which_sha;
  409    size_t key_size, hash_size;
  410    uint8_t hashbuff[USHAMaxHashSize];
  411 
  412    /* Defeat the fallback to SHA256 default */
  413    if (CL_INVALID == which_hash)
  414       return -1;
  415 
  416    /*
  417     * Ensure that key length is supported
  418     * Currently the maximum length is for base64 encoded SHA512: 88
  419     * Theoretical limit: UINT_MAX
  420     * (must always be representable as 'unsigned int')
  421     */
  422    key_size = strlen(key);
  423    if ((size_t) 88 < key_size)
  424       return -1;
  425 
  426    which_sha = which_cl_hash(which_hash);
  427 
  428    /* The function 'USHAHashSize()' never returns negative values */
  429    hash_size = (size_t) USHAHashSize(which_sha);
  430 
  431    if (USHAReset(&hash_ctx, which_sha) != shaSuccess)
  432       return -1;
  433 
  434    if (USHAInput(&hash_ctx, (const uint8_t *) key, (unsigned int) key_size)
  435        != shaSuccess)
  436       return -1;
  437 
  438    if (USHAResult(&hash_ctx, hashbuff) != shaSuccess)
  439       return -1;
  440 
  441    if (!base64_encode(hashbuff, (int) hash_size, templock))
  442       return -1;
  443 
  444    res = strcmp(*templock, lock);
  445    free((void*) *templock);
  446 
  447    return res;
  448 }