"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.6.2/libcanlock/util/canlock.c" (23 Aug 2021, 14702 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.

    1 /* ========================================================================== */
    2 /* Copyright (c) 2017 Michael Baeuerle
    3  *
    4  * All rights reserved.
    5  *
    6  * Permission is hereby granted, free of charge, to any person obtaining
    7  * a copy of this software and associated documentation files (the
    8  * "Software"), to deal in the Software without restriction, including
    9  * without limitation the rights to use, copy, modify, merge, publish,
   10  * distribute, and/or sell copies of the Software, and to permit persons
   11  * to whom the Software is furnished to do so, provided that the above
   12  * copyright notice(s) and this permission notice appear in all copies of
   13  * the Software and that both the above copyright notice(s) and this
   14  * permission notice appear in supporting documentation.
   15  *
   16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
   19  * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
   20  * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
   21  * SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
   22  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
   23  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
   24  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   25  *
   26  * Except as contained in this notice, the name of a copyright holder
   27  * shall not be used in advertising or otherwise to promote the sale, use
   28  * or other dealings in this Software without prior written authorization
   29  * of the copyright holder.
   30  */
   31 
   32 /* GNU autoconf */
   33 #include <config.h>
   34 
   35 /* C99 */
   36 #include <stdio.h>
   37 #include <stdlib.h>
   38 #include <string.h>
   39 
   40 /* Local */
   41 #include "canlock.h"
   42 
   43 
   44 /* ========================================================================== */
   45 /* Constants */
   46 
   47 /*! Size of buffer for secret data */
   48 #define SEC_DATA_SIZE_MAX (size_t) 1024
   49 
   50 
   51 /* ========================================================================== */
   52 /*! \brief Print program version information */
   53 
   54 static void print_version(void)
   55 {
   56    const char*  p = PACKAGE_STRING;
   57 
   58    printf("%s\n", &p[3]);
   59    printf("%s\n", "Command line frontend for libcanlock.");
   60 
   61    return;
   62 }
   63 
   64 
   65 /* ========================================================================== */
   66 /*! \brief Print help */
   67 
   68 static void print_help(void)
   69 {
   70    const char*  p = PACKAGE_NAME;
   71 
   72    printf("Usage: %s %s\n", &p[3], "[options]\n"          "Options:\n"
   73           "   -a scheme        Use <scheme> as hash algorithm for -k and -l "
   74                                "options\n"
   75           "                    (must be specified first)\n"
   76           "   -q               Suppress output to stdout for -c and -o "
   77                                "options\n"
   78           "                    (must be specified first)\n"
   79           "The following options are mutually exclusive:\n"
   80           "   -c c-key,c-lock  Check Cancel-Key <c-key> against "
   81                                "Cancel-Lock <c-lock>\n"
   82           "   -h               Print this help message to stdout and exit\n"
   83           "                    (must be the only option)\n"
   84           "   -k [uid]mid      Get Cancel-Key for Message-ID <mid>\n"
   85           "                    and an optional User-ID <uid>\n"
   86           "                    (secret is read from stdin)\n"
   87           "   -l [uid]mid      Get Cancel-Lock for Message-ID <mid>\n"
   88           "                    and an optional User-ID <uid>\n"
   89           "                    (secret is read from stdin)\n"
   90           "   -o               Print memory overwrite info to stdout and exit\n"
   91           "                    (must be the only option)\n"
   92           "   -v               Print version information to stdout and exit\n"
   93           "                    (must be the only option)\n"
   94           "(See manual page for details)"
   95    );
   96 
   97    return;
   98 }
   99 
  100 
  101 /* ========================================================================== */
  102 /*! \brief Check scheme for supported hash algorithm
  103  *
  104  * \param[in] scheme  String with scheme in lowercase
  105  *
  106  * \return
  107  * - Hash algorithm ID on success
  108  * - \c CL_INVALID on error
  109  */
  110 
  111 static cl_hash_version get_hash(const char *scheme)
  112 {
  113    cl_hash_version hash = CL_INVALID;
  114 
  115    if (!strcmp(scheme, "sha1"))  { hash = CL_SHA1; }
  116    else if (!strcmp(scheme, "sha224"))  { hash = CL_SHA224; }
  117    else if (!strcmp(scheme, "sha256"))  { hash = CL_SHA256; }
  118    else if (!strcmp(scheme, "sha384"))  { hash = CL_SHA384; }
  119    else if (!strcmp(scheme, "sha512"))  { hash = CL_SHA512; }
  120 
  121    if (CL_INVALID == hash)
  122    {
  123       fprintf(stderr, "%s\n", "Hash algorithm not supported");
  124    }
  125 
  126    return (hash);
  127 }
  128 
  129 
  130 /* ========================================================================== */
  131 /*! \brief Read secret data from stdin
  132  *
  133  * \param[out] sec_size  Pointer to size of secret data
  134  * \param[out] buf_size  Pointer to size of buffer
  135  *
  136  * Secret data is read until EOF.
  137  * Hitting the buffer size limit \c SEC_DATA_SIZE_MAX is treated as an error.
  138  *
  139  * \attention
  140  * The caller must not call \c free() for the returned pointer but should call
  141  * \ref cl_clear_secret() instead.
  142  *
  143  * \return
  144  * - Pointer to secret data on success
  145  * - \c NULL on error (nothing was written to \e secsize and \e bufsize )
  146  */
  147 
  148 static unsigned char *get_secret(size_t *sec_size, size_t *buf_size)
  149 {
  150    static unsigned char buf[SEC_DATA_SIZE_MAX];
  151    unsigned char *res = buf;
  152    int rv = 0;
  153    size_t i = 0;
  154 
  155    while (EOF != rv)
  156    {
  157       if (SEC_DATA_SIZE_MAX <= i)
  158       {
  159          res = NULL;
  160          break;
  161       }
  162       rv = fgetc(stdin);
  163       if (EOF != rv) { buf[i++] = (unsigned char) rv; }
  164    }
  165    cl_clear_secret((void *) &rv, sizeof(int), sizeof(int));
  166    if (NULL == res)
  167    {
  168       cl_clear_secret((void *) buf, SEC_DATA_SIZE_MAX, SEC_DATA_SIZE_MAX);
  169    }
  170    else
  171    {
  172       /* Return size of buffer and size of secret data */
  173       *buf_size = SEC_DATA_SIZE_MAX;
  174       *sec_size = i;
  175    }
  176 
  177    return (res);
  178 }
  179 
  180 
  181 /* ========================================================================== */
  182 /*! \brief Execute request
  183  *
  184  * \param[in] hash       Hash algorithm ID
  185  * \param[in] quiet      Suppress result on stdout for check operation
  186  * \param[in] opt        Pointer to option string
  187  * \param[in] opt_value  Pointer to option value string
  188  *
  189  * \attention
  190  * The caller must ensure that \e opt and \e opt_val are not \c NULL .
  191  *
  192  * \return
  193  * - 0 on success
  194  * - -1 on error
  195  */
  196 
  197 static int exec_request(cl_hash_version hash, int quiet,
  198                         const char *opt, const char *opt_value)
  199 {
  200    int res = 0;
  201    enum { UK, KEY, LOCK, CHECK, OMEM } op = UK;
  202    unsigned char *sec = NULL;
  203    size_t  sec_size = 0, buf_size = 0;
  204    const unsigned char *mid;
  205    const char *out = NULL;
  206    char *key, *key_string, *lock, *lock_string;
  207    cl_hash_version key_hash, lock_hash;
  208    int memtest = 1;
  209 
  210    if (NULL == opt)  { return (-1); }
  211    if (strcmp(opt, "-o") && NULL == opt_value)  { return (-1); }
  212 
  213    if (!strcmp(opt, "-k")) { op = KEY; }
  214    if (!strcmp(opt, "-l")) { op = LOCK; }
  215    if (!strcmp(opt, "-c")) { op = CHECK; }
  216    if (!strcmp(opt, "-o")) { op = OMEM; }
  217    switch (op)
  218    {
  219       case KEY:
  220       case LOCK:
  221          /* Read secret data */
  222          sec = get_secret(&sec_size, &buf_size);
  223          if (NULL == sec)  { res = -1; }
  224          else
  225          {
  226             mid = (unsigned char *) opt_value;
  227             if (KEY == op)
  228             {
  229                out = cl_get_key(hash, sec, sec_size, mid, strlen(opt_value));
  230             }
  231             else
  232             {
  233                out = cl_get_lock(hash, sec, sec_size, mid, strlen(opt_value));
  234             }
  235             /* Remove secret data from memory */
  236             res = cl_clear_secret((void *) sec, sec_size, buf_size);
  237             if (0 > res)
  238             {
  239                fprintf(stderr, "%s\n", "Failed to overwrite secret data (bug)");
  240                res = -1;
  241             }
  242             else
  243             {
  244                if (0 < res)
  245                {
  246                   fprintf(stderr, "%s\n",
  247                           "Warning: Overwriting secret data was not reliable");
  248                }
  249                printf("%s\n", out);
  250                res = 0;
  251             }
  252             free((void *) out);
  253          }
  254          break;
  255       case CHECK:
  256          /* Split option value into key and lock part */
  257          key = (char *) malloc(strlen(opt_value) + (size_t) 1);
  258          if (NULL == key) { res = -1; }
  259          else
  260          {
  261             strcpy(key, opt_value);
  262             lock = strchr(key, (int) ',');
  263             if (NULL == lock)
  264             {
  265                fprintf(stderr, "%s\n", "Field separator not found (bug)");
  266                res = -1;
  267             }
  268             else { *lock++ = 0; }
  269             /* Check for colon after scheme ("-a" option is ignored) */
  270             if (NULL == strchr(key, (int) ':')
  271                 || NULL == strchr(lock, (int) ':'))
  272             {
  273                fprintf(stderr, "%s\n", "Colon missing after scheme");
  274                res = -1;
  275             }
  276             else
  277             {
  278                /* Check whether key matches lock */
  279                key_hash = cl_split(key, &key_string);
  280                lock_hash = cl_split(lock, &lock_string);
  281                if (CL_INVALID == key_hash || CL_INVALID == lock_hash)
  282                {
  283                   fprintf(stderr, "%s\n", "Extracting scheme failed");
  284                   res = -1;
  285                }
  286                else
  287                {
  288                   if (key_hash != lock_hash)
  289                   {
  290                      /* Different scheme */
  291                      if(!quiet) { printf("%s\n", "Scheme mismatch"); }
  292                      res = -1;
  293                   }
  294                   else
  295                   {
  296                      if(cl_verify(key_hash, key_string, lock_string))
  297                      {
  298                         if(!quiet) { printf("%s\n", "Mismatch"); }
  299                         res = -1;
  300                      }
  301                      else
  302                      {
  303                         if(!quiet) { printf("%s\n", "Good"); }
  304                      }
  305                   }
  306                }
  307             }
  308             free((void *) key);
  309          }
  310          break;
  311       case OMEM:
  312          /* Check whether memory overwrite support is available */
  313          if (cl_clear_secret((void *) &memtest, sizeof(int), sizeof(int)))
  314          {
  315             if(!quiet)
  316             {
  317                printf("%s\n", "Memory overwrite support not available");
  318             }
  319             res = -1;
  320          }
  321          else
  322          {
  323             /* Available */
  324             if(!quiet) { printf("%s\n", "Memory overwrite support available"); }
  325          }
  326          break;
  327       case UK:
  328       default:
  329          fprintf(stderr, "%s\n", "Unknown operation (bug)");
  330          res = -1;
  331          break;
  332    }
  333 
  334    return (res);
  335 }
  336 
  337 
  338 /* ========================================================================== */
  339 /*! \brief CLI utility
  340  *
  341  * \param[in] argc  Number of command line arguments
  342  * \param[in] argv  Array containing command line argument strings
  343  *
  344  * \return
  345  * - \c EXIT_SUCCESS on success
  346  * - \c EXIT_FAILURE on error
  347  */
  348 
  349 int main(int argc, char **argv)
  350 {
  351    int rv;
  352    enum { OK, ERROR, ABORT } rv2 = ERROR;
  353    unsigned int i;
  354    char option = 0;  /* Flag indicating option value will follow */
  355    cl_hash_version hash = CL_SHA256;  /* Mandatory algorithm as default */
  356    int quiet = 0;
  357    const char *opt = NULL;
  358    const char *opt_value = NULL;
  359 
  360    if (argc)
  361    {
  362       for (i = 1; i < (unsigned int) argc; i++)
  363       {
  364          if (option)
  365          {
  366             /* Process value of former option */
  367             opt_value = argv[i];
  368             if ('-' == opt_value[0])
  369             {
  370                fprintf(stderr, "%s\n", "Option value missing");
  371                break;
  372             }
  373             /* Accept option value */
  374             if (!strcmp(opt, "-a"))
  375             {
  376                hash = get_hash(opt_value);
  377                if (CL_INVALID == hash)
  378                {
  379                   break;
  380                }
  381                option = 0;
  382                /* Additional option must follow */
  383             }
  384             else
  385             {
  386                rv2 = OK;
  387                break;
  388             }
  389          }
  390          if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version"))
  391          {
  392             /* Print version information and report success */
  393             print_version();
  394             rv2 = ABORT;
  395             break;
  396          }
  397          else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
  398          {
  399             /* Print help and report success */
  400             print_help();
  401             rv2 = ABORT;
  402             break;
  403          }
  404          else if (!strcmp(argv[i], "-q"))
  405          {
  406             /* The "-c" or "-o" option should not print the result to stdout */
  407             quiet = 1;
  408             /* Additional option must follow */
  409          }
  410          else if (!strcmp(argv[i], "-o"))
  411          {
  412             opt = argv[i];
  413             rv2 = OK;
  414             break;
  415          }
  416          else if (!strcmp(argv[i], "-a")
  417                   || !strcmp(argv[i], "-c")
  418                   || !strcmp(argv[i], "-k")
  419                   || !strcmp(argv[i], "-l"))
  420          {
  421             /* Option value must follow */
  422             opt = argv[i];
  423             option = 1;
  424          }
  425          else if ('-' == argv[i][0])
  426          {
  427             /* Unknown option */
  428             fprintf(stderr, "%s\n", "Unknown option");
  429             break;
  430          }
  431       }
  432       if (ERROR == rv2)
  433       {
  434          fprintf(stderr, "%s\n", "Use '-h' or read the man page for help");
  435       }
  436    }
  437 
  438    /* Check options */
  439    switch (rv2)
  440    {
  441       case OK:
  442       {
  443          /* Check option value */
  444          if (strcmp(opt, "-o") && NULL == opt_value)
  445          {
  446             fprintf(stderr, "%s\n", "Option value missing (bug)");
  447             rv = EXIT_FAILURE;
  448             break;
  449          }
  450          else if (!strcmp(opt, "-c"))
  451          {
  452             if (NULL == strchr(opt_value, (int) ','))
  453             {
  454                fprintf(stderr, "%s\n", "Comma missing in option value");
  455                rv = EXIT_FAILURE;
  456                break;
  457             }
  458          }
  459          /* Execute requested operation */
  460          if (exec_request(hash, quiet, opt, opt_value)) { rv = EXIT_FAILURE; }
  461          else { rv = EXIT_SUCCESS; }
  462          break;
  463       }
  464       case ABORT:
  465       {
  466          /* Nothing more to do, but no error */
  467          rv = EXIT_SUCCESS;
  468          break;
  469       }
  470       case ERROR:
  471       default:
  472       {
  473          /* Error */
  474          rv = EXIT_FAILURE;
  475          break;
  476       }
  477    }
  478 
  479    exit(rv);
  480 }
  481 
  482 
  483 /* EOF */