LCOV - code coverage report
Current view: top level - exchange-tools - taler-exchange-offline.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 339 980 34.6 %
Date: 2021-08-30 06:43:37 Functions: 25 44 56.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2020, 2021 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-exchange-offline.c
      18             :  * @brief Support for operations involving the exchange's offline master key.
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include <platform.h>
      22             : #include <gnunet/gnunet_json_lib.h>
      23             : #include "taler_json_lib.h"
      24             : #include "taler_exchange_service.h"
      25             : 
      26             : /**
      27             :  * Name of the input for the 'sign' and 'show' operation.
      28             :  * The last component --by convention-- identifies the protocol version
      29             :  * and should be incremented whenever the JSON format of the 'argument' changes.
      30             :  */
      31             : #define OP_INPUT_KEYS "exchange-input-keys-0"
      32             : 
      33             : /**
      34             :  * Name of the operation to 'disable auditor'
      35             :  * The last component --by convention-- identifies the protocol version
      36             :  * and should be incremented whenever the JSON format of the 'argument' changes.
      37             :  */
      38             : #define OP_DISABLE_AUDITOR "exchange-disable-auditor-0"
      39             : 
      40             : /**
      41             :  * Name of the operation to 'enable auditor'
      42             :  * The last component --by convention-- identifies the protocol version
      43             :  * and should be incremented whenever the JSON format of the 'argument' changes.
      44             :  */
      45             : #define OP_ENABLE_AUDITOR "exchange-enable-auditor-0"
      46             : 
      47             : /**
      48             :  * Name of the operation to 'enable wire'
      49             :  * The last component --by convention-- identifies the protocol version
      50             :  * and should be incremented whenever the JSON format of the 'argument' changes.
      51             :  */
      52             : #define OP_ENABLE_WIRE "exchange-enable-wire-0"
      53             : 
      54             : /**
      55             :  * Name of the operation to 'disable wire'
      56             :  * The last component --by convention-- identifies the protocol version
      57             :  * and should be incremented whenever the JSON format of the 'argument' changes.
      58             :  */
      59             : #define OP_DISABLE_WIRE "exchange-disable-wire-0"
      60             : 
      61             : /**
      62             :  * Name of the operation to set a 'wire-fee'
      63             :  * The last component --by convention-- identifies the protocol version
      64             :  * and should be incremented whenever the JSON format of the 'argument' changes.
      65             :  */
      66             : #define OP_SET_WIRE_FEE "exchange-set-wire-fee-0"
      67             : 
      68             : /**
      69             :  * Name of the operation to 'upload' key signatures
      70             :  * The last component --by convention-- identifies the protocol version
      71             :  * and should be incremented whenever the JSON format of the 'argument' changes.
      72             :  */
      73             : #define OP_UPLOAD_SIGS "exchange-upload-sigs-0"
      74             : 
      75             : /**
      76             :  * Name of the operation to 'revoke-denomination' key
      77             :  * The last component --by convention-- identifies the protocol version
      78             :  * and should be incremented whenever the JSON format of the 'argument' changes.
      79             :  */
      80             : #define OP_REVOKE_DENOMINATION "exchange-revoke-denomination-0"
      81             : 
      82             : /**
      83             :  * Name of the operation to 'revoke-signkey'
      84             :  * The last component --by convention-- identifies the protocol version
      85             :  * and should be incremented whenever the JSON format of the 'argument' changes.
      86             :  */
      87             : #define OP_REVOKE_SIGNKEY "exchange-revoke-signkey-0"
      88             : 
      89             : /**
      90             :  * Show the offline signing key.
      91             :  * The last component --by convention-- identifies the protocol version
      92             :  * and should be incremented whenever the JSON format of the 'argument' changes.
      93             :  */
      94             : #define OP_SETUP "exchange-setup-0"
      95             : 
      96             : 
      97             : /**
      98             :  * Our private key, initialized in #load_offline_key().
      99             :  */
     100             : static struct TALER_MasterPrivateKeyP master_priv;
     101             : 
     102             : /**
     103             :  * Our private key, initialized in #load_offline_key().
     104             :  */
     105             : static struct TALER_MasterPublicKeyP master_pub;
     106             : 
     107             : /**
     108             :  * Our context for making HTTP requests.
     109             :  */
     110             : static struct GNUNET_CURL_Context *ctx;
     111             : 
     112             : /**
     113             :  * Reschedule context for #ctx.
     114             :  */
     115             : static struct GNUNET_CURL_RescheduleContext *rc;
     116             : 
     117             : /**
     118             :  * Handle to the exchange's configuration
     119             :  */
     120             : static const struct GNUNET_CONFIGURATION_Handle *kcfg;
     121             : 
     122             : /**
     123             :  * Return value from main().
     124             :  */
     125             : static int global_ret;
     126             : 
     127             : /**
     128             :  * Input to consume.
     129             :  */
     130             : static json_t *in;
     131             : 
     132             : /**
     133             :  * Array of actions to perform.
     134             :  */
     135             : static json_t *out;
     136             : 
     137             : /**
     138             :  * Currency we have configured.
     139             :  */
     140             : static char *currency;
     141             : 
     142             : /**
     143             :  * URL of the exchange we are interacting with
     144             :  * as per our configuration.
     145             :  */
     146             : static char *CFG_exchange_url;
     147             : 
     148             : 
     149             : /**
     150             :  * A subcommand supported by this program.
     151             :  */
     152             : struct SubCommand
     153             : {
     154             :   /**
     155             :    * Name of the command.
     156             :    */
     157             :   const char *name;
     158             : 
     159             :   /**
     160             :    * Help text for the command.
     161             :    */
     162             :   const char *help;
     163             : 
     164             :   /**
     165             :    * Function implementing the command.
     166             :    *
     167             :    * @param args subsequent command line arguments (char **)
     168             :    */
     169             :   void (*cb)(char *const *args);
     170             : };
     171             : 
     172             : 
     173             : /**
     174             :  * Data structure for denomination revocation requests.
     175             :  */
     176             : struct DenomRevocationRequest
     177             : {
     178             : 
     179             :   /**
     180             :    * Kept in a DLL.
     181             :    */
     182             :   struct DenomRevocationRequest *next;
     183             : 
     184             :   /**
     185             :    * Kept in a DLL.
     186             :    */
     187             :   struct DenomRevocationRequest *prev;
     188             : 
     189             :   /**
     190             :    * Operation handle.
     191             :    */
     192             :   struct TALER_EXCHANGE_ManagementRevokeDenominationKeyHandle *h;
     193             : 
     194             :   /**
     195             :    * Array index of the associated command.
     196             :    */
     197             :   size_t idx;
     198             : };
     199             : 
     200             : 
     201             : /**
     202             :  * Data structure for signkey revocation requests.
     203             :  */
     204             : struct SignkeyRevocationRequest
     205             : {
     206             : 
     207             :   /**
     208             :    * Kept in a DLL.
     209             :    */
     210             :   struct SignkeyRevocationRequest *next;
     211             : 
     212             :   /**
     213             :    * Kept in a DLL.
     214             :    */
     215             :   struct SignkeyRevocationRequest *prev;
     216             : 
     217             :   /**
     218             :    * Operation handle.
     219             :    */
     220             :   struct TALER_EXCHANGE_ManagementRevokeSigningKeyHandle *h;
     221             : 
     222             :   /**
     223             :    * Array index of the associated command.
     224             :    */
     225             :   size_t idx;
     226             : };
     227             : 
     228             : 
     229             : /**
     230             :  * Data structure for auditor add requests.
     231             :  */
     232             : struct AuditorAddRequest
     233             : {
     234             : 
     235             :   /**
     236             :    * Kept in a DLL.
     237             :    */
     238             :   struct AuditorAddRequest *next;
     239             : 
     240             :   /**
     241             :    * Kept in a DLL.
     242             :    */
     243             :   struct AuditorAddRequest *prev;
     244             : 
     245             :   /**
     246             :    * Operation handle.
     247             :    */
     248             :   struct TALER_EXCHANGE_ManagementAuditorEnableHandle *h;
     249             : 
     250             :   /**
     251             :    * Array index of the associated command.
     252             :    */
     253             :   size_t idx;
     254             : };
     255             : 
     256             : 
     257             : /**
     258             :  * Data structure for auditor del requests.
     259             :  */
     260             : struct AuditorDelRequest
     261             : {
     262             : 
     263             :   /**
     264             :    * Kept in a DLL.
     265             :    */
     266             :   struct AuditorDelRequest *next;
     267             : 
     268             :   /**
     269             :    * Kept in a DLL.
     270             :    */
     271             :   struct AuditorDelRequest *prev;
     272             : 
     273             :   /**
     274             :    * Operation handle.
     275             :    */
     276             :   struct TALER_EXCHANGE_ManagementAuditorDisableHandle *h;
     277             : 
     278             :   /**
     279             :    * Array index of the associated command.
     280             :    */
     281             :   size_t idx;
     282             : };
     283             : 
     284             : 
     285             : /**
     286             :  * Data structure for wire add requests.
     287             :  */
     288             : struct WireAddRequest
     289             : {
     290             : 
     291             :   /**
     292             :    * Kept in a DLL.
     293             :    */
     294             :   struct WireAddRequest *next;
     295             : 
     296             :   /**
     297             :    * Kept in a DLL.
     298             :    */
     299             :   struct WireAddRequest *prev;
     300             : 
     301             :   /**
     302             :    * Operation handle.
     303             :    */
     304             :   struct TALER_EXCHANGE_ManagementWireEnableHandle *h;
     305             : 
     306             :   /**
     307             :    * Array index of the associated command.
     308             :    */
     309             :   size_t idx;
     310             : };
     311             : 
     312             : 
     313             : /**
     314             :  * Data structure for wire del requests.
     315             :  */
     316             : struct WireDelRequest
     317             : {
     318             : 
     319             :   /**
     320             :    * Kept in a DLL.
     321             :    */
     322             :   struct WireDelRequest *next;
     323             : 
     324             :   /**
     325             :    * Kept in a DLL.
     326             :    */
     327             :   struct WireDelRequest *prev;
     328             : 
     329             :   /**
     330             :    * Operation handle.
     331             :    */
     332             :   struct TALER_EXCHANGE_ManagementWireDisableHandle *h;
     333             : 
     334             :   /**
     335             :    * Array index of the associated command.
     336             :    */
     337             :   size_t idx;
     338             : };
     339             : 
     340             : 
     341             : /**
     342             :  * Data structure for announcing wire fees.
     343             :  */
     344             : struct WireFeeRequest
     345             : {
     346             : 
     347             :   /**
     348             :    * Kept in a DLL.
     349             :    */
     350             :   struct WireFeeRequest *next;
     351             : 
     352             :   /**
     353             :    * Kept in a DLL.
     354             :    */
     355             :   struct WireFeeRequest *prev;
     356             : 
     357             :   /**
     358             :    * Operation handle.
     359             :    */
     360             :   struct TALER_EXCHANGE_ManagementSetWireFeeHandle *h;
     361             : 
     362             :   /**
     363             :    * Array index of the associated command.
     364             :    */
     365             :   size_t idx;
     366             : };
     367             : 
     368             : 
     369             : /**
     370             :  * Ongoing /keys request.
     371             :  */
     372             : struct UploadKeysRequest
     373             : {
     374             :   /**
     375             :    * Kept in a DLL.
     376             :    */
     377             :   struct UploadKeysRequest *next;
     378             : 
     379             :   /**
     380             :    * Kept in a DLL.
     381             :    */
     382             :   struct UploadKeysRequest *prev;
     383             : 
     384             :   /**
     385             :    * Operation handle.
     386             :    */
     387             :   struct TALER_EXCHANGE_ManagementPostKeysHandle *h;
     388             : 
     389             :   /**
     390             :    * Operation index.
     391             :    */
     392             :   size_t idx;
     393             : };
     394             : 
     395             : 
     396             : /**
     397             :  * Next work item to perform.
     398             :  */
     399             : static struct GNUNET_SCHEDULER_Task *nxt;
     400             : 
     401             : /**
     402             :  * Handle for #do_download.
     403             :  */
     404             : static struct TALER_EXCHANGE_ManagementGetKeysHandle *mgkh;
     405             : 
     406             : /**
     407             :  * Active denomiantion revocation requests.
     408             :  */
     409             : static struct DenomRevocationRequest *drr_head;
     410             : 
     411             : /**
     412             :  * Active denomiantion revocation requests.
     413             :  */
     414             : static struct DenomRevocationRequest *drr_tail;
     415             : 
     416             : /**
     417             :  * Active signkey revocation requests.
     418             :  */
     419             : static struct SignkeyRevocationRequest *srr_head;
     420             : 
     421             : /**
     422             :  * Active signkey revocation requests.
     423             :  */
     424             : static struct SignkeyRevocationRequest *srr_tail;
     425             : 
     426             : /**
     427             :  * Active auditor add requests.
     428             :  */
     429             : static struct AuditorAddRequest *aar_head;
     430             : 
     431             : /**
     432             :  * Active auditor add requests.
     433             :  */
     434             : static struct AuditorAddRequest *aar_tail;
     435             : 
     436             : /**
     437             :  * Active auditor del requests.
     438             :  */
     439             : static struct AuditorDelRequest *adr_head;
     440             : 
     441             : /**
     442             :  * Active auditor del requests.
     443             :  */
     444             : static struct AuditorDelRequest *adr_tail;
     445             : 
     446             : /**
     447             :  * Active wire add requests.
     448             :  */
     449             : static struct WireAddRequest *war_head;
     450             : 
     451             : /**
     452             :  * Active wire add requests.
     453             :  */
     454             : static struct WireAddRequest *war_tail;
     455             : 
     456             : /**
     457             :  * Active wire del requests.
     458             :  */
     459             : static struct WireDelRequest *wdr_head;
     460             : 
     461             : /**
     462             :  * Active wire del requests.
     463             :  */
     464             : static struct WireDelRequest *wdr_tail;
     465             : 
     466             : /**
     467             :  * Active wire fee requests.
     468             :  */
     469             : static struct WireFeeRequest *wfr_head;
     470             : 
     471             : /**
     472             :  * Active wire fee requests.
     473             :  */
     474             : static struct WireFeeRequest *wfr_tail;
     475             : 
     476             : /**
     477             :  * Active keys upload requests.
     478             :  */
     479             : static struct UploadKeysRequest *ukr_head;
     480             : 
     481             : /**
     482             :  * Active keys upload requests.
     483             :  */
     484             : static struct UploadKeysRequest *ukr_tail;
     485             : 
     486             : 
     487             : /**
     488             :  * Shutdown task. Invoked when the application is being terminated.
     489             :  *
     490             :  * @param cls NULL
     491             :  */
     492             : static void
     493          23 : do_shutdown (void *cls)
     494             : {
     495             :   (void) cls;
     496             : 
     497             :   {
     498             :     struct DenomRevocationRequest *drr;
     499             : 
     500          23 :     while (NULL != (drr = drr_head))
     501             :     {
     502           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     503             :                   "Aborting incomplete denomination revocation #%u\n",
     504             :                   (unsigned int) drr->idx);
     505           0 :       TALER_EXCHANGE_management_revoke_denomination_key_cancel (drr->h);
     506           0 :       GNUNET_CONTAINER_DLL_remove (drr_head,
     507             :                                    drr_tail,
     508             :                                    drr);
     509           0 :       GNUNET_free (drr);
     510             :     }
     511             :   }
     512             :   {
     513             :     struct SignkeyRevocationRequest *srr;
     514             : 
     515          23 :     while (NULL != (srr = srr_head))
     516             :     {
     517           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     518             :                   "Aborting incomplete signkey revocation #%u\n",
     519             :                   (unsigned int) srr->idx);
     520           0 :       TALER_EXCHANGE_management_revoke_signing_key_cancel (srr->h);
     521           0 :       GNUNET_CONTAINER_DLL_remove (srr_head,
     522             :                                    srr_tail,
     523             :                                    srr);
     524           0 :       GNUNET_free (srr);
     525             :     }
     526             :   }
     527             : 
     528             :   {
     529             :     struct AuditorAddRequest *aar;
     530             : 
     531          23 :     while (NULL != (aar = aar_head))
     532             :     {
     533           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     534             :                   "Aborting incomplete auditor add #%u\n",
     535             :                   (unsigned int) aar->idx);
     536           0 :       TALER_EXCHANGE_management_enable_auditor_cancel (aar->h);
     537           0 :       GNUNET_CONTAINER_DLL_remove (aar_head,
     538             :                                    aar_tail,
     539             :                                    aar);
     540           0 :       GNUNET_free (aar);
     541             :     }
     542             :   }
     543             :   {
     544             :     struct AuditorDelRequest *adr;
     545             : 
     546          23 :     while (NULL != (adr = adr_head))
     547             :     {
     548           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     549             :                   "Aborting incomplete auditor del #%u\n",
     550             :                   (unsigned int) adr->idx);
     551           0 :       TALER_EXCHANGE_management_disable_auditor_cancel (adr->h);
     552           0 :       GNUNET_CONTAINER_DLL_remove (adr_head,
     553             :                                    adr_tail,
     554             :                                    adr);
     555           0 :       GNUNET_free (adr);
     556             :     }
     557             :   }
     558             :   {
     559             :     struct WireAddRequest *war;
     560             : 
     561          23 :     while (NULL != (war = war_head))
     562             :     {
     563           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     564             :                   "Aborting incomplete wire add #%u\n",
     565             :                   (unsigned int) war->idx);
     566           0 :       TALER_EXCHANGE_management_enable_wire_cancel (war->h);
     567           0 :       GNUNET_CONTAINER_DLL_remove (war_head,
     568             :                                    war_tail,
     569             :                                    war);
     570           0 :       GNUNET_free (war);
     571             :     }
     572             :   }
     573             :   {
     574             :     struct WireDelRequest *wdr;
     575             : 
     576          23 :     while (NULL != (wdr = wdr_head))
     577             :     {
     578           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     579             :                   "Aborting incomplete wire del #%u\n",
     580             :                   (unsigned int) wdr->idx);
     581           0 :       TALER_EXCHANGE_management_disable_wire_cancel (wdr->h);
     582           0 :       GNUNET_CONTAINER_DLL_remove (wdr_head,
     583             :                                    wdr_tail,
     584             :                                    wdr);
     585           0 :       GNUNET_free (wdr);
     586             :     }
     587             :   }
     588             :   {
     589             :     struct WireFeeRequest *wfr;
     590             : 
     591          23 :     while (NULL != (wfr = wfr_head))
     592             :     {
     593           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     594             :                   "Aborting incomplete wire fee #%u\n",
     595             :                   (unsigned int) wfr->idx);
     596           0 :       TALER_EXCHANGE_management_set_wire_fees_cancel (wfr->h);
     597           0 :       GNUNET_CONTAINER_DLL_remove (wfr_head,
     598             :                                    wfr_tail,
     599             :                                    wfr);
     600           0 :       GNUNET_free (wfr);
     601             :     }
     602             :   }
     603             :   {
     604             :     struct UploadKeysRequest *ukr;
     605             : 
     606          23 :     while (NULL != (ukr = ukr_head))
     607             :     {
     608           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     609             :                   "Aborting incomplete key signature upload #%u\n",
     610             :                   (unsigned int) ukr->idx);
     611           0 :       TALER_EXCHANGE_post_management_keys_cancel (ukr->h);
     612           0 :       GNUNET_CONTAINER_DLL_remove (ukr_head,
     613             :                                    ukr_tail,
     614             :                                    ukr);
     615           0 :       GNUNET_free (ukr);
     616             :     }
     617             :   }
     618          23 :   if (NULL != out)
     619             :   {
     620           0 :     json_dumpf (out,
     621             :                 stdout,
     622             :                 JSON_INDENT (2));
     623           0 :     json_decref (out);
     624           0 :     out = NULL;
     625             :   }
     626          23 :   if (NULL != in)
     627             :   {
     628           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     629             :                 "Input not consumed!\n");
     630           0 :     json_decref (in);
     631           0 :     in = NULL;
     632             :   }
     633          23 :   if (NULL != nxt)
     634             :   {
     635           0 :     GNUNET_SCHEDULER_cancel (nxt);
     636           0 :     nxt = NULL;
     637             :   }
     638          23 :   if (NULL != mgkh)
     639             :   {
     640           0 :     TALER_EXCHANGE_get_management_keys_cancel (mgkh);
     641           0 :     mgkh = NULL;
     642             :   }
     643          23 :   if (NULL != ctx)
     644             :   {
     645          23 :     GNUNET_CURL_fini (ctx);
     646          23 :     ctx = NULL;
     647             :   }
     648          23 :   if (NULL != rc)
     649             :   {
     650          23 :     GNUNET_CURL_gnunet_rc_destroy (rc);
     651          23 :     rc = NULL;
     652             :   }
     653          23 : }
     654             : 
     655             : 
     656             : /**
     657             :  * Test if we should shut down because all tasks are done.
     658             :  */
     659             : static void
     660          23 : test_shutdown (void)
     661             : {
     662          23 :   if ( (NULL == drr_head) &&
     663          23 :        (NULL == srr_head) &&
     664          23 :        (NULL == aar_head) &&
     665          23 :        (NULL == adr_head) &&
     666          23 :        (NULL == war_head) &&
     667          23 :        (NULL == wdr_head) &&
     668          23 :        (NULL == wfr_head) &&
     669          23 :        (NULL == ukr_head) &&
     670          23 :        (NULL == mgkh) &&
     671          23 :        (NULL == nxt) )
     672          23 :     GNUNET_SCHEDULER_shutdown ();
     673          23 : }
     674             : 
     675             : 
     676             : /**
     677             :  * Function to continue processing the next command.
     678             :  *
     679             :  * @param cls must be a `char *const*` with the array of
     680             :  *        command-line arguments to process next
     681             :  */
     682             : static void
     683             : work (void *cls);
     684             : 
     685             : 
     686             : /**
     687             :  * Function to schedule job to process the next command.
     688             :  *
     689             :  * @param args the array of command-line arguments to process next
     690             :  */
     691             : static void
     692          52 : next (char *const *args)
     693             : {
     694          52 :   GNUNET_assert (NULL == nxt);
     695          52 :   if (NULL == args[0])
     696             :   {
     697           0 :     test_shutdown ();
     698           0 :     return;
     699             :   }
     700          52 :   nxt = GNUNET_SCHEDULER_add_now (&work,
     701             :                                   (void *) args);
     702             : }
     703             : 
     704             : 
     705             : /**
     706             :  * Add an operation to the #out JSON array for processing later.
     707             :  *
     708             :  * @param op_name name of the operation
     709             :  * @param op_value values for the operation (consumed)
     710             :  */
     711             : static void
     712          21 : output_operation (const char *op_name,
     713             :                   json_t *op_value)
     714             : {
     715             :   json_t *action;
     716             : 
     717          21 :   GNUNET_break (NULL != op_value);
     718          21 :   if (NULL == out)
     719             :   {
     720          21 :     out = json_array ();
     721          21 :     GNUNET_assert (NULL != out);
     722             :   }
     723          21 :   action = GNUNET_JSON_PACK (
     724             :     GNUNET_JSON_pack_string ("operation",
     725             :                              op_name),
     726             :     GNUNET_JSON_pack_object_steal ("arguments",
     727             :                                    op_value));
     728          21 :   GNUNET_assert (0 ==
     729             :                  json_array_append_new (out,
     730             :                                         action));
     731          21 : }
     732             : 
     733             : 
     734             : /**
     735             :  * Information about a subroutine for an upload.
     736             :  */
     737             : struct UploadHandler
     738             : {
     739             :   /**
     740             :    * Key to trigger this subroutine.
     741             :    */
     742             :   const char *key;
     743             : 
     744             :   /**
     745             :    * Function implementing an upload.
     746             :    *
     747             :    * @param exchange_url URL of the exchange
     748             :    * @param idx index of the operation we are performing
     749             :    * @param value arguments to drive the upload.
     750             :    */
     751             :   void (*cb)(const char *exchange_url,
     752             :              size_t idx,
     753             :              const json_t *value);
     754             : 
     755             : };
     756             : 
     757             : 
     758             : /**
     759             :  * Load the offline key (if not yet done). Triggers shutdown on failure.
     760             :  *
     761             :  * @param do_create #GNUNET_YES if the key may be created
     762             :  * @return #GNUNET_OK on success
     763             :  */
     764             : static int
     765          21 : load_offline_key (int do_create)
     766             : {
     767             :   static bool done;
     768             :   int ret;
     769             :   char *fn;
     770             : 
     771          21 :   if (done)
     772           0 :     return GNUNET_OK;
     773          21 :   if (GNUNET_OK !=
     774          21 :       GNUNET_CONFIGURATION_get_value_filename (kcfg,
     775             :                                                "exchange-offline",
     776             :                                                "MASTER_PRIV_FILE",
     777             :                                                &fn))
     778             :   {
     779           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     780             :                                "exchange-offline",
     781             :                                "MASTER_PRIV_FILE");
     782           0 :     test_shutdown ();
     783           0 :     return GNUNET_SYSERR;
     784             :   }
     785          21 :   if (GNUNET_YES !=
     786          21 :       GNUNET_DISK_file_test (fn))
     787           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     788             :                 "Exchange master private key `%s' does not exist yet, creating it!\n",
     789             :                 fn);
     790          21 :   ret = GNUNET_CRYPTO_eddsa_key_from_file (fn,
     791             :                                            do_create,
     792             :                                            &master_priv.eddsa_priv);
     793          21 :   if (GNUNET_SYSERR == ret)
     794             :   {
     795           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     796             :                 "Failed to initialize master key from file `%s': %s\n",
     797             :                 fn,
     798             :                 "could not create file");
     799           0 :     GNUNET_free (fn);
     800           0 :     test_shutdown ();
     801           0 :     return GNUNET_SYSERR;
     802             :   }
     803          21 :   GNUNET_free (fn);
     804          21 :   GNUNET_CRYPTO_eddsa_key_get_public (&master_priv.eddsa_priv,
     805             :                                       &master_pub.eddsa_pub);
     806          21 :   done = true;
     807          21 :   return GNUNET_OK;
     808             : }
     809             : 
     810             : 
     811             : /**
     812             :  * Function called with information about the post revocation operation result.
     813             :  *
     814             :  * @param cls closure with a `struct DenomRevocationRequest`
     815             :  * @param hr HTTP response data
     816             :  */
     817             : static void
     818           8 : denom_revocation_cb (
     819             :   void *cls,
     820             :   const struct TALER_EXCHANGE_HttpResponse *hr)
     821             : {
     822           8 :   struct DenomRevocationRequest *drr = cls;
     823             : 
     824           8 :   if (MHD_HTTP_NO_CONTENT != hr->http_status)
     825             :   {
     826           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     827             :                 "Upload failed for command %u with status %u: %s (%s)\n",
     828             :                 (unsigned int) drr->idx,
     829             :                 hr->http_status,
     830             :                 hr->hint,
     831             :                 TALER_JSON_get_error_hint (hr->reply));
     832           0 :     global_ret = EXIT_FAILURE;
     833             :   }
     834           8 :   GNUNET_CONTAINER_DLL_remove (drr_head,
     835             :                                drr_tail,
     836             :                                drr);
     837           8 :   GNUNET_free (drr);
     838           8 :   test_shutdown ();
     839           8 : }
     840             : 
     841             : 
     842             : /**
     843             :  * Upload denomination revocation request data.
     844             :  *
     845             :  * @param exchange_url base URL of the exchange
     846             :  * @param idx index of the operation we are performing (for logging)
     847             :  * @param value arguments for denomination revocation
     848             :  */
     849             : static void
     850           8 : upload_denom_revocation (const char *exchange_url,
     851             :                          size_t idx,
     852             :                          const json_t *value)
     853             : {
     854             :   struct TALER_MasterSignatureP master_sig;
     855             :   struct GNUNET_HashCode h_denom_pub;
     856             :   struct DenomRevocationRequest *drr;
     857             :   const char *err_name;
     858             :   unsigned int err_line;
     859             :   struct GNUNET_JSON_Specification spec[] = {
     860           8 :     GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
     861             :                                  &h_denom_pub),
     862           8 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     863             :                                  &master_sig),
     864           8 :     GNUNET_JSON_spec_end ()
     865             :   };
     866             : 
     867           8 :   if (GNUNET_OK !=
     868           8 :       GNUNET_JSON_parse (value,
     869             :                          spec,
     870             :                          &err_name,
     871             :                          &err_line))
     872             :   {
     873           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     874             :                 "Invalid input for denomination revocation: %s#%u at %u (skipping)\n",
     875             :                 err_name,
     876             :                 err_line,
     877             :                 (unsigned int) idx);
     878           0 :     json_dumpf (value,
     879             :                 stderr,
     880             :                 JSON_INDENT (2));
     881           0 :     global_ret = EXIT_FAILURE;
     882           0 :     test_shutdown ();
     883           0 :     return;
     884             :   }
     885           8 :   drr = GNUNET_new (struct DenomRevocationRequest);
     886           8 :   drr->idx = idx;
     887           8 :   drr->h =
     888           8 :     TALER_EXCHANGE_management_revoke_denomination_key (ctx,
     889             :                                                        exchange_url,
     890             :                                                        &h_denom_pub,
     891             :                                                        &master_sig,
     892             :                                                        &denom_revocation_cb,
     893             :                                                        drr);
     894           8 :   GNUNET_CONTAINER_DLL_insert (drr_head,
     895             :                                drr_tail,
     896             :                                drr);
     897             : }
     898             : 
     899             : 
     900             : /**
     901             :  * Function called with information about the post revocation operation result.
     902             :  *
     903             :  * @param cls closure with a `struct SignkeyRevocationRequest`
     904             :  * @param hr HTTP response data
     905             :  */
     906             : static void
     907           0 : signkey_revocation_cb (
     908             :   void *cls,
     909             :   const struct TALER_EXCHANGE_HttpResponse *hr)
     910             : {
     911           0 :   struct SignkeyRevocationRequest *srr = cls;
     912             : 
     913           0 :   if (MHD_HTTP_NO_CONTENT != hr->http_status)
     914             :   {
     915           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     916             :                 "Upload failed for command %u with status %u: %s (%s)\n",
     917             :                 (unsigned int) srr->idx,
     918             :                 hr->http_status,
     919             :                 hr->hint,
     920             :                 TALER_JSON_get_error_hint (hr->reply));
     921           0 :     global_ret = EXIT_FAILURE;
     922             :   }
     923           0 :   GNUNET_CONTAINER_DLL_remove (srr_head,
     924             :                                srr_tail,
     925             :                                srr);
     926           0 :   GNUNET_free (srr);
     927           0 :   test_shutdown ();
     928           0 : }
     929             : 
     930             : 
     931             : /**
     932             :  * Upload signkey revocation request data.
     933             :  *
     934             :  * @param exchange_url base URL of the exchange
     935             :  * @param idx index of the operation we are performing (for logging)
     936             :  * @param value arguments for denomination revocation
     937             :  */
     938             : static void
     939           0 : upload_signkey_revocation (const char *exchange_url,
     940             :                            size_t idx,
     941             :                            const json_t *value)
     942             : {
     943             :   struct TALER_MasterSignatureP master_sig;
     944             :   struct TALER_ExchangePublicKeyP exchange_pub;
     945             :   struct SignkeyRevocationRequest *srr;
     946             :   const char *err_name;
     947             :   unsigned int err_line;
     948             :   struct GNUNET_JSON_Specification spec[] = {
     949           0 :     GNUNET_JSON_spec_fixed_auto ("exchange_pub",
     950             :                                  &exchange_pub),
     951           0 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     952             :                                  &master_sig),
     953           0 :     GNUNET_JSON_spec_end ()
     954             :   };
     955             : 
     956           0 :   if (GNUNET_OK !=
     957           0 :       GNUNET_JSON_parse (value,
     958             :                          spec,
     959             :                          &err_name,
     960             :                          &err_line))
     961             :   {
     962           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     963             :                 "Invalid input for signkey revocation: %s#%u at %u (skipping)\n",
     964             :                 err_name,
     965             :                 err_line,
     966             :                 (unsigned int) idx);
     967           0 :     json_dumpf (value,
     968             :                 stderr,
     969             :                 JSON_INDENT (2));
     970           0 :     global_ret = EXIT_FAILURE;
     971           0 :     test_shutdown ();
     972           0 :     return;
     973             :   }
     974           0 :   srr = GNUNET_new (struct SignkeyRevocationRequest);
     975           0 :   srr->idx = idx;
     976           0 :   srr->h =
     977           0 :     TALER_EXCHANGE_management_revoke_signing_key (ctx,
     978             :                                                   exchange_url,
     979             :                                                   &exchange_pub,
     980             :                                                   &master_sig,
     981             :                                                   &signkey_revocation_cb,
     982             :                                                   srr);
     983           0 :   GNUNET_CONTAINER_DLL_insert (srr_head,
     984             :                                srr_tail,
     985             :                                srr);
     986             : }
     987             : 
     988             : 
     989             : /**
     990             :  * Function called with information about the post auditor add operation result.
     991             :  *
     992             :  * @param cls closure with a `struct AuditorAddRequest`
     993             :  * @param hr HTTP response data
     994             :  */
     995             : static void
     996           0 : auditor_add_cb (void *cls,
     997             :                 const struct TALER_EXCHANGE_HttpResponse *hr)
     998             : {
     999           0 :   struct AuditorAddRequest *aar = cls;
    1000             : 
    1001           0 :   if (MHD_HTTP_NO_CONTENT != hr->http_status)
    1002             :   {
    1003           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1004             :                 "Upload failed for command %u with status %u: %s (%s)\n",
    1005             :                 (unsigned int) aar->idx,
    1006             :                 hr->http_status,
    1007             :                 TALER_ErrorCode_get_hint (hr->ec),
    1008             :                 hr->hint);
    1009           0 :     global_ret = EXIT_FAILURE;
    1010             :   }
    1011           0 :   GNUNET_CONTAINER_DLL_remove (aar_head,
    1012             :                                aar_tail,
    1013             :                                aar);
    1014           0 :   GNUNET_free (aar);
    1015           0 :   test_shutdown ();
    1016           0 : }
    1017             : 
    1018             : 
    1019             : /**
    1020             :  * Upload auditor add data.
    1021             :  *
    1022             :  * @param exchange_url base URL of the exchange
    1023             :  * @param idx index of the operation we are performing (for logging)
    1024             :  * @param value arguments for denomination revocation
    1025             :  */
    1026             : static void
    1027           0 : upload_auditor_add (const char *exchange_url,
    1028             :                     size_t idx,
    1029             :                     const json_t *value)
    1030             : {
    1031             :   struct TALER_MasterSignatureP master_sig;
    1032             :   const char *auditor_url;
    1033             :   const char *auditor_name;
    1034             :   struct GNUNET_TIME_Absolute start_time;
    1035             :   struct TALER_AuditorPublicKeyP auditor_pub;
    1036             :   struct AuditorAddRequest *aar;
    1037             :   const char *err_name;
    1038             :   unsigned int err_line;
    1039             :   struct GNUNET_JSON_Specification spec[] = {
    1040           0 :     GNUNET_JSON_spec_string ("auditor_url",
    1041             :                              &auditor_url),
    1042           0 :     GNUNET_JSON_spec_string ("auditor_name",
    1043             :                              &auditor_name),
    1044           0 :     GNUNET_JSON_spec_absolute_time ("validity_start",
    1045             :                                     &start_time),
    1046           0 :     GNUNET_JSON_spec_fixed_auto ("auditor_pub",
    1047             :                                  &auditor_pub),
    1048           0 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
    1049             :                                  &master_sig),
    1050           0 :     GNUNET_JSON_spec_end ()
    1051             :   };
    1052             : 
    1053           0 :   if (GNUNET_OK !=
    1054           0 :       GNUNET_JSON_parse (value,
    1055             :                          spec,
    1056             :                          &err_name,
    1057             :                          &err_line))
    1058             :   {
    1059           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1060             :                 "Invalid input for adding auditor: %s#%u at %u (skipping)\n",
    1061             :                 err_name,
    1062             :                 err_line,
    1063             :                 (unsigned int) idx);
    1064           0 :     json_dumpf (value,
    1065             :                 stderr,
    1066             :                 JSON_INDENT (2));
    1067           0 :     global_ret = EXIT_FAILURE;
    1068           0 :     test_shutdown ();
    1069           0 :     return;
    1070             :   }
    1071           0 :   aar = GNUNET_new (struct AuditorAddRequest);
    1072           0 :   aar->idx = idx;
    1073           0 :   aar->h =
    1074           0 :     TALER_EXCHANGE_management_enable_auditor (ctx,
    1075             :                                               exchange_url,
    1076             :                                               &auditor_pub,
    1077             :                                               auditor_url,
    1078             :                                               auditor_name,
    1079             :                                               start_time,
    1080             :                                               &master_sig,
    1081             :                                               &auditor_add_cb,
    1082             :                                               aar);
    1083           0 :   GNUNET_CONTAINER_DLL_insert (aar_head,
    1084             :                                aar_tail,
    1085             :                                aar);
    1086             : }
    1087             : 
    1088             : 
    1089             : /**
    1090             :  * Function called with information about the post auditor del operation result.
    1091             :  *
    1092             :  * @param cls closure with a `struct AuditorDelRequest`
    1093             :  * @param hr HTTP response data
    1094             :  */
    1095             : static void
    1096           0 : auditor_del_cb (void *cls,
    1097             :                 const struct TALER_EXCHANGE_HttpResponse *hr)
    1098             : {
    1099           0 :   struct AuditorDelRequest *adr = cls;
    1100             : 
    1101           0 :   if (MHD_HTTP_NO_CONTENT != hr->http_status)
    1102             :   {
    1103           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1104             :                 "Upload failed for command %u with status %u: %s (%s)\n",
    1105             :                 (unsigned int) adr->idx,
    1106             :                 hr->http_status,
    1107             :                 TALER_ErrorCode_get_hint (hr->ec),
    1108             :                 hr->hint);
    1109           0 :     global_ret = EXIT_FAILURE;
    1110             :   }
    1111           0 :   GNUNET_CONTAINER_DLL_remove (adr_head,
    1112             :                                adr_tail,
    1113             :                                adr);
    1114           0 :   GNUNET_free (adr);
    1115           0 :   test_shutdown ();
    1116           0 : }
    1117             : 
    1118             : 
    1119             : /**
    1120             :  * Upload auditor del data.
    1121             :  *
    1122             :  * @param exchange_url base URL of the exchange
    1123             :  * @param idx index of the operation we are performing (for logging)
    1124             :  * @param value arguments for denomination revocation
    1125             :  */
    1126             : static void
    1127           0 : upload_auditor_del (const char *exchange_url,
    1128             :                     size_t idx,
    1129             :                     const json_t *value)
    1130             : {
    1131             :   struct TALER_AuditorPublicKeyP auditor_pub;
    1132             :   struct TALER_MasterSignatureP master_sig;
    1133             :   struct GNUNET_TIME_Absolute end_time;
    1134             :   struct AuditorDelRequest *adr;
    1135             :   const char *err_name;
    1136             :   unsigned int err_line;
    1137             :   struct GNUNET_JSON_Specification spec[] = {
    1138           0 :     GNUNET_JSON_spec_fixed_auto ("auditor_pub",
    1139             :                                  &auditor_pub),
    1140           0 :     GNUNET_JSON_spec_absolute_time ("validity_end",
    1141             :                                     &end_time),
    1142           0 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
    1143             :                                  &master_sig),
    1144           0 :     GNUNET_JSON_spec_end ()
    1145             :   };
    1146             : 
    1147           0 :   if (GNUNET_OK !=
    1148           0 :       GNUNET_JSON_parse (value,
    1149             :                          spec,
    1150             :                          &err_name,
    1151             :                          &err_line))
    1152             :   {
    1153           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1154             :                 "Invalid input to disable auditor: %s#%u at %u (skipping)\n",
    1155             :                 err_name,
    1156             :                 err_line,
    1157             :                 (unsigned int) idx);
    1158           0 :     json_dumpf (value,
    1159             :                 stderr,
    1160             :                 JSON_INDENT (2));
    1161           0 :     global_ret = EXIT_FAILURE;
    1162           0 :     test_shutdown ();
    1163           0 :     return;
    1164             :   }
    1165           0 :   adr = GNUNET_new (struct AuditorDelRequest);
    1166           0 :   adr->idx = idx;
    1167           0 :   adr->h =
    1168           0 :     TALER_EXCHANGE_management_disable_auditor (ctx,
    1169             :                                                exchange_url,
    1170             :                                                &auditor_pub,
    1171             :                                                end_time,
    1172             :                                                &master_sig,
    1173             :                                                &auditor_del_cb,
    1174             :                                                adr);
    1175           0 :   GNUNET_CONTAINER_DLL_insert (adr_head,
    1176             :                                adr_tail,
    1177             :                                adr);
    1178             : }
    1179             : 
    1180             : 
    1181             : /**
    1182             :  * Function called with information about the post wire add operation result.
    1183             :  *
    1184             :  * @param cls closure with a `struct WireAddRequest`
    1185             :  * @param hr HTTP response data
    1186             :  */
    1187             : static void
    1188           0 : wire_add_cb (void *cls,
    1189             :              const struct TALER_EXCHANGE_HttpResponse *hr)
    1190             : {
    1191           0 :   struct WireAddRequest *war = cls;
    1192             : 
    1193           0 :   if (MHD_HTTP_NO_CONTENT != hr->http_status)
    1194             :   {
    1195           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1196             :                 "Upload failed for command %u with status %u: %s (%s)\n",
    1197             :                 (unsigned int) war->idx,
    1198             :                 hr->http_status,
    1199             :                 TALER_ErrorCode_get_hint (hr->ec),
    1200             :                 hr->hint);
    1201           0 :     global_ret = EXIT_FAILURE;
    1202             :   }
    1203           0 :   GNUNET_CONTAINER_DLL_remove (war_head,
    1204             :                                war_tail,
    1205             :                                war);
    1206           0 :   GNUNET_free (war);
    1207           0 :   test_shutdown ();
    1208           0 : }
    1209             : 
    1210             : 
    1211             : /**
    1212             :  * Upload wire add data.
    1213             :  *
    1214             :  * @param exchange_url base URL of the exchange
    1215             :  * @param idx index of the operation we are performing (for logging)
    1216             :  * @param value arguments for denomination revocation
    1217             :  */
    1218             : static void
    1219           0 : upload_wire_add (const char *exchange_url,
    1220             :                  size_t idx,
    1221             :                  const json_t *value)
    1222             : {
    1223             :   struct TALER_MasterSignatureP master_sig_add;
    1224             :   struct TALER_MasterSignatureP master_sig_wire;
    1225             :   const char *payto_uri;
    1226             :   struct GNUNET_TIME_Absolute start_time;
    1227             :   struct WireAddRequest *war;
    1228             :   const char *err_name;
    1229             :   unsigned int err_line;
    1230             :   struct GNUNET_JSON_Specification spec[] = {
    1231           0 :     GNUNET_JSON_spec_string ("payto_uri",
    1232             :                              &payto_uri),
    1233           0 :     GNUNET_JSON_spec_absolute_time ("validity_start",
    1234             :                                     &start_time),
    1235           0 :     GNUNET_JSON_spec_fixed_auto ("master_sig_add",
    1236             :                                  &master_sig_add),
    1237           0 :     GNUNET_JSON_spec_fixed_auto ("master_sig_wire",
    1238             :                                  &master_sig_wire),
    1239           0 :     GNUNET_JSON_spec_end ()
    1240             :   };
    1241             : 
    1242           0 :   if (GNUNET_OK !=
    1243           0 :       GNUNET_JSON_parse (value,
    1244             :                          spec,
    1245             :                          &err_name,
    1246             :                          &err_line))
    1247             :   {
    1248           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1249             :                 "Invalid input for adding wire account: %s#%u at %u (skipping)\n",
    1250             :                 err_name,
    1251             :                 err_line,
    1252             :                 (unsigned int) idx);
    1253           0 :     json_dumpf (value,
    1254             :                 stderr,
    1255             :                 JSON_INDENT (2));
    1256           0 :     global_ret = EXIT_FAILURE;
    1257           0 :     test_shutdown ();
    1258           0 :     return;
    1259             :   }
    1260             :   {
    1261             :     char *wire_method;
    1262             : 
    1263           0 :     wire_method = TALER_payto_get_method (payto_uri);
    1264           0 :     if (NULL == wire_method)
    1265             :     {
    1266           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1267             :                   "payto:// URI `%s' is malformed\n",
    1268             :                   payto_uri);
    1269           0 :       global_ret = EXIT_FAILURE;
    1270           0 :       test_shutdown ();
    1271           0 :       return;
    1272             :     }
    1273           0 :     GNUNET_free (wire_method);
    1274             :   }
    1275           0 :   war = GNUNET_new (struct WireAddRequest);
    1276           0 :   war->idx = idx;
    1277           0 :   war->h =
    1278           0 :     TALER_EXCHANGE_management_enable_wire (ctx,
    1279             :                                            exchange_url,
    1280             :                                            payto_uri,
    1281             :                                            start_time,
    1282             :                                            &master_sig_add,
    1283             :                                            &master_sig_wire,
    1284             :                                            &wire_add_cb,
    1285             :                                            war);
    1286           0 :   GNUNET_CONTAINER_DLL_insert (war_head,
    1287             :                                war_tail,
    1288             :                                war);
    1289             : }
    1290             : 
    1291             : 
    1292             : /**
    1293             :  * Function called with information about the post wire del operation result.
    1294             :  *
    1295             :  * @param cls closure with a `struct WireDelRequest`
    1296             :  * @param hr HTTP response data
    1297             :  */
    1298             : static void
    1299           0 : wire_del_cb (void *cls,
    1300             :              const struct TALER_EXCHANGE_HttpResponse *hr)
    1301             : {
    1302           0 :   struct WireDelRequest *wdr = cls;
    1303             : 
    1304           0 :   if (MHD_HTTP_NO_CONTENT != hr->http_status)
    1305             :   {
    1306           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1307             :                 "Upload failed for command %u with status %u: %s (%s)\n",
    1308             :                 (unsigned int) wdr->idx,
    1309             :                 hr->http_status,
    1310             :                 TALER_ErrorCode_get_hint (hr->ec),
    1311             :                 hr->hint);
    1312           0 :     global_ret = EXIT_FAILURE;
    1313             :   }
    1314           0 :   GNUNET_CONTAINER_DLL_remove (wdr_head,
    1315             :                                wdr_tail,
    1316             :                                wdr);
    1317           0 :   GNUNET_free (wdr);
    1318           0 :   test_shutdown ();
    1319           0 : }
    1320             : 
    1321             : 
    1322             : /**
    1323             :  * Upload wire del data.
    1324             :  *
    1325             :  * @param exchange_url base URL of the exchange
    1326             :  * @param idx index of the operation we are performing (for logging)
    1327             :  * @param value arguments for denomination revocation
    1328             :  */
    1329             : static void
    1330           0 : upload_wire_del (const char *exchange_url,
    1331             :                  size_t idx,
    1332             :                  const json_t *value)
    1333             : {
    1334             :   struct TALER_MasterSignatureP master_sig;
    1335             :   const char *payto_uri;
    1336             :   struct GNUNET_TIME_Absolute end_time;
    1337             :   struct WireDelRequest *wdr;
    1338             :   const char *err_name;
    1339             :   unsigned int err_line;
    1340             :   struct GNUNET_JSON_Specification spec[] = {
    1341           0 :     GNUNET_JSON_spec_string ("payto_uri",
    1342             :                              &payto_uri),
    1343           0 :     GNUNET_JSON_spec_absolute_time ("validity_end",
    1344             :                                     &end_time),
    1345           0 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
    1346             :                                  &master_sig),
    1347           0 :     GNUNET_JSON_spec_end ()
    1348             :   };
    1349             : 
    1350           0 :   if (GNUNET_OK !=
    1351           0 :       GNUNET_JSON_parse (value,
    1352             :                          spec,
    1353             :                          &err_name,
    1354             :                          &err_line))
    1355             :   {
    1356           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1357             :                 "Invalid input to disable wire account: %s#%u at %u (skipping)\n",
    1358             :                 err_name,
    1359             :                 err_line,
    1360             :                 (unsigned int) idx);
    1361           0 :     json_dumpf (value,
    1362             :                 stderr,
    1363             :                 JSON_INDENT (2));
    1364           0 :     global_ret = EXIT_FAILURE;
    1365           0 :     test_shutdown ();
    1366           0 :     return;
    1367             :   }
    1368           0 :   wdr = GNUNET_new (struct WireDelRequest);
    1369           0 :   wdr->idx = idx;
    1370           0 :   wdr->h =
    1371           0 :     TALER_EXCHANGE_management_disable_wire (ctx,
    1372             :                                             exchange_url,
    1373             :                                             payto_uri,
    1374             :                                             end_time,
    1375             :                                             &master_sig,
    1376             :                                             &wire_del_cb,
    1377             :                                             wdr);
    1378           0 :   GNUNET_CONTAINER_DLL_insert (wdr_head,
    1379             :                                wdr_tail,
    1380             :                                wdr);
    1381             : }
    1382             : 
    1383             : 
    1384             : /**
    1385             :  * Function called with information about the post wire fee operation result.
    1386             :  *
    1387             :  * @param cls closure with a `struct WireFeeRequest`
    1388             :  * @param hr HTTP response data
    1389             :  */
    1390             : static void
    1391           5 : wire_fee_cb (
    1392             :   void *cls,
    1393             :   const struct TALER_EXCHANGE_HttpResponse *hr)
    1394             : {
    1395           5 :   struct WireFeeRequest *wfr = cls;
    1396             : 
    1397           5 :   if (MHD_HTTP_NO_CONTENT != hr->http_status)
    1398             :   {
    1399           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1400             :                 "Upload failed for command %u with status %u: %s (%s)\n",
    1401             :                 (unsigned int) wfr->idx,
    1402             :                 hr->http_status,
    1403             :                 TALER_ErrorCode_get_hint (hr->ec),
    1404             :                 hr->hint);
    1405           0 :     global_ret = EXIT_FAILURE;
    1406             :   }
    1407           5 :   GNUNET_CONTAINER_DLL_remove (wfr_head,
    1408             :                                wfr_tail,
    1409             :                                wfr);
    1410           5 :   GNUNET_free (wfr);
    1411           5 :   test_shutdown ();
    1412           5 : }
    1413             : 
    1414             : 
    1415             : /**
    1416             :  * Upload wire fee.
    1417             :  *
    1418             :  * @param exchange_url base URL of the exchange
    1419             :  * @param idx index of the operation we are performing (for logging)
    1420             :  * @param value arguments for denomination revocation
    1421             :  */
    1422             : static void
    1423           5 : upload_wire_fee (const char *exchange_url,
    1424             :                  size_t idx,
    1425             :                  const json_t *value)
    1426             : {
    1427             :   struct TALER_MasterSignatureP master_sig;
    1428             :   const char *wire_method;
    1429             :   struct WireFeeRequest *wfr;
    1430             :   const char *err_name;
    1431             :   unsigned int err_line;
    1432             :   struct TALER_Amount wire_fee;
    1433             :   struct TALER_Amount closing_fee;
    1434             :   struct GNUNET_TIME_Absolute start_time;
    1435             :   struct GNUNET_TIME_Absolute end_time;
    1436             :   struct GNUNET_JSON_Specification spec[] = {
    1437           5 :     GNUNET_JSON_spec_string ("wire_method",
    1438             :                              &wire_method),
    1439           5 :     TALER_JSON_spec_amount ("wire_fee",
    1440             :                             currency,
    1441             :                             &wire_fee),
    1442           5 :     TALER_JSON_spec_amount ("closing_fee",
    1443             :                             currency,
    1444             :                             &closing_fee),
    1445           5 :     GNUNET_JSON_spec_absolute_time ("start_time",
    1446             :                                     &start_time),
    1447           5 :     GNUNET_JSON_spec_absolute_time ("end_time",
    1448             :                                     &end_time),
    1449           5 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
    1450             :                                  &master_sig),
    1451           5 :     GNUNET_JSON_spec_end ()
    1452             :   };
    1453             : 
    1454           5 :   if (GNUNET_OK !=
    1455           5 :       GNUNET_JSON_parse (value,
    1456             :                          spec,
    1457             :                          &err_name,
    1458             :                          &err_line))
    1459             :   {
    1460           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1461             :                 "Invalid input to set wire fee: %s#%u at %u (skipping)\n",
    1462             :                 err_name,
    1463             :                 err_line,
    1464             :                 (unsigned int) idx);
    1465           0 :     json_dumpf (value,
    1466             :                 stderr,
    1467             :                 JSON_INDENT (2));
    1468           0 :     global_ret = EXIT_FAILURE;
    1469           0 :     test_shutdown ();
    1470           0 :     return;
    1471             :   }
    1472           5 :   wfr = GNUNET_new (struct WireFeeRequest);
    1473           5 :   wfr->idx = idx;
    1474           5 :   wfr->h =
    1475           5 :     TALER_EXCHANGE_management_set_wire_fees (ctx,
    1476             :                                              exchange_url,
    1477             :                                              wire_method,
    1478             :                                              start_time,
    1479             :                                              end_time,
    1480             :                                              &wire_fee,
    1481             :                                              &closing_fee,
    1482             :                                              &master_sig,
    1483             :                                              &wire_fee_cb,
    1484             :                                              wfr);
    1485           5 :   GNUNET_CONTAINER_DLL_insert (wfr_head,
    1486             :                                wfr_tail,
    1487             :                                wfr);
    1488             : }
    1489             : 
    1490             : 
    1491             : /**
    1492             :  * Function called with information about the post upload keys operation result.
    1493             :  *
    1494             :  * @param cls closure with a `struct UploadKeysRequest`
    1495             :  * @param hr HTTP response data
    1496             :  */
    1497             : static void
    1498           8 : keys_cb (
    1499             :   void *cls,
    1500             :   const struct TALER_EXCHANGE_HttpResponse *hr)
    1501             : {
    1502           8 :   struct UploadKeysRequest *ukr = cls;
    1503             : 
    1504           8 :   if (MHD_HTTP_NO_CONTENT != hr->http_status)
    1505             :   {
    1506           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1507             :                 "Upload failed for command %u with status %u: %s (%s)\n",
    1508             :                 (unsigned int) ukr->idx,
    1509             :                 hr->http_status,
    1510             :                 TALER_ErrorCode_get_hint (hr->ec),
    1511             :                 hr->hint);
    1512           0 :     global_ret = EXIT_FAILURE;
    1513             :   }
    1514           8 :   GNUNET_CONTAINER_DLL_remove (ukr_head,
    1515             :                                ukr_tail,
    1516             :                                ukr);
    1517           8 :   GNUNET_free (ukr);
    1518           8 :   test_shutdown ();
    1519           8 : }
    1520             : 
    1521             : 
    1522             : /**
    1523             :  * Upload (denomination and signing) key master signatures.
    1524             :  *
    1525             :  * @param exchange_url base URL of the exchange
    1526             :  * @param idx index of the operation we are performing (for logging)
    1527             :  * @param value arguments for POSTing keys
    1528             :  */
    1529             : static void
    1530           8 : upload_keys (const char *exchange_url,
    1531             :              size_t idx,
    1532             :              const json_t *value)
    1533             : {
    1534             :   struct TALER_EXCHANGE_ManagementPostKeysData pkd;
    1535             :   struct UploadKeysRequest *ukr;
    1536             :   const char *err_name;
    1537             :   unsigned int err_line;
    1538             :   json_t *denom_sigs;
    1539             :   json_t *signkey_sigs;
    1540             :   struct GNUNET_JSON_Specification spec[] = {
    1541           8 :     GNUNET_JSON_spec_json ("denom_sigs",
    1542             :                            &denom_sigs),
    1543           8 :     GNUNET_JSON_spec_json ("signkey_sigs",
    1544             :                            &signkey_sigs),
    1545           8 :     GNUNET_JSON_spec_end ()
    1546             :   };
    1547           8 :   bool ok = true;
    1548             : 
    1549           8 :   if (GNUNET_OK !=
    1550           8 :       GNUNET_JSON_parse (value,
    1551             :                          spec,
    1552             :                          &err_name,
    1553             :                          &err_line))
    1554             :   {
    1555           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1556             :                 "Invalid input to 'upload': %s#%u (skipping)\n",
    1557             :                 err_name,
    1558             :                 err_line);
    1559           0 :     json_dumpf (value,
    1560             :                 stderr,
    1561             :                 JSON_INDENT (2));
    1562           0 :     global_ret = EXIT_FAILURE;
    1563           0 :     test_shutdown ();
    1564           0 :     return;
    1565             :   }
    1566           8 :   pkd.num_sign_sigs = json_array_size (signkey_sigs);
    1567           8 :   pkd.num_denom_sigs = json_array_size (denom_sigs);
    1568           8 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1569             :               "Uploading %u denomination and %u signing key signatures\n",
    1570             :               pkd.num_denom_sigs,
    1571             :               pkd.num_sign_sigs);
    1572           8 :   pkd.sign_sigs = GNUNET_new_array (
    1573             :     pkd.num_sign_sigs,
    1574             :     struct TALER_EXCHANGE_SigningKeySignature);
    1575           8 :   pkd.denom_sigs = GNUNET_new_array (
    1576             :     pkd.num_denom_sigs,
    1577             :     struct TALER_EXCHANGE_DenominationKeySignature);
    1578          22 :   for (unsigned int i = 0; i<pkd.num_sign_sigs; i++)
    1579             :   {
    1580          14 :     struct TALER_EXCHANGE_SigningKeySignature *ss = &pkd.sign_sigs[i];
    1581          14 :     json_t *val = json_array_get (signkey_sigs,
    1582             :                                   i);
    1583             :     struct GNUNET_JSON_Specification spec[] = {
    1584          14 :       GNUNET_JSON_spec_fixed_auto ("exchange_pub",
    1585             :                                    &ss->exchange_pub),
    1586          14 :       GNUNET_JSON_spec_fixed_auto ("master_sig",
    1587             :                                    &ss->master_sig),
    1588          14 :       GNUNET_JSON_spec_end ()
    1589             :     };
    1590             : 
    1591          14 :     if (GNUNET_OK !=
    1592          14 :         GNUNET_JSON_parse (val,
    1593             :                            spec,
    1594             :                            &err_name,
    1595             :                            &err_line))
    1596             :     {
    1597           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1598             :                   "Invalid input for signkey validity: %s#%u at %u (aborting)\n",
    1599             :                   err_name,
    1600             :                   err_line,
    1601             :                   i);
    1602           0 :       json_dumpf (val,
    1603             :                   stderr,
    1604             :                   JSON_INDENT (2));
    1605           0 :       ok = false;
    1606             :     }
    1607             :   }
    1608         124 :   for (unsigned int i = 0; i<pkd.num_denom_sigs; i++)
    1609             :   {
    1610         116 :     struct TALER_EXCHANGE_DenominationKeySignature *ds = &pkd.denom_sigs[i];
    1611         116 :     json_t *val = json_array_get (denom_sigs,
    1612             :                                   i);
    1613             :     struct GNUNET_JSON_Specification spec[] = {
    1614         116 :       GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
    1615             :                                    &ds->h_denom_pub),
    1616         116 :       GNUNET_JSON_spec_fixed_auto ("master_sig",
    1617             :                                    &ds->master_sig),
    1618         116 :       GNUNET_JSON_spec_end ()
    1619             :     };
    1620             : 
    1621         116 :     if (GNUNET_OK !=
    1622         116 :         GNUNET_JSON_parse (val,
    1623             :                            spec,
    1624             :                            &err_name,
    1625             :                            &err_line))
    1626             :     {
    1627           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1628             :                   "Invalid input for denomination validity: %s#%u at %u (aborting)\n",
    1629             :                   err_name,
    1630             :                   err_line,
    1631             :                   i);
    1632           0 :       json_dumpf (val,
    1633             :                   stderr,
    1634             :                   JSON_INDENT (2));
    1635           0 :       ok = false;
    1636             :     }
    1637             :   }
    1638             : 
    1639           8 :   if (ok)
    1640             :   {
    1641           8 :     ukr = GNUNET_new (struct UploadKeysRequest);
    1642           8 :     ukr->idx = idx;
    1643           8 :     ukr->h =
    1644           8 :       TALER_EXCHANGE_post_management_keys (ctx,
    1645             :                                            exchange_url,
    1646             :                                            &pkd,
    1647             :                                            &keys_cb,
    1648             :                                            ukr);
    1649           8 :     GNUNET_CONTAINER_DLL_insert (ukr_head,
    1650             :                                  ukr_tail,
    1651             :                                  ukr);
    1652             :   }
    1653             :   else
    1654             :   {
    1655           0 :     global_ret = EXIT_FAILURE;
    1656           0 :     test_shutdown ();
    1657             :   }
    1658           8 :   GNUNET_free (pkd.sign_sigs);
    1659           8 :   GNUNET_free (pkd.denom_sigs);
    1660           8 :   GNUNET_JSON_parse_free (spec);
    1661             : }
    1662             : 
    1663             : 
    1664             : /**
    1665             :  * Perform uploads based on the JSON in #out.
    1666             :  *
    1667             :  * @param exchange_url base URL of the exchange to use
    1668             :  */
    1669             : static void
    1670          21 : trigger_upload (const char *exchange_url)
    1671             : {
    1672          21 :   struct UploadHandler uhs[] = {
    1673             :     {
    1674             :       .key = OP_REVOKE_DENOMINATION,
    1675             :       .cb = &upload_denom_revocation
    1676             :     },
    1677             :     {
    1678             :       .key = OP_REVOKE_SIGNKEY,
    1679             :       .cb = &upload_signkey_revocation
    1680             :     },
    1681             :     {
    1682             :       .key = OP_ENABLE_AUDITOR,
    1683             :       .cb = &upload_auditor_add
    1684             :     },
    1685             :     {
    1686             :       .key = OP_DISABLE_AUDITOR,
    1687             :       .cb = &upload_auditor_del
    1688             :     },
    1689             :     {
    1690             :       .key = OP_ENABLE_WIRE,
    1691             :       .cb = &upload_wire_add
    1692             :     },
    1693             :     {
    1694             :       .key = OP_DISABLE_WIRE,
    1695             :       .cb = &upload_wire_del
    1696             :     },
    1697             :     {
    1698             :       .key = OP_SET_WIRE_FEE,
    1699             :       .cb = &upload_wire_fee
    1700             :     },
    1701             :     {
    1702             :       .key = OP_UPLOAD_SIGS,
    1703             :       .cb = &upload_keys
    1704             :     },
    1705             :     /* array termination */
    1706             :     {
    1707             :       .key = NULL
    1708             :     }
    1709             :   };
    1710             :   size_t index;
    1711             :   json_t *obj;
    1712             : 
    1713          42 :   json_array_foreach (out, index, obj) {
    1714          21 :     bool found = false;
    1715             :     const char *key;
    1716             :     const json_t *value;
    1717             : 
    1718          21 :     key = json_string_value (json_object_get (obj, "operation"));
    1719          21 :     value = json_object_get (obj, "arguments");
    1720          21 :     if (NULL == key)
    1721             :     {
    1722           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1723             :                   "Malformed JSON input\n");
    1724           0 :       global_ret = EXIT_FAILURE;
    1725           0 :       test_shutdown ();
    1726           0 :       return;
    1727             :     }
    1728             :     /* block of code that uses key and value */
    1729         107 :     for (unsigned int i = 0; NULL != uhs[i].key; i++)
    1730             :     {
    1731         107 :       if (0 == strcasecmp (key,
    1732             :                            uhs[i].key))
    1733             :       {
    1734          21 :         found = true;
    1735          21 :         uhs[i].cb (exchange_url,
    1736             :                    index,
    1737             :                    value);
    1738          21 :         break;
    1739             :       }
    1740             :     }
    1741          21 :     if (! found)
    1742             :     {
    1743           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1744             :                   "Upload does not know how to handle `%s'\n",
    1745             :                   key);
    1746           0 :       global_ret = EXIT_FAILURE;
    1747           0 :       test_shutdown ();
    1748           0 :       return;
    1749             :     }
    1750             :   }
    1751             : }
    1752             : 
    1753             : 
    1754             : /**
    1755             :  * Upload operation result (signatures) to exchange.
    1756             :  *
    1757             :  * @param args the array of command-line arguments to process next
    1758             :  */
    1759             : static void
    1760          21 : do_upload (char *const *args)
    1761             : {
    1762          21 :   if (NULL != in)
    1763             :   {
    1764           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1765             :                 "Downloaded data was not consumed, refusing upload\n");
    1766           0 :     test_shutdown ();
    1767           0 :     global_ret = EXIT_FAILURE;
    1768           0 :     return;
    1769             :   }
    1770          21 :   if (NULL == out)
    1771             :   {
    1772             :     json_error_t err;
    1773             : 
    1774           0 :     out = json_loadf (stdin,
    1775             :                       JSON_REJECT_DUPLICATES,
    1776             :                       &err);
    1777           0 :     if (NULL == out)
    1778             :     {
    1779           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1780             :                   "Failed to read JSON input: %s at %d:%s (offset: %d)\n",
    1781             :                   err.text,
    1782             :                   err.line,
    1783             :                   err.source,
    1784             :                   err.position);
    1785           0 :       test_shutdown ();
    1786           0 :       global_ret = EXIT_FAILURE;
    1787           0 :       return;
    1788             :     }
    1789             :   }
    1790          21 :   if (! json_is_array (out))
    1791             :   {
    1792           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1793             :                 "Error: expected JSON array for `upload` command\n");
    1794           0 :     test_shutdown ();
    1795           0 :     global_ret = EXIT_FAILURE;
    1796           0 :     return;
    1797             :   }
    1798          34 :   if ( (NULL == CFG_exchange_url) &&
    1799             :        (GNUNET_OK !=
    1800          13 :         GNUNET_CONFIGURATION_get_value_string (kcfg,
    1801             :                                                "exchange",
    1802             :                                                "BASE_URL",
    1803             :                                                &CFG_exchange_url)) )
    1804             :   {
    1805           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1806             :                                "exchange",
    1807             :                                "BASE_URL");
    1808           0 :     global_ret = EXIT_NOTCONFIGURED;
    1809           0 :     test_shutdown ();
    1810           0 :     return;
    1811             :   }
    1812          21 :   trigger_upload (CFG_exchange_url);
    1813          21 :   json_decref (out);
    1814          21 :   out = NULL;
    1815             : }
    1816             : 
    1817             : 
    1818             : /**
    1819             :  * Revoke denomination key.
    1820             :  *
    1821             :  * @param args the array of command-line arguments to process next;
    1822             :  *        args[0] must be the hash of the denomination key to revoke
    1823             :  */
    1824             : static void
    1825           8 : do_revoke_denomination_key (char *const *args)
    1826             : {
    1827             :   struct GNUNET_HashCode h_denom_pub;
    1828             :   struct TALER_MasterSignatureP master_sig;
    1829             : 
    1830           8 :   if (NULL != in)
    1831             :   {
    1832           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1833             :                 "Downloaded data was not consumed, refusing revocation\n");
    1834           0 :     test_shutdown ();
    1835           0 :     global_ret = EXIT_FAILURE;
    1836           0 :     return;
    1837             :   }
    1838          16 :   if ( (NULL == args[0]) ||
    1839             :        (GNUNET_OK !=
    1840           8 :         GNUNET_STRINGS_string_to_data (args[0],
    1841             :                                        strlen (args[0]),
    1842             :                                        &h_denom_pub,
    1843             :                                        sizeof (h_denom_pub))) )
    1844             :   {
    1845           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1846             :                 "You must specify a denomination key with this subcommand\n");
    1847           0 :     test_shutdown ();
    1848           0 :     global_ret = EXIT_INVALIDARGUMENT;
    1849           0 :     return;
    1850             :   }
    1851           8 :   if (GNUNET_OK !=
    1852           8 :       load_offline_key (GNUNET_NO))
    1853           0 :     return;
    1854           8 :   TALER_exchange_offline_denomination_revoke_sign (&h_denom_pub,
    1855             :                                                    &master_priv,
    1856             :                                                    &master_sig);
    1857           8 :   output_operation (OP_REVOKE_DENOMINATION,
    1858           8 :                     GNUNET_JSON_PACK (
    1859             :                       GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1860             :                                                   &h_denom_pub),
    1861             :                       GNUNET_JSON_pack_data_auto ("master_sig",
    1862             :                                                   &master_sig)));
    1863           8 :   next (args + 1);
    1864             : }
    1865             : 
    1866             : 
    1867             : /**
    1868             :  * Revoke signkey.
    1869             :  *
    1870             :  * @param args the array of command-line arguments to process next;
    1871             :  *        args[0] must be the hash of the denomination key to revoke
    1872             :  */
    1873             : static void
    1874           0 : do_revoke_signkey (char *const *args)
    1875             : {
    1876             :   struct TALER_ExchangePublicKeyP exchange_pub;
    1877             :   struct TALER_MasterSignatureP master_sig;
    1878             : 
    1879           0 :   if (NULL != in)
    1880             :   {
    1881           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1882             :                 "Downloaded data was not consumed, refusing revocation\n");
    1883           0 :     test_shutdown ();
    1884           0 :     global_ret = EXIT_FAILURE;
    1885           0 :     return;
    1886             :   }
    1887           0 :   if ( (NULL == args[0]) ||
    1888             :        (GNUNET_OK !=
    1889           0 :         GNUNET_STRINGS_string_to_data (args[0],
    1890             :                                        strlen (args[0]),
    1891             :                                        &exchange_pub,
    1892             :                                        sizeof (exchange_pub))) )
    1893             :   {
    1894           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1895             :                 "You must specify an exchange signing key with this subcommand\n");
    1896           0 :     test_shutdown ();
    1897           0 :     global_ret = EXIT_INVALIDARGUMENT;
    1898           0 :     return;
    1899             :   }
    1900           0 :   if (GNUNET_OK !=
    1901           0 :       load_offline_key (GNUNET_NO))
    1902           0 :     return;
    1903           0 :   TALER_exchange_offline_signkey_revoke_sign (&exchange_pub,
    1904             :                                               &master_priv,
    1905             :                                               &master_sig);
    1906           0 :   output_operation (OP_REVOKE_SIGNKEY,
    1907           0 :                     GNUNET_JSON_PACK (
    1908             :                       GNUNET_JSON_pack_data_auto ("exchange_pub",
    1909             :                                                   &exchange_pub),
    1910             :                       GNUNET_JSON_pack_data_auto ("master_sig",
    1911             :                                                   &master_sig)));
    1912           0 :   next (args + 1);
    1913             : }
    1914             : 
    1915             : 
    1916             : /**
    1917             :  * Add auditor.
    1918             :  *
    1919             :  * @param args the array of command-line arguments to process next;
    1920             :  *        args[0] must be the auditor's public key, args[1] the auditor's
    1921             :  *        API base URL, and args[2] the auditor's name.
    1922             :  */
    1923             : static void
    1924           0 : do_add_auditor (char *const *args)
    1925             : {
    1926             :   struct TALER_MasterSignatureP master_sig;
    1927             :   struct TALER_AuditorPublicKeyP auditor_pub;
    1928             :   struct GNUNET_TIME_Absolute now;
    1929             : 
    1930           0 :   if (NULL != in)
    1931             :   {
    1932           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1933             :                 "Downloaded data was not consumed, not adding auditor\n");
    1934           0 :     test_shutdown ();
    1935           0 :     global_ret = EXIT_FAILURE;
    1936           0 :     return;
    1937             :   }
    1938           0 :   if ( (NULL == args[0]) ||
    1939             :        (GNUNET_OK !=
    1940           0 :         GNUNET_STRINGS_string_to_data (args[0],
    1941             :                                        strlen (args[0]),
    1942             :                                        &auditor_pub,
    1943             :                                        sizeof (auditor_pub))) )
    1944             :   {
    1945           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1946             :                 "You must specify an auditor public key as first argument for this subcommand\n");
    1947           0 :     test_shutdown ();
    1948           0 :     global_ret = EXIT_INVALIDARGUMENT;
    1949           0 :     return;
    1950             :   }
    1951             : 
    1952           0 :   if ( (NULL == args[1]) ||
    1953           0 :        (0 != strncmp ("http",
    1954           0 :                       args[1],
    1955           0 :                       strlen ("http"))) ||
    1956           0 :        (NULL == args[2]) )
    1957             :   {
    1958           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1959             :                 "You must specify an auditor URI and auditor name as 2nd and 3rd arguments to this subcommand\n");
    1960           0 :     test_shutdown ();
    1961           0 :     global_ret = EXIT_INVALIDARGUMENT;
    1962           0 :     return;
    1963             :   }
    1964           0 :   if (GNUNET_OK !=
    1965           0 :       load_offline_key (GNUNET_NO))
    1966           0 :     return;
    1967           0 :   now = GNUNET_TIME_absolute_get ();
    1968           0 :   (void) GNUNET_TIME_round_abs (&now);
    1969           0 :   TALER_exchange_offline_auditor_add_sign (&auditor_pub,
    1970           0 :                                            args[1],
    1971             :                                            now,
    1972             :                                            &master_priv,
    1973             :                                            &master_sig);
    1974           0 :   output_operation (OP_ENABLE_AUDITOR,
    1975           0 :                     GNUNET_JSON_PACK (
    1976             :                       GNUNET_JSON_pack_string ("auditor_url",
    1977             :                                                args[1]),
    1978             :                       GNUNET_JSON_pack_string ("auditor_name",
    1979             :                                                args[2]),
    1980             :                       GNUNET_JSON_pack_time_abs ("validity_start",
    1981             :                                                  now),
    1982             :                       GNUNET_JSON_pack_data_auto ("auditor_pub",
    1983             :                                                   &auditor_pub),
    1984             :                       GNUNET_JSON_pack_data_auto ("master_sig",
    1985             :                                                   &master_sig)));
    1986           0 :   next (args + 3);
    1987             : }
    1988             : 
    1989             : 
    1990             : /**
    1991             :  * Disable auditor account.
    1992             :  *
    1993             :  * @param args the array of command-line arguments to process next;
    1994             :  *        args[0] must be the hash of the denomination key to revoke
    1995             :  */
    1996             : static void
    1997           0 : do_del_auditor (char *const *args)
    1998             : {
    1999             :   struct TALER_MasterSignatureP master_sig;
    2000             :   struct TALER_AuditorPublicKeyP auditor_pub;
    2001             :   struct GNUNET_TIME_Absolute now;
    2002             : 
    2003           0 :   if (NULL != in)
    2004             :   {
    2005           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2006             :                 "Downloaded data was not consumed, not deleting auditor account\n");
    2007           0 :     test_shutdown ();
    2008           0 :     global_ret = EXIT_FAILURE;
    2009           0 :     return;
    2010             :   }
    2011           0 :   if ( (NULL == args[0]) ||
    2012             :        (GNUNET_OK !=
    2013           0 :         GNUNET_STRINGS_string_to_data (args[0],
    2014             :                                        strlen (args[0]),
    2015             :                                        &auditor_pub,
    2016             :                                        sizeof (auditor_pub))) )
    2017             :   {
    2018           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2019             :                 "You must specify an auditor public key as first argument for this subcommand\n");
    2020           0 :     test_shutdown ();
    2021           0 :     global_ret = EXIT_INVALIDARGUMENT;
    2022           0 :     return;
    2023             :   }
    2024           0 :   if (GNUNET_OK !=
    2025           0 :       load_offline_key (GNUNET_NO))
    2026           0 :     return;
    2027           0 :   now = GNUNET_TIME_absolute_get ();
    2028           0 :   (void) GNUNET_TIME_round_abs (&now);
    2029             : 
    2030           0 :   TALER_exchange_offline_auditor_del_sign (&auditor_pub,
    2031             :                                            now,
    2032             :                                            &master_priv,
    2033             :                                            &master_sig);
    2034           0 :   output_operation (OP_DISABLE_AUDITOR,
    2035           0 :                     GNUNET_JSON_PACK (
    2036             :                       GNUNET_JSON_pack_data_auto ("auditor_pub",
    2037             :                                                   &auditor_pub),
    2038             :                       GNUNET_JSON_pack_time_abs ("validity_end",
    2039             :                                                  now),
    2040             :                       GNUNET_JSON_pack_data_auto ("master_sig",
    2041             :                                                   &master_sig)));
    2042           0 :   next (args + 1);
    2043             : }
    2044             : 
    2045             : 
    2046             : /**
    2047             :  * Add wire account.
    2048             :  *
    2049             :  * @param args the array of command-line arguments to process next;
    2050             :  *        args[0] must be the hash of the denomination key to revoke
    2051             :  */
    2052             : static void
    2053           0 : do_add_wire (char *const *args)
    2054             : {
    2055             :   struct TALER_MasterSignatureP master_sig_add;
    2056             :   struct TALER_MasterSignatureP master_sig_wire;
    2057             :   struct GNUNET_TIME_Absolute now;
    2058             : 
    2059           0 :   if (NULL != in)
    2060             :   {
    2061           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2062             :                 "Downloaded data was not consumed, not adding wire account\n");
    2063           0 :     test_shutdown ();
    2064           0 :     global_ret = EXIT_FAILURE;
    2065           0 :     return;
    2066             :   }
    2067           0 :   if (NULL == args[0])
    2068             :   {
    2069           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2070             :                 "You must specify a payto://-URI with this subcommand\n");
    2071           0 :     test_shutdown ();
    2072           0 :     global_ret = EXIT_INVALIDARGUMENT;
    2073           0 :     return;
    2074             :   }
    2075           0 :   if (GNUNET_OK !=
    2076           0 :       load_offline_key (GNUNET_NO))
    2077           0 :     return;
    2078           0 :   now = GNUNET_TIME_absolute_get ();
    2079           0 :   (void) GNUNET_TIME_round_abs (&now);
    2080             : 
    2081             :   {
    2082             :     char *wire_method;
    2083             : 
    2084           0 :     wire_method = TALER_payto_get_method (args[0]);
    2085           0 :     if (NULL == wire_method)
    2086             :     {
    2087           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2088             :                   "payto:// URI `%s' is malformed\n",
    2089             :                   args[0]);
    2090           0 :       global_ret = EXIT_INVALIDARGUMENT;
    2091           0 :       test_shutdown ();
    2092           0 :       return;
    2093             :     }
    2094           0 :     GNUNET_free (wire_method);
    2095             :   }
    2096           0 :   TALER_exchange_offline_wire_add_sign (args[0],
    2097             :                                         now,
    2098             :                                         &master_priv,
    2099             :                                         &master_sig_add);
    2100           0 :   TALER_exchange_wire_signature_make (args[0],
    2101             :                                       &master_priv,
    2102             :                                       &master_sig_wire);
    2103           0 :   output_operation (OP_ENABLE_WIRE,
    2104           0 :                     GNUNET_JSON_PACK (
    2105             :                       GNUNET_JSON_pack_string ("payto_uri",
    2106             :                                                args[0]),
    2107             :                       GNUNET_JSON_pack_time_abs ("validity_start",
    2108             :                                                  now),
    2109             :                       GNUNET_JSON_pack_data_auto ("master_sig_add",
    2110             :                                                   &master_sig_add),
    2111             :                       GNUNET_JSON_pack_data_auto ("master_sig_wire",
    2112             :                                                   &master_sig_wire)));
    2113           0 :   next (args + 1);
    2114             : }
    2115             : 
    2116             : 
    2117             : /**
    2118             :  * Disable wire account.
    2119             :  *
    2120             :  * @param args the array of command-line arguments to process next;
    2121             :  *        args[0] must be the hash of the denomination key to revoke
    2122             :  */
    2123             : static void
    2124           0 : do_del_wire (char *const *args)
    2125             : {
    2126             :   struct TALER_MasterSignatureP master_sig;
    2127             :   struct GNUNET_TIME_Absolute now;
    2128             : 
    2129           0 :   if (NULL != in)
    2130             :   {
    2131           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2132             :                 "Downloaded data was not consumed, not deleting wire account\n");
    2133           0 :     test_shutdown ();
    2134           0 :     global_ret = EXIT_FAILURE;
    2135           0 :     return;
    2136             :   }
    2137           0 :   if (NULL == args[0])
    2138             :   {
    2139           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2140             :                 "You must specify a payto://-URI with this subcommand\n");
    2141           0 :     test_shutdown ();
    2142           0 :     global_ret = EXIT_INVALIDARGUMENT;
    2143           0 :     return;
    2144             :   }
    2145           0 :   if (GNUNET_OK !=
    2146           0 :       load_offline_key (GNUNET_NO))
    2147           0 :     return;
    2148           0 :   now = GNUNET_TIME_absolute_get ();
    2149           0 :   (void) GNUNET_TIME_round_abs (&now);
    2150             : 
    2151           0 :   TALER_exchange_offline_wire_del_sign (args[0],
    2152             :                                         now,
    2153             :                                         &master_priv,
    2154             :                                         &master_sig);
    2155           0 :   output_operation (OP_DISABLE_WIRE,
    2156           0 :                     GNUNET_JSON_PACK (
    2157             :                       GNUNET_JSON_pack_string ("payto_uri",
    2158             :                                                args[0]),
    2159             :                       GNUNET_JSON_pack_time_abs ("validity_end",
    2160             :                                                  now),
    2161             :                       GNUNET_JSON_pack_data_auto ("master_sig",
    2162             :                                                   &master_sig)));
    2163           0 :   next (args + 1);
    2164             : }
    2165             : 
    2166             : 
    2167             : /**
    2168             :  * Set wire fees for the given year.
    2169             :  *
    2170             :  * @param args the array of command-line arguments to process next;
    2171             :  *        args[0] must be the year, args[1] the wire fee and args[2]
    2172             :  *        the closing fee.
    2173             :  */
    2174             : static void
    2175           5 : do_set_wire_fee (char *const *args)
    2176             : {
    2177             :   struct TALER_MasterSignatureP master_sig;
    2178             :   char dummy;
    2179             :   unsigned int year;
    2180             :   struct TALER_Amount wire_fee;
    2181             :   struct TALER_Amount closing_fee;
    2182             :   struct GNUNET_TIME_Absolute start_time;
    2183             :   struct GNUNET_TIME_Absolute end_time;
    2184             : 
    2185           5 :   if (NULL != in)
    2186             :   {
    2187           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2188             :                 "Downloaded data was not consumed, not setting wire fee\n");
    2189           0 :     test_shutdown ();
    2190           0 :     global_ret = EXIT_FAILURE;
    2191           0 :     return;
    2192             :   }
    2193           5 :   if ( (NULL == args[0]) ||
    2194           5 :        (NULL == args[1]) ||
    2195           5 :        (NULL == args[2]) ||
    2196           5 :        (NULL == args[3]) ||
    2197           5 :        ( (1 != sscanf (args[0],
    2198             :                        "%u%c",
    2199             :                        &year,
    2200           5 :                        &dummy)) &&
    2201           5 :          (0 != strcasecmp ("now",
    2202           5 :                            args[0])) ) ||
    2203             :        (GNUNET_OK !=
    2204           5 :         TALER_string_to_amount (args[2],
    2205           5 :                                 &wire_fee)) ||
    2206             :        (GNUNET_OK !=
    2207           5 :         TALER_string_to_amount (args[3],
    2208             :                                 &closing_fee)) )
    2209             :   {
    2210           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2211             :                 "You must use YEAR, METHOD, WIRE-FEE and CLOSING-FEE as arguments for this subcommand\n");
    2212           0 :     test_shutdown ();
    2213           0 :     global_ret = EXIT_INVALIDARGUMENT;
    2214           0 :     return;
    2215             :   }
    2216           5 :   if (0 == strcasecmp ("now",
    2217             :                        args[0]))
    2218           5 :     year = GNUNET_TIME_get_current_year ();
    2219           5 :   if (GNUNET_OK !=
    2220           5 :       load_offline_key (GNUNET_NO))
    2221           0 :     return;
    2222           5 :   start_time = GNUNET_TIME_year_to_time (year);
    2223           5 :   end_time = GNUNET_TIME_year_to_time (year + 1);
    2224             : 
    2225           5 :   TALER_exchange_offline_wire_fee_sign (args[1],
    2226             :                                         start_time,
    2227             :                                         end_time,
    2228             :                                         &wire_fee,
    2229             :                                         &closing_fee,
    2230             :                                         &master_priv,
    2231             :                                         &master_sig);
    2232           5 :   output_operation (OP_SET_WIRE_FEE,
    2233           5 :                     GNUNET_JSON_PACK (
    2234             :                       GNUNET_JSON_pack_string ("wire_method",
    2235             :                                                args[1]),
    2236             :                       GNUNET_JSON_pack_time_abs ("start_time",
    2237             :                                                  start_time),
    2238             :                       GNUNET_JSON_pack_time_abs ("end_time",
    2239             :                                                  end_time),
    2240             :                       TALER_JSON_pack_amount ("wire_fee",
    2241             :                                               &wire_fee),
    2242             :                       TALER_JSON_pack_amount ("closing_fee",
    2243             :                                               &closing_fee),
    2244             :                       GNUNET_JSON_pack_data_auto ("master_sig",
    2245             :                                                   &master_sig)));
    2246           5 :   next (args + 4);
    2247             : }
    2248             : 
    2249             : 
    2250             : /**
    2251             :  * Function called with information about future keys.  Dumps the JSON output
    2252             :  * (on success), either into an internal buffer or to stdout (depending on
    2253             :  * whether there are subsequent commands).
    2254             :  *
    2255             :  * @param cls closure with the `char **` remaining args
    2256             :  * @param hr HTTP response data
    2257             :  * @param keys information about the various keys used
    2258             :  *        by the exchange, NULL if /management/keys failed
    2259             :  */
    2260             : static void
    2261          10 : download_cb (void *cls,
    2262             :              const struct TALER_EXCHANGE_HttpResponse *hr,
    2263             :              const struct TALER_EXCHANGE_FutureKeys *keys)
    2264             : {
    2265          10 :   char *const *args = cls;
    2266             : 
    2267          10 :   mgkh = NULL;
    2268          10 :   switch (hr->http_status)
    2269             :   {
    2270           8 :   case MHD_HTTP_OK:
    2271           8 :     break;
    2272           2 :   default:
    2273           2 :     if (0 != hr->http_status)
    2274           2 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2275             :                   "Failed to download keys from `%s': %s (HTTP status: %u/%u)\n",
    2276             :                   CFG_exchange_url,
    2277             :                   hr->hint,
    2278             :                   hr->http_status,
    2279             :                   (unsigned int) hr->ec);
    2280             :     else
    2281           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2282             :                   "Failed to download keys from `%s' (no HTTP response)\n",
    2283             :                   CFG_exchange_url);
    2284           2 :     test_shutdown ();
    2285           2 :     global_ret = EXIT_FAILURE;
    2286           2 :     return;
    2287             :   }
    2288           8 :   in = GNUNET_JSON_PACK (
    2289             :     GNUNET_JSON_pack_string ("operation",
    2290             :                              OP_INPUT_KEYS),
    2291             :     GNUNET_JSON_pack_object_incref ("arguments",
    2292             :                                     (json_t *) hr->reply));
    2293           8 :   if (NULL == args[0])
    2294             :   {
    2295           0 :     json_dumpf (in,
    2296             :                 stdout,
    2297             :                 JSON_INDENT (2));
    2298           0 :     json_decref (in);
    2299           0 :     in = NULL;
    2300             :   }
    2301           8 :   next (args);
    2302             : }
    2303             : 
    2304             : 
    2305             : /**
    2306             :  * Download future keys.
    2307             :  *
    2308             :  * @param args the array of command-line arguments to process next
    2309             :  */
    2310             : static void
    2311          10 : do_download (char *const *args)
    2312             : {
    2313          20 :   if ( (NULL == CFG_exchange_url) &&
    2314             :        (GNUNET_OK !=
    2315          10 :         GNUNET_CONFIGURATION_get_value_string (kcfg,
    2316             :                                                "exchange",
    2317             :                                                "BASE_URL",
    2318             :                                                &CFG_exchange_url)) )
    2319             :   {
    2320           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    2321             :                                "exchange",
    2322             :                                "BASE_URL");
    2323           0 :     test_shutdown ();
    2324           0 :     global_ret = EXIT_NOTCONFIGURED;
    2325           0 :     return;
    2326             :   }
    2327          10 :   mgkh = TALER_EXCHANGE_get_management_keys (ctx,
    2328             :                                              CFG_exchange_url,
    2329             :                                              &download_cb,
    2330             :                                              (void *) args);
    2331             : }
    2332             : 
    2333             : 
    2334             : /**
    2335             :  * Check that the security module keys are the same as before.  If we had no
    2336             :  * keys in store before, remember them (Trust On First Use).
    2337             :  *
    2338             :  * @param secm security module keys, must be an array of length 2
    2339             :  * @return #GNUNET_OK if keys match with what we have in store
    2340             :  *         #GNUNET_NO if we had nothing in store but now do
    2341             :  *         #GNUNET_SYSERR if keys changed from what we remember or other error
    2342             :  */
    2343             : static int
    2344           8 : tofu_check (const struct TALER_SecurityModulePublicKeyP secm[2])
    2345             : {
    2346             :   char *fn;
    2347             :   struct TALER_SecurityModulePublicKeyP old[2];
    2348             :   ssize_t ret;
    2349             : 
    2350           8 :   if (GNUNET_OK !=
    2351           8 :       GNUNET_CONFIGURATION_get_value_filename (kcfg,
    2352             :                                                "exchange-offline",
    2353             :                                                "SECM_TOFU_FILE",
    2354             :                                                &fn))
    2355             :   {
    2356           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    2357             :                                "exchange-offline",
    2358             :                                "SECM_TOFU_FILE");
    2359           0 :     return GNUNET_SYSERR;
    2360             :   }
    2361           8 :   if (GNUNET_OK ==
    2362           8 :       GNUNET_DISK_file_test (fn))
    2363             :   {
    2364           0 :     ret = GNUNET_DISK_fn_read (fn,
    2365             :                                &old,
    2366             :                                sizeof (old));
    2367           0 :     if (GNUNET_SYSERR != ret)
    2368             :     {
    2369           0 :       if (ret != sizeof (old))
    2370             :       {
    2371           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2372             :                     "File `%s' corrupt\n",
    2373             :                     fn);
    2374           0 :         GNUNET_free (fn);
    2375           0 :         return GNUNET_SYSERR;
    2376             :       }
    2377             :       /* TOFU check */
    2378           0 :       if (0 != memcmp (old,
    2379             :                        secm,
    2380             :                        sizeof (old)))
    2381             :       {
    2382           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2383             :                     "Fatal: security module keys changed (file `%s')!\n",
    2384             :                     fn);
    2385           0 :         GNUNET_free (fn);
    2386           0 :         return GNUNET_SYSERR;
    2387             :       }
    2388           0 :       GNUNET_free (fn);
    2389           0 :       return GNUNET_OK;
    2390             :     }
    2391             :   }
    2392             : 
    2393             :   {
    2394             :     char *key;
    2395             : 
    2396             :     /* check against SECMOD-keys pinned in configuration */
    2397           8 :     if (GNUNET_OK ==
    2398           8 :         GNUNET_CONFIGURATION_get_value_string (kcfg,
    2399             :                                                "exchange-offline",
    2400             :                                                "SECM_ESIGN_PUBKEY",
    2401             :                                                &key))
    2402             :     {
    2403             :       struct TALER_SecurityModulePublicKeyP k;
    2404             : 
    2405           0 :       if (GNUNET_OK !=
    2406           0 :           GNUNET_STRINGS_string_to_data (key,
    2407             :                                          strlen (key),
    2408             :                                          &k,
    2409             :                                          sizeof (k)))
    2410             :       {
    2411           0 :         GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    2412             :                                    "exchange-offline",
    2413             :                                    "SECM_ESIGN_PUBKEY",
    2414             :                                    "key malformed");
    2415           0 :         GNUNET_free (key);
    2416           0 :         return GNUNET_SYSERR;
    2417             :       }
    2418           0 :       GNUNET_free (key);
    2419           0 :       if (0 !=
    2420           0 :           GNUNET_memcmp (&k,
    2421             :                          &secm[1]))
    2422             :       {
    2423           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2424             :                     "ESIGN security module key does not match SECM_ESIGN_PUBKEY in configuration\n");
    2425           0 :         return GNUNET_SYSERR;
    2426             :       }
    2427             :     }
    2428           8 :     if (GNUNET_OK ==
    2429           8 :         GNUNET_CONFIGURATION_get_value_string (kcfg,
    2430             :                                                "exchange-offline",
    2431             :                                                "SECM_DENOM_PUBKEY",
    2432             :                                                &key))
    2433             :     {
    2434             :       struct TALER_SecurityModulePublicKeyP k;
    2435             : 
    2436           0 :       if (GNUNET_OK !=
    2437           0 :           GNUNET_STRINGS_string_to_data (key,
    2438             :                                          strlen (key),
    2439             :                                          &k,
    2440             :                                          sizeof (k)))
    2441             :       {
    2442           0 :         GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    2443             :                                    "exchange-offline",
    2444             :                                    "SECM_DENOM_PUBKEY",
    2445             :                                    "key malformed");
    2446           0 :         GNUNET_free (key);
    2447           0 :         return GNUNET_SYSERR;
    2448             :       }
    2449           0 :       GNUNET_free (key);
    2450           0 :       if (0 !=
    2451           0 :           GNUNET_memcmp (&k,
    2452             :                          &secm[0]))
    2453             :       {
    2454           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2455             :                     "DENOM security module key does not match SECM_DENOM_PUBKEY in configuration\n");
    2456           0 :         return GNUNET_SYSERR;
    2457             :       }
    2458             :     }
    2459             :   }
    2460           8 :   if (GNUNET_OK !=
    2461           8 :       GNUNET_DISK_directory_create_for_file (fn))
    2462             :   {
    2463           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2464             :                 "Failed create directory to store key material in file `%s'\n",
    2465             :                 fn);
    2466           0 :     GNUNET_free (fn);
    2467           0 :     return GNUNET_SYSERR;
    2468             :   }
    2469             :   /* persist keys for future runs */
    2470           8 :   if (GNUNET_OK !=
    2471           8 :       GNUNET_DISK_fn_write (fn,
    2472             :                             secm,
    2473             :                             sizeof (old),
    2474             :                             GNUNET_DISK_PERM_USER_READ))
    2475             :   {
    2476           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2477             :                 "Failed to store key material in file `%s'\n",
    2478             :                 fn);
    2479           0 :     GNUNET_free (fn);
    2480           0 :     return GNUNET_SYSERR;
    2481             :   }
    2482           8 :   return GNUNET_NO;
    2483             : }
    2484             : 
    2485             : 
    2486             : /**
    2487             :  * Output @a signkeys for human consumption.
    2488             :  *
    2489             :  * @param secm_pub security module public key used to sign the denominations
    2490             :  * @param signkeys keys to output
    2491             :  * @return #GNUNET_OK on success
    2492             :  */
    2493             : static int
    2494           0 : show_signkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
    2495             :                const json_t *signkeys)
    2496             : {
    2497             :   size_t index;
    2498             :   json_t *value;
    2499             : 
    2500           0 :   json_array_foreach (signkeys, index, value) {
    2501             :     const char *err_name;
    2502             :     unsigned int err_line;
    2503             :     struct TALER_ExchangePublicKeyP exchange_pub;
    2504             :     struct TALER_SecurityModuleSignatureP secm_sig;
    2505             :     struct GNUNET_TIME_Absolute start_time;
    2506             :     struct GNUNET_TIME_Absolute sign_end;
    2507             :     struct GNUNET_TIME_Absolute legal_end;
    2508             :     struct GNUNET_TIME_Relative duration;
    2509             :     struct GNUNET_JSON_Specification spec[] = {
    2510           0 :       GNUNET_JSON_spec_absolute_time ("stamp_start",
    2511             :                                       &start_time),
    2512           0 :       GNUNET_JSON_spec_absolute_time ("stamp_expire",
    2513             :                                       &sign_end),
    2514           0 :       GNUNET_JSON_spec_absolute_time ("stamp_end",
    2515             :                                       &legal_end),
    2516           0 :       GNUNET_JSON_spec_fixed_auto ("key",
    2517             :                                    &exchange_pub),
    2518           0 :       GNUNET_JSON_spec_fixed_auto ("signkey_secmod_sig",
    2519             :                                    &secm_sig),
    2520           0 :       GNUNET_JSON_spec_end ()
    2521             :     };
    2522             : 
    2523           0 :     if (GNUNET_OK !=
    2524           0 :         GNUNET_JSON_parse (value,
    2525             :                            spec,
    2526             :                            &err_name,
    2527             :                            &err_line))
    2528             :     {
    2529           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2530             :                   "Invalid input for signing key to 'show': %s#%u at %u (skipping)\n",
    2531             :                   err_name,
    2532             :                   err_line,
    2533             :                   (unsigned int) index);
    2534           0 :       json_dumpf (value,
    2535             :                   stderr,
    2536             :                   JSON_INDENT (2));
    2537           0 :       global_ret = EXIT_FAILURE;
    2538           0 :       test_shutdown ();
    2539           0 :       return GNUNET_SYSERR;
    2540             :     }
    2541           0 :     duration = GNUNET_TIME_absolute_get_difference (start_time,
    2542             :                                                     sign_end);
    2543           0 :     if (GNUNET_OK !=
    2544           0 :         TALER_exchange_secmod_eddsa_verify (&exchange_pub,
    2545             :                                             start_time,
    2546             :                                             duration,
    2547             :                                             secm_pub,
    2548             :                                             &secm_sig))
    2549             :     {
    2550           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2551             :                   "Invalid security module signature for signing key %s (aborting)\n",
    2552             :                   TALER_B2S (&exchange_pub));
    2553           0 :       global_ret = EXIT_FAILURE;
    2554           0 :       test_shutdown ();
    2555           0 :       return GNUNET_SYSERR;
    2556             :     }
    2557             :     {
    2558             :       char *legal_end_s;
    2559             : 
    2560           0 :       legal_end_s = GNUNET_strdup (
    2561             :         GNUNET_STRINGS_absolute_time_to_string (legal_end));
    2562           0 :       printf ("EXCHANGE-KEY %s starting at %s (used for: %s, legal end: %s)\n",
    2563             :               TALER_B2S (&exchange_pub),
    2564             :               GNUNET_STRINGS_absolute_time_to_string (start_time),
    2565             :               GNUNET_STRINGS_relative_time_to_string (duration,
    2566             :                                                       GNUNET_NO),
    2567             :               legal_end_s);
    2568           0 :       GNUNET_free (legal_end_s);
    2569             :     }
    2570             :   }
    2571           0 :   return GNUNET_OK;
    2572             : }
    2573             : 
    2574             : 
    2575             : /**
    2576             :  * Output @a denomkeys for human consumption.
    2577             :  *
    2578             :  * @param secm_pub security module public key used to sign the denominations
    2579             :  * @param denomkeys keys to output
    2580             :  * @return #GNUNET_OK on success
    2581             :  */
    2582             : static int
    2583           0 : show_denomkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
    2584             :                 const json_t *denomkeys)
    2585             : {
    2586             :   size_t index;
    2587             :   json_t *value;
    2588             : 
    2589           0 :   json_array_foreach (denomkeys, index, value) {
    2590             :     const char *err_name;
    2591             :     unsigned int err_line;
    2592             :     const char *section_name;
    2593             :     struct TALER_DenominationPublicKey denom_pub;
    2594             :     struct GNUNET_TIME_Absolute stamp_start;
    2595             :     struct GNUNET_TIME_Absolute stamp_expire_withdraw;
    2596             :     struct GNUNET_TIME_Absolute stamp_expire_deposit;
    2597             :     struct GNUNET_TIME_Absolute stamp_expire_legal;
    2598             :     struct TALER_Amount coin_value;
    2599             :     struct TALER_Amount fee_withdraw;
    2600             :     struct TALER_Amount fee_deposit;
    2601             :     struct TALER_Amount fee_refresh;
    2602             :     struct TALER_Amount fee_refund;
    2603             :     struct TALER_SecurityModuleSignatureP secm_sig;
    2604             :     struct GNUNET_JSON_Specification spec[] = {
    2605           0 :       GNUNET_JSON_spec_string ("section_name",
    2606             :                                &section_name),
    2607           0 :       GNUNET_JSON_spec_rsa_public_key ("denom_pub",
    2608             :                                        &denom_pub.rsa_public_key),
    2609           0 :       TALER_JSON_spec_amount ("value",
    2610             :                               currency,
    2611             :                               &coin_value),
    2612           0 :       TALER_JSON_spec_amount ("fee_withdraw",
    2613             :                               currency,
    2614             :                               &fee_withdraw),
    2615           0 :       TALER_JSON_spec_amount ("fee_deposit",
    2616             :                               currency,
    2617             :                               &fee_deposit),
    2618           0 :       TALER_JSON_spec_amount ("fee_refresh",
    2619             :                               currency,
    2620             :                               &fee_refresh),
    2621           0 :       TALER_JSON_spec_amount ("fee_refund",
    2622             :                               currency,
    2623             :                               &fee_refund),
    2624           0 :       GNUNET_JSON_spec_absolute_time ("stamp_start",
    2625             :                                       &stamp_start),
    2626           0 :       GNUNET_JSON_spec_absolute_time ("stamp_expire_withdraw",
    2627             :                                       &stamp_expire_withdraw),
    2628           0 :       GNUNET_JSON_spec_absolute_time ("stamp_expire_deposit",
    2629             :                                       &stamp_expire_deposit),
    2630           0 :       GNUNET_JSON_spec_absolute_time ("stamp_expire_legal",
    2631             :                                       &stamp_expire_legal),
    2632           0 :       GNUNET_JSON_spec_fixed_auto ("denom_secmod_sig",
    2633             :                                    &secm_sig),
    2634           0 :       GNUNET_JSON_spec_end ()
    2635             :     };
    2636             :     struct GNUNET_TIME_Relative duration;
    2637             :     struct GNUNET_HashCode h_denom_pub;
    2638             : 
    2639           0 :     if (GNUNET_OK !=
    2640           0 :         GNUNET_JSON_parse (value,
    2641             :                            spec,
    2642             :                            &err_name,
    2643             :                            &err_line))
    2644             :     {
    2645           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2646             :                   "Invalid input for denomination key to 'show': %s#%u at %u (skipping)\n",
    2647             :                   err_name,
    2648             :                   err_line,
    2649             :                   (unsigned int) index);
    2650           0 :       json_dumpf (value,
    2651             :                   stderr,
    2652             :                   JSON_INDENT (2));
    2653           0 :       GNUNET_JSON_parse_free (spec);
    2654           0 :       global_ret = EXIT_FAILURE;
    2655           0 :       test_shutdown ();
    2656           0 :       return GNUNET_SYSERR;
    2657             :     }
    2658           0 :     duration = GNUNET_TIME_absolute_get_difference (stamp_start,
    2659             :                                                     stamp_expire_withdraw);
    2660           0 :     GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key,
    2661             :                                        &h_denom_pub);
    2662           0 :     if (GNUNET_OK !=
    2663           0 :         TALER_exchange_secmod_rsa_verify (&h_denom_pub,
    2664             :                                           section_name,
    2665             :                                           stamp_start,
    2666             :                                           duration,
    2667             :                                           secm_pub,
    2668             :                                           &secm_sig))
    2669             :     {
    2670           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2671             :                   "Invalid security module signature for denomination key %s (aborting)\n",
    2672             :                   GNUNET_h2s (&h_denom_pub));
    2673           0 :       global_ret = EXIT_FAILURE;
    2674           0 :       test_shutdown ();
    2675           0 :       return GNUNET_SYSERR;
    2676             :     }
    2677             : 
    2678             :     {
    2679             :       char *withdraw_fee_s;
    2680             :       char *deposit_fee_s;
    2681             :       char *refresh_fee_s;
    2682             :       char *refund_fee_s;
    2683             :       char *deposit_s;
    2684             :       char *legal_s;
    2685             : 
    2686           0 :       withdraw_fee_s = TALER_amount_to_string (&fee_withdraw);
    2687           0 :       deposit_fee_s = TALER_amount_to_string (&fee_deposit);
    2688           0 :       refresh_fee_s = TALER_amount_to_string (&fee_refresh);
    2689           0 :       refund_fee_s = TALER_amount_to_string (&fee_refund);
    2690           0 :       deposit_s = GNUNET_strdup (
    2691             :         GNUNET_STRINGS_absolute_time_to_string (stamp_expire_deposit));
    2692           0 :       legal_s = GNUNET_strdup (
    2693             :         GNUNET_STRINGS_absolute_time_to_string (stamp_expire_legal));
    2694             : 
    2695           0 :       printf (
    2696             :         "DENOMINATION-KEY(%s) %s of value %s starting at %s "
    2697             :         "(used for: %s, deposit until: %s legal end: %s) with fees %s/%s/%s/%s\n",
    2698             :         section_name,
    2699             :         TALER_B2S (&h_denom_pub),
    2700             :         TALER_amount2s (&coin_value),
    2701             :         GNUNET_STRINGS_absolute_time_to_string (stamp_start),
    2702             :         GNUNET_STRINGS_relative_time_to_string (duration,
    2703             :                                                 GNUNET_NO),
    2704             :         deposit_s,
    2705             :         legal_s,
    2706             :         withdraw_fee_s,
    2707             :         deposit_fee_s,
    2708             :         refresh_fee_s,
    2709             :         refund_fee_s);
    2710           0 :       GNUNET_free (withdraw_fee_s);
    2711           0 :       GNUNET_free (deposit_fee_s);
    2712           0 :       GNUNET_free (refresh_fee_s);
    2713           0 :       GNUNET_free (refund_fee_s);
    2714           0 :       GNUNET_free (deposit_s);
    2715           0 :       GNUNET_free (legal_s);
    2716             :     }
    2717             : 
    2718           0 :     GNUNET_JSON_parse_free (spec);
    2719             :   }
    2720           0 :   return GNUNET_OK;
    2721             : }
    2722             : 
    2723             : 
    2724             : /**
    2725             :  * Parse the input of exchange keys for the 'show' and 'sign' commands.
    2726             :  *
    2727             :  * @param command_name name of the command, for logging
    2728             :  * @return NULL on error, otherwise the keys details to be free'd by caller
    2729             :  */
    2730             : static json_t *
    2731           8 : parse_keys_input (const char *command_name)
    2732             : {
    2733             :   const char *op_str;
    2734             :   json_t *keys;
    2735             :   struct GNUNET_JSON_Specification spec[] = {
    2736           8 :     GNUNET_JSON_spec_json ("arguments",
    2737             :                            &keys),
    2738           8 :     GNUNET_JSON_spec_string ("operation",
    2739             :                              &op_str),
    2740           8 :     GNUNET_JSON_spec_end ()
    2741             :   };
    2742             :   const char *err_name;
    2743             :   unsigned int err_line;
    2744             : 
    2745           8 :   if (NULL == in)
    2746             :   {
    2747             :     json_error_t err;
    2748             : 
    2749           0 :     in = json_loadf (stdin,
    2750             :                      JSON_REJECT_DUPLICATES,
    2751             :                      &err);
    2752           0 :     if (NULL == in)
    2753             :     {
    2754           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2755             :                   "Failed to read JSON input: %s at %d:%s (offset: %d)\n",
    2756             :                   err.text,
    2757             :                   err.line,
    2758             :                   err.source,
    2759             :                   err.position);
    2760           0 :       global_ret = EXIT_FAILURE;
    2761           0 :       test_shutdown ();
    2762           0 :       return NULL;
    2763             :     }
    2764             :   }
    2765           8 :   if (GNUNET_OK !=
    2766           8 :       GNUNET_JSON_parse (in,
    2767             :                          spec,
    2768             :                          &err_name,
    2769             :                          &err_line))
    2770             :   {
    2771           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2772             :                 "Invalid input to '%s': %s#%u (skipping)\n",
    2773             :                 command_name,
    2774             :                 err_name,
    2775             :                 err_line);
    2776           0 :     json_dumpf (in,
    2777             :                 stderr,
    2778             :                 JSON_INDENT (2));
    2779           0 :     global_ret = EXIT_FAILURE;
    2780           0 :     test_shutdown ();
    2781           0 :     return NULL;
    2782             :   }
    2783           8 :   if (0 != strcmp (op_str,
    2784             :                    OP_INPUT_KEYS))
    2785             :   {
    2786           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2787             :                 "Invalid input to '%s' : operation is `%s', expected `%s'\n",
    2788             :                 command_name,
    2789             :                 op_str,
    2790             :                 OP_INPUT_KEYS);
    2791           0 :     GNUNET_JSON_parse_free (spec);
    2792           0 :     return NULL;
    2793             :   }
    2794           8 :   json_decref (in);
    2795           8 :   in = NULL;
    2796           8 :   return keys;
    2797             : }
    2798             : 
    2799             : 
    2800             : /**
    2801             :  * Show future keys.
    2802             :  *
    2803             :  * @param args the array of command-line arguments to process next
    2804             :  */
    2805             : static void
    2806           0 : do_show (char *const *args)
    2807             : {
    2808             :   json_t *keys;
    2809             :   const char *err_name;
    2810             :   unsigned int err_line;
    2811             :   json_t *denomkeys;
    2812             :   json_t *signkeys;
    2813             :   struct TALER_MasterPublicKeyP mpub;
    2814             :   struct TALER_SecurityModulePublicKeyP secm[2];
    2815             :   struct GNUNET_JSON_Specification spec[] = {
    2816           0 :     GNUNET_JSON_spec_json ("future_denoms",
    2817             :                            &denomkeys),
    2818           0 :     GNUNET_JSON_spec_json ("future_signkeys",
    2819             :                            &signkeys),
    2820           0 :     GNUNET_JSON_spec_fixed_auto ("master_pub",
    2821             :                                  &mpub),
    2822           0 :     GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
    2823             :                                  &secm[0]),
    2824           0 :     GNUNET_JSON_spec_fixed_auto ("signkey_secmod_public_key",
    2825             :                                  &secm[1]),
    2826           0 :     GNUNET_JSON_spec_end ()
    2827             :   };
    2828             : 
    2829           0 :   keys = parse_keys_input ("show");
    2830           0 :   if (NULL == keys)
    2831           0 :     return;
    2832           0 :   if (GNUNET_OK !=
    2833           0 :       load_offline_key (GNUNET_NO))
    2834           0 :     return;
    2835           0 :   if (GNUNET_OK !=
    2836           0 :       GNUNET_JSON_parse (keys,
    2837             :                          spec,
    2838             :                          &err_name,
    2839             :                          &err_line))
    2840             :   {
    2841           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2842             :                 "Invalid input to 'show': %s #%u (skipping)\n",
    2843             :                 err_name,
    2844             :                 err_line);
    2845           0 :     json_dumpf (in,
    2846             :                 stderr,
    2847             :                 JSON_INDENT (2));
    2848           0 :     global_ret = EXIT_FAILURE;
    2849           0 :     test_shutdown ();
    2850           0 :     json_decref (keys);
    2851           0 :     return;
    2852             :   }
    2853           0 :   if (0 !=
    2854           0 :       GNUNET_memcmp (&master_pub,
    2855             :                      &mpub))
    2856             :   {
    2857           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2858             :                 "Fatal: exchange uses different master key!\n");
    2859           0 :     global_ret = EXIT_FAILURE;
    2860           0 :     test_shutdown ();
    2861           0 :     GNUNET_JSON_parse_free (spec);
    2862           0 :     json_decref (keys);
    2863           0 :     return;
    2864             :   }
    2865           0 :   if (GNUNET_SYSERR ==
    2866           0 :       tofu_check (secm))
    2867             :   {
    2868           0 :     global_ret = EXIT_FAILURE;
    2869           0 :     test_shutdown ();
    2870           0 :     GNUNET_JSON_parse_free (spec);
    2871           0 :     json_decref (keys);
    2872           0 :     return;
    2873             :   }
    2874           0 :   if ( (GNUNET_OK !=
    2875           0 :         show_signkeys (&secm[1],
    2876           0 :                        signkeys)) ||
    2877             :        (GNUNET_OK !=
    2878           0 :         show_denomkeys (&secm[0],
    2879             :                         denomkeys)) )
    2880             :   {
    2881           0 :     global_ret = EXIT_FAILURE;
    2882           0 :     test_shutdown ();
    2883           0 :     GNUNET_JSON_parse_free (spec);
    2884           0 :     json_decref (keys);
    2885           0 :     return;
    2886             :   }
    2887           0 :   json_decref (keys);
    2888           0 :   GNUNET_JSON_parse_free (spec);
    2889           0 :   next (args);
    2890             : }
    2891             : 
    2892             : 
    2893             : /**
    2894             :  * Sign @a signkeys with offline key.
    2895             :  *
    2896             :  * @param secm_pub security module public key used to sign the denominations
    2897             :  * @param signkeys keys to output
    2898             :  * @param[in,out] result array where to output the signatures
    2899             :  * @return #GNUNET_OK on success
    2900             :  */
    2901             : static int
    2902           8 : sign_signkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
    2903             :                const json_t *signkeys,
    2904             :                json_t *result)
    2905             : {
    2906             :   size_t index;
    2907             :   json_t *value;
    2908             : 
    2909          22 :   json_array_foreach (signkeys, index, value) {
    2910             :     const char *err_name;
    2911             :     unsigned int err_line;
    2912             :     struct TALER_ExchangePublicKeyP exchange_pub;
    2913             :     struct TALER_SecurityModuleSignatureP secm_sig;
    2914             :     struct GNUNET_TIME_Absolute start_time;
    2915             :     struct GNUNET_TIME_Absolute sign_end;
    2916             :     struct GNUNET_TIME_Absolute legal_end;
    2917             :     struct GNUNET_TIME_Relative duration;
    2918             :     struct GNUNET_JSON_Specification spec[] = {
    2919          14 :       GNUNET_JSON_spec_absolute_time ("stamp_start",
    2920             :                                       &start_time),
    2921          14 :       GNUNET_JSON_spec_absolute_time ("stamp_expire",
    2922             :                                       &sign_end),
    2923          14 :       GNUNET_JSON_spec_absolute_time ("stamp_end",
    2924             :                                       &legal_end),
    2925          14 :       GNUNET_JSON_spec_fixed_auto ("key",
    2926             :                                    &exchange_pub),
    2927          14 :       GNUNET_JSON_spec_fixed_auto ("signkey_secmod_sig",
    2928             :                                    &secm_sig),
    2929          14 :       GNUNET_JSON_spec_end ()
    2930             :     };
    2931             : 
    2932          14 :     if (GNUNET_OK !=
    2933          14 :         GNUNET_JSON_parse (value,
    2934             :                            spec,
    2935             :                            &err_name,
    2936             :                            &err_line))
    2937             :     {
    2938           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2939             :                   "Invalid input for signing key to 'show': %s #%u at %u (skipping)\n",
    2940             :                   err_name,
    2941             :                   err_line,
    2942             :                   (unsigned int) index);
    2943           0 :       json_dumpf (value,
    2944             :                   stderr,
    2945             :                   JSON_INDENT (2));
    2946           0 :       global_ret = EXIT_FAILURE;
    2947           0 :       test_shutdown ();
    2948           0 :       return GNUNET_SYSERR;
    2949             :     }
    2950             : 
    2951          14 :     duration = GNUNET_TIME_absolute_get_difference (start_time,
    2952             :                                                     sign_end);
    2953          14 :     if (GNUNET_OK !=
    2954          14 :         TALER_exchange_secmod_eddsa_verify (&exchange_pub,
    2955             :                                             start_time,
    2956             :                                             duration,
    2957             :                                             secm_pub,
    2958             :                                             &secm_sig))
    2959             :     {
    2960           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2961             :                   "Invalid security module signature for signing key %s (aborting)\n",
    2962             :                   TALER_B2S (&exchange_pub));
    2963           0 :       global_ret = EXIT_FAILURE;
    2964           0 :       test_shutdown ();
    2965           0 :       GNUNET_JSON_parse_free (spec);
    2966           0 :       return GNUNET_SYSERR;
    2967             :     }
    2968             :     {
    2969             :       struct TALER_MasterSignatureP master_sig;
    2970             : 
    2971          14 :       TALER_exchange_offline_signkey_validity_sign (&exchange_pub,
    2972             :                                                     start_time,
    2973             :                                                     sign_end,
    2974             :                                                     legal_end,
    2975             :                                                     &master_priv,
    2976             :                                                     &master_sig);
    2977          14 :       GNUNET_assert (0 ==
    2978             :                      json_array_append_new (
    2979             :                        result,
    2980             :                        GNUNET_JSON_PACK (
    2981             :                          GNUNET_JSON_pack_data_auto ("exchange_pub",
    2982             :                                                      &exchange_pub),
    2983             :                          GNUNET_JSON_pack_data_auto ("master_sig",
    2984             :                                                      &master_sig))));
    2985             :     }
    2986          14 :     GNUNET_JSON_parse_free (spec);
    2987             :   }
    2988           8 :   return GNUNET_OK;
    2989             : }
    2990             : 
    2991             : 
    2992             : /**
    2993             :  * Sign @a denomkeys with offline key.
    2994             :  *
    2995             :  * @param secm_pub security module public key used to sign the denominations
    2996             :  * @param denomkeys keys to output
    2997             :  * @param[in,out] result array where to output the signatures
    2998             :  * @return #GNUNET_OK on success
    2999             :  */
    3000             : static int
    3001           8 : sign_denomkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
    3002             :                 const json_t *denomkeys,
    3003             :                 json_t *result)
    3004             : {
    3005             :   size_t index;
    3006             :   json_t *value;
    3007             : 
    3008         124 :   json_array_foreach (denomkeys, index, value) {
    3009             :     const char *err_name;
    3010             :     unsigned int err_line;
    3011             :     const char *section_name;
    3012             :     struct TALER_DenominationPublicKey denom_pub;
    3013             :     struct GNUNET_TIME_Absolute stamp_start;
    3014             :     struct GNUNET_TIME_Absolute stamp_expire_withdraw;
    3015             :     struct GNUNET_TIME_Absolute stamp_expire_deposit;
    3016             :     struct GNUNET_TIME_Absolute stamp_expire_legal;
    3017             :     struct TALER_Amount coin_value;
    3018             :     struct TALER_Amount fee_withdraw;
    3019             :     struct TALER_Amount fee_deposit;
    3020             :     struct TALER_Amount fee_refresh;
    3021             :     struct TALER_Amount fee_refund;
    3022             :     struct TALER_SecurityModuleSignatureP secm_sig;
    3023             :     struct GNUNET_JSON_Specification spec[] = {
    3024         116 :       GNUNET_JSON_spec_string ("section_name",
    3025             :                                &section_name),
    3026         116 :       GNUNET_JSON_spec_rsa_public_key ("denom_pub",
    3027             :                                        &denom_pub.rsa_public_key),
    3028         116 :       TALER_JSON_spec_amount ("value",
    3029             :                               currency,
    3030             :                               &coin_value),
    3031         116 :       TALER_JSON_spec_amount ("fee_withdraw",
    3032             :                               currency,
    3033             :                               &fee_withdraw),
    3034         116 :       TALER_JSON_spec_amount ("fee_deposit",
    3035             :                               currency,
    3036             :                               &fee_deposit),
    3037         116 :       TALER_JSON_spec_amount ("fee_refresh",
    3038             :                               currency,
    3039             :                               &fee_refresh),
    3040         116 :       TALER_JSON_spec_amount ("fee_refund",
    3041             :                               currency,
    3042             :                               &fee_refund),
    3043         116 :       GNUNET_JSON_spec_absolute_time ("stamp_start",
    3044             :                                       &stamp_start),
    3045         116 :       GNUNET_JSON_spec_absolute_time ("stamp_expire_withdraw",
    3046             :                                       &stamp_expire_withdraw),
    3047         116 :       GNUNET_JSON_spec_absolute_time ("stamp_expire_deposit",
    3048             :                                       &stamp_expire_deposit),
    3049         116 :       GNUNET_JSON_spec_absolute_time ("stamp_expire_legal",
    3050             :                                       &stamp_expire_legal),
    3051         116 :       GNUNET_JSON_spec_fixed_auto ("denom_secmod_sig",
    3052             :                                    &secm_sig),
    3053         116 :       GNUNET_JSON_spec_end ()
    3054             :     };
    3055             :     struct GNUNET_TIME_Relative duration;
    3056             :     struct GNUNET_HashCode h_denom_pub;
    3057             : 
    3058         116 :     if (GNUNET_OK !=
    3059         116 :         GNUNET_JSON_parse (value,
    3060             :                            spec,
    3061             :                            &err_name,
    3062             :                            &err_line))
    3063             :     {
    3064           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3065             :                   "Invalid input for denomination key to 'sign': %s #%u at %u (skipping)\n",
    3066             :                   err_name,
    3067             :                   err_line,
    3068             :                   (unsigned int) index);
    3069           0 :       json_dumpf (value,
    3070             :                   stderr,
    3071             :                   JSON_INDENT (2));
    3072           0 :       GNUNET_JSON_parse_free (spec);
    3073           0 :       global_ret = EXIT_FAILURE;
    3074           0 :       test_shutdown ();
    3075           0 :       return GNUNET_SYSERR;
    3076             :     }
    3077         116 :     duration = GNUNET_TIME_absolute_get_difference (stamp_start,
    3078             :                                                     stamp_expire_withdraw);
    3079         116 :     GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key,
    3080             :                                        &h_denom_pub);
    3081         116 :     if (GNUNET_OK !=
    3082         116 :         TALER_exchange_secmod_rsa_verify (&h_denom_pub,
    3083             :                                           section_name,
    3084             :                                           stamp_start,
    3085             :                                           duration,
    3086             :                                           secm_pub,
    3087             :                                           &secm_sig))
    3088             :     {
    3089           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3090             :                   "Invalid security module signature for denomination key %s (aborting)\n",
    3091             :                   GNUNET_h2s (&h_denom_pub));
    3092           0 :       global_ret = EXIT_FAILURE;
    3093           0 :       test_shutdown ();
    3094           0 :       GNUNET_JSON_parse_free (spec);
    3095           0 :       return GNUNET_SYSERR;
    3096             :     }
    3097             : 
    3098             :     {
    3099             :       struct TALER_MasterSignatureP master_sig;
    3100             : 
    3101         116 :       TALER_exchange_offline_denom_validity_sign (&h_denom_pub,
    3102             :                                                   stamp_start,
    3103             :                                                   stamp_expire_withdraw,
    3104             :                                                   stamp_expire_deposit,
    3105             :                                                   stamp_expire_legal,
    3106             :                                                   &coin_value,
    3107             :                                                   &fee_withdraw,
    3108             :                                                   &fee_deposit,
    3109             :                                                   &fee_refresh,
    3110             :                                                   &fee_refund,
    3111             :                                                   &master_priv,
    3112             :                                                   &master_sig);
    3113         116 :       GNUNET_assert (0 ==
    3114             :                      json_array_append_new (
    3115             :                        result,
    3116             :                        GNUNET_JSON_PACK (
    3117             :                          GNUNET_JSON_pack_data_auto ("h_denom_pub",
    3118             :                                                      &h_denom_pub),
    3119             :                          GNUNET_JSON_pack_data_auto ("master_sig",
    3120             :                                                      &master_sig))));
    3121             :     }
    3122         116 :     GNUNET_JSON_parse_free (spec);
    3123             :   }
    3124           8 :   return GNUNET_OK;
    3125             : }
    3126             : 
    3127             : 
    3128             : /**
    3129             :  * Sign future keys.
    3130             :  *
    3131             :  * @param args the array of command-line arguments to process next
    3132             :  */
    3133             : static void
    3134           8 : do_sign (char *const *args)
    3135             : {
    3136             :   json_t *keys;
    3137             :   const char *err_name;
    3138             :   unsigned int err_line;
    3139             :   json_t *denomkeys;
    3140             :   json_t *signkeys;
    3141             :   struct TALER_MasterPublicKeyP mpub;
    3142             :   struct TALER_SecurityModulePublicKeyP secm[2];
    3143             :   struct GNUNET_JSON_Specification spec[] = {
    3144           8 :     GNUNET_JSON_spec_json ("future_denoms",
    3145             :                            &denomkeys),
    3146           8 :     GNUNET_JSON_spec_json ("future_signkeys",
    3147             :                            &signkeys),
    3148           8 :     GNUNET_JSON_spec_fixed_auto ("master_pub",
    3149             :                                  &mpub),
    3150           8 :     GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
    3151             :                                  &secm[0]),
    3152           8 :     GNUNET_JSON_spec_fixed_auto ("signkey_secmod_public_key",
    3153             :                                  &secm[1]),
    3154           8 :     GNUNET_JSON_spec_end ()
    3155             :   };
    3156             : 
    3157           8 :   keys = parse_keys_input ("sign");
    3158           8 :   if (NULL == keys)
    3159           0 :     return;
    3160           8 :   if (GNUNET_OK !=
    3161           8 :       load_offline_key (GNUNET_NO))
    3162             :   {
    3163           0 :     json_decref (keys);
    3164           0 :     return;
    3165             :   }
    3166           8 :   if (GNUNET_OK !=
    3167           8 :       GNUNET_JSON_parse (keys,
    3168             :                          spec,
    3169             :                          &err_name,
    3170             :                          &err_line))
    3171             :   {
    3172           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3173             :                 "Invalid input to 'sign' : %s #%u (skipping)\n",
    3174             :                 err_name,
    3175             :                 err_line);
    3176           0 :     json_dumpf (in,
    3177             :                 stderr,
    3178             :                 JSON_INDENT (2));
    3179           0 :     global_ret = EXIT_FAILURE;
    3180           0 :     test_shutdown ();
    3181           0 :     json_decref (keys);
    3182           0 :     return;
    3183             :   }
    3184           8 :   if (0 !=
    3185           8 :       GNUNET_memcmp (&master_pub,
    3186             :                      &mpub))
    3187             :   {
    3188           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3189             :                 "Fatal: exchange uses different master key!\n");
    3190           0 :     global_ret = EXIT_FAILURE;
    3191           0 :     test_shutdown ();
    3192           0 :     GNUNET_JSON_parse_free (spec);
    3193           0 :     json_decref (keys);
    3194           0 :     return;
    3195             :   }
    3196           8 :   if (GNUNET_SYSERR ==
    3197           8 :       tofu_check (secm))
    3198             :   {
    3199           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3200             :                 "Fatal: security module keys changed!\n");
    3201           0 :     global_ret = EXIT_FAILURE;
    3202           0 :     test_shutdown ();
    3203           0 :     GNUNET_JSON_parse_free (spec);
    3204           0 :     json_decref (keys);
    3205           0 :     return;
    3206             :   }
    3207             :   {
    3208           8 :     json_t *signkey_sig_array = json_array ();
    3209           8 :     json_t *denomkey_sig_array = json_array ();
    3210             : 
    3211           8 :     GNUNET_assert (NULL != signkey_sig_array);
    3212           8 :     GNUNET_assert (NULL != denomkey_sig_array);
    3213           8 :     if ( (GNUNET_OK !=
    3214           8 :           sign_signkeys (&secm[1],
    3215             :                          signkeys,
    3216           8 :                          signkey_sig_array)) ||
    3217             :          (GNUNET_OK !=
    3218           8 :           sign_denomkeys (&secm[0],
    3219             :                           denomkeys,
    3220             :                           denomkey_sig_array)) )
    3221             :     {
    3222           0 :       global_ret = EXIT_FAILURE;
    3223           0 :       test_shutdown ();
    3224           0 :       json_decref (signkey_sig_array);
    3225           0 :       json_decref (denomkey_sig_array);
    3226           0 :       GNUNET_JSON_parse_free (spec);
    3227           0 :       json_decref (keys);
    3228           0 :       return;
    3229             :     }
    3230             : 
    3231           8 :     output_operation (OP_UPLOAD_SIGS,
    3232           8 :                       GNUNET_JSON_PACK (
    3233             :                         GNUNET_JSON_pack_array_steal ("denom_sigs",
    3234             :                                                       denomkey_sig_array),
    3235             :                         GNUNET_JSON_pack_array_steal ("signkey_sigs",
    3236             :                                                       signkey_sig_array)));
    3237             :   }
    3238           8 :   GNUNET_JSON_parse_free (spec);
    3239           8 :   json_decref (keys);
    3240           8 :   next (args);
    3241             : }
    3242             : 
    3243             : 
    3244             : /**
    3245             :  * Setup and output offline signing key.
    3246             :  *
    3247             :  * @param args the array of command-line arguments to process next
    3248             :  */
    3249             : static void
    3250           0 : do_setup (char *const *args)
    3251             : {
    3252           0 :   if (GNUNET_OK !=
    3253           0 :       load_offline_key (GNUNET_YES))
    3254             :   {
    3255           0 :     global_ret = EXIT_NOPERMISSION;
    3256           0 :     return;
    3257             :   }
    3258           0 :   if (NULL != *args)
    3259             :   {
    3260           0 :     output_operation (OP_SETUP,
    3261           0 :                       GNUNET_JSON_PACK (
    3262             :                         GNUNET_JSON_pack_data_auto ("exchange_offline_pub",
    3263             :                                                     &master_pub)));
    3264             :   }
    3265             : 
    3266             :   else
    3267             :   {
    3268             :     char *pub_s;
    3269             : 
    3270           0 :     pub_s = GNUNET_STRINGS_data_to_string_alloc (&master_pub,
    3271             :                                                  sizeof (master_pub));
    3272           0 :     fprintf (stdout,
    3273             :              "%s\n",
    3274             :              pub_s);
    3275           0 :     GNUNET_free (pub_s);
    3276             :   }
    3277           0 :   if ( (NULL != *args) &&
    3278           0 :        (0 == strcmp (*args,
    3279             :                      "-")) )
    3280           0 :     args++;
    3281           0 :   next (args);
    3282             : }
    3283             : 
    3284             : 
    3285             : static void
    3286          52 : work (void *cls)
    3287             : {
    3288          52 :   char *const *args = cls;
    3289          52 :   struct SubCommand cmds[] = {
    3290             :     {
    3291             :       .name = "setup",
    3292             :       .help =
    3293             :         "initialize offline key signing material and display public offline key",
    3294             :       .cb = &do_setup
    3295             :     },
    3296             :     {
    3297             :       .name = "download",
    3298             :       .help =
    3299             :         "obtain future public keys from exchange (to be performed online!)",
    3300             :       .cb = &do_download
    3301             :     },
    3302             :     {
    3303             :       .name = "show",
    3304             :       .help =
    3305             :         "display future public keys from exchange for human review (pass '-' as argument to disable consuming input)",
    3306             :       .cb = &do_show
    3307             :     },
    3308             :     {
    3309             :       .name = "sign",
    3310             :       .help = "sign all future public keys from the input",
    3311             :       .cb = &do_sign
    3312             :     },
    3313             :     {
    3314             :       .name = "revoke-denomination",
    3315             :       .help =
    3316             :         "revoke denomination key (hash of public key must be given as argument)",
    3317             :       .cb = &do_revoke_denomination_key
    3318             :     },
    3319             :     {
    3320             :       .name = "revoke-signkey",
    3321             :       .help =
    3322             :         "revoke exchange online signing key (public key must be given as argument)",
    3323             :       .cb = &do_revoke_signkey
    3324             :     },
    3325             :     {
    3326             :       .name = "enable-auditor",
    3327             :       .help =
    3328             :         "enable auditor for the exchange (auditor-public key, auditor-URI and auditor-name must be given as arguments)",
    3329             :       .cb = &do_add_auditor
    3330             :     },
    3331             :     {
    3332             :       .name = "disable-auditor",
    3333             :       .help =
    3334             :         "disable auditor at the exchange (auditor-public key must be given as argument)",
    3335             :       .cb = &do_del_auditor
    3336             :     },
    3337             :     {
    3338             :       .name = "enable-account",
    3339             :       .help =
    3340             :         "enable wire account of the exchange (payto-URI must be given as argument)",
    3341             :       .cb = &do_add_wire
    3342             :     },
    3343             :     {
    3344             :       .name = "disable-account",
    3345             :       .help =
    3346             :         "disable wire account of the exchange (payto-URI must be given as argument)",
    3347             :       .cb = &do_del_wire
    3348             :     },
    3349             :     {
    3350             :       .name = "wire-fee",
    3351             :       .help =
    3352             :         "sign wire fees for the given year (year, wire method, wire fee and closing fee must be given as arguments)",
    3353             :       .cb = &do_set_wire_fee
    3354             :     },
    3355             :     {
    3356             :       .name = "upload",
    3357             :       .help =
    3358             :         "upload operation result to exchange (to be performed online!)",
    3359             :       .cb = &do_upload
    3360             :     },
    3361             :     /* list terminator */
    3362             :     {
    3363             :       .name = NULL,
    3364             :     }
    3365             :   };
    3366             :   (void) cls;
    3367             : 
    3368          52 :   nxt = NULL;
    3369         399 :   for (unsigned int i = 0; NULL != cmds[i].name; i++)
    3370             :   {
    3371         399 :     if (0 == strcasecmp (cmds[i].name,
    3372             :                          args[0]))
    3373             :     {
    3374          52 :       cmds[i].cb (&args[1]);
    3375          52 :       return;
    3376             :     }
    3377             :   }
    3378             : 
    3379           0 :   if (0 != strcasecmp ("help",
    3380             :                        args[0]))
    3381             :   {
    3382           0 :     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    3383             :                 "Unexpected command `%s'\n",
    3384             :                 args[0]);
    3385           0 :     global_ret = EXIT_INVALIDARGUMENT;
    3386             :   }
    3387           0 :   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    3388             :               "Supported subcommands:\n");
    3389           0 :   for (unsigned int i = 0; NULL != cmds[i].name; i++)
    3390             :   {
    3391           0 :     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    3392             :                 "- %s: %s\n",
    3393             :                 cmds[i].name,
    3394             :                 cmds[i].help);
    3395             :   }
    3396             : }
    3397             : 
    3398             : 
    3399             : /**
    3400             :  * Main function that will be run.
    3401             :  *
    3402             :  * @param cls closure
    3403             :  * @param args remaining command-line arguments
    3404             :  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
    3405             :  * @param cfg configuration
    3406             :  */
    3407             : static void
    3408          23 : run (void *cls,
    3409             :      char *const *args,
    3410             :      const char *cfgfile,
    3411             :      const struct GNUNET_CONFIGURATION_Handle *cfg)
    3412             : {
    3413          23 :   kcfg = cfg;
    3414          23 :   if (GNUNET_OK !=
    3415          23 :       TALER_config_get_currency (kcfg,
    3416             :                                  &currency))
    3417             :   {
    3418           0 :     global_ret = EXIT_NOTCONFIGURED;
    3419           0 :     return;
    3420             :   }
    3421          23 :   ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
    3422             :                           &rc);
    3423          23 :   rc = GNUNET_CURL_gnunet_rc_create (ctx);
    3424          23 :   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
    3425             :                                  NULL);
    3426          23 :   next (args);
    3427             : }
    3428             : 
    3429             : 
    3430             : /**
    3431             :  * The main function of the taler-exchange-offline tool.  This tool is used to
    3432             :  * create the signing and denomination keys for the exchange.  It uses the
    3433             :  * long-term offline private key and generates signatures with it. It also
    3434             :  * supports online operations with the exchange to download its input data and
    3435             :  * to upload its results. Those online operations should be performed on
    3436             :  * another machine in production!
    3437             :  *
    3438             :  * @param argc number of arguments from the command line
    3439             :  * @param argv command line arguments
    3440             :  * @return 0 ok, 1 on error
    3441             :  */
    3442             : int
    3443          23 : main (int argc,
    3444             :       char *const *argv)
    3445             : {
    3446          23 :   struct GNUNET_GETOPT_CommandLineOption options[] = {
    3447             :     GNUNET_GETOPT_OPTION_END
    3448             :   };
    3449             :   enum GNUNET_GenericReturnValue ret;
    3450             : 
    3451             :   /* force linker to link against libtalerutil; if we do
    3452             :      not do this, the linker may "optimize" libtalerutil
    3453             :      away and skip #TALER_OS_init(), which we do need */
    3454          23 :   (void) TALER_project_data_default ();
    3455          23 :   if (GNUNET_OK !=
    3456          23 :       GNUNET_STRINGS_get_utf8_args (argc, argv,
    3457             :                                     &argc, &argv))
    3458           0 :     return EXIT_INVALIDARGUMENT;
    3459          23 :   TALER_OS_init ();
    3460          23 :   ret = GNUNET_PROGRAM_run (
    3461             :     argc, argv,
    3462             :     "taler-exchange-offline",
    3463             :     gettext_noop ("Operations for offline signing for a Taler exchange"),
    3464             :     options,
    3465             :     &run, NULL);
    3466          23 :   GNUNET_free_nz ((void *) argv);
    3467          23 :   if (GNUNET_SYSERR == ret)
    3468           0 :     return EXIT_INVALIDARGUMENT;
    3469          23 :   if (GNUNET_NO == ret)
    3470           0 :     return EXIT_SUCCESS;
    3471          23 :   return global_ret;
    3472             : }
    3473             : 
    3474             : 
    3475             : /* end of taler-exchange-offline.c */

Generated by: LCOV version 1.14