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

          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 <platform.h>
      22             : #include <gnunet/gnunet_json_lib.h>
      23             : #include <microhttpd.h>
      24             : #include "taler_json_lib.h"
      25             : #include "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           8 : do_shutdown (void *cls)
     188             : {
     189             :   (void) cls;
     190             : 
     191             :   {
     192             :     struct DenominationAddRequest *dar;
     193             : 
     194           8 :     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           8 :   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           8 :   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           8 :   if (NULL != exchange)
     222             :   {
     223           0 :     TALER_EXCHANGE_get_keys_cancel (exchange);
     224           0 :     exchange = NULL;
     225             :   }
     226           8 :   if (NULL != nxt)
     227             :   {
     228           0 :     GNUNET_SCHEDULER_cancel (nxt);
     229           0 :     nxt = NULL;
     230             :   }
     231           8 :   if (NULL != ctx)
     232             :   {
     233           8 :     GNUNET_CURL_fini (ctx);
     234           8 :     ctx = NULL;
     235             :   }
     236           8 :   if (NULL != rc)
     237             :   {
     238           8 :     GNUNET_CURL_gnunet_rc_destroy (rc);
     239           8 :     rc = NULL;
     240             :   }
     241           8 : }
     242             : 
     243             : 
     244             : /**
     245             :  * Test if we should shut down because all tasks are done.
     246             :  */
     247             : static void
     248        4036 : test_shutdown (void)
     249             : {
     250        4036 :   if ( (NULL == dar_head) &&
     251           8 :        (NULL == exchange) &&
     252           8 :        (NULL == nxt) )
     253           8 :     GNUNET_SCHEDULER_shutdown ();
     254        4036 : }
     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          24 : next (char *const *args)
     274             : {
     275          24 :   GNUNET_assert (NULL == nxt);
     276          24 :   if (NULL == args[0])
     277             :   {
     278           0 :     test_shutdown ();
     279           0 :     return;
     280             :   }
     281          24 :   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        4028 : output_operation (const char *op_name,
     294             :                   json_t *op_value)
     295             : {
     296             :   json_t *action;
     297             : 
     298        4028 :   GNUNET_assert (NULL != out);
     299        4028 :   action = GNUNET_JSON_PACK (
     300             :     GNUNET_JSON_pack_string ("operation",
     301             :                              op_name),
     302             :     GNUNET_JSON_pack_object_steal ("arguments",
     303             :                                    op_value));
     304        4028 :   GNUNET_break (0 ==
     305             :                 json_array_append_new (out,
     306             :                                        action));
     307        4028 : }
     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           8 : load_offline_key (int do_create)
     342             : {
     343             :   static bool done;
     344             :   int ret;
     345             :   char *fn;
     346             : 
     347           8 :   if (done)
     348           0 :     return GNUNET_OK;
     349           8 :   if (GNUNET_OK !=
     350           8 :       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           8 :   ret = GNUNET_CRYPTO_eddsa_key_from_file (fn,
     362             :                                            do_create,
     363             :                                            &auditor_priv.eddsa_priv);
     364           8 :   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           8 :   GNUNET_free (fn);
     380           8 :   GNUNET_CRYPTO_eddsa_key_get_public (&auditor_priv.eddsa_priv,
     381             :                                       &auditor_pub.eddsa_pub);
     382           8 :   done = true;
     383           8 :   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        4028 : denomination_add_cb (
     396             :   void *cls,
     397             :   const struct TALER_EXCHANGE_AuditorAddDenominationResponse *adr)
     398             : {
     399        4028 :   struct DenominationAddRequest *dar = cls;
     400        4028 :   const struct TALER_EXCHANGE_HttpResponse *hr = &adr->hr;
     401             : 
     402        4028 :   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        4028 :   GNUNET_CONTAINER_DLL_remove (dar_head,
     415             :                                dar_tail,
     416             :                                dar);
     417        4028 :   GNUNET_free (dar);
     418        4028 :   test_shutdown ();
     419        4028 : }
     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        4028 : 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        4028 :     GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
     441             :                                  &h_denom_pub),
     442        4028 :     GNUNET_JSON_spec_fixed_auto ("auditor_sig",
     443             :                                  &auditor_sig),
     444        4028 :     GNUNET_JSON_spec_end ()
     445             :   };
     446             : 
     447        4028 :   if (GNUNET_OK !=
     448        4028 :       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        4028 :   dar = GNUNET_new (struct DenominationAddRequest);
     463        4028 :   dar->idx = idx;
     464        4028 :   dar->h =
     465        4028 :     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        4028 :   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           8 : trigger_upload (const char *exchange_url)
     485             : {
     486           8 :   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        4036 :   json_array_foreach (out, index, obj) {
     500        4028 :     bool found = false;
     501             :     const char *key;
     502             :     const json_t *value;
     503             : 
     504        4028 :     key = json_string_value (json_object_get (obj, "operation"));
     505        4028 :     value = json_object_get (obj, "arguments");
     506        4028 :     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        4028 :     for (unsigned int i = 0; NULL != uhs[i].key; i++)
     516             :     {
     517        4028 :       if (0 == strcasecmp (key,
     518             :                            uhs[i].key))
     519             :       {
     520        4028 :         found = true;
     521        4028 :         uhs[i].cb (exchange_url,
     522             :                    index,
     523             :                    value);
     524        4028 :         break;
     525             :       }
     526             :     }
     527        4028 :     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           8 :   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           8 : do_upload (char *const *args)
     549             : {
     550             :   char *exchange_url;
     551             : 
     552             :   (void) args;
     553           8 :   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           8 :   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           8 :   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           8 :   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           8 :   if (GNUNET_OK !=
     625           8 :       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           8 :   trigger_upload (exchange_url);
     638           8 :   json_decref (out);
     639           8 :   out = NULL;
     640           8 :   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           8 : keys_cb (
     654             :   void *cls,
     655             :   const struct TALER_EXCHANGE_KeysResponse *kr,
     656             :   struct TALER_EXCHANGE_Keys *keys)
     657             : {
     658           8 :   char *const *args = cls;
     659             : 
     660           8 :   exchange = NULL;
     661           8 :   switch (kr->hr.http_status)
     662             :   {
     663           8 :   case MHD_HTTP_OK:
     664           8 :     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           8 :     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           8 :   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           8 :   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           8 :   next (args);
     696           8 :   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           8 : do_download (char *const *args)
     707             : {
     708             :   char *exchange_url;
     709             : 
     710           8 :   if (GNUNET_OK !=
     711           8 :       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           8 :   exchange = TALER_EXCHANGE_get_keys (ctx,
     724             :                                       exchange_url,
     725             :                                       NULL,
     726             :                                       &keys_cb,
     727             :                                       (void *) args);
     728           8 :   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           8 : parse_keys (const char *command_name)
     900             : {
     901             :   json_t *keys;
     902             :   const char *op_str;
     903             :   struct GNUNET_JSON_Specification spec[] = {
     904           8 :     GNUNET_JSON_spec_json ("arguments",
     905             :                            &keys),
     906           8 :     GNUNET_JSON_spec_string ("operation",
     907             :                              &op_str),
     908           8 :     GNUNET_JSON_spec_end ()
     909             :   };
     910             :   const char *err_name;
     911             :   unsigned int err_line;
     912             : 
     913           8 :   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           8 :   if (GNUNET_OK !=
     934           8 :       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           8 :   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           8 :   json_decref (in);
     963           8 :   in = NULL;
     964           8 :   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           8 : sign_denomkeys (const json_t *denomkeys)
    1051             : {
    1052             :   size_t group_idx;
    1053             :   json_t *value;
    1054             : 
    1055          84 :   json_array_foreach (denomkeys, group_idx, value) {
    1056          76 :     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          76 :       TALER_JSON_spec_denomination_group (NULL,
    1062             :                                           currency,
    1063             :                                           &group),
    1064          76 :       GNUNET_JSON_spec_array_const ("denoms",
    1065             :                                     &denom_keys_array),
    1066          76 :       GNUNET_JSON_spec_end ()
    1067             :     };
    1068             :     size_t index;
    1069             :     json_t *denom_key_obj;
    1070             : 
    1071          76 :     if (GNUNET_OK !=
    1072          76 :         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        4104 :     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        4028 :       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        4028 :         TALER_JSON_spec_denom_pub_cipher (NULL,
    1098             :                                           group.cipher,
    1099             :                                           &denom_pub),
    1100        4028 :         GNUNET_JSON_spec_timestamp ("stamp_start",
    1101             :                                     &stamp_start),
    1102        4028 :         GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
    1103             :                                     &stamp_expire_withdraw),
    1104        4028 :         GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
    1105             :                                     &stamp_expire_deposit),
    1106        4028 :         GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
    1107             :                                     &stamp_expire_legal),
    1108        4028 :         GNUNET_JSON_spec_fixed_auto ("master_sig",
    1109             :                                      &master_sig),
    1110        4028 :         GNUNET_JSON_spec_end ()
    1111             :       };
    1112             :       struct TALER_DenominationHashP h_denom_pub;
    1113             : 
    1114        4028 :       if (GNUNET_OK !=
    1115        4028 :           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        4028 :       TALER_denom_pub_hash (&denom_pub,
    1132             :                             &h_denom_pub);
    1133        4028 :       if (GNUNET_OK !=
    1134        4028 :           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        4028 :         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        4028 :         output_operation (OP_SIGN_DENOMINATION,
    1168        4028 :                           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        4028 :       GNUNET_JSON_parse_free (ispec);
    1175             :     }
    1176          76 :     GNUNET_JSON_parse_free (spec);
    1177             :   }
    1178           8 :   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           8 : 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           8 :     GNUNET_JSON_spec_array_const ("denominations",
    1197             :                                   &denomkeys),
    1198           8 :     GNUNET_JSON_spec_fixed_auto ("master_public_key",
    1199             :                                  &mpub),
    1200           8 :     GNUNET_JSON_spec_end ()
    1201             :   };
    1202             : 
    1203           8 :   keys = parse_keys ("sign");
    1204           8 :   if (NULL == keys)
    1205             :   {
    1206           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1207             :                 "Signing failed: no valid input\n");
    1208           0 :     return;
    1209             :   }
    1210           8 :   if (GNUNET_OK !=
    1211           8 :       load_offline_key (GNUNET_NO))
    1212             :   {
    1213           0 :     json_decref (keys);
    1214           0 :     return;
    1215             :   }
    1216           8 :   if (GNUNET_OK !=
    1217           8 :       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           8 :   if (0 !=
    1232           8 :       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           8 :   if (NULL == out)
    1243             :   {
    1244           8 :     out = json_array ();
    1245           8 :     GNUNET_assert (NULL != out);
    1246             :   }
    1247           8 :   if (GNUNET_OK !=
    1248           8 :       sign_denomkeys (denomkeys))
    1249             :   {
    1250           0 :     global_ret = EXIT_FAILURE;
    1251           0 :     test_shutdown ();
    1252           0 :     json_decref (keys);
    1253           0 :     return;
    1254             :   }
    1255           8 :   json_decref (keys);
    1256           8 :   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          24 : work (void *cls)
    1308             : {
    1309          24 :   char *const *args = cls;
    1310          24 :   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          24 :   nxt = NULL;
    1349          88 :   for (unsigned int i = 0; NULL != cmds[i].name; i++)
    1350             :   {
    1351          88 :     if (0 == strcasecmp (cmds[i].name,
    1352             :                          args[0]))
    1353             :     {
    1354          24 :       cmds[i].cb (&args[1]);
    1355          24 :       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           8 : 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           8 :   kcfg = cfg;
    1396           8 :   if (GNUNET_OK !=
    1397           8 :       TALER_config_get_currency (kcfg,
    1398             :                                  "exchange",
    1399             :                                  &currency))
    1400             :   {
    1401           0 :     global_ret = EXIT_NOTCONFIGURED;
    1402           0 :     return;
    1403             :   }
    1404           8 :   if (GNUNET_OK !=
    1405           8 :       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           8 :     if (GNUNET_OK !=
    1420           8 :         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           8 :     if (GNUNET_OK !=
    1432           8 :         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           8 :     GNUNET_free (master_public_key_str);
    1444             :   }
    1445           8 :   ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
    1446             :                           &rc);
    1447           8 :   rc = GNUNET_CURL_gnunet_rc_create (ctx);
    1448           8 :   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
    1449             :                                  NULL);
    1450           8 :   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           8 : main (int argc,
    1468             :       char *const *argv)
    1469             : {
    1470           8 :   struct GNUNET_GETOPT_CommandLineOption options[] = {
    1471             :     GNUNET_GETOPT_OPTION_END
    1472             :   };
    1473             :   enum GNUNET_GenericReturnValue ret;
    1474             : 
    1475           8 :   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           8 :   if (GNUNET_SYSERR == ret)
    1483           0 :     return EXIT_INVALIDARGUMENT;
    1484           8 :   if (GNUNET_NO == ret)
    1485           0 :     return EXIT_SUCCESS;
    1486           8 :   return global_ret;
    1487             : }
    1488             : 
    1489             : 
    1490             : /* end of taler-auditor-offline.c */

Generated by: LCOV version 1.16