LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_keys.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 929 1238 75.0 %
Date: 2025-07-09 07:38:29 Functions: 68 74 91.9 %

          Line data    Source code
       1             : /*
       2             :    This file is part of TALER
       3             :    Copyright (C) 2020-2024 Taler Systems SA
       4             : 
       5             :    TALER is free software; you can redistribute it and/or modify it under the
       6             :    terms of the GNU Affero 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 Affero General Public License for more details.
      12             : 
      13             :    You should have received a copy of the GNU Affero General Public License along with
      14             :    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             :  */
      16             : /**
      17             :  * @file taler-exchange-httpd_keys.c
      18             :  * @brief management of our various keys
      19             :  * @author Christian Grothoff
      20             :  * @author Özgür Kesim
      21             :  */
      22             : #include "taler/platform.h"
      23             : #include "taler/taler_json_lib.h"
      24             : #include "taler/taler_mhd_lib.h"
      25             : #include "taler/taler_kyclogic_lib.h"
      26             : #include "taler/taler_dbevents.h"
      27             : #include "taler-exchange-httpd.h"
      28             : #include "taler-exchange-httpd_config.h"
      29             : #include "taler-exchange-httpd_keys.h"
      30             : #include "taler-exchange-httpd_responses.h"
      31             : #include "taler/taler_exchangedb_plugin.h"
      32             : #include "taler/taler_extensions.h"
      33             : 
      34             : 
      35             : /**
      36             :  * How many /keys request do we hold in suspension at
      37             :  * most at any time?
      38             :  */
      39             : #define SKR_LIMIT 32
      40             : 
      41             : 
      42             : /**
      43             :  * When do we forcefully timeout a /keys request?
      44             :  * Matches the 120s hard-coded into exchange_api_handle.c
      45             :  */
      46             : #define KEYS_TIMEOUT \
      47             :         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
      48             : 
      49             : 
      50             : /**
      51             :  * Information about a denomination on offer by the denomination helper.
      52             :  */
      53             : struct HelperDenomination
      54             : {
      55             : 
      56             :   /**
      57             :    * When will the helper start to use this key for signing?
      58             :    */
      59             :   struct GNUNET_TIME_Timestamp start_time;
      60             : 
      61             :   /**
      62             :    * For how long will the helper allow signing? 0 if
      63             :    * the key was revoked or purged.
      64             :    */
      65             :   struct GNUNET_TIME_Relative validity_duration;
      66             : 
      67             :   /**
      68             :    * Hash of the full denomination key.
      69             :    */
      70             :   struct TALER_DenominationHashP h_denom_pub;
      71             : 
      72             :   /**
      73             :    * Signature over this key from the security module's key.
      74             :    */
      75             :   struct TALER_SecurityModuleSignatureP sm_sig;
      76             : 
      77             :   /**
      78             :    * The (full) public key.
      79             :    */
      80             :   struct TALER_DenominationPublicKey denom_pub;
      81             : 
      82             :   /**
      83             :    * Details depend on the @e denom_pub.cipher type.
      84             :    */
      85             :   union
      86             :   {
      87             : 
      88             :     /**
      89             :      * Hash of the RSA key.
      90             :      */
      91             :     struct TALER_RsaPubHashP h_rsa;
      92             : 
      93             :     /**
      94             :      * Hash of the CS key.
      95             :      */
      96             :     struct TALER_CsPubHashP h_cs;
      97             : 
      98             :   } h_details;
      99             : 
     100             :   /**
     101             :    * Name in configuration section for this denomination type.
     102             :    */
     103             :   char *section_name;
     104             : 
     105             : 
     106             : };
     107             : 
     108             : 
     109             : /**
     110             :  * Signatures of an auditor over a denomination key of this exchange.
     111             :  */
     112             : struct TEH_AuditorSignature
     113             : {
     114             :   /**
     115             :    * We store the signatures in a DLL.
     116             :    */
     117             :   struct TEH_AuditorSignature *prev;
     118             : 
     119             :   /**
     120             :    * We store the signatures in a DLL.
     121             :    */
     122             :   struct TEH_AuditorSignature *next;
     123             : 
     124             :   /**
     125             :    * A signature from the auditor.
     126             :    */
     127             :   struct TALER_AuditorSignatureP asig;
     128             : 
     129             :   /**
     130             :    * Public key of the auditor.
     131             :    */
     132             :   struct TALER_AuditorPublicKeyP apub;
     133             : 
     134             : };
     135             : 
     136             : 
     137             : /**
     138             :  * Information about a signing key on offer by the esign helper.
     139             :  */
     140             : struct HelperSignkey
     141             : {
     142             :   /**
     143             :    * When will the helper start to use this key for signing?
     144             :    */
     145             :   struct GNUNET_TIME_Timestamp start_time;
     146             : 
     147             :   /**
     148             :    * For how long will the helper allow signing? 0 if
     149             :    * the key was revoked or purged.
     150             :    */
     151             :   struct GNUNET_TIME_Relative validity_duration;
     152             : 
     153             :   /**
     154             :    * The public key.
     155             :    */
     156             :   struct TALER_ExchangePublicKeyP exchange_pub;
     157             : 
     158             :   /**
     159             :    * Signature over this key from the security module's key.
     160             :    */
     161             :   struct TALER_SecurityModuleSignatureP sm_sig;
     162             : 
     163             : };
     164             : 
     165             : 
     166             : /**
     167             :  * State associated with the crypto helpers / security modules.  NOT updated
     168             :  * when the #key_generation is updated (instead constantly kept in sync
     169             :  * whenever #TEH_keys_get_state() is called).
     170             :  */
     171             : struct HelperState
     172             : {
     173             : 
     174             :   /**
     175             :    * Handle for the esign/EdDSA helper.
     176             :    */
     177             :   struct TALER_CRYPTO_ExchangeSignHelper *esh;
     178             : 
     179             :   /**
     180             :    * Handle for the denom/RSA helper.
     181             :    */
     182             :   struct TALER_CRYPTO_RsaDenominationHelper *rsadh;
     183             : 
     184             :   /**
     185             :    * Handle for the denom/CS helper.
     186             :    */
     187             :   struct TALER_CRYPTO_CsDenominationHelper *csdh;
     188             : 
     189             :   /**
     190             :    * Map from H(denom_pub) to `struct HelperDenomination` entries.
     191             :    */
     192             :   struct GNUNET_CONTAINER_MultiHashMap *denom_keys;
     193             : 
     194             :   /**
     195             :    * Map from H(rsa_pub) to `struct HelperDenomination` entries.
     196             :    */
     197             :   struct GNUNET_CONTAINER_MultiHashMap *rsa_keys;
     198             : 
     199             :   /**
     200             :    * Map from H(cs_pub) to `struct HelperDenomination` entries.
     201             :    */
     202             :   struct GNUNET_CONTAINER_MultiHashMap *cs_keys;
     203             : 
     204             :   /**
     205             :    * Map from `struct TALER_ExchangePublicKey` to `struct HelperSignkey`
     206             :    * entries.  Based on the fact that a `struct GNUNET_PeerIdentity` is also
     207             :    * an EdDSA public key.
     208             :    */
     209             :   struct GNUNET_CONTAINER_MultiPeerMap *esign_keys;
     210             : 
     211             : };
     212             : 
     213             : 
     214             : /**
     215             :  * Entry in (sorted) array with possible pre-build responses for /keys.
     216             :  * We keep pre-build responses for the various (valid) cherry-picking
     217             :  * values around.
     218             :  */
     219             : struct KeysResponseData
     220             : {
     221             : 
     222             :   /**
     223             :    * Response to return if the client supports (deflate) compression.
     224             :    */
     225             :   struct MHD_Response *response_compressed;
     226             : 
     227             :   /**
     228             :    * Response to return if the client does not support compression.
     229             :    */
     230             :   struct MHD_Response *response_uncompressed;
     231             : 
     232             :   /**
     233             :    * ETag for these responses.
     234             :    */
     235             :   char *etag;
     236             : 
     237             :   /**
     238             :    * Cherry-picking timestamp the client must have set for this
     239             :    * response to be valid.  0 if this is the "full" response.
     240             :    * The client's request must include this date or a higher one
     241             :    * for this response to be applicable.
     242             :    */
     243             :   struct GNUNET_TIME_Timestamp cherry_pick_date;
     244             : 
     245             : };
     246             : 
     247             : 
     248             : /**
     249             :  * @brief All information about an exchange online signing key (which is used to
     250             :  * sign messages from the exchange).
     251             :  */
     252             : struct SigningKey
     253             : {
     254             : 
     255             :   /**
     256             :    * The exchange's (online signing) public key.
     257             :    */
     258             :   struct TALER_ExchangePublicKeyP exchange_pub;
     259             : 
     260             :   /**
     261             :    * Meta data about the signing key, such as validity periods.
     262             :    */
     263             :   struct TALER_EXCHANGEDB_SignkeyMetaData meta;
     264             : 
     265             :   /**
     266             :    * The long-term offline master key's signature for this signing key.
     267             :    * Signs over @e exchange_pub and @e meta.
     268             :    */
     269             :   struct TALER_MasterSignatureP master_sig;
     270             : 
     271             : };
     272             : 
     273             : struct TEH_KeyStateHandle
     274             : {
     275             : 
     276             :   /**
     277             :    * Mapping from denomination keys to denomination key issue struct.
     278             :    * Used to lookup the key by hash.
     279             :    */
     280             :   struct GNUNET_CONTAINER_MultiHashMap *denomkey_map;
     281             : 
     282             :   /**
     283             :    * Mapping from serial ID's to denomination key issue struct.
     284             :    * Used to lookup the key by serial ID.
     285             :    *
     286             :    * FIXME: We need a 64-bit version of this in GNUNET.
     287             :    */
     288             :   struct GNUNET_CONTAINER_MultiHashMap32 *denomserial_map;
     289             : 
     290             :   /**
     291             :    * Map from `struct TALER_ExchangePublicKey` to `struct SigningKey`
     292             :    * entries.  Based on the fact that a `struct GNUNET_PeerIdentity` is also
     293             :    * an EdDSA public key.
     294             :    */
     295             :   struct GNUNET_CONTAINER_MultiPeerMap *signkey_map;
     296             : 
     297             :   /**
     298             :    * Head of DLL of our global fees.
     299             :    */
     300             :   struct TEH_GlobalFee *gf_head;
     301             : 
     302             :   /**
     303             :    * Tail of DLL of our global fees.
     304             :    */
     305             :   struct TEH_GlobalFee *gf_tail;
     306             : 
     307             :   /**
     308             :    * json array with the auditors of this exchange. Contains exactly
     309             :    * the information needed for the "auditors" field of the /keys response.
     310             :    */
     311             :   json_t *auditors;
     312             : 
     313             :   /**
     314             :    * json array with the global fees of this exchange. Contains exactly
     315             :    * the information needed for the "global_fees" field of the /keys response.
     316             :    */
     317             :   json_t *global_fees;
     318             : 
     319             :   /**
     320             :    * Sorted array of responses to /keys (MUST be sorted by cherry-picking date) of
     321             :    * length @e krd_array_length;
     322             :    */
     323             :   struct KeysResponseData *krd_array;
     324             : 
     325             :   /**
     326             :    * Length of the @e krd_array.
     327             :    */
     328             :   unsigned int krd_array_length;
     329             : 
     330             :   /**
     331             :    * Information we track for thecrypto helpers.  Preserved
     332             :    * when the @e key_generation changes, thus kept separate.
     333             :    */
     334             :   struct HelperState *helpers;
     335             : 
     336             :   /**
     337             :    * Cached reply for a GET /management/keys request.  Used so we do not
     338             :    * re-create the reply every time.
     339             :    */
     340             :   json_t *management_keys_reply;
     341             : 
     342             :   /**
     343             :    * For which (global) key_generation was this data structure created?
     344             :    * Used to check when we are outdated and need to be re-generated.
     345             :    */
     346             :   uint64_t key_generation;
     347             : 
     348             :   /**
     349             :    * When did we initiate the key reloading?
     350             :    */
     351             :   struct GNUNET_TIME_Timestamp reload_time;
     352             : 
     353             :   /**
     354             :    * What is the period at which we rotate keys
     355             :    * (signing or denomination keys)?
     356             :    */
     357             :   struct GNUNET_TIME_Relative rekey_frequency;
     358             : 
     359             :   /**
     360             :    * When does our online signing key expire and we
     361             :    * thus need to re-generate this response?
     362             :    */
     363             :   struct GNUNET_TIME_Timestamp signature_expires;
     364             : 
     365             :   /**
     366             :    * True if #finish_keys_response() was not yet run and this key state
     367             :    * is only suitable for the /management/keys API.
     368             :    */
     369             :   bool management_only;
     370             : 
     371             : };
     372             : 
     373             : 
     374             : /**
     375             :  * Entry of /keys requests that are currently suspended because we are
     376             :  * waiting for /keys to become ready.
     377             :  */
     378             : struct SuspendedKeysRequests
     379             : {
     380             :   /**
     381             :    * Kept in a DLL.
     382             :    */
     383             :   struct SuspendedKeysRequests *next;
     384             : 
     385             :   /**
     386             :    * Kept in a DLL.
     387             :    */
     388             :   struct SuspendedKeysRequests *prev;
     389             : 
     390             :   /**
     391             :    * The suspended connection.
     392             :    */
     393             :   struct MHD_Connection *connection;
     394             : 
     395             :   /**
     396             :    * When does this request timeout?
     397             :    */
     398             :   struct GNUNET_TIME_Absolute timeout;
     399             : };
     400             : 
     401             : 
     402             : /**
     403             :  * Information we track about wire fees.
     404             :  */
     405             : struct WireFeeSet
     406             : {
     407             : 
     408             :   /**
     409             :    * Kept in a DLL.
     410             :    */
     411             :   struct WireFeeSet *next;
     412             : 
     413             :   /**
     414             :    * Kept in a DLL.
     415             :    */
     416             :   struct WireFeeSet *prev;
     417             : 
     418             :   /**
     419             :    * Actual fees.
     420             :    */
     421             :   struct TALER_WireFeeSet fees;
     422             : 
     423             :   /**
     424             :    * Start date of fee validity (inclusive).
     425             :    */
     426             :   struct GNUNET_TIME_Timestamp start_date;
     427             : 
     428             :   /**
     429             :    * End date of fee validity (exclusive).
     430             :    */
     431             :   struct GNUNET_TIME_Timestamp end_date;
     432             : 
     433             :   /**
     434             :    * Wire method the fees apply to.
     435             :    */
     436             :   char *method;
     437             : };
     438             : 
     439             : 
     440             : /**
     441             :  * State we keep per thread to cache the wire part of the /keys response.
     442             :  */
     443             : struct WireStateHandle
     444             : {
     445             : 
     446             :   /**
     447             :    * JSON reply for wire response.
     448             :    */
     449             :   json_t *json_reply;
     450             : 
     451             :   /**
     452             :    * ETag for this response (if any).
     453             :    */
     454             :   char *etag;
     455             : 
     456             :   /**
     457             :    * head of DLL of wire fees.
     458             :    */
     459             :   struct WireFeeSet *wfs_head;
     460             : 
     461             :   /**
     462             :    * Tail of DLL of wire fees.
     463             :    */
     464             :   struct WireFeeSet *wfs_tail;
     465             : 
     466             :   /**
     467             :    * Earliest timestamp of all the wire methods when we have no more fees.
     468             :    */
     469             :   struct GNUNET_TIME_Absolute cache_expiration;
     470             : 
     471             :   /**
     472             :    * @e cache_expiration time, formatted.
     473             :    */
     474             :   char dat[128];
     475             : 
     476             :   /**
     477             :    * For which (global) wire_generation was this data structure created?
     478             :    * Used to check when we are outdated and need to be re-generated.
     479             :    */
     480             :   uint64_t wire_generation;
     481             : 
     482             :   /**
     483             :    * Is the wire data ready?
     484             :    */
     485             :   bool ready;
     486             : 
     487             : };
     488             : 
     489             : 
     490             : /**
     491             :  * Stores the latest generation of our wire response.
     492             :  */
     493             : static struct WireStateHandle *wire_state;
     494             : 
     495             : /**
     496             :  * Handler listening for wire updates by other exchange
     497             :  * services.
     498             :  */
     499             : static struct GNUNET_DB_EventHandler *wire_eh;
     500             : 
     501             : /**
     502             :  * Counter incremented whenever we have a reason to re-build the #wire_state
     503             :  * because something external changed.
     504             :  */
     505             : static uint64_t wire_generation;
     506             : 
     507             : 
     508             : /**
     509             :  * Stores the latest generation of our key state.
     510             :  */
     511             : static struct TEH_KeyStateHandle *key_state;
     512             : 
     513             : /**
     514             :  * Counter incremented whenever we have a reason to re-build the keys because
     515             :  * something external changed.  See #TEH_keys_get_state() and
     516             :  * #TEH_keys_update_states() for uses of this variable.
     517             :  */
     518             : static uint64_t key_generation;
     519             : 
     520             : /**
     521             :  * Handler listening for wire updates by other exchange
     522             :  * services.
     523             :  */
     524             : static struct GNUNET_DB_EventHandler *keys_eh;
     525             : 
     526             : /**
     527             :  * Head of DLL of suspended /keys requests.
     528             :  */
     529             : static struct SuspendedKeysRequests *skr_head;
     530             : 
     531             : /**
     532             :  * Tail of DLL of suspended /keys requests.
     533             :  */
     534             : static struct SuspendedKeysRequests *skr_tail;
     535             : 
     536             : /**
     537             :  * Number of entries in the @e skr_head DLL.
     538             :  */
     539             : static unsigned int skr_size;
     540             : 
     541             : /**
     542             :  * Handle to a connection that should be force-resumed
     543             :  * with a hard error due to @a skr_size hitting
     544             :  * #SKR_LIMIT.
     545             :  */
     546             : static struct MHD_Connection *skr_connection;
     547             : 
     548             : /**
     549             :  * Task to force timeouts on /keys requests.
     550             :  */
     551             : static struct GNUNET_SCHEDULER_Task *keys_tt;
     552             : 
     553             : /**
     554             :  * For how long should a signing key be legally retained?
     555             :  * Configuration value.
     556             :  */
     557             : static struct GNUNET_TIME_Relative signkey_legal_duration;
     558             : 
     559             : /**
     560             :  * What type of asset are we dealing with here?
     561             :  */
     562             : static char *asset_type;
     563             : 
     564             : /**
     565             :  * RSA security module public key, all zero if not known.
     566             :  */
     567             : static struct TALER_SecurityModulePublicKeyP denom_rsa_sm_pub;
     568             : 
     569             : /**
     570             :  * CS security module public key, all zero if not known.
     571             :  */
     572             : static struct TALER_SecurityModulePublicKeyP denom_cs_sm_pub;
     573             : 
     574             : /**
     575             :  * EdDSA security module public key, all zero if not known.
     576             :  */
     577             : static struct TALER_SecurityModulePublicKeyP esign_sm_pub;
     578             : 
     579             : /**
     580             :  * Are we shutting down?
     581             :  */
     582             : static bool terminating;
     583             : 
     584             : 
     585             : /**
     586             :  * Free memory associated with @a wsh
     587             :  *
     588             :  * @param[in] wsh wire state to destroy
     589             :  */
     590             : static void
     591          29 : destroy_wire_state (struct WireStateHandle *wsh)
     592             : {
     593             :   struct WireFeeSet *wfs;
     594             : 
     595          52 :   while (NULL != (wfs = wsh->wfs_head))
     596             :   {
     597          23 :     GNUNET_CONTAINER_DLL_remove (wsh->wfs_head,
     598             :                                  wsh->wfs_tail,
     599             :                                  wfs);
     600          23 :     GNUNET_free (wfs->method);
     601          23 :     GNUNET_free (wfs);
     602             :   }
     603          29 :   json_decref (wsh->json_reply);
     604          29 :   GNUNET_free (wsh->etag);
     605          29 :   GNUNET_free (wsh);
     606          29 : }
     607             : 
     608             : 
     609             : /**
     610             :  * Function called whenever another exchange process has updated
     611             :  * the wire data in the database.
     612             :  *
     613             :  * @param cls NULL
     614             :  * @param extra unused
     615             :  * @param extra_size number of bytes in @a extra unused
     616             :  */
     617             : static void
     618          56 : wire_update_event_cb (void *cls,
     619             :                       const void *extra,
     620             :                       size_t extra_size)
     621             : {
     622             :   (void) cls;
     623             :   (void) extra;
     624             :   (void) extra_size;
     625          56 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     626             :               "Received wire update event\n");
     627          56 :   TEH_check_invariants ();
     628          56 :   wire_generation++;
     629          56 :   key_generation++;
     630          56 :   TEH_resume_keys_requests (false);
     631          56 : }
     632             : 
     633             : 
     634             : enum GNUNET_GenericReturnValue
     635          21 : TEH_wire_init ()
     636             : {
     637          21 :   struct GNUNET_DB_EventHeaderP es = {
     638          21 :     .size = htons (sizeof (es)),
     639          21 :     .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
     640             :   };
     641             : 
     642          42 :   wire_eh = TEH_plugin->event_listen (TEH_plugin->cls,
     643          21 :                                       GNUNET_TIME_UNIT_FOREVER_REL,
     644             :                                       &es,
     645             :                                       &wire_update_event_cb,
     646             :                                       NULL);
     647          21 :   if (NULL == wire_eh)
     648             :   {
     649           0 :     GNUNET_break (0);
     650           0 :     return GNUNET_SYSERR;
     651             :   }
     652          21 :   return GNUNET_OK;
     653             : }
     654             : 
     655             : 
     656             : void
     657          21 : TEH_wire_done ()
     658             : {
     659          21 :   if (NULL != wire_state)
     660             :   {
     661          19 :     destroy_wire_state (wire_state);
     662          19 :     wire_state = NULL;
     663             :   }
     664          21 :   if (NULL != wire_eh)
     665             :   {
     666          21 :     TEH_plugin->event_listen_cancel (TEH_plugin->cls,
     667             :                                      wire_eh);
     668          21 :     wire_eh = NULL;
     669             :   }
     670          21 : }
     671             : 
     672             : 
     673             : /**
     674             :  * Add information about a wire account to @a cls.
     675             :  *
     676             :  * @param cls a `json_t *` object to expand with wire account details
     677             :  * @param payto_uri the exchange bank account URI to add
     678             :  * @param conversion_url URL of a conversion service, NULL if there is no conversion
     679             :  * @param debit_restrictions JSON array with debit restrictions on the account
     680             :  * @param credit_restrictions JSON array with credit restrictions on the account
     681             :  * @param master_sig master key signature affirming that this is a bank
     682             :  *                   account of the exchange (of purpose #TALER_SIGNATURE_MASTER_WIRE_DETAILS)
     683             :  * @param bank_label label the wallet should use to display the account, can be NULL
     684             :  * @param priority priority for ordering bank account labels
     685             :  */
     686             : static void
     687          25 : add_wire_account (void *cls,
     688             :                   const struct TALER_FullPayto payto_uri,
     689             :                   const char *conversion_url,
     690             :                   const json_t *debit_restrictions,
     691             :                   const json_t *credit_restrictions,
     692             :                   const struct TALER_MasterSignatureP *master_sig,
     693             :                   const char *bank_label,
     694             :                   int64_t priority)
     695             : {
     696          25 :   json_t *a = cls;
     697             : 
     698          25 :   if (GNUNET_OK !=
     699          25 :       TALER_exchange_wire_signature_check (
     700             :         payto_uri,
     701             :         conversion_url,
     702             :         debit_restrictions,
     703             :         credit_restrictions,
     704             :         &TEH_master_public_key,
     705             :         master_sig))
     706             :   {
     707           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     708             :                 "Database has wire account with invalid signature. Skipping entry. Did the exchange offline public key change?\n");
     709           0 :     return;
     710             :   }
     711          25 :   if (0 !=
     712          25 :       json_array_append_new (
     713             :         a,
     714          25 :         GNUNET_JSON_PACK (
     715             :           TALER_JSON_pack_full_payto ("payto_uri",
     716             :                                       payto_uri),
     717             :           GNUNET_JSON_pack_allow_null (
     718             :             GNUNET_JSON_pack_string ("conversion_url",
     719             :                                      conversion_url)),
     720             :           GNUNET_JSON_pack_allow_null (
     721             :             GNUNET_JSON_pack_string ("bank_label",
     722             :                                      bank_label)),
     723             :           GNUNET_JSON_pack_int64 ("priority",
     724             :                                   priority),
     725             :           GNUNET_JSON_pack_array_incref ("debit_restrictions",
     726             :                                          (json_t *) debit_restrictions),
     727             :           GNUNET_JSON_pack_array_incref ("credit_restrictions",
     728             :                                          (json_t *) credit_restrictions),
     729             :           GNUNET_JSON_pack_data_auto ("master_sig",
     730             :                                       master_sig))))
     731             :   {
     732           0 :     GNUNET_break (0);   /* out of memory!? */
     733           0 :     return;
     734             :   }
     735             : }
     736             : 
     737             : 
     738             : /**
     739             :  * Closure for #add_wire_fee().
     740             :  */
     741             : struct AddContext
     742             : {
     743             :   /**
     744             :    * Wire method the fees are for.
     745             :    */
     746             :   char *wire_method;
     747             : 
     748             :   /**
     749             :    * Wire state we are building.
     750             :    */
     751             :   struct WireStateHandle *wsh;
     752             : 
     753             :   /**
     754             :    * Array to append the fee to.
     755             :    */
     756             :   json_t *a;
     757             : 
     758             :   /**
     759             :    * Set to the maximum end-date seen.
     760             :    */
     761             :   struct GNUNET_TIME_Absolute max_seen;
     762             : };
     763             : 
     764             : 
     765             : /**
     766             :  * Add information about a wire account to @a cls.
     767             :  *
     768             :  * @param cls a `struct AddContext`
     769             :  * @param fees the wire fees we charge
     770             :  * @param start_date from when are these fees valid (start date)
     771             :  * @param end_date until when are these fees valid (end date, exclusive)
     772             :  * @param master_sig master key signature affirming that this is the correct
     773             :  *                   fee (of purpose #TALER_SIGNATURE_MASTER_WIRE_FEES)
     774             :  */
     775             : static void
     776          23 : add_wire_fee (void *cls,
     777             :               const struct TALER_WireFeeSet *fees,
     778             :               struct GNUNET_TIME_Timestamp start_date,
     779             :               struct GNUNET_TIME_Timestamp end_date,
     780             :               const struct TALER_MasterSignatureP *master_sig)
     781             : {
     782          23 :   struct AddContext *ac = cls;
     783             :   struct WireFeeSet *wfs;
     784             : 
     785          23 :   if (GNUNET_OK !=
     786          23 :       TALER_exchange_offline_wire_fee_verify (
     787          23 :         ac->wire_method,
     788             :         start_date,
     789             :         end_date,
     790             :         fees,
     791             :         &TEH_master_public_key,
     792             :         master_sig))
     793             :   {
     794           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     795             :                 "Database has wire fee with invalid signature. Skipping entry. Did the exchange offline public key change?\n");
     796           0 :     return;
     797             :   }
     798          23 :   ac->max_seen = GNUNET_TIME_absolute_max (ac->max_seen,
     799             :                                            end_date.abs_time);
     800          23 :   wfs = GNUNET_new (struct WireFeeSet);
     801          23 :   wfs->start_date = start_date;
     802          23 :   wfs->end_date = end_date;
     803          23 :   wfs->fees = *fees;
     804          23 :   wfs->method = GNUNET_strdup (ac->wire_method);
     805          23 :   GNUNET_CONTAINER_DLL_insert (ac->wsh->wfs_head,
     806             :                                ac->wsh->wfs_tail,
     807             :                                wfs);
     808          23 :   if (0 !=
     809          23 :       json_array_append_new (
     810             :         ac->a,
     811          23 :         GNUNET_JSON_PACK (
     812             :           TALER_JSON_pack_amount ("wire_fee",
     813             :                                   &fees->wire),
     814             :           TALER_JSON_pack_amount ("closing_fee",
     815             :                                   &fees->closing),
     816             :           GNUNET_JSON_pack_timestamp ("start_date",
     817             :                                       start_date),
     818             :           GNUNET_JSON_pack_timestamp ("end_date",
     819             :                                       end_date),
     820             :           GNUNET_JSON_pack_data_auto ("sig",
     821             :                                       master_sig))))
     822             :   {
     823           0 :     GNUNET_break (0);   /* out of memory!? */
     824           0 :     return;
     825             :   }
     826             : }
     827             : 
     828             : 
     829             : /**
     830             :  * Create the wire response from our database state.
     831             :  *
     832             :  * @return NULL on error
     833             :  */
     834             : static struct WireStateHandle *
     835          29 : build_wire_state (void)
     836             : {
     837             :   json_t *wire_accounts_array;
     838             :   json_t *wire_fee_object;
     839          29 :   uint64_t wg = wire_generation; /* must be obtained FIRST */
     840             :   enum GNUNET_DB_QueryStatus qs;
     841             :   struct WireStateHandle *wsh;
     842             :   json_t *wads;
     843             : 
     844          29 :   wsh = GNUNET_new (struct WireStateHandle);
     845          29 :   wsh->wire_generation = wg;
     846          29 :   wire_accounts_array = json_array ();
     847          29 :   GNUNET_assert (NULL != wire_accounts_array);
     848          29 :   qs = TEH_plugin->get_wire_accounts (TEH_plugin->cls,
     849             :                                       &add_wire_account,
     850             :                                       wire_accounts_array);
     851          29 :   if (0 > qs)
     852             :   {
     853           0 :     GNUNET_break (0);
     854           0 :     json_decref (wire_accounts_array);
     855           0 :     wsh->ready = false;
     856           0 :     return wsh;
     857             :   }
     858          29 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     859             :               "Built wire data with %u accounts\n",
     860             :               (unsigned int) json_array_size (wire_accounts_array));
     861          29 :   wire_fee_object = json_object ();
     862          29 :   GNUNET_assert (NULL != wire_fee_object);
     863          29 :   wsh->cache_expiration = GNUNET_TIME_UNIT_FOREVER_ABS;
     864             :   {
     865             :     json_t *account;
     866             :     size_t index;
     867             : 
     868          54 :     json_array_foreach (wire_accounts_array,
     869             :                         index,
     870             :                         account)
     871             :     {
     872             :       char *wire_method;
     873          25 :       const char *payto_uri = json_string_value (json_object_get (account,
     874             :                                                                   "payto_uri"));
     875             : 
     876          25 :       GNUNET_assert (NULL != payto_uri);
     877          25 :       wire_method = TALER_payto_get_method (payto_uri);
     878          25 :       if (NULL == wire_method)
     879             :       {
     880           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     881             :                     "No wire method in `%s'\n",
     882             :                     payto_uri);
     883           0 :         wsh->ready = false;
     884           0 :         json_decref (wire_accounts_array);
     885           0 :         json_decref (wire_fee_object);
     886           0 :         return wsh;
     887             :       }
     888          25 :       if (NULL == json_object_get (wire_fee_object,
     889             :                                    wire_method))
     890             :       {
     891          46 :         struct AddContext ac = {
     892             :           .wire_method = wire_method,
     893             :           .wsh = wsh,
     894          23 :           .a = json_array ()
     895             :         };
     896             : 
     897          23 :         GNUNET_assert (NULL != ac.a);
     898          23 :         qs = TEH_plugin->get_wire_fees (TEH_plugin->cls,
     899             :                                         wire_method,
     900             :                                         &add_wire_fee,
     901             :                                         &ac);
     902          23 :         if (0 > qs)
     903             :         {
     904           0 :           GNUNET_break (0);
     905           0 :           json_decref (ac.a);
     906           0 :           json_decref (wire_fee_object);
     907           0 :           json_decref (wire_accounts_array);
     908           0 :           GNUNET_free (wire_method);
     909           0 :           wsh->ready = false;
     910           0 :           return wsh;
     911             :         }
     912          23 :         if (0 != json_array_size (ac.a))
     913             :         {
     914             :           wsh->cache_expiration
     915          23 :             = GNUNET_TIME_absolute_min (ac.max_seen,
     916             :                                         wsh->cache_expiration);
     917          23 :           GNUNET_assert (0 ==
     918             :                          json_object_set_new (wire_fee_object,
     919             :                                               wire_method,
     920             :                                               ac.a));
     921             :         }
     922             :         else
     923             :         {
     924           0 :           json_decref (ac.a);
     925             :         }
     926             :       }
     927          25 :       GNUNET_free (wire_method);
     928             :     }
     929             :   }
     930             : 
     931          29 :   wads = json_array (); /* #7271 */
     932          29 :   GNUNET_assert (NULL != wads);
     933          29 :   wsh->json_reply = GNUNET_JSON_PACK (
     934             :     GNUNET_JSON_pack_array_steal ("accounts",
     935             :                                   wire_accounts_array),
     936             :     GNUNET_JSON_pack_array_steal ("wads",
     937             :                                   wads),
     938             :     GNUNET_JSON_pack_object_steal ("fees",
     939             :                                    wire_fee_object));
     940          29 :   wsh->ready = true;
     941          29 :   return wsh;
     942             : }
     943             : 
     944             : 
     945             : void
     946          52 : TEH_wire_update_state (void)
     947             : {
     948          52 :   struct GNUNET_DB_EventHeaderP es = {
     949          52 :     .size = htons (sizeof (es)),
     950          52 :     .type = htons (TALER_DBEVENT_EXCHANGE_WIRE_UPDATED),
     951             :   };
     952             : 
     953          52 :   TEH_plugin->event_notify (TEH_plugin->cls,
     954             :                             &es,
     955             :                             NULL,
     956             :                             0);
     957          52 :   wire_generation++;
     958          52 :   key_generation++;
     959          52 : }
     960             : 
     961             : 
     962             : /**
     963             :  * Return the current key state for this thread.  Possibly
     964             :  * re-builds the key state if we have reason to believe
     965             :  * that something changed.
     966             :  *
     967             :  * @return NULL on error
     968             :  */
     969             : static struct WireStateHandle *
     970         933 : get_wire_state (void)
     971             : {
     972             :   struct WireStateHandle *old_wsh;
     973             : 
     974         933 :   old_wsh = wire_state;
     975         933 :   if ( (NULL == old_wsh) ||
     976         914 :        (old_wsh->wire_generation < wire_generation) )
     977             :   {
     978             :     struct WireStateHandle *wsh;
     979             : 
     980          29 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     981             :                 "Rebuilding wire, generation upgrade from %llu to %llu\n",
     982             :                 (unsigned long long) (NULL == old_wsh) ? 0LL :
     983             :                 old_wsh->wire_generation,
     984             :                 (unsigned long long) wire_generation);
     985          29 :     TEH_check_invariants ();
     986          29 :     wsh = build_wire_state ();
     987          29 :     wire_state = wsh;
     988          29 :     if (NULL != old_wsh)
     989          10 :       destroy_wire_state (old_wsh);
     990          29 :     TEH_check_invariants ();
     991          29 :     return wsh;
     992             :   }
     993         904 :   return old_wsh;
     994             : }
     995             : 
     996             : 
     997             : const struct TALER_WireFeeSet *
     998           2 : TEH_wire_fees_by_time (
     999             :   struct GNUNET_TIME_Timestamp ts,
    1000             :   const char *method)
    1001             : {
    1002           2 :   struct WireStateHandle *wsh = get_wire_state ();
    1003             : 
    1004           2 :   for (struct WireFeeSet *wfs = wsh->wfs_head;
    1005           2 :        NULL != wfs;
    1006           0 :        wfs = wfs->next)
    1007             :   {
    1008           2 :     if (0 != strcmp (method,
    1009           2 :                      wfs->method))
    1010           0 :       continue;
    1011           2 :     if ( (GNUNET_TIME_timestamp_cmp (wfs->start_date,
    1012             :                                      >,
    1013           2 :                                      ts)) ||
    1014           2 :          (GNUNET_TIME_timestamp_cmp (ts,
    1015             :                                      >=,
    1016             :                                      wfs->end_date)) )
    1017           0 :       continue;
    1018           2 :     return &wfs->fees;
    1019             :   }
    1020           0 :   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1021             :               "No wire fees for method `%s' at %s configured\n",
    1022             :               method,
    1023             :               GNUNET_TIME_timestamp2s (ts));
    1024           0 :   return NULL;
    1025             : }
    1026             : 
    1027             : 
    1028             : /**
    1029             :  * Function called to forcefully resume suspended keys requests.
    1030             :  *
    1031             :  * @param cls unused, NULL
    1032             :  */
    1033             : static void
    1034           0 : keys_timeout_cb (void *cls)
    1035             : {
    1036             :   struct SuspendedKeysRequests *skr;
    1037             : 
    1038             :   (void) cls;
    1039           0 :   keys_tt = NULL;
    1040           0 :   while (NULL != (skr = skr_head))
    1041             :   {
    1042           0 :     if (GNUNET_TIME_absolute_is_future (skr->timeout))
    1043           0 :       break;
    1044           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1045             :                 "Resuming /keys request due to timeout\n");
    1046           0 :     GNUNET_CONTAINER_DLL_remove (skr_head,
    1047             :                                  skr_tail,
    1048             :                                  skr);
    1049           0 :     MHD_resume_connection (skr->connection);
    1050           0 :     TALER_MHD_daemon_trigger ();
    1051           0 :     GNUNET_free (skr);
    1052             :   }
    1053           0 :   if (NULL == skr)
    1054           0 :     return;
    1055           0 :   keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
    1056             :                                      &keys_timeout_cb,
    1057             :                                      NULL);
    1058             : }
    1059             : 
    1060             : 
    1061             : /**
    1062             :  * Suspend /keys request while we (hopefully) are waiting to be
    1063             :  * provisioned with key material.
    1064             :  *
    1065             :  * @param[in] connection to suspend
    1066             :  */
    1067             : static MHD_RESULT
    1068          10 : suspend_request (struct MHD_Connection *connection)
    1069             : {
    1070             :   struct SuspendedKeysRequests *skr;
    1071             : 
    1072          10 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1073             :               "Suspending /keys request until key material changes\n");
    1074          10 :   if (terminating)
    1075             :   {
    1076           0 :     return TALER_MHD_reply_with_error (connection,
    1077             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    1078             :                                        TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
    1079             :                                        "Exchange terminating");
    1080             :   }
    1081          10 :   skr = GNUNET_new (struct SuspendedKeysRequests);
    1082          10 :   skr->connection = connection;
    1083          10 :   MHD_suspend_connection (connection);
    1084          10 :   GNUNET_CONTAINER_DLL_insert (skr_head,
    1085             :                                skr_tail,
    1086             :                                skr);
    1087          10 :   skr->timeout = GNUNET_TIME_relative_to_absolute (KEYS_TIMEOUT);
    1088          10 :   if (NULL == keys_tt)
    1089             :   {
    1090           2 :     keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
    1091             :                                        &keys_timeout_cb,
    1092             :                                        NULL);
    1093             :   }
    1094          10 :   skr_size++;
    1095          10 :   if (skr_size > SKR_LIMIT)
    1096             :   {
    1097           0 :     skr = skr_tail;
    1098           0 :     GNUNET_CONTAINER_DLL_remove (skr_head,
    1099             :                                  skr_tail,
    1100             :                                  skr);
    1101           0 :     skr_size--;
    1102           0 :     skr_connection = skr->connection;
    1103           0 :     MHD_resume_connection (skr->connection);
    1104           0 :     TALER_MHD_daemon_trigger ();
    1105           0 :     GNUNET_free (skr);
    1106             :   }
    1107          10 :   return MHD_YES;
    1108             : }
    1109             : 
    1110             : 
    1111             : /**
    1112             :  * Called on each denomination key. Checks that the key still works.
    1113             :  *
    1114             :  * @param cls NULL
    1115             :  * @param hc denomination hash (unused)
    1116             :  * @param value a `struct TEH_DenominationKey`
    1117             :  * @return #GNUNET_OK
    1118             :  */
    1119             : static enum GNUNET_GenericReturnValue
    1120           0 : check_dk (void *cls,
    1121             :           const struct GNUNET_HashCode *hc,
    1122             :           void *value)
    1123             : {
    1124           0 :   struct TEH_DenominationKey *dk = value;
    1125             : 
    1126             :   (void) cls;
    1127             :   (void) hc;
    1128           0 :   switch (dk->denom_pub.bsign_pub_key->cipher)
    1129             :   {
    1130           0 :   case GNUNET_CRYPTO_BSA_INVALID:
    1131           0 :     break;
    1132           0 :   case GNUNET_CRYPTO_BSA_RSA:
    1133           0 :     GNUNET_assert (GNUNET_CRYPTO_rsa_public_key_check (
    1134             :                      dk->denom_pub.bsign_pub_key->details.rsa_public_key));
    1135           0 :     return GNUNET_OK;
    1136           0 :   case GNUNET_CRYPTO_BSA_CS:
    1137             :     /* nothing to do for GNUNET_CRYPTO_BSA_CS */
    1138           0 :     return GNUNET_OK;
    1139             :   }
    1140           0 :   GNUNET_assert (0);
    1141             :   return GNUNET_SYSERR;
    1142             : }
    1143             : 
    1144             : 
    1145             : void
    1146       28914 : TEH_check_invariants ()
    1147             : {
    1148             :   struct TEH_KeyStateHandle *ksh;
    1149             : 
    1150       28914 :   if (0 == TEH_check_invariants_flag)
    1151       28914 :     return;
    1152           0 :   ksh = TEH_keys_get_state ();
    1153           0 :   if (NULL == ksh)
    1154           0 :     return;
    1155           0 :   GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
    1156             :                                          &check_dk,
    1157             :                                          NULL);
    1158             : }
    1159             : 
    1160             : 
    1161             : void
    1162       10779 : TEH_resume_keys_requests (bool do_shutdown)
    1163             : {
    1164             :   struct SuspendedKeysRequests *skr;
    1165             : 
    1166       10779 :   if (do_shutdown)
    1167          21 :     terminating = true;
    1168       10789 :   while (NULL != (skr = skr_head))
    1169             :   {
    1170          10 :     GNUNET_CONTAINER_DLL_remove (skr_head,
    1171             :                                  skr_tail,
    1172             :                                  skr);
    1173          10 :     skr_size--;
    1174          10 :     MHD_resume_connection (skr->connection);
    1175          10 :     TALER_MHD_daemon_trigger ();
    1176          10 :     GNUNET_free (skr);
    1177             :   }
    1178       10779 : }
    1179             : 
    1180             : 
    1181             : /**
    1182             :  * Clear memory for responses to "/keys" in @a ksh.
    1183             :  *
    1184             :  * @param[in,out] ksh key state to update
    1185             :  */
    1186             : static void
    1187          89 : clear_response_cache (struct TEH_KeyStateHandle *ksh)
    1188             : {
    1189         985 :   for (unsigned int i = 0; i<ksh->krd_array_length; i++)
    1190             :   {
    1191         896 :     struct KeysResponseData *krd = &ksh->krd_array[i];
    1192             : 
    1193         896 :     MHD_destroy_response (krd->response_compressed);
    1194         896 :     MHD_destroy_response (krd->response_uncompressed);
    1195         896 :     GNUNET_free (krd->etag);
    1196             :   }
    1197          89 :   GNUNET_array_grow (ksh->krd_array,
    1198             :                      ksh->krd_array_length,
    1199             :                      0);
    1200          89 : }
    1201             : 
    1202             : 
    1203             : /**
    1204             :  * Check that the given RSA security module's public key is the one
    1205             :  * we have pinned.  If it does not match, we die hard.
    1206             :  *
    1207             :  * @param sm_pub RSA security module public key to check
    1208             :  */
    1209             : static void
    1210        7799 : check_denom_rsa_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
    1211             : {
    1212        7799 :   if (0 !=
    1213        7799 :       GNUNET_memcmp (sm_pub,
    1214             :                      &denom_rsa_sm_pub))
    1215             :   {
    1216          12 :     if (! GNUNET_is_zero (&denom_rsa_sm_pub))
    1217             :     {
    1218           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1219             :                   "Our RSA security module changed its key. This must not happen.\n");
    1220           0 :       GNUNET_assert (0);
    1221             :     }
    1222          12 :     denom_rsa_sm_pub = *sm_pub; /* TOFU ;-) */
    1223             :   }
    1224        7799 : }
    1225             : 
    1226             : 
    1227             : /**
    1228             :  * Check that the given CS security module's public key is the one
    1229             :  * we have pinned.  If it does not match, we die hard.
    1230             :  *
    1231             :  * @param sm_pub RSA security module public key to check
    1232             :  */
    1233             : static void
    1234        2663 : check_denom_cs_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
    1235             : {
    1236        2663 :   if (0 !=
    1237        2663 :       GNUNET_memcmp (sm_pub,
    1238             :                      &denom_cs_sm_pub))
    1239             :   {
    1240           7 :     if (! GNUNET_is_zero (&denom_cs_sm_pub))
    1241             :     {
    1242           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1243             :                   "Our CS security module changed its key. This must not happen.\n");
    1244           0 :       GNUNET_assert (0);
    1245             :     }
    1246           7 :     denom_cs_sm_pub = *sm_pub; /* TOFU ;-) */
    1247             :   }
    1248        2663 : }
    1249             : 
    1250             : 
    1251             : /**
    1252             :  * Check that the given EdDSA security module's public key is the one
    1253             :  * we have pinned.  If it does not match, we die hard.
    1254             :  *
    1255             :  * @param sm_pub EdDSA security module public key to check
    1256             :  */
    1257             : static void
    1258         117 : check_esign_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
    1259             : {
    1260         117 :   if (0 !=
    1261         117 :       GNUNET_memcmp (sm_pub,
    1262             :                      &esign_sm_pub))
    1263             :   {
    1264          19 :     if (! GNUNET_is_zero (&esign_sm_pub))
    1265             :     {
    1266           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1267             :                   "Our EdDSA security module changed its key. This must not happen.\n");
    1268           0 :       GNUNET_assert (0);
    1269             :     }
    1270          19 :     esign_sm_pub = *sm_pub; /* TOFU ;-) */
    1271             :   }
    1272         117 : }
    1273             : 
    1274             : 
    1275             : /**
    1276             :  * Helper function for #destroy_key_helpers to free all entries
    1277             :  * in the `denom_keys` map.
    1278             :  *
    1279             :  * @param cls the `struct HelperDenomination`
    1280             :  * @param h_denom_pub hash of the denomination public key
    1281             :  * @param value the `struct HelperDenomination` to release
    1282             :  * @return #GNUNET_OK (continue to iterate)
    1283             :  */
    1284             : static enum GNUNET_GenericReturnValue
    1285       10462 : free_denom_cb (void *cls,
    1286             :                const struct GNUNET_HashCode *h_denom_pub,
    1287             :                void *value)
    1288             : {
    1289       10462 :   struct HelperDenomination *hd = value;
    1290             : 
    1291             :   (void) cls;
    1292             :   (void) h_denom_pub;
    1293       10462 :   TALER_denom_pub_free (&hd->denom_pub);
    1294       10462 :   GNUNET_free (hd->section_name);
    1295       10462 :   GNUNET_free (hd);
    1296       10462 :   return GNUNET_OK;
    1297             : }
    1298             : 
    1299             : 
    1300             : /**
    1301             :  * Helper function for #destroy_key_helpers to free all entries
    1302             :  * in the `esign_keys` map.
    1303             :  *
    1304             :  * @param cls the `struct HelperSignkey`
    1305             :  * @param pid unused, matches the exchange public key
    1306             :  * @param value the `struct HelperSignkey` to release
    1307             :  * @return #GNUNET_OK (continue to iterate)
    1308             :  */
    1309             : static enum GNUNET_GenericReturnValue
    1310         117 : free_esign_cb (void *cls,
    1311             :                const struct GNUNET_PeerIdentity *pid,
    1312             :                void *value)
    1313             : {
    1314         117 :   struct HelperSignkey *hsk = value;
    1315             : 
    1316             :   (void) cls;
    1317             :   (void) pid;
    1318         117 :   GNUNET_free (hsk);
    1319         117 :   return GNUNET_OK;
    1320             : }
    1321             : 
    1322             : 
    1323             : /**
    1324             :  * Destroy helper state. Does NOT call free() on @a hs, as that
    1325             :  * state is not separately allocated!  Dual to #setup_key_helpers().
    1326             :  *
    1327             :  * @param[in] hs helper state to free, but NOT the @a hs pointer itself!
    1328             :  */
    1329             : static void
    1330          29 : destroy_key_helpers (struct HelperState *hs)
    1331             : {
    1332          29 :   GNUNET_CONTAINER_multihashmap_iterate (hs->denom_keys,
    1333             :                                          &free_denom_cb,
    1334             :                                          hs);
    1335          29 :   GNUNET_CONTAINER_multihashmap_destroy (hs->rsa_keys);
    1336          29 :   hs->rsa_keys = NULL;
    1337          29 :   GNUNET_CONTAINER_multihashmap_destroy (hs->cs_keys);
    1338          29 :   hs->cs_keys = NULL;
    1339          29 :   GNUNET_CONTAINER_multihashmap_destroy (hs->denom_keys);
    1340          29 :   hs->denom_keys = NULL;
    1341          29 :   GNUNET_CONTAINER_multipeermap_iterate (hs->esign_keys,
    1342             :                                          &free_esign_cb,
    1343             :                                          hs);
    1344          29 :   GNUNET_CONTAINER_multipeermap_destroy (hs->esign_keys);
    1345          29 :   hs->esign_keys = NULL;
    1346          29 :   if (NULL != hs->rsadh)
    1347             :   {
    1348          29 :     TALER_CRYPTO_helper_rsa_disconnect (hs->rsadh);
    1349          29 :     hs->rsadh = NULL;
    1350             :   }
    1351          29 :   if (NULL != hs->csdh)
    1352             :   {
    1353          29 :     TALER_CRYPTO_helper_cs_disconnect (hs->csdh);
    1354          29 :     hs->csdh = NULL;
    1355             :   }
    1356          29 :   if (NULL != hs->esh)
    1357             :   {
    1358          29 :     TALER_CRYPTO_helper_esign_disconnect (hs->esh);
    1359          29 :     hs->esh = NULL;
    1360             :   }
    1361          29 : }
    1362             : 
    1363             : 
    1364             : /**
    1365             :  * Looks up the AGE_RESTRICTED setting for a denomination in the config and
    1366             :  * returns the age restriction (mask) accordingly.
    1367             :  *
    1368             :  * @param section_name Section in the configuration for the particular
    1369             :  *    denomination.
    1370             :  */
    1371             : static struct TALER_AgeMask
    1372       29122 : load_age_mask (const char *section_name)
    1373             : {
    1374             :   static const struct TALER_AgeMask null_mask = {0};
    1375             :   enum GNUNET_GenericReturnValue ret;
    1376             : 
    1377       29122 :   if (GNUNET_OK != (GNUNET_CONFIGURATION_have_value (
    1378             :                       TEH_cfg,
    1379             :                       section_name,
    1380             :                       "AGE_RESTRICTED")))
    1381       18442 :     return null_mask;
    1382             : 
    1383       10680 :   if (GNUNET_SYSERR ==
    1384       10680 :       (ret = GNUNET_CONFIGURATION_get_value_yesno (TEH_cfg,
    1385             :                                                    section_name,
    1386             :                                                    "AGE_RESTRICTED")))
    1387             :   {
    1388           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    1389             :                                section_name,
    1390             :                                "AGE_RESTRICTED",
    1391             :                                "Value must be YES or NO\n");
    1392           0 :     return null_mask;
    1393             :   }
    1394             : 
    1395       10680 :   if (GNUNET_OK == ret)
    1396             :   {
    1397       10680 :     if (! TEH_age_restriction_enabled)
    1398           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1399             :                   "age restriction set in section %s, yet, age restriction is not enabled\n",
    1400             :                   section_name);
    1401       10680 :     return TEH_age_restriction_config.mask;
    1402             :   }
    1403             : 
    1404             : 
    1405           0 :   return null_mask;
    1406             : }
    1407             : 
    1408             : 
    1409             : /**
    1410             :  * Function called with information about available keys for signing.  Usually
    1411             :  * only called once per key upon connect. Also called again in case a key is
    1412             :  * being revoked, in that case with an @a end_time of zero.
    1413             :  *
    1414             :  * @param cls closure with the `struct HelperState *`
    1415             :  * @param section_name name of the denomination type in the configuration;
    1416             :  *                 NULL if the key has been revoked or purged
    1417             :  * @param start_time when does the key become available for signing;
    1418             :  *                 zero if the key has been revoked or purged
    1419             :  * @param validity_duration how long does the key remain available for signing;
    1420             :  *                 zero if the key has been revoked or purged
    1421             :  * @param h_rsa hash of the @a denom_pub that is available (or was purged)
    1422             :  * @param bs_pub the public key itself, NULL if the key was revoked or purged
    1423             :  * @param sm_pub public key of the security module, NULL if the key was revoked or purged
    1424             :  * @param sm_sig signature from the security module, NULL if the key was revoked or purged
    1425             :  *               The signature was already verified against @a sm_pub.
    1426             :  */
    1427             : static void
    1428        7799 : helper_rsa_cb (
    1429             :   void *cls,
    1430             :   const char *section_name,
    1431             :   struct GNUNET_TIME_Timestamp start_time,
    1432             :   struct GNUNET_TIME_Relative validity_duration,
    1433             :   const struct TALER_RsaPubHashP *h_rsa,
    1434             :   struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub,
    1435             :   const struct TALER_SecurityModulePublicKeyP *sm_pub,
    1436             :   const struct TALER_SecurityModuleSignatureP *sm_sig)
    1437             : {
    1438        7799 :   struct HelperState *hs = cls;
    1439             :   struct HelperDenomination *hd;
    1440             : 
    1441        7799 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1442             :               "RSA helper announces key %s for denomination type %s with validity %s\n",
    1443             :               GNUNET_h2s (&h_rsa->hash),
    1444             :               section_name,
    1445             :               GNUNET_STRINGS_relative_time_to_string (validity_duration,
    1446             :                                                       GNUNET_NO));
    1447        7799 :   key_generation++;
    1448        7799 :   TEH_resume_keys_requests (false);
    1449        7799 :   hd = GNUNET_CONTAINER_multihashmap_get (hs->rsa_keys,
    1450             :                                           &h_rsa->hash);
    1451        7799 :   if (NULL != hd)
    1452             :   {
    1453             :     /* should be just an update (revocation!), so update existing entry */
    1454           0 :     hd->validity_duration = validity_duration;
    1455           0 :     return;
    1456             :   }
    1457        7799 :   GNUNET_assert (NULL != sm_pub);
    1458        7799 :   check_denom_rsa_sm_pub (sm_pub);
    1459        7799 :   hd = GNUNET_new (struct HelperDenomination);
    1460        7799 :   hd->start_time = start_time;
    1461        7799 :   hd->validity_duration = validity_duration;
    1462        7799 :   hd->h_details.h_rsa = *h_rsa;
    1463        7799 :   hd->sm_sig = *sm_sig;
    1464        7799 :   GNUNET_assert (GNUNET_CRYPTO_BSA_RSA == bs_pub->cipher);
    1465        7799 :   hd->denom_pub.bsign_pub_key =
    1466        7799 :     GNUNET_CRYPTO_bsign_pub_incref (bs_pub);
    1467             :   /* load the age mask for the denomination, if applicable */
    1468        7799 :   hd->denom_pub.age_mask = load_age_mask (section_name);
    1469        7799 :   TALER_denom_pub_hash (&hd->denom_pub,
    1470             :                         &hd->h_denom_pub);
    1471        7799 :   hd->section_name = GNUNET_strdup (section_name);
    1472        7799 :   GNUNET_assert (
    1473             :     GNUNET_OK ==
    1474             :     GNUNET_CONTAINER_multihashmap_put (
    1475             :       hs->denom_keys,
    1476             :       &hd->h_denom_pub.hash,
    1477             :       hd,
    1478             :       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1479        7799 :   GNUNET_assert (
    1480             :     GNUNET_OK ==
    1481             :     GNUNET_CONTAINER_multihashmap_put (
    1482             :       hs->rsa_keys,
    1483             :       &hd->h_details.h_rsa.hash,
    1484             :       hd,
    1485             :       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1486             : }
    1487             : 
    1488             : 
    1489             : /**
    1490             :  * Function called with information about available CS keys for signing. Usually
    1491             :  * only called once per key upon connect. Also called again in case a key is
    1492             :  * being revoked, in that case with an @a end_time of zero.
    1493             :  *
    1494             :  * @param cls closure with the `struct HelperState *`
    1495             :  * @param section_name name of the denomination type in the configuration;
    1496             :  *                 NULL if the key has been revoked or purged
    1497             :  * @param start_time when does the key become available for signing;
    1498             :  *                 zero if the key has been revoked or purged
    1499             :  * @param validity_duration how long does the key remain available for signing;
    1500             :  *                 zero if the key has been revoked or purged
    1501             :  * @param h_cs hash of the @a denom_pub that is available (or was purged)
    1502             :  * @param bs_pub the public key itself, NULL if the key was revoked or purged
    1503             :  * @param sm_pub public key of the security module, NULL if the key was revoked or purged
    1504             :  * @param sm_sig signature from the security module, NULL if the key was revoked or purged
    1505             :  *               The signature was already verified against @a sm_pub.
    1506             :  */
    1507             : static void
    1508        2663 : helper_cs_cb (
    1509             :   void *cls,
    1510             :   const char *section_name,
    1511             :   struct GNUNET_TIME_Timestamp start_time,
    1512             :   struct GNUNET_TIME_Relative validity_duration,
    1513             :   const struct TALER_CsPubHashP *h_cs,
    1514             :   struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub,
    1515             :   const struct TALER_SecurityModulePublicKeyP *sm_pub,
    1516             :   const struct TALER_SecurityModuleSignatureP *sm_sig)
    1517             : {
    1518        2663 :   struct HelperState *hs = cls;
    1519             :   struct HelperDenomination *hd;
    1520             : 
    1521        2663 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1522             :               "CS helper announces key %s for denomination type %s with validity %s\n",
    1523             :               GNUNET_h2s (&h_cs->hash),
    1524             :               section_name,
    1525             :               GNUNET_STRINGS_relative_time_to_string (validity_duration,
    1526             :                                                       GNUNET_NO));
    1527        2663 :   key_generation++;
    1528        2663 :   TEH_resume_keys_requests (false);
    1529        2663 :   hd = GNUNET_CONTAINER_multihashmap_get (hs->cs_keys,
    1530             :                                           &h_cs->hash);
    1531        2663 :   if (NULL != hd)
    1532             :   {
    1533             :     /* should be just an update (revocation!), so update existing entry */
    1534           0 :     hd->validity_duration = validity_duration;
    1535           0 :     return;
    1536             :   }
    1537        2663 :   GNUNET_assert (NULL != sm_pub);
    1538        2663 :   check_denom_cs_sm_pub (sm_pub);
    1539        2663 :   hd = GNUNET_new (struct HelperDenomination);
    1540        2663 :   hd->start_time = start_time;
    1541        2663 :   hd->validity_duration = validity_duration;
    1542        2663 :   hd->h_details.h_cs = *h_cs;
    1543        2663 :   hd->sm_sig = *sm_sig;
    1544        2663 :   GNUNET_assert (GNUNET_CRYPTO_BSA_CS == bs_pub->cipher);
    1545             :   hd->denom_pub.bsign_pub_key
    1546        2663 :     = GNUNET_CRYPTO_bsign_pub_incref (bs_pub);
    1547             :   /* load the age mask for the denomination, if applicable */
    1548        2663 :   hd->denom_pub.age_mask = load_age_mask (section_name);
    1549        2663 :   TALER_denom_pub_hash (&hd->denom_pub,
    1550             :                         &hd->h_denom_pub);
    1551        2663 :   hd->section_name = GNUNET_strdup (section_name);
    1552        2663 :   GNUNET_assert (
    1553             :     GNUNET_OK ==
    1554             :     GNUNET_CONTAINER_multihashmap_put (
    1555             :       hs->denom_keys,
    1556             :       &hd->h_denom_pub.hash,
    1557             :       hd,
    1558             :       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1559        2663 :   GNUNET_assert (
    1560             :     GNUNET_OK ==
    1561             :     GNUNET_CONTAINER_multihashmap_put (
    1562             :       hs->cs_keys,
    1563             :       &hd->h_details.h_cs.hash,
    1564             :       hd,
    1565             :       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1566             : }
    1567             : 
    1568             : 
    1569             : /**
    1570             :  * Function called with information about available keys for signing.  Usually
    1571             :  * only called once per key upon connect. Also called again in case a key is
    1572             :  * being revoked, in that case with an @a end_time of zero.
    1573             :  *
    1574             :  * @param cls closure with the `struct HelperState *`
    1575             :  * @param start_time when does the key become available for signing;
    1576             :  *                 zero if the key has been revoked or purged
    1577             :  * @param validity_duration how long does the key remain available for signing;
    1578             :  *                 zero if the key has been revoked or purged
    1579             :  * @param exchange_pub the public key itself, NULL if the key was revoked or purged
    1580             :  * @param sm_pub public key of the security module, NULL if the key was revoked or purged
    1581             :  * @param sm_sig signature from the security module, NULL if the key was revoked or purged
    1582             :  *               The signature was already verified against @a sm_pub.
    1583             :  */
    1584             : static void
    1585         117 : helper_esign_cb (
    1586             :   void *cls,
    1587             :   struct GNUNET_TIME_Timestamp start_time,
    1588             :   struct GNUNET_TIME_Relative validity_duration,
    1589             :   const struct TALER_ExchangePublicKeyP *exchange_pub,
    1590             :   const struct TALER_SecurityModulePublicKeyP *sm_pub,
    1591             :   const struct TALER_SecurityModuleSignatureP *sm_sig)
    1592             : {
    1593         117 :   struct HelperState *hs = cls;
    1594             :   struct HelperSignkey *hsk;
    1595             :   struct GNUNET_PeerIdentity pid;
    1596             : 
    1597         117 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1598             :               "EdDSA helper announces signing key %s with validity %s\n",
    1599             :               TALER_B2S (exchange_pub),
    1600             :               GNUNET_STRINGS_relative_time_to_string (validity_duration,
    1601             :                                                       GNUNET_NO));
    1602         117 :   key_generation++;
    1603         117 :   TEH_resume_keys_requests (false);
    1604         117 :   pid.public_key = exchange_pub->eddsa_pub;
    1605         117 :   hsk = GNUNET_CONTAINER_multipeermap_get (hs->esign_keys,
    1606             :                                            &pid);
    1607         117 :   if (NULL != hsk)
    1608             :   {
    1609             :     /* should be just an update (revocation!), so update existing entry */
    1610           0 :     hsk->validity_duration = validity_duration;
    1611           0 :     return;
    1612             :   }
    1613         117 :   GNUNET_assert (NULL != sm_pub);
    1614         117 :   check_esign_sm_pub (sm_pub);
    1615         117 :   hsk = GNUNET_new (struct HelperSignkey);
    1616         117 :   hsk->start_time = start_time;
    1617         117 :   hsk->validity_duration = validity_duration;
    1618         117 :   hsk->exchange_pub = *exchange_pub;
    1619         117 :   hsk->sm_sig = *sm_sig;
    1620         117 :   GNUNET_assert (
    1621             :     GNUNET_OK ==
    1622             :     GNUNET_CONTAINER_multipeermap_put (
    1623             :       hs->esign_keys,
    1624             :       &pid,
    1625             :       hsk,
    1626             :       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1627             : }
    1628             : 
    1629             : 
    1630             : /**
    1631             :  * Setup helper state.
    1632             :  *
    1633             :  * @param[out] hs helper state to initialize
    1634             :  * @return #GNUNET_OK on success
    1635             :  */
    1636             : static enum GNUNET_GenericReturnValue
    1637          29 : setup_key_helpers (struct HelperState *hs)
    1638             : {
    1639             :   hs->denom_keys
    1640          29 :     = GNUNET_CONTAINER_multihashmap_create (1024,
    1641             :                                             GNUNET_YES);
    1642             :   hs->rsa_keys
    1643          29 :     = GNUNET_CONTAINER_multihashmap_create (1024,
    1644             :                                             GNUNET_YES);
    1645             :   hs->cs_keys
    1646          29 :     = GNUNET_CONTAINER_multihashmap_create (1024,
    1647             :                                             GNUNET_YES);
    1648             :   hs->esign_keys
    1649          29 :     = GNUNET_CONTAINER_multipeermap_create (32,
    1650             :                                             GNUNET_NO /* MUST BE NO! */);
    1651          29 :   hs->rsadh = TALER_CRYPTO_helper_rsa_connect (TEH_cfg,
    1652             :                                                "taler-exchange",
    1653             :                                                &helper_rsa_cb,
    1654             :                                                hs);
    1655          29 :   if (NULL == hs->rsadh)
    1656             :   {
    1657           0 :     destroy_key_helpers (hs);
    1658           0 :     return GNUNET_SYSERR;
    1659             :   }
    1660          29 :   hs->csdh = TALER_CRYPTO_helper_cs_connect (TEH_cfg,
    1661             :                                              "taler-exchange",
    1662             :                                              &helper_cs_cb,
    1663             :                                              hs);
    1664          29 :   if (NULL == hs->csdh)
    1665             :   {
    1666           0 :     destroy_key_helpers (hs);
    1667           0 :     return GNUNET_SYSERR;
    1668             :   }
    1669          29 :   hs->esh = TALER_CRYPTO_helper_esign_connect (TEH_cfg,
    1670             :                                                "taler-exchange",
    1671             :                                                &helper_esign_cb,
    1672             :                                                hs);
    1673          29 :   if (NULL == hs->esh)
    1674             :   {
    1675           0 :     destroy_key_helpers (hs);
    1676           0 :     return GNUNET_SYSERR;
    1677             :   }
    1678          29 :   return GNUNET_OK;
    1679             : }
    1680             : 
    1681             : 
    1682             : /**
    1683             :  * Synchronize helper state. Polls the key helper for updates.
    1684             :  *
    1685             :  * @param[in,out] hs helper state to synchronize
    1686             :  */
    1687             : static void
    1688         852 : sync_key_helpers (struct HelperState *hs)
    1689             : {
    1690         852 :   TALER_CRYPTO_helper_rsa_poll (hs->rsadh);
    1691         852 :   TALER_CRYPTO_helper_cs_poll (hs->csdh);
    1692         852 :   TALER_CRYPTO_helper_esign_poll (hs->esh);
    1693         852 : }
    1694             : 
    1695             : 
    1696             : /**
    1697             :  * Free denomination key data.
    1698             :  *
    1699             :  * @param cls a `struct TEH_KeyStateHandle`, unused
    1700             :  * @param h_denom_pub hash of the denomination public key, unused
    1701             :  * @param value a `struct TEH_DenominationKey` to free
    1702             :  * @return #GNUNET_OK (continue to iterate)
    1703             :  */
    1704             : static enum GNUNET_GenericReturnValue
    1705       10896 : clear_denomination_cb (void *cls,
    1706             :                        const struct GNUNET_HashCode *h_denom_pub,
    1707             :                        void *value)
    1708             : {
    1709       10896 :   struct TEH_DenominationKey *dk = value;
    1710             :   struct TEH_AuditorSignature *as;
    1711             : 
    1712             :   (void) cls;
    1713             :   (void) h_denom_pub;
    1714       10896 :   TALER_denom_pub_free (&dk->denom_pub);
    1715       10896 :   while (NULL != (as = dk->as_head))
    1716             :   {
    1717           0 :     GNUNET_CONTAINER_DLL_remove (dk->as_head,
    1718             :                                  dk->as_tail,
    1719             :                                  as);
    1720           0 :     GNUNET_free (as);
    1721             :   }
    1722       10896 :   GNUNET_free (dk);
    1723       10896 :   return GNUNET_OK;
    1724             : }
    1725             : 
    1726             : 
    1727             : /**
    1728             :  * Free denomination key data.
    1729             :  *
    1730             :  * @param cls a `struct TEH_KeyStateHandle`, unused
    1731             :  * @param pid the online signing key (type-disguised), unused
    1732             :  * @param value a `struct SigningKey` to free
    1733             :  * @return #GNUNET_OK (continue to iterate)
    1734             :  */
    1735             : static enum GNUNET_GenericReturnValue
    1736         119 : clear_signkey_cb (void *cls,
    1737             :                   const struct GNUNET_PeerIdentity *pid,
    1738             :                   void *value)
    1739             : {
    1740         119 :   struct SigningKey *sk = value;
    1741             : 
    1742             :   (void) cls;
    1743             :   (void) pid;
    1744         119 :   GNUNET_free (sk);
    1745         119 :   return GNUNET_OK;
    1746             : }
    1747             : 
    1748             : 
    1749             : /**
    1750             :  * Free resources associated with @a cls, possibly excluding
    1751             :  * the helper data.
    1752             :  *
    1753             :  * @param[in] ksh key state to release
    1754             :  * @param free_helper true to also release the helper state
    1755             :  */
    1756             : static void
    1757          89 : destroy_key_state (struct TEH_KeyStateHandle *ksh,
    1758             :                    bool free_helper)
    1759             : {
    1760             :   struct TEH_GlobalFee *gf;
    1761             : 
    1762          89 :   clear_response_cache (ksh);
    1763         134 :   while (NULL != (gf = ksh->gf_head))
    1764             :   {
    1765          45 :     GNUNET_CONTAINER_DLL_remove (ksh->gf_head,
    1766             :                                  ksh->gf_tail,
    1767             :                                  gf);
    1768          45 :     GNUNET_free (gf);
    1769             :   }
    1770          89 :   GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
    1771             :                                          &clear_denomination_cb,
    1772             :                                          ksh);
    1773          89 :   GNUNET_CONTAINER_multihashmap_destroy (ksh->denomkey_map);
    1774          89 :   GNUNET_CONTAINER_multihashmap32_destroy (ksh->denomserial_map);
    1775          89 :   GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map,
    1776             :                                          &clear_signkey_cb,
    1777             :                                          ksh);
    1778          89 :   GNUNET_CONTAINER_multipeermap_destroy (ksh->signkey_map);
    1779          89 :   json_decref (ksh->auditors);
    1780          89 :   ksh->auditors = NULL;
    1781          89 :   json_decref (ksh->global_fees);
    1782          89 :   ksh->global_fees = NULL;
    1783          89 :   if (free_helper)
    1784             :   {
    1785          29 :     destroy_key_helpers (ksh->helpers);
    1786          29 :     GNUNET_free (ksh->helpers);
    1787             :   }
    1788          89 :   if (NULL != ksh->management_keys_reply)
    1789             :   {
    1790          40 :     json_decref (ksh->management_keys_reply);
    1791          40 :     ksh->management_keys_reply = NULL;
    1792             :   }
    1793          89 :   GNUNET_free (ksh);
    1794          89 : }
    1795             : 
    1796             : 
    1797             : /**
    1798             :  * Function called whenever another exchange process has updated
    1799             :  * the keys data in the database.
    1800             :  *
    1801             :  * @param cls NULL
    1802             :  * @param extra unused
    1803             :  * @param extra_size number of bytes in @a extra unused
    1804             :  */
    1805             : static void
    1806          56 : keys_update_event_cb (void *cls,
    1807             :                       const void *extra,
    1808             :                       size_t extra_size)
    1809             : {
    1810             :   (void) cls;
    1811             :   (void) extra;
    1812             :   (void) extra_size;
    1813          56 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1814             :               "Received /keys update event\n");
    1815          56 :   TEH_check_invariants ();
    1816          56 :   key_generation++;
    1817          56 :   TEH_resume_keys_requests (false);
    1818          56 :   TEH_check_invariants ();
    1819          56 : }
    1820             : 
    1821             : 
    1822             : enum GNUNET_GenericReturnValue
    1823          21 : TEH_keys_init ()
    1824             : {
    1825          21 :   struct GNUNET_DB_EventHeaderP es = {
    1826          21 :     .size = htons (sizeof (es)),
    1827          21 :     .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
    1828             :   };
    1829             : 
    1830          21 :   if (GNUNET_OK !=
    1831          21 :       GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
    1832             :                                            "exchange",
    1833             :                                            "SIGNKEY_LEGAL_DURATION",
    1834             :                                            &signkey_legal_duration))
    1835             :   {
    1836           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1837             :                                "exchange",
    1838             :                                "SIGNKEY_LEGAL_DURATION");
    1839           0 :     return GNUNET_SYSERR;
    1840             :   }
    1841          21 :   if (GNUNET_OK !=
    1842          21 :       GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
    1843             :                                              "exchange",
    1844             :                                              "ASSET_TYPE",
    1845             :                                              &asset_type))
    1846             :   {
    1847           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
    1848             :                                "exchange",
    1849             :                                "ASSET_TYPE");
    1850           0 :     asset_type = GNUNET_strdup ("fiat");
    1851             :   }
    1852          42 :   keys_eh = TEH_plugin->event_listen (TEH_plugin->cls,
    1853          21 :                                       GNUNET_TIME_UNIT_FOREVER_REL,
    1854             :                                       &es,
    1855             :                                       &keys_update_event_cb,
    1856             :                                       NULL);
    1857          21 :   if (NULL == keys_eh)
    1858             :   {
    1859           0 :     GNUNET_break (0);
    1860           0 :     return GNUNET_SYSERR;
    1861             :   }
    1862          21 :   return GNUNET_OK;
    1863             : }
    1864             : 
    1865             : 
    1866             : /**
    1867             :  * Fully clean up our state.
    1868             :  */
    1869             : void
    1870          21 : TEH_keys_finished ()
    1871             : {
    1872          21 :   if (NULL != keys_tt)
    1873             :   {
    1874           2 :     GNUNET_SCHEDULER_cancel (keys_tt);
    1875           2 :     keys_tt = NULL;
    1876             :   }
    1877          21 :   if (NULL != key_state)
    1878          19 :     destroy_key_state (key_state,
    1879             :                        true);
    1880          21 :   if (NULL != keys_eh)
    1881             :   {
    1882          21 :     TEH_plugin->event_listen_cancel (TEH_plugin->cls,
    1883             :                                      keys_eh);
    1884          21 :     keys_eh = NULL;
    1885             :   }
    1886          21 : }
    1887             : 
    1888             : 
    1889             : /**
    1890             :  * Function called with information about the exchange's denomination keys.
    1891             :  *
    1892             :  * @param cls closure with a `struct TEH_KeyStateHandle *`
    1893             :  * @param denom_pub public key of the denomination
    1894             :  * @param h_denom_pub hash of @a denom_pub
    1895             :  * @param meta meta data information about the denomination type (value, expirations, fees)
    1896             :  * @param master_sig master signature affirming the validity of this denomination
    1897             :  * @param recoup_possible true if the key was revoked and clients can currently recoup
    1898             :  *        coins of this denomination
    1899             :  */
    1900             : static void
    1901       10896 : denomination_info_cb (
    1902             :   void *cls,
    1903             :   const struct TALER_DenominationPublicKey *denom_pub,
    1904             :   const struct TALER_DenominationHashP *h_denom_pub,
    1905             :   const struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta,
    1906             :   const struct TALER_MasterSignatureP *master_sig,
    1907             :   bool recoup_possible)
    1908             : {
    1909       10896 :   struct TEH_KeyStateHandle *ksh = cls;
    1910             :   struct TEH_DenominationKey *dk;
    1911             : 
    1912       10896 :   if (GNUNET_OK !=
    1913       10896 :       TALER_exchange_offline_denom_validity_verify (
    1914             :         h_denom_pub,
    1915             :         meta->start,
    1916             :         meta->expire_withdraw,
    1917             :         meta->expire_deposit,
    1918             :         meta->expire_legal,
    1919             :         &meta->value,
    1920             :         &meta->fees,
    1921             :         &TEH_master_public_key,
    1922             :         master_sig))
    1923             :   {
    1924           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1925             :                 "Database has denomination with invalid signature. Skipping entry. Did the exchange offline public key change?\n");
    1926           0 :     return;
    1927             :   }
    1928             : 
    1929       10896 :   GNUNET_assert (GNUNET_CRYPTO_BSA_INVALID !=
    1930             :                  denom_pub->bsign_pub_key->cipher);
    1931       21792 :   if (GNUNET_TIME_absolute_is_zero (meta->start.abs_time) ||
    1932       21792 :       GNUNET_TIME_absolute_is_zero (meta->expire_withdraw.abs_time) ||
    1933       21792 :       GNUNET_TIME_absolute_is_zero (meta->expire_deposit.abs_time) ||
    1934       10896 :       GNUNET_TIME_absolute_is_zero (meta->expire_legal.abs_time) )
    1935             :   {
    1936           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1937             :                 "Database contains invalid denomination key %s\n",
    1938             :                 GNUNET_h2s (&h_denom_pub->hash));
    1939           0 :     return;
    1940             :   }
    1941       10896 :   dk = GNUNET_new (struct TEH_DenominationKey);
    1942       10896 :   TALER_denom_pub_copy (&dk->denom_pub,
    1943             :                         denom_pub);
    1944       10896 :   dk->h_denom_pub = *h_denom_pub;
    1945       10896 :   dk->meta = *meta;
    1946       10896 :   dk->master_sig = *master_sig;
    1947       10896 :   dk->recoup_possible = recoup_possible;
    1948       10896 :   dk->denom_pub.age_mask = meta->age_mask;
    1949             : 
    1950       10896 :   GNUNET_assert (
    1951             :     GNUNET_OK ==
    1952             :     GNUNET_CONTAINER_multihashmap_put (ksh->denomkey_map,
    1953             :                                        &dk->h_denom_pub.hash,
    1954             :                                        dk,
    1955             :                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1956             :   {
    1957       10896 :     uint32_t serial32 = (uint32_t) dk->meta.serial;
    1958             : 
    1959       10896 :     GNUNET_assert (dk->meta.serial == (uint64_t) serial32);
    1960       10896 :     GNUNET_assert (
    1961             :       GNUNET_OK ==
    1962             :       GNUNET_CONTAINER_multihashmap32_put (ksh->denomserial_map,
    1963             :                                            serial32,
    1964             :                                            dk,
    1965             :                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1966             :   }
    1967             : }
    1968             : 
    1969             : 
    1970             : /**
    1971             :  * Function called with information about the exchange's online signing keys.
    1972             :  *
    1973             :  * @param cls closure with a `struct TEH_KeyStateHandle *`
    1974             :  * @param exchange_pub the public key
    1975             :  * @param meta meta data information about the denomination type (expirations)
    1976             :  * @param master_sig master signature affirming the validity of this denomination
    1977             :  */
    1978             : static void
    1979         119 : signkey_info_cb (
    1980             :   void *cls,
    1981             :   const struct TALER_ExchangePublicKeyP *exchange_pub,
    1982             :   const struct TALER_EXCHANGEDB_SignkeyMetaData *meta,
    1983             :   const struct TALER_MasterSignatureP *master_sig)
    1984             : {
    1985         119 :   struct TEH_KeyStateHandle *ksh = cls;
    1986             :   struct SigningKey *sk;
    1987             :   struct GNUNET_PeerIdentity pid;
    1988             : 
    1989         119 :   if (GNUNET_OK !=
    1990         119 :       TALER_exchange_offline_signkey_validity_verify (
    1991             :         exchange_pub,
    1992             :         meta->start,
    1993             :         meta->expire_sign,
    1994             :         meta->expire_legal,
    1995             :         &TEH_master_public_key,
    1996             :         master_sig))
    1997             :   {
    1998           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1999             :                 "Database has signing key with invalid signature. Skipping entry. Did the exchange offline public key change?\n");
    2000           0 :     return;
    2001             :   }
    2002         119 :   sk = GNUNET_new (struct SigningKey);
    2003         119 :   sk->exchange_pub = *exchange_pub;
    2004         119 :   sk->meta = *meta;
    2005         119 :   sk->master_sig = *master_sig;
    2006         119 :   pid.public_key = exchange_pub->eddsa_pub;
    2007         119 :   GNUNET_assert (
    2008             :     GNUNET_OK ==
    2009             :     GNUNET_CONTAINER_multipeermap_put (ksh->signkey_map,
    2010             :                                        &pid,
    2011             :                                        sk,
    2012             :                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    2013             : }
    2014             : 
    2015             : 
    2016             : /**
    2017             :  * Closure for #get_auditor_sigs.
    2018             :  */
    2019             : struct GetAuditorSigsContext
    2020             : {
    2021             :   /**
    2022             :    * Where to store the matching signatures.
    2023             :    */
    2024             :   json_t *denom_keys;
    2025             : 
    2026             :   /**
    2027             :    * Public key of the auditor to match against.
    2028             :    */
    2029             :   const struct TALER_AuditorPublicKeyP *auditor_pub;
    2030             : };
    2031             : 
    2032             : 
    2033             : /**
    2034             :  * Extract the auditor signatures matching the auditor's public
    2035             :  * key from the @a value and generate the respective JSON.
    2036             :  *
    2037             :  * @param cls a `struct GetAuditorSigsContext`
    2038             :  * @param h_denom_pub hash of the denomination public key
    2039             :  * @param value a `struct TEH_DenominationKey`
    2040             :  * @return #GNUNET_OK (continue to iterate)
    2041             :  */
    2042             : static enum GNUNET_GenericReturnValue
    2043        3816 : get_auditor_sigs (void *cls,
    2044             :                   const struct GNUNET_HashCode *h_denom_pub,
    2045             :                   void *value)
    2046             : {
    2047        3816 :   struct GetAuditorSigsContext *ctx = cls;
    2048        3816 :   struct TEH_DenominationKey *dk = value;
    2049             : 
    2050        3816 :   for (struct TEH_AuditorSignature *as = dk->as_head;
    2051        3816 :        NULL != as;
    2052           0 :        as = as->next)
    2053             :   {
    2054           0 :     if (0 !=
    2055           0 :         GNUNET_memcmp (ctx->auditor_pub,
    2056             :                        &as->apub))
    2057           0 :       continue;
    2058           0 :     GNUNET_break (0 ==
    2059             :                   json_array_append_new (
    2060             :                     ctx->denom_keys,
    2061             :                     GNUNET_JSON_PACK (
    2062             :                       GNUNET_JSON_pack_data_auto ("denom_pub_h",
    2063             :                                                   h_denom_pub),
    2064             :                       GNUNET_JSON_pack_data_auto ("auditor_sig",
    2065             :                                                   &as->asig))));
    2066             :   }
    2067        3816 :   return GNUNET_OK;
    2068             : }
    2069             : 
    2070             : 
    2071             : /**
    2072             :  * Function called with information about the exchange's auditors.
    2073             :  *
    2074             :  * @param cls closure with a `struct TEH_KeyStateHandle *`
    2075             :  * @param auditor_pub the public key of the auditor
    2076             :  * @param auditor_url URL of the REST API of the auditor
    2077             :  * @param auditor_name human readable official name of the auditor
    2078             :  */
    2079             : static void
    2080           8 : auditor_info_cb (
    2081             :   void *cls,
    2082             :   const struct TALER_AuditorPublicKeyP *auditor_pub,
    2083             :   const char *auditor_url,
    2084             :   const char *auditor_name)
    2085             : {
    2086           8 :   struct TEH_KeyStateHandle *ksh = cls;
    2087             :   struct GetAuditorSigsContext ctx;
    2088             : 
    2089           8 :   ctx.denom_keys = json_array ();
    2090           8 :   GNUNET_assert (NULL != ctx.denom_keys);
    2091           8 :   ctx.auditor_pub = auditor_pub;
    2092           8 :   GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
    2093             :                                          &get_auditor_sigs,
    2094             :                                          &ctx);
    2095           8 :   GNUNET_break (0 ==
    2096             :                 json_array_append_new (
    2097             :                   ksh->auditors,
    2098             :                   GNUNET_JSON_PACK (
    2099             :                     GNUNET_JSON_pack_string ("auditor_name",
    2100             :                                              auditor_name),
    2101             :                     GNUNET_JSON_pack_data_auto ("auditor_pub",
    2102             :                                                 auditor_pub),
    2103             :                     GNUNET_JSON_pack_string ("auditor_url",
    2104             :                                              auditor_url),
    2105             :                     GNUNET_JSON_pack_array_steal ("denomination_keys",
    2106             :                                                   ctx.denom_keys))));
    2107           8 : }
    2108             : 
    2109             : 
    2110             : /**
    2111             :  * Function called with information about the denominations
    2112             :  * audited by the exchange's auditors.
    2113             :  *
    2114             :  * @param cls closure with a `struct TEH_KeyStateHandle *`
    2115             :  * @param auditor_pub the public key of an auditor
    2116             :  * @param h_denom_pub hash of a denomination key audited by this auditor
    2117             :  * @param auditor_sig signature from the auditor affirming this
    2118             :  */
    2119             : static void
    2120           0 : auditor_denom_cb (
    2121             :   void *cls,
    2122             :   const struct TALER_AuditorPublicKeyP *auditor_pub,
    2123             :   const struct TALER_DenominationHashP *h_denom_pub,
    2124             :   const struct TALER_AuditorSignatureP *auditor_sig)
    2125             : {
    2126           0 :   struct TEH_KeyStateHandle *ksh = cls;
    2127             :   struct TEH_DenominationKey *dk;
    2128             :   struct TEH_AuditorSignature *as;
    2129             : 
    2130           0 :   dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map,
    2131             :                                           &h_denom_pub->hash);
    2132           0 :   if (NULL == dk)
    2133             :   {
    2134             :     /* Odd, this should be impossible as per foreign key
    2135             :        constraint on 'auditor_denom_sigs'! Well, we can
    2136             :        safely continue anyway, so let's just log it. */
    2137           0 :     GNUNET_break (0);
    2138           0 :     return;
    2139             :   }
    2140           0 :   as = GNUNET_new (struct TEH_AuditorSignature);
    2141           0 :   as->asig = *auditor_sig;
    2142           0 :   as->apub = *auditor_pub;
    2143           0 :   GNUNET_CONTAINER_DLL_insert (dk->as_head,
    2144             :                                dk->as_tail,
    2145             :                                as);
    2146             : }
    2147             : 
    2148             : 
    2149             : /**
    2150             :  * Closure for #add_sign_key_cb.
    2151             :  */
    2152             : struct SignKeyCtx
    2153             : {
    2154             :   /**
    2155             :    * What is the current rotation frequency for signing keys. Updated.
    2156             :    */
    2157             :   struct GNUNET_TIME_Relative min_sk_frequency;
    2158             : 
    2159             :   /**
    2160             :    * JSON array of signing keys (being created).
    2161             :    */
    2162             :   json_t *signkeys;
    2163             : };
    2164             : 
    2165             : 
    2166             : /**
    2167             :  * Function called for all signing keys, used to build up the
    2168             :  * respective JSON response.
    2169             :  *
    2170             :  * @param cls a `struct SignKeyCtx *` with the array to append keys to
    2171             :  * @param pid the exchange public key (in type disguise)
    2172             :  * @param value a `struct SigningKey`
    2173             :  * @return #GNUNET_OK (continue to iterate)
    2174             :  */
    2175             : static enum GNUNET_GenericReturnValue
    2176          89 : add_sign_key_cb (void *cls,
    2177             :                  const struct GNUNET_PeerIdentity *pid,
    2178             :                  void *value)
    2179             : {
    2180          89 :   struct SignKeyCtx *ctx = cls;
    2181          89 :   struct SigningKey *sk = value;
    2182             : 
    2183             :   (void) pid;
    2184          89 :   if (GNUNET_TIME_absolute_is_future (sk->meta.expire_sign.abs_time))
    2185             :   {
    2186             :     ctx->min_sk_frequency =
    2187          89 :       GNUNET_TIME_relative_min (ctx->min_sk_frequency,
    2188             :                                 GNUNET_TIME_absolute_get_difference (
    2189             :                                   sk->meta.start.abs_time,
    2190             :                                   sk->meta.expire_sign.abs_time));
    2191             :   }
    2192          89 :   GNUNET_assert (
    2193             :     0 ==
    2194             :     json_array_append_new (
    2195             :       ctx->signkeys,
    2196             :       GNUNET_JSON_PACK (
    2197             :         GNUNET_JSON_pack_timestamp ("stamp_start",
    2198             :                                     sk->meta.start),
    2199             :         GNUNET_JSON_pack_timestamp ("stamp_expire",
    2200             :                                     sk->meta.expire_sign),
    2201             :         GNUNET_JSON_pack_timestamp ("stamp_end",
    2202             :                                     sk->meta.expire_legal),
    2203             :         GNUNET_JSON_pack_data_auto ("master_sig",
    2204             :                                     &sk->master_sig),
    2205             :         GNUNET_JSON_pack_data_auto ("key",
    2206             :                                     &sk->exchange_pub))));
    2207          89 :   return GNUNET_OK;
    2208             : }
    2209             : 
    2210             : 
    2211             : /**
    2212             :  * Closure for #add_denom_key_cb.
    2213             :  */
    2214             : struct DenomKeyCtx
    2215             : {
    2216             :   /**
    2217             :    * Heap for sorting active denomination keys by start time.
    2218             :    */
    2219             :   struct GNUNET_CONTAINER_Heap *heap;
    2220             : 
    2221             :   /**
    2222             :    * JSON array of revoked denomination keys.
    2223             :    */
    2224             :   json_t *recoup;
    2225             : 
    2226             :   /**
    2227             :    * What is the minimum key rotation frequency of
    2228             :    * valid denomination keys?
    2229             :    */
    2230             :   struct GNUNET_TIME_Relative min_dk_frequency;
    2231             : };
    2232             : 
    2233             : 
    2234             : /**
    2235             :  * Function called for all denomination keys, used to build up the
    2236             :  * JSON list of *revoked* denomination keys and the
    2237             :  * heap of non-revoked denomination keys by timeout.
    2238             :  *
    2239             :  * @param cls a `struct DenomKeyCtx`
    2240             :  * @param h_denom_pub hash of the denomination key
    2241             :  * @param value a `struct TEH_DenominationKey`
    2242             :  * @return #GNUNET_OK (continue to iterate)
    2243             :  */
    2244             : static enum GNUNET_GenericReturnValue
    2245        8140 : add_denom_key_cb (void *cls,
    2246             :                   const struct GNUNET_HashCode *h_denom_pub,
    2247             :                   void *value)
    2248             : {
    2249        8140 :   struct DenomKeyCtx *dkc = cls;
    2250        8140 :   struct TEH_DenominationKey *dk = value;
    2251             : 
    2252        8140 :   if (dk->recoup_possible)
    2253             :   {
    2254           0 :     GNUNET_assert (
    2255             :       0 ==
    2256             :       json_array_append_new (
    2257             :         dkc->recoup,
    2258             :         GNUNET_JSON_PACK (
    2259             :           GNUNET_JSON_pack_data_auto ("h_denom_pub",
    2260             :                                       h_denom_pub))));
    2261             :   }
    2262             :   else
    2263             :   {
    2264        8140 :     if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time))
    2265             :     {
    2266             :       dkc->min_dk_frequency =
    2267        7968 :         GNUNET_TIME_relative_min (dkc->min_dk_frequency,
    2268             :                                   GNUNET_TIME_absolute_get_difference (
    2269             :                                     dk->meta.start.abs_time,
    2270             :                                     dk->meta.expire_withdraw.abs_time));
    2271             :     }
    2272        8140 :     (void) GNUNET_CONTAINER_heap_insert (dkc->heap,
    2273             :                                          dk,
    2274             :                                          dk->meta.start.abs_time.abs_value_us);
    2275             :   }
    2276        8140 :   return GNUNET_OK;
    2277             : }
    2278             : 
    2279             : 
    2280             : /**
    2281             :  * Add the headers we want to set for every /keys response.
    2282             :  *
    2283             :  * @param cls the key state to use
    2284             :  * @param[in,out] response the response to modify
    2285             :  */
    2286             : static void
    2287        1792 : setup_general_response_headers (void *cls,
    2288             :                                 struct MHD_Response *response)
    2289             : {
    2290        1792 :   struct TEH_KeyStateHandle *ksh = cls;
    2291             :   char dat[128];
    2292             : 
    2293        1792 :   TALER_MHD_add_global_headers (response,
    2294             :                                 true);
    2295        1792 :   GNUNET_break (MHD_YES ==
    2296             :                 MHD_add_response_header (response,
    2297             :                                          MHD_HTTP_HEADER_CONTENT_TYPE,
    2298             :                                          "application/json"));
    2299        1792 :   GNUNET_break (MHD_YES ==
    2300             :                 MHD_add_response_header (response,
    2301             :                                          MHD_HTTP_HEADER_CACHE_CONTROL,
    2302             :                                          "public,must-revalidate,max-age=86400")
    2303             :                 );
    2304        1792 :   if (! GNUNET_TIME_relative_is_zero (ksh->rekey_frequency))
    2305             :   {
    2306             :     struct GNUNET_TIME_Relative r;
    2307             :     struct GNUNET_TIME_Absolute a;
    2308             :     struct GNUNET_TIME_Timestamp km;
    2309             :     struct GNUNET_TIME_Timestamp m;
    2310             :     struct GNUNET_TIME_Timestamp we;
    2311             : 
    2312        1792 :     r = GNUNET_TIME_relative_min (TEH_max_keys_caching,
    2313             :                                   ksh->rekey_frequency);
    2314        1792 :     a = GNUNET_TIME_relative_to_absolute (r);
    2315             :     /* Round up to next full day to ensure the expiration
    2316             :        time does not become a fingerprint! */
    2317        1792 :     a = GNUNET_TIME_absolute_round_down (a,
    2318             :                                          GNUNET_TIME_UNIT_DAYS);
    2319        1792 :     a = GNUNET_TIME_absolute_add (a,
    2320             :                                   GNUNET_TIME_UNIT_DAYS);
    2321        1792 :     km = GNUNET_TIME_absolute_to_timestamp (a);
    2322        1792 :     we = GNUNET_TIME_absolute_to_timestamp (wire_state->cache_expiration);
    2323        1792 :     m = GNUNET_TIME_timestamp_min (we,
    2324             :                                    km);
    2325        1792 :     TALER_MHD_get_date_string (m.abs_time,
    2326             :                                dat);
    2327        1792 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2328             :                 "Setting /keys 'Expires' header to '%s' (rekey frequency is %s)\n",
    2329             :                 dat,
    2330             :                 GNUNET_TIME_relative2s (ksh->rekey_frequency,
    2331             :                                         false));
    2332        1792 :     GNUNET_break (MHD_YES ==
    2333             :                   MHD_add_response_header (response,
    2334             :                                            MHD_HTTP_HEADER_EXPIRES,
    2335             :                                            dat));
    2336             :     ksh->signature_expires
    2337        1792 :       = GNUNET_TIME_timestamp_min (m,
    2338             :                                    ksh->signature_expires);
    2339             :   }
    2340             :   /* Set cache control headers: our response varies depending on these headers */
    2341        1792 :   GNUNET_break (MHD_YES ==
    2342             :                 MHD_add_response_header (response,
    2343             :                                          MHD_HTTP_HEADER_VARY,
    2344             :                                          MHD_HTTP_HEADER_ACCEPT_ENCODING));
    2345        1792 : }
    2346             : 
    2347             : 
    2348             : /**
    2349             :  * Initialize @a krd using the given values for @a signkeys,
    2350             :  * @a recoup and @a denoms.
    2351             :  *
    2352             :  * @param[in,out] ksh key state handle we build @a krd for
    2353             :  * @param[in] denom_keys_hash hash over all the denomination keys in @a denoms
    2354             :  * @param last_cherry_pick_date timestamp to use
    2355             :  * @param[in,out] signkeys list of sign keys to return
    2356             :  * @param[in,out] recoup list of revoked keys to return
    2357             :  * @param[in,out] grouped_denominations list of grouped denominations to return
    2358             :  * @return #GNUNET_OK on success
    2359             :  */
    2360             : static enum GNUNET_GenericReturnValue
    2361         896 : create_krd (struct TEH_KeyStateHandle *ksh,
    2362             :             const struct GNUNET_HashCode *denom_keys_hash,
    2363             :             struct GNUNET_TIME_Timestamp last_cherry_pick_date,
    2364             :             json_t *signkeys,
    2365             :             json_t *recoup,
    2366             :             json_t *grouped_denominations)
    2367             : {
    2368             :   struct KeysResponseData krd;
    2369             :   struct TALER_ExchangePublicKeyP exchange_pub;
    2370             :   struct TALER_ExchangeSignatureP exchange_sig;
    2371             :   struct WireStateHandle *wsh;
    2372             :   json_t *keys;
    2373             : 
    2374         896 :   wsh = get_wire_state ();
    2375         896 :   if (! wsh->ready)
    2376             :   {
    2377           0 :     GNUNET_break (0);
    2378           0 :     return GNUNET_SYSERR;
    2379             :   }
    2380         896 :   GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
    2381             :                    last_cherry_pick_date.abs_time));
    2382         896 :   GNUNET_assert (NULL != signkeys);
    2383         896 :   GNUNET_assert (NULL != recoup);
    2384         896 :   GNUNET_assert (NULL != grouped_denominations);
    2385         896 :   GNUNET_assert (NULL != ksh->auditors);
    2386         896 :   GNUNET_assert (NULL != TEH_currency);
    2387         896 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2388             :               "Creating /keys at cherry pick date %s\n",
    2389             :               GNUNET_TIME_timestamp2s (last_cherry_pick_date));
    2390             : 
    2391             :   /* Sign hash over master signatures of all denomination keys until this time
    2392             :      (in reverse order). */
    2393             :   {
    2394             :     enum TALER_ErrorCode ec;
    2395             : 
    2396         896 :     if (TALER_EC_NONE !=
    2397             :         (ec =
    2398         896 :            TALER_exchange_online_key_set_sign (
    2399             :              &TEH_keys_exchange_sign2_,
    2400             :              ksh,
    2401             :              last_cherry_pick_date,
    2402             :              denom_keys_hash,
    2403             :              &exchange_pub,
    2404             :              &exchange_sig)))
    2405             :     {
    2406           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2407             :                   "Could not create key response data: cannot sign (%s)\n",
    2408             :                   TALER_ErrorCode_get_hint (ec));
    2409           0 :       return GNUNET_SYSERR;
    2410             :     }
    2411             :   }
    2412             : 
    2413             :   {
    2414             :     const struct SigningKey *sk;
    2415             : 
    2416         896 :     sk = GNUNET_CONTAINER_multipeermap_get (
    2417         896 :       ksh->signkey_map,
    2418             :       (const struct GNUNET_PeerIdentity *) &exchange_pub);
    2419         896 :     ksh->signature_expires = GNUNET_TIME_timestamp_min (sk->meta.expire_sign,
    2420             :                                                         ksh->signature_expires);
    2421             :   }
    2422             : 
    2423         896 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2424             :               "Build /keys data with %u wire accounts\n",
    2425             :               (unsigned int) json_array_size (
    2426             :                 json_object_get (wsh->json_reply,
    2427             :                                  "accounts")));
    2428             : 
    2429         896 :   keys = GNUNET_JSON_PACK (
    2430             :     GNUNET_JSON_pack_string ("version",
    2431             :                              EXCHANGE_PROTOCOL_VERSION),
    2432             :     GNUNET_JSON_pack_string ("base_url",
    2433             :                              TEH_base_url),
    2434             :     GNUNET_JSON_pack_string ("currency",
    2435             :                              TEH_currency),
    2436             :     GNUNET_JSON_pack_allow_null (
    2437             :       GNUNET_JSON_pack_string (
    2438             :         "bank_compliance_language",
    2439             :         TEH_bank_compliance_language)),
    2440             :     GNUNET_JSON_pack_object_steal (
    2441             :       "currency_specification",
    2442             :       TALER_JSON_currency_specs_to_json (TEH_cspec)),
    2443             :     GNUNET_JSON_pack_array_incref (
    2444             :       "hard_limits",
    2445             :       TEH_hard_limits),
    2446             :     GNUNET_JSON_pack_array_incref (
    2447             :       "zero_limits",
    2448             :       TEH_zero_limits),
    2449             :     TALER_JSON_pack_amount ("stefan_abs",
    2450             :                             &TEH_stefan_abs),
    2451             :     TALER_JSON_pack_amount ("stefan_log",
    2452             :                             &TEH_stefan_log),
    2453             :     GNUNET_JSON_pack_double ("stefan_lin",
    2454             :                              (double) TEH_stefan_lin),
    2455             :     GNUNET_JSON_pack_string ("asset_type",
    2456             :                              asset_type),
    2457             :     GNUNET_JSON_pack_bool ("kyc_enabled",
    2458             :                            GNUNET_YES == TEH_enable_kyc),
    2459             :     GNUNET_JSON_pack_bool ("rewards_allowed",
    2460             :                            false),
    2461             :     GNUNET_JSON_pack_data_auto ("master_public_key",
    2462             :                                 &TEH_master_public_key),
    2463             :     GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
    2464             :                                TEH_reserve_closing_delay),
    2465             :     GNUNET_JSON_pack_array_incref ("signkeys",
    2466             :                                    signkeys),
    2467             :     GNUNET_JSON_pack_array_incref ("recoup",
    2468             :                                    recoup),
    2469             :     GNUNET_JSON_pack_array_incref ("wads",
    2470             :                                    json_object_get (wsh->json_reply,
    2471             :                                                     "wads")),
    2472             :     GNUNET_JSON_pack_array_incref ("accounts",
    2473             :                                    json_object_get (wsh->json_reply,
    2474             :                                                     "accounts")),
    2475             :     GNUNET_JSON_pack_object_incref ("wire_fees",
    2476             :                                     json_object_get (wsh->json_reply,
    2477             :                                                      "fees")),
    2478             :     GNUNET_JSON_pack_array_incref ("denominations",
    2479             :                                    grouped_denominations),
    2480             :     GNUNET_JSON_pack_array_incref ("auditors",
    2481             :                                    ksh->auditors),
    2482             :     GNUNET_JSON_pack_array_incref ("global_fees",
    2483             :                                    ksh->global_fees),
    2484             :     GNUNET_JSON_pack_timestamp ("list_issue_date",
    2485             :                                 last_cherry_pick_date),
    2486             :     GNUNET_JSON_pack_allow_null (
    2487             :       GNUNET_JSON_pack_array_steal (
    2488             :         "wallet_balance_limit_without_kyc",
    2489             :         TALER_KYCLOGIC_get_wallet_thresholds ())),
    2490             :     GNUNET_JSON_pack_allow_null (
    2491             :       GNUNET_JSON_pack_string ("shopping_url",
    2492             :                                TEH_shopping_url)),
    2493             :     GNUNET_JSON_pack_allow_null (
    2494             :       TALER_amount_is_zero (&TEH_tiny_amount)
    2495             :       ? GNUNET_JSON_pack_string ("dummy",
    2496             :                                  NULL)
    2497             :       : TALER_JSON_pack_amount ("tiny_amount",
    2498             :                                 &TEH_tiny_amount)),
    2499             :     GNUNET_JSON_pack_data_auto ("exchange_pub",
    2500             :                                 &exchange_pub),
    2501             :     GNUNET_JSON_pack_data_auto ("exchange_sig",
    2502             :                                 &exchange_sig));
    2503         896 :   GNUNET_assert (NULL != keys);
    2504             :   /* Signal support for the configured, enabled extensions. */
    2505             :   {
    2506         896 :     json_t *extensions = json_object ();
    2507         896 :     bool has_extensions = false;
    2508             : 
    2509         896 :     GNUNET_assert (NULL != extensions);
    2510             :     /* Fill in the configurations of the enabled extensions */
    2511         896 :     for (const struct TALER_Extensions *iter = TALER_extensions_get_head ();
    2512        1536 :          NULL != iter && NULL != iter->extension;
    2513         640 :          iter = iter->next)
    2514             :     {
    2515         640 :       const struct TALER_Extension *extension = iter->extension;
    2516             :       json_t *manifest;
    2517             :       int r;
    2518             : 
    2519             :       /* skip if not enabled */
    2520         640 :       if (! extension->enabled)
    2521           0 :         continue;
    2522             : 
    2523             :       /* flag our findings so far */
    2524         640 :       has_extensions = true;
    2525             : 
    2526             : 
    2527         640 :       manifest = extension->manifest (extension);
    2528         640 :       GNUNET_assert (manifest);
    2529             : 
    2530         640 :       r = json_object_set_new (
    2531             :         extensions,
    2532         640 :         extension->name,
    2533             :         manifest);
    2534         640 :       GNUNET_assert (0 == r);
    2535             :     }
    2536             : 
    2537             :     /* Update the keys object with the extensions and its signature */
    2538         896 :     if (has_extensions)
    2539             :     {
    2540             :       json_t *sig;
    2541             :       int r;
    2542             : 
    2543         640 :       r = json_object_set_new (
    2544             :         keys,
    2545             :         "extensions",
    2546             :         extensions);
    2547         640 :       GNUNET_assert (0 == r);
    2548             : 
    2549             :       /* Add the signature of the extensions, if it is not zero */
    2550         640 :       if (TEH_extensions_signed)
    2551             :       {
    2552           0 :         sig = GNUNET_JSON_PACK (
    2553             :           GNUNET_JSON_pack_data_auto ("extensions_sig",
    2554             :                                       &TEH_extensions_sig));
    2555             : 
    2556           0 :         r = json_object_update (keys, sig);
    2557           0 :         GNUNET_assert (0 == r);
    2558             :       }
    2559             :     }
    2560             :     else
    2561             :     {
    2562         256 :       json_decref (extensions);
    2563             :     }
    2564             :   }
    2565             : 
    2566             : 
    2567             :   {
    2568             :     char *keys_json;
    2569             :     void *keys_jsonz;
    2570             :     size_t keys_jsonz_size;
    2571             :     int comp;
    2572             :     char etag[sizeof (struct GNUNET_HashCode) * 2];
    2573             : 
    2574             :     /* Convert /keys response to UTF8-String */
    2575         896 :     keys_json = json_dumps (keys,
    2576             :                             JSON_INDENT (2));
    2577         896 :     json_decref (keys);
    2578         896 :     GNUNET_assert (NULL != keys_json);
    2579             : 
    2580             :     /* Keep copy for later compression... */
    2581         896 :     keys_jsonz = GNUNET_strdup (keys_json);
    2582         896 :     keys_jsonz_size = strlen (keys_json);
    2583             : 
    2584             :     /* hash to compute etag */
    2585             :     {
    2586             :       struct GNUNET_HashCode ehash;
    2587             :       char *end;
    2588             : 
    2589         896 :       GNUNET_CRYPTO_hash (keys_jsonz,
    2590             :                           keys_jsonz_size,
    2591             :                           &ehash);
    2592         896 :       end = GNUNET_STRINGS_data_to_string (&ehash,
    2593             :                                            sizeof (ehash),
    2594             :                                            etag,
    2595             :                                            sizeof (etag));
    2596         896 :       *end = '\0';
    2597             :     }
    2598             : 
    2599             :     /* Create uncompressed response */
    2600             :     krd.response_uncompressed
    2601         896 :       = MHD_create_response_from_buffer (keys_jsonz_size,
    2602             :                                          keys_json,
    2603             :                                          MHD_RESPMEM_MUST_FREE);
    2604         896 :     GNUNET_assert (NULL != krd.response_uncompressed);
    2605         896 :     setup_general_response_headers (ksh,
    2606             :                                     krd.response_uncompressed);
    2607             :     /* Information is always public, revalidate after 1 day */
    2608         896 :     GNUNET_break (MHD_YES ==
    2609             :                   MHD_add_response_header (krd.response_uncompressed,
    2610             :                                            MHD_HTTP_HEADER_ETAG,
    2611             :                                            etag));
    2612             :     /* Also compute compressed version of /keys response */
    2613         896 :     comp = TALER_MHD_body_compress (&keys_jsonz,
    2614             :                                     &keys_jsonz_size);
    2615             :     krd.response_compressed
    2616         896 :       = MHD_create_response_from_buffer (keys_jsonz_size,
    2617             :                                          keys_jsonz,
    2618             :                                          MHD_RESPMEM_MUST_FREE);
    2619         896 :     GNUNET_assert (NULL != krd.response_compressed);
    2620             :     /* If the response is actually compressed, set the
    2621             :        respective header. */
    2622         896 :     GNUNET_assert ( (MHD_YES != comp) ||
    2623             :                     (MHD_YES ==
    2624             :                      MHD_add_response_header (krd.response_compressed,
    2625             :                                               MHD_HTTP_HEADER_CONTENT_ENCODING,
    2626             :                                               "deflate")) );
    2627         896 :     setup_general_response_headers (ksh,
    2628             :                                     krd.response_compressed);
    2629             :     /* Information is always public, revalidate after 1 day */
    2630         896 :     GNUNET_break (MHD_YES ==
    2631             :                   MHD_add_response_header (krd.response_compressed,
    2632             :                                            MHD_HTTP_HEADER_ETAG,
    2633             :                                            etag));
    2634         896 :     krd.etag = GNUNET_strdup (etag);
    2635             :   }
    2636         896 :   krd.cherry_pick_date = last_cherry_pick_date;
    2637         896 :   GNUNET_array_append (ksh->krd_array,
    2638             :                        ksh->krd_array_length,
    2639             :                        krd);
    2640         896 :   return GNUNET_OK;
    2641             : }
    2642             : 
    2643             : 
    2644             : /**
    2645             :  * Element in the `struct SignatureContext` array.
    2646             :  */
    2647             : struct SignatureElement
    2648             : {
    2649             : 
    2650             :   /**
    2651             :    * Offset of the denomination in the group array,
    2652             :    * for sorting (2nd rank, ascending).
    2653             :    */
    2654             :   unsigned int offset;
    2655             : 
    2656             :   /**
    2657             :    * Offset of the group in the denominations array,
    2658             :    * for sorting (2nd rank, ascending).
    2659             :    */
    2660             :   unsigned int group_offset;
    2661             : 
    2662             :   /**
    2663             :    * Pointer to actual master signature to hash over.
    2664             :    */
    2665             :   struct TALER_MasterSignatureP master_sig;
    2666             : };
    2667             : 
    2668             : /**
    2669             :  * Context for collecting the array of master signatures
    2670             :  * needed to verify the exchange_sig online signature.
    2671             :  */
    2672             : struct SignatureContext
    2673             : {
    2674             :   /**
    2675             :    * Array of signatures to hash over.
    2676             :    */
    2677             :   struct SignatureElement *elements;
    2678             : 
    2679             :   /**
    2680             :    * Write offset in the @e elements array.
    2681             :    */
    2682             :   unsigned int elements_pos;
    2683             : 
    2684             :   /**
    2685             :    * Allocated space for @e elements.
    2686             :    */
    2687             :   unsigned int elements_size;
    2688             : };
    2689             : 
    2690             : 
    2691             : /**
    2692             :  * Determine order to sort two elements by before
    2693             :  * we hash the master signatures.  Used for
    2694             :  * sorting with qsort().
    2695             :  *
    2696             :  * @param a pointer to a `struct SignatureElement`
    2697             :  * @param b pointer to a `struct SignatureElement`
    2698             :  * @return 0 if equal, -1 if a < b, 1 if a > b.
    2699             :  */
    2700             : static int
    2701      904085 : signature_context_sort_cb (const void *a,
    2702             :                            const void *b)
    2703             : {
    2704      904085 :   const struct SignatureElement *sa = a;
    2705      904085 :   const struct SignatureElement *sb = b;
    2706             : 
    2707      904085 :   if (sa->group_offset < sb->group_offset)
    2708      160466 :     return -1;
    2709      743619 :   if (sa->group_offset > sb->group_offset)
    2710       38119 :     return 1;
    2711      705500 :   if (sa->offset < sb->offset)
    2712      705500 :     return -1;
    2713           0 :   if (sa->offset > sb->offset)
    2714           0 :     return 1;
    2715             :   /* We should never have two disjoint elements
    2716             :      with same time and offset */
    2717           0 :   GNUNET_assert (sa == sb);
    2718           0 :   return 0;
    2719             : }
    2720             : 
    2721             : 
    2722             : /**
    2723             :  * Append a @a master_sig to the @a sig_ctx using the
    2724             :  * given attributes for (later) sorting.
    2725             :  *
    2726             :  * @param[in,out] sig_ctx signature context to update
    2727             :  * @param group_offset offset for the group
    2728             :  * @param offset offset for the entry
    2729             :  * @param master_sig master signature for the entry
    2730             :  */
    2731             : static void
    2732        8140 : append_signature (struct SignatureContext *sig_ctx,
    2733             :                   unsigned int group_offset,
    2734             :                   unsigned int offset,
    2735             :                   const struct TALER_MasterSignatureP *master_sig)
    2736             : {
    2737             :   struct SignatureElement *element;
    2738             :   unsigned int new_size;
    2739             : 
    2740        8140 :   if (sig_ctx->elements_pos == sig_ctx->elements_size)
    2741             :   {
    2742          25 :     if (0 == sig_ctx->elements_size)
    2743          25 :       new_size = 1024;
    2744             :     else
    2745           0 :       new_size = sig_ctx->elements_size * 2;
    2746          25 :     GNUNET_array_grow (sig_ctx->elements,
    2747             :                        sig_ctx->elements_size,
    2748             :                        new_size);
    2749             :   }
    2750        8140 :   element = &sig_ctx->elements[sig_ctx->elements_pos++];
    2751        8140 :   element->offset = offset;
    2752        8140 :   element->group_offset = group_offset;
    2753        8140 :   element->master_sig = *master_sig;
    2754        8140 : }
    2755             : 
    2756             : 
    2757             : /**
    2758             :  *GroupData is the value we store for each group meta-data */
    2759             : struct GroupData
    2760             : {
    2761             :   /**
    2762             :    * The json blob with the group meta-data and list of denominations
    2763             :    */
    2764             :   json_t *json;
    2765             : 
    2766             :   /**
    2767             :    * List of denominations for the group,
    2768             :    * included in @e json, do not free separately!
    2769             :    */
    2770             :   json_t *list;
    2771             : 
    2772             :   /**
    2773             :    * Offset of the group in the final array.
    2774             :    */
    2775             :   unsigned int group_off;
    2776             : 
    2777             : };
    2778             : 
    2779             : 
    2780             : /**
    2781             :  * Helper function called to clean up the group data
    2782             :  * in the denominations_by_group below.
    2783             :  *
    2784             :  * @param cls unused
    2785             :  * @param key unused
    2786             :  * @param value a `struct GroupData` to free
    2787             :  * @return #GNUNET_OK
    2788             :  */
    2789             : static int
    2790         170 : free_group (void *cls,
    2791             :             const struct GNUNET_HashCode *key,
    2792             :             void *value)
    2793             : {
    2794         170 :   struct GroupData *gd = value;
    2795             : 
    2796             :   (void) cls;
    2797             :   (void) key;
    2798         170 :   GNUNET_free (gd);
    2799         170 :   return GNUNET_OK;
    2800             : }
    2801             : 
    2802             : 
    2803             : static void
    2804         896 : compute_msig_hash (struct SignatureContext *sig_ctx,
    2805             :                    struct GNUNET_HashCode *hc)
    2806             : {
    2807             :   struct GNUNET_HashContext *hash_context;
    2808             : 
    2809         896 :   hash_context = GNUNET_CRYPTO_hash_context_start ();
    2810         896 :   qsort (sig_ctx->elements,
    2811         896 :          sig_ctx->elements_pos,
    2812             :          sizeof (struct SignatureElement),
    2813             :          &signature_context_sort_cb);
    2814      218654 :   for (unsigned int i = 0; i<sig_ctx->elements_pos; i++)
    2815             :   {
    2816      217758 :     struct SignatureElement *element = &sig_ctx->elements[i];
    2817             : 
    2818      217758 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2819             :                 "Adding %u,%u,%s\n",
    2820             :                 element->group_offset,
    2821             :                 element->offset,
    2822             :                 TALER_B2S (&element->master_sig));
    2823      217758 :     GNUNET_CRYPTO_hash_context_read (hash_context,
    2824      217758 :                                      &element->master_sig,
    2825             :                                      sizeof (element->master_sig));
    2826             :   }
    2827         896 :   GNUNET_CRYPTO_hash_context_finish (hash_context,
    2828             :                                      hc);
    2829         896 : }
    2830             : 
    2831             : 
    2832             : /**
    2833             :  * Update the "/keys" responses in @a ksh, computing the detailed replies.
    2834             :  *
    2835             :  * This function is to recompute all (including cherry-picked) responses we
    2836             :  * might want to return, based on the state already in @a ksh.
    2837             :  *
    2838             :  * @param[in,out] ksh state handle to update
    2839             :  * @return #GNUNET_OK on success
    2840             :  */
    2841             : static enum GNUNET_GenericReturnValue
    2842          35 : finish_keys_response (struct TEH_KeyStateHandle *ksh)
    2843             : {
    2844          35 :   enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
    2845             :   json_t *recoup;
    2846          35 :   struct SignKeyCtx sctx = {
    2847             :     .min_sk_frequency = GNUNET_TIME_UNIT_FOREVER_REL
    2848             :   };
    2849          35 :   json_t *grouped_denominations = NULL;
    2850             :   struct GNUNET_TIME_Timestamp last_cherry_pick_date;
    2851             :   struct GNUNET_CONTAINER_Heap *heap;
    2852          35 :   struct SignatureContext sig_ctx = { 0 };
    2853             :   /* Remember if we have any denomination with age restriction */
    2854          35 :   bool has_age_restricted_denomination = false;
    2855             :   struct WireStateHandle *wsh;
    2856             : 
    2857          35 :   wsh = get_wire_state ();
    2858          35 :   if (! wsh->ready)
    2859             :   {
    2860           0 :     GNUNET_break (0);
    2861           0 :     return GNUNET_SYSERR;
    2862             :   }
    2863          35 :   if (0 ==
    2864          35 :       json_array_size (json_object_get (wsh->json_reply,
    2865             :                                         "accounts")) )
    2866             :   {
    2867          10 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2868             :                 "No wire accounts available. Refusing to generate /keys response.\n");
    2869          10 :     return GNUNET_NO;
    2870             :   }
    2871          25 :   sctx.signkeys = json_array ();
    2872          25 :   GNUNET_assert (NULL != sctx.signkeys);
    2873          25 :   recoup = json_array ();
    2874          25 :   GNUNET_assert (NULL != recoup);
    2875          25 :   grouped_denominations = json_array ();
    2876          25 :   GNUNET_assert (NULL != grouped_denominations);
    2877             : 
    2878          25 :   GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map,
    2879             :                                          &add_sign_key_cb,
    2880             :                                          &sctx);
    2881          25 :   if (0 == json_array_size (sctx.signkeys))
    2882             :   {
    2883           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2884             :                 "No online signing keys available. Refusing to generate /keys response.\n");
    2885           0 :     ret = GNUNET_NO;
    2886           0 :     goto CLEANUP;
    2887             :   }
    2888          25 :   heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
    2889             :   {
    2890          25 :     struct DenomKeyCtx dkc = {
    2891             :       .recoup = recoup,
    2892             :       .heap = heap,
    2893             :       .min_dk_frequency = GNUNET_TIME_UNIT_FOREVER_REL,
    2894             :     };
    2895             : 
    2896          25 :     GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
    2897             :                                            &add_denom_key_cb,
    2898             :                                            &dkc);
    2899             :     ksh->rekey_frequency
    2900          25 :       = GNUNET_TIME_relative_min (dkc.min_dk_frequency,
    2901             :                                   sctx.min_sk_frequency);
    2902             :   }
    2903             : 
    2904          25 :   last_cherry_pick_date = GNUNET_TIME_UNIT_ZERO_TS;
    2905             : 
    2906             :   {
    2907             :     struct TEH_DenominationKey *dk;
    2908             :     struct GNUNET_CONTAINER_MultiHashMap *denominations_by_group;
    2909             : 
    2910             :     denominations_by_group =
    2911          25 :       GNUNET_CONTAINER_multihashmap_create (1024,
    2912             :                                             GNUNET_NO /* NO, because keys are only on the stack */
    2913             :                                             );
    2914             :     /* heap = max heap, sorted by start time */
    2915        8165 :     while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap)))
    2916             :     {
    2917        8140 :       if (GNUNET_TIME_timestamp_cmp (last_cherry_pick_date,
    2918             :                                      !=,
    2919         896 :                                      dk->meta.start) &&
    2920         896 :           (! GNUNET_TIME_absolute_is_zero (last_cherry_pick_date.abs_time)) )
    2921             :       {
    2922             :         /*
    2923             :          * This is not the first entry in the heap (because last_cherry_pick_date !=
    2924             :          * GNUNET_TIME_UNIT_ZERO_TS) and the previous entry had a different
    2925             :          * start time.  Therefore, we create a new entry in ksh.
    2926             :          */
    2927             :         struct GNUNET_HashCode hc;
    2928             : 
    2929         871 :         compute_msig_hash (&sig_ctx,
    2930             :                            &hc);
    2931         871 :         if (GNUNET_OK !=
    2932         871 :             create_krd (ksh,
    2933             :                         &hc,
    2934             :                         last_cherry_pick_date,
    2935             :                         sctx.signkeys,
    2936             :                         recoup,
    2937             :                         grouped_denominations))
    2938             :         {
    2939           0 :           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2940             :                       "Failed to generate key response data for %s\n",
    2941             :                       GNUNET_TIME_timestamp2s (last_cherry_pick_date));
    2942             :           /* drain heap before destroying it */
    2943           0 :           while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap)))
    2944             :             /* intentionally empty */;
    2945           0 :           GNUNET_CONTAINER_heap_destroy (heap);
    2946           0 :           goto CLEANUP;
    2947             :         }
    2948             :       }
    2949             : 
    2950        8140 :       last_cherry_pick_date = dk->meta.start;
    2951             :       /*
    2952             :        * Group the denominations by {cipher, value, fees, age_mask}.
    2953             :        *
    2954             :        * For each group we save the group meta-data and the list of
    2955             :        * denominations in this group as a json-blob in the multihashmap
    2956             :        * denominations_by_group.
    2957             :        */
    2958             :       {
    2959             :         struct GroupData *group;
    2960             :         json_t *entry;
    2961             :         struct GNUNET_HashCode key;
    2962        8140 :         struct TALER_DenominationGroup meta = {
    2963        8140 :           .cipher = dk->denom_pub.bsign_pub_key->cipher,
    2964             :           .value = dk->meta.value,
    2965             :           .fees = dk->meta.fees,
    2966             :           .age_mask = dk->meta.age_mask,
    2967             :         };
    2968             : 
    2969             :         /* Search the group/JSON-blob for the key */
    2970        8140 :         TALER_denomination_group_get_key (&meta,
    2971             :                                           &key);
    2972        8140 :         group = GNUNET_CONTAINER_multihashmap_get (
    2973             :           denominations_by_group,
    2974             :           &key);
    2975        8140 :         if (NULL == group)
    2976             :         {
    2977             :           /* There is no group for this meta-data yet, so we create a new group */
    2978         170 :           bool age_restricted = meta.age_mask.bits != 0;
    2979             :           const char *cipher;
    2980             : 
    2981         170 :           group = GNUNET_new (struct GroupData);
    2982         170 :           switch (meta.cipher)
    2983             :           {
    2984         107 :           case GNUNET_CRYPTO_BSA_RSA:
    2985         107 :             cipher = age_restricted ? "RSA+age_restricted" : "RSA";
    2986         107 :             break;
    2987          63 :           case GNUNET_CRYPTO_BSA_CS:
    2988          63 :             cipher = age_restricted ? "CS+age_restricted" : "CS";
    2989          63 :             break;
    2990           0 :           default:
    2991           0 :             GNUNET_assert (false);
    2992             :           }
    2993             :           /* Create a new array for the denominations in this group */
    2994         170 :           group->list = json_array ();
    2995         170 :           GNUNET_assert (NULL != group->list);
    2996         170 :           group->json = GNUNET_JSON_PACK (
    2997             :             GNUNET_JSON_pack_string ("cipher",
    2998             :                                      cipher),
    2999             :             GNUNET_JSON_pack_array_steal ("denoms",
    3000             :                                           group->list),
    3001             :             TALER_JSON_PACK_DENOM_FEES ("fee",
    3002             :                                         &meta.fees),
    3003             :             TALER_JSON_pack_amount ("value",
    3004             :                                     &meta.value));
    3005         170 :           GNUNET_assert (NULL != group->json);
    3006         170 :           if (age_restricted)
    3007             :           {
    3008          65 :             GNUNET_assert (
    3009             :               0 ==
    3010             :               json_object_set_new (group->json,
    3011             :                                    "age_mask",
    3012             :                                    json_integer (
    3013             :                                      meta.age_mask.bits)));
    3014             :             /* Remember that we have found at least _one_ age restricted denomination */
    3015          65 :             has_age_restricted_denomination = true;
    3016             :           }
    3017             :           group->group_off
    3018         170 :             = json_array_size (grouped_denominations);
    3019         170 :           GNUNET_assert (0 ==
    3020             :                          json_array_append_new (
    3021             :                            grouped_denominations,
    3022             :                            group->json));
    3023         170 :           GNUNET_assert (
    3024             :             GNUNET_OK ==
    3025             :             GNUNET_CONTAINER_multihashmap_put (denominations_by_group,
    3026             :                                                &key,
    3027             :                                                group,
    3028             :                                                GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    3029             :         }
    3030             : 
    3031             :         /* Now that we have found/created the right group, add the
    3032             :            denomination to the list */
    3033             :         {
    3034             :           struct HelperDenomination *hd;
    3035             :           struct GNUNET_JSON_PackSpec key_spec;
    3036             :           bool private_key_lost;
    3037             : 
    3038        8140 :           hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    3039        8140 :                                                   &dk->h_denom_pub.hash);
    3040             :           private_key_lost
    3041       16280 :             = (NULL == hd) ||
    3042        8140 :               GNUNET_TIME_absolute_is_past (
    3043             :                 GNUNET_TIME_absolute_add (
    3044             :                   hd->start_time.abs_time,
    3045             :                   hd->validity_duration));
    3046        8140 :           switch (meta.cipher)
    3047             :           {
    3048        4942 :           case GNUNET_CRYPTO_BSA_RSA:
    3049             :             key_spec =
    3050        4942 :               GNUNET_JSON_pack_rsa_public_key (
    3051             :                 "rsa_pub",
    3052        4942 :                 dk->denom_pub.bsign_pub_key->details.rsa_public_key);
    3053        4942 :             break;
    3054        3198 :           case GNUNET_CRYPTO_BSA_CS:
    3055             :             key_spec =
    3056        3198 :               GNUNET_JSON_pack_data_varsize (
    3057             :                 "cs_pub",
    3058        3198 :                 &dk->denom_pub.bsign_pub_key->details.cs_public_key,
    3059             :                 sizeof (dk->denom_pub.bsign_pub_key->details.cs_public_key));
    3060        3198 :             break;
    3061           0 :           default:
    3062           0 :             GNUNET_assert (false);
    3063             :           }
    3064             : 
    3065        8140 :           entry = GNUNET_JSON_PACK (
    3066             :             GNUNET_JSON_pack_data_auto ("master_sig",
    3067             :                                         &dk->master_sig),
    3068             :             GNUNET_JSON_pack_allow_null (
    3069             :               private_key_lost
    3070             :               ? GNUNET_JSON_pack_bool ("lost",
    3071             :                                        true)
    3072             :               : GNUNET_JSON_pack_string ("dummy",
    3073             :                                          NULL)),
    3074             :             GNUNET_JSON_pack_timestamp ("stamp_start",
    3075             :                                         dk->meta.start),
    3076             :             GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
    3077             :                                         dk->meta.expire_withdraw),
    3078             :             GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
    3079             :                                         dk->meta.expire_deposit),
    3080             :             GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
    3081             :                                         dk->meta.expire_legal),
    3082             :             key_spec
    3083             :             );
    3084        8140 :           GNUNET_assert (NULL != entry);
    3085             :         }
    3086             : 
    3087             :         /* Build up the running hash of all master signatures of the
    3088             :            denominations */
    3089        8140 :         append_signature (&sig_ctx,
    3090             :                           group->group_off,
    3091        8140 :                           (unsigned int) json_array_size (group->list),
    3092        8140 :                           &dk->master_sig);
    3093             :         /* Finally, add the denomination to the list of denominations in this
    3094             :            group */
    3095        8140 :         GNUNET_assert (json_is_array (group->list));
    3096        8140 :         GNUNET_assert (0 ==
    3097             :                        json_array_append_new (group->list,
    3098             :                                               entry));
    3099             :       }
    3100             :     } /* loop over heap ends */
    3101             : 
    3102          25 :     GNUNET_CONTAINER_multihashmap_iterate (denominations_by_group,
    3103             :                                            &free_group,
    3104             :                                            NULL);
    3105          25 :     GNUNET_CONTAINER_multihashmap_destroy (denominations_by_group);
    3106             :   }
    3107          25 :   GNUNET_CONTAINER_heap_destroy (heap);
    3108             : 
    3109          25 :   if (! GNUNET_TIME_absolute_is_zero (last_cherry_pick_date.abs_time))
    3110             :   {
    3111             :     struct GNUNET_HashCode hc;
    3112             : 
    3113          25 :     compute_msig_hash (&sig_ctx,
    3114             :                        &hc);
    3115          25 :     if (GNUNET_OK !=
    3116          25 :         create_krd (ksh,
    3117             :                     &hc,
    3118             :                     last_cherry_pick_date,
    3119             :                     sctx.signkeys,
    3120             :                     recoup,
    3121             :                     grouped_denominations))
    3122             :     {
    3123           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    3124             :                   "Failed to generate key response data for %s\n",
    3125             :                   GNUNET_TIME_timestamp2s (last_cherry_pick_date));
    3126           0 :       goto CLEANUP;
    3127             :     }
    3128          25 :     ksh->management_only = false;
    3129             : 
    3130             :     /* Sanity check:  Make sure that age restriction is enabled IFF at least
    3131             :      * one age restricted denomination exist */
    3132          25 :     if (! has_age_restricted_denomination && TEH_age_restriction_enabled)
    3133             :     {
    3134           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3135             :                   "Age restriction is enabled, but NO denominations with age restriction found!\n");
    3136           0 :       goto CLEANUP;
    3137             :     }
    3138          25 :     else if (has_age_restricted_denomination && ! TEH_age_restriction_enabled)
    3139             :     {
    3140           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3141             :                   "Age restriction is NOT enabled, but denominations with age restriction found!\n");
    3142           0 :       goto CLEANUP;
    3143             :     }
    3144             :   }
    3145             :   else
    3146             :   {
    3147           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    3148             :                 "No denomination keys available. Refusing to generate /keys response.\n");
    3149             :   }
    3150          25 :   ret = GNUNET_OK;
    3151             : 
    3152          25 : CLEANUP:
    3153          25 :   GNUNET_array_grow (sig_ctx.elements,
    3154             :                      sig_ctx.elements_size,
    3155             :                      0);
    3156          25 :   json_decref (grouped_denominations);
    3157          25 :   if (NULL != sctx.signkeys)
    3158          25 :     json_decref (sctx.signkeys);
    3159          25 :   json_decref (recoup);
    3160          25 :   return ret;
    3161             : }
    3162             : 
    3163             : 
    3164             : /**
    3165             :  * Called with information about global fees.
    3166             :  *
    3167             :  * @param cls `struct TEH_KeyStateHandle *` we are building
    3168             :  * @param fees the global fees we charge
    3169             :  * @param purse_timeout when do purses time out
    3170             :  * @param history_expiration how long are account histories preserved
    3171             :  * @param purse_account_limit how many purses are free per account
    3172             :  * @param start_date from when are these fees valid (start date)
    3173             :  * @param end_date until when are these fees valid (end date, exclusive)
    3174             :  * @param master_sig master key signature affirming that this is the correct
    3175             :  *                   fee (of purpose #TALER_SIGNATURE_MASTER_GLOBAL_FEES)
    3176             :  */
    3177             : static void
    3178          45 : global_fee_info_cb (
    3179             :   void *cls,
    3180             :   const struct TALER_GlobalFeeSet *fees,
    3181             :   struct GNUNET_TIME_Relative purse_timeout,
    3182             :   struct GNUNET_TIME_Relative history_expiration,
    3183             :   uint32_t purse_account_limit,
    3184             :   struct GNUNET_TIME_Timestamp start_date,
    3185             :   struct GNUNET_TIME_Timestamp end_date,
    3186             :   const struct TALER_MasterSignatureP *master_sig)
    3187             : {
    3188          45 :   struct TEH_KeyStateHandle *ksh = cls;
    3189             :   struct TEH_GlobalFee *gf;
    3190             : 
    3191          45 :   if (GNUNET_OK !=
    3192          45 :       TALER_exchange_offline_global_fee_verify (
    3193             :         start_date,
    3194             :         end_date,
    3195             :         fees,
    3196             :         purse_timeout,
    3197             :         history_expiration,
    3198             :         purse_account_limit,
    3199             :         &TEH_master_public_key,
    3200             :         master_sig))
    3201             :   {
    3202           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3203             :                 "Database has global fee with invalid signature. Skipping entry. Did the exchange offline public key change?\n");
    3204           0 :     return;
    3205             :   }
    3206          45 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3207             :               "Found global fees with %u purses\n",
    3208             :               purse_account_limit);
    3209          45 :   gf = GNUNET_new (struct TEH_GlobalFee);
    3210          45 :   gf->start_date = start_date;
    3211          45 :   gf->end_date = end_date;
    3212          45 :   gf->fees = *fees;
    3213          45 :   gf->purse_timeout = purse_timeout;
    3214          45 :   gf->history_expiration = history_expiration;
    3215          45 :   gf->purse_account_limit = purse_account_limit;
    3216          45 :   gf->master_sig = *master_sig;
    3217          45 :   GNUNET_CONTAINER_DLL_insert (ksh->gf_head,
    3218             :                                ksh->gf_tail,
    3219             :                                gf);
    3220          45 :   GNUNET_assert (
    3221             :     0 ==
    3222             :     json_array_append_new (
    3223             :       ksh->global_fees,
    3224             :       GNUNET_JSON_PACK (
    3225             :         GNUNET_JSON_pack_timestamp ("start_date",
    3226             :                                     start_date),
    3227             :         GNUNET_JSON_pack_timestamp ("end_date",
    3228             :                                     end_date),
    3229             :         TALER_JSON_PACK_GLOBAL_FEES (fees),
    3230             :         GNUNET_JSON_pack_time_rel ("history_expiration",
    3231             :                                    history_expiration),
    3232             :         GNUNET_JSON_pack_time_rel ("purse_timeout",
    3233             :                                    purse_timeout),
    3234             :         GNUNET_JSON_pack_uint64 ("purse_account_limit",
    3235             :                                  purse_account_limit),
    3236             :         GNUNET_JSON_pack_data_auto ("master_sig",
    3237             :                                     master_sig))));
    3238             : }
    3239             : 
    3240             : 
    3241             : /**
    3242             :  * Create a key state.
    3243             :  *
    3244             :  * @param[in] hs helper state to (re)use, NULL if not available
    3245             :  * @param management_only if we should NOT run 'finish_keys_response()'
    3246             :  *                  because we only need the state for the /management/keys API
    3247             :  * @return NULL on error (i.e. failed to access database)
    3248             :  */
    3249             : static struct TEH_KeyStateHandle *
    3250          89 : build_key_state (struct HelperState *hs,
    3251             :                  bool management_only)
    3252             : {
    3253             :   struct TEH_KeyStateHandle *ksh;
    3254             :   enum GNUNET_DB_QueryStatus qs;
    3255             : 
    3256          89 :   ksh = GNUNET_new (struct TEH_KeyStateHandle);
    3257          89 :   ksh->signature_expires = GNUNET_TIME_UNIT_FOREVER_TS;
    3258          89 :   ksh->reload_time = GNUNET_TIME_timestamp_get ();
    3259             :   /* We must use the key_generation from when we STARTED the process! */
    3260          89 :   ksh->key_generation = key_generation;
    3261          89 :   if (NULL == hs)
    3262             :   {
    3263          29 :     ksh->helpers = GNUNET_new (struct HelperState);
    3264          29 :     if (GNUNET_OK !=
    3265          29 :         setup_key_helpers (ksh->helpers))
    3266             :     {
    3267           0 :       GNUNET_free (ksh->helpers);
    3268           0 :       GNUNET_assert (NULL == ksh->management_keys_reply);
    3269           0 :       GNUNET_free (ksh);
    3270           0 :       return NULL;
    3271             :     }
    3272             :   }
    3273             :   else
    3274             :   {
    3275          60 :     ksh->helpers = hs;
    3276             :   }
    3277          89 :   ksh->denomserial_map = GNUNET_CONTAINER_multihashmap32_create (1024);
    3278          89 :   ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024,
    3279             :                                                             true);
    3280          89 :   ksh->signkey_map = GNUNET_CONTAINER_multipeermap_create (32,
    3281             :                                                            false /* MUST be false! */
    3282             :                                                            );
    3283          89 :   ksh->auditors = json_array ();
    3284          89 :   GNUNET_assert (NULL != ksh->auditors);
    3285             :   /* NOTE: fetches master-signed signkeys, but ALSO those that were revoked! */
    3286          89 :   GNUNET_break (GNUNET_OK ==
    3287             :                 TEH_plugin->preflight (TEH_plugin->cls));
    3288          89 :   if (NULL != ksh->global_fees)
    3289           0 :     json_decref (ksh->global_fees);
    3290          89 :   ksh->global_fees = json_array ();
    3291          89 :   qs = TEH_plugin->get_global_fees (TEH_plugin->cls,
    3292             :                                     &global_fee_info_cb,
    3293             :                                     ksh);
    3294          89 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3295             :               "Loading global fees from DB: %d\n",
    3296             :               qs);
    3297          89 :   if (qs < 0)
    3298             :   {
    3299           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
    3300           0 :     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
    3301           0 :     destroy_key_state (ksh,
    3302             :                        true);
    3303           0 :     return NULL;
    3304             :   }
    3305          89 :   qs = TEH_plugin->iterate_denominations (TEH_plugin->cls,
    3306             :                                           &denomination_info_cb,
    3307             :                                           ksh);
    3308          89 :   if (qs < 0)
    3309             :   {
    3310           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
    3311           0 :     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
    3312           0 :     destroy_key_state (ksh,
    3313             :                        true);
    3314           0 :     return NULL;
    3315             :   }
    3316             :   /* NOTE: ONLY fetches non-revoked AND master-signed signkeys! */
    3317          89 :   qs = TEH_plugin->iterate_active_signkeys (TEH_plugin->cls,
    3318             :                                             &signkey_info_cb,
    3319             :                                             ksh);
    3320          89 :   if (qs < 0)
    3321             :   {
    3322           0 :     GNUNET_break (0);
    3323           0 :     destroy_key_state (ksh,
    3324             :                        true);
    3325           0 :     return NULL;
    3326             :   }
    3327          89 :   qs = TEH_plugin->iterate_auditor_denominations (TEH_plugin->cls,
    3328             :                                                   &auditor_denom_cb,
    3329             :                                                   ksh);
    3330          89 :   if (qs < 0)
    3331             :   {
    3332           0 :     GNUNET_break (0);
    3333           0 :     destroy_key_state (ksh,
    3334             :                        true);
    3335           0 :     return NULL;
    3336             :   }
    3337          89 :   qs = TEH_plugin->iterate_active_auditors (TEH_plugin->cls,
    3338             :                                             &auditor_info_cb,
    3339             :                                             ksh);
    3340          89 :   if (qs < 0)
    3341             :   {
    3342           0 :     GNUNET_break (0);
    3343           0 :     destroy_key_state (ksh,
    3344             :                        true);
    3345           0 :     return NULL;
    3346             :   }
    3347             : 
    3348          89 :   if (management_only)
    3349             :   {
    3350          54 :     ksh->management_only = true;
    3351          54 :     return ksh;
    3352             :   }
    3353             : 
    3354          35 :   if (GNUNET_OK !=
    3355          35 :       finish_keys_response (ksh))
    3356             :   {
    3357          10 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    3358             :                 "Could not finish /keys response (required data not configured yet)\n");
    3359          10 :     destroy_key_state (ksh,
    3360             :                        true);
    3361          10 :     return NULL;
    3362             :   }
    3363             : 
    3364          25 :   return ksh;
    3365             : }
    3366             : 
    3367             : 
    3368             : void
    3369          67 : TEH_keys_update_states ()
    3370             : {
    3371          67 :   struct GNUNET_DB_EventHeaderP es = {
    3372          67 :     .size = htons (sizeof (es)),
    3373          67 :     .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
    3374             :   };
    3375             : 
    3376          67 :   TEH_plugin->event_notify (TEH_plugin->cls,
    3377             :                             &es,
    3378             :                             NULL,
    3379             :                             0);
    3380          67 :   key_generation++;
    3381          67 :   TEH_resume_keys_requests (false);
    3382          67 : }
    3383             : 
    3384             : 
    3385             : static struct TEH_KeyStateHandle *
    3386         901 : keys_get_state (bool management_only)
    3387             : {
    3388             :   struct TEH_KeyStateHandle *old_ksh;
    3389             :   struct TEH_KeyStateHandle *ksh;
    3390             : 
    3391         901 :   old_ksh = key_state;
    3392         901 :   if (NULL == old_ksh)
    3393             :   {
    3394          29 :     ksh = build_key_state (NULL,
    3395             :                            management_only);
    3396          29 :     if (NULL == ksh)
    3397           4 :       return NULL;
    3398          25 :     key_state = ksh;
    3399          25 :     return ksh;
    3400             :   }
    3401        1684 :   if ( (old_ksh->key_generation < key_generation) ||
    3402         812 :        (GNUNET_TIME_absolute_is_past (old_ksh->signature_expires.abs_time)) )
    3403             :   {
    3404          60 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3405             :                 "Rebuilding /keys, generation upgrade from %llu to %llu\n",
    3406             :                 (unsigned long long) old_ksh->key_generation,
    3407             :                 (unsigned long long) key_generation);
    3408          60 :     ksh = build_key_state (old_ksh->helpers,
    3409             :                            management_only);
    3410          60 :     key_state = ksh;
    3411          60 :     old_ksh->helpers = NULL;
    3412          60 :     destroy_key_state (old_ksh,
    3413             :                        false);
    3414          60 :     return ksh;
    3415             :   }
    3416         812 :   sync_key_helpers (old_ksh->helpers);
    3417         812 :   return old_ksh;
    3418             : }
    3419             : 
    3420             : 
    3421             : struct TEH_KeyStateHandle *
    3422         128 : TEH_keys_get_state_for_management_only (void)
    3423             : {
    3424         128 :   return keys_get_state (true);
    3425             : }
    3426             : 
    3427             : 
    3428             : struct TEH_KeyStateHandle *
    3429         773 : TEH_keys_get_state (void)
    3430             : {
    3431             :   struct TEH_KeyStateHandle *ksh;
    3432             : 
    3433         773 :   ksh = keys_get_state (false);
    3434         773 :   if (NULL == ksh)
    3435          10 :     return NULL;
    3436             : 
    3437         763 :   if (ksh->management_only)
    3438             :   {
    3439           0 :     if (GNUNET_OK !=
    3440           0 :         finish_keys_response (ksh))
    3441           0 :       return NULL;
    3442             :   }
    3443             : 
    3444         763 :   return ksh;
    3445             : }
    3446             : 
    3447             : 
    3448             : const struct TEH_GlobalFee *
    3449          31 : TEH_keys_global_fee_by_time (
    3450             :   struct TEH_KeyStateHandle *ksh,
    3451             :   struct GNUNET_TIME_Timestamp ts)
    3452             : {
    3453          31 :   for (const struct TEH_GlobalFee *gf = ksh->gf_head;
    3454          31 :        NULL != gf;
    3455           0 :        gf = gf->next)
    3456             :   {
    3457          31 :     if (GNUNET_TIME_timestamp_cmp (ts,
    3458             :                                    >=,
    3459          31 :                                    gf->start_date) &&
    3460          31 :         GNUNET_TIME_timestamp_cmp (ts,
    3461             :                                    <,
    3462             :                                    gf->end_date))
    3463          31 :       return gf;
    3464             :   }
    3465           0 :   return NULL;
    3466             : }
    3467             : 
    3468             : 
    3469             : struct TEH_DenominationKey *
    3470         142 : TEH_keys_denomination_by_hash (
    3471             :   const struct TALER_DenominationHashP *h_denom_pub,
    3472             :   struct MHD_Connection *conn,
    3473             :   MHD_RESULT *mret)
    3474             : {
    3475             :   struct TEH_KeyStateHandle *ksh;
    3476             : 
    3477         142 :   ksh = TEH_keys_get_state ();
    3478         142 :   if (NULL == ksh)
    3479             :   {
    3480           0 :     *mret = TALER_MHD_reply_with_error (conn,
    3481             :                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
    3482             :                                         TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
    3483             :                                         NULL);
    3484           0 :     return NULL;
    3485             :   }
    3486             : 
    3487         142 :   return TEH_keys_denomination_by_hash_from_state (ksh,
    3488             :                                                    h_denom_pub,
    3489             :                                                    conn,
    3490             :                                                    mret);
    3491             : }
    3492             : 
    3493             : 
    3494             : struct TEH_DenominationKey *
    3495         628 : TEH_keys_denomination_by_hash_from_state (
    3496             :   const struct TEH_KeyStateHandle *ksh,
    3497             :   const struct TALER_DenominationHashP *h_denom_pub,
    3498             :   struct MHD_Connection *conn,
    3499             :   MHD_RESULT *mret)
    3500             : {
    3501             :   struct TEH_DenominationKey *dk;
    3502             : 
    3503         628 :   dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map,
    3504             :                                           &h_denom_pub->hash);
    3505         628 :   if (NULL == dk)
    3506             :   {
    3507           0 :     if (NULL == conn)
    3508           0 :       return NULL;
    3509           0 :     *mret = TEH_RESPONSE_reply_unknown_denom_pub_hash (conn,
    3510             :                                                        h_denom_pub);
    3511           0 :     return NULL;
    3512             :   }
    3513         628 :   return dk;
    3514             : }
    3515             : 
    3516             : 
    3517             : struct TEH_DenominationKey *
    3518         151 : TEH_keys_denomination_by_serial_from_state (
    3519             :   const struct TEH_KeyStateHandle *ksh,
    3520             :   uint64_t denom_serial)
    3521             : {
    3522             :   struct TEH_DenominationKey *dk;
    3523         151 :   uint32_t serial32 = (uint32_t) denom_serial;
    3524             : 
    3525         151 :   GNUNET_assert (denom_serial == (uint64_t) serial32);
    3526         151 :   dk = GNUNET_CONTAINER_multihashmap32_get (ksh->denomserial_map,
    3527             :                                             serial32);
    3528         151 :   return dk;
    3529             : }
    3530             : 
    3531             : 
    3532             : enum TALER_ErrorCode
    3533         113 : TEH_keys_denomination_batch_sign (
    3534             :   unsigned int csds_length,
    3535             :   const struct TEH_CoinSignData csds[static csds_length],
    3536             :   bool for_melt,
    3537             :   struct TALER_BlindedDenominationSignature bss[static csds_length])
    3538         113 : {
    3539             :   struct TEH_KeyStateHandle *ksh;
    3540             :   struct HelperDenomination *hd;
    3541         113 :   struct TALER_CRYPTO_RsaSignRequest rsrs[csds_length];
    3542         113 :   struct TALER_CRYPTO_CsSignRequest csrs[csds_length];
    3543         113 :   struct TALER_BlindedDenominationSignature rs[csds_length];
    3544         113 :   struct TALER_BlindedDenominationSignature cs[csds_length];
    3545         113 :   unsigned int rsrs_pos = 0;
    3546         113 :   unsigned int csrs_pos = 0;
    3547             :   enum TALER_ErrorCode ec;
    3548             : 
    3549         113 :   ksh = TEH_keys_get_state ();
    3550         113 :   if (NULL == ksh)
    3551           0 :     return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
    3552         450 :   for (unsigned int i = 0; i<csds_length; i++)
    3553             :   {
    3554         337 :     const struct TALER_DenominationHashP *h_denom_pub = csds[i].h_denom_pub;
    3555         337 :     const struct TALER_BlindedPlanchet *bp = csds[i].bp;
    3556             : 
    3557         337 :     hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    3558             :                                             &h_denom_pub->hash);
    3559         337 :     if (NULL == hd)
    3560           0 :       return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
    3561         337 :     if (bp->blinded_message->cipher !=
    3562         337 :         hd->denom_pub.bsign_pub_key->cipher)
    3563           0 :       return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    3564         337 :     switch (hd->denom_pub.bsign_pub_key->cipher)
    3565             :     {
    3566         240 :     case GNUNET_CRYPTO_BSA_RSA:
    3567         240 :       rsrs[rsrs_pos].h_rsa = &hd->h_details.h_rsa;
    3568             :       rsrs[rsrs_pos].msg
    3569         240 :         = bp->blinded_message->details.rsa_blinded_message.blinded_msg;
    3570             :       rsrs[rsrs_pos].msg_size
    3571         240 :         = bp->blinded_message->details.rsa_blinded_message.blinded_msg_size;
    3572         240 :       rsrs_pos++;
    3573         240 :       break;
    3574          97 :     case GNUNET_CRYPTO_BSA_CS:
    3575          97 :       csrs[csrs_pos].h_cs = &hd->h_details.h_cs;
    3576             :       csrs[csrs_pos].blinded_planchet
    3577          97 :         = &bp->blinded_message->details.cs_blinded_message;
    3578          97 :       csrs_pos++;
    3579          97 :       break;
    3580           0 :     default:
    3581           0 :       return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    3582             :     }
    3583             :   }
    3584             : 
    3585         113 :   if (0 != rsrs_pos)
    3586             :   {
    3587          64 :     memset (rs,
    3588             :             0,
    3589             :             sizeof (rs));
    3590             :   }
    3591         113 :   if (0 != csrs_pos)
    3592             :   {
    3593          49 :     memset (cs,
    3594             :             0,
    3595             :             sizeof (cs));
    3596             :   }
    3597         113 :   ec = TALER_EC_NONE;
    3598         113 :   if (0 != csrs_pos)
    3599             :   {
    3600          49 :     ec = TALER_CRYPTO_helper_cs_batch_sign (
    3601          49 :       ksh->helpers->csdh,
    3602             :       csrs_pos,
    3603             :       csrs,
    3604             :       for_melt,
    3605             :       (0 == rsrs_pos) ? bss : cs);
    3606          49 :     if (TALER_EC_NONE != ec)
    3607             :     {
    3608           0 :       for (unsigned int i = 0; i<csrs_pos; i++)
    3609           0 :         TALER_blinded_denom_sig_free (&cs[i]);
    3610           0 :       return ec;
    3611             :     }
    3612          49 :     TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_CS] += csrs_pos;
    3613             :   }
    3614         113 :   if (0 != rsrs_pos)
    3615             :   {
    3616          64 :     ec = TALER_CRYPTO_helper_rsa_batch_sign (
    3617          64 :       ksh->helpers->rsadh,
    3618             :       rsrs_pos,
    3619             :       rsrs,
    3620             :       (0 == csrs_pos) ? bss : rs);
    3621          64 :     if (TALER_EC_NONE != ec)
    3622             :     {
    3623           0 :       for (unsigned int i = 0; i<csrs_pos; i++)
    3624           0 :         TALER_blinded_denom_sig_free (&cs[i]);
    3625           0 :       for (unsigned int i = 0; i<rsrs_pos; i++)
    3626           0 :         TALER_blinded_denom_sig_free (&rs[i]);
    3627           0 :       return ec;
    3628             :     }
    3629          64 :     TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_RSA] += rsrs_pos;
    3630             :   }
    3631             : 
    3632         113 :   if ( (0 != csrs_pos) &&
    3633             :        (0 != rsrs_pos) )
    3634             :   {
    3635           0 :     rsrs_pos = 0;
    3636           0 :     csrs_pos = 0;
    3637           0 :     for (unsigned int i = 0; i<csds_length; i++)
    3638             :     {
    3639           0 :       const struct TALER_BlindedPlanchet *bp = csds[i].bp;
    3640             : 
    3641           0 :       switch (bp->blinded_message->cipher)
    3642             :       {
    3643           0 :       case GNUNET_CRYPTO_BSA_RSA:
    3644           0 :         bss[i] = rs[rsrs_pos++];
    3645           0 :         break;
    3646           0 :       case GNUNET_CRYPTO_BSA_CS:
    3647           0 :         bss[i] = cs[csrs_pos++];
    3648           0 :         break;
    3649           0 :       default:
    3650           0 :         GNUNET_assert (0);
    3651             :       }
    3652             :     }
    3653             :   }
    3654         113 :   return TALER_EC_NONE;
    3655             : }
    3656             : 
    3657             : 
    3658             : enum TALER_ErrorCode
    3659           0 : TEH_keys_denomination_cs_r_pub (
    3660             :   const struct TEH_CsDeriveData *cdd,
    3661             :   bool for_melt,
    3662             :   struct GNUNET_CRYPTO_CSPublicRPairP *r_pub)
    3663             : {
    3664           0 :   const struct TALER_DenominationHashP *h_denom_pub = cdd->h_denom_pub;
    3665           0 :   const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdd->nonce;
    3666             :   struct TEH_KeyStateHandle *ksh;
    3667             :   struct HelperDenomination *hd;
    3668             : 
    3669           0 :   ksh = TEH_keys_get_state ();
    3670           0 :   if (NULL == ksh)
    3671             :   {
    3672           0 :     return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
    3673             :   }
    3674           0 :   hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    3675             :                                           &h_denom_pub->hash);
    3676           0 :   if (NULL == hd)
    3677             :   {
    3678           0 :     return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
    3679             :   }
    3680           0 :   if (GNUNET_CRYPTO_BSA_CS !=
    3681           0 :       hd->denom_pub.bsign_pub_key->cipher)
    3682             :   {
    3683           0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    3684             :   }
    3685             : 
    3686             :   {
    3687           0 :     struct TALER_CRYPTO_CsDeriveRequest cdr = {
    3688           0 :       .h_cs = &hd->h_details.h_cs,
    3689             :       .nonce = nonce
    3690             :     };
    3691           0 :     return TALER_CRYPTO_helper_cs_r_derive (ksh->helpers->csdh,
    3692             :                                             &cdr,
    3693             :                                             for_melt,
    3694             :                                             r_pub);
    3695             :   }
    3696             : }
    3697             : 
    3698             : 
    3699             : enum TALER_ErrorCode
    3700          49 : TEH_keys_denomination_cs_batch_r_pub_simple (
    3701             :   unsigned int cdds_length,
    3702             :   const struct TEH_CsDeriveData cdds[static cdds_length],
    3703             :   bool for_melt,
    3704             :   struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[static cdds_length])
    3705          49 : {
    3706             :   struct TEH_KeyStateHandle *ksh;
    3707             :   struct HelperDenomination *hd;
    3708          49 :   struct TALER_CRYPTO_CsDeriveRequest cdrs[cdds_length];
    3709             : 
    3710          49 :   ksh = TEH_keys_get_state ();
    3711          49 :   if (NULL == ksh)
    3712             :   {
    3713           0 :     return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
    3714             :   }
    3715         146 :   for (unsigned int i = 0; i<cdds_length; i++)
    3716             :   {
    3717          97 :     const struct TALER_DenominationHashP *h_denom_pub = cdds[i].h_denom_pub;
    3718          97 :     const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdds[i].nonce;
    3719             : 
    3720          97 :     hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    3721             :                                             &h_denom_pub->hash);
    3722          97 :     if (NULL == hd)
    3723             :     {
    3724           0 :       return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
    3725             :     }
    3726          97 :     if (GNUNET_CRYPTO_BSA_CS !=
    3727          97 :         hd->denom_pub.bsign_pub_key->cipher)
    3728             :     {
    3729           0 :       return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    3730             :     }
    3731          97 :     cdrs[i].h_cs = &hd->h_details.h_cs;
    3732          97 :     cdrs[i].nonce = nonce;
    3733             :   }
    3734             : 
    3735          49 :   return TALER_CRYPTO_helper_cs_r_batch_derive (ksh->helpers->csdh,
    3736             :                                                 cdds_length,
    3737             :                                                 cdrs,
    3738             :                                                 for_melt,
    3739             :                                                 r_pubs);
    3740             : }
    3741             : 
    3742             : 
    3743             : enum TALER_ErrorCode
    3744          50 : TEH_keys_denomination_cs_batch_r_pub (
    3745             :   const struct TEH_KeyStateHandle *ksh,
    3746             :   size_t num,
    3747             :   const struct TALER_DenominationHashP h_denom_pubs[static num],
    3748             :   const struct GNUNET_CRYPTO_CsSessionNonce nonces[static num],
    3749             :   bool for_melt,
    3750             :   struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[static num],
    3751             :   size_t *err_idx)
    3752          50 : {
    3753          50 :   struct TALER_CRYPTO_CsDeriveRequest cdrs[num];
    3754             : 
    3755         148 :   for (unsigned int i = 0; i<num; i++)
    3756             :   {
    3757             :     const struct TEH_DenominationKey *dk;
    3758             :     const struct HelperDenomination *hd;
    3759             : 
    3760          98 :     *err_idx = i;
    3761             : 
    3762             :     /* FIXME: right now we need both,
    3763             :      * TEH_DenominationKey and HelperDenomination,
    3764             :      * because only TEH_DenominationKey has .recoup_possible
    3765             :      */
    3766          98 :     hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    3767          98 :                                             &h_denom_pubs[i].hash);
    3768          98 :     dk = TEH_keys_denomination_by_hash_from_state (ksh,
    3769          98 :                                                    &h_denom_pubs[i],
    3770             :                                                    NULL,
    3771             :                                                    NULL);
    3772          98 :     if (NULL == hd)
    3773           0 :       return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
    3774             : 
    3775          98 :     GNUNET_assert (NULL != dk);
    3776             : 
    3777          98 :     if (GNUNET_CRYPTO_BSA_CS !=
    3778          98 :         hd->denom_pub.bsign_pub_key->cipher)
    3779           0 :       return TALER_EC_EXCHANGE_GENERIC_INVALID_DENOMINATION_CIPHER_FOR_OPERATION
    3780             :       ;
    3781             : 
    3782          98 :     if (GNUNET_TIME_absolute_is_future (hd->start_time.abs_time))
    3783           0 :       return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE;
    3784             : 
    3785          98 :     if (dk->recoup_possible)
    3786           0 :       return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED;
    3787             : 
    3788          98 :     if (GNUNET_TIME_relative_is_zero (hd->validity_duration))
    3789           0 :       return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED;
    3790             : 
    3791          98 :     cdrs[i].h_cs = &hd->h_details.h_cs;
    3792          98 :     cdrs[i].nonce = &nonces[i];
    3793             :   }
    3794             : 
    3795          50 :   return TALER_CRYPTO_helper_cs_r_batch_derive (ksh->helpers->csdh,
    3796             :                                                 num,
    3797             :                                                 cdrs,
    3798             :                                                 for_melt,
    3799             :                                                 r_pubs);
    3800             : }
    3801             : 
    3802             : 
    3803             : void
    3804           0 : TEH_keys_denomination_revoke (const struct TALER_DenominationHashP *h_denom_pub)
    3805             : {
    3806             :   struct TEH_KeyStateHandle *ksh;
    3807             :   struct HelperDenomination *hd;
    3808             : 
    3809           0 :   ksh = TEH_keys_get_state ();
    3810           0 :   if (NULL == ksh)
    3811             :   {
    3812           0 :     GNUNET_break (0);
    3813           0 :     return;
    3814             :   }
    3815           0 :   hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    3816             :                                           &h_denom_pub->hash);
    3817           0 :   if (NULL == hd)
    3818             :   {
    3819           0 :     GNUNET_break (0);
    3820           0 :     return;
    3821             :   }
    3822           0 :   switch (hd->denom_pub.bsign_pub_key->cipher)
    3823             :   {
    3824           0 :   case GNUNET_CRYPTO_BSA_INVALID:
    3825           0 :     break;
    3826           0 :   case GNUNET_CRYPTO_BSA_RSA:
    3827           0 :     TALER_CRYPTO_helper_rsa_revoke (ksh->helpers->rsadh,
    3828           0 :                                     &hd->h_details.h_rsa);
    3829           0 :     TEH_keys_update_states ();
    3830           0 :     return;
    3831           0 :   case GNUNET_CRYPTO_BSA_CS:
    3832           0 :     TALER_CRYPTO_helper_cs_revoke (ksh->helpers->csdh,
    3833           0 :                                    &hd->h_details.h_cs);
    3834           0 :     TEH_keys_update_states ();
    3835           0 :     return;
    3836             :   }
    3837           0 :   GNUNET_break (0);
    3838           0 :   return;
    3839             : }
    3840             : 
    3841             : 
    3842             : enum TALER_ErrorCode
    3843         170 : TEH_keys_exchange_sign_ (
    3844             :   const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
    3845             :   struct TALER_ExchangePublicKeyP *pub,
    3846             :   struct TALER_ExchangeSignatureP *sig)
    3847             : {
    3848             :   struct TEH_KeyStateHandle *ksh;
    3849             : 
    3850         170 :   ksh = TEH_keys_get_state ();
    3851         170 :   if (NULL == ksh)
    3852             :   {
    3853             :     /* This *can* happen if the exchange's crypto helper is not running
    3854             :        or had some bad error. */
    3855           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3856             :                 "Cannot sign request, no valid signing keys available.\n");
    3857           0 :     return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
    3858             :   }
    3859         170 :   return TEH_keys_exchange_sign2_ (ksh,
    3860             :                                    purpose,
    3861             :                                    pub,
    3862             :                                    sig);
    3863             : }
    3864             : 
    3865             : 
    3866             : enum TALER_ErrorCode
    3867        1066 : TEH_keys_exchange_sign2_ (
    3868             :   void *cls,
    3869             :   const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
    3870             :   struct TALER_ExchangePublicKeyP *pub,
    3871             :   struct TALER_ExchangeSignatureP *sig)
    3872             : {
    3873        1066 :   struct TEH_KeyStateHandle *ksh = cls;
    3874             :   enum TALER_ErrorCode ec;
    3875             : 
    3876        1066 :   TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_EDDSA]++;
    3877        1066 :   ec = TALER_CRYPTO_helper_esign_sign_ (ksh->helpers->esh,
    3878             :                                         purpose,
    3879             :                                         pub,
    3880             :                                         sig);
    3881        1066 :   if (TALER_EC_NONE != ec)
    3882           0 :     return ec;
    3883             :   {
    3884             :     /* Here we check here that 'pub' is set to an exchange public key that is
    3885             :        actually signed by the master key! Otherwise, we happily continue to
    3886             :        use key material even if the offline signatures have not been made
    3887             :        yet! */
    3888             :     struct GNUNET_PeerIdentity pid;
    3889             :     struct SigningKey *sk;
    3890             : 
    3891        1066 :     pid.public_key = pub->eddsa_pub;
    3892        1066 :     sk = GNUNET_CONTAINER_multipeermap_get (ksh->signkey_map,
    3893             :                                             &pid);
    3894        1066 :     if (NULL == sk)
    3895             :     {
    3896             :       /* just to be safe, zero out the (valid) signature, as the key
    3897             :          should not or no longer be used */
    3898           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    3899             :                   "Cannot sign, offline key signatures are missing!\n");
    3900           0 :       memset (sig,
    3901             :               0,
    3902             :               sizeof (*sig));
    3903           0 :       return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    3904             :     }
    3905             :   }
    3906        1066 :   return ec;
    3907             : }
    3908             : 
    3909             : 
    3910             : void
    3911           0 : TEH_keys_exchange_revoke (const struct TALER_ExchangePublicKeyP *exchange_pub)
    3912             : {
    3913             :   struct TEH_KeyStateHandle *ksh;
    3914             : 
    3915           0 :   ksh = TEH_keys_get_state ();
    3916           0 :   if (NULL == ksh)
    3917             :   {
    3918           0 :     GNUNET_break (0);
    3919           0 :     return;
    3920             :   }
    3921           0 :   TALER_CRYPTO_helper_esign_revoke (ksh->helpers->esh,
    3922             :                                     exchange_pub);
    3923           0 :   TEH_keys_update_states ();
    3924             : }
    3925             : 
    3926             : 
    3927             : /**
    3928             :  * Comparator used for a binary search by cherry_pick_date for @a key in the
    3929             :  * `struct KeysResponseData` array. See libc's qsort() and bsearch() functions.
    3930             :  *
    3931             :  * @param key pointer to a `struct GNUNET_TIME_Timestamp`
    3932             :  * @param value pointer to a `struct KeysResponseData` array entry
    3933             :  * @return 0 if time matches, -1 if key is smaller, 1 if key is larger
    3934             :  */
    3935             : static int
    3936         240 : krd_search_comparator (const void *key,
    3937             :                        const void *value)
    3938             : {
    3939         240 :   const struct GNUNET_TIME_Timestamp *kd = key;
    3940         240 :   const struct KeysResponseData *krd = value;
    3941             : 
    3942         240 :   if (GNUNET_TIME_timestamp_cmp (*kd,
    3943             :                                  >,
    3944             :                                  krd->cherry_pick_date))
    3945          22 :     return -1;
    3946         218 :   if (GNUNET_TIME_timestamp_cmp (*kd,
    3947             :                                  <,
    3948             :                                  krd->cherry_pick_date))
    3949         210 :     return 1;
    3950           8 :   return 0;
    3951             : }
    3952             : 
    3953             : 
    3954             : MHD_RESULT
    3955          69 : TEH_keys_get_handler (struct TEH_RequestContext *rc,
    3956             :                       const char *const args[])
    3957             : {
    3958             :   struct GNUNET_TIME_Timestamp last_issue_date;
    3959             :   const char *etag;
    3960             : 
    3961          69 :   etag = MHD_lookup_connection_value (rc->connection,
    3962             :                                       MHD_HEADER_KIND,
    3963             :                                       MHD_HTTP_HEADER_IF_NONE_MATCH);
    3964             :   (void) args;
    3965             :   {
    3966             :     const char *have_cherrypick;
    3967             : 
    3968          69 :     have_cherrypick = MHD_lookup_connection_value (rc->connection,
    3969             :                                                    MHD_GET_ARGUMENT_KIND,
    3970             :                                                    "last_issue_date");
    3971          69 :     if (NULL != have_cherrypick)
    3972             :     {
    3973             :       unsigned long long cherrypickn;
    3974             : 
    3975           8 :       if (1 !=
    3976           8 :           sscanf (have_cherrypick,
    3977             :                   "%llu",
    3978             :                   &cherrypickn))
    3979             :       {
    3980           0 :         GNUNET_break_op (0);
    3981           0 :         return TALER_MHD_reply_with_error (rc->connection,
    3982             :                                            MHD_HTTP_BAD_REQUEST,
    3983             :                                            TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3984             :                                            have_cherrypick);
    3985             :       }
    3986             :       /* The following multiplication may overflow; but this should not really
    3987             :          be a problem, as giving back 'older' data than what the client asks for
    3988             :          (given that the client asks for data in the distant future) is not
    3989             :          problematic */
    3990           8 :       last_issue_date = GNUNET_TIME_timestamp_from_s (cherrypickn);
    3991             :     }
    3992             :     else
    3993             :     {
    3994          61 :       last_issue_date = GNUNET_TIME_UNIT_ZERO_TS;
    3995             :     }
    3996             :   }
    3997             : 
    3998             :   {
    3999             :     struct TEH_KeyStateHandle *ksh;
    4000             :     const struct KeysResponseData *krd;
    4001             : 
    4002          69 :     ksh = TEH_keys_get_state ();
    4003          69 :     if ( (NULL == ksh) ||
    4004          59 :          (0 == ksh->krd_array_length) )
    4005             :     {
    4006          10 :       if ( ( (SKR_LIMIT == skr_size) &&
    4007          10 :              (rc->connection == skr_connection) ) ||
    4008             :            TEH_suicide)
    4009             :       {
    4010           0 :         return TALER_MHD_reply_with_error (
    4011             :           rc->connection,
    4012             :           MHD_HTTP_SERVICE_UNAVAILABLE,
    4013             :           TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
    4014             :           TEH_suicide
    4015           0 :           ? "server terminating"
    4016             :           : "too many connections suspended waiting on /keys");
    4017             :       }
    4018          10 :       return suspend_request (rc->connection);
    4019             :     }
    4020          59 :     krd = bsearch (&last_issue_date,
    4021          59 :                    ksh->krd_array,
    4022          59 :                    ksh->krd_array_length,
    4023             :                    sizeof (struct KeysResponseData),
    4024             :                    &krd_search_comparator);
    4025          59 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    4026             :                 "Filtering /keys by cherry pick date %s found entry %u/%u\n",
    4027             :                 GNUNET_TIME_timestamp2s (last_issue_date),
    4028             :                 (unsigned int) (krd - ksh->krd_array),
    4029             :                 ksh->krd_array_length);
    4030          59 :     if ( (NULL == krd) &&
    4031          51 :          (ksh->krd_array_length > 0) )
    4032             :     {
    4033          51 :       if (! GNUNET_TIME_absolute_is_zero (last_issue_date.abs_time))
    4034           0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    4035             :                     "Client provided invalid cherry picking timestamp %s, returning full response\n",
    4036             :                     GNUNET_TIME_timestamp2s (last_issue_date));
    4037          51 :       krd = &ksh->krd_array[ksh->krd_array_length - 1];
    4038             :     }
    4039          59 :     if (NULL == krd)
    4040             :     {
    4041             :       /* Likely keys not ready *yet*.
    4042             :          Wait until they are. */
    4043           0 :       return suspend_request (rc->connection);
    4044             :     }
    4045          59 :     if ( (NULL != etag) &&
    4046           0 :          (0 == strcmp (etag,
    4047           0 :                        krd->etag)) )
    4048           0 :       return TEH_RESPONSE_reply_not_modified (rc->connection,
    4049           0 :                                               krd->etag,
    4050             :                                               &setup_general_response_headers,
    4051             :                                               ksh);
    4052             : 
    4053          59 :     return MHD_queue_response (
    4054             :       rc->connection,
    4055             :       MHD_HTTP_OK,
    4056             :       (TALER_MHD_CT_DEFLATE ==
    4057          59 :        TALER_MHD_can_compress (rc->connection,
    4058             :                                TALER_MHD_CT_DEFLATE))
    4059             :       ? krd->response_compressed
    4060             :       : krd->response_uncompressed);
    4061             :   }
    4062             : }
    4063             : 
    4064             : 
    4065             : /**
    4066             :  * Load extension data, like fees, expiration times (!) and age restriction
    4067             :  * flags for the denomination type configured in section @a section_name.
    4068             :  * Before calling this function, the `start` and `validity_duration` times must
    4069             :  * already be initialized in @a meta.
    4070             :  *
    4071             :  * @param section_name section in the configuration to use
    4072             :  * @param[in,out] meta denomination type data to complete
    4073             :  * @return #GNUNET_OK on success
    4074             :  */
    4075             : static enum GNUNET_GenericReturnValue
    4076       18660 : load_extension_data (const char *section_name,
    4077             :                      struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta)
    4078             : {
    4079             :   struct GNUNET_TIME_Relative deposit_duration;
    4080             :   struct GNUNET_TIME_Relative legal_duration;
    4081             : 
    4082       18660 :   GNUNET_assert (! GNUNET_TIME_absolute_is_zero (meta->start.abs_time)); /* caller bug */
    4083       18660 :   if (GNUNET_OK !=
    4084       18660 :       GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
    4085             :                                            section_name,
    4086             :                                            "DURATION_SPEND",
    4087             :                                            &deposit_duration))
    4088             :   {
    4089           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    4090             :                                section_name,
    4091             :                                "DURATION_SPEND");
    4092           0 :     return GNUNET_SYSERR;
    4093             :   }
    4094       18660 :   if (GNUNET_OK !=
    4095       18660 :       GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
    4096             :                                            section_name,
    4097             :                                            "DURATION_LEGAL",
    4098             :                                            &legal_duration))
    4099             :   {
    4100           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    4101             :                                section_name,
    4102             :                                "DURATION_LEGAL");
    4103           0 :     return GNUNET_SYSERR;
    4104             :   }
    4105             :   meta->expire_deposit
    4106       18660 :     = GNUNET_TIME_absolute_to_timestamp (
    4107             :         GNUNET_TIME_absolute_add (meta->expire_withdraw.abs_time,
    4108             :                                   deposit_duration));
    4109       18660 :   meta->expire_legal = GNUNET_TIME_absolute_to_timestamp (
    4110             :     GNUNET_TIME_absolute_add (meta->expire_deposit.abs_time,
    4111             :                               legal_duration));
    4112       18660 :   if (GNUNET_OK !=
    4113       18660 :       TALER_config_get_amount (TEH_cfg,
    4114             :                                section_name,
    4115             :                                "VALUE",
    4116             :                                &meta->value))
    4117             :   {
    4118           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    4119             :                                "Need amount for option `%s' in section `%s'\n",
    4120             :                                "VALUE",
    4121             :                                section_name);
    4122           0 :     return GNUNET_SYSERR;
    4123             :   }
    4124       18660 :   if (0 != strcasecmp (TEH_currency,
    4125       18660 :                        meta->value.currency))
    4126             :   {
    4127           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    4128             :                 "Need denomination value in section `%s' to use currency `%s'\n",
    4129             :                 section_name,
    4130             :                 TEH_currency);
    4131           0 :     return GNUNET_SYSERR;
    4132             :   }
    4133       18660 :   if (GNUNET_OK !=
    4134       18660 :       TALER_config_get_denom_fees (TEH_cfg,
    4135             :                                    TEH_currency,
    4136             :                                    section_name,
    4137             :                                    &meta->fees))
    4138           0 :     return GNUNET_SYSERR;
    4139       18660 :   meta->age_mask = load_age_mask (section_name);
    4140       18660 :   return GNUNET_OK;
    4141             : }
    4142             : 
    4143             : 
    4144             : enum GNUNET_GenericReturnValue
    4145        6220 : TEH_keys_load_fees (struct TEH_KeyStateHandle *ksh,
    4146             :                     const struct TALER_DenominationHashP *h_denom_pub,
    4147             :                     struct TALER_DenominationPublicKey *denom_pub,
    4148             :                     struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta)
    4149             : {
    4150             :   struct HelperDenomination *hd;
    4151             :   enum GNUNET_GenericReturnValue ok;
    4152             : 
    4153        6220 :   hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    4154             :                                           &h_denom_pub->hash);
    4155        6220 :   if (NULL == hd)
    4156             :   {
    4157           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    4158             :                 "Denomination %s not known\n",
    4159             :                 GNUNET_h2s (&h_denom_pub->hash));
    4160           0 :     return GNUNET_NO;
    4161             :   }
    4162        6220 :   meta->start = hd->start_time;
    4163        6220 :   meta->expire_withdraw = GNUNET_TIME_absolute_to_timestamp (
    4164             :     GNUNET_TIME_absolute_add (meta->start.abs_time,
    4165             :                               hd->validity_duration));
    4166        6220 :   ok = load_extension_data (hd->section_name,
    4167             :                             meta);
    4168        6220 :   if (GNUNET_OK == ok)
    4169             :   {
    4170        6220 :     GNUNET_assert (GNUNET_CRYPTO_BSA_INVALID !=
    4171             :                    hd->denom_pub.bsign_pub_key->cipher);
    4172        6220 :     TALER_denom_pub_copy (denom_pub,
    4173        6220 :                           &hd->denom_pub);
    4174             :   }
    4175             :   else
    4176             :   {
    4177           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    4178             :                 "No fees for `%s', voiding key\n",
    4179             :                 hd->section_name);
    4180           0 :     memset (denom_pub,
    4181             :             0,
    4182             :             sizeof (*denom_pub));
    4183             :   }
    4184        6220 :   return ok;
    4185             : }
    4186             : 
    4187             : 
    4188             : enum GNUNET_GenericReturnValue
    4189          67 : TEH_keys_get_timing (const struct TALER_ExchangePublicKeyP *exchange_pub,
    4190             :                      struct TALER_EXCHANGEDB_SignkeyMetaData *meta)
    4191             : {
    4192             :   struct TEH_KeyStateHandle *ksh;
    4193             :   struct HelperSignkey *hsk;
    4194             :   struct GNUNET_PeerIdentity pid;
    4195             : 
    4196          67 :   ksh = TEH_keys_get_state_for_management_only ();
    4197          67 :   if (NULL == ksh)
    4198             :   {
    4199           0 :     GNUNET_break (0);
    4200           0 :     return GNUNET_SYSERR;
    4201             :   }
    4202             : 
    4203          67 :   pid.public_key = exchange_pub->eddsa_pub;
    4204          67 :   hsk = GNUNET_CONTAINER_multipeermap_get (ksh->helpers->esign_keys,
    4205             :                                            &pid);
    4206          67 :   if (NULL == hsk)
    4207             :   {
    4208           0 :     GNUNET_break (0);
    4209           0 :     return GNUNET_NO;
    4210             :   }
    4211          67 :   meta->start = hsk->start_time;
    4212             : 
    4213          67 :   meta->expire_sign = GNUNET_TIME_absolute_to_timestamp (
    4214             :     GNUNET_TIME_absolute_add (meta->start.abs_time,
    4215             :                               hsk->validity_duration));
    4216          67 :   meta->expire_legal = GNUNET_TIME_absolute_to_timestamp (
    4217             :     GNUNET_TIME_absolute_add (meta->expire_sign.abs_time,
    4218             :                               signkey_legal_duration));
    4219          67 :   return GNUNET_OK;
    4220             : }
    4221             : 
    4222             : 
    4223             : /**
    4224             :  * Closure for #add_future_denomkey_cb and #add_future_signkey_cb.
    4225             :  */
    4226             : struct FutureBuilderContext
    4227             : {
    4228             :   /**
    4229             :    * Our key state.
    4230             :    */
    4231             :   struct TEH_KeyStateHandle *ksh;
    4232             : 
    4233             :   /**
    4234             :    * Array of denomination keys.
    4235             :    */
    4236             :   json_t *denoms;
    4237             : 
    4238             :   /**
    4239             :    * Array of signing keys.
    4240             :    */
    4241             :   json_t *signkeys;
    4242             : 
    4243             : };
    4244             : 
    4245             : 
    4246             : /**
    4247             :  * Function called on all of our current and future denomination keys
    4248             :  * known to the helper process. Filters out those that are current
    4249             :  * and adds the remaining denomination keys (with their configuration
    4250             :  * data) to the JSON array.
    4251             :  *
    4252             :  * @param cls the `struct FutureBuilderContext *`
    4253             :  * @param h_denom_pub hash of the denomination public key
    4254             :  * @param value a `struct HelperDenomination`
    4255             :  * @return #GNUNET_OK (continue to iterate)
    4256             :  */
    4257             : static enum GNUNET_GenericReturnValue
    4258       13500 : add_future_denomkey_cb (void *cls,
    4259             :                         const struct GNUNET_HashCode *h_denom_pub,
    4260             :                         void *value)
    4261             : {
    4262       13500 :   struct FutureBuilderContext *fbc = cls;
    4263       13500 :   struct HelperDenomination *hd = value;
    4264             :   struct TEH_DenominationKey *dk;
    4265       13500 :   struct TALER_EXCHANGEDB_DenominationKeyMetaData meta = {0};
    4266             : 
    4267       13500 :   dk = GNUNET_CONTAINER_multihashmap_get (fbc->ksh->denomkey_map,
    4268             :                                           h_denom_pub);
    4269       13500 :   if (NULL != dk)
    4270        1060 :     return GNUNET_OK; /* skip: this key is already active! */
    4271       12440 :   if (GNUNET_TIME_relative_is_zero (hd->validity_duration))
    4272           0 :     return GNUNET_OK; /* this key already expired! */
    4273       12440 :   meta.start = hd->start_time;
    4274       12440 :   meta.expire_withdraw = GNUNET_TIME_absolute_to_timestamp (
    4275             :     GNUNET_TIME_absolute_add (meta.start.abs_time,
    4276             :                               hd->validity_duration));
    4277       12440 :   if (GNUNET_OK !=
    4278       12440 :       load_extension_data (hd->section_name,
    4279             :                            &meta))
    4280             :   {
    4281             :     /* Woops, couldn't determine fee structure!? */
    4282           0 :     return GNUNET_OK;
    4283             :   }
    4284       12440 :   GNUNET_assert (
    4285             :     0 ==
    4286             :     json_array_append_new (
    4287             :       fbc->denoms,
    4288             :       GNUNET_JSON_PACK (
    4289             :         TALER_JSON_pack_amount ("value",
    4290             :                                 &meta.value),
    4291             :         GNUNET_JSON_pack_timestamp ("stamp_start",
    4292             :                                     meta.start),
    4293             :         GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
    4294             :                                     meta.expire_withdraw),
    4295             :         GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
    4296             :                                     meta.expire_deposit),
    4297             :         GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
    4298             :                                     meta.expire_legal),
    4299             :         TALER_JSON_pack_denom_pub ("denom_pub",
    4300             :                                    &hd->denom_pub),
    4301             :         TALER_JSON_PACK_DENOM_FEES ("fee",
    4302             :                                     &meta.fees),
    4303             :         GNUNET_JSON_pack_data_auto ("denom_secmod_sig",
    4304             :                                     &hd->sm_sig),
    4305             :         GNUNET_JSON_pack_string ("section_name",
    4306             :                                  hd->section_name))));
    4307       12440 :   return GNUNET_OK;
    4308             : }
    4309             : 
    4310             : 
    4311             : /**
    4312             :  * Function called on all of our current and future exchange signing keys
    4313             :  * known to the helper process. Filters out those that are current
    4314             :  * and adds the remaining signing keys (with their configuration
    4315             :  * data) to the JSON array.
    4316             :  *
    4317             :  * @param cls the `struct FutureBuilderContext *`
    4318             :  * @param pid actually the exchange public key (type disguised)
    4319             :  * @param value a `struct HelperDenomination`
    4320             :  * @return #GNUNET_OK (continue to iterate)
    4321             :  */
    4322             : static enum GNUNET_GenericReturnValue
    4323         144 : add_future_signkey_cb (void *cls,
    4324             :                        const struct GNUNET_PeerIdentity *pid,
    4325             :                        void *value)
    4326             : {
    4327         144 :   struct FutureBuilderContext *fbc = cls;
    4328         144 :   struct HelperSignkey *hsk = value;
    4329             :   struct SigningKey *sk;
    4330             :   struct GNUNET_TIME_Timestamp stamp_expire;
    4331             :   struct GNUNET_TIME_Timestamp legal_end;
    4332             : 
    4333         144 :   sk = GNUNET_CONTAINER_multipeermap_get (fbc->ksh->signkey_map,
    4334             :                                           pid);
    4335         144 :   if (NULL != sk)
    4336          10 :     return GNUNET_OK; /* skip: this key is already active */
    4337         134 :   if (GNUNET_TIME_relative_is_zero (hsk->validity_duration))
    4338           0 :     return GNUNET_OK; /* this key already expired! */
    4339         134 :   stamp_expire = GNUNET_TIME_absolute_to_timestamp (
    4340             :     GNUNET_TIME_absolute_add (hsk->start_time.abs_time,
    4341             :                               hsk->validity_duration));
    4342         134 :   legal_end = GNUNET_TIME_absolute_to_timestamp (
    4343             :     GNUNET_TIME_absolute_add (stamp_expire.abs_time,
    4344             :                               signkey_legal_duration));
    4345         134 :   GNUNET_assert (0 ==
    4346             :                  json_array_append_new (
    4347             :                    fbc->signkeys,
    4348             :                    GNUNET_JSON_PACK (
    4349             :                      GNUNET_JSON_pack_data_auto ("key",
    4350             :                                                  &hsk->exchange_pub),
    4351             :                      GNUNET_JSON_pack_timestamp ("stamp_start",
    4352             :                                                  hsk->start_time),
    4353             :                      GNUNET_JSON_pack_timestamp ("stamp_expire",
    4354             :                                                  stamp_expire),
    4355             :                      GNUNET_JSON_pack_timestamp ("stamp_end",
    4356             :                                                  legal_end),
    4357             :                      GNUNET_JSON_pack_data_auto ("signkey_secmod_sig",
    4358             :                                                  &hsk->sm_sig))));
    4359         134 :   return GNUNET_OK;
    4360             : }
    4361             : 
    4362             : 
    4363             : MHD_RESULT
    4364          40 : TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh,
    4365             :                                       struct MHD_Connection *connection)
    4366             : {
    4367             :   struct TEH_KeyStateHandle *ksh;
    4368             :   json_t *reply;
    4369             : 
    4370             :   (void) rh;
    4371          40 :   ksh = TEH_keys_get_state_for_management_only ();
    4372          40 :   if (NULL == ksh)
    4373             :   {
    4374           0 :     return TALER_MHD_reply_with_error (connection,
    4375             :                                        MHD_HTTP_SERVICE_UNAVAILABLE,
    4376             :                                        TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
    4377             :                                        "no key state");
    4378             :   }
    4379          40 :   sync_key_helpers (ksh->helpers);
    4380          40 :   if (NULL == ksh->management_keys_reply)
    4381             :   {
    4382         120 :     struct FutureBuilderContext fbc = {
    4383             :       .ksh = ksh,
    4384          40 :       .denoms = json_array (),
    4385          40 :       .signkeys = json_array ()
    4386             :     };
    4387             : 
    4388          55 :     if ( (GNUNET_is_zero (&denom_rsa_sm_pub)) &&
    4389          15 :          (GNUNET_is_zero (&denom_cs_sm_pub)) )
    4390             :     {
    4391             :       /* Either IPC failed, or neither helper had any denominations configured. */
    4392           0 :       return TALER_MHD_reply_with_error (connection,
    4393             :                                          MHD_HTTP_BAD_GATEWAY,
    4394             :                                          TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE,
    4395             :                                          NULL);
    4396             :     }
    4397          40 :     if (GNUNET_is_zero (&esign_sm_pub))
    4398             :     {
    4399           0 :       return TALER_MHD_reply_with_error (connection,
    4400             :                                          MHD_HTTP_BAD_GATEWAY,
    4401             :                                          TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE,
    4402             :                                          NULL);
    4403             :     }
    4404          40 :     GNUNET_assert (NULL != fbc.denoms);
    4405          40 :     GNUNET_assert (NULL != fbc.signkeys);
    4406          40 :     GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->denom_keys,
    4407             :                                            &add_future_denomkey_cb,
    4408             :                                            &fbc);
    4409          40 :     GNUNET_CONTAINER_multipeermap_iterate (ksh->helpers->esign_keys,
    4410             :                                            &add_future_signkey_cb,
    4411             :                                            &fbc);
    4412          40 :     reply = GNUNET_JSON_PACK (
    4413             :       GNUNET_JSON_pack_array_steal ("future_denoms",
    4414             :                                     fbc.denoms),
    4415             :       GNUNET_JSON_pack_array_steal ("future_signkeys",
    4416             :                                     fbc.signkeys),
    4417             :       GNUNET_JSON_pack_data_auto ("master_pub",
    4418             :                                   &TEH_master_public_key),
    4419             :       GNUNET_JSON_pack_data_auto ("denom_secmod_public_key",
    4420             :                                   &denom_rsa_sm_pub),
    4421             :       GNUNET_JSON_pack_data_auto ("denom_secmod_cs_public_key",
    4422             :                                   &denom_cs_sm_pub),
    4423             :       GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key",
    4424             :                                   &esign_sm_pub));
    4425          40 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    4426             :                 "Returning GET /management/keys response:\n");
    4427          40 :     if (NULL == reply)
    4428           0 :       return TALER_MHD_reply_with_error (connection,
    4429             :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    4430             :                                          TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
    4431             :                                          NULL);
    4432          40 :     GNUNET_assert (NULL == ksh->management_keys_reply);
    4433          40 :     ksh->management_keys_reply = reply;
    4434             :   }
    4435             :   else
    4436             :   {
    4437           0 :     reply = ksh->management_keys_reply;
    4438             :   }
    4439          40 :   return TALER_MHD_reply_json (connection,
    4440             :                                reply,
    4441             :                                MHD_HTTP_OK);
    4442             : }
    4443             : 
    4444             : 
    4445             : /* end of taler-exchange-httpd_keys.c */

Generated by: LCOV version 1.16