exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

taler-exchange-httpd_keys.c (134823B)


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