frosix

Multiparty signature service (experimental)
Log | Files | Refs | README | LICENSE

frosix-cli.c (15874B)


      1 /*
      2   This file is part of Frosix
      3   Copyright (C) 2020,2021,2022 Anastasis SARL
      4 
      5   Frosix is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Lesser General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   Frosix is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   Frosix; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file cli/frosix-cli.c
     18  * @brief command line tool for Frosix client
     19  * @author Christian Grothoff
     20  * @author Dennis Neufeld
     21  * @author Dominik Meister
     22  * @author Joel Urech
     23  */
     24 
     25 #include "platform.h"
     26 #include <gnunet/gnunet_util_lib.h>
     27 #include <gnunet/gnunet_curl_lib.h>
     28 #include "frosix.h"
     29 #include <taler/taler_util.h>
     30 #include <taler/taler_error_codes.h>
     31 #include <taler/taler_json_lib.h>
     32 #include "frosix_util_lib.h"
     33 
     34 /**
     35  * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule().
     36  */
     37 static struct GNUNET_CURL_RescheduleContext *rc;
     38 
     39 /**
     40  * Curl context for communication with Frosix backend
     41  */
     42 static struct GNUNET_CURL_Context *ctx;
     43 
     44 /**
     45  * Input to -a option given.
     46  */
     47 static char *input = NULL;
     48 
     49 /**
     50  * Output filename, if given.
     51  */
     52 static char *output_filename = NULL;
     53 
     54 /**
     55  * Message we want to sign, -m option.
     56 */
     57 static char *message = NULL;
     58 
     59 /**
     60  * JSON containing additional arguments
     61  */
     62 static json_t *arguments;
     63 
     64 /**
     65  * JSON containing data from stdin
     66 */
     67 static json_t *std_input;
     68 
     69 /**
     70  * Handle to an ongoing action.
     71  */
     72 static struct FROSIX_ReduxAction *ra;
     73 
     74 /**
     75  * Return value from main.
     76  */
     77 static int global_ret;
     78 
     79 
     80 /**
     81  * Persist a json state, report errors.
     82  *
     83  * @param state to persist
     84  * @param filename where to write the state to, NULL for stdout
     85  */
     86 static void
     87 persist_new_state (json_t *state,
     88                    const char *filename)
     89 {
     90   if (NULL != filename)
     91   {
     92     if (0 !=
     93         json_dump_file (state,
     94                         filename,
     95                         JSON_INDENT (1)))
     96     {
     97       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     98                   "Could not dump state to `%s'\n",
     99                   filename);
    100       return;
    101     }
    102     return;
    103   }
    104   {
    105     char *state_str = json_dumps (state,
    106                                   JSON_INDENT (1));
    107     if (-1 >=
    108         fprintf (stdout,
    109                  "%s",
    110                  state_str))
    111     {
    112       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    113                   "Could not dump state to stdout\n");
    114       GNUNET_free (state_str);
    115       return;
    116     }
    117     GNUNET_free (state_str);
    118   }
    119 }
    120 
    121 
    122 /**
    123  * @brief Shutdown the application.
    124  *
    125  * @param cls closure
    126  */
    127 static void
    128 shutdown_task (void *cls)
    129 {
    130   (void) cls;
    131 
    132   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    133               "Shutdown initiated\n");
    134   if (NULL != ra)
    135   {
    136     FROSIX_redux_action_cancel (ra);
    137   }
    138   if (NULL != ctx)
    139   {
    140     GNUNET_CURL_fini (ctx);
    141     ctx = NULL;
    142   }
    143   if (NULL != rc)
    144   {
    145     GNUNET_CURL_gnunet_rc_destroy (rc);
    146     rc = NULL;
    147   }
    148   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    149               "Shutdown complete\n");
    150 }
    151 
    152 
    153 /**
    154  * Function called with the results of #FROSIX_redux_action().
    155  *
    156  * @param cls closure
    157  * @param error_code Error code
    158  * @param result_state new state as result
    159  */
    160 static void
    161 action_cb (void *cls,
    162            enum TALER_ErrorCode error_code,
    163            json_t *result_state)
    164 {
    165   (void) cls;
    166   // ra = NULL;
    167   if (NULL != result_state)
    168 
    169     persist_new_state (result_state,
    170                        output_filename);
    171 
    172   if (TALER_EC_NONE != error_code)
    173   {
    174     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    175                 "Redux failed with error %d: %s\n",
    176                 error_code,
    177                 TALER_ErrorCode_get_hint (error_code));
    178     json_dumpf (result_state,
    179                 stderr,
    180                 JSON_INDENT (2));
    181     fprintf (stderr, "action_cb - error\n");
    182   }
    183 
    184   /* free json argument and result */
    185   json_decref (result_state);
    186 
    187   GNUNET_SCHEDULER_shutdown ();
    188   global_ret = (TALER_EC_NONE != error_code) ? 1 : 0;
    189 }
    190 
    191 
    192 /**
    193  * @brief Start the application
    194  *
    195  * @param cls closure
    196  * @param args arguments left
    197  * @param cfgfile config file name
    198  * @param cfg handle for the configuration file
    199  */
    200 static void
    201 run (void *cls,
    202      char *const *args,
    203      const char *cfgfile,
    204      const struct GNUNET_CONFIGURATION_Handle *cfg)
    205 {
    206   (void) cls;
    207   json_error_t error;
    208 
    209   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    210               "Starting frosix-reducer\n");
    211   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
    212                                  NULL);
    213 
    214   /* action processing */
    215   {
    216     const char *action = args[0];
    217 
    218     if (NULL == action)
    219     {
    220       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    221                   "You must specify an action as the first argument (or `-k' or `-s')\n");
    222       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    223                   "Example: frosix-reducer --keygen -a 'json-formatted-argument'\n");
    224       GNUNET_SCHEDULER_shutdown ();
    225       global_ret = 1;
    226       return;
    227     }
    228 
    229     /*** KEYGEN ***/
    230     if (0 == strcasecmp (action,
    231                          "keygen"))
    232     {
    233       /* load json file from std input */
    234       std_input = json_loadf (stdin,
    235                               JSON_DECODE_ANY,
    236                               &error);
    237       if (NULL == std_input)
    238       {
    239         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    240                     "Failed to parse arguments on line %u:%u: %s!\n",
    241                     error.line,
    242                     error.column,
    243                     error.text);
    244         GNUNET_SCHEDULER_shutdown ();
    245         global_ret = 1;
    246         return;
    247       }
    248 
    249       /* initialize HTTP client event loop */
    250       ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
    251                               &rc);
    252       rc = GNUNET_CURL_gnunet_rc_create (ctx);
    253 
    254       FROSIX_redux_init (ctx);
    255 
    256       ra = FROSIX_redux_keygen_start (std_input,
    257                                       &action_cb,
    258                                       cls);
    259     }
    260 
    261     /*** REQUEST-CHALLENGE ***/
    262     if (0 == strcasecmp (action,
    263                          "request-challenge"))
    264     {
    265       /* check if -a and -m flag, abort if not found */
    266       if (NULL != input && NULL != message)
    267       {
    268         std_input = json_loadf (stdin,
    269                                 JSON_DECODE_ANY,
    270                                 &error);
    271         if (NULL == std_input)
    272         {
    273           GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    274                       "Failed to parse arguments on line %u:%u: %s!\n",
    275                       error.line,
    276                       error.column,
    277                       error.text);
    278           GNUNET_SCHEDULER_shutdown ();
    279           global_ret = 1;
    280           return;
    281         }
    282 
    283         arguments = json_loads (input,
    284                                 JSON_DECODE_ANY,
    285                                 &error);
    286         if (NULL == arguments)
    287         {
    288           GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    289                       "Failed to parse arguments on line %u:%u: %s!\n",
    290                       error.line,
    291                       error.column,
    292                       error.text);
    293           GNUNET_SCHEDULER_shutdown ();
    294           global_ret = 1;
    295           return;
    296         }
    297       }
    298       else {
    299         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    300                     "Failed to parse arguments on line %u:%u: %s!\n",
    301                     error.line,
    302                     error.column,
    303                     error.text);
    304         GNUNET_SCHEDULER_shutdown ();
    305         global_ret = 1;
    306         return;
    307       }
    308 
    309       /* initialize HTTP client event loop */
    310       ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
    311                               &rc);
    312       rc = GNUNET_CURL_gnunet_rc_create (ctx);
    313 
    314       FROSIX_redux_init (ctx);
    315 
    316       ra = FROSIX_redux_challenge_request_start (std_input,
    317                                                  arguments,
    318                                                  message,
    319                                                  &action_cb,
    320                                                  cls);
    321     }
    322 
    323     /*** SIGN ***/
    324     if (0 == strcasecmp (action,
    325                          "sign"))
    326     {
    327       /* check if -a and -m flag, abort if not found */
    328       if (NULL != input && NULL != message)
    329       {
    330         std_input = json_loadf (stdin,
    331                                 JSON_DECODE_ANY,
    332                                 &error);
    333         if (NULL == std_input)
    334         {
    335           GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    336                       "Failed to parse arguments on line %u:%u: %s!\n",
    337                       error.line,
    338                       error.column,
    339                       error.text);
    340           GNUNET_SCHEDULER_shutdown ();
    341           global_ret = 1;
    342           return;
    343         }
    344 
    345         arguments = json_loads (input,
    346                                 JSON_DECODE_ANY,
    347                                 &error);
    348         if (NULL == arguments)
    349         {
    350           GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    351                       "Failed to parse arguments on line %u:%u: %s!\n",
    352                       error.line,
    353                       error.column,
    354                       error.text);
    355           GNUNET_SCHEDULER_shutdown ();
    356           global_ret = 1;
    357           return;
    358         }
    359       }
    360       else {
    361         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    362                     "Failed to parse arguments on line %u:%u: %s!\n",
    363                     error.line,
    364                     error.column,
    365                     error.text);
    366         GNUNET_SCHEDULER_shutdown ();
    367         global_ret = 1;
    368         return;
    369       }
    370 
    371       /* initialize HTTP client event loop */
    372       ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
    373                               &rc);
    374       rc = GNUNET_CURL_gnunet_rc_create (ctx);
    375 
    376       FROSIX_redux_init (ctx);
    377 
    378       ra = FROSIX_redux_sign_start (std_input,
    379                                     arguments,
    380                                     message,
    381                                     &action_cb,
    382                                     cls);
    383     }
    384 
    385     /*** VERIFY ***/
    386     if (0 == strcasecmp (action,
    387                          "verify"))
    388     {
    389       /* check if -m flag, abort if not found */
    390       if (NULL != message)
    391       {
    392         std_input = json_loadf (stdin,
    393                                 JSON_DECODE_ANY,
    394                                 &error);
    395         if (NULL == std_input)
    396         {
    397           GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    398                       "Failed to parse arguments on line %u:%u: %s!\n",
    399                       error.line,
    400                       error.column,
    401                       error.text);
    402           GNUNET_SCHEDULER_shutdown ();
    403           global_ret = 1;
    404           return;
    405         }
    406       }
    407       else {
    408         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    409                     "Failed to parse arguments on line %u:%u: %s!\n",
    410                     error.line,
    411                     error.column,
    412                     error.text);
    413         GNUNET_SCHEDULER_shutdown ();
    414         global_ret = 1;
    415         return;
    416       }
    417 
    418       /* verify signature and return OK */
    419       if (GNUNET_OK != FROSIX_verify_signature (message,
    420                                                 std_input))
    421       {
    422         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    423                     "Failed to verify signature!\n");
    424         global_ret = 1;
    425       }
    426       else {
    427         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    428                     "Signature verified!\n");
    429       }
    430     }
    431 
    432     /*** EXPORT-PK ***/
    433     if (0 == strcasecmp (action,
    434                          "export-pk"))
    435     {
    436       std_input = json_loadf (stdin,
    437                               JSON_DECODE_ANY,
    438                               &error);
    439       if (NULL == std_input)
    440       {
    441         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    442                     "Failed to parse arguments on line %u:%u: %s!\n",
    443                     error.line,
    444                     error.column,
    445                     error.text);
    446         GNUNET_SCHEDULER_shutdown ();
    447         global_ret = 1;
    448         return;
    449       }
    450 
    451       FROSIX_export_public_key (std_input,
    452                                 &action_cb,
    453                                 cls);
    454     }
    455 
    456     /*** VERIFY-PK ***/
    457     if (0 == strcasecmp (action,
    458                          "verify-pk"))
    459     {
    460       std_input = json_loadf (stdin,
    461                               JSON_DECODE_ANY,
    462                               &error);
    463       if (NULL == std_input)
    464       {
    465         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    466                     "Failed to parse arguments on line %u:%u: %s!\n",
    467                     error.line,
    468                     error.column,
    469                     error.text);
    470         GNUNET_SCHEDULER_shutdown ();
    471         global_ret = 1;
    472         return;
    473       }
    474 
    475       /* verify signature and return OK */
    476       if (GNUNET_OK != FROSIX_verify_public_key (std_input))
    477       {
    478         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    479                     "Failed to verify public key!\n");
    480         global_ret = 1;
    481       }
    482       else {
    483         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    484                     "Public key verified!\n");
    485       }
    486     }
    487 
    488     /*** DELETE-KEY ***/
    489     if (0 == strcasecmp (action,
    490                          "delete-key"))
    491     {
    492       /* load json file from std input */
    493       std_input = json_loadf (stdin,
    494                               JSON_DECODE_ANY,
    495                               &error);
    496       if (NULL == std_input)
    497       {
    498         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    499                     "Failed to parse arguments on line %u:%u: %s!\n",
    500                     error.line,
    501                     error.column,
    502                     error.text);
    503         GNUNET_SCHEDULER_shutdown ();
    504         global_ret = 1;
    505         return;
    506       }
    507 
    508       /* initialize HTTP client event loop */
    509       ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
    510                               &rc);
    511       rc = GNUNET_CURL_gnunet_rc_create (ctx);
    512 
    513       FROSIX_redux_init (ctx);
    514 
    515       ra = FROSIX_redux_key_delete_start (std_input,
    516                                           &action_cb,
    517                                           cls);
    518     }
    519   }
    520 }
    521 
    522 
    523 int
    524 main (int argc,
    525       char *const *argv)
    526 {
    527   /* the available command line options */
    528   struct GNUNET_GETOPT_CommandLineOption options[] = {
    529     GNUNET_GETOPT_option_string ('a',
    530                                  "arguments",
    531                                  "JSON",
    532                                  "pass a JSON string containing arguments to cli",
    533                                  &input),
    534     GNUNET_GETOPT_option_string ('o',
    535                                  "output",
    536                                  "Filename",
    537                                  "define output filename",
    538                                  &output_filename),
    539     GNUNET_GETOPT_option_string ('m',
    540                                  "message",
    541                                  "Message to sign",
    542                                  "The message to sign",
    543                                  &message),
    544     GNUNET_GETOPT_OPTION_END
    545   };
    546   enum GNUNET_GenericReturnValue ret;
    547 
    548   /* FIRST get the libtalerutil initialization out
    549      of the way. Then throw that one away, and force
    550      the SYNC defaults to be used! */
    551   (void) TALER_project_data_default ();
    552   GNUNET_OS_init (FROSIX_project_data_default ());
    553   ret = GNUNET_PROGRAM_run (argc,
    554                             argv,
    555                             "frosix-cli",
    556                             "This is an application for using Frosix.\n",
    557                             options,
    558                             &run,
    559                             NULL);
    560   if (GNUNET_SYSERR == ret)
    561     return 3;
    562   if (GNUNET_NO == ret)
    563     return 0;
    564   return global_ret;
    565 }
    566 
    567 
    568 /* end of frosix-cli-redux.c */