LCOV - code coverage report
Current view: top level - exchange-tools - taler-auditor-offline.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 40.9 % 452 185
Test Date: 2025-12-28 14:06:02 Functions: 85.0 % 20 17

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2020-2023 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it under the
       6              :   terms of the GNU General Public License as published by the Free Software
       7              :   Foundation; either version 3, or (at your option) any later version.
       8              : 
       9              :   TALER 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 General Public License for more details.
      12              : 
      13              :   You should have received a copy of the GNU General Public License along with
      14              :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15              : */
      16              : /**
      17              :  * @file taler-auditor-offline.c
      18              :  * @brief Support for operations involving the auditor's (offline) key.
      19              :  * @author Christian Grothoff
      20              :  */
      21              : #include "taler/platform.h"
      22              : #include <gnunet/gnunet_json_lib.h>
      23              : #include <microhttpd.h>
      24              : #include "taler/taler_json_lib.h"
      25              : #include "taler/taler_exchange_service.h"
      26              : 
      27              : /**
      28              :  * Name of the input of a denomination key signature for the 'upload' operation.
      29              :  * The "auditor-" prefix ensures that there is no ambiguity between
      30              :  * taler-exchange-offline and taler-auditor-offline JSON formats.
      31              :  * The last component --by convention-- identifies the protocol version
      32              :  * and should be incremented whenever the JSON format of the 'argument' changes.
      33              :  */
      34              : #define OP_SIGN_DENOMINATION "auditor-sign-denomination-0"
      35              : 
      36              : /**
      37              :  * Name of the input for the 'sign' and 'show' operations.
      38              :  * The "auditor-" prefix ensures that there is no ambiguity between
      39              :  * taler-exchange-offline and taler-auditor-offline JSON formats.
      40              :  * The last component --by convention-- identifies the protocol version
      41              :  * and should be incremented whenever the JSON format of the 'argument' changes.
      42              :  */
      43              : #define OP_INPUT_KEYS "auditor-keys-0"
      44              : 
      45              : /**
      46              :  * Show the offline signing key.
      47              :  * The last component --by convention-- identifies the protocol version
      48              :  * and should be incremented whenever the JSON format of the 'argument' changes.
      49              :  */
      50              : #define OP_SETUP "auditor-setup-0"
      51              : 
      52              : /**
      53              :  * Our private key, initialized in #load_offline_key().
      54              :  */
      55              : static struct TALER_AuditorPrivateKeyP auditor_priv;
      56              : 
      57              : /**
      58              :  * Our private key, initialized in #load_offline_key().
      59              :  */
      60              : static struct TALER_AuditorPublicKeyP auditor_pub;
      61              : 
      62              : /**
      63              :  * Base URL of this auditor's REST endpoint.
      64              :  */
      65              : static char *auditor_url;
      66              : 
      67              : /**
      68              :  * Exchange's master public key.
      69              :  */
      70              : static struct TALER_MasterPublicKeyP master_pub;
      71              : 
      72              : /**
      73              :  * Our context for making HTTP requests.
      74              :  */
      75              : static struct GNUNET_CURL_Context *ctx;
      76              : 
      77              : /**
      78              :  * Reschedule context for #ctx.
      79              :  */
      80              : static struct GNUNET_CURL_RescheduleContext *rc;
      81              : 
      82              : /**
      83              :  * Handle to the exchange's configuration
      84              :  */
      85              : static const struct GNUNET_CONFIGURATION_Handle *kcfg;
      86              : 
      87              : /**
      88              :  * Return value from main().
      89              :  */
      90              : static int global_ret;
      91              : 
      92              : /**
      93              :  * Input to consume.
      94              :  */
      95              : static json_t *in;
      96              : 
      97              : /**
      98              :  * Array of actions to perform.
      99              :  */
     100              : static json_t *out;
     101              : 
     102              : /**
     103              :  * Currency supported by this auditor.
     104              :  */
     105              : static char *currency;
     106              : 
     107              : 
     108              : /**
     109              :  * A subcommand supported by this program.
     110              :  */
     111              : struct SubCommand
     112              : {
     113              :   /**
     114              :    * Name of the command.
     115              :    */
     116              :   const char *name;
     117              : 
     118              :   /**
     119              :    * Help text for the command.
     120              :    */
     121              :   const char *help;
     122              : 
     123              :   /**
     124              :    * Function implementing the command.
     125              :    *
     126              :    * @param args subsequent command line arguments (char **)
     127              :    */
     128              :   void (*cb)(char *const *args);
     129              : };
     130              : 
     131              : 
     132              : /**
     133              :  * Data structure for wire add requests.
     134              :  */
     135              : struct DenominationAddRequest
     136              : {
     137              : 
     138              :   /**
     139              :    * Kept in a DLL.
     140              :    */
     141              :   struct DenominationAddRequest *next;
     142              : 
     143              :   /**
     144              :    * Kept in a DLL.
     145              :    */
     146              :   struct DenominationAddRequest *prev;
     147              : 
     148              :   /**
     149              :    * Operation handle.
     150              :    */
     151              :   struct TALER_EXCHANGE_AuditorAddDenominationHandle *h;
     152              : 
     153              :   /**
     154              :    * Array index of the associated command.
     155              :    */
     156              :   size_t idx;
     157              : };
     158              : 
     159              : 
     160              : /**
     161              :  * Next work item to perform.
     162              :  */
     163              : static struct GNUNET_SCHEDULER_Task *nxt;
     164              : 
     165              : /**
     166              :  * Active denomination add requests.
     167              :  */
     168              : static struct DenominationAddRequest *dar_head;
     169              : 
     170              : /**
     171              :  * Active denomination add requests.
     172              :  */
     173              : static struct DenominationAddRequest *dar_tail;
     174              : 
     175              : /**
     176              :  * Handle to the exchange, used to request /keys.
     177              :  */
     178              : static struct TALER_EXCHANGE_GetKeysHandle *exchange;
     179              : 
     180              : 
     181              : /**
     182              :  * Shutdown task. Invoked when the application is being terminated.
     183              :  *
     184              :  * @param cls NULL
     185              :  */
     186              : static void
     187            6 : do_shutdown (void *cls)
     188              : {
     189              :   (void) cls;
     190              : 
     191              :   {
     192              :     struct DenominationAddRequest *dar;
     193              : 
     194            6 :     while (NULL != (dar = dar_head))
     195              :     {
     196            0 :       fprintf (stderr,
     197              :                "Aborting incomplete wire add #%u\n",
     198            0 :                (unsigned int) dar->idx);
     199            0 :       TALER_EXCHANGE_add_auditor_denomination_cancel (dar->h);
     200            0 :       GNUNET_CONTAINER_DLL_remove (dar_head,
     201              :                                    dar_tail,
     202              :                                    dar);
     203            0 :       GNUNET_free (dar);
     204              :     }
     205              :   }
     206            6 :   if (NULL != out)
     207              :   {
     208            0 :     json_dumpf (out,
     209              :                 stdout,
     210              :                 JSON_INDENT (2));
     211            0 :     json_decref (out);
     212            0 :     out = NULL;
     213              :   }
     214            6 :   if (NULL != in)
     215              :   {
     216            0 :     fprintf (stderr,
     217              :              "Darning: input not consumed!\n");
     218            0 :     json_decref (in);
     219            0 :     in = NULL;
     220              :   }
     221            6 :   if (NULL != exchange)
     222              :   {
     223            0 :     TALER_EXCHANGE_get_keys_cancel (exchange);
     224            0 :     exchange = NULL;
     225              :   }
     226            6 :   if (NULL != nxt)
     227              :   {
     228            0 :     GNUNET_SCHEDULER_cancel (nxt);
     229            0 :     nxt = NULL;
     230              :   }
     231            6 :   if (NULL != ctx)
     232              :   {
     233            6 :     GNUNET_CURL_fini (ctx);
     234            6 :     ctx = NULL;
     235              :   }
     236            6 :   if (NULL != rc)
     237              :   {
     238            6 :     GNUNET_CURL_gnunet_rc_destroy (rc);
     239            6 :     rc = NULL;
     240              :   }
     241            6 : }
     242              : 
     243              : 
     244              : /**
     245              :  * Test if we should shut down because all tasks are done.
     246              :  */
     247              : static void
     248         3186 : test_shutdown (void)
     249              : {
     250         3186 :   if ( (NULL == dar_head) &&
     251            6 :        (NULL == exchange) &&
     252            6 :        (NULL == nxt) )
     253            6 :     GNUNET_SCHEDULER_shutdown ();
     254         3186 : }
     255              : 
     256              : 
     257              : /**
     258              :  * Function to continue processing the next command.
     259              :  *
     260              :  * @param cls must be a `char *const*` with the array of
     261              :  *        command-line arguments to process next
     262              :  */
     263              : static void
     264              : work (void *cls);
     265              : 
     266              : 
     267              : /**
     268              :  * Function to schedule job to process the next command.
     269              :  *
     270              :  * @param args the array of command-line arguments to process next
     271              :  */
     272              : static void
     273           18 : next (char *const *args)
     274              : {
     275           18 :   GNUNET_assert (NULL == nxt);
     276           18 :   if (NULL == args[0])
     277              :   {
     278            0 :     test_shutdown ();
     279            0 :     return;
     280              :   }
     281           18 :   nxt = GNUNET_SCHEDULER_add_now (&work,
     282              :                                   (void *) args);
     283              : }
     284              : 
     285              : 
     286              : /**
     287              :  * Add an operation to the #out JSON array for processing later.
     288              :  *
     289              :  * @param op_name name of the operation
     290              :  * @param op_value values for the operation (consumed)
     291              :  */
     292              : static void
     293         3180 : output_operation (const char *op_name,
     294              :                   json_t *op_value)
     295              : {
     296              :   json_t *action;
     297              : 
     298         3180 :   GNUNET_assert (NULL != out);
     299         3180 :   action = GNUNET_JSON_PACK (
     300              :     GNUNET_JSON_pack_string ("operation",
     301              :                              op_name),
     302              :     GNUNET_JSON_pack_object_steal ("arguments",
     303              :                                    op_value));
     304         3180 :   GNUNET_break (0 ==
     305              :                 json_array_append_new (out,
     306              :                                        action));
     307         3180 : }
     308              : 
     309              : 
     310              : /**
     311              :  * Information about a subroutine for an upload.
     312              :  */
     313              : struct UploadHandler
     314              : {
     315              :   /**
     316              :    * Key to trigger this subroutine.
     317              :    */
     318              :   const char *key;
     319              : 
     320              :   /**
     321              :    * Function implementing an upload.
     322              :    *
     323              :    * @param exchange_url URL of the exchange
     324              :    * @param idx index of the operation we are performing
     325              :    * @param value arguments to drive the upload.
     326              :    */
     327              :   void (*cb)(const char *exchange_url,
     328              :              size_t idx,
     329              :              const json_t *value);
     330              : 
     331              : };
     332              : 
     333              : 
     334              : /**
     335              :  * Load the offline key (if not yet done). Triggers shutdown on failure.
     336              :  *
     337              :  * @param do_create #GNUNET_YES if the key may be created
     338              :  * @return #GNUNET_OK on success
     339              :  */
     340              : static int
     341            6 : load_offline_key (int do_create)
     342              : {
     343              :   static bool done;
     344              :   int ret;
     345              :   char *fn;
     346              : 
     347            6 :   if (done)
     348            0 :     return GNUNET_OK;
     349            6 :   if (GNUNET_OK !=
     350            6 :       GNUNET_CONFIGURATION_get_value_filename (kcfg,
     351              :                                                "auditor",
     352              :                                                "AUDITOR_PRIV_FILE",
     353              :                                                &fn))
     354              :   {
     355            0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     356              :                                "auditor",
     357              :                                "AUDITOR_PRIV_FILE");
     358            0 :     test_shutdown ();
     359            0 :     return GNUNET_SYSERR;
     360              :   }
     361            6 :   ret = GNUNET_CRYPTO_eddsa_key_from_file (fn,
     362              :                                            do_create,
     363              :                                            &auditor_priv.eddsa_priv);
     364            6 :   if (GNUNET_SYSERR == ret)
     365              :   {
     366            0 :     if (do_create)
     367            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     368              :                   "Failed to initialize auditor key at `%s': %s\n",
     369              :                   fn,
     370              :                   "could not create file");
     371              :     else
     372            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     373              :                   "Failed to load auditor key from file `%s': try running `taler-auditor-offline setup'?\n",
     374              :                   fn);
     375            0 :     GNUNET_free (fn);
     376            0 :     test_shutdown ();
     377            0 :     return GNUNET_SYSERR;
     378              :   }
     379            6 :   GNUNET_free (fn);
     380            6 :   GNUNET_CRYPTO_eddsa_key_get_public (&auditor_priv.eddsa_priv,
     381              :                                       &auditor_pub.eddsa_pub);
     382            6 :   done = true;
     383            6 :   return GNUNET_OK;
     384              : }
     385              : 
     386              : 
     387              : /**
     388              :  * Function called with information about the post denomination (signature)
     389              :  * add operation result.
     390              :  *
     391              :  * @param cls closure with a `struct DenominationAddRequest`
     392              :  * @param adr response data
     393              :  */
     394              : static void
     395         3180 : denomination_add_cb (
     396              :   void *cls,
     397              :   const struct TALER_EXCHANGE_AuditorAddDenominationResponse *adr)
     398              : {
     399         3180 :   struct DenominationAddRequest *dar = cls;
     400         3180 :   const struct TALER_EXCHANGE_HttpResponse *hr = &adr->hr;
     401              : 
     402         3180 :   if (MHD_HTTP_NO_CONTENT != hr->http_status)
     403              :   {
     404            0 :     fprintf (stderr,
     405              :              "Upload failed for command #%u with status %u: %s (%s)\n",
     406            0 :              (unsigned int) dar->idx,
     407            0 :              hr->http_status,
     408            0 :              TALER_ErrorCode_get_hint (hr->ec),
     409            0 :              NULL != hr->hint
     410              :              ? hr->hint
     411              :              : "no hint provided");
     412            0 :     global_ret = EXIT_FAILURE;
     413              :   }
     414         3180 :   GNUNET_CONTAINER_DLL_remove (dar_head,
     415              :                                dar_tail,
     416              :                                dar);
     417         3180 :   GNUNET_free (dar);
     418         3180 :   test_shutdown ();
     419         3180 : }
     420              : 
     421              : 
     422              : /**
     423              :  * Upload denomination add data.
     424              :  *
     425              :  * @param exchange_url base URL of the exchange
     426              :  * @param idx index of the operation we are performing (for logging)
     427              :  * @param value arguments for denomination revocation
     428              :  */
     429              : static void
     430         3180 : upload_denomination_add (const char *exchange_url,
     431              :                          size_t idx,
     432              :                          const json_t *value)
     433              : {
     434              :   struct TALER_AuditorSignatureP auditor_sig;
     435              :   struct TALER_DenominationHashP h_denom_pub;
     436              :   struct DenominationAddRequest *dar;
     437              :   const char *err_name;
     438              :   unsigned int err_line;
     439              :   struct GNUNET_JSON_Specification spec[] = {
     440         3180 :     GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
     441              :                                  &h_denom_pub),
     442         3180 :     GNUNET_JSON_spec_fixed_auto ("auditor_sig",
     443              :                                  &auditor_sig),
     444         3180 :     GNUNET_JSON_spec_end ()
     445              :   };
     446              : 
     447         3180 :   if (GNUNET_OK !=
     448         3180 :       GNUNET_JSON_parse (value,
     449              :                          spec,
     450              :                          &err_name,
     451              :                          &err_line))
     452              :   {
     453            0 :     fprintf (stderr,
     454              :              "Invalid input for adding denomination: %s#%u at %u (skipping)\n",
     455              :              err_name,
     456              :              err_line,
     457              :              (unsigned int) idx);
     458            0 :     global_ret = EXIT_FAILURE;
     459            0 :     test_shutdown ();
     460            0 :     return;
     461              :   }
     462         3180 :   dar = GNUNET_new (struct DenominationAddRequest);
     463         3180 :   dar->idx = idx;
     464         3180 :   dar->h =
     465         3180 :     TALER_EXCHANGE_add_auditor_denomination (ctx,
     466              :                                              exchange_url,
     467              :                                              &h_denom_pub,
     468              :                                              &auditor_pub,
     469              :                                              &auditor_sig,
     470              :                                              &denomination_add_cb,
     471              :                                              dar);
     472         3180 :   GNUNET_CONTAINER_DLL_insert (dar_head,
     473              :                                dar_tail,
     474              :                                dar);
     475              : }
     476              : 
     477              : 
     478              : /**
     479              :  * Perform uploads based on the JSON in #out.
     480              :  *
     481              :  * @param exchange_url base URL of the exchange to use
     482              :  */
     483              : static void
     484            6 : trigger_upload (const char *exchange_url)
     485              : {
     486            6 :   struct UploadHandler uhs[] = {
     487              :     {
     488              :       .key = OP_SIGN_DENOMINATION,
     489              :       .cb = &upload_denomination_add
     490              :     },
     491              :     /* array termination */
     492              :     {
     493              :       .key = NULL
     494              :     }
     495              :   };
     496              :   size_t index;
     497              :   json_t *obj;
     498              : 
     499         3186 :   json_array_foreach (out, index, obj) {
     500         3180 :     bool found = false;
     501              :     const char *key;
     502              :     const json_t *value;
     503              : 
     504         3180 :     key = json_string_value (json_object_get (obj, "operation"));
     505         3180 :     value = json_object_get (obj, "arguments");
     506         3180 :     if (NULL == key)
     507              :     {
     508            0 :       fprintf (stderr,
     509              :                "Malformed JSON input\n");
     510            0 :       global_ret = EXIT_FAILURE;
     511            0 :       test_shutdown ();
     512            0 :       return;
     513              :     }
     514              :     /* block of code that uses key and value */
     515         3180 :     for (unsigned int i = 0; NULL != uhs[i].key; i++)
     516              :     {
     517         3180 :       if (0 == strcasecmp (key,
     518              :                            uhs[i].key))
     519              :       {
     520         3180 :         found = true;
     521         3180 :         uhs[i].cb (exchange_url,
     522              :                    index,
     523              :                    value);
     524         3180 :         break;
     525              :       }
     526              :     }
     527         3180 :     if (! found)
     528              :     {
     529            0 :       fprintf (stderr,
     530              :                "Upload does not know how to handle `%s'\n",
     531              :                key);
     532            0 :       global_ret = EXIT_FAILURE;
     533            0 :       test_shutdown ();
     534            0 :       return;
     535              :     }
     536              :   }
     537              :   /* test here, in case no upload was triggered (i.e. empty input) */
     538            6 :   test_shutdown ();
     539              : }
     540              : 
     541              : 
     542              : /**
     543              :  * Upload operation result (signatures) to exchange.
     544              :  *
     545              :  * @param args the array of command-line arguments to process next
     546              :  */
     547              : static void
     548            6 : do_upload (char *const *args)
     549              : {
     550              :   char *exchange_url;
     551              : 
     552              :   (void) args;
     553            6 :   if (GNUNET_YES == GNUNET_is_zero (&auditor_pub))
     554              :   {
     555              :     /* private key not available, try configuration for public key */
     556              :     char *auditor_public_key_str;
     557              : 
     558            0 :     if (GNUNET_OK !=
     559            0 :         GNUNET_CONFIGURATION_get_value_string (kcfg,
     560              :                                                "auditor",
     561              :                                                "PUBLIC_KEY",
     562              :                                                &auditor_public_key_str))
     563              :     {
     564            0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     565              :                                  "auditor",
     566              :                                  "PUBLIC_KEY");
     567            0 :       global_ret = EXIT_NOTCONFIGURED;
     568            0 :       test_shutdown ();
     569            0 :       return;
     570              :     }
     571            0 :     if (GNUNET_OK !=
     572            0 :         GNUNET_CRYPTO_eddsa_public_key_from_string (
     573              :           auditor_public_key_str,
     574              :           strlen (auditor_public_key_str),
     575              :           &auditor_pub.eddsa_pub))
     576              :     {
     577            0 :       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     578              :                                  "auditor",
     579              :                                  "PUBLIC_KEY",
     580              :                                  "invalid key");
     581            0 :       GNUNET_free (auditor_public_key_str);
     582            0 :       global_ret = EXIT_NOTCONFIGURED;
     583            0 :       test_shutdown ();
     584            0 :       return;
     585              :     }
     586            0 :     GNUNET_free (auditor_public_key_str);
     587              :   }
     588            6 :   if (NULL != in)
     589              :   {
     590            0 :     fprintf (stderr,
     591              :              "Downloaded data was not consumed, refusing upload\n");
     592            0 :     test_shutdown ();
     593            0 :     global_ret = EXIT_FAILURE;
     594            0 :     return;
     595              :   }
     596            6 :   if (NULL == out)
     597              :   {
     598              :     json_error_t err;
     599              : 
     600            0 :     out = json_loadf (stdin,
     601              :                       JSON_REJECT_DUPLICATES,
     602              :                       &err);
     603            0 :     if (NULL == out)
     604              :     {
     605            0 :       fprintf (stderr,
     606              :                "Failed to read JSON input: %s at %d:%s (offset: %d)\n",
     607              :                err.text,
     608              :                err.line,
     609              :                err.source,
     610              :                err.position);
     611            0 :       test_shutdown ();
     612            0 :       global_ret = EXIT_FAILURE;
     613            0 :       return;
     614              :     }
     615              :   }
     616            6 :   if (! json_is_array (out))
     617              :   {
     618            0 :     fprintf (stderr,
     619              :              "Error: expected JSON array for `upload` command\n");
     620            0 :     test_shutdown ();
     621            0 :     global_ret = EXIT_FAILURE;
     622            0 :     return;
     623              :   }
     624            6 :   if (GNUNET_OK !=
     625            6 :       GNUNET_CONFIGURATION_get_value_string (kcfg,
     626              :                                              "exchange",
     627              :                                              "BASE_URL",
     628              :                                              &exchange_url))
     629              :   {
     630            0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     631              :                                "exchange",
     632              :                                "BASE_URL");
     633            0 :     global_ret = EXIT_NOTCONFIGURED;
     634            0 :     test_shutdown ();
     635            0 :     return;
     636              :   }
     637            6 :   trigger_upload (exchange_url);
     638            6 :   json_decref (out);
     639            6 :   out = NULL;
     640            6 :   GNUNET_free (exchange_url);
     641              : }
     642              : 
     643              : 
     644              : /**
     645              :  * Function called with information about who is auditing
     646              :  * a particular exchange and what keys the exchange is using.
     647              :  *
     648              :  * @param cls closure with the `char **` remaining args
     649              :  * @param kr response data
     650              :  * @param keys key data from the exchange
     651              :  */
     652              : static void
     653            6 : keys_cb (
     654              :   void *cls,
     655              :   const struct TALER_EXCHANGE_KeysResponse *kr,
     656              :   struct TALER_EXCHANGE_Keys *keys)
     657              : {
     658            6 :   char *const *args = cls;
     659              : 
     660            6 :   exchange = NULL;
     661            6 :   switch (kr->hr.http_status)
     662              :   {
     663            6 :   case MHD_HTTP_OK:
     664            6 :     if (NULL == kr->hr.reply)
     665              :     {
     666            0 :       GNUNET_break (0);
     667            0 :       test_shutdown ();
     668            0 :       global_ret = EXIT_FAILURE;
     669            0 :       return;
     670              :     }
     671            6 :     break;
     672            0 :   default:
     673            0 :     fprintf (stderr,
     674              :              "Failed to download keys: %s (HTTP status: %u/%u)\n",
     675            0 :              kr->hr.hint,
     676            0 :              kr->hr.http_status,
     677            0 :              (unsigned int) kr->hr.ec);
     678            0 :     test_shutdown ();
     679            0 :     global_ret = EXIT_FAILURE;
     680            0 :     return;
     681              :   }
     682            6 :   in = GNUNET_JSON_PACK (
     683              :     GNUNET_JSON_pack_string ("operation",
     684              :                              OP_INPUT_KEYS),
     685              :     GNUNET_JSON_pack_object_incref ("arguments",
     686              :                                     (json_t *) kr->hr.reply));
     687            6 :   if (NULL == args[0])
     688              :   {
     689            0 :     json_dumpf (in,
     690              :                 stdout,
     691              :                 JSON_INDENT (2));
     692            0 :     json_decref (in);
     693            0 :     in = NULL;
     694              :   }
     695            6 :   next (args);
     696            6 :   TALER_EXCHANGE_keys_decref (keys);
     697              : }
     698              : 
     699              : 
     700              : /**
     701              :  * Download future keys.
     702              :  *
     703              :  * @param args the array of command-line arguments to process next
     704              :  */
     705              : static void
     706            6 : do_download (char *const *args)
     707              : {
     708              :   char *exchange_url;
     709              : 
     710            6 :   if (GNUNET_OK !=
     711            6 :       GNUNET_CONFIGURATION_get_value_string (kcfg,
     712              :                                              "exchange",
     713              :                                              "BASE_URL",
     714              :                                              &exchange_url))
     715              :   {
     716            0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     717              :                                "exchange",
     718              :                                "BASE_URL");
     719            0 :     test_shutdown ();
     720            0 :     global_ret = EXIT_NOTCONFIGURED;
     721            0 :     return;
     722              :   }
     723            6 :   exchange = TALER_EXCHANGE_get_keys (ctx,
     724              :                                       exchange_url,
     725              :                                       NULL,
     726              :                                       &keys_cb,
     727              :                                       (void *) args);
     728            6 :   GNUNET_free (exchange_url);
     729              : }
     730              : 
     731              : 
     732              : /**
     733              :  * Output @a denomkeys for human consumption.
     734              :  *
     735              :  * @param denomkeys keys to output
     736              :  * @return #GNUNET_OK on success
     737              :  */
     738              : static enum GNUNET_GenericReturnValue
     739            0 : show_denomkeys (const json_t *denomkeys)
     740              : {
     741              :   size_t index;
     742              :   json_t *value;
     743              : 
     744            0 :   json_array_foreach (denomkeys, index, value) {
     745              :     struct TALER_DenominationGroup group;
     746              :     const json_t *denoms;
     747              :     const char *err_name;
     748              :     unsigned int err_line;
     749              :     struct GNUNET_JSON_Specification spec[] = {
     750            0 :       TALER_JSON_spec_denomination_group (NULL,
     751              :                                           currency,
     752              :                                           &group),
     753            0 :       GNUNET_JSON_spec_array_const ("denoms",
     754              :                                     &denoms),
     755            0 :       GNUNET_JSON_spec_end ()
     756              :     };
     757              :     size_t index2;
     758              :     json_t *value2;
     759              : 
     760            0 :     if (GNUNET_OK !=
     761            0 :         GNUNET_JSON_parse (value,
     762              :                            spec,
     763              :                            &err_name,
     764              :                            &err_line))
     765              :     {
     766            0 :       fprintf (stderr,
     767              :                "Invalid input for denomination key to 'show': %s#%u at %u (skipping)\n",
     768              :                err_name,
     769              :                err_line,
     770              :                (unsigned int) index);
     771            0 :       GNUNET_JSON_parse_free (spec);
     772            0 :       global_ret = EXIT_FAILURE;
     773            0 :       test_shutdown ();
     774            0 :       return GNUNET_SYSERR;
     775              :     }
     776            0 :     json_array_foreach (denoms, index2, value2) {
     777              :       struct GNUNET_TIME_Timestamp stamp_start;
     778              :       struct GNUNET_TIME_Timestamp stamp_expire_withdraw;
     779              :       struct GNUNET_TIME_Timestamp stamp_expire_deposit;
     780              :       struct GNUNET_TIME_Timestamp stamp_expire_legal;
     781              :       struct TALER_DenominationPublicKey denom_pub;
     782              :       struct TALER_MasterSignatureP master_sig;
     783              :       struct GNUNET_JSON_Specification ispec[] = {
     784            0 :         TALER_JSON_spec_denom_pub_cipher (NULL,
     785              :                                           group.cipher,
     786              :                                           &denom_pub),
     787            0 :         GNUNET_JSON_spec_timestamp ("stamp_start",
     788              :                                     &stamp_start),
     789            0 :         GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
     790              :                                     &stamp_expire_withdraw),
     791            0 :         GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
     792              :                                     &stamp_expire_deposit),
     793            0 :         GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
     794              :                                     &stamp_expire_legal),
     795            0 :         GNUNET_JSON_spec_fixed_auto ("master_sig",
     796              :                                      &master_sig),
     797            0 :         GNUNET_JSON_spec_end ()
     798              :       };
     799              :       struct GNUNET_TIME_Relative duration;
     800              :       struct TALER_DenominationHashP h_denom_pub;
     801              : 
     802            0 :       if (GNUNET_OK !=
     803            0 :           GNUNET_JSON_parse (value2,
     804              :                              ispec,
     805              :                              &err_name,
     806              :                              &err_line))
     807              :       {
     808            0 :         fprintf (stderr,
     809              :                  "Invalid input for denomination key to 'show': %s#%u at %u/%u (skipping)\n",
     810              :                  err_name,
     811              :                  err_line,
     812              :                  (unsigned int) index,
     813              :                  (unsigned int) index2);
     814            0 :         GNUNET_JSON_parse_free (spec);
     815            0 :         global_ret = EXIT_FAILURE;
     816            0 :         test_shutdown ();
     817            0 :         return GNUNET_SYSERR;
     818              :       }
     819            0 :       duration = GNUNET_TIME_absolute_get_difference (
     820              :         stamp_start.abs_time,
     821              :         stamp_expire_withdraw.abs_time);
     822            0 :       TALER_denom_pub_hash (&denom_pub,
     823              :                             &h_denom_pub);
     824            0 :       if (GNUNET_OK !=
     825            0 :           TALER_exchange_offline_denom_validity_verify (
     826              :             &h_denom_pub,
     827              :             stamp_start,
     828              :             stamp_expire_withdraw,
     829              :             stamp_expire_deposit,
     830              :             stamp_expire_legal,
     831              :             &group.value,
     832              :             &group.fees,
     833              :             &master_pub,
     834              :             &master_sig))
     835              :       {
     836            0 :         fprintf (stderr,
     837              :                  "Invalid master signature for key %s (aborting)\n",
     838              :                  TALER_B2S (&h_denom_pub));
     839            0 :         global_ret = EXIT_FAILURE;
     840            0 :         GNUNET_JSON_parse_free (ispec);
     841            0 :         GNUNET_JSON_parse_free (spec);
     842            0 :         test_shutdown ();
     843            0 :         return GNUNET_SYSERR;
     844              :       }
     845              : 
     846              :       {
     847              :         char *withdraw_fee_s;
     848              :         char *deposit_fee_s;
     849              :         char *refresh_fee_s;
     850              :         char *refund_fee_s;
     851              :         char *deposit_s;
     852              :         char *legal_s;
     853              : 
     854            0 :         withdraw_fee_s = TALER_amount_to_string (&group.fees.withdraw);
     855            0 :         deposit_fee_s = TALER_amount_to_string (&group.fees.deposit);
     856            0 :         refresh_fee_s = TALER_amount_to_string (&group.fees.refresh);
     857            0 :         refund_fee_s = TALER_amount_to_string (&group.fees.refund);
     858            0 :         deposit_s = GNUNET_strdup (
     859              :           GNUNET_TIME_timestamp2s (stamp_expire_deposit));
     860            0 :         legal_s = GNUNET_strdup (
     861              :           GNUNET_TIME_timestamp2s (stamp_expire_legal));
     862              : 
     863            0 :         printf (
     864              :           "DENOMINATION-KEY %s of value %s starting at %s "
     865              :           "(used for: %s, deposit until: %s legal end: %s) with fees %s/%s/%s/%s\n",
     866              :           TALER_B2S (&h_denom_pub),
     867              :           TALER_amount2s (&group.value),
     868              :           GNUNET_TIME_timestamp2s (stamp_start),
     869              :           GNUNET_TIME_relative2s (duration,
     870              :                                   false),
     871              :           deposit_s,
     872              :           legal_s,
     873              :           withdraw_fee_s,
     874              :           deposit_fee_s,
     875              :           refresh_fee_s,
     876              :           refund_fee_s);
     877            0 :         GNUNET_free (withdraw_fee_s);
     878            0 :         GNUNET_free (deposit_fee_s);
     879            0 :         GNUNET_free (refresh_fee_s);
     880            0 :         GNUNET_free (refund_fee_s);
     881            0 :         GNUNET_free (deposit_s);
     882            0 :         GNUNET_free (legal_s);
     883              :       }
     884            0 :       GNUNET_JSON_parse_free (ispec);
     885              :     }
     886            0 :     GNUNET_JSON_parse_free (spec);
     887              :   }
     888            0 :   return GNUNET_OK;
     889              : }
     890              : 
     891              : 
     892              : /**
     893              :  * Parse the '/keys' input for operation called @a command_name.
     894              :  *
     895              :  * @param command_name name of the command, for logging errors
     896              :  * @return NULL if the input is malformed
     897              :  */
     898              : static json_t *
     899            6 : parse_keys (const char *command_name)
     900              : {
     901              :   json_t *keys;
     902              :   const char *op_str;
     903              :   struct GNUNET_JSON_Specification spec[] = {
     904            6 :     GNUNET_JSON_spec_json ("arguments",
     905              :                            &keys),
     906            6 :     GNUNET_JSON_spec_string ("operation",
     907              :                              &op_str),
     908            6 :     GNUNET_JSON_spec_end ()
     909              :   };
     910              :   const char *err_name;
     911              :   unsigned int err_line;
     912              : 
     913            6 :   if (NULL == in)
     914              :   {
     915              :     json_error_t err;
     916              : 
     917            0 :     in = json_loadf (stdin,
     918              :                      JSON_REJECT_DUPLICATES,
     919              :                      &err);
     920            0 :     if (NULL == in)
     921              :     {
     922            0 :       fprintf (stderr,
     923              :                "Failed to read JSON input: %s at %d:%s (offset: %d)\n",
     924              :                err.text,
     925              :                err.line,
     926              :                err.source,
     927              :                err.position);
     928            0 :       global_ret = EXIT_FAILURE;
     929            0 :       test_shutdown ();
     930            0 :       return NULL;
     931              :     }
     932              :   }
     933            6 :   if (GNUNET_OK !=
     934            6 :       GNUNET_JSON_parse (in,
     935              :                          spec,
     936              :                          &err_name,
     937              :                          &err_line))
     938              :   {
     939            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     940              :                 "Invalid input to '%s': %s#%u (skipping)\n",
     941              :                 command_name,
     942              :                 err_name,
     943              :                 err_line);
     944            0 :     json_dumpf (in,
     945              :                 stderr,
     946              :                 JSON_INDENT (2));
     947            0 :     global_ret = EXIT_FAILURE;
     948            0 :     test_shutdown ();
     949            0 :     return NULL;
     950              :   }
     951            6 :   if (0 != strcmp (op_str,
     952              :                    OP_INPUT_KEYS))
     953              :   {
     954            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     955              :                 "Invalid input to '%s' : operation is `%s', expected `%s'\n",
     956              :                 command_name,
     957              :                 op_str,
     958              :                 OP_INPUT_KEYS);
     959            0 :     GNUNET_JSON_parse_free (spec);
     960            0 :     return NULL;
     961              :   }
     962            6 :   json_decref (in);
     963            6 :   in = NULL;
     964            6 :   return keys;
     965              : }
     966              : 
     967              : 
     968              : /**
     969              :  * Show exchange denomination keys.
     970              :  *
     971              :  * @param args the array of command-line arguments to process next
     972              :  */
     973              : static void
     974            0 : do_show (char *const *args)
     975              : {
     976              :   json_t *keys;
     977              :   const char *err_name;
     978              :   unsigned int err_line;
     979              :   const json_t *denomkeys;
     980              :   struct TALER_MasterPublicKeyP mpub;
     981              :   struct GNUNET_JSON_Specification spec[] = {
     982            0 :     GNUNET_JSON_spec_array_const ("denominations",
     983              :                                   &denomkeys),
     984            0 :     GNUNET_JSON_spec_fixed_auto ("master_public_key",
     985              :                                  &mpub),
     986            0 :     GNUNET_JSON_spec_end ()
     987              :   };
     988              : 
     989            0 :   keys = parse_keys ("show");
     990            0 :   if (NULL == keys)
     991              :   {
     992            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     993              :                 "Showing failed: no valid input\n");
     994            0 :     return;
     995              :   }
     996            0 :   if (GNUNET_OK !=
     997            0 :       GNUNET_JSON_parse (keys,
     998              :                          spec,
     999              :                          &err_name,
    1000              :                          &err_line))
    1001              :   {
    1002            0 :     fprintf (stderr,
    1003              :              "Invalid input to 'show': %s#%u (skipping)\n",
    1004              :              err_name,
    1005              :              err_line);
    1006            0 :     global_ret = EXIT_FAILURE;
    1007            0 :     test_shutdown ();
    1008            0 :     json_decref (keys);
    1009            0 :     return;
    1010              :   }
    1011            0 :   if (0 !=
    1012            0 :       GNUNET_memcmp (&mpub,
    1013              :                      &master_pub))
    1014              :   {
    1015            0 :     fprintf (stderr,
    1016              :              "Exchange master public key does not match key we have configured (aborting)\n");
    1017            0 :     global_ret = EXIT_FAILURE;
    1018            0 :     test_shutdown ();
    1019            0 :     json_decref (keys);
    1020            0 :     return;
    1021              :   }
    1022            0 :   if (GNUNET_OK !=
    1023            0 :       show_denomkeys (denomkeys))
    1024              :   {
    1025            0 :     global_ret = EXIT_FAILURE;
    1026            0 :     test_shutdown ();
    1027            0 :     json_decref (keys);
    1028            0 :     return;
    1029              :   }
    1030            0 :   json_decref (keys);
    1031              :   /* do NOT consume input if next argument is '-' */
    1032            0 :   if ( (NULL != args[0]) &&
    1033            0 :        (0 == strcmp ("-",
    1034              :                      args[0])) )
    1035              :   {
    1036            0 :     next (args + 1);
    1037            0 :     return;
    1038              :   }
    1039            0 :   next (args);
    1040              : }
    1041              : 
    1042              : 
    1043              : /**
    1044              :  * Sign @a denomkeys with offline key.
    1045              :  *
    1046              :  * @param denomkeys keys to output
    1047              :  * @return #GNUNET_OK on success
    1048              :  */
    1049              : static enum GNUNET_GenericReturnValue
    1050            6 : sign_denomkeys (const json_t *denomkeys)
    1051              : {
    1052              :   size_t group_idx;
    1053              :   json_t *value;
    1054              : 
    1055           66 :   json_array_foreach (denomkeys, group_idx, value) {
    1056           60 :     struct TALER_DenominationGroup group = { 0 };
    1057              :     const json_t *denom_keys_array;
    1058              :     const char *err_name;
    1059              :     unsigned int err_line;
    1060              :     struct GNUNET_JSON_Specification spec[] = {
    1061           60 :       TALER_JSON_spec_denomination_group (NULL,
    1062              :                                           currency,
    1063              :                                           &group),
    1064           60 :       GNUNET_JSON_spec_array_const ("denoms",
    1065              :                                     &denom_keys_array),
    1066           60 :       GNUNET_JSON_spec_end ()
    1067              :     };
    1068              :     size_t index;
    1069              :     json_t *denom_key_obj;
    1070              : 
    1071           60 :     if (GNUNET_OK !=
    1072           60 :         GNUNET_JSON_parse (value,
    1073              :                            spec,
    1074              :                            &err_name,
    1075              :                            &err_line))
    1076              :     {
    1077            0 :       fprintf (stderr,
    1078              :                "Invalid input for denomination key to 'sign': %s#%u at %u (skipping)\n",
    1079              :                err_name,
    1080              :                err_line,
    1081              :                (unsigned int) group_idx);
    1082            0 :       GNUNET_JSON_parse_free (spec);
    1083            0 :       global_ret = EXIT_FAILURE;
    1084            0 :       test_shutdown ();
    1085            0 :       return GNUNET_SYSERR;
    1086              :     }
    1087         3240 :     json_array_foreach (denom_keys_array, index, denom_key_obj) {
    1088              :       struct GNUNET_TIME_Timestamp stamp_start;
    1089              :       struct GNUNET_TIME_Timestamp stamp_expire_withdraw;
    1090              :       struct GNUNET_TIME_Timestamp stamp_expire_deposit;
    1091              :       struct GNUNET_TIME_Timestamp stamp_expire_legal;
    1092         3180 :       struct TALER_DenominationPublicKey denom_pub = {
    1093              :         .age_mask = group.age_mask
    1094              :       };
    1095              :       struct TALER_MasterSignatureP master_sig;
    1096              :       struct GNUNET_JSON_Specification ispec[] = {
    1097         3180 :         TALER_JSON_spec_denom_pub_cipher (NULL,
    1098              :                                           group.cipher,
    1099              :                                           &denom_pub),
    1100         3180 :         GNUNET_JSON_spec_timestamp ("stamp_start",
    1101              :                                     &stamp_start),
    1102         3180 :         GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
    1103              :                                     &stamp_expire_withdraw),
    1104         3180 :         GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
    1105              :                                     &stamp_expire_deposit),
    1106         3180 :         GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
    1107              :                                     &stamp_expire_legal),
    1108         3180 :         GNUNET_JSON_spec_fixed_auto ("master_sig",
    1109              :                                      &master_sig),
    1110         3180 :         GNUNET_JSON_spec_end ()
    1111              :       };
    1112              :       struct TALER_DenominationHashP h_denom_pub;
    1113              : 
    1114         3180 :       if (GNUNET_OK !=
    1115         3180 :           GNUNET_JSON_parse (denom_key_obj,
    1116              :                              ispec,
    1117              :                              &err_name,
    1118              :                              &err_line))
    1119              :       {
    1120            0 :         fprintf (stderr,
    1121              :                  "Invalid input for denomination key to 'show': %s#%u at %u/%u (skipping)\n",
    1122              :                  err_name,
    1123              :                  err_line,
    1124              :                  (unsigned int) group_idx,
    1125              :                  (unsigned int) index);
    1126            0 :         GNUNET_JSON_parse_free (spec);
    1127            0 :         global_ret = EXIT_FAILURE;
    1128            0 :         test_shutdown ();
    1129            0 :         return GNUNET_SYSERR;
    1130              :       }
    1131         3180 :       TALER_denom_pub_hash (&denom_pub,
    1132              :                             &h_denom_pub);
    1133         3180 :       if (GNUNET_OK !=
    1134         3180 :           TALER_exchange_offline_denom_validity_verify (
    1135              :             &h_denom_pub,
    1136              :             stamp_start,
    1137              :             stamp_expire_withdraw,
    1138              :             stamp_expire_deposit,
    1139              :             stamp_expire_legal,
    1140              :             &group.value,
    1141              :             &group.fees,
    1142              :             &master_pub,
    1143              :             &master_sig))
    1144              :       {
    1145            0 :         fprintf (stderr,
    1146              :                  "Invalid master signature for key %s (aborting)\n",
    1147              :                  TALER_B2S (&h_denom_pub));
    1148            0 :         global_ret = EXIT_FAILURE;
    1149            0 :         test_shutdown ();
    1150            0 :         return GNUNET_SYSERR;
    1151              :       }
    1152              : 
    1153              :       {
    1154              :         struct TALER_AuditorSignatureP auditor_sig;
    1155              : 
    1156         3180 :         TALER_auditor_denom_validity_sign (auditor_url,
    1157              :                                            &h_denom_pub,
    1158              :                                            &master_pub,
    1159              :                                            stamp_start,
    1160              :                                            stamp_expire_withdraw,
    1161              :                                            stamp_expire_deposit,
    1162              :                                            stamp_expire_legal,
    1163              :                                            &group.value,
    1164              :                                            &group.fees,
    1165              :                                            &auditor_priv,
    1166              :                                            &auditor_sig);
    1167         3180 :         output_operation (OP_SIGN_DENOMINATION,
    1168         3180 :                           GNUNET_JSON_PACK (
    1169              :                             GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1170              :                                                         &h_denom_pub),
    1171              :                             GNUNET_JSON_pack_data_auto ("auditor_sig",
    1172              :                                                         &auditor_sig)));
    1173              :       }
    1174         3180 :       GNUNET_JSON_parse_free (ispec);
    1175              :     }
    1176           60 :     GNUNET_JSON_parse_free (spec);
    1177              :   }
    1178            6 :   return GNUNET_OK;
    1179              : }
    1180              : 
    1181              : 
    1182              : /**
    1183              :  * Sign denomination keys.
    1184              :  *
    1185              :  * @param args the array of command-line arguments to process next
    1186              :  */
    1187              : static void
    1188            6 : do_sign (char *const *args)
    1189              : {
    1190              :   json_t *keys;
    1191              :   const char *err_name;
    1192              :   unsigned int err_line;
    1193              :   struct TALER_MasterPublicKeyP mpub;
    1194              :   const json_t *denomkeys;
    1195              :   struct GNUNET_JSON_Specification spec[] = {
    1196            6 :     GNUNET_JSON_spec_array_const ("denominations",
    1197              :                                   &denomkeys),
    1198            6 :     GNUNET_JSON_spec_fixed_auto ("master_public_key",
    1199              :                                  &mpub),
    1200            6 :     GNUNET_JSON_spec_end ()
    1201              :   };
    1202              : 
    1203            6 :   keys = parse_keys ("sign");
    1204            6 :   if (NULL == keys)
    1205              :   {
    1206            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1207              :                 "Signing failed: no valid input\n");
    1208            0 :     return;
    1209              :   }
    1210            6 :   if (GNUNET_OK !=
    1211            6 :       load_offline_key (GNUNET_NO))
    1212              :   {
    1213            0 :     json_decref (keys);
    1214            0 :     return;
    1215              :   }
    1216            6 :   if (GNUNET_OK !=
    1217            6 :       GNUNET_JSON_parse (keys,
    1218              :                          spec,
    1219              :                          &err_name,
    1220              :                          &err_line))
    1221              :   {
    1222            0 :     fprintf (stderr,
    1223              :              "Invalid input to 'sign': %s#%u (skipping)\n",
    1224              :              err_name,
    1225              :              err_line);
    1226            0 :     global_ret = EXIT_FAILURE;
    1227            0 :     test_shutdown ();
    1228            0 :     json_decref (keys);
    1229            0 :     return;
    1230              :   }
    1231            6 :   if (0 !=
    1232            6 :       GNUNET_memcmp (&mpub,
    1233              :                      &master_pub))
    1234              :   {
    1235            0 :     fprintf (stderr,
    1236              :              "Exchange master public key does not match key we have configured (aborting)\n");
    1237            0 :     global_ret = EXIT_FAILURE;
    1238            0 :     test_shutdown ();
    1239            0 :     json_decref (keys);
    1240            0 :     return;
    1241              :   }
    1242            6 :   if (NULL == out)
    1243              :   {
    1244            6 :     out = json_array ();
    1245            6 :     GNUNET_assert (NULL != out);
    1246              :   }
    1247            6 :   if (GNUNET_OK !=
    1248            6 :       sign_denomkeys (denomkeys))
    1249              :   {
    1250            0 :     global_ret = EXIT_FAILURE;
    1251            0 :     test_shutdown ();
    1252            0 :     json_decref (keys);
    1253            0 :     return;
    1254              :   }
    1255            6 :   json_decref (keys);
    1256            6 :   next (args);
    1257              : }
    1258              : 
    1259              : 
    1260              : /**
    1261              :  * Setup and output offline signing key.
    1262              :  *
    1263              :  * @param args the array of command-line arguments to process next
    1264              :  */
    1265              : static void
    1266            0 : do_setup (char *const *args)
    1267              : {
    1268            0 :   if (GNUNET_OK !=
    1269            0 :       load_offline_key (GNUNET_YES))
    1270              :   {
    1271            0 :     global_ret = EXIT_FAILURE;
    1272            0 :     return;
    1273              :   }
    1274            0 :   if (NULL != *args)
    1275              :   {
    1276            0 :     if (NULL == out)
    1277              :     {
    1278            0 :       out = json_array ();
    1279            0 :       GNUNET_assert (NULL != out);
    1280              :     }
    1281            0 :     output_operation (OP_SETUP,
    1282            0 :                       GNUNET_JSON_PACK (
    1283              :                         GNUNET_JSON_pack_data_auto ("auditor_pub",
    1284              :                                                     &auditor_pub)));
    1285              :   }
    1286              : 
    1287              :   else
    1288              :   {
    1289              :     char *pub_s;
    1290              : 
    1291            0 :     pub_s = GNUNET_STRINGS_data_to_string_alloc (&auditor_pub,
    1292              :                                                  sizeof (auditor_pub));
    1293            0 :     fprintf (stdout,
    1294              :              "%s\n",
    1295              :              pub_s);
    1296            0 :     GNUNET_free (pub_s);
    1297              :   }
    1298            0 :   if ( (NULL != *args) &&
    1299            0 :        (0 == strcmp (*args,
    1300              :                      "-")) )
    1301            0 :     args++;
    1302            0 :   next (args);
    1303              : }
    1304              : 
    1305              : 
    1306              : static void
    1307           18 : work (void *cls)
    1308              : {
    1309           18 :   char *const *args = cls;
    1310           18 :   struct SubCommand cmds[] = {
    1311              :     {
    1312              :       .name = "setup",
    1313              :       .help =
    1314              :         "setup auditor offline private key and show the public key",
    1315              :       .cb = &do_setup
    1316              :     },
    1317              :     {
    1318              :       .name = "download",
    1319              :       .help =
    1320              :         "obtain keys from exchange (to be performed online!)",
    1321              :       .cb = &do_download
    1322              :     },
    1323              :     {
    1324              :       .name = "show",
    1325              :       .help =
    1326              :         "display keys from exchange for human review (pass '-' as argument to disable consuming input)",
    1327              :       .cb = &do_show
    1328              :     },
    1329              :     {
    1330              :       .name = "sign",
    1331              :       .help =
    1332              :         "sing all denomination keys from the input",
    1333              :       .cb = &do_sign
    1334              :     },
    1335              :     {
    1336              :       .name = "upload",
    1337              :       .help =
    1338              :         "upload operation result to exchange (to be performed online!)",
    1339              :       .cb = &do_upload
    1340              :     },
    1341              :     /* list terminator */
    1342              :     {
    1343              :       .name = NULL,
    1344              :     }
    1345              :   };
    1346              :   (void) cls;
    1347              : 
    1348           18 :   nxt = NULL;
    1349           66 :   for (unsigned int i = 0; NULL != cmds[i].name; i++)
    1350              :   {
    1351           66 :     if (0 == strcasecmp (cmds[i].name,
    1352              :                          args[0]))
    1353              :     {
    1354           18 :       cmds[i].cb (&args[1]);
    1355           18 :       return;
    1356              :     }
    1357              :   }
    1358              : 
    1359            0 :   if (0 != strcasecmp ("help",
    1360              :                        args[0]))
    1361              :   {
    1362            0 :     fprintf (stderr,
    1363              :              "Unexpected command `%s'\n",
    1364              :              args[0]);
    1365            0 :     global_ret = EXIT_INVALIDARGUMENT;
    1366              :   }
    1367            0 :   fprintf (stderr,
    1368              :            "Supported subcommands:\n");
    1369            0 :   for (unsigned int i = 0; NULL != cmds[i].name; i++)
    1370              :   {
    1371            0 :     fprintf (stderr,
    1372              :              "\t%s - %s\n",
    1373              :              cmds[i].name,
    1374              :              cmds[i].help);
    1375              :   }
    1376              : }
    1377              : 
    1378              : 
    1379              : /**
    1380              :  * Main function that will be run.
    1381              :  *
    1382              :  * @param cls closure
    1383              :  * @param args remaining command-line arguments
    1384              :  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
    1385              :  * @param cfg configuration
    1386              :  */
    1387              : static void
    1388            6 : run (void *cls,
    1389              :      char *const *args,
    1390              :      const char *cfgfile,
    1391              :      const struct GNUNET_CONFIGURATION_Handle *cfg)
    1392              : {
    1393              :   (void) cls;
    1394              :   (void) cfgfile;
    1395            6 :   kcfg = cfg;
    1396            6 :   if (GNUNET_OK !=
    1397            6 :       TALER_config_get_currency (kcfg,
    1398              :                                  "exchange",
    1399              :                                  &currency))
    1400              :   {
    1401            0 :     global_ret = EXIT_NOTCONFIGURED;
    1402            0 :     return;
    1403              :   }
    1404            6 :   if (GNUNET_OK !=
    1405            6 :       GNUNET_CONFIGURATION_get_value_string (kcfg,
    1406              :                                              "auditor",
    1407              :                                              "BASE_URL",
    1408              :                                              &auditor_url))
    1409              :   {
    1410            0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1411              :                                "auditor",
    1412              :                                "BASE_URL");
    1413            0 :     global_ret = EXIT_NOTCONFIGURED;
    1414            0 :     return;
    1415              :   }
    1416              :   {
    1417              :     char *master_public_key_str;
    1418              : 
    1419            6 :     if (GNUNET_OK !=
    1420            6 :         GNUNET_CONFIGURATION_get_value_string (cfg,
    1421              :                                                "exchange",
    1422              :                                                "MASTER_PUBLIC_KEY",
    1423              :                                                &master_public_key_str))
    1424              :     {
    1425            0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1426              :                                  "exchange",
    1427              :                                  "MASTER_PUBLIC_KEY");
    1428            0 :       global_ret = EXIT_NOTCONFIGURED;
    1429            0 :       return;
    1430              :     }
    1431            6 :     if (GNUNET_OK !=
    1432            6 :         GNUNET_CRYPTO_eddsa_public_key_from_string (
    1433              :           master_public_key_str,
    1434              :           strlen (master_public_key_str),
    1435              :           &master_pub.eddsa_pub))
    1436              :     {
    1437            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1438              :                   "Invalid master public key given in exchange configuration.");
    1439            0 :       GNUNET_free (master_public_key_str);
    1440            0 :       global_ret = EXIT_NOTCONFIGURED;
    1441            0 :       return;
    1442              :     }
    1443            6 :     GNUNET_free (master_public_key_str);
    1444              :   }
    1445            6 :   ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
    1446              :                           &rc);
    1447            6 :   rc = GNUNET_CURL_gnunet_rc_create (ctx);
    1448            6 :   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
    1449              :                                  NULL);
    1450            6 :   next (args);
    1451              : }
    1452              : 
    1453              : 
    1454              : /**
    1455              :  * The main function of the taler-auditor-offline tool.  This tool is used to
    1456              :  * sign denomination keys with the auditor's key.  It uses the long-term
    1457              :  * offline private key of the auditor and generates signatures with it. It
    1458              :  * also supports online operations with the exchange to download its input
    1459              :  * data and to upload its results. Those online operations should be performed
    1460              :  * on another machine in production!
    1461              :  *
    1462              :  * @param argc number of arguments from the command line
    1463              :  * @param argv command line arguments
    1464              :  * @return 0 ok, 1 on error
    1465              :  */
    1466              : int
    1467            6 : main (int argc,
    1468              :       char *const *argv)
    1469              : {
    1470            6 :   struct GNUNET_GETOPT_CommandLineOption options[] = {
    1471              :     GNUNET_GETOPT_OPTION_END
    1472              :   };
    1473              :   enum GNUNET_GenericReturnValue ret;
    1474              : 
    1475            6 :   ret = GNUNET_PROGRAM_run (
    1476              :     TALER_AUDITOR_project_data (),
    1477              :     argc, argv,
    1478              :     "taler-auditor-offline",
    1479              :     gettext_noop ("Operations for offline signing for a Taler exchange"),
    1480              :     options,
    1481              :     &run, NULL);
    1482            6 :   if (GNUNET_SYSERR == ret)
    1483            0 :     return EXIT_INVALIDARGUMENT;
    1484            6 :   if (GNUNET_NO == ret)
    1485            0 :     return EXIT_SUCCESS;
    1486            6 :   return global_ret;
    1487              : }
    1488              : 
    1489              : 
    1490              : /* end of taler-auditor-offline.c */
        

Generated by: LCOV version 2.0-1